diff --git a/packages/core/test/render3/change_detection_spec.ts b/packages/core/test/render3/change_detection_spec.ts
index 99457ef95ce..fb31c4ed02d 100644
--- a/packages/core/test/render3/change_detection_spec.ts
+++ b/packages/core/test/render3/change_detection_spec.ts
@@ -6,54 +6,45 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {NgIf} from '@angular/common';
+import {CommonModule, DOCUMENT} from '@angular/common';
+import {TestBed} from '@angular/core/testing';
import {withBody} from '@angular/private/testing';
-import {ChangeDetectionStrategy, DoCheck, OnInit} from '../../src/core';
+import {Component, DoCheck, OnInit, Renderer2, RendererFactory2} from '../../src/core';
import {whenRendered} from '../../src/render3/component';
-import {AttributeMarker, getRenderedText, LifecycleHooksFeature, ɵɵadvance, ɵɵdefineComponent, ɵɵgetCurrentView, ɵɵproperty, ɵɵtextInterpolate1, ɵɵtextInterpolate2} from '../../src/render3/index';
-import {detectChanges, markDirty, tick, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵlistener, ɵɵtemplate, ɵɵtext, ɵɵtextInterpolate} from '../../src/render3/instructions/all';
-import {RenderFlags} from '../../src/render3/interfaces/definition';
-import {Renderer3, RendererFactory3} from '../../src/render3/interfaces/renderer';
-import {FLAGS, LViewFlags} from '../../src/render3/interfaces/view';
-
-import {containerEl, createComponent, renderComponent, requestAnimationFrame} from './render_util';
+import {getRenderedText} from '../../src/render3/index';
+import {detectChanges, markDirty} from '../../src/render3/instructions/all';
describe('change detection', () => {
describe('markDirty, detectChanges, whenRendered, getRenderedText', () => {
let mycompOninit: MyComponentWithOnInit;
+
+ @Component({
+ selector: 'my-comp',
+ standalone: true,
+ template: '{{ value }}',
+ })
class MyComponent implements DoCheck {
value: string = 'works';
doCheckCount = 0;
ngDoCheck(): void {
this.doCheckCount++;
}
-
- static ɵfac = () => new MyComponent();
- static ɵcmp = ɵɵdefineComponent({
- type: MyComponent,
- selectors: [['my-comp']],
- decls: 2,
- vars: 1,
- template:
- (rf: RenderFlags, ctx: MyComponent) => {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'span');
- ɵɵtext(1);
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- ɵɵadvance(1);
- ɵɵtextInterpolate(ctx.value);
- }
- }
- });
}
+ @Component({
+ selector: 'my-comp-oninit',
+ standalone: true,
+ template: '{{ value }}',
+ })
class MyComponentWithOnInit implements OnInit, DoCheck {
value: string = 'works';
doCheckCount = 0;
+ constructor() {
+ mycompOninit = this;
+ }
+
ngOnInit() {
markDirty(this);
}
@@ -66,28 +57,19 @@ describe('change detection', () => {
this.value = 'click works';
markDirty(this);
}
-
- static ɵfac = () => mycompOninit = new MyComponentWithOnInit();
- static ɵcmp = ɵɵdefineComponent({
- type: MyComponentWithOnInit,
- selectors: [['my-comp-oninit']],
- decls: 2,
- vars: 1,
- template:
- (rf: RenderFlags, ctx: MyComponentWithOnInit) => {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'span');
- ɵɵtext(1);
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- ɵɵadvance(1);
- ɵɵtextInterpolate(ctx.value);
- }
- }
- });
}
+ @Component({
+ selector: 'my-parent-comp',
+ standalone: true,
+ imports: [CommonModule, MyComponentWithOnInit],
+ template: `
+ -->
+
+
+
+ `,
+ })
class MyParentComponent implements OnInit {
show = false;
value = 'parent';
@@ -99,47 +81,28 @@ describe('change detection', () => {
this.show = true;
markDirty(this);
}
-
- static ɵfac = () => new MyParentComponent();
- static ɵcmp = ɵɵdefineComponent({
- type: MyParentComponent,
- selectors: [['my-parent-comp']],
- decls: 2,
- vars: 1,
- dependencies: [NgIf, MyComponentWithOnInit],
- consts: [[AttributeMarker.Template, 'ngIf']],
- template:
- (rf: RenderFlags, ctx: MyParentComponent) => {
- if (rf & RenderFlags.Create) {
- ɵɵtext(0, ' -->\n');
- ɵɵtemplate(1, (rf, ctx) => {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'div');
- ɵɵelement(1, 'my-comp-oninit');
- ɵɵelementEnd();
- }
- }, 2, 0, 'div', 0);
- }
- if (rf & RenderFlags.Update) {
- ɵɵadvance(1);
- ɵɵproperty('ngIf', ctx.show);
- }
- }
- });
}
it('should mark a component dirty and schedule change detection', withBody('my-comp', () => {
- const myComp = renderComponent(MyComponent, {hostFeatures: [LifecycleHooksFeature]});
+ const fixture = TestBed.createComponent(MyComponent);
+ fixture.detectChanges();
+
+ const myComp = fixture.componentInstance;
expect(getRenderedText(myComp)).toEqual('works');
myComp.value = 'updated';
markDirty(myComp);
expect(getRenderedText(myComp)).toEqual('works');
- requestAnimationFrame.flush();
+
+ fixture.detectChanges();
+
expect(getRenderedText(myComp)).toEqual('updated');
}));
it('should detectChanges on a component', withBody('my-comp', () => {
- const myComp = renderComponent(MyComponent, {hostFeatures: [LifecycleHooksFeature]});
+ const fixture = TestBed.createComponent(MyComponent);
+ fixture.detectChanges();
+
+ const myComp = fixture.componentInstance;
expect(getRenderedText(myComp)).toEqual('works');
myComp.value = 'updated';
detectChanges(myComp);
@@ -148,25 +111,34 @@ describe('change detection', () => {
it('should detectChanges after markDirty is called multiple times within ngOnInit',
withBody('my-comp-oninit', () => {
- const myParentComp =
- renderComponent(MyParentComponent, {hostFeatures: [LifecycleHooksFeature]});
+ const fixture = TestBed.createComponent(MyParentComponent);
+ fixture.detectChanges();
+
+ const myParentComp = fixture.componentInstance;
expect(myParentComp.show).toBe(false);
myParentComp.click();
- requestAnimationFrame.flush();
+ fixture.detectChanges();
+
expect(myParentComp.show).toBe(true);
const myComp = mycompOninit;
expect(getRenderedText(myComp)).toEqual('works');
expect(myComp.doCheckCount).toBe(1);
myComp.click();
expect(getRenderedText(myComp)).toEqual('works');
- requestAnimationFrame.flush();
+
+ fixture.detectChanges();
+
expect(getRenderedText(myComp)).toEqual('click works');
expect(myComp.doCheckCount).toBe(2);
}));
it('should detectChanges only once if markDirty is called multiple times',
withBody('my-comp', () => {
- const myComp = renderComponent(MyComponent, {hostFeatures: [LifecycleHooksFeature]});
+ const fixture = TestBed.createComponent(MyComponent);
+ fixture.detectChanges();
+
+ const myComp = fixture.componentInstance;
+
expect(getRenderedText(myComp)).toEqual('works');
expect(myComp.doCheckCount).toBe(1);
myComp.value = 'ignore';
@@ -174,59 +146,75 @@ describe('change detection', () => {
myComp.value = 'updated';
markDirty(myComp);
expect(getRenderedText(myComp)).toEqual('works');
- requestAnimationFrame.flush();
+
+ fixture.detectChanges();
+
expect(getRenderedText(myComp)).toEqual('updated');
expect(myComp.doCheckCount).toBe(2);
}));
it('should notify whenRendered', withBody('my-comp', async () => {
- const myComp = renderComponent(MyComponent, {hostFeatures: [LifecycleHooksFeature]});
+ const fixture = TestBed.createComponent(MyComponent);
+ fixture.detectChanges();
+
+ const myComp = fixture.componentInstance;
await whenRendered(myComp);
myComp.value = 'updated';
markDirty(myComp);
- setTimeout(requestAnimationFrame.flush, 0);
+ setTimeout(() => fixture.detectChanges(), 0);
await whenRendered(myComp);
expect(getRenderedText(myComp)).toEqual('updated');
}));
});
- it('should call begin and end when the renderer factory implements them', () => {
- const log: string[] = [];
+ it('should call begin and end when the renderer factory implements them',
+ withBody('', () => {
+ const log: string[] = [];
- const testRendererFactory: RendererFactory3 = {
- createRenderer: (): Renderer3 => {
- return document;
- },
- begin: () => log.push('begin'),
- end: () => log.push('end'),
- };
+ const testRendererFactory: RendererFactory2 = {
+ createRenderer: (): Renderer2 => {
+ return document as unknown as Renderer2;
+ },
+ begin: () => log.push('begin'),
+ end: () => log.push('end'),
+ };
- class MyComponent {
- get value(): string {
- log.push('detect changes');
- return 'works';
- }
+ @Component({
+ selector: 'my-comp',
+ standalone: true,
+ template: '{{ value }}',
+ })
+ class MyComponent {
+ get value(): string {
+ log.push('detect changes');
+ return 'works';
+ }
+ }
- static ɵfac = () => new MyComponent();
- static ɵcmp = ɵɵdefineComponent({
- type: MyComponent,
- selectors: [['my-comp']],
- decls: 1,
- vars: 1,
- template:
- (rf: RenderFlags, ctx: MyComponent) => {
- if (rf & RenderFlags.Create) {
- ɵɵtext(0);
- }
- if (rf & RenderFlags.Update) {
- ɵɵtextInterpolate(ctx.value);
- }
- }
- });
- }
+ TestBed.configureTestingModule({
+ providers: [
+ {
+ provide: DOCUMENT,
+ useFactory: () => document,
+ },
+ {
+ provide: RendererFactory2,
+ useValue: testRendererFactory,
+ }
+ ]
+ });
- const myComp = renderComponent(MyComponent, {rendererFactory: testRendererFactory});
- expect(getRenderedText(myComp)).toEqual('works');
- expect(log).toEqual(['begin', 'detect changes', 'end']);
- });
+ const fixture = TestBed.createComponent(MyComponent);
+ fixture.detectChanges();
+
+ const myComp = fixture.componentInstance;
+ expect(getRenderedText(myComp)).toEqual('works');
+
+ expect(log).toEqual([
+ 'begin',
+ 'detect changes', // regular change detection cycle
+ 'end',
+ 'detect changes' // check no changes cycle
+ ]);
+ }));
});