frames-react-native 1.2.5 → 1.2.6
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/package.json +7 -10
- package/.github/workflows/cd.yml +0 -42
- package/.github/workflows/ci.yml +0 -15
- package/__mocks__/fileTransformer.js +0 -9
- package/__tests__/CardUtils.test.tsx +0 -43
- package/__tests__/FramesContextGuards.test.tsx +0 -30
- package/__tests__/HttpAndLogger.test.tsx +0 -204
- package/__tests__/Integration.test.tsx +0 -232
- package/__tests__/Unit.test.tsx +0 -60
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frames-react-native",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.6",
|
|
4
4
|
"description": "Frames React Native",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,9 +10,11 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"creditcards": "^4.2.0",
|
|
13
|
-
"creditcards-types": "^3.2.0"
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
"creditcards-types": "^3.2.0"
|
|
14
|
+
},
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"react": ">=16.8.0",
|
|
17
|
+
"react-native": ">=0.60.0"
|
|
16
18
|
},
|
|
17
19
|
"keywords": [],
|
|
18
20
|
"author": "",
|
|
@@ -21,21 +23,16 @@
|
|
|
21
23
|
"@babel/cli": "^7.0.0",
|
|
22
24
|
"@babel/core": ">=7.23.2",
|
|
23
25
|
"@babel/preset-react": "^7.12.13",
|
|
24
|
-
"@testing-library/jest-dom": "^
|
|
26
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
25
27
|
"@testing-library/jest-native": "3.3.0",
|
|
26
28
|
"@testing-library/react-native": "^7.1.0",
|
|
27
29
|
"@types/jest": "^26.0.20",
|
|
28
|
-
"@types/node-fetch": "^2.5.8",
|
|
29
30
|
"@types/react": "^18.2.75",
|
|
30
31
|
"@types/react-test-renderer": "^18.0.7",
|
|
31
|
-
"@types/uuid": "^9.0.1",
|
|
32
|
-
"babel-preset-expo": "^11.0.0",
|
|
33
32
|
"jest": ">=29.7.0",
|
|
34
|
-
"jest-expo": "^53.0.0",
|
|
35
33
|
"react": "~18.2.0",
|
|
36
34
|
"react-native": "~0.73.6",
|
|
37
35
|
"react-test-renderer": "18.2.0",
|
|
38
|
-
"ts-jest": "^29.1.2",
|
|
39
36
|
"typescript": "~5.4.4"
|
|
40
37
|
},
|
|
41
38
|
"jest": {
|
package/.github/workflows/cd.yml
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
name: Test and Deploy
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
|
-
pull_request:
|
|
8
|
-
branches:
|
|
9
|
-
- main
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
test-and-coverage:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- uses: actions/checkout@v4
|
|
16
|
-
- uses: actions/setup-node@v4
|
|
17
|
-
with:
|
|
18
|
-
node-version: 21
|
|
19
|
-
- run: npm ci
|
|
20
|
-
- run: npm test
|
|
21
|
-
- name: Upload coverage to Codecov
|
|
22
|
-
uses: codecov/codecov-action@v1
|
|
23
|
-
with:
|
|
24
|
-
token: ${{ secrets.CODECOV_TOKEN }}
|
|
25
|
-
verbose: true
|
|
26
|
-
|
|
27
|
-
publish-npm:
|
|
28
|
-
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
|
29
|
-
needs: test-and-coverage
|
|
30
|
-
runs-on: ubuntu-latest
|
|
31
|
-
steps:
|
|
32
|
-
- uses: actions/checkout@v4
|
|
33
|
-
- uses: actions/setup-node@v4
|
|
34
|
-
with:
|
|
35
|
-
node-version: 21
|
|
36
|
-
registry-url: https://registry.npmjs.org/
|
|
37
|
-
- run: npm ci
|
|
38
|
-
- run: npm run build
|
|
39
|
-
- run: cp -R src/icons dist/
|
|
40
|
-
- run: npm publish
|
|
41
|
-
env:
|
|
42
|
-
NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}}
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
name: CI Tests
|
|
2
|
-
|
|
3
|
-
on: [push, pull_request]
|
|
4
|
-
|
|
5
|
-
jobs:
|
|
6
|
-
test:
|
|
7
|
-
runs-on: ubuntu-latest
|
|
8
|
-
steps:
|
|
9
|
-
- uses: actions/checkout@master
|
|
10
|
-
- uses: actions/checkout@v4
|
|
11
|
-
- uses: actions/setup-node@v4
|
|
12
|
-
with:
|
|
13
|
-
node-version: 21
|
|
14
|
-
- run: npm ci
|
|
15
|
-
- run: npm test
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
formatCard,
|
|
3
|
-
getCardType,
|
|
4
|
-
getIcon,
|
|
5
|
-
isValidCard,
|
|
6
|
-
cvvLength,
|
|
7
|
-
isValidCvv,
|
|
8
|
-
isValidDate,
|
|
9
|
-
} from "../src/utils/card";
|
|
10
|
-
|
|
11
|
-
describe("card utils", () => {
|
|
12
|
-
it("formats and validates card number", () => {
|
|
13
|
-
expect(formatCard("4242424242424242")).toBe("4242 4242 4242 4242");
|
|
14
|
-
expect(isValidCard("4242 4242 4242 4242")).toBe(true);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it("detects card type including extended whitelist (Discover)", () => {
|
|
18
|
-
expect(getCardType("6011111111111117")).toBe("Discover");
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("cvvLength varies by type (Amex -> 4)", () => {
|
|
22
|
-
// Amex test number
|
|
23
|
-
const amex = "378282246310005";
|
|
24
|
-
expect(cvvLength(amex)).toBe(4);
|
|
25
|
-
expect(cvvLength("4242 4242 4242 4242")).toBe(3);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("validates cvv by inferred type", () => {
|
|
29
|
-
// Amex 4-digit CVC (It's an AMEX Test card number)
|
|
30
|
-
expect(isValidCvv("1234", "345678901234564")).toBe(true);
|
|
31
|
-
// Visa 3-digit CVC
|
|
32
|
-
expect(isValidCvv("123", "4242 4242 4242 4242")).toBe(true);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("getIcon returns undefined for unknown type", () => {
|
|
36
|
-
// @ts-ignore
|
|
37
|
-
expect(getIcon("UnknownBrand")).toBeUndefined();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it("isValidDate rejects incomplete or past dates", () => {
|
|
41
|
-
expect(isValidDate("06/")).toBe(false);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { render } from "@testing-library/react-native";
|
|
3
|
-
|
|
4
|
-
import { CardNumber, ExpiryDate, Cvv, SubmitButton } from "../src/index";
|
|
5
|
-
|
|
6
|
-
describe("Component context guards", () => {
|
|
7
|
-
it("throws when CardNumber is rendered outside Frames", () => {
|
|
8
|
-
expect(() => render(<CardNumber />)).toThrow(
|
|
9
|
-
"It looks like you are trying to render the CardNumber outside of the Frames Component."
|
|
10
|
-
);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it("throws when ExpiryDate is rendered outside Frames", () => {
|
|
14
|
-
expect(() => render(<ExpiryDate />)).toThrow(
|
|
15
|
-
"It looks like you are trying to render the ExpiryDate outside of the Frames Component."
|
|
16
|
-
);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it("throws when Cvv is rendered outside Frames", () => {
|
|
20
|
-
expect(() => render(<Cvv />)).toThrow(
|
|
21
|
-
"It looks like you are trying to render the Cvv outside of the Frames Component."
|
|
22
|
-
);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("throws when SubmitButton is rendered outside Frames", () => {
|
|
26
|
-
expect(() => render(<SubmitButton title="Pay" />)).toThrow(
|
|
27
|
-
"It looks like you are trying to render the SubmitButton outside of the Frames Component."
|
|
28
|
-
);
|
|
29
|
-
});
|
|
30
|
-
});
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { render, fireEvent, waitFor } from "@testing-library/react-native";
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
Frames,
|
|
6
|
-
CardNumber,
|
|
7
|
-
ExpiryDate,
|
|
8
|
-
Cvv,
|
|
9
|
-
SubmitButton,
|
|
10
|
-
} from "../src/index";
|
|
11
|
-
|
|
12
|
-
import { SANDBOX_LOGGER, LIVE_LOGGER } from "../src/utils/constants";
|
|
13
|
-
|
|
14
|
-
describe("http.tokenize and helpers", () => {
|
|
15
|
-
const { tokenize, formatDataForTokenization, getEnvironment } =
|
|
16
|
-
jest.requireActual("../src/utils/http");
|
|
17
|
-
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
// @ts-ignore
|
|
20
|
-
global.fetch = jest.fn();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it("tokenize returns json when response ok", async () => {
|
|
24
|
-
// @ts-ignore
|
|
25
|
-
global.fetch.mockResolvedValueOnce({
|
|
26
|
-
ok: true,
|
|
27
|
-
json: jest.fn().mockResolvedValue({ ok: true }),
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
const res = await tokenize({
|
|
31
|
-
key: "pk_sbox_dummy",
|
|
32
|
-
body: {
|
|
33
|
-
type: "card",
|
|
34
|
-
number: "4242424242424242",
|
|
35
|
-
expiry_month: "12",
|
|
36
|
-
expiry_year: "2030",
|
|
37
|
-
cvv: "123",
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
expect(res).toEqual({ ok: true });
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it("tokenize throws json when response not ok", async () => {
|
|
45
|
-
// @ts-ignore
|
|
46
|
-
global.fetch.mockResolvedValueOnce({
|
|
47
|
-
ok: false,
|
|
48
|
-
json: jest.fn().mockResolvedValue({ error: "bad" }),
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
await expect(
|
|
52
|
-
tokenize({
|
|
53
|
-
key: "pk_sbox_dummy",
|
|
54
|
-
body: {
|
|
55
|
-
type: "card",
|
|
56
|
-
number: "4242424242424242",
|
|
57
|
-
expiry_month: "12",
|
|
58
|
-
expiry_year: "2030",
|
|
59
|
-
cvv: "123",
|
|
60
|
-
},
|
|
61
|
-
})
|
|
62
|
-
).rejects.toEqual({ error: "bad" });
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it("formatDataForTokenization maps fields and billing address including addressLine2", () => {
|
|
66
|
-
const { EXPIRY_DATE_DELIMITER } = require("../src/utils/constants");
|
|
67
|
-
const state = {
|
|
68
|
-
cardNumber: "4242 4242 4242 4242",
|
|
69
|
-
cardBin: { bin: null, scheme: null },
|
|
70
|
-
cardIcon: undefined,
|
|
71
|
-
cardType: null,
|
|
72
|
-
expiryDate: `12${EXPIRY_DATE_DELIMITER}30`,
|
|
73
|
-
cvv: "123",
|
|
74
|
-
cvvLength: 3,
|
|
75
|
-
validation: { cardNumber: true, expiryDate: true, cvv: true, card: true },
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const config = {
|
|
79
|
-
publicKey: "pk_sbox_dummy",
|
|
80
|
-
cardholder: {
|
|
81
|
-
name: "John Doe",
|
|
82
|
-
phone: "+1234567890",
|
|
83
|
-
billingAddress: {
|
|
84
|
-
addressLine1: "Line 1",
|
|
85
|
-
addressLine2: "Line 2",
|
|
86
|
-
city: "City",
|
|
87
|
-
state: "ST",
|
|
88
|
-
zip: "12345",
|
|
89
|
-
country: "US",
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const params = formatDataForTokenization(state, config);
|
|
95
|
-
expect(params.key).toBe(config.publicKey);
|
|
96
|
-
expect(params.body.number).toBe("4242424242424242");
|
|
97
|
-
expect(params.body.expiry_month).toBe("12");
|
|
98
|
-
expect(params.body.expiry_year).toMatch(/^20\d{2}$/);
|
|
99
|
-
expect(params.body.cvv).toBe("123");
|
|
100
|
-
expect(params.body.name).toBe("John Doe");
|
|
101
|
-
expect(params.body.billing_address).toEqual({
|
|
102
|
-
address_line1: "Line 1",
|
|
103
|
-
address_line2: "Line 2",
|
|
104
|
-
city: "City",
|
|
105
|
-
state: "ST",
|
|
106
|
-
zip: "12345",
|
|
107
|
-
country: "US",
|
|
108
|
-
});
|
|
109
|
-
expect(params.body.phone).toEqual({ number: "+1234567890" });
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it("formatDataForTokenization sets billing_address to null when not provided", () => {
|
|
113
|
-
const state = {
|
|
114
|
-
cardNumber: "4242 4242 4242 4242",
|
|
115
|
-
cardBin: { bin: null, scheme: null },
|
|
116
|
-
cardIcon: undefined,
|
|
117
|
-
cardType: null,
|
|
118
|
-
expiryDate: "12/30",
|
|
119
|
-
cvv: "123",
|
|
120
|
-
cvvLength: 3,
|
|
121
|
-
validation: { cardNumber: true, expiryDate: true, cvv: true, card: true },
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const config = {
|
|
125
|
-
publicKey: "pk_sbox_dummy",
|
|
126
|
-
cardholder: { name: "John Doe" },
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const params = formatDataForTokenization(state, config);
|
|
130
|
-
// @ts-ignore
|
|
131
|
-
expect(params.body.billing_address).toBeNull();
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it("getEnvironment returns expected token URL", () => {
|
|
135
|
-
expect(getEnvironment("pk_sbox_dummy")).toBe(
|
|
136
|
-
"https://api.sandbox.checkout.com/tokens"
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
describe("logger.log", () => {
|
|
142
|
-
const { log, getEnvironment } = require("../src/utils/logger");
|
|
143
|
-
|
|
144
|
-
beforeEach(() => {
|
|
145
|
-
// @ts-ignore
|
|
146
|
-
global.fetch = jest.fn().mockResolvedValue({});
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it("posts to sandbox logger with structured body", async () => {
|
|
150
|
-
await log("info", "type_event", { publicKey: "pk_sbox_dummy" }, { a: 1 });
|
|
151
|
-
|
|
152
|
-
expect(global.fetch).toHaveBeenCalledWith(
|
|
153
|
-
SANDBOX_LOGGER,
|
|
154
|
-
expect.anything()
|
|
155
|
-
);
|
|
156
|
-
const [, options] = (global.fetch as jest.Mock).mock.calls[0];
|
|
157
|
-
const body = JSON.parse(options.body);
|
|
158
|
-
expect(body.specversion).toBe("1.0");
|
|
159
|
-
expect(body.type).toBe("type_event");
|
|
160
|
-
expect(body.data.environment).toBe("sandbox");
|
|
161
|
-
expect(body.cko.loglevel).toBe("info");
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it("getEnvironment returns live logger for prod keys", () => {
|
|
165
|
-
expect(getEnvironment("pk_4296fd52-efba-4a38-b6ce-cf0d93639d8a")).toBe(
|
|
166
|
-
LIVE_LOGGER
|
|
167
|
-
);
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
describe("Frames error path on tokenization failure", () => {
|
|
172
|
-
it("emits cardTokenizationFailed when tokenization rejects", async () => {
|
|
173
|
-
const httpMod = require("../src/utils/http");
|
|
174
|
-
jest.spyOn(httpMod, "tokenize").mockRejectedValueOnce({ error: "failure" });
|
|
175
|
-
|
|
176
|
-
const { Frames } = require("../src/index");
|
|
177
|
-
|
|
178
|
-
const cardTokenizationFailed = jest.fn();
|
|
179
|
-
|
|
180
|
-
const screen = render(
|
|
181
|
-
<Frames
|
|
182
|
-
config={{ publicKey: "pk_sbox_dummy", debug: true }}
|
|
183
|
-
cardTokenizationFailed={cardTokenizationFailed}
|
|
184
|
-
>
|
|
185
|
-
<CardNumber />
|
|
186
|
-
<ExpiryDate />
|
|
187
|
-
<Cvv />
|
|
188
|
-
<SubmitButton title="Pay" />
|
|
189
|
-
</Frames>
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
fireEvent.changeText(
|
|
193
|
-
screen.getByPlaceholderText("•••• •••• •••• ••••"),
|
|
194
|
-
"4242 4242 4242 4242"
|
|
195
|
-
);
|
|
196
|
-
fireEvent.changeText(screen.getByPlaceholderText("MM/YY"), "12/30");
|
|
197
|
-
fireEvent.changeText(screen.getByPlaceholderText("•••"), "123");
|
|
198
|
-
|
|
199
|
-
fireEvent.press(screen.getByText("Pay"));
|
|
200
|
-
|
|
201
|
-
await waitFor(() => expect(cardTokenizationFailed).toHaveBeenCalled());
|
|
202
|
-
expect(cardTokenizationFailed).toHaveBeenCalledWith({ error: "failure" });
|
|
203
|
-
});
|
|
204
|
-
});
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
import React, { createRef } from "react";
|
|
2
|
-
import { render, fireEvent, waitFor } from "@testing-library/react-native";
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
Frames,
|
|
6
|
-
CardNumber,
|
|
7
|
-
ExpiryDate,
|
|
8
|
-
Cvv,
|
|
9
|
-
SubmitButton,
|
|
10
|
-
} from "../src/index";
|
|
11
|
-
import type { FramesRef } from "../src/index";
|
|
12
|
-
|
|
13
|
-
// Mock network-dependent modules to avoid real HTTP requests
|
|
14
|
-
jest.mock("../src/utils/http", () => {
|
|
15
|
-
const actual = jest.requireActual("../src/utils/http");
|
|
16
|
-
return {
|
|
17
|
-
...actual,
|
|
18
|
-
tokenize: jest.fn(),
|
|
19
|
-
};
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
jest.mock("../src/utils/logger", () => {
|
|
23
|
-
const actual = jest.requireActual("../src/utils/logger");
|
|
24
|
-
return {
|
|
25
|
-
...actual,
|
|
26
|
-
log: jest.fn(),
|
|
27
|
-
};
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
describe("Frames integration", () => {
|
|
31
|
-
const validVisa = "4242 4242 4242 4242"; // Visa test number
|
|
32
|
-
const validExpiry = "12/30"; // future year
|
|
33
|
-
const validCvv = "123";
|
|
34
|
-
|
|
35
|
-
const config = {
|
|
36
|
-
publicKey: "pk_sbox_eo3yb3urja2ozf6ycgn5kuy7ke#",
|
|
37
|
-
debug: true,
|
|
38
|
-
cardholder: {
|
|
39
|
-
name: "John Doe",
|
|
40
|
-
phone: "+1234567890",
|
|
41
|
-
billingAddress: {
|
|
42
|
-
addressLine1: "123 Test St",
|
|
43
|
-
city: "Test City",
|
|
44
|
-
state: "TS",
|
|
45
|
-
zip: "12345",
|
|
46
|
-
country: "US",
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
beforeEach(() => {
|
|
52
|
-
jest.clearAllMocks();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("emits validation and bin events, and tokenizes on submit", async () => {
|
|
56
|
-
const { tokenize } = require("../src/utils/http");
|
|
57
|
-
|
|
58
|
-
const mockTokenResponse = {
|
|
59
|
-
type: "card",
|
|
60
|
-
token: "tok_test_123",
|
|
61
|
-
expires_on: "2030-12-31T23:59:59Z",
|
|
62
|
-
expiry_month: 12,
|
|
63
|
-
expiry_year: 2030,
|
|
64
|
-
scheme: "Visa",
|
|
65
|
-
last4: "4242",
|
|
66
|
-
bin: "424242",
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
tokenize.mockResolvedValueOnce(mockTokenResponse);
|
|
70
|
-
|
|
71
|
-
const frameValidationChanged = jest.fn();
|
|
72
|
-
const paymentMethodChanged = jest.fn();
|
|
73
|
-
const cardValidationChanged = jest.fn();
|
|
74
|
-
const cardTokenized = jest.fn();
|
|
75
|
-
const cardTokenizationFailed = jest.fn();
|
|
76
|
-
const cardBinChanged = jest.fn();
|
|
77
|
-
|
|
78
|
-
const screen = render(
|
|
79
|
-
<Frames
|
|
80
|
-
config={config}
|
|
81
|
-
frameValidationChanged={frameValidationChanged}
|
|
82
|
-
paymentMethodChanged={paymentMethodChanged}
|
|
83
|
-
cardValidationChanged={cardValidationChanged}
|
|
84
|
-
cardTokenized={cardTokenized}
|
|
85
|
-
cardTokenizationFailed={cardTokenizationFailed}
|
|
86
|
-
cardBinChanged={cardBinChanged}
|
|
87
|
-
>
|
|
88
|
-
<CardNumber />
|
|
89
|
-
<ExpiryDate />
|
|
90
|
-
<Cvv />
|
|
91
|
-
<SubmitButton title="Pay" />
|
|
92
|
-
</Frames>
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
const cardNumberInput = screen.getByPlaceholderText("•••• •••• •••• ••••");
|
|
96
|
-
const expiryInput = screen.getByPlaceholderText("MM/YY");
|
|
97
|
-
const cvvInput = screen.getByPlaceholderText("•••");
|
|
98
|
-
|
|
99
|
-
// Enter card number -> should emit bin and payment method changes
|
|
100
|
-
fireEvent.changeText(cardNumberInput, validVisa);
|
|
101
|
-
|
|
102
|
-
await waitFor(() => expect(paymentMethodChanged).toHaveBeenCalled());
|
|
103
|
-
expect(paymentMethodChanged).toHaveBeenCalledWith(
|
|
104
|
-
expect.objectContaining({ paymentMethod: "Visa", isValid: false })
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
await waitFor(() => expect(cardBinChanged).toHaveBeenCalled());
|
|
108
|
-
expect(cardBinChanged).toHaveBeenCalledWith(
|
|
109
|
-
expect.objectContaining({
|
|
110
|
-
bin: expect.stringMatching(/^42424242/),
|
|
111
|
-
scheme: "Visa",
|
|
112
|
-
})
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
// Enter expiry date
|
|
116
|
-
fireEvent.changeText(expiryInput, validExpiry);
|
|
117
|
-
|
|
118
|
-
// Enter cvv
|
|
119
|
-
fireEvent.changeText(cvvInput, validCvv);
|
|
120
|
-
|
|
121
|
-
// After all fields valid, cardValidationChanged should report isValid: true
|
|
122
|
-
await waitFor(() => expect(cardValidationChanged).toHaveBeenCalled());
|
|
123
|
-
expect(cardValidationChanged).toHaveBeenLastCalledWith(
|
|
124
|
-
expect.objectContaining({
|
|
125
|
-
isValid: true,
|
|
126
|
-
isElementValid: expect.objectContaining({
|
|
127
|
-
cardNumber: true,
|
|
128
|
-
expiryDate: true,
|
|
129
|
-
cvv: true,
|
|
130
|
-
}),
|
|
131
|
-
})
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
// Submit and expect tokenization to be called and success event emitted
|
|
135
|
-
const payButton = screen.getByText("Pay");
|
|
136
|
-
fireEvent.press(payButton);
|
|
137
|
-
|
|
138
|
-
await waitFor(() => expect(tokenize).toHaveBeenCalledTimes(1));
|
|
139
|
-
expect(cardTokenized).toHaveBeenCalledWith(mockTokenResponse);
|
|
140
|
-
expect(cardTokenizationFailed).not.toHaveBeenCalled();
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it("allows submitting via Frames ref submitCard()", async () => {
|
|
144
|
-
const { tokenize } = require("../src/utils/http");
|
|
145
|
-
|
|
146
|
-
const mockTokenResponse = {
|
|
147
|
-
type: "card",
|
|
148
|
-
token: "tok_test_ref_123",
|
|
149
|
-
expires_on: "2030-12-31T23:59:59Z",
|
|
150
|
-
expiry_month: 12,
|
|
151
|
-
expiry_year: 2030,
|
|
152
|
-
scheme: "Visa",
|
|
153
|
-
last4: "4242",
|
|
154
|
-
bin: "424242",
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
tokenize.mockResolvedValueOnce(mockTokenResponse);
|
|
158
|
-
|
|
159
|
-
const cardTokenized = jest.fn();
|
|
160
|
-
|
|
161
|
-
const ref = createRef<FramesRef>();
|
|
162
|
-
|
|
163
|
-
const screen = render(
|
|
164
|
-
<Frames config={config} cardTokenized={cardTokenized} ref={ref}>
|
|
165
|
-
<CardNumber />
|
|
166
|
-
<ExpiryDate />
|
|
167
|
-
<Cvv />
|
|
168
|
-
</Frames>
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
const cardNumberInput = screen.getByPlaceholderText("•••• •••• •••• ••••");
|
|
172
|
-
const expiryInput = screen.getByPlaceholderText("MM/YY");
|
|
173
|
-
const cvvInput = screen.getByPlaceholderText("•••");
|
|
174
|
-
|
|
175
|
-
// Fill valid data
|
|
176
|
-
fireEvent.changeText(cardNumberInput, validVisa);
|
|
177
|
-
fireEvent.changeText(expiryInput, validExpiry);
|
|
178
|
-
fireEvent.changeText(cvvInput, validCvv);
|
|
179
|
-
|
|
180
|
-
// Call submit via ref
|
|
181
|
-
await waitFor(async () => {
|
|
182
|
-
expect(ref.current).not.toBeNull();
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
await ref.current!.submitCard();
|
|
186
|
-
|
|
187
|
-
await waitFor(() => expect(tokenize).toHaveBeenCalledTimes(1));
|
|
188
|
-
expect(cardTokenized).toHaveBeenCalledWith(mockTokenResponse);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
it("SubmitButton triggers submitCard and forwards onPress to consumer", async () => {
|
|
192
|
-
const { tokenize } = require("../src/utils/http");
|
|
193
|
-
|
|
194
|
-
const mockTokenResponse = {
|
|
195
|
-
type: "card",
|
|
196
|
-
token: "tok_test_press_123",
|
|
197
|
-
expires_on: "2030-12-31T23:59:59Z",
|
|
198
|
-
expiry_month: 12,
|
|
199
|
-
expiry_year: 2030,
|
|
200
|
-
scheme: "Visa",
|
|
201
|
-
last4: "4242",
|
|
202
|
-
bin: "424242",
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
tokenize.mockResolvedValueOnce(mockTokenResponse);
|
|
206
|
-
|
|
207
|
-
const onPressSpy = jest.fn();
|
|
208
|
-
const cardTokenized = jest.fn();
|
|
209
|
-
|
|
210
|
-
const screen = render(
|
|
211
|
-
<Frames config={config} cardTokenized={cardTokenized}>
|
|
212
|
-
<CardNumber />
|
|
213
|
-
<ExpiryDate />
|
|
214
|
-
<Cvv />
|
|
215
|
-
<SubmitButton title="Pay" onPress={onPressSpy} />
|
|
216
|
-
</Frames>
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
fireEvent.changeText(
|
|
220
|
-
screen.getByPlaceholderText("•••• •••• •••• ••••"),
|
|
221
|
-
validVisa
|
|
222
|
-
);
|
|
223
|
-
fireEvent.changeText(screen.getByPlaceholderText("MM/YY"), validExpiry);
|
|
224
|
-
fireEvent.changeText(screen.getByPlaceholderText("•••"), validCvv);
|
|
225
|
-
|
|
226
|
-
fireEvent.press(screen.getByText("Pay"));
|
|
227
|
-
|
|
228
|
-
await waitFor(() => expect(tokenize).toHaveBeenCalledTimes(1));
|
|
229
|
-
expect(cardTokenized).toHaveBeenCalledWith(mockTokenResponse);
|
|
230
|
-
expect(onPressSpy).toHaveBeenCalledTimes(1);
|
|
231
|
-
});
|
|
232
|
-
});
|
package/__tests__/Unit.test.tsx
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { isValidDate } from "../src/utils/card";
|
|
2
|
-
import { getFormattedDate } from "../src/utils/date";
|
|
3
|
-
import { getEnvironment } from "../src/utils/http";
|
|
4
|
-
import { getEnvironment as loggerGetEnvironment } from "../src/utils/logger";
|
|
5
|
-
|
|
6
|
-
const PK_SB = "pk_sbox_eo3yb3urja2ozf6ycgn5kuy7ke#";
|
|
7
|
-
const PK_PROD = "pk_4296fd52-efba-4a38-b6ce-cf0d93639d8a"; // fake key
|
|
8
|
-
|
|
9
|
-
describe("Date", () => {
|
|
10
|
-
it("formats date", async () => {
|
|
11
|
-
let outcome = isValidDate("06/");
|
|
12
|
-
expect(outcome).toBe(false);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it("adds 0 for date values", async () => {
|
|
16
|
-
let outcome = getFormattedDate("6");
|
|
17
|
-
expect(outcome).toBe("06/");
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it("allows leading 0 for date values", async () => {
|
|
21
|
-
let outcome = getFormattedDate("0");
|
|
22
|
-
expect(outcome).toBe("0");
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("ignores other date values", async () => {
|
|
26
|
-
let outcome = getFormattedDate("!");
|
|
27
|
-
expect(outcome).toBe("!");
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe("Environment", () => {
|
|
32
|
-
it("it gets the live environment", async () => {
|
|
33
|
-
let env = getEnvironment(PK_PROD);
|
|
34
|
-
expect(env).toBe("https://api.checkout.com/tokens");
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("gets the sb environment", async () => {
|
|
38
|
-
let env = getEnvironment(PK_SB);
|
|
39
|
-
expect(env).toBe("https://api.sandbox.checkout.com/tokens");
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
describe("Logger Environment", () => {
|
|
44
|
-
it("it gets the live environment", async () => {
|
|
45
|
-
let env = loggerGetEnvironment(PK_PROD);
|
|
46
|
-
expect(env).toBe("https://cloudevents.integration.checkout.com/logging");
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("gets the sb environment", async () => {
|
|
50
|
-
let env = loggerGetEnvironment(PK_SB);
|
|
51
|
-
expect(env).toBe(
|
|
52
|
-
"https://cloudevents.integration.sandbox.checkout.com/logging"
|
|
53
|
-
);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("returns empty", async () => {
|
|
57
|
-
let date = getFormattedDate("");
|
|
58
|
-
expect(date).toBe("");
|
|
59
|
-
});
|
|
60
|
-
});
|