@vertesia/common 1.5.0-dev.20260714.072725Z → 1.5.0-dev.20260722.120446Z
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/lib/apikey.d.ts +1 -0
- package/lib/apikey.d.ts.map +1 -1
- package/lib/apikey.js.map +1 -1
- package/lib/apps.d.ts +500 -34
- package/lib/apps.d.ts.map +1 -1
- package/lib/apps.js +63 -70
- package/lib/apps.js.map +1 -1
- package/lib/audit-trail.d.ts +61 -1
- package/lib/audit-trail.d.ts.map +1 -1
- package/lib/audit-trail.js +15 -0
- package/lib/audit-trail.js.map +1 -1
- package/lib/data-platform.d.ts +121 -5
- package/lib/data-platform.d.ts.map +1 -1
- package/lib/index.d.ts +7 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +7 -0
- package/lib/index.js.map +1 -1
- package/lib/interaction.d.ts +19 -1
- package/lib/interaction.d.ts.map +1 -1
- package/lib/interaction.js.map +1 -1
- package/lib/json-schema.d.ts +1 -1
- package/lib/json-schema.d.ts.map +1 -1
- package/lib/platform-event.d.ts +79 -3
- package/lib/platform-event.d.ts.map +1 -1
- package/lib/platform-event.js.map +1 -1
- package/lib/project.d.ts +119 -20
- package/lib/project.d.ts.map +1 -1
- package/lib/project.js +65 -0
- package/lib/project.js.map +1 -1
- package/lib/query.d.ts +6 -0
- package/lib/query.d.ts.map +1 -1
- package/lib/refs.d.ts +1 -0
- package/lib/refs.d.ts.map +1 -1
- package/lib/schema-for-extraction.d.ts +21 -0
- package/lib/schema-for-extraction.d.ts.map +1 -0
- package/lib/schema-for-extraction.js +205 -0
- package/lib/schema-for-extraction.js.map +1 -0
- package/lib/store/agent-run.d.ts +2 -0
- package/lib/store/agent-run.d.ts.map +1 -1
- package/lib/store/conversation-state.d.ts +39 -0
- package/lib/store/conversation-state.d.ts.map +1 -1
- package/lib/store/conversation-state.js +3 -0
- package/lib/store/conversation-state.js.map +1 -1
- package/lib/store/doc-analyzer.d.ts +10 -67
- package/lib/store/doc-analyzer.d.ts.map +1 -1
- package/lib/store/dsl-workflow.d.ts +1 -0
- package/lib/store/dsl-workflow.d.ts.map +1 -1
- package/lib/store/dsl-workflow.js.map +1 -1
- package/lib/store/grounded-extraction.d.ts +146 -0
- package/lib/store/grounded-extraction.d.ts.map +1 -0
- package/lib/store/grounded-extraction.js +8 -0
- package/lib/store/grounded-extraction.js.map +1 -0
- package/lib/store/index.d.ts +1 -0
- package/lib/store/index.d.ts.map +1 -1
- package/lib/store/index.js +1 -0
- package/lib/store/index.js.map +1 -1
- package/lib/store/store.d.ts +307 -1
- package/lib/store/store.d.ts.map +1 -1
- package/lib/store/store.js +438 -0
- package/lib/store/store.js.map +1 -1
- package/lib/store/workflow.d.ts +3 -0
- package/lib/store/workflow.d.ts.map +1 -1
- package/lib/store/workflow.js.map +1 -1
- package/lib/user.d.ts +14 -0
- package/lib/user.d.ts.map +1 -1
- package/lib/user.js +31 -0
- package/lib/user.js.map +1 -1
- package/lib/vertesia-common.js +2 -2
- package/lib/vertesia-common.js.map +1 -1
- package/lib/view-configuration-validation.d.ts +15 -0
- package/lib/view-configuration-validation.d.ts.map +1 -0
- package/lib/view-configuration-validation.js +63 -0
- package/lib/view-configuration-validation.js.map +1 -0
- package/lib/view-query-validation.d.ts +13 -0
- package/lib/view-query-validation.d.ts.map +1 -0
- package/lib/view-query-validation.js +266 -0
- package/lib/view-query-validation.js.map +1 -0
- package/lib/view-validation-helpers.d.ts +15 -0
- package/lib/view-validation-helpers.d.ts.map +1 -0
- package/lib/view-validation-helpers.js +25 -0
- package/lib/view-validation-helpers.js.map +1 -0
- package/lib/views-schema.d.ts +1992 -0
- package/lib/views-schema.d.ts.map +1 -0
- package/lib/views-schema.js +674 -0
- package/lib/views-schema.js.map +1 -0
- package/lib/views-validation.d.ts +21 -0
- package/lib/views-validation.d.ts.map +1 -0
- package/lib/views-validation.js +164 -0
- package/lib/views-validation.js.map +1 -0
- package/lib/views.d.ts +381 -0
- package/lib/views.d.ts.map +1 -0
- package/lib/views.js +41 -0
- package/lib/views.js.map +1 -0
- package/package.json +5 -4
- package/src/apikey.ts +1 -0
- package/src/apps.test.ts +9 -1
- package/src/apps.ts +583 -90
- package/src/audit-trail.ts +83 -0
- package/src/data-platform.ts +129 -5
- package/src/index.ts +12 -0
- package/src/interaction.ts +20 -1
- package/src/json-schema.ts +0 -1
- package/src/platform-event.ts +92 -2
- package/src/project.test.ts +44 -0
- package/src/project.ts +205 -22
- package/src/query.ts +6 -0
- package/src/refs.ts +1 -0
- package/src/roles.test.ts +32 -0
- package/src/schema-for-extraction.test.ts +191 -0
- package/src/schema-for-extraction.ts +231 -0
- package/src/store/agent-run.ts +2 -0
- package/src/store/conversation-state.ts +47 -0
- package/src/store/doc-analyzer.ts +10 -76
- package/src/store/dsl-workflow.ts +1 -0
- package/src/store/grounded-extraction.ts +154 -0
- package/src/store/index.ts +1 -0
- package/src/store/store.ts +778 -1
- package/src/store/workflow.ts +3 -0
- package/src/user.ts +46 -0
- package/src/view-configuration-validation.ts +74 -0
- package/src/view-query-validation.test.ts +21 -0
- package/src/view-query-validation.ts +319 -0
- package/src/view-validation-helpers.ts +28 -0
- package/src/views-schema.test.ts +364 -0
- package/src/views-schema.ts +689 -0
- package/src/views-validation.ts +234 -0
- package/src/views.ts +484 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import Ajv from 'ajv';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { validateViewConfiguration } from './view-configuration-validation.js';
|
|
4
|
+
import { type ViewExperienceConfiguration, type ViewNavigationItem, viewExperienceRoute } from './views.js';
|
|
5
|
+
import {
|
|
6
|
+
PersistedViewExperienceConfigurationJsonSchema,
|
|
7
|
+
ViewExperienceConfigurationJsonSchema,
|
|
8
|
+
} from './views-schema.js';
|
|
9
|
+
import { parseAppViewExperienceId, validateViewExperienceId } from './views-validation.js';
|
|
10
|
+
|
|
11
|
+
function documentLibrary(): ViewExperienceConfiguration {
|
|
12
|
+
return {
|
|
13
|
+
name: 'Document Library',
|
|
14
|
+
layout: {
|
|
15
|
+
mode: 'browse',
|
|
16
|
+
navigation_position: 'sidebar',
|
|
17
|
+
},
|
|
18
|
+
scope: {
|
|
19
|
+
locations: ['/documents'],
|
|
20
|
+
head_only: true,
|
|
21
|
+
},
|
|
22
|
+
navigation: [
|
|
23
|
+
{
|
|
24
|
+
id: 'location',
|
|
25
|
+
label: 'Folders',
|
|
26
|
+
source: 'location',
|
|
27
|
+
roots: ['/documents'],
|
|
28
|
+
presentation: 'tree',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'brand',
|
|
32
|
+
label: 'Brand',
|
|
33
|
+
source: 'terms',
|
|
34
|
+
field: 'properties.brand.keyword',
|
|
35
|
+
size: 30,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 'geography',
|
|
39
|
+
label: 'Geography',
|
|
40
|
+
source: 'hierarchy',
|
|
41
|
+
levels: [
|
|
42
|
+
{ id: 'state', label: 'State', field: 'properties.state' },
|
|
43
|
+
{ id: 'city', label: 'City', field: 'properties.city', sort: 'label' },
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'project_size',
|
|
48
|
+
label: 'Project size',
|
|
49
|
+
source: 'range',
|
|
50
|
+
field: 'properties.project_size',
|
|
51
|
+
ranges: [
|
|
52
|
+
{ id: 'small', label: 'Small', to: 100 },
|
|
53
|
+
{ id: 'large', label: 'Large', from: 100 },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
search: {
|
|
58
|
+
mode: 'agentic',
|
|
59
|
+
placeholder: 'Describe what you need',
|
|
60
|
+
fields: [
|
|
61
|
+
{
|
|
62
|
+
field: 'text',
|
|
63
|
+
description: 'Full ingested and OCR document text.',
|
|
64
|
+
type: 'text',
|
|
65
|
+
mode: 'full_text',
|
|
66
|
+
boost: 1.5,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
key_terms: [{ id: 'client', label: 'Client', type: 'keyword' }],
|
|
70
|
+
agentic: {
|
|
71
|
+
interaction: 'sys:ContentSearchAgent',
|
|
72
|
+
config: {
|
|
73
|
+
environment: 'production-search',
|
|
74
|
+
model: 'openai:gpt-5-mini',
|
|
75
|
+
},
|
|
76
|
+
mode: 'query',
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
results: {
|
|
80
|
+
default_display: 'table',
|
|
81
|
+
allow_display_switch: true,
|
|
82
|
+
displays: [
|
|
83
|
+
{
|
|
84
|
+
id: 'table',
|
|
85
|
+
label: 'Table',
|
|
86
|
+
type: 'table',
|
|
87
|
+
columns: [
|
|
88
|
+
{
|
|
89
|
+
field: 'name',
|
|
90
|
+
label: 'Name',
|
|
91
|
+
sortable: true,
|
|
92
|
+
sort_option: 'name_asc',
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: 'cards',
|
|
98
|
+
label: 'Cards',
|
|
99
|
+
type: 'cards',
|
|
100
|
+
title: { field: 'name' },
|
|
101
|
+
fields: [{ field: 'properties.brand', label: 'Brand' }],
|
|
102
|
+
columns: 3,
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
default_sort: 'name_asc',
|
|
106
|
+
sort_options: [
|
|
107
|
+
{
|
|
108
|
+
id: 'name_asc',
|
|
109
|
+
label: 'Name',
|
|
110
|
+
sort: [{ field: 'name.keyword', order: 'asc' }],
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
describe('View Experience configuration schema', () => {
|
|
118
|
+
it('accepts navigation, one agentic model, and visual result displays', () => {
|
|
119
|
+
const validate = new Ajv.default({ allErrors: true, strict: false }).compile(
|
|
120
|
+
ViewExperienceConfigurationJsonSchema,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
expect(validate(documentLibrary())).toBe(true);
|
|
124
|
+
expect(validate.errors).toBeNull();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('rejects malformed discriminated navigation and display entries', () => {
|
|
128
|
+
const validate = new Ajv.default({ allErrors: true, strict: false }).compile(
|
|
129
|
+
ViewExperienceConfigurationJsonSchema,
|
|
130
|
+
);
|
|
131
|
+
const invalid = documentLibrary() as unknown as Record<string, unknown>;
|
|
132
|
+
invalid.navigation = [{ id: 'brand', label: 'Brand', source: 'terms' }];
|
|
133
|
+
|
|
134
|
+
expect(validate(invalid)).toBe(false);
|
|
135
|
+
expect(validate.errors?.some((error) => error.instancePath.includes('/navigation/0'))).toBe(true);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('advertises only executable version 1 options', () => {
|
|
139
|
+
const validate = new Ajv.default({ allErrors: true, strict: false }).compile(
|
|
140
|
+
ViewExperienceConfigurationJsonSchema,
|
|
141
|
+
);
|
|
142
|
+
const unsupported = [
|
|
143
|
+
{ name: 'Drawer', layout: { navigation_position: 'drawer' } },
|
|
144
|
+
{
|
|
145
|
+
name: 'Missing bucket',
|
|
146
|
+
navigation: [
|
|
147
|
+
{
|
|
148
|
+
id: 'brand',
|
|
149
|
+
label: 'Brand',
|
|
150
|
+
source: 'terms',
|
|
151
|
+
field: 'properties.brand',
|
|
152
|
+
missing_label: 'Unknown',
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
{ name: 'Rerank', search: { mode: 'agentic', agentic: { mode: 'rerank' } } },
|
|
157
|
+
{ name: 'Candidate limit', search: { mode: 'agentic', agentic: { candidate_limit: 50 } } },
|
|
158
|
+
{
|
|
159
|
+
name: 'Annotations',
|
|
160
|
+
search: { mode: 'agentic', agentic: { annotations: { mode: 'why_match' } } },
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: 'Board card renderer',
|
|
164
|
+
results: {
|
|
165
|
+
default_display: 'board',
|
|
166
|
+
displays: [
|
|
167
|
+
{
|
|
168
|
+
id: 'board',
|
|
169
|
+
label: 'Board',
|
|
170
|
+
type: 'board',
|
|
171
|
+
group_by: 'status',
|
|
172
|
+
card: { renderer: 'custom-card', title: { field: 'name' } },
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
unsupported.forEach((configuration) => {
|
|
180
|
+
expect(validate(configuration), JSON.stringify(validate.errors)).toBe(false);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('matches the agentic timeout schema to the runtime budget', () => {
|
|
185
|
+
const validate = new Ajv.default({ allErrors: true, strict: false }).compile(
|
|
186
|
+
ViewExperienceConfigurationJsonSchema,
|
|
187
|
+
);
|
|
188
|
+
expect(validate({ name: 'Agentic', search: { mode: 'agentic', agentic: { timeout_ms: 60_000 } } })).toBe(true);
|
|
189
|
+
expect(validate({ name: 'Too short', search: { mode: 'agentic', agentic: { timeout_ms: 999 } } })).toBe(false);
|
|
190
|
+
expect(validate({ name: 'Too long', search: { mode: 'agentic', agentic: { timeout_ms: 60_001 } } })).toBe(
|
|
191
|
+
false,
|
|
192
|
+
);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('requires a description only for persisted View resources', () => {
|
|
196
|
+
const validatePersisted = new Ajv.default({ allErrors: true, strict: false }).compile(
|
|
197
|
+
PersistedViewExperienceConfigurationJsonSchema,
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
expect(validatePersisted(documentLibrary())).toBe(false);
|
|
201
|
+
expect(
|
|
202
|
+
validatePersisted({
|
|
203
|
+
...documentLibrary(),
|
|
204
|
+
description: 'Browse the project document library by location and business metadata.',
|
|
205
|
+
}),
|
|
206
|
+
).toBe(true);
|
|
207
|
+
expect(validateViewConfiguration(documentLibrary())).toEqual([]);
|
|
208
|
+
const missingDescriptionIssues = validateViewConfiguration(documentLibrary(), 'persisted');
|
|
209
|
+
expect(missingDescriptionIssues).toHaveLength(1);
|
|
210
|
+
expect(missingDescriptionIssues[0]?.path).toBe('description');
|
|
211
|
+
expect(
|
|
212
|
+
validateViewConfiguration(
|
|
213
|
+
{
|
|
214
|
+
...documentLibrary(),
|
|
215
|
+
description: ' ',
|
|
216
|
+
},
|
|
217
|
+
'persisted',
|
|
218
|
+
),
|
|
219
|
+
).toContainEqual({
|
|
220
|
+
path: 'description',
|
|
221
|
+
message: 'must explain the View purpose',
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
describe('View Experience semantic validation', () => {
|
|
227
|
+
it('accepts a complete document library configuration', () => {
|
|
228
|
+
expect(validateViewConfiguration(documentLibrary())).toEqual([]);
|
|
229
|
+
expect(validateViewExperienceId('document-library')).toEqual([]);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('reports invalid cross-references that JSON Schema cannot express', () => {
|
|
233
|
+
const invalid = documentLibrary();
|
|
234
|
+
if (invalid.results) {
|
|
235
|
+
invalid.results.default_display = 'missing';
|
|
236
|
+
invalid.results.displays.push({
|
|
237
|
+
id: 'table',
|
|
238
|
+
label: 'Duplicate table',
|
|
239
|
+
type: 'table',
|
|
240
|
+
columns: [{ field: 'name' }],
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const issues = validateViewConfiguration(invalid);
|
|
245
|
+
|
|
246
|
+
expect(issues).toContainEqual({
|
|
247
|
+
path: 'results.default_display',
|
|
248
|
+
message: 'must reference a configured display',
|
|
249
|
+
});
|
|
250
|
+
expect(issues).toContainEqual({
|
|
251
|
+
path: 'results.displays[2].id',
|
|
252
|
+
message: 'must be unique',
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('rejects duplicate and incompatible search field definitions', () => {
|
|
257
|
+
const invalid = documentLibrary();
|
|
258
|
+
if (invalid.search) {
|
|
259
|
+
invalid.search.fields = [
|
|
260
|
+
{ field: 'properties.total', type: 'number', mode: 'full_text' },
|
|
261
|
+
{ field: 'properties.total', type: 'number' },
|
|
262
|
+
];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
expect(validateViewConfiguration(invalid)).toEqual(
|
|
266
|
+
expect.arrayContaining([
|
|
267
|
+
{
|
|
268
|
+
path: 'search.fields[0].type',
|
|
269
|
+
message: 'must be text when mode is full_text',
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
path: 'search.fields[1].field',
|
|
273
|
+
message: 'must be unique',
|
|
274
|
+
},
|
|
275
|
+
]),
|
|
276
|
+
);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('rejects ambiguous property hierarchies', () => {
|
|
280
|
+
const invalid = documentLibrary();
|
|
281
|
+
invalid.navigation = [
|
|
282
|
+
{
|
|
283
|
+
id: 'geography',
|
|
284
|
+
label: 'Geography',
|
|
285
|
+
source: 'hierarchy',
|
|
286
|
+
levels: [
|
|
287
|
+
{ id: 'state', label: 'State', field: 'properties.state' },
|
|
288
|
+
{ id: 'state', label: 'City', field: 'properties.state' },
|
|
289
|
+
],
|
|
290
|
+
} as ViewNavigationItem,
|
|
291
|
+
];
|
|
292
|
+
|
|
293
|
+
expect(validateViewConfiguration(invalid)).toEqual(
|
|
294
|
+
expect.arrayContaining([
|
|
295
|
+
{
|
|
296
|
+
path: 'navigation[0].levels[1].id',
|
|
297
|
+
message: 'must be unique within the hierarchy',
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
path: 'navigation[0].levels[1].field',
|
|
301
|
+
message: 'must be unique within the hierarchy',
|
|
302
|
+
},
|
|
303
|
+
]),
|
|
304
|
+
);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('runs structural validation before semantic validation', () => {
|
|
308
|
+
const invalid = {
|
|
309
|
+
...documentLibrary(),
|
|
310
|
+
navigation: [
|
|
311
|
+
{
|
|
312
|
+
id: 'geography',
|
|
313
|
+
label: 'Geography',
|
|
314
|
+
source: 'hierarchy',
|
|
315
|
+
multi_select: true,
|
|
316
|
+
levels: [
|
|
317
|
+
{ id: 'state', label: 'State', field: 'properties.state' },
|
|
318
|
+
{ id: 'state', label: 'City', field: 'properties.state' },
|
|
319
|
+
],
|
|
320
|
+
},
|
|
321
|
+
],
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
const issues = validateViewConfiguration(invalid);
|
|
325
|
+
expect(issues.some((issue) => issue.path === 'navigation[0].multi_select')).toBe(true);
|
|
326
|
+
expect(issues.some((issue) => issue.message === 'must be unique within the hierarchy')).toBe(false);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('normalizes required and array paths from JSON Schema errors', () => {
|
|
330
|
+
const issues = validateViewConfiguration({
|
|
331
|
+
name: 'Invalid',
|
|
332
|
+
navigation: [{ id: 'brand', label: 'Brand', source: 'terms' }],
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
expect(issues.some((issue) => issue.path === 'navigation[0].field')).toBe(true);
|
|
336
|
+
expect(issues.every((issue) => !issue.path.startsWith('/'))).toBe(true);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it('rejects fixed filters that the execution runtime cannot apply', () => {
|
|
340
|
+
const invalid = documentLibrary();
|
|
341
|
+
if (invalid.scope) {
|
|
342
|
+
invalid.scope.fixed_filter = { query_string: { query: '*' } };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
expect(validateViewConfiguration(invalid)).toContainEqual({
|
|
346
|
+
path: 'scope.fixed_filter.query_string',
|
|
347
|
+
message: "query type 'query_string' is not supported",
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it('parses canonical app View ids and rejects URL path material', () => {
|
|
352
|
+
expect(parseAppViewExperienceId('app:content:document-lib')).toEqual({
|
|
353
|
+
app_name: 'content',
|
|
354
|
+
local_id: 'document-lib',
|
|
355
|
+
});
|
|
356
|
+
expect(parseAppViewExperienceId('app:content:../../environments')).toBeUndefined();
|
|
357
|
+
expect(parseAppViewExperienceId('app:content:%2F..%2Fenvironments')).toBeUndefined();
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it('builds the generic route without exposing path material from an id', () => {
|
|
361
|
+
expect(viewExperienceRoute('app:content:document-library')).toBe('/view/app%3Acontent%3Adocument-library');
|
|
362
|
+
expect(viewExperienceRoute('unsafe/id')).toBe('/view/unsafe%2Fid');
|
|
363
|
+
});
|
|
364
|
+
});
|