@akinon/next 1.92.0-rc.38 → 1.92.0-rc.40

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # @akinon/next
2
2
 
3
+ ## 1.92.0-rc.40
4
+
5
+ ### Minor Changes
6
+
7
+ - dc678c31: ZERO-3523: Enhance redirect tests with dynamic locale handling and settings integration
8
+
9
+ ## 1.92.0-rc.39
10
+
3
11
  ## 1.92.0-rc.38
4
12
 
5
13
  ### Minor Changes
@@ -1,8 +1,17 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
 
4
+ interface Locale {
5
+ value: string;
6
+ label: string;
7
+ localePath?: string;
8
+ apiValue?: string;
9
+ rtl?: boolean;
10
+ }
11
+
4
12
  const mockNextRedirect = jest.fn();
5
13
  const mockHeaders = jest.fn();
14
+ const mockCookies = jest.fn();
6
15
 
7
16
  function findBaseDir() {
8
17
  const insideNodeModules = __dirname.includes('node_modules');
@@ -35,7 +44,8 @@ jest.mock('next/navigation', () => ({
35
44
  }));
36
45
 
37
46
  jest.mock('next/headers', () => ({
38
- headers: () => mockHeaders()
47
+ headers: () => mockHeaders(),
48
+ cookies: () => mockCookies()
39
49
  }));
40
50
 
41
51
  const mockServerVariables = {
@@ -47,15 +57,65 @@ jest.mock('@akinon/next/utils/server-variables', () => ({
47
57
  }));
48
58
 
49
59
  jest.mock('@akinon/next/utils', () => ({
50
- urlLocaleMatcherRegex: /^\/(?:tr|ar)(?=\/|$)/
60
+ urlLocaleMatcherRegex: /^\/(?:tr)(?=\/|$)/
51
61
  }));
52
62
 
63
+ const mockSettings = {
64
+ localization: {
65
+ defaultLocaleValue: 'en',
66
+ localeUrlStrategy: 'hide-default-locale',
67
+ locales: [
68
+ { value: 'en', label: 'EN' },
69
+ { value: 'tr', label: 'TR' }
70
+ ]
71
+ }
72
+ };
73
+
74
+ jest.mock('settings', () => mockSettings, { virtual: true });
75
+
53
76
  describe('Redirect utility functional tests', () => {
54
77
  let redirect: any;
55
78
  let getUrlPathWithLocale: any;
56
79
  let LocaleUrlStrategy: any;
80
+ let actualSettings: any;
57
81
 
58
82
  beforeAll(async () => {
83
+ try {
84
+ const baseDir = findBaseDir();
85
+ const settingsPath = path.resolve(baseDir, 'src/settings.js');
86
+ actualSettings = require(settingsPath);
87
+
88
+ Object.assign(mockSettings.localization, actualSettings.localization);
89
+
90
+ const nonDefaultLocales = actualSettings.localization.locales
91
+ .filter(
92
+ (locale: Locale) =>
93
+ locale.value !== actualSettings.localization.defaultLocaleValue
94
+ )
95
+ .map((locale: Locale) => locale.value);
96
+ if (nonDefaultLocales.length > 0) {
97
+ jest.doMock('@akinon/next/utils', () => ({
98
+ urlLocaleMatcherRegex: new RegExp(
99
+ `^\\/(${nonDefaultLocales.join('|')})(?=\\/|$)`
100
+ )
101
+ }));
102
+ } else {
103
+ jest.doMock('@akinon/next/utils', () => ({
104
+ urlLocaleMatcherRegex: /^\/(?!.*)/
105
+ }));
106
+ console.log('No non-default locales found, using empty regex');
107
+ }
108
+ } catch (error) {
109
+ console.warn(
110
+ 'Could not load actual settings, using default mock settings'
111
+ );
112
+
113
+ jest.doMock('@akinon/next/utils', () => ({
114
+ urlLocaleMatcherRegex: /^\/(?!.*)/
115
+ }));
116
+ console.log('Using fallback empty regex (no locale matching)');
117
+ }
118
+
59
119
  const localizationModule = await import('@akinon/next/localization');
60
120
  LocaleUrlStrategy = localizationModule.LocaleUrlStrategy;
61
121
 
@@ -72,80 +132,191 @@ describe('Redirect utility functional tests', () => {
72
132
  jest.clearAllMocks();
73
133
  process.env.NEXT_PUBLIC_URL = 'https://example.com';
74
134
 
75
- mockServerVariables.locale = 'en';
76
- });
135
+ mockServerVariables.locale =
136
+ actualSettings?.localization?.defaultLocaleValue || 'en';
77
137
 
78
- describe('getUrlPathWithLocale functional tests', () => {
79
- describe('Actual behavior testing', () => {
80
- it('should test actual function behavior with real inputs', () => {
81
- const result1 = getUrlPathWithLocale('/login', 'en');
82
- const result2 = getUrlPathWithLocale('/login', 'tr');
83
- const result3 = getUrlPathWithLocale('/login', undefined);
138
+ mockCookies.mockReturnValue({
139
+ get: jest.fn().mockReturnValue(undefined)
140
+ });
84
141
 
85
- expect(result1).toBe('/login');
86
- expect(result2).toBe('/tr/login');
87
- expect(result3).toBe('/login');
88
- });
142
+ mockHeaders.mockReturnValue(new Map());
143
+ });
89
144
 
90
- it('should handle complex paths with locale prefixes', () => {
91
- const result1 = getUrlPathWithLocale('/account/orders/123', 'en');
92
- const result2 = getUrlPathWithLocale('/account/orders/123', 'tr');
93
- const result3 = getUrlPathWithLocale('/account/orders/123', 'ar');
145
+ describe('getUrlPathWithLocale functional tests', () => {
146
+ describe('Dynamic behavior based on actual settings', () => {
147
+ it('should work correctly with project localeUrlStrategy', () => {
148
+ const defaultLocale =
149
+ actualSettings?.localization?.defaultLocaleValue || 'en';
150
+ const strategy =
151
+ actualSettings?.localization?.localeUrlStrategy ||
152
+ LocaleUrlStrategy.HideDefaultLocale;
153
+ const locales = actualSettings?.localization?.locales || [
154
+ { value: 'en', label: 'EN' },
155
+ { value: 'tr', label: 'TR' }
156
+ ];
157
+
158
+ const result1 = getUrlPathWithLocale('/login', defaultLocale);
159
+
160
+ const nonDefaultLocale = locales.find(
161
+ (locale: Locale) => locale.value !== defaultLocale
162
+ );
163
+ const result2 = nonDefaultLocale
164
+ ? getUrlPathWithLocale('/login', nonDefaultLocale.value)
165
+ : null;
94
166
 
95
- expect(result1).toBe('/account/orders/123');
96
- expect(result2).toBe('/tr/account/orders/123');
97
- expect(result3).toBe('/ar/account/orders/123');
98
- });
167
+ const result3 = getUrlPathWithLocale('/login', undefined);
99
168
 
100
- it('should fallback to default locale behavior when currentLocale is undefined', () => {
101
- const result = getUrlPathWithLocale('/dashboard', undefined);
102
- expect(result).toBe('/dashboard');
169
+ if (strategy === LocaleUrlStrategy.HideDefaultLocale) {
170
+ expect(result1).toBe('/login');
171
+ if (result2 && nonDefaultLocale) {
172
+ expect(result2).toBe(`/${nonDefaultLocale.value}/login`);
173
+ }
174
+ expect(result3).toBe('/login');
175
+ } else if (strategy === LocaleUrlStrategy.ShowAllLocales) {
176
+ expect(result1).toBe(`/${defaultLocale}/login`);
177
+ if (result2 && nonDefaultLocale) {
178
+ expect(result2).toBe(`/${nonDefaultLocale.value}/login`);
179
+ }
180
+ expect(result3).toBe(`/${defaultLocale}/login`);
181
+ } else if (strategy === LocaleUrlStrategy.HideAllLocales) {
182
+ expect(result1).toBe('/login');
183
+ if (result2) {
184
+ expect(result2).toBe('/login');
185
+ }
186
+ expect(result3).toBe('/login');
187
+ } else if (strategy === LocaleUrlStrategy.Subdomain) {
188
+ expect(result1).toBe('/login');
189
+ if (result2) {
190
+ expect(result2).toBe('/login');
191
+ }
192
+ expect(result3).toBe('/login');
193
+ }
103
194
  });
104
195
 
105
- it('should handle empty paths correctly', () => {
106
- const result1 = getUrlPathWithLocale('/', 'en');
107
- const result2 = getUrlPathWithLocale('/', 'tr');
196
+ it('should handle complex paths correctly with project settings', () => {
197
+ const defaultLocale =
198
+ actualSettings?.localization?.defaultLocaleValue || 'en';
199
+ const locales = actualSettings?.localization?.locales || [
200
+ { value: 'en', label: 'EN' },
201
+ { value: 'tr', label: 'TR' }
202
+ ];
203
+ const strategy =
204
+ actualSettings?.localization?.localeUrlStrategy ||
205
+ LocaleUrlStrategy.HideDefaultLocale;
206
+
207
+ const complexPath = '/account/orders/123';
208
+ const nonDefaultLocale = locales.find(
209
+ (locale: Locale) => locale.value !== defaultLocale
210
+ );
108
211
 
109
- expect(result1).toBe('/');
110
- expect(result2).toBe('/tr/');
212
+ const result1 = getUrlPathWithLocale(complexPath, defaultLocale);
213
+ const result2 = nonDefaultLocale
214
+ ? getUrlPathWithLocale(complexPath, nonDefaultLocale.value)
215
+ : null;
216
+
217
+ if (strategy === LocaleUrlStrategy.HideDefaultLocale) {
218
+ expect(result1).toBe(complexPath);
219
+ if (result2 && nonDefaultLocale) {
220
+ expect(result2).toBe(`/${nonDefaultLocale.value}${complexPath}`);
221
+ }
222
+ } else if (strategy === LocaleUrlStrategy.ShowAllLocales) {
223
+ expect(result1).toBe(`/${defaultLocale}${complexPath}`);
224
+ if (result2 && nonDefaultLocale) {
225
+ expect(result2).toBe(`/${nonDefaultLocale.value}${complexPath}`);
226
+ }
227
+ }
111
228
  });
112
229
 
113
- it('should handle paths with query parameters', () => {
114
- const result1 = getUrlPathWithLocale('/search?q=test', 'en');
115
- const result2 = getUrlPathWithLocale('/search?q=test', 'tr');
230
+ it('should handle query parameters correctly', () => {
231
+ const defaultLocale =
232
+ actualSettings?.localization?.defaultLocaleValue || 'en';
233
+ const locales = actualSettings?.localization?.locales || [
234
+ { value: 'en', label: 'EN' },
235
+ { value: 'tr', label: 'TR' }
236
+ ];
237
+ const strategy =
238
+ actualSettings?.localization?.localeUrlStrategy ||
239
+ LocaleUrlStrategy.HideDefaultLocale;
240
+
241
+ const pathWithQuery = '/search?q=test';
242
+ const nonDefaultLocale = locales.find(
243
+ (locale: Locale) => locale.value !== defaultLocale
244
+ );
116
245
 
117
- expect(result1).toBe('/search?q=test');
118
- expect(result2).toBe('/tr/search?q=test');
246
+ const result1 = getUrlPathWithLocale(pathWithQuery, defaultLocale);
247
+ const result2 = nonDefaultLocale
248
+ ? getUrlPathWithLocale(pathWithQuery, nonDefaultLocale.value)
249
+ : null;
250
+
251
+ if (strategy === LocaleUrlStrategy.HideDefaultLocale) {
252
+ expect(result1).toBe(pathWithQuery);
253
+ if (result2 && nonDefaultLocale) {
254
+ expect(result2).toBe(`/${nonDefaultLocale.value}${pathWithQuery}`);
255
+ }
256
+ } else if (strategy === LocaleUrlStrategy.ShowAllLocales) {
257
+ expect(result1).toBe(`/${defaultLocale}${pathWithQuery}`);
258
+ if (result2 && nonDefaultLocale) {
259
+ expect(result2).toBe(`/${nonDefaultLocale.value}${pathWithQuery}`);
260
+ }
261
+ }
119
262
  });
120
263
  });
121
264
  });
122
265
 
123
266
  describe('URL locale matcher regex behavior', () => {
124
- const urlLocaleMatcherRegex = /^\/(?:tr|ar)(?=\/|$)/;
267
+ it('should match non-default locale prefixes based on project settings', () => {
268
+ const defaultLocale =
269
+ actualSettings?.localization?.defaultLocaleValue || 'en';
270
+ const locales = actualSettings?.localization?.locales || [
271
+ { value: 'en', label: 'EN' },
272
+ { value: 'tr', label: 'TR' }
273
+ ];
125
274
 
126
- it('should match non-default locale prefixes', () => {
127
- expect(urlLocaleMatcherRegex.test('/tr/profile')).toBe(true);
128
- expect(urlLocaleMatcherRegex.test('/ar/dashboard')).toBe(true);
129
- });
275
+ const nonDefaultLocales = locales
276
+ .filter((locale: Locale) => locale.value !== defaultLocale)
277
+ .map((locale: Locale) => locale.value);
130
278
 
131
- it('should not match default locale or paths without locale', () => {
132
- expect(urlLocaleMatcherRegex.test('/en/profile')).toBe(false);
279
+ const urlLocaleMatcherRegex = new RegExp(
280
+ `^\\/(${nonDefaultLocales.join('|')})(?=\\/|$)`
281
+ );
282
+
283
+ nonDefaultLocales.forEach((locale: string) => {
284
+ expect(urlLocaleMatcherRegex.test(`/${locale}/profile`)).toBe(true);
285
+ expect(urlLocaleMatcherRegex.test(`/${locale}`)).toBe(true);
286
+ });
287
+
288
+ expect(urlLocaleMatcherRegex.test(`/${defaultLocale}/profile`)).toBe(
289
+ false
290
+ );
133
291
  expect(urlLocaleMatcherRegex.test('/profile')).toBe(false);
134
- expect(urlLocaleMatcherRegex.test('/dashboard')).toBe(false);
135
292
  });
136
293
 
137
- it('should match locale at start of path only', () => {
138
- expect(urlLocaleMatcherRegex.test('/tr/some/path')).toBe(true);
139
- expect(urlLocaleMatcherRegex.test('/tr')).toBe(true);
140
- expect(urlLocaleMatcherRegex.test('/some/tr/path')).toBe(false);
141
- });
294
+ it('should handle callback URL extraction correctly with project locales', () => {
295
+ const defaultLocale =
296
+ actualSettings?.localization?.defaultLocaleValue || 'en';
297
+ const locales = actualSettings?.localization?.locales || [
298
+ { value: 'en', label: 'EN' },
299
+ { value: 'tr', label: 'TR' }
300
+ ];
301
+
302
+ const nonDefaultLocales = locales
303
+ .filter((locale: Locale) => locale.value !== defaultLocale)
304
+ .map((locale: Locale) => locale.value);
305
+
306
+ const urlLocaleMatcherRegex = new RegExp(
307
+ `^\\/(${nonDefaultLocales.join('|')})(?=\\/|$)`
308
+ );
142
309
 
143
- it('should handle callback URL extraction correctly', () => {
144
310
  const testPaths = [
145
- { input: '/tr/profile', expected: '/profile' },
146
- { input: '/ar/dashboard/settings', expected: '/dashboard/settings' },
311
+ ...nonDefaultLocales.map((locale: string) => ({
312
+ input: `/${locale}/profile`,
313
+ expected: '/profile'
314
+ })),
147
315
  { input: '/profile', expected: '/profile' },
148
- { input: '/en/profile', expected: '/en/profile' }
316
+ {
317
+ input: `/${defaultLocale}/profile`,
318
+ expected: `/${defaultLocale}/profile`
319
+ }
149
320
  ];
150
321
 
151
322
  testPaths.forEach(({ input, expected }) => {
@@ -158,7 +329,9 @@ describe('Redirect utility functional tests', () => {
158
329
  describe('redirect function behavior', () => {
159
330
  describe('Default locale strategy tests', () => {
160
331
  beforeEach(() => {
161
- mockServerVariables.locale = 'en';
332
+ const defaultLocale =
333
+ actualSettings?.localization?.defaultLocaleValue || 'en';
334
+ mockServerVariables.locale = defaultLocale;
162
335
  });
163
336
 
164
337
  it('should redirect with correct URL for default locale', () => {
@@ -174,42 +347,118 @@ describe('Redirect utility functional tests', () => {
174
347
  });
175
348
 
176
349
  it('should redirect with locale handling for non-default locale', () => {
177
- mockServerVariables.locale = 'tr';
178
- mockHeaders.mockReturnValue(
179
- new Map([['pz-url', 'https://example.com/tr/profile']])
350
+ const locales = actualSettings?.localization?.locales || [
351
+ { value: 'en', label: 'EN' },
352
+ { value: 'tr', label: 'TR' }
353
+ ];
354
+ const defaultLocale =
355
+ actualSettings?.localization?.defaultLocaleValue || 'en';
356
+ const nonDefaultLocale = locales.find(
357
+ (locale: Locale) => locale.value !== defaultLocale
180
358
  );
181
359
 
182
- redirect('/login');
360
+ if (nonDefaultLocale) {
361
+ mockServerVariables.locale = nonDefaultLocale.value;
362
+ mockHeaders.mockReturnValue(
363
+ new Map([
364
+ [
365
+ 'pz-url',
366
+ `https://example.com/${nonDefaultLocale.value}/profile`
367
+ ]
368
+ ])
369
+ );
183
370
 
184
- expect(mockNextRedirect).toHaveBeenCalledWith(
185
- '/tr/login?callbackUrl=/profile'
186
- );
371
+ redirect('/login');
372
+
373
+ expect(mockNextRedirect).toHaveBeenCalledWith(
374
+ `/${nonDefaultLocale.value}/login?callbackUrl=/profile`
375
+ );
376
+ } else {
377
+ expect(true).toBe(true);
378
+ }
187
379
  });
188
380
 
189
381
  it('should extract callback URL correctly removing locale prefix', () => {
190
- mockServerVariables.locale = 'tr';
191
- mockHeaders.mockReturnValue(
192
- new Map([['pz-url', 'https://example.com/tr/dashboard/settings']])
382
+ const locales = actualSettings?.localization?.locales || [
383
+ { value: 'en', label: 'EN' },
384
+ { value: 'tr', label: 'TR' }
385
+ ];
386
+ const defaultLocale =
387
+ actualSettings?.localization?.defaultLocaleValue || 'en';
388
+ const nonDefaultLocale = locales.find(
389
+ (locale: Locale) => locale.value !== defaultLocale
193
390
  );
194
391
 
195
- redirect('/auth');
196
-
197
- expect(mockNextRedirect).toHaveBeenCalledWith(
198
- '/tr/auth?callbackUrl=/dashboard/settings'
199
- );
392
+ if (nonDefaultLocale) {
393
+ mockServerVariables.locale = nonDefaultLocale.value;
394
+ mockHeaders.mockReturnValue(
395
+ new Map([
396
+ [
397
+ 'pz-url',
398
+ `https://example.com/${nonDefaultLocale.value}/dashboard/settings`
399
+ ]
400
+ ])
401
+ );
402
+
403
+ redirect('/auth');
404
+
405
+ expect(mockNextRedirect).toHaveBeenCalledWith(
406
+ `/${nonDefaultLocale.value}/auth?callbackUrl=/dashboard/settings`
407
+ );
408
+ } else {
409
+ expect(true).toBe(true);
410
+ }
200
411
  });
201
412
 
202
- it('should handle Arabic RTL locale correctly', () => {
203
- mockServerVariables.locale = 'ar';
204
- mockHeaders.mockReturnValue(
205
- new Map([['pz-url', 'https://example.com/ar/products/123']])
413
+ it('should handle RTL or additional locale correctly if available', () => {
414
+ const locales = actualSettings?.localization?.locales || [
415
+ { value: 'en', label: 'EN' },
416
+ { value: 'tr', label: 'TR' }
417
+ ];
418
+ const defaultLocale =
419
+ actualSettings?.localization?.defaultLocaleValue || 'en';
420
+ const rtlLocale = locales.find(
421
+ (locale: Locale) =>
422
+ locale.value !== defaultLocale && locale.value !== 'tr'
206
423
  );
207
424
 
208
- redirect('/checkout');
209
-
210
- expect(mockNextRedirect).toHaveBeenCalledWith(
211
- '/checkout?callbackUrl=/products/123'
212
- );
425
+ if (rtlLocale) {
426
+ mockServerVariables.locale = rtlLocale.value;
427
+ mockHeaders.mockReturnValue(
428
+ new Map([
429
+ ['pz-url', `https://example.com/${rtlLocale.value}/products/123`]
430
+ ])
431
+ );
432
+
433
+ redirect('/checkout');
434
+
435
+ expect(mockNextRedirect).toHaveBeenCalledWith(
436
+ `/${rtlLocale.value}/checkout?callbackUrl=/products/123`
437
+ );
438
+ } else {
439
+ const nonDefaultLocale = locales.find(
440
+ (locale: Locale) => locale.value !== defaultLocale
441
+ );
442
+ if (nonDefaultLocale) {
443
+ mockServerVariables.locale = nonDefaultLocale.value;
444
+ mockHeaders.mockReturnValue(
445
+ new Map([
446
+ [
447
+ 'pz-url',
448
+ `https://example.com/${nonDefaultLocale.value}/products/123`
449
+ ]
450
+ ])
451
+ );
452
+
453
+ redirect('/checkout');
454
+
455
+ expect(mockNextRedirect).toHaveBeenCalledWith(
456
+ `/${nonDefaultLocale.value}/checkout?callbackUrl=/products/123`
457
+ );
458
+ } else {
459
+ expect(true).toBe(true);
460
+ }
461
+ }
213
462
  });
214
463
 
215
464
  it('should preserve complex callback URLs', () => {
@@ -285,7 +534,10 @@ describe('Redirect utility functional tests', () => {
285
534
  new Map([['pz-url', 'https://example.com/profile']])
286
535
  );
287
536
 
288
- redirect('/login');
537
+ // Should not throw error, should handle gracefully
538
+ expect(() => {
539
+ redirect('/login');
540
+ }).not.toThrow();
289
541
 
290
542
  expect(mockNextRedirect).toHaveBeenCalledWith(
291
543
  '/login?callbackUrl=/profile'
@@ -298,14 +550,17 @@ describe('Redirect utility functional tests', () => {
298
550
  new Map([['pz-url', 'https://example.com/profile']])
299
551
  );
300
552
 
301
- redirect('/login');
553
+ // Should not throw error, should handle gracefully
554
+ expect(() => {
555
+ redirect('/login');
556
+ }).not.toThrow();
302
557
 
303
558
  expect(mockNextRedirect).toHaveBeenCalledWith(
304
559
  '/login?callbackUrl=/profile'
305
560
  );
306
561
  });
307
562
 
308
- it('should strip query parameters from callback URL', () => {
563
+ it('should preserve query parameters in callback URL', () => {
309
564
  mockHeaders.mockReturnValue(
310
565
  new Map([
311
566
  ['pz-url', 'https://example.com/profile?tab=settings&view=list']
@@ -315,11 +570,11 @@ describe('Redirect utility functional tests', () => {
315
570
  redirect('/login');
316
571
 
317
572
  expect(mockNextRedirect).toHaveBeenCalledWith(
318
- '/login?callbackUrl=/profile'
573
+ '/login?callbackUrl=/profile?tab=settings&view=list'
319
574
  );
320
575
  });
321
576
 
322
- it('should strip fragments from callback URL', () => {
577
+ it('should strip fragments from callback URL (expected behavior)', () => {
323
578
  mockHeaders.mockReturnValue(
324
579
  new Map([['pz-url', 'https://example.com/profile#section']])
325
580
  );
@@ -331,7 +586,7 @@ describe('Redirect utility functional tests', () => {
331
586
  );
332
587
  });
333
588
 
334
- it('should handle URL with both query params and fragments', () => {
589
+ it('should handle URL with both query params and fragments (fragments stripped)', () => {
335
590
  mockHeaders.mockReturnValue(
336
591
  new Map([['pz-url', 'https://example.com/profile?tab=orders#recent']])
337
592
  );
@@ -339,7 +594,7 @@ describe('Redirect utility functional tests', () => {
339
594
  redirect('/auth');
340
595
 
341
596
  expect(mockNextRedirect).toHaveBeenCalledWith(
342
- '/auth?callbackUrl=/profile'
597
+ '/auth?callbackUrl=/profile?tab=orders'
343
598
  );
344
599
  });
345
600
  });
@@ -347,38 +602,95 @@ describe('Redirect utility functional tests', () => {
347
602
 
348
603
  describe('Integration scenarios', () => {
349
604
  it('should handle complete flow with non-default locale and complex path', () => {
350
- mockServerVariables.locale = 'tr';
351
- mockHeaders.mockReturnValue(
352
- new Map([['pz-url', 'https://example.com/tr/account/orders/123']])
605
+ const locales = actualSettings?.localization?.locales || [
606
+ { value: 'en', label: 'EN' },
607
+ { value: 'tr', label: 'TR' }
608
+ ];
609
+ const defaultLocale =
610
+ actualSettings?.localization?.defaultLocaleValue || 'en';
611
+ const nonDefaultLocale = locales.find(
612
+ (locale: Locale) => locale.value !== defaultLocale
353
613
  );
354
614
 
355
- redirect('/auth/login');
615
+ if (nonDefaultLocale) {
616
+ mockServerVariables.locale = nonDefaultLocale.value;
617
+ mockHeaders.mockReturnValue(
618
+ new Map([
619
+ [
620
+ 'pz-url',
621
+ `https://example.com/${nonDefaultLocale.value}/account/orders/123`
622
+ ]
623
+ ])
624
+ );
356
625
 
357
- expect(mockNextRedirect).toHaveBeenCalledWith(
358
- '/tr/auth/login?callbackUrl=/account/orders/123'
359
- );
626
+ redirect('/auth/login');
627
+
628
+ expect(mockNextRedirect).toHaveBeenCalledWith(
629
+ `/${nonDefaultLocale.value}/auth/login?callbackUrl=/account/orders/123`
630
+ );
631
+ } else {
632
+ expect(true).toBe(true);
633
+ }
360
634
  });
361
635
 
362
- it('should handle RTL locale with deep nested paths', () => {
363
- mockServerVariables.locale = 'ar';
364
- mockHeaders.mockReturnValue(
365
- new Map([
366
- [
367
- 'pz-url',
368
- 'https://example.com/ar/products/category/electronics/item/456'
369
- ]
370
- ])
636
+ it('should handle additional locale with deep nested paths if available', () => {
637
+ const locales = actualSettings?.localization?.locales || [
638
+ { value: 'en', label: 'EN' },
639
+ { value: 'tr', label: 'TR' }
640
+ ];
641
+ const defaultLocale =
642
+ actualSettings?.localization?.defaultLocaleValue || 'en';
643
+ const additionalLocale = locales.find(
644
+ (locale: Locale) =>
645
+ locale.value !== defaultLocale && locale.value !== 'tr'
371
646
  );
372
647
 
373
- redirect('/auth');
648
+ if (additionalLocale) {
649
+ mockServerVariables.locale = additionalLocale.value;
650
+ mockHeaders.mockReturnValue(
651
+ new Map([
652
+ [
653
+ 'pz-url',
654
+ `https://example.com/${additionalLocale.value}/products/category/electronics/item/456`
655
+ ]
656
+ ])
657
+ );
374
658
 
375
- expect(mockNextRedirect).toHaveBeenCalledWith(
376
- '/auth?callbackUrl=/products/category/electronics/item/456'
377
- );
659
+ redirect('/auth');
660
+
661
+ expect(mockNextRedirect).toHaveBeenCalledWith(
662
+ `/${additionalLocale.value}/auth?callbackUrl=/products/category/electronics/item/456`
663
+ );
664
+ } else {
665
+ const nonDefaultLocale = locales.find(
666
+ (locale: Locale) => locale.value !== defaultLocale
667
+ );
668
+ if (nonDefaultLocale) {
669
+ mockServerVariables.locale = nonDefaultLocale.value;
670
+ mockHeaders.mockReturnValue(
671
+ new Map([
672
+ [
673
+ 'pz-url',
674
+ `https://example.com/${nonDefaultLocale.value}/products/category/electronics/item/456`
675
+ ]
676
+ ])
677
+ );
678
+
679
+ redirect('/auth');
680
+
681
+ expect(mockNextRedirect).toHaveBeenCalledWith(
682
+ `/${nonDefaultLocale.value}/auth?callbackUrl=/products/category/electronics/item/456`
683
+ );
684
+ } else {
685
+ expect(true).toBe(true);
686
+ }
687
+ }
378
688
  });
379
689
 
380
690
  it('should handle default locale with no prefix in callback', () => {
381
- mockServerVariables.locale = 'en';
691
+ const defaultLocale =
692
+ actualSettings?.localization?.defaultLocaleValue || 'en';
693
+ mockServerVariables.locale = defaultLocale;
382
694
  mockHeaders.mockReturnValue(
383
695
  new Map([['pz-url', 'https://example.com/checkout/payment']])
384
696
  );
@@ -391,21 +703,35 @@ describe('Redirect utility functional tests', () => {
391
703
  });
392
704
 
393
705
  it('should handle complex URLs with mixed locale scenarios', () => {
394
- mockServerVariables.locale = 'tr';
395
- mockHeaders.mockReturnValue(
396
- new Map([
397
- [
398
- 'pz-url',
399
- 'https://subdomain.example.com/tr/user/dashboard?section=profile&tab=settings#preferences'
400
- ]
401
- ])
706
+ const locales = actualSettings?.localization?.locales || [
707
+ { value: 'en', label: 'EN' },
708
+ { value: 'tr', label: 'TR' }
709
+ ];
710
+ const defaultLocale =
711
+ actualSettings?.localization?.defaultLocaleValue || 'en';
712
+ const nonDefaultLocale = locales.find(
713
+ (locale: Locale) => locale.value !== defaultLocale
402
714
  );
403
715
 
404
- redirect('/verify-account');
716
+ if (nonDefaultLocale) {
717
+ mockServerVariables.locale = nonDefaultLocale.value;
718
+ mockHeaders.mockReturnValue(
719
+ new Map([
720
+ [
721
+ 'pz-url',
722
+ `https://subdomain.example.com/${nonDefaultLocale.value}/user/dashboard?section=profile&tab=settings#preferences`
723
+ ]
724
+ ])
725
+ );
405
726
 
406
- expect(mockNextRedirect).toHaveBeenCalledWith(
407
- '/tr/verify-account?callbackUrl=/user/dashboard'
408
- );
727
+ redirect('/verify-account');
728
+
729
+ expect(mockNextRedirect).toHaveBeenCalledWith(
730
+ `/${nonDefaultLocale.value}/verify-account?callbackUrl=/user/dashboard?section=profile&tab=settings`
731
+ );
732
+ } else {
733
+ expect(true).toBe(true);
734
+ }
409
735
  });
410
736
  });
411
737
 
@@ -35,8 +35,10 @@ import {
35
35
 
36
36
  interface CheckoutResponse {
37
37
  pre_order?: PreOrder;
38
- errors: {
39
- non_field_errors: string;
38
+ errors?: {
39
+ non_field_errors?: string;
40
+ sample_products?: string[];
41
+ [key: string]: string | string[] | undefined;
40
42
  };
41
43
  context_list?: CheckoutContext[];
42
44
  template_name?: string;
package/jest.config.js CHANGED
@@ -7,9 +7,9 @@ module.exports = {
7
7
  preset: 'ts-jest',
8
8
  testEnvironment: 'node',
9
9
  rootDir: path.resolve(__dirname),
10
- testMatch: ['**/__tests__/**/*.test.ts'],
10
+ testMatch: ['**/*.test.ts'],
11
11
  testPathIgnorePatterns: [],
12
- roots: [],
12
+ roots: [path.resolve(__dirname)],
13
13
  transformIgnorePatterns: [],
14
14
  moduleNameMapper: {
15
15
  '^settings$': path.resolve(baseDir, 'src/settings.js')
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@akinon/next",
3
3
  "description": "Core package for Project Zero Next",
4
- "version": "1.92.0-rc.38",
4
+ "version": "1.92.0-rc.40",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -34,7 +34,7 @@
34
34
  "set-cookie-parser": "2.6.0"
35
35
  },
36
36
  "devDependencies": {
37
- "@akinon/eslint-plugin-projectzero": "1.92.0-rc.38",
37
+ "@akinon/eslint-plugin-projectzero": "1.92.0-rc.40",
38
38
  "@babel/core": "7.26.10",
39
39
  "@babel/preset-env": "7.26.9",
40
40
  "@babel/preset-typescript": "7.27.0",