@rebilly/framepay-react 2.0.1 → 2.1.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/.env.example +2 -0
- package/CHANGELOG.md +7 -0
- package/env.js +7 -0
- package/package.json +10 -2
- package/src/index.spec.ts +19 -0
- package/src/index.ts +42 -0
- package/src/lib/components/elements/applepay-element.tsx +36 -0
- package/src/lib/components/elements/bank-element.spec.tsx +119 -0
- package/src/lib/components/elements/bank-element.tsx +74 -0
- package/src/lib/components/elements/base-element.tsx +100 -0
- package/src/lib/components/elements/card-element.spec.tsx +113 -0
- package/src/lib/components/elements/card-element.tsx +73 -0
- package/src/lib/components/elements/googlepay-element.tsx +36 -0
- package/src/lib/components/elements/iban-element.spec.tsx +104 -0
- package/src/lib/components/elements/iban-element.tsx +75 -0
- package/src/lib/components/elements/paypal-element.tsx +36 -0
- package/src/lib/components/injector.spec.tsx +162 -0
- package/src/lib/components/injector.tsx +495 -0
- package/src/lib/components/provider.spec.tsx +98 -0
- package/src/lib/components/provider.tsx +111 -0
- package/src/lib/constants.ts +43 -0
- package/src/lib/context.ts +24 -0
- package/src/lib/dom-util.ts +35 -0
- package/src/lib/framepay-error.ts +59 -0
- package/src/lib/get-rebilly-api.ts +11 -0
- package/test/e2e/assets/prop-types.js +849 -0
- package/test/e2e/assets/react-0.14.0.js +18759 -0
- package/test/e2e/assets/react-15.0.0.js +19309 -0
- package/test/e2e/assets/react-16.js +3318 -0
- package/test/e2e/assets/react-17.js +3357 -0
- package/test/e2e/assets/react-18.js +3342 -0
- package/test/e2e/assets/react-dom-0.14.0.js +42 -0
- package/test/e2e/assets/react-dom-15.0.0.js +42 -0
- package/test/e2e/assets/react-dom-16.js +25147 -0
- package/test/e2e/assets/react-dom-17.js +26292 -0
- package/test/e2e/assets/react-dom-18.js +29869 -0
- package/test/e2e/cypress-support.js +2 -0
- package/test/e2e/cypress.d.ts +1 -0
- package/test/e2e/fixtures/apple-pay.html +15 -0
- package/test/e2e/fixtures/apple-pay.js +63 -0
- package/test/e2e/fixtures/bank-separate.html +12 -0
- package/test/e2e/fixtures/bank-separate.js +323 -0
- package/test/e2e/fixtures/card-separate-brands.html +12 -0
- package/test/e2e/fixtures/card-separate-brands.js +260 -0
- package/test/e2e/fixtures/card-separate-rebilly-fields.html +12 -0
- package/test/e2e/fixtures/card-separate-rebilly-fields.js +281 -0
- package/test/e2e/fixtures/card-separate.html +12 -0
- package/test/e2e/fixtures/card-separate.js +227 -0
- package/test/e2e/fixtures/checkout-combined.html +12 -0
- package/test/e2e/fixtures/checkout-combined.js +199 -0
- package/test/e2e/fixtures/google-pay.html +15 -0
- package/test/e2e/fixtures/google-pay.js +63 -0
- package/test/e2e/fixtures/iban.html +12 -0
- package/test/e2e/fixtures/iban.js +239 -0
- package/test/e2e/fixtures/multiple-methods.html +12 -0
- package/test/e2e/fixtures/multiple-methods.js +470 -0
- package/test/e2e/fixtures/nav.js +20 -0
- package/test/e2e/fixtures/paypal.html +15 -0
- package/test/e2e/fixtures/paypal.js +62 -0
- package/test/e2e/fixtures/style.css +55 -0
- package/test/e2e/fixtures/util.js +71 -0
- package/test/e2e/local-server.mjs +12 -0
- package/test/e2e/server.mjs +43 -0
- package/test/e2e/specs/bank-separate.cy.ts +27 -0
- package/test/e2e/specs/card-separate-brands.cy.ts +70 -0
- package/test/e2e/specs/card-separate.cy.ts +27 -0
- package/test/e2e/specs/checkout-combined.cy.ts +24 -0
- package/test/e2e/specs/google-pay.cy.ts +13 -0
- package/test/e2e/specs/iban.cy.ts +17 -0
- package/test/e2e/specs/multiple-methods.cy.ts +130 -0
- package/test/e2e/specs/paypal.cy.ts +13 -0
- package/test/e2e/specs/react-version.cy.ts +12 -0
- package/test/e2e/switch-react-version.js +42 -0
- package/test/e2e/tsconfig.json +8 -0
- package/test/unit/jest.config.js +29 -0
- package/test/unit/specs/declaration-mock.spec.tsx +143 -0
- package/tsconfig.json +31 -0
- package/tsconfig.spec.json +13 -0
- package/tslint.json +36 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import portfinder from 'portfinder';
|
|
5
|
+
import AutoEncryptLocalhost from '@small-tech/auto-encrypt-localhost';
|
|
6
|
+
import HttpServer from '@small-tech/auto-encrypt-localhost/lib/HttpServer.js';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
|
|
9
|
+
// __dirname is not available in esmodules, so we must build it
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
|
|
13
|
+
const app = express();
|
|
14
|
+
|
|
15
|
+
const staticFiles = path.resolve(__dirname, './build');
|
|
16
|
+
|
|
17
|
+
app.use(express.static(staticFiles));
|
|
18
|
+
|
|
19
|
+
const addDirRoutes = (dir, category) => {
|
|
20
|
+
fs.readdirSync(dir)
|
|
21
|
+
.filter(name => !!name.includes('.html'))
|
|
22
|
+
.forEach((name) => {
|
|
23
|
+
const basename = path.basename(name, path.extname(name));
|
|
24
|
+
const url = category ? `/${category}/${basename}` : `/${basename}`;
|
|
25
|
+
app.use(url, express.static(path.resolve(dir, name)));
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
addDirRoutes(path.resolve(__dirname, './build'), '');
|
|
30
|
+
|
|
31
|
+
export default function() {
|
|
32
|
+
return new Promise((resolve) => {
|
|
33
|
+
portfinder.getPort((err, port) => {
|
|
34
|
+
// Do not create a http redirect server
|
|
35
|
+
HttpServer.instance = true;
|
|
36
|
+
|
|
37
|
+
const server = AutoEncryptLocalhost.https.createServer(app);
|
|
38
|
+
server.listen(port);
|
|
39
|
+
console.log(`Running at https://localhost:${port}`);
|
|
40
|
+
resolve({ port, server, app });
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
describe('bank-separate', () => {
|
|
2
|
+
beforeEach(() => {
|
|
3
|
+
cy.visit({ url: '/bank-separate' });
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
it('should load the page', () => {
|
|
7
|
+
cy.title().should('eq', 'Test Bank Page Separate Fields');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should inject the bank iframes into the page', () => {
|
|
11
|
+
cy.get('iframe#bbanAccountType');
|
|
12
|
+
cy.get('iframe#bbanAccountNumber');
|
|
13
|
+
cy.get('iframe#bbanRoutingNumber');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should call the on-ready BankAccountType element hook', () => {
|
|
17
|
+
cy.get('#events-bankAccountType-onReady-true');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should call the on-ready BankAccountNumber element hook', () => {
|
|
21
|
+
cy.get('#events-bankAccountNumber-onReady-true');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should call the on-ready BankRoutingNumber element hook', () => {
|
|
25
|
+
cy.get('#events-bankRoutingNumber-onReady-true');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
describe('card-separate-brands', () => {
|
|
2
|
+
beforeEach(() => {
|
|
3
|
+
cy.visit({ url: '/card-separate-brands' });
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
it('should load the page', () => {
|
|
7
|
+
cy.title().should(
|
|
8
|
+
'eq',
|
|
9
|
+
'Test Card Page Separate Fields allowed Brands'
|
|
10
|
+
);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should inject the card iframes into the page', () => {
|
|
14
|
+
cy.get('iframe#cardNumber');
|
|
15
|
+
cy.get('iframe#cardCvv');
|
|
16
|
+
cy.get('iframe#cardExpiration');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should be call the on-ready card element hook', () => {
|
|
20
|
+
cy.get('#events-number-onReady-true');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should be call the on-ready cvv element hook', () => {
|
|
24
|
+
cy.get('#events-cvv-onReady-true');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should be call the on-ready expiry element hook', () => {
|
|
28
|
+
cy.get('#events-expiry-onReady-true');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should decline the MasterCard by default', () => {
|
|
32
|
+
cy.get('#events-number-onReady-true');
|
|
33
|
+
|
|
34
|
+
cy.iframe('iframe#cardNumber')
|
|
35
|
+
.findByTestId('cardnumber')
|
|
36
|
+
.type('4111 1111 1111 1111');
|
|
37
|
+
|
|
38
|
+
cy.get('#events-number-onChange-error-code-unavailable-card-brand');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should allow the Visa after update and decline after restore', () => {
|
|
42
|
+
cy.iframe('iframe#cardNumber')
|
|
43
|
+
.findByTestId('cardnumber')
|
|
44
|
+
.type('4111 1111 1111 1111');
|
|
45
|
+
|
|
46
|
+
cy.iframe('iframe#cardCvv')
|
|
47
|
+
.findByTestId('cvv')
|
|
48
|
+
.type('123');
|
|
49
|
+
|
|
50
|
+
cy.iframe('iframe#cardExpiration').within(() => {
|
|
51
|
+
const expiry =
|
|
52
|
+
String('0' + (new Date().getMonth() + 1)).substr(-2) +
|
|
53
|
+
String(new Date().getFullYear()).substr(-2);
|
|
54
|
+
|
|
55
|
+
cy.findByTestId('exp-date').type(expiry);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
cy.get('#events-number-onChange-error-code-unavailable-card-brand');
|
|
59
|
+
|
|
60
|
+
cy.get('#btn-update').click();
|
|
61
|
+
|
|
62
|
+
cy.get(
|
|
63
|
+
'#events-number-onChange-error-code-unavailable-card-brand'
|
|
64
|
+
).should('not.exist');
|
|
65
|
+
|
|
66
|
+
cy.get('#btn-restore').click();
|
|
67
|
+
|
|
68
|
+
cy.get('#events-number-onChange-error-code-unavailable-card-brand');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
describe('card-separate', () => {
|
|
2
|
+
beforeEach(() => {
|
|
3
|
+
cy.visit({ url: '/card-separate' });
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
it('should load the page', () => {
|
|
7
|
+
cy.title().should('eq', 'Test Card Page Separate Fields');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should inject the card iframes into the page', () => {
|
|
11
|
+
cy.get('iframe#cardNumber');
|
|
12
|
+
cy.get('iframe#cardCvv');
|
|
13
|
+
cy.get('iframe#cardExpiration');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should be call the on-ready card element hook', () => {
|
|
17
|
+
cy.get('#events-number-onReady-true');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should be call the on-ready cvv element hook', () => {
|
|
21
|
+
cy.get('#events-cvv-onReady-true');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should be call the on-ready expiry element hook', () => {
|
|
25
|
+
cy.get('#events-expiry-onReady-true');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
describe('checkout-combined', () => {
|
|
2
|
+
beforeEach(() => {
|
|
3
|
+
cy.visit({ url: '/checkout-combined' });
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
it('should load the page', () => {
|
|
7
|
+
cy.title().should('eq', 'Test Checkout Page Combined Field');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should inject the card iframe into the page', () => {
|
|
11
|
+
cy.get('iframe#card');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should be call the on-ready hook', () => {
|
|
15
|
+
cy.get('#events-onReady-true');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should call the on-change hook', () => {
|
|
19
|
+
cy.get('#events-onReady-true');
|
|
20
|
+
cy.get('#submit').click();
|
|
21
|
+
cy.get('#key-onChange');
|
|
22
|
+
cy.get('#token-data-code-invalid-payment-card');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
describe('google-pay', () => {
|
|
2
|
+
beforeEach(() => {
|
|
3
|
+
cy.visit({ url: '/google-pay' });
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
it('should load the page', () => {
|
|
7
|
+
cy.title().should('eq', 'Test Google Pay');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should inject the Google pay iframe into the page', () => {
|
|
11
|
+
cy.get('iframe#googlePay');
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
describe('iban', () => {
|
|
2
|
+
beforeEach(() => {
|
|
3
|
+
cy.visit({ url: '/iban' });
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
it('should load the page', () => {
|
|
7
|
+
cy.title().should('eq', 'Test IBAN Field');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should inject the card iframe into the page', () => {
|
|
11
|
+
cy.get('iframe#iban');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should call the on-ready iban element hook', () => {
|
|
15
|
+
cy.get('#events-iban-onReady-true');
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
describe('multiple-methods', () => {
|
|
2
|
+
beforeEach(() => {
|
|
3
|
+
cy.visit({ url: '/multiple-methods' });
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
it('should load the page', () => {
|
|
7
|
+
cy.title().should('eq', 'Test Multiple Methods');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should call the on-ready card element hook', () => {
|
|
11
|
+
cy.get('#events-card-onReady-true');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should init with payment-card method by default', () => {
|
|
15
|
+
cy.get('#events-card-onReady-true');
|
|
16
|
+
cy.get('#events-bankAccountType-onReady-false');
|
|
17
|
+
cy.get('#events-bankAccountNumber-onReady-false');
|
|
18
|
+
cy.get('#events-bankRoutingNumber-onReady-false');
|
|
19
|
+
cy.get('#events-iban-onReady-false');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should load other methods', () => {
|
|
23
|
+
cy.get('#events-card-onReady-true');
|
|
24
|
+
|
|
25
|
+
cy.get('#set-active-element-bank').click();
|
|
26
|
+
|
|
27
|
+
// check other methods are disabled
|
|
28
|
+
cy.get('#events-card-onReady-false');
|
|
29
|
+
cy.get('#events-iban-onReady-false');
|
|
30
|
+
|
|
31
|
+
// check bank is loaded
|
|
32
|
+
cy.get('#events-bankAccountNumber-onReady-true');
|
|
33
|
+
cy.get('#events-bankAccountType-onReady-true');
|
|
34
|
+
cy.get('#events-bankRoutingNumber-onReady-true');
|
|
35
|
+
|
|
36
|
+
// load IBAN
|
|
37
|
+
cy.get('#set-active-element-iban').click();
|
|
38
|
+
|
|
39
|
+
// check other methods are disabled
|
|
40
|
+
cy.get('#events-card-onReady-false');
|
|
41
|
+
cy.get('#events-bankAccountType-onReady-false');
|
|
42
|
+
cy.get('#events-bankAccountNumber-onReady-false');
|
|
43
|
+
cy.get('#events-bankRoutingNumber-onReady-false');
|
|
44
|
+
|
|
45
|
+
// check IBAN is loaded
|
|
46
|
+
cy.get('#events-iban-onReady-true');
|
|
47
|
+
|
|
48
|
+
// load Google Pay
|
|
49
|
+
cy.get('#set-active-element-googlepay').click();
|
|
50
|
+
|
|
51
|
+
// check other methods are disabled
|
|
52
|
+
cy.get('#events-card-onReady-false');
|
|
53
|
+
cy.get('#events-bankAccountType-onReady-false');
|
|
54
|
+
cy.get('#events-bankAccountNumber-onReady-false');
|
|
55
|
+
cy.get('#events-bankRoutingNumber-onReady-false');
|
|
56
|
+
cy.get('#events-iban-onReady-false');
|
|
57
|
+
|
|
58
|
+
// check Google Pay is loaded
|
|
59
|
+
cy.iframe('#googlePay');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should generate the card token', () => {
|
|
63
|
+
cy.get('#events-card-onReady-true');
|
|
64
|
+
|
|
65
|
+
cy.iframe('iframe#card').within(() => {
|
|
66
|
+
const cardNumber = '4111111111111111';
|
|
67
|
+
const expiry =
|
|
68
|
+
String('0' + (new Date().getMonth() + 1)).substr(-2) +
|
|
69
|
+
String(new Date().getFullYear()).substr(-2);
|
|
70
|
+
const cvv = '123';
|
|
71
|
+
|
|
72
|
+
cy.findByTestId('cardnumber').type(cardNumber);
|
|
73
|
+
cy.findByTestId('exp-date').type(expiry);
|
|
74
|
+
cy.findByTestId('cvv').type(cvv);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
cy.get('#submit').click();
|
|
78
|
+
|
|
79
|
+
cy.get('#events-card-onChange-valid-true');
|
|
80
|
+
cy.get('#events-card-onChange-source-card');
|
|
81
|
+
cy.get('#token-error-false');
|
|
82
|
+
cy.get('#token-data-method-payment-card');
|
|
83
|
+
cy.get('#token-data-paymentInstrument-brand-Visa');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should generate the bank token', () => {
|
|
87
|
+
cy.get('#set-active-element-bank').click();
|
|
88
|
+
|
|
89
|
+
cy.get('#events-bankAccountType-onReady-true');
|
|
90
|
+
cy.get('#events-bankAccountNumber-onReady-true');
|
|
91
|
+
cy.get('#events-bankRoutingNumber-onReady-true');
|
|
92
|
+
|
|
93
|
+
cy.iframe('iframe#bbanAccountType')
|
|
94
|
+
.findByTestId('savings')
|
|
95
|
+
.click();
|
|
96
|
+
cy.iframe('iframe#bbanAccountNumber')
|
|
97
|
+
.findByTestId('bbanAccountNumber')
|
|
98
|
+
.type('22222222');
|
|
99
|
+
cy.iframe('iframe#bbanRoutingNumber')
|
|
100
|
+
.findByTestId('bbanRoutingNumber')
|
|
101
|
+
.type('11111111');
|
|
102
|
+
|
|
103
|
+
cy.get('#submit').click();
|
|
104
|
+
|
|
105
|
+
cy.get('#events-bankAccountNumber-onChange-valid-true');
|
|
106
|
+
cy.get('#events-bankAccountNumber-onChange-source-bankAccountNumber');
|
|
107
|
+
cy.get('#events-bankRoutingNumber-onChange-valid-true');
|
|
108
|
+
cy.get('#events-bankRoutingNumber-onChange-source-bankRoutingNumber');
|
|
109
|
+
cy.get('#events-bankAccountType-onChange-valid-true');
|
|
110
|
+
cy.get('#events-bankAccountType-onChange-source-bankAccountType');
|
|
111
|
+
cy.get('#token-error-false');
|
|
112
|
+
cy.get('#token-data-method-ach');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should generate the iban token', () => {
|
|
116
|
+
cy.get('#set-active-element-iban').click();
|
|
117
|
+
|
|
118
|
+
cy.get('#events-iban-onReady-true');
|
|
119
|
+
|
|
120
|
+
cy.iframe('iframe#iban')
|
|
121
|
+
.findByTestId('iban')
|
|
122
|
+
.type('DE89 3704 0044 0532 0130 00');
|
|
123
|
+
|
|
124
|
+
cy.get('#submit').click();
|
|
125
|
+
|
|
126
|
+
cy.get('#events-iban-onChange-valid-true');
|
|
127
|
+
cy.get('#token-error-false');
|
|
128
|
+
cy.get('#token-data-method-ach');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
describe('paypal', () => {
|
|
2
|
+
beforeEach(() => {
|
|
3
|
+
cy.visit({ url: '/paypal' });
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
it('should load the page', () => {
|
|
7
|
+
cy.title().should('eq', 'Test Paypal');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should inject the PayPal iframe into the page', () => {
|
|
11
|
+
cy.get('iframe[title="PayPal"]');
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const pkg = require('../../../package.json');
|
|
2
|
+
const expectedVersion =
|
|
3
|
+
Cypress.env('REACT_VERSION') ?? pkg.devDependencies.react.slice(1);
|
|
4
|
+
|
|
5
|
+
it(`should render with correct react version (${expectedVersion})`, () => {
|
|
6
|
+
cy.visit('/');
|
|
7
|
+
cy.get('#react-version')
|
|
8
|
+
.invoke('text')
|
|
9
|
+
.should(actualVersion => {
|
|
10
|
+
expect(actualVersion.startsWith(expectedVersion)).to.be.true;
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny util to switch react version in test
|
|
3
|
+
*
|
|
4
|
+
* @type {string}
|
|
5
|
+
*/
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const pkg = require('../../package');
|
|
8
|
+
|
|
9
|
+
const version = process.env.REACT_VERSION;
|
|
10
|
+
const clean = !Boolean(version) || version === 'clean';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const template = {
|
|
14
|
+
'prop-types': './test/e2e/assets/prop-types.js',
|
|
15
|
+
'react': `./test/e2e/assets/react-${version}.js`,
|
|
16
|
+
'react-dom': `./test/e2e/assets/react-dom-${version}.js`
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Delete aliases
|
|
22
|
+
*/
|
|
23
|
+
if (clean) {
|
|
24
|
+
if (pkg.alias) {
|
|
25
|
+
Object.keys(template).forEach(key => delete pkg.alias[key]);
|
|
26
|
+
|
|
27
|
+
if (!Object.keys(pkg.alias).length) {
|
|
28
|
+
delete pkg.alias;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
pkg.alias = pkg.alias || {};
|
|
33
|
+
Object.assign(pkg.alias, template);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!clean) {
|
|
37
|
+
console.log(`>>> REACT_VERSION ${version} <<<`);
|
|
38
|
+
} else {
|
|
39
|
+
console.log(`>>> CLEAN REACT ALIAS <<<`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 4), 'utf8');
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
rootDir: '../..',
|
|
3
|
+
testEnvironment: 'jsdom',
|
|
4
|
+
testPathIgnorePatterns: [
|
|
5
|
+
'.*/e2e/.*',
|
|
6
|
+
],
|
|
7
|
+
transform: {
|
|
8
|
+
'.(ts|tsx)': [
|
|
9
|
+
'ts-jest',
|
|
10
|
+
{
|
|
11
|
+
tsconfig: 'tsconfig.spec.json',
|
|
12
|
+
diagnostics: {
|
|
13
|
+
warnOnly: true,
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
moduleFileExtensions: [
|
|
19
|
+
'js',
|
|
20
|
+
'json',
|
|
21
|
+
'ts',
|
|
22
|
+
'tsx',
|
|
23
|
+
],
|
|
24
|
+
moduleDirectories: [
|
|
25
|
+
'node_modules',
|
|
26
|
+
'src',
|
|
27
|
+
'types',
|
|
28
|
+
],
|
|
29
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Arg, Substitute } from '@fluffy-spoon/substitute';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @see https://www.npmjs.com/package/@fluffy-spoon/substitute
|
|
7
|
+
*/
|
|
8
|
+
describe('Mock functionality works correctly', () => {
|
|
9
|
+
it('String property of interface', () => {
|
|
10
|
+
interface Example {
|
|
11
|
+
readonly bar: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const baz = 'baz';
|
|
15
|
+
const foo = Substitute.for<Example>();
|
|
16
|
+
|
|
17
|
+
foo.bar.returns(baz);
|
|
18
|
+
const call1 = foo.bar;
|
|
19
|
+
const call2 = foo.bar;
|
|
20
|
+
expect(call1).toEqual(baz);
|
|
21
|
+
expect(call2).toEqual(baz);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('Can mock parent interface', () => {
|
|
25
|
+
interface NestedApi {
|
|
26
|
+
readonly nestedMethod: () => boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface SuperParent {
|
|
30
|
+
readonly property1: string;
|
|
31
|
+
readonly method1: () => number;
|
|
32
|
+
readonly api: NestedApi;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface Parent extends SuperParent {
|
|
36
|
+
readonly property2: string;
|
|
37
|
+
readonly method2: (arg: any) => string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface Child extends Parent {
|
|
41
|
+
readonly bar: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const params = Substitute.for<Child>();
|
|
45
|
+
|
|
46
|
+
params.property1.returns('property1-value');
|
|
47
|
+
params.property2.returns('property2-value');
|
|
48
|
+
params.method1().returns(10);
|
|
49
|
+
params.method2(Arg.any()).returns('method2-value');
|
|
50
|
+
|
|
51
|
+
params.api.nestedMethod().returns(false);
|
|
52
|
+
|
|
53
|
+
expect(params.property1).toEqual('property1-value');
|
|
54
|
+
expect(params.property2).toEqual('property2-value');
|
|
55
|
+
expect(params.method1()).toEqual(10);
|
|
56
|
+
expect(params.method2(10)).toEqual('method2-value');
|
|
57
|
+
|
|
58
|
+
expect(params.api.nestedMethod()).toEqual(false);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('Extended calls on the same level works correctly', () => {
|
|
62
|
+
interface Element {
|
|
63
|
+
readonly destroy: () => void;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface ParentMethod {
|
|
67
|
+
readonly mount: () => Element;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface ChildMethod1 extends ParentMethod {
|
|
71
|
+
readonly name: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface ChildMethod2 extends ParentMethod {
|
|
75
|
+
readonly name: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface Api {
|
|
79
|
+
readonly child1: ChildMethod1;
|
|
80
|
+
readonly child2: ChildMethod2;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const api = Substitute.for<Api>();
|
|
84
|
+
const spy1 = jest.fn();
|
|
85
|
+
const spy2 = jest.fn();
|
|
86
|
+
|
|
87
|
+
api.child1.mount().returns(Substitute.for<Element>());
|
|
88
|
+
|
|
89
|
+
api.child2.mount().returns(Substitute.for<Element>());
|
|
90
|
+
|
|
91
|
+
api.child1
|
|
92
|
+
.mount()
|
|
93
|
+
.destroy()
|
|
94
|
+
|
|
95
|
+
.mimicks(spy1);
|
|
96
|
+
|
|
97
|
+
api.child2
|
|
98
|
+
.mount()
|
|
99
|
+
.destroy()
|
|
100
|
+
|
|
101
|
+
.mimicks(spy2);
|
|
102
|
+
|
|
103
|
+
const el = api.child1.mount();
|
|
104
|
+
el.destroy();
|
|
105
|
+
|
|
106
|
+
expect(spy1).toBeCalledTimes(1);
|
|
107
|
+
expect(spy2).not.toHaveBeenCalled();
|
|
108
|
+
|
|
109
|
+
interface ComponentProps {
|
|
110
|
+
readonly api: Api;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
interface ComponentState {
|
|
114
|
+
readonly element: Element;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
class TmpParentComponent extends React.Component<
|
|
118
|
+
ComponentProps,
|
|
119
|
+
ComponentState
|
|
120
|
+
> {
|
|
121
|
+
componentDidMount() {
|
|
122
|
+
this.setState({ element: this.props.api.child1.mount() });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
componentWillUnmount() {
|
|
126
|
+
this.state.element.destroy();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
render() {
|
|
130
|
+
return <div />;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const { unmount } = render(<TmpParentComponent api={api} />);
|
|
135
|
+
expect(spy1).toBeCalledTimes(1);
|
|
136
|
+
expect(spy2).not.toHaveBeenCalled();
|
|
137
|
+
|
|
138
|
+
unmount();
|
|
139
|
+
|
|
140
|
+
expect(spy1).toBeCalledTimes(2);
|
|
141
|
+
expect(spy2).not.toHaveBeenCalled();
|
|
142
|
+
});
|
|
143
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es5",
|
|
4
|
+
"outDir": "build",
|
|
5
|
+
"rootDir": "src",
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"module": "commonjs",
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"inlineSourceMap": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"noUnusedLocals": false,
|
|
13
|
+
"noUnusedParameters": true,
|
|
14
|
+
"noImplicitReturns": true,
|
|
15
|
+
"noFallthroughCasesInSwitch": true,
|
|
16
|
+
"traceResolution": false,
|
|
17
|
+
"listEmittedFiles": false,
|
|
18
|
+
"listFiles": false,
|
|
19
|
+
"pretty": true,
|
|
20
|
+
"lib": ["es2015", "dom"],
|
|
21
|
+
"typeRoots": [
|
|
22
|
+
"node_modules/@types",
|
|
23
|
+
"types",
|
|
24
|
+
"../../node_modules/@types"
|
|
25
|
+
],
|
|
26
|
+
"jsx": "react"
|
|
27
|
+
},
|
|
28
|
+
"include": ["src/**/*.ts", "src/**/*.tsx", "types/**/*.d.ts"],
|
|
29
|
+
"exclude": ["node_modules/**", "*/**/**.spec.tsx"],
|
|
30
|
+
"compileOnSave": false
|
|
31
|
+
}
|