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

170 lines 5.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Press = void 0; const core_1 = require("@serenity-js/core"); const io_1 = require("@serenity-js/core/lib/io"); const abilities_1 = require("../abilities"); const models_1 = require("../models"); const PageElementInteraction_1 = require("./PageElementInteraction"); /** * Instructs an [actor](https://serenity-js.org/api/core/class/Actor/) who has the [ability](https://serenity-js.org/api/core/class/Ability/) to [`BrowseTheWeb`](https://serenity-js.org/api/web/class/BrowseTheWeb/) * to send a key press or a sequence of keys to a Web element. * * **Note:** On macOS, some keyboard shortcuts might not work * with the [`devtools` protocol](https://webdriver.io/docs/automationProtocols/#devtools-protocol). * * For example: * - to *copy*, instead of [`Key.Meta`](https://serenity-js.org/api/web/class/Key/#Meta)+`C`, use [`Key.Control`](https://serenity-js.org/api/web/class/Key/#Control)+[`Key.Insert`](https://serenity-js.org/api/web/class/Key/#Insert) * - to *cut*, instead of [`Key.Meta`](https://serenity-js.org/api/web/class/Key/#Meta)+`X`, use [`Key.Control`](https://serenity-js.org/api/web/class/Key/#Control)+[`Key.Delete`](https://serenity-js.org/api/web/class/Key/#Delete) * - to *paste*, instead of [`Key.Meta`](https://serenity-js.org/api/web/class/Key/#Meta)+`V`, use [`Key.Shift`](https://serenity-js.org/api/web/class/Key/#Shift)+[`Key.Insert`](https://serenity-js.org/api/web/class/Key/#Insert) * * ## Example widget * * ```html * <form> * <input type="text" name="example" id="example" /> * </form> * ``` * * ## Lean Page Object describing the widget * * ```ts * import { By, PageElement } from '@serenity-js/web' * * class Form { * static exampleInput = () => * PageElement.located(By.id('example')) * .describedAs('example input') * } * ``` * * ## Pressing keys * * ```ts * import { actorCalled } from '@serenity-js/core' * import { Key, Press, Value } from '@serenity-js/web' * import { Ensure, equals } from '@serenity-js/assertions' * * await actorCalled('Priyanka') * .attemptsTo( * Press.the('H', 'i', '!', Key.ENTER).in(Form.exampleInput()), * Ensure.that(Value.of(Form.exampleInput), equals('Hi!')), * ) * ``` * * ## Learn more * * - [`Key`](https://serenity-js.org/api/web/class/Key/) * - [`BrowseTheWeb`](https://serenity-js.org/api/web/class/BrowseTheWeb/) * - [`PageElement`](https://serenity-js.org/api/web/class/PageElement/) * * @group Activities */ class Press extends PageElementInteraction_1.PageElementInteraction { keys; /** * Instantiates an [interaction](https://serenity-js.org/api/core/class/Interaction/) * that instructs the [actor](https://serenity-js.org/api/core/class/Actor/) * to press a sequence of [keys](https://serenity-js.org/api/web/class/Key/), * * When no `field` is specified, the key sequence will be sent to the currently focused element, * and if no element is focused - to the `document.body` to handle. * * @param keys * A sequence of one or more keys to press */ static the(...keys) { return new Press(KeySequence.of(keys)); } /** * Send the key sequence to a specific element. * * @param field */ in(field) { return new PressKeyInField(this.keys, field); } /** * @param keys * A sequence of one or more keys to press */ constructor(keys) { super((0, core_1.the) `#actor presses ${keys}`); this.keys = keys; } /** * @inheritDoc */ async performAs(actor) { const keys = await actor.answer(this.keys); const page = await abilities_1.BrowseTheWeb.as(actor).currentPage(); return page.sendKeys(keys); } } exports.Press = Press; class PressKeyInField extends PageElementInteraction_1.PageElementInteraction { keys; field; /** * @param {Answerable<Array<Key | string>>} keys * A sequence of one or more keys to press * * @param {Answerable<PageElement>} field * Web element to send the keys to */ constructor(keys, field /* todo | Question<AlertPromise> | AlertPromise */) { super((0, core_1.the) `#actor presses ${keys} in ${field}`, core_1.Interaction.callerLocation(3)); this.keys = keys; this.field = field; } /** * @inheritDoc */ async performAs(actor) { const field = await this.resolve(actor, this.field); const keys = await actor.answer(this.keys); const page = await abilities_1.BrowseTheWeb.as(actor).currentPage(); // fix for protractor await page.executeScript( /* c8 ignore next */ function focus(element) { element.focus(); }, await field); return page.sendKeys(keys); } } /** * @package */ class KeySequence extends core_1.Question { keys; static of(keys) { return new KeySequence(keys); } constructor(keys) { super(KeySequence.describe(keys)); this.keys = keys; } async answeredBy(actor) { const keys = await (0, io_1.asyncMap)(this.keys, key => actor.answer(key)); return keys .flat() .filter(key => !!key); } static describe(keys) { const prefix = keys.length === 1 ? 'key' : 'keys'; const description = keys.reduce((acc, key, index) => { const separator = models_1.Key.isKey(key) && key.isModifier ? '-' : acc.separator; return { description: index === 0 ? `${key}` : `${acc.description}${acc.separator}${key}`, separator, }; }, { description: '', separator: ', ' }).description; return `${prefix} ${description}`; } } //# sourceMappingURL=Press.js.map