Skip to content

Commit 3fe94da

Browse files
fix: don't invoke ngOnChanges when no properties are provided (#326)
Closes #323 BREAKING CHANGE: This change is made to have the same behavior as the run time behavior. BEFORE: The `ngOnChanges` lifecycle is always invoked when a component is rendered. AFTER: The `ngOnChanges` lifecycle is only invoked if a component is rendered with `componentProperties`.
1 parent d4a6ef4 commit 3fe94da

File tree

2 files changed

+27
-14
lines changed

2 files changed

+27
-14
lines changed

Diff for: projects/testing-library/src/lib/testing-library.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export async function render<SutType, WrapperType = SutType>(
208208
let isAlive = true;
209209
fixture.componentRef.onDestroy(() => (isAlive = false));
210210

211-
if (hasOnChangesHook(fixture.componentInstance)) {
211+
if (hasOnChangesHook(fixture.componentInstance) && Object.keys(properties).length > 0) {
212212
const changes = getChangesObj(null, componentProperties);
213213
fixture.componentInstance.ngOnChanges(changes);
214214
}

Diff for: projects/testing-library/tests/render.spec.ts

+26-13
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,18 @@ import { render, fireEvent, screen } from '../src/public_api';
2121
})
2222
class FixtureComponent {}
2323

24-
test('creates queries and events', async () => {
25-
const view = await render(FixtureComponent);
24+
describe('DTL functionality', () => {
25+
it('creates queries and events', async () => {
26+
const view = await render(FixtureComponent);
2627

27-
/// We wish to test the utility function from `render` here.
28-
// eslint-disable-next-line testing-library/prefer-screen-queries
29-
fireEvent.input(view.getByTestId('input'), { target: { value: 'a super awesome input' } });
30-
// eslint-disable-next-line testing-library/prefer-screen-queries
31-
expect(view.getByDisplayValue('a super awesome input')).toBeInTheDocument();
32-
// eslint-disable-next-line testing-library/prefer-screen-queries
33-
fireEvent.click(view.getByText('button'));
28+
/// We wish to test the utility function from `render` here.
29+
// eslint-disable-next-line testing-library/prefer-screen-queries
30+
fireEvent.input(view.getByTestId('input'), { target: { value: 'a super awesome input' } });
31+
// eslint-disable-next-line testing-library/prefer-screen-queries
32+
expect(view.getByDisplayValue('a super awesome input')).toBeInTheDocument();
33+
// eslint-disable-next-line testing-library/prefer-screen-queries
34+
fireEvent.click(view.getByText('button'));
35+
});
3436
});
3537

3638
describe('standalone', () => {
@@ -162,13 +164,13 @@ describe('Angular component life-cycle hooks', () => {
162164
}
163165

164166
ngOnChanges(changes: SimpleChanges) {
165-
if (changes.name && this.nameChanged) {
166-
this.nameChanged(changes.name.currentValue, changes.name.isFirstChange());
167+
if (this.nameChanged) {
168+
this.nameChanged(changes.name?.currentValue, changes.name?.isFirstChange());
167169
}
168170
}
169171
}
170172

171-
it('will call ngOnInit on initial render', async () => {
173+
it('invokes ngOnInit on initial render', async () => {
172174
const nameInitialized = jest.fn();
173175
const componentProperties = { nameInitialized };
174176
const view = await render(FixtureWithNgOnChangesComponent, { componentProperties });
@@ -179,7 +181,7 @@ describe('Angular component life-cycle hooks', () => {
179181
expect(nameInitialized).toHaveBeenCalledWith('Initial');
180182
});
181183

182-
it('will call ngOnChanges on initial render before ngOnInit', async () => {
184+
it('invokes ngOnChanges on initial render before ngOnInit', async () => {
183185
const nameInitialized = jest.fn();
184186
const nameChanged = jest.fn();
185187
const componentProperties = { nameInitialized, nameChanged, name: 'Sarah' };
@@ -193,6 +195,17 @@ describe('Angular component life-cycle hooks', () => {
193195
/// expect `nameChanged` to be called before `nameInitialized`
194196
expect(nameChanged.mock.invocationCallOrder[0]).toBeLessThan(nameInitialized.mock.invocationCallOrder[0]);
195197
});
198+
199+
it('does not invoke ngOnChanges when no properties are provided', async () => {
200+
@Component({ template: `` })
201+
class TestFixtureComponent implements OnChanges {
202+
ngOnChanges() {
203+
throw new Error('should not be called');
204+
}
205+
}
206+
207+
await render(TestFixtureComponent);
208+
});
196209
});
197210

198211
test('waits for angular app initialization before rendering components', async () => {

0 commit comments

Comments
 (0)