Skip to content

Commit

Permalink
fix(angular): call ngOnChanges after mount
Browse files Browse the repository at this point in the history
  • Loading branch information
jordanpowell88 committed Oct 3, 2022
1 parent a76df0b commit 95aa120
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 4 deletions.
21 changes: 17 additions & 4 deletions npm/angular/src/mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ window.Mocha['__zone_patch__'] = false
import 'zone.js/testing'

import { CommonModule } from '@angular/common'
import { Component, EventEmitter, Type } from '@angular/core'
import { Component, EventEmitter, SimpleChange, SimpleChanges, Type } from '@angular/core'
import {
ComponentFixture,
getTestBed,
Expand Down Expand Up @@ -215,10 +215,9 @@ function setupFixture<T> (
* @param {ComponentFixture<T>} fixture Fixture for debugging and testing a component.
* @returns {T} Component being mounted
*/
function setupComponent<T> (
function setupComponent<T extends { ngOnChanges? (changes: SimpleChanges): void }> (
config: MountConfig<T>,
fixture: ComponentFixture<T>,
): T {
fixture: ComponentFixture<T>): T {
let component: T = fixture.componentInstance

if (config?.componentProperties) {
Expand All @@ -235,6 +234,20 @@ function setupComponent<T> (
})
}

if (component.ngOnChanges && config.componentProperties) {
const { componentProperties } = config
let simpleChanges: SimpleChanges

Object.keys(componentProperties).forEach((key: string, index: number, keys: string[]) => {
simpleChanges = {
...simpleChanges,
[key]: new SimpleChange(null, componentProperties[key], true),
}
})

component.ngOnChanges(simpleChanges)
}

return component
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Component, Input, OnInit, OnChanges, SimpleChanges } from '@angular/core'

@Component({
selector: 'app-lifecycle',
template: `<p>Hi {{ name }}. ngOnInit fired: {{ ngOnInitFired }} and ngOnChanges fired: {{ ngOnChangesFired }} and conditionalName: {{ conditionalName }}</p>`
})
export class LifecycleComponent implements OnInit, OnChanges {
@Input() name = ''
ngOnInitFired = false
ngOnChangesFired = false
conditionalName = false

ngOnInit(): void {
this.ngOnInitFired = true
}

ngOnChanges(changes: SimpleChanges): void {
this.ngOnChangesFired = true;
if (changes['name'].currentValue === 'CONDITIONAL NAME') {
this.conditionalName = true
}
}
}
54 changes: 54 additions & 0 deletions system-tests/project-fixtures/angular/src/app/mount.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ButtonOutputComponent } from "./components/button-output.component";
import { createOutputSpy } from 'cypress/angular';
import { EventEmitter, Component } from '@angular/core';
import { ProjectionComponent } from "./components/projection.component";
import { LifecycleComponent } from "./components/lifecycle.component";

@Component({
template: `<app-projection>Hello World</app-projection>`
Expand Down Expand Up @@ -164,7 +165,60 @@ describe("angular mount", () => {
})
cy.get('h3').contains('Hello World')
})

it('handles ngOnChanges on mount', () => {
cy.mount(LifecycleComponent, {
componentProperties: {
name: 'Angular'
}
})

cy.get('p').should('have.text', 'Hi Angular. ngOnInit fired: true and ngOnChanges fired: true and conditionalName: false')
})

it('handles ngOnChanges on mount with templates', () => {
cy.mount('<app-lifecycle [name]="name"></app-lifecycle>', {
declarations: [LifecycleComponent],
componentProperties: {
name: 'Angular'
}
})

cy.get('p').should('have.text', 'Hi Angular. ngOnInit fired: true and ngOnChanges fired: true and conditionalName: false')
})

it('creates simpleChanges from componentProperties and calls ngOnChanges on Mount', () => {
cy.mount(LifecycleComponent, {
componentProperties: {
name: 'CONDITIONAL NAME'
}
})
cy.get('p').should('have.text', 'Hi CONDITIONAL NAME. ngOnInit fired: true and ngOnChanges fired: true and conditionalName: true')
})

it('creates simpleChanges from componentProperties and calls ngOnChanges on Mount with template', () => {
cy.mount('<app-lifecycle [name]="name"></app-lifecycle>', {
declarations: [LifecycleComponent],
componentProperties: {
name: 'CONDITIONAL NAME'
}
})
cy.get('p').should('have.text', 'Hi CONDITIONAL NAME. ngOnInit fired: true and ngOnChanges fired: true and conditionalName: true')
})

it('ngOnChanges is not fired when no componentProperties given', () => {
cy.mount(LifecycleComponent)
cy.get('p').should('have.text', 'Hi . ngOnInit fired: true and ngOnChanges fired: false and conditionalName: false')
})

it('ngOnChanges is not fired when no componentProperties given with template', () => {
cy.mount('<app-lifecycle></app-lifecycle>', {
declarations: [LifecycleComponent]
})
cy.get('p').should('have.text', 'Hi . ngOnInit fired: true and ngOnChanges fired: false and conditionalName: false')
})


describe("teardown", () => {
beforeEach(() => {
cy.get("[id^=root]").should("not.exist");
Expand Down

0 comments on commit 95aa120

Please sign in to comment.