@serenity-js/web
Version:
Serenity/JS Screenplay Pattern library offering a flexible, web driver-agnostic approach for interacting with web-based user interfaces and components, suitable for various testing contexts
177 lines • 7.07 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModalDialog = void 0;
const core_1 = require("@serenity-js/core");
const Page_1 = require("../Page");
/**
* Manages interactions with JavaScript modal dialog windows,
* triggered by [window.alert](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert),
* [window.confirm](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm),
* or [`window.prompt`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt),
* and stores their `message` so that it can be asserted on once the dialog is handled.
*
* Note that in order to make handling modal windows
* consistent across the various Web integration tools (such as Playwright, Puppeteer,
* WebdriverIO or Selenium), Serenity/JS works as follows:
* - Serenity/JS dismisses any modal dialogs by default and stores their message so that it can be asserted on.
* - This behaviour can be changed by invoking [`ModalDialog.acceptNext`](https://serenity-js.org/api/web/class/ModalDialog/#acceptNext),
* [`ModalDialog.acceptNextWithValue`](https://serenity-js.org/api/web/class/ModalDialog/#acceptNextWithValue),
* or [`ModalDialog.dismissNext`](https://serenity-js.org/api/web/class/ModalDialog/#dismissNext)
* before the dialog is triggered, as per the below examples.
* - Serenity/JS also allows you to `Wait.until(ModalDialog, isPresent())` so that you can synchronise your tests
* with modal dialogs that appear after a delay.
*
* ## Example HTML widget
*
* In the below example widget, clicking on the button results in a [confirmation dialog](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm)
* appearing.
*
* ```html
* <button id="trigger" onclick="trigger()">Trigger Alert</button>
* <p id="result"></p>
*
* <script>
* function trigger() {
* document.getElementById("result").innerHTML = (
* function () {
* return confirm('Continue?')
* ? 'accepted'
* : 'dismissed';
* }
* )();
* }
* </script>
* ```
*
* ## Modal dialog gets dismissed by default
*
* ```ts
* import { actorCalled } from '@serenity-js/core'
* import { By, Click, Text, PageElement, ModalDialog } from '@serenity-js/web'
* import { Ensure, equals } from '@serenity-js/assertions'
*
* const Example = {
* trigger: () =>
* PageElement.located(By.id('trigger')).describedAs('the modal dialog trigger'),
*
* result: () =>
* PageElement.located(By.id('result')).describedAs('result'),
* }
*
* await actorCalled('Nick').attemptsTo(
* Click.on(Example.trigger()),
*
* Ensure.that(ModalDialog.lastDialogState(), equals('dismissed')),
*
* Ensure.that(Text.of(Example.result()), equals('dismissed')),
* )
* ```
*
* ## Changing modal dialog handler
*
* ```ts
* import { actorCalled } from '@serenity-js/core'
* import { By, Click, Text, PageElement, ModalDialog } from '@serenity-js/web'
* import { Ensure, equals } from '@serenity-js/assertions'
*
* const Example = {
* trigger: () =>
* PageElement.located(By.id('trigger')).describedAs('the modal dialog trigger'),
*
* result: () =>
* PageElement.located(By.id('result')).describedAs('result'),
* }
*
* await actorCalled('Nick').attemptsTo(
* ModalDialog.acceptNext(),
* // or: ModalDialog.acceptNextWithValue('some value'),
* // or: ModalDialog.dismissNext(),
*
* Click.on(Example.trigger),
*
* Ensure.that(ModalDialog.lastDialogState(), equals('accepted')),
*
* Ensure.that(Text.of(Example.result), equals('accepted')),
* )
* ```
*
* ## Learn more
* - [`Optional`](https://serenity-js.org/api/core/interface/Optional/)
*
* @group Models
*/
class ModalDialog {
/**
* Returns a promise that resolves to `true`
* when a modal dialog has been handled, so accepted or dismissed.
* Returns `false` for dialogs that haven't been handled yet.
*
* Useful when a JavaScript modal dialog is generated after a delay,
* e.g. triggered by `setTimeout`.
*
* #### Example usage
*
* ```ts
* import { actorCalled, Wait } from '@serenity-js/core'
* import { Ensure, equals, isPresent } from '@serenity-js/assertions'
* import { ModalDialog } from '@serenity-js/web'
*
* await actorCalled('Nick').attemptsTo(
* ModalDialog.acceptNext(),
* Wait.until(ModalDialog, isPresent()),
* Ensure.that(ModalDialog.lastDialogState(), equals('accepted')),
* )
* ```
*/
static isPresent() {
return Page_1.Page.current().modalDialog().last().isPresent();
}
/**
* Produces an [interaction](https://serenity-js.org/api/core/class/Interaction/) that invokes [`ModalDialog.acceptNext`](https://serenity-js.org/api/web/class/ModalDialog/#acceptNext).
*/
static acceptNext() {
return Page_1.Page.current().modalDialog().acceptNext()
.describedAs('#actor accepts next modal dialog window');
}
/**
* Produces an [interaction](https://serenity-js.org/api/core/class/Interaction/) that invokes [`ModalDialog.acceptNextWithValue`](https://serenity-js.org/api/web/class/ModalDialog/#acceptNextWithValue).
*
* @param value
*/
static acceptNextWithValue(value) {
return Page_1.Page.current().modalDialog().acceptNextWithValue(value)
.describedAs((0, core_1.the) `#actor accepts next modal dialog window with value ${value}`);
}
/**
* Produces an [interaction](https://serenity-js.org/api/core/class/Interaction/) that invokes [`ModalDialog.dismissNext`](https://serenity-js.org/api/web/class/ModalDialog/#dismissNext).
*/
static dismissNext() {
return Page_1.Page.current().modalDialog().dismissNext()
.describedAs((0, core_1.the) `#actor dismisses next modal dialog window`);
}
/**
* [`QuestionAdapter`](https://serenity-js.org/api/core/#QuestionAdapter) that resolves to [`ModalDialog.message`](https://serenity-js.org/api/web/class/ModalDialog/#message) for the current [`Page`](https://serenity-js.org/api/web/class/Page/).
*/
static lastDialogMessage() {
return Page_1.Page.current().modalDialog().last().message()
.describedAs(`last dialog message`);
}
/**
* [`QuestionAdapter`](https://serenity-js.org/api/core/#QuestionAdapter) that resolves to [`ModalDialog.state`](https://serenity-js.org/api/web/class/ModalDialog/#state) for the current [`Page`](https://serenity-js.org/api/web/class/Page/).
*/
static lastDialogState() {
return Page_1.Page.current().modalDialog().last().state()
.describedAs(`last dialog state`);
}
/**
* Returns `accepted` or `dismissed` for dialogs that have been handled,
* or `absent` for those that haven't been handled yet.
*/
state() {
return this.constructor.name
.replace('ModalDialog', '')
.toLowerCase();
}
}
exports.ModalDialog = ModalDialog;
//# sourceMappingURL=ModalDialog.js.map