{"id":13660915,"url":"https://github.com/Ninja-Squad/ngx-speculoos","last_synced_at":"2025-04-24T23:31:03.693Z","repository":{"id":38454505,"uuid":"134071461","full_name":"Ninja-Squad/ngx-speculoos","owner":"Ninja-Squad","description":"Simpler, cleaner Angular unit tests ","archived":false,"fork":false,"pushed_at":"2025-04-21T15:24:22.000Z","size":12664,"stargazers_count":76,"open_issues_count":3,"forks_count":3,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-21T16:32:10.304Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://ngx-speculoos.ninja-squad.com/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ninja-Squad.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-05-19T14:55:50.000Z","updated_at":"2025-04-21T15:24:26.000Z","dependencies_parsed_at":"2023-09-27T22:40:09.485Z","dependency_job_id":"98c82562-4091-437f-af2c-61affa29689a","html_url":"https://github.com/Ninja-Squad/ngx-speculoos","commit_stats":{"total_commits":1347,"total_committers":7,"mean_commits":"192.42857142857142","dds":"0.30586488492947295","last_synced_commit":"6e4f2c4eeff4d6f12702e94a331f3c547c4ca77a"},"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ninja-Squad%2Fngx-speculoos","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ninja-Squad%2Fngx-speculoos/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ninja-Squad%2Fngx-speculoos/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ninja-Squad%2Fngx-speculoos/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ninja-Squad","download_url":"https://codeload.github.com/Ninja-Squad/ngx-speculoos/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250727522,"owners_count":21477324,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T05:01:27.356Z","updated_at":"2025-04-24T23:31:03.686Z","avatar_url":"https://github.com/Ninja-Squad.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","Testing"],"sub_categories":["Component"],"readme":"[![CircleCI](https://circleci.com/gh/Ninja-Squad/ngx-speculoos.svg?style=svg)](https://circleci.com/gh/Ninja-Squad/ngx-speculoos)\n[![Codecov](https://codecov.io/gh/Ninja-Squad/ngx-speculoos/branch/master/graph/badge.svg)](https://codecov.io/gh/Ninja-Squad/ngx-speculoos)\n\n# ngx-speculoos\n\nngx-speculoos helps you write simpler, cleaner unit tests for your Angular components, based on the\n*page object* pattern. It also provides utilities to make writing Angular unit tests easier.\n\nThe library simply wraps the standard Angular ComponentFixture, and you should thus be\nable to understand and start using ngx-speculoos in just a few minutes if you already know\nhow to write Angular unit tests.\n\n## Table of Contents\n\n- [Quick presentation](#quick-presentation)\n  - [Why should you care?](#why-should-you-care)\n  - [Installation](#installation)\n  - [Getting started](#getting-started)\n- [Features in details](#features-in-details)\n  - [ComponentTester](#componenttester)\n  - [Automatic change detection](#automatic-change-detection)\n  - [Queries](#queries)\n    - [Queries for elements](#queries-for-elements)\n    - [CSS and Type selectors](#css-and-type-selectors)\n    - [Queries for sub components](#queries-for-sub-components)\n    - [Queries for injection tokens](#queries-for-injection-tokens)\n    - [Queries for custom TestElement](#queries-for-custom-testelement)\n    - [Subqueries](#subqueries)\n  - [Dispatching events](#dispatching-events)\n  - [Custom Jasmine matchers](#custom-jasmine-matchers)\n  - [Routing helpers](#routing-helpers)\n    - [ActivatedRoute stub](#activatedroute-stub)\n    - [RoutingTester](#routingtester)\n  - [Mocking helper](#mocking-helper)\n  - [Testing with a host component](#testing-with-a-host-component)\n- [Gotchas](#gotchas)\n  - [When do I need to call detectChanges()](#when-do-i-need-to-call-change-or-detectchanges)\n  - [Can I use the TestElement methods to act on the component element itself, rather than a sub-element?](#can-i-use-the-testelement-methods-to-act-on-the-component-element-itself-rather-than-a-sub-element)\n- [Issues, questions](#issues-questions)\n- [Complete example](#complete-example)\n- [Upgrading to v13](#upgrading-to-v13)\n\n## Quick presentation\n\n### Why should you care?\n\nIf you've ever written tests like the following:\n\n```typescript\nit('should display French cities when selecting the country France', () =\u003e {\n  const countrySelect = fixture.nativeElement.querySelector('#country'); // countrySelect is of type any\n  countrySelect.selectedIndex = 12; // what is at index 12?\n  countrySelect.dispatchEvent(new Event('change')); // why do I need to do that?\n  fixture.detectChanges();\n  \n  const city = fixture.nativeElement.querySelector('#city'); // city is of type any\n  expect(city).toBeTruthy();\n  expect(city.options.length).toBe(3);\n  expect(city.options[0].value).toBe('');\n  expect(city.options[0].label).toBe('');\n  expect(city.options[1].value).toBe('PARIS');\n  expect(city.options[1].label).toBe('Paris');\n  expect(city.options[2].value).toBe('LYON');\n  expect(city.options[2].label).toBe('Lyon');\n});\n\nit('should hide cities when selecting the empty country option', () =\u003e {\n  const countrySelect = fixture.nativeElement.querySelector('#country'); // I did that previously. What about DRY?\n  countrySelect.selectedIndex = 0;\n  countrySelect.dispatchEvent(new Event('change')); // why do I need to do that?\n  fixture.detectChanges(); // why do I need to do that?\n  \n  expect(fixture.nativeElement.querySelector('#city')).toBeFalsy(); // I did that previously. What about DRY?\n});\n```\n\nngx-speculoos allows writing the above tests in a simpler, cleaner way:\n\n- by using the page object pattern (which is optional, but recommended), you avoid repetitions.\n- by using wrappers around elements, dispatching events and triggering change detection is automatic.\n- by using wrappers around elements, you get useful additional methods to make tests easier to write and read.\n- by using custom matchers, you get even simpler expectations and more readable error messages\n- in any case you need them, you always have access to the fixture, the native elements, the debug elements, etc.\n\n```typescript\nclass MyComponentTester extends ComponentTester\u003cMyComponent\u003e {\n  constructor() {\n    super(MyComponent);\n  }\n  \n  get country() {\n    return this.select('#country'); // returns a TestSelect object, not any. Similar methods exist for inputs, buttons, etc.\n  }\n  \n  get city() {\n    return this.select('#city'); // returns a TestSelect object, not any\n  }\n}\n\n[...]\n\nit('should display French cities when selecting the country France', () =\u003e {\n  tester.country.selectLabel('France'); // no dispatchEvent, no detectChanges needed\n  \n  expect(tester.city.optionValues).toEqual(['', 'PARIS', 'LYON']);\n  expect(tester.city.optionLabels).toEqual(['', 'Paris', 'Lyon']);\n});\n\nit('should hide cities when selecting empty country option', () =\u003e {\n  tester.country.selectIndex(0); // no repetition of the selector, no dispatchEvent, no detectChanges needed\n  \n  expect(tester.city).toBeFalsy(); // no repetition of the selector\n});\n```\n\n### Installation\n\nUsing the CLI: `ng add ngx-speculoos`\n\nUsing npm: `npm install --save-dev ngx-speculoos`\n\nUsing yarn: `yarn add --dev ngx-speculoos`\n\n### Getting started\n\n- import ComponentTester, and other needed classes from ngx-speculoos\n- Create a `MyComponentTester` class (in your `my-component.spec.ts` file, typically) extending\n  `ComponentTester\u003cMyComponent\u003e`, as shown above.\n- Expose getters (or methods, if you prefer) returning the elements used in your tests, using\n  one of the ComponentTester methods (`element`, `elements`, `input`, `select`, `textarea`, `button`, etc.).\n  See the [API documentation](https://ngx-speculoos.ninja-squad.com/documentation/classes/ComponentTester.html) for details\n- Write your tests, as shown above, benefiting from the additional methods on the TestXxx classes.\n- If needed, you can always get the fixture, componentInstance, debugElement, nativeElement, etc.\n  from the ComponentTester, and the nativeElement from each TestXxx wrapper.\n- If you like our custom matchers, add them in a `beforeEach` block as shown above, and enjoy.\n  You can also add them for all tests at once by adding the beforeEach block to the CLI-generated `test.ts` file.\n\n## Features in details\n\n### ComponentTester\n\nThis is the entry point for most of the functionalities of ngx-speculoos. It wraps a `ComponentFixture`.\nYou can simply create one in your tests using\n\n```typescript\nconst tester = new ComponentTester(MyComponent);\n```\n\nand then use it to query for sub elements, components, directives, etc. But we recommend adopting the\npage object pattern, in order to make your test easier to write and read, and to avoid repeating the\nsame selectors over and over again.\n\nYou do that by writing a class that extends `ComponentTester`, and provides getters (or functions)\nto query for elements, components, etc.\n\n```typescript\nclass MyComponentTester extends ComponentTester\u003cMyComponent\u003e {\n  constructor() {\n    super(MyComponent);\n  }\n  \n  get country() {\n    return this.select('#country'); // returns a TestSelect object, not any. Similar methods exist for inputs, buttons, etc.\n  }\n  \n  get city() {\n    return this.select('#city'); // returns a TestSelect object, not any\n  }\n}\n```\n\nand then in your tests, or in your `beforeEach`, once you've configured the testing module, you create\nan instance of your component tester.\n\n```typescript\ndescribe('My component', () =\u003e {\n  let tester: MyComponentTester;\n\n  beforeEach(() =\u003e {\n    TestBed.configureTestingModule({\n      declarations: [MyComponent],\n      ...\n    });\n\n    tester = new MyComponentTester();\n    tester.change();\n  });\n\n  it('should ...', () =\u003e {\n\n  });\n});\n```\n\n### Automatic change detection\n\nThe future of Angular is zoneless. Without ZoneJS, components have to make sure to properly notify\nAngular that they must be checked for changes, typically by updating signals.\nInstead of imperatively triggering change detections in tests, it's thus a better idea to let\nAngular decide if change detection must be run, in order to spot bugs where the component doesn't\nproperly handle its state changes.\n\nThis can be done by:\n\n- adding a provider in the testing module to configure the fixtures to be in _automatic_ mode,\n  or to use zoneless change detection\n- awaiting the component fixture stability when the test *thinks* that a change detection should\n  automatically happen.\n\nWhen the `provideAutomaticChangeDetection()` or the `provideExperimentalZonelessChangeDetection()` \nprovider is added, the `ComponentTester` will run in\n_automatic_ mode. In this mode, calling `detectChanges()` throws an error, because you should always\nlet Angular decide if change detection is necessary.\n\nHere's an example of a test that uses this technique:\n\n```ts\nclass AppComponentTester extends ComponentTester\u003cAppComponent\u003e {\n  constructor() {\n    super(AppComponent);\n  }\n\n  get incrementButton() {\n    return this.button('button');\n  }\n\n  get count() {\n    return this.element('#count');\n  }\n}\n\ndescribe('AppComponent', () =\u003e {\n  let tester: AppComponentTester;\n\n  beforeEach(async () =\u003e {\n    TestBed.configureTestingModule({\n      providers: [\n        provideComponentFixtureAutoDetection()\n        // or provideExperimentalZonelessChangeDetection() if you already use zoneless\n      ]\n    });\n\n    jasmine.addMatchers(speculoosMatchers);\n    \n    tester = new AppComponentTester();\n    // a first call to change() is necessary to let Angular run its first change detection\n    await tester.change();\n  });\n\n  it('should display the counter value and increment it', async () =\u003e {\n    expect(tester.count).toHaveText('0');\n    \n    // this clicks the button and then lets Angular decide if a CD is necessary, and waits until\n    // the DOM has been updated (or not)\n    await tester.incrementButton.click();\n    \n    expect(tester.count).toHaveText('1');\n  });\n});\n```\n\nIn _automatic_ mode, your test functions should be `async`, and each action you do with the elements\n(`click()`, `dispatchEvent`, etc.) should be awaited.\n\n### Queries\n\n#### Queries for elements\n\nMost of the queries that ngx-speculoos supports are used to query for DOM elements. The queries, however,\ndon't actually returns native DOM elements, but wrappers around them, which are instances of `TestElement`.\n\n`TestElement` has more specialized subclasses: `TestHtmlElement`, `TestInput`, `TestSelect`, `TestTextarea`, `TestButton`.\nThose subclasses offer helpful methods to get information or dispatch events to HTML elements, inputs, selects, etc.\nOur custom matchers act on those `TestElement` objects.\n\nYou can [create your own subclasses of TestElement](#queries-for-custom-testelement) and query for them, too.\n\nA TestElement is a wrapper around an Angular `DebugElement`. So it can access the `DebugElement` and the\nnative DOM element that it wraps. It also has an instance of the `ComponentTester` which created it,\nwhich itself wraps the Angular `ComponentFixture` and thus allows detecting changes automatically after\nan element has been dispatched, for example.\n\n#### CSS and Type selectors\n\nThe first kind of query uses CSS selectors. This is simply a wrapper around Angular's `DebugElement.query(By.css())`.\nThe second kind of query uses directive types. This is simply a wrapper around Angular's `DebugElement.query(By.directive())`.\n\nWhatever the kind of selector you choose, the methods are the same though:\n\n- `element(selector)` to get the first element matching the selector\n- `elements(selector)` to get an array of elements matching the selector\n\nBoth of those methods will automatically return a `TestInput`, or a `TestSelect`, or any other `TestElement`\nsubclass that ngx-speculoos provides based on the actual type of element being matched. But if you know\nin advance what the result of the query is, you can use more-specific methods, or their generic parameter.\nPassing an HTML element name as selector also automatically returns the right type\n\n- `input(selector)` returns a `TestInput`\n- `textarea(selector)` returns a `TestTextarea`\n- `select(selector)` returns a `TestSelect`\n- `button(selector)` returns a `TestButton`\n- `element\u003cHtmlInputElement\u003e(selector)` returns a `TestInput`\n- `element\u003cHtmlDivElement\u003e(selector)` returns a `TestHtmlElement\u003cHtmlDivElement\u003e`\n- `elements\u003cHtmlButtonElement\u003e(selector)` returns an `Array\u003cTestButton\u003e`\n- `element('input')` returns a `TestInput`\n\n#### Queries for sub components\n\nIt's often useful to get the component instance of a sub component, for example to inspect its state,\nor to make one of its outputs emit something. You can do that using the `component` and `components`\nmethods:\n\n```typescript\nget productIcon() {\n  return this.component(ProductIconComponent); // returns a ProductIconComponent \n}\n\nget reviewers() {\n  return this.components(ReviewerComponent); // returns an Array\u003cReviewerComponent\u003e \n}\n```\n\n#### Queries for injection tokens\n\nQuerying using `element(DatepickerDirective)` will return you a `TestElement` on which the\n`DatepickerDirective` has been applied.\n\nIf you need to get the `Datepicker` directive instance itself, then use the `token()` method\n(or `tokens()` to get several of them)\nwhich takes a selector (CSS or type) as first argument, and the token as second argument:\n\n```typescript\nget datepicker() {\n  return this.token('#birth-date', DatepickerDirective); // returns a DatepickerDirective instance\n}\n```\n\n#### Queries for custom `TestElement`\n\nWe provide `TestInput`, `TestSelect`, etc. to easily inspect or interact with inputs and selects in our tests.\nBut what if you want the same kind of test abstraction for your own reusable components or directives, like\nfor example your `DatepickerDirective`.\n\nYou can create your own `TestElement` subclass for that. This subclass must have a constructor that\ntakes a `ComponentTester` as first argument, and a `DebugElement` as second argument.\n\n```typescript\nclass TestDatepicker extends TestHtmlElement\u003cHTMLElement\u003e {\n  constructor(tester: ComponentTester\u003cunknown\u003e, debugElement: DebugElement) {\n    super(tester, debugElement);\n  }\n\n  get inputField() {\n    return this.input('input');\n  }\n\n  async setDate(year: number, month: number, day: number) {\n    await this.inputField.fillWith(`${year}-${month}-${day}`);\n  }\n\n  async toggleDropdown() {\n    await this.button('button').click();\n  }\n}\n```\n\nOnce you have created that class, you can use the `custom()` and `customs()` methods, using any selector,\nto get instances of your custom `TestElement``\n\n```typescript\nget birthDate() {\n  return this.custom('#birth-date', TestDatepicker);\n}\n```\n\n```typescript\nit('should not save if birth date is in the future', () =\u003e {\n  // ...\n  tester.birthDate.setDate(2200, 1, 1);\n  tester.save.click();\n  expect(userService.create).not.toHaveBenCalled();\n});\n```\n\nor, in _automatic_ mode\n\n```typescript\nit('should not save if birth date is in the future', async () =\u003e {\n  // ...\n  await tester.birthDate.setDate(2200, 1, 1);\n  await tester.save.click();\n  expect(userService.create).not.toHaveBenCalled();\n});\n```\n\n\n#### Subqueries\n\nA query is made from the root `ComponentTester`. But `TestElement` themselves also support queries.\nSo you can query for a parent `TestElement`, and then use it to perform subqueries:\n\n```typescript\nget cardEditButton() {\n  return this.element('.card').button('.edit');\n}\n\nget cardReviewerComponent() {\n  return this.element('.card').component(ReviewerComponent);\n}\n```\n\n### Custom Jasmine matchers\n\nWe provide custom matchers, that act on `TestElement` and on its more specific subclasses (`TestInput`, `TestSelect`, etc.).\n\nThe complete matcher list includes:\n\n- `toHaveClass(className: string)`\n- `toHaveValue(value: string)`\n- `toHaveText(textContent: string)`\n- `toHaveTrimmedText(textContent: string)`\n- `toContainText(textContent: string)`\n- `toBeChecked()`\n- `toHaveSelectedIndex(index: number)`\n- `toHaveSelectedValue(value: string)`\n- `toHaveSelectedLabel(label: string)`\n- `toBeVisible()`\n\nThese matchers must be installed in each test using them:\n\n```typescript\nbeforeEach(() =\u003e jasmine.addMatchers(speculoosMatchers));\n```\n\nor in all tests, by adding the above line of code in the `test.ts` file.\n\n### Dispatching events\n\n`TestElement` provides two methods that allow dispatching events in a simple way.\n\n- `dispatchEvent(event: Event)`\n- `dispatchEventOfType(type: string)`\n\nGoing through these methods automatically calls `detectChanges()` on the `ComponentTester` after the event has been dispatched,\nso you don't need to call that yourself.\n\nThe TestElement subclasses that we provide have more specific event dispatching methods.\nFor example\n\n- `TestHtmlElement.click()`\n- `TestInput.fillWith()` for text, password, number, etc.\n- `TestInput.check()` for radios and checkboxes\n- `TestInput.uncheck()` for checkboxes\n- `TestTextarea.fillWith()`\n- `TestSelect.selectIndex()`\n- `TestSelect.selectValue()`\n- `TestSelect.selectLabel()`\n\nCreating your own TestElement subclasses is a good way to provide such custom methods to interact\nwith your own reusable components in tests.\n\n### Routing helpers\n\n#### ActivatedRoute stub\n\nThe library provides a stub for the `ActivatedRoute` class that you typically inject in your routed components.\nIt mimics the behavior of the actual `ActivatedRoute`, by having a snapshot and observables that emit when this\nsnapshot changes. And it also allows simulating navigations by imperatively changing the parameters, query parameters,\netc.\n\n```typescript\nimport { ActivatedRouteStub } from 'ngx-speculoos';\n\nclass RoutingComponentTester extends ComponentTester\u003cRoutingComponent\u003e {\n  // ...\n}\n\ndescribe('routing component', () =\u003e {\n  let route: ActivatedRouteStub;\n  let tester: RoutingComponentTester;\n  \n  beforeEach(() =\u003e {\n    route = stubRoute({\n      params: { categoryId: 'pets' }\n    });\n    \n    TestBed.configureTestingModule({\n      declarations: [RoutingComponent],\n      providers: [\n        { provide: ActivatedRoute, useValue: route }\n      ]\n    });\n    \n    tester = new RoutingComponentTester();\n    tester.detectChanges();\n  });\n  \n  it('should display all the products of the category', () =\u003e {\n    // test based on the initial route state\n  });\n\n  it('should load other products when the category changes or when the query changes', () =\u003e {\n    route.setParam('category', 'toys');\n    tester.detectChanges();\n    // ...\n\n    route.setQueryParams({ 'max-price': '30', target: 'children' });\n    tester.detectChanges();\n    // ...\n  });\n});\n```\n\n#### RoutingTester\n\nAn alternative approach to injecting a stub activated route consists in using the Angular `RouterTestingHarness`.\nThe library helps using it by providing a `RoutingTester`, which is a `ComponentTester` wrapping the\n`RouterTestingHarness` in addition to wrapping its fixture, and additionally provides helper properties.\n\nHere's an example usage of a component displaying the value of the query parameter `'page'` and allowing\nto navigate to itself with a different value for that query parameter.\n\n```typescript\nclass PageComponentTester extends RoutingTester {\n  constructor(harness: RouterTestingHarness) {\n    super(harness);\n  }\n\n  get title() {\n    return this.element('h1');\n  }\n\n  get link() {\n    return this.element('a');\n  }\n}\n\ndescribe('RoutingTester', () =\u003e {\n  beforeEach(() =\u003e {\n    TestBed.configureTestingModule({\n      providers: [\n        provideRouter([\n          { path: 'list', component: PageComponent }\n        ])\n      ]\n    });\n  });\n\n  it('should display the page of the query params', async () =\u003e {\n    const tester = new PageComponentTester(await RouterTestingHarness.create('/list?page=42'));\n\n    expect(tester.title).toHaveText('Current page: 42');\n\n    await tester.harness.navigateByUrl('/list?page=54');\n\n    expect(tester.title).toHaveText('Current page: 54');\n  });\n\n  it('should navigate to the next page when clicking the link', async () =\u003e {\n    const tester = new PageComponentTester(await RouterTestingHarness.create('/list?page=42'));\n\n    expect(tester.title).toHaveText('Current page: 42');\n\n    tester.link.click();\n    await tester.stable();\n\n    expect(tester.urlTree.queryParamMap.get('page')).toBe('43');\n    expect(tester.url).toBe('/list?page=43');\n    expect(tester.title).toHaveText('Current page: 43');\n  });\n});\n\n```\n\n### Mocking helper\n\nJasmine is quite verbose when creating mock objects in a typesafe way:\n\n```typescript\nconst productService = jasmine.createSpyObj\u003cProductService\u003e('ProductService', ['list', 'get', 'create', 'update']);\n```\n\nSince most of what we mock (usually Angular services) are classes, we can actually do a bit of introspection\nand create a mock that will automatically mock all the methods declared in the class. That's what our\n`createMock()` function does. The above code can thus be reduced to:\n\n```typescript\nconst productService = createMock(ProductService);\n```\n\n### Testing with a host component\n\nngx-speculoos doesn't provide any specific support for testing with host components, but we do it\na lot, simply by creating a ComponentTester for the host component rather than the component under test:\n\n```typescript\n@Component({\n  template: '\u003capp-user [user]=\"user\" (smile)=\"smiled = true\"\u003e\u003c/app-user\u003e'\n})\nclass HostComponent {\n  user: User = {\n    id: 'u1',\n    name: 'John'\n  };\n\n  smiled = false;\n}\n\nclass HostComponentTester extends ComponentTester\u003cHostComponent\u003e {\n  constructor() {\n    super(HostComponent);\n  }\n\n  get userComponent() {\n    return this.component(UserComponent);\n  }\n\n  // ...\n}\n```\n\nOnce you have that, you can access the host component using `componentInstance()`,\nthe component under test using `userComponent()`, and any element of the component under test\nusing the usual queries.\n\n## Gotchas\n\n### When do I need to call `change` or `detectChanges()`?\n\nIn _imperative_ mode, any event dispatched through a `TestElement` automatically calls `detectChanges()` for you.\nBut you still need to call `change()` or `detectChanges()` by yourself in the other cases:\n\n- to actually initialize your component. Sometimes, you want to configure some mocks before the `ngOnInit()`\n  method of your component is called. That's why creating a `ComponentTester` does not automatically call\n  `detectChanges()`. You need to do it yourself. The first call will cause the component lifecycle to start,\n  just as when using a `ComponentFixture` directly.\n- to force change detection once you've changed the state of your component without dispatching an event:\n  by changing the state, or emitting an event through a subject, or triggering a navigation\n  from the `ActivatedRouteStub`\n\nNote that, in _imperative_ mode, `change()` calls `detectChanges()`. So you can call either one of the other\nwhen you want to trigger a change detection.\n\nIn _automatic_ mode, any event dispatched through a `TestElement` automatically calls `await change()` for you.\nBut you still need to call `await change()` by yourself in the same other cases as in the _imperative_ mode:\n\n- to actually initialize your component. \n- to force change detection once you've changed the state of your component without dispatching an event.\n\n### Can I use the `TestElement` methods to act on the component element itself, rather than a sub-element?\n\nYes. The `ComponentTester` has a `testElement` property, which is the `TestHtmlElement` wrapping the component's element.\n\n## Issues, questions\n\nPlease, provide feedback by filing issues, or by submitting pull requests, to the [Github Project](https://github.com/Ninja-Squad/ngx-speculoos).\n\n## Complete example\n\nYou can look at a minimal complete example in the [demo](https://github.com/Ninja-Squad/ngx-speculoos/tree/master/projects/demo/src/app) project.\n\n## Upgrading to v13\n\nVersion 13 of `ngx-speculoos` introduces the _automatic_ mode, consisting in using automatic change detection\ninstead of imperatively running change detections. See the [Automatic change detection](#automatic-change-detection)\nsection above for details.\n\nAs a result, all the methods that used to call `detectChanges()` for you now return a `Promise` instead of returning\n`void`. In _imperative_ mode (the default), they are in fact synchronous and call `detectChanges()`, just as before.\nIn _automatic_ mode however, they call `await change()` and should thus be awaited.\n\nYour tests should generally keep compiling and running without changes. \nBut if you created custom test elements which override methods that now return a promise, and return something \nother than `void`, for example:\n\n```typescript\nclass CustomInput extends TestInput {\n  //...\n  fillWith(s: string): CustomInput {\n    super.fillWith(s);\n    return this;\n  }\n}\n```\n\nThen that won't compile anymore.\n\nAnd in general, if you want your custom test element to be usable in both modes, all their method that explicitly\nor indirectly called `detectChanges()` should now return a promise and explicitly of indirectly call `await change()`.\nFor example:\n\n```typescript\nclass CustomInput extends TestHtmlElement {\n  //...\n  async fillInput(s: string): Promise\u003cvoid\u003e {\n    await this.element('input').fillWith(s);\n    // ...\n  }\n  \n  async clickButton(): Promise\u003cvoid\u003e {\n    await this.element('button').click();\n    // ...\n  } \n  \n  async changeState(): Promise\u003cvoid\u003e {\n    this.component(Foo).doSomething();\n    await this.change();\n  }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNinja-Squad%2Fngx-speculoos","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FNinja-Squad%2Fngx-speculoos","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNinja-Squad%2Fngx-speculoos/lists"}