Skip to content

Commit 9870259

Browse files
refactor: address review feedback on in-element-shadow-root.ts and add document fragment suite
Co-authored-by: NullVoxPopuli <[email protected]>
1 parent 69f7254 commit 9870259

4 files changed

Lines changed: 168 additions & 86 deletions

File tree

packages/@glimmer-workspace/integration-tests/lib/suites.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export * from './suites/entry-point';
77
export * from './suites/has-block';
88
export * from './suites/has-block-params';
99
export * from './suites/in-element';
10+
export * from './suites/in-element-document-fragment';
1011
export * from './suites/in-element-shadow-root';
1112
export * from './suites/initial-render';
1213
export * from './suites/scope';
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import { RenderTest } from '../render-test';
2+
import { test } from '../test-decorator';
3+
4+
export class InElementDocumentFragmentSuite extends RenderTest {
5+
static suiteName = '#in-element (DocumentFragment)';
6+
7+
@test
8+
'Renders curlies into a detached DocumentFragment'() {
9+
const fragment = document.createDocumentFragment();
10+
11+
this.render('{{#in-element this.fragment}}[{{this.foo}}]{{/in-element}}', {
12+
fragment,
13+
foo: 'Hello Fragment!',
14+
});
15+
16+
this.assert.strictEqual(
17+
fragment.textContent,
18+
'[Hello Fragment!]',
19+
'content rendered in document fragment'
20+
);
21+
this.assertHTML('<!---->');
22+
this.assertStableRerender();
23+
24+
this.rerender({ foo: 'Updated!' });
25+
this.assert.strictEqual(
26+
fragment.textContent,
27+
'[Updated!]',
28+
'content updated in document fragment'
29+
);
30+
this.assertHTML('<!---->');
31+
32+
this.rerender({ foo: 'Hello Fragment!' });
33+
this.assert.strictEqual(
34+
fragment.textContent,
35+
'[Hello Fragment!]',
36+
'content reverted in document fragment'
37+
);
38+
this.assertHTML('<!---->');
39+
}
40+
41+
@test
42+
'Renders curlies into a template.content fragment'() {
43+
const templateEl = document.createElement('template');
44+
const fragment = templateEl.content;
45+
46+
this.render('{{#in-element this.fragment}}[{{this.foo}}]{{/in-element}}', {
47+
fragment,
48+
foo: 'Hello Template Content!',
49+
});
50+
51+
this.assert.strictEqual(
52+
fragment.textContent,
53+
'[Hello Template Content!]',
54+
'content rendered in template.content fragment'
55+
);
56+
this.assertHTML('<!---->');
57+
this.assertStableRerender();
58+
59+
this.rerender({ foo: 'Updated!' });
60+
this.assert.strictEqual(
61+
fragment.textContent,
62+
'[Updated!]',
63+
'content updated in template.content fragment'
64+
);
65+
this.assertHTML('<!---->');
66+
67+
this.rerender({ foo: 'Hello Template Content!' });
68+
this.assert.strictEqual(
69+
fragment.textContent,
70+
'[Hello Template Content!]',
71+
'content reverted in template.content fragment'
72+
);
73+
this.assertHTML('<!---->');
74+
}
75+
76+
@test
77+
'Renders elements into a fragment that is later attached to the DOM'() {
78+
const fragment = document.createDocumentFragment();
79+
const container = document.createElement('div');
80+
81+
this.render('{{#in-element this.fragment}}<p id="frag-p">{{this.message}}</p>{{/in-element}}', {
82+
fragment,
83+
message: 'in fragment',
84+
});
85+
86+
this.assert.strictEqual(
87+
fragment.querySelector('#frag-p')?.textContent,
88+
'in fragment',
89+
'content rendered in detached fragment'
90+
);
91+
this.assertHTML('<!---->');
92+
93+
// Attach fragment's children to the DOM
94+
container.appendChild(fragment);
95+
this.assert.strictEqual(
96+
container.querySelector('#frag-p')?.textContent,
97+
'in fragment',
98+
'content is in the DOM after fragment is appended'
99+
);
100+
// Fragment itself is now empty (children moved to container)
101+
this.assert.strictEqual(fragment.childNodes.length, 0, 'fragment is empty after append');
102+
}
103+
104+
@test
105+
'Multiple in-element calls to the same DocumentFragment'() {
106+
const fragment = document.createDocumentFragment();
107+
108+
this.render(
109+
'{{#in-element this.fragment}}[{{this.foo}}]{{/in-element}}' +
110+
'{{#in-element this.fragment insertBefore=null}}[{{this.bar}}]{{/in-element}}',
111+
{
112+
fragment,
113+
foo: 'first',
114+
bar: 'second',
115+
}
116+
);
117+
118+
this.assert.ok(fragment.textContent?.includes('[first]'), 'first block present in fragment');
119+
this.assert.ok(fragment.textContent?.includes('[second]'), 'second block present in fragment');
120+
this.assertHTML('<!----><!---->');
121+
this.assertStableRerender();
122+
123+
this.rerender({ foo: 'updated-first', bar: 'updated-second' });
124+
this.assert.ok(
125+
fragment.textContent?.includes('[updated-first]'),
126+
'first block updated in fragment'
127+
);
128+
this.assert.ok(
129+
fragment.textContent?.includes('[updated-second]'),
130+
'second block updated in fragment'
131+
);
132+
this.assertHTML('<!----><!---->');
133+
}
134+
135+
@test
136+
'Multiple in-element calls to the same DocumentFragment with insertBefore=null'() {
137+
const fragment = document.createDocumentFragment();
138+
139+
this.render(
140+
'{{#in-element this.fragment insertBefore=null}}<p id="a">{{this.foo}}</p>{{/in-element}}' +
141+
'{{#in-element this.fragment insertBefore=null}}<p id="b">{{this.bar}}</p>{{/in-element}}',
142+
{
143+
fragment,
144+
foo: 'first',
145+
bar: 'second',
146+
}
147+
);
148+
149+
// Use childNodes to query into the fragment since querySelector doesn't work on detached fragment nodes in all browsers
150+
const nodes = Array.from(fragment.childNodes);
151+
const pA = nodes.find((n) => (n as Element).id === 'a') as HTMLElement | undefined;
152+
const pB = nodes.find((n) => (n as Element).id === 'b') as HTMLElement | undefined;
153+
154+
this.assert.strictEqual(pA?.textContent, 'first', 'first block appended to fragment');
155+
this.assert.strictEqual(pB?.textContent, 'second', 'second block appended to fragment');
156+
this.assertHTML('<!----><!---->');
157+
this.assertStableRerender();
158+
159+
this.rerender({ foo: 'updated-first', bar: 'updated-second' });
160+
this.assert.strictEqual(pA?.textContent, 'updated-first', 'first block updated in fragment');
161+
this.assert.strictEqual(pB?.textContent, 'updated-second', 'second block updated in fragment');
162+
this.assertHTML('<!----><!---->');
163+
}
164+
}

