Queries
The Spectator API includes convenient methods for querying the DOM as part of a test: query, queryAll, queryLast , queryHost and queryHostAll. All query methods are polymorphic and allow you to query using any of the following techniques.
String Selector
Section titled “String Selector”Pass a string selector (in the same style as you would when using jQuery or document.querySelector) to query for elements that match that path in the DOM. This method for querying is equivalent to Angular’s By.css predicate. Note that native HTML elements will be returned. For example:
// Returns a single HTMLElementspectator.query('div > ul.nav li:first-child');// Returns an array of all matching HTMLElementsspectator.queryAll('div > ul.nav li');
// Query from the document contextspectator.query('div', { root: true });
spectator.query('app-child', { read: ChildServiceService });Type Selector
Section titled “Type Selector”Pass a type (such as a component, directive or provider class) to query for instances of that type in the DOM. This is equivalent to Angular’s By.directive predicate. You can optionally pass in a second parameter to read a specific injection token from the matching elements’ injectors. For example:
// Returns a single instance of MyComponent (if present)spectator.query(MyComponent);
// Returns the instance of `SomeService` found in the instance of `MyComponent` that exists in the DOM (if present)spectator.query(MyComponent, { read: SomeService });
spectator.query(MyComponent, { read: ElementRef });host.queryLast(ChildComponent);host.queryAll(ChildComponent);DOM Selector
Section titled “DOM Selector”Spectator allows you to query for elements using selectors inspired by dom-testing-library. The available selectors are:
spectator.query(byPlaceholder('Please enter your email address'));spectator.query(byValue('By value'));spectator.query(byTitle('By title'));spectator.query(byAltText('By alt text'));spectator.query(byLabel('By label'));spectator.query(byText('By text'));spectator.query(byText('By text', {selector: '#some .selector'}));spectator.query(byTextContent('By text content', {selector: '#some .selector'}));spectator.query(byRole('checkbox', { checked: true }));spectator.query(byTestId('someTestId'))The difference between byText and byTextContent is that the former doesn’t match text inside a nested elements.
For example, in this following HTML byText('foobar', {selector: 'div'}) won’t match the following div, but byTextContent will:
<div> <span>foo</span> <span>bar</span></div>These DOM selectors are directly supported by our Custom Matchers:
expect(byTextContent('By text content', {selector: '#some .selector'})).toExist();expect(byPlaceholder('Please enter your email address')).toHaveValue('my-value');// ... See the Custom Matchers section for a full list of possible matchersConfigure @testing-library/dom to use byTestId with a different testIdAttribute
import { configure } from '@testing-library/dom';
configure({ testIdAttribute: 'data-test' });Parent Selector
Section titled “Parent Selector”Spectator allows you to query for nested elements within a parent element. This is useful when you have multiple instances of the same component on the page and you want to query for children within a specific one. The parent selector is a string selector or DOMSelector that is used to find the parent element. The parent selector is passed as the second parameter to the query methods. For example:
spectator.query(ChildComponent, { parentSelector: '#parent-component-1' });spectator.queryAll(ChildComponent, { parentSelector: '#parent-component-1' });
spectator.query(ChildComponent, { parentSelector: byTestId('parent-component-1') });spectator.queryAll(ChildComponent, { parentSelector: byTestId('parent-component-1') });Testing Select Elements
Section titled “Testing Select Elements”Spectator allows you to test <select></select> elements easily, and supports multi select.
Example:
it('should set the correct options on multi select', () => { const select = spectator.query('#test-multi-select') as HTMLSelectElement; spectator.selectOption(select, ['1', '2']); expect(select).toHaveSelectedOptions(['1', '2']);});
it('should set the correct option on standard select', () => { const select = spectator.query('#test-single-select') as HTMLSelectElement; spectator.selectOption(select, '1'); expect(select).toHaveSelectedOptions('1');});It also allows you to check if your change event handler is acting correctly for each item selected. You can disable this if you need to pre set choices without dispatching the change event.
API:
spectator.selectOption(selectElement: HTMLSelectElement, options: string | string[] | HTMLOptionElement | HTMLOptionElement[], config: { emitEvents: boolean } = { emitEvents: true });Example:
it('should dispatch correct number of change events', () => { const onChangeSpy = spyOn(spectator.component, 'handleChange'); const select = spectator.query('#test-onchange-select') as HTMLSelectElement;
spectator.selectOption(select, ['1', '2'], { emitEvents: true});
expect(select).toHaveSelectedOptions(['1', '2']); expect(onChangeSpy).toHaveBeenCalledTimes(2);});
it('should not dispatch correct number of change events', () => { const onChangeSpy = spyOn(spectator.component, 'handleChange'); const select = spectator.query('#test-onchange-select') as HTMLSelectElement;
spectator.selectOption(select, ['1', '2'], { emitEvents: false});
expect(select).toHaveSelectedOptions(['1', '2']); expect(onChangeSpy).not.toHaveBeenCalledTimes(2);});You can also pass HTMLOptionElement(s) as arguments to selectOption and the toHaveSelectedOptions matcher. This is particularly useful when you are using [ngValue] binding on the <option>:
it('should set the correct option on single select when passing the element', () => { const select = spectator.query('#test-single-select-element') as HTMLSelectElement;
spectator.selectOption(select, spectator.query(byText('Two')) as HTMLOptionElement);
expect(select).toHaveSelectedOptions(spectator.query(byText('Two')) as HTMLOptionElement);});