@volter/twin-stripe 0.1.2 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -27
- package/client/dashboard-api.ts +286 -0
- package/client/stripe-mirror.css +272 -159
- package/client/stripe-mirror.tsx +1384 -541
- package/dist/client/dashboard-api.d.ts +107 -0
- package/dist/client/dashboard-api.js +238 -0
- package/dist/client/dashboard-api.ts +286 -0
- package/dist/client/stripe-mirror.bundle.js +236 -0
- package/dist/client/stripe-mirror.css +275 -0
- package/dist/client/stripe-mirror.d.ts +134 -0
- package/dist/client/stripe-mirror.js +823 -0
- package/dist/client/stripe-mirror.tsx +1534 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +39 -0
- package/dist/src/generated/events.gen.json +1 -0
- package/dist/src/generated/surface.gen.json +1 -0
- package/dist/src/generated/ui.gen.json +1 -0
- package/dist/src/index.d.ts +14 -0
- package/dist/src/index.js +75 -0
- package/dist/src/manifest.d.ts +2 -0
- package/dist/src/manifest.js +1070 -0
- package/dist/src/screens/checkout.d.ts +31 -0
- package/dist/src/screens/checkout.js +255 -0
- package/dist/src/screens/connect-oauth.d.ts +27 -0
- package/dist/src/screens/connect-oauth.js +414 -0
- package/dist/src/screens/connect-settings.d.ts +22 -0
- package/dist/src/screens/connect-settings.js +103 -0
- package/dist/src/screens/consent-skin.d.ts +4 -0
- package/dist/src/screens/consent-skin.js +18 -0
- package/dist/src/screens/financial-connections.d.ts +5 -0
- package/dist/src/screens/financial-connections.js +90 -0
- package/dist/src/screens/identity.d.ts +5 -0
- package/dist/src/screens/identity.js +86 -0
- package/dist/src/screens/industries.d.ts +1 -0
- package/dist/src/screens/industries.js +267 -0
- package/dist/src/screens/onboarding.d.ts +13 -0
- package/dist/src/screens/onboarding.js +225 -0
- package/dist/src/screens/portal.d.ts +5 -0
- package/dist/src/screens/portal.js +216 -0
- package/dist/src/screens/public-details.d.ts +5 -0
- package/dist/src/screens/public-details.js +90 -0
- package/dist/src/semantics/after-payment.d.ts +22 -0
- package/dist/src/semantics/after-payment.js +99 -0
- package/dist/src/semantics/apps-secrets.d.ts +2 -0
- package/dist/src/semantics/apps-secrets.js +54 -0
- package/dist/src/semantics/balance.d.ts +11 -0
- package/dist/src/semantics/balance.js +195 -0
- package/dist/src/semantics/billing.d.ts +2 -0
- package/dist/src/semantics/billing.js +220 -0
- package/dist/src/semantics/charges.d.ts +28 -0
- package/dist/src/semantics/charges.js +209 -0
- package/dist/src/semantics/checkout.d.ts +15 -0
- package/dist/src/semantics/checkout.js +316 -0
- package/dist/src/semantics/connect.d.ts +5 -0
- package/dist/src/semantics/connect.js +493 -0
- package/dist/src/semantics/coupons.d.ts +6 -0
- package/dist/src/semantics/coupons.js +92 -0
- package/dist/src/semantics/credit-notes.d.ts +2 -0
- package/dist/src/semantics/credit-notes.js +172 -0
- package/dist/src/semantics/customers.d.ts +6 -0
- package/dist/src/semantics/customers.js +429 -0
- package/dist/src/semantics/disputes.d.ts +2 -0
- package/dist/src/semantics/disputes.js +51 -0
- package/dist/src/semantics/entitlements.d.ts +2 -0
- package/dist/src/semantics/entitlements.js +95 -0
- package/dist/src/semantics/ephemeral-keys.d.ts +2 -0
- package/dist/src/semantics/ephemeral-keys.js +34 -0
- package/dist/src/semantics/files.d.ts +2 -0
- package/dist/src/semantics/files.js +125 -0
- package/dist/src/semantics/invoices.d.ts +18 -0
- package/dist/src/semantics/invoices.js +545 -0
- package/dist/src/semantics/issuing.d.ts +13 -0
- package/dist/src/semantics/issuing.js +575 -0
- package/dist/src/semantics/ledger.d.ts +59 -0
- package/dist/src/semantics/ledger.js +200 -0
- package/dist/src/semantics/payment-intents.d.ts +18 -0
- package/dist/src/semantics/payment-intents.js +404 -0
- package/dist/src/semantics/payment-links.d.ts +2 -0
- package/dist/src/semantics/payment-links.js +133 -0
- package/dist/src/semantics/payment-methods.d.ts +20 -0
- package/dist/src/semantics/payment-methods.js +140 -0
- package/dist/src/semantics/plans.d.ts +5 -0
- package/dist/src/semantics/plans.js +121 -0
- package/dist/src/semantics/platform.d.ts +9 -0
- package/dist/src/semantics/platform.js +206 -0
- package/dist/src/semantics/products.d.ts +2 -0
- package/dist/src/semantics/products.js +140 -0
- package/dist/src/semantics/radar.d.ts +2 -0
- package/dist/src/semantics/radar.js +83 -0
- package/dist/src/semantics/refunds.d.ts +9 -0
- package/dist/src/semantics/refunds.js +195 -0
- package/dist/src/semantics/renewals.d.ts +47 -0
- package/dist/src/semantics/renewals.js +251 -0
- package/dist/src/semantics/setup-intents.d.ts +2 -0
- package/dist/src/semantics/setup-intents.js +84 -0
- package/dist/src/semantics/shared.d.ts +82 -0
- package/dist/src/semantics/shared.js +203 -0
- package/dist/src/semantics/subscription-schedules.d.ts +2 -0
- package/dist/src/semantics/subscription-schedules.js +119 -0
- package/dist/src/semantics/subscriptions.d.ts +11 -0
- package/dist/src/semantics/subscriptions.js +605 -0
- package/dist/src/semantics/tax.d.ts +2 -0
- package/dist/src/semantics/tax.js +197 -0
- package/dist/src/semantics/terminal.d.ts +5 -0
- package/dist/src/semantics/terminal.js +182 -0
- package/dist/src/semantics/test-cards.d.ts +4 -0
- package/dist/src/semantics/test-cards.js +7 -0
- package/dist/src/semantics/test-clocks.d.ts +6 -0
- package/dist/src/semantics/test-clocks.js +73 -0
- package/dist/src/semantics/tokens.d.ts +4 -0
- package/dist/src/semantics/tokens.js +44 -0
- package/dist/src/semantics/transfers.d.ts +2 -0
- package/dist/src/semantics/transfers.js +154 -0
- package/dist/src/semantics/treasury.d.ts +2 -0
- package/dist/src/semantics/treasury.js +377 -0
- package/dist/src/semantics/webhook-endpoints.d.ts +3 -0
- package/dist/src/semantics/webhook-endpoints.js +85 -0
- package/dist/src/stripe-budget.d.ts +55 -0
- package/dist/src/stripe-budget.js +155 -0
- package/dist/src/stripe-capabilities.d.ts +3 -0
- package/dist/src/stripe-capabilities.js +5695 -0
- package/dist/src/stripe-conformance.d.ts +43 -0
- package/dist/src/stripe-conformance.js +105 -0
- package/dist/src/stripe-connector.d.ts +161 -0
- package/dist/src/stripe-connector.js +414 -0
- package/dist/src/stripe-emit.d.ts +2 -0
- package/dist/src/stripe-emit.js +145 -0
- package/dist/src/stripe-events.d.ts +93 -0
- package/dist/src/stripe-events.js +392 -0
- package/dist/src/stripe-js.d.ts +4 -0
- package/dist/src/stripe-js.js +70 -0
- package/dist/src/stripe-mirror-ui.d.ts +15 -0
- package/dist/src/stripe-mirror-ui.js +87 -0
- package/dist/src/stripe-params.d.ts +3 -0
- package/dist/src/stripe-params.js +43 -0
- package/dist/src/stripe-perform-harness.d.ts +9 -0
- package/dist/src/stripe-perform-harness.js +26 -0
- package/dist/src/stripe-server.d.ts +33 -0
- package/dist/src/stripe-server.js +393 -0
- package/dist/src/stripe-shared.d.ts +109 -0
- package/dist/src/stripe-shared.js +276 -0
- package/dist/src/stripe-twin.d.ts +155 -0
- package/dist/src/stripe-twin.js +1232 -0
- package/dist/src/stripe-ui-conformance.d.ts +5 -0
- package/dist/src/stripe-ui-conformance.js +79 -0
- package/dist/src/stripe-ui-structure.d.ts +3 -0
- package/dist/src/stripe-ui-structure.js +168 -0
- package/dist/src/stripe-version.d.ts +12 -0
- package/dist/src/stripe-version.js +287 -0
- package/dist/test-fixtures/stripe-known-deviations.json +110 -0
- package/dist/test-fixtures/stripe-openapi-operations.SOURCE.md +14 -0
- package/dist/test-fixtures/stripe-openapi-operations.json +4717 -0
- package/dist/test-fixtures/stripe-schemas.SOURCE.md +35 -0
- package/dist/test-fixtures/stripe-schemas.json +3813 -0
- package/package.json +18 -10
- package/src/cli.ts +7 -7
- package/src/generated/events.gen.json +1 -0
- package/src/generated/surface.gen.json +1 -0
- package/src/generated/ui.gen.json +1 -0
- package/src/index.ts +34 -10
- package/src/manifest.ts +1102 -0
- package/src/screens/checkout.tsx +267 -0
- package/src/screens/connect-oauth.tsx +400 -0
- package/src/screens/connect-settings.tsx +121 -0
- package/src/screens/consent-skin.ts +20 -0
- package/src/screens/financial-connections.tsx +101 -0
- package/src/screens/identity.tsx +96 -0
- package/src/screens/industries.ts +267 -0
- package/src/screens/onboarding.tsx +243 -0
- package/src/screens/portal.tsx +220 -0
- package/src/screens/public-details.tsx +105 -0
- package/src/semantics/after-payment.ts +118 -0
- package/src/semantics/apps-secrets.ts +58 -0
- package/src/semantics/balance.ts +209 -0
- package/src/semantics/billing.ts +216 -0
- package/src/semantics/charges.ts +220 -0
- package/src/semantics/checkout.ts +310 -0
- package/src/semantics/connect.ts +487 -0
- package/src/semantics/coupons.ts +97 -0
- package/src/semantics/credit-notes.ts +168 -0
- package/src/semantics/customers.ts +432 -0
- package/src/semantics/disputes.ts +62 -0
- package/src/semantics/entitlements.ts +94 -0
- package/src/semantics/ephemeral-keys.ts +34 -0
- package/src/semantics/files.ts +143 -0
- package/src/semantics/invoices.ts +545 -0
- package/src/semantics/issuing.ts +590 -0
- package/src/semantics/ledger.ts +253 -0
- package/src/semantics/payment-intents.ts +420 -0
- package/src/semantics/payment-links.ts +148 -0
- package/src/semantics/payment-methods.ts +145 -0
- package/src/semantics/plans.ts +131 -0
- package/src/semantics/platform.ts +220 -0
- package/src/semantics/products.ts +154 -0
- package/src/semantics/radar.ts +85 -0
- package/src/semantics/refunds.ts +218 -0
- package/src/semantics/renewals.ts +274 -0
- package/src/semantics/setup-intents.ts +87 -0
- package/src/semantics/shared.ts +226 -0
- package/src/semantics/subscription-schedules.ts +129 -0
- package/src/semantics/subscriptions.ts +610 -0
- package/src/semantics/tax.ts +220 -0
- package/src/semantics/terminal.ts +195 -0
- package/src/semantics/test-cards.ts +7 -0
- package/src/semantics/test-clocks.ts +77 -0
- package/src/semantics/tokens.ts +52 -0
- package/src/semantics/transfers.ts +174 -0
- package/src/semantics/treasury.ts +383 -0
- package/src/semantics/webhook-endpoints.ts +87 -0
- package/src/stripe-budget.ts +4 -4
- package/src/stripe-capabilities.ts +2258 -380
- package/src/stripe-conformance.ts +19 -7
- package/src/stripe-connector.ts +68 -40
- package/src/stripe-emit.ts +15 -8
- package/src/stripe-events.ts +102 -40
- package/src/stripe-js.ts +70 -0
- package/src/stripe-mirror-ui.ts +28 -298
- package/src/stripe-params.ts +44 -0
- package/src/stripe-perform-harness.ts +29 -0
- package/src/stripe-server.ts +318 -38
- package/src/stripe-shared.ts +297 -0
- package/src/stripe-twin.ts +434 -5325
- package/src/stripe-ui-conformance.ts +70 -107
- package/src/stripe-ui-structure.ts +124 -348
- package/src/stripe-version.ts +281 -0
- package/test-fixtures/stripe-known-deviations.json +8 -8
- package/test-fixtures/stripe-openapi-operations.json +1188 -2855
- package/test-fixtures/stripe-schemas.json +85 -12
- package/src/stripe-form.ts +0 -35
|
@@ -1,404 +1,180 @@
|
|
|
1
|
-
// Stripe
|
|
1
|
+
// The Stripe Dashboard — structural DOM checklist (RUNG-5).
|
|
2
2
|
//
|
|
3
|
-
// Completeness (stripe-ui-conformance.ts) asks "does the
|
|
4
|
-
//
|
|
5
|
-
// the
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// product image <img> thumbnails, a prominent payment-decline banner (last_payment_error)
|
|
10
|
-
// and the synthesized balance available/pending summary buckets.
|
|
3
|
+
// Completeness (stripe-ui-conformance.ts) asks "does the Dashboard SHOW the data?". Structure asks
|
|
4
|
+
// "does its rendered DOM have the landmarks Stripe's Dashboard has?": the left navigation at Stripe's
|
|
5
|
+
// paths, the test-mode band, the Payments table with Stripe's columns and status pills, a payment's page
|
|
6
|
+
// (amount, status, timeline from its events, breakdown, refunds, card), a customer's page (details,
|
|
7
|
+
// subscriptions, payments, payment methods, invoices), a subscription's page (pricing, period, invoices,
|
|
8
|
+
// the cancel control), the balance buckets, a connected account's readiness and the resource lists.
|
|
11
9
|
//
|
|
12
|
-
// Each check's `present` is computed from the ACTUAL markup
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// pass unless the component truly emits that structure. Read-only; deterministic.
|
|
10
|
+
// Each check's `present` is computed from the ACTUAL markup renderToStaticMarkup() produces from the
|
|
11
|
+
// Dashboard's own components (client/stripe-mirror.tsx) over objects shaped as the API returns them, so a
|
|
12
|
+
// check cannot pass unless the component truly emits that structure. Read-only; deterministic.
|
|
16
13
|
import { createElement } from 'react';
|
|
17
14
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
18
|
-
import { checkUiStructure, type UiStructureReport } from '@volter/
|
|
15
|
+
import { checkUiStructure, type UiStructureReport } from '@volter/world-tooling';
|
|
19
16
|
import {
|
|
20
|
-
SECTIONS, SideNav, ListPane,
|
|
17
|
+
SECTIONS, SideNav, ListPane, TestModeBand, PaymentsTable, PaymentDetailView, CustomerDetailView,
|
|
18
|
+
SubscriptionDetailView, BalanceSummary, ConnectAccountPanel,
|
|
21
19
|
} from '../client/stripe-mirror.tsx';
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
type StripeRow, type CrossRefs,
|
|
25
|
-
} from './stripe-mirror-ui.ts';
|
|
20
|
+
import type { CustomerDetail, Payment, PaymentDetail, SubscriptionDetail } from '../client/dashboard-api.ts';
|
|
21
|
+
import type { StripeRow } from './stripe-mirror-ui.ts';
|
|
26
22
|
|
|
27
|
-
const
|
|
23
|
+
const noop = () => {};
|
|
24
|
+
const AT = 1790263345;
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
id: 'cus_twin001', object: 'customer', name: 'Ada Lovelace', email: 'ada@example.com', currency: 'usd',
|
|
36
|
-
metadata: { plan: 'pro', seats: '5' },
|
|
37
|
-
};
|
|
38
|
-
const PRODUCT: StripeRow = {
|
|
39
|
-
id: 'prod_twin001', object: 'product', name: 'Analytics Suite', active: true,
|
|
40
|
-
images: ['https://files.stripe.com/img/one.png', 'https://files.stripe.com/img/two.png'],
|
|
41
|
-
};
|
|
42
|
-
const PRICE: StripeRow = {
|
|
43
|
-
id: 'price_twin001', object: 'price', product: 'prod_twin001', currency: 'usd', unit_amount: 4200,
|
|
44
|
-
recurring: { interval: 'month', interval_count: 1 },
|
|
45
|
-
};
|
|
46
|
-
const SUBSCRIPTION: StripeRow = {
|
|
47
|
-
id: 'sub_twin001', object: 'subscription', status: 'active', customer: 'cus_twin001', currency: 'usd',
|
|
48
|
-
items: {
|
|
49
|
-
object: 'list',
|
|
50
|
-
data: [
|
|
51
|
-
{ id: 'si_twin001', object: 'subscription_item', quantity: 5, price: 'price_twin001' },
|
|
52
|
-
],
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
const INVOICE: StripeRow = {
|
|
56
|
-
id: 'in_twin001', object: 'invoice', status: 'paid', customer: 'cus_twin001', subscription: 'sub_twin001',
|
|
57
|
-
currency: 'usd', total: 21000, amount_due: 21000,
|
|
58
|
-
lines: {
|
|
59
|
-
object: 'list',
|
|
60
|
-
data: [
|
|
61
|
-
{ id: 'il_twin001', object: 'line_item', amount: 21000, quantity: 5, price: 'price_twin001' },
|
|
62
|
-
],
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
const DISPUTE: StripeRow = {
|
|
66
|
-
id: 'dp_twin001', object: 'dispute', amount: 4200, currency: 'usd', reason: 'fraudulent',
|
|
67
|
-
status: 'warning_needs_response', charge: 'ch_twin001',
|
|
68
|
-
};
|
|
69
|
-
const PAYOUT: StripeRow = {
|
|
70
|
-
id: 'po_twin001', object: 'payout', amount: 16800, currency: 'usd', status: 'in_transit',
|
|
71
|
-
arrival_date: 1718409600,
|
|
72
|
-
};
|
|
73
|
-
// A declined payment_intent carries the vendor-faithful last_payment_error (test-card
|
|
74
|
-
// decline state) the mirror lifts into a prominent banner.
|
|
75
|
-
const DECLINED_PAYMENT: StripeRow = {
|
|
76
|
-
id: 'pi_twin009', object: 'payment_intent', amount: 4200, currency: 'usd', customer: 'cus_twin001',
|
|
77
|
-
status: 'requires_payment_method',
|
|
78
|
-
last_payment_error: { type: 'card_error', code: 'card_declined', decline_code: 'insufficient_funds', message: 'Your card has insufficient funds.', param: 'card' },
|
|
79
|
-
};
|
|
80
|
-
// The synthesized account balance summary (GET /v1/balance), presented as a one-row list.
|
|
81
|
-
const BALANCE: StripeRow = {
|
|
82
|
-
id: 'balance', object: 'balance', livemode: false,
|
|
83
|
-
available: [{ amount: 16800, currency: 'usd', source_types: { card: 16800 } }],
|
|
84
|
-
pending: [{ amount: 4200, currency: 'usd', source_types: { card: 4200 } }],
|
|
85
|
-
};
|
|
86
|
-
// A Connect connected account, freshly created (not yet onboarded): charges/payouts
|
|
87
|
-
// disabled, details not submitted, with outstanding `requirements.currently_due`.
|
|
88
|
-
const ACCOUNT: StripeRow = {
|
|
89
|
-
id: 'acct_twin001', object: 'account', type: 'express', country: 'US', email: 'seller@example.com',
|
|
90
|
-
charges_enabled: false, payouts_enabled: false, details_submitted: false,
|
|
91
|
-
capabilities: { card_payments: 'inactive' },
|
|
92
|
-
requirements: { currently_due: ['external_account', 'tos_acceptance.date'], eventually_due: [], past_due: [], pending_verification: [] },
|
|
93
|
-
};
|
|
94
|
-
// A transfer from the platform balance to the connected account above (destination cross-ref).
|
|
95
|
-
const TRANSFER: StripeRow = {
|
|
96
|
-
id: 'tr_twin001', object: 'transfer', amount: 16800, currency: 'usd', destination: 'acct_twin001',
|
|
97
|
-
reversed: false, amount_reversed: 0,
|
|
98
|
-
};
|
|
26
|
+
const CUSTOMER: StripeRow = { id: 'cus_twin001', object: 'customer', name: 'Ada Lovelace', email: 'ada@example.com', created: AT, invoice_settings: { default_payment_method: 'pm_twin001' }, metadata: {} };
|
|
27
|
+
const CARD: StripeRow = { id: 'pm_twin001', object: 'payment_method', type: 'card', customer: 'cus_twin001', card: { brand: 'visa', last4: '4242', exp_month: 12, exp_year: 2034, funding: 'credit', country: 'US', checks: { cvc_check: 'pass' } }, billing_details: {} };
|
|
28
|
+
const INTENT: StripeRow = { id: 'pi_twin001', object: 'payment_intent', amount: 30000, currency: 'usd', status: 'succeeded', customer: 'cus_twin001', payment_method: 'pm_twin001', latest_charge: 'ch_twin001', description: 'Annual workshop seat', created: AT, metadata: {} };
|
|
29
|
+
const CHARGE: StripeRow = { id: 'ch_twin001', object: 'charge', amount: 30000, currency: 'usd', status: 'succeeded', refunded: false, amount_refunded: 10000, payment_intent: 'pi_twin001', customer: 'cus_twin001', created: AT };
|
|
30
|
+
const REFUND: StripeRow = { id: 're_twin001', object: 'refund', amount: 10000, currency: 'usd', status: 'succeeded', charge: 'ch_twin001', payment_intent: 'pi_twin001', reason: 'requested_by_customer', created: AT + 60 };
|
|
31
|
+
const event = (id: string, type: string, object: StripeRow, created: number): StripeRow => ({ id, object: 'event', type, created, data: { object } });
|
|
99
32
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
33
|
+
const PARTIAL: PaymentDetail = {
|
|
34
|
+
id: 'pi_twin001', amount: 30000, currency: 'usd', status: 'partially_refunded', description: 'Annual workshop seat', created: AT,
|
|
35
|
+
customer: CUSTOMER, charge: CHARGE, intent: INTENT, paymentMethod: CARD, amountRefunded: 10000, refundedAt: AT + 60,
|
|
36
|
+
refunds: [REFUND],
|
|
37
|
+
events: [
|
|
38
|
+
event('evt_3', 'charge.refunded', CHARGE, AT + 60),
|
|
39
|
+
event('evt_2', 'payment_intent.succeeded', INTENT, AT + 1),
|
|
40
|
+
event('evt_1', 'payment_intent.created', INTENT, AT),
|
|
41
|
+
],
|
|
42
|
+
};
|
|
43
|
+
const DECLINED_INTENT: StripeRow = {
|
|
44
|
+
id: 'pi_twin009', object: 'payment_intent', amount: 15000, currency: 'usd', status: 'requires_payment_method', customer: 'cus_twin001', created: AT,
|
|
45
|
+
last_payment_error: { type: 'card_error', code: 'card_declined', decline_code: 'insufficient_funds', message: 'Your card has insufficient funds.', param: 'card' },
|
|
104
46
|
};
|
|
105
|
-
const
|
|
106
|
-
id: '
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
object: 'list',
|
|
110
|
-
data: [
|
|
111
|
-
{ id: 'tax_li_taxcalc_twin001_1', object: 'tax.calculation_line_item', amount: 1000, amount_tax: 100, reference: 'sku_1', tax_behavior: 'exclusive' },
|
|
112
|
-
],
|
|
113
|
-
},
|
|
47
|
+
const DECLINED: PaymentDetail = {
|
|
48
|
+
id: 'pi_twin009', amount: 15000, currency: 'usd', status: 'failed', created: AT, customer: CUSTOMER, intent: DECLINED_INTENT,
|
|
49
|
+
amountRefunded: 0, declineReason: 'Insufficient funds', declineMessage: 'Your card has insufficient funds.', refunds: [],
|
|
50
|
+
events: [event('evt_9', 'payment_intent.payment_failed', DECLINED_INTENT, AT)],
|
|
114
51
|
};
|
|
52
|
+
const REFUNDED: Payment = { id: 'pi_twin002', amount: 2500, currency: 'usd', status: 'refunded', description: 'Twin T-shirt', created: AT, customer: CUSTOMER, paymentMethod: CARD, amountRefunded: 2500, refundedAt: AT + 30 };
|
|
53
|
+
const PAYMENTS: Payment[] = [PARTIAL, DECLINED, REFUNDED, { ...REFUNDED, id: 'pi_twin003', status: 'succeeded', amountRefunded: 0, refundedAt: undefined, description: 'Consulting' }];
|
|
115
54
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
lines: {
|
|
122
|
-
object: 'list',
|
|
123
|
-
data: [
|
|
124
|
-
{ id: 'cnli_cn_twin001_1', object: 'credit_note_line_item', type: 'custom_line_item', amount: 5000, description: 'goodwill credit' },
|
|
125
|
-
],
|
|
126
|
-
},
|
|
127
|
-
};
|
|
128
|
-
// A customer tax ID (EU VAT) on the customer above (customer cross-ref).
|
|
129
|
-
const TAX_ID: StripeRow = {
|
|
130
|
-
id: 'txi_twin001', object: 'tax_id', type: 'eu_vat', value: 'DE123456789',
|
|
131
|
-
customer: 'cus_twin001', country: 'DE', verification: { status: 'pending' },
|
|
132
|
-
};
|
|
133
|
-
// A customer balance transaction (a -2000 credit) with its running ending_balance.
|
|
134
|
-
const CUSTOMER_BALANCE_TXN: StripeRow = {
|
|
135
|
-
id: 'cbtxn_twin001', object: 'customer_balance_transaction', amount: -2000, currency: 'usd',
|
|
136
|
-
ending_balance: -2000, type: 'adjustment', customer: 'cus_twin001', credit_note: 'cn_twin001',
|
|
55
|
+
const PRODUCT: StripeRow = { id: 'prod_twin001', object: 'product', name: 'Pro plan' };
|
|
56
|
+
const SUBSCRIPTION: StripeRow = {
|
|
57
|
+
id: 'sub_twin001', object: 'subscription', status: 'trialing', customer: 'cus_twin001', currency: 'usd', created: AT, start_date: AT,
|
|
58
|
+
current_period_start: AT, current_period_end: AT + 14 * 86400, trial_start: AT, trial_end: AT + 14 * 86400, collection_method: 'charge_automatically',
|
|
59
|
+
items: { object: 'list', data: [{ id: 'si_twin001', object: 'subscription_item', quantity: 3, price: { id: 'price_twin001', product: 'prod_twin001', unit_amount: 4900, currency: 'usd', recurring: { interval: 'month' } } }] },
|
|
137
60
|
};
|
|
61
|
+
const INVOICE: StripeRow = { id: 'in_twin001', object: 'invoice', number: 'TWIN-0001', status: 'paid', customer: 'cus_twin001', subscription: 'sub_twin001', currency: 'usd', total: 14700, amount_due: 14700, created: AT };
|
|
62
|
+
const CUSTOMER_PAGE: CustomerDetail = { customer: CUSTOMER, paymentMethods: [CARD], subscriptions: [SUBSCRIPTION], invoices: [INVOICE], payments: PAYMENTS, products: new Map([[PRODUCT.id, PRODUCT]]), events: [] };
|
|
63
|
+
const SUBSCRIPTION_PAGE: SubscriptionDetail = { subscription: SUBSCRIPTION, customer: CUSTOMER, invoices: [INVOICE], products: new Map([[PRODUCT.id, PRODUCT]]), events: [event('evt_s', 'customer.subscription.created', SUBSCRIPTION, AT)], paymentMethod: CARD };
|
|
138
64
|
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
customer_balance_transactions: [CUSTOMER_BALANCE_TXN],
|
|
144
|
-
tax_rates: [TAX_RATE],
|
|
145
|
-
'tax/calculations': [TAX_CALCULATION],
|
|
146
|
-
products: [PRODUCT],
|
|
147
|
-
prices: [PRICE],
|
|
148
|
-
subscriptions: [SUBSCRIPTION],
|
|
149
|
-
invoices: [INVOICE],
|
|
150
|
-
disputes: [DISPUTE],
|
|
151
|
-
payouts: [PAYOUT],
|
|
152
|
-
payment_intents: [DECLINED_PAYMENT],
|
|
153
|
-
balance: [BALANCE],
|
|
154
|
-
accounts: [ACCOUNT],
|
|
155
|
-
transfers: [TRANSFER],
|
|
65
|
+
const BALANCE: StripeRow = { id: 'balance', object: 'balance', available: [{ amount: 16800, currency: 'usd' }], pending: [{ amount: 4200, currency: 'usd' }] };
|
|
66
|
+
const ACCOUNT: StripeRow = {
|
|
67
|
+
id: 'acct_twin001', object: 'account', type: 'express', country: 'US', charges_enabled: false, payouts_enabled: false, details_submitted: false,
|
|
68
|
+
requirements: { currently_due: ['external_account', 'tos_acceptance.date'] },
|
|
156
69
|
};
|
|
70
|
+
const TAX_RATE: StripeRow = { id: 'txr_twin001', object: 'tax_rate', display_name: 'Sales Tax', percentage: 8.5, inclusive: false, active: true, jurisdiction: 'US', created: AT };
|
|
157
71
|
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
/** renderToStaticMarkup the left nav (one item + count per collection). */
|
|
161
|
-
function renderNav(): string {
|
|
162
|
-
const counts = Object.fromEntries(SECTIONS.map((s) => [s.key, DATA[s.key]?.length ?? 0]));
|
|
163
|
-
return renderToStaticMarkup(
|
|
164
|
-
createElement(SideNav, { sections: SECTIONS, counts, activeKey: SECTIONS[0]!.key, onSelect: noop }),
|
|
165
|
-
);
|
|
166
|
-
}
|
|
72
|
+
const html = (el: Parameters<typeof renderToStaticMarkup>[0]) => renderToStaticMarkup(el);
|
|
73
|
+
const count = (markup: string, needle: RegExp) => (markup.match(needle) ?? []).length;
|
|
167
74
|
|
|
168
|
-
/**
|
|
169
|
-
function renderList(collection: string, rows: StripeRow[]): string {
|
|
170
|
-
return renderToStaticMarkup(
|
|
171
|
-
createElement(ListPane, { section: SECTION_BY_KEY[collection]!, rows, currentId: rows[0]?.id, onSelect: noop }),
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/** renderToStaticMarkup the detail pane for a row, with its resolved cross-refs. */
|
|
176
|
-
function renderDetail(collection: string, row: StripeRow): string {
|
|
177
|
-
const refs: CrossRefs = resolveCrossRefs(collection, row, DATA);
|
|
178
|
-
return renderToStaticMarkup(
|
|
179
|
-
createElement(Detail, { collection, row, refs, onJump: noop }),
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Build the structural checklist from the real rendered markup and run it.
|
|
185
|
-
* ~10 checks, every one asserting a Stripe-dashboard structural landmark.
|
|
186
|
-
*/
|
|
75
|
+
/** Build the structural checklist from the real rendered markup and run it. */
|
|
187
76
|
export function stripeUiStructure(): UiStructureReport {
|
|
188
|
-
const nav =
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
const
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
const
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
const
|
|
198
|
-
const taxRatesList = renderList('tax_rates', DATA.tax_rates!);
|
|
199
|
-
const taxCalculationDetail = renderDetail('tax/calculations', TAX_CALCULATION);
|
|
200
|
-
const creditNotesList = renderList('credit_notes', DATA.credit_notes!);
|
|
201
|
-
const creditNoteDetail = renderDetail('credit_notes', CREDIT_NOTE);
|
|
202
|
-
const taxIdsList = renderList('tax_ids', DATA.tax_ids!);
|
|
203
|
-
const customerBalanceTxnDetail = renderDetail('customer_balance_transactions', CUSTOMER_BALANCE_TXN);
|
|
204
|
-
|
|
205
|
-
// How many collection nav items the markup emits. The left nav now also renders the Home
|
|
206
|
-
// and Settings chrome buttons (which carry no per-collection count), so the per-collection
|
|
207
|
-
// landmark counts the items that carry a nav-count — exactly one per collection.
|
|
208
|
-
const navItems = (nav.match(/nav-count/g) ?? []).length;
|
|
209
|
-
const customerRows = (customersList.match(/list-row/g) ?? []).length;
|
|
77
|
+
const nav = html(createElement(SideNav, { route: ['payments'], go: noop }));
|
|
78
|
+
const band = html(createElement(TestModeBand));
|
|
79
|
+
const payments = html(createElement(PaymentsTable, { payments: PAYMENTS, go: noop }));
|
|
80
|
+
const partial = html(createElement(PaymentDetailView, { p: PARTIAL, go: noop, onRefund: noop }));
|
|
81
|
+
const declined = html(createElement(PaymentDetailView, { p: DECLINED, go: noop, onRefund: noop }));
|
|
82
|
+
const customer = html(createElement(CustomerDetailView, { data: CUSTOMER_PAGE, go: noop }));
|
|
83
|
+
const subscription = html(createElement(SubscriptionDetailView, { data: SUBSCRIPTION_PAGE, go: noop, onCancel: noop }));
|
|
84
|
+
const balance = html(createElement(BalanceSummary, { row: BALANCE }));
|
|
85
|
+
const account = html(createElement(ConnectAccountPanel, { row: ACCOUNT }));
|
|
86
|
+
const taxRates = html(createElement(ListPane, { section: SECTIONS.find((s) => s.key === 'tax_rates')!, rows: [TAX_RATE], onSelect: noop }));
|
|
210
87
|
|
|
211
88
|
const checks = [
|
|
212
89
|
{
|
|
213
|
-
key: '
|
|
214
|
-
label:
|
|
215
|
-
present:
|
|
216
|
-
|
|
217
|
-
{
|
|
218
|
-
key: 'navCounts',
|
|
219
|
-
label: 'Each left-nav item carries a per-collection object count',
|
|
220
|
-
present: (nav.match(/nav-count/g) ?? []).length === SECTIONS.length,
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
key: 'listRowPerObject',
|
|
224
|
-
label: 'List pane emits one row per object in the section',
|
|
225
|
-
present: customerRows === DATA.customers!.length && customersList.includes('class="list"'),
|
|
90
|
+
key: 'navigation',
|
|
91
|
+
label: "Left navigation: Home, Balances, Transactions, Customers, Product catalog, Billing's Subscriptions and Invoices, Developers — at Stripe's /test/ paths",
|
|
92
|
+
present: ['>Home<', '>Balances<', '>Transactions<', '>Customers<', '>Product catalog<', '>Subscriptions<', '>Invoices<', '>Developers<'].every((l) => nav.includes(l))
|
|
93
|
+
&& nav.includes('href="/test/payments"') && nav.includes('href="/test/customers"') && nav.includes('href="/test/subscriptions"'),
|
|
226
94
|
},
|
|
227
95
|
{
|
|
228
|
-
key: '
|
|
229
|
-
label: '
|
|
230
|
-
present:
|
|
96
|
+
key: 'navActive',
|
|
97
|
+
label: 'The navigation marks the section being viewed',
|
|
98
|
+
present: /class="nav-item [^"]*active"[^>]*href="\/test\/payments"|href="\/test\/payments" class="nav-item [^"]*active"/.test(nav),
|
|
231
99
|
},
|
|
232
100
|
{
|
|
233
|
-
key: '
|
|
234
|
-
label:
|
|
235
|
-
present:
|
|
101
|
+
key: 'testModeBand',
|
|
102
|
+
label: "The orange test-mode band across the top",
|
|
103
|
+
present: band.includes('class="test-band"') && band.includes('Test mode'),
|
|
236
104
|
},
|
|
237
105
|
{
|
|
238
|
-
key: '
|
|
239
|
-
label: '
|
|
240
|
-
present:
|
|
241
|
-
subscriptionDetail.includes('class="nested"') &&
|
|
242
|
-
subscriptionDetail.includes('nested-line') &&
|
|
243
|
-
!subscriptionDetail.includes('[object Object]') &&
|
|
244
|
-
!invoiceDetail.includes('[object Object]'),
|
|
106
|
+
key: 'paymentsColumns',
|
|
107
|
+
label: "Payments table carries Stripe's columns (Amount, Payment method, Description, Customer, Date, Refunded date, Decline reason)",
|
|
108
|
+
present: ['>Amount<', '>Payment method<', '>Description<', '>Customer<', '>Date<', '>Refunded date<', '>Decline reason<'].every((c) => payments.includes(c)),
|
|
245
109
|
},
|
|
246
110
|
{
|
|
247
|
-
key: '
|
|
248
|
-
label: '
|
|
249
|
-
present:
|
|
250
|
-
subscriptionDetail.includes('si_twin001') &&
|
|
251
|
-
invoiceDetail.includes('il_twin001'),
|
|
111
|
+
key: 'paymentsRowPerPayment',
|
|
112
|
+
label: 'Payments table emits one row per payment, amount with its currency',
|
|
113
|
+
present: count(payments, /class="list-row"/g) === PAYMENTS.length && payments.includes('$300.00') && payments.includes('USD'),
|
|
252
114
|
},
|
|
253
115
|
{
|
|
254
|
-
key: '
|
|
255
|
-
label: '
|
|
256
|
-
present:
|
|
116
|
+
key: 'paymentsStatusPills',
|
|
117
|
+
label: 'Status pills worded as Stripe words them (Succeeded, Refunded, Partial refund, Failed)',
|
|
118
|
+
present: ['>Succeeded<', '>Refunded<', '>Partial refund<', '>Failed<'].every((l) => payments.includes(l)),
|
|
257
119
|
},
|
|
258
120
|
{
|
|
259
|
-
key: '
|
|
260
|
-
label: 'A
|
|
261
|
-
present:
|
|
262
|
-
invoiceDetail.includes('detail-block refs') &&
|
|
263
|
-
invoiceDetail.includes('>Related<') &&
|
|
264
|
-
invoiceDetail.includes('>References<') &&
|
|
265
|
-
(invoiceDetail.match(/ref-chip/g) ?? []).length >= 1,
|
|
121
|
+
key: 'paymentsDeclineReason',
|
|
122
|
+
label: 'A failed payment shows its decline reason in the list',
|
|
123
|
+
present: payments.includes('Insufficient funds'),
|
|
266
124
|
},
|
|
267
125
|
{
|
|
268
|
-
key: '
|
|
269
|
-
label: '
|
|
270
|
-
|
|
271
|
-
present:
|
|
272
|
-
customerDetail.includes('detail-block refs') &&
|
|
273
|
-
customerDetail.includes('>Referenced by<') &&
|
|
274
|
-
(customerDetail.match(/ref-chip/g) ?? []).length >= 1,
|
|
126
|
+
key: 'paymentHeader',
|
|
127
|
+
label: "A payment's page leads with its amount, currency and status, and a Refund control while refundable",
|
|
128
|
+
present: partial.includes('$300.00') && partial.includes('Partial refund') && partial.includes('Refund</button>'),
|
|
275
129
|
},
|
|
276
130
|
{
|
|
277
|
-
key: '
|
|
278
|
-
label: '
|
|
279
|
-
|
|
280
|
-
present: invoiceDetail.includes('Ada Lovelace'),
|
|
131
|
+
key: 'paymentTimeline',
|
|
132
|
+
label: "A payment's timeline lists its events (started, succeeded, refunded)",
|
|
133
|
+
present: partial.includes('class="timeline"') && partial.includes('Payment started') && partial.includes('Payment succeeded') && partial.includes('refunded'),
|
|
281
134
|
},
|
|
282
135
|
{
|
|
283
|
-
key: '
|
|
284
|
-
label: '
|
|
285
|
-
present:
|
|
286
|
-
productDetail.includes('class="thumbs"') &&
|
|
287
|
-
(productDetail.match(/<img/g) ?? []).length === productImageUrls(PRODUCT.images).length &&
|
|
288
|
-
productImageUrls(PRODUCT.images).length > 0,
|
|
136
|
+
key: 'paymentBreakdownAndRefunds',
|
|
137
|
+
label: "A payment's breakdown (amount, refunded, net) and its refunds",
|
|
138
|
+
present: partial.includes('Payment breakdown') && partial.includes('$200.00') && partial.includes('>Refunds<') && partial.includes('re_twin001'),
|
|
289
139
|
},
|
|
290
140
|
{
|
|
291
|
-
key: '
|
|
292
|
-
label:
|
|
293
|
-
present:
|
|
294
|
-
declinedPaymentDetail.includes('class="pay-error"') &&
|
|
295
|
-
declinedPaymentDetail.includes('Payment error') &&
|
|
296
|
-
declinedPaymentDetail.includes('card_declined') &&
|
|
297
|
-
declinedPaymentDetail.includes('insufficient_funds') &&
|
|
298
|
-
// lifted out of the generic grid, not buried as a raw nested object
|
|
299
|
-
!declinedPaymentDetail.includes('[object Object]'),
|
|
300
|
-
},
|
|
301
|
-
{
|
|
302
|
-
key: 'balanceSummaryBuckets',
|
|
303
|
-
label: 'The balance section renders available/pending summary buckets with formatted amounts',
|
|
304
|
-
present:
|
|
305
|
-
balanceDetail.includes('class="balance-summary"') &&
|
|
306
|
-
balanceDetail.includes('balance-bucket available') &&
|
|
307
|
-
(balanceDetail.match(/balance-bucket/g) ?? []).length >= 2 &&
|
|
308
|
-
balanceDetail.includes('$168.00') &&
|
|
309
|
-
balanceDetail.includes('$42.00'),
|
|
141
|
+
key: 'paymentMethodBlock',
|
|
142
|
+
label: "A payment's card: number's last four, expiry, type, CVC check",
|
|
143
|
+
present: partial.includes('4242') && partial.includes('12 / 2034') && partial.includes('Visa credit card') && partial.includes('Passed'),
|
|
310
144
|
},
|
|
311
145
|
{
|
|
312
|
-
key: '
|
|
313
|
-
label: 'A
|
|
314
|
-
present:
|
|
315
|
-
accountDetail.includes('class="connect-panel"') &&
|
|
316
|
-
(accountDetail.match(/connect-flag /g) ?? []).length >= 3 &&
|
|
317
|
-
accountDetail.includes('>Charges<') &&
|
|
318
|
-
accountDetail.includes('>Payouts<') &&
|
|
319
|
-
accountDetail.includes('>Details submitted<') &&
|
|
320
|
-
// a freshly-created account is not enabled → disabled state shown
|
|
321
|
-
accountDetail.includes('>disabled<'),
|
|
146
|
+
key: 'paymentDecline',
|
|
147
|
+
label: 'A declined payment states its error and decline code, and offers no refund',
|
|
148
|
+
present: declined.includes('class="pay-error"') && declined.includes('Your card has insufficient funds.') && declined.includes('insufficient_funds') && !declined.includes('Refund</button>'),
|
|
322
149
|
},
|
|
323
150
|
{
|
|
324
|
-
key: '
|
|
325
|
-
label:
|
|
326
|
-
present:
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
accountDetail.includes('external_account') &&
|
|
330
|
-
accountDetail.includes('tos_acceptance.date'),
|
|
151
|
+
key: 'customerPage',
|
|
152
|
+
label: "A customer's page: name, email, Details, Subscriptions, Payments, Payment methods, Invoices",
|
|
153
|
+
present: customer.includes('Ada Lovelace') && customer.includes('ada@example.com')
|
|
154
|
+
&& ['>Details<', '>Subscriptions<', '>Payments<', '>Payment methods<', '>Invoices<'].every((h) => customer.includes(h))
|
|
155
|
+
&& customer.includes('Pro plan') && customer.includes('TWIN-0001') && customer.includes('>Default<'),
|
|
331
156
|
},
|
|
332
157
|
{
|
|
333
|
-
key: '
|
|
334
|
-
label:
|
|
335
|
-
present:
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
transferDetail.includes('acct_twin001'),
|
|
158
|
+
key: 'subscriptionPage',
|
|
159
|
+
label: "A subscription's page: customer on product, status, period, pricing items, invoices and Cancel subscription",
|
|
160
|
+
present: subscription.includes('Ada Lovelace') && subscription.includes('Pro plan') && subscription.includes('>Trialing<')
|
|
161
|
+
&& subscription.includes('Current period') && subscription.includes('>Pricing<') && subscription.includes('$147.00')
|
|
162
|
+
&& subscription.includes('TWIN-0001') && subscription.includes('Cancel subscription'),
|
|
339
163
|
},
|
|
340
164
|
{
|
|
341
|
-
key: '
|
|
342
|
-
label: 'The
|
|
343
|
-
present:
|
|
344
|
-
(taxRatesList.match(/list-row/g) ?? []).length === DATA.tax_rates!.length &&
|
|
345
|
-
taxRatesList.includes('Sales Tax') &&
|
|
346
|
-
taxRatesList.includes('8.5'),
|
|
347
|
-
},
|
|
348
|
-
{
|
|
349
|
-
key: 'taxCalculationLineItems',
|
|
350
|
-
label: 'A tax calculation renders its priced line_items as nested lines (per-item tax)',
|
|
351
|
-
present:
|
|
352
|
-
taxCalculationDetail.includes('class="nested"') &&
|
|
353
|
-
taxCalculationDetail.includes('tax_li_taxcalc_twin001_1') &&
|
|
354
|
-
!taxCalculationDetail.includes('[object Object]'),
|
|
355
|
-
},
|
|
356
|
-
{
|
|
357
|
-
key: 'taxCalculationTotals',
|
|
358
|
-
label: 'A tax calculation renders its amount_total and tax_amount_exclusive (currency-formatted)',
|
|
359
|
-
present:
|
|
360
|
-
taxCalculationDetail.includes('$11.00') &&
|
|
361
|
-
taxCalculationDetail.includes('$1.00'),
|
|
362
|
-
},
|
|
363
|
-
{
|
|
364
|
-
key: 'creditNotesListRow',
|
|
365
|
-
label: 'The Credit Notes section emits a list row per credit note (credited amount + status)',
|
|
366
|
-
present:
|
|
367
|
-
(creditNotesList.match(/list-row/g) ?? []).length === DATA.credit_notes!.length &&
|
|
368
|
-
creditNotesList.includes('$50.00') &&
|
|
369
|
-
creditNotesList.includes('issued'),
|
|
370
|
-
},
|
|
371
|
-
{
|
|
372
|
-
key: 'creditNoteLineItems',
|
|
373
|
-
label: 'A credit note renders its nested line_items (per-line credited amount), never "[object Object]"',
|
|
374
|
-
present:
|
|
375
|
-
creditNoteDetail.includes('class="nested"') &&
|
|
376
|
-
creditNoteDetail.includes('cnli_cn_twin001_1') &&
|
|
377
|
-
!creditNoteDetail.includes('[object Object]'),
|
|
378
|
-
},
|
|
379
|
-
{
|
|
380
|
-
key: 'creditNoteInvoiceCrossRef',
|
|
381
|
-
label: 'A credit note renders a cross-ref link to the invoice it credits',
|
|
382
|
-
present:
|
|
383
|
-
creditNoteDetail.includes('detail-block refs') &&
|
|
384
|
-
(creditNoteDetail.match(/ref-chip/g) ?? []).length >= 1 &&
|
|
385
|
-
creditNoteDetail.includes('in_twin001'),
|
|
165
|
+
key: 'balanceSummaryBuckets',
|
|
166
|
+
label: 'The balance renders its incoming and available buckets, amounts formatted',
|
|
167
|
+
present: balance.includes('class="balance-summary"') && balance.includes('Incoming') && balance.includes('Available') && balance.includes('$168.00') && balance.includes('$42.00'),
|
|
386
168
|
},
|
|
387
169
|
{
|
|
388
|
-
key: '
|
|
389
|
-
label:
|
|
390
|
-
present:
|
|
391
|
-
(taxIdsList.match(/list-row/g) ?? []).length === DATA.tax_ids!.length &&
|
|
392
|
-
taxIdsList.includes('DE123456789') &&
|
|
393
|
-
taxIdsList.includes('eu_vat'),
|
|
170
|
+
key: 'connectAccountReadiness',
|
|
171
|
+
label: "A connected account's charges/payouts/details flags and what is currently due",
|
|
172
|
+
present: account.includes('class="connect-panel"') && count(account, /connect-flag /g) >= 3 && account.includes('Requirements currently due') && account.includes('external_account'),
|
|
394
173
|
},
|
|
395
174
|
{
|
|
396
|
-
key: '
|
|
397
|
-
label: 'A
|
|
398
|
-
present:
|
|
399
|
-
customerBalanceTxnDetail.includes('detail-block refs') &&
|
|
400
|
-
customerBalanceTxnDetail.includes('-$20.00') &&
|
|
401
|
-
(customerBalanceTxnDetail.match(/ref-chip/g) ?? []).length >= 1,
|
|
175
|
+
key: 'resourceListRow',
|
|
176
|
+
label: 'A resource list emits one row per object (Tax rates: name and percentage)',
|
|
177
|
+
present: count(taxRates, /list-row/g) === 1 && taxRates.includes('Sales Tax') && taxRates.includes('8.5'),
|
|
402
178
|
},
|
|
403
179
|
];
|
|
404
180
|
|