Skip to content

Commit b0fcb47

Browse files
fix: remove dead @Tracked property from Counter; add round-trip test for existingShadowRoot path
Agent-Logs-Url: https://github.com/emberjs/ember.js/sessions/423b5a29-b3fe-40d7-b47f-bf00050510c5 Co-authored-by: NullVoxPopuli <[email protected]>
1 parent 05dbbb1 commit b0fcb47

1 file changed

Lines changed: 43 additions & 4 deletions

File tree

  • packages/@glimmer-workspace/integration-tests/lib/suites

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

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { castToBrowser } from '@glimmer/debug-util';
33
import { GlimmerishComponent } from '../components/emberish-glimmer';
44
import { RenderTest } from '../render-test';
55
import { test } from '../test-decorator';
6-
import { tracked } from '../test-helpers/tracked';
76

87
export class ShadowDOMSuite extends RenderTest {
98
static suiteName = 'Shadow DOM';
@@ -132,9 +131,7 @@ export class ShadowDOMSuite extends RenderTest {
132131

133132
@test
134133
'<template shadowrootmode="open"> as component root with tracked state re-renders into same shadow root'() {
135-
class Counter extends GlimmerishComponent {
136-
@tracked count = 0;
137-
}
134+
class Counter extends GlimmerishComponent {}
138135

139136
this.registerComponent(
140137
'Glimmer',
@@ -201,4 +198,46 @@ export class ShadowDOMSuite extends RenderTest {
201198
'regular content renders in host after switching from shadow branch'
202199
);
203200
}
201+
202+
@test
203+
'conditional <template shadowrootmode="open"> re-enables shadow root on toggle back (exercises existingShadowRoot path)'() {
204+
// When a declarative shadow root block is torn down and re-created on the same
205+
// host element, VM_ATTACH_SHADOW_ROOT_OP encounters rawParent.shadowRoot !== null
206+
// (shadow roots cannot be removed from a host). The existingShadowRoot branch in
207+
// the opcode clears and reuses the existing shadow root so that attachShadow() is
208+
// not called again (which would throw DOMException).
209+
this.render(
210+
'<div class="host">{{#if this.useShadow}}<template shadowrootmode="open"><p>{{this.msg}}</p></template>{{else}}<span>off</span>{{/if}}</div>',
211+
{ useShadow: true, msg: 'first' }
212+
);
213+
214+
const rootEl = castToBrowser(this.element, 'HTML');
215+
const host = rootEl.querySelector('.host') as HTMLElement | null;
216+
const initialShadowRoot = host?.shadowRoot;
217+
218+
this.assert.ok(initialShadowRoot !== null, 'shadow root attached on first render');
219+
this.assert.strictEqual(
220+
host?.shadowRoot?.querySelector('p')?.textContent,
221+
'first',
222+
'initial shadow content correct'
223+
);
224+
225+
// Tear down the shadow DOM block — shadow root stays on the host (platform behavior)
226+
this.rerender({ useShadow: false, msg: 'first' });
227+
this.assert.ok(host?.querySelector('span') !== null, 'else branch rendered');
228+
229+
// Re-enable shadow DOM — VM_ATTACH_SHADOW_ROOT_OP hits the existingShadowRoot path
230+
this.rerender({ useShadow: true, msg: 'second' });
231+
this.assert.ok(host?.shadowRoot !== null, 'shadow root still attached after re-enable');
232+
this.assert.strictEqual(
233+
host?.shadowRoot,
234+
initialShadowRoot,
235+
'same shadow root instance reused (not recreated)'
236+
);
237+
this.assert.strictEqual(
238+
host?.shadowRoot?.querySelector('p')?.textContent,
239+
'second',
240+
'shadow content updated correctly after re-enable'
241+
);
242+
}
204243
}

0 commit comments

Comments
 (0)