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

298 lines 11.8 kB
import type { Answerable, AnswersQuestions, CollectsArtifacts, UsesAbilities } from '@serenity-js/core'; import { Interaction } from '@serenity-js/core'; /** * 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 inject a script into the browser and execute it in the context of the current browser tab. * * ## Learn more * * - [`BrowseTheWeb`](https://serenity-js.org/api/web/class/BrowseTheWeb/) * - [`LastScriptExecution.result`](https://serenity-js.org/api/web/class/LastScriptExecution/#result) * * @group Activities */ export declare class ExecuteScript { /** * Instantiates a version of this [`Interaction`](https://serenity-js.org/api/core/class/Interaction/) * configured to load a script from `sourceUrl`. * * @param sourceUrl * The URL to load the script from */ static from(sourceUrl: Answerable<string>): Interaction; /** * 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 execute an asynchronous script within the context of the current browser tab. * * The script fragment will be executed as the body of an anonymous function. * If the script is provided as a function object, that function will be converted to a string for injection * into the target window. * * Any arguments provided in addition to the script will be included as script arguments and may be referenced * using the `arguments` object. Arguments may be a `boolean`, `number`, `string` * or [`PageElement`](https://serenity-js.org/api/web/class/PageElement/). * Arrays and objects may also be used as script arguments as long as each item adheres * to the types previously mentioned. * * Unlike executing synchronous JavaScript with [`ExecuteScript.sync`](https://serenity-js.org/api/web/class/ExecuteScript/#sync), * scripts executed with this function must explicitly signal they are finished by invoking the provided callback. * * This callback will always be injected into the executed function as the last argument, * and thus may be referenced with `arguments[arguments.length - 1]`. * * If the script invokes the `callback` with a return value, this will be made available * via the [`LastScriptExecution.result`](https://serenity-js.org/api/web/class/LastScriptExecution/#result). * * **Please note** that in order to signal an error in the `script` you need to throw an [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) * instead of passing it to the callback function. * * #### Executing an async script * * ```ts * import { actorCalled } from '@serenity-js/core' * import { ExecuteScript } from '@serenity-js/web' * * await actorCalled('Esti').attemptsTo( * ExecuteScript.async(` * var callback = arguments[arguments.length - 1] * * // do stuff * * callback(result) * `) * ) * ``` * * #### Executing async script as function * * ```ts * import { actorCalled } from '@serenity-js/core' * import { ExecuteScript } from '@serenity-js/web' * * const MyPage = { * header: () => * PageElement.located(By.css('h1')).describedAs('header'), * } * * await actorCalled('Esti').attemptsTo( * ExecuteScript.async(function getText(header, callback) { * callback(header.innerText) * }).withArguments(MyPage.header()) * ) * ``` * * #### Passing arguments to an async script * * ```ts * import { actorCalled } from '@serenity-js/core' * import { ExecuteScript } from '@serenity-js/web' * * await actorCalled('Esti').attemptsTo( * ExecuteScript.async(` * var name = arguments[0]; * var age = arguments[1]; * var callback = arguments[arguments.length - 1] * * // do stuff * * callback(result) * `).withArguments('Bob', 24) * ) * ``` * * #### Passing PageElement arguments to an async script * * Serenity/JS automatically converts [`PageElement`](https://serenity-js.org/api/web/class/PageElement/) objects passed as arguments to the script * into their corresponding DOM elements. * * ```ts * import { actorCalled } from '@serenity-js/core' * import { ExecuteScript, PageElement } from '@serenity-js/web' * * const MyPage = { * header: () => * PageElement.located(By.css('h1')).describedAs('header'), * } * * await actorCalled('Esti').attemptsTo( * ExecuteScript.async(` * var header = arguments[0] * var callback = arguments[arguments.length - 1] * * callback(header.innerText) * `).withArguments(MyPage.header()) * ) * ``` * * #### Using nested data structures containing PageElement objects * * Serenity/JS automatically converts any [`PageElement`](https://serenity-js.org/api/web/class/PageElement/) objects * contained in nested data structures passed to the script * into their corresponding DOM elements. * * ```ts * import { actorCalled } from '@serenity-js/core' * import { ExecuteScript, PageElement } from '@serenity-js/web' * * const MyPage = { * header: () => * PageElement.located(By.css('h1')).describedAs('header'), * * article: () => * PageElement.located(By.css('article')).describedAs('article'), * } * * await actorCalled('Esti').attemptsTo( * ExecuteScript.async(` * var { include, exclude } = arguments[0] * var callback = arguments[arguments.length - 1] * * callback(include[0].innerText) * `).withArguments({ * include: [ MyPage.article() ], * exclude: [ MyPage.header() ], * }) * ) * ``` * * #### Learn more * - [`LastScriptExecution.result`](https://serenity-js.org/api/web/class/LastScriptExecution/#result) * * @param script * The script to be executed */ static async(script: string | Function): ExecuteScriptWithArguments; /** * 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 execute a synchronous script within the context of the current browser tab. * * If the script returns a value, it will be made available via [`LastScriptExecution.result`](https://serenity-js.org/api/web/class/LastScriptExecution/#result). * * #### Executing a sync script as string and reading the result * * ```ts * import { actorCalled } from '@serenity-js/core' * import { ExecuteScript, LastScriptExecution } from '@serenity-js/web' * import { Ensure, includes } from '@serenity-js/assertions' * * await actorCalled('Joseph') * .attemptsTo( * ExecuteScript.sync('return navigator.userAgent'), * Ensure.that(LastScriptExecution.result<string>(), includes('Chrome')), * ) * ``` * * #### Executing a sync script as function and retrieving the result * * ```ts * import { actorCalled } from '@serenity-js/core' * import { By, Enter, ExecuteScript, LastScriptExecution, PageElement } from '@serenity-js/web' * * const Checkout = { * someOfferField: () => * PageElement.located(By.id('offer-code')) * .describedAs('offer code') * * applyOfferCodeField = () => * PageElement.located(By.id('apply-offer-code')) * .describedAs('apply offer field') * } * * await actorCalled('Joseph') * .attemptsTo( * // inject JavaScript to read some property of an element * ExecuteScript.sync(function getValue(element) { * return element.value; * }).withArguments(Checkout.someOfferField()), * * // use LastScriptExecution.result() to read the value * // returned from the injected script * // and pass it to another interaction * Enter.theValue(LastScriptExecution.result<string>()).into(Checkout.applyOfferCodeField()), * ) * ``` * * #### Passing PageElement arguments to a sync script * * Serenity/JS automatically converts [`PageElement`](https://serenity-js.org/api/web/class/PageElement/) objects passed as arguments to the script * into their corresponding DOM elements. * * ```ts * import { actorCalled } from '@serenity-js/core' * import { ExecuteScript, PageElement } from '@serenity-js/web' * * const MyPage = { * header: () => * PageElement.located(By.css('h1')).describedAs('header'), * } * * await actorCalled('Esti').attemptsTo( * ExecuteScript.sync(function getInnerHtml(element) { * return element.innerHTML; * }).withArguments(MyPage.header()) * ) * ``` * * #### Using nested data structures containing PageElement objects * * Serenity/JS automatically converts any [`PageElement`](https://serenity-js.org/api/web/class/PageElement/) objects * contained in nested data structures passed to the script * into their corresponding DOM elements. * * ```ts * import { actorCalled } from '@serenity-js/core' * import { ExecuteScript, PageElement } from '@serenity-js/web' * * const MyPage = { * header: () => * PageElement.located(By.css('h1')).describedAs('header'), * * article: () => * PageElement.located(By.css('article')).describedAs('article'), * } * * await actorCalled('Esti').attemptsTo( * ExecuteScript.async(function getInnerHtml(scope) { * return scope.include[0].innerHTML; * `).withArguments({ * include: [ MyPage.article() ], * exclude: [ MyPage.header() ], * }) * ) * ``` * * #### Learn more * - [`LastScriptExecution.result`](https://serenity-js.org/api/web/class/LastScriptExecution/#result) * * @param script * The script to be executed */ static sync(script: string | Function): ExecuteScriptWithArguments; } /** * Allows for a script to be executed to be parametrised. * * ## Learn more * - [`ExecuteScript`](https://serenity-js.org/api/web/class/ExecuteScript/) * * @group Activities */ export declare abstract class ExecuteScriptWithArguments extends Interaction { protected readonly script: string | Function; protected readonly args: Array<Answerable<any>>; constructor(description: Answerable<string>, script: string | Function, // eslint-disable-line @typescript-eslint/ban-types args?: Array<Answerable<any>>); /** * Instantiates this [`Interaction`](https://serenity-js.org/api/core/class/Interaction/) * * @param args * Arguments to parametrise the script with */ abstract withArguments(...args: Array<Answerable<any>>): Interaction; /** * @inheritDoc */ performAs(actor: UsesAbilities & CollectsArtifacts & AnswersQuestions): Promise<void>; protected abstract executeAs(actor: UsesAbilities & AnswersQuestions, args: any[]): Promise<any>; } //# sourceMappingURL=ExecuteScript.d.ts.map