@hug/cypress-harness
Version:
Cypress support for Angular component test harnesses.
308 lines (307 loc) • 14.6 kB
JavaScript
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 { MatChipHarness } from '@angular/material/chips/testing';
import { MatTabGroupHarness, MatTabHarness } from '@angular/material/tabs/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 getTabGroupHarness = (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(`getTabGroupHarness for selector ${options?.selector || MatTabGroupHarness.hostSelector}`);
const harnessQuery = MatTabGroupHarness.with(options);
return getHarness(harnessQuery);
};
export const getTabHarness = (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(`getTabHarness for selector ${options?.selector || MatTabHarness.hostSelector}`);
const harnessQuery = MatTabHarness.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 getChipHarness = (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(`getChipHarness for selector ${options?.selector || MatChipHarness.hostSelector}`);
const harnessQuery = MatChipHarness.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);
};