@s-libs/ng-vitest
    Preparing search index...

    Class ComponentContext<T>

    Provides the foundation for an opinionated pattern for component tests.

    • Includes all features from AngularContext
    • Automatically creates your component at the beginning of run().
    • Sets up Angular change detection and lifecycle hooks like it would in production. This covers cases you would normally have to trigger manually if you use the standard TestBed.createComponent() directly.
    • Wraps your component in a parent that you can easily style however you like.
    • Lets you use component harnesses with Vitest's fake timers, which is normally a challenge.
    • Causes async APP_INITIALIZERs to complete before instantiating the component. A caveat, they must not include a setTimeout delay, or the test will hang.

    A very simple example:

    @Component({ template: 'Hello, {{name()}}!' })
    class GreeterComponent {
    readonly name = input.required<string>();
    }

    it('greets you by name', async () => {
    const ctx = new ComponentContext(GreeterComponent);
    await ctx.assignInputs({ name: 'World' });
    await ctx.run(() => {
    expect(ctx.fixture.nativeElement.textContent).toBe('Hello, World!');
    });
    });

    A full example, with routing and a component harness. This is the full code for a tiny Angular app:

     /////////////////
    // app-context.ts

    // To re-use your context setup, make a subclass of ComponentContext to import into any spec
    class AppContext extends ComponentContext<AppComponent> {
    constructor() {
    // Import `appConfig` from `app.config.ts`
    super(AppComponent, appConfig);
    }
    }

    ////////////////////////
    // app.component.spec.ts

    describe('AppComponent', () => {
    let ctx: AppContext;
    beforeEach(() => {
    ctx = new AppContext();
    });

    it('can navigate to the first page', async () => {
    await ctx.run(async () => {
    const app = await ctx.getHarness(AppComponentHarness);
    await app.navigateToFirstPage();
    expect(ctx.fixture.nativeElement.textContent).toContain(
    'First works!',
    );
    });
    });
    });

    ///////////////////////////
    // app.component.harness.ts

    // A simple component harness to demonstrate its integration with component contexts
    class AppComponentHarness extends ComponentHarness {
    static hostSelector = 'app-root';

    #getFirstPageLink = this.locatorFor('a');

    async navigateToFirstPage(): Promise<void> {
    const link = await this.#getFirstPageLink();
    await link.click();
    }
    }

    /////////////////////
    // first.component.ts

    // A minimal component for demonstration purposes
    @Component({ template: '<p>First works!</p>' })
    class FirstComponent {}

    ///////////////////
    // app.component.ts

    // A minimal app component with routing for demonstration purposes
    @Component({
    selector: 'app-root',
    imports: [RouterOutlet, RouterLink],
    template: `
    <a routerLink="/first-page">First Page</a>
    <router-outlet />
    `,
    })
    class AppComponent {}

    ////////////////////////
    // app.routes.ts

    const routes: Routes = [{ path: 'first-page', component: FirstComponent }];

    ////////////////
    // app.config.ts

    const appConfig: ApplicationConfig = { providers: [provideRouter(routes)] };

    Type Parameters

    • T

    Hierarchy (View Summary)

    Index

    Constructors

    Properties

    fixture: ComponentFixture<unknown>

    The ComponentFixture for a synthetic wrapper around your component. Available within the callback to run().

    startTime: Date = ...

    Set this before calling run() to mock the time at which the test starts.

    Methods

    • Assign inputs to your component. Can be called before run() to set the initial inputs, or within run() to update them and trigger all the appropriate change detection and lifecycle hooks.

      Parameters

      • inputs: Inputs<T>

      Returns Promise<void>

    • Assign CSS styles to the div wrapping your component. Can be called before or during run(). Accepts an object with the same structure as the ngStyle directive.

      ctx.assignWrapperStyles({
      width: '400px',
      height: '600px',
      margin: '20px auto',
      border: '1px solid',
      });

      Parameters

      • styles: Record<string, unknown>

      Returns Promise<void>

    • Runs test with fake timers enabled. It can use async/await, but be sure anything you await is already due to execute (e.g. if a timeout is due in 3 seconds, call .tick(3000) before awaiting its result).

      Also runs the following in this order:

      1. this.init()
      2. test()
      3. this.verifyPostTestConditions()
      4. this.cleanUp()

      Parameters

      • test: () => void | Promise<void>

      Returns Promise<void>