@serenity-js/webdriverio
Version:
Adapter that integrates @serenity-js/web with the latest stable version of WebdriverIO, enabling Serenity/JS reporting and using the Screenplay Pattern to write web and mobile test scenarios
112 lines (84 loc) • 3.34 kB
text/typescript
import 'webdriverio';
import { type Discardable } from '@serenity-js/core';
import { AbsentModalDialog, AcceptedModalDialog, DismissedModalDialog, type ModalDialog, ModalDialogHandler } from '@serenity-js/web';
import { WebdriverProtocolErrorCode } from './WebdriverProtocolErrorCode.js';
/**
* WebdriverIO-specific implementation of [`ModalDialogHandler`](https://serenity-js.org/api/web/class/ModalDialogHandler/),
* used with the [WebDriver protocol](https://webdriver.io/docs/api/webdriver).
*
* @group Models
*/
export class WebdriverIOModalDialogHandler extends ModalDialogHandler implements Discardable {
private readonly defaultHandler: (dialog: WebdriverIO.Dialog) => Promise<void> =
async (dialog: WebdriverIO.Dialog) => {
const message = dialog.message();
await dialog.dismiss();
this.modalDialog = new DismissedModalDialog(message);
}
private currentHandler: (dialog: WebdriverIO.Dialog) => Promise<void>;
private dialog?: WebdriverIO.Dialog;
constructor(private readonly browser: WebdriverIO.Browser) {
super();
this.currentHandler = this.defaultHandler;
this.browser.on('dialog', this.onDialog);
}
private onDialog = this.tryToHandleDialog.bind(this);
private async tryToHandleDialog(dialog: WebdriverIO.Dialog): Promise<void> {
try {
await this.currentHandler(dialog);
}
catch(error) {
if (error.name === WebdriverProtocolErrorCode.UnexpectedAlertOpenError) {
await dialog.dismiss();
return;
}
if (error.message.includes(WebdriverProtocolErrorCode.NoSuchAlertError)) {
this.modalDialog = new AbsentModalDialog();
return;
}
throw error;
}
}
async acceptNext(): Promise<void> {
this.currentHandler = async (dialog: WebdriverIO.Dialog) => {
const message = dialog.message();
await this.browser.acceptAlert();
this.modalDialog = new AcceptedModalDialog(message);
};
}
async acceptNextWithValue(text: string | number): Promise<void> {
this.currentHandler = async (dialog: WebdriverIO.Dialog) => {
const message = dialog.message();
await dialog.accept(String(text))
this.modalDialog = new AcceptedModalDialog(message);
};
}
async dismissNext(): Promise<void> {
this.currentHandler = async (dialog: WebdriverIO.Dialog) => {
const message = dialog.message();
await dialog.dismiss();
this.modalDialog = new DismissedModalDialog(message);
}
}
async dismiss(): Promise<void> {
if (! this.dialog) {
return;
}
const message = this.dialog.message();
await this.dialog.dismiss();
this.modalDialog = new DismissedModalDialog(message);
}
async reset(): Promise<void> {
this.modalDialog = new AbsentModalDialog();
this.currentHandler = this.defaultHandler;
}
/**
* @override
*/
async last(): Promise<ModalDialog> {
return this.modalDialog;
}
async discard(): Promise<void> {
this.browser.off('dialog', this.onDialog);
}
}