Skip to content

Commit de171d8

Browse files
AndrewKushnirdylhunn
authored andcommitted
test(core): replace hand-written instructions in change detection tests with TestBed (angular#46529)
This commit updates a set of change detection tests to avoid using hand-written instructions and replace them with TestBed APIs. PR Close angular#46529
1 parent 2e59f9f commit de171d8

File tree

1 file changed

+114
-126
lines changed

1 file changed

+114
-126
lines changed

packages/core/test/render3/change_detection_spec.ts

Lines changed: 114 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -6,54 +6,45 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {NgIf} from '@angular/common';
9+
import {CommonModule, DOCUMENT} from '@angular/common';
10+
import {TestBed} from '@angular/core/testing';
1011
import {withBody} from '@angular/private/testing';
1112

12-
import {ChangeDetectionStrategy, DoCheck, OnInit} from '../../src/core';
13+
import {Component, DoCheck, OnInit, Renderer2, RendererFactory2} from '../../src/core';
1314
import {whenRendered} from '../../src/render3/component';
14-
import {AttributeMarker, getRenderedText, LifecycleHooksFeature, ɵɵadvance, ɵɵdefineComponent, ɵɵgetCurrentView, ɵɵproperty, ɵɵtextInterpolate1, ɵɵtextInterpolate2} from '../../src/render3/index';
15-
import {detectChanges, markDirty, tick, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵlistener, ɵɵtemplate, ɵɵtext, ɵɵtextInterpolate} from '../../src/render3/instructions/all';
16-
import {RenderFlags} from '../../src/render3/interfaces/definition';
17-
import {Renderer3, RendererFactory3} from '../../src/render3/interfaces/renderer';
18-
import {FLAGS, LViewFlags} from '../../src/render3/interfaces/view';
19-
20-
import {containerEl, createComponent, renderComponent, requestAnimationFrame} from './render_util';
15+
import {getRenderedText} from '../../src/render3/index';
16+
import {detectChanges, markDirty} from '../../src/render3/instructions/all';
2117

2218
describe('change detection', () => {
2319
describe('markDirty, detectChanges, whenRendered, getRenderedText', () => {
2420
let mycompOninit: MyComponentWithOnInit;
21+
22+
@Component({
23+
selector: 'my-comp',
24+
standalone: true,
25+
template: '<span>{{ value }}</span>',
26+
})
2527
class MyComponent implements DoCheck {
2628
value: string = 'works';
2729
doCheckCount = 0;
2830
ngDoCheck(): void {
2931
this.doCheckCount++;
3032
}
31-
32-
static ɵfac = () => new MyComponent();
33-
static ɵcmp = ɵɵdefineComponent({
34-
type: MyComponent,
35-
selectors: [['my-comp']],
36-
decls: 2,
37-
vars: 1,
38-
template:
39-
(rf: RenderFlags, ctx: MyComponent) => {
40-
if (rf & RenderFlags.Create) {
41-
ɵɵelementStart(0, 'span');
42-
ɵɵtext(1);
43-
ɵɵelementEnd();
44-
}
45-
if (rf & RenderFlags.Update) {
46-
ɵɵadvance(1);
47-
ɵɵtextInterpolate(ctx.value);
48-
}
49-
}
50-
});
5133
}
5234

35+
@Component({
36+
selector: 'my-comp-oninit',
37+
standalone: true,
38+
template: '<span>{{ value }}</span>',
39+
})
5340
class MyComponentWithOnInit implements OnInit, DoCheck {
5441
value: string = 'works';
5542
doCheckCount = 0;
5643

44+
constructor() {
45+
mycompOninit = this;
46+
}
47+
5748
ngOnInit() {
5849
markDirty(this);
5950
}
@@ -66,28 +57,19 @@ describe('change detection', () => {
6657
this.value = 'click works';
6758
markDirty(this);
6859
}
69-
70-
static ɵfac = () => mycompOninit = new MyComponentWithOnInit();
71-
static ɵcmp = ɵɵdefineComponent({
72-
type: MyComponentWithOnInit,
73-
selectors: [['my-comp-oninit']],
74-
decls: 2,
75-
vars: 1,
76-
template:
77-
(rf: RenderFlags, ctx: MyComponentWithOnInit) => {
78-
if (rf & RenderFlags.Create) {
79-
ɵɵelementStart(0, 'span');
80-
ɵɵtext(1);
81-
ɵɵelementEnd();
82-
}
83-
if (rf & RenderFlags.Update) {
84-
ɵɵadvance(1);
85-
ɵɵtextInterpolate(ctx.value);
86-
}
87-
}
88-
});
8960
}
9061

62+
@Component({
63+
selector: 'my-parent-comp',
64+
standalone: true,
65+
imports: [CommonModule, MyComponentWithOnInit],
66+
template: `
67+
-->
68+
<div *ngIf="show">
69+
<my-comp-oninit></my-comp-oninit>
70+
</div>
71+
`,
72+
})
9173
class MyParentComponent implements OnInit {
9274
show = false;
9375
value = 'parent';
@@ -99,47 +81,28 @@ describe('change detection', () => {
9981
this.show = true;
10082
markDirty(this);
10183
}
102-
103-
static ɵfac = () => new MyParentComponent();
104-
static ɵcmp = ɵɵdefineComponent({
105-
type: MyParentComponent,
106-
selectors: [['my-parent-comp']],
107-
decls: 2,
108-
vars: 1,
109-
dependencies: [NgIf, MyComponentWithOnInit],
110-
consts: [[AttributeMarker.Template, 'ngIf']],
111-
template:
112-
(rf: RenderFlags, ctx: MyParentComponent) => {
113-
if (rf & RenderFlags.Create) {
114-
ɵɵtext(0, ' -->\n');
115-
ɵɵtemplate(1, (rf, ctx) => {
116-
if (rf & RenderFlags.Create) {
117-
ɵɵelementStart(0, 'div');
118-
ɵɵelement(1, 'my-comp-oninit');
119-
ɵɵelementEnd();
120-
}
121-
}, 2, 0, 'div', 0);
122-
}
123-
if (rf & RenderFlags.Update) {
124-
ɵɵadvance(1);
125-
ɵɵproperty('ngIf', ctx.show);
126-
}
127-
}
128-
});
12984
}
13085

13186
it('should mark a component dirty and schedule change detection', withBody('my-comp', () => {
132-
const myComp = renderComponent(MyComponent, {hostFeatures: [LifecycleHooksFeature]});
87+
const fixture = TestBed.createComponent(MyComponent);
88+
fixture.detectChanges();
89+
90+
const myComp = fixture.componentInstance;
13391
expect(getRenderedText(myComp)).toEqual('works');
13492
myComp.value = 'updated';
13593
markDirty(myComp);
13694
expect(getRenderedText(myComp)).toEqual('works');
137-
requestAnimationFrame.flush();
95+
96+
fixture.detectChanges();
97+
13898
expect(getRenderedText(myComp)).toEqual('updated');
13999
}));
140100

141101
it('should detectChanges on a component', withBody('my-comp', () => {
142-
const myComp = renderComponent(MyComponent, {hostFeatures: [LifecycleHooksFeature]});
102+
const fixture = TestBed.createComponent(MyComponent);
103+
fixture.detectChanges();
104+
105+
const myComp = fixture.componentInstance;
143106
expect(getRenderedText(myComp)).toEqual('works');
144107
myComp.value = 'updated';
145108
detectChanges(myComp);
@@ -148,85 +111,110 @@ describe('change detection', () => {
148111

149112
it('should detectChanges after markDirty is called multiple times within ngOnInit',
150113
withBody('my-comp-oninit', () => {
151-
const myParentComp =
152-
renderComponent(MyParentComponent, {hostFeatures: [LifecycleHooksFeature]});
114+
const fixture = TestBed.createComponent(MyParentComponent);
115+
fixture.detectChanges();
116+
117+
const myParentComp = fixture.componentInstance;
153118
expect(myParentComp.show).toBe(false);
154119
myParentComp.click();
155-
requestAnimationFrame.flush();
120+
fixture.detectChanges();
121+
156122
expect(myParentComp.show).toBe(true);
157123
const myComp = mycompOninit;
158124
expect(getRenderedText(myComp)).toEqual('works');
159125
expect(myComp.doCheckCount).toBe(1);
160126
myComp.click();
161127
expect(getRenderedText(myComp)).toEqual('works');
162-
requestAnimationFrame.flush();
128+
129+
fixture.detectChanges();
130+
163131
expect(getRenderedText(myComp)).toEqual('click works');
164132
expect(myComp.doCheckCount).toBe(2);
165133
}));
166134

167135
it('should detectChanges only once if markDirty is called multiple times',
168136
withBody('my-comp', () => {
169-
const myComp = renderComponent(MyComponent, {hostFeatures: [LifecycleHooksFeature]});
137+
const fixture = TestBed.createComponent(MyComponent);
138+
fixture.detectChanges();
139+
140+
const myComp = fixture.componentInstance;
141+
170142
expect(getRenderedText(myComp)).toEqual('works');
171143
expect(myComp.doCheckCount).toBe(1);
172144
myComp.value = 'ignore';
173145
markDirty(myComp);
174146
myComp.value = 'updated';
175147
markDirty(myComp);
176148
expect(getRenderedText(myComp)).toEqual('works');
177-
requestAnimationFrame.flush();
149+
150+
fixture.detectChanges();
151+
178152
expect(getRenderedText(myComp)).toEqual('updated');
179153
expect(myComp.doCheckCount).toBe(2);
180154
}));
181155

182156
it('should notify whenRendered', withBody('my-comp', async () => {
183-
const myComp = renderComponent(MyComponent, {hostFeatures: [LifecycleHooksFeature]});
157+
const fixture = TestBed.createComponent(MyComponent);
158+
fixture.detectChanges();
159+
160+
const myComp = fixture.componentInstance;
184161
await whenRendered(myComp);
185162
myComp.value = 'updated';
186163
markDirty(myComp);
187-
setTimeout(requestAnimationFrame.flush, 0);
164+
setTimeout(() => fixture.detectChanges(), 0);
188165
await whenRendered(myComp);
189166
expect(getRenderedText(myComp)).toEqual('updated');
190167
}));
191168
});
192169

193-
it('should call begin and end when the renderer factory implements them', () => {
194-
const log: string[] = [];
195-
196-
const testRendererFactory: RendererFactory3 = {
197-
createRenderer: (): Renderer3 => {
198-
return document;
199-
},
200-
begin: () => log.push('begin'),
201-
end: () => log.push('end'),
202-
};
203-
204-
class MyComponent {
205-
get value(): string {
206-
log.push('detect changes');
207-
return 'works';
208-
}
209-
210-
static ɵfac = () => new MyComponent();
211-
static ɵcmp = ɵɵdefineComponent({
212-
type: MyComponent,
213-
selectors: [['my-comp']],
214-
decls: 1,
215-
vars: 1,
216-
template:
217-
(rf: RenderFlags, ctx: MyComponent) => {
218-
if (rf & RenderFlags.Create) {
219-
ɵɵtext(0);
220-
}
221-
if (rf & RenderFlags.Update) {
222-
ɵɵtextInterpolate(ctx.value);
223-
}
224-
}
225-
});
226-
}
227-
228-
const myComp = renderComponent(MyComponent, {rendererFactory: testRendererFactory});
229-
expect(getRenderedText(myComp)).toEqual('works');
230-
expect(log).toEqual(['begin', 'detect changes', 'end']);
231-
});
170+
it('should call begin and end when the renderer factory implements them',
171+
withBody('<my-comp></my-comp>', () => {
172+
const log: string[] = [];
173+
174+
const testRendererFactory: RendererFactory2 = {
175+
createRenderer: (): Renderer2 => {
176+
return document as unknown as Renderer2;
177+
},
178+
begin: () => log.push('begin'),
179+
end: () => log.push('end'),
180+
};
181+
182+
@Component({
183+
selector: 'my-comp',
184+
standalone: true,
185+
template: '{{ value }}',
186+
})
187+
class MyComponent {
188+
get value(): string {
189+
log.push('detect changes');
190+
return 'works';
191+
}
192+
}
193+
194+
TestBed.configureTestingModule({
195+
providers: [
196+
{
197+
provide: DOCUMENT,
198+
useFactory: () => document,
199+
},
200+
{
201+
provide: RendererFactory2,
202+
useValue: testRendererFactory,
203+
}
204+
]
205+
});
206+
207+
const fixture = TestBed.createComponent(MyComponent);
208+
fixture.detectChanges();
209+
210+
const myComp = fixture.componentInstance;
211+
expect(getRenderedText(myComp)).toEqual('works');
212+
213+
expect(log).toEqual([
214+
'begin',
215+
'detect changes', // regular change detection cycle
216+
'end',
217+
'detect changes' // check no changes cycle
218+
]);
219+
}));
232220
});

0 commit comments

Comments
 (0)