### Install Dependencies Source: https://github.com/testing-library/angular-testing-library/blob/main/CONTRIBUTING.md Run this command in your terminal to install all necessary project dependencies after cloning the repository. ```bash npm install ``` -------------------------------- ### Run Tests Source: https://github.com/testing-library/angular-testing-library/blob/main/CONTRIBUTING.md Execute this command to run the library's tests and the example application's tests to ensure code quality. ```bash npm run test ``` -------------------------------- ### Install Angular Testing Library with npm Source: https://github.com/testing-library/angular-testing-library/blob/main/README.md Installs Angular Testing Library and @testing-library/dom as development dependencies using npm. Ensure these are installed for testing Angular applications. ```bash npm install --save-dev @testing-library/angular @testing-library/dom ``` -------------------------------- ### Add Angular Testing Library with ng add Source: https://github.com/testing-library/angular-testing-library/blob/main/README.md Uses the Angular CLI to add Angular Testing Library to your project. This command also installs @testing-library/dom and sets up the testing environment. ```bash ng add @testing-library/angular ``` -------------------------------- ### Build Library Source: https://github.com/testing-library/angular-testing-library/blob/main/CONTRIBUTING.md Run this command to build the library, typically done before testing or deploying changes. ```bash npm run build ``` -------------------------------- ### Programmatic Navigation with `navigate` Helper Source: https://context7.com/testing-library/angular-testing-library/llms.txt Demonstrates using the `navigate` helper function provided by `render` for programmatic navigation. This is useful for testing scenarios where navigation is triggered by logic rather than user interaction. ```typescript import { render, screen } from '@testing-library/angular'; import userEvent from '@testing-library/user-event'; import { RootComponent, DetailComponent } from './router-example'; test('uses navigate helper for programmatic navigation', async () => { const { navigate } = await render(RootComponent, { routes: [ { path: '', children: [ { path: 'detail/:id', component: DetailComponent }, ], }, ], }); // Navigate using the helper await navigate('/detail/one'); expect(screen.getByRole('heading', { name: /Detail one/i })).toBeInTheDocument(); // Navigate with query params await navigate('detail/two?text=Hello&subtext=World'); expect(screen.getByRole('heading', { name: /Detail two/i })).toBeInTheDocument(); expect(screen.getByText(/Hello World/i)).toBeInTheDocument(); }); ``` -------------------------------- ### Automatic Mocking with `provideMock` Source: https://context7.com/testing-library/angular-testing-library/llms.txt Demonstrates using `provideMock` to automatically create mock implementations for services. This simplifies setting up mocks for dependencies when you only need to verify method calls. ```typescript import { render, screen } from '@testing-library/angular'; import { TestBed } from '@angular/core/testing'; import { provideMock, createMock, Mock } from '@testing-library/angular/vitest-utils'; import userEvent from '@testing-library/user-event'; import { ComponentWithProviderComponent, CounterService } from './component-provider'; test('uses provideMock for automatic mocking', async () => { const user = userEvent.setup(); await render(ComponentWithProviderComponent, { componentProviders: [provideMock(CounterService)], }); await user.click(screen.getByRole('button', { name: /increment/i })); await user.click(screen.getByRole('button', { name: /increment/i })); const counterService = TestBed.inject(CounterService) as Mock; expect(counterService.increment).toHaveBeenCalledTimes(2); }); ``` -------------------------------- ### Set Inputs and Listen to Outputs Source: https://context7.com/testing-library/angular-testing-library/llms.txt Shows how to set component input properties, including aliased inputs, and subscribe to component output events using the `inputs` and `on` options during rendering. Useful for testing data flow and event handling. ```typescript import { render, screen, aliasedInput } from '@testing-library/angular'; import { vi } from 'vitest'; import userEvent from '@testing-library/user-event'; import { InputOutputComponent } from './input-output.component'; test('sets inputs and listens to outputs', async () => { const user = userEvent.setup(); const sendValueSpy = vi.fn(); await render(InputOutputComponent, { inputs: { value: 47, // For aliased inputs, use the aliasedInput helper ...aliasedInput('greeting', 'Hello World'), }, on: { sendValue: sendValueSpy, }, }); const incrementButton = screen.getByRole('button', { name: /increment/i }); const sendButton = screen.getByRole('button', { name: /send/i }); const valueDisplay = screen.getByTestId('value'); expect(valueDisplay).toHaveTextContent('47'); await user.click(incrementButton); await user.click(incrementButton); await user.click(incrementButton); expect(valueDisplay).toHaveTextContent('50'); await user.click(sendButton); expect(sendValueSpy).toHaveBeenCalledTimes(1); expect(sendValueSpy).toHaveBeenCalledWith(50); }); ``` -------------------------------- ### Render and Interact with Counter Component Source: https://context7.com/testing-library/angular-testing-library/llms.txt Demonstrates rendering a component with initial inputs and interacting with its elements using user events. Includes querying the DOM, asserting initial state, performing clicks, and debugging the rendered output. ```typescript import { render, screen } from '@testing-library/angular'; import userEvent from '@testing-library/user-event'; import { CounterComponent } from './counter.component'; test('renders and interacts with counter component', async () => { const user = userEvent.setup(); // Render the component with initial inputs const { fixture, detectChanges, debug } = await render(CounterComponent, { inputs: { counter: 5, }, }); // Query the DOM using screen const incrementButton = screen.getByRole('button', { name: /increment/i }); const decrementButton = screen.getByRole('button', { name: /decrement/i }); const valueDisplay = screen.getByTestId('value'); // Assert initial state expect(valueDisplay).toHaveTextContent('5'); // Interact with the component await user.click(incrementButton); await user.click(incrementButton); expect(valueDisplay).toHaveTextContent('7'); await user.click(decrementButton); expect(valueDisplay).toHaveTextContent('6'); // Debug output (prints DOM to console) debug(); }); ``` -------------------------------- ### Render Component Using Inline Template Source: https://context7.com/testing-library/angular-testing-library/llms.txt Demonstrates rendering a component directly from an inline template string, allowing for testing directives or specific template structures without a separate component class. Requires specifying imports and component properties. ```typescript import { render, screen } from '@testing-library/angular'; import userEvent from '@testing-library/user-event'; import { vi } from 'vitest'; import { InputOutputComponent } from './input-output.component'; test('renders component using inline template', async () => { const user = userEvent.setup(); const sendSpy = vi.fn(); await render('', { imports: [InputOutputComponent], componentProperties: { sendValue: sendSpy, }, }); const incrementButton = screen.getByRole('button', { name: /increment/i }); const sendButton = screen.getByRole('button', { name: /send/i }); await user.click(incrementButton); await user.click(incrementButton); await user.click(sendButton); expect(sendSpy).toHaveBeenCalledWith(49); }); ``` -------------------------------- ### Add Files for Commit Source: https://github.com/testing-library/angular-testing-library/blob/main/CONTRIBUTING.md Stage specific files for your next commit using 'git add filename'. Alternatively, use 'git add .' to stage all changes in the current directory and its subdirectories. ```bash git add filename ``` ```bash git add . ``` -------------------------------- ### Provide Custom Component-Level Dependencies Source: https://context7.com/testing-library/angular-testing-library/llms.txt Tests rendering a component with custom providers, such as mock services. This allows for isolated testing of component logic without relying on global or module-level configurations. ```typescript import { render, screen } from '@testing-library/angular'; import { TestBed } from '@angular/core/testing'; import { provideMock, createMock, Mock } from '@testing-library/angular/vitest-utils'; import userEvent from '@testing-library/user-event'; import { ComponentWithProviderComponent, CounterService } from './component-provider'; test('renders with custom provider implementation', async () => { const user = userEvent.setup(); const mockCounter = createMock(CounterService); let fakeValue = 50; mockCounter.increment.mockImplementation(() => (fakeValue += 10)); mockCounter.decrement.mockImplementation(() => (fakeValue -= 10)); mockCounter.value.mockImplementation(() => fakeValue); await render(ComponentWithProviderComponent, { componentProviders: [ { provide: CounterService, useValue: mockCounter }, ], }); const valueDisplay = screen.getByTestId('value'); expect(valueDisplay).toHaveTextContent('50'); await user.click(screen.getByRole('button', { name: /increment/i })); expect(valueDisplay).toHaveTextContent('60'); }); ``` -------------------------------- ### Push Changes to Fork Source: https://github.com/testing-library/angular-testing-library/blob/main/CONTRIBUTING.md Push your local commits to your forked repository on GitHub using 'git push'. ```bash git push ``` -------------------------------- ### Render Counter Component with Inputs Source: https://github.com/testing-library/angular-testing-library/blob/main/README.md Renders the CounterComponent and sets initial input values, including aliased inputs. Use this to test component initialization with specific states. ```typescript import { render, screen, fireEvent, aliasedInput } from '@testing-library/angular'; import { CounterComponent } from './counter.component'; describe('Counter', () => { it('should render counter', async () => { await render(CounterComponent, { inputs: { counter: 5, // aliases need to be specified this way ...aliasedInput('greeting', 'Hello Alias!'), }, }); expect(screen.getByText('Current Count: 5')).toBeVisible(); expect(screen.getByText('Hello Alias!')).toBeVisible(); }); it('should increment the counter on click', async () => { await render(CounterComponent, { inputs: { counter: 5 } }); const incrementButton = screen.getByRole('button', { name: '+' }); fireEvent.click(incrementButton); expect(screen.getByText('Current Count: 6')).toBeVisible(); }); }); ``` -------------------------------- ### Importing NgRx Store Modules Source: https://context7.com/testing-library/angular-testing-library/llms.txt Shows how to import NgRx store modules for components that rely on NgRx for state management. This is essential for testing components integrated with NgRx. ```typescript import { render, screen } from '@testing-library/angular'; import { StoreModule } from '@ngrx/store'; import userEvent from '@testing-library/user-event'; import { WithNgRxStoreComponent, reducer } from './with-ngrx-store'; test('works with NgRx store', async () => { const user = userEvent.setup(); await render(WithNgRxStoreComponent, { imports: [ StoreModule.forRoot( { value: reducer }, { runtimeChecks: {} }, ), ], }); const incrementButton = screen.getByRole('button', { name: /increment/i }); const decrementButton = screen.getByRole('button', { name: /decrement/i }); const valueDisplay = screen.getByTestId('value'); expect(valueDisplay).toHaveTextContent('0'); await user.click(incrementButton); await user.click(incrementButton); expect(valueDisplay).toHaveTextContent('20'); await user.click(decrementButton); expect(valueDisplay).toHaveTextContent('10'); }); ``` -------------------------------- ### Create Feature Branch Source: https://github.com/testing-library/angular-testing-library/blob/main/CONTRIBUTING.md Use this command to create a new branch for your feature development, following Git best practices. ```bash git checkout -b feature-branch-name ``` -------------------------------- ### Global Queries with 'screen' Source: https://context7.com/testing-library/angular-testing-library/llms.txt The 'screen' object provides all query functions bound to 'document.body', making it the recommended way to query elements without needing container references. It supports various query types like getBy, queryBy, and findBy for different assertion needs. ```typescript import { render, screen } from '@testing-library/angular'; import { MyComponent } from './my.component'; test('uses screen for queries', async () => { await render(MyComponent); // getBy* - throws if not found const heading = screen.getByRole('heading', { name: /welcome/i }); expect(heading).toBeInTheDocument(); // queryBy* - returns null if not found (no throw) expect(screen.queryByText('Not present')).not.toBeInTheDocument(); // findBy* - async, waits for element to appear const asyncContent = await screen.findByText('Loaded content'); expect(asyncContent).toBeInTheDocument(); // getAllBy* - returns array, throws if none found const buttons = screen.getAllByRole('button'); expect(buttons).toHaveLength(3); // queryAllBy* - returns array, empty if none found const links = screen.queryAllByRole('link'); expect(links).toHaveLength(0); }); ``` -------------------------------- ### Re-render Component with Partial Update Source: https://context7.com/testing-library/angular-testing-library/llms.txt Shows how to re-render a component while preserving existing properties using `partialUpdate: true`. Only the specified inputs are updated. ```typescript import { render, screen } from '@testing-library/angular'; import { FixtureComponent } from './fixture.component'; test('rerenders with partial update preserving existing props', async () => { const { rerender } = await render(FixtureComponent, { inputs: { firstName: 'Mark', lastName: 'Peeters', }, }); expect(screen.getByText('Mark Peeters')).toBeInTheDocument(); // Partial update - only firstName changes, lastName preserved await rerender({ inputs: { firstName: 'Chris' }, partialUpdate: true, }); expect(screen.getByText('Chris Peeters')).toBeInTheDocument(); }); ``` -------------------------------- ### Re-render Component with New Inputs Source: https://context7.com/testing-library/angular-testing-library/llms.txt Demonstrates re-rendering a component with updated input properties. Note that properties not provided in the update are removed by default. ```typescript import { render, screen } from '@testing-library/angular'; import { FixtureComponent } from './fixture.component'; test('rerenders component with new inputs', async () => { const { rerender } = await render(FixtureComponent, { inputs: { firstName: 'Mark', lastName: 'Peeters', }, }); expect(screen.getByText('Mark Peeters')).toBeInTheDocument(); // Rerender with new values (lastName will be removed) await rerender({ inputs: { firstName: 'Chris' }, }); expect(screen.getByText('Chris')).toBeInTheDocument(); expect(screen.queryByText('Peeters')).not.toBeInTheDocument(); }); ``` -------------------------------- ### Use Native Angular Bindings API Source: https://context7.com/testing-library/angular-testing-library/llms.txt Leverage Angular's native bindings API with `inputBinding`, `outputBinding`, and `twoWayBinding` for granular control over component inputs, outputs, and reactive data flow. This is useful for complex test scenarios. ```typescript import { signal, inputBinding, outputBinding, twoWayBinding } from '@angular/core'; import { render, screen } from '@testing-library/angular'; import { vi } from 'vitest'; import { BindingsApiComponent } from './bindings-api.component'; test('uses native bindings API', async () => { const submitHandler = vi.fn(); const nameSignal = signal('John'); await render(BindingsApiComponent, { bindings: [ inputBinding('greeting', () => 'Hello'), inputBinding('age', () => 25), twoWayBinding('name', nameSignal), outputBinding('submitValue', submitHandler), ], }); expect(screen.getByTestId('input-value')).toHaveTextContent('Hello John of 25 years old'); // Click submit screen.getByTestId('submit-button').click(); expect(submitHandler).toHaveBeenCalledWith('John'); }); ``` ```typescript test('two-way binding updates reactively', async () => { const nameSignal = signal('Initial'); await render(BindingsApiComponent, { bindings: [ inputBinding('greeting', () => 'Hello'), inputBinding('age', () => 25), twoWayBinding('name', nameSignal), ], }); expect(screen.getByDisplayValue('Initial')).toBeInTheDocument(); // Update signal externally nameSignal.set('Updated'); // Component updates reactively expect(await screen.findByDisplayValue('Updated')).toBeInTheDocument(); expect(screen.getByTestId('input-value')).toHaveTextContent('Hello Updated of 25 years old'); }); ``` -------------------------------- ### Configure Global Testing Defaults Source: https://context7.com/testing-library/angular-testing-library/llms.txt Set global defaults for all `render` calls using the `configure` function. This is useful for applying common imports or DOM Testing Library configurations across your entire test suite. Remember to reset configurations if necessary. ```typescript import { configure } from '@testing-library/angular'; import { CommonModule } from '@angular/common'; // In your test setup file (e.g., setup.ts) configure({ // Add default imports to all render calls defaultImports: [CommonModule], // Configure DOM Testing Library options dom: { testIdAttribute: 'data-test-id', }, }); // Reset configuration if needed configure({ defaultImports: [], dom: {}, }); ``` -------------------------------- ### Test Navigation Between Routes with Angular Router Source: https://context7.com/testing-library/angular-testing-library/llms.txt Tests navigation between different routes using links. Ensure routes are configured correctly in the render options. ```typescript import { render, screen } from '@testing-library/angular'; import userEvent from '@testing-library/user-event'; import { RootComponent, DetailComponent, HiddenDetailComponent } from './router-example'; test('navigates between routes', async () => { const user = userEvent.setup(); await render(RootComponent, { routes: [ { path: '', children: [ { path: 'detail/:id', component: DetailComponent }, { path: 'hidden-detail', component: HiddenDetailComponent }, ], }, ], }); expect(screen.queryByText(/Detail one/i)).not.toBeInTheDocument(); // Click navigation link await user.click(screen.getByRole('link', { name: /load one/i })); expect(await screen.findByRole('heading', { name: /Detail one/i })).toBeInTheDocument(); // Navigate to another route await user.click(screen.getByRole('link', { name: /load three/i })); expect(await screen.findByRole('heading', { name: /Detail three/i })).toBeInTheDocument(); }); ``` -------------------------------- ### Commit Changes Source: https://github.com/testing-library/angular-testing-library/blob/main/CONTRIBUTING.md Commit your staged changes locally with a descriptive message using 'git commit -m "your message"'. ```bash git commit -m "my changes here" ``` -------------------------------- ### Test Angular Defer Blocks with renderDeferBlock Source: https://context7.com/testing-library/angular-testing-library/llms.txt Control and test Angular's `@defer` blocks by manipulating their states using `renderDeferBlock` and `DeferBlockState`. This allows testing placeholder, loading, complete, and error states. ```typescript import { render, screen } from '@testing-library/angular'; import { DeferBlockState } from '@angular/core/testing'; import { DeferableViewComponent } from './deferable-view.component'; test('renders deferred views based on state', async () => { const { renderDeferBlock } = await render(DeferableViewComponent); // Initially shows placeholder expect(screen.getByText(/Hello from placeholder/i)).toBeInTheDocument(); // Transition to loading state await renderDeferBlock(DeferBlockState.Loading); expect(screen.getByText(/Hello from loading/i)).toBeInTheDocument(); // Transition to complete state (renders deferred content) await renderDeferBlock(DeferBlockState.Complete); expect(screen.getByText(/Hello from deferred child component/i)).toBeInTheDocument(); }); ``` ```typescript test('sets initial defer block state', async () => { await render(DeferableViewComponent, { deferBlockStates: DeferBlockState.Error, }); expect(screen.getByText(/Hello from error/i)).toBeInTheDocument(); }); ``` -------------------------------- ### Wait for Async Updates with waitFor and findBy Source: https://context7.com/testing-library/angular-testing-library/llms.txt Use `findBy` queries for single elements that appear asynchronously and `waitFor` for more complex assertions or retries. Both integrate with Angular's change detection. ```typescript import { render, screen, waitFor, fireEvent } from '@testing-library/angular'; import { AsyncComponent } from './async.component'; test('waits for async content to appear', async () => { await render(AsyncComponent); expect(screen.queryByText('Success')).not.toBeInTheDocument(); fireEvent.click(screen.getByTestId('load-button')); // Using findBy (recommended for single element) expect(await screen.findByText('Success')).toBeInTheDocument(); }); ``` ```typescript test('uses waitFor for complex assertions', async () => { await render(AsyncComponent); fireEvent.click(screen.getByTestId('load-button')); // waitFor retries the assertion until it passes or times out await waitFor(() => { expect(screen.getByText('Success')).toBeInTheDocument(); expect(screen.getByTestId('status')).toHaveTextContent('loaded'); }); }); ``` ```typescript test('configures waitFor timeout', async () => { await render(AsyncComponent); fireEvent.click(screen.getByTestId('load-button')); // Expect timeout if element doesn't appear within 200ms await expect( waitFor(() => screen.getByText('Success'), { timeout: 200 }) ).rejects.toThrow(/Unable to find an element/i); }); ``` -------------------------------- ### Test Angular Directive with Inline Template Source: https://context7.com/testing-library/angular-testing-library/llms.txt Tests a directive by rendering it within an inline HTML template. Verifies directive behavior through DOM interactions like hover events. ```typescript import { Component } from '@angular/core'; import { render, screen } from '@testing-library/angular'; import userEvent from '@testing-library/user-event'; import { SpoilerDirective } from './spoiler.directive'; test('tests directive with inline template', async () => { const user = userEvent.setup(); await render('
', { imports: [SpoilerDirective], }); const directive = screen.getByTestId('spoiler'); expect(screen.queryByText('I am visible now...')).not.toBeInTheDocument(); expect(screen.getByText('SPOILER')).toBeInTheDocument(); await user.hover(directive); expect(screen.queryByText('SPOILER')).not.toBeInTheDocument(); expect(screen.getByText('I am visible now...')).toBeInTheDocument(); await user.unhover(directive); expect(screen.getByText('SPOILER')).toBeInTheDocument(); }); ``` -------------------------------- ### Test Angular Directive with Custom Properties Source: https://context7.com/testing-library/angular-testing-library/llms.txt Tests a directive by passing custom input properties ('hidden' and 'visible') via component properties. Verifies that the directive's content changes based on these props. ```typescript import { Component } from '@angular/core'; import { render, screen } from '@testing-library/angular'; import userEvent from '@testing-library/user-event'; import { SpoilerDirective } from './spoiler.directive'; test('tests directive with custom props', async () => { const user = userEvent.setup(); const hidden = 'SPOILER ALERT'; const visible = 'Content revealed!'; await render('
', { imports: [SpoilerDirective], componentProperties: { hidden, visible, }, }); expect(screen.getByText(hidden)).toBeInTheDocument(); await user.hover(screen.getByText(hidden)); expect(screen.getByText(visible)).toBeInTheDocument(); }); ``` -------------------------------- ### Test Angular Form Validation and Submission Source: https://context7.com/testing-library/angular-testing-library/llms.txt Tests an Angular form, including initial validation errors, filling form fields, and verifying that validation passes. Asserts form values after user interactions. ```typescript import { render, screen, fireEvent } from '@testing-library/angular'; import userEvent from '@testing-library/user-event'; import { FormsComponent } from './forms.component'; test('fills form and validates errors', async () => { const user = userEvent.setup(); await render(FormsComponent); const nameInput = screen.getByRole('textbox', { name: /name/i }); const scoreInput = screen.getByRole('spinbutton', { name: /score/i }); const colorSelect = screen.getByRole('combobox', { name: /color/i }); const errors = screen.getByRole('alert'); // Check initial validation errors expect(errors).toContainElement(screen.queryByText('name is required')); expect(errors).toContainElement(screen.queryByText('score must be greater than 1')); expect(nameInput).toBeInvalid(); // Fill form await user.type(nameInput, 'Tim'); await user.clear(scoreInput); await user.type(scoreInput, '7'); fireEvent.blur(scoreInput); await user.selectOptions(colorSelect, 'G'); // Verify validation passes expect(screen.queryByText('name is required')).not.toBeInTheDocument(); expect(nameInput).toHaveValue('Tim'); expect(scoreInput).toHaveValue(7); expect(scoreInput).toBeValid(); // Verify form values const form = screen.getByRole('form'); expect(form).toHaveFormValues({ name: 'Tim', score: 7, color: 'G', }); }); ``` -------------------------------- ### Scoped Queries with 'within' Source: https://context7.com/testing-library/angular-testing-library/llms.txt Use 'within' to scope queries to a specific container element. This is useful for testing repeated patterns or nested components. Ensure the container element is correctly identified. ```typescript import { render, screen, within } from '@testing-library/angular'; import { ListComponent } from './list.component'; test('queries within specific containers', async () => { await render(ListComponent, { inputs: { items: [ { id: 1, name: 'Item 1', status: 'active' }, { id: 2, name: 'Item 2', status: 'inactive' }, ], }, }); const firstItem = screen.getByTestId('item-1'); const secondItem = screen.getByTestId('item-2'); // Query within first item only expect(within(firstItem).getByText('active')).toBeInTheDocument(); expect(within(firstItem).queryByText('inactive')).not.toBeInTheDocument(); // Query within second item only expect(within(secondItem).getByText('inactive')).toBeInTheDocument(); expect(within(secondItem).queryByText('active')).not.toBeInTheDocument(); }); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.