@akinon/pz-theme 2.0.166-rc.1 → 2.0.166
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 +7 -60
- package/package.json +4 -4
- package/src/__tests__/editor-locale-bridge.test.tsx +1 -32
- package/src/blocks/__tests__/order-detail-layout.test.tsx +311 -0
- package/src/blocks/__tests__/text-block.test.tsx +6 -34
- package/src/blocks/order-detail-block.tsx +273 -115
- package/src/blocks/text-block.tsx +2 -6
- package/src/custom/README.md +219 -100
- package/src/custom/__tests__/use-theme-setting.test.tsx +0 -97
- package/src/custom/collect.ts +9 -4
- package/src/custom/property-types.ts +15 -15
- package/src/custom/use-theme-setting.ts +5 -21
- package/src/editor-locale-bridge.tsx +11 -39
- package/src/theme-block.tsx +26 -2
- package/src/theme-placeholder-wrapper.tsx +0 -3
- package/src/utils/iterator-utils.ts +11 -0
- package/src/blocks/__tests__/order-line-actions.test.tsx +0 -54
- package/src/blocks/order-line-actions.ts +0 -45
- package/src/utils/__tests__/sanitize-rich-text.test.ts +0 -80
- package/src/utils/sanitize-rich-text.ts +0 -215
package/CHANGELOG.md
CHANGED
|
@@ -1,65 +1,12 @@
|
|
|
1
1
|
# @akinon/pz-theme
|
|
2
2
|
|
|
3
|
-
## 2.0.166
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
- @akinon/
|
|
10
|
-
- @akinon/theme-contract@2.0.166-rc.1
|
|
11
|
-
|
|
12
|
-
## 2.0.166-rc.0
|
|
13
|
-
|
|
14
|
-
### Patch Changes
|
|
15
|
-
|
|
16
|
-
- 8e040731e: ZERO-5235: let brands hang actions on order detail lines
|
|
17
|
-
- c761b9fd4: ZERO-5296: fall back to the storefront default language in the text block
|
|
18
|
-
- 17a598dae: ZERO-5296: report the storefront default language to the editor
|
|
19
|
-
- 3b05a407d: ZERO-5232: allow richtext settings on custom blocks
|
|
20
|
-
- Updated dependencies [86187b1c2]
|
|
21
|
-
- Updated dependencies [08390a87]
|
|
22
|
-
- Updated dependencies [0cf9ea239]
|
|
23
|
-
- Updated dependencies [324f97d55]
|
|
24
|
-
- Updated dependencies [4c3465ae]
|
|
25
|
-
- Updated dependencies [51ea06888]
|
|
26
|
-
- Updated dependencies
|
|
27
|
-
- Updated dependencies [549da545]
|
|
28
|
-
- Updated dependencies [2fea41430]
|
|
29
|
-
- Updated dependencies [b55acb768]
|
|
30
|
-
- Updated dependencies [760258c1c]
|
|
31
|
-
- Updated dependencies [143be2b9d]
|
|
32
|
-
- Updated dependencies [7889b08fe]
|
|
33
|
-
- Updated dependencies [9f8cd3bc5]
|
|
34
|
-
- Updated dependencies [d635d345]
|
|
35
|
-
- Updated dependencies [bfafa3f49]
|
|
36
|
-
- Updated dependencies [d860c917]
|
|
37
|
-
- Updated dependencies [ac6cada1]
|
|
38
|
-
- Updated dependencies [e90c0e02]
|
|
39
|
-
- Updated dependencies [dc7f9ca5]
|
|
40
|
-
- Updated dependencies [57d7eb305]
|
|
41
|
-
- Updated dependencies [0145dc3f]
|
|
42
|
-
- Updated dependencies [d99a6a7d5]
|
|
43
|
-
- Updated dependencies [92086b29]
|
|
44
|
-
- Updated dependencies [227b7408]
|
|
45
|
-
- Updated dependencies [9db81a714]
|
|
46
|
-
- Updated dependencies [591e345e1]
|
|
47
|
-
- Updated dependencies [4de5303c5]
|
|
48
|
-
- Updated dependencies [95b139dc1]
|
|
49
|
-
- Updated dependencies [1d00f2d06]
|
|
50
|
-
- Updated dependencies [4ac7b2a1e]
|
|
51
|
-
- Updated dependencies [4998a9631]
|
|
52
|
-
- Updated dependencies [804d2bd6c]
|
|
53
|
-
- Updated dependencies [3909d3224]
|
|
54
|
-
- Updated dependencies [6a3d8a631]
|
|
55
|
-
- Updated dependencies [e18836b20]
|
|
56
|
-
- Updated dependencies [b1111d7b1]
|
|
57
|
-
- Updated dependencies [1595d458e]
|
|
58
|
-
- Updated dependencies [dca128112]
|
|
59
|
-
- Updated dependencies [9a7b0937]
|
|
60
|
-
- Updated dependencies [8853822c]
|
|
61
|
-
- @akinon/next@2.0.166-rc.0
|
|
62
|
-
- @akinon/theme-contract@2.0.166-rc.0
|
|
3
|
+
## 2.0.166
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f6871947: ZERO-5509: The order-detail block can hand its whole page to a child group with role `order-detail-layout`. The group is drawn once over the order in place of the built-in markup: its blocks bind `item.*` to the order (number, date, status, totals, discounts, installments, invoice / cancel / tracking links, addresses, payment), already formatted with the block's money style, and a repeat over `item.lines` draws the line rows. Line rows (also in the existing row layout) now carry color, size, tracking, carrier, return code / method / carrier / pickup date, and are scoped as a one-line order so the rate & review action placed in a line rates that line only. Clones of a repeat inside a row now open a row scope for their entry (`Block.itemScopeRow`). Without a layout the block renders exactly as before.
|
|
8
|
+
- @akinon/next@2.0.166
|
|
9
|
+
- @akinon/theme-contract@2.0.166
|
|
63
10
|
|
|
64
11
|
## 2.0.165
|
|
65
12
|
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/pz-theme",
|
|
3
3
|
"description": "Theme package for Project Zero Next — ThemePlaceholder system and theme editor infrastructure",
|
|
4
|
-
"version": "2.0.166
|
|
4
|
+
"version": "2.0.166",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"test": "jest"
|
|
9
9
|
},
|
|
10
10
|
"peerDependencies": {
|
|
11
|
-
"@akinon/next": "2.0.166
|
|
11
|
+
"@akinon/next": "2.0.166",
|
|
12
12
|
"react": "^18.0.0 || ^19.0.0",
|
|
13
13
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@akinon/theme-contract": "2.0.166
|
|
16
|
+
"@akinon/theme-contract": "2.0.166",
|
|
17
17
|
"clsx": "2.1.1",
|
|
18
18
|
"lottie-web": "^5.13.0",
|
|
19
19
|
"react-multi-carousel": "2.8.4",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"zod": "4.4.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@akinon/next": "2.0.166
|
|
24
|
+
"@akinon/next": "2.0.166",
|
|
25
25
|
"@testing-library/jest-dom": "5.16.4",
|
|
26
26
|
"@testing-library/react": "16.3.2",
|
|
27
27
|
"@testing-library/user-event": "14.1.1",
|
|
@@ -28,7 +28,6 @@ const SETTINGS_LOCALES = [
|
|
|
28
28
|
const mockLocalization = {
|
|
29
29
|
locale: 'tr',
|
|
30
30
|
locales: SETTINGS_LOCALES as Array<Record<string, unknown>>,
|
|
31
|
-
defaultLocaleValue: 'tr',
|
|
32
31
|
setLocale: jest.fn()
|
|
33
32
|
};
|
|
34
33
|
|
|
@@ -107,7 +106,6 @@ beforeEach(() => {
|
|
|
107
106
|
postMessage.mockClear();
|
|
108
107
|
mockLocalization.locale = 'tr';
|
|
109
108
|
mockLocalization.locales = SETTINGS_LOCALES;
|
|
110
|
-
mockLocalization.defaultLocaleValue = 'tr';
|
|
111
109
|
mockLocalization.setLocale = jest.fn();
|
|
112
110
|
delete (window as { __iframeReadySent?: boolean }).__iframeReadySent;
|
|
113
111
|
});
|
|
@@ -146,8 +144,7 @@ describe('inside the editor', () => {
|
|
|
146
144
|
{ value: 'en', label: 'English' },
|
|
147
145
|
{ value: 'tr', label: 'Türkçe' },
|
|
148
146
|
{ value: 'de', label: 'de' }
|
|
149
|
-
]
|
|
150
|
-
defaultLocale: 'tr'
|
|
147
|
+
]
|
|
151
148
|
}
|
|
152
149
|
})
|
|
153
150
|
]);
|
|
@@ -157,34 +154,6 @@ describe('inside the editor', () => {
|
|
|
157
154
|
expect(targetOrigin).toBe(EDITOR_ORIGIN);
|
|
158
155
|
});
|
|
159
156
|
|
|
160
|
-
it('posts the languages before the document reports ready', () => {
|
|
161
|
-
// The editor holds every per-language write until IFRAME_READY and takes
|
|
162
|
-
// "ready without languages" to mean they are never coming, so the order
|
|
163
|
-
// of the two frames is part of the contract.
|
|
164
|
-
render(placeholder('header'));
|
|
165
|
-
|
|
166
|
-
const types = postMessage.mock.calls.map(([message]) => message?.type);
|
|
167
|
-
expect(types).toContain('LOCALE_UPDATE');
|
|
168
|
-
expect(types).toContain('IFRAME_READY');
|
|
169
|
-
expect(types.indexOf('LOCALE_UPDATE')).toBeLessThan(
|
|
170
|
-
types.indexOf('IFRAME_READY')
|
|
171
|
-
);
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it("posts the brand's default language, whichever it is", () => {
|
|
175
|
-
// The editor's per-language text controls take the plain-string form to
|
|
176
|
-
// mean this language; left to guess, the editor assumed English.
|
|
177
|
-
mockLocalization.defaultLocaleValue = 'de';
|
|
178
|
-
|
|
179
|
-
render(<EditorLocaleBridge />);
|
|
180
|
-
|
|
181
|
-
expect(localeFrames()).toEqual([
|
|
182
|
-
expect.objectContaining({
|
|
183
|
-
data: expect.objectContaining({ locale: 'tr', defaultLocale: 'de' })
|
|
184
|
-
})
|
|
185
|
-
]);
|
|
186
|
-
});
|
|
187
|
-
|
|
188
157
|
it("follows the editor's switch exactly once, with several placeholders mounted", () => {
|
|
189
158
|
render(
|
|
190
159
|
<>
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import OrderDetailBlock from '../order-detail-block';
|
|
4
|
+
import blockRendererRegistry from '../block-renderer-registry';
|
|
5
|
+
import { useThemeRowScope } from '../row-scope';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ZERO-5509 — the order detail page as blocks. A child group with role
|
|
9
|
+
* `order-detail-layout` is drawn once over the order instead of the built-in
|
|
10
|
+
* markup: its blocks bind `item.*` to the order, a repeat over `item.lines`
|
|
11
|
+
* draws a row per line, and each line row is a row of its own, so a block that
|
|
12
|
+
* acts on "its row" (the rate & review action) answers for that line only.
|
|
13
|
+
*/
|
|
14
|
+
let order: Record<string, unknown> | null = null;
|
|
15
|
+
let isLoading = false;
|
|
16
|
+
|
|
17
|
+
jest.mock('next/navigation', () => ({
|
|
18
|
+
useParams: () => ({ id: '42' }),
|
|
19
|
+
useSearchParams: () => null
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
jest.mock('next-auth/react', () => ({
|
|
23
|
+
useSession: () => ({ data: null, status: 'authenticated' })
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
jest.mock('@akinon/next/hooks', () => ({
|
|
27
|
+
__esModule: true,
|
|
28
|
+
useLocalization: () => ({ locale: 'tr', currency: 'try' })
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
jest.mock('@akinon/next/data/client/account', () => ({
|
|
32
|
+
__esModule: true,
|
|
33
|
+
useGetOrderQuery: () => ({ data: order, isLoading })
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
// Stands in for the rate & review action: shows which row it was handed.
|
|
37
|
+
const RowProbe = () => {
|
|
38
|
+
const scope = useThemeRowScope();
|
|
39
|
+
const row = (scope?.row ?? {}) as {
|
|
40
|
+
number?: string;
|
|
41
|
+
items?: Array<{ product?: { sku?: string } }>;
|
|
42
|
+
};
|
|
43
|
+
return (
|
|
44
|
+
<span data-testid="row-probe">
|
|
45
|
+
{`${row.number}:${(row.items ?? [])
|
|
46
|
+
.map((item) => item.product?.sku)
|
|
47
|
+
.join(',')}`}
|
|
48
|
+
</span>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
blockRendererRegistry.register('test-row-probe', RowProbe as never);
|
|
52
|
+
|
|
53
|
+
const line = (id: number, sku: string, color: string, size: string) => ({
|
|
54
|
+
id,
|
|
55
|
+
price: '5499.00',
|
|
56
|
+
quantity: 1,
|
|
57
|
+
status: { value: '550', label: 'Teslim edildi' },
|
|
58
|
+
tracking_number: `TRK${id}`,
|
|
59
|
+
tracking_url: `https://carrier.example/${id}`,
|
|
60
|
+
product: {
|
|
61
|
+
pk: id,
|
|
62
|
+
sku,
|
|
63
|
+
base_code: `BASE-${id}`,
|
|
64
|
+
name: `Gömlek ${id}`,
|
|
65
|
+
image: `/img-${id}.jpg`,
|
|
66
|
+
absolute_url: `/p-${id}/`,
|
|
67
|
+
attributes: { integration_renk_detay: color, filtrenebilir_beden: size }
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const ORDER = {
|
|
72
|
+
id: 42,
|
|
73
|
+
number: '20920397829',
|
|
74
|
+
created_date: '2026-06-10T10:00:00Z',
|
|
75
|
+
amount: '15499.00',
|
|
76
|
+
amount_without_discount: '15499.00',
|
|
77
|
+
discount_amount: '2499.00',
|
|
78
|
+
shipping_amount: '0.00',
|
|
79
|
+
status: { value: '400', label: 'Onaylandı' },
|
|
80
|
+
currency: { value: 'try', label: 'TRY' },
|
|
81
|
+
e_archive_url: 'https://invoice.example/42',
|
|
82
|
+
tracking_number: 'TRK1',
|
|
83
|
+
tracking_url: 'https://carrier.example/1',
|
|
84
|
+
installment_count: 3,
|
|
85
|
+
orderitem_set: [
|
|
86
|
+
line(1, 'SKU-1', 'Beyaz', 'S'),
|
|
87
|
+
line(2, 'SKU-2', 'Lacivert', 'M')
|
|
88
|
+
],
|
|
89
|
+
discountitem_set: [{ name: 'Sepet indirimi', amount: '2499.00' }],
|
|
90
|
+
shipping_address: {
|
|
91
|
+
first_name: 'İlker',
|
|
92
|
+
last_name: 'Gökçil',
|
|
93
|
+
line: 'Atatürk Cad. No:2/5',
|
|
94
|
+
district: { name: 'Atatürk Mah.' },
|
|
95
|
+
city: { name: 'İstanbul' }
|
|
96
|
+
},
|
|
97
|
+
billing_address: null,
|
|
98
|
+
bank: { name: 'İş Bankası' },
|
|
99
|
+
payment_option: { name: 'Kredi Kartı' }
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const text = (id: string, binding: string, extra = {}) => ({
|
|
103
|
+
id,
|
|
104
|
+
type: 'text',
|
|
105
|
+
label: id,
|
|
106
|
+
value: '',
|
|
107
|
+
properties: { tag: 'span', dataBinding: binding, ...extra },
|
|
108
|
+
styles: {},
|
|
109
|
+
blocks: []
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const layout = (overrides: Record<string, unknown> = {}) => ({
|
|
113
|
+
id: 'order-layout',
|
|
114
|
+
type: 'group',
|
|
115
|
+
label: 'Order Layout',
|
|
116
|
+
properties: { tag: 'div', role: 'order-detail-layout' },
|
|
117
|
+
styles: {},
|
|
118
|
+
blocks: [
|
|
119
|
+
text('number', 'item.number'),
|
|
120
|
+
text('date', 'item.date'),
|
|
121
|
+
text('total', 'item.total'),
|
|
122
|
+
{
|
|
123
|
+
...text('shipping-free', '', {
|
|
124
|
+
visibleWhenField: 'item.isFreeShipping',
|
|
125
|
+
visibleWhenMode: 'truthy'
|
|
126
|
+
}),
|
|
127
|
+
value: 'Ücretsiz'
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
...text('shipping-paid', 'item.shipping', {
|
|
131
|
+
visibleWhenField: 'item.isFreeShipping',
|
|
132
|
+
visibleWhenMode: 'falsy'
|
|
133
|
+
})
|
|
134
|
+
},
|
|
135
|
+
text(
|
|
136
|
+
'installments',
|
|
137
|
+
'{{item.installmentCount}} x {{item.installmentAmount}}'
|
|
138
|
+
),
|
|
139
|
+
text('address', 'item.shippingAddress'),
|
|
140
|
+
text('billing', 'item.billingAddress', {
|
|
141
|
+
visibleWhenField: 'item.hasBillingAddress',
|
|
142
|
+
visibleWhenMode: 'truthy'
|
|
143
|
+
}),
|
|
144
|
+
{
|
|
145
|
+
id: 'discounts',
|
|
146
|
+
type: 'group',
|
|
147
|
+
label: 'Discounts',
|
|
148
|
+
isIterator: true,
|
|
149
|
+
iteratorDataPath: 'item.discounts',
|
|
150
|
+
properties: { tag: 'div' },
|
|
151
|
+
styles: {},
|
|
152
|
+
blocks: [text('discount', '{{item.name}} {{item.amount}}')]
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: 'lines',
|
|
156
|
+
type: 'group',
|
|
157
|
+
label: 'Lines',
|
|
158
|
+
isIterator: true,
|
|
159
|
+
iteratorDataPath: 'item.lines',
|
|
160
|
+
properties: { tag: 'div' },
|
|
161
|
+
styles: {},
|
|
162
|
+
blocks: [
|
|
163
|
+
{
|
|
164
|
+
id: 'line',
|
|
165
|
+
type: 'group',
|
|
166
|
+
label: 'Line',
|
|
167
|
+
properties: { tag: 'div' },
|
|
168
|
+
styles: {},
|
|
169
|
+
blocks: [
|
|
170
|
+
text('line-name', 'item.name'),
|
|
171
|
+
text('line-color', 'Renk: {{item.color}}'),
|
|
172
|
+
text('line-size', 'Beden: {{item.size}}'),
|
|
173
|
+
text('line-tracking', 'item.trackingNumber'),
|
|
174
|
+
{
|
|
175
|
+
id: 'probe',
|
|
176
|
+
type: 'test-row-probe',
|
|
177
|
+
label: 'Probe',
|
|
178
|
+
properties: {},
|
|
179
|
+
styles: {},
|
|
180
|
+
blocks: []
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
],
|
|
187
|
+
...overrides
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const block = (blocks: unknown[] = [layout()]) =>
|
|
191
|
+
({
|
|
192
|
+
id: 'order-detail-1',
|
|
193
|
+
type: 'order-detail',
|
|
194
|
+
properties: {
|
|
195
|
+
colorAttributeKey: { desktop: 'integration_renk_detay' },
|
|
196
|
+
sizeAttributeKey: { desktop: 'filtrenebilir_beden' },
|
|
197
|
+
currencyDisplay: { desktop: 'custom' },
|
|
198
|
+
currencyText: { desktop: 'TL' },
|
|
199
|
+
currencyPosition: { desktop: 'after' },
|
|
200
|
+
decimals: { desktop: 'auto' }
|
|
201
|
+
},
|
|
202
|
+
styles: {},
|
|
203
|
+
blocks
|
|
204
|
+
} as never);
|
|
205
|
+
|
|
206
|
+
const renderBlock = (blocks?: unknown[], isDesigner = false) =>
|
|
207
|
+
render(
|
|
208
|
+
<OrderDetailBlock
|
|
209
|
+
block={block(blocks)}
|
|
210
|
+
placeholderId="p1"
|
|
211
|
+
sectionId="s1"
|
|
212
|
+
isDesigner={isDesigner}
|
|
213
|
+
/>
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
beforeEach(() => {
|
|
217
|
+
order = ORDER;
|
|
218
|
+
isLoading = false;
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
describe('order detail layout', () => {
|
|
222
|
+
it('draws the authored layout in place of the built-in markup', () => {
|
|
223
|
+
const { container } = renderBlock();
|
|
224
|
+
|
|
225
|
+
expect(
|
|
226
|
+
container.querySelector('[data-order-detail-layout]')
|
|
227
|
+
).not.toBeNull();
|
|
228
|
+
expect(container.querySelector('[data-order-detail-header]')).toBeNull();
|
|
229
|
+
expect(container.querySelector('[data-order-detail-items]')).toBeNull();
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('binds the order-level values, formatted the way the block formats money', () => {
|
|
233
|
+
const { container } = renderBlock();
|
|
234
|
+
const textOf = (selector: string) =>
|
|
235
|
+
container.querySelector(`[data-block-id^="${selector}"]`)?.textContent;
|
|
236
|
+
|
|
237
|
+
expect(textOf('number')).toBe('20920397829');
|
|
238
|
+
expect(textOf('date')).toBe('10.06.2026');
|
|
239
|
+
expect(textOf('total')).toMatch(/^15\.499(,00)? TL$/);
|
|
240
|
+
expect(textOf('installments')).toMatch(/^3 x 5\.166,33 TL$/);
|
|
241
|
+
expect(textOf('address')).toBe(
|
|
242
|
+
'Atatürk Cad. No:2/5 Atatürk Mah. / İstanbul'
|
|
243
|
+
);
|
|
244
|
+
expect(textOf('discount')).toMatch(/^Sepet indirimi -2\.499(,00)? TL$/);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('shows and hides per the row conditions on the storefront', () => {
|
|
248
|
+
const { container } = renderBlock();
|
|
249
|
+
|
|
250
|
+
expect(container.textContent).toContain('Ücretsiz');
|
|
251
|
+
expect(
|
|
252
|
+
container.querySelector('[data-block-id^="shipping-paid"]')
|
|
253
|
+
).toBeNull();
|
|
254
|
+
// No billing address on this order: the bound block is hidden.
|
|
255
|
+
expect(container.querySelector('[data-block-id^="billing"]')).toBeNull();
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('repeats a row per line with its color, size and tracking', () => {
|
|
259
|
+
const { container } = renderBlock();
|
|
260
|
+
const lines = container.querySelectorAll('[data-block-id^="line-color"]');
|
|
261
|
+
|
|
262
|
+
expect(lines).toHaveLength(2);
|
|
263
|
+
expect(lines[0].textContent).toBe('Renk: Beyaz');
|
|
264
|
+
expect(lines[1].textContent).toBe('Renk: Lacivert');
|
|
265
|
+
expect(
|
|
266
|
+
container.querySelectorAll('[data-block-id^="line-size"]')[1].textContent
|
|
267
|
+
).toBe('Beden: M');
|
|
268
|
+
expect(
|
|
269
|
+
container.querySelectorAll('[data-block-id^="line-tracking"]')[0]
|
|
270
|
+
.textContent
|
|
271
|
+
).toBe('TRK1');
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('gives every line row its own row scope, as a one-line order', () => {
|
|
275
|
+
renderBlock();
|
|
276
|
+
|
|
277
|
+
expect(
|
|
278
|
+
screen.getAllByTestId('row-probe').map((el) => el.textContent)
|
|
279
|
+
).toEqual(['20920397829:SKU-1', '20920397829:SKU-2']);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('leaves a hidden layout off the storefront and draws the built-in order', () => {
|
|
283
|
+
const { container } = renderBlock([layout({ hidden: true })]);
|
|
284
|
+
|
|
285
|
+
expect(container.querySelector('[data-order-detail-layout]')).toBeNull();
|
|
286
|
+
expect(
|
|
287
|
+
container.querySelector('[data-order-detail-header]')
|
|
288
|
+
).not.toBeNull();
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('keeps drawing the built-in order when there is no layout', () => {
|
|
292
|
+
const { container } = renderBlock([]);
|
|
293
|
+
|
|
294
|
+
expect(container.querySelector('[data-order-detail-layout]')).toBeNull();
|
|
295
|
+
expect(
|
|
296
|
+
container.querySelector('[data-order-detail-header]')
|
|
297
|
+
).not.toBeNull();
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('draws the layout over the sample order on the canvas', () => {
|
|
301
|
+
order = null;
|
|
302
|
+
const { container } = renderBlock(undefined, true);
|
|
303
|
+
|
|
304
|
+
expect(
|
|
305
|
+
container.querySelector('[data-order-detail-layout]')
|
|
306
|
+
).not.toBeNull();
|
|
307
|
+
expect(
|
|
308
|
+
container.querySelectorAll('[data-block-id^="line-color"]').length
|
|
309
|
+
).toBeGreaterThan(0);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
@@ -2,31 +2,9 @@ import React from 'react';
|
|
|
2
2
|
import { render } from '@testing-library/react';
|
|
3
3
|
import TextBlock from '../text-block';
|
|
4
4
|
|
|
5
|
-
// The
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
const mockLocalization = { locale: 'en-us', defaultLocaleValue: 'en-us' };
|
|
9
|
-
|
|
10
|
-
jest.mock('@akinon/next/hooks', () => ({
|
|
11
|
-
__esModule: true,
|
|
12
|
-
useLocalization: () => ({
|
|
13
|
-
t: (path: string) => path,
|
|
14
|
-
setLocale: () => {},
|
|
15
|
-
setCurrency: () => {},
|
|
16
|
-
locale: mockLocalization.locale,
|
|
17
|
-
currency: 'USD',
|
|
18
|
-
locales: [{ value: 'en-us' }, { value: 'tr-tr' }],
|
|
19
|
-
currencies: ['USD'],
|
|
20
|
-
defaultLocaleValue: mockLocalization.defaultLocaleValue,
|
|
21
|
-
defaultCurrencyCode: 'USD',
|
|
22
|
-
localeUrlStrategy: 'hide-default-locale'
|
|
23
|
-
})
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
mockLocalization.locale = 'en-us';
|
|
28
|
-
mockLocalization.defaultLocaleValue = 'en-us';
|
|
29
|
-
});
|
|
5
|
+
// The mocked useLocalization (jest/__mocks__/akinon-next-hooks.js) returns
|
|
6
|
+
// locale: 'en-us'. process.env.NEXT_PUBLIC_DEFAULT_LOCALE is unset in the
|
|
7
|
+
// jest env, so the component's defaultLocale falls back to 'en'.
|
|
30
8
|
|
|
31
9
|
const renderBlock = (value: unknown, styles?: Record<string, unknown>) => {
|
|
32
10
|
const block: any = { id: 'b1', type: 'text', value, styles };
|
|
@@ -56,16 +34,10 @@ describe('TextBlock value-shape resolution', () => {
|
|
|
56
34
|
);
|
|
57
35
|
});
|
|
58
36
|
|
|
59
|
-
it(
|
|
60
|
-
|
|
61
|
-
// the block used to show: its default was read from an env variable
|
|
62
|
-
// that falls back to English, not from the storefront (ZERO-5296).
|
|
63
|
-
mockLocalization.locale = 'de-de';
|
|
64
|
-
mockLocalization.defaultLocaleValue = 'tr-tr';
|
|
65
|
-
|
|
66
|
-
const { container } = renderBlock({ en: 'EN', 'tr-tr': 'TR' });
|
|
37
|
+
it('falls back to defaultLocale ("en") when active locale is absent', () => {
|
|
38
|
+
const { container } = renderBlock({ en: 'EN', fr: 'FR' });
|
|
67
39
|
expect((container.querySelector('div') as HTMLDivElement).innerHTML).toBe(
|
|
68
|
-
'
|
|
40
|
+
'EN'
|
|
69
41
|
);
|
|
70
42
|
});
|
|
71
43
|
|