|
| 1 | +import { moduleFor, RenderingTestCase, runTask } from 'internal-test-helpers'; |
| 2 | + |
| 3 | +import Component from '@glimmer/component'; |
| 4 | +import { tracked } from '@glimmer/tracking'; |
| 5 | + |
| 6 | +class Toggle { |
| 7 | + @tracked isShowing = true; |
| 8 | +} |
| 9 | + |
| 10 | +class Label { |
| 11 | + @tracked text = 'first'; |
| 12 | +} |
| 13 | + |
| 14 | +moduleFor( |
| 15 | + 'Components test: @glimmer/component', |
| 16 | + class extends RenderingTestCase { |
| 17 | + '@test isDestroying and isDestroyed transition as the component is torn down'(assert) { |
| 18 | + let toggle = new Toggle(); |
| 19 | + let instance; |
| 20 | + |
| 21 | + class Subject extends Component { |
| 22 | + constructor() { |
| 23 | + super(...arguments); |
| 24 | + instance = this; |
| 25 | + assert.step( |
| 26 | + `constructor: isDestroying=${this.isDestroying} isDestroyed=${this.isDestroyed}` |
| 27 | + ); |
| 28 | + } |
| 29 | + |
| 30 | + willDestroy() { |
| 31 | + super.willDestroy(); |
| 32 | + assert.step( |
| 33 | + `willDestroy: isDestroying=${this.isDestroying} isDestroyed=${this.isDestroyed}` |
| 34 | + ); |
| 35 | + } |
| 36 | + |
| 37 | + <template>subject</template> |
| 38 | + } |
| 39 | + |
| 40 | + const Root = <template>{{#if toggle.isShowing}}<Subject />{{/if}}</template>; |
| 41 | + |
| 42 | + this.renderComponent(Root, { expect: 'subject' }); |
| 43 | + |
| 44 | + assert.verifySteps(['constructor: isDestroying=false isDestroyed=false']); |
| 45 | + assert.false(instance.isDestroying, 'isDestroying is false while rendered'); |
| 46 | + assert.false(instance.isDestroyed, 'isDestroyed is false while rendered'); |
| 47 | + |
| 48 | + runTask(() => (toggle.isShowing = false)); |
| 49 | + |
| 50 | + this.assertText(''); |
| 51 | + assert.verifySteps(['willDestroy: isDestroying=true isDestroyed=false']); |
| 52 | + assert.true(instance.isDestroying, 'isDestroying is true after teardown'); |
| 53 | + assert.true(instance.isDestroyed, 'isDestroyed is true after teardown'); |
| 54 | + } |
| 55 | + |
| 56 | + '@test tracked state and args are reactive without re-constructing the component'(assert) { |
| 57 | + let label = new Label(); |
| 58 | + let instance; |
| 59 | + |
| 60 | + class Subject extends Component { |
| 61 | + @tracked count = 0; |
| 62 | + |
| 63 | + constructor() { |
| 64 | + super(...arguments); |
| 65 | + instance = this; |
| 66 | + assert.step('constructor'); |
| 67 | + } |
| 68 | + |
| 69 | + <template>{{@text}}-{{this.count}}</template> |
| 70 | + } |
| 71 | + |
| 72 | + const Root = <template><Subject @text={{label.text}} /></template>; |
| 73 | + |
| 74 | + this.renderComponent(Root, { expect: 'first-0' }); |
| 75 | + |
| 76 | + assert.verifySteps(['constructor']); |
| 77 | + |
| 78 | + runTask(() => instance.count++); |
| 79 | + |
| 80 | + this.assertText('first-1'); |
| 81 | + |
| 82 | + runTask(() => (label.text = 'second')); |
| 83 | + |
| 84 | + this.assertText('second-1'); |
| 85 | + assert.verifySteps([], 'the component updated in place rather than being re-constructed'); |
| 86 | + } |
| 87 | + |
| 88 | + '@test re-mounting constructs a new instance and leaves the old one destroyed'(assert) { |
| 89 | + let toggle = new Toggle(); |
| 90 | + let instances = []; |
| 91 | + |
| 92 | + class Subject extends Component { |
| 93 | + constructor() { |
| 94 | + super(...arguments); |
| 95 | + instances.push(this); |
| 96 | + assert.step(`constructor: ${instances.length}`); |
| 97 | + } |
| 98 | + |
| 99 | + willDestroy() { |
| 100 | + super.willDestroy(); |
| 101 | + assert.step(`willDestroy: ${instances.indexOf(this) + 1}`); |
| 102 | + } |
| 103 | + |
| 104 | + <template>subject</template> |
| 105 | + } |
| 106 | + |
| 107 | + const Root = <template>{{#if toggle.isShowing}}<Subject />{{/if}}</template>; |
| 108 | + |
| 109 | + this.renderComponent(Root, { expect: 'subject' }); |
| 110 | + |
| 111 | + assert.verifySteps(['constructor: 1']); |
| 112 | + |
| 113 | + runTask(() => (toggle.isShowing = false)); |
| 114 | + |
| 115 | + this.assertText(''); |
| 116 | + assert.verifySteps(['willDestroy: 1']); |
| 117 | + |
| 118 | + runTask(() => (toggle.isShowing = true)); |
| 119 | + |
| 120 | + this.assertText('subject'); |
| 121 | + assert.verifySteps(['constructor: 2']); |
| 122 | + |
| 123 | + assert.strictEqual(instances.length, 2, 'a second instance was constructed'); |
| 124 | + assert.notStrictEqual(instances[0], instances[1], 'the instances are distinct'); |
| 125 | + assert.true(instances[0].isDestroyed, 'the first instance stayed destroyed'); |
| 126 | + assert.false(instances[1].isDestroying, 'the second instance is not destroying'); |
| 127 | + assert.false(instances[1].isDestroyed, 'the second instance is not destroyed'); |
| 128 | + |
| 129 | + runTask(() => (toggle.isShowing = false)); |
| 130 | + |
| 131 | + this.assertText(''); |
| 132 | + assert.verifySteps(['willDestroy: 2']); |
| 133 | + assert.true(instances[1].isDestroyed, 'the second instance was destroyed in turn'); |
| 134 | + } |
| 135 | + } |
| 136 | +); |
0 commit comments