ngx-speculoos
Version:
Helps writing Angular unit tests
1 lines • 114 kB
Source Map (JSON)
{"version":3,"file":"ngx-speculoos.mjs","sources":["../../../projects/ngx-speculoos/src/lib/test-element.ts","../../../projects/ngx-speculoos/src/lib/test-html-element.ts","../../../projects/ngx-speculoos/src/lib/test-button.ts","../../../projects/ngx-speculoos/src/lib/test-select.ts","../../../projects/ngx-speculoos/src/lib/test-textarea.ts","../../../projects/ngx-speculoos/src/lib/test-input.ts","../../../projects/ngx-speculoos/src/lib/test-element-querier.ts","../../../projects/ngx-speculoos/src/lib/component-tester.ts","../../../projects/ngx-speculoos/src/lib/routing-tester.ts","../../../projects/ngx-speculoos/src/lib/route.ts","../../../projects/ngx-speculoos/src/lib/matchers.ts","../../../projects/ngx-speculoos/src/lib/mock.ts","../../../projects/ngx-speculoos/src/lib/providers.ts","../../../projects/ngx-speculoos/src/public_api.ts","../../../projects/ngx-speculoos/src/ngx-speculoos.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { ComponentTester } from './component-tester';\nimport { TestButton } from './test-button';\nimport { TestSelect } from './test-select';\nimport { TestTextArea } from './test-textarea';\nimport { TestInput } from './test-input';\nimport { TestElementQuerier } from './test-element-querier';\nimport { DebugElement, ProviderToken, Type } from '@angular/core';\nimport { TestHtmlElement } from './test-html-element';\n\n/**\n * A wrapped DOM element, providing additional methods and attributes helping with writing tests\n */\nexport class TestElement<E extends Element = Element> {\n private querier: TestElementQuerier;\n\n constructor(\n protected tester: ComponentTester<unknown>,\n /**\n * the wrapped debug element\n */\n readonly debugElement: DebugElement\n ) {\n this.querier = new TestElementQuerier(tester, debugElement);\n }\n\n get nativeElement(): E {\n return this.debugElement.nativeElement;\n }\n\n /**\n * the text content of this element\n */\n get textContent(): string | null {\n return this.nativeElement.textContent;\n }\n\n /**\n * dispatches an event of the given type from the wrapped element, then triggers a change detection\n */\n async dispatchEventOfType(type: string): Promise<void> {\n this.nativeElement.dispatchEvent(new Event(type));\n await this.tester.change();\n }\n\n /**\n * dispatches the given event from the wrapped element, then triggers a change detection\n */\n async dispatchEvent(event: Event): Promise<void> {\n this.nativeElement.dispatchEvent(event);\n await this.tester.change();\n }\n\n /**\n * Gets the CSS classes of the wrapped element, as an array\n */\n get classes(): Array<string> {\n return Array.prototype.slice.call(this.nativeElement.classList);\n }\n\n /**\n * Gets the attribute of the wrapped element with the given name\n * @param name the name of the attribute to get\n */\n attr(name: string): string | null {\n return this.nativeElement.getAttribute(name);\n }\n\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestHtmlElement<HTMLDivElement> | null = tester.element('div');\n * </code>\n * @param selector a CSS selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<K extends keyof HTMLElementTagNameMap>(selector: K): TestHtmlElement<HTMLElementTagNameMap[K]> | null;\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement<SVGLineElement> | null = tester.element('line');\n * </code>\n * @param selector a CSS selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<K extends keyof SVGElementTagNameMap>(selector: K): TestElement<SVGElementTagNameMap[K]> | null;\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement | null = tester.element('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element(selector: string | Type<any>): TestElement | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestInput | null = tester.element<HTMLInputElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLInputElement>(selector: string | Type<any>): TestInput | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestTextArea | null = tester.element<HTMLTextAreaElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLTextAreaElement>(selector: string | Type<any>): TestTextArea | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestSelect | null = tester.element<HTMLSelectElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLSelectElement>(selector: string | Type<any>): TestSelect | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestButton | null = tester.element<HTMLButtonElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLButtonElement>(selector: string | Type<any>): TestButton | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestHtmlElement<HTMLDivElement> | null = tester.element<HTMLDivElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLElement>(selector: string | Type<any>): TestHtmlElement<T> | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement<SVGLineElement> | null = tester.element<SVGLineElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends Element>(selector: string | Type<any>): TestElement<T> | null;\n element(selector: string | Type<any>): TestElement | null {\n return this.querier.element(selector);\n }\n\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestHtmlElement<HTMLDivElement>> = tester.elements('div');\n * </code>\n * @param selector a CSS selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<K extends keyof HTMLElementTagNameMap>(selector: K): Array<TestHtmlElement<HTMLElementTagNameMap[K]>>;\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestElement<SVGLineElement>> = tester.elements('line');\n * </code>\n * @param selector a CSS selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<K extends keyof SVGElementTagNameMap>(selector: K): Array<TestElement<SVGElementTagNameMap[K]>>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestElement> = tester.elements('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements(selector: string | Type<any>): Array<TestElement>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestInput> = tester.elements<HTMLInputElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLInputElement>(selector: string | Type<any>): Array<TestInput>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestTextArea> = tester.elements<HTMLTextAreaElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLTextAreaElement>(selector: string | Type<any>): Array<TestTextArea>;\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestButton> = tester.elements<HTMLButtonElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLButtonElement>(selector: string | Type<any>): Array<TestButton>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestSelect> = tester.elements<HTMLSelectElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLSelectElement>(selector: string | Type<any>): Array<TestSelect>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestHtmlElement<HTMLDivElement>> = tester.elements<HTMLDivElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLElement>(selector: string | Type<any>): Array<TestHtmlElement<T>>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestElement<SVGLineElement>> = tester.elements<SVGLineElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends Element>(selector: string | Type<any>): Array<TestElement<T>>;\n elements(selector: string | Type<any>): Array<TestElement> {\n return this.querier.elements(selector);\n }\n\n /**\n * Gets the first input matched by the given selector. Throws an Error if the matched element isn't actually an input.\n * @param selector a CSS or directive selector\n * @returns the wrapped input, or null if no element was matched\n */\n input(selector: string | Type<any>): TestInput | null {\n return this.querier.input(selector);\n }\n\n /**\n * Gets the first select matched by the given selector. Throws an Error if the matched element isn't actually a select.\n * @param selector a CSS or directive selector\n * @returns the wrapped select, or null if no element was matched\n */\n select(selector: string | Type<any>): TestSelect | null {\n return this.querier.select(selector);\n }\n\n /**\n * Gets the first textarea matched by the given selector\n * @param selector a CSS or directive selector\n * @returns the wrapped textarea, or null if no element was matched. Throws an Error if the matched element isn't actually a textarea.\n * @throws {Error} if the matched element isn't actually a textarea\n */\n textarea(selector: string | Type<any>): TestTextArea | null {\n return this.querier.textarea(selector);\n }\n\n /**\n * Gets the first button matched by the given selector. Throws an Error if the matched element isn't actually a button.\n * @param selector a CSS or directive selector\n * @returns the wrapped button, or null if no element was matched\n */\n button(selector: string | Type<any>): TestButton | null {\n return this.querier.button(selector);\n }\n\n /**\n * Gets the first directive matching the given component directive selector and returns its component instance\n * @param selector the selector of a component directive\n */\n component<R>(selector: Type<R>): R {\n return this.querier.element(selector)?.debugElement?.componentInstance ?? null;\n }\n\n /**\n * Gets the directives matching the given component directive selector and returns their component instance\n * @param selector the selector of a component directive\n */\n components<R>(selector: Type<R>): Array<R> {\n return this.querier.elements(selector).map(e => e.debugElement.componentInstance);\n }\n\n /**\n * Gets the first element matching the given selector, then gets the given token from its injector, or null if there is no such token\n * @param selector a CSS or directive selector\n * @param token the token to get from the matched element injector\n */\n token<R>(selector: string | Type<any>, token: ProviderToken<R>): R | null {\n return this.querier.element(selector)?.debugElement?.injector?.get(token, null) ?? null;\n }\n\n /**\n * Gets the elements matching the given selector, then gets their given token from their injector, or null if there is no such token\n * @param selector a CSS or directive selector\n * @param token the token to get from the matched element injector\n */\n tokens<R>(selector: string | Type<any>, token: ProviderToken<R>): Array<R | null> {\n return this.querier.elements(selector).map(e => e.debugElement.injector.get(token, null) ?? null);\n }\n\n /**\n * Gets the element matching the given selector, and if found, creates and returns a custom TestElement of the provided\n * type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for\n * custom elements or components.\n * @param selector a CSS or directive selector\n * @param customTestElementType the type of the TestElement subclass that will wrap the found element\n */\n custom<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): E | null {\n const element = this.querier.element(selector);\n return element && new customTestElementType(this.tester, element.debugElement);\n }\n\n /**\n * Gets the elements matching the given selector, and creates and returns custom TestElements of the provided\n * type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for\n * custom elements or components.\n * @param selector a CSS or directive selector\n * @param customTestElementType the type of the TestElement subclass that will wrap the found elements\n */\n customs<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): Array<E> {\n return this.querier.elements(selector).map(element => new customTestElementType(this.tester, element.debugElement));\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestElement } from './test-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped DOM HTML element, providing additional methods and attributes helping with writing tests\n */\nexport class TestHtmlElement<E extends HTMLElement> extends TestElement<E> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * Clicks on the wrapped element, then triggers a change detection\n */\n async click(): Promise<void> {\n this.nativeElement.click();\n await this.tester.change();\n }\n\n /**\n * Tests if the element is visible, in the same meaning (and implementation) as in jQuery, i.e.\n * present anywhere in the DOM, and visible.\n * An element is not visible typically, if its display style or any of its ancestors display style is none.\n */\n get visible(): boolean {\n return !!(this.nativeElement.offsetWidth || this.nativeElement.offsetHeight || this.nativeElement.getClientRects().length);\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestHtmlElement } from './test-html-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped button element, providing additional methods and attributes helping with writing tests\n */\nexport class TestButton extends TestHtmlElement<HTMLButtonElement> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * the disabled flag of the button\n */\n get disabled(): boolean {\n return this.nativeElement.disabled;\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestHtmlElement } from './test-html-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped DOM HTML select element, providing additional methods and attributes helping with writing tests\n */\nexport class TestSelect extends TestHtmlElement<HTMLSelectElement> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * Selects the option at the given index, then dispatches an event of type change and triggers a change detection.\n * If the index is out of bounds and is not -1, then throws an error.\n */\n selectIndex(index: number): Promise<void> {\n if (index < -1 || index >= this.nativeElement.options.length) {\n throw new Error(`The index ${index} is out of bounds`);\n }\n this.nativeElement.selectedIndex = index;\n return this.dispatchEventOfType('change');\n }\n\n /**\n * Selects the first option with the given value, then dispatches an event of type change and triggers a change detection.\n * If there is no option with the given value, then throws an error.\n */\n selectValue(value: string): Promise<void> {\n const index = this.optionValues.indexOf(value);\n if (index >= 0) {\n return this.selectIndex(index);\n } else {\n throw new Error(`The value ${value} is not part of the option values (${this.optionValues.join(', ')})`);\n }\n }\n\n /**\n * Selects the first option with the given label (or text), then dispatches an event of type change and triggers a change detection.\n * If there is no option with the given label, then throws an error.\n */\n selectLabel(label: string): Promise<void> {\n const index = this.optionLabels.indexOf(label);\n if (index >= 0) {\n return this.selectIndex(index);\n } else {\n throw new Error(`The label ${label} is not part of the option labels (${this.optionLabels.join(', ')})`);\n }\n }\n\n /**\n * the selected index of the wrapped select\n */\n get selectedIndex(): number {\n return this.nativeElement.selectedIndex;\n }\n\n /**\n * the value of the selected option of the wrapped select, or null if there is no selected option\n */\n get selectedValue(): string | null {\n if (this.selectedIndex < 0) {\n return null;\n }\n return this.nativeElement.options[this.selectedIndex].value;\n }\n\n /**\n * the label (or text if no label) of the selected option of the wrapped select, or null if there is no selected option\n */\n get selectedLabel(): string | null {\n if (this.selectedIndex < 0) {\n return null;\n }\n return this.nativeElement.options[this.selectedIndex].label;\n }\n\n /**\n * the values of the options, as an array\n */\n get optionValues(): Array<string> {\n return (Array.prototype.slice.call(this.nativeElement.options) as Array<HTMLOptionElement>).map(option => option.value);\n }\n\n /**\n * the labels (or texts if no label) of the options, as an array\n */\n get optionLabels(): Array<string> {\n return (Array.prototype.slice.call(this.nativeElement.options) as Array<HTMLOptionElement>).map(option => option.label);\n }\n\n /**\n * the number of options in the select\n */\n get size(): number {\n return this.nativeElement.options.length;\n }\n\n /**\n * the disabled property of the wrapped select\n */\n get disabled(): boolean {\n return this.nativeElement.disabled;\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestHtmlElement } from './test-html-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped DOM HTML textarea element, providing additional methods and attributes helping with writing tests\n */\nexport class TestTextArea extends TestHtmlElement<HTMLTextAreaElement> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * Sets the value of the wrapped textarea, then dispatches an event of type input and triggers a change detection\n * @param value the new value of the textarea\n */\n async fillWith(value: string): Promise<void> {\n this.nativeElement.value = value;\n await this.dispatchEventOfType('input');\n }\n\n /**\n * the value of the wrapped textarea\n */\n get value(): string {\n return this.nativeElement.value;\n }\n\n /**\n * the disabled property of the wrapped textarea\n */\n get disabled(): boolean {\n return this.nativeElement.disabled;\n }\n}\n","import { ComponentTester } from './component-tester';\nimport { TestHtmlElement } from './test-html-element';\nimport { DebugElement } from '@angular/core';\n\n/**\n * A wrapped DOM HTML input element, providing additional methods and attributes helping with writing tests\n */\nexport class TestInput extends TestHtmlElement<HTMLInputElement> {\n constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {\n super(tester, debugElement);\n }\n\n /**\n * Sets the value of the wrapped input, then dispatches an event of type input and triggers a change detection\n * @param value the new value of the input\n */\n async fillWith(value: string): Promise<void> {\n this.nativeElement.value = value;\n await this.dispatchEventOfType('input');\n }\n\n /**\n * the value of the wrapped input\n */\n get value(): string {\n return this.nativeElement.value;\n }\n\n /**\n * the checked property of the wrapped input\n */\n get checked(): boolean {\n return this.nativeElement.checked;\n }\n\n /**\n * the disabled property of the wrapped input\n */\n get disabled(): boolean {\n return this.nativeElement.disabled;\n }\n\n /**\n * Checks the wrapped input, then dispatches an event of type change and triggers a change detection\n */\n async check(): Promise<void> {\n this.nativeElement.checked = true;\n await this.dispatchEventOfType('change');\n }\n\n /**\n * Unchecks the wrapped input, then dispatches an event of type change and triggers a change detection\n */\n async uncheck(): Promise<void> {\n this.nativeElement.checked = false;\n await this.dispatchEventOfType('change');\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { TestButton } from './test-button';\nimport { TestSelect } from './test-select';\nimport { TestElement } from './test-element';\nimport { TestTextArea } from './test-textarea';\nimport { TestInput } from './test-input';\nimport { TestHtmlElement } from './test-html-element';\nimport { ComponentTester } from './component-tester';\nimport { DebugElement, Type } from '@angular/core';\nimport { By } from '@angular/platform-browser';\n\n/**\n * @internal\n */\nexport class TestElementQuerier {\n constructor(\n private tester: ComponentTester<unknown>,\n private root: DebugElement\n ) {}\n\n static wrap(childDebugElement: DebugElement, tester: ComponentTester<unknown>): TestElement {\n const childElement = childDebugElement.nativeElement;\n if (childElement instanceof HTMLButtonElement) {\n return new TestButton(tester, childDebugElement);\n } else if (childElement instanceof HTMLInputElement) {\n return new TestInput(tester, childDebugElement);\n } else if (childElement instanceof HTMLSelectElement) {\n return new TestSelect(tester, childDebugElement);\n } else if (childElement instanceof HTMLTextAreaElement) {\n return new TestTextArea(tester, childDebugElement);\n } else if (childElement instanceof HTMLElement) {\n return new TestHtmlElement(tester, childDebugElement);\n } else {\n return new TestElement(tester, childDebugElement);\n }\n }\n\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput. You can thus use\n * `tester.element('#some-input') as TestInput`.\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element(selector: string | Type<any>): TestElement | null {\n const childElement = this.query(selector);\n return childElement && TestElementQuerier.wrap(childElement, this.tester);\n }\n\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput. You can thus use\n * `tester.elements('input') as Array<TestInput>`.\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements(selector: string | Type<any>): Array<TestElement> {\n const childElements = this.queryAll(selector);\n return childElements.map(debugElement => TestElementQuerier.wrap(debugElement, this.tester));\n }\n\n /**\n * Gets the first input matched by the given selector. Throws an Error if the matched element isn't actually an input.\n * @param selector a CSS or directive selector\n * @returns the wrapped input, or null if no element was matched\n */\n input(selector: string | Type<any>): TestInput | null {\n const childElement = this.query(selector);\n if (!childElement) {\n return null;\n } else if (!(childElement.nativeElement instanceof HTMLInputElement)) {\n throw new Error(`Element with selector ${selector} is not an HTMLInputElement`);\n }\n return new TestInput(this.tester, childElement);\n }\n\n /**\n * Gets the first select matched by the given selector. Throws an Error if the matched element isn't actually a select.\n * @param selector a CSS or directive selector\n * @returns the wrapped select, or null if no element was matched\n */\n select(selector: string | Type<any>): TestSelect | null {\n const childElement = this.query(selector);\n if (!childElement) {\n return null;\n } else if (!(childElement.nativeElement instanceof HTMLSelectElement)) {\n throw new Error(`Element with selector ${selector} is not an HTMLSelectElement`);\n }\n return new TestSelect(this.tester, childElement);\n }\n\n /**\n * Gets the first textarea matched by the given selector\n * @param selector a CSS or directive selector\n * @returns the wrapped textarea, or null if no element was matched. Throws an Error if the matched element isn't actually a textarea.\n * @throws {Error} if the matched element isn't actually a textarea\n */\n textarea(selector: string | Type<any>): TestTextArea | null {\n const childElement = this.query(selector);\n if (!childElement) {\n return null;\n } else if (!(childElement.nativeElement instanceof HTMLTextAreaElement)) {\n throw new Error(`Element with selector ${selector} is not an HTMLTextAreaElement`);\n }\n return new TestTextArea(this.tester, childElement);\n }\n\n /**\n * Gets the first button matched by the given selector. Throws an Error if the matched element isn't actually a button.\n * @param selector a CSS or directive selector\n * @returns the wrapped button, or null if no element was matched\n */\n button(selector: string | Type<any>): TestButton | null {\n const childElement = this.query(selector);\n if (!childElement) {\n return null;\n } else if (!(childElement.nativeElement instanceof HTMLButtonElement)) {\n throw new Error(`Element with selector ${selector} is not an HTMLButtonElement`);\n }\n return new TestButton(this.tester, childElement);\n }\n\n private query(selector: string | Type<any>): DebugElement | null {\n if (typeof selector === 'string') {\n return this.root.query(By.css(selector));\n } else {\n return this.root.query(By.directive(selector));\n }\n }\n\n private queryAll(selector: string | Type<any>): Array<DebugElement> {\n if (typeof selector === 'string') {\n return this.root.queryAll(By.css(selector));\n } else {\n return this.root.queryAll(By.directive(selector));\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { ComponentFixture, ComponentFixtureAutoDetect, TestBed } from '@angular/core/testing';\nimport { DebugElement, NgZone, ProviderToken, Type } from '@angular/core';\nimport { TestTextArea } from './test-textarea';\nimport { TestElement } from './test-element';\nimport { TestInput } from './test-input';\nimport { TestSelect } from './test-select';\nimport { TestButton } from './test-button';\nimport { TestElementQuerier } from './test-element-querier';\nimport { TestHtmlElement } from './test-html-element';\n\n/**\n * The main entry point of the API. It wraps an Angular ComponentFixture<T>, and gives access to its\n * most used properties and methods. It also allows getting elements wrapped in TestElement (and its subclasses)\n * @param <C> the type of the component to test\n */\nexport class ComponentTester<C> {\n /**\n * The test element of the component\n */\n readonly testElement: TestElement<HTMLElement>;\n\n /**\n * The component fixture of the component\n */\n readonly fixture: ComponentFixture<C>;\n\n /**\n * The mode used by the ComponentTester\n */\n readonly mode: 'imperative' | 'automatic';\n\n /**\n * Creates a component fixture of the given type with the TestBed and wraps it into a ComponentTester\n */\n static create<C>(componentType: Type<C>): ComponentTester<C> {\n const fixture = TestBed.createComponent(componentType);\n return new ComponentTester(fixture);\n }\n\n /**\n * Creates a ComponentFixture for the given component type using the TestBed, and creates a ComponentTester\n * wrapping (and delegating) to this fixture. If a fixture is passed, then delegates to this fixture directly.\n *\n * Note that no `detectChanges()` call is made by this constructor. It's up to the subclass constructor,\n * or to the user of the created ComponentTester, to call `detectChanges()` at least once to trigger change\n * detection. This is necessary because some component templates can only be evaluated once inputs\n * have been set on the component instance.\n *\n * @param arg the type of the component to wrap, or a component fixture to wrap\n */\n constructor(arg: Type<C> | ComponentFixture<C>) {\n this.fixture = arg instanceof ComponentFixture ? arg : TestBed.createComponent(arg);\n const autoDetect = TestBed.inject(ComponentFixtureAutoDetect, false);\n const zoneless = !(TestBed.inject(NgZone) instanceof NgZone);\n this.testElement = TestElementQuerier.wrap(this.debugElement, this) as TestElement<HTMLElement>;\n this.mode = autoDetect || zoneless ? 'automatic' : 'imperative';\n }\n\n /**\n * The native DOM host element of the component\n */\n get nativeElement(): HTMLElement {\n return this.fixture.nativeElement;\n }\n\n /**\n * Gets the instance of the tested component from the wrapped fixture\n */\n get componentInstance(): C {\n return this.fixture.componentInstance;\n }\n\n /**\n * Gets the debug element from the wrapped fixture\n */\n get debugElement(): DebugElement {\n return this.fixture.debugElement;\n }\n\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestHtmlElement<HTMLDivElement> | null = tester.element('div');\n * </code>\n * @param selector a CSS selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<K extends keyof HTMLElementTagNameMap>(selector: K): TestHtmlElement<HTMLElementTagNameMap[K]> | null;\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement<SVGLineElement> | null = tester.element('line');\n * </code>\n * @param selector a CSS selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<K extends keyof SVGElementTagNameMap>(selector: K): TestElement<SVGElementTagNameMap[K]> | null;\n /**\n * Gets the first element matching the given CSS selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement | null = tester.element('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element(selector: string | Type<any>): TestElement | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestInput | null = tester.element<HTMLInputElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLInputElement>(selector: string | Type<any>): TestInput | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestTextArea | null = tester.element<HTMLTextAreaElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLTextAreaElement>(selector: string | Type<any>): TestTextArea | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestSelect | null = tester.element<HTMLSelectElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLSelectElement>(selector: string | Type<any>): TestSelect | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestButton | null = tester.element<HTMLButtonElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLButtonElement>(selector: string | Type<any>): TestButton | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestHtmlElement<HTMLDivElement> | null = tester.element<HTMLDivElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends HTMLElement>(selector: string | Type<any>): TestHtmlElement<T> | null;\n /**\n * Gets the first element matching the given selector and wraps it into a TestElement. The actual type\n * of the returned value is the TestElement subclass matching the type of the found element. So, if the\n * matched element is an input for example, the method will return a TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElement: TestElement<SVGLineElement> | null = tester.element<SVGLineElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the wrapped element, or null if no element matches the selector.\n */\n element<T extends Element>(selector: string | Type<any>): TestElement<T> | null;\n element(selector: string | Type<any>): TestElement | null {\n return this.testElement.element(selector);\n }\n\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestHtmlElement<HTMLDivElement>> = tester.elements('div');\n * </code>\n * @param selector a CSS selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<K extends keyof HTMLElementTagNameMap>(selector: K): Array<TestHtmlElement<HTMLElementTagNameMap[K]>>;\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestElement<SVGLineElement>> = tester.elements('line');\n * </code>\n * @param selector a CSS selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<K extends keyof SVGElementTagNameMap>(selector: K): Array<TestElement<SVGElementTagNameMap[K]>>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestElement> = tester.elements('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements(selector: string | Type<any>): Array<TestElement>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestInput> = tester.elements<HTMLInputElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLInputElement>(selector: string | Type<any>): Array<TestInput>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestTextArea> = tester.elements<HTMLTextAreaElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLTextAreaElement>(selector: string | Type<any>): Array<TestTextArea>;\n /**\n * Gets all the elements matching the given CSS selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestButton> = tester.elements<HTMLButtonElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLButtonElement>(selector: string | Type<any>): Array<TestButton>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestSelect> = tester.elements<HTMLSelectElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLSelectElement>(selector: string | Type<any>): Array<TestSelect>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestHtmlElement<HTMLDivElement>> = tester.elements<HTMLDivElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends HTMLElement>(selector: string | Type<any>): Array<TestHtmlElement<T>>;\n /**\n * Gets all the elements matching the given selector and wraps them into a TestElement. The actual type\n * of the returned elements is the TestElement subclass matching the type of the found element. So, if the\n * matched elements are inputs for example, the method will return an array of TestInput.\n * <p>Usage:</p>\n * <code>\n * const testElements: Array<TestElement<SVGLineElement>> = tester.elements<SVGLineElement>('.selector');\n * </code>\n * @param selector a CSS or directive selector\n * @returns the array of matched elements, empty if no element was matched\n */\n elements<T extends Element>(selector: string | Type<any>): Array<TestElement<T>>;\n elements(selector: string | Type<any>): Array<TestElement> {\n return this.testElement.elements(selector);\n }\n\n /**\n * Gets the first input matched by the given selector. Throws an Error if the matched element isn't actually an input.\n * @param selector a CSS o