TAP version 13 # (node:31) ExperimentalWarning: Module mocking is an experimental feature and might change at any time # (Use `node --trace-warnings ...` to show where the warning was created) # Subtest: stripe adapter — outbound # Subtest: is configured, because adapter-env.ts sets a key this suite can never spend ok 1 - is configured, because adapter-env.ts sets a key this suite can never spend --- duration_ms: 1.553958 type: 'test' ... # Subtest: creates customer, draft invoice, items and finalises — in that order ok 2 - creates customer, draft invoice, items and finalises — in that order --- duration_ms: 14.573208 type: 'test' ... # Subtest: attaches every item to the draft invoice by id, never to the pending queue ok 3 - attaches every item to the draft invoice by id, never to the pending queue --- duration_ms: 0.987292 type: 'test' ... # Subtest: opens the draft with a stated currency and nothing else allowed to join it ok 4 - opens the draft with a stated currency and nothing else allowed to join it --- duration_ms: 0.794584 type: 'test' ... # Subtest: posts one item per quote line plus a separate HST line ok 5 - posts one item per quote line plus a separate HST line --- duration_ms: 0.994791 type: 'test' ... # Subtest: carries a per-object idempotency key derived from the quote ok 6 - carries a per-object idempotency key derived from the quote --- duration_ms: 0.815583 type: 'test' ... # Subtest: sends the pinned API version and never a floating one ok 7 - sends the pinned API version and never a floating one --- duration_ms: 0.884375 type: 'test' ... # Subtest: creates the invoice as send_invoice, net 14, without auto-advance ok 8 - creates the invoice as send_invoice, net 14, without auto-advance --- duration_ms: 0.760333 type: 'test' ... # Subtest: reuses an existing customer found by email ok 9 - reuses an existing customer found by email --- duration_ms: 0.699625 type: 'test' ... # Subtest: does not search for a customer when the quote has no email ok 10 - does not search for a customer when the quote has no email --- duration_ms: 0.723 type: 'test' ... # Subtest: names the quote when the customer has no name ok 11 - names the quote when the customer has no name --- duration_ms: 0.924834 type: 'test' ... # Subtest: omits the tax line when the subtotal is zero ok 12 - omits the tax line when the subtotal is zero --- duration_ms: 0.532958 type: 'test' ... # Subtest: fails, rather than recording, an invoice whose total is not the quote's ok 13 - fails, rather than recording, an invoice whose total is not the quote's --- duration_ms: 0.759041 type: 'test' ... # Subtest: fails an invoice that finalises at zero when the quote is not zero ok 14 - fails an invoice that finalises at zero when the quote is not zero --- duration_ms: 0.700291 type: 'test' ... # Subtest: fails rather than guessing when Stripe omits the total ok 15 - fails rather than guessing when Stripe omits the total --- duration_ms: 0.74525 type: 'test' ... # Subtest: turns a provider error into FAILED and never throws ok 16 - turns a provider error into FAILED and never throws --- duration_ms: 0.469875 type: 'test' ... # Subtest: stops before writing any item when the draft invoice is rejected ok 17 - stops before writing any item when the draft invoice is rejected --- duration_ms: 0.402041 type: 'test' ... 1..17 ok 1 - stripe adapter — outbound --- duration_ms: 28.080792 type: 'suite' ... # Subtest: stripe invoice — read-back # Subtest: reads the mode off livemode rather than off any environment variable ok 1 - reads the mode off livemode rather than off any environment variable --- duration_ms: 3.711292 type: 'test' ... # Subtest: picks the tax line out by the description tax.ts owns ok 2 - picks the tax line out by the description tax.ts owns --- duration_ms: 0.129541 type: 'test' ... # Subtest: reports null, not zero, when no line carries that description ok 3 - reports null, not zero, when no line carries that description --- duration_ms: 0.097834 type: 'test' ... # Subtest: sums several tax lines rather than reporting the first ok 4 - sums several tax lines rather than reporting the first --- duration_ms: 8.427875 type: 'test' ... # Subtest: reports the subtotal net of our own tax lines, so subtotal + tax = total ok 5 - reports the subtotal net of our own tax lines, so subtotal + tax = total --- duration_ms: 0.117959 type: 'test' ... # Subtest: leaves the subtotal alone when no line carries our tax label ok 6 - leaves the subtotal alone when no line carries our tax label --- duration_ms: 3.64325 type: 'test' ... # Subtest: does not manufacture a subtotal Stripe did not send ok 7 - does not manufacture a subtotal Stripe did not send --- duration_ms: 0.166708 type: 'test' ... # Subtest: converts Stripe's epoch seconds to the ISO instants the rest of the API publishes ok 8 - converts Stripe's epoch seconds to the ISO instants the rest of the API publishes --- duration_ms: 0.108208 type: 'test' ... # Subtest: survives a response missing every field it reads ok 9 - survives a response missing every field it reads --- duration_ms: 0.107875 type: 'test' ... # Subtest: expands the line items in the request, so a caller needs one round trip ok 10 - expands the line items in the request, so a caller needs one round trip --- duration_ms: 0.298 type: 'test' ... 1..10 ok 2 - stripe invoice — read-back --- duration_ms: 16.997791 type: 'suite' ... # Subtest: stripe invoice — repair # Subtest: writes the missing invoice and returns it as created ok 1 - writes the missing invoice and returns it as created --- duration_ms: 237.907625 type: 'test' ... # Subtest: records the sync so the GET can find the invoice afterwards ok 2 - records the sync so the GET can find the invoice afterwards --- duration_ms: 6.785708 type: 'test' ... # Subtest: called twice, produces one invoice ok 3 - called twice, produces one invoice --- duration_ms: 10.346792 type: 'test' ... # Subtest: refuses a quote that is not approved, before reaching Stripe ok 4 - refuses a quote that is not approved, before reaching Stripe --- duration_ms: 4.084416 type: 'test' ... # Subtest: answers 404 for another tenant's quote rather than 403 ok 5 - answers 404 for another tenant's quote rather than 403 --- duration_ms: 77.679167 type: 'test' ... # Subtest: is closed to a technician, like everything else under /quotes ok 6 - is closed to a technician, like everything else under /quotes --- duration_ms: 57.802083 type: 'test' ... # Subtest: records a refusal as FAILED, answers 502, and counts the retry ok 7 - records a refusal as FAILED, answers 502, and counts the retry --- duration_ms: 3.115 type: 'test' ... 1..7 ok 3 - stripe invoice — repair --- duration_ms: 397.996 type: 'suite' ... # Subtest: stripe checkout — session creation # Subtest: posts one line per quote line plus HST, each with quantity 1 ok 1 - posts one line per quote line plus HST, each with quantity 1 --- duration_ms: 0.372125 type: 'test' ... # Subtest: names card explicitly rather than inheriting the account's methods ok 2 - names card explicitly rather than inheriting the account's methods --- duration_ms: 0.10625 type: 'test' ... # Subtest: never names payment_method_types while leaving Managed Payments to also choose ok 3 - never names payment_method_types while leaving Managed Payments to also choose --- duration_ms: 0.116625 type: 'test' ... # Subtest: carries the quote id in metadata and in client_reference_id ok 4 - carries the quote id in metadata and in client_reference_id --- duration_ms: 0.110292 type: 'test' ... # Subtest: omits customer_email when the quote has none ok 5 - omits customer_email when the quote has none --- duration_ms: 0.092209 type: 'test' ... # Subtest: leaves Stripe's session-id placeholder unencoded in success_url ok 6 - leaves Stripe's session-id placeholder unencoded in success_url --- duration_ms: 0.146375 type: 'test' ... # Subtest: expires the page inside Stripe's 30-minute floor and 24-hour ceiling ok 7 - expires the page inside Stripe's 30-minute floor and 24-hour ceiling --- duration_ms: 0.111209 type: 'test' ... # Subtest: builds a byte-identical body for the same bucket, whatever the clock says ok 8 - builds a byte-identical body for the same bucket, whatever the clock says --- duration_ms: 0.119 type: 'test' ... # Subtest: holds expires_at still across a bucket and moves it on between buckets ok 9 - holds expires_at still across a bucket and moves it on between buckets --- duration_ms: 0.103917 type: 'test' ... # Subtest: derives the idempotency key from the same bucket the body was built with ok 10 - derives the idempotency key from the same bucket the body was built with --- duration_ms: 0.179458 type: 'test' ... # Subtest: changes the key when the body changes, without anyone remembering to ok 11 - changes the key when the body changes, without anyone remembering to --- duration_ms: 0.116375 type: 'test' ... # Subtest: holds the key still when the body is unchanged ok 12 - holds the key still when the body is unchanged --- duration_ms: 0.130667 type: 'test' ... # Subtest: keeps the key inside Stripe's 255-character limit ok 13 - keeps the key inside Stripe's 255-character limit --- duration_ms: 0.108458 type: 'test' ... # Subtest: accepts a return_url whose origin is already trusted for CORS ok 14 - accepts a return_url whose origin is already trusted for CORS --- duration_ms: 0.131875 type: 'test' ... # Subtest: refuses a return_url on any other origin ok 15 - refuses a return_url on any other origin --- duration_ms: 0.289 type: 'test' ... # Subtest: refuses a return_url that is not an absolute http(s) URL ok 16 - refuses a return_url that is not an absolute http(s) URL --- duration_ms: 0.112167 type: 'test' ... # Subtest: defaults to the first CORS origin rather than a hardcoded marketing URL ok 17 - defaults to the first CORS origin rather than a hardcoded marketing URL --- duration_ms: 0.088666 type: 'test' ... # Subtest: creates the session and returns what Stripe answered ok 18 - creates the session and returns what Stripe answered --- duration_ms: 0.326333 type: 'test' ... # Subtest: sends an idempotency key derived from the body it was sent with ok 19 - sends an idempotency key derived from the body it was sent with --- duration_ms: 0.427333 type: 'test' ... # Subtest: reads a session back and reports whether it is still payable ok 20 - reads a session back and reports whether it is still payable --- duration_ms: 0.224292 type: 'test' ... # Subtest: surfaces a Stripe rejection rather than returning a session-shaped nothing ok 21 - surfaces a Stripe rejection rather than returning a session-shaped nothing --- duration_ms: 0.362209 type: 'test' ... 1..21 ok 4 - stripe checkout — session creation --- duration_ms: 4.079458 type: 'suite' ... # Subtest: quickbooks adapter — outbound # Subtest: posts an invoice and reports the figure QuickBooks stored ok 1 - posts an invoice and reports the figure QuickBooks stored --- duration_ms: 2.016666 type: 'test' ... # Subtest: addresses the sandbox host and the pinned minor version ok 2 - addresses the sandbox host and the pinned minor version --- duration_ms: 0.679292 type: 'test' ... # Subtest: puts the tax code on every line when the company file has HST ON ok 3 - puts the tax code on every line when the company file has HST ON --- duration_ms: 0.57675 type: 'test' ... # Subtest: adds an explicit HST line when the company file has no HST ON code ok 4 - adds an explicit HST line when the company file has no HST ON code --- duration_ms: 0.56825 type: 'test' ... # Subtest: doubles an apostrophe before it reaches the query language ok 5 - doubles an apostrophe before it reaches the query language --- duration_ms: 0.602333 type: 'test' ... # Subtest: creates the service item once, against an income account, when the realm has none ok 6 - creates the service item once, against an income account, when the realm has none --- duration_ms: 0.592583 type: 'test' ... # Subtest: fails with a readable message when the realm has no income account ok 7 - fails with a readable message when the realm has no income account --- duration_ms: 0.483958 type: 'test' ... # Subtest: refreshes proactively when the access token is inside the two-minute margin ok 8 - refreshes proactively when the access token is inside the two-minute margin --- duration_ms: 0.819333 type: 'test' ... # Subtest: does not refresh a token that is not close to expiry ok 9 - does not refresh a token that is not close to expiry --- duration_ms: 0.510125 type: 'test' ... # Subtest: marks the connection EXPIRED on a 401 and ERROR on anything else ok 10 - marks the connection EXPIRED on a 401 and ERROR on anything else --- duration_ms: 0.827167 type: 'test' ... # Subtest: skips rather than fails when the tenant has never connected ok 11 - skips rather than fails when the tenant has never connected --- duration_ms: 0.142792 type: 'test' ... # Subtest: skips when the connection has no realm id ok 12 - skips when the connection has no realm id --- duration_ms: 0.212875 type: 'test' ... # Subtest: clears a previous error after a successful post ok 13 - clears a previous error after a successful post --- duration_ms: 1.055084 type: 'test' ... # Subtest: reports the disagreement rather than raising it ok 14 - reports the disagreement rather than raising it --- duration_ms: 2.441083 type: 'test' ... # Subtest: records a null amount when the read-back has no total ok 15 - records a null amount when the read-back has no total --- duration_ms: 1.552458 type: 'test' ... 1..15 ok 5 - quickbooks adapter — outbound --- duration_ms: 13.353 type: 'suite' ... # Subtest: salesforce adapter — outbound # Subtest: creates a Closed Won opportunity against a matched account ok 1 - creates a Closed Won opportunity against a matched account --- duration_ms: 0.902042 type: 'test' ... # Subtest: addresses the per-org instance URL from the connection, not the login host ok 2 - addresses the per-org instance URL from the connection, not the login host --- duration_ms: 0.445375 type: 'test' ... # Subtest: creates the account when no name matches ok 3 - creates the account when no name matches --- duration_ms: 0.563208 type: 'test' ... # Subtest: escapes a backslash and an apostrophe in SOQL, in that order ok 4 - escapes a backslash and an apostrophe in SOQL, in that order --- duration_ms: 0.514541 type: 'test' ... # Subtest: refreshes once on a 401 and carries the old refresh token forward ok 5 - refreshes once on a 401 and carries the old refresh token forward --- duration_ms: 1.331542 type: 'test' ... # Subtest: does not retry a second 401 — that is a revoked grant, not a stale token ok 6 - does not retry a second 401 — that is a revoked grant, not a stale token --- duration_ms: 0.740167 type: 'test' ... # Subtest: does not attempt a refresh when there is no refresh token ok 7 - does not attempt a refresh when there is no refresh token --- duration_ms: 0.569916 type: 'test' ... # Subtest: skips when the connection has no instance URL ok 8 - skips when the connection has no instance URL --- duration_ms: 0.25875 type: 'test' ... # Subtest: records a null amount when the read-back omits it ok 9 - records a null amount when the read-back omits it --- duration_ms: 0.4875 type: 'test' ... # Subtest: marks ERROR rather than EXPIRED on a 403, which is a scope problem ok 10 - marks ERROR rather than EXPIRED on a 403, which is a scope problem --- duration_ms: 0.35925 type: 'test' ... 1..10 ok 6 - salesforce adapter — outbound --- duration_ms: 6.359667 type: 'suite' ... # Subtest: quickbooks oauth # Subtest: sends the client credentials as HTTP Basic, not as form fields ok 1 - sends the client credentials as HTTP Basic, not as form fields --- duration_ms: 0.326542 type: 'test' ... # Subtest: leaves the refresh expiry null when Intuit omits it ok 2 - leaves the refresh expiry null when Intuit omits it --- duration_ms: 0.192041 type: 'test' ... # Subtest: defaults to the sandbox data host ok 3 - defaults to the sandbox data host --- duration_ms: 0.078917 type: 'test' ... 1..3 ok 7 - quickbooks oauth --- duration_ms: 0.659083 type: 'suite' ... # Subtest: salesforce oauth # Subtest: reads the org id out of the identity URL and strips the instance trailing slash ok 1 - reads the org id out of the identity URL and strips the instance trailing slash --- duration_ms: 0.25825 type: 'test' ... # Subtest: returns a null org id when the identity URL is absent ok 2 - returns a null org id when the identity URL is absent --- duration_ms: 0.163708 type: 'test' ... 1..2 ok 8 - salesforce oauth --- duration_ms: 0.467625 type: 'suite' ... # Subtest: providerFetch # Subtest: returns an empty object for an empty 200 body ok 1 - returns an empty object for an empty 200 body --- duration_ms: 2.721959 type: 'test' ... # Subtest: reports a non-JSON body as an error rather than throwing a SyntaxError ok 2 - reports a non-JSON body as an error rather than throwing a SyntaxError --- duration_ms: 0.23875 type: 'test' ... # Subtest: collapses and truncates a long provider error ok 3 - collapses and truncates a long provider error --- duration_ms: 0.223417 type: 'test' ... # Subtest: reports a transport failure as status 0 ok 4 - reports a transport failure as status 0 --- duration_ms: 0.162584 type: 'test' ... # Subtest: treats 401 and only 401 as a reason to reconnect ok 5 - treats 401 and only 401 as a reason to reconnect --- duration_ms: 0.109666 type: 'test' ... # Subtest: sends JSON when given json and form encoding when given form ok 6 - sends JSON when given json and form encoding when given form --- duration_ms: 0.28125 type: 'test' ... # Subtest: names itself in the user agent on every call ok 7 - names itself in the user agent on every call --- duration_ms: 0.381833 type: 'test' ... 1..7 ok 9 - providerFetch --- duration_ms: 4.297583 type: 'suite' ... # Subtest: fetch trap # Subtest: throws on an unregistered host instead of reaching the network ok 1 - throws on an unregistered host instead of reaching the network --- duration_ms: 0.1275 type: 'test' ... # Subtest: lets a request through to the harness on loopback, and does not record it ok 2 - lets a request through to the harness on loopback, and does not record it --- duration_ms: 27.026875 type: 'test' ... # Subtest: exhausts a route with a call budget rather than answering forever ok 3 - exhausts a route with a call budget rather than answering forever --- duration_ms: 0.413834 type: 'test' ... 1..3 ok 10 - fetch trap --- duration_ms: 27.656459 type: 'suite' ... # (node:32) ExperimentalWarning: Module mocking is an experimental feature and might change at any time # (Use `node --trace-warnings ...` to show where the warning was created) # Subtest: infrastructure # Subtest: reports healthy when the database answers ok 1 - reports healthy when the database answers --- duration_ms: 4.024541 type: 'test' ... # Subtest: says which build answered, on both arms ok 2 - says which build answered, on both arms --- duration_ms: 3.245916 type: 'test' ... # Subtest: reports degraded with 503 when the database does not ok 3 - reports degraded with 503 when the database does not --- duration_ms: 1.471584 type: 'test' ... # Subtest: publishes the route table this process serves ok 4 - publishes the route table this process serves --- duration_ms: 8.0895 type: 'test' ... # Subtest: does not list a path the app has never served, though probing cannot tell ok 5 - does not list a path the app has never served, though probing cannot tell --- duration_ms: 4.049334 type: 'test' ... # Subtest: derives connector readiness from the adapters rather than restating it ok 6 - derives connector readiness from the adapters rather than restating it --- duration_ms: 1.534792 type: 'test' ... # Subtest: says which connectors are ready without naming a secret or requiring a token ok 7 - says which connectors are ready without naming a secret or requiring a token --- duration_ms: 1.251084 type: 'test' ... # Subtest: answers an unknown route with a 404 in the standard error shape ok 8 - answers an unknown route with a 404 in the standard error shape --- duration_ms: 1.306708 type: 'test' ... # Subtest: sets helmet's headers and hides the framework ok 9 - sets helmet's headers and hides the framework --- duration_ms: 1.414208 type: 'test' ... # Subtest: echoes an inbound x-request-id into the error body ok 10 - echoes an inbound x-request-id into the error body --- duration_ms: 1.236417 type: 'test' ... # Subtest: allows a configured origin and refuses an unlisted one ok 11 - allows a configured origin and refuses an unlisted one --- duration_ms: 1.727125 type: 'test' ... # Subtest: answers a preflight from a configured origin ok 12 - answers a preflight from a configured origin --- duration_ms: 2.924875 type: 'test' ... # Subtest: rejects a malformed JSON body with 400 rather than 500 ok 13 - rejects a malformed JSON body with 400 rather than 500 --- duration_ms: 3.413958 type: 'test' ... # Subtest: rejects a body over the 256 KB limit with 413 rather than 500 ok 14 - rejects a body over the 256 KB limit with 413 rather than 500 --- duration_ms: 7.457417 type: 'test' ... 1..14 ok 11 - infrastructure --- duration_ms: 44.286333 type: 'suite' ... # Subtest: POST /api/v1/auth/login # Subtest: issues a token and returns the caller's identity ok 1 - issues a token and returns the caller's identity --- duration_ms: 65.281667 type: 'test' ... # Subtest: normalises the subdomain and email before looking them up ok 2 - normalises the subdomain and email before looking them up --- duration_ms: 48.043916 type: 'test' ... # Subtest: records the login attempt against the user ok 3 - records the login attempt against the user --- duration_ms: 48.104917 type: 'test' ... # Subtest: answers a wrong password, unknown email, unknown workspace and disabled account identically ok 4 - answers a wrong password, unknown email, unknown workspace and disabled account identically --- duration_ms: 220.363875 type: 'test' ... # Subtest: refuses a user whose organization has been suspended ok 5 - refuses a user whose organization has been suspended --- duration_ms: 45.009083 type: 'test' ... # Subtest: returns 422 with the offending fields named when the body is malformed ok 6 - returns 422 with the offending fields named when the body is malformed --- duration_ms: 2.253208 type: 'test' ... # Subtest: rejects a subdomain that is not a hostname label ok 7 - rejects a subdomain that is not a hostname label --- duration_ms: 1.568583 type: 'test' ... # Subtest: rate limits repeated attempts against one account ok 8 - rate limits repeated attempts against one account --- duration_ms: 670.188 type: 'test' ... # Subtest: counts a whitespace-padded address against the same bucket ok 9 - counts a whitespace-padded address against the same bucket --- duration_ms: 1.580208 type: 'test' ... 1..9 ok 12 - POST /api/v1/auth/login --- duration_ms: 1102.803168 type: 'suite' ... # Subtest: GET /api/v1/auth/me # Subtest: returns the caller's profile and organization ok 1 - returns the caller's profile and organization --- duration_ms: 4.016833 type: 'test' ... # Subtest: refuses a request with no Authorization header ok 2 - refuses a request with no Authorization header --- duration_ms: 4.510417 type: 'test' ... # Subtest: refuses a header that is not a bearer scheme ok 3 - refuses a header that is not a bearer scheme --- duration_ms: 1.539666 type: 'test' ... # Subtest: refuses a garbage token ok 4 - refuses a garbage token --- duration_ms: 1.155042 type: 'test' ... # Subtest: distinguishes an expired token, because a client can act on that one ok 5 - distinguishes an expired token, because a client can act on that one --- duration_ms: 2.321542 type: 'test' ... # Subtest: refuses a token signed with the wrong key ok 6 - refuses a token signed with the wrong key --- duration_ms: 1.766292 type: 'test' ... # Subtest: refuses a token issued for another audience ok 7 - refuses a token issued for another audience --- duration_ms: 1.478875 type: 'test' ... # Subtest: refuses a token whose organization does not contain its user ok 8 - refuses a token whose organization does not contain its user --- duration_ms: 4.504917 type: 'test' ... # Subtest: refuses a token held by a deactivated user ok 9 - refuses a token held by a deactivated user --- duration_ms: 1.942458 type: 'test' ... # Subtest: refuses every token once the organization is suspended ok 10 - refuses every token once the organization is suspended --- duration_ms: 1.600959 type: 'test' ... # Subtest: takes the role from the database, not from the token ok 11 - takes the role from the database, not from the token --- duration_ms: 2.28625 type: 'test' ... 1..11 ok 13 - GET /api/v1/auth/me --- duration_ms: 27.474708 type: 'suite' ... # Subtest: POST /api/v1/quotes/calculate # Subtest: prices at the floor by default and reports the policy in force ok 1 - prices at the floor by default and reports the policy in force --- duration_ms: 11.660417 type: 'test' ... # Subtest: never returns a realised margin below the floor ok 2 - never returns a realised margin below the floor --- duration_ms: 5.736 type: 'test' ... # Subtest: returns the cut list for a 96 × 120 opening, per unit ok 3 - returns the cut list for a 96 × 120 opening, per unit --- duration_ms: 2.545584 type: 'test' ... # Subtest: keeps the cut list per unit when the quantity rises ok 4 - keeps the cut list per unit when the quantity rises --- duration_ms: 4.079042 type: 'test' ... # Subtest: keeps the cut area and the purchased area distinct ok 5 - keeps the cut area and the purchased area distinct --- duration_ms: 8.804584 type: 'test' ... # Subtest: accepts a margin above the floor without ceremony ok 6 - accepts a margin above the floor without ceremony --- duration_ms: 10.296333 type: 'test' ... # Subtest: refuses a margin below the floor ok 7 - refuses a margin below the floor --- duration_ms: 14.558125 type: 'test' ... # Subtest: refuses a margin above the ceiling ok 8 - refuses a margin above the ceiling --- duration_ms: 7.374666 type: 'test' ... # Subtest: refuses an override from a non-administrator even at a legal margin ok 9 - refuses an override from a non-administrator even at a legal margin --- duration_ms: 4.691084 type: 'test' ... # Subtest: honours an administrator's override and marks the quote ok 10 - honours an administrator's override and marks the quote --- duration_ms: 3.371042 type: 'test' ... # Subtest: requires a written reason on an override ok 11 - requires a written reason on an override --- duration_ms: 11.851667 type: 'test' ... # Subtest: records the override on the persisted quote's snapshot ok 12 - records the override on the persisted quote's snapshot --- duration_ms: 6.709166 type: 'test' ... # Subtest: leaves the override null on an ordinary quote ok 13 - leaves the override null on an ordinary quote --- duration_ms: 2.564417 type: 'test' ... # Subtest: persists a quote with a per-tenant sequential number ok 14 - persists a quote with a per-tenant sequential number --- duration_ms: 11.588542 type: 'test' ... # Subtest: refuses a SKU code the tenant does not carry ok 15 - refuses a SKU code the tenant does not carry --- duration_ms: 3.069041 type: 'test' ... # Subtest: reports another tenant's SKU code as missing ok 16 - reports another tenant's SKU code as missing --- duration_ms: 3.596959 type: 'test' ... # Subtest: refuses a withdrawn labour tier ok 17 - refuses a withdrawn labour tier --- duration_ms: 2.019458 type: 'test' ... # Subtest: refuses a SKU used in the wrong component slot ok 18 - refuses a SKU used in the wrong component slot --- duration_ms: 1.800542 type: 'test' ... # Subtest: refuses dimensions outside what can be manufactured ok 19 - refuses dimensions outside what can be manufactured --- duration_ms: 1.63375 type: 'test' ... # Subtest: refuses an empty line-item array at the schema ok 20 - refuses an empty line-item array at the schema --- duration_ms: 1.347 type: 'test' ... # Subtest: refuses a technician, whose device must not carry cost or margin ok 21 - refuses a technician, whose device must not carry cost or margin --- duration_ms: 2.352166 type: 'test' ... # Subtest: strips unknown keys rather than storing them ok 22 - strips unknown keys rather than storing them --- duration_ms: 2.112959 type: 'test' ... 1..22 ok 14 - POST /api/v1/quotes/calculate --- duration_ms: 125.022292 type: 'suite' ... # Subtest: GET /api/v1/quotes # Subtest: lists the tenant's own quotes, newest first ok 1 - lists the tenant's own quotes, newest first --- duration_ms: 6.408875 type: 'test' ... # Subtest: does not show one tenant's quotes to another ok 2 - does not show one tenant's quotes to another --- duration_ms: 2.74275 type: 'test' ... # Subtest: filters by status ok 3 - filters by status --- duration_ms: 6.837791 type: 'test' ... # Subtest: returns a cursor when the page is full and paginates past it ok 4 - returns a cursor when the page is full and paginates past it --- duration_ms: 4.848209 type: 'test' ... # Subtest: returns 422, not 500, for an out-of-range limit ok 5 - returns 422, not 500, for an out-of-range limit --- duration_ms: 3.1525 type: 'test' ... # Subtest: returns 422, not 500, for an unknown status filter ok 6 - returns 422, not 500, for an unknown status filter --- duration_ms: 1.627041 type: 'test' ... # Subtest: refuses a technician ok 7 - refuses a technician --- duration_ms: 1.258 type: 'test' ... 1..7 ok 15 - GET /api/v1/quotes --- duration_ms: 27.163042 type: 'suite' ... # Subtest: POST /api/v1/quotes/:id/approve # Subtest: approves a draft and stamps the time ok 1 - approves a draft and stamps the time --- duration_ms: 5.890583 type: 'test' ... # Subtest: refuses a second approval rather than firing the webhook twice ok 2 - refuses a second approval rather than firing the webhook twice --- duration_ms: 5.306417 type: 'test' ... # Subtest: refuses to approve an expired quote ok 3 - refuses to approve an expired quote --- duration_ms: 7.535958 type: 'test' ... # Subtest: answers 404 for an id that does not exist ok 4 - answers 404 for an id that does not exist --- duration_ms: 2.215042 type: 'test' ... # Subtest: answers 404, not 403, for another tenant's quote ok 5 - answers 404, not 403, for another tenant's quote --- duration_ms: 2.444084 type: 'test' ... # Subtest: returns 422, not 500, when the id is not a uuid ok 6 - returns 422, not 500, when the id is not a uuid --- duration_ms: 0.984291 type: 'test' ... # Subtest: records a delivery and refuses a webhook destination on the loopback range ok 7 - records a delivery and refuses a webhook destination on the loopback range --- duration_ms: 31.250833 type: 'test' ... 1..7 ok 16 - POST /api/v1/quotes/:id/approve --- duration_ms: 55.909125 type: 'suite' ... # Subtest: POST /api/v1/quotes/:id/checkout-session # Subtest: answers 503 naming the variable when card payment is not configured ok 1 - answers 503 naming the variable when card payment is not configured --- duration_ms: 5.396458 type: 'test' ... # Subtest: refuses a technician before it considers anything else ok 2 - refuses a technician before it considers anything else --- duration_ms: 3.72875 type: 'test' ... # Subtest: returns 422, not 500, when the id is not a uuid ok 3 - returns 422, not 500, when the id is not a uuid --- duration_ms: 1.156958 type: 'test' ... # Subtest: rejects a return_url that is not a URL at all ok 4 - rejects a return_url that is not a URL at all --- duration_ms: 3.324459 type: 'test' ... # Subtest: rejects a return_url longer than the documented limit ok 5 - rejects a return_url longer than the documented limit --- duration_ms: 3.111334 type: 'test' ... # Subtest: is reachable at the documented path rather than 404 from the router ok 6 - is reachable at the documented path rather than 404 from the router --- duration_ms: 4.080792 type: 'test' ... 1..6 ok 17 - POST /api/v1/quotes/:id/checkout-session --- duration_ms: 21.002625 type: 'suite' ... # Subtest: POST /api/v1/work-orders # Subtest: creates a pending work order for an administrator ok 1 - creates a pending work order for an administrator --- duration_ms: 1.828334 type: 'test' ... # Subtest: refuses a salesperson — quoting work is not dispatching it ok 2 - refuses a salesperson — quoting work is not dispatching it --- duration_ms: 1.514875 type: 'test' ... # Subtest: refuses assignment to a user who is not a technician ok 3 - refuses assignment to a user who is not a technician --- duration_ms: 1.242125 type: 'test' ... # Subtest: refuses assignment to a deactivated account ok 4 - refuses assignment to a deactivated account --- duration_ms: 1.714333 type: 'test' ... # Subtest: reports another tenant's technician as missing ok 5 - reports another tenant's technician as missing --- duration_ms: 1.254208 type: 'test' ... # Subtest: reports another tenant's quote as missing ok 6 - reports another tenant's quote as missing --- duration_ms: 2.385833 type: 'test' ... # Subtest: refuses a scheduled date that is not YYYY-MM-DD ok 7 - refuses a scheduled date that is not YYYY-MM-DD --- duration_ms: 1.366959 type: 'test' ... 1..7 ok 18 - POST /api/v1/work-orders --- duration_ms: 11.491666 type: 'suite' ... # Subtest: GET /api/v1/work-orders # Subtest: shows an administrator the whole schedule ok 1 - shows an administrator the whole schedule --- duration_ms: 3.188541 type: 'test' ... # Subtest: shows a technician only their own jobs ok 2 - shows a technician only their own jobs --- duration_ms: 3.97825 type: 'test' ... # Subtest: carries no commercial figures, since a technician can read it ok 3 - carries no commercial figures, since a technician can read it --- duration_ms: 1.85975 type: 'test' ... # Subtest: filters by scheduled date ok 4 - filters by scheduled date --- duration_ms: 5.786291 type: 'test' ... # Subtest: does not show one tenant's work orders to another ok 5 - does not show one tenant's work orders to another --- duration_ms: 2.076083 type: 'test' ... # Subtest: returns 422, not 500, for a malformed date filter ok 6 - returns 422, not 500, for a malformed date filter --- duration_ms: 0.957125 type: 'test' ... 1..6 ok 19 - GET /api/v1/work-orders --- duration_ms: 18.026 type: 'suite' ... # Subtest: PATCH /api/v1/work-orders/:id/status # Subtest: walks a job from pending to dispatched to completed ok 1 - walks a job from pending to dispatched to completed --- duration_ms: 4.639416 type: 'test' ... # Subtest: is idempotent when the status is already the requested one ok 2 - is idempotent when the status is already the requested one --- duration_ms: 2.877875 type: 'test' ... # Subtest: refuses a transition the state machine does not allow ok 3 - refuses a transition the state machine does not allow --- duration_ms: 1.813416 type: 'test' ... # Subtest: treats a completed job as final ok 4 - treats a completed job as final --- duration_ms: 3.484125 type: 'test' ... # Subtest: refuses to dispatch a job with nobody assigned to it ok 5 - refuses to dispatch a job with nobody assigned to it --- duration_ms: 1.927833 type: 'test' ... # Subtest: refuses a technician who is not the one assigned ok 6 - refuses a technician who is not the one assigned --- duration_ms: 2.011208 type: 'test' ... # Subtest: refuses a salesperson — quoting a job does not confer the right to close it ok 7 - refuses a salesperson — quoting a job does not confer the right to close it --- duration_ms: 1.72825 type: 'test' ... # Subtest: answers 404, not 403, for another tenant's work order ok 8 - answers 404, not 403, for another tenant's work order --- duration_ms: 1.773583 type: 'test' ... # Subtest: refuses a status the enum does not contain ok 9 - refuses a status the enum does not contain --- duration_ms: 2.132 type: 'test' ... # Subtest: returns 422, not 500, when the id is not a uuid ok 10 - returns 422, not 500, when the id is not a uuid --- duration_ms: 1.067417 type: 'test' ... # Subtest: ignores a client-supplied completion timestamp ok 11 - ignores a client-supplied completion timestamp --- duration_ms: 2.391959 type: 'test' ... 1..11 ok 20 - PATCH /api/v1/work-orders/:id/status --- duration_ms: 26.099792 type: 'suite' ... # Subtest: documented response shapes # Subtest: GET /api/health, both branches of the union ok 1 - GET /api/health, both branches of the union --- duration_ms: 1.902709 type: 'test' ... # Subtest: GET /api/routes ok 2 - GET /api/routes --- duration_ms: 0.903125 type: 'test' ... # Subtest: GET /api/connectors ok 3 - GET /api/connectors --- duration_ms: 0.728334 type: 'test' ... # Subtest: POST /api/v1/auth/login ok 4 - POST /api/v1/auth/login --- duration_ms: 50.906125 type: 'test' ... # Subtest: GET /api/v1/auth/me ok 5 - GET /api/v1/auth/me --- duration_ms: 1.149167 type: 'test' ... # Subtest: POST /api/v1/quotes/calculate, transient and persisted ok 6 - POST /api/v1/quotes/calculate, transient and persisted --- duration_ms: 3.405209 type: 'test' ... # Subtest: POST /api/v1/quotes/calculate covers every component slot ok 7 - POST /api/v1/quotes/calculate covers every component slot --- duration_ms: 1.416458 type: 'test' ... # Subtest: GET /api/v1/quotes, populated and empty ok 8 - GET /api/v1/quotes, populated and empty --- duration_ms: 7.910958 type: 'test' ... # Subtest: POST /api/v1/quotes/:id/approve ok 9 - POST /api/v1/quotes/:id/approve --- duration_ms: 2.6685 type: 'test' ... # Subtest: POST /api/v1/work-orders, assigned and unassigned ok 10 - POST /api/v1/work-orders, assigned and unassigned --- duration_ms: 2.368375 type: 'test' ... # Subtest: GET /api/v1/work-orders ok 11 - GET /api/v1/work-orders --- duration_ms: 4.597458 type: 'test' ... # Subtest: PATCH /api/v1/work-orders/:id/status, transition and replay ok 12 - PATCH /api/v1/work-orders/:id/status, transition and replay --- duration_ms: 2.598166 type: 'test' ... # Subtest: the error envelope, across all three of its shapes ok 13 - the error envelope, across all three of its shapes --- duration_ms: 2.036959 type: 'test' ... 1..13 ok 21 - documented response shapes --- duration_ms: 82.917334 type: 'suite' ... # Subtest: fabric consumption includes the 15% waste factor ok 22 - fabric consumption includes the 15% waste factor --- duration_ms: 1.572 type: 'test' ... # Subtest: labour is base hours plus area, and the tier multiplier scales the rate ok 23 - labour is base hours plus area, and the tier multiplier scales the rate --- duration_ms: 0.301667 type: 'test' ... # Subtest: motorisation adds hardware cost and half an hour of commissioning ok 24 - motorisation adds hardware cost and half an hour of commissioning --- duration_ms: 0.333541 type: 'test' ... # Subtest: margin is on the sell price, not a markup on cost ok 25 - margin is on the sell price, not a markup on cost --- duration_ms: 0.240792 type: 'test' ... # Subtest: line totals sum to the quote total exactly ok 26 - line totals sum to the quote total exactly --- duration_ms: 0.390333 type: 'test' ... # Subtest: a SKU used in the wrong slot is refused ok 27 - a SKU used in the wrong slot is refused --- duration_ms: 1.397291 type: 'test' ... # Subtest: implausible dimensions are refused rather than quoted ok 28 - implausible dimensions are refused rather than quoted --- duration_ms: 0.114708 type: 'test' ... # Subtest: a margin at or above the ceiling is refused before it divides by zero ok 29 - a margin at or above the ceiling is refused before it divides by zero --- duration_ms: 0.085584 type: 'test' ... # Subtest: the default margin is the floor, not something lower ok 30 - the default margin is the floor, not something lower --- duration_ms: 0.249583 type: 'test' ... # Subtest: a margin below the floor is refused without an approved override ok 31 - a margin below the floor is refused without an approved override --- duration_ms: 0.104667 type: 'test' ... # Subtest: an approved override prices below the floor and says so ok 32 - an approved override prices below the floor and says so --- duration_ms: 0.150333 type: 'test' ... # Subtest: a margin above the floor needs no permission ok 33 - a margin above the floor needs no permission --- duration_ms: 0.154417 type: 'test' ... # Subtest: rounding never lands the realised margin below the floor ok 34 - rounding never lands the realised margin below the floor --- duration_ms: 21.630875 type: 'test' ... # Subtest: quantity multiplies before rounding, not after ok 35 - quantity multiplies before rounding, not after --- duration_ms: 0.165125 type: 'test' ... # Subtest: the cut list matches the browser engine's locked reference derivation ok 36 - the cut list matches the browser engine's locked reference derivation --- duration_ms: 0.070125 type: 'test' ... # Subtest: every priced line carries its cut list ok 37 - every priced line carries its cut list --- duration_ms: 0.532542 type: 'test' ... # Subtest: the cut list is per unit and does not scale with quantity ok 38 - the cut list is per unit and does not scale with quantity --- duration_ms: 0.202917 type: 'test' ... # Subtest: cut area and purchased area are different figures and stay different ok 39 - cut area and purchased area are different figures and stay different --- duration_ms: 0.0935 type: 'test' ... # Subtest: cut sizes stay exact on quarter-inch and awkward decimal openings ok 40 - cut sizes stay exact on quarter-inch and awkward decimal openings --- duration_ms: 0.081791 type: 'test' ... # Subtest: cut sizes match the browser engine on every fixture case ok 41 - cut sizes match the browser engine on every fixture case --- duration_ms: 1.612584 type: 'test' ... # Subtest: the engine refuses the openings the fixture envelope excludes ok 42 - the engine refuses the openings the fixture envelope excludes --- duration_ms: 0.462417 type: 'test' ... # Subtest: notFoundHandler # Subtest: names the method and path that matched nothing ok 1 - names the method and path that matched nothing --- duration_ms: 0.566041 type: 'test' ... # Subtest: returns a null request id rather than omitting the key ok 2 - returns a null request id rather than omitting the key --- duration_ms: 0.101042 type: 'test' ... 1..2 ok 43 - notFoundHandler --- duration_ms: 1.387709 type: 'suite' ... # Subtest: errorHandler — ApiError # Subtest: carries each code to its documented status ok 1 - carries each code to its documented status --- duration_ms: 0.416208 type: 'test' ... # Subtest: carries field details through untouched ok 2 - carries field details through untouched --- duration_ms: 0.760792 type: 'test' ... # Subtest: sets details to null rather than omitting them when there are none ok 3 - sets details to null rather than omitting them when there are none --- duration_ms: 0.090292 type: 'test' ... 1..3 ok 44 - errorHandler — ApiError --- duration_ms: 1.467667 type: 'suite' ... # Subtest: errorHandler — ZodError net # Subtest: answers 422 with the field names, not 500 ok 1 - answers 422 with the field names, not 500 --- duration_ms: 0.765583 type: 'test' ... # Subtest: keys a nested path with dots so a form can find the input ok 2 - keys a nested path with dots so a form can find the input --- duration_ms: 0.4305 type: 'test' ... # Subtest: keys a root-level failure as _ rather than as the empty string ok 3 - keys a root-level failure as _ rather than as the empty string --- duration_ms: 0.225333 type: 'test' ... # Subtest: keeps the first message when one field fails twice ok 4 - keeps the first message when one field fails twice --- duration_ms: 0.088 type: 'test' ... 1..4 ok 45 - errorHandler — ZodError net --- duration_ms: 1.681208 type: 'suite' ... # Subtest: errorHandler — Prisma codes # Subtest: translates a unique violation to 409 without naming the column ok 1 - translates a unique violation to 409 without naming the column --- duration_ms: 0.291375 type: 'test' ... # Subtest: translates a foreign key violation to 409 ok 2 - translates a foreign key violation to 409 --- duration_ms: 0.110292 type: 'test' ... # Subtest: translates a missing record to 404 ok 3 - translates a missing record to 404 --- duration_ms: 0.113375 type: 'test' ... # Subtest: sends an untranslated Prisma code to the 500 branch rather than guessing ok 4 - sends an untranslated Prisma code to the 500 branch rather than guessing --- duration_ms: 0.148541 type: 'test' ... # Subtest: never puts raw database text on the wire ok 5 - never puts raw database text on the wire --- duration_ms: 0.116625 type: 'test' ... 1..5 ok 46 - errorHandler — Prisma codes --- duration_ms: 0.944166 type: 'suite' ... # Subtest: errorHandler — body-parser failures # Subtest: answers 400 for entity.parse.failed ok 1 - answers 400 for entity.parse.failed --- duration_ms: 0.219083 type: 'test' ... # Subtest: answers 413 for entity.too.large ok 2 - answers 413 for entity.too.large --- duration_ms: 0.061083 type: 'test' ... # Subtest: answers 415 for encoding.unsupported ok 3 - answers 415 for encoding.unsupported --- duration_ms: 0.1625 type: 'test' ... # Subtest: answers 415 for charset.unsupported ok 4 - answers 415 for charset.unsupported --- duration_ms: 0.092792 type: 'test' ... # Subtest: answers 400 for request.aborted ok 5 - answers 400 for request.aborted --- duration_ms: 0.055 type: 'test' ... # Subtest: uses the fixed message, not the parser's, so no body fragment is reflected ok 6 - uses the fixed message, not the parser's, so no body fragment is reflected --- duration_ms: 0.071208 type: 'test' ... # Subtest: sends an application error with a stray status to the 500 branch ok 7 - sends an application error with a stray status to the 500 branch --- duration_ms: 0.092291 type: 'test' ... # Subtest: ignores a non-string type ok 8 - ignores a non-string type --- duration_ms: 0.072333 type: 'test' ... # Subtest: does not treat a bare string or null as a body-parser failure ok 9 - does not treat a bare string or null as a body-parser failure --- duration_ms: 0.168833 type: 'test' ... 1..9 ok 47 - errorHandler — body-parser failures --- duration_ms: 1.18525 type: 'suite' ... # Subtest: errorHandler — provider refusals # Subtest: answers 502, not 500, so an upstream refusal stops reading as our defect ok 1 - answers 502, not 500, so an upstream refusal stops reading as our defect --- duration_ms: 0.389166 type: 'test' ... # Subtest: names the parameter the provider rejected ok 2 - names the parameter the provider rejected --- duration_ms: 0.093833 type: 'test' ... # Subtest: never puts the provider's prose on the wire ok 3 - never puts the provider's prose on the wire --- duration_ms: 0.1265 type: 'test' ... # Subtest: carries status 0 through, so unreachable is distinguishable from refused ok 4 - carries status 0 through, so unreachable is distinguishable from refused --- duration_ms: 0.109125 type: 'test' ... # Subtest: finds the code in a QuickBooks fault and a Salesforce array alike ok 5 - finds the code in a QuickBooks fault and a Salesforce array alike --- duration_ms: 0.123167 type: 'test' ... # Subtest: returns no identifiers rather than inventing them when the body is not JSON ok 6 - returns no identifiers rather than inventing them when the body is not JSON --- duration_ms: 0.076417 type: 'test' ... 1..6 ok 48 - errorHandler — provider refusals --- duration_ms: 1.124417 type: 'suite' ... # Subtest: errorHandler — the 500 branch # Subtest: returns the request id and nothing that names the database ok 1 - returns the request id and nothing that names the database --- duration_ms: 0.145083 type: 'test' ... # Subtest: includes a debug string outside production ok 2 - includes a debug string outside production --- duration_ms: 0.096917 type: 'test' ... 1..2 ok 49 - errorHandler — the 500 branch --- duration_ms: 0.344 type: 'suite' ... # (node:80) ExperimentalWarning: Module mocking is an experimental feature and might change at any time # (Use `node --trace-warnings ...` to show where the warning was created) # Subtest: crypto.seal / crypto.open # Subtest: round-trips a token ok 1 - round-trips a token --- duration_ms: 0.805458 type: 'test' ... # Subtest: produces a different envelope every time ok 2 - produces a different envelope every time --- duration_ms: 0.18925 type: 'test' ... # Subtest: emits a versioned four-field envelope ok 3 - emits a versioned four-field envelope --- duration_ms: 0.149459 type: 'test' ... # Subtest: refuses an envelope whose ciphertext has been altered ok 4 - refuses an envelope whose ciphertext has been altered --- duration_ms: 0.235334 type: 'test' ... # Subtest: refuses an envelope whose authentication tag has been altered ok 5 - refuses an envelope whose authentication tag has been altered --- duration_ms: 0.228416 type: 'test' ... # Subtest: refuses a truncated envelope by shape rather than by decryption failure ok 6 - refuses a truncated envelope by shape rather than by decryption failure --- duration_ms: 0.208125 type: 'test' ... # Subtest: refuses an unknown version prefix ok 7 - refuses an unknown version prefix --- duration_ms: 0.137375 type: 'test' ... # Subtest: refuses a malformed nonce and a malformed tag distinctly ok 8 - refuses a malformed nonce and a malformed tag distinctly --- duration_ms: 0.167875 type: 'test' ... 1..8 ok 50 - crypto.seal / crypto.open --- duration_ms: 2.721166 type: 'suite' ... # Subtest: crypto.constantTimeEquals # Subtest: is true only for identical strings ok 1 - is true only for identical strings --- duration_ms: 0.144792 type: 'test' ... # Subtest: returns false rather than throwing on a length mismatch ok 2 - returns false rather than throwing on a length mismatch --- duration_ms: 0.11125 type: 'test' ... 1..2 ok 51 - crypto.constantTimeEquals --- duration_ms: 0.306709 type: 'suite' ... # Subtest: oauth-state # Subtest: round-trips the organization and provider ok 1 - round-trips the organization and provider --- duration_ms: 0.25475 type: 'test' ... # Subtest: accepts a state at the edge of its ten-minute window and rejects it one second later ok 2 - accepts a state at the edge of its ten-minute window and rejects it one second later --- duration_ms: 0.200083 type: 'test' ... # Subtest: rejects a payload that has been edited ok 3 - rejects a payload that has been edited --- duration_ms: 0.159083 type: 'test' ... # Subtest: rejects a missing, empty or separatorless state ok 4 - rejects a missing, empty or separatorless state --- duration_ms: 0.14325 type: 'test' ... # Subtest: builds the redirect URI the provider consoles have to be given ok 5 - builds the redirect URI the provider consoles have to be given --- duration_ms: 0.131375 type: 'test' ... 1..5 ok 52 - oauth-state --- duration_ms: 1.043917 type: 'suite' ... # Subtest: stripe signature verification # Subtest: accepts a correctly signed body ok 1 - accepts a correctly signed body --- duration_ms: 0.322959 type: 'test' ... # Subtest: rejects a body signed with a different secret ok 2 - rejects a body signed with a different secret --- duration_ms: 0.231542 type: 'test' ... # Subtest: rejects a body altered after signing ok 3 - rejects a body altered after signing --- duration_ms: 0.194709 type: 'test' ... # Subtest: accepts either signature while a secret is being rolled ok 4 - accepts either signature while a secret is being rolled --- duration_ms: 0.193709 type: 'test' ... # Subtest: rejects a timestamp outside the tolerance in either direction ok 5 - rejects a timestamp outside the tolerance in either direction --- duration_ms: 0.228583 type: 'test' ... # Subtest: rejects a header with no timestamp, no v1, or no header at all ok 6 - rejects a header with no timestamp, no v1, or no header at all --- duration_ms: 0.175834 type: 'test' ... # Subtest: is sensitive to re-serialisation, which is why the route reads a raw body ok 7 - is sensitive to re-serialisation, which is why the route reads a raw body --- duration_ms: 0.653625 type: 'test' ... 1..7 ok 53 - stripe signature verification --- duration_ms: 2.142417 type: 'suite' ... # Subtest: registry # Subtest: can store credentials, because the suite sets a valid sealing key ok 1 - can store credentials, because the suite sets a valid sealing key --- duration_ms: 0.144958 type: 'test' ... # Subtest: names the environment variable each provider is still missing ok 2 - names the environment variable each provider is still missing --- duration_ms: 0.270625 type: 'test' ... 1..2 ok 54 - registry --- duration_ms: 0.472583 type: 'suite' ... # Subtest: GET /api/v1/integrations # Subtest: requires a token ok 1 - requires a token --- duration_ms: 10.644792 type: 'test' ... # Subtest: is closed to SALES and TECHNICIAN ok 2 - is closed to SALES and TECHNICIAN --- duration_ms: 3.894458 type: 'test' ... # Subtest: returns all three providers with no connection for a fresh tenant ok 3 - returns all three providers with no connection for a fresh tenant --- duration_ms: 1.885125 type: 'test' ... # Subtest: reports a stored connection without ever returning its ciphertext ok 4 - reports a stored connection without ever returning its ciphertext --- duration_ms: 1.900166 type: 'test' ... # Subtest: does not show one tenant's connection to another ok 5 - does not show one tenant's connection to another --- duration_ms: 1.455958 type: 'test' ... 1..5 ok 55 - GET /api/v1/integrations --- duration_ms: 20.0125 type: 'suite' ... # Subtest: POST /api/v1/integrations/:provider/connect # Subtest: refuses Stripe, which has no per-tenant consent to give ok 1 - refuses Stripe, which has no per-tenant consent to give --- duration_ms: 6.461042 type: 'test' ... # Subtest: returns an Intuit consent URL carrying a verifiable state ok 2 - returns an Intuit consent URL carrying a verifiable state --- duration_ms: 1.845125 type: 'test' ... # Subtest: returns a Salesforce consent URL asking for refresh_token ok 3 - returns a Salesforce consent URL asking for refresh_token --- duration_ms: 1.57475 type: 'test' ... # Subtest: mints a state scoped to the calling tenant, not a fixed one ok 4 - mints a state scoped to the calling tenant, not a fixed one --- duration_ms: 1.653792 type: 'test' ... # Subtest: rejects an unknown provider slug as a validation failure ok 5 - rejects an unknown provider slug as a validation failure --- duration_ms: 1.852084 type: 'test' ... # Subtest: is closed to SALES ok 6 - is closed to SALES --- duration_ms: 1.462542 type: 'test' ... 1..6 ok 56 - POST /api/v1/integrations/:provider/connect --- duration_ms: 15.066083 type: 'suite' ... # Subtest: DELETE /api/v1/integrations/:provider # Subtest: forgets the credentials but keeps the row ok 1 - forgets the credentials but keeps the row --- duration_ms: 4.932916 type: 'test' ... # Subtest: refuses to disconnect Stripe per organization ok 2 - refuses to disconnect Stripe per organization --- duration_ms: 1.39575 type: 'test' ... # Subtest: is a no-op rather than a 404 when nothing was connected ok 3 - is a no-op rather than a 404 when nothing was connected --- duration_ms: 1.205541 type: 'test' ... 1..3 ok 57 - DELETE /api/v1/integrations/:provider --- duration_ms: 7.639583 type: 'suite' ... # Subtest: GET /api/v1/integrations/syncs # Subtest: is empty for a tenant that has approved nothing ok 1 - is empty for a tenant that has approved nothing --- duration_ms: 1.321875 type: 'test' ... # Subtest: returns this tenant's rows and filters by provider ok 2 - returns this tenant's rows and filters by provider --- duration_ms: 2.814958 type: 'test' ... # Subtest: honours limit and rejects one outside the range ok 3 - honours limit and rejects one outside the range --- duration_ms: 1.930709 type: 'test' ... # Subtest: is closed to TECHNICIAN ok 4 - is closed to TECHNICIAN --- duration_ms: 0.945916 type: 'test' ... 1..4 ok 58 - GET /api/v1/integrations/syncs --- duration_ms: 7.129875 type: 'suite' ... # Subtest: GET /api/v1/integrations/:provider/callback # Subtest: is reachable without a token, because the provider redirects a browser to it ok 1 - is reachable without a token, because the provider redirects a browser to it --- duration_ms: 1.451417 type: 'test' ... # Subtest: treats a denied consent as a completed flow with a no ok 2 - treats a denied consent as a completed flow with a no --- duration_ms: 1.068542 type: 'test' ... # Subtest: escapes a provider-supplied description rather than rendering it ok 3 - escapes a provider-supplied description rather than rendering it --- duration_ms: 0.942416 type: 'test' ... # Subtest: refuses a callback with no authorization code ok 4 - refuses a callback with no authorization code --- duration_ms: 1.024958 type: 'test' ... # Subtest: refuses a forged state ok 5 - refuses a forged state --- duration_ms: 1.050916 type: 'test' ... # Subtest: refuses an expired state ok 6 - refuses an expired state --- duration_ms: 1.046041 type: 'test' ... # Subtest: refuses a state minted for a different provider ok 7 - refuses a state minted for a different provider --- duration_ms: 0.986083 type: 'test' ... # Subtest: refuses an Intuit callback carrying no realmId before exchanging anything ok 8 - refuses an Intuit callback carrying no realmId before exchanging anything --- duration_ms: 0.977666 type: 'test' ... # Subtest: rejects an unknown provider slug ok 9 - rejects an unknown provider slug --- duration_ms: 0.878375 type: 'test' ... 1..9 ok 59 - GET /api/v1/integrations/:provider/callback --- duration_ms: 9.626625 type: 'suite' ... # Subtest: POST /api/v1/integrations/stripe/webhook # Subtest: is reachable without a token ok 1 - is reachable without a token --- duration_ms: 1.937209 type: 'test' ... # Subtest: rejects a delivery with no signature ok 2 - rejects a delivery with no signature --- duration_ms: 1.101709 type: 'test' ... # Subtest: rejects a delivery signed with the wrong secret ok 3 - rejects a delivery signed with the wrong secret --- duration_ms: 1.09325 type: 'test' ... # Subtest: does not leak why verification failed ok 4 - does not leak why verification failed --- duration_ms: 0.956542 type: 'test' ... # Subtest: answers 400 for a signed body that is not JSON ok 5 - answers 400 for a signed body that is not JSON --- duration_ms: 0.979667 type: 'test' ... # Subtest: acknowledges an event type it has no handler for ok 6 - acknowledges an event type it has no handler for --- duration_ms: 1.652584 type: 'test' ... # Subtest: acknowledges an invoice this platform never created ok 7 - acknowledges an invoice this platform never created --- duration_ms: 1.640334 type: 'test' ... # Subtest: marks the quote paid and records the payment intent ok 8 - marks the quote paid and records the payment intent --- duration_ms: 1.319875 type: 'test' ... # Subtest: does not rewrite the payment date when Stripe replays the delivery ok 9 - does not rewrite the payment date when Stripe replays the delivery --- duration_ms: 9.85675 type: 'test' ... # Subtest: records a failed payment on the sync row without touching the quote ok 10 - records a failed payment on the sync row without touching the quote --- duration_ms: 1.205708 type: 'test' ... # Subtest: resolves the tenant from the invoice id and writes only inside that tenant ok 11 - resolves the tenant from the invoice id and writes only inside that tenant --- duration_ms: 1.031625 type: 'test' ... # Subtest: marks the quote paid from a completed checkout session ok 12 - marks the quote paid from a completed checkout session --- duration_ms: 1.411625 type: 'test' ... # Subtest: does not mark a quote paid when the session completed but the money has not moved ok 13 - does not mark a quote paid when the session completed but the money has not moved --- duration_ms: 1.427792 type: 'test' ... # Subtest: accepts no_payment_required, which is a zero-value session and not a failure ok 14 - accepts no_payment_required, which is a zero-value session and not a failure --- duration_ms: 1.39275 type: 'test' ... # Subtest: records an expired page without touching the quote ok 15 - records an expired page without touching the quote --- duration_ms: 1.524084 type: 'test' ... # Subtest: does not rewrite the payment date when Stripe replays a completed session ok 16 - does not rewrite the payment date when Stripe replays a completed session --- duration_ms: 8.977084 type: 'test' ... # Subtest: keeps the invoice and checkout rows for one quote apart ok 17 - keeps the invoice and checkout rows for one quote apart --- duration_ms: 3.786458 type: 'test' ... # Subtest: acknowledges a checkout session this platform never created ok 18 - acknowledges a checkout session this platform never created --- duration_ms: 1.491 type: 'test' ... 1..18 ok 60 - POST /api/v1/integrations/stripe/webhook --- duration_ms: 43.247292 type: 'suite' ... # Subtest: connection-store # Subtest: seals both tokens before they reach the table ok 1 - seals both tokens before they reach the table --- duration_ms: 0.355833 type: 'test' ... # Subtest: replaces rather than accumulates credentials ok 2 - replaces rather than accumulates credentials --- duration_ms: 0.373083 type: 'test' ... # Subtest: distinguishes never-connected from expired, both asking for a reconnect ok 3 - distinguishes never-connected from expired, both asking for a reconnect --- duration_ms: 0.4175 type: 'test' ... # Subtest: treats an unreadable credential as a platform fault, not a consent problem ok 4 - treats an unreadable credential as a platform fault, not a consent problem --- duration_ms: 0.365167 type: 'test' ... # Subtest: marks an ordinary failure ERROR rather than EXPIRED ok 5 - marks an ordinary failure ERROR rather than EXPIRED --- duration_ms: 0.222792 type: 'test' ... # Subtest: swallows a bookkeeping write against a row that is not there ok 6 - swallows a bookkeeping write against a row that is not there --- duration_ms: 0.19875 type: 'test' ... 1..6 ok 61 - connection-store --- duration_ms: 2.049917 type: 'suite' ... # Subtest: sync-store # Subtest: counts attempts cumulatively across failures and a later success ok 1 - counts attempts cumulatively across failures and a later success --- duration_ms: 0.385125 type: 'test' ... # Subtest: trims a provider error to something a support engineer can read ok 2 - trims a provider error to something a support engineer can read --- duration_ms: 0.122375 type: 'test' ... # Subtest: finds only a succeeded sync ok 3 - finds only a succeeded sync --- duration_ms: 0.235917 type: 'test' ... # Subtest: keeps two tenants' syncs for the same quote id apart ok 4 - keeps two tenants' syncs for the same quote id apart --- duration_ms: 0.14525 type: 'test' ... # Subtest: resolves a tenant from a provider object id, and nothing from an unknown one ok 5 - resolves a tenant from a provider object id, and nothing from an unknown one --- duration_ms: 0.112583 type: 'test' ... # Subtest: merges a related id into detail without dropping what was there ok 6 - merges a related id into detail without dropping what was there --- duration_ms: 0.125083 type: 'test' ... # Subtest: does not throw when a related id cannot be attached ok 7 - does not throw when a related id cannot be attached --- duration_ms: 0.120958 type: 'test' ... 1..7 ok 62 - sync-store --- duration_ms: 1.356375 type: 'suite' ... # Subtest: fan-out # Subtest: skips every provider that is not usable, and records why ok 1 - skips every provider that is not usable, and records why --- duration_ms: 0.730416 type: 'test' ... # Subtest: uses the right entity type per provider ok 2 - uses the right entity type per provider --- duration_ms: 0.608417 type: 'test' ... # Subtest: counts a second run as a second attempt on the same rows ok 3 - counts a second run as a second attempt on the same rows --- duration_ms: 0.587 type: 'test' ... # Subtest: does not re-push a quote a provider has already accepted ok 4 - does not re-push a quote a provider has already accepted --- duration_ms: 0.339667 type: 'test' ... 1..4 ok 63 - fan-out --- duration_ms: 2.34675 type: 'suite' ... # Subtest: route manifest # Subtest: reproduces a nested mount, prefix and all ok 1 - reproduces a nested mount, prefix and all --- duration_ms: 6.602417 type: 'test' ... # Subtest: converts every Express parameter to its OpenAPI spelling ok 2 - converts every Express parameter to its OpenAPI spelling --- duration_ms: 0.173041 type: 'test' ... # Subtest: omits the HEAD and _all entries Express adds on its own ok 3 - omits the HEAD and _all entries Express adds on its own --- duration_ms: 0.345625 type: 'test' ... # Subtest: expands a handler registered under several paths ok 4 - expands a handler registered under several paths --- duration_ms: 0.1575 type: 'test' ... # Subtest: sorts by path then method, so two deploys compare as text ok 5 - sorts by path then method, so two deploys compare as text --- duration_ms: 0.136875 type: 'test' ... # Subtest: handles a router mounted at the root, which carries no prefix ok 6 - handles a router mounted at the root, which carries no prefix --- duration_ms: 0.12025 type: 'test' ... # Subtest: ignores plain middleware, which serves no path ok 7 - ignores plain middleware, which serves no path --- duration_ms: 0.157958 type: 'test' ... # Subtest: refuses to guess at a mount path it cannot decode ok 8 - refuses to guess at a mount path it cannot decode --- duration_ms: 0.286167 type: 'test' ... # Subtest: refuses an application with no router stack rather than reporting nothing ok 9 - refuses an application with no router stack rather than reporting nothing --- duration_ms: 0.128167 type: 'test' ... # Subtest: distinguishes a guarded route from a path that merely resolves to the guard ok 10 - distinguishes a guarded route from a path that merely resolves to the guard --- duration_ms: 0.218959 type: 'test' ... 1..10 ok 64 - route manifest --- duration_ms: 8.912916 type: 'suite' ... # (node:1739) ExperimentalWarning: Module mocking is an experimental feature and might change at any time # (Use `node --trace-warnings ...` to show where the warning was created) # Subtest: assertSafeDestination — scheme # Subtest: refuses http, so a signed payload is never sent in the clear ok 1 - refuses http, so a signed payload is never sent in the clear --- duration_ms: 0.556959 type: 'test' ... # Subtest: refuses non-http schemes outright ok 2 - refuses non-http schemes outright --- duration_ms: 0.122125 type: 'test' ... # Subtest: rejects a malformed URL rather than passing it to fetch ok 3 - rejects a malformed URL rather than passing it to fetch --- duration_ms: 0.079042 type: 'test' ... 1..3 ok 65 - assertSafeDestination — scheme --- duration_ms: 1.247667 type: 'suite' ... # Subtest: assertSafeDestination — IPv4 ranges # Subtest: blocks 0.0.0.0 ok 1 - blocks 0.0.0.0 --- duration_ms: 0.44525 type: 'test' ... # Subtest: blocks 10.0.0.5 ok 2 - blocks 10.0.0.5 --- duration_ms: 0.067959 type: 'test' ... # Subtest: blocks 10.255.255.255 ok 3 - blocks 10.255.255.255 --- duration_ms: 0.04675 type: 'test' ... # Subtest: blocks 127.0.0.1 ok 4 - blocks 127.0.0.1 --- duration_ms: 0.044584 type: 'test' ... # Subtest: blocks 127.1.2.3 ok 5 - blocks 127.1.2.3 --- duration_ms: 0.043416 type: 'test' ... # Subtest: blocks 169.254.169.254 ok 6 - blocks 169.254.169.254 --- duration_ms: 0.053208 type: 'test' ... # Subtest: blocks 192.168.1.1 ok 7 - blocks 192.168.1.1 --- duration_ms: 0.059667 type: 'test' ... # Subtest: blocks 172.16.0.1 ok 8 - blocks 172.16.0.1 --- duration_ms: 0.047167 type: 'test' ... # Subtest: blocks 172.20.10.4 ok 9 - blocks 172.20.10.4 --- duration_ms: 0.042209 type: 'test' ... # Subtest: blocks 172.31.255.254 ok 10 - blocks 172.31.255.254 --- duration_ms: 0.049833 type: 'test' ... # Subtest: does not over-block the public addresses either side of 172.16/12 ok 11 - does not over-block the public addresses either side of 172.16/12 --- duration_ms: 0.046375 type: 'test' ... # Subtest: allows an ordinary public address ok 12 - allows an ordinary public address --- duration_ms: 0.04325 type: 'test' ... # Subtest: does not block 100.x, which is public unicast outside the CGNAT range ok 13 - does not block 100.x, which is public unicast outside the CGNAT range --- duration_ms: 0.035875 type: 'test' ... 1..13 ok 66 - assertSafeDestination — IPv4 ranges --- duration_ms: 1.234667 type: 'suite' ... # Subtest: assertSafeDestination — IPv6 # Subtest: blocks https://[::]/hook ok 1 - blocks https://[::]/hook --- duration_ms: 3.071875 type: 'test' ... # Subtest: blocks https://[::1]/hook ok 2 - blocks https://[::1]/hook --- duration_ms: 0.052375 type: 'test' ... # Subtest: blocks https://[fc00::1]/hook ok 3 - blocks https://[fc00::1]/hook --- duration_ms: 0.043791 type: 'test' ... # Subtest: blocks https://[fd12::1]/hook ok 4 - blocks https://[fd12::1]/hook --- duration_ms: 0.042084 type: 'test' ... # Subtest: blocks https://[fe80::1]/hook ok 5 - blocks https://[fe80::1]/hook --- duration_ms: 0.049458 type: 'test' ... # Subtest: blocks https://[fe93::1]/hook ok 6 - blocks https://[fe93::1]/hook --- duration_ms: 0.052917 type: 'test' ... # Subtest: blocks https://[feba::1]/hook ok 7 - blocks https://[feba::1]/hook --- duration_ms: 0.038875 type: 'test' ... # Subtest: strips the brackets the URL parser leaves on a v6 literal ok 8 - strips the brackets the URL parser leaves on a v6 literal --- duration_ms: 0.135375 type: 'test' ... # Subtest: blocks an IPv4 private address wearing a v6 hat ok 9 - blocks an IPv4 private address wearing a v6 hat --- duration_ms: 0.133292 type: 'test' ... # Subtest: allows a public IPv6 address ok 10 - allows a public IPv6 address --- duration_ms: 0.042792 type: 'test' ... 1..10 ok 67 - assertSafeDestination — IPv6 --- duration_ms: 3.790458 type: 'suite' ... # Subtest: assertSafeDestination — hostnames # Subtest: resolves the hostname rather than trusting it ok 1 - resolves the hostname rather than trusting it --- duration_ms: 7.129958 type: 'test' ... # Subtest: reports the address it resolved, not just that something was blocked ok 2 - reports the address it resolved, not just that something was blocked --- duration_ms: 0.289292 type: 'test' ... 1..2 ok 68 - assertSafeDestination — hostnames --- duration_ms: 7.498958 type: 'suite' ... # Subtest: sign / verifyWebhookSignature # Subtest: is stable for the same inputs and different for different ones ok 1 - is stable for the same inputs and different for different ones --- duration_ms: 0.369 type: 'test' ... # Subtest: accepts a signature this dispatcher would actually send ok 2 - accepts a signature this dispatcher would actually send --- duration_ms: 0.125625 type: 'test' ... # Subtest: tolerates whitespace in the header ok 3 - tolerates whitespace in the header --- duration_ms: 0.048917 type: 'test' ... # Subtest: rejects a tampered body ok 4 - rejects a tampered body --- duration_ms: 0.054417 type: 'test' ... # Subtest: rejects the wrong secret ok 5 - rejects the wrong secret --- duration_ms: 0.043333 type: 'test' ... # Subtest: rejects a valid signature that is older than the tolerance ok 6 - rejects a valid signature that is older than the tolerance --- duration_ms: 0.0505 type: 'test' ... # Subtest: rejects a timestamp from the future beyond the tolerance ok 7 - rejects a timestamp from the future beyond the tolerance --- duration_ms: 0.039416 type: 'test' ... # Subtest: returns false rather than throwing on a malformed header ok 8 - returns false rather than throwing on a malformed header --- duration_ms: 0.05925 type: 'test' ... # Subtest: returns false rather than throwing when the digest length is wrong ok 9 - returns false rather than throwing when the digest length is wrong --- duration_ms: 0.054542 type: 'test' ... 1..9 ok 69 - sign / verifyWebhookSignature --- duration_ms: 0.956333 type: 'suite' ... # Subtest: dispatchWebhook # Subtest: does nothing, quietly, when the tenant has no subscriptions ok 1 - does nothing, quietly, when the tenant has no subscriptions --- duration_ms: 1.091333 type: 'test' ... # Subtest: records a delivery and signs it with the subscription's own secret ok 2 - records a delivery and signs it with the subscription's own secret --- duration_ms: 115.55925 type: 'test' ... # Subtest: does not follow redirects, since a 302 would defeat the destination check ok 3 - does not follow redirects, since a 302 would defeat the destination check --- duration_ms: 110.071959 type: 'test' ... # Subtest: carries the delivery id as an idempotency key the receiver can dedupe on ok 4 - carries the delivery id as an idempotency key the receiver can dedupe on --- duration_ms: 101.574541 type: 'test' ... # Subtest: treats an empty events array as a wildcard, not as a filter matching nothing ok 5 - treats an empty events array as a wildcard, not as a filter matching nothing --- duration_ms: 104.70625 type: 'test' ... # Subtest: respects a subscription that names its events ok 6 - respects a subscription that names its events --- duration_ms: 110.592958 type: 'test' ... # Subtest: skips a deactivated subscription ok 7 - skips a deactivated subscription --- duration_ms: 0.9695 type: 'test' ... # Subtest: delivers to every matching endpoint independently ok 8 - delivers to every matching endpoint independently --- duration_ms: 114.223042 type: 'test' ... # Subtest: does not retry a 4xx, which is a considered rejection rather than an outage ok 9 - does not retry a 4xx, which is a considered rejection rather than an outage --- duration_ms: 109.99375 type: 'test' ... # Subtest: records a 5xx as failed once attempts are exhausted ok 10 - records a 5xx as failed once attempts are exhausted --- duration_ms: 103.148208 type: 'test' ... # Subtest: records a blocked destination without ever calling fetch ok 11 - records a blocked destination without ever calling fetch --- duration_ms: 111.846667 type: 'test' ... # Subtest: records a transport failure as failed rather than throwing at the caller ok 12 - records a transport failure as failed rather than throwing at the caller --- duration_ms: 110.922792 type: 'test' ... # Subtest: truncates a long error so one endpoint cannot fill the table ok 13 - truncates a long error so one endpoint cannot fill the table --- duration_ms: 102.23975 type: 'test' ... # Subtest: returns before delivery finishes, so the caller never waits on a third party ok 14 - returns before delivery finishes, so the caller never waits on a third party --- duration_ms: 111.300208 type: 'test' ... 1..14 ok 70 - dispatchWebhook --- duration_ms: 1310.894084 type: 'suite' ... # Subtest: drainPendingDeliveries # Subtest: returns immediately when nothing is in flight ok 1 - returns immediately when nothing is in flight --- duration_ms: 0.46825 type: 'test' ... # Subtest: gives up at the deadline rather than blocking shutdown forever ok 2 - gives up at the deadline rather than blocking shutdown forever --- duration_ms: 333.329958 type: 'test' ... 1..2 ok 71 - drainPendingDeliveries --- duration_ms: 334.484542 type: 'suite' ... 1..71 # tests 409 # suites 50 # pass 409 # fail 0 # cancelled 0 # skipped 0 # todo 0 # duration_ms 9103.154046 # start of coverage report # ---------------------------------------------------------------------------------------------------------------------------------------------- # file | line % | branch % | funcs % | uncovered lines # ---------------------------------------------------------------------------------------------------------------------------------------------- # src | | | | # app.ts | 99.32 | 92.31 | 85.71 | 38 # config | | | | # env.ts | 94.41 | 57.14 | 60.00 | 41-45 49-51 55 # controllers | | | | # auth.controller.ts | 99.35 | 92.31 | 80.00 | 36 # integrations.controller.ts | 93.79 | 80.21 | 100.00 | 46-48 55-56 85-91 93-106 116-117 157-160 163 # quotes.controller.ts | 93.07 | 76.32 | 89.66 | 108-113 135 137-152 154-162 166-170 177-178 180-197 202-203 218 225-228 324-327 # work-orders.controller.ts | 99.66 | 94.44 | 88.89 | 55 # db | | | | # tenant.ts | 97.44 | 77.78 | 100.00 | 9-11 # integrations | | | | # connection-store.ts | 100.00 | 100.00 | 100.00 | # crypto.ts | 97.75 | 88.00 | 77.78 | 13-14 17-18 # fan-out.ts | 87.83 | 90.00 | 75.00 | 20-33 # http.ts | 100.00 | 97.37 | 100.00 | # oauth-state.ts | 98.15 | 95.24 | 100.00 | 38-39 # quickbooks | | | | # adapter.ts | 96.99 | 86.36 | 100.00 | 161-162 168-170 174-179 # oauth.ts | 100.00 | 71.43 | 100.00 | # registry.ts | 90.11 | 90.00 | 75.00 | 11 28-35 # salesforce | | | | # adapter.ts | 98.86 | 85.71 | 100.00 | 104 112 132 # oauth.ts | 100.00 | 63.16 | 100.00 | # stripe | | | | # adapter.ts | 99.71 | 92.50 | 100.00 | 78 # checkout.ts | 99.72 | 83.78 | 94.74 | 21 # invoice.ts | 100.00 | 91.67 | 100.00 | # signature.ts | 100.00 | 89.66 | 100.00 | # sync-store.ts | 100.00 | 100.00 | 100.00 | # tax.ts | 96.25 | 60.00 | 66.67 | 8 12-13 # types.ts | 100.00 | 100.00 | 100.00 | # lib | | | | # build-info.ts | 100.00 | 75.00 | 100.00 | # errors.ts | 100.00 | 100.00 | 100.00 | # jwt.ts | 97.17 | 87.50 | 100.00 | 31-33 # logger.ts | 100.00 | 50.00 | 100.00 | # password.ts | 100.00 | 83.33 | 100.00 | # middlewares | | | | # error-handler.ts | 100.00 | 93.10 | 100.00 | # require-auth.ts | 97.96 | 94.12 | 100.00 | 29-30 # require-role.ts | 100.00 | 100.00 | 100.00 | # validate.ts | 100.00 | 100.00 | 100.00 | # models | | | | # sku.repository.ts | 93.81 | 90.91 | 83.33 | 23-28 # routes | | | | # auth.routes.ts | 100.00 | 80.00 | 100.00 | # index.ts | 98.92 | 92.31 | 87.50 | 36 53 # integrations.routes.ts | 100.00 | 100.00 | 100.00 | # manifest.ts | 100.00 | 96.97 | 100.00 | # quotes.routes.ts | 100.00 | 100.00 | 100.00 | # work-orders.routes.ts | 100.00 | 100.00 | 100.00 | # schemas | | | | # auth.schema.ts | 100.00 | 100.00 | 100.00 | # common.schema.ts | 100.00 | 100.00 | 100.00 | # integrations.schema.ts | 100.00 | 100.00 | 100.00 | # quotes.schema.ts | 100.00 | 100.00 | 100.00 | # work-orders.schema.ts | 100.00 | 100.00 | 100.00 | # services | | | | # cpq-engine.ts | 99.27 | 93.18 | 100.00 | 44-47 # money.ts | 97.73 | 87.50 | 85.71 | 11-12 # webhook-dispatcher.ts | 98.63 | 89.41 | 95.65 | 29-31 98-101 # ---------------------------------------------------------------------------------------------------------------------------------------------- # all files | 97.96 | 87.87 | 94.40 | # ---------------------------------------------------------------------------------------------------------------------------------------------- # end of coverage report