@tryfinch/react-connect 3.15.1 → 4.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/.eslintrc.js +12 -0
- package/.github/pull_request_template.md +66 -0
- package/.github/workflows/pr.yml +92 -0
- package/.github/workflows/release.yml +80 -0
- package/.nvmrc +1 -0
- package/CHANGELOG.md +11 -0
- package/README.md +17 -10
- package/dist/index.d.ts +23 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +55 -66
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +56 -65
- package/dist/index.js.map +1 -1
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/example/package-lock.json +13 -1
- package/example/src/App.tsx +37 -10
- package/jest.config.js +7 -0
- package/package.json +9 -1
- package/src/index.test.ts +111 -0
- package/src/index.ts +95 -115
package/dist/index.js
CHANGED
|
@@ -6,68 +6,38 @@ var react = require('react');
|
|
|
6
6
|
|
|
7
7
|
const POST_MESSAGE_NAME = 'finch-auth-message-v2';
|
|
8
8
|
const BASE_FINCH_CONNECT_URI = 'https://connect.tryfinch.com';
|
|
9
|
-
const DEFAULT_FINCH_REDIRECT_URI = 'https://tryfinch.com';
|
|
10
9
|
const FINCH_CONNECT_IFRAME_ID = 'finch-connect-iframe';
|
|
11
|
-
const
|
|
12
|
-
|
|
10
|
+
const appendBaseParams = (url) => {
|
|
11
|
+
url.searchParams.append('app_type', 'spa');
|
|
12
|
+
// The host URL of the SDK. This is used to store the referrer for postMessage purposes
|
|
13
|
+
url.searchParams.append('sdk_host_url', window.location.origin);
|
|
14
|
+
url.searchParams.append('mode', 'employer');
|
|
15
|
+
// replace with actual SDK version by rollup
|
|
16
|
+
url.searchParams.append('sdk_version', 'react-4.1.0');
|
|
17
|
+
};
|
|
18
|
+
const constructAuthUrl = ({ sessionId, state, apiConfig, }) => {
|
|
13
19
|
const CONNECT_URL = (apiConfig === null || apiConfig === void 0 ? void 0 : apiConfig.connectUrl) || BASE_FINCH_CONNECT_URI;
|
|
14
|
-
const REDIRECT_URL = (apiConfig === null || apiConfig === void 0 ? void 0 : apiConfig.redirectUrl) || DEFAULT_FINCH_REDIRECT_URI;
|
|
15
20
|
const authUrl = new URL(`${CONNECT_URL}/authorize`);
|
|
16
|
-
|
|
17
|
-
const { sessionId, products } = connectOptions;
|
|
18
|
-
authUrl.searchParams.append('session', sessionId);
|
|
19
|
-
if (products)
|
|
20
|
-
authUrl.searchParams.append('products', products.join(' '));
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
const { clientId, payrollProvider, category, products, manual, sandbox, clientName, connectionId, } = connectOptions;
|
|
24
|
-
if (clientId)
|
|
25
|
-
authUrl.searchParams.append('client_id', clientId);
|
|
26
|
-
if (payrollProvider)
|
|
27
|
-
authUrl.searchParams.append('payroll_provider', payrollProvider);
|
|
28
|
-
if (category)
|
|
29
|
-
authUrl.searchParams.append('category', category);
|
|
30
|
-
if (clientName)
|
|
31
|
-
authUrl.searchParams.append('client_name', clientName);
|
|
32
|
-
if (connectionId)
|
|
33
|
-
authUrl.searchParams.append('connection_id', connectionId);
|
|
34
|
-
authUrl.searchParams.append('products', (products !== null && products !== void 0 ? products : []).join(' '));
|
|
35
|
-
if (manual)
|
|
36
|
-
authUrl.searchParams.append('manual', String(manual));
|
|
37
|
-
if (sandbox)
|
|
38
|
-
authUrl.searchParams.append('sandbox', String(sandbox));
|
|
39
|
-
}
|
|
40
|
-
authUrl.searchParams.append('app_type', 'spa');
|
|
41
|
-
authUrl.searchParams.append('redirect_uri', REDIRECT_URL);
|
|
42
|
-
/** The host URL of the SDK. This is used to store the referrer for postMessage purposes */
|
|
43
|
-
authUrl.searchParams.append('sdk_host_url', window.location.origin);
|
|
44
|
-
authUrl.searchParams.append('mode', 'employer');
|
|
21
|
+
authUrl.searchParams.append('session', sessionId);
|
|
45
22
|
if (state)
|
|
46
23
|
authUrl.searchParams.append('state', state);
|
|
47
|
-
|
|
48
|
-
authUrl.searchParams.append('sdk_version', 'react-3.15.1');
|
|
24
|
+
appendBaseParams(authUrl);
|
|
49
25
|
return authUrl.href;
|
|
50
26
|
};
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
27
|
+
const constructPreviewUrl = ({ clientId, products, apiConfig, }) => {
|
|
28
|
+
const CONNECT_URL = (apiConfig === null || apiConfig === void 0 ? void 0 : apiConfig.connectUrl) || BASE_FINCH_CONNECT_URI;
|
|
29
|
+
const previewUrl = new URL(`${CONNECT_URL}/authorize`);
|
|
30
|
+
previewUrl.searchParams.append('preview', 'true');
|
|
31
|
+
previewUrl.searchParams.append('client_id', clientId);
|
|
32
|
+
previewUrl.searchParams.append('products', (products !== null && products !== void 0 ? products : []).join(' '));
|
|
33
|
+
// This will be replaced by a universally allowed redirect URI in the backend
|
|
34
|
+
// We won't ever redirect to anything in preview mode, so we just need a value to pass validation
|
|
35
|
+
previewUrl.searchParams.append('redirect_uri', 'https://www.tryfinch.com');
|
|
36
|
+
appendBaseParams(previewUrl);
|
|
37
|
+
return previewUrl.href;
|
|
60
38
|
};
|
|
61
|
-
const DEFAULT_OPTIONS_WITH_CLIENT_ID = Object.assign(Object.assign({}, BASE_DEFAULTS), { clientId: '', category: null, manual: false, payrollProvider: null, products: [], clientName: undefined, sandbox: false });
|
|
62
|
-
const DEFAULT_OPTIONS_WITH_SESSION_ID = Object.assign(Object.assign({}, BASE_DEFAULTS), { sessionId: '' });
|
|
63
39
|
let isUseFinchConnectInitialized = false;
|
|
64
|
-
const useFinchConnect = (
|
|
65
|
-
if (!('sessionId' in options) && !('clientId' in options)) {
|
|
66
|
-
throw new Error('must specify either sessionId or clientId in options for useFinchConnect');
|
|
67
|
-
}
|
|
68
|
-
if ('sessionId' in options && 'clientId' in options) {
|
|
69
|
-
throw new Error('cannot specify both sessionId and clientId in options for useFinchConnect');
|
|
70
|
-
}
|
|
40
|
+
const useFinchConnect = (initializeArgs) => {
|
|
71
41
|
const isHookMounted = react.useRef(false);
|
|
72
42
|
react.useEffect(() => {
|
|
73
43
|
if (!isHookMounted.current) {
|
|
@@ -80,17 +50,14 @@ const useFinchConnect = (options) => {
|
|
|
80
50
|
isHookMounted.current = true;
|
|
81
51
|
}
|
|
82
52
|
}, []);
|
|
83
|
-
const
|
|
84
|
-
? Object.assign(Object.assign({}, DEFAULT_OPTIONS_WITH_SESSION_ID), options) : Object.assign(Object.assign({}, DEFAULT_OPTIONS_WITH_CLIENT_ID), options);
|
|
85
|
-
const open = (overrides) => {
|
|
86
|
-
const openOptions = Object.assign(Object.assign({}, combinedOptions), overrides);
|
|
53
|
+
const createAndAttachIFrame = ({ src, zIndexOverride, }) => {
|
|
87
54
|
if (!document.getElementById(FINCH_CONNECT_IFRAME_ID)) {
|
|
88
55
|
const iframe = document.createElement('iframe');
|
|
89
|
-
iframe.src =
|
|
56
|
+
iframe.src = src;
|
|
90
57
|
iframe.frameBorder = '0';
|
|
91
58
|
iframe.id = FINCH_CONNECT_IFRAME_ID;
|
|
92
59
|
iframe.style.position = 'fixed';
|
|
93
|
-
iframe.style.zIndex =
|
|
60
|
+
iframe.style.zIndex = (zIndexOverride === null || zIndexOverride === void 0 ? void 0 : zIndexOverride.toString()) || '999';
|
|
94
61
|
iframe.style.height = '100%';
|
|
95
62
|
iframe.style.width = '100%';
|
|
96
63
|
iframe.style.top = '0';
|
|
@@ -101,6 +68,27 @@ const useFinchConnect = (options) => {
|
|
|
101
68
|
document.body.style.overflow = 'hidden';
|
|
102
69
|
}
|
|
103
70
|
};
|
|
71
|
+
const open = (launchArgs) => {
|
|
72
|
+
const iframeSrc = constructAuthUrl({
|
|
73
|
+
sessionId: launchArgs.sessionId,
|
|
74
|
+
state: launchArgs.state,
|
|
75
|
+
apiConfig: initializeArgs.apiConfig,
|
|
76
|
+
});
|
|
77
|
+
createAndAttachIFrame({
|
|
78
|
+
src: iframeSrc,
|
|
79
|
+
zIndexOverride: launchArgs.zIndex,
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
const openPreview = (launchArgs) => {
|
|
83
|
+
const iframeSrc = constructPreviewUrl({
|
|
84
|
+
clientId: launchArgs.clientId,
|
|
85
|
+
products: launchArgs.products,
|
|
86
|
+
apiConfig: initializeArgs.apiConfig,
|
|
87
|
+
});
|
|
88
|
+
createAndAttachIFrame({
|
|
89
|
+
src: iframeSrc,
|
|
90
|
+
});
|
|
91
|
+
};
|
|
104
92
|
const close = () => {
|
|
105
93
|
var _a;
|
|
106
94
|
const frameToRemove = document.getElementById(FINCH_CONNECT_IFRAME_ID);
|
|
@@ -112,7 +100,7 @@ const useFinchConnect = (options) => {
|
|
|
112
100
|
react.useEffect(() => {
|
|
113
101
|
function handleFinchAuth(event) {
|
|
114
102
|
var _a, _b, _c, _d;
|
|
115
|
-
const CONNECT_URL = ((_a =
|
|
103
|
+
const CONNECT_URL = ((_a = initializeArgs.apiConfig) === null || _a === void 0 ? void 0 : _a.connectUrl) || BASE_FINCH_CONNECT_URI;
|
|
116
104
|
if (!event.data)
|
|
117
105
|
return;
|
|
118
106
|
if (event.data.name !== POST_MESSAGE_NAME)
|
|
@@ -123,18 +111,18 @@ const useFinchConnect = (options) => {
|
|
|
123
111
|
close();
|
|
124
112
|
switch (event.data.kind) {
|
|
125
113
|
case 'closed':
|
|
126
|
-
|
|
114
|
+
initializeArgs.onClose();
|
|
127
115
|
break;
|
|
128
116
|
case 'error':
|
|
129
117
|
if ((_b = event.data.error) === null || _b === void 0 ? void 0 : _b.shouldClose)
|
|
130
118
|
close();
|
|
131
|
-
|
|
119
|
+
initializeArgs.onError({
|
|
132
120
|
errorMessage: (_c = event.data.error) === null || _c === void 0 ? void 0 : _c.message,
|
|
133
121
|
errorType: (_d = event.data.error) === null || _d === void 0 ? void 0 : _d.type,
|
|
134
122
|
});
|
|
135
123
|
break;
|
|
136
124
|
case 'success':
|
|
137
|
-
|
|
125
|
+
initializeArgs.onSuccess({
|
|
138
126
|
code: event.data.code,
|
|
139
127
|
state: event.data.state,
|
|
140
128
|
idpRedirectUri: event.data.idpRedirectUri,
|
|
@@ -142,7 +130,7 @@ const useFinchConnect = (options) => {
|
|
|
142
130
|
break;
|
|
143
131
|
default: {
|
|
144
132
|
// This case should never happen, if it does it should be reported to us
|
|
145
|
-
|
|
133
|
+
initializeArgs.onError({
|
|
146
134
|
errorMessage: `Report to developers@tryfinch.com: unable to handle window.postMessage for: ${JSON.stringify(event.data)}`,
|
|
147
135
|
});
|
|
148
136
|
}
|
|
@@ -153,11 +141,14 @@ const useFinchConnect = (options) => {
|
|
|
153
141
|
window.removeEventListener('message', handleFinchAuth);
|
|
154
142
|
isUseFinchConnectInitialized = false;
|
|
155
143
|
};
|
|
156
|
-
}, [
|
|
144
|
+
}, [initializeArgs.onClose, initializeArgs.onError, initializeArgs.onSuccess]);
|
|
157
145
|
return {
|
|
158
146
|
open,
|
|
147
|
+
openPreview,
|
|
159
148
|
};
|
|
160
149
|
};
|
|
161
150
|
|
|
151
|
+
exports.constructAuthUrl = constructAuthUrl;
|
|
152
|
+
exports.constructPreviewUrl = constructPreviewUrl;
|
|
162
153
|
exports.useFinchConnect = useFinchConnect;
|
|
163
154
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":[null],"names":["useRef","useEffect"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":[null],"names":["useRef","useEffect"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"./","sources":["index.test.ts"],"names":[],"mappings":""}
|
|
@@ -21,11 +21,12 @@
|
|
|
21
21
|
},
|
|
22
22
|
"..": {
|
|
23
23
|
"name": "@tryfinch/react-connect",
|
|
24
|
-
"version": "
|
|
24
|
+
"version": "4.1.0",
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@rollup/plugin-replace": "^4.0.0",
|
|
28
28
|
"@rollup/plugin-typescript": "^11.1.0",
|
|
29
|
+
"@types/jest": "^30.0.0",
|
|
29
30
|
"@types/react": "^16.14.40",
|
|
30
31
|
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
|
31
32
|
"@typescript-eslint/parser": "^5.59.0",
|
|
@@ -33,9 +34,14 @@
|
|
|
33
34
|
"eslint-config-airbnb": "^18.2.0",
|
|
34
35
|
"eslint-config-prettier": "^6.11.0",
|
|
35
36
|
"eslint-plugin-prettier": "^3.1.4",
|
|
37
|
+
"jest": "^30.0.5",
|
|
38
|
+
"jest-environment-jsdom": "^30.0.5",
|
|
39
|
+
"jsdom": "^26.1.0",
|
|
36
40
|
"react": "^16.9.0",
|
|
37
41
|
"rollup": "^2.75.7",
|
|
38
42
|
"rollup-plugin-peer-deps-external": "^2.2.0",
|
|
43
|
+
"ts-jest": "^29.4.1",
|
|
44
|
+
"tslib": "^2.8.1",
|
|
39
45
|
"typescript": "^4.9.5"
|
|
40
46
|
},
|
|
41
47
|
"engines": {
|
|
@@ -21321,6 +21327,7 @@
|
|
|
21321
21327
|
"requires": {
|
|
21322
21328
|
"@rollup/plugin-replace": "^4.0.0",
|
|
21323
21329
|
"@rollup/plugin-typescript": "^11.1.0",
|
|
21330
|
+
"@types/jest": "^30.0.0",
|
|
21324
21331
|
"@types/react": "^16.14.40",
|
|
21325
21332
|
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
|
21326
21333
|
"@typescript-eslint/parser": "^5.59.0",
|
|
@@ -21328,9 +21335,14 @@
|
|
|
21328
21335
|
"eslint-config-airbnb": "^18.2.0",
|
|
21329
21336
|
"eslint-config-prettier": "^6.11.0",
|
|
21330
21337
|
"eslint-plugin-prettier": "^3.1.4",
|
|
21338
|
+
"jest": "^30.0.5",
|
|
21339
|
+
"jest-environment-jsdom": "^30.0.5",
|
|
21340
|
+
"jsdom": "^26.1.0",
|
|
21331
21341
|
"react": "^16.9.0",
|
|
21332
21342
|
"rollup": "^2.75.7",
|
|
21333
21343
|
"rollup-plugin-peer-deps-external": "^2.2.0",
|
|
21344
|
+
"ts-jest": "^29.4.1",
|
|
21345
|
+
"tslib": "^2.8.1",
|
|
21334
21346
|
"typescript": "^4.9.5"
|
|
21335
21347
|
},
|
|
21336
21348
|
"dependencies": {
|
package/example/src/App.tsx
CHANGED
|
@@ -6,36 +6,61 @@ import Result, { ResultContainer } from './Result';
|
|
|
6
6
|
import './App.css';
|
|
7
7
|
|
|
8
8
|
const App = () => {
|
|
9
|
+
const [sessionId, setSessionId] = useState<string>('');
|
|
9
10
|
const [sendState, setSendState] = useState<boolean>(false);
|
|
10
11
|
const [result, setResult] = useState<ResultContainer>();
|
|
11
12
|
|
|
13
|
+
// Define callbacks
|
|
12
14
|
const onSuccess = (value: SuccessEvent) => setResult({ kind: 'success', value });
|
|
13
15
|
const onError = (value: ErrorEvent) => setResult({ kind: 'error', value });
|
|
14
16
|
const onClose = () => setResult({ kind: 'closed' });
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
// Initialize the FinchConnect hook
|
|
18
19
|
const { open } = useFinchConnect({
|
|
19
|
-
sessionId,
|
|
20
20
|
onSuccess,
|
|
21
21
|
onError,
|
|
22
22
|
onClose,
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
// Call the open method when submitting the form
|
|
26
|
+
const submissionHandler: React.FormEventHandler<HTMLFormElement> = (e) => {
|
|
26
27
|
e.preventDefault();
|
|
27
28
|
open({
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
// Generate a session ID using the /connect/sessions endpoint on the Finch API
|
|
30
|
+
// See the docs here https://developer.tryfinch.com/api-reference/connect/new-session#create-a-new-connect-session
|
|
31
|
+
sessionId: sessionId.trim(),
|
|
32
|
+
// An optional state parameter can be passed
|
|
33
|
+
// https://datatracker.ietf.org/doc/html/rfc6749#section-10.12
|
|
34
|
+
...(sendState ? { state: new Date().toISOString() } : {}),
|
|
35
|
+
// An optional value for the z-index of the Finch Connect iframe
|
|
36
|
+
// Defaults to 999 if not provided
|
|
37
|
+
// zIndex: 998,
|
|
38
|
+
});
|
|
30
39
|
};
|
|
31
40
|
|
|
32
41
|
return (
|
|
33
42
|
<div className="container">
|
|
34
|
-
<h2
|
|
43
|
+
<h2>
|
|
44
|
+
<a href="https://www.npmjs.com/package/@tryfinch/react-connect">@tryfinch/react-connect</a>{' '}
|
|
45
|
+
Example App
|
|
46
|
+
</h2>
|
|
35
47
|
<form className="actions" onSubmit={submissionHandler}>
|
|
48
|
+
<div className="row">
|
|
49
|
+
<label className="top-label">Session UUID:</label>
|
|
50
|
+
<input
|
|
51
|
+
type="text"
|
|
52
|
+
placeholder="Enter session UUID"
|
|
53
|
+
value={sessionId}
|
|
54
|
+
onChange={(e) => setSessionId(e.target.value)}
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
36
57
|
<div className="row">
|
|
37
58
|
<label className="top-label">Include State:</label>
|
|
38
|
-
<input
|
|
59
|
+
<input
|
|
60
|
+
type="checkbox"
|
|
61
|
+
checked={sendState}
|
|
62
|
+
onChange={() => setSendState((prev) => !prev)}
|
|
63
|
+
/>
|
|
39
64
|
</div>
|
|
40
65
|
<div className="row">
|
|
41
66
|
<button className="cta" type="submit">
|
|
@@ -44,8 +69,10 @@ const App = () => {
|
|
|
44
69
|
</div>
|
|
45
70
|
</form>
|
|
46
71
|
<div className="results">
|
|
47
|
-
|
|
48
|
-
|
|
72
|
+
{!result && (
|
|
73
|
+
<p>Complete a Finch Connect session and the success event will be displayed here</p>
|
|
74
|
+
)}
|
|
75
|
+
{result && <Result result={result} />}
|
|
49
76
|
</div>
|
|
50
77
|
</div>
|
|
51
78
|
);
|
package/jest.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tryfinch/react-connect",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Finch SDK for embedding Finch Connect in API React Single Page Applications (SPA)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"finch",
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
"build": "rollup -c",
|
|
26
26
|
"lint": "eslint --ext .js,.jsx,.ts,.tsx src",
|
|
27
27
|
"start": "rollup -c -w",
|
|
28
|
+
"test": "jest",
|
|
29
|
+
"test:watch": "jest --watch",
|
|
28
30
|
"prepare": "npm run build",
|
|
29
31
|
"predeploy": "cd example && npm install && npm run build"
|
|
30
32
|
},
|
|
@@ -34,6 +36,7 @@
|
|
|
34
36
|
"devDependencies": {
|
|
35
37
|
"@rollup/plugin-replace": "^4.0.0",
|
|
36
38
|
"@rollup/plugin-typescript": "^11.1.0",
|
|
39
|
+
"@types/jest": "^30.0.0",
|
|
37
40
|
"@types/react": "^16.14.40",
|
|
38
41
|
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
|
39
42
|
"@typescript-eslint/parser": "^5.59.0",
|
|
@@ -41,9 +44,14 @@
|
|
|
41
44
|
"eslint-config-airbnb": "^18.2.0",
|
|
42
45
|
"eslint-config-prettier": "^6.11.0",
|
|
43
46
|
"eslint-plugin-prettier": "^3.1.4",
|
|
47
|
+
"jest": "^30.0.5",
|
|
48
|
+
"jest-environment-jsdom": "^30.0.5",
|
|
49
|
+
"jsdom": "^26.1.0",
|
|
44
50
|
"react": "^16.9.0",
|
|
45
51
|
"rollup": "^2.75.7",
|
|
46
52
|
"rollup-plugin-peer-deps-external": "^2.2.0",
|
|
53
|
+
"ts-jest": "^29.4.1",
|
|
54
|
+
"tslib": "^2.8.1",
|
|
47
55
|
"typescript": "^4.9.5"
|
|
48
56
|
}
|
|
49
57
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { constructAuthUrl, constructPreviewUrl } from './index';
|
|
2
|
+
|
|
3
|
+
const NOOP_CALLBACKS = {
|
|
4
|
+
onSuccess: jest.fn(),
|
|
5
|
+
onError: jest.fn(),
|
|
6
|
+
onClose: jest.fn(),
|
|
7
|
+
zIndex: 999,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
describe('Finch React SDK', () => {
|
|
11
|
+
describe('constructAuthUrl', () => {
|
|
12
|
+
it('adds the session parameter', () => {
|
|
13
|
+
const authUrl = constructAuthUrl({
|
|
14
|
+
sessionId: 'test-session-id',
|
|
15
|
+
});
|
|
16
|
+
expect(authUrl).toContain('session=test-session-id');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('adds all the expected base parameters to the auth URL', () => {
|
|
20
|
+
const expectedParameters = {
|
|
21
|
+
app_type: 'spa',
|
|
22
|
+
sdk_host_url: encodeURIComponent('http://localhost'),
|
|
23
|
+
mode: 'employer',
|
|
24
|
+
sdk_version: 'react-SDK_VERSION',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const authUrl = constructAuthUrl({
|
|
28
|
+
sessionId: 'test-session-id',
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
Object.entries(expectedParameters).forEach(([key, value]) => {
|
|
32
|
+
expect(authUrl).toContain(`${key}=${value}`);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('adds the state parameter if it is provided', () => {
|
|
37
|
+
const testOptions = { sessionId: 'test-session-id', state: 'test-state', ...NOOP_CALLBACKS };
|
|
38
|
+
const authUrl = constructAuthUrl(testOptions);
|
|
39
|
+
|
|
40
|
+
expect(authUrl).toContain('state=test-state');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('uses the provided connectUrl if provided', () => {
|
|
44
|
+
const authUrl = constructAuthUrl({
|
|
45
|
+
sessionId: '123',
|
|
46
|
+
apiConfig: {
|
|
47
|
+
connectUrl: 'https://cool.site',
|
|
48
|
+
},
|
|
49
|
+
...NOOP_CALLBACKS,
|
|
50
|
+
});
|
|
51
|
+
expect(authUrl.startsWith('https://cool.site/authorize?')).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('constructPreviewUrl', () => {
|
|
56
|
+
it('sets the preview parameter to true', () => {
|
|
57
|
+
const previewUrl = constructPreviewUrl({
|
|
58
|
+
clientId: 'test-client-id',
|
|
59
|
+
products: ['test-product'],
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
expect(previewUrl).toContain('preview=true');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('sets the client ID parameter', () => {
|
|
66
|
+
const previewUrl = constructPreviewUrl({
|
|
67
|
+
clientId: 'test-client-id',
|
|
68
|
+
products: ['test-product'],
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
expect(previewUrl).toContain('client_id=test-client-id');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('sets the products parameter', () => {
|
|
75
|
+
const previewUrl = constructPreviewUrl({
|
|
76
|
+
clientId: 'test-client-id',
|
|
77
|
+
products: ['test-product', 'test-product-2'],
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(previewUrl).toContain('products=test-product+test-product-2');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('sets a default redirect URI', () => {
|
|
84
|
+
const expectedRedirectUri = encodeURIComponent('https://www.tryfinch.com');
|
|
85
|
+
const previewUrl = constructPreviewUrl({
|
|
86
|
+
clientId: 'test-client-id',
|
|
87
|
+
products: ['test-product'],
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
expect(previewUrl).toContain(`redirect_uri=${expectedRedirectUri}`);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('adds all the expected base parameters to the auth URL', () => {
|
|
94
|
+
const expectedParameters = {
|
|
95
|
+
app_type: 'spa',
|
|
96
|
+
sdk_host_url: encodeURIComponent('http://localhost'),
|
|
97
|
+
mode: 'employer',
|
|
98
|
+
sdk_version: 'react-SDK_VERSION',
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const authUrl = constructPreviewUrl({
|
|
102
|
+
clientId: 'test-client-id',
|
|
103
|
+
products: ['test-product'],
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
Object.entries(expectedParameters).forEach(([key, value]) => {
|
|
107
|
+
expect(authUrl).toContain(`${key}=${value}`);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|