@12-apps/payments-e2e 1.4.0 → 1.5.0

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 CHANGED
@@ -4,9 +4,10 @@ The buyer journeys for the payments checkout, as Gherkin you run **against your
4
4
  own app**.
5
5
 
6
6
  Mounting `createPaymentFlows` gives you a checkout. This gives you its
7
- end-to-end coverage: twenty scenarios across seven features — PIX, card, hosted
8
- hand-off and return, provider failover, issuer declines, an unresolved charge, a
9
- store that cannot charge at all, and per-provider screens. You implement one
7
+ end-to-end coverage: twenty-seven scenarios across ten features — PIX, card,
8
+ digital wallets, hosted hand-off and return, provider failover, issuer
9
+ declines, an unresolved charge, a store that cannot charge at all,
10
+ per-provider screens, and saving a card outside checkout. You implement one
10
11
  port and add three lines of config. Nothing is copied, so a scenario added here
11
12
  later runs in your app on the next version bump.
12
13
 
@@ -84,12 +85,33 @@ files do not change either way.
84
85
  `pix-only` · `card` · `both-methods` · `hosted` · `awaiting` · `settles` ·
85
86
  `declined` · `unresolved` · `unavailable` · `no-provider` ·
86
87
  `no-provider-remedy` · `payments-off` · `two-mintable` · `redirect-head` ·
87
- `google-pay` · `apple-pay` · `apple-pay-unsupported` · `screen-on-page` ·
88
- `screen-handoff` · `screen-undeclared` · `screen-unknown`
88
+ `google-pay` · `apple-pay` · `apple-pay-unsupported` · `wallet` ·
89
+ `activation` · `screen-on-page` · `screen-handoff` · `screen-undeclared` ·
90
+ `screen-unknown`
89
91
 
90
92
  Adding a member is a breaking change for hosts, deliberately: a scenario needing
91
93
  a store nobody can build is a scenario that silently never runs.
92
94
 
95
+ `wallet` (added for FUT-183/FUT-478) is one of two members that are **not a
96
+ checkout**: `open(page, 'wallet')` must land the buyer on the package's
97
+ manage-cards surface (`screens.ManageCards` from `createPaymentFlows`) at a
98
+ store whose single provider can vault — the chain head declares the adapter
99
+ `vault` seam, the connection runs in stub mode, and the wallet starts empty.
100
+ The journey types the shared `DECLINE_PAN` for the refusal path, so no store
101
+ flag decides the outcome; the card does. Hosts upgrading across this version
102
+ must add the member to their `open` mapping or their world stops compiling —
103
+ which is the point.
104
+
105
+ `activation` (added for FUT-689) is the other, and the first **admin**-side
106
+ shape: `open(page, 'activation')` must land the OWNER on the settings panel of
107
+ one provider that declares `activationCharge`, connected in stub mode and
108
+ never charged — the sales switch starts locked off. The host's
109
+ `renderVerification` slot must render the shared card form plus the
110
+ `activation-*` test ids `src/steps/activation.steps.ts` documents (pay button,
111
+ outcome, refund line, and the raw enable-attempt probe pair). As in `wallet`,
112
+ the typed card decides the outcome: `DECLINE_PAN` is refused with a named
113
+ reason, anything else pays the cent and gets it refunded.
114
+
93
115
  ## Why this package ships compiled JavaScript
94
116
 
