163 lines
4.1 KiB
TypeScript
163 lines
4.1 KiB
TypeScript
/**
|
|
* External dependencies
|
|
*/
|
|
import { ElementHandle, Page } from 'puppeteer';
|
|
|
|
/**
|
|
* Internal dependencies
|
|
*/
|
|
import { DropdownField } from '../elements/DropdownField';
|
|
import { DropdownTypeaheadField } from '../elements/DropdownTypeaheadField';
|
|
import { FormToggle } from '../elements/FormToggle';
|
|
import { getElementByText, waitForTimeout } from '../utils/actions';
|
|
|
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
const config = require( 'config' );
|
|
/* eslint-enable @typescript-eslint/no-var-requires */
|
|
const baseUrl = config.get( 'url' );
|
|
|
|
// Represents a page that can be navigated to
|
|
export abstract class BasePage {
|
|
protected page: Page;
|
|
protected url = '';
|
|
protected baseUrl: string = baseUrl;
|
|
|
|
// cache of elements that have been setup, note that they are unique "per page/per selector"
|
|
private dropDownElements: Record< string, DropdownField > = {};
|
|
private dropDownTypeAheadElements: Record<
|
|
string,
|
|
DropdownTypeaheadField
|
|
> = {};
|
|
private formToggleElements: Record< string, FormToggle > = {};
|
|
|
|
constructor( page: Page ) {
|
|
this.page = page;
|
|
}
|
|
|
|
getDropdownField( selector: string ): DropdownField {
|
|
if ( ! this.dropDownElements[ selector ] ) {
|
|
this.dropDownElements[ selector ] = new DropdownField(
|
|
page,
|
|
selector
|
|
);
|
|
}
|
|
|
|
return this.dropDownElements[ selector ];
|
|
}
|
|
|
|
getDropdownTypeahead( selector: string ): DropdownTypeaheadField {
|
|
if ( ! this.dropDownTypeAheadElements[ selector ] ) {
|
|
this.dropDownTypeAheadElements[
|
|
selector
|
|
] = new DropdownTypeaheadField( page, selector );
|
|
}
|
|
|
|
return this.dropDownTypeAheadElements[ selector ];
|
|
}
|
|
|
|
getFormToggle( selector: string ): FormToggle {
|
|
if ( ! this.formToggleElements[ selector ] ) {
|
|
this.formToggleElements[ selector ] = new FormToggle(
|
|
page,
|
|
selector
|
|
);
|
|
}
|
|
|
|
return this.formToggleElements[ selector ];
|
|
}
|
|
|
|
async click( selector: string ): Promise< void > {
|
|
await this.page.waitForSelector( selector );
|
|
await this.page.click( selector );
|
|
}
|
|
|
|
async clickButtonWithText( text: string ): Promise< void > {
|
|
const el = await getElementByText( 'button', text );
|
|
await el?.click();
|
|
}
|
|
|
|
async clickElementWithText(
|
|
element: string,
|
|
text: string
|
|
): Promise< void > {
|
|
const el = await getElementByText( element, text );
|
|
await el?.click();
|
|
}
|
|
|
|
async setCheckboxWithText( text: string ): Promise< void > {
|
|
let checkbox = await getElementByText( 'label', text );
|
|
|
|
if ( ! checkbox ) {
|
|
checkbox = await getElementByText( 'span', text );
|
|
}
|
|
|
|
if ( checkbox ) {
|
|
const checkboxStatus = await (
|
|
await checkbox.getProperty( 'checked' )
|
|
).jsonValue();
|
|
|
|
if ( checkboxStatus !== true ) {
|
|
await checkbox.click();
|
|
}
|
|
} else {
|
|
throw new Error( `Could not find checkbox with text "${ text }"` );
|
|
}
|
|
}
|
|
|
|
async unsetAllCheckboxes( selector: string ): Promise< void > {
|
|
const checkboxes = await page.$$( selector );
|
|
// Uncheck all checkboxes, to avoid installing plugins
|
|
for ( const checkbox of checkboxes ) {
|
|
await this.toggleCheckbox( checkbox, false );
|
|
await waitForTimeout( 200 );
|
|
}
|
|
}
|
|
|
|
async setAllCheckboxes( selector: string ): Promise< void > {
|
|
const checkboxes = await page.$$( selector );
|
|
// Uncheck all checkboxes, to avoid installing plugins
|
|
for ( const checkbox of checkboxes ) {
|
|
await this.toggleCheckbox( checkbox, true );
|
|
await waitForTimeout( 200 );
|
|
}
|
|
}
|
|
|
|
// Set or unset a checkbox based on `checked` value passed.
|
|
async toggleCheckbox(
|
|
checkbox: ElementHandle< Element >,
|
|
checked: boolean
|
|
): Promise< void > {
|
|
const checkboxStatus = await (
|
|
await checkbox.getProperty( 'checked' )
|
|
).jsonValue();
|
|
|
|
if ( checkboxStatus !== checked ) {
|
|
await checkbox.click();
|
|
}
|
|
}
|
|
|
|
async navigate(): Promise< void > {
|
|
if ( ! this.url ) {
|
|
throw new Error( 'You must define a url for the page object' );
|
|
}
|
|
|
|
await this.goto( this.url );
|
|
}
|
|
|
|
protected async goto( url: string ): Promise< void > {
|
|
const fullUrl = baseUrl + url;
|
|
try {
|
|
await this.page.goto( fullUrl, {
|
|
waitUntil: 'networkidle0',
|
|
timeout: 10000,
|
|
} );
|
|
} catch ( e ) {
|
|
if ( e instanceof Error ) {
|
|
throw new Error(
|
|
`Could not navigate to url: ${ fullUrl } with error: ${ e.message }`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|