Skip to content

Commit 0d737e4

Browse files
committed
Progress on rendering tests -- unit tests were too easy -- rendering tests require a lot of adapting, becasue we can't use @ember/test-helpers
1 parent d34c629 commit 0d737e4

File tree

5 files changed

+715
-0
lines changed

5 files changed

+715
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/* eslint-disable @typescript-eslint/no-this-alias */
2+
const test = QUnit.test;
3+
4+
function compareResults(assert, items) {
5+
findAll('.test-item').forEach((el, index) => {
6+
let key = Array.isArray(items[index]) ? items[index][0] : index;
7+
let value = Array.isArray(items[index]) ? items[index][1] : items[index];
8+
9+
assert.equal(el.innerText, `${key}.${value}`);
10+
});
11+
}
12+
13+
export function eachReactivityTest(desc, Klass) {
14+
test(`${desc} #each reactivity`, async function (assert) {
15+
let instance;
16+
17+
class TestComponent extends Klass {
18+
constructor() {
19+
super(...arguments);
20+
instance = this;
21+
}
22+
23+
get collection() {
24+
throw new Error('did you forget to specify a collection?');
25+
}
26+
}
27+
28+
setComponentTemplate(
29+
hbs`
30+
<ul>
31+
{{#each this.collection as |value index|}}
32+
<li class="test-item">{{index}}.{{value}}</li>
33+
{{/each}}
34+
</ul>
35+
`,
36+
TestComponent
37+
);
38+
this.owner.register('component:test-component', TestComponent);
39+
40+
await render(hbs`<TestComponent/>`);
41+
42+
compareResults(
43+
assert,
44+
Array.from(instance.collection).map((v, i) => [i, v])
45+
);
46+
47+
instance.update();
48+
49+
await settled();
50+
51+
compareResults(
52+
assert,
53+
Array.from(instance.collection).map((v, i) => [i, v])
54+
);
55+
});
56+
}
57+
58+
export function eachInReactivityTest(desc, Klass) {
59+
test(`${desc} #each-in reactivity`, async function (assert) {
60+
let instance;
61+
62+
class TestComponent extends Klass {
63+
constructor() {
64+
super(...arguments);
65+
instance = this;
66+
}
67+
68+
get collection() {
69+
throw new Error('did you forget to specify a collection?');
70+
}
71+
}
72+
73+
setComponentTemplate(
74+
hbs`
75+
<ul>
76+
{{#each-in this.collection as |lhs rhs|}}
77+
<li class="test-item">{{lhs}}.{{rhs}}</li>
78+
{{/each-in}}
79+
</ul>
80+
`,
81+
TestComponent
82+
);
83+
84+
this.owner.register('component:test-component', TestComponent);
85+
86+
await render(hbs`<TestComponent/>`);
87+
88+
let { collection } = instance;
89+
90+
compareResults(
91+
assert,
92+
Symbol.iterator in collection ? Array.from(collection) : Object.entries(collection)
93+
);
94+
95+
instance.update();
96+
97+
await settled();
98+
99+
compareResults(
100+
assert,
101+
Symbol.iterator in collection ? Array.from(collection) : Object.entries(collection)
102+
);
103+
});
104+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import type { RenderTest } from '@glimmer-workspace/integration-tests';
2+
import { defineComponent } from '@glimmer-workspace/integration-tests';
3+
4+
const assert = QUnit.assert;
5+
6+
export function reactivityTest(context: RenderTest, Klass: any, shouldUpdate = true) {
7+
let instance;
8+
let count = 0;
9+
10+
class TestComponent extends Klass {
11+
constructor(...args: unknown[]) {
12+
super(...args);
13+
// eslint-disable-next-line @typescript-eslint/no-this-alias
14+
instance = this;
15+
}
16+
17+
get value() {
18+
count++;
19+
20+
return super.value;
21+
}
22+
}
23+
24+
let comp = defineComponent({}, `<div class="test">{{this.value}}</div>`, {
25+
strictMode: true,
26+
definition: TestComponent,
27+
});
28+
29+
context.renderComponent(comp);
30+
31+
assert.equal(count, 1, 'The count is 1');
32+
33+
instance.update();
34+
35+
context.rerender();
36+
37+
assert.equal(
38+
count,
39+
shouldUpdate ? 2 : 1,
40+
shouldUpdate ? `The count is updated` : `The could should not update`
41+
);
42+
}
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
import { TrackedArray } from '@glimmer/validator';
2+
import {
3+
GlimmerishComponent as Component,
4+
jitSuite,
5+
RenderTest,
6+
test,
7+
} from '@glimmer-workspace/integration-tests';
8+
9+
import { reactivityTest } from '../-helpers/reactivity';
10+
11+
const ARRAY_GETTER_METHODS = [
12+
'concat',
13+
'entries',
14+
'every',
15+
'filter',
16+
'find',
17+
'findIndex',
18+
'flat',
19+
'flatMap',
20+
'forEach',
21+
'includes',
22+
'indexOf',
23+
'join',
24+
'keys',
25+
'lastIndexOf',
26+
'map',
27+
'reduce',
28+
'reduceRight',
29+
'slice',
30+
'some',
31+
'values',
32+
];
33+
34+
const ARRAY_SETTER_METHODS = [
35+
'copyWithin',
36+
'fill',
37+
'pop',
38+
'push',
39+
'reverse',
40+
'shift',
41+
'sort',
42+
'splice',
43+
'unshift',
44+
];
45+
46+
class TrackedArrayTest extends RenderTest {
47+
static suiteName = `TrackedArray (rendering)`;
48+
49+
@test
50+
'getting and setting an index'() {
51+
reactivityTest(
52+
this,
53+
class extends Component {
54+
arr = new TrackedArray(['foo']);
55+
56+
get value() {
57+
return this.arr[0];
58+
}
59+
60+
update() {
61+
this.arr[0] = 'bar';
62+
}
63+
}
64+
);
65+
}
66+
67+
@test
68+
'Can push into a newly created TrackedArray during construction'() {
69+
reactivityTest(
70+
this,
71+
class extends Component {
72+
arr = new TrackedArray<string>();
73+
74+
constructor(owner: Owner, args: object) {
75+
super(owner, args);
76+
this.arr.push('hello');
77+
}
78+
79+
get value() {
80+
return this.arr[0];
81+
}
82+
83+
update() {
84+
this.arr[0] = 'goodbye';
85+
}
86+
}
87+
);
88+
}
89+
90+
@test
91+
'Can unshift into a newly created TrackedArray during construction'() {
92+
reactivityTest(
93+
this,
94+
class extends Component {
95+
arr = new TrackedArray<string>();
96+
97+
constructor(owner: Owner, args: object) {
98+
super(owner, args);
99+
this.arr.unshift('hello');
100+
}
101+
102+
get value() {
103+
return this.arr[0];
104+
}
105+
106+
update() {
107+
this.arr[0] = 'goodbye';
108+
}
109+
}
110+
);
111+
}
112+
}
113+
114+
jitSuite(TrackedArrayTest);
115+
116+
// QUnit.module('reactivity', () => {
117+
// eachReactivityTest(
118+
// '{{each}} works with new items',
119+
// class extends Component {
120+
// collection = new TrackedArray([1, 2, 3]);
121+
//
122+
// update() {
123+
// this.collection.push(4);
124+
// }
125+
// }
126+
// );
127+
//
128+
// eachReactivityTest(
129+
// '{{each}} works when updating old items',
130+
// class extends Component {
131+
// collection = new TrackedArray([1, 2, 3]);
132+
//
133+
// update() {
134+
// this.collection[2] = 5;
135+
// }
136+
// }
137+
// );
138+
//
139+
// eachInReactivityTest(
140+
// '{{each-in}} works with new items',
141+
// class extends Component {
142+
// collection = new TrackedArray([1, 2, 3]);
143+
//
144+
// update() {
145+
// this.collection.push(4);
146+
// }
147+
// }
148+
// );
149+
//
150+
// eachInReactivityTest(
151+
// '{{each-in}} works when updating old items',
152+
// class extends Component {
153+
// collection = new TrackedArray([1, 2, 3]);
154+
//
155+
// update() {
156+
// this.collection[2] = 5;
157+
// }
158+
// }
159+
// );
160+
//
161+
// ARRAY_GETTER_METHODS.forEach((method) => {
162+
// reactivityTest(
163+
// `${method} individual index`,
164+
// class extends Component {
165+
// arr = new TrackedArray(['foo', 'bar']);
166+
//
167+
// get value() {
168+
// // @ts-ignore -- this can't be represented easily in TS, and we
169+
// // don't actually care that it is; we're *just* testing reactivity.
170+
// return this.arr[method](() => {
171+
// /* no op */
172+
// });
173+
// }
174+
//
175+
// update() {
176+
// this.arr[0] = 'bar';
177+
// }
178+
// }
179+
// );
180+
//
181+
// reactivityTest(
182+
// `${method} collection tag`,
183+
// class extends Component {
184+
// arr = new TrackedArray(['foo', 'bar']);
185+
//
186+
// get value() {
187+
// // @ts-ignore -- this can't be represented easily in TS, and we
188+
// // don't actually care that it is; we're *just* testing reactivity.
189+
// return this.arr[method](() => {
190+
// /* no op */
191+
// });
192+
// }
193+
//
194+
// update() {
195+
// this.arr.sort();
196+
// }
197+
// }
198+
// );
199+
// });
200+
//
201+
// ARRAY_SETTER_METHODS.forEach((method) => {
202+
// reactivityTest(
203+
// `${method} individual index`,
204+
// class extends Component {
205+
// arr = new TrackedArray(['foo', 'bar']);
206+
//
207+
// get value() {
208+
// return this.arr[0];
209+
// }
210+
//
211+
// update() {
212+
// // @ts-ignore -- this can't be represented easily in TS, and we
213+
// // don't actually care that it is; we're *just* testing reactivity.
214+
// this.arr[method](undefined);
215+
// }
216+
// }
217+
// );
218+
//
219+
// reactivityTest(
220+
// `${method} collection tag`,
221+
// class extends Component {
222+
// arr = new TrackedArray(['foo', 'bar']);
223+
//
224+
// get value() {
225+
// return void this.arr.forEach(() => {
226+
// /* no op */
227+
// });
228+
// }
229+
//
230+
// update() {
231+
// // @ts-ignore -- this can't be represented easily in TS, and we
232+
// // don't actually care that it is; we're *just* testing reactivity.
233+
// this.arr[method](undefined);
234+
// }
235+
// }
236+
// );
237+
// });
238+
// });

packages/@glimmer/validator/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"@glimmer-workspace/env": "workspace:*",
4343
"@glimmer/debug-util": "workspace:*",
4444
"eslint": "^9.20.1",
45+
"expect-type": "^1.1.0",
4546
"publint": "^0.3.2",
4647
"rollup": "^4.34.8",
4748
"typescript": "^5.7.3"

0 commit comments

Comments
 (0)