95
117
  Its siblings export raw `.ts` through their `exports` map, because an
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=activation.steps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activation.steps.d.ts","sourceRoot":"","sources":["../../src/steps/activation.steps.ts"],"names":[],"mappings":""}
@@ -0,0 +1,74 @@
1
+ import { expect } from '@playwright/test';
2
+ import { DECLINE_PAN, fillCard, fillCpf } from '../helpers/checkout.js';
3
+ import { paymentsWorld } from '../world.js';
4
+ import { Given, Then, When } from './fixtures.js';
5
+ /**
6
+ * ACTIVATING A PROVIDER (FUT-463, made real for every SDK provider by
7
+ * FUT-689) — the merchant admin's side of the till.
8
+ *
9
+ * The package renders the switch and its lock (`payments-enabled-toggle`,
10
+ * `payments-enable-hint`, `payments-status`); the activation step itself is
11
+ * HOST-owned, rendered into the `renderVerification` slot. So these steps
12
+ * read two vocabularies:
13
+ *
14
+ * - the package's own test ids, which mean the same thing in any host;
15
+ * - the activation-step contract a host's slot must render — the shared
16
+ * card form (`card-number`…, `buyer-cpf`) plus `activation-pay`,
17
+ * `activation-result`, `activation-refunded`, `activation-error`, and the
18
+ * fixture probe pair `activation-enable-attempt` /
19
+ * `activation-enable-refusal` (a raw enable request and the refusal it
20
+ * gets, the same affordance the wire probe is).
21
+ *
22
+ * The card the owner types decides the outcome, exactly as in the wallet
23
+ * journey: the shared `DECLINE_PAN` is refused with a named reason, any other
24
+ * valid card pays the cent and gets it back.
25
+ */
26
+ /** The "Recebendo vendas" switch — MUI puts the state on the inner checkbox. */
27
+ function salesSwitch(page) {
28
+ return page.getByTestId('payments-enabled-toggle').getByRole('checkbox');
29
+ }
30
+ Given('the owner opens the settings of a connected but unproven provider', async ({ page }) => {
31
+ await paymentsWorld().open(page, 'activation');
32
+ });
33
+ Then('the sales switch is locked off until a real charge lands', async ({ page }) => {
34
+ await expect(salesSwitch(page)).toBeDisabled();
35
+ // The package's own lock hint — the quoted words are its pt-BR product copy.
36
+ await expect(page.getByTestId('payments-enable-hint')).toContainText('depois dos 3 passos');
37
+ });
38
+ When('the owner tries to force the provider on anyway', async ({ page }) => {
39
+ await page.getByTestId('activation-enable-attempt').click();
40
+ });
41
+ Then('the enable request is refused as unproven', async ({ page }) => {
42
+ // The package's own refusal, by name: the server said no, not the screen.
43
+ await expect(page.getByTestId('activation-enable-refusal')).toContainText('409');
44
+ await expect(page.getByTestId('activation-enable-refusal')).toContainText('UnprovenProviderError');
45
+ });
46
+ When('the owner pays the verification charge with their card', async ({ page }) => {
47
+ await fillCard(page);
48
+ await fillCpf(page);
49
+ await page.getByTestId('activation-pay').click();
50
+ });
51
+ When('the owner pays the verification charge with a refused card', async ({ page }) => {
52
+ await fillCard(page, DECLINE_PAN);
53
+ await fillCpf(page);
54
+ await page.getByTestId('activation-pay').click();
55
+ });
56
+ Then('the provider is proven and receiving sales', async ({ page }) => {
57
+ // VERIFICADO is reserved for a landed charge — the chip's one green word.
58
+ await expect(page.getByTestId('payments-status')).toHaveText('VERIFICADO');
59
+ await expect(salesSwitch(page)).toBeChecked();
60
+ });
61
+ Then('the screen says the cent came back', async ({ page }) => {
62
+ // The refund fact, in the screen's own pt-BR copy.
63
+ await expect(page.getByTestId('activation-refunded')).toContainText('estornado');
64
+ });
65
+ Then("the refusal names the provider's reason", async ({ page }) => {
66
+ await expect(page.getByTestId('activation-error')).toContainText('recusada');
67
+ await expect(page.getByTestId('activation-error')).toContainText('CARD_DECLINED');
68
+ });
69
+ Then('the provider received each attempt as its own charge', async ({ page }) => {
70
+ // Two charges REACHED the provider: a retry that replayed the first
71
+ // refusal would have left this at one.
72
+ await expect(paymentsWorld().wire.providerChargeCount(page)).toHaveText('2');
73
+ });
74
+ //# sourceMappingURL=activation.steps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activation.steps.js","sourceRoot":"","sources":["../../src/steps/activation.steps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=saved-card-wallet.steps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"saved-card-wallet.steps.d.ts","sourceRoot":"","sources":["../../src/steps/saved-card-wallet.steps.ts"],"names":[],"mappings":""}
@@ -0,0 +1,65 @@
1
+ import { expect } from '@playwright/test';
2
+ import { DECLINE_PAN, fillCard } from '../helpers/checkout.js';
3
+ import { paymentsWorld } from '../world.js';
4
+ import { Given, Then, When } from './fixtures.js';
5
+ /**
6
+ * SAVING A CARD WITHOUT BUYING (FUT-183, over FUT-478's buyer vault rows).
7
+ *
8
+ * A separate file from `carteira.steps.ts` on purpose: that one is the DIGITAL
9
+ * wallets (Google Pay / Apple Pay) — a faster way to pay inside checkout.
10
+ * These steps are the SAVED-CARD wallet: the package's manage-cards surface,
11
+ * reached outside any purchase, where nothing is charged at all.
12
+ *
13
+ * Every Then reads a test id the package's own vault screens render
14
+ * (`manage-cards*`, `add-card*`), plus the shared card form ids — so the
15
+ * journey means the same thing in any host that mounts `screens.ManageCards`.
16
+ * The card the buyer types decides the outcome: the shared `DECLINE_PAN` is
17
+ * the one the stub refuses at validation.
18
+ */
19
+ Given("the shopper opens the store's card wallet", async ({ page }) => {
20
+ await paymentsWorld().open(page, 'wallet');
21
+ });
22
+ When('she decides to add a card', async ({ page }) => {
23
+ await page.getByTestId('manage-cards-add').click();
24
+ // Wait for the FORM, not merely the click: `/cards/begin` runs in between,
25
+ // and typing into a form that has not mounted is the flake this avoids.
26
+ await expect(page.getByTestId('add-card')).toBeVisible();
27
+ });
28
+ When('she fills in the card and saves it', async ({ page }) => {
29
+ await fillCard(page);
30
+ await page.getByTestId('add-card-save').click();
31
+ });
32
+ When('she tries to save a refused card', async ({ page }) => {
33
+ await fillCard(page, DECLINE_PAN);
34
+ await page.getByTestId('add-card-save').click();
35
+ });
36
+ Then('the card is stored and appears in the list', async ({ page }) => {
37
+ await expect(page.getByTestId('add-card-saved')).toBeVisible();
38
+ await expect(page.getByTestId('manage-cards-list')).toBeVisible();
39
+ await expect(page.getByTestId('manage-cards-empty')).toHaveCount(0);
40
+ });
41
+ Then('the list shows only the brand and the last digits', async ({ page }) => {
42
+ // Display metadata ONLY. The vault token — the thing that can charge —
43
+ // never reaches this screen; what she reads back is brand + last4 + expiry.
44
+ // The quoted strings are the screen's pt-BR product copy, asserted as-is.
45
+ const list = page.getByTestId('manage-cards-list');
46
+ await expect(list).toContainText('••••');
47
+ await expect(list).toContainText('Validade');
48
+ });
49
+ Then('the refusal explains why and the form stays on screen', async ({ page }) => {
50
+ // The endpoint's own reason, and the form kept editable under it — wiping
51
+ // her input to say the card was refused would be the screen working
52
+ // against her. The asserted word is the pt-BR product copy of the reason.
53
+ await expect(page.getByTestId('add-card-error')).toBeVisible();
54
+ await expect(page.getByTestId('add-card-error')).toContainText('cartão');
55
+ await expect(page.getByTestId('card-number')).toBeVisible();
56
+ });
57
+ Then('the wallet still holds no card', async ({ page }) => {
58
+ await expect(page.getByTestId('manage-cards-empty')).toBeVisible();
59
+ await expect(page.getByTestId('manage-cards-list')).toHaveCount(0);
60
+ });
61
+ Then('the empty wallet invites saving the first card', async ({ page }) => {
62
+ await expect(page.getByTestId('manage-cards-empty')).toBeVisible();
63
+ await expect(page.getByTestId('manage-cards-add')).toBeVisible();
64
+ });
65
+ //# sourceMappingURL=saved-card-wallet.steps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"saved-card-wallet.steps.js","sourceRoot":"","sources":["../../src/steps/saved-card-wallet.steps.ts"],"names":[],"mappings":"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"}
package/dist/world.d.ts CHANGED
@@ -76,6 +76,26 @@ export type PaymentsStore =
76
76
  * fallback rule — no button, and the card form stays the way to pay.
