@payloadcms/ui 4.0.0-canary.35 → 4.0.0-canary.36

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.
Files changed (180) hide show
  1. package/dist/css/app.css +1 -0
  2. package/dist/css/preflight.css +1 -0
  3. package/dist/css/spacing.css +3 -0
  4. package/dist/elements/AppHeader/index.css +3 -0
  5. package/dist/elements/BulkUpload/ActionsBar/index.css +1 -0
  6. package/dist/elements/BulkUpload/AddingFilesView/index.css +2 -4
  7. package/dist/elements/BulkUpload/FileSidebar/index.css +1 -0
  8. package/dist/elements/BulkUpload/FormsManager/index.d.ts.map +1 -1
  9. package/dist/elements/BulkUpload/FormsManager/index.js +12 -7
  10. package/dist/elements/BulkUpload/FormsManager/index.js.map +1 -1
  11. package/dist/elements/BulkUpload/index.css +2 -0
  12. package/dist/elements/Collapsible/index.css +1 -0
  13. package/dist/elements/DatePicker/index.css +2 -0
  14. package/dist/elements/Dialog/index.css +1 -0
  15. package/dist/elements/DocumentControls/index.css +1 -0
  16. package/dist/elements/DocumentFields/index.css +2 -0
  17. package/dist/elements/DocumentHeader/Tabs/index.css +1 -0
  18. package/dist/elements/DocumentHeader/index.css +1 -0
  19. package/dist/elements/EditUpload/index.css +1 -1
  20. package/dist/elements/FieldDiffContainer/index.css +1 -0
  21. package/dist/elements/FieldDiffLabel/index.css +1 -0
  22. package/dist/elements/FileDetails/StaticFileDetails/index.css +2 -0
  23. package/dist/elements/HTMLDiff/index.css +1 -0
  24. package/dist/elements/ItemsDrawer/index.css +3 -0
  25. package/dist/elements/ListControls/index.css +1 -0
  26. package/dist/elements/ListControls/index.d.ts.map +1 -1
  27. package/dist/elements/ListControls/index.js +7 -1
  28. package/dist/elements/ListControls/index.js.map +1 -1
  29. package/dist/elements/ListControls/types.d.ts +3 -1
  30. package/dist/elements/ListControls/types.d.ts.map +1 -1
  31. package/dist/elements/ListControls/types.js.map +1 -1
  32. package/dist/elements/ListControlsBar/index.css +1 -0
  33. package/dist/elements/ListHeader/TitleActions/ListEmptyTrashButton.js +1 -1
  34. package/dist/elements/ListHeader/TitleActions/ListEmptyTrashButton.js.map +1 -1
  35. package/dist/elements/LivePreview/Window/index.css +1 -0
  36. package/dist/elements/Nav/index.css +2 -0
  37. package/dist/elements/PageControls/index.css +1 -0
  38. package/dist/elements/PillSelector/index.css +1 -0
  39. package/dist/elements/PreviewSizes/index.css +2 -0
  40. package/dist/elements/PublishButton/index.css +1 -0
  41. package/dist/elements/QueryPresets/fields/Heading/index.css +1 -0
  42. package/dist/elements/RenderTitle/index.css +1 -0
  43. package/dist/elements/Table/index.css +1 -0
  44. package/dist/elements/TableSection/index.css +1 -0
  45. package/dist/elements/Tabs/index.css +1 -0
  46. package/dist/elements/Thumbnail/index.css +1 -0
  47. package/dist/elements/TimezonePicker/index.css +1 -0
  48. package/dist/elements/Tooltip/index.css +7 -0
  49. package/dist/elements/WhereBuilder/Condition/index.css +1 -0
  50. package/dist/elements/WhereBuilder/index.css +2 -0
  51. package/dist/fields/Array/index.css +1 -0
  52. package/dist/fields/Blocks/index.css +1 -0
  53. package/dist/fields/Group/index.css +1 -0
  54. package/dist/fields/Row/index.css +2 -0
  55. package/dist/fields/Tabs/index.css +1 -0
  56. package/dist/forms/RenderFields/index.css +1 -0
  57. package/dist/hooks/useControllableState.js +3 -3
  58. package/dist/hooks/useControllableState.js.map +1 -1
  59. package/dist/providers/DocumentInfo/index.d.ts.map +1 -1
  60. package/dist/providers/DocumentInfo/index.js +30 -19
  61. package/dist/providers/DocumentInfo/index.js.map +1 -1
  62. package/dist/providers/Locale/index.d.ts.map +1 -1
  63. package/dist/providers/Locale/index.js +6 -7
  64. package/dist/providers/Locale/index.js.map +1 -1
  65. package/dist/styles.css +5 -1
  66. package/dist/templates/Default/Wrapper/index.css +2 -0
  67. package/dist/templates/Default/index.css +1 -0
  68. package/dist/utilities/handleAuthRedirect.d.ts.map +1 -1
  69. package/dist/utilities/handleAuthRedirect.js +4 -1
  70. package/dist/utilities/handleAuthRedirect.js.map +1 -1
  71. package/dist/utilities/isPathMatchingRoute.d.ts.map +1 -1
  72. package/dist/utilities/isPathMatchingRoute.js +7 -5
  73. package/dist/utilities/isPathMatchingRoute.js.map +1 -1
  74. package/dist/views/API/index.css +1 -0
  75. package/dist/views/Dashboard/Default/ModularDashboard/index.css +2 -0
  76. package/dist/views/Edit/index.css +1 -0
  77. package/dist/views/HierarchyList/HierarchyTable/SlotTable.css +1 -0
  78. package/dist/views/HierarchyList/index.css +1 -0
  79. package/dist/views/List/ListHeader/index.css +1 -0
  80. package/dist/views/List/ListHeader/index.d.ts +0 -1
  81. package/dist/views/List/ListHeader/index.d.ts.map +1 -1
  82. package/dist/views/List/ListHeader/index.js +2 -6
  83. package/dist/views/List/ListHeader/index.js.map +1 -1
  84. package/dist/views/List/index.client.d.ts.map +1 -1
  85. package/dist/views/List/index.client.js +3 -2
  86. package/dist/views/List/index.client.js.map +1 -1
  87. package/dist/views/List/index.css +2 -0
  88. package/dist/views/Root/index.d.ts.map +1 -1
  89. package/dist/views/Root/index.js +26 -19
  90. package/dist/views/Root/index.js.map +1 -1
  91. package/dist/views/Version/Default/index.css +2 -0
  92. package/dist/views/Version/RenderFieldsToDiff/fields/Date/index.css +8 -0
  93. package/dist/views/Version/RenderFieldsToDiff/fields/Relationship/index.css +1 -0
  94. package/dist/views/Version/RenderFieldsToDiff/fields/Upload/index.css +1 -0
  95. package/dist/views/Version/RenderFieldsToDiff/index.css +2 -0
  96. package/dist/views/Version/Restore/index.d.ts.map +1 -1
  97. package/dist/views/Version/Restore/index.js +9 -6
  98. package/dist/views/Version/Restore/index.js.map +1 -1
  99. package/dist/views/Versions/VersionPillLabel/index.css +1 -0
  100. package/dist/views/Versions/index.css +1 -0
  101. package/dist/widgets/CollectionCards/index.css +4 -0
  102. package/package.json +5 -5
  103. package/dist/elements/ClipboardAction/clipboardUtilities.spec.js +0 -120
  104. package/dist/elements/ClipboardAction/clipboardUtilities.spec.js.map +0 -1
  105. package/dist/elements/ClipboardAction/isClipboardDataValid.spec.js +0 -144
  106. package/dist/elements/ClipboardAction/isClipboardDataValid.spec.js.map +0 -1
  107. package/dist/elements/ClipboardAction/mergeFormStateFromClipboard.spec.js +0 -885
  108. package/dist/elements/ClipboardAction/mergeFormStateFromClipboard.spec.js.map +0 -1
  109. package/dist/elements/ColumnSelection/matchesColumnSearch.spec.js +0 -87
  110. package/dist/elements/ColumnSelection/matchesColumnSearch.spec.js.map +0 -1
  111. package/dist/elements/CommandPalette/buildActions.spec.js +0 -158
  112. package/dist/elements/CommandPalette/buildActions.spec.js.map +0 -1
  113. package/dist/elements/CommandPalette/highlightLabel.spec.js +0 -78
  114. package/dist/elements/CommandPalette/highlightLabel.spec.js.map +0 -1
  115. package/dist/elements/FieldSelect/reduceFieldOptions.spec.js +0 -143
  116. package/dist/elements/FieldSelect/reduceFieldOptions.spec.js.map +0 -1
  117. package/dist/elements/Toasts/fieldErrors.spec.js +0 -46
  118. package/dist/elements/Toasts/fieldErrors.spec.js.map +0 -1
  119. package/dist/elements/WhereBuilder/Condition/Relationship/optionsReducer.spec.js +0 -152
  120. package/dist/elements/WhereBuilder/Condition/Relationship/optionsReducer.spec.js.map +0 -1
  121. package/dist/elements/WhereBuilder/conditionValue.spec.js +0 -65
  122. package/dist/elements/WhereBuilder/conditionValue.spec.js.map +0 -1
  123. package/dist/fields/Upload/Input.spec.js +0 -242
  124. package/dist/fields/Upload/Input.spec.js.map +0 -1
  125. package/dist/forms/fieldSchemasToFormState/fieldSchemasToFormState.spec.d.ts +0 -2
  126. package/dist/forms/fieldSchemasToFormState/fieldSchemasToFormState.spec.d.ts.map +0 -1
  127. package/dist/forms/fieldSchemasToFormState/fieldSchemasToFormState.spec.js +0 -67
  128. package/dist/forms/fieldSchemasToFormState/fieldSchemasToFormState.spec.js.map +0 -1
  129. package/dist/forms/fieldSchemasToFormState/serverFunctions/renderFieldServerFn.spec.js +0 -150
  130. package/dist/forms/fieldSchemasToFormState/serverFunctions/renderFieldServerFn.spec.js.map +0 -1
  131. package/dist/layouts/Root/index.spec.js +0 -20
  132. package/dist/layouts/Root/index.spec.js.map +0 -1
  133. package/dist/providers/Auth/authSessionRequests.spec.js +0 -121
  134. package/dist/providers/Auth/authSessionRequests.spec.js.map +0 -1
  135. package/dist/providers/Auth/sessionActivity.spec.js +0 -44
  136. package/dist/providers/Auth/sessionActivity.spec.js.map +0 -1
  137. package/dist/providers/Auth/tabSessionSync/index.spec.js +0 -463
  138. package/dist/providers/Auth/tabSessionSync/index.spec.js.map +0 -1
  139. package/dist/providers/Auth/useAuthSessionTimers.spec.js +0 -311
  140. package/dist/providers/Auth/useAuthSessionTimers.spec.js.map +0 -1
  141. package/dist/providers/RouteTransition/ProgressBar/index.spec.js +0 -44
  142. package/dist/providers/RouteTransition/ProgressBar/index.spec.js.map +0 -1
  143. package/dist/providers/TableColumns/buildColumnState/index.spec.js +0 -40
  144. package/dist/providers/TableColumns/buildColumnState/index.spec.js.map +0 -1
  145. package/dist/utilities/appendCacheTag.spec.js +0 -34
  146. package/dist/utilities/appendCacheTag.spec.js.map +0 -1
  147. package/dist/utilities/formatAbsoluteURL.spec.js +0 -27
  148. package/dist/utilities/formatAbsoluteURL.spec.js.map +0 -1
  149. package/dist/utilities/formatMetadata.spec.js +0 -83
  150. package/dist/utilities/formatMetadata.spec.js.map +0 -1
  151. package/dist/utilities/fuzzyMatch.spec.js +0 -38
  152. package/dist/utilities/fuzzyMatch.spec.js.map +0 -1
  153. package/dist/utilities/initReq.spec.js +0 -226
  154. package/dist/utilities/initReq.spec.js.map +0 -1
  155. package/dist/utilities/isAbsoluteURL.spec.js +0 -11
  156. package/dist/utilities/isAbsoluteURL.spec.js.map +0 -1
  157. package/dist/utilities/isCustomAdminView.spec.js +0 -90
  158. package/dist/utilities/isCustomAdminView.spec.js.map +0 -1
  159. package/dist/utilities/isHttpURL.spec.js +0 -25
  160. package/dist/utilities/isHttpURL.spec.js.map +0 -1
  161. package/dist/utilities/isPathMatchingRoute.spec.js +0 -178
  162. package/dist/utilities/isPathMatchingRoute.spec.js.map +0 -1
  163. package/dist/utilities/isPublicAdminRoute.spec.js +0 -34
  164. package/dist/utilities/isPublicAdminRoute.spec.js.map +0 -1
  165. package/dist/utilities/normalizeRelationshipValue.spec.js +0 -373
  166. package/dist/utilities/normalizeRelationshipValue.spec.js.map +0 -1
  167. package/dist/utilities/recentlyViewed.spec.js +0 -92
  168. package/dist/utilities/recentlyViewed.spec.js.map +0 -1
  169. package/dist/views/Root/getCustomCollectionViewByRoute.spec.js +0 -168
  170. package/dist/views/Root/getCustomCollectionViewByRoute.spec.js.map +0 -1
  171. package/dist/views/Version/RenderFieldsToDiff/buildVersionFields.spec.js +0 -258
  172. package/dist/views/Version/RenderFieldsToDiff/buildVersionFields.spec.js.map +0 -1
  173. package/dist/views/Version/RenderFieldsToDiff/utilities/countChangedFields.spec.js +0 -915
  174. package/dist/views/Version/RenderFieldsToDiff/utilities/countChangedFields.spec.js.map +0 -1
  175. package/dist/views/Version/RenderFieldsToDiff/utilities/fieldHasChanges.spec.js +0 -47
  176. package/dist/views/Version/RenderFieldsToDiff/utilities/fieldHasChanges.spec.js.map +0 -1
  177. package/dist/views/Version/RenderFieldsToDiff/utilities/getFieldsForRowComparison.spec.js +0 -125
  178. package/dist/views/Version/RenderFieldsToDiff/utilities/getFieldsForRowComparison.spec.js.map +0 -1
  179. package/dist/widgets/CollectionQuery/getCollectionFieldPaths.spec.js +0 -100
  180. package/dist/widgets/CollectionQuery/getCollectionFieldPaths.spec.js.map +0 -1