packages/@glimmer-workspace/integration-tests/lib/suites/in-element-shadow-root.ts

Lines changed: 1 addition & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,12 @@
1-
import type { Owner } from '@glimmer/interfaces';
2-
import type { Dict } from '@glimmer/util';
3-
41
import { GlimmerishComponent } from '../components/emberish-glimmer';
52
import { RenderTest } from '../render-test';
63
import { test } from '../test-decorator';
7-
import { tracked } from '../test-helpers/tracked';
8-
9-
function hasShadowDom() {
10-
return typeof document !== 'undefined' && 'attachShadow' in document.createElement('div');
11-
}
124

135
export class InElementShadowRootSuite extends RenderTest {
146
static suiteName = '#in-element (ShadowRoot)';
157

168
@test
179
'Renders curlies into a ShadowRoot'() {
18-
if (!hasShadowDom()) {
19-
this.assert.ok(true, 'Shadow DOM not supported, skipping');
20-
return;
21-
}
22-
2310
const hostElement = document.createElement('div');
2411
const shadowRoot = hostElement.attachShadow({ mode: 'open' });
2512

@@ -49,64 +36,12 @@ export class InElementShadowRootSuite extends RenderTest {
4936
this.assertHTML('<!---->');
5037
}
5138

52-
@test
53-
'Renders curlies into a DocumentFragment'() {
54-
if (typeof document === 'undefined') {
55-
this.assert.ok(true, 'DOM not supported, skipping');
56-
return;
57-
}
58-
59-
const templateElement = document.createElement('template');
60-
const fragment = templateElement.content;
61-
62-
this.render('{{#in-element this.fragment}}[{{this.foo}}]{{/in-element}}', {
63-
fragment,
64-
foo: 'Hello Fragment!',
65-
});
66-
67-
this.assert.strictEqual(
68-
fragment.textContent,
69-
'[Hello Fragment!]',
70-
'content rendered in document fragment'
71-
);
72-
this.assertHTML('<!---->');
73-
this.assertStableRerender();
74-
75-
this.rerender({ foo: 'Updated Fragment!' });
76-
this.assert.strictEqual(
77-
fragment.textContent,
78-
'[Updated Fragment!]',
79-
'content updated in document fragment'
80-
);
81-
this.assertHTML('<!---->');
82-
83-
this.rerender({ foo: 'Hello Fragment!' });
84-
this.assert.strictEqual(
85-
fragment.textContent,
86-
'[Hello Fragment!]',
87-
'content reverted in fragment'
88-
);
89-
this.assertHTML('<!---->');
90-
}
91-
9239
@test
9340
'Class-based component with tracked property renders into shadow root without full DOM replacement on update'() {
94-
if (!hasShadowDom()) {
95-
this.assert.ok(true, 'Shadow DOM not supported, skipping');
96-
return;
97-
}
98-
9941
const hostElement = document.createElement('div');
10042
const shadowRoot = hostElement.attachShadow({ mode: 'open' });
10143

102-
class Counter extends GlimmerishComponent {
103-
@tracked count: number;
104-
105-
constructor(owner: Owner, args: Dict) {
106-
super(owner, args);
107-
this.count = (args['initial'] as number) ?? 0;
108-
}
109-
}
44+
class Counter extends GlimmerishComponent {}
11045

11146
this.registerComponent('Glimmer', 'Counter', '<p>Count: {{@count}}</p>', Counter as any);
11247

@@ -149,11 +84,6 @@ export class InElementShadowRootSuite extends RenderTest {
14984

15085
@test
15186
'Sibling components rendered into the same shadow root'() {
152-
if (!hasShadowDom()) {
153-
this.assert.ok(true, 'Shadow DOM not supported, skipping');
154-
return;
155-
}
156-
15787
const hostElement = document.createElement('div');
15888
const shadowRoot = hostElement.attachShadow({ mode: 'open' });
15989

@@ -199,11 +129,6 @@ export class InElementShadowRootSuite extends RenderTest {
199129

200130
@test
201131
'Sibling shadow roots each receive their own component'() {
202-
if (!hasShadowDom()) {
203-
this.assert.ok(true, 'Shadow DOM not supported, skipping');
204-
return;
205-
}
206-
207132
const host1 = document.createElement('div');
208133
const shadow1 = host1.attachShadow({ mode: 'open' });
209134
const host2 = document.createElement('div');
@@ -251,11 +176,6 @@ export class InElementShadowRootSuite extends RenderTest {
251176

252177
@test
253178
'Multiple in-element calls to the same shadow root'() {
254-
if (!hasShadowDom()) {
255-
this.assert.ok(true, 'Shadow DOM not supported, skipping');
256-
return;
257-
}
258-
259179
const hostElement = document.createElement('div');
260180
const shadowRoot = hostElement.attachShadow({ mode: 'open' });
261181

@@ -293,11 +213,6 @@ export class InElementShadowRootSuite extends RenderTest {
293213

294214
@test
295215
'Multiple in-element calls to the same shadow root with insertBefore=null'() {
296-
if (!hasShadowDom()) {
297-
this.assert.ok(true, 'Shadow DOM not supported, skipping');
298-
return;
299-
}
300-
301216
const hostElement = document.createElement('div');
302217
const shadowRoot = hostElement.attachShadow({ mode: 'open' });
303218

packages/@glimmer-workspace/integration-tests/test/jit-suites-test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
GlimmerishComponents,
66
HasBlockParamsHelperSuite,
77
HasBlockSuite,
8+
InElementDocumentFragmentSuite,
89
InElementShadowRootSuite,
910
InElementSuite,
1011
jitComponentSuite,
@@ -20,6 +21,7 @@ import {
2021
jitComponentSuite(DebuggerSuite);
2122
jitSuite(EachSuite);
2223
jitSuite(InElementSuite);
24+
jitSuite(InElementDocumentFragmentSuite);
2325
jitSuite(InElementShadowRootSuite);
2426
jitSuite(ShadowDOMSuite);
2527

0 commit comments

Comments
 (0)