77
77
  */
78
78
  | 'apple-pay-unsupported'
79
+ /**
80
+ * The buyer's saved-card WALLET (FUT-183 over FUT-478), not a checkout: the
81
+ * host opens the package's manage-cards surface at a store whose provider
82
+ * can vault — one mintable chain entry with the vault seam, connected in
83
+ * stub mode — and the wallet starts EMPTY. The card the buyer types decides
84
+ * the outcome: the package's `DECLINE_PAN` is refused at validation, any
85
+ * other valid card is stored. (Not a digital wallet — those are the
86
+ * `google-pay` / `apple-pay` shapes above.)
87
+ */
88
+ | 'wallet'
89
+ /**
90
+ * A merchant ADMIN surface, not a checkout (FUT-463/FUT-689): the settings
91
+ * screen of ONE provider that declares the activation charge, connected in
92
+ * stub mode and never charged — so the sales switch starts locked off. The
93
+ * host lands the owner on that provider's own panel, whose host-rendered
94
+ * activation step shows the shared card form (`card-number`…, `buyer-cpf`)
95
+ * plus the `activation-*` test ids the steps file documents. The card the
96
+ * owner types decides the outcome, exactly as in the `wallet` shape.
97
+ */
98
+ | 'activation'
79
99
  /** Declares the on-page screen (FUT-596). */
