@akinon/next 1.126.15 → 1.126.16
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 +6 -0
- package/__tests__/widget-schema-data.test.ts +121 -0
- package/data/server/widget.ts +40 -1
- package/lib/cache.ts +1 -0
- package/package.json +2 -2
- package/types/commerce/widget.ts +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
jest.mock('server-only', () => ({}), { virtual: true });
|
|
2
|
+
|
|
3
|
+
const appFetch = jest.fn();
|
|
4
|
+
|
|
5
|
+
jest.mock('../utils/app-fetch', () => ({
|
|
6
|
+
__esModule: true,
|
|
7
|
+
default: (...args: unknown[]) => appFetch(...args)
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
jest.mock('../utils/server-variables', () => ({
|
|
11
|
+
ServerVariables: { locale: 'tr', currency: 'try' }
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
import { getWidgetData, getWidgetSchemaData } from '../data/server/widget';
|
|
15
|
+
import { Cache, CacheKey } from '../lib/cache';
|
|
16
|
+
|
|
17
|
+
const SLUG = 'section-hero';
|
|
18
|
+
|
|
19
|
+
const SCHEMA = {
|
|
20
|
+
pk: 12,
|
|
21
|
+
name: SLUG,
|
|
22
|
+
schema: {
|
|
23
|
+
[SLUG]: { metadata: { blocks: [{ id: 'block-banner', type: 'image' }] } }
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
describe('getWidgetSchemaData', () => {
|
|
28
|
+
let wrap: jest.SpyInstance;
|
|
29
|
+
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
appFetch.mockReset().mockResolvedValue(SCHEMA);
|
|
32
|
+
wrap = jest
|
|
33
|
+
.spyOn(Cache, 'wrap')
|
|
34
|
+
.mockImplementation(async (_key, _locale, handler) => handler());
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
wrap.mockRestore();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('reads the schema endpoint for the request locale and currency', async () => {
|
|
42
|
+
await expect(getWidgetSchemaData({ widgetSlug: SLUG })).resolves.toEqual(
|
|
43
|
+
SCHEMA
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
expect(appFetch).toHaveBeenCalledTimes(1);
|
|
47
|
+
expect(appFetch).toHaveBeenCalledWith({
|
|
48
|
+
url: `/widgets/${SLUG}/schema/`,
|
|
49
|
+
locale: 'tr',
|
|
50
|
+
currency: 'try',
|
|
51
|
+
init: {}
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('caches under its own key, per locale', async () => {
|
|
56
|
+
await getWidgetSchemaData({ widgetSlug: SLUG });
|
|
57
|
+
|
|
58
|
+
expect(wrap).toHaveBeenCalledWith(
|
|
59
|
+
`widget_schema_${SLUG}`,
|
|
60
|
+
'tr',
|
|
61
|
+
expect.any(Function),
|
|
62
|
+
undefined
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('never shares a cache entry with the widget answer', () => {
|
|
67
|
+
expect(CacheKey.WidgetSchema(SLUG)).not.toBe(CacheKey.Widget(SLUG));
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('honours an explicit locale, currency and cache options', async () => {
|
|
71
|
+
const cacheOptions = { expire: 30 };
|
|
72
|
+
|
|
73
|
+
await getWidgetSchemaData({
|
|
74
|
+
widgetSlug: SLUG,
|
|
75
|
+
locale: 'en',
|
|
76
|
+
currency: 'usd',
|
|
77
|
+
cacheOptions
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(wrap).toHaveBeenCalledWith(
|
|
81
|
+
`widget_schema_${SLUG}`,
|
|
82
|
+
'en',
|
|
83
|
+
expect.any(Function),
|
|
84
|
+
cacheOptions
|
|
85
|
+
);
|
|
86
|
+
expect(appFetch).toHaveBeenCalledWith({
|
|
87
|
+
url: `/widgets/${SLUG}/schema/`,
|
|
88
|
+
locale: 'en',
|
|
89
|
+
currency: 'usd',
|
|
90
|
+
init: {}
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('serves a cached schema without calling the api', async () => {
|
|
95
|
+
wrap.mockResolvedValue(SCHEMA);
|
|
96
|
+
|
|
97
|
+
await expect(getWidgetSchemaData({ widgetSlug: SLUG })).resolves.toEqual(
|
|
98
|
+
SCHEMA
|
|
99
|
+
);
|
|
100
|
+
expect(appFetch).not.toHaveBeenCalled();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('answers null for an empty slug without calling the api', async () => {
|
|
104
|
+
await expect(getWidgetSchemaData({ widgetSlug: '' })).resolves.toBeNull();
|
|
105
|
+
expect(appFetch).not.toHaveBeenCalled();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('lives exactly as long as the widget answer it is paired with', async () => {
|
|
109
|
+
await getWidgetData({ slug: SLUG });
|
|
110
|
+
await getWidgetSchemaData({ widgetSlug: SLUG });
|
|
111
|
+
|
|
112
|
+
const [dataOptions, schemaOptions] = wrap.mock.calls.map((call) => call[3]);
|
|
113
|
+
|
|
114
|
+
expect(wrap.mock.calls.map((call) => call[0])).toEqual([
|
|
115
|
+
`widget_${SLUG}`,
|
|
116
|
+
`widget_schema_${SLUG}`
|
|
117
|
+
]);
|
|
118
|
+
expect(dataOptions?.expire).toBeUndefined();
|
|
119
|
+
expect(schemaOptions?.expire).toBeUndefined();
|
|
120
|
+
});
|
|
121
|
+
});
|
package/data/server/widget.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Cache, CacheKey } from '../../lib/cache';
|
|
2
2
|
import 'server-only';
|
|
3
|
-
import { CacheOptions, WidgetResultType } from '../../types';
|
|
3
|
+
import { CacheOptions, WidgetResultType, WidgetSchemaType } from '../../types';
|
|
4
4
|
import appFetch from '../../utils/app-fetch';
|
|
5
5
|
import { widgets } from '../urls';
|
|
6
6
|
import { ServerVariables } from '../../utils/server-variables';
|
|
@@ -264,3 +264,42 @@ export const getWidgetData = async <T>({
|
|
|
264
264
|
}
|
|
265
265
|
);
|
|
266
266
|
};
|
|
267
|
+
|
|
268
|
+
const getWidgetSchemaDataHandler =
|
|
269
|
+
(
|
|
270
|
+
widgetSlug: string,
|
|
271
|
+
locale: string,
|
|
272
|
+
currency: string,
|
|
273
|
+
next?: { revalidate: number }
|
|
274
|
+
) =>
|
|
275
|
+
async () => {
|
|
276
|
+
if (!widgetSlug) {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return await appFetch({
|
|
281
|
+
url: widgets.getWidgetSchema(widgetSlug),
|
|
282
|
+
locale,
|
|
283
|
+
currency,
|
|
284
|
+
init: next ? { next } : {}
|
|
285
|
+
});
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
export const getWidgetSchemaData = async <T>({
|
|
289
|
+
widgetSlug,
|
|
290
|
+
locale = ServerVariables.locale,
|
|
291
|
+
currency = ServerVariables.currency,
|
|
292
|
+
cacheOptions
|
|
293
|
+
}: {
|
|
294
|
+
widgetSlug: string;
|
|
295
|
+
locale?: string;
|
|
296
|
+
currency?: string;
|
|
297
|
+
cacheOptions?: CacheOptions;
|
|
298
|
+
}): Promise<WidgetSchemaType<T>> => {
|
|
299
|
+
return Cache.wrap(
|
|
300
|
+
CacheKey.WidgetSchema(widgetSlug),
|
|
301
|
+
locale,
|
|
302
|
+
getWidgetSchemaDataHandler(widgetSlug, locale, currency),
|
|
303
|
+
cacheOptions
|
|
304
|
+
);
|
|
305
|
+
};
|
package/lib/cache.ts
CHANGED
|
@@ -108,6 +108,7 @@ export const CacheKey = {
|
|
|
108
108
|
FlatPage: (pk: number) => `flat_page_${pk}`,
|
|
109
109
|
LandingPage: (pk: number) => `landing_page_${pk}`,
|
|
110
110
|
Widget: (slug: string) => `widget_${slug}`,
|
|
111
|
+
WidgetSchema: (widgetSlug: string) => `widget_schema_${widgetSlug}`,
|
|
111
112
|
PrettyUrl: (pathname: string) => `pretty_url_${pathname}`,
|
|
112
113
|
Menu: (depth: number, parent?: string) =>
|
|
113
114
|
`menu_${depth}${parent ? `_${parent}` : ''}`,
|
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.126.
|
|
4
|
+
"version": "1.126.16",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"set-cookie-parser": "2.6.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@akinon/eslint-plugin-projectzero": "1.126.
|
|
38
|
+
"@akinon/eslint-plugin-projectzero": "1.126.16",
|
|
39
39
|
"@babel/core": "7.26.10",
|
|
40
40
|
"@babel/preset-env": "7.26.9",
|
|
41
41
|
"@babel/preset-typescript": "7.27.0",
|