@startinblox/components-ds4go 2.3.0 → 3.0.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/.gitlab-ci.yml +8 -2
- package/AGENTS.md +516 -0
- package/biome.json +1 -1
- package/cypress/component/no-component-test.cy.ts +9 -0
- package/cypress/e2e/helpers/components/setupCacheInvalidation.cy.ts +512 -0
- package/cypress/e2e/helpers/components/setupCacheOnResourceReady.cy.ts +483 -0
- package/cypress/e2e/helpers/components/setupComponentSubscriptions.cy.ts +239 -0
- package/cypress/e2e/helpers/components/setupOnSaveReset.cy.ts +380 -0
- package/cypress/e2e/helpers/datas/checkValueInIntervalRecursive.cy.ts +563 -0
- package/cypress/e2e/helpers/datas/dataBuilder.cy.ts +508 -0
- package/cypress/e2e/helpers/datas/filterGenerator.cy.ts +285 -0
- package/cypress/e2e/helpers/datas/filterObjectByDateAfter.cy.ts +389 -0
- package/cypress/e2e/helpers/datas/filterObjectByDateInterval.cy.ts +613 -0
- package/cypress/e2e/helpers/datas/filterObjectById.cy.ts +276 -0
- package/cypress/e2e/helpers/datas/filterObjectByInterval.cy.ts +237 -0
- package/cypress/e2e/helpers/datas/filterObjectByNamedValue.cy.ts +299 -0
- package/cypress/e2e/helpers/datas/filterObjectByType.cy.ts +307 -0
- package/cypress/e2e/helpers/datas/filterObjectByValue.cy.ts +375 -0
- package/cypress/e2e/helpers/datas/sort.cy.ts +293 -0
- package/cypress/e2e/helpers/ui/formatDate.cy.ts +233 -0
- package/cypress/e2e/helpers/utils/requestNavigation.cy.ts +257 -0
- package/cypress/e2e/helpers/utils/uniq.cy.ts +160 -0
- package/cypress/support/e2e.ts +1 -0
- package/cypress.config.ts +2 -0
- package/dist/index.js +1113 -1004
- package/package.json +10 -10
- package/src/components/solid-boilerplate.ts +76 -0
- package/src/helpers/components/componentObjectHandler.ts +5 -7
- package/src/helpers/components/componentObjectsHandler.ts +8 -3
- package/src/helpers/components/orbitComponent.ts +87 -68
- package/src/helpers/components/orbitDspComponent.ts +14 -4
- package/src/helpers/components/setupCacheInvalidation.ts +50 -23
- package/src/helpers/components/setupCacheOnResourceReady.ts +42 -23
- package/src/helpers/components/setupComponentSubscriptions.ts +10 -9
- package/src/helpers/components/setupOnSaveReset.ts +27 -5
- package/src/helpers/datas/checkValueInIntervalRecursive.ts +66 -0
- package/src/helpers/datas/dataBuilder.ts +4 -4
- package/src/helpers/datas/filterGenerator.ts +13 -10
- package/src/helpers/datas/filterObjectByDateAfter.ts +3 -3
- package/src/helpers/datas/filterObjectByDateInterval.ts +44 -0
- package/src/helpers/datas/filterObjectById.ts +7 -6
- package/src/helpers/datas/filterObjectByInterval.ts +6 -110
- package/src/helpers/datas/filterObjectByNamedValue.ts +35 -33
- package/src/helpers/datas/filterObjectByType.ts +3 -3
- package/src/helpers/datas/filterObjectByValue.ts +17 -16
- package/src/helpers/datas/sort.ts +50 -23
- package/src/helpers/index.ts +2 -0
- package/src/helpers/ui/formatDate.ts +14 -1
- package/src/helpers/utils/requestNavigation.ts +5 -2
- package/src/helpers/utils/uniq.ts +1 -1
- package/cypress/component/solid-boilerplate.cy.ts +0 -9
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import setupComponentSubscriptions from "@helpers/components/setupComponentSubscriptions";
|
|
2
|
+
|
|
3
|
+
describe("setupComponentSubscriptions helper function", () => {
|
|
4
|
+
const createMockComponent = () => {
|
|
5
|
+
const _subscriptions = new Set();
|
|
6
|
+
|
|
7
|
+
const mockComponent: any = {
|
|
8
|
+
_subscriptions,
|
|
9
|
+
_subscribe() {
|
|
10
|
+
for (const subscription of this._subscriptions) {
|
|
11
|
+
document.addEventListener(subscription[0], subscription[1]);
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
_unsubscribe() {
|
|
15
|
+
for (const subscription of this._subscriptions) {
|
|
16
|
+
document.removeEventListener(subscription[0], subscription[1]);
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
requestUpdate: cy.stub(),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return mockComponent;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
before(() => {
|
|
26
|
+
cy.window().then((win) => {
|
|
27
|
+
(win as any).orbit = {
|
|
28
|
+
getRoute: cy.stub(),
|
|
29
|
+
};
|
|
30
|
+
(win as any).sibRouter = {
|
|
31
|
+
currentResource: "https://example.com/current-resource",
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
cy.window().then((win) => {
|
|
38
|
+
(win as any).sibRouter = {
|
|
39
|
+
currentResource: "https://example.com/current-resource",
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
afterEach(() => {
|
|
45
|
+
const routers = document.querySelectorAll("solid-router");
|
|
46
|
+
for (const router of routers) {
|
|
47
|
+
router.remove();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const ensureSibRouterExists = () => {
|
|
52
|
+
return cy.window().then((win) => {
|
|
53
|
+
if (!(win as any).sibRouter) {
|
|
54
|
+
(win as any).sibRouter = {
|
|
55
|
+
currentResource: "https://example.com/current-resource",
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
describe("Basic functionality", () => {
|
|
62
|
+
it("should create _subscriptions Set", () => {
|
|
63
|
+
const mockComponent = createMockComponent();
|
|
64
|
+
|
|
65
|
+
setupComponentSubscriptions({
|
|
66
|
+
component: mockComponent,
|
|
67
|
+
defaultRoute: false,
|
|
68
|
+
ignoreRouter: true,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
expect(mockComponent._subscriptions).to.be.an.instanceOf(Set);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("should not set noRouter when ignoring router", () => {
|
|
75
|
+
const mockComponent = createMockComponent();
|
|
76
|
+
|
|
77
|
+
setupComponentSubscriptions({
|
|
78
|
+
component: mockComponent,
|
|
79
|
+
defaultRoute: false,
|
|
80
|
+
ignoreRouter: true,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(mockComponent.noRouter).to.be.undefined;
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("should set up _subscribe method", () => {
|
|
87
|
+
const mockComponent: any = {
|
|
88
|
+
requestUpdate: cy.stub(),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
setupComponentSubscriptions({
|
|
92
|
+
component: mockComponent,
|
|
93
|
+
defaultRoute: false,
|
|
94
|
+
ignoreRouter: true,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(mockComponent._subscribe).to.be.a("function");
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe("Uniq property", () => {
|
|
102
|
+
it("should set uniq property if not already set", () => {
|
|
103
|
+
const mockComponent = createMockComponent();
|
|
104
|
+
|
|
105
|
+
setupComponentSubscriptions({
|
|
106
|
+
component: mockComponent,
|
|
107
|
+
defaultRoute: false,
|
|
108
|
+
ignoreRouter: true,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
expect(mockComponent.uniq).to.be.a("string");
|
|
112
|
+
expect(mockComponent.uniq).to.not.equal("");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should not override existing uniq property", () => {
|
|
116
|
+
const mockComponent = createMockComponent();
|
|
117
|
+
mockComponent.uniq = "existing-id";
|
|
118
|
+
|
|
119
|
+
setupComponentSubscriptions({
|
|
120
|
+
component: mockComponent,
|
|
121
|
+
defaultRoute: false,
|
|
122
|
+
ignoreRouter: true,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
expect(mockComponent.uniq).to.equal("existing-id");
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe("Subscription management", () => {
|
|
130
|
+
it("should provide _subscribe method to add event listeners", () => {
|
|
131
|
+
const mockComponent = createMockComponent();
|
|
132
|
+
|
|
133
|
+
setupComponentSubscriptions({
|
|
134
|
+
component: mockComponent,
|
|
135
|
+
defaultRoute: false,
|
|
136
|
+
ignoreRouter: true,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const mockListener = cy.stub();
|
|
140
|
+
mockComponent._subscriptions.add(["test-event", mockListener]);
|
|
141
|
+
mockComponent._subscribe();
|
|
142
|
+
|
|
143
|
+
document.dispatchEvent(new Event("test-event"));
|
|
144
|
+
|
|
145
|
+
expect(mockListener).to.be.called;
|
|
146
|
+
|
|
147
|
+
mockComponent._unsubscribe();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("should provide _unsubscribe method to remove event listeners", () => {
|
|
151
|
+
const mockComponent = createMockComponent();
|
|
152
|
+
|
|
153
|
+
setupComponentSubscriptions({
|
|
154
|
+
component: mockComponent,
|
|
155
|
+
defaultRoute: false,
|
|
156
|
+
ignoreRouter: true,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const mockListener = cy.stub();
|
|
160
|
+
mockComponent._subscriptions.add(["test-event", mockListener]);
|
|
161
|
+
mockComponent._subscribe();
|
|
162
|
+
|
|
163
|
+
mockComponent._unsubscribe();
|
|
164
|
+
|
|
165
|
+
document.dispatchEvent(new Event("test-event"));
|
|
166
|
+
|
|
167
|
+
expect(mockListener).to.not.be.called;
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe("Navigation event handling", () => {
|
|
172
|
+
it("should not listen to navigate events when ignoring router", () => {
|
|
173
|
+
const mockComponent = createMockComponent();
|
|
174
|
+
|
|
175
|
+
setupComponentSubscriptions({
|
|
176
|
+
component: mockComponent,
|
|
177
|
+
defaultRoute: false,
|
|
178
|
+
ignoreRouter: true,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const subscriptions = Array.from(mockComponent._subscriptions);
|
|
182
|
+
expect(subscriptions.some((sub: any) => sub[0] === "navigate")).to.be
|
|
183
|
+
.false;
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe("ignoreRouter parameter", () => {
|
|
188
|
+
it("should skip router setup when ignoreRouter is true", () => {
|
|
189
|
+
return ensureSibRouterExists().then(() => {
|
|
190
|
+
return cy.document().then((doc) => {
|
|
191
|
+
const router = doc.createElement("solid-router");
|
|
192
|
+
router.setAttribute("currentRouteName", "test-route");
|
|
193
|
+
doc.body.appendChild(router);
|
|
194
|
+
|
|
195
|
+
const mockComponent = createMockComponent();
|
|
196
|
+
mockComponent.route = "/custom-route";
|
|
197
|
+
|
|
198
|
+
setupComponentSubscriptions({
|
|
199
|
+
component: mockComponent,
|
|
200
|
+
defaultRoute: false,
|
|
201
|
+
ignoreRouter: true,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
expect(mockComponent.noRouter).to.be.undefined;
|
|
205
|
+
expect(mockComponent.currentRoute).to.be.undefined;
|
|
206
|
+
expect(mockComponent.currentResource).to.be.undefined;
|
|
207
|
+
expect(mockComponent.route).to.equal("/custom-route");
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("should skip navigation listener when ignoreRouter is true", () => {
|
|
213
|
+
const mockComponent = createMockComponent();
|
|
214
|
+
|
|
215
|
+
setupComponentSubscriptions({
|
|
216
|
+
component: mockComponent,
|
|
217
|
+
defaultRoute: false,
|
|
218
|
+
ignoreRouter: true,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const subscriptions = Array.from(mockComponent._subscriptions);
|
|
222
|
+
expect(subscriptions.some((sub: any) => sub[0] === "navigate")).to.be
|
|
223
|
+
.false;
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("should not set defaultRoute when ignoreRouter is true", () => {
|
|
227
|
+
const mockComponent = createMockComponent();
|
|
228
|
+
|
|
229
|
+
setupComponentSubscriptions({
|
|
230
|
+
component: mockComponent,
|
|
231
|
+
defaultRoute: "/default",
|
|
232
|
+
ignoreRouter: true,
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
expect(mockComponent.route).to.not.equal("/default");
|
|
236
|
+
expect(mockComponent.uniq).to.be.a("string");
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import setupOnSaveReset from "@helpers/components/setupOnSaveReset";
|
|
2
|
+
|
|
3
|
+
describe("setupOnSaveReset helper function", () => {
|
|
4
|
+
const createMockComponent = () => {
|
|
5
|
+
const _subscriptions = new Set();
|
|
6
|
+
|
|
7
|
+
const mockComponent: any = {
|
|
8
|
+
_subscriptions,
|
|
9
|
+
_subscribe() {
|
|
10
|
+
for (const subscription of this._subscriptions) {
|
|
11
|
+
document.addEventListener(subscription[0], subscription[1]);
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
_unsubscribe() {
|
|
15
|
+
for (const subscription of this._subscriptions) {
|
|
16
|
+
document.removeEventListener(subscription[0], subscription[1]);
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
_setValue: cy.stub(),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return mockComponent;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
describe("Basic functionality", () => {
|
|
26
|
+
it("should set up save listener on component", () => {
|
|
27
|
+
const mockComponent = createMockComponent();
|
|
28
|
+
|
|
29
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
30
|
+
|
|
31
|
+
expect(mockComponent._subscriptions.size).to.be.greaterThan(0);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should subscribe to save event", () => {
|
|
35
|
+
const mockComponent = createMockComponent();
|
|
36
|
+
|
|
37
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
38
|
+
|
|
39
|
+
const subscriptions = Array.from(mockComponent._subscriptions);
|
|
40
|
+
expect(subscriptions.some((sub: any) => sub[0] === "save")).to.be.true;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should call _subscribe method", () => {
|
|
44
|
+
const mockComponent: any = {
|
|
45
|
+
_subscriptions: new Set(),
|
|
46
|
+
_subscribe: cy.stub(),
|
|
47
|
+
_setValue: cy.stub(),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
51
|
+
|
|
52
|
+
expect(mockComponent._subscribe).to.be.calledOnce;
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe("Keyword matching", () => {
|
|
57
|
+
it("should not call _setValue when keyword doesn't match", () => {
|
|
58
|
+
const mockComponent = createMockComponent();
|
|
59
|
+
|
|
60
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
61
|
+
|
|
62
|
+
const saveEvent = new CustomEvent("save", {
|
|
63
|
+
detail: { id: "https://example.com/nomatch/resource" },
|
|
64
|
+
});
|
|
65
|
+
document.dispatchEvent(saveEvent);
|
|
66
|
+
|
|
67
|
+
expect(mockComponent._setValue).to.not.be.called;
|
|
68
|
+
|
|
69
|
+
mockComponent._unsubscribe();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("should call _setValue when keyword matches at start", () => {
|
|
73
|
+
const mockComponent = createMockComponent();
|
|
74
|
+
|
|
75
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
76
|
+
|
|
77
|
+
const saveEvent = new CustomEvent("save", {
|
|
78
|
+
detail: { id: "https://test.com/resource" },
|
|
79
|
+
});
|
|
80
|
+
document.dispatchEvent(saveEvent);
|
|
81
|
+
|
|
82
|
+
expect(mockComponent._setValue).to.be.calledOnce;
|
|
83
|
+
|
|
84
|
+
mockComponent._unsubscribe();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should call _setValue when keyword matches after slash", () => {
|
|
88
|
+
const mockComponent = createMockComponent();
|
|
89
|
+
|
|
90
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
91
|
+
|
|
92
|
+
const saveEvent = new CustomEvent("save", {
|
|
93
|
+
detail: { id: "https://example.com/test/resource" },
|
|
94
|
+
});
|
|
95
|
+
document.dispatchEvent(saveEvent);
|
|
96
|
+
|
|
97
|
+
expect(mockComponent._setValue).to.be.calledOnce;
|
|
98
|
+
|
|
99
|
+
mockComponent._unsubscribe();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("should not match keyword in middle of path segment", () => {
|
|
103
|
+
const mockComponent = createMockComponent();
|
|
104
|
+
|
|
105
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
106
|
+
|
|
107
|
+
const saveEvent = new CustomEvent("save", {
|
|
108
|
+
detail: { id: "https://example.com/atestresource" },
|
|
109
|
+
});
|
|
110
|
+
document.dispatchEvent(saveEvent);
|
|
111
|
+
|
|
112
|
+
expect(mockComponent._setValue).to.not.be.called;
|
|
113
|
+
|
|
114
|
+
mockComponent._unsubscribe();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should match keyword in last segment", () => {
|
|
118
|
+
const mockComponent = createMockComponent();
|
|
119
|
+
|
|
120
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
121
|
+
|
|
122
|
+
const saveEvent = new CustomEvent("save", {
|
|
123
|
+
detail: { id: "https://example.com/path/test" },
|
|
124
|
+
});
|
|
125
|
+
document.dispatchEvent(saveEvent);
|
|
126
|
+
|
|
127
|
+
expect(mockComponent._setValue).to.be.calledOnce;
|
|
128
|
+
|
|
129
|
+
mockComponent._unsubscribe();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("should handle multiple keywords", () => {
|
|
133
|
+
const mockComponent = createMockComponent();
|
|
134
|
+
|
|
135
|
+
setupOnSaveReset(mockComponent, { keywords: ["test", "project", "user"] });
|
|
136
|
+
|
|
137
|
+
const saveEvent1 = new CustomEvent("save", {
|
|
138
|
+
detail: { id: "https://example.com/test/resource" },
|
|
139
|
+
});
|
|
140
|
+
document.dispatchEvent(saveEvent1);
|
|
141
|
+
|
|
142
|
+
const saveEvent2 = new CustomEvent("save", {
|
|
143
|
+
detail: { id: "https://example.com/user/profile" },
|
|
144
|
+
});
|
|
145
|
+
document.dispatchEvent(saveEvent2);
|
|
146
|
+
|
|
147
|
+
expect(mockComponent._setValue).to.be.calledTwice;
|
|
148
|
+
|
|
149
|
+
mockComponent._unsubscribe();
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("should support keyword with special characters", () => {
|
|
153
|
+
const mockComponent = createMockComponent();
|
|
154
|
+
|
|
155
|
+
setupOnSaveReset(mockComponent, { keywords: ["@type"] });
|
|
156
|
+
|
|
157
|
+
const saveEvent = new CustomEvent("save", {
|
|
158
|
+
detail: { id: "https://example.com/@type/resource" },
|
|
159
|
+
});
|
|
160
|
+
document.dispatchEvent(saveEvent);
|
|
161
|
+
|
|
162
|
+
expect(mockComponent._setValue).to.be.calledOnce;
|
|
163
|
+
|
|
164
|
+
mockComponent._unsubscribe();
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe("Event detail resource handling", () => {
|
|
169
|
+
it("should handle resource with @id property", () => {
|
|
170
|
+
const mockComponent = createMockComponent();
|
|
171
|
+
|
|
172
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
173
|
+
|
|
174
|
+
const saveEvent = new CustomEvent("save", {
|
|
175
|
+
detail: {
|
|
176
|
+
resource: { "@id": "https://example.com/test/resource" },
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
document.dispatchEvent(saveEvent);
|
|
180
|
+
|
|
181
|
+
expect(mockComponent._setValue).to.be.calledOnce;
|
|
182
|
+
|
|
183
|
+
mockComponent._unsubscribe();
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("should prioritize id over resource.@id", () => {
|
|
187
|
+
const mockComponent = createMockComponent();
|
|
188
|
+
|
|
189
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
190
|
+
|
|
191
|
+
const saveEvent = new CustomEvent("save", {
|
|
192
|
+
detail: {
|
|
193
|
+
id: "https://example.com/test/id",
|
|
194
|
+
resource: { "@id": "https://example.com/test/resource" },
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
document.dispatchEvent(saveEvent);
|
|
198
|
+
|
|
199
|
+
expect(mockComponent._setValue).to.be.calledOnce;
|
|
200
|
+
const setValueCall = mockComponent._setValue.getCall(0);
|
|
201
|
+
expect(setValueCall).to.exist;
|
|
202
|
+
|
|
203
|
+
mockComponent._unsubscribe();
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it("should not call _setValue when id is missing", () => {
|
|
207
|
+
const mockComponent = createMockComponent();
|
|
208
|
+
|
|
209
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
210
|
+
|
|
211
|
+
const saveEvent = new CustomEvent("save", {
|
|
212
|
+
detail: { resource: { name: "test" } },
|
|
213
|
+
});
|
|
214
|
+
document.dispatchEvent(saveEvent);
|
|
215
|
+
|
|
216
|
+
expect(mockComponent._setValue).to.not.be.called;
|
|
217
|
+
|
|
218
|
+
mockComponent._unsubscribe();
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
describe("_setValue call behavior", () => {
|
|
223
|
+
it("should call _setValue with empty value object", () => {
|
|
224
|
+
const mockComponent = createMockComponent();
|
|
225
|
+
|
|
226
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
227
|
+
|
|
228
|
+
const saveEvent = new CustomEvent("save", {
|
|
229
|
+
detail: { id: "https://example.com/test/resource" },
|
|
230
|
+
});
|
|
231
|
+
document.dispatchEvent(saveEvent);
|
|
232
|
+
|
|
233
|
+
expect(mockComponent._setValue).to.be.calledOnce;
|
|
234
|
+
const callArgs = mockComponent._setValue.getCall(0).args[0];
|
|
235
|
+
expect(callArgs).to.be.an("object");
|
|
236
|
+
expect(callArgs.target).to.be.an("object");
|
|
237
|
+
expect(callArgs.target.value).to.equal("");
|
|
238
|
+
|
|
239
|
+
mockComponent._unsubscribe();
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
describe("Empty keywords handling", () => {
|
|
244
|
+
it("should not set up listener when keywords array is empty", () => {
|
|
245
|
+
const mockComponent = createMockComponent();
|
|
246
|
+
|
|
247
|
+
setupOnSaveReset(mockComponent, { keywords: [] });
|
|
248
|
+
|
|
249
|
+
expect(mockComponent._subscriptions.size).to.equal(0);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it("should not set up listener when keywords is undefined", () => {
|
|
253
|
+
const mockComponent = createMockComponent();
|
|
254
|
+
|
|
255
|
+
setupOnSaveReset(mockComponent, {});
|
|
256
|
+
|
|
257
|
+
expect(mockComponent._subscriptions.size).to.equal(0);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
describe("Document ready state", () => {
|
|
262
|
+
it("should set up immediately when document is complete", () => {
|
|
263
|
+
const mockComponent: any = {
|
|
264
|
+
_subscriptions: new Set(),
|
|
265
|
+
_subscribe: cy.stub(),
|
|
266
|
+
_setValue: cy.stub(),
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
cy.document().then((doc) => {
|
|
270
|
+
const originalReadyState = Object.getOwnPropertyDescriptor(
|
|
271
|
+
Document.prototype,
|
|
272
|
+
"readyState",
|
|
273
|
+
);
|
|
274
|
+
Object.defineProperty(doc, "readyState", {
|
|
275
|
+
get: () => "complete",
|
|
276
|
+
configurable: true,
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
280
|
+
|
|
281
|
+
expect(mockComponent._subscribe).to.be.calledOnce;
|
|
282
|
+
|
|
283
|
+
if (originalReadyState) {
|
|
284
|
+
Object.defineProperty(doc, "readyState", originalReadyState);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
describe("Multiple save events", () => {
|
|
291
|
+
it("should handle multiple save events", () => {
|
|
292
|
+
const mockComponent = createMockComponent();
|
|
293
|
+
|
|
294
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
295
|
+
|
|
296
|
+
for (let i = 0; i < 5; i++) {
|
|
297
|
+
const saveEvent = new CustomEvent("save", {
|
|
298
|
+
detail: { id: `https://example.com/test/resource${i}` },
|
|
299
|
+
});
|
|
300
|
+
document.dispatchEvent(saveEvent);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
expect(mockComponent._setValue).to.have.callCount(5);
|
|
304
|
+
|
|
305
|
+
mockComponent._unsubscribe();
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
describe("Edge cases", () => {
|
|
310
|
+
it("should handle URL with no path", () => {
|
|
311
|
+
const mockComponent = createMockComponent();
|
|
312
|
+
|
|
313
|
+
setupOnSaveReset(mockComponent, { keywords: ["example.com"] });
|
|
314
|
+
|
|
315
|
+
const saveEvent = new CustomEvent("save", {
|
|
316
|
+
detail: { id: "https://example.com" },
|
|
317
|
+
});
|
|
318
|
+
document.dispatchEvent(saveEvent);
|
|
319
|
+
|
|
320
|
+
expect(mockComponent._setValue).to.be.calledOnce;
|
|
321
|
+
|
|
322
|
+
mockComponent._unsubscribe();
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it("should handle URL with multiple slashes", () => {
|
|
326
|
+
const mockComponent = createMockComponent();
|
|
327
|
+
|
|
328
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
329
|
+
|
|
330
|
+
const saveEvent = new CustomEvent("save", {
|
|
331
|
+
detail: { id: "https://example.com///test///resource" },
|
|
332
|
+
});
|
|
333
|
+
document.dispatchEvent(saveEvent);
|
|
334
|
+
|
|
335
|
+
expect(mockComponent._setValue).to.be.calledOnce;
|
|
336
|
+
|
|
337
|
+
mockComponent._unsubscribe();
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it("should handle duplicate keywords", () => {
|
|
341
|
+
const mockComponent = createMockComponent();
|
|
342
|
+
|
|
343
|
+
setupOnSaveReset(mockComponent, { keywords: ["test", "test", "test"] });
|
|
344
|
+
|
|
345
|
+
const saveEvent = new CustomEvent("save", {
|
|
346
|
+
detail: { id: "https://example.com/test/resource" },
|
|
347
|
+
});
|
|
348
|
+
document.dispatchEvent(saveEvent);
|
|
349
|
+
|
|
350
|
+
expect(mockComponent._setValue).to.be.calledOnce;
|
|
351
|
+
|
|
352
|
+
mockComponent._unsubscribe();
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
describe("Component property requirements", () => {
|
|
357
|
+
it("should require component to provide _subscriptions Set", () => {
|
|
358
|
+
const mockComponent: any = {
|
|
359
|
+
_subscriptions: new Set(),
|
|
360
|
+
_subscribe: cy.stub(),
|
|
361
|
+
_setValue: cy.stub(),
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
365
|
+
|
|
366
|
+
expect(mockComponent._subscriptions).to.be.an.instanceOf(Set);
|
|
367
|
+
expect(mockComponent._subscriptions.size).to.be.greaterThan(0);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it("should create saveListener property", () => {
|
|
371
|
+
const mockComponent = createMockComponent();
|
|
372
|
+
|
|
373
|
+
setupOnSaveReset(mockComponent, { keywords: ["test"] });
|
|
374
|
+
|
|
375
|
+
expect(mockComponent.saveListener).to.be.a("function");
|
|
376
|
+
|
|
377
|
+
mockComponent._unsubscribe();
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
});
|