80
100
  | 'screen-on-page'
81
101
  /** Declares the hand-off screen (FUT-596). */
@@ -1 +1 @@
1
- {"version":3,"file":"world.d.ts","sourceRoot":"","sources":["../src/world.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"world.d.ts","sourceRoot":"","sources":["../src/world.ts"],"names":[],"mappings":"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"}
package/dist/world.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"world.js","sourceRoot":"","sources":["../src/world.ts"],"names":[],"mappings":"AAsJA,IAAI,SAAS,GAAyB,IAAI,CAAC;AAE3C;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAoB;IACtD,SAAS,GAAG,KAAK,CAAC;AACpB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,0EAA0E;YACxE,0EAA0E,CAC7E,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"world.js","sourceRoot":"","sources":["../src/world.ts"],"names":[],"mappings":"AA0KA,IAAI,SAAS,GAAyB,IAAI,CAAC;AAE3C;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAoB;IACtD,SAAS,GAAG,KAAK,CAAC;AACpB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,0EAA0E;YACxE,0EAA0E,CAC7E,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,29 @@
1
+ @journey @activation
2
+ Feature: Activating a provider
3
+
4
+ "Connected" and "can charge" are different facts, and the gap between them
5
+ is where a store ships broken: credentials authenticate, the switch flips,
6
+ and the first real shopper is refused. So a provider that declares the
7
+ activation charge EARNS its switch — one cent through the owner's own card,
8
+ on the same rails a shopper's money takes, refunded on the spot — and stays
9
+ off until that cent has landed.
10
+
11
+ Background:
12
+ Given the owner opens the settings of a connected but unproven provider
13
+
14
+ Scenario: Enabling without proof is refused
15
+ Then the sales switch is locked off until a real charge lands
16
+ When the owner tries to force the provider on anyway
17
+ Then the enable request is refused as unproven
18
+
19
+ Scenario: Paying the one-cent verification enables the provider
20
+ When the owner pays the verification charge with their card
21
+ Then the provider is proven and receiving sales
22
+ And the screen says the cent came back
23
+
24
+ Scenario: A refused card names the reason and a retry is a fresh charge
25
+ When the owner pays the verification charge with a refused card
26
+ Then the refusal names the provider's reason
27
+ When the owner pays the verification charge with their card
28
+ Then the provider is proven and receiving sales
29
+ And the provider received each attempt as its own charge
@@ -0,0 +1,29 @@
1
+ @journey @saved-cards
2
+ Feature: Saving a card without buying
3
+
4
+ Saving a card is not buying: no order exists, nothing is charged, and the
5
+ card still travels its usual path — the browser mints the token and the
6
+ provider validates it. What the shopper reads back is only what is fit to
7
+ show: the brand and the last digits. The token that can charge stays on the
8
+ store's side and never reaches this screen.
9
+
10
+ There is deliberately no delete button here: taking a card off the list is
11
+ between the store and the provider, not a tap on this screen.
12
+
13
+ Background:
14
+ Given the shopper opens the store's card wallet
15
+
16
+ Scenario: Saving a card without buying anything
17
+ When she decides to add a card
18
+ And she fills in the card and saves it
19
+ Then the card is stored and appears in the list
20
+ And the list shows only the brand and the last digits
21
+
22
+ Scenario: A card refused at validation explains why and stays off the list
23
+ When she decides to add a card
24
+ And she tries to save a refused card
25
+ Then the refusal explains why and the form stays on screen
26
+ And the wallet still holds no card
27
+
28
+ Scenario: The empty wallet invites saving the first card
29
+ Then the empty wallet invites saving the first card
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/payments-e2e",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "type": "module",
5
5
  "description": "The payments buyer journeys, as Gherkin a host runs against its own app",
6
6
  "repository": {