|
| 1 | +import type { Dict, Owner } from '@glimmer/interfaces'; |
| 2 | + |
1 | 3 | import { castToBrowser } from '@glimmer/debug-util'; |
2 | 4 |
|
3 | 5 | import { GlimmerishComponent } from '../components/emberish-glimmer'; |
4 | 6 | import { RenderTest } from '../render-test'; |
5 | 7 | import { test } from '../test-decorator'; |
| 8 | +import { tracked } from '../test-helpers/tracked'; |
6 | 9 |
|
7 | 10 | export class ShadowDOMSuite extends RenderTest { |
8 | 11 | static suiteName = 'Shadow DOM'; |
@@ -169,6 +172,56 @@ export class ShadowDOMSuite extends RenderTest { |
169 | 172 | ); |
170 | 173 | } |
171 | 174 |
|
| 175 | + @test |
| 176 | + '<template shadowrootmode="open"> as component root re-renders via internal @tracked property (no rerender args)'() { |
| 177 | + let instance = this.capture<Counter>(); |
| 178 | + |
| 179 | + class Counter extends GlimmerishComponent { |
| 180 | + @tracked count = 0; |
| 181 | + |
| 182 | + constructor(owner: Owner, args: Dict) { |
| 183 | + super(owner, args); |
| 184 | + instance.capture(this); |
| 185 | + } |
| 186 | + } |
| 187 | + |
| 188 | + this.registerComponent( |
| 189 | + 'Glimmer', |
| 190 | + 'Counter', |
| 191 | + '<template shadowrootmode="open"><p>{{this.count}}</p></template>', |
| 192 | + Counter as any |
| 193 | + ); |
| 194 | + |
| 195 | + // No data is passed to render — the count is owned entirely by the component |
| 196 | + this.render('<div class="host"><Counter /></div>'); |
| 197 | + |
| 198 | + const rootEl = castToBrowser(this.element, 'HTML'); |
| 199 | + const host = rootEl.querySelector('.host') as HTMLElement | null; |
| 200 | + const shadowRootRef = host?.shadowRoot; |
| 201 | + |
| 202 | + this.assert.ok(shadowRootRef !== null, 'shadow root attached on first render'); |
| 203 | + this.assert.strictEqual( |
| 204 | + host?.shadowRoot?.querySelector('p')?.textContent, |
| 205 | + '0', |
| 206 | + 'initial count renders in shadow root' |
| 207 | + ); |
| 208 | + |
| 209 | + // Mutate the tracked property directly — no data passed to rerender |
| 210 | + instance.captured.count = 1; |
| 211 | + this.rerender(); |
| 212 | + |
| 213 | + this.assert.strictEqual( |
| 214 | + host?.shadowRoot?.querySelector('p')?.textContent, |
| 215 | + '1', |
| 216 | + 'count updated in shadow root after tracked mutation' |
| 217 | + ); |
| 218 | + this.assert.strictEqual( |
| 219 | + host?.shadowRoot, |
| 220 | + shadowRootRef, |
| 221 | + 'same shadow root instance reused (not recreated) after tracked mutation' |
| 222 | + ); |
| 223 | + } |
| 224 | + |
172 | 225 | @test |
173 | 226 | 'conditional <template shadowrootmode="open"> inside a host element attaches shadow root when rendered'() { |
174 | 227 | this.render( |
|
0 commit comments