@akinon/next 1.93.0-rc.49 → 1.93.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 +36 -1260
- package/__tests__/next-config.test.ts +10 -1
- package/bin/pz-prebuild.js +1 -0
- package/components/accordion.tsx +5 -20
- package/components/file-input.tsx +3 -65
- package/components/input.tsx +0 -2
- package/components/link.tsx +12 -16
- package/components/modal.tsx +16 -32
- package/components/plugin-module.tsx +3 -35
- package/components/selected-payment-option-view.tsx +0 -11
- package/data/client/checkout.ts +4 -25
- package/data/server/category.ts +28 -48
- package/data/server/flatpage.ts +12 -16
- package/data/server/landingpage.ts +12 -16
- package/data/server/list.ts +13 -23
- package/data/server/product.ts +39 -66
- package/data/server/special-page.ts +12 -16
- package/data/urls.ts +2 -7
- package/hocs/server/with-segment-defaults.tsx +2 -5
- package/hooks/use-localization.ts +3 -2
- package/instrumentation/node.ts +13 -15
- package/jest.config.js +1 -7
- package/lib/cache.ts +0 -2
- package/middlewares/checkout-provider.ts +1 -1
- package/middlewares/complete-gpay.ts +2 -6
- package/middlewares/complete-masterpass.ts +2 -7
- package/middlewares/default.ts +183 -232
- package/middlewares/index.ts +1 -3
- package/middlewares/locale.ts +1 -9
- package/middlewares/redirection-payment.ts +2 -6
- package/middlewares/saved-card-redirection.ts +2 -7
- package/middlewares/three-d-redirection.ts +2 -7
- package/middlewares/url-redirection.ts +15 -9
- package/package.json +3 -3
- package/plugins.d.ts +0 -10
- package/plugins.js +1 -4
- package/redux/middlewares/checkout.ts +2 -15
- package/redux/reducers/checkout.ts +1 -9
- package/sentry/index.ts +17 -54
- package/types/commerce/order.ts +0 -1
- package/types/index.ts +1 -42
- package/utils/app-fetch.ts +2 -7
- package/utils/index.ts +10 -34
- package/utils/redirect.ts +6 -31
- package/with-pz-config.js +5 -1
- package/__tests__/redirect.test.ts +0 -758
- package/api/image-proxy.ts +0 -75
- package/api/similar-product-list.ts +0 -84
- package/api/similar-products.ts +0 -120
- package/data/server/basket.ts +0 -72
- package/hooks/use-loyalty-availability.ts +0 -21
- package/middlewares/wallet-complete-redirection.ts +0 -203
- package/utils/redirect-ignore.ts +0 -35
|
@@ -1,758 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
|
|
4
|
-
interface Locale {
|
|
5
|
-
value: string;
|
|
6
|
-
label: string;
|
|
7
|
-
localePath?: string;
|
|
8
|
-
apiValue?: string;
|
|
9
|
-
rtl?: boolean;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const mockNextRedirect = jest.fn();
|
|
13
|
-
const mockHeaders = jest.fn();
|
|
14
|
-
const mockCookies = jest.fn();
|
|
15
|
-
|
|
16
|
-
function findBaseDir() {
|
|
17
|
-
const insideNodeModules = __dirname.includes('node_modules');
|
|
18
|
-
|
|
19
|
-
if (insideNodeModules) {
|
|
20
|
-
return path.resolve(__dirname, '../../../../');
|
|
21
|
-
} else {
|
|
22
|
-
return path.resolve(__dirname, '../../../apps/projectzeronext');
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
jest.mock(
|
|
27
|
-
'@theme/routes',
|
|
28
|
-
() => ({
|
|
29
|
-
ROUTES: {
|
|
30
|
-
AUTH: '/auth',
|
|
31
|
-
BASKET: '/basket',
|
|
32
|
-
ACCOUNT_ORDERS: '/account/orders'
|
|
33
|
-
}
|
|
34
|
-
}),
|
|
35
|
-
{ virtual: true }
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
jest.mock('next/navigation', () => ({
|
|
39
|
-
redirect: mockNextRedirect,
|
|
40
|
-
RedirectType: {
|
|
41
|
-
replace: 'replace',
|
|
42
|
-
push: 'push'
|
|
43
|
-
}
|
|
44
|
-
}));
|
|
45
|
-
|
|
46
|
-
jest.mock('next/headers', () => ({
|
|
47
|
-
headers: () => mockHeaders(),
|
|
48
|
-
cookies: () => mockCookies()
|
|
49
|
-
}));
|
|
50
|
-
|
|
51
|
-
const mockServerVariables = {
|
|
52
|
-
locale: 'en' as string | undefined
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
jest.mock('@akinon/next/utils/server-variables', () => ({
|
|
56
|
-
ServerVariables: mockServerVariables
|
|
57
|
-
}));
|
|
58
|
-
|
|
59
|
-
jest.mock('@akinon/next/utils', () => ({
|
|
60
|
-
urlLocaleMatcherRegex: /^\/(?:tr)(?=\/|$)/
|
|
61
|
-
}));
|
|
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
|
-
|
|
76
|
-
describe('Redirect utility functional tests', () => {
|
|
77
|
-
let redirect: any;
|
|
78
|
-
let getUrlPathWithLocale: any;
|
|
79
|
-
let LocaleUrlStrategy: any;
|
|
80
|
-
let actualSettings: any;
|
|
81
|
-
|
|
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
|
-
|
|
119
|
-
const localizationModule = await import('@akinon/next/localization');
|
|
120
|
-
LocaleUrlStrategy = localizationModule.LocaleUrlStrategy;
|
|
121
|
-
|
|
122
|
-
const redirectModule = await import('@akinon/next/utils/redirect');
|
|
123
|
-
redirect = redirectModule.redirect;
|
|
124
|
-
|
|
125
|
-
const localizationUtilsModule = await import(
|
|
126
|
-
'@akinon/next/utils/localization'
|
|
127
|
-
);
|
|
128
|
-
getUrlPathWithLocale = localizationUtilsModule.getUrlPathWithLocale;
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
beforeEach(() => {
|
|
132
|
-
jest.clearAllMocks();
|
|
133
|
-
process.env.NEXT_PUBLIC_URL = 'https://example.com';
|
|
134
|
-
|
|
135
|
-
mockServerVariables.locale =
|
|
136
|
-
actualSettings?.localization?.defaultLocaleValue || 'en';
|
|
137
|
-
|
|
138
|
-
mockCookies.mockReturnValue({
|
|
139
|
-
get: jest.fn().mockReturnValue(undefined)
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
mockHeaders.mockReturnValue(new Map());
|
|
143
|
-
});
|
|
144
|
-
|
|
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;
|
|
166
|
-
|
|
167
|
-
const result3 = getUrlPathWithLocale('/login', undefined);
|
|
168
|
-
|
|
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
|
-
}
|
|
194
|
-
});
|
|
195
|
-
|
|
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
|
-
);
|
|
211
|
-
|
|
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
|
-
}
|
|
228
|
-
});
|
|
229
|
-
|
|
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
|
-
);
|
|
245
|
-
|
|
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
|
-
}
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
describe('URL locale matcher regex behavior', () => {
|
|
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
|
-
];
|
|
274
|
-
|
|
275
|
-
const nonDefaultLocales = locales
|
|
276
|
-
.filter((locale: Locale) => locale.value !== defaultLocale)
|
|
277
|
-
.map((locale: Locale) => locale.value);
|
|
278
|
-
|
|
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
|
-
);
|
|
291
|
-
expect(urlLocaleMatcherRegex.test('/profile')).toBe(false);
|
|
292
|
-
});
|
|
293
|
-
|
|
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
|
-
);
|
|
309
|
-
|
|
310
|
-
const testPaths = [
|
|
311
|
-
...nonDefaultLocales.map((locale: string) => ({
|
|
312
|
-
input: `/${locale}/profile`,
|
|
313
|
-
expected: '/profile'
|
|
314
|
-
})),
|
|
315
|
-
{ input: '/profile', expected: '/profile' },
|
|
316
|
-
{
|
|
317
|
-
input: `/${defaultLocale}/profile`,
|
|
318
|
-
expected: `/${defaultLocale}/profile`
|
|
319
|
-
}
|
|
320
|
-
];
|
|
321
|
-
|
|
322
|
-
testPaths.forEach(({ input, expected }) => {
|
|
323
|
-
const result = input.replace(urlLocaleMatcherRegex, '');
|
|
324
|
-
expect(result).toBe(expected);
|
|
325
|
-
});
|
|
326
|
-
});
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
describe('redirect function behavior', () => {
|
|
330
|
-
describe('Default locale strategy tests', () => {
|
|
331
|
-
beforeEach(() => {
|
|
332
|
-
const defaultLocale =
|
|
333
|
-
actualSettings?.localization?.defaultLocaleValue || 'en';
|
|
334
|
-
mockServerVariables.locale = defaultLocale;
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
it('should redirect with correct URL for default locale', () => {
|
|
338
|
-
mockHeaders.mockReturnValue(
|
|
339
|
-
new Map([['pz-url', 'https://example.com/profile']])
|
|
340
|
-
);
|
|
341
|
-
|
|
342
|
-
redirect('/login');
|
|
343
|
-
|
|
344
|
-
expect(mockNextRedirect).toHaveBeenCalledWith(
|
|
345
|
-
'/login?callbackUrl=/profile'
|
|
346
|
-
);
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
it('should redirect with locale handling for non-default locale', () => {
|
|
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
|
|
358
|
-
);
|
|
359
|
-
|
|
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
|
-
);
|
|
370
|
-
|
|
371
|
-
redirect('/login');
|
|
372
|
-
|
|
373
|
-
expect(mockNextRedirect).toHaveBeenCalledWith(
|
|
374
|
-
`/${nonDefaultLocale.value}/login?callbackUrl=/profile`
|
|
375
|
-
);
|
|
376
|
-
} else {
|
|
377
|
-
expect(true).toBe(true);
|
|
378
|
-
}
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
it('should extract callback URL correctly removing locale prefix', () => {
|
|
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
|
|
390
|
-
);
|
|
391
|
-
|
|
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
|
-
}
|
|
411
|
-
});
|
|
412
|
-
|
|
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'
|
|
423
|
-
);
|
|
424
|
-
|
|
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
|
-
}
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
it('should preserve complex callback URLs', () => {
|
|
465
|
-
mockServerVariables.locale = 'tr';
|
|
466
|
-
mockHeaders.mockReturnValue(
|
|
467
|
-
new Map([
|
|
468
|
-
['pz-url', 'https://example.com/tr/account/orders/123/details']
|
|
469
|
-
])
|
|
470
|
-
);
|
|
471
|
-
|
|
472
|
-
redirect('/auth/login');
|
|
473
|
-
|
|
474
|
-
expect(mockNextRedirect).toHaveBeenCalledWith(
|
|
475
|
-
'/tr/auth/login?callbackUrl=/account/orders/123/details'
|
|
476
|
-
);
|
|
477
|
-
});
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
describe('Redirect type handling', () => {
|
|
481
|
-
beforeEach(() => {
|
|
482
|
-
mockHeaders.mockReturnValue(
|
|
483
|
-
new Map([['pz-url', 'https://example.com/profile']])
|
|
484
|
-
);
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
it('should pass RedirectType when provided', () => {
|
|
488
|
-
const { RedirectType } = require('next/navigation');
|
|
489
|
-
|
|
490
|
-
redirect('/login', RedirectType.replace);
|
|
491
|
-
|
|
492
|
-
expect(mockNextRedirect).toHaveBeenCalledTimes(1);
|
|
493
|
-
const [redirectUrl, type] = mockNextRedirect.mock.calls[0];
|
|
494
|
-
expect(redirectUrl).toContain('/login');
|
|
495
|
-
expect(type).toBe(RedirectType.replace);
|
|
496
|
-
});
|
|
497
|
-
|
|
498
|
-
it('should call redirect without type when not provided', () => {
|
|
499
|
-
redirect('/login');
|
|
500
|
-
|
|
501
|
-
expect(mockNextRedirect).toHaveBeenCalledTimes(1);
|
|
502
|
-
const args = mockNextRedirect.mock.calls[0];
|
|
503
|
-
expect(args.length).toBe(1);
|
|
504
|
-
});
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
describe('Error handling and edge cases', () => {
|
|
508
|
-
it('should handle missing pz-url header with env fallback', () => {
|
|
509
|
-
mockHeaders.mockReturnValue(new Map());
|
|
510
|
-
process.env.NEXT_PUBLIC_URL = 'https://fallback.com/some/path';
|
|
511
|
-
|
|
512
|
-
redirect('/login');
|
|
513
|
-
|
|
514
|
-
expect(mockNextRedirect).toHaveBeenCalledWith(
|
|
515
|
-
'/login?callbackUrl=/some/path'
|
|
516
|
-
);
|
|
517
|
-
});
|
|
518
|
-
|
|
519
|
-
it('should handle completely missing URL sources gracefully', () => {
|
|
520
|
-
mockHeaders.mockReturnValue(new Map());
|
|
521
|
-
const originalEnv = process.env.NEXT_PUBLIC_URL;
|
|
522
|
-
delete process.env.NEXT_PUBLIC_URL;
|
|
523
|
-
|
|
524
|
-
expect(() => {
|
|
525
|
-
redirect('/login');
|
|
526
|
-
}).toThrow('Invalid URL');
|
|
527
|
-
|
|
528
|
-
process.env.NEXT_PUBLIC_URL = originalEnv;
|
|
529
|
-
});
|
|
530
|
-
|
|
531
|
-
it('should handle undefined locale gracefully', () => {
|
|
532
|
-
mockServerVariables.locale = undefined;
|
|
533
|
-
mockHeaders.mockReturnValue(
|
|
534
|
-
new Map([['pz-url', 'https://example.com/profile']])
|
|
535
|
-
);
|
|
536
|
-
|
|
537
|
-
// Should not throw error, should handle gracefully
|
|
538
|
-
expect(() => {
|
|
539
|
-
redirect('/login');
|
|
540
|
-
}).not.toThrow();
|
|
541
|
-
|
|
542
|
-
expect(mockNextRedirect).toHaveBeenCalledWith(
|
|
543
|
-
'/login?callbackUrl=/profile'
|
|
544
|
-
);
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
it('should handle invalid locale gracefully', () => {
|
|
548
|
-
mockServerVariables.locale = 'invalid-locale';
|
|
549
|
-
mockHeaders.mockReturnValue(
|
|
550
|
-
new Map([['pz-url', 'https://example.com/profile']])
|
|
551
|
-
);
|
|
552
|
-
|
|
553
|
-
// Should not throw error, should handle gracefully
|
|
554
|
-
expect(() => {
|
|
555
|
-
redirect('/login');
|
|
556
|
-
}).not.toThrow();
|
|
557
|
-
|
|
558
|
-
expect(mockNextRedirect).toHaveBeenCalledWith(
|
|
559
|
-
'/login?callbackUrl=/profile'
|
|
560
|
-
);
|
|
561
|
-
});
|
|
562
|
-
|
|
563
|
-
it('should preserve query parameters in callback URL', () => {
|
|
564
|
-
mockHeaders.mockReturnValue(
|
|
565
|
-
new Map([
|
|
566
|
-
['pz-url', 'https://example.com/profile?tab=settings&view=list']
|
|
567
|
-
])
|
|
568
|
-
);
|
|
569
|
-
|
|
570
|
-
redirect('/login');
|
|
571
|
-
|
|
572
|
-
expect(mockNextRedirect).toHaveBeenCalledWith(
|
|
573
|
-
'/login?callbackUrl=/profile?tab=settings&view=list'
|
|
574
|
-
);
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
it('should strip fragments from callback URL (expected behavior)', () => {
|
|
578
|
-
mockHeaders.mockReturnValue(
|
|
579
|
-
new Map([['pz-url', 'https://example.com/profile#section']])
|
|
580
|
-
);
|
|
581
|
-
|
|
582
|
-
redirect('/login');
|
|
583
|
-
|
|
584
|
-
expect(mockNextRedirect).toHaveBeenCalledWith(
|
|
585
|
-
'/login?callbackUrl=/profile'
|
|
586
|
-
);
|
|
587
|
-
});
|
|
588
|
-
|
|
589
|
-
it('should handle URL with both query params and fragments (fragments stripped)', () => {
|
|
590
|
-
mockHeaders.mockReturnValue(
|
|
591
|
-
new Map([['pz-url', 'https://example.com/profile?tab=orders#recent']])
|
|
592
|
-
);
|
|
593
|
-
|
|
594
|
-
redirect('/auth');
|
|
595
|
-
|
|
596
|
-
expect(mockNextRedirect).toHaveBeenCalledWith(
|
|
597
|
-
'/auth?callbackUrl=/profile?tab=orders'
|
|
598
|
-
);
|
|
599
|
-
});
|
|
600
|
-
});
|
|
601
|
-
});
|
|
602
|
-
|
|
603
|
-
describe('Integration scenarios', () => {
|
|
604
|
-
it('should handle complete flow with non-default locale and complex path', () => {
|
|
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
|
|
613
|
-
);
|
|
614
|
-
|
|
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
|
-
);
|
|
625
|
-
|
|
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
|
-
}
|
|
634
|
-
});
|
|
635
|
-
|
|
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'
|
|
646
|
-
);
|
|
647
|
-
|
|
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
|
-
);
|
|
658
|
-
|
|
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
|
-
}
|
|
688
|
-
});
|
|
689
|
-
|
|
690
|
-
it('should handle default locale with no prefix in callback', () => {
|
|
691
|
-
const defaultLocale =
|
|
692
|
-
actualSettings?.localization?.defaultLocaleValue || 'en';
|
|
693
|
-
mockServerVariables.locale = defaultLocale;
|
|
694
|
-
mockHeaders.mockReturnValue(
|
|
695
|
-
new Map([['pz-url', 'https://example.com/checkout/payment']])
|
|
696
|
-
);
|
|
697
|
-
|
|
698
|
-
redirect('/auth/login');
|
|
699
|
-
|
|
700
|
-
expect(mockNextRedirect).toHaveBeenCalledWith(
|
|
701
|
-
'/auth/login?callbackUrl=/checkout/payment'
|
|
702
|
-
);
|
|
703
|
-
});
|
|
704
|
-
|
|
705
|
-
it('should handle complex URLs with mixed locale scenarios', () => {
|
|
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
|
|
714
|
-
);
|
|
715
|
-
|
|
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
|
-
);
|
|
726
|
-
|
|
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
|
-
}
|
|
735
|
-
});
|
|
736
|
-
});
|
|
737
|
-
|
|
738
|
-
it('should verify redirect utility file exists and has expected structure', () => {
|
|
739
|
-
const baseDir = findBaseDir();
|
|
740
|
-
const insideNodeModules = __dirname.includes('node_modules');
|
|
741
|
-
|
|
742
|
-
let redirectFilePath;
|
|
743
|
-
if (insideNodeModules) {
|
|
744
|
-
redirectFilePath = path.resolve(__dirname, '../utils/redirect.ts');
|
|
745
|
-
} else {
|
|
746
|
-
redirectFilePath = path.resolve(
|
|
747
|
-
baseDir,
|
|
748
|
-
'../../packages/akinon-next/utils/redirect.ts'
|
|
749
|
-
);
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
const redirectFileContent = fs.readFileSync(redirectFilePath, 'utf8');
|
|
753
|
-
|
|
754
|
-
expect(redirectFileContent.includes('export const redirect')).toBe(true);
|
|
755
|
-
expect(redirectFileContent.includes('getUrlPathWithLocale')).toBe(true);
|
|
756
|
-
expect(redirectFileContent.includes('callbackUrl')).toBe(true);
|
|
757
|
-
});
|
|
758
|
-
});
|