UNPKG

@hug/cypress-harness

Version:

Cypress support for Angular component test harnesses.

276 lines (275 loc) 13 kB
import { HarnessEnvironment } from '@angular/cdk/testing'; import { MatAutocompleteHarness } from '@angular/material/autocomplete/testing'; import { MatButtonHarness } from '@angular/material/button/testing'; import { MatButtonToggleGroupHarness } from '@angular/material/button-toggle/testing'; import { MatCheckboxHarness } from '@angular/material/checkbox/testing'; import { MatOptionHarness } from '@angular/material/core/testing'; import { MatDatepickerInputHarness } from '@angular/material/datepicker/testing'; import { MatInputHarness } from '@angular/material/input/testing'; import { MatListItemHarness, MatListOptionHarness, MatNavListHarness, MatNavListItemHarness } from '@angular/material/list/testing'; import { MatMenuHarness, MatMenuItemHarness } from '@angular/material/menu/testing'; import { MatRadioButtonHarness, MatRadioGroupHarness } from '@angular/material/radio/testing'; import { MatSelectHarness } from '@angular/material/select/testing'; import { MatSlideToggleHarness } from '@angular/material/slide-toggle/testing'; import { UnitTestElement } from '@angular/cdk/testing/testbed'; /* * Adds harness methods to chainer. * * Given a harness with a `getValue()` method, * users can call `getHarness().getValue()` * instead of `getHarness().invoke('getValue')` */ const addHarnessMethodsToChainer = (chainableHarness) => { const handler = { get: (chainableTarget, prop) => (...args) => { /* Don't wrap cypress methods like `invoke`, `should` etc.... */ if (prop in chainableTarget) { const pkey = prop; return chainableTarget[pkey](...args); } const propkey = prop; const chainer = chainableTarget.then(target => { const fct2 = target[propkey]; return fct2(...args); }); return addHarnessMethodsToChainer(chainer); } }; return new Proxy(chainableHarness, handler); }; const getDocumentRoot = () => cy.root(); const createRootEnvironment = ($documentRoot) => { const documentRoot = $documentRoot.get(0); return new CypressHarnessEnvironment(documentRoot, { documentRoot }); }; export class CypressHarnessEnvironment extends HarnessEnvironment { /** * We need this to keep a reference to the document. * This is different to `rawRootElement` which is the root element * of the harness's environment. * (The harness's environment is more of a context) */ _documentRoot; constructor(rawRootElement, { documentRoot }) { super(rawRootElement); this._documentRoot = documentRoot; } // eslint-disable-next-line @typescript-eslint/require-await async forceStabilize() { console.warn('`HarnessEnvironment#forceStabilize()` was called but it is a noop in Cypress environment.'); } waitForTasksOutsideAngular() { return Promise.reject(new Error('`HarnessEnvironment#waitForTasksOutsideAngular()` is not supported in Cypress environment.')); } getDocumentRoot() { return this._documentRoot; } createTestElement(element) { return new UnitTestElement(element, () => Promise.resolve()); } createEnvironment(element) { return new CypressHarnessEnvironment(element, { documentRoot: this._documentRoot }); } // eslint-disable-next-line @typescript-eslint/require-await async getAllRawElements(selector) { return Array.from(this.rawRootElement.querySelectorAll(selector)); } } export const getHarness = (harnessQuery) => { /* Create a local variable so `pipe` can log name. */ const getHarnessFct = ($documentRoot) => createRootEnvironment($documentRoot).getHarness(harnessQuery); return new Proxy({}, { get: (_, prop) => { const documentRoot = getDocumentRoot(); const chainer = documentRoot.pipe(getHarnessFct); const method = addHarnessMethodsToChainer(chainer); const propKey = prop; return method[propKey]; } }); }; export const getAllHarnesses = (query) => { /* Create a local variable so `pipe` can log name. */ const getAllHarnessesFct = ($documentRoot) => createRootEnvironment($documentRoot).getAllHarnesses(query); return new Proxy({}, { get: (_, prop) => { const documentRoot = getDocumentRoot(); const method = documentRoot.pipe(getAllHarnessesFct); const propKey = prop; return method[propKey]; } }); }; export const getInputHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); } cy.log(`getInputHarness for selector ${options?.selector || MatInputHarness.hostSelector}`); const harnessQuery = MatInputHarness.with(options); return getHarness(harnessQuery); }; export const getAutocompleteHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); } cy.log(`getAutocompleteHarness for selector ${options?.selector || MatAutocompleteHarness.hostSelector}`); const harnessQuery = MatAutocompleteHarness.with(options); return getHarness(harnessQuery); }; export const getListOptionHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); } cy.log(`getListOptionHarness for selector ${options?.selector || MatListOptionHarness.hostSelector}`); const harnessQuery = MatListOptionHarness.with(options); return getHarness(harnessQuery); }; export const getButtonHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(`${options.selector}:not(disabled)`).first().should('be.visible'); } cy.log(`getButtonHarness for selector ${options?.selector || MatButtonHarness.hostSelector}`); const harnessQuery = MatButtonHarness.with(options); return getHarness(harnessQuery); }; export const getButtonToggleGroupHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); } cy.log(`getButtonToggleGroupHarness for selector ${options?.selector || MatButtonToggleGroupHarness.hostSelector}`); const harnessQuery = MatButtonToggleGroupHarness.with(options); return getHarness(harnessQuery); }; export const getNavListHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); } cy.log(`getNavListHarness for selector ${options?.selector || MatNavListHarness.hostSelector}`); const harnessQuery = MatNavListHarness.with(options); return getHarness(harnessQuery); }; export const getNavListItemHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter || {}; if (!options.selector) { options.selector = 'mat-list-item'; } cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); cy.log(`getNavListItemHarness for selector ${options.selector || MatNavListItemHarness.hostSelector}`); const harnessQuery = MatNavListItemHarness.with(options); return getHarness(harnessQuery); }; export const getListItemHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter || {}; if (!options.selector) { options.selector = 'mat-list-item'; } cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); cy.log(`getListItemHarness for selector ${options.selector || MatListItemHarness.hostSelector}`); const harnessQuery = MatListItemHarness.with(options); return getHarness(harnessQuery); }; export const getCheckBoxHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); } cy.log(`getCheckBoxHarness for selector ${options?.selector || MatCheckboxHarness.hostSelector}`); const harnessQuery = MatCheckboxHarness.with(options); return getHarness(harnessQuery); }; export const getRadioButtonHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); } cy.log(`getRadioButtonHarness for selector ${options?.selector || MatRadioButtonHarness.hostSelector}`); const harnessQuery = MatRadioButtonHarness.with(options); return getHarness(harnessQuery); }; export const getRadioGroupHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); } cy.log(`getRadioGroupHarness for selector ${options?.selector || MatRadioGroupHarness.hostSelector}`); const harnessQuery = MatRadioGroupHarness.with(options); return getHarness(harnessQuery); }; export const getMenuHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); } cy.log(`getMenuHarness for selector ${options?.selector || MatMenuHarness.hostSelector}`); const harnessQuery = MatMenuHarness.with(options); return getHarness(harnessQuery); }; export const getMenuItemHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); } cy.log(`getMenuItemHarness for selector ${options?.selector || MatMenuItemHarness.hostSelector}`); const harnessQuery = MatMenuItemHarness.with(options); return getHarness(harnessQuery); }; export const getDatePickerInputHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); } cy.log(`getDatePickerInputHarness for selector ${options?.selector || MatDatepickerInputHarness.hostSelector}`); const harnessQuery = MatDatepickerInputHarness.with(options); return getHarness(harnessQuery); }; export const getSlideToggleHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); } cy.log(`getSlideToggleHarness for selector ${options?.selector || MatSlideToggleHarness.hostSelector}`); const harnessQuery = MatSlideToggleHarness.with(options); return getHarness(harnessQuery); }; export const getSelectHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter; if (options?.selector) { cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).first().should('be.visible'); } cy.log(`getSelectHarness for selector ${options?.selector || MatSelectHarness.hostSelector}`); const harnessQuery = MatSelectHarness.with(options); return getHarness(harnessQuery); }; export const getOptionHarness = (filter) => { const options = typeof filter === 'string' ? { selector: filter } : filter || {}; if (!options.selector) { options.selector = 'mat-option'; } cy.get(options.selector).first().scrollIntoView(); cy.get(options.selector).should('be.visible'); cy.log(`getOptionsHarness for selector ${options.selector || MatOptionHarness.hostSelector}`); const harnessQuery = MatOptionHarness.with(options); return getHarness(harnessQuery); };