@@ -1,38 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { fuzzyMatch } from './fuzzyMatch.js';
3
- describe('fuzzyMatch', () => {
4
- it('should match a subsequence case-insensitively', () => {
5
- const result = fuzzyMatch('pst', 'Posts');
6
- expect(result).not.toBeNull();
7
- expect(result?.indices).toEqual([0, 2, 3]);
8
- });
9
- it('should match regardless of query case', () => {
10
- expect(fuzzyMatch('POS', 'Posts')).not.toBeNull();
11
- });
12
- it('should return null when not all query chars are present in order', () => {
13
- expect(fuzzyMatch('xyz', 'Posts')).toBeNull();
14
- expect(fuzzyMatch('sp', 'Posts')).toBeNull(); // wrong order
15
- });
16
- it('should return a zero-score empty match for an empty query', () => {
17
- expect(fuzzyMatch('', 'Posts')).toEqual({
18
- indices: [],
19
- score: 0
20
- });
21
- });
22
- it('should score a leading consecutive match higher than a mid-word match', () => {
23
- const leading = fuzzyMatch('pa', 'Pages');
24
- const midWord = fuzzyMatch('pa', 'Media Packs');
25
- expect(leading.score).toBeGreaterThan(midWord.score);
26
- });
27
- it('should score consecutive matches higher than gapped matches', () => {
28
- const consecutive = fuzzyMatch('po', 'Posts');
29
- const gapped = fuzzyMatch('ps', 'Posts');
30
- expect(consecutive.score).toBeGreaterThan(gapped.score);
31
- });
32
- it('returns a non-null match with a negative score for a very sparse match', () => {
33
- const result = fuzzyMatch('az', 'abcdefghijklmnopqrstuvwxyz');
34
- expect(result).not.toBeNull();
35
- expect(result.score).toBeLessThan(0);
36
- });
37
- });
38
- //# sourceMappingURL=fuzzyMatch.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fuzzyMatch.spec.js","names":["describe","expect","it","fuzzyMatch","result","not","toBeNull","indices","toEqual","score","leading","midWord","toBeGreaterThan","consecutive","gapped","toBeLessThan"],"sources":["../../src/utilities/fuzzyMatch.spec.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport { fuzzyMatch } from './fuzzyMatch.js'\n\ndescribe('fuzzyMatch', () => {\n it('should match a subsequence case-insensitively', () => {\n const result = fuzzyMatch('pst', 'Posts')\n expect(result).not.toBeNull()\n expect(result?.indices).toEqual([0, 2, 3])\n })\n\n it('should match regardless of query case', () => {\n expect(fuzzyMatch('POS', 'Posts')).not.toBeNull()\n })\n\n it('should return null when not all query chars are present in order', () => {\n expect(fuzzyMatch('xyz', 'Posts')).toBeNull()\n expect(fuzzyMatch('sp', 'Posts')).toBeNull() // wrong order\n })\n\n it('should return a zero-score empty match for an empty query', () => {\n expect(fuzzyMatch('', 'Posts')).toEqual({ indices: [], score: 0 })\n })\n\n it('should score a leading consecutive match higher than a mid-word match', () => {\n const leading = fuzzyMatch('pa', 'Pages')\n const midWord = fuzzyMatch('pa', 'Media Packs')\n expect(leading!.score).toBeGreaterThan(midWord!.score)\n })\n\n it('should score consecutive matches higher than gapped matches', () => {\n const consecutive = fuzzyMatch('po', 'Posts')\n const gapped = fuzzyMatch('ps', 'Posts')\n expect(consecutive!.score).toBeGreaterThan(gapped!.score)\n })\n\n it('returns a non-null match with a negative score for a very sparse match', () => {\n const result = fuzzyMatch('az', 'abcdefghijklmnopqrstuvwxyz')\n expect(result).not.toBeNull()\n expect(result!.score).toBeLessThan(0)\n })\n})\n"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ;AAErC,SAASC,UAAU,QAAQ;AAE3BH,QAAA,CAAS,cAAc;EACrBE,EAAA,CAAG,iDAAiD;IAClD,MAAME,MAAA,GAASD,UAAA,CAAW,OAAO;IACjCF,MAAA,CAAOG,MAAA,EAAQC,GAAG,CAACC,QAAQ;IAC3BL,MAAA,CAAOG,MAAA,EAAQG,OAAA,EAASC,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE;EAC3C;EAEAN,EAAA,CAAG,yCAAyC;IAC1CD,MAAA,CAAOE,UAAA,CAAW,OAAO,UAAUE,GAAG,CAACC,QAAQ;EACjD;EAEAJ,EAAA,CAAG,oEAAoE;IACrED,MAAA,CAAOE,UAAA,CAAW,OAAO,UAAUG,QAAQ;IAC3CL,MAAA,CAAOE,UAAA,CAAW,MAAM,UAAUG,QAAQ,IAAG;EAC/C;EAEAJ,EAAA,CAAG,6DAA6D;IAC9DD,MAAA,CAAOE,UAAA,CAAW,IAAI,UAAUK,OAAO,CAAC;MAAED,OAAA,EAAS,EAAE;MAAEE,KAAA,EAAO;IAAE;EAClE;EAEAP,EAAA,CAAG,yEAAyE;IAC1E,MAAMQ,OAAA,GAAUP,UAAA,CAAW,MAAM;IACjC,MAAMQ,OAAA,GAAUR,UAAA,CAAW,MAAM;IACjCF,MAAA,CAAOS,OAAA,CAASD,KAAK,EAAEG,eAAe,CAACD,OAAA,CAASF,KAAK;EACvD;EAEAP,EAAA,CAAG,+DAA+D;IAChE,MAAMW,WAAA,GAAcV,UAAA,CAAW,MAAM;IACrC,MAAMW,MAAA,GAASX,UAAA,CAAW,MAAM;IAChCF,MAAA,CAAOY,WAAA,CAAaJ,KAAK,EAAEG,eAAe,CAACE,MAAA,CAAQL,KAAK;EAC1D;EAEAP,EAAA,CAAG,0EAA0E;IAC3E,MAAME,MAAA,GAASD,UAAA,CAAW,MAAM;IAChCF,MAAA,CAAOG,MAAA,EAAQC,GAAG,CAACC,QAAQ;IAC3BL,MAAA,CAAOG,MAAA,CAAQK,KAAK,EAAEM,YAAY,CAAC;EACrC;AACF","ignoreList":[]}
@@ -1,226 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
2
- const mocks = vi.hoisted(() => ({
3
- accessContexts: [],
4
- accessUser: null,
5
- applyUserReadAccess: vi.fn(),
6
- cacheStores: new Map(),
7
- executeAuthStrategies: vi.fn(),
8
- user: {
9
- collection: 'users',
10
- id: 'user-id',
11
- role: 'admin'
12
- }
13
- }));
14
- vi.mock('@payloadcms/translations', () => ({
15
- initI18n: vi.fn(async () => ({
16
- fallbackLanguage: 'en',
17
- language: 'en',
18
- t: key => key,
19
- translations: {}
20
- }))
21
- }));
22
- vi.mock('payload', () => ({
23
- createLocalReq: vi.fn(async (options, payload) => {
24
- const request = options.req ?? {};
25
- const user = options.user ?? request.user ?? null;
26
- return {
27
- ...request,
28
- context: options.context ?? request.context ?? {},
29
- headers: request.headers ?? new Headers(),
30
- locale: options.locale ?? request.locale ?? 'en',
31
- pathname: options.urlSuffix,
32
- payload,
33
- query: request.query ?? {},
34
- responseHeaders: request.responseHeaders ?? new Headers(),
35
- user: user && !user.collection ? {
36
- ...user,
37
- collection: payload.config.admin.user
38
- } : user
39
- };
40
- }),
41
- executeAuthStrategies: mocks.executeAuthStrategies,
42
- getAccessResults: vi.fn(async ({
43
- req
44
- }) => {
45
- mocks.accessContexts.push(req.context.name);
46
- mocks.accessUser = req.user;
47
- return {};
48
- }),
49
- getPayload: vi.fn(async () => ({
50
- collections: {
51
- users: {
52
- config: {
53
- auth: {
54
- depth: 1
55
- },
56
- slug: 'users'
57
- }
58
- }
59
- },
60
- config: {
61
- admin: {
62
- user: 'users'
63
- },
64
- i18n: {
65
- fallbackLanguage: 'en',
66
- supportedLanguages: {
67
- en: {}
68
- },
69
- translations: {}
70
- }
71
- },
72
- logger: {
73
- error: vi.fn()
74
- }
75
- })),
76
- getRequestLanguage: vi.fn(() => 'en'),
77
- parseCookies: vi.fn(() => new Map())
78
- }));
79
- vi.mock('payload/internal', () => ({
80
- applyUserReadAccess: mocks.applyUserReadAccess
81
- }));
82
- vi.mock('./getRequestLocale.js', () => ({
83
- getRequestLocale: vi.fn(async ({
84
- req
85
- }) => ({
86
- code: req.locale
87
- }))
88
- }));
89
- vi.mock('./selectiveCache.js', () => ({
90
- selectiveCache: namespace => ({
91
- get: async (factory, ...args) => {
92
- let entries = mocks.cacheStores.get(namespace);
93
- if (!entries) {
94
- entries = [];
95
- mocks.cacheStores.set(namespace, entries);
96
- }
97
- const cached = entries.find(entry => entry.args.length === args.length && entry.args.every((arg, i) => arg === args[i]));
98
- if (cached) {
99
- return cached.value;
100
- }
101
- const value = await factory();
102
- entries.push({
103
- args,
104
- value
105
- });
106
- return value;
107
- }
108
- })
109
- }));
110
- import { initReq } from './initReq.js';
111
- describe('initReq', () => {
112
- beforeEach(() => {
113
- mocks.accessContexts = [];
114
- mocks.accessUser = null;
115
- mocks.applyUserReadAccess.mockReset();
116
- mocks.applyUserReadAccess.mockImplementation(async ({
117
- req,
118
- user
119
- }) => ({
120
- collection: user.collection,
121
- id: user.id,
122
- name: req.context.name
123
- }));
124
- mocks.cacheStores.clear();
125
- mocks.executeAuthStrategies.mockReset();
126
- mocks.executeAuthStrategies.mockResolvedValue({
127
- user: mocks.user
128
- });
129
- });
130
- it('should keep the complete req.user and filter the user for each response', async () => {
131
- const first = await initReq({
132
- configPromise: {},
133
- importMap: {},
134
- key: 'response',
135
- overrides: {
136
- context: {
137
- name: 'First'
138
- }
139
- },
140
- serverAdapter: {
141
- getHeaders: async () => new Headers()
142
- }
143
- });
144
- const second = await initReq({
145
- configPromise: {},
146
- importMap: {},
147
- key: 'response',
148
- overrides: {
149
- context: {
150
- name: 'Second'
151
- }
152
- },
153
- serverAdapter: {
154
- getHeaders: async () => new Headers()
155
- }
156
- });
157
- expect(mocks.executeAuthStrategies).toHaveBeenCalledOnce();
158
- expect(mocks.applyUserReadAccess).toHaveBeenCalledTimes(2);
159
- expect(first.req.user).toHaveProperty('role', 'admin');
160
- expect(second.req.user).toHaveProperty('role', 'admin');
161
- expect(first.user).toMatchObject({
162
- name: 'First'
163
- });
164
- expect(second.user).toMatchObject({
165
- name: 'Second'
166
- });
167
- expect(first.user).not.toHaveProperty('role');
168
- expect(mocks.accessUser).toHaveProperty('role', 'admin');
169
- expect(mocks.accessContexts).toEqual(['First', 'Second']);
170
- });
171
- it('should use anonymous access when user read access fails', async () => {
172
- mocks.applyUserReadAccess.mockRejectedValue(new Error('read access failed'));
173
- const result = await initReq({
174
- configPromise: {},
175
- importMap: {},
176
- key: 'failure',
177
- serverAdapter: {
178
- getHeaders: async () => new Headers()
179
- }
180
- });
181
- expect(result.req.user).toBeNull();
182
- expect(result.user).toBeNull();
183
- expect(mocks.accessUser).toBeNull();
184
- });
185
- it('should preserve an explicit req.user override', async () => {
186
- const user = {
187
- id: 'override-user'
188
- };
189
- const result = await initReq({
190
- configPromise: {},
191
- importMap: {},
192
- key: 'override',
193
- overrides: {
194
- req: {
195
- user
196
- }
197
- },
198
- serverAdapter: {
199
- getHeaders: async () => new Headers()
200
- }
201
- });
202
- expect(result.req.user).toMatchObject({
203
- collection: 'users',
204
- id: 'override-user'
205
- });
206
- expect(result.user).toBe(result.req.user);
207
- expect(mocks.applyUserReadAccess).not.toHaveBeenCalled();
208
- });
209
- it('should preserve an explicit null user override', async () => {
210
- const result = await initReq({
211
- configPromise: {},
212
- importMap: {},
213
- key: 'anonymous',
214
- overrides: {
215
- user: null
216
- },
217
- serverAdapter: {
218
- getHeaders: async () => new Headers()
219
- }
220
- });
221
- expect(result.req.user).toBeNull();
222
- expect(result.user).toBeNull();
223
- expect(mocks.applyUserReadAccess).not.toHaveBeenCalled();
224
- });
225
- });
226
- //# sourceMappingURL=initReq.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"initReq.spec.js","names":["beforeEach","describe","expect","it","vi","mocks","hoisted","accessContexts","accessUser","applyUserReadAccess","fn","cacheStores","Map","executeAuthStrategies","user","collection","id","role","mock","initI18n","fallbackLanguage","language","t","key","translations","createLocalReq","options","payload","request","req","context","headers","Headers","locale","pathname","urlSuffix","query","responseHeaders","config","admin","getAccessResults","push","name","getPayload","collections","users","auth","depth","slug","i18n","supportedLanguages","en","logger","error","getRequestLanguage","parseCookies","getRequestLocale","code","selectiveCache","namespace","get","factory","args","entries","set","cached","find","entry","length","every","arg","i","value","initReq","mockReset","mockImplementation","clear","mockResolvedValue","first","configPromise","importMap","overrides","serverAdapter","getHeaders","second","toHaveBeenCalledOnce","toHaveBeenCalledTimes","toHaveProperty","toMatchObject","not","toEqual","mockRejectedValue","Error","result","toBeNull","toBe","toHaveBeenCalled"],"sources":["../../src/utilities/initReq.spec.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest'\n\nconst mocks = vi.hoisted(() => ({\n accessContexts: [] as unknown[],\n accessUser: null as PayloadRequest['user'],\n applyUserReadAccess: vi.fn(),\n cacheStores: new Map<string, Array<{ args: unknown[]; value: object }>>(),\n executeAuthStrategies: vi.fn(),\n user: {\n collection: 'users',\n id: 'user-id',\n role: 'admin',\n } as PayloadRequest['user'],\n}))\n\nvi.mock('@payloadcms/translations', () => ({\n initI18n: vi.fn(async () => ({\n fallbackLanguage: 'en',\n language: 'en',\n t: (key: string) => key,\n translations: {},\n })),\n}))\n\nvi.mock('payload', () => ({\n createLocalReq: vi.fn(async (options, payload) => {\n const request = options.req ?? {}\n const user = options.user ?? request.user ?? null\n\n return {\n ...request,\n context: options.context ?? request.context ?? {},\n headers: request.headers ?? new Headers(),\n locale: options.locale ?? request.locale ?? 'en',\n pathname: options.urlSuffix,\n payload,\n query: request.query ?? {},\n responseHeaders: request.responseHeaders ?? new Headers(),\n user: user && !user.collection ? { ...user, collection: payload.config.admin.user } : user,\n }\n }),\n executeAuthStrategies: mocks.executeAuthStrategies,\n getAccessResults: vi.fn(async ({ req }: { req: PayloadRequest }) => {\n mocks.accessContexts.push(req.context.name)\n mocks.accessUser = req.user\n return {}\n }),\n getPayload: vi.fn(async () => ({\n collections: {\n users: {\n config: {\n auth: { depth: 1 },\n slug: 'users',\n },\n },\n },\n config: {\n admin: { user: 'users' },\n i18n: {\n fallbackLanguage: 'en',\n supportedLanguages: { en: {} },\n translations: {},\n },\n },\n logger: { error: vi.fn() },\n })),\n getRequestLanguage: vi.fn(() => 'en'),\n parseCookies: vi.fn(() => new Map()),\n}))\n\nvi.mock('payload/internal', () => ({\n applyUserReadAccess: mocks.applyUserReadAccess,\n}))\n\nvi.mock('./getRequestLocale.js', () => ({\n getRequestLocale: vi.fn(async ({ req }: { req: PayloadRequest }) => ({\n code: req.locale,\n })),\n}))\n\nvi.mock('./selectiveCache.js', () => ({\n selectiveCache: (namespace: string) => ({\n get: async (factory: () => Promise<object>, ...args: unknown[]) => {\n let entries = mocks.cacheStores.get(namespace)\n\n if (!entries) {\n entries = []\n mocks.cacheStores.set(namespace, entries)\n }\n\n const cached = entries.find(\n (entry) =>\n entry.args.length === args.length && entry.args.every((arg, i) => arg === args[i]),\n )\n\n if (cached) {\n return cached.value\n }\n\n const value = await factory()\n entries.push({ args, value })\n\n return value\n },\n }),\n}))\n\nimport { initReq } from './initReq.js'\n\ndescribe('initReq', () => {\n beforeEach(() => {\n mocks.accessContexts = []\n mocks.accessUser = null\n mocks.applyUserReadAccess.mockReset()\n mocks.applyUserReadAccess.mockImplementation(async ({ req, user }) => ({\n collection: user.collection,\n id: user.id,\n name: req.context.name,\n }))\n mocks.cacheStores.clear()\n mocks.executeAuthStrategies.mockReset()\n mocks.executeAuthStrategies.mockResolvedValue({ user: mocks.user })\n })\n\n it('should keep the complete req.user and filter the user for each response', async () => {\n const first = await initReq({\n configPromise: {} as never,\n importMap: {},\n key: 'response',\n overrides: { context: { name: 'First' } },\n serverAdapter: { getHeaders: async () => new Headers() } as never,\n })\n const second = await initReq({\n configPromise: {} as never,\n importMap: {},\n key: 'response',\n overrides: { context: { name: 'Second' } },\n serverAdapter: { getHeaders: async () => new Headers() } as never,\n })\n\n expect(mocks.executeAuthStrategies).toHaveBeenCalledOnce()\n expect(mocks.applyUserReadAccess).toHaveBeenCalledTimes(2)\n expect(first.req.user).toHaveProperty('role', 'admin')\n expect(second.req.user).toHaveProperty('role', 'admin')\n expect(first.user).toMatchObject({ name: 'First' })\n expect(second.user).toMatchObject({ name: 'Second' })\n expect(first.user).not.toHaveProperty('role')\n expect(mocks.accessUser).toHaveProperty('role', 'admin')\n expect(mocks.accessContexts).toEqual(['First', 'Second'])\n })\n\n it('should use anonymous access when user read access fails', async () => {\n mocks.applyUserReadAccess.mockRejectedValue(new Error('read access failed'))\n\n const result = await initReq({\n configPromise: {} as never,\n importMap: {},\n key: 'failure',\n serverAdapter: { getHeaders: async () => new Headers() } as never,\n })\n\n expect(result.req.user).toBeNull()\n expect(result.user).toBeNull()\n expect(mocks.accessUser).toBeNull()\n })\n\n it('should preserve an explicit req.user override', async () => {\n const user = { id: 'override-user' }\n\n const result = await initReq({\n configPromise: {} as never,\n importMap: {},\n key: 'override',\n overrides: { req: { user } as never },\n serverAdapter: { getHeaders: async () => new Headers() } as never,\n })\n\n expect(result.req.user).toMatchObject({ collection: 'users', id: 'override-user' })\n expect(result.user).toBe(result.req.user)\n expect(mocks.applyUserReadAccess).not.toHaveBeenCalled()\n })\n\n it('should preserve an explicit null user override', async () => {\n const result = await initReq({\n configPromise: {} as never,\n importMap: {},\n key: 'anonymous',\n overrides: { user: null } as never,\n serverAdapter: { getHeaders: async () => new Headers() } as never,\n })\n\n expect(result.req.user).toBeNull()\n expect(result.user).toBeNull()\n expect(mocks.applyUserReadAccess).not.toHaveBeenCalled()\n })\n})\n"],"mappings":"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","ignoreList":[]}
@@ -1,11 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { isAbsoluteURL } from './isAbsoluteURL.js';
3
- describe('isAbsoluteURL', () => {
4
- it.each(['http://example.com', 'https://example.com/preview', 'mailto:editor@example.com', 'file:///preview.html', new URL('https://example.com/preview')])('should accept absolute URL %s', input => {
5
- expect(isAbsoluteURL(input)).toBe(true);
6
- });
7
- it.each([undefined, '', '/preview', '../preview', 'preview?draft=true', '?draft=true', '#preview', '//example.com/preview', 'https://', 'https://[invalid'])('should reject relative, absent, or invalid URL %s', input => {
8
- expect(isAbsoluteURL(input)).toBe(false);
9
- });
10
- });
11
- //# sourceMappingURL=isAbsoluteURL.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isAbsoluteURL.spec.js","names":["describe","expect","it","isAbsoluteURL","each","URL","input","toBe","undefined"],"sources":["../../src/utilities/isAbsoluteURL.spec.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport { isAbsoluteURL } from './isAbsoluteURL.js'\n\ndescribe('isAbsoluteURL', () => {\n it.each([\n 'http://example.com',\n 'https://example.com/preview',\n 'mailto:editor@example.com',\n 'file:///preview.html',\n new URL('https://example.com/preview'),\n ])('should accept absolute URL %s', (input) => {\n expect(isAbsoluteURL(input)).toBe(true)\n })\n\n it.each([\n undefined,\n '',\n '/preview',\n '../preview',\n 'preview?draft=true',\n '?draft=true',\n '#preview',\n '//example.com/preview',\n 'https://',\n 'https://[invalid',\n ])('should reject relative, absent, or invalid URL %s', (input) => {\n expect(isAbsoluteURL(input)).toBe(false)\n })\n})\n"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ;AAErC,SAASC,aAAa,QAAQ;AAE9BH,QAAA,CAAS,iBAAiB;EACxBE,EAAA,CAAGE,IAAI,CAAC,CACN,sBACA,+BACA,6BACA,wBACA,IAAIC,GAAA,CAAI,+BACT,EAAE,iCAAkCC,KAAA;IACnCL,MAAA,CAAOE,aAAA,CAAcG,KAAA,GAAQC,IAAI,CAAC;EACpC;EAEAL,EAAA,CAAGE,IAAI,CAAC,CACNI,SAAA,EACA,IACA,YACA,cACA,sBACA,eACA,YACA,yBACA,YACA,mBACD,EAAE,qDAAsDF,KAAA;IACvDL,MAAA,CAAOE,aAAA,CAAcG,KAAA,GAAQC,IAAI,CAAC;EACpC;AACF","ignoreList":[]}
@@ -1,90 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { isCustomAdminView } from './isCustomAdminView.js';
3
- describe('isCustomAdminView', () => {
4
- const adminRoute = '/admin';
5
- const configWithCustomDashboard = {
6
- admin: {
7
- components: {
8
- views: {
9
- dashboard: {
10
- path: '/'
11
- }
12
- }
13
- }
14
- }
15
- };
16
- it('should not bypass admin access for the root admin route even with a custom dashboard view', () => {
17
- // The root path '/' maps to the dashboard — it is not a public custom view.
18
- // canAccessAdmin must still be enforced for the admin root.
19
- const result = isCustomAdminView({
20
- adminRoute,
21
- config: configWithCustomDashboard,
22
- route: '/admin'
23
- });
24
- expect(result).toBe(false);
25
- });
26
- it('should not match collection routes as custom dashboard views when dashboard path is "/"', () => {
27
- const result = isCustomAdminView({
28
- adminRoute,
29
- config: configWithCustomDashboard,
30
- route: '/admin/collections/tickets'
31
- });
32
- expect(result).toBe(false);
33
- });
34
- it('should not match document routes as custom dashboard views when dashboard path is "/"', () => {
35
- const result = isCustomAdminView({
36
- adminRoute,
37
- config: configWithCustomDashboard,
38
- route: '/admin/collections/tickets/123'
39
- });
40
- expect(result).toBe(false);
41
- });
42
- it('should return false when no custom views are configured', () => {
43
- const config = {};
44
- const result = isCustomAdminView({
45
- adminRoute,
46
- config,
47
- route: '/admin/collections/tickets'
48
- });
49
- expect(result).toBe(false);
50
- });
51
- it('should return true for a custom view with a non-root path', () => {
52
- const config = {
53
- admin: {
54
- components: {
55
- views: {
56
- myCustomView: {
57
- path: '/my-custom-view'
58
- }
59
- }
60
- }
61
- }
62
- };
63
- const result = isCustomAdminView({
64
- adminRoute,
65
- config,
66
- route: '/admin/my-custom-view'
67
- });
68
- expect(result).toBe(true);
69
- });
70
- it('should not match collection routes when a non-root custom view path is set', () => {
71
- const config = {
72
- admin: {
73
- components: {
74
- views: {
75
- myCustomView: {
76
- path: '/my-custom-view'
77
- }
78
- }
79
- }
80
- }
81
- };
82
- const result = isCustomAdminView({
83
- adminRoute,
84
- config,
85
- route: '/admin/collections/tickets'
86
- });
87
- expect(result).toBe(false);
88
- });
89
- });
90
- //# sourceMappingURL=isCustomAdminView.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isCustomAdminView.spec.js","names":["describe","expect","it","isCustomAdminView","adminRoute","configWithCustomDashboard","admin","components","views","dashboard","path","result","config","route","toBe","myCustomView"],"sources":["../../src/utilities/isCustomAdminView.spec.ts"],"sourcesContent":["import type { SanitizedConfig } from 'payload'\n\nimport { describe, expect, it } from 'vitest'\n\nimport { isCustomAdminView } from './isCustomAdminView.js'\n\ndescribe('isCustomAdminView', () => {\n const adminRoute = '/admin'\n\n const configWithCustomDashboard = {\n admin: {\n components: {\n views: {\n dashboard: {\n path: '/',\n },\n },\n },\n },\n } as unknown as SanitizedConfig\n\n it('should not bypass admin access for the root admin route even with a custom dashboard view', () => {\n // The root path '/' maps to the dashboard — it is not a public custom view.\n // canAccessAdmin must still be enforced for the admin root.\n const result = isCustomAdminView({\n adminRoute,\n config: configWithCustomDashboard,\n route: '/admin',\n })\n\n expect(result).toBe(false)\n })\n\n it('should not match collection routes as custom dashboard views when dashboard path is \"/\"', () => {\n const result = isCustomAdminView({\n adminRoute,\n config: configWithCustomDashboard,\n route: '/admin/collections/tickets',\n })\n\n expect(result).toBe(false)\n })\n\n it('should not match document routes as custom dashboard views when dashboard path is \"/\"', () => {\n const result = isCustomAdminView({\n adminRoute,\n config: configWithCustomDashboard,\n route: '/admin/collections/tickets/123',\n })\n\n expect(result).toBe(false)\n })\n\n it('should return false when no custom views are configured', () => {\n const config = {} as SanitizedConfig\n\n const result = isCustomAdminView({\n adminRoute,\n config,\n route: '/admin/collections/tickets',\n })\n\n expect(result).toBe(false)\n })\n\n it('should return true for a custom view with a non-root path', () => {\n const config = {\n admin: {\n components: {\n views: {\n myCustomView: {\n path: '/my-custom-view',\n },\n },\n },\n },\n } as unknown as SanitizedConfig\n\n const result = isCustomAdminView({\n adminRoute,\n config,\n route: '/admin/my-custom-view',\n })\n\n expect(result).toBe(true)\n })\n\n it('should not match collection routes when a non-root custom view path is set', () => {\n const config = {\n admin: {\n components: {\n views: {\n myCustomView: {\n path: '/my-custom-view',\n },\n },\n },\n },\n } as unknown as SanitizedConfig\n\n const result = isCustomAdminView({\n adminRoute,\n config,\n route: '/admin/collections/tickets',\n })\n\n expect(result).toBe(false)\n })\n})\n"],"mappings":"AAEA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ;AAErC,SAASC,iBAAiB,QAAQ;AAElCH,QAAA,CAAS,qBAAqB;EAC5B,MAAMI,UAAA,GAAa;EAEnB,MAAMC,yBAAA,GAA4B;IAChCC,KAAA,EAAO;MACLC,UAAA,EAAY;QACVC,KAAA,EAAO;UACLC,SAAA,EAAW;YACTC,IAAA,EAAM;UACR;QACF;MACF;IACF;EACF;EAEAR,EAAA,CAAG,6FAA6F;IAC9F;IACA;IACA,MAAMS,MAAA,GAASR,iBAAA,CAAkB;MAC/BC,UAAA;MACAQ,MAAA,EAAQP,yBAAA;MACRQ,KAAA,EAAO;IACT;IAEAZ,MAAA,CAAOU,MAAA,EAAQG,IAAI,CAAC;EACtB;EAEAZ,EAAA,CAAG,2FAA2F;IAC5F,MAAMS,MAAA,GAASR,iBAAA,CAAkB;MAC/BC,UAAA;MACAQ,MAAA,EAAQP,yBAAA;MACRQ,KAAA,EAAO;IACT;IAEAZ,MAAA,CAAOU,MAAA,EAAQG,IAAI,CAAC;EACtB;EAEAZ,EAAA,CAAG,yFAAyF;IAC1F,MAAMS,MAAA,GAASR,iBAAA,CAAkB;MAC/BC,UAAA;MACAQ,MAAA,EAAQP,yBAAA;MACRQ,KAAA,EAAO;IACT;IAEAZ,MAAA,CAAOU,MAAA,EAAQG,IAAI,CAAC;EACtB;EAEAZ,EAAA,CAAG,2DAA2D;IAC5D,MAAMU,MAAA,GAAS,CAAC;IAEhB,MAAMD,MAAA,GAASR,iBAAA,CAAkB;MAC/BC,UAAA;MACAQ,MAAA;MACAC,KAAA,EAAO;IACT;IAEAZ,MAAA,CAAOU,MAAA,EAAQG,IAAI,CAAC;EACtB;EAEAZ,EAAA,CAAG,6DAA6D;IAC9D,MAAMU,MAAA,GAAS;MACbN,KAAA,EAAO;QACLC,UAAA,EAAY;UACVC,KAAA,EAAO;YACLO,YAAA,EAAc;cACZL,IAAA,EAAM;YACR;UACF;QACF;MACF;IACF;IAEA,MAAMC,MAAA,GAASR,iBAAA,CAAkB;MAC/BC,UAAA;MACAQ,MAAA;MACAC,KAAA,EAAO;IACT;IAEAZ,MAAA,CAAOU,MAAA,EAAQG,IAAI,CAAC;EACtB;EAEAZ,EAAA,CAAG,8EAA8E;IAC/E,MAAMU,MAAA,GAAS;MACbN,KAAA,EAAO;QACLC,UAAA,EAAY;UACVC,KAAA,EAAO;YACLO,YAAA,EAAc;cACZL,IAAA,EAAM;YACR;UACF;QACF;MACF;IACF;IAEA,MAAMC,MAAA,GAASR,iBAAA,CAAkB;MAC/BC,UAAA;MACAQ,MAAA;MACAC,KAAA,EAAO;IACT;IAEAZ,MAAA,CAAOU,MAAA,EAAQG,IAAI,CAAC;EACtB;AACF","ignoreList":[]}
@@ -1,25 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { isHttpURL } from './isHttpURL.js';
3
- describe('isHttpURL', () => {
4
- beforeEach(() => {
5
- vi.stubGlobal('window', {
6
- location: {
7
- origin: 'https://admin.example.com'
8
- }
9
- });
10
- });
11
- afterEach(() => {
12
- vi.unstubAllGlobals();
13
- });
14
- it.each([['https://preview.example.com', true], ['mailto:editor@example.com', false]])('should validate parsed URL %s without the client environment', (input, expected) => {
15
- vi.stubGlobal('window', undefined);
16
- expect(isHttpURL(new URL(input))).toBe(expected);
17
- });
18
- it.each(['http://preview.example.com', 'https://preview.example.com', '/preview', 'preview?draft=true', '../preview', '?draft=true', '#preview', '//preview.example.com/page'])('should accept HTTP(S) or relative URL %s', input => {
19
- expect(isHttpURL(input)).toBe(true);
20
- });
21
- it.each([undefined, '', 'mailto:editor@example.com', 'file:///preview.html', 'https://[invalid', 'http://'])('should reject absent, unsupported, or invalid URL %s', input => {
22
- expect(isHttpURL(input)).toBe(false);
23
- });
24
- });
25
- //# sourceMappingURL=isHttpURL.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isHttpURL.spec.js","names":["afterEach","beforeEach","describe","expect","it","vi","isHttpURL","stubGlobal","location","origin","unstubAllGlobals","each","input","expected","undefined","URL","toBe"],"sources":["../../src/utilities/isHttpURL.spec.ts"],"sourcesContent":["import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'\n\nimport { isHttpURL } from './isHttpURL.js'\n\ndescribe('isHttpURL', () => {\n beforeEach(() => {\n vi.stubGlobal('window', {\n location: { origin: 'https://admin.example.com' },\n })\n })\n\n afterEach(() => {\n vi.unstubAllGlobals()\n })\n\n it.each([\n ['https://preview.example.com', true],\n ['mailto:editor@example.com', false],\n ] as const)('should validate parsed URL %s without the client environment', (input, expected) => {\n vi.stubGlobal('window', undefined)\n\n expect(isHttpURL(new URL(input))).toBe(expected)\n })\n\n it.each([\n 'http://preview.example.com',\n 'https://preview.example.com',\n '/preview',\n 'preview?draft=true',\n '../preview',\n '?draft=true',\n '#preview',\n '//preview.example.com/page',\n ])('should accept HTTP(S) or relative URL %s', (input) => {\n expect(isHttpURL(input)).toBe(true)\n })\n\n it.each([\n undefined,\n '',\n 'mailto:editor@example.com',\n 'file:///preview.html',\n 'https://[invalid',\n 'http://',\n ])('should reject absent, unsupported, or invalid URL %s', (input) => {\n expect(isHttpURL(input)).toBe(false)\n })\n})\n"],"mappings":"AAAA,SAASA,SAAS,EAAEC,UAAU,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ;AAEhE,SAASC,SAAS,QAAQ;AAE1BJ,QAAA,CAAS,aAAa;EACpBD,UAAA,CAAW;IACTI,EAAA,CAAGE,UAAU,CAAC,UAAU;MACtBC,QAAA,EAAU;QAAEC,MAAA,EAAQ;MAA4B;IAClD;EACF;EAEAT,SAAA,CAAU;IACRK,EAAA,CAAGK,gBAAgB;EACrB;EAEAN,EAAA,CAAGO,IAAI,CAAC,CACN,CAAC,+BAA+B,KAAK,EACrC,CAAC,6BAA6B,MAAM,CACrC,EAAW,gEAAgE,CAACC,KAAA,EAAOC,QAAA;IAClFR,EAAA,CAAGE,UAAU,CAAC,UAAUO,SAAA;IAExBX,MAAA,CAAOG,SAAA,CAAU,IAAIS,GAAA,CAAIH,KAAA,IAASI,IAAI,CAACH,QAAA;EACzC;EAEAT,EAAA,CAAGO,IAAI,CAAC,CACN,8BACA,+BACA,YACA,sBACA,cACA,eACA,YACA,6BACD,EAAE,4CAA6CC,KAAA;IAC9CT,MAAA,CAAOG,SAAA,CAAUM,KAAA,GAAQI,IAAI,CAAC;EAChC;EAEAZ,EAAA,CAAGO,IAAI,CAAC,CACNG,SAAA,EACA,IACA,6BACA,wBACA,oBACA,UACD,EAAE,wDAAyDF,KAAA;IAC1DT,MAAA,CAAOG,SAAA,CAAUM,KAAA,GAAQI,IAAI,CAAC;EAChC;AACF","ignoreList":[]}
@@ -1,178 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { isPathMatchingRoute } from './isPathMatchingRoute.js';
3
- describe('isPathMatchingRoute', () => {
4
- describe('no path defined', () => {
5
- it('should return false when path is undefined', () => {
6
- expect(isPathMatchingRoute({
7
- currentRoute: '/anything',
8
- path: undefined
9
- })).toBe(false);
10
- });
11
- it('should return false when path is empty string', () => {
12
- expect(isPathMatchingRoute({
13
- currentRoute: '/anything',
14
- path: ''
15
- })).toBe(false);
16
- });
17
- });
18
- describe('exact matching', () => {
19
- it('should match when currentRoute exactly equals the static path', () => {
20
- expect(isPathMatchingRoute({
21
- currentRoute: '/dashboard',
22
- exact: true,
23
- path: '/dashboard'
24
- })).toBe(true);
25
- });
26
- it('should not match when currentRoute differs from the path', () => {
27
- expect(isPathMatchingRoute({
28
- currentRoute: '/settings',
29
- exact: true,
30
- path: '/dashboard'
31
- })).toBe(false);
32
- });
33
- it('should not match a sub-path when exact is true', () => {
34
- expect(isPathMatchingRoute({
35
- currentRoute: '/dashboard/settings',
36
- exact: true,
37
- path: '/dashboard'
38
- })).toBe(false);
39
- });
40
- it('should match a parameterized path exactly', () => {
41
- expect(isPathMatchingRoute({
42
- currentRoute: '/custom/123',
43
- exact: true,
44
- path: '/custom/:id'
45
- })).toBe(true);
46
- });
47
- it('should not match a parameterized path with extra segments', () => {
48
- expect(isPathMatchingRoute({
49
- currentRoute: '/custom/123/edit',
50
- exact: true,
51
- path: '/custom/:id'
52
- })).toBe(false);
53
- });
54
- it('should match root path exactly', () => {
55
- expect(isPathMatchingRoute({
56
- currentRoute: '/',
57
- exact: true,
58
- path: '/'
59
- })).toBe(true);
60
- });
61
- it('should not match root path against other routes when exact', () => {
62
- expect(isPathMatchingRoute({
63
- currentRoute: '/login',
64
- exact: true,
65
- path: '/'
66
- })).toBe(false);
67
- });
68
- });
69
- describe('non-exact (prefix) matching', () => {
70
- it('should match when currentRoute equals the path', () => {
71
- expect(isPathMatchingRoute({
72
- currentRoute: '/dashboard',
73
- path: '/dashboard'
74
- })).toBe(true);
75
- });
76
- it('should match a sub-path at a segment boundary', () => {
77
- expect(isPathMatchingRoute({
78
- currentRoute: '/dashboard/settings',
79
- path: '/dashboard'
80
- })).toBe(true);
81
- });
82
- it('should match deeply nested sub-paths', () => {
83
- expect(isPathMatchingRoute({
84
- currentRoute: '/dashboard/settings/advanced/debug',
85
- path: '/dashboard'
86
- })).toBe(true);
87
- });
88
- it('should not match when route shares a prefix but not at a segment boundary', () => {
89
- expect(isPathMatchingRoute({
90
- currentRoute: '/dashboard-extra',
91
- path: '/dashboard'
92
- })).toBe(false);
93
- });
94
- it('should not match a completely different route', () => {
95
- expect(isPathMatchingRoute({
96
- currentRoute: '/settings',
97
- path: '/dashboard'
98
- })).toBe(false);
99
- });
100
- it('should match a parameterized path with a sub-path', () => {
101
- expect(isPathMatchingRoute({
102
- currentRoute: '/custom/123/edit',
103
- path: '/custom/:id'
104
- })).toBe(false);
105
- // pathToRegexp is end-anchored by default, so /custom/:id does not match /custom/123/edit.
106
- // The literal fallback '/custom/:id' also won't startsWith-match.
107
- // Parameterized views should use exact: true or include all segments in the pattern.
108
- });
109
- it('should match when :id captures the full segment including non-slash characters', () => {
110
- expect(isPathMatchingRoute({
111
- currentRoute: '/custom/123extra',
112
- path: '/custom/:id'
113
- })).toBe(true);
114
- // :id captures everything up to the next / — '123extra' is a valid :id value
115
- });
116
- });
117
- describe('root path / without exact — regression for route shadowing bug', () => {
118
- it('should match root path against itself', () => {
119
- expect(isPathMatchingRoute({
120
- currentRoute: '/',
121
- path: '/'
122
- })).toBe(true);
123
- });
124
- it('should not match root path against /login', () => {
125
- expect(isPathMatchingRoute({
126
- currentRoute: '/login',
127
- path: '/'
128
- })).toBe(false);
129
- });
130
- it('should not match root path against /collections/posts', () => {
131
- expect(isPathMatchingRoute({
132
- currentRoute: '/collections/posts',
133
- path: '/'
134
- })).toBe(false);
135
- });
136
- it('should not match root path against /collections/posts/123', () => {
137
- expect(isPathMatchingRoute({
138
- currentRoute: '/collections/posts/123',
139
- path: '/'
140
- })).toBe(false);
141
- });
142
- });
143
- describe('sensitive option', () => {
144
- it('should match case-insensitively by default', () => {
145
- expect(isPathMatchingRoute({
146
- currentRoute: '/Dashboard',
147
- exact: true,
148
- path: '/dashboard'
149
- })).toBe(true);
150
- });
151
- it('should not match different cases when sensitive is true', () => {
152
- expect(isPathMatchingRoute({
153
- currentRoute: '/Dashboard',
154
- exact: true,
155
- path: '/dashboard',
156
- sensitive: true
157
- })).toBe(false);
158
- });
159
- });
160
- describe('strict option', () => {
161
- it('should match with or without trailing slash by default', () => {
162
- expect(isPathMatchingRoute({
163
- currentRoute: '/dashboard/',
164
- exact: true,
165
- path: '/dashboard'
166
- })).toBe(true);
167
- });
168
- it('should not match trailing slash mismatch when strict is true', () => {
169
- expect(isPathMatchingRoute({
170
- currentRoute: '/dashboard/',
171
- exact: true,
172
- path: '/dashboard',
173
- strict: true
174
- })).toBe(false);
175
- });
176
- });
177
- });
178
- //# sourceMappingURL=isPathMatchingRoute.spec.js.map