@akinon/pz-theme 2.0.37-beta.0 → 2.0.37
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/CHANGELOG.md +4 -4
- package/package.json +4 -4
- package/src/__tests__/__snapshots__/facet-filters-block.test.tsx.snap +11 -0
- package/src/__tests__/custom-css.test.ts +181 -0
- package/src/__tests__/designer-chrome-clipping.test.tsx +497 -0
- package/src/__tests__/facet-filters-block.test.tsx +707 -0
- package/src/__tests__/item-template.test.tsx +184 -0
- package/src/__tests__/listing-controls.test.tsx +961 -0
- package/src/__tests__/part-style-scope.test.tsx +229 -0
- package/src/__tests__/part-styles.test.ts +311 -0
- package/src/__tests__/registry-parity.test.ts +42 -0
- package/src/__tests__/row-visibility.test.ts +672 -0
- package/src/__tests__/sort-select-page-cursor.test.tsx +336 -0
- package/src/__tests__/theme-block-html-id.test.tsx +167 -0
- package/src/blocks/__tests__/__snapshots__/product-gallery-block.test.tsx.snap +15 -0
- package/src/blocks/__tests__/accordion-block-state.test.tsx +201 -0
- package/src/blocks/__tests__/facet-filters-block.test.tsx +190 -0
- package/src/blocks/__tests__/listing-context-card-model.test.tsx +230 -0
- package/src/blocks/__tests__/listing-lookup-hardening.test.ts +80 -0
- package/src/blocks/__tests__/product-gallery-block.test.tsx +974 -0
- package/src/blocks/__tests__/product-grid-composition.test.tsx +570 -0
- package/src/blocks/__tests__/product-grid-lookups.test.tsx +230 -0
- package/src/blocks/__tests__/product-price-block.test.tsx +248 -0
- package/src/blocks/__tests__/product-recommendations-block.test.tsx +702 -0
- package/src/blocks/__tests__/share-block.test.tsx +392 -0
- package/src/blocks/__tests__/store-locator-block.test.tsx +691 -0
- package/src/blocks/__tests__/variant-selector-block.test.tsx +817 -0
- package/src/blocks/__tests__/variant-selector-golden.json +20 -0
- package/src/blocks/account-menu-block.tsx +264 -0
- package/src/blocks/add-to-cart-block.tsx +417 -0
- package/src/blocks/address-list-block.tsx +348 -0
- package/src/blocks/applied-filters-block.tsx +288 -0
- package/src/blocks/auth-form-block.tsx +295 -0
- package/src/blocks/basket-items-block.tsx +457 -0
- package/src/blocks/basket-summary-block.tsx +404 -0
- package/src/blocks/block-renderer-registry.tsx +94 -0
- package/src/blocks/change-password-form-block.tsx +240 -0
- package/src/blocks/checkout-steps-block.tsx +288 -0
- package/src/blocks/checkout-summary-block.tsx +449 -0
- package/src/blocks/countdown-block.tsx +182 -0
- package/src/blocks/coupon-list-block.tsx +292 -0
- package/src/blocks/facet-filters-block.tsx +1686 -0
- package/src/blocks/faq-accordion-block.tsx +358 -0
- package/src/blocks/favorite-button-block.tsx +252 -0
- package/src/blocks/favourites-grid-block.tsx +510 -0
- package/src/blocks/forgot-password-block.tsx +155 -0
- package/src/blocks/item-template-utils.ts +131 -0
- package/src/blocks/item-template.tsx +164 -0
- package/src/blocks/listing-breadcrumb-block.tsx +175 -0
- package/src/blocks/listing-context.ts +850 -0
- package/src/blocks/listing-pagination-block.tsx +923 -0
- package/src/blocks/listing-result-count-block.tsx +126 -0
- package/src/blocks/listing-title-block.tsx +115 -0
- package/src/blocks/oauth-buttons-block.tsx +205 -0
- package/src/blocks/order-detail-block.tsx +474 -0
- package/src/blocks/order-list-block.tsx +274 -0
- package/src/blocks/order-success-block.tsx +641 -0
- package/src/blocks/order-tracking-block.tsx +533 -0
- package/src/blocks/product-attributes-block.tsx +307 -0
- package/src/blocks/product-block-utils.tsx +639 -0
- package/src/blocks/product-breadcrumb-block.tsx +215 -0
- package/src/blocks/product-description-block.tsx +169 -0
- package/src/blocks/product-gallery-block.tsx +1523 -0
- package/src/blocks/product-grid-block.tsx +966 -0
- package/src/blocks/product-price-block.tsx +373 -0
- package/src/blocks/product-recommendations-block.tsx +1433 -0
- package/src/blocks/product-title-block.tsx +129 -0
- package/src/blocks/profile-form-block.tsx +297 -0
- package/src/blocks/recently-viewed-store.ts +201 -0
- package/src/blocks/register-form-block.tsx +362 -0
- package/src/blocks/share-block.tsx +667 -0
- package/src/blocks/size-guide-block.tsx +313 -0
- package/src/blocks/sort-select-block.tsx +636 -0
- package/src/blocks/stock-status-block.tsx +168 -0
- package/src/blocks/store-locator-block.tsx +1184 -0
- package/src/blocks/variant-selector-block.tsx +1110 -0
- package/src/sections/__tests__/tablet-raw-bucket-readers.test.tsx +186 -0
- package/src/utils/__tests__/part-ownership-guard.test.tsx +29 -4
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The readers that go at a per-breakpoint bucket by hand.
|
|
3
|
+
*
|
|
4
|
+
* `getResponsiveValue` knows where a breakpoint looks when it has nothing of
|
|
5
|
+
* its own. A handful of renderers never asked it — they index the bucket
|
|
6
|
+
* themselves and fall straight to `desktop`. That was harmless while `mobile`
|
|
7
|
+
* was the only other key there was, and it is a live regression the moment a
|
|
8
|
+
* viewport starts reporting `tablet`: at 900px these readers stop seeing the
|
|
9
|
+
* mobile value they saw the day before and hand back the desktop one.
|
|
10
|
+
*
|
|
11
|
+
* Every case below is a composition that authored desktop and mobile and
|
|
12
|
+
* nothing else. The assertion is always the same shape — what 900px renders
|
|
13
|
+
* must be what 767px renders, because that is what it rendered before this
|
|
14
|
+
* breakpoint existed.
|
|
15
|
+
*/
|
|
16
|
+
import React from 'react';
|
|
17
|
+
import { render, screen } from '@testing-library/react';
|
|
18
|
+
|
|
19
|
+
jest.mock('../../theme-block', () => ({
|
|
20
|
+
__esModule: true,
|
|
21
|
+
default: ({ block }: { block: { id?: string } }) => (
|
|
22
|
+
<div data-testid="tb" data-id={block?.id} />
|
|
23
|
+
)
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
import TabsSection from '../tabs-section';
|
|
27
|
+
import ContactFormSection from '../contact-form-section';
|
|
28
|
+
import OrderTrackingLookupSection from '../order-tracking-lookup-section';
|
|
29
|
+
import ImageGalleryBlock from '../../blocks/image-gallery-block';
|
|
30
|
+
import type { Section } from '../../theme-section';
|
|
31
|
+
|
|
32
|
+
const makeSection = (overrides: Record<string, unknown>): Section =>
|
|
33
|
+
({
|
|
34
|
+
id: 'section-1',
|
|
35
|
+
name: 'S',
|
|
36
|
+
label: 'S',
|
|
37
|
+
properties: {},
|
|
38
|
+
styles: {},
|
|
39
|
+
blocks: [],
|
|
40
|
+
order: 0,
|
|
41
|
+
hidden: false,
|
|
42
|
+
...overrides
|
|
43
|
+
} as unknown as Section);
|
|
44
|
+
|
|
45
|
+
describe('tabs-section reads the max-width bucket', () => {
|
|
46
|
+
// `max-width: full` on a phone, `narrow` on a desktop: the container is
|
|
47
|
+
// edge-to-edge below 1024 and centred above it.
|
|
48
|
+
const section = makeSection({
|
|
49
|
+
type: 'tabs',
|
|
50
|
+
styles: { 'max-width': { desktop: 'narrow', mobile: 'full' } },
|
|
51
|
+
blocks: [
|
|
52
|
+
{
|
|
53
|
+
id: 't1',
|
|
54
|
+
type: 'tab',
|
|
55
|
+
label: 'One',
|
|
56
|
+
blocks: [
|
|
57
|
+
{ id: 't1-header', label: 'Tab Header', blocks: [] },
|
|
58
|
+
{ id: 't1-content', label: 'Tab Content', blocks: [] }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const containerClassAt = (breakpoint: string): string => {
|
|
65
|
+
const { container, unmount } = render(
|
|
66
|
+
<TabsSection section={section} currentBreakpoint={breakpoint} />
|
|
67
|
+
);
|
|
68
|
+
const className = (container.firstChild as HTMLElement).className;
|
|
69
|
+
unmount();
|
|
70
|
+
return className;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
it('keeps the mobile width across the whole band below 1024', () => {
|
|
74
|
+
expect(containerClassAt('tablet')).toBe(containerClassAt('mobile'));
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('does not centre a container the composition asked to run full-width', () => {
|
|
78
|
+
const className = containerClassAt('tablet');
|
|
79
|
+
expect(className).toContain('w-full');
|
|
80
|
+
expect(className).not.toContain('mx-auto');
|
|
81
|
+
expect(className).not.toContain('max-w-4xl');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('still reads the desktop value on a desktop', () => {
|
|
85
|
+
expect(containerClassAt('desktop')).toContain('max-w-4xl');
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('image-gallery-block reads the alt bucket', () => {
|
|
90
|
+
const block = {
|
|
91
|
+
id: 'gallery-1',
|
|
92
|
+
blocks: [
|
|
93
|
+
{
|
|
94
|
+
id: 'img-1',
|
|
95
|
+
type: 'image',
|
|
96
|
+
value: 'https://cdn/a.jpg',
|
|
97
|
+
properties: { alt: { desktop: 'Full product shot', mobile: 'Product' } }
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const altAt = (breakpoint: string): string => {
|
|
103
|
+
const { unmount } = render(
|
|
104
|
+
<ImageGalleryBlock
|
|
105
|
+
{...({
|
|
106
|
+
block,
|
|
107
|
+
placeholderId: 'ph',
|
|
108
|
+
sectionId: 'sec',
|
|
109
|
+
isDesigner: false,
|
|
110
|
+
selectedBlockId: null,
|
|
111
|
+
currentBreakpoint: breakpoint
|
|
112
|
+
} as never)}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
const alt = (screen.getByRole('img') as HTMLImageElement).alt;
|
|
116
|
+
unmount();
|
|
117
|
+
return alt;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
it('keeps the mobile alt text across the whole band below 1024', () => {
|
|
121
|
+
expect(altAt('tablet')).toBe(altAt('mobile'));
|
|
122
|
+
expect(altAt('tablet')).toBe('Product');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('still reads the desktop alt text on a desktop', () => {
|
|
126
|
+
expect(altAt('desktop')).toBe('Full product shot');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe('contact-form-section reads a property bucket', () => {
|
|
131
|
+
const section = makeSection({
|
|
132
|
+
type: 'contact-form',
|
|
133
|
+
properties: {
|
|
134
|
+
'button-text': { desktop: 'Send us a message', mobile: 'Send' }
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const buttonTextAt = (breakpoint: string): string => {
|
|
139
|
+
const { unmount } = render(
|
|
140
|
+
<ContactFormSection section={section} currentBreakpoint={breakpoint} />
|
|
141
|
+
);
|
|
142
|
+
const text = screen.getByRole('button', { name: /send/i }).textContent ?? '';
|
|
143
|
+
unmount();
|
|
144
|
+
return text;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
it('keeps the mobile label across the whole band below 1024', () => {
|
|
148
|
+
expect(buttonTextAt('tablet')).toBe(buttonTextAt('mobile'));
|
|
149
|
+
expect(buttonTextAt('tablet')).toBe('Send');
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('still reads the desktop label on a desktop', () => {
|
|
153
|
+
expect(buttonTextAt('desktop')).toBe('Send us a message');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('order-tracking-lookup-section reads a property bucket', () => {
|
|
158
|
+
const section = makeSection({
|
|
159
|
+
type: 'order-tracking-lookup',
|
|
160
|
+
properties: {
|
|
161
|
+
'button-text': { desktop: 'Track my order', mobile: 'Track' }
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const buttonTextAt = (breakpoint: string): string => {
|
|
166
|
+
const { unmount } = render(
|
|
167
|
+
<OrderTrackingLookupSection
|
|
168
|
+
section={section}
|
|
169
|
+
currentBreakpoint={breakpoint}
|
|
170
|
+
/>
|
|
171
|
+
);
|
|
172
|
+
const text =
|
|
173
|
+
screen.getByRole('button', { name: /track/i }).textContent ?? '';
|
|
174
|
+
unmount();
|
|
175
|
+
return text;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
it('keeps the mobile label across the whole band below 1024', () => {
|
|
179
|
+
expect(buttonTextAt('tablet')).toBe(buttonTextAt('mobile'));
|
|
180
|
+
expect(buttonTextAt('tablet')).toBe('Track');
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('still reads the desktop label on a desktop', () => {
|
|
184
|
+
expect(buttonTextAt('desktop')).toBe('Track my order');
|
|
185
|
+
});
|
|
186
|
+
});
|
|
@@ -62,6 +62,21 @@ const accordion = (
|
|
|
62
62
|
]
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
+
const faq = (id: string) => ({
|
|
66
|
+
id,
|
|
67
|
+
type: 'faq-accordion',
|
|
68
|
+
label: 'FAQ',
|
|
69
|
+
value: '',
|
|
70
|
+
properties: { searchable: true },
|
|
71
|
+
styles: {},
|
|
72
|
+
order: 0,
|
|
73
|
+
hidden: false,
|
|
74
|
+
blocks: [
|
|
75
|
+
group(`${id}-q1`, 'First question', [text(`${id}-a1`)]),
|
|
76
|
+
group(`${id}-q2`, 'Second question', [text(`${id}-a2`)])
|
|
77
|
+
]
|
|
78
|
+
});
|
|
79
|
+
|
|
65
80
|
const sectionOf = (root: unknown): Section[] =>
|
|
66
81
|
[
|
|
67
82
|
{
|
|
@@ -194,10 +209,20 @@ describe('the guard reaches every level, not just the first', () => {
|
|
|
194
209
|
});
|
|
195
210
|
|
|
196
211
|
describe('the guard never costs a block a part it owns', () => {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
212
|
+
it('across nested containers built from shipped renderers', () => {
|
|
213
|
+
const { container } = renderRoot(
|
|
214
|
+
accordion('outer', {}, [
|
|
215
|
+
faq('faq-1'),
|
|
216
|
+
accordion('nested', {}, [faq('faq-2')])
|
|
217
|
+
])
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
// Premise: the sweep below is meaningless if nothing rendered a part.
|
|
221
|
+
expect(
|
|
222
|
+
container.querySelectorAll('[data-part]').length
|
|
223
|
+
).toBeGreaterThanOrEqual(20);
|
|
224
|
+
expect(partsTheirOwnBlockCannotReach(container)).toEqual([]);
|
|
225
|
+
});
|
|
201
226
|
|
|
202
227
|
it('across repeated rows, which share one style identity', () => {
|
|
203
228
|
const expanded = buildIteratorBlock({
|