@akinon/pz-theme 2.0.75-rc.0 → 2.0.76-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -32
- package/jest/__mocks__/akinon-next-plugin-module.js +19 -3
- package/package.json +4 -4
- package/src/blocks/__tests__/basket-line-layout.test.tsx +174 -5
- package/src/blocks/__tests__/basket-line-price.test.tsx +24 -0
- package/src/blocks/__tests__/basket-offers.test.tsx +96 -1
- package/src/blocks/basket-items-block.tsx +204 -14
- package/src/blocks/basket-summary-block.tsx +223 -59
- package/src/chrome/__tests__/composition-source.test.ts +125 -0
- package/src/chrome/composition-source.ts +37 -10
- package/src/chrome/retrying-widget-data.ts +33 -0
- package/src/chrome/theme-config-source.ts +6 -7
- package/src/load-placeholder-sections.ts +4 -10
- package/src/utils/__tests__/color-alpha.test.ts +29 -0
- package/src/utils/index.ts +39 -3
- package/src/utils/style-resolution.test.ts +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,37 +1,20 @@
|
|
|
1
1
|
# @akinon/pz-theme
|
|
2
2
|
|
|
3
|
-
## 2.0.
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- Updated dependencies [
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- Updated dependencies [57d7eb305]
|
|
19
|
-
- Updated dependencies [d99a6a7d5]
|
|
20
|
-
- Updated dependencies [9db81a714]
|
|
21
|
-
- Updated dependencies [591e345e1]
|
|
22
|
-
- Updated dependencies [4de5303c5]
|
|
23
|
-
- Updated dependencies [95b139dc1]
|
|
24
|
-
- Updated dependencies [1d00f2d06]
|
|
25
|
-
- Updated dependencies [4ac7b2a1e]
|
|
26
|
-
- Updated dependencies [e9598c71]
|
|
27
|
-
- Updated dependencies [4998a9631]
|
|
28
|
-
- Updated dependencies [804d2bd6c]
|
|
29
|
-
- Updated dependencies [3909d3224]
|
|
30
|
-
- Updated dependencies [6a3d8a631]
|
|
31
|
-
- Updated dependencies [e18836b20]
|
|
32
|
-
- Updated dependencies [b1111d7b]
|
|
33
|
-
- @akinon/next@2.0.75-rc.0
|
|
34
|
-
- @akinon/theme-contract@2.0.75-rc.0
|
|
3
|
+
## 2.0.76-beta.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [cbbbfd757]
|
|
8
|
+
- @akinon/next@2.0.76-beta.0
|
|
9
|
+
- @akinon/theme-contract@2.0.76-beta.0
|
|
10
|
+
|
|
11
|
+
## 2.0.75
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 01f69c6a: ZERO-4840: add basket gift card, wallet, gift wrap and upsell
|
|
16
|
+
- @akinon/next@2.0.75
|
|
17
|
+
- @akinon/theme-contract@2.0.75
|
|
35
18
|
|
|
36
19
|
## 2.0.74
|
|
37
20
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Mock for @akinon/next/components/plugin-module: the real one dynamically
|
|
2
2
|
// imports brand plugins, which have no place in a unit test. The slot renders
|
|
3
|
-
// a marker so a test can assert where a block placed it.
|
|
3
|
+
// a marker so a test can assert where a block placed it. When the block hands
|
|
4
|
+
// the gift pack plugin a customUIRender, the mock drives it with a local
|
|
5
|
+
// hasGiftPack so a test can exercise the add/remove toggling.
|
|
4
6
|
const React = require('react');
|
|
5
7
|
|
|
6
8
|
const Component = {
|
|
@@ -8,8 +10,22 @@ const Component = {
|
|
|
8
10
|
CheckoutGiftPack: 'CheckoutGiftPack'
|
|
9
11
|
};
|
|
10
12
|
|
|
11
|
-
const PluginModule = ({ component }) =>
|
|
12
|
-
|
|
13
|
+
const PluginModule = ({ component, props }) => {
|
|
14
|
+
const [hasGiftPack, setHasGiftPack] = React.useState(false);
|
|
15
|
+
const customUIRender = props?.customUIRender;
|
|
16
|
+
return React.createElement(
|
|
17
|
+
'div',
|
|
18
|
+
{ 'data-plugin-module': component },
|
|
19
|
+
customUIRender
|
|
20
|
+
? customUIRender({
|
|
21
|
+
hasGiftPack,
|
|
22
|
+
onAddGiftPack: () => setHasGiftPack(true),
|
|
23
|
+
onRemoveGiftPack: () => setHasGiftPack(false),
|
|
24
|
+
translations: props?.translations ?? {}
|
|
25
|
+
})
|
|
26
|
+
: null
|
|
27
|
+
);
|
|
28
|
+
};
|
|
13
29
|
|
|
14
30
|
module.exports = {
|
|
15
31
|
__esModule: true,
|
package/package.json
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
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.
|
|
4
|
+
"version": "2.0.76-beta.0",
|
|
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.
|
|
11
|
+
"@akinon/next": "2.0.76-beta.0",
|
|
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.
|
|
16
|
+
"@akinon/theme-contract": "2.0.76-beta.0",
|
|
17
17
|
"clsx": "2.1.1",
|
|
18
18
|
"lottie-web": "^5.13.0",
|
|
19
19
|
"tailwind-merge": "^2.5.4",
|
|
20
20
|
"zod": "4.4.1"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@akinon/next": "2.0.
|
|
23
|
+
"@akinon/next": "2.0.76-beta.0",
|
|
24
24
|
"@testing-library/jest-dom": "5.16.4",
|
|
25
25
|
"@testing-library/react": "16.3.2",
|
|
26
26
|
"@testing-library/user-event": "14.1.1",
|
|
@@ -38,6 +38,12 @@ const basketLine = {
|
|
|
38
38
|
let basketData: unknown = {
|
|
39
39
|
basketitem_set: [basketLine],
|
|
40
40
|
total_quantity: 2,
|
|
41
|
+
upsell_details: [
|
|
42
|
+
{
|
|
43
|
+
message: '2 more to go',
|
|
44
|
+
params: { required: 3, partial: 1, remaining: 2 }
|
|
45
|
+
}
|
|
46
|
+
],
|
|
41
47
|
total_product_amount: '11998.00',
|
|
42
48
|
total_discount_amount: '0.00',
|
|
43
49
|
total_amount: '11998.00',
|
|
@@ -173,6 +179,53 @@ describe('basket-items line layout', () => {
|
|
|
173
179
|
).not.toBeNull();
|
|
174
180
|
});
|
|
175
181
|
|
|
182
|
+
it('renders the checkbox gift wrap presentation and toggles it through the plugin', () => {
|
|
183
|
+
const { container } = renderBlock(BasketItemsBlock, 'basket-items', {
|
|
184
|
+
showGiftWrap: true,
|
|
185
|
+
giftWrapPresentation: 'checkbox',
|
|
186
|
+
giftWrapAddLabel: 'Hediye Paketi'
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const toggle = container.querySelector(
|
|
190
|
+
'[data-part="gift-wrap-toggle"]'
|
|
191
|
+
) as HTMLButtonElement;
|
|
192
|
+
expect(toggle).not.toBeNull();
|
|
193
|
+
expect(toggle.getAttribute('aria-checked')).toBe('false');
|
|
194
|
+
expect(
|
|
195
|
+
container.querySelector('[data-part="gift-wrap-label"]')?.textContent
|
|
196
|
+
).toBe('Hediye Paketi');
|
|
197
|
+
expect(
|
|
198
|
+
container.querySelector('[data-part="gift-wrap-box"] svg')
|
|
199
|
+
).toBeNull();
|
|
200
|
+
|
|
201
|
+
fireEvent.click(toggle);
|
|
202
|
+
expect(toggle.getAttribute('aria-checked')).toBe('true');
|
|
203
|
+
expect(toggle.getAttribute('data-state')).toContain('checked');
|
|
204
|
+
expect(
|
|
205
|
+
container.querySelector('[data-part="gift-wrap-box"] svg')
|
|
206
|
+
).not.toBeNull();
|
|
207
|
+
|
|
208
|
+
fireEvent.click(toggle);
|
|
209
|
+
expect(toggle.getAttribute('aria-checked')).toBe('false');
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('shows the upsell campaign banner only when asked, with placeholders', () => {
|
|
213
|
+
const silent = renderBlock(BasketItemsBlock, 'basket-items');
|
|
214
|
+
expect(
|
|
215
|
+
silent.container.querySelector('[data-part="upsell-banner"]')
|
|
216
|
+
).toBeNull();
|
|
217
|
+
|
|
218
|
+
const { container } = renderBlock(BasketItemsBlock, 'basket-items', {
|
|
219
|
+
showUpsellBanner: true,
|
|
220
|
+
upsellBannerFormat: 'Kampanya: {message} ({remaining}/{required})'
|
|
221
|
+
});
|
|
222
|
+
const banner = container.querySelector('[data-part="upsell-banner"]');
|
|
223
|
+
expect(banner?.textContent).toBe('Kampanya: 2 more to go (2/3)');
|
|
224
|
+
expect(
|
|
225
|
+
container.querySelector('[data-part="root"] > [data-part="upsell-banner"]')
|
|
226
|
+
).not.toBeNull();
|
|
227
|
+
});
|
|
228
|
+
|
|
176
229
|
it('formats the unit price with the shared money options', () => {
|
|
177
230
|
const { container } = renderBlock(BasketItemsBlock, 'basket-items', {
|
|
178
231
|
decimals: 'never',
|
|
@@ -229,13 +282,14 @@ describe('basket-summary panels', () => {
|
|
|
229
282
|
expect(container.querySelector('[data-part="coupon-form"]')).not.toBeNull();
|
|
230
283
|
});
|
|
231
284
|
|
|
232
|
-
it('
|
|
285
|
+
it('redeems the gift card as number|cvv through the voucher endpoint', () => {
|
|
233
286
|
const { container } = renderBlock(BasketSummaryBlock, 'basket-summary', {
|
|
234
287
|
showCoupon: false,
|
|
235
288
|
showGiftCard: true,
|
|
236
289
|
couponPlacement: 'after-cta',
|
|
237
290
|
giftCardToggleLabel: 'Hediye Kartı',
|
|
238
|
-
giftCardApplyLabel: 'Uygula'
|
|
291
|
+
giftCardApplyLabel: 'Uygula',
|
|
292
|
+
giftCardError: 'Geçersiz kart.'
|
|
239
293
|
});
|
|
240
294
|
|
|
241
295
|
const toggle = container.querySelector(
|
|
@@ -248,12 +302,127 @@ describe('basket-summary panels', () => {
|
|
|
248
302
|
const number = container.querySelector(
|
|
249
303
|
'[data-part="gift-card-input"]'
|
|
250
304
|
) as HTMLInputElement;
|
|
305
|
+
const form = container.querySelector(
|
|
306
|
+
'[data-part="gift-card-form"]'
|
|
307
|
+
) as HTMLFormElement;
|
|
251
308
|
fireEvent.change(number, { target: { value: '1234 5678' } });
|
|
252
|
-
|
|
253
|
-
|
|
309
|
+
|
|
310
|
+
// A missing CVV is the same invalid-card answer, without the round trip;
|
|
311
|
+
// both fields carry the invalid state the design colours red.
|
|
312
|
+
fireEvent.submit(form);
|
|
313
|
+
expect(applyVoucher).not.toHaveBeenCalled();
|
|
314
|
+
expect(
|
|
315
|
+
container.querySelector('[data-part="gift-card-error"]')?.textContent
|
|
316
|
+
).toBe('Geçersiz kart.');
|
|
317
|
+
expect(
|
|
318
|
+
container
|
|
319
|
+
.querySelector('[data-part="gift-card-input"]')
|
|
320
|
+
?.getAttribute('data-state')
|
|
321
|
+
).toBe('invalid');
|
|
322
|
+
expect(
|
|
323
|
+
container
|
|
324
|
+
.querySelector('[data-part="gift-card-cvv"]')
|
|
325
|
+
?.getAttribute('data-state')
|
|
326
|
+
).toBe('invalid');
|
|
327
|
+
|
|
328
|
+
fireEvent.change(
|
|
329
|
+
container.querySelector('[data-part="gift-card-cvv"]') as HTMLInputElement,
|
|
330
|
+
{ target: { value: '123' } }
|
|
254
331
|
);
|
|
332
|
+
fireEvent.submit(form);
|
|
333
|
+
expect(applyVoucher).toHaveBeenCalledWith({
|
|
334
|
+
voucher_code: '1234 5678|123'
|
|
335
|
+
});
|
|
336
|
+
});
|
|
255
337
|
|
|
256
|
-
|
|
338
|
+
it('locks the gift card panel while a promo code is applied', () => {
|
|
339
|
+
basketData = {
|
|
340
|
+
basketitem_set: [basketLine],
|
|
341
|
+
total_quantity: 2,
|
|
342
|
+
total_product_amount: '11998.00',
|
|
343
|
+
total_discount_amount: '0.00',
|
|
344
|
+
total_amount: '11998.00',
|
|
345
|
+
voucher_code: 'GANT2026'
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
const { container } = renderBlock(BasketSummaryBlock, 'basket-summary', {
|
|
349
|
+
showGiftCard: true,
|
|
350
|
+
couponPresentation: 'collapsible'
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
const giftToggle = container.querySelector(
|
|
354
|
+
'[data-part="gift-card-toggle"]'
|
|
355
|
+
) as HTMLButtonElement;
|
|
356
|
+
expect(giftToggle.disabled).toBe(true);
|
|
357
|
+
fireEvent.click(giftToggle);
|
|
358
|
+
expect(container.querySelector('[data-part="gift-card-form"]')).toBeNull();
|
|
359
|
+
|
|
360
|
+
// The promo panel is the applied code's owner and stays usable.
|
|
361
|
+
const couponToggle = container.querySelector(
|
|
362
|
+
'[data-part="coupon-toggle"]'
|
|
363
|
+
) as HTMLButtonElement;
|
|
364
|
+
expect(couponToggle.disabled).toBe(false);
|
|
365
|
+
fireEvent.click(couponToggle);
|
|
366
|
+
expect(
|
|
367
|
+
container.querySelector('[data-part="coupon-code"]')?.textContent
|
|
368
|
+
).toBe('GANT2026');
|
|
369
|
+
|
|
370
|
+
basketData = {
|
|
371
|
+
basketitem_set: [basketLine],
|
|
372
|
+
total_quantity: 2,
|
|
373
|
+
total_product_amount: '11998.00',
|
|
374
|
+
total_discount_amount: '0.00',
|
|
375
|
+
total_amount: '11998.00',
|
|
376
|
+
voucher_code: null
|
|
377
|
+
};
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it('locks the promo panel while a gift card is applied and offers its removal', () => {
|
|
381
|
+
basketData = {
|
|
382
|
+
basketitem_set: [basketLine],
|
|
383
|
+
total_quantity: 2,
|
|
384
|
+
total_product_amount: '11998.00',
|
|
385
|
+
total_discount_amount: '0.00',
|
|
386
|
+
total_amount: '11998.00',
|
|
387
|
+
voucher_code: '1234 5678|123'
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
const { container } = renderBlock(BasketSummaryBlock, 'basket-summary', {
|
|
391
|
+
showGiftCard: true,
|
|
392
|
+
couponPresentation: 'collapsible',
|
|
393
|
+
giftCardRemoveLabel: 'Kaldır'
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const couponToggle = container.querySelector(
|
|
397
|
+
'[data-part="coupon-toggle"]'
|
|
398
|
+
) as HTMLButtonElement;
|
|
399
|
+
expect(couponToggle.disabled).toBe(true);
|
|
400
|
+
fireEvent.click(couponToggle);
|
|
401
|
+
expect(container.querySelector('[data-part="coupon-form"]')).toBeNull();
|
|
402
|
+
// The gift card's code must not leak into the promo panel's applied row.
|
|
403
|
+
expect(container.querySelector('[data-part="coupon-applied"]')).toBeNull();
|
|
404
|
+
|
|
405
|
+
const giftToggle = container.querySelector(
|
|
406
|
+
'[data-part="gift-card-toggle"]'
|
|
407
|
+
) as HTMLButtonElement;
|
|
408
|
+
expect(giftToggle.disabled).toBe(false);
|
|
409
|
+
fireEvent.click(giftToggle);
|
|
410
|
+
// The applied row prints the number without its CVV.
|
|
411
|
+
expect(
|
|
412
|
+
container.querySelector('[data-part="gift-card-code"]')?.textContent
|
|
413
|
+
).toBe('1234 5678');
|
|
414
|
+
expect(
|
|
415
|
+
container.querySelector('[data-part="gift-card-remove"]')?.textContent
|
|
416
|
+
).toBe('Kaldır');
|
|
417
|
+
|
|
418
|
+
basketData = {
|
|
419
|
+
basketitem_set: [basketLine],
|
|
420
|
+
total_quantity: 2,
|
|
421
|
+
total_product_amount: '11998.00',
|
|
422
|
+
total_discount_amount: '0.00',
|
|
423
|
+
total_amount: '11998.00',
|
|
424
|
+
voucher_code: null
|
|
425
|
+
};
|
|
257
426
|
});
|
|
258
427
|
|
|
259
428
|
it('prints one discount row per basket campaign when asked to', () => {
|
|
@@ -61,6 +61,18 @@ const basketDiscountLine = {
|
|
|
61
61
|
product: { ...plainLine.product, pk: 1003 }
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
+
// A basket-level voucher writes its share into `discount_amount` but leaves
|
|
65
|
+
// the unit price alone — that must never read as an in-basket campaign.
|
|
66
|
+
const voucherTouchedLine = {
|
|
67
|
+
...plainLine,
|
|
68
|
+
id: 4,
|
|
69
|
+
price: '2199.00',
|
|
70
|
+
unit_price: '2199.00',
|
|
71
|
+
total_amount: '2199.00',
|
|
72
|
+
discount_amount: '2177.00',
|
|
73
|
+
product: { ...plainLine.product, pk: 1004, price: '2199.00' }
|
|
74
|
+
};
|
|
75
|
+
|
|
64
76
|
let basketData: unknown = { basketitem_set: [plainLine] };
|
|
65
77
|
|
|
66
78
|
jest.mock('next-auth/react', () => ({
|
|
@@ -153,6 +165,18 @@ describe('basket-items price extras', () => {
|
|
|
153
165
|
expect(text(container, 'price')).toBe('5,499 TL');
|
|
154
166
|
});
|
|
155
167
|
|
|
168
|
+
it('does not badge a line whose discount came from a basket voucher', () => {
|
|
169
|
+
basketData = { basketitem_set: [voucherTouchedLine] };
|
|
170
|
+
const { container } = renderLines({
|
|
171
|
+
...money,
|
|
172
|
+
showBasketDiscount: true,
|
|
173
|
+
basketDiscountFormat: 'SEPETTE {price}'
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
expect(container.querySelector('[data-part="basket-price"]')).toBeNull();
|
|
177
|
+
expect(text(container, 'price')).toBe('2,199 TL');
|
|
178
|
+
});
|
|
179
|
+
|
|
156
180
|
it('shows the undiscounted price with the in-basket figure when a campaign cut the line', () => {
|
|
157
181
|
basketData = { basketitem_set: [basketDiscountLine] };
|
|
158
182
|
const { container } = renderLines({
|
|
@@ -30,6 +30,7 @@ let offersPayload: unknown = {
|
|
|
30
30
|
]
|
|
31
31
|
};
|
|
32
32
|
let voucherCode: string | null = null;
|
|
33
|
+
let basketDiscounts: Array<{ description: string; discount: string }> = [];
|
|
33
34
|
|
|
34
35
|
const applyVoucher = jest.fn(() => ({
|
|
35
36
|
unwrap: () => Promise.resolve({ total_amount: '1.00' })
|
|
@@ -57,7 +58,8 @@ jest.mock('@akinon/next/data/client/basket', () => ({
|
|
|
57
58
|
total_quantity: 1,
|
|
58
59
|
total_product_amount: '500.00',
|
|
59
60
|
total_amount: '500.00',
|
|
60
|
-
voucher_code: voucherCode
|
|
61
|
+
voucher_code: voucherCode,
|
|
62
|
+
discounts: basketDiscounts
|
|
61
63
|
},
|
|
62
64
|
isLoading: false
|
|
63
65
|
}),
|
|
@@ -97,6 +99,7 @@ const renderSummary = (
|
|
|
97
99
|
beforeEach(() => {
|
|
98
100
|
sessionStatus = 'authenticated';
|
|
99
101
|
voucherCode = null;
|
|
102
|
+
basketDiscounts = [];
|
|
100
103
|
applyVoucher.mockClear();
|
|
101
104
|
removeVoucher.mockClear();
|
|
102
105
|
});
|
|
@@ -190,6 +193,98 @@ describe('basket-summary coupon wallet', () => {
|
|
|
190
193
|
).toBe(true);
|
|
191
194
|
});
|
|
192
195
|
|
|
196
|
+
it('reads the all_discounts payload and keeps only the active entries', () => {
|
|
197
|
+
offersPayload = {
|
|
198
|
+
total_discount: 0,
|
|
199
|
+
discounts: [],
|
|
200
|
+
all_discounts: [
|
|
201
|
+
{
|
|
202
|
+
label: 'test kupon',
|
|
203
|
+
amount: 0,
|
|
204
|
+
percentage: 99,
|
|
205
|
+
end_datetime: '2026-08-31T15:22:19.709000Z',
|
|
206
|
+
voucher_code: null,
|
|
207
|
+
status: { value: 'active', label: 'Active' },
|
|
208
|
+
offer_type: { value: 'coupon', label: 'Coupon' }
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
label: 'test indirim kodu',
|
|
212
|
+
amount: 0,
|
|
213
|
+
percentage: 99,
|
|
214
|
+
end_datetime: '2026-08-31T08:23:41.887000Z',
|
|
215
|
+
voucher_code: '3BC357B3',
|
|
216
|
+
status: { value: 'active', label: 'Active' },
|
|
217
|
+
offer_type: { value: 'coupon_code', label: 'Coupon Code' }
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
label: 'bitmiş kampanya',
|
|
221
|
+
amount: 0,
|
|
222
|
+
percentage: 10,
|
|
223
|
+
voucher_code: 'OLD',
|
|
224
|
+
status: { value: 'expired', label: 'Expired' }
|
|
225
|
+
}
|
|
226
|
+
]
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const { container } = renderSummary({
|
|
230
|
+
showOffers: true,
|
|
231
|
+
offerApplyLabel: 'Uygula'
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const cards = container.querySelectorAll('[data-part="offer"]');
|
|
235
|
+
expect(cards).toHaveLength(2);
|
|
236
|
+
expect(cards[0].querySelector('[data-part="offer-value"]')?.textContent).toBe(
|
|
237
|
+
'%99'
|
|
238
|
+
);
|
|
239
|
+
// The automatic coupon has no code, so no apply control.
|
|
240
|
+
expect(cards[0].querySelector('[data-part="offer-apply"]')).toBeNull();
|
|
241
|
+
|
|
242
|
+
const apply = cards[1].querySelector(
|
|
243
|
+
'[data-part="offer-apply"]'
|
|
244
|
+
) as HTMLButtonElement;
|
|
245
|
+
fireEvent.click(apply);
|
|
246
|
+
expect(applyVoucher).toHaveBeenCalledWith({ voucher_code: '3BC357B3' });
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('prints the applied voucher discount row as "Kupon Kodu - <code>"', () => {
|
|
250
|
+
voucherCode = '3BC357B3';
|
|
251
|
+
basketDiscounts = [
|
|
252
|
+
{ description: 'Sepette %30 İndirim', discount: '150.00' },
|
|
253
|
+
{ description: 'test indirim kodu', discount: '345.00' }
|
|
254
|
+
];
|
|
255
|
+
offersPayload = {
|
|
256
|
+
discounts: [],
|
|
257
|
+
all_discounts: [
|
|
258
|
+
{
|
|
259
|
+
label: 'test indirim kodu',
|
|
260
|
+
percentage: 99,
|
|
261
|
+
voucher_code: '3BC357B3',
|
|
262
|
+
status: { value: 'active' }
|
|
263
|
+
}
|
|
264
|
+
]
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const { container } = renderSummary({
|
|
268
|
+
showOffers: true,
|
|
269
|
+
discountRows: 'each',
|
|
270
|
+
voucherDiscountLabel: 'Kupon Kodu - {code}',
|
|
271
|
+
decimals: 'never',
|
|
272
|
+
currencyDisplay: 'custom',
|
|
273
|
+
currencyText: 'TL',
|
|
274
|
+
currencyPosition: 'after'
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
const labels = Array.from(
|
|
278
|
+
container.querySelectorAll('[data-basket-summary-row="discount"]')
|
|
279
|
+
).map((row) => row.textContent);
|
|
280
|
+
// The campaign row keeps its name; the voucher's own row takes the
|
|
281
|
+
// "Kupon Kodu - <code>" form of the design.
|
|
282
|
+
expect(labels).toEqual([
|
|
283
|
+
'Sepette %30 İndirim-150 TL',
|
|
284
|
+
'Kupon Kodu - 3BC357B3-345 TL'
|
|
285
|
+
]);
|
|
286
|
+
});
|
|
287
|
+
|
|
193
288
|
it('caps the list with offersLimit', () => {
|
|
194
289
|
const { container } = renderSummary({ showOffers: true, offersLimit: 1 });
|
|
195
290
|
|