@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
TypeScript
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