UNPKG

@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

256 lines 9.61 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Page = void 0; const core_1 = require("@serenity-js/core"); const tiny_types_1 = require("tiny-types"); const abilities_1 = require("../abilities"); /** * Serenity/JS Screenplay Pattern-style model that enables interactions with a Web page * rendered in a Web browser tab. * * ## Referring to the current page * * ```ts * import { Ensure, endsWith } from '@serenity-js/assertions' * import { actorCalled } from '@serenity-js/core' * import { Navigate, Page } from '@serenity-js/web' * * await actorCalled('Serena').attemptsTo( * Navigate.to('https://serenity-js.org'), * Ensure.that(Page.current().title(), endsWith('Serenity/JS')), * ) * ``` * * ## Switching to another open page * * ```ts * import { Ensure, equals, includes, startsWith } from '@serenity-js/assertions' * import { actorCalled } from '@serenity-js/core' * import { Navigate, Page, Switch, Text } from '@serenity-js/web' * * const Navigation = { * linkTo = (name: Answerable<string>) => * PageElements.located(By.css('nav a')) * .where(Text, includes(name)) * .first() * } * * await actorCalled('Serena').attemptsTo( * Navigate.to('https://serenity-js.org'), * Click.on(Navigation.linkTo('GitHub')), * * Switch.to(Page.whichUrl(startsWith('https://github.com'))) * * Ensure.that( * Page.current().url().href, * equals('https://github.com/serenity-js/serenity-js') * ), * ) * ``` * * ## Retrieving information about another open page * * You can retrieve information about another open page without having to explicitly switch to it: * * ```ts * import { Ensure, equals, includes, startsWith } from '@serenity-js/assertions' * import { actorCalled } from '@serenity-js/core' * import { Navigate, Page, Text } from '@serenity-js/web' * * const Navigation = { * linkTo = (name: Answerable<string>) => * PageElements.located(By.css('nav a')) * .where(Text, includes(name)) * .first() * } * * await actorCalled('Serena').attemptsTo( * Navigate.to('https://serenity-js.org'), * Click.on(Navigation.linkTo('GitHub')), * Ensure.that( * Page.whichUrl(startsWith('https://github.com')).url().href, * equals('https://github.com/serenity-js/serenity-js') * ), * ) * ``` * * ## Performing activities in the context of another page * * ```ts * import { Ensure, equals, includes, startsWith } from '@serenity-js/assertions' * import { actorCalled } from '@serenity-js/core' * import { Navigate, Page, Text } from '@serenity-js/web' * * const Navigation = { * linkTo = (name: Answerable<string>) => * PageElements.located(By.css('nav a')) * .where(Text, includes(name)) * .first() * } * * await actorCalled('Serena').attemptsTo( * * // Serenity/JS GitHub repository opens in a new browser tab * Navigate.to('https://serenity-js.org'), * Click.on(Navigation.linkTo('GitHub')), * * // Switch to the newly opened page and perform an assertion * Switch.to(Page.whichUrl(startsWith('https://github.com'))) * .and( * Ensure.that( * Page.current().url().href, * equals('https://github.com/serenity-js/serenity-js') * ) * ), * // Automatically switch back to the original page * * Ensure.that(Page.current().url().href, equals('https://serenity-js.org'), * ) * ``` * * ## Learn more * * - [`BrowseTheWeb`](https://serenity-js.org/api/web/class/BrowseTheWeb/) * - [`PageElement`](https://serenity-js.org/api/web/class/PageElement/) * - [`Optional`](https://serenity-js.org/api/core/interface/Optional/) * - [`Switchable`](https://serenity-js.org/api/web/interface/Switchable/) * * @group Models */ class Page { session; rootLocator; modalDialogHandler; id; /** * Creates a [`QuestionAdapter`](https://serenity-js.org/api/core/#QuestionAdapter) representing the currently active [`Page`](https://serenity-js.org/api/web/class/Page/). */ static current() { return core_1.Question.about('current page', actor => { return abilities_1.BrowseTheWeb.as(actor).currentPage(); }); } /** * Creates a [`QuestionAdapter`](https://serenity-js.org/api/core/#QuestionAdapter) that resolves to a [`Page`](https://serenity-js.org/api/web/class/Page/) which [`Page.name`](https://serenity-js.org/api/web/class/Page/#name) * meets the [expectation](https://serenity-js.org/api/core/class/Expectation/). * * #### Switching to a page with the desired name * * ```ts * import { includes } from '@serenity-js/assertions' * import { actorCalled } from '@serenity-js/core' * import { Switch } from '@serenity-js/web' * * actorCalled('Bernie').attemptsTo( * Switch.to(Page.whichName(includes(`photo-gallery`))), * ) * ``` * * @param expectation */ static whichName(expectation) { return core_1.Question.about(`page which name does ${expectation}`, async (actor) => { const pages = await abilities_1.BrowseTheWeb.as(actor).allPages(); return Page.findMatchingPage(`name does ${expectation}`, pages, page => actor.answer(expectation.isMetFor(page.name()))); }); } /** * Creates a [`QuestionAdapter`](https://serenity-js.org/api/core/#QuestionAdapter) that resolves to a [`Page`](https://serenity-js.org/api/web/class/Page/) which [`Page.title`](https://serenity-js.org/api/web/class/Page/#title) * meets the [expectation](https://serenity-js.org/api/core/class/Expectation/). * * #### Switching to a page with the desired title * * ```ts * import { includes } from '@serenity-js/assertions' * import { actorCalled } from '@serenity-js/core' * import { Switch } from '@serenity-js/web' * * actorCalled('Bernie').attemptsTo( * Switch.to(Page.whichTitle(includes(`Summer collection`))), * ) * ``` * * @param expectation */ static whichTitle(expectation) { return core_1.Question.about(`page which title does ${expectation}`, async (actor) => { const pages = await abilities_1.BrowseTheWeb.as(actor).allPages(); return Page.findMatchingPage(`title does ${expectation}`, pages, page => actor.answer(expectation.isMetFor(page.title()))); }); } /** * Creates a [`QuestionAdapter`](https://serenity-js.org/api/core/#QuestionAdapter) that resolves to a [`Page`](https://serenity-js.org/api/web/class/Page/) which [`Page.url`](https://serenity-js.org/api/web/class/Page/#url) * meets the [expectation](https://serenity-js.org/api/core/class/Expectation/). * * #### Switching to a page with the desired URL * * ```ts * import { endsWith } from '@serenity-js/assertions' * import { actorCalled } from '@serenity-js/core' * import { Switch } from '@serenity-js/web' * * actorCalled('Bernie').attemptsTo( * Switch.to(Page.whichUrl(endsWith(`/gallery.html`))), * ) * ``` * * @param expectation */ static whichUrl(expectation) { return core_1.Question.about(`page which URL does ${expectation}`, async (actor) => { const pages = await abilities_1.BrowseTheWeb.as(actor).allPages(); return Page.findMatchingPage(`url does ${expectation}`, pages, page => actor.answer(expectation.isMetFor(page.url().then(url => url.toString())))); }); } static async findMatchingPage(expectationDescription, pages, matcher) { for (const page of pages) { const outcome = await matcher(page); if (outcome instanceof core_1.ExpectationMet) { return page; } } throw new core_1.LogicError(`Couldn't find a page which ${expectationDescription}`); } constructor(session, rootLocator, modalDialogHandler, id) { this.session = session; this.rootLocator = rootLocator; this.modalDialogHandler = modalDialogHandler; this.id = id; (0, tiny_types_1.ensure)('session', session, (0, tiny_types_1.isDefined)()); (0, tiny_types_1.ensure)('rootLocator', rootLocator, (0, tiny_types_1.isDefined)()); (0, tiny_types_1.ensure)('modalDialogHandler', modalDialogHandler, (0, tiny_types_1.isDefined)()); (0, tiny_types_1.ensure)('id', id, (0, tiny_types_1.isDefined)()); } /** * Switches the current browsing context to the given page * and returns an object that allows the caller to switch back * to the previous context when needed. * * ## Learn more * - [`Switch`](https://serenity-js.org/api/web/class/Switch/) * - [`Switchable`](https://serenity-js.org/api/web/interface/Switchable/) */ async switchTo() { const originalPage = await this.session.currentPage(); await this.session.changeCurrentPageTo(this); return { switchBack: async () => { await this.session.changeCurrentPageTo(originalPage); } }; } /** * Returns the [`ModalDialogHandler`](https://serenity-js.org/api/web/class/ModalDialogHandler/) for the current [`Page`](https://serenity-js.org/api/web/class/Page/). */ modalDialog() { return this.modalDialogHandler; } /** * Returns a description of this Page and its ID. */ toString() { return `page (id=${this.id.value})`; } } exports.Page = Page; //# sourceMappingURL=Page.js.map