Skip to content

Commit 6d98f4e

Browse files
committed
Convert config/CircularDependencies.mjs Test from Siesta to Playwright #7275
1 parent 0294c93 commit 6d98f4e

3 files changed

Lines changed: 181 additions & 3 deletions

File tree

.github/ISSUE/epic-enhance-workflow-with-mandatory-unit-testing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ The primary goal is to prevent regressions, especially in the complex core modul
7676
- **Done:** ticket-convert-collectionbase-test.md
7777
- **Done:** ticket-convert-config-aftersetconfig-test.md
7878
- **Done:** ticket-convert-config-basic-test.md
79-
- **To Do:** ticket-convert-config-circulardependencies-test.md
79+
- **Done:** ticket-convert-config-circulardependencies-test.md
8080
- **To Do:** ticket-convert-config-customfunctions-test.md
8181
- **To Do:** ticket-convert-config-hierarchy-test.md
8282
- **To Do:** ticket-convert-config-memoryleak-test.md

.github/ISSUE/ticket-convert-config-circulardependencies-test.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
GH ticket id: #7275
44

5-
**Assignee:**
6-
**Status:** To Do
5+
**Assignee:** Gemini
6+
**Status:** Done
77

88
**Parent Epic:** epic-enhance-workflow-with-mandatory-unit-testing.md
99

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import { setup } from '../../setup.mjs';
2+
3+
setup();
4+
5+
import { test, expect } from '@playwright/test';
6+
7+
import Neo from '../../../../src/Neo.mjs';
8+
import Base from '../../../../src/core/Base.mjs';
9+
10+
class TestComponent extends Base {
11+
static config = {
12+
className : 'Neo.Test.CircularDependenciesComponent',
13+
configA_ : 'initialA',
14+
configB_ : 'initialB',
15+
configC_ : 'initialC',
16+
nonReactive: 'initialNonReactive'
17+
}
18+
19+
classField = 'initialClassField';
20+
21+
_customProp = 'initialCustomProp'; // Private backing field for customProp
22+
23+
// Custom getter/setter for a property not defined in static config
24+
get customProp() {
25+
return this._customProp;
26+
}
27+
set customProp(value) {
28+
this._customProp = value;
29+
30+
// Simulate interaction with other properties
31+
this.customPropSetLog.push({
32+
value,
33+
currentConfigA : this.configA,
34+
currentNonReactive: this.nonReactive,
35+
currentClassField : this.classField
36+
});
37+
}
38+
39+
// To record the state inside afterSet hooks and customProp setter
40+
afterSetLogs = {
41+
configA: [],
42+
configB: [],
43+
configC: []
44+
};
45+
customPropSetLog = [];
46+
47+
afterSetConfigA(newValue, oldValue) {
48+
this.afterSetLogs.configA.push({
49+
newValue,
50+
oldValue,
51+
currentConfigB : this.configB,
52+
currentConfigC : this.configC,
53+
currentClassField : this.classField,
54+
currentNonReactive: this.nonReactive,
55+
currentCustomProp : this.customProp
56+
});
57+
}
58+
59+
afterSetConfigB(newValue, oldValue) {
60+
this.afterSetLogs.configB.push({
61+
newValue,
62+
oldValue,
63+
currentConfigA : this.configA,
64+
currentConfigC : this.configC,
65+
currentClassField : this.classField,
66+
currentNonReactive: this.nonReactive,
67+
currentCustomProp : this.customProp
68+
});
69+
}
70+
71+
afterSetConfigC(newValue, oldValue) {
72+
this.afterSetLogs.configC.push({
73+
newValue,
74+
oldValue,
75+
currentConfigA : this.configA,
76+
currentConfigB : this.configB,
77+
currentClassField : this.classField,
78+
currentNonReactive: this.nonReactive,
79+
currentCustomProp : this.customProp
80+
});
81+
}
82+
}
83+
TestComponent = Neo.setupClass(TestComponent);
84+
85+
/**
86+
* @summary Tests for circular dependencies in Neo.core.Base configs
87+
* This suite tests that afterSet hooks for configs see the latest values of other configs and fields
88+
* that are being updated in the same set() operation. This is a test for the correct batching
89+
* and ordering of config applications.
90+
*/
91+
test.describe('Neo.core.Base#configs-circular-dependencies', () => {
92+
test('afterSet hooks should see latest values of other configs and fields during simultaneous update', () => {
93+
const instance = Neo.create(TestComponent);
94+
instance.afterSetLogs = { configA: [], configB: [], configC: [] }; // Clear logs from initial config processing
95+
instance.customPropSetLog = []; // Clear customProp logs
96+
97+
instance.set({
98+
configA : 'newA',
99+
configB : 'newB',
100+
configC : 'newC',
101+
nonReactive: 'newNonReactive',
102+
classField : 'newClassField',
103+
customProp : 'newCustomProp'
104+
});
105+
106+
// Verify afterSetConfigA log
107+
expect(instance.afterSetLogs.configA.length).toBe(1);
108+
const logA = instance.afterSetLogs.configA[0];
109+
expect(logA.newValue).toBe('newA');
110+
expect(logA.oldValue).toBe('initialA');
111+
expect(logA.currentConfigB).toBe('newB');
112+
expect(logA.currentConfigC).toBe('newC');
113+
expect(logA.currentClassField).toBe('newClassField');
114+
expect(logA.currentNonReactive).toBe('newNonReactive');
115+
expect(logA.currentCustomProp).toBe('newCustomProp');
116+
117+
// Verify afterSetConfigB log
118+
expect(instance.afterSetLogs.configB.length).toBe(1);
119+
const logB = instance.afterSetLogs.configB[0];
120+
expect(logB.newValue).toBe('newB');
121+
expect(logB.oldValue).toBe('initialB');
122+
expect(logB.currentConfigA).toBe('newA');
123+
expect(logB.currentConfigC).toBe('newC');
124+
expect(logB.currentClassField).toBe('newClassField');
125+
expect(logB.currentNonReactive).toBe('newNonReactive');
126+
expect(logB.currentCustomProp).toBe('newCustomProp');
127+
128+
// Verify afterSetConfigC log
129+
expect(instance.afterSetLogs.configC.length).toBe(1);
130+
const logC = instance.afterSetLogs.configC[0];
131+
expect(logC.newValue).toBe('newC');
132+
expect(logC.oldValue).toBe('initialC');
133+
expect(logC.currentConfigA).toBe('newA');
134+
expect(logC.currentConfigB).toBe('newB');
135+
expect(logC.currentClassField).toBe('newClassField');
136+
expect(logC.currentNonReactive).toBe('newNonReactive');
137+
expect(logC.currentCustomProp).toBe('newCustomProp');
138+
139+
// Verify customProp setter log
140+
expect(instance.customPropSetLog.length).toBe(1);
141+
const customPropLog = instance.customPropSetLog[0];
142+
expect(customPropLog.value).toBe('newCustomProp');
143+
expect(customPropLog.currentConfigA).toBe('newA');
144+
expect(customPropLog.currentNonReactive).toBe('newNonReactive');
145+
expect(customPropLog.currentClassField).toBe('newClassField');
146+
});
147+
148+
test('afterSet hooks should see existing values if not part of current set() operation', () => {
149+
const instance = Neo.create(TestComponent, {
150+
configA : 'preSetA',
151+
configB : 'preSetB',
152+
configC : 'preSetC',
153+
nonReactive: 'preSetNonReactive',
154+
classField : 'preSetClassField',
155+
customProp : 'preSetCustomProp'
156+
});
157+
instance.afterSetLogs = { configA: [], configB: [], configC: [] }; // Reset logs
158+
instance.customPropSetLog = []; // Reset customProp logs
159+
160+
instance.set({
161+
configA: 'newAOnly'
162+
});
163+
164+
expect(instance.afterSetLogs.configA.length).toBe(1);
165+
const logA = instance.afterSetLogs.configA[0];
166+
expect(logA.newValue).toBe('newAOnly');
167+
expect(logA.oldValue).toBe('preSetA');
168+
expect(logA.currentConfigB).toBe('preSetB');
169+
expect(logA.currentConfigC).toBe('preSetC');
170+
expect(logA.currentClassField).toBe('preSetClassField');
171+
expect(logA.currentNonReactive).toBe('preSetNonReactive');
172+
expect(logA.currentCustomProp).toBe('preSetCustomProp');
173+
174+
expect(instance.afterSetLogs.configB.length).toBe(0);
175+
expect(instance.afterSetLogs.configC.length).toBe(0);
176+
expect(instance.customPropSetLog.length).toBe(0);
177+
});
178+
});

0 commit comments

Comments
 (0)