@syntrologie/adapt-content 2.4.0 → 2.5.1
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/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +59 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +67 -12
- package/dist/summarize.d.ts.map +1 -1
- package/dist/summarize.js +12 -1
- package/dist/types.d.ts +9 -42
- package/dist/types.d.ts.map +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/AnchorPicker.test.d.ts +2 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/AnchorPicker.test.d.ts.map +1 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/AnchorPicker.test.js +224 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/ConditionStatusLine.test.js +102 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/DetectionBadge.test.js +58 -6
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/DismissedSection.test.js +18 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorCard.test.js +61 -2
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/EditorPanelShell.test.js +478 -7
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/ElementHighlight.test.js +54 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/selectorGenerator.test.d.ts +2 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/selectorGenerator.test.d.ts.map +1 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/selectorGenerator.test.js +257 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useTriggerWhenStatus.test.d.ts +2 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useTriggerWhenStatus.test.d.ts.map +1 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useTriggerWhenStatus.test.js +1015 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPicker.js +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLine.d.ts +4 -4
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLine.d.ts.map +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLine.js +2 -2
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadge.d.ts +2 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadge.d.ts.map +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadge.js +20 -3
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.d.ts +10 -8
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.d.ts.map +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.js +350 -87
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlight.js +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourney.d.ts +3 -3
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourney.d.ts.map +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourney.js +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/formatConditionLabel.d.ts +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/formatConditionLabel.d.ts.map +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/formatConditionLabel.js +5 -2
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useTriggerWhenStatus.d.ts +24 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useTriggerWhenStatus.d.ts.map +1 -0
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/{useShowWhenStatus.js → useTriggerWhenStatus.js} +18 -15
- package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts +3 -3
- package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts.map +1 -1
- package/node_modules/@syntrologie/shared-editor-ui/dist/index.js +1 -1
- package/package.json +4 -5
- package/node_modules/@syntrologie/sdk-contracts/dist/index.d.ts +0 -26
- package/node_modules/@syntrologie/sdk-contracts/dist/index.js +0 -13
- package/node_modules/@syntrologie/sdk-contracts/dist/schemas.d.ts +0 -1428
- package/node_modules/@syntrologie/sdk-contracts/dist/schemas.js +0 -142
- package/node_modules/@syntrologie/sdk-contracts/package.json +0 -33
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useShowWhenStatus.d.ts +0 -24
- package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useShowWhenStatus.d.ts.map +0 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
// Shim CSS.escape for jsdom (not available by default)
|
|
3
|
+
if (typeof CSS === 'undefined') {
|
|
4
|
+
globalThis.CSS = { escape: (str) => str.replace(/([^\w-])/g, '\\$1') };
|
|
5
|
+
}
|
|
6
|
+
else if (!CSS.escape) {
|
|
7
|
+
CSS.escape = (str) => str.replace(/([^\w-])/g, '\\$1');
|
|
8
|
+
}
|
|
9
|
+
import { generateSelector, getElementDescription, validateSelector, } from '../utils/selectorGenerator';
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// Mock css-selector-generator
|
|
12
|
+
// =============================================================================
|
|
13
|
+
vi.mock('css-selector-generator', () => ({
|
|
14
|
+
getCssSelector: vi.fn(),
|
|
15
|
+
}));
|
|
16
|
+
import { getCssSelector } from 'css-selector-generator';
|
|
17
|
+
const mockGetCssSelector = vi.mocked(getCssSelector);
|
|
18
|
+
// =============================================================================
|
|
19
|
+
// HELPERS
|
|
20
|
+
// =============================================================================
|
|
21
|
+
function createElement(tag, attrs = {}) {
|
|
22
|
+
const el = document.createElement(tag);
|
|
23
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
24
|
+
if (key === 'textContent') {
|
|
25
|
+
el.textContent = value;
|
|
26
|
+
}
|
|
27
|
+
else if (key === 'className') {
|
|
28
|
+
el.className = value;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
el.setAttribute(key, value);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
document.body.appendChild(el);
|
|
35
|
+
return el;
|
|
36
|
+
}
|
|
37
|
+
// =============================================================================
|
|
38
|
+
// generateSelector
|
|
39
|
+
// =============================================================================
|
|
40
|
+
describe('generateSelector', () => {
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
vi.clearAllMocks();
|
|
43
|
+
document.body.innerHTML = '';
|
|
44
|
+
});
|
|
45
|
+
it('calls getCssSelector with element and default options', () => {
|
|
46
|
+
const el = createElement('div');
|
|
47
|
+
mockGetCssSelector.mockReturnValue('div');
|
|
48
|
+
generateSelector(el);
|
|
49
|
+
expect(mockGetCssSelector).toHaveBeenCalledWith(el, expect.objectContaining({
|
|
50
|
+
includeTag: true,
|
|
51
|
+
maxCombinations: 100,
|
|
52
|
+
}));
|
|
53
|
+
});
|
|
54
|
+
it('returns the selector from getCssSelector', () => {
|
|
55
|
+
const el = createElement('div', { id: 'my-id' });
|
|
56
|
+
mockGetCssSelector.mockReturnValue('#my-id');
|
|
57
|
+
const result = generateSelector(el);
|
|
58
|
+
expect(result).toBe('#my-id');
|
|
59
|
+
});
|
|
60
|
+
it('passes custom options through', () => {
|
|
61
|
+
const el = createElement('div');
|
|
62
|
+
mockGetCssSelector.mockReturnValue('div');
|
|
63
|
+
generateSelector(el, { includeTag: false, maxCombinations: 50 });
|
|
64
|
+
expect(mockGetCssSelector).toHaveBeenCalledWith(el, expect.objectContaining({
|
|
65
|
+
includeTag: false,
|
|
66
|
+
maxCombinations: 50,
|
|
67
|
+
}));
|
|
68
|
+
});
|
|
69
|
+
it('includes attribute selectors when preferTestIds is true (default)', () => {
|
|
70
|
+
const el = createElement('div');
|
|
71
|
+
mockGetCssSelector.mockReturnValue('div');
|
|
72
|
+
generateSelector(el);
|
|
73
|
+
const call = mockGetCssSelector.mock.calls[0];
|
|
74
|
+
const options = call[1];
|
|
75
|
+
expect(options.selectors).toContain('attribute');
|
|
76
|
+
});
|
|
77
|
+
it('excludes attribute selectors when preferTestIds is false', () => {
|
|
78
|
+
const el = createElement('div');
|
|
79
|
+
mockGetCssSelector.mockReturnValue('div');
|
|
80
|
+
generateSelector(el, { preferTestIds: false });
|
|
81
|
+
const call = mockGetCssSelector.mock.calls[0];
|
|
82
|
+
const options = call[1];
|
|
83
|
+
expect(options.selectors).not.toContain('attribute');
|
|
84
|
+
});
|
|
85
|
+
it('includes blacklist patterns for dynamic classes', () => {
|
|
86
|
+
const el = createElement('div');
|
|
87
|
+
mockGetCssSelector.mockReturnValue('div');
|
|
88
|
+
generateSelector(el);
|
|
89
|
+
const call = mockGetCssSelector.mock.calls[0];
|
|
90
|
+
const options = call[1];
|
|
91
|
+
expect(options.blacklist).toBeDefined();
|
|
92
|
+
expect(Array.isArray(options.blacklist)).toBe(true);
|
|
93
|
+
expect(options.blacklist.length).toBeGreaterThan(0);
|
|
94
|
+
});
|
|
95
|
+
it('includes whitelist for stable attributes', () => {
|
|
96
|
+
const el = createElement('div');
|
|
97
|
+
mockGetCssSelector.mockReturnValue('div');
|
|
98
|
+
generateSelector(el);
|
|
99
|
+
const call = mockGetCssSelector.mock.calls[0];
|
|
100
|
+
const options = call[1];
|
|
101
|
+
expect(options.whitelist).toBeDefined();
|
|
102
|
+
expect(Array.isArray(options.whitelist)).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
it('falls back to generateFallbackSelector when getCssSelector throws', () => {
|
|
105
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
106
|
+
const parent = document.createElement('div');
|
|
107
|
+
parent.id = 'parent';
|
|
108
|
+
document.body.appendChild(parent);
|
|
109
|
+
const child = document.createElement('span');
|
|
110
|
+
parent.appendChild(child);
|
|
111
|
+
mockGetCssSelector.mockImplementation(() => {
|
|
112
|
+
throw new Error('Failed');
|
|
113
|
+
});
|
|
114
|
+
const result = generateSelector(child);
|
|
115
|
+
// Fallback should produce a path-based selector
|
|
116
|
+
expect(result).toContain('#parent');
|
|
117
|
+
expect(result).toContain('span');
|
|
118
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
119
|
+
document.body.removeChild(parent);
|
|
120
|
+
});
|
|
121
|
+
describe('fallback selector generation', () => {
|
|
122
|
+
it('uses ID when element has an ID', () => {
|
|
123
|
+
const el = document.createElement('div');
|
|
124
|
+
el.id = 'unique-element';
|
|
125
|
+
document.body.appendChild(el);
|
|
126
|
+
mockGetCssSelector.mockImplementation(() => {
|
|
127
|
+
throw new Error('Failed');
|
|
128
|
+
});
|
|
129
|
+
vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
130
|
+
const result = generateSelector(el);
|
|
131
|
+
expect(result).toContain('#unique-element');
|
|
132
|
+
document.body.removeChild(el);
|
|
133
|
+
});
|
|
134
|
+
it('uses nth-child for elements without ID', () => {
|
|
135
|
+
const parent = document.createElement('div');
|
|
136
|
+
document.body.appendChild(parent);
|
|
137
|
+
const child1 = document.createElement('p');
|
|
138
|
+
const child2 = document.createElement('p');
|
|
139
|
+
parent.appendChild(child1);
|
|
140
|
+
parent.appendChild(child2);
|
|
141
|
+
mockGetCssSelector.mockImplementation(() => {
|
|
142
|
+
throw new Error('Failed');
|
|
143
|
+
});
|
|
144
|
+
vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
145
|
+
const result = generateSelector(child2);
|
|
146
|
+
expect(result).toContain('nth-child');
|
|
147
|
+
document.body.removeChild(parent);
|
|
148
|
+
});
|
|
149
|
+
it('stops at element with ID (shortest unique path)', () => {
|
|
150
|
+
const grandparent = document.createElement('div');
|
|
151
|
+
grandparent.id = 'root';
|
|
152
|
+
document.body.appendChild(grandparent);
|
|
153
|
+
const parent = document.createElement('div');
|
|
154
|
+
grandparent.appendChild(parent);
|
|
155
|
+
const child = document.createElement('span');
|
|
156
|
+
parent.appendChild(child);
|
|
157
|
+
mockGetCssSelector.mockImplementation(() => {
|
|
158
|
+
throw new Error('Failed');
|
|
159
|
+
});
|
|
160
|
+
vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
161
|
+
const result = generateSelector(child);
|
|
162
|
+
// Should start with #root
|
|
163
|
+
expect(result.startsWith('#root')).toBe(true);
|
|
164
|
+
document.body.removeChild(grandparent);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
// =============================================================================
|
|
169
|
+
// validateSelector
|
|
170
|
+
// =============================================================================
|
|
171
|
+
describe('validateSelector', () => {
|
|
172
|
+
afterEach(() => {
|
|
173
|
+
document.body.innerHTML = '';
|
|
174
|
+
});
|
|
175
|
+
it('returns true when selector matches the expected element', () => {
|
|
176
|
+
const el = createElement('div', { id: 'target' });
|
|
177
|
+
expect(validateSelector('#target', el)).toBe(true);
|
|
178
|
+
});
|
|
179
|
+
it('returns false when selector matches a different element', () => {
|
|
180
|
+
const el1 = createElement('div', { id: 'first' });
|
|
181
|
+
createElement('div', { id: 'second' });
|
|
182
|
+
expect(validateSelector('#second', el1)).toBe(false);
|
|
183
|
+
});
|
|
184
|
+
it('returns false when selector matches nothing', () => {
|
|
185
|
+
const el = createElement('div');
|
|
186
|
+
expect(validateSelector('#nonexistent', el)).toBe(false);
|
|
187
|
+
});
|
|
188
|
+
it('returns false for invalid selector syntax', () => {
|
|
189
|
+
const el = createElement('div');
|
|
190
|
+
expect(validateSelector('[[[invalid', el)).toBe(false);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
// =============================================================================
|
|
194
|
+
// getElementDescription
|
|
195
|
+
// =============================================================================
|
|
196
|
+
describe('getElementDescription', () => {
|
|
197
|
+
afterEach(() => {
|
|
198
|
+
document.body.innerHTML = '';
|
|
199
|
+
});
|
|
200
|
+
it('includes tag name', () => {
|
|
201
|
+
const el = createElement('button');
|
|
202
|
+
expect(getElementDescription(el)).toContain('button');
|
|
203
|
+
});
|
|
204
|
+
it('includes ID when present', () => {
|
|
205
|
+
const el = createElement('div', { id: 'my-btn' });
|
|
206
|
+
expect(getElementDescription(el)).toContain('#my-btn');
|
|
207
|
+
});
|
|
208
|
+
it('includes static class names', () => {
|
|
209
|
+
const el = createElement('div', { className: 'header main-content' });
|
|
210
|
+
const desc = getElementDescription(el);
|
|
211
|
+
expect(desc).toContain('.header');
|
|
212
|
+
expect(desc).toContain('.main-content');
|
|
213
|
+
});
|
|
214
|
+
it('excludes dynamic class names', () => {
|
|
215
|
+
const el = createElement('div', { className: 'css-1abc23 my-class' });
|
|
216
|
+
const desc = getElementDescription(el);
|
|
217
|
+
// Dynamic class css-1abc23 should be filtered out
|
|
218
|
+
expect(desc).not.toContain('css-1abc23');
|
|
219
|
+
expect(desc).toContain('my-class');
|
|
220
|
+
});
|
|
221
|
+
it('includes text content preview (truncated at 30 chars)', () => {
|
|
222
|
+
const el = createElement('p', {
|
|
223
|
+
textContent: 'This is a very long text that should be truncated',
|
|
224
|
+
});
|
|
225
|
+
const desc = getElementDescription(el);
|
|
226
|
+
expect(desc).toContain('"');
|
|
227
|
+
expect(desc).toContain('...');
|
|
228
|
+
});
|
|
229
|
+
it('includes full text for short content', () => {
|
|
230
|
+
const el = createElement('span', { textContent: 'Hello' });
|
|
231
|
+
const desc = getElementDescription(el);
|
|
232
|
+
expect(desc).toContain('"Hello"');
|
|
233
|
+
expect(desc).not.toContain('...');
|
|
234
|
+
});
|
|
235
|
+
it('handles elements with no text content', () => {
|
|
236
|
+
const el = createElement('img');
|
|
237
|
+
const desc = getElementDescription(el);
|
|
238
|
+
expect(desc).toBe('img');
|
|
239
|
+
});
|
|
240
|
+
it('limits class names to 2', () => {
|
|
241
|
+
const el = createElement('div', { className: 'cls-a cls-b cls-c cls-d' });
|
|
242
|
+
const desc = getElementDescription(el);
|
|
243
|
+
// Should include at most 2 classes
|
|
244
|
+
expect(desc).toContain('.cls-a');
|
|
245
|
+
expect(desc).toContain('.cls-b');
|
|
246
|
+
expect(desc).not.toContain('.cls-c');
|
|
247
|
+
});
|
|
248
|
+
it('handles SVGElement className (not a string)', () => {
|
|
249
|
+
const svgNS = 'http://www.w3.org/2000/svg';
|
|
250
|
+
const svg = document.createElementNS(svgNS, 'svg');
|
|
251
|
+
document.body.appendChild(svg);
|
|
252
|
+
// SVGElement.className is an SVGAnimatedString, not a string
|
|
253
|
+
const desc = getElementDescription(svg);
|
|
254
|
+
expect(desc).toContain('svg');
|
|
255
|
+
document.body.removeChild(svg);
|
|
256
|
+
});
|
|
257
|
+
});
|
package/node_modules/@syntrologie/shared-editor-ui/dist/__tests__/useTriggerWhenStatus.test.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTriggerWhenStatus.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/useTriggerWhenStatus.test.ts"],"names":[],"mappings":""}
|