@windstream/react-shared-components 0.1.94 → 0.1.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +635 -635
- package/dist/contentful/index.esm.js +3 -3
- package/dist/contentful/index.esm.js.map +1 -1
- package/dist/contentful/index.js +3 -3
- package/dist/contentful/index.js.map +1 -1
- package/dist/core.d.ts +4 -4
- package/dist/index.esm.js +5 -13
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +5 -13
- package/dist/index.js.map +1 -1
- package/dist/next/index.esm.js +2 -2
- package/dist/next/index.esm.js.map +1 -1
- package/dist/next/index.js +2 -2
- package/dist/next/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/utils/index.esm.js +1 -1
- package/dist/utils/index.esm.js.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +191 -191
- package/src/components/accordion/Accordion.stories.tsx +230 -230
- package/src/components/accordion/index.test.tsx +270 -270
- package/src/components/accordion/index.tsx +70 -70
- package/src/components/accordion/types.ts +12 -12
- package/src/components/alert-card/AlertCard.stories.tsx +171 -171
- package/src/components/alert-card/index.test.tsx +152 -152
- package/src/components/alert-card/index.tsx +41 -41
- package/src/components/alert-card/types.ts +13 -13
- package/src/components/animation-wrapper/index.test.tsx +424 -424
- package/src/components/animation-wrapper/index.tsx +129 -129
- package/src/components/animation-wrapper/types.ts +11 -11
- package/src/components/brand-button/BrandButton.stories.tsx +223 -223
- package/src/components/brand-button/helpers.ts +35 -35
- package/src/components/brand-button/index.test.tsx +292 -292
- package/src/components/brand-button/index.tsx +120 -120
- package/src/components/brand-button/types.ts +38 -38
- package/src/components/button/Button.stories.tsx +108 -108
- package/src/components/button/index.test.tsx +91 -91
- package/src/components/button/index.tsx +27 -27
- package/src/components/button/types.ts +14 -14
- package/src/components/call-button/CallButton.stories.tsx +324 -324
- package/src/components/call-button/index.test.tsx +260 -260
- package/src/components/call-button/index.tsx +106 -106
- package/src/components/call-button/types.ts +16 -16
- package/src/components/checkbox/Checkbox.stories.tsx +247 -247
- package/src/components/checkbox/index.test.tsx +252 -252
- package/src/components/checkbox/index.tsx +197 -197
- package/src/components/checkbox/types.ts +27 -27
- package/src/components/checklist/Checklist.stories.tsx +150 -150
- package/src/components/checklist/index.test.tsx +231 -231
- package/src/components/checklist/index.tsx +96 -96
- package/src/components/checklist/types.ts +23 -23
- package/src/components/collapse/Collapse.stories.tsx +255 -255
- package/src/components/collapse/index.test.tsx +277 -277
- package/src/components/collapse/index.tsx +47 -47
- package/src/components/collapse/types.ts +6 -6
- package/src/components/divider/Divider.stories.tsx +205 -205
- package/src/components/divider/index.test.tsx +53 -53
- package/src/components/divider/index.tsx +22 -22
- package/src/components/divider/type.ts +3 -3
- package/src/components/image/Image.stories.tsx +113 -113
- package/src/components/image/index.test.tsx +174 -174
- package/src/components/image/index.tsx +25 -25
- package/src/components/image/types.ts +40 -40
- package/src/components/input/Input.stories.tsx +325 -325
- package/src/components/input/index.test.tsx +348 -348
- package/src/components/input/index.tsx +177 -177
- package/src/components/input/types.ts +37 -37
- package/src/components/link/Link.stories.tsx +163 -163
- package/src/components/link/index.test.tsx +199 -199
- package/src/components/link/index.tsx +116 -116
- package/src/components/link/types.ts +25 -25
- package/src/components/list/List.stories.tsx +272 -272
- package/src/components/list/index.test.tsx +166 -166
- package/src/components/list/index.tsx +88 -88
- package/src/components/list/list-item/index.tsx +38 -38
- package/src/components/list/list-item/types.ts +13 -13
- package/src/components/list/types.ts +29 -29
- package/src/components/material-icon/MaterialIcon.stories.tsx +322 -322
- package/src/components/material-icon/constants.ts +99 -99
- package/src/components/material-icon/index.test.tsx +130 -130
- package/src/components/material-icon/index.tsx +47 -47
- package/src/components/material-icon/types.ts +31 -31
- package/src/components/modal/Modal.stories.tsx +171 -171
- package/src/components/modal/index.test.tsx +310 -310
- package/src/components/modal/index.tsx +164 -164
- package/src/components/modal/types.ts +24 -24
- package/src/components/next-image/index.test.tsx +406 -406
- package/src/components/next-image/index.tsx +74 -74
- package/src/components/next-image/types.ts +1 -1
- package/src/components/pagination/index.test.tsx +521 -521
- package/src/components/pagination/index.tsx +91 -91
- package/src/components/pagination/types.ts +6 -6
- package/src/components/radio-button/RadioButton.stories.tsx +307 -307
- package/src/components/radio-button/index.test.tsx +151 -151
- package/src/components/radio-button/index.tsx +75 -75
- package/src/components/radio-button/types.ts +21 -21
- package/src/components/see-more/SeeMore.stories.tsx +181 -181
- package/src/components/see-more/index.test.tsx +96 -96
- package/src/components/see-more/index.tsx +44 -44
- package/src/components/see-more/types.ts +4 -4
- package/src/components/select/Select.stories.tsx +411 -411
- package/src/components/select/index.test.tsx +256 -256
- package/src/components/select/index.tsx +155 -155
- package/src/components/select/types.ts +36 -36
- package/src/components/select-plan-button/SelectPlanButton.stories.tsx +184 -184
- package/src/components/select-plan-button/index.test.tsx +173 -173
- package/src/components/select-plan-button/index.tsx +63 -63
- package/src/components/select-plan-button/types.ts +17 -17
- package/src/components/skeleton/Skeleton.stories.tsx +179 -179
- package/src/components/skeleton/index.test.tsx +74 -74
- package/src/components/skeleton/index.tsx +61 -61
- package/src/components/skeleton/types.ts +4 -4
- package/src/components/spinner/Spinner.stories.tsx +335 -335
- package/src/components/spinner/index.test.tsx +76 -76
- package/src/components/spinner/index.tsx +44 -44
- package/src/components/spinner/types.ts +5 -5
- package/src/components/text/Text.stories.tsx +321 -321
- package/src/components/text/index.test.tsx +65 -65
- package/src/components/text/index.tsx +25 -25
- package/src/components/text/types.ts +45 -45
- package/src/components/tooltip/Tooltip.stories.tsx +219 -219
- package/src/components/tooltip/index.test.tsx +50 -50
- package/src/components/tooltip/index.tsx +74 -74
- package/src/components/tooltip/types.ts +7 -7
- package/src/components/view-cart-button/ViewCartButton.stories.tsx +252 -252
- package/src/components/view-cart-button/index.test.tsx +57 -57
- package/src/components/view-cart-button/index.tsx +42 -42
- package/src/components/view-cart-button/types.ts +5 -5
- package/src/contentful/blocks/accordion/Accordion.stories.mocks.tsx +128 -128
- package/src/contentful/blocks/accordion/Accordion.stories.tsx +98 -98
- package/src/contentful/blocks/accordion/index.test.tsx +218 -218
- package/src/contentful/blocks/accordion/index.tsx +114 -114
- package/src/contentful/blocks/accordion/types.ts +34 -34
- package/src/contentful/blocks/address-input-banner/index.test.tsx +132 -132
- package/src/contentful/blocks/address-input-banner/index.tsx +52 -52
- package/src/contentful/blocks/address-input-banner/types.ts +14 -14
- package/src/contentful/blocks/anchored-bottom-banner/index.test.tsx +287 -287
- package/src/contentful/blocks/anchored-bottom-banner/index.tsx +181 -181
- package/src/contentful/blocks/anchored-bottom-banner/types.ts +13 -13
- package/src/contentful/blocks/blogs-grid/BlogGrid.stories.mocks.tsx +144 -144
- package/src/contentful/blocks/blogs-grid/BlogGrid.stories.tsx +157 -157
- package/src/contentful/blocks/blogs-grid/index.test.tsx +355 -355
- package/src/contentful/blocks/blogs-grid/index.tsx +134 -134
- package/src/contentful/blocks/blogs-grid/types.ts +26 -26
- package/src/contentful/blocks/blogs-grid-base/index.test.tsx +274 -274
- package/src/contentful/blocks/blogs-grid-base/index.tsx +119 -119
- package/src/contentful/blocks/blogs-grid-base/types.ts +36 -36
- package/src/contentful/blocks/breadcrumbs/BreadcrumbNavigation.stories.tsx +147 -147
- package/src/contentful/blocks/breadcrumbs/index.test.tsx +281 -281
- package/src/contentful/blocks/breadcrumbs/index.tsx +95 -95
- package/src/contentful/blocks/breadcrumbs/types.ts +8 -8
- package/src/contentful/blocks/button/Button.stories.tsx +40 -40
- package/src/contentful/blocks/button/index.test.tsx +339 -339
- package/src/contentful/blocks/button/index.tsx +131 -131
- package/src/contentful/blocks/button/types.ts +39 -39
- package/src/contentful/blocks/callout/Callout.stories.tsx +23 -23
- package/src/contentful/blocks/callout/index.test.tsx +539 -539
- package/src/contentful/blocks/callout/index.tsx +277 -277
- package/src/contentful/blocks/callout/types.ts +78 -78
- package/src/contentful/blocks/cards/Cards.stories.tsx +23 -23
- package/src/contentful/blocks/cards/blog-card/index.test.tsx +218 -218
- package/src/contentful/blocks/cards/blog-card/index.tsx +129 -129
- package/src/contentful/blocks/cards/blog-card/types.ts +34 -34
- package/src/contentful/blocks/cards/floating-image-card/index.test.tsx +201 -201
- package/src/contentful/blocks/cards/floating-image-card/index.tsx +119 -119
- package/src/contentful/blocks/cards/floating-image-card/types.ts +30 -30
- package/src/contentful/blocks/cards/full-image-card/index.test.tsx +216 -216
- package/src/contentful/blocks/cards/full-image-card/index.tsx +130 -130
- package/src/contentful/blocks/cards/full-image-card/types.ts +29 -29
- package/src/contentful/blocks/cards/index.test.tsx +39 -39
- package/src/contentful/blocks/cards/index.tsx +13 -13
- package/src/contentful/blocks/cards/product-card/index.test.tsx +263 -263
- package/src/contentful/blocks/cards/product-card/index.tsx +251 -251
- package/src/contentful/blocks/cards/product-card/types.ts +28 -28
- package/src/contentful/blocks/cards/simple-card/index.test.tsx +364 -364
- package/src/contentful/blocks/cards/simple-card/index.tsx +325 -325
- package/src/contentful/blocks/cards/simple-card/types.ts +71 -71
- package/src/contentful/blocks/cards/testimonial-card/index.test.tsx +180 -180
- package/src/contentful/blocks/cards/testimonial-card/index.tsx +90 -90
- package/src/contentful/blocks/cards/testimonial-card/types.tsx +12 -12
- package/src/contentful/blocks/cards/types.ts +1 -1
- package/src/contentful/blocks/carousel/Carousel.stories.tsx +23 -23
- package/src/contentful/blocks/carousel/helper.test.tsx +539 -539
- package/src/contentful/blocks/carousel/helper.tsx +494 -494
- package/src/contentful/blocks/carousel/index.test.tsx +308 -308
- package/src/contentful/blocks/carousel/index.tsx +87 -87
- package/src/contentful/blocks/carousel/types.test.ts +16 -16
- package/src/contentful/blocks/carousel/types.ts +145 -145
- package/src/contentful/blocks/cart-retention-banner/index.test.tsx +409 -409
- package/src/contentful/blocks/cart-retention-banner/index.tsx +109 -109
- package/src/contentful/blocks/cart-retention-banner/types.ts +11 -11
- package/src/contentful/blocks/comparison-table/index.test.tsx +114 -114
- package/src/contentful/blocks/comparison-table/index.tsx +29 -29
- package/src/contentful/blocks/comparison-table/types.ts +6 -6
- package/src/contentful/blocks/cookiebanner/index.test.tsx +277 -277
- package/src/contentful/blocks/cookiebanner/index.tsx +146 -146
- package/src/contentful/blocks/cookiebanner/type.ts +7 -7
- package/src/contentful/blocks/cta-callout/CtaCallout.stories.tsx +46 -46
- package/src/contentful/blocks/cta-callout/index.test.tsx +244 -244
- package/src/contentful/blocks/cta-callout/index.tsx +73 -73
- package/src/contentful/blocks/cta-callout/types.ts +26 -26
- package/src/contentful/blocks/dynamic-tabs/index.test.tsx +240 -240
- package/src/contentful/blocks/dynamic-tabs/index.tsx +204 -204
- package/src/contentful/blocks/dynamic-tabs/types.ts +21 -21
- package/src/contentful/blocks/email-input-block/index.test.tsx +213 -213
- package/src/contentful/blocks/email-input-block/index.tsx +121 -121
- package/src/contentful/blocks/email-input-block/types.ts +16 -16
- package/src/contentful/blocks/find-kinetic/FindKinetic.stories.tsx +23 -23
- package/src/contentful/blocks/find-kinetic/index.test.tsx +269 -269
- package/src/contentful/blocks/find-kinetic/index.tsx +138 -138
- package/src/contentful/blocks/find-kinetic/types.ts +20 -20
- package/src/contentful/blocks/floating-banner/FloatingBanner.stories.tsx +34 -34
- package/src/contentful/blocks/floating-banner/index.test.tsx +246 -246
- package/src/contentful/blocks/floating-banner/index.tsx +97 -97
- package/src/contentful/blocks/floating-banner/types.ts +22 -22
- package/src/contentful/blocks/footer/Footer.stories.tsx +317 -317
- package/src/contentful/blocks/footer/index.test.tsx +302 -302
- package/src/contentful/blocks/footer/index.tsx +91 -91
- package/src/contentful/blocks/footer/types.ts +13 -13
- package/src/contentful/blocks/image-promo-bar/ImagePromoBar.stories.tsx +23 -23
- package/src/contentful/blocks/image-promo-bar/helper.test.tsx +61 -61
- package/src/contentful/blocks/image-promo-bar/helper.tsx +28 -28
- package/src/contentful/blocks/image-promo-bar/index.test.tsx +467 -467
- package/src/contentful/blocks/image-promo-bar/index.tsx +8 -6
- package/src/contentful/blocks/image-promo-bar/types.ts +44 -44
- package/src/contentful/blocks/image-promo-bar/vimeo-embed.test.tsx +142 -142
- package/src/contentful/blocks/image-promo-bar/vimeo-embed.tsx +93 -93
- package/src/contentful/blocks/image-promo-bar/youtube-embed.test.tsx +104 -104
- package/src/contentful/blocks/image-promo-bar/youtube-embed.tsx +46 -46
- package/src/contentful/blocks/modal/constants.ts +53 -53
- package/src/contentful/blocks/modal/index.test.tsx +209 -209
- package/src/contentful/blocks/modal/index.tsx +108 -108
- package/src/contentful/blocks/modal/types.ts +12 -12
- package/src/contentful/blocks/navigation/Navigation.stories.mocks.tsx +78 -78
- package/src/contentful/blocks/navigation/Navigation.stories.tsx +138 -138
- package/src/contentful/blocks/navigation/desktop-link-groups.tsx/index.test.tsx +208 -208
- package/src/contentful/blocks/navigation/desktop-link-groups.tsx/index.tsx +141 -141
- package/src/contentful/blocks/navigation/index.test.tsx +924 -924
- package/src/contentful/blocks/navigation/index.tsx +569 -569
- package/src/contentful/blocks/navigation/mobile-link-groups.tsx/index.test.tsx +131 -131
- package/src/contentful/blocks/navigation/mobile-link-groups.tsx/index.tsx +82 -82
- package/src/contentful/blocks/navigation/types.ts +71 -71
- package/src/contentful/blocks/primary-hero/PrimaryHero.stories.tsx +23 -23
- package/src/contentful/blocks/primary-hero/index.test.tsx +286 -286
- package/src/contentful/blocks/primary-hero/index.tsx +239 -239
- package/src/contentful/blocks/primary-hero/types.ts +37 -37
- package/src/contentful/blocks/search-block/index.test.tsx +268 -268
- package/src/contentful/blocks/search-block/index.tsx +90 -90
- package/src/contentful/blocks/search-block/types.ts +15 -15
- package/src/contentful/blocks/shape-background-wrapper/ShapeBackgroundWrapper.stories.tsx +26 -26
- package/src/contentful/blocks/shape-background-wrapper/index.test.tsx +284 -284
- package/src/contentful/blocks/shape-background-wrapper/index.tsx +124 -124
- package/src/contentful/blocks/shape-background-wrapper/types.ts +36 -36
- package/src/contentful/blocks/text/Text.stories.tsx +23 -23
- package/src/contentful/blocks/text/index.test.tsx +36 -36
- package/src/contentful/blocks/text/index.tsx +12 -12
- package/src/contentful/blocks/text/types.ts +1 -1
- package/src/contentful/index.test.ts +45 -45
- package/src/contentful/index.ts +105 -105
- package/src/global-mocks/contentful/to-document.ts +25 -25
- package/src/global-mocks/cookie.ts +48 -48
- package/src/global-mocks/cx.ts +37 -37
- package/src/global-mocks/index.ts +89 -89
- package/src/global-mocks/speed-card-bg.ts +27 -27
- package/src/global-mocks/utm.ts +49 -49
- package/src/hooks/contentful/use-contentful-rich-text.test.tsx +1758 -1758
- package/src/hooks/contentful/use-contentful-rich-text.tsx +309 -309
- package/src/hooks/contentful/use-processed-check-list.test.tsx +277 -277
- package/src/hooks/contentful/use-processed-check-list.ts +63 -63
- package/src/hooks/use-body-scroll-lock.test.ts +134 -134
- package/src/hooks/use-body-scroll-lock.ts +34 -34
- package/src/hooks/use-carousel-swipe.test.ts +393 -393
- package/src/hooks/use-carousel-swipe.ts +264 -264
- package/src/hooks/use-outside-click.test.ts +142 -142
- package/src/hooks/use-outside-click.ts +17 -17
- package/src/index.ts +107 -107
- package/src/next/index.test.ts +7 -7
- package/src/next/index.ts +5 -5
- package/src/setupTests.ts +52 -52
- package/src/stories/DocsTemplate.tsx +24 -24
- package/src/styles/globals.css +343 -343
- package/src/types/global.d.ts +9 -9
- package/src/types/micro-components.ts +99 -99
- package/src/types/utm.ts +49 -49
- package/src/utils/contentful/to-document.test.ts +85 -85
- package/src/utils/contentful/to-document.ts +24 -24
- package/src/utils/cookie.test.ts +180 -180
- package/src/utils/cookie.ts +84 -84
- package/src/utils/cx.test.ts +90 -90
- package/src/utils/cx.ts +49 -49
- package/src/utils/index.test.ts +115 -115
- package/src/utils/index.ts +41 -41
- package/src/utils/speed-card-bg.test.ts +46 -46
- package/src/utils/speed-card-bg.ts +24 -24
- package/src/utils/utm.test.ts +359 -359
- package/src/utils/utm.ts +221 -221
|
@@ -1,409 +1,409 @@
|
|
|
1
|
-
import "@testing-library/jest-dom";
|
|
2
|
-
|
|
3
|
-
import CartRetentionBanner from "./index";
|
|
4
|
-
import { TypeCartRetentionBannerFields } from "./types";
|
|
5
|
-
|
|
6
|
-
import { act, fireEvent, render, screen } from "@testing-library/react";
|
|
7
|
-
|
|
8
|
-
// Mock dependencies
|
|
9
|
-
jest.mock("@shared/components/text", () => ({
|
|
10
|
-
Text: ({ children, ...props }: any) => <span {...props}>{children}</span>,
|
|
11
|
-
}));
|
|
12
|
-
|
|
13
|
-
jest.mock("@shared/contentful/blocks/button", () => ({
|
|
14
|
-
Button: ({ children, onClick, buttonLabel, ...props }: any) => (
|
|
15
|
-
<button onClick={onClick} data-testid="banner-button" {...props}>
|
|
16
|
-
{buttonLabel || children}
|
|
17
|
-
</button>
|
|
18
|
-
),
|
|
19
|
-
}));
|
|
20
|
-
|
|
21
|
-
jest.mock("@shared/contentful/blocks/modal", () => ({
|
|
22
|
-
Modal: ({ isOpen, onRequestClose, children, ...props }: any) => (
|
|
23
|
-
<div data-testid="modal" data-open={isOpen} data-type={props.type}>
|
|
24
|
-
{isOpen && (
|
|
25
|
-
<>
|
|
26
|
-
<button data-testid="modal-close" onClick={onRequestClose}>
|
|
27
|
-
Close
|
|
28
|
-
</button>
|
|
29
|
-
{children}
|
|
30
|
-
</>
|
|
31
|
-
)}
|
|
32
|
-
</div>
|
|
33
|
-
),
|
|
34
|
-
}));
|
|
35
|
-
|
|
36
|
-
jest.mock("@shared/hooks/contentful/use-contentful-rich-text", () => ({
|
|
37
|
-
renderContentfulRichText: (doc: any, _: any, className: string) => (
|
|
38
|
-
<div data-testid="rich-text" className={className}>
|
|
39
|
-
Rich Text Content
|
|
40
|
-
</div>
|
|
41
|
-
),
|
|
42
|
-
}));
|
|
43
|
-
|
|
44
|
-
jest.mock("@shared/utils/contentful/to-document", () => ({
|
|
45
|
-
toDocument: (json: any) => json,
|
|
46
|
-
}));
|
|
47
|
-
|
|
48
|
-
describe("CartRetentionBanner", () => {
|
|
49
|
-
const defaultFields: TypeCartRetentionBannerFields = {
|
|
50
|
-
entryTitle: "Cart Banner",
|
|
51
|
-
anchorId: "cart-banner",
|
|
52
|
-
mainHeading: "Welcome back!",
|
|
53
|
-
description: { json: { content: [{ nodeType: "paragraph" }] } },
|
|
54
|
-
cta: { buttonLabel: "Continue checkout" },
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
beforeEach(() => {
|
|
58
|
-
jest.useFakeTimers();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
afterEach(() => {
|
|
62
|
-
jest.useRealTimers();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
describe("modal behavior", () => {
|
|
66
|
-
it("renders a section with anchorId", () => {
|
|
67
|
-
render(<CartRetentionBanner fields={defaultFields} />);
|
|
68
|
-
const section = document.querySelector("section#cart-banner");
|
|
69
|
-
expect(section).toBeInTheDocument();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it("renders with data-testid cart-retention-banner", () => {
|
|
73
|
-
render(<CartRetentionBanner fields={defaultFields} />);
|
|
74
|
-
expect(screen.getByTestId("cart-retention-banner")).toBeInTheDocument();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it("opens modal when checkShouldShowBanner returns true", async () => {
|
|
78
|
-
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
79
|
-
render(
|
|
80
|
-
<CartRetentionBanner
|
|
81
|
-
fields={defaultFields}
|
|
82
|
-
checkShouldShowBanner={checkShouldShowBanner}
|
|
83
|
-
/>
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
// Allow useEffect to fire
|
|
87
|
-
act(() => {
|
|
88
|
-
jest.advanceTimersByTime(200);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
const modal = screen.getByTestId("modal");
|
|
92
|
-
expect(modal).toHaveAttribute("data-open", "true");
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it("does not open modal when checkShouldShowBanner returns false", () => {
|
|
96
|
-
const checkShouldShowBanner = jest.fn().mockReturnValue(false);
|
|
97
|
-
render(
|
|
98
|
-
<CartRetentionBanner
|
|
99
|
-
fields={defaultFields}
|
|
100
|
-
checkShouldShowBanner={checkShouldShowBanner}
|
|
101
|
-
/>
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
act(() => {
|
|
105
|
-
jest.advanceTimersByTime(200);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
const modal = screen.getByTestId("modal");
|
|
109
|
-
expect(modal).toHaveAttribute("data-open", "false");
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it("calls onBannerShown when modal opens", () => {
|
|
113
|
-
const onBannerShown = jest.fn();
|
|
114
|
-
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
115
|
-
render(
|
|
116
|
-
<CartRetentionBanner
|
|
117
|
-
fields={defaultFields}
|
|
118
|
-
checkShouldShowBanner={checkShouldShowBanner}
|
|
119
|
-
onBannerShown={onBannerShown}
|
|
120
|
-
/>
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
act(() => {
|
|
124
|
-
jest.advanceTimersByTime(200);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
expect(onBannerShown).toHaveBeenCalled();
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it("closes modal and calls onClose", () => {
|
|
131
|
-
const onClose = jest.fn();
|
|
132
|
-
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
133
|
-
render(
|
|
134
|
-
<CartRetentionBanner
|
|
135
|
-
fields={defaultFields}
|
|
136
|
-
checkShouldShowBanner={checkShouldShowBanner}
|
|
137
|
-
onClose={onClose}
|
|
138
|
-
/>
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
act(() => {
|
|
142
|
-
jest.advanceTimersByTime(200);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
fireEvent.click(screen.getByTestId("modal-close"));
|
|
146
|
-
expect(onClose).toHaveBeenCalled();
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it("calls onContinueCheckout when CTA button is clicked in modal", () => {
|
|
150
|
-
const onContinueCheckout = jest.fn();
|
|
151
|
-
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
152
|
-
render(
|
|
153
|
-
<CartRetentionBanner
|
|
154
|
-
fields={defaultFields}
|
|
155
|
-
checkShouldShowBanner={checkShouldShowBanner}
|
|
156
|
-
onContinueCheckout={onContinueCheckout}
|
|
157
|
-
/>
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
act(() => {
|
|
161
|
-
jest.advanceTimersByTime(200);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
fireEvent.click(screen.getByTestId("banner-button"));
|
|
165
|
-
expect(onContinueCheckout).toHaveBeenCalled();
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it("uses default heading when mainHeading is not provided", () => {
|
|
169
|
-
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
170
|
-
const fields = { ...defaultFields, mainHeading: undefined };
|
|
171
|
-
render(
|
|
172
|
-
<CartRetentionBanner
|
|
173
|
-
fields={fields}
|
|
174
|
-
checkShouldShowBanner={checkShouldShowBanner}
|
|
175
|
-
/>
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
act(() => {
|
|
179
|
-
jest.advanceTimersByTime(200);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
expect(screen.getByText(/Welcome back/i)).toBeInTheDocument();
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
it("uses default CTA label when cta.buttonLabel is not provided", () => {
|
|
186
|
-
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
187
|
-
const fields = { ...defaultFields, cta: {} };
|
|
188
|
-
render(
|
|
189
|
-
<CartRetentionBanner
|
|
190
|
-
fields={fields}
|
|
191
|
-
checkShouldShowBanner={checkShouldShowBanner}
|
|
192
|
-
/>
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
act(() => {
|
|
196
|
-
jest.advanceTimersByTime(200);
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
expect(screen.getByTestId("banner-button")).toHaveTextContent(
|
|
200
|
-
"Continue checkout"
|
|
201
|
-
);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it("renders rich text description in modal", () => {
|
|
205
|
-
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
206
|
-
render(
|
|
207
|
-
<CartRetentionBanner
|
|
208
|
-
fields={defaultFields}
|
|
209
|
-
checkShouldShowBanner={checkShouldShowBanner}
|
|
210
|
-
/>
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
act(() => {
|
|
214
|
-
jest.advanceTimersByTime(200);
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
expect(screen.getByTestId("rich-text")).toBeInTheDocument();
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
it("does not render rich text when description is undefined", () => {
|
|
221
|
-
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
222
|
-
const fields = { ...defaultFields, description: undefined };
|
|
223
|
-
render(
|
|
224
|
-
<CartRetentionBanner
|
|
225
|
-
fields={fields}
|
|
226
|
-
checkShouldShowBanner={checkShouldShowBanner}
|
|
227
|
-
/>
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
act(() => {
|
|
231
|
-
jest.advanceTimersByTime(200);
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
expect(screen.queryByTestId("rich-text")).not.toBeInTheDocument();
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
it("passes type=cart-retention-banner to Modal", () => {
|
|
238
|
-
render(<CartRetentionBanner fields={defaultFields} />);
|
|
239
|
-
const modal = screen.getByTestId("modal");
|
|
240
|
-
expect(modal).toHaveAttribute("data-type", "cart-retention-banner");
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
describe("popup container mode", () => {
|
|
245
|
-
it("renders inline content when isInPopupContainer is true", () => {
|
|
246
|
-
render(
|
|
247
|
-
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
248
|
-
);
|
|
249
|
-
// Should render the pop-up-body div directly
|
|
250
|
-
const popupBody = document.querySelector(".pop-up-body");
|
|
251
|
-
expect(popupBody).toBeInTheDocument();
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
it("renders data-section-type attribute in popup mode", () => {
|
|
255
|
-
render(
|
|
256
|
-
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
257
|
-
);
|
|
258
|
-
const div = document.querySelector(
|
|
259
|
-
'[data-section-type="cart-retention-banner"]'
|
|
260
|
-
);
|
|
261
|
-
expect(div).toBeInTheDocument();
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
it("renders heading in popup mode", () => {
|
|
265
|
-
render(
|
|
266
|
-
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
267
|
-
);
|
|
268
|
-
expect(screen.getByText("Welcome back!")).toBeInTheDocument();
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
it("renders default heading in popup mode when mainHeading is undefined", () => {
|
|
272
|
-
const fields = { ...defaultFields, mainHeading: undefined };
|
|
273
|
-
render(<CartRetentionBanner fields={fields} isInPopupContainer={true} />);
|
|
274
|
-
expect(screen.getByText(/Welcome back/)).toBeInTheDocument();
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
it("renders CTA in popup mode", () => {
|
|
278
|
-
render(
|
|
279
|
-
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
280
|
-
);
|
|
281
|
-
expect(screen.getByTestId("banner-button")).toHaveTextContent(
|
|
282
|
-
"Continue checkout"
|
|
283
|
-
);
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
it("calls onContinueCheckout in popup mode", () => {
|
|
287
|
-
const onContinueCheckout = jest.fn();
|
|
288
|
-
render(
|
|
289
|
-
<CartRetentionBanner
|
|
290
|
-
fields={defaultFields}
|
|
291
|
-
isInPopupContainer={true}
|
|
292
|
-
onContinueCheckout={onContinueCheckout}
|
|
293
|
-
/>
|
|
294
|
-
);
|
|
295
|
-
fireEvent.click(screen.getByTestId("banner-button"));
|
|
296
|
-
expect(onContinueCheckout).toHaveBeenCalled();
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
it("does not render Modal in popup mode", () => {
|
|
300
|
-
render(
|
|
301
|
-
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
302
|
-
);
|
|
303
|
-
expect(screen.queryByTestId("modal")).not.toBeInTheDocument();
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
it("renders rich text in popup mode", () => {
|
|
307
|
-
render(
|
|
308
|
-
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
309
|
-
);
|
|
310
|
-
expect(screen.getByTestId("rich-text")).toBeInTheDocument();
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
describe("timer cleanup", () => {
|
|
315
|
-
it("cleans up timeout on unmount", () => {
|
|
316
|
-
const checkShouldShowBanner = jest.fn().mockReturnValue(false);
|
|
317
|
-
const { unmount } = render(
|
|
318
|
-
<CartRetentionBanner
|
|
319
|
-
fields={defaultFields}
|
|
320
|
-
checkShouldShowBanner={checkShouldShowBanner}
|
|
321
|
-
/>
|
|
322
|
-
);
|
|
323
|
-
unmount();
|
|
324
|
-
// No error should occur after unmount
|
|
325
|
-
act(() => {
|
|
326
|
-
jest.advanceTimersByTime(200);
|
|
327
|
-
});
|
|
328
|
-
});
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
describe("optional callback branches", () => {
|
|
332
|
-
it("handles close without onClose callback", () => {
|
|
333
|
-
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
334
|
-
render(
|
|
335
|
-
<CartRetentionBanner
|
|
336
|
-
fields={defaultFields}
|
|
337
|
-
checkShouldShowBanner={checkShouldShowBanner}
|
|
338
|
-
/>
|
|
339
|
-
);
|
|
340
|
-
|
|
341
|
-
act(() => {
|
|
342
|
-
jest.advanceTimersByTime(200);
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
// Should not throw when clicking close without onClose
|
|
346
|
-
fireEvent.click(screen.getByTestId("modal-close"));
|
|
347
|
-
expect(screen.getByTestId("modal")).toHaveAttribute("data-open", "false");
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
it("handles continue checkout without onContinueCheckout callback", () => {
|
|
351
|
-
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
352
|
-
render(
|
|
353
|
-
<CartRetentionBanner
|
|
354
|
-
fields={defaultFields}
|
|
355
|
-
checkShouldShowBanner={checkShouldShowBanner}
|
|
356
|
-
/>
|
|
357
|
-
);
|
|
358
|
-
|
|
359
|
-
act(() => {
|
|
360
|
-
jest.advanceTimersByTime(200);
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
// Should not throw when clicking CTA without onContinueCheckout
|
|
364
|
-
fireEvent.click(screen.getByTestId("banner-button"));
|
|
365
|
-
expect(screen.getByTestId("banner-button")).toBeInTheDocument();
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
it("handles continue checkout in popup mode without callback", () => {
|
|
369
|
-
render(
|
|
370
|
-
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
371
|
-
);
|
|
372
|
-
// Should not throw
|
|
373
|
-
fireEvent.click(screen.getByTestId("banner-button"));
|
|
374
|
-
expect(screen.getByTestId("banner-button")).toBeInTheDocument();
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
it("opens modal without onBannerShown callback", () => {
|
|
378
|
-
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
379
|
-
render(
|
|
380
|
-
<CartRetentionBanner
|
|
381
|
-
fields={defaultFields}
|
|
382
|
-
checkShouldShowBanner={checkShouldShowBanner}
|
|
383
|
-
/>
|
|
384
|
-
);
|
|
385
|
-
|
|
386
|
-
act(() => {
|
|
387
|
-
jest.advanceTimersByTime(200);
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
expect(screen.getByTestId("modal")).toHaveAttribute("data-open", "true");
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
it("does not open if checkShouldShowBanner is not provided", () => {
|
|
394
|
-
render(<CartRetentionBanner fields={defaultFields} />);
|
|
395
|
-
|
|
396
|
-
act(() => {
|
|
397
|
-
jest.advanceTimersByTime(200);
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
expect(screen.getByTestId("modal")).toHaveAttribute("data-open", "false");
|
|
401
|
-
});
|
|
402
|
-
|
|
403
|
-
it("renders popup without description", () => {
|
|
404
|
-
const fields = { ...defaultFields, description: undefined };
|
|
405
|
-
render(<CartRetentionBanner fields={fields} isInPopupContainer={true} />);
|
|
406
|
-
expect(screen.queryByTestId("rich-text")).not.toBeInTheDocument();
|
|
407
|
-
});
|
|
408
|
-
});
|
|
409
|
-
});
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
|
|
3
|
+
import CartRetentionBanner from "./index";
|
|
4
|
+
import { TypeCartRetentionBannerFields } from "./types";
|
|
5
|
+
|
|
6
|
+
import { act, fireEvent, render, screen } from "@testing-library/react";
|
|
7
|
+
|
|
8
|
+
// Mock dependencies
|
|
9
|
+
jest.mock("@shared/components/text", () => ({
|
|
10
|
+
Text: ({ children, ...props }: any) => <span {...props}>{children}</span>,
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
jest.mock("@shared/contentful/blocks/button", () => ({
|
|
14
|
+
Button: ({ children, onClick, buttonLabel, ...props }: any) => (
|
|
15
|
+
<button onClick={onClick} data-testid="banner-button" {...props}>
|
|
16
|
+
{buttonLabel || children}
|
|
17
|
+
</button>
|
|
18
|
+
),
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
jest.mock("@shared/contentful/blocks/modal", () => ({
|
|
22
|
+
Modal: ({ isOpen, onRequestClose, children, ...props }: any) => (
|
|
23
|
+
<div data-testid="modal" data-open={isOpen} data-type={props.type}>
|
|
24
|
+
{isOpen && (
|
|
25
|
+
<>
|
|
26
|
+
<button data-testid="modal-close" onClick={onRequestClose}>
|
|
27
|
+
Close
|
|
28
|
+
</button>
|
|
29
|
+
{children}
|
|
30
|
+
</>
|
|
31
|
+
)}
|
|
32
|
+
</div>
|
|
33
|
+
),
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
jest.mock("@shared/hooks/contentful/use-contentful-rich-text", () => ({
|
|
37
|
+
renderContentfulRichText: (doc: any, _: any, className: string) => (
|
|
38
|
+
<div data-testid="rich-text" className={className}>
|
|
39
|
+
Rich Text Content
|
|
40
|
+
</div>
|
|
41
|
+
),
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
jest.mock("@shared/utils/contentful/to-document", () => ({
|
|
45
|
+
toDocument: (json: any) => json,
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
describe("CartRetentionBanner", () => {
|
|
49
|
+
const defaultFields: TypeCartRetentionBannerFields = {
|
|
50
|
+
entryTitle: "Cart Banner",
|
|
51
|
+
anchorId: "cart-banner",
|
|
52
|
+
mainHeading: "Welcome back!",
|
|
53
|
+
description: { json: { content: [{ nodeType: "paragraph" }] } },
|
|
54
|
+
cta: { buttonLabel: "Continue checkout" },
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
jest.useFakeTimers();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
afterEach(() => {
|
|
62
|
+
jest.useRealTimers();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("modal behavior", () => {
|
|
66
|
+
it("renders a section with anchorId", () => {
|
|
67
|
+
render(<CartRetentionBanner fields={defaultFields} />);
|
|
68
|
+
const section = document.querySelector("section#cart-banner");
|
|
69
|
+
expect(section).toBeInTheDocument();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("renders with data-testid cart-retention-banner", () => {
|
|
73
|
+
render(<CartRetentionBanner fields={defaultFields} />);
|
|
74
|
+
expect(screen.getByTestId("cart-retention-banner")).toBeInTheDocument();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("opens modal when checkShouldShowBanner returns true", async () => {
|
|
78
|
+
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
79
|
+
render(
|
|
80
|
+
<CartRetentionBanner
|
|
81
|
+
fields={defaultFields}
|
|
82
|
+
checkShouldShowBanner={checkShouldShowBanner}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// Allow useEffect to fire
|
|
87
|
+
act(() => {
|
|
88
|
+
jest.advanceTimersByTime(200);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const modal = screen.getByTestId("modal");
|
|
92
|
+
expect(modal).toHaveAttribute("data-open", "true");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("does not open modal when checkShouldShowBanner returns false", () => {
|
|
96
|
+
const checkShouldShowBanner = jest.fn().mockReturnValue(false);
|
|
97
|
+
render(
|
|
98
|
+
<CartRetentionBanner
|
|
99
|
+
fields={defaultFields}
|
|
100
|
+
checkShouldShowBanner={checkShouldShowBanner}
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
act(() => {
|
|
105
|
+
jest.advanceTimersByTime(200);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const modal = screen.getByTestId("modal");
|
|
109
|
+
expect(modal).toHaveAttribute("data-open", "false");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("calls onBannerShown when modal opens", () => {
|
|
113
|
+
const onBannerShown = jest.fn();
|
|
114
|
+
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
115
|
+
render(
|
|
116
|
+
<CartRetentionBanner
|
|
117
|
+
fields={defaultFields}
|
|
118
|
+
checkShouldShowBanner={checkShouldShowBanner}
|
|
119
|
+
onBannerShown={onBannerShown}
|
|
120
|
+
/>
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
act(() => {
|
|
124
|
+
jest.advanceTimersByTime(200);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(onBannerShown).toHaveBeenCalled();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("closes modal and calls onClose", () => {
|
|
131
|
+
const onClose = jest.fn();
|
|
132
|
+
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
133
|
+
render(
|
|
134
|
+
<CartRetentionBanner
|
|
135
|
+
fields={defaultFields}
|
|
136
|
+
checkShouldShowBanner={checkShouldShowBanner}
|
|
137
|
+
onClose={onClose}
|
|
138
|
+
/>
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
act(() => {
|
|
142
|
+
jest.advanceTimersByTime(200);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
fireEvent.click(screen.getByTestId("modal-close"));
|
|
146
|
+
expect(onClose).toHaveBeenCalled();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("calls onContinueCheckout when CTA button is clicked in modal", () => {
|
|
150
|
+
const onContinueCheckout = jest.fn();
|
|
151
|
+
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
152
|
+
render(
|
|
153
|
+
<CartRetentionBanner
|
|
154
|
+
fields={defaultFields}
|
|
155
|
+
checkShouldShowBanner={checkShouldShowBanner}
|
|
156
|
+
onContinueCheckout={onContinueCheckout}
|
|
157
|
+
/>
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
act(() => {
|
|
161
|
+
jest.advanceTimersByTime(200);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
fireEvent.click(screen.getByTestId("banner-button"));
|
|
165
|
+
expect(onContinueCheckout).toHaveBeenCalled();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("uses default heading when mainHeading is not provided", () => {
|
|
169
|
+
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
170
|
+
const fields = { ...defaultFields, mainHeading: undefined };
|
|
171
|
+
render(
|
|
172
|
+
<CartRetentionBanner
|
|
173
|
+
fields={fields}
|
|
174
|
+
checkShouldShowBanner={checkShouldShowBanner}
|
|
175
|
+
/>
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
act(() => {
|
|
179
|
+
jest.advanceTimersByTime(200);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
expect(screen.getByText(/Welcome back/i)).toBeInTheDocument();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("uses default CTA label when cta.buttonLabel is not provided", () => {
|
|
186
|
+
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
187
|
+
const fields = { ...defaultFields, cta: {} };
|
|
188
|
+
render(
|
|
189
|
+
<CartRetentionBanner
|
|
190
|
+
fields={fields}
|
|
191
|
+
checkShouldShowBanner={checkShouldShowBanner}
|
|
192
|
+
/>
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
act(() => {
|
|
196
|
+
jest.advanceTimersByTime(200);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
expect(screen.getByTestId("banner-button")).toHaveTextContent(
|
|
200
|
+
"Continue checkout"
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("renders rich text description in modal", () => {
|
|
205
|
+
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
206
|
+
render(
|
|
207
|
+
<CartRetentionBanner
|
|
208
|
+
fields={defaultFields}
|
|
209
|
+
checkShouldShowBanner={checkShouldShowBanner}
|
|
210
|
+
/>
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
act(() => {
|
|
214
|
+
jest.advanceTimersByTime(200);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
expect(screen.getByTestId("rich-text")).toBeInTheDocument();
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("does not render rich text when description is undefined", () => {
|
|
221
|
+
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
222
|
+
const fields = { ...defaultFields, description: undefined };
|
|
223
|
+
render(
|
|
224
|
+
<CartRetentionBanner
|
|
225
|
+
fields={fields}
|
|
226
|
+
checkShouldShowBanner={checkShouldShowBanner}
|
|
227
|
+
/>
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
act(() => {
|
|
231
|
+
jest.advanceTimersByTime(200);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
expect(screen.queryByTestId("rich-text")).not.toBeInTheDocument();
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it("passes type=cart-retention-banner to Modal", () => {
|
|
238
|
+
render(<CartRetentionBanner fields={defaultFields} />);
|
|
239
|
+
const modal = screen.getByTestId("modal");
|
|
240
|
+
expect(modal).toHaveAttribute("data-type", "cart-retention-banner");
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
describe("popup container mode", () => {
|
|
245
|
+
it("renders inline content when isInPopupContainer is true", () => {
|
|
246
|
+
render(
|
|
247
|
+
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
248
|
+
);
|
|
249
|
+
// Should render the pop-up-body div directly
|
|
250
|
+
const popupBody = document.querySelector(".pop-up-body");
|
|
251
|
+
expect(popupBody).toBeInTheDocument();
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it("renders data-section-type attribute in popup mode", () => {
|
|
255
|
+
render(
|
|
256
|
+
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
257
|
+
);
|
|
258
|
+
const div = document.querySelector(
|
|
259
|
+
'[data-section-type="cart-retention-banner"]'
|
|
260
|
+
);
|
|
261
|
+
expect(div).toBeInTheDocument();
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it("renders heading in popup mode", () => {
|
|
265
|
+
render(
|
|
266
|
+
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
267
|
+
);
|
|
268
|
+
expect(screen.getByText("Welcome back!")).toBeInTheDocument();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it("renders default heading in popup mode when mainHeading is undefined", () => {
|
|
272
|
+
const fields = { ...defaultFields, mainHeading: undefined };
|
|
273
|
+
render(<CartRetentionBanner fields={fields} isInPopupContainer={true} />);
|
|
274
|
+
expect(screen.getByText(/Welcome back/)).toBeInTheDocument();
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("renders CTA in popup mode", () => {
|
|
278
|
+
render(
|
|
279
|
+
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
280
|
+
);
|
|
281
|
+
expect(screen.getByTestId("banner-button")).toHaveTextContent(
|
|
282
|
+
"Continue checkout"
|
|
283
|
+
);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it("calls onContinueCheckout in popup mode", () => {
|
|
287
|
+
const onContinueCheckout = jest.fn();
|
|
288
|
+
render(
|
|
289
|
+
<CartRetentionBanner
|
|
290
|
+
fields={defaultFields}
|
|
291
|
+
isInPopupContainer={true}
|
|
292
|
+
onContinueCheckout={onContinueCheckout}
|
|
293
|
+
/>
|
|
294
|
+
);
|
|
295
|
+
fireEvent.click(screen.getByTestId("banner-button"));
|
|
296
|
+
expect(onContinueCheckout).toHaveBeenCalled();
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it("does not render Modal in popup mode", () => {
|
|
300
|
+
render(
|
|
301
|
+
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
302
|
+
);
|
|
303
|
+
expect(screen.queryByTestId("modal")).not.toBeInTheDocument();
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it("renders rich text in popup mode", () => {
|
|
307
|
+
render(
|
|
308
|
+
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
309
|
+
);
|
|
310
|
+
expect(screen.getByTestId("rich-text")).toBeInTheDocument();
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
describe("timer cleanup", () => {
|
|
315
|
+
it("cleans up timeout on unmount", () => {
|
|
316
|
+
const checkShouldShowBanner = jest.fn().mockReturnValue(false);
|
|
317
|
+
const { unmount } = render(
|
|
318
|
+
<CartRetentionBanner
|
|
319
|
+
fields={defaultFields}
|
|
320
|
+
checkShouldShowBanner={checkShouldShowBanner}
|
|
321
|
+
/>
|
|
322
|
+
);
|
|
323
|
+
unmount();
|
|
324
|
+
// No error should occur after unmount
|
|
325
|
+
act(() => {
|
|
326
|
+
jest.advanceTimersByTime(200);
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
describe("optional callback branches", () => {
|
|
332
|
+
it("handles close without onClose callback", () => {
|
|
333
|
+
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
334
|
+
render(
|
|
335
|
+
<CartRetentionBanner
|
|
336
|
+
fields={defaultFields}
|
|
337
|
+
checkShouldShowBanner={checkShouldShowBanner}
|
|
338
|
+
/>
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
act(() => {
|
|
342
|
+
jest.advanceTimersByTime(200);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
// Should not throw when clicking close without onClose
|
|
346
|
+
fireEvent.click(screen.getByTestId("modal-close"));
|
|
347
|
+
expect(screen.getByTestId("modal")).toHaveAttribute("data-open", "false");
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it("handles continue checkout without onContinueCheckout callback", () => {
|
|
351
|
+
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
352
|
+
render(
|
|
353
|
+
<CartRetentionBanner
|
|
354
|
+
fields={defaultFields}
|
|
355
|
+
checkShouldShowBanner={checkShouldShowBanner}
|
|
356
|
+
/>
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
act(() => {
|
|
360
|
+
jest.advanceTimersByTime(200);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// Should not throw when clicking CTA without onContinueCheckout
|
|
364
|
+
fireEvent.click(screen.getByTestId("banner-button"));
|
|
365
|
+
expect(screen.getByTestId("banner-button")).toBeInTheDocument();
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it("handles continue checkout in popup mode without callback", () => {
|
|
369
|
+
render(
|
|
370
|
+
<CartRetentionBanner fields={defaultFields} isInPopupContainer={true} />
|
|
371
|
+
);
|
|
372
|
+
// Should not throw
|
|
373
|
+
fireEvent.click(screen.getByTestId("banner-button"));
|
|
374
|
+
expect(screen.getByTestId("banner-button")).toBeInTheDocument();
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it("opens modal without onBannerShown callback", () => {
|
|
378
|
+
const checkShouldShowBanner = jest.fn().mockReturnValue(true);
|
|
379
|
+
render(
|
|
380
|
+
<CartRetentionBanner
|
|
381
|
+
fields={defaultFields}
|
|
382
|
+
checkShouldShowBanner={checkShouldShowBanner}
|
|
383
|
+
/>
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
act(() => {
|
|
387
|
+
jest.advanceTimersByTime(200);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
expect(screen.getByTestId("modal")).toHaveAttribute("data-open", "true");
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it("does not open if checkShouldShowBanner is not provided", () => {
|
|
394
|
+
render(<CartRetentionBanner fields={defaultFields} />);
|
|
395
|
+
|
|
396
|
+
act(() => {
|
|
397
|
+
jest.advanceTimersByTime(200);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
expect(screen.getByTestId("modal")).toHaveAttribute("data-open", "false");
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it("renders popup without description", () => {
|
|
404
|
+
const fields = { ...defaultFields, description: undefined };
|
|
405
|
+
render(<CartRetentionBanner fields={fields} isInPopupContainer={true} />);
|
|
406
|
+
expect(screen.queryByTestId("rich-text")).not.toBeInTheDocument();
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
});
|