Skip to content

teardown.destroyAfterEach breaks change detection when false #444

Open
@NechiK

Description

@NechiK

Hi,

This issue is related to this thread.

I'm writing a test for a form wizard using Angular Testing Library, and my approach involves splitting each test case using the it or describe methods. To avoid mocking the user session and other application parts, I render the <app-root></app-root> component in beforeAll. This allows me to lead my test to the wizard and test each step.

However, Angular clears/destroys the component/view/app after each it call. This means that if I move all preparations (login, navigation to the wizard, etc.) to the first it and start testing the wizard in the next calls, the whole progress will be lost, and the view will contain only the body tag.

Thanks to @timdeschryver, I could avoid this behavior and turn off view destroying after each it call using the next configuration:

configureTestBed: (testBed): void => {
  testBed.configureTestingModule(
    {
      teardown: { destroyAfterEach: false },
    },
  );
},

But it looks like this configuration breaks change detection because nothing happens if I enter any data into the form or want to navigate.

Here's what my test looks like:

import { AppComponent } from './app.component';
import { RenderResult, render, screen } from '@testing-library/angular';
import { APP_ROUTES } from './app.routes';
import { userEvent } from '@testing-library/user-event';

describe('AppComponent', () => {
  const user = userEvent.setup();
  let component: RenderResult<AppComponent>;

  beforeAll(async () => {
    component = await render('<app-root></app-root>', {
      imports: [
        AppComponent,
      ],
      routes: APP_ROUTES,
      // This configuration keeps the component instance and render results between tests
      // But breaks change detection
      configureTestBed: (testBed): void => {
        testBed.configureTestingModule(
          {
            teardown: { destroyAfterEach: false },
          },
        );
      },
    });

    component.detectChanges();
  });

  it('should render loginBtn', () => {
    const loginBtn: HTMLButtonElement = component.getByText('Login').closest('button')!;
    expect(loginBtn).toBeTruthy();
  });

  it('should disable login button by default', () => {
    const loginBtn: HTMLButtonElement = component.getByText('Login').closest('button')!;
    expect(loginBtn.disabled).toBeTruthy();
  });

  it('should enter username value', async () => {
    const usernameInput: HTMLInputElement = screen.getByLabelText(/Username/i);

    await user.type(usernameInput, 'John Doe');
    expect(usernameInput.value).toBe('John Doe');
  });

  it('should have username value entered before, enter password and enable button', async () => {
    const usernameInput: HTMLInputElement = screen.getByLabelText(/Username/i);
    const passwordInput: HTMLInputElement = screen.getByLabelText(/Password/i);

    // Have username value entered before
    expect(usernameInput.value).toBe('John Doe');

    await user.type(passwordInput, 'mysuperpassword');
    expect(passwordInput.value).toBe('mysuperpassword');

    const loginBtn: HTMLButtonElement = component.getByText('Login').closest('button')!;

    // This test is failing because the change detection is not working when teardown.destroyAfterEach is set to false
    expect(loginBtn.disabled).toBeFalsy();
  });
});

I've created a repo with minimal reproduction code (not from a real app) and left a few comments there.

The main goal I want to achieve is to have one big test for each functionality in my app but be able to split each such test by test cases using it and describe to have better readability and maintenance.

P.S. @timdeschryver also suggested using ATL_SKIP_AUTO_CLEANUP, but it doesn't work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions