# Instructions - Following Playwright test failed. - Explain why, be concise, respect Playwright best practices. - Provide a snippet of code with the fix, if possible. # Test info - Name: src/manager/tests/e2e/unit/unit-create.spec.ts >> creates a vacant unit with measurements - Location: src/manager/tests/e2e/unit/unit-create.spec.ts:13:7 # Error details ``` Error: Failed to sync billing catalog via http://billing-api-dev:8080/e2e/storeroom/import: 500 ``` # Test source ```ts 1 | import { request as playwrightRequest } from '@playwright/test'; 2 | 3 | type BillingMode = 'modern' | 'classic'; 4 | 5 | const DEFAULT_BILLING_API_URL = 'https://billing-api-test.kinnovis.com'; 6 | 7 | // `KINNOVIS_BILLING=1` runs the suite against the modern (Kinnovis) billing system; any other value 8 | // (including `0` and unset) is classic. Mirrors the manager SPA's `isKinnovisBillingUser` switch: in 9 | // modern mode booking create/cancel move from the manager API to the billing API. 10 | function resolveBillingMode(): BillingMode { 11 | return process.env.KINNOVIS_BILLING === '1' ? 'modern' : 'classic'; 12 | } 13 | 14 | export function isModernBillingMode(): boolean { 15 | return resolveBillingMode() === 'modern'; 16 | } 17 | 18 | // Calls one of billing's unauthenticated e2e routes; `action` describes the intent in failure 19 | // messages, e.g. `Failed to via : `. 20 | async function callBillingE2eRoute(path: string, action: string): Promise { 21 | const baseURL = process.env.BILLING_API_URL ?? DEFAULT_BILLING_API_URL; 22 | const ctx = await playwrightRequest.newContext({ 23 | baseURL, 24 | extraHTTPHeaders: { Accept: 'application/json' }, 25 | }); 26 | 27 | try { 28 | const response = await ctx.get(path); 29 | 30 | if (!response.ok()) { > 31 | throw new Error(`Failed to ${action} via ${baseURL}${path}: ${response.status()} ${await response.text()}`); | ^ Error: Failed to sync billing catalog via http://billing-api-dev:8080/e2e/storeroom/import: 500 32 | } 33 | } finally { 34 | await ctx.dispose(); 35 | } 36 | } 37 | 38 | // Pins the shared QA storeroom tenant to the resolved billing mode via billing's unauthenticated 39 | // e2e reset route. Used by global setup so runs are deterministic regardless of the mode a 40 | // previous run left the environment in. 41 | export async function pinBillingMode(): Promise { 42 | const mode = resolveBillingMode(); 43 | await callBillingE2eRoute(`/e2e/storeroom/${mode}`, `pin billing mode to "${mode}"`); 44 | } 45 | 46 | // The modern billing system only learns about CLASSIC catalog changes through 47 | // `kin:catalog:import`, which is scheduled every five minutes — far too slow for a test 48 | // that creates a unit type (or discount, product, ...) and books it seconds later. This 49 | // triggers the import synchronously via billing's e2e route; the route serializes 50 | // concurrent callers server-side, so parallel workers can call it freely. 51 | // No-op in classic mode, where the billing catalog is not involved. 52 | export async function syncBillingCatalog(): Promise { 53 | if (!isModernBillingMode()) { 54 | return; 55 | } 56 | 57 | await callBillingE2eRoute('/e2e/storeroom/import', 'sync billing catalog'); 58 | } 59 | ```