From 379a7ca59f8a432c06efbd6da8af038dc4a23874 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Sat, 3 Oct 2026 16:51:03 -0400 Subject: [PATCH] Wait with renderSettled in the renderComponent tests, not run() The renderComponent tests wrapped each render, update and destroy in `run(() => ...)`. The tests now call the API directly and wait with `await renderSettled()`, as an application does. - `renderComponent()` renders synchronously. The test helper asserts the HTML immediately after the call, with no wait. - Each tracked update and each destroy is followed by `await renderSettled()`. - `AbstractStrictTestCase` no longer uses `runTask` and `runDestroy`. Only this test file extends that class. No test was added, removed or renamed. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../components/render-component-test.ts | 379 +++++++++--------- .../lib/test-cases/abstract.ts | 15 +- 2 files changed, 207 insertions(+), 187 deletions(-) diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/render-component-test.ts b/packages/@ember/-internals/glimmer/tests/integration/components/render-component-test.ts index 0ffbd17155b..95679af45be 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/components/render-component-test.ts +++ b/packages/@ember/-internals/glimmer/tests/integration/components/render-component-test.ts @@ -8,7 +8,6 @@ import { defineSimpleModifier, moduleFor, type ClassicComponentShape, - runDestroy, } from 'internal-test-helpers'; import { Input, Textarea } from '@ember/component'; @@ -20,9 +19,8 @@ import templateOnly from '@ember/component/template-only'; import { array, concat, fn, get, hash, on } from '@glimmer/runtime'; import GlimmerishComponent from '../../utils/glimmerish-component'; -import { run } from '@ember/runloop'; import { destroy, associateDestroyableChild, registerDestructor } from '@glimmer/destroyable'; -import { renderComponent, type RenderResult } from '../../../lib/renderer'; +import { renderComponent, renderSettled, type RenderResult } from '../../../lib/renderer'; import { renderers } from '../../../lib/renderers'; import { trackedObject } from '@ember/reactive/collections'; import { cached, tracked } from '@glimmer/tracking'; @@ -47,35 +45,34 @@ class RenderComponentTestCase extends AbstractStrictTestCase { return document.querySelector('#qunit-fixture')!; } - assertChange({ change, expect }: { change: () => void; expect: string }) { - run(() => change()); + async assertChange({ change, expect }: { change: () => void; expect: string }) { + change(); + await renderSettled(); assertHTML(expect); - this.assertStableRerender(); + await this.assertStableRerender(); } - renderComponent( + async renderComponent( component: object, options: { args?: Record; expect: string } | { classic: ClassicComponentShape } ) { let { owner } = this; - run(() => { - const result = renderComponent(component, { - owner, - args: 'args' in options ? options.args : {}, - env: { document: document, isInteractive: true, hasDOM: true }, - into: this.element, - }); - this.component = { - ...result, - rerender() { - // unused, but asserted against - }, - }; - registerDestructor(this, () => result.destroy()); + const result = renderComponent(component, { + owner, + args: 'args' in options ? options.args : {}, + env: { document: document, isInteractive: true, hasDOM: true }, + into: this.element, }); + this.component = { + ...result, + rerender() { + // unused, but asserted against + }, + }; + registerDestructor(this, () => result.destroy()); if ('expect' in options) { assertHTML(options.expect); @@ -83,62 +80,67 @@ class RenderComponentTestCase extends AbstractStrictTestCase { assertClassicComponentElement(options.classic); } - this.assertStableRerender(); + await this.assertStableRerender(); } } moduleFor( 'Strict Mode - RenderComponentTestCase', class extends RenderComponentTestCase { - afterEach() { + async afterEach() { if (this.component) { - runDestroy(this); + destroy(this); + await renderSettled(); } } - '@test destroy cleans up dom via destrying the test context'() { + async '@test destroy cleans up dom via destrying the test context'() { let Foo = setComponentTemplate(precompileTemplate('Hello, world!'), templateOnly()); let Root = setComponentTemplate( precompileTemplate('', { strictMode: true, scope: () => ({ Foo }) }), templateOnly() ); - this.renderComponent(Root, { expect: 'Hello, world!' }); + await this.renderComponent(Root, { expect: 'Hello, world!' }); - run(() => destroy(this)); + destroy(this); + await renderSettled(); assertHTML(''); } - '@test destroy of the owner cleans up dom via destrying the test context'() { + async '@test destroy of the owner cleans up dom via destrying the test context'() { let Foo = setComponentTemplate(precompileTemplate('Hello, world!'), templateOnly()); let Root = setComponentTemplate( precompileTemplate('', { strictMode: true, scope: () => ({ Foo }) }), templateOnly() ); - this.renderComponent(Root, { expect: 'Hello, world!' }); + await this.renderComponent(Root, { expect: 'Hello, world!' }); - run(() => destroy(this.owner)); + destroy(this.owner); + await renderSettled(); assertHTML(''); } - '@test captureRenderTree includes the rendered components'(assert: QUnit['assert']) { + async '@test captureRenderTree includes the rendered components'(assert: QUnit['assert']) { let HelloWorld = setComponentTemplate(precompileTemplate('Hello, world!'), templateOnly()); let Root = setComponentTemplate( precompileTemplate('', { strictMode: true, scope: () => ({ HelloWorld }) }), templateOnly() ); - this.renderComponent(Root, { expect: 'Hello, world!' }); + await this.renderComponent(Root, { expect: 'Hello, world!' }); if (!ENV._DEBUG_RENDER_TREE) return; assert.deepEqual(renderTreeNames(this.owner), ['{ROOT}', 'HelloWorld']); } - '@test captureRenderTree includes components rendered with any owner'(assert: QUnit['assert']) { + async '@test captureRenderTree includes components rendered with any owner'( + assert: QUnit['assert'] + ) { let Owned = setComponentTemplate(precompileTemplate('owned'), templateOnly()); let Ownerless = setComponentTemplate(precompileTemplate('ownerless'), templateOnly()); let OwnedRoot = setComponentTemplate( @@ -154,10 +156,10 @@ moduleFor( let ownerlessElement = document.createElement('div'); this.element.append(ownedElement, ownerlessElement); - let results = run(() => [ + let results = [ renderComponent(OwnedRoot, { owner: this.owner, into: ownedElement }), renderComponent(OwnerlessRoot, { into: ownerlessElement }), - ]); + ]; assertHTML('
owned
ownerless
'); @@ -165,17 +167,17 @@ moduleFor( assert.deepEqual(renderTreeNames(this.owner), ['{ROOT}', 'Owned', '{ROOT}', 'Ownerless']); } - run(() => { - for (let result of results) { - result.destroy(); - } - }); + for (let result of results) { + result.destroy(); + } + await renderSettled(); if (ENV._DEBUG_RENDER_TREE) { assert.deepEqual(renderTreeNames(this.owner), [], 'destroyed renders are gone'); } - run(() => destroy(this)); + destroy(this); + await renderSettled(); } } ); @@ -199,62 +201,59 @@ moduleFor( return document.querySelector('#qunit-fixture')!; } - '@test manually calling destroy cleans up the DOM'() { + async '@test manually calling destroy cleans up the DOM'() { let Foo = setComponentTemplate(precompileTemplate('Hello, world!'), templateOnly()); let owner = buildOwner({}); - let manualDestroy: () => void; - run(() => { - let result = renderComponent(Foo, { - owner, - into: this.element, - }); - manualDestroy = result.destroy; - this.component = { - ...result, - rerender() { - // unused, but asserted against - }, - }; + let result = renderComponent(Foo, { + owner, + into: this.element, }); + this.component = { + ...result, + rerender() { + // unused, but asserted against + }, + }; assertHTML('Hello, world!'); - this.assertStableRerender(); + await this.assertStableRerender(); - run(() => manualDestroy()); + result.destroy(); + await renderSettled(); assertHTML(''); - this.assertStableRerender(); + await this.assertStableRerender(); - run(() => destroy(owner)); + destroy(owner); + await renderSettled(); } - '@test destroying the owner cleans up the DOM'() { + async '@test destroying the owner cleans up the DOM'() { let Foo = setComponentTemplate(precompileTemplate('Hello, world!'), templateOnly()); let owner = buildOwner({}); - run(() => { - let result = renderComponent(Foo, { - owner, - into: this.element, - }); - this.component = { - ...result, - rerender() { - // unused, but asserted against - }, - }; + let result = renderComponent(Foo, { + owner, + into: this.element, }); + this.component = { + ...result, + rerender() { + // unused, but asserted against + }, + }; assertHTML('Hello, world!'); - this.assertStableRerender(); + await this.assertStableRerender(); - run(() => destroy(owner)); + destroy(owner); + await renderSettled(); assertHTML(''); - this.assertStableRerender(); + await this.assertStableRerender(); } } ); @@ -262,75 +261,77 @@ moduleFor( moduleFor( 'Strict Mode - renderComponent', class extends RenderComponentTestCase { - afterEach() { + async afterEach() { if (this.component) { - runDestroy(this); + destroy(this); + await renderSettled(); } } - '@test destroy cleans up dom via destroying the owner'() { + async '@test destroy cleans up dom via destroying the owner'() { let Foo = setComponentTemplate(precompileTemplate('Hello, world!'), templateOnly()); let Root = setComponentTemplate( precompileTemplate('', { strictMode: true, scope: () => ({ Foo }) }), templateOnly() ); - this.renderComponent(Root, { expect: 'Hello, world!' }); + await this.renderComponent(Root, { expect: 'Hello, world!' }); - run(() => destroy(this.owner)); + destroy(this.owner); + await renderSettled(); assertHTML(''); } - '@test Can use a component in scope'() { + async '@test Can use a component in scope'() { let Foo = setComponentTemplate(precompileTemplate('Hello, world!'), templateOnly()); let Root = setComponentTemplate( precompileTemplate('', { strictMode: true, scope: () => ({ Foo }) }), templateOnly() ); - this.renderComponent(Root, { expect: 'Hello, world!' }); + await this.renderComponent(Root, { expect: 'Hello, world!' }); } - '@test Can use a custom helper in scope (in append position)'() { + async '@test Can use a custom helper in scope (in append position)'() { let foo = defineSimpleHelper(() => 'Hello, world!'); let Root = setComponentTemplate( precompileTemplate('{{foo}}', { strictMode: true, scope: () => ({ foo }) }), templateOnly() ); - this.renderComponent(Root, { expect: 'Hello, world!' }); + await this.renderComponent(Root, { expect: 'Hello, world!' }); } - '@test Can use a custom modifier in scope'() { + async '@test Can use a custom modifier in scope'() { let foo = defineSimpleModifier((element) => (element.innerHTML = 'Hello, world!')); let Root = setComponentTemplate( precompileTemplate('
', { strictMode: true, scope: () => ({ foo }) }), templateOnly() ); - this.renderComponent(Root, { expect: '
Hello, world!
' }); + await this.renderComponent(Root, { expect: '
Hello, world!
' }); } - '@test Can shadow keywords (runtime)'() { + async '@test Can shadow keywords (runtime)'() { let each = setComponentTemplate(precompileTemplate('Hello, world!'), templateOnly()); let Bar = template('{{#each}}{{/each}}', { scope: () => ({ each }), }); - this.renderComponent(Bar, { expect: 'Hello, world!' }); + await this.renderComponent(Bar, { expect: 'Hello, world!' }); } - '@test Can shadow keywords (compile-time)'() { + async '@test Can shadow keywords (compile-time)'() { let each = setComponentTemplate(precompileTemplate('Hello, world!'), templateOnly()); let Bar = compileTimeTemplate('{{#each}}{{/each}}', { scope: () => ({ each }), }); - this.renderComponent(Bar, { expect: 'Hello, world!' }); + await this.renderComponent(Bar, { expect: 'Hello, world!' }); } - '@test Can use constant values in ambiguous helper/component position'() { + async '@test Can use constant values in ambiguous helper/component position'() { let value = 'Hello, world!'; let Root = setComponentTemplate( @@ -338,19 +339,19 @@ moduleFor( templateOnly() ); - this.renderComponent(Root, { expect: 'Hello, world!' }); + await this.renderComponent(Root, { expect: 'Hello, world!' }); } - '@test Can use inline if and unless in strict mode templates'() { + async '@test Can use inline if and unless in strict mode templates'() { let Root = setComponentTemplate( precompileTemplate('{{if true "foo" "bar"}}{{unless true "foo" "bar"}}'), templateOnly() ); - this.renderComponent(Root, { expect: 'foobar' }); + await this.renderComponent(Root, { expect: 'foobar' }); } - '@test multiple components have independent lifetimes'() { + async '@test multiple components have independent lifetimes'() { class State { @tracked showSecond = true; } @@ -364,15 +365,15 @@ moduleFor( templateOnly() ); - this.renderComponent(Root, { expect: 'Hello, world!Hello, world!' }); + await this.renderComponent(Root, { expect: 'Hello, world!Hello, world!' }); - this.assertChange({ + await this.assertChange({ change: () => (state.showSecond = false), expect: 'Hello, world!', }); } - '@test Can use a dynamic component definition'() { + async '@test Can use a dynamic component definition'() { let Foo = setComponentTemplate(precompileTemplate('Hello, world!'), templateOnly()); let Root = setComponentTemplate( precompileTemplate(''), @@ -381,10 +382,10 @@ moduleFor( } ); - this.renderComponent(Root, { expect: 'Hello, world!' }); + await this.renderComponent(Root, { expect: 'Hello, world!' }); } - '@test Can use a dynamic component definition (curly)'() { + async '@test Can use a dynamic component definition (curly)'() { let Foo = setComponentTemplate(precompileTemplate('Hello, world!'), templateOnly()); let Root = setComponentTemplate( precompileTemplate('{{this.Foo}}'), @@ -393,10 +394,10 @@ moduleFor( } ); - this.renderComponent(Root, { expect: 'Hello, world!' }); + await this.renderComponent(Root, { expect: 'Hello, world!' }); } - '@test Can use a dynamic helper definition'() { + async '@test Can use a dynamic helper definition'() { let foo = defineSimpleHelper(() => 'Hello, world!'); let Root = setComponentTemplate( precompileTemplate('{{this.foo}}'), @@ -405,10 +406,10 @@ moduleFor( } ); - this.renderComponent(Root, { expect: 'Hello, world!' }); + await this.renderComponent(Root, { expect: 'Hello, world!' }); } - '@test Can use a curried dynamic helper'() { + async '@test Can use a curried dynamic helper'() { let foo = defineSimpleHelper((value) => value); let Foo = setComponentTemplate(precompileTemplate('{{@value}}'), templateOnly()); let Root = setComponentTemplate( @@ -419,10 +420,10 @@ moduleFor( templateOnly() ); - this.renderComponent(Root, { expect: 'Hello, world!' }); + await this.renderComponent(Root, { expect: 'Hello, world!' }); } - '@test Can use a curried dynamic modifier'() { + async '@test Can use a curried dynamic modifier'() { let foo = defineSimpleModifier((element, [text]) => (element.innerHTML = text)); let Foo = setComponentTemplate(precompileTemplate('
'), templateOnly()); let Root = setComponentTemplate( @@ -433,22 +434,22 @@ moduleFor( templateOnly() ); - this.renderComponent(Root, { expect: '
Hello, world!
' }); + await this.renderComponent(Root, { expect: '
Hello, world!
' }); } - '@test when args are trackedObject, the rendered component response appropriately'() { + async '@test when args are trackedObject, the rendered component response appropriately'() { let args = trackedObject({ foo: 2 }); let Root = setComponentTemplate(precompileTemplate('{{@foo}}'), templateOnly()); - this.renderComponent(Root, { args, expect: '2' }); + await this.renderComponent(Root, { args, expect: '2' }); - this.assertChange({ + await this.assertChange({ change: () => args.foo++, expect: '3', }); } - '@skip when args are a custom tracked class, the rendered component response appropriately'() { + async '@skip when args are a custom tracked class, the rendered component response appropriately'() { class Args { @tracked foo = 2; } @@ -456,15 +457,15 @@ moduleFor( let Root = setComponentTemplate(precompileTemplate('{{@foo}}'), templateOnly()); // @ts-expect-error SAFETY: custom class is not currently supported as args, but would be nice to support? - this.renderComponent(Root, { args, expect: '2' }); + await this.renderComponent(Root, { args, expect: '2' }); - this.assertChange({ + await this.assertChange({ change: () => args.foo++, expect: '3', }); } - '@test a modifier can call renderComponent'() { + async '@test a modifier can call renderComponent'() { let render = defineSimpleModifier((element, [comp]) => { let result = renderComponent(comp, { into: element }); @@ -480,10 +481,10 @@ moduleFor( templateOnly() ); - this.renderComponent(Root, { expect: '
hi there
' }); + await this.renderComponent(Root, { expect: '
hi there
' }); } - '@test destroying the result releases its root and renderer'(assert: QUnit['assert']) { + async '@test destroying the result releases its root and renderer'(assert: QUnit['assert']) { let render = defineSimpleModifier((element, [comp]) => { let result = renderComponent(comp, { into: element }); @@ -505,14 +506,16 @@ moduleFor( templateOnly() ); - this.renderComponent(Root, { expect: '
hi there
' }); + await this.renderComponent(Root, { expect: '
hi there
' }); let baseline = renderers.length; for (let i = 0; i < 5; i++) { - run(() => (state.show = false)); + state.show = false; + await renderSettled(); assertHTML(''); - run(() => (state.show = true)); + state.show = true; + await renderSettled(); assertHTML('
hi there
'); } @@ -523,32 +526,37 @@ moduleFor( ); } - '@test destroying the result removes its root from a shared renderer'(assert: QUnit['assert']) { + async '@test destroying the result removes its root from a shared renderer'( + assert: QUnit['assert'] + ) { let Inner = setComponentTemplate(precompileTemplate('hi there'), templateOnly()); let { owner } = this; let element = document.createElement('div'); - let first = run(() => renderComponent(Inner, { owner, into: element })); + let first = renderComponent(Inner, { owner, into: element }); let renderer = renderers[renderers.length - 1]!; assert.strictEqual(renderer.state.roots.length, 1); for (let i = 0; i < 5; i++) { let other = document.createElement('div'); - let result = run(() => renderComponent(Inner, { owner, into: other })); - run(() => result.destroy()); + let result = renderComponent(Inner, { owner, into: other }); + result.destroy(); + await renderSettled(); } assert.strictEqual(renderer.state.roots.length, 1, 'destroyed roots are not retained'); - run(() => first.destroy()); + first.destroy(); + await renderSettled(); assert.false(renderers.includes(renderer), 'renderer with no roots is deregistered'); - run(() => destroy(this)); + destroy(this); + await renderSettled(); } - '@test can render in to a detached element'() { + async '@test can render in to a detached element'() { let Inner = setComponentTemplate(precompileTemplate('hello there'), templateOnly()); let element = document.createElement('div'); let attach: () => void; @@ -569,9 +577,9 @@ moduleFor( let Root = setComponentTemplate(precompileTemplate(`{{this.attached}}`), _Root); - this.renderComponent(Root, { expect: '' }); + await this.renderComponent(Root, { expect: '' }); - this.assertChange({ + await this.assertChange({ change: () => attach(), expect: `
hello there
`, }); @@ -581,7 +589,7 @@ moduleFor( * Test skipped because when an error occurs, * we mess up the cache used by renderComponent. */ - '@skip can *not* render in to a TextNode'(assert: Assert) { + async '@skip can *not* render in to a TextNode'(assert: Assert) { let Inner = setComponentTemplate(precompileTemplate('hello there'), templateOnly()); let element = document.createTextNode(''); @@ -605,11 +613,11 @@ moduleFor( let Root = setComponentTemplate(precompileTemplate(``), _Root); - this.renderComponent(Root, { expect: '' }); + await this.renderComponent(Root, { expect: '' }); assert.verifySteps(['throw']); } - '@test replaces existing contents within the target element'() { + async '@test replaces existing contents within the target element'() { let Inner = setComponentTemplate(precompileTemplate('hello there'), templateOnly()); let element = document.createElement('div'); element.innerHTML = 'general kenobi'; @@ -633,15 +641,15 @@ moduleFor( _Root ); - this.renderComponent(Root, { expect: '
general kenobi
' }); + await this.renderComponent(Root, { expect: '
general kenobi
' }); - this.assertChange({ + await this.assertChange({ change: () => render(), expect: `
hello there
`, }); } - [`@test renderComponent is eager, so it tracks with its parent`](assert: Assert) { + async [`@test renderComponent is eager, so it tracks with its parent`](assert: Assert) { let step = (...x: unknown[]) => assert.step(x.join(':')); let Inner = setComponentTemplate( @@ -682,10 +690,10 @@ moduleFor( _Root ); - this.renderComponent(Root, { expect: '
2
' }); + await this.renderComponent(Root, { expect: '
2
' }); assert.verifySteps(['render:root', 'foo:2']); - this.assertChange({ + await this.assertChange({ change: () => { this.element.querySelector('button')?.click(); }, @@ -707,14 +715,13 @@ moduleFor( assert.strictEqual(this.element.innerHTML, '
3
'); - run(() => { - destroy(this.owner); - }); + destroy(this.owner); + await renderSettled(); assert.strictEqual(this.element.innerHTML, ''); } - '@test multiple renderComponents share reactivity'() { + async '@test multiple renderComponents share reactivity'() { let args = trackedObject({ foo: 2 }); let InnerOne = setComponentTemplate(precompileTemplate('{{@foo}}'), templateOnly()); @@ -748,15 +755,17 @@ moduleFor( _Root ); - this.renderComponent(Root, { expect: '
2
2
' }); + await this.renderComponent(Root, { + expect: '
2
2
', + }); - this.assertChange({ + await this.assertChange({ change: () => args.foo++, expect: '
3
3
', }); } - '@test multiple renderComponents share service injection'() { + async '@test multiple renderComponents share service injection'() { class State extends Service { @tracked foo = 2; } @@ -800,17 +809,19 @@ moduleFor( _Root ); - this.renderComponent(Root, { expect: '
2
2
' }); + await this.renderComponent(Root, { + expect: '
2
2
', + }); let x = this.owner.lookup('service:state') as State; - this.assertChange({ + await this.assertChange({ change: () => x.foo++, expect: '
3
3
', }); } - '@test rendering multiple times to adjacent elements'() { + async '@test rendering multiple times to adjacent elements'() { let aHelper = (str: string) => str.toUpperCase(); let Child = setComponentTemplate( precompileTemplate(`Hi: {{aHelper "there"}}`, { @@ -843,18 +854,19 @@ moduleFor( templateOnly() ); - this.renderComponent(Root, { + await this.renderComponent(Root, { expect: [`
a:Hi: THERE

`, `
b:Hi: THERE
`, ``, ``].join( '\n' ), }); - run(() => destroy(this)); + destroy(this); + await renderSettled(); assertHTML(''); } - '@test multiple calls to render in to the same element appear as siblings'() { + async '@test multiple calls to render in to the same element appear as siblings'() { let aHelper = (str: string) => str.toUpperCase(); let Child = setComponentTemplate( precompileTemplate(`Hi: {{aHelper "there"}}`, { @@ -883,10 +895,11 @@ moduleFor( templateOnly() ); - this.renderComponent(Root, { + await this.renderComponent(Root, { expect: `
a:Hi: THEREa:Hi: THERE

\n\n`, }); - run(() => destroy(this)); + destroy(this); + await renderSettled(); assertHTML(''); } @@ -894,7 +907,7 @@ moduleFor( /** * NOTE: subsequent renders to the same element are prepended to the element's children */ - '@test multiple calls to render in to the same element appear as siblings and can be updated'() { + async '@test multiple calls to render in to the same element appear as siblings and can be updated'() { let aHelper = (str: string) => str.toUpperCase(); let dataA = trackedObject({ count: 1 }); let dataB = trackedObject({ count: -1 }); @@ -937,7 +950,7 @@ moduleFor( templateOnly() ); - this.renderComponent(Root, { + await this.renderComponent(Root, { expect: [ `
`, `b:Hi: THERE:-1`, @@ -948,7 +961,7 @@ moduleFor( ].join('\n'), }); - this.assertChange({ + await this.assertChange({ change: () => dataA.count++, expect: [ `
`, @@ -964,7 +977,7 @@ moduleFor( * ERROR in conflict with the NOTE on this test. * the elementns flip locations... which is kinda bonkers */ - this.assertChange({ + await this.assertChange({ change: () => dataB.count--, expect: [ `
`, @@ -976,7 +989,8 @@ moduleFor( ].join('\n'), }); - run(() => destroy(this)); + destroy(this); + await renderSettled(); assertHTML(''); } @@ -1018,7 +1032,7 @@ moduleFor( templateOnly() ); - this.renderComponent(Root, { + await this.renderComponent(Root, { expect: [`

`, `
`, ``, ``].join('\n'), }); @@ -1026,7 +1040,8 @@ moduleFor( assertHTML([`
a:Hi

`, `
b:Hi
`, ``, ``].join('\n')); - run(() => destroy(this)); + destroy(this); + await renderSettled(); assertHTML(''); } @@ -1036,7 +1051,7 @@ moduleFor( moduleFor( 'Strict Mode <-> Loose Mode - renderComponent', class extends RenderComponentTestCase { - '@test incidentally invoked loose-mode components can still resolve helpers'() { + async '@test incidentally invoked loose-mode components can still resolve helpers'() { this.owner.register('helper:a-helper', (str: string) => str.toUpperCase()); let Loose = setComponentTemplate( precompileTemplate(`Hi: {{a-helper "there"}}`), @@ -1047,9 +1062,10 @@ moduleFor( templateOnly() ); - this.renderComponent(Root, { expect: 'Hi: THERE' }); + await this.renderComponent(Root, { expect: 'Hi: THERE' }); - run(() => destroy(this)); + destroy(this); + await renderSettled(); assertHTML(''); } @@ -1065,7 +1081,7 @@ moduleFor( }, /but that value was not in scope: a-helper/); } - '@test rendering multiple times to adjacent elements'() { + async '@test rendering multiple times to adjacent elements'() { this.owner.register('helper:a-helper', (str: string) => str.toUpperCase()); let Loose = setComponentTemplate( precompileTemplate(`Hi: {{a-helper "there"}}`), @@ -1095,13 +1111,14 @@ moduleFor( templateOnly() ); - this.renderComponent(Root, { + await this.renderComponent(Root, { expect: [`
a:Hi: THERE

`, `
b:Hi: THERE
`, ``, ``].join( '\n' ), }); - run(() => destroy(this)); + destroy(this); + await renderSettled(); assertHTML(''); } @@ -1111,13 +1128,13 @@ moduleFor( moduleFor( 'Strict Mode - renderComponent - built ins', class extends RenderComponentTestCase { - '@test Can use Input'() { + async '@test Can use Input'() { let Root = setComponentTemplate( precompileTemplate('', { strictMode: true, scope: () => ({ Input }) }), templateOnly() ); - this.renderComponent(Root, { + await this.renderComponent(Root, { classic: { tagName: 'input', attrs: { @@ -1128,13 +1145,13 @@ moduleFor( }); } - '@test Can use Textarea'() { + async '@test Can use Textarea'() { let Root = setComponentTemplate( precompileTemplate('