@paypal/checkout-components 5.0.409 → 5.0.411
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/__sdk__.js +6 -0
- package/dist/button.js +1 -1
- package/dist/test/button.js +1 -1
- package/globals.js +1 -0
- package/package.json +1 -1
- package/src/declarations.js +1 -0
- package/src/interface/saved-payment-methods.js +15 -0
- package/src/lib/perceived-latency-instrumentation.js +4 -3
- package/src/three-domain-secure/interface.js +27 -18
- package/src/three-domain-secure/interface.test.js +18 -1
- package/src/ui/buttons/props.js +2 -2
- package/src/ui/buttons/styles/responsive.js +1 -3
- package/src/zoid/buttons/component.jsx +4 -1
- package/src/zoid/saved-payment-methods/component.jsx +797 -0
- package/src/zoid/saved-payment-methods/container.jsx +124 -0
- package/src/zoid/saved-payment-methods/index.js +4 -0
- package/src/zoid/saved-payment-methods/prerender.jsx +45 -0
- package/src/zoid/saved-payment-methods/props.js +116 -0
- package/src/zoid/saved-payment-methods/util.js +115 -0
- package/src/zoid/saved-payment-methods/util.test.js +117 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
/** @jsx node */
|
|
3
|
+
|
|
4
|
+
import { node, dom } from "@krakenjs/jsx-pragmatic/src";
|
|
5
|
+
import { EVENT, type RenderOptionsType } from "@krakenjs/zoid/src";
|
|
6
|
+
import { getVersion } from "@paypal/sdk-client/src";
|
|
7
|
+
import { destroyElement, toCSS } from "@krakenjs/belter/src";
|
|
8
|
+
|
|
9
|
+
import { type SavedPaymentMethodsProps } from "./props";
|
|
10
|
+
|
|
11
|
+
const CLASS = {
|
|
12
|
+
VISIBLE: "visible",
|
|
13
|
+
INVISIBLE: "invisible",
|
|
14
|
+
COMPONENT_FRAME: "component-frame",
|
|
15
|
+
PRERENDER_FRAME: "prerender-frame",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const ATTRIBUTE = {
|
|
19
|
+
VERSION: "data-version",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function containerTemplate({
|
|
23
|
+
uid,
|
|
24
|
+
props,
|
|
25
|
+
tag,
|
|
26
|
+
context,
|
|
27
|
+
frame,
|
|
28
|
+
prerenderFrame,
|
|
29
|
+
doc,
|
|
30
|
+
event,
|
|
31
|
+
dimensions,
|
|
32
|
+
}: RenderOptionsType<SavedPaymentMethodsProps>): ?HTMLElement {
|
|
33
|
+
if (!frame || !prerenderFrame) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
frame.classList.add(CLASS.COMPONENT_FRAME);
|
|
38
|
+
prerenderFrame.classList.add(CLASS.PRERENDER_FRAME);
|
|
39
|
+
|
|
40
|
+
frame.classList.add(CLASS.INVISIBLE);
|
|
41
|
+
prerenderFrame.classList.add(CLASS.VISIBLE);
|
|
42
|
+
|
|
43
|
+
const { width: initialWidth, height: initialHeight } = dimensions;
|
|
44
|
+
|
|
45
|
+
event.on(EVENT.RENDERED, () => {
|
|
46
|
+
prerenderFrame.classList.remove(CLASS.VISIBLE);
|
|
47
|
+
prerenderFrame.classList.add(CLASS.INVISIBLE);
|
|
48
|
+
|
|
49
|
+
frame.classList.remove(CLASS.INVISIBLE);
|
|
50
|
+
frame.classList.add(CLASS.VISIBLE);
|
|
51
|
+
|
|
52
|
+
setTimeout(() => {
|
|
53
|
+
destroyElement(prerenderFrame);
|
|
54
|
+
}, 1000);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const setupAutoResize = (el) => {
|
|
58
|
+
event.on(EVENT.RESIZE, ({ width: newWidth, height: newHeight }) => {
|
|
59
|
+
if (typeof newWidth === "number") {
|
|
60
|
+
el.style.width = toCSS(newWidth);
|
|
61
|
+
}
|
|
62
|
+
if (typeof newHeight === "number") {
|
|
63
|
+
el.style.height = toCSS(newHeight);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const { nonce } = props;
|
|
69
|
+
|
|
70
|
+
const element = (
|
|
71
|
+
<div
|
|
72
|
+
id={uid}
|
|
73
|
+
class={`${tag} ${tag}-context-${context}`}
|
|
74
|
+
{...{ [ATTRIBUTE.VERSION]: `${getVersion()}` }}
|
|
75
|
+
style={{
|
|
76
|
+
width: initialWidth,
|
|
77
|
+
height: initialHeight,
|
|
78
|
+
}}
|
|
79
|
+
onRender={setupAutoResize}
|
|
80
|
+
>
|
|
81
|
+
<style nonce={nonce}>
|
|
82
|
+
{`
|
|
83
|
+
#${uid} {
|
|
84
|
+
position: relative;
|
|
85
|
+
display: block;
|
|
86
|
+
font-size: 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
#${uid} > iframe {
|
|
90
|
+
position: absolute;
|
|
91
|
+
top: 0;
|
|
92
|
+
left: 0;
|
|
93
|
+
width: 100%;
|
|
94
|
+
height: 100%;
|
|
95
|
+
border: none;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
#${uid} > iframe.${CLASS.COMPONENT_FRAME} {
|
|
99
|
+
z-index: 100;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
#${uid} > iframe.${CLASS.PRERENDER_FRAME} {
|
|
103
|
+
transition: opacity .2s linear;
|
|
104
|
+
z-index: 200;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
#${uid} > iframe.${CLASS.VISIBLE} {
|
|
108
|
+
opacity: 1;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
#${uid} > iframe.${CLASS.INVISIBLE} {
|
|
112
|
+
opacity: 0;
|
|
113
|
+
pointer-events: none;
|
|
114
|
+
}
|
|
115
|
+
`}
|
|
116
|
+
</style>
|
|
117
|
+
|
|
118
|
+
<node el={frame} />
|
|
119
|
+
<node el={prerenderFrame} />
|
|
120
|
+
</div>
|
|
121
|
+
).render(dom({ doc }));
|
|
122
|
+
|
|
123
|
+
return element;
|
|
124
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
/** @jsx node */
|
|
3
|
+
|
|
4
|
+
import { node, type ChildType } from "@krakenjs/jsx-pragmatic/src";
|
|
5
|
+
import type { ZoidProps } from "@krakenjs/zoid/src";
|
|
6
|
+
|
|
7
|
+
import { type SavedPaymentMethodsProps } from "./props";
|
|
8
|
+
|
|
9
|
+
type PrerenderedSavedPaymentMethodsProps = {|
|
|
10
|
+
nonce: ?string,
|
|
11
|
+
props: ZoidProps<SavedPaymentMethodsProps>,
|
|
12
|
+
|};
|
|
13
|
+
|
|
14
|
+
export function PrerenderedSavedPaymentMethods({
|
|
15
|
+
nonce,
|
|
16
|
+
}: // props,
|
|
17
|
+
PrerenderedSavedPaymentMethodsProps): ChildType {
|
|
18
|
+
return (
|
|
19
|
+
<html>
|
|
20
|
+
<head>
|
|
21
|
+
<style nonce={nonce}>
|
|
22
|
+
{`
|
|
23
|
+
* {
|
|
24
|
+
box-sizing: border-box;
|
|
25
|
+
}
|
|
26
|
+
body {
|
|
27
|
+
margin: 0;
|
|
28
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
29
|
+
}
|
|
30
|
+
.saved-payment-methods-loading {
|
|
31
|
+
display: flex;
|
|
32
|
+
align-items: center;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
height: 100vh;
|
|
35
|
+
color: #999;
|
|
36
|
+
}
|
|
37
|
+
`}
|
|
38
|
+
</style>
|
|
39
|
+
</head>
|
|
40
|
+
<body>
|
|
41
|
+
<div class="saved-payment-methods-loading">...</div>
|
|
42
|
+
</body>
|
|
43
|
+
</html>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
|
|
3
|
+
import type { FundingEligibilityType } from "@paypal/sdk-client/src";
|
|
4
|
+
import {
|
|
5
|
+
ENV,
|
|
6
|
+
INTENT,
|
|
7
|
+
PLATFORM,
|
|
8
|
+
type LocaleType,
|
|
9
|
+
} from "@paypal/sdk-constants/src";
|
|
10
|
+
|
|
11
|
+
import type { Experiment } from "../../types";
|
|
12
|
+
import type {
|
|
13
|
+
CreateOrder,
|
|
14
|
+
GetPrerenderDetails,
|
|
15
|
+
HidePayPalAppSwitchOverlay,
|
|
16
|
+
OnApprove,
|
|
17
|
+
OnCancel,
|
|
18
|
+
OnClick,
|
|
19
|
+
OnComplete,
|
|
20
|
+
OnShippingAddressChange,
|
|
21
|
+
OnShippingOptionsChange,
|
|
22
|
+
ShowPayPalAppSwitchOverlay,
|
|
23
|
+
} from "../../ui/buttons/props";
|
|
24
|
+
|
|
25
|
+
/** Mirrors smart-payment-buttons SavedPaymentMethodsStyleConfig root keys (partial overrides). */
|
|
26
|
+
export type SavedPaymentMethodsStyleRootInput = {|
|
|
27
|
+
backgroundColor?: string,
|
|
28
|
+
fontFamily?: string,
|
|
29
|
+
textColorBase?: string,
|
|
30
|
+
fontSizeBase?: string,
|
|
31
|
+
primaryColor?: string,
|
|
32
|
+
|};
|
|
33
|
+
|
|
34
|
+
/** Mirrors smart-payment-buttons SavedPaymentMethodsStyleConfig component keys (partial overrides). */
|
|
35
|
+
export type SavedPaymentMethodsStyleComponentInput = {|
|
|
36
|
+
height?: string,
|
|
37
|
+
padding?: string,
|
|
38
|
+
borderRadius?: string,
|
|
39
|
+
borderColor?: string,
|
|
40
|
+
borderWidth?: string,
|
|
41
|
+
|};
|
|
42
|
+
|
|
43
|
+
/** Mirrors smart-payment-buttons SavedPaymentMethodsStyleConfig layout keys (partial overrides). */
|
|
44
|
+
export type SavedPaymentMethodsStyleLayoutInput = {|
|
|
45
|
+
logo?: boolean,
|
|
46
|
+
label?: boolean,
|
|
47
|
+
message?: boolean,
|
|
48
|
+
logoWidth?: string,
|
|
49
|
+
logoLabelGap?: string,
|
|
50
|
+
labelFiGap?: string,
|
|
51
|
+
labelFontSize?: string,
|
|
52
|
+
fiTextFontSize?: string,
|
|
53
|
+
iconSize?: string,
|
|
54
|
+
|};
|
|
55
|
+
|
|
56
|
+
export type SavedPaymentMethodsStyleInputs = {|
|
|
57
|
+
root?: SavedPaymentMethodsStyleRootInput,
|
|
58
|
+
component?: SavedPaymentMethodsStyleComponentInput,
|
|
59
|
+
layout?: SavedPaymentMethodsStyleLayoutInput,
|
|
60
|
+
|};
|
|
61
|
+
|
|
62
|
+
export type SavedPaymentMethodsProps = {|
|
|
63
|
+
// app switch properties
|
|
64
|
+
appSwitchWhenAvailable?: boolean,
|
|
65
|
+
preferences?: {|
|
|
66
|
+
appSwitchWhenAvailable?: boolean,
|
|
67
|
+
launchAppSwitchIn?: "newTab" | "sameTab",
|
|
68
|
+
|},
|
|
69
|
+
listenForHashChanges: () => void,
|
|
70
|
+
removeListenerForHashChanges: () => void,
|
|
71
|
+
// Not passed to child iframe
|
|
72
|
+
// change any to HashChangeEvent when we move to typescript
|
|
73
|
+
// eslint-disable-next-line flowtype/no-weak-types
|
|
74
|
+
hashChangeHandler: (event: any) => void,
|
|
75
|
+
listenForVisibilityChange: () => void,
|
|
76
|
+
removeListenerForVisibilityChanges: () => void,
|
|
77
|
+
visibilityChangeHandler: () => void,
|
|
78
|
+
showPayPalAppSwitchOverlay: (args: ShowPayPalAppSwitchOverlay) => void,
|
|
79
|
+
hidePayPalAppSwitchOverlay: (args: HidePayPalAppSwitchOverlay) => void,
|
|
80
|
+
|
|
81
|
+
intent?: $Values<typeof INTENT>,
|
|
82
|
+
createOrder: CreateOrder,
|
|
83
|
+
currency?: string,
|
|
84
|
+
onCancel?: OnCancel,
|
|
85
|
+
onApprove: OnApprove,
|
|
86
|
+
onComplete?: OnComplete,
|
|
87
|
+
onClick?: OnClick,
|
|
88
|
+
getPrerenderDetails?: GetPrerenderDetails,
|
|
89
|
+
style?: SavedPaymentMethodsStyleInputs,
|
|
90
|
+
locale?: LocaleType,
|
|
91
|
+
commit?: boolean,
|
|
92
|
+
env?: $Values<typeof ENV>,
|
|
93
|
+
stage?: string,
|
|
94
|
+
stageUrl?: string,
|
|
95
|
+
platform?: $Values<typeof PLATFORM>,
|
|
96
|
+
fundingEligibility?: FundingEligibilityType,
|
|
97
|
+
clientID?: string,
|
|
98
|
+
sessionID?: string,
|
|
99
|
+
buttonLocation?: string,
|
|
100
|
+
buttonSessionID: string,
|
|
101
|
+
onShippingAddressChange: ?OnShippingAddressChange,
|
|
102
|
+
onShippingOptionsChange: ?OnShippingOptionsChange,
|
|
103
|
+
hasShippingCallback: boolean,
|
|
104
|
+
clientAccessToken?: ?string,
|
|
105
|
+
customerId?: ?string,
|
|
106
|
+
nonce?: string,
|
|
107
|
+
merchantID?: $ReadOnlyArray<string>,
|
|
108
|
+
merchantRequestedPopupsDisabled?: ?boolean,
|
|
109
|
+
userIDToken?: ?string,
|
|
110
|
+
experiment?: Experiment,
|
|
111
|
+
supportsPopups?: boolean,
|
|
112
|
+
supportedNativeBrowser?: boolean,
|
|
113
|
+
supportedNativeVenmoBrowser?: boolean,
|
|
114
|
+
meta?: {||},
|
|
115
|
+
userAgent: string,
|
|
116
|
+
|};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Utility functions for SavedPaymentMethods component
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const STYLE_ROOT_KEYS: Set<string> = new Set([
|
|
8
|
+
"backgroundColor",
|
|
9
|
+
"fontFamily",
|
|
10
|
+
"textColorBase",
|
|
11
|
+
"fontSizeBase",
|
|
12
|
+
"primaryColor",
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
const STYLE_COMPONENT_KEYS: Set<string> = new Set([
|
|
16
|
+
"height",
|
|
17
|
+
"padding",
|
|
18
|
+
"borderRadius",
|
|
19
|
+
"borderColor",
|
|
20
|
+
"borderWidth",
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
const STYLE_LAYOUT_FIELD_TYPES: {|
|
|
24
|
+
[string]: "string" | "boolean",
|
|
25
|
+
|} = {
|
|
26
|
+
logo: "boolean",
|
|
27
|
+
label: "boolean",
|
|
28
|
+
message: "boolean",
|
|
29
|
+
logoWidth: "string",
|
|
30
|
+
logoLabelGap: "string",
|
|
31
|
+
labelFiGap: "string",
|
|
32
|
+
labelFontSize: "string",
|
|
33
|
+
fiTextFontSize: "string",
|
|
34
|
+
iconSize: "string",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function assertPlainObject(value: mixed, path: string): void {
|
|
38
|
+
if (value === undefined || value === null) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
42
|
+
throw new TypeError(`Expected ${path} to be a plain object`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Validates `style` against the shape used by smart-payment-buttons
|
|
48
|
+
* `saved-payment-methods.jsx` (root / component / layout partials).
|
|
49
|
+
*/
|
|
50
|
+
export function validateSavedPaymentMethodsStyle(style: mixed): void {
|
|
51
|
+
if (style === undefined || style === null) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
assertPlainObject(style, "style");
|
|
56
|
+
|
|
57
|
+
// $FlowFixMe[incompatible-type]
|
|
58
|
+
const s: Object = style;
|
|
59
|
+
const topKeys = Object.keys(s);
|
|
60
|
+
const allowedTop = new Set(["root", "component", "layout"]);
|
|
61
|
+
|
|
62
|
+
for (const key of topKeys) {
|
|
63
|
+
if (!allowedTop.has(key)) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Invalid style key: ${key}. Expected only root, component, and layout`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (s.root !== undefined && s.root !== null) {
|
|
71
|
+
assertPlainObject(s.root, "style.root");
|
|
72
|
+
// $FlowFixMe[prop-missing]
|
|
73
|
+
const root: Object = s.root;
|
|
74
|
+
for (const key of Object.keys(root)) {
|
|
75
|
+
if (!STYLE_ROOT_KEYS.has(key)) {
|
|
76
|
+
throw new Error(`Invalid style.root key: ${key}`);
|
|
77
|
+
}
|
|
78
|
+
if (typeof root[key] !== "string") {
|
|
79
|
+
throw new TypeError(`Expected style.root.${key} to be a string`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (s.component !== undefined && s.component !== null) {
|
|
85
|
+
assertPlainObject(s.component, "style.component");
|
|
86
|
+
// $FlowFixMe[prop-missing]
|
|
87
|
+
const component: Object = s.component;
|
|
88
|
+
for (const key of Object.keys(component)) {
|
|
89
|
+
if (!STYLE_COMPONENT_KEYS.has(key)) {
|
|
90
|
+
throw new Error(`Invalid style.component key: ${key}`);
|
|
91
|
+
}
|
|
92
|
+
if (typeof component[key] !== "string") {
|
|
93
|
+
throw new TypeError(`Expected style.component.${key} to be a string`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (s.layout !== undefined && s.layout !== null) {
|
|
99
|
+
assertPlainObject(s.layout, "style.layout");
|
|
100
|
+
// $FlowFixMe[prop-missing]
|
|
101
|
+
const layout: Object = s.layout;
|
|
102
|
+
for (const key of Object.keys(layout)) {
|
|
103
|
+
const expected = STYLE_LAYOUT_FIELD_TYPES[key];
|
|
104
|
+
if (!expected) {
|
|
105
|
+
throw new Error(`Invalid style.layout key: ${key}`);
|
|
106
|
+
}
|
|
107
|
+
const actual = typeof layout[key];
|
|
108
|
+
if (actual !== expected) {
|
|
109
|
+
throw new TypeError(
|
|
110
|
+
`Expected style.layout.${key} to be a ${expected}, got: ${layout[key]}`
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
|
|
5
|
+
import { validateSavedPaymentMethodsStyle } from "./util";
|
|
6
|
+
|
|
7
|
+
describe("validateSavedPaymentMethodsStyle", () => {
|
|
8
|
+
it("allows undefined, null, and empty object", () => {
|
|
9
|
+
expect(() => validateSavedPaymentMethodsStyle(undefined)).not.toThrow();
|
|
10
|
+
expect(() => validateSavedPaymentMethodsStyle(null)).not.toThrow();
|
|
11
|
+
expect(() => validateSavedPaymentMethodsStyle({})).not.toThrow();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("allows a valid style with root, component, and layout", () => {
|
|
15
|
+
expect(() =>
|
|
16
|
+
validateSavedPaymentMethodsStyle({
|
|
17
|
+
root: {
|
|
18
|
+
backgroundColor: "#fff",
|
|
19
|
+
fontFamily: "Arial",
|
|
20
|
+
textColorBase: "#000",
|
|
21
|
+
fontSizeBase: "16px",
|
|
22
|
+
primaryColor: "#0070ba",
|
|
23
|
+
},
|
|
24
|
+
component: {
|
|
25
|
+
height: "32px",
|
|
26
|
+
padding: "6px 9px",
|
|
27
|
+
borderRadius: "6px",
|
|
28
|
+
borderColor: "transparent",
|
|
29
|
+
borderWidth: "0",
|
|
30
|
+
},
|
|
31
|
+
layout: {
|
|
32
|
+
logo: true,
|
|
33
|
+
label: true,
|
|
34
|
+
message: false,
|
|
35
|
+
logoWidth: "45px",
|
|
36
|
+
logoLabelGap: "12px",
|
|
37
|
+
labelFiGap: "8px",
|
|
38
|
+
labelFontSize: "16px",
|
|
39
|
+
fiTextFontSize: "14px",
|
|
40
|
+
iconSize: "28px",
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
).not.toThrow();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("allows partial root, component, or layout only", () => {
|
|
47
|
+
expect(() =>
|
|
48
|
+
validateSavedPaymentMethodsStyle({
|
|
49
|
+
root: { backgroundColor: "transparent" },
|
|
50
|
+
})
|
|
51
|
+
).not.toThrow();
|
|
52
|
+
expect(() =>
|
|
53
|
+
validateSavedPaymentMethodsStyle({
|
|
54
|
+
component: { height: "40px" },
|
|
55
|
+
})
|
|
56
|
+
).not.toThrow();
|
|
57
|
+
expect(() =>
|
|
58
|
+
validateSavedPaymentMethodsStyle({
|
|
59
|
+
layout: { logo: false },
|
|
60
|
+
})
|
|
61
|
+
).not.toThrow();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("rejects non-plain-object style", () => {
|
|
65
|
+
expect(() => validateSavedPaymentMethodsStyle("")).toThrow(TypeError);
|
|
66
|
+
expect(() => validateSavedPaymentMethodsStyle(1)).toThrow(TypeError);
|
|
67
|
+
expect(() => validateSavedPaymentMethodsStyle([])).toThrow(TypeError);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("rejects unknown top-level keys", () => {
|
|
71
|
+
expect(() => validateSavedPaymentMethodsStyle({ color: "red" })).toThrow(
|
|
72
|
+
/Invalid style key: color/
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("rejects non-object root", () => {
|
|
77
|
+
expect(() => validateSavedPaymentMethodsStyle({ root: [] })).toThrow(
|
|
78
|
+
/Expected style\.root to be a plain object/
|
|
79
|
+
);
|
|
80
|
+
expect(() => validateSavedPaymentMethodsStyle({ root: "x" })).toThrow(
|
|
81
|
+
/Expected style\.root to be a plain object/
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("rejects unknown root keys and non-string root values", () => {
|
|
86
|
+
expect(() =>
|
|
87
|
+
validateSavedPaymentMethodsStyle({ root: { unknown: "a" } })
|
|
88
|
+
).toThrow(/Invalid style\.root key: unknown/);
|
|
89
|
+
expect(() =>
|
|
90
|
+
validateSavedPaymentMethodsStyle({ root: { backgroundColor: 1 } })
|
|
91
|
+
).toThrow(/Expected style\.root\.backgroundColor to be a string/);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("rejects unknown component keys and non-string component values", () => {
|
|
95
|
+
expect(() =>
|
|
96
|
+
validateSavedPaymentMethodsStyle({ component: { width: "1" } })
|
|
97
|
+
).toThrow(/Invalid style\.component key: width/);
|
|
98
|
+
expect(() =>
|
|
99
|
+
validateSavedPaymentMethodsStyle({ component: { height: true } })
|
|
100
|
+
).toThrow(/Expected style\.component\.height to be a string/);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("rejects unknown layout keys", () => {
|
|
104
|
+
expect(() =>
|
|
105
|
+
validateSavedPaymentMethodsStyle({ layout: { extra: true } })
|
|
106
|
+
).toThrow(/Invalid style\.layout key: extra/);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("rejects layout fields with wrong types", () => {
|
|
110
|
+
expect(() =>
|
|
111
|
+
validateSavedPaymentMethodsStyle({ layout: { logo: "yes" } })
|
|
112
|
+
).toThrow(/Expected style\.layout\.logo to be a boolean/);
|
|
113
|
+
expect(() =>
|
|
114
|
+
validateSavedPaymentMethodsStyle({ layout: { logoWidth: true } })
|
|
115
|
+
).toThrow(/Expected style\.layout\.logoWidth to be a string/);
|
|
116
|
+
});
|
|
117
|
+
});
|