declare namespace CodeceptJS { /** * Helper for managing remote data using REST API. * Uses data generators like [rosie](https://github.com/rosiejs/rosie) or factory girl to create new record. * * By defining a factory you set the rules of how data is generated. * This data will be saved on server via REST API and deleted in the end of a test. * * ## Use Case * * Acceptance tests interact with a websites using UI and real browser. * There is no way to create data for a specific test other than from user interface. * That makes tests slow and fragile. Instead of testing a single feature you need to follow all creation/removal process. * * This helper solves this problem. * Most of web application have API, and it can be used to create and delete test records. * By combining REST API with Factories you can easily create records for tests: * * ```js * I.have('user', { login: 'davert', email: 'davert@mail.com' }); * let id = await I.have('post', { title: 'My first post'}); * I.haveMultiple('comment', 3, {post_id: id}); * ``` * * To make this work you need * * 1. REST API endpoint which allows to perform create / delete requests and * 2. define data generation rules * * ### Setup * * Install [Rosie](https://github.com/rosiejs/rosie) and [Faker](https://www.npmjs.com/package/faker) libraries. * * ```sh * npm i rosie @faker-js/faker --save-dev * ``` * * Create a factory file for a resource. * * See the example for Posts factories: * * ```js * // tests/factories/posts.js * * const Factory = require('rosie').Factory; * const faker = require('@faker-js/faker'); * * module.exports = new Factory() * // no need to set id, it will be set by REST API * .attr('author', () => faker.name.findName()) * .attr('title', () => faker.lorem.sentence()) * .attr('body', () => faker.lorem.paragraph()); * ``` * For more options see [rosie documentation](https://github.com/rosiejs/rosie). * * Then configure ApiDataHelper to match factories and REST API: * ### Configuration * * ApiDataFactory has following config options: * * * `endpoint`: base URL for the API to send requests to. * * `cleanup` (default: true): should inserted records be deleted up after tests * * `factories`: list of defined factories * * `returnId` (default: false): return id instead of a complete response when creating items. * * `headers`: list of headers * * `REST`: configuration for REST requests * * See the example: * * ```js * ApiDataFactory: { * endpoint: "http://user.com/api", * cleanup: true, * headers: { * 'Content-Type': 'application/json', * 'Accept': 'application/json', * }, * factories: { * post: { * uri: "/posts", * factory: "./factories/post", * }, * comment: { * factory: "./factories/comment", * create: { post: "/comments/create" }, * delete: { post: "/comments/delete/{id}" }, * fetchId: (data) => data.result.id * } * } * } * ``` * It is required to set REST API `endpoint` which is the baseURL for all API requests. * Factory file is expected to be passed via `factory` option. * * This Helper uses [REST](http://codecept.io/helpers/REST/) helper and accepts its configuration in "REST" section. * For instance, to set timeout you should add: * * ```js * "ApiDataFactory": { * "REST": { * "timeout": "100000", * } * } * ``` * * ### Requests * * By default to create a record ApiDataFactory will use endpoint and plural factory name: * * * create: `POST {endpoint}/{resource} data` * * delete: `DELETE {endpoint}/{resource}/id` * * Example (`endpoint`: `http://app.com/api`): * * * create: POST request to `http://app.com/api/users` * * delete: DELETE request to `http://app.com/api/users/1` * * This behavior can be configured with following options: * * * `uri`: set different resource uri. Example: `uri: account` => `http://app.com/api/account`. * * `create`: override create options. Expected format: `{ method: uri }`. Example: `{ "post": "/users/create" }` * * `delete`: override delete options. Expected format: `{ method: uri }`. Example: `{ "post": "/users/delete/{id}" }` * * Requests can also be overridden with a function which returns [axois request config](https://github.com/axios/axios#request-config). * * ```js * create: (data) => ({ method: 'post', url: '/posts', data }), * delete: (id) => ({ method: 'delete', url: '/posts', data: { id } }) * * ``` * * Requests can be updated on the fly by using `onRequest` function. For instance, you can pass in current session from a cookie. * * ```js * onRequest: async (request) => { * // using global codeceptjs instance * let cookie = await codeceptjs.container.helpers('WebDriver').grabCookie('session'); * request.headers = { Cookie: `session=${cookie.value}` }; * } * ``` * * ### Responses * * By default `I.have()` returns a promise with a created data: * * ```js * let client = await I.have('client'); * ``` * * Ids of created records are collected and used in the end of a test for the cleanup. * If you need to receive `id` instead of full response enable `returnId` in a helper config: * * ```js * // returnId: false * let clientId = await I.have('client'); * // clientId == 1 * * // returnId: true * let clientId = await I.have('client'); * // client == { name: 'John', email: 'john@snow.com' } * ``` * * By default `id` property of response is taken. This behavior can be changed by setting `fetchId` function in a factory config. * * * ```js * factories: { * post: { * uri: "/posts", * factory: "./factories/post", * fetchId: (data) => data.result.posts[0].id * } * } * ``` * * * ## Methods */ class ApiDataFactory { /** * Generates a new record using factory and saves API request to store it. * * ```js * // create a user * I.have('user'); * // create user with defined email * // and receive it when inside async function * const user = await I.have('user', { email: 'user@user.com'}); * // create a user with options that will not be included in the final request * I.have('user', { }, { age: 33, height: 55 }) * ``` * @param factory - factory to use * @param params - predefined parameters * @param options - options for programmatically generate the attributes */ have(factory: any, params: any, options: any): Promise; /** * Generates bunch of records and saves multiple API requests to store them. * * ```js * // create 3 posts * I.haveMultiple('post', 3); * * // create 3 posts by one author * I.haveMultiple('post', 3, { author: 'davert' }); * * // create 3 posts by one author with options * I.haveMultiple('post', 3, { author: 'davert' }, { publish_date: '01.01.1997' }); * ``` */ haveMultiple(factory: any, times: any, params: any, options: any): void; /** * Executes request to create a record in API. * Can be replaced from a in custom helper. */ _requestCreate(factory: any, data: any): void; /** * Executes request to delete a record in API * Can be replaced from a custom helper. */ _requestDelete(factory: any, id: any): void; } /** * Appium Special Methods for Mobile only */ class Appium extends WebDriver { /** * Execute code only on iOS * * ```js * I.runOnIOS(() => { * I.click('//UIAApplication[1]/UIAWindow[1]/UIAButton[1]'); * I.see('Hi, IOS', '~welcome'); * }); * ``` * * Additional filter can be applied by checking for capabilities. * For instance, this code will be executed only on iPhone 5s: * * * ```js * I.runOnIOS({deviceName: 'iPhone 5s'},() => { * // ... * }); * ``` * * Also capabilities can be checked by a function. * * ```js * I.runOnAndroid((caps) => { * // caps is current config of desiredCapabiliites * return caps.platformVersion >= 6 * },() => { * // ... * }); * ``` */ runOnIOS(caps: any, fn: any): void; /** * Execute code only on Android * * ```js * I.runOnAndroid(() => { * I.click('io.selendroid.testapp:id/buttonTest'); * }); * ``` * * Additional filter can be applied by checking for capabilities. * For instance, this code will be executed only on Android 6.0: * * * ```js * I.runOnAndroid({platformVersion: '6.0'},() => { * // ... * }); * ``` * * Also capabilities can be checked by a function. * In this case, code will be executed only on Android >= 6. * * ```js * I.runOnAndroid((caps) => { * // caps is current config of desiredCapabiliites * return caps.platformVersion >= 6 * },() => { * // ... * }); * ``` */ runOnAndroid(caps: any, fn: any): void; /** * Returns app installation status. * * ```js * I.checkIfAppIsInstalled("com.example.android.apis"); * ``` * @param bundleId - String ID of bundled app * @returns Appium: support only Android */ checkIfAppIsInstalled(bundleId: string): Promise; /** * Check if an app is installed. * * ```js * I.seeAppIsInstalled("com.example.android.apis"); * ``` * @param bundleId - String ID of bundled app * @returns Appium: support only Android */ seeAppIsInstalled(bundleId: string): Promise; /** * Check if an app is not installed. * * ```js * I.seeAppIsNotInstalled("com.example.android.apis"); * ``` * @param bundleId - String ID of bundled app * @returns Appium: support only Android */ seeAppIsNotInstalled(bundleId: string): Promise; /** * Install an app on device. * * ```js * I.installApp('/path/to/file.apk'); * ``` * @param path - path to apk file * @returns Appium: support only Android */ installApp(path: string): Promise; /** * Remove an app from the device. * * ```js * I.removeApp('appName', 'com.example.android.apis'); * ``` * * Appium: support only Android * @param [bundleId] - ID of bundle */ removeApp(appId: string, bundleId?: string): void; /** * Reset the currently running app for current session. * * ```js * I.resetApp(); * ``` */ resetApp(): void; /** * Check current activity on an Android device. * * ```js * I.seeCurrentActivityIs(".HomeScreenActivity") * ``` * @returns Appium: support only Android */ seeCurrentActivityIs(currentActivity: string): Promise; /** * Check whether the device is locked. * * ```js * I.seeDeviceIsLocked(); * ``` * @returns Appium: support only Android */ seeDeviceIsLocked(): Promise; /** * Check whether the device is not locked. * * ```js * I.seeDeviceIsUnlocked(); * ``` * @returns Appium: support only Android */ seeDeviceIsUnlocked(): Promise; /** * Check the device orientation * * ```js * I.seeOrientationIs('PORTRAIT'); * I.seeOrientationIs('LANDSCAPE') * ``` * @param orientation - LANDSCAPE or PORTRAIT * * Appium: support Android and iOS */ seeOrientationIs(orientation: 'LANDSCAPE' | 'PORTRAIT'): Promise; /** * Set a device orientation. Will fail, if app will not set orientation * * ```js * I.setOrientation('PORTRAIT'); * I.setOrientation('LANDSCAPE') * ``` * @param orientation - LANDSCAPE or PORTRAIT * * Appium: support Android and iOS */ setOrientation(orientation: 'LANDSCAPE' | 'PORTRAIT'): void; /** * Get list of all available contexts * * ``` * let contexts = await I.grabAllContexts(); * ``` * @returns Appium: support Android and iOS */ grabAllContexts(): Promise; /** * Retrieve current context * * ```js * let context = await I.grabContext(); * ``` * @returns Appium: support Android and iOS */ grabContext(): Promise; /** * Get current device activity. * * ```js * let activity = await I.grabCurrentActivity(); * ``` * @returns Appium: support only Android */ grabCurrentActivity(): Promise; /** * Get information about the current network connection (Data/WIFI/Airplane). * The actual server value will be a number. However WebdriverIO additional * properties to the response object to allow easier assertions. * * ```js * let con = await I.grabNetworkConnection(); * ``` * @returns Appium: support only Android */ grabNetworkConnection(): Promise<{}>; /** * Get current orientation. * * ```js * let orientation = await I.grabOrientation(); * ``` * @returns Appium: support Android and iOS */ grabOrientation(): Promise; /** * Get all the currently specified settings. * * ```js * let settings = await I.grabSettings(); * ``` * @returns Appium: support Android and iOS */ grabSettings(): Promise; /** * Switch to the specified context. * @param context - the context to switch to */ _switchToContext(context: any): void; /** * Switches to web context. * If no context is provided switches to the first detected web context * * ```js * // switch to first web context * I.switchToWeb(); * * // or set the context explicitly * I.switchToWeb('WEBVIEW_io.selendroid.testapp'); * ``` */ switchToWeb(context?: string): Promise; /** * Switches to native context. * By default switches to NATIVE_APP context unless other specified. * * ```js * I.switchToNative(); * * // or set context explicitly * I.switchToNative('SOME_OTHER_CONTEXT'); * ``` */ switchToNative(context?: any): Promise; /** * Start an arbitrary Android activity during a session. * * ```js * I.startActivity('io.selendroid.testapp', '.RegisterUserActivity'); * ``` * * Appium: support only Android */ startActivity(appPackage: string, appActivity: string): Promise; /** * Set network connection mode. * * * airplane mode * * wifi mode * * data data * * ```js * I.setNetworkConnection(0) // airplane mode off, wifi off, data off * I.setNetworkConnection(1) // airplane mode on, wifi off, data off * I.setNetworkConnection(2) // airplane mode off, wifi on, data off * I.setNetworkConnection(4) // airplane mode off, wifi off, data on * I.setNetworkConnection(6) // airplane mode off, wifi on, data on * ``` * See corresponding [webdriverio reference](http://webdriver.io/api/mobile/setNetworkConnection.html). * @returns Appium: support only Android */ setNetworkConnection(): Promise<{}>; /** * Update the current setting on the device * * ```js * I.setSettings({cyberdelia: 'open'}); * ``` * @param settings - object * * Appium: support Android and iOS */ setSettings(settings: any): void; /** * Hide the keyboard. * * ```js * // taps outside to hide keyboard per default * I.hideDeviceKeyboard(); * I.hideDeviceKeyboard('tapOutside'); * * // or by pressing key * I.hideDeviceKeyboard('pressKey', 'Done'); * ``` * * Appium: support Android and iOS * @param [strategy] - Desired strategy to close keyboard (‘tapOutside’ or ‘pressKey’) * @param [key] - Optional key */ hideDeviceKeyboard(strategy?: 'tapOutside' | 'pressKey', key?: string): void; /** * Send a key event to the device. * List of keys: https://developer.android.com/reference/android/view/KeyEvent.html * * ```js * I.sendDeviceKeyEvent(3); * ``` * @param keyValue - Device specific key value * @returns Appium: support only Android */ sendDeviceKeyEvent(keyValue: number): Promise; /** * Open the notifications panel on the device. * * ```js * I.openNotifications(); * ``` * @returns Appium: support only Android */ openNotifications(): Promise; /** * The Touch Action API provides the basis of all gestures that can be * automated in Appium. At its core is the ability to chain together ad hoc * individual actions, which will then be applied to an element in the * application on the device. * [See complete documentation](http://webdriver.io/api/mobile/touchAction.html) * * ```js * I.makeTouchAction("~buttonStartWebviewCD", 'tap'); * ``` * @returns Appium: support Android and iOS */ makeTouchAction(): Promise; /** * Taps on element. * * ```js * I.tap("~buttonStartWebviewCD"); * ``` * * Shortcut for `makeTouchAction` */ tap(locator: any): Promise; /** * Perform a swipe on the screen. * * ```js * I.performSwipe({ x: 300, y: 100 }, { x: 200, y: 100 }); * ``` * @param to - Appium: support Android and iOS */ performSwipe(from: any, to: any): void; /** * Perform a swipe down on an element. * * ```js * let locator = "#io.selendroid.testapp:id/LinearLayout1"; * I.swipeDown(locator); // simple swipe * I.swipeDown(locator, 500); // set speed * I.swipeDown(locator, 1200, 1000); // set offset and speed * ``` * @param [yoffset = 1000] - (optional) * @param [speed = 1000] - (optional), 1000 by default * @returns Appium: support Android and iOS */ swipeDown(locator: CodeceptJS.LocatorOrString, yoffset?: number, speed?: number): Promise; /** * Perform a swipe left on an element. * * ```js * let locator = "#io.selendroid.testapp:id/LinearLayout1"; * I.swipeLeft(locator); // simple swipe * I.swipeLeft(locator, 500); // set speed * I.swipeLeft(locator, 1200, 1000); // set offset and speed * ``` * @param [xoffset = 1000] - (optional) * @param [speed = 1000] - (optional), 1000 by default * @returns Appium: support Android and iOS */ swipeLeft(locator: CodeceptJS.LocatorOrString, xoffset?: number, speed?: number): Promise; /** * Perform a swipe right on an element. * * ```js * let locator = "#io.selendroid.testapp:id/LinearLayout1"; * I.swipeRight(locator); // simple swipe * I.swipeRight(locator, 500); // set speed * I.swipeRight(locator, 1200, 1000); // set offset and speed * ``` * @param [xoffset = 1000] - (optional) * @param [speed = 1000] - (optional), 1000 by default * @returns Appium: support Android and iOS */ swipeRight(locator: CodeceptJS.LocatorOrString, xoffset?: number, speed?: number): Promise; /** * Perform a swipe up on an element. * * ```js * let locator = "#io.selendroid.testapp:id/LinearLayout1"; * I.swipeUp(locator); // simple swipe * I.swipeUp(locator, 500); // set speed * I.swipeUp(locator, 1200, 1000); // set offset and speed * ``` * @param [yoffset = 1000] - (optional) * @param [speed = 1000] - (optional), 1000 by default * @returns Appium: support Android and iOS */ swipeUp(locator: CodeceptJS.LocatorOrString, yoffset?: number, speed?: number): Promise; /** * Perform a swipe in selected direction on an element to searchable element. * * ```js * I.swipeTo( * "android.widget.CheckBox", // searchable element * "//android.widget.ScrollView/android.widget.LinearLayout", // scroll element * "up", // direction * 30, * 100, * 500); * ``` * @returns Appium: support Android and iOS */ swipeTo(searchableLocator: string, scrollLocator: string, direction: string, timeout: number, offset: number, speed: number): Promise; /** * Performs a specific touch action. * The action object need to contain the action name, x/y coordinates * * ```js * I.touchPerform([{ * action: 'press', * options: { * x: 100, * y: 200 * } * }, {action: 'release'}]) * * I.touchPerform([{ * action: 'tap', * options: { * element: '1', // json web element was queried before * x: 10, // x offset * y: 20, // y offset * count: 1 // number of touches * } * }]); * ``` * * Appium: support Android and iOS * @param actions - Array of touch actions */ touchPerform(actions: any[]): void; /** * Pulls a file from the device. * * ```js * I.pullFile('/storage/emulated/0/DCIM/logo.png', 'my/path'); * // save file to output dir * I.pullFile('/storage/emulated/0/DCIM/logo.png', output_dir); * ``` * @returns Appium: support Android and iOS */ pullFile(path: string, dest: string): Promise; /** * Perform a shake action on the device. * * ```js * I.shakeDevice(); * ``` * @returns Appium: support only iOS */ shakeDevice(): Promise; /** * Perform a rotation gesture centered on the specified element. * * ```js * I.rotate(120, 120) * ``` * * See corresponding [webdriverio reference](http://webdriver.io/api/mobile/rotate.html). * @returns Appium: support only iOS */ rotate(): Promise; /** * Set immediate value in app. * * See corresponding [webdriverio reference](http://webdriver.io/api/mobile/setImmediateValue.html). * @returns Appium: support only iOS */ setImmediateValue(): Promise; /** * Simulate Touch ID with either valid (match == true) or invalid (match == false) fingerprint. * * ```js * I.touchId(); // simulates valid fingerprint * I.touchId(true); // simulates valid fingerprint * I.touchId(false); // simulates invalid fingerprint * ``` * @returns Appium: support only iOS * TODO: not tested */ simulateTouchId(): Promise; /** * Close the given application. * * ```js * I.closeApp(); * ``` * @returns Appium: support only iOS */ closeApp(): Promise; /** * Appends text to a input field or textarea. * Field is located by name, label, CSS or XPath * * ```js * I.appendField('#myTextField', 'appended'); * ``` * @param field - located by label|name|CSS|XPath|strict locator * @param value - text value to append. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ appendField(field: CodeceptJS.LocatorOrString, value: string): void; /** * Selects a checkbox or radio button. * Element is located by label or name or CSS or XPath. * * The second parameter is a context (CSS or XPath locator) to narrow the search. * * ```js * I.checkOption('#agree'); * I.checkOption('I Agree to Terms and Conditions'); * I.checkOption('agree', '//form'); * ``` * @param field - checkbox located by label | name | CSS | XPath | strict locator. * @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ checkOption(field: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void; /** * Perform a click on a link or a button, given by a locator. * If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string. * For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched. * For images, the "alt" attribute and inner text of any parent links are searched. * * The second parameter is a context (CSS or XPath locator) to narrow the search. * * ```js * // simple link * I.click('Logout'); * // button of form * I.click('Submit'); * // CSS button * I.click('#form input[type=submit]'); * // XPath * I.click('//form/*[@type=submit]'); * // link in context * I.click('Logout', '#nav'); * // using strict locator * I.click({css: 'nav a.login'}); * ``` * @param locator - clickable link or button located by text, or any element located by CSS|XPath|strict locator. * @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ click(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString | null): void; /** * Verifies that the specified checkbox is not checked. * * ```js * I.dontSeeCheckboxIsChecked('#agree'); // located by ID * I.dontSeeCheckboxIsChecked('I agree to terms'); // located by label * I.dontSeeCheckboxIsChecked('agree'); // located by name * ``` * @param field - located by label|name|CSS|XPath|strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSeeCheckboxIsChecked(field: CodeceptJS.LocatorOrString): void; /** * Opposite to `seeElement`. Checks that element is not visible (or in DOM) * * ```js * I.dontSeeElement('.modal'); // modal is not shown * ``` * @param locator - located by CSS|XPath|Strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSeeElement(locator: CodeceptJS.LocatorOrString): void; /** * Checks that value of input field or textarea doesn't equal to given value * Opposite to `seeInField`. * * ```js * I.dontSeeInField('email', 'user@user.com'); // field by name * I.dontSeeInField({ css: 'form input.email' }, 'user@user.com'); // field by CSS * ``` * @param field - located by label|name|CSS|XPath|strict locator. * @param value - value to check. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSeeInField(field: CodeceptJS.LocatorOrString, value: string): void; /** * Opposite to `see`. Checks that a text is not present on a page. * Use context parameter to narrow down the search. * * ```js * I.dontSee('Login'); // assume we are already logged in. * I.dontSee('Login', '.nav'); // no login inside .nav element * ``` * @param text - which is not present. * @param [context = null] - (optional) element located by CSS|XPath|strict locator in which to perfrom search. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSee(text: string, context?: CodeceptJS.LocatorOrString): void; /** * Fills a text field or textarea, after clearing its value, with the given string. * Field is located by name, label, CSS, or XPath. * * ```js * // by label * I.fillField('Email', 'hello@world.com'); * // by name * I.fillField('password', secret('123456')); * // by CSS * I.fillField('form#login input[name=username]', 'John'); * // or by strict locator * I.fillField({css: 'form#login input[name=username]'}, 'John'); * ``` * @param field - located by label|name|CSS|XPath|strict locator. * @param value - text value to fill. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ fillField(field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret): void; /** * Retrieves all texts from an element located by CSS or XPath and returns it to test. * Resumes test execution, so **should be used inside async with `await`** operator. * * ```js * let pins = await I.grabTextFromAll('#pin li'); * ``` * @param locator - element located by CSS|XPath|strict locator. * @returns attribute value */ grabTextFromAll(locator: CodeceptJS.LocatorOrString): Promise; /** * Retrieves a text from an element located by CSS or XPath and returns it to test. * Resumes test execution, so **should be used inside async with `await`** operator. * * ```js * let pin = await I.grabTextFrom('#pin'); * ``` * If multiple elements found returns first element. * @param locator - element located by CSS|XPath|strict locator. * @returns attribute value */ grabTextFrom(locator: CodeceptJS.LocatorOrString): Promise; /** * Grab number of visible elements by locator. * Resumes test execution, so **should be used inside async function with `await`** operator. * * ```js * let numOfElements = await I.grabNumberOfVisibleElements('p'); * ``` * @param locator - located by CSS|XPath|strict locator. * @returns number of visible elements */ grabNumberOfVisibleElements(locator: CodeceptJS.LocatorOrString): Promise; /** * Can be used for apps only with several values ("contentDescription", "text", "className", "resourceId") * * Retrieves an attribute from an element located by CSS or XPath and returns it to test. * Resumes test execution, so **should be used inside async with `await`** operator. * If more than one element is found - attribute of first element is returned. * * ```js * let hint = await I.grabAttributeFrom('#tooltip', 'title'); * ``` * @param locator - element located by CSS|XPath|strict locator. * @param attr - attribute name. * @returns attribute value */ grabAttributeFrom(locator: CodeceptJS.LocatorOrString, attr: string): Promise; /** * Can be used for apps only with several values ("contentDescription", "text", "className", "resourceId") * Retrieves an array of attributes from elements located by CSS or XPath and returns it to test. * Resumes test execution, so **should be used inside async with `await`** operator. * * ```js * let hints = await I.grabAttributeFromAll('.tooltip', 'title'); * ``` * @param locator - element located by CSS|XPath|strict locator. * @param attr - attribute name. * @returns attribute value */ grabAttributeFromAll(locator: CodeceptJS.LocatorOrString, attr: string): Promise; /** * Retrieves an array of value from a form located by CSS or XPath and returns it to test. * Resumes test execution, so **should be used inside async function with `await`** operator. * * ```js * let inputs = await I.grabValueFromAll('//form/input'); * ``` * @param locator - field located by label|name|CSS|XPath|strict locator. * @returns attribute value */ grabValueFromAll(locator: CodeceptJS.LocatorOrString): Promise; /** * Retrieves a value from a form element located by CSS or XPath and returns it to test. * Resumes test execution, so **should be used inside async function with `await`** operator. * If more than one element is found - value of first element is returned. * * ```js * let email = await I.grabValueFrom('input[name=email]'); * ``` * @param locator - field located by label|name|CSS|XPath|strict locator. * @returns attribute value */ grabValueFrom(locator: CodeceptJS.LocatorOrString): Promise; /** * Saves a screenshot to ouput folder (set in codecept.conf.ts or codecept.conf.js). * Filename is relative to output folder. * * ```js * I.saveScreenshot('debug.png'); * ``` * @param fileName - file name to save. */ saveScreenshot(fileName: string): Promise; /** * Scroll element into viewport. * * ```js * I.scrollIntoView('#submit'); * I.scrollIntoView('#submit', true); * I.scrollIntoView('#submit', { behavior: "smooth", block: "center", inline: "center" }); * ``` * @param locator - located by CSS|XPath|strict locator. * @param scrollIntoViewOptions - see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView. * ⚠️ returns a _promise_ which is synchronized internally by recorder * * * Supported only for web testing */ scrollIntoView(locator: LocatorOrString, scrollIntoViewOptions: ScrollIntoViewOptions): void; /** * Verifies that the specified checkbox is checked. * * ```js * I.seeCheckboxIsChecked('Agree'); * I.seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms * I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'}); * ``` * @param field - located by label|name|CSS|XPath|strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeCheckboxIsChecked(field: CodeceptJS.LocatorOrString): void; /** * Checks that a given Element is visible * Element is located by CSS or XPath. * * ```js * I.seeElement('#modal'); * ``` * @param locator - located by CSS|XPath|strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeElement(locator: CodeceptJS.LocatorOrString): void; /** * Checks that the given input field or textarea equals to given value. * For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath. * * ```js * I.seeInField('Username', 'davert'); * I.seeInField({css: 'form textarea'},'Type your comment here'); * I.seeInField('form input[type=hidden]','hidden_value'); * I.seeInField('#searchform input','Search'); * ``` * @param field - located by label|name|CSS|XPath|strict locator. * @param value - value to check. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeInField(field: CodeceptJS.LocatorOrString, value: string): void; /** * Checks that a page contains a visible text. * Use context parameter to narrow down the search. * * ```js * I.see('Welcome'); // text welcome on a page * I.see('Welcome', '.content'); // text inside .content div * I.see('Register', {css: 'form.register'}); // use strict locator * ``` * @param text - expected on page. * @param [context = null] - (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ see(text: string, context?: CodeceptJS.LocatorOrString): void; /** * Selects an option in a drop-down select. * Field is searched by label | name | CSS | XPath. * Option is selected by visible text or by value. * * ```js * I.selectOption('Choose Plan', 'Monthly'); // select by label * I.selectOption('subscription', 'Monthly'); // match option by text * I.selectOption('subscription', '0'); // or by value * I.selectOption('//form/select[@name=account]','Premium'); * I.selectOption('form select[name=account]', 'Premium'); * I.selectOption({css: 'form select[name=account]'}, 'Premium'); * ``` * * Provide an array for the second argument to select multiple options. * * ```js * I.selectOption('Which OS do you use?', ['Android', 'iOS']); * ``` * @param select - field located by label|name|CSS|XPath|strict locator. * @param option - visible text or value of option. * ⚠️ returns a _promise_ which is synchronized internally by recorder * * * Supported only for web testing */ selectOption(select: LocatorOrString, option: string | any[]): void; /** * Waits for element to be present on page (by default waits for 1sec). * Element can be located by CSS or XPath. * * ```js * I.waitForElement('.btn.continue'); * I.waitForElement('.btn.continue', 5); // wait for 5 secs * ``` * @param locator - element located by CSS|XPath|strict locator. * @param [sec = null] - (optional, `1` by default) time in seconds to wait * ⚠️ returns a _promise_ which is synchronized internally by recorder */ waitForElement(locator: CodeceptJS.LocatorOrString, sec?: number): void; /** * Waits for an element to become visible on a page (by default waits for 1sec). * Element can be located by CSS or XPath. * * ```js * I.waitForVisible('#popup'); * ``` * @param locator - element located by CSS|XPath|strict locator. * @param [sec = 1] - (optional, `1` by default) time in seconds to wait * ⚠️ returns a _promise_ which is synchronized internally by recorder */ waitForVisible(locator: CodeceptJS.LocatorOrString, sec?: number): void; /** * Waits for an element to be removed or become invisible on a page (by default waits for 1sec). * Element can be located by CSS or XPath. * * ```js * I.waitForInvisible('#popup'); * ``` * @param locator - element located by CSS|XPath|strict locator. * @param [sec = 1] - (optional, `1` by default) time in seconds to wait * ⚠️ returns a _promise_ which is synchronized internally by recorder */ waitForInvisible(locator: CodeceptJS.LocatorOrString, sec?: number): void; /** * Waits for a text to appear (by default waits for 1sec). * Element can be located by CSS or XPath. * Narrow down search results by providing context. * * ```js * I.waitForText('Thank you, form has been submitted'); * I.waitForText('Thank you, form has been submitted', 5, '#modal'); * ``` * @param text - to wait for. * @param [sec = 1] - (optional, `1` by default) time in seconds to wait * @param [context = null] - (optional) element located by CSS|XPath|strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ waitForText(text: string, sec?: number, context?: CodeceptJS.LocatorOrString): void; } /** * Helper for testing filesystem. * Can be easily used to check file structures: * * ```js * I.amInPath('test'); * I.seeFile('codecept.js'); * I.seeInThisFile('FileSystem'); * I.dontSeeInThisFile("WebDriver"); * ``` * * ## Configuration * * Enable helper in config file: * * ```js * helpers: { * FileSystem: {}, * } * ``` * * ## Methods */ class FileSystem { /** * Enters a directory In local filesystem. * Starts from a current directory */ amInPath(openPath: string): void; /** * Writes test to file */ writeToFile(name: string, text: string): void; /** * Checks that file exists */ seeFile(name: string): void; /** * Waits for file to be present in current directory. * * ```js * I.handleDownloads(); * I.click('Download large File'); * I.amInPath('output/downloads'); * I.waitForFile('largeFilesName.txt', 10); // wait 10 seconds for file * ``` * @param [sec = 1] - seconds to wait */ waitForFile(name: string, sec?: number): void; /** * Checks that file with a name including given text exists in the current directory. * * ```js * I.handleDownloads(); * I.click('Download as PDF'); * I.amInPath('output/downloads'); * I.seeFileNameMatching('.pdf'); * ``` */ seeFileNameMatching(text: string): void; /** * Checks that file found by `seeFile` includes a text. */ seeInThisFile(text: string, encoding?: string): void; /** * Checks that file found by `seeFile` doesn't include text. */ dontSeeInThisFile(text: string, encoding?: string): void; /** * Checks that contents of file found by `seeFile` equal to text. */ seeFileContentsEqual(text: string, encoding?: string): void; /** * Checks that contents of the file found by `seeFile` equal to contents of the file at `pathToReferenceFile`. */ seeFileContentsEqualReferenceFile(pathToReferenceFile: string, encoding?: string, encodingReference?: string): void; /** * Checks that contents of file found by `seeFile` doesn't equal to text. */ dontSeeFileContentsEqual(text: string, encoding?: string): void; /** * Returns file names in current directory. * * ```js * I.handleDownloads(); * I.click('Download Files'); * I.amInPath('output/downloads'); * const downloadedFileNames = I.grabFileNames(); * ``` */ grabFileNames(): void; } /** * GraphQL helper allows to send additional requests to a GraphQl endpoint during acceptance tests. * [Axios](https://github.com/axios/axios) library is used to perform requests. * * ## Configuration * * * endpoint: GraphQL base URL * * timeout: timeout for requests in milliseconds. 10000ms by default * * defaultHeaders: a list of default headers * * onRequest: a async function which can update request object. * * ## Example * * ```js * GraphQL: { * endpoint: 'http://site.com/graphql/', * onRequest: (request) => { * request.headers.auth = '123'; * } * } * ``` * * ## Access From Helpers * * Send GraphQL requests by accessing `_executeQuery` method: * * ```js * this.helpers['GraphQL']._executeQuery({ * url, * data, * }); * ``` * * ## Methods */ class GraphQL { /** * Executes query via axios call */ _executeQuery(request: any): void; /** * Prepares request for axios call * @returns graphQLRequest */ _prepareGraphQLRequest(operation: any, headers: any): any; /** * Send query to GraphQL endpoint over http. * Returns a response as a promise. * * ```js * * const response = await I.sendQuery('{ users { name email }}'); * // with variables * const response = await I.sendQuery( * 'query getUser($id: ID) { user(id: $id) { name email }}', * { id: 1 }, * ) * const user = response.data.data; * ``` * @param [variables] - that may go along with the query * @param [options] - are additional query options * @returns Promise */ sendQuery(query: string, variables?: any, options?: any, headers?: any): any; /** * Send query to GraphQL endpoint over http * * ```js * I.sendMutation(` * mutation createUser($user: UserInput!) { * createUser(user: $user) { * id * name * email * } * } * `, * { user: { * name: 'John Doe', * email: 'john@xmail.com' * } * }, * }); * ``` * @param [variables] - that may go along with the mutation * @param [options] - are additional query options * @returns Promise */ sendMutation(mutation: string, variables?: any, options?: any, headers?: any): any; } /** * Helper for managing remote data using GraphQL queries. * Uses data generators like [rosie](https://github.com/rosiejs/rosie) or factory girl to create new record. * * By defining a factory you set the rules of how data is generated. * This data will be saved on server via GraphQL queries and deleted in the end of a test. * * ## Use Case * * Acceptance tests interact with a websites using UI and real browser. * There is no way to create data for a specific test other than from user interface. * That makes tests slow and fragile. Instead of testing a single feature you need to follow all creation/removal process. * * This helper solves this problem. * If a web application has GraphQL support, it can be used to create and delete test records. * By combining GraphQL with Factories you can easily create records for tests: * * ```js * I.mutateData('createUser', { name: 'davert', email: 'davert@mail.com' }); * let user = await I.mutateData('createUser', { name: 'davert'}); * I.mutateMultiple('createPost', 3, {post_id: user.id}); * ``` * * To make this work you need * * 1. GraphQL endpoint which allows to perform create / delete requests and * 2. define data generation rules * * ### Setup * * Install [Rosie](https://github.com/rosiejs/rosie) and [Faker](https://www.npmjs.com/package/faker) libraries. * * ```sh * npm i rosie @faker-js/faker --save-dev * ``` * * Create a factory file for a resource. * * See the example for Users factories: * * ```js * // tests/factories/users.js * * const Factory = require('rosie').Factory; * const faker = require('@faker-js/faker'); * * // Used with a constructor function passed to Factory, so that the final build * // object matches the necessary pattern to be sent as the variables object. * module.exports = new Factory((buildObj) => ({ * input: { ...buildObj }, * })) * // 'attr'-id can be left out depending on the GraphQl resolvers * .attr('name', () => faker.name.findName()) * .attr('email', () => faker.interact.email()) * ``` * For more options see [rosie documentation](https://github.com/rosiejs/rosie). * * Then configure GraphQLDataHelper to match factories and GraphQL schema: * ### Configuration * * GraphQLDataFactory has following config options: * * * `endpoint`: URL for the GraphQL server. * * `cleanup` (default: true): should inserted records be deleted up after tests * * `factories`: list of defined factories * * `headers`: list of headers * * `GraphQL`: configuration for GraphQL requests. * * * See the example: * * ```js * GraphQLDataFactory: { * endpoint: "http://user.com/graphql", * cleanup: true, * headers: { * 'Content-Type': 'application/json', * 'Accept': 'application/json', * }, * factories: { * createUser: { * query: 'mutation createUser($input: UserInput!) { createUser(input: $input) { id name }}', * factory: './factories/users', * revert: (data) => ({ * query: 'mutation deleteUser($id: ID!) { deleteUser(id: $id) }', * variables: { id : data.id}, * }), * }, * } * } * ``` * It is required to set GraphQL `endpoint` which is the URL to which all the queries go to. * Factory file is expected to be passed via `factory` option. * * This Helper uses [GraphQL](http://codecept.io/helpers/GraphQL/) helper and accepts its configuration in "GraphQL" section. * For instance, to set timeout you should add: * * ```js * "GraphQLDataFactory": { * "GraphQL": { * "timeout": "100000", * } * } * ``` * * ### Factory * * Factory contains operations - * * * `operation`: The operation/mutation that needs to be performed for creating a record in the backend. * * Each operation must have the following: * * * `query`: The mutation(query) string. It is expected to use variables to send data with the query. * * `factory`: The path to factory file. The object built by the factory in this file will be passed * as the 'variables' object to go along with the mutation. * * `revert`: A function called with the data returned when an item is created. The object returned by * this function is will be used to later delete the items created. So, make sure RELEVANT DATA IS RETURNED * when a record is created by a mutation. * * ### Requests * * Requests can be updated on the fly by using `onRequest` function. For instance, you can pass in current session from a cookie. * * ```js * onRequest: async (request) => { * // using global codeceptjs instance * let cookie = await codeceptjs.container.helpers('WebDriver').grabCookie('session'); * request.headers = { Cookie: `session=${cookie.value}` }; * } * ``` * * ### Responses * * By default `I.mutateData()` returns a promise with created data as specified in operation query string: * * ```js * let client = await I.mutateData('createClient'); * ``` * * Data of created records are collected and used in the end of a test for the cleanup. * * ## Methods */ class GraphQLDataFactory { /** * Generates a new record using factory, sends a GraphQL mutation to store it. * * ```js * // create a user * I.mutateData('createUser'); * // create user with defined email * // and receive it when inside async function * const user = await I.mutateData('createUser', { email: 'user@user.com'}); * ``` * @param operation - to be performed * @param params - predefined parameters */ mutateData(operation: string, params: any): void; /** * Generates bunch of records and sends multiple GraphQL mutation requests to store them. * * ```js * // create 3 users * I.mutateMultiple('createUser', 3); * * // create 3 users of same age * I.mutateMultiple('createUser', 3, { age: 25 }); * ``` */ mutateMultiple(operation: string, times: number, params: any): void; /** * Executes request to create a record to the GraphQL endpoint. * Can be replaced from a custom helper. * @param variables - to be sent along with the query */ _requestCreate(operation: string, variables: any): void; /** * Executes request to delete a record to the GraphQL endpoint. * Can be replaced from a custom helper. * @param data - of the record to be deleted. */ _requestDelete(operation: string, data: any): void; } /** * This helper allows performing assertions on JSON responses paired with following helpers: * * * REST * * GraphQL * * Playwright * * It can check status codes, response data, response structure. * * * ## Configuration * * * `requestHelper` - a helper which will perform requests. `REST` by default, also `Playwright` or `GraphQL` can be used. Custom helpers must have `onResponse` hook in their config, which will be executed when request is performed. * * ### Examples * * Zero-configuration when paired with REST: * * ```js * // inside codecept.conf.js * { * helpers: { * REST: { * endpoint: 'http://site.com/api', * }, * JSONResponse: {} * } * } * ``` * Explicitly setting request helper if you use `makeApiRequest` of Playwright to perform requests and not paired REST: * * ```js * // inside codecept.conf.js * // ... * helpers: { * Playwright: { * url: 'https://localhost', * browser: 'chromium', * }, * JSONResponse: { * requestHelper: 'Playwright', * } * } * ``` * ## Access From Helpers * * If you plan to add custom assertions it is recommended to create a helper that will retrieve response object from JSONResponse: * * * ```js * // inside custom helper * const response = this.helpers.JSONResponse.response; * ``` * * ## Methods */ class JSONResponse { /** * Checks that response code is equal to the provided one * * ```js * I.seeResponseCodeIs(200); * ``` */ seeResponseCodeIs(code: number): void; /** * Checks that response code is not equal to the provided one * * ```js * I.dontSeeResponseCodeIs(500); * ``` */ dontSeeResponseCodeIs(code: number): void; /** * Checks that the response code is 4xx */ seeResponseCodeIsClientError(): void; /** * Checks that the response code is 3xx */ seeResponseCodeIsRedirection(): void; /** * Checks that the response code is 5xx */ seeResponseCodeIsServerError(): void; /** * Checks that the response code is 2xx * Use it instead of seeResponseCodeIs(200) if server can return 204 instead. * * ```js * I.seeResponseCodeIsSuccessful(); * ``` */ seeResponseCodeIsSuccessful(): void; /** * Checks for deep inclusion of a provided json in a response data. * * ```js * // response.data == { user: { name: 'jon', email: 'jon@doe.com' } } * * I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } }); * ``` * If an array is received, checks that at least one element contains JSON * ```js * // response.data == [{ user: { name: 'jon', email: 'jon@doe.com' } }] * * I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } }); * ``` */ seeResponseContainsJson(json: any): void; /** * Checks for deep inclusion of a provided json in a response data. * * ```js * // response.data == { data: { user: 1 } } * * I.dontSeeResponseContainsJson({ user: 2 }); * ``` * If an array is received, checks that no element of array contains json: * ```js * // response.data == [{ user: 1 }, { user: 3 }] * * I.dontSeeResponseContainsJson({ user: 2 }); * ``` */ dontSeeResponseContainsJson(json: any): void; /** * Checks for deep inclusion of a provided json in a response data. * * ```js * // response.data == { user: { name: 'jon', email: 'jon@doe.com' } } * * I.seeResponseContainsKeys(['user']); * ``` * * If an array is received, check is performed for each element of array: * * ```js * // response.data == [{ user: 'jon' }, { user: 'matt'}] * * I.seeResponseContainsKeys(['user']); * ``` */ seeResponseContainsKeys(keys: any[]): void; /** * Executes a callback function passing in `response` object and chai assertions with `expect` * Use it to perform custom checks of response data * * ```js * I.seeResponseValidByCallback(({ data, status, expect }) => { * expect(status).to.eql(200); * expect(data).keys.to.include(['user', 'company']); * }); * ``` */ seeResponseValidByCallback(fn: (...params: any[]) => any): void; /** * Checks that response data equals to expected: * * ```js * // response.data is { error: 'Not allowed' } * * I.seeResponseEquals({ error: 'Not allowed' }) * ``` */ seeResponseEquals(resp: any): void; /** * Validates JSON structure of response using [joi library](https://joi.dev). * See [joi API](https://joi.dev/api/) for complete reference on usage. * * Use pre-initialized joi instance by passing function callback: * * ```js * // response.data is { name: 'jon', id: 1 } * * I.seeResponseMatchesJsonSchema(joi => { * return joi.object({ * name: joi.string(); * id: joi.number(); * }) * }); * * // or pass a valid schema * const joi = require('joi); * * I.seeResponseMatchesJsonSchema(joi.object({ * name: joi.string(); * id: joi.number(); * }); * ``` */ seeResponseMatchesJsonSchema(fnOrSchema: any): void; } /** * Nightmare helper wraps [Nightmare](https://github.com/segmentio/nightmare) library to provide * fastest headless testing using Electron engine. Unlike Selenium-based drivers this uses * Chromium-based browser with Electron with lots of client side scripts, thus should be less stable and * less trusted. * * Requires `nightmare` package to be installed. * * ## Configuration * * This helper should be configured in codecept.conf.ts or codecept.conf.js * * * `url` - base url of website to be tested * * `restart` (optional, default: true) - restart browser between tests. * * `disableScreenshots` (optional, default: false) - don't save screenshot on failure. * * `uniqueScreenshotNames` (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites. * * `fullPageScreenshots` (optional, default: false) - make full page screenshots on failure. * * `keepBrowserState` (optional, default: false) - keep browser state between tests when `restart` set to false. * * `keepCookies` (optional, default: false) - keep cookies between tests when `restart` set to false. * * `waitForAction`: (optional) how long to wait after click, doubleClick or PressKey actions in ms. Default: 500. * * `waitForTimeout`: (optional) default wait* timeout in ms. Default: 1000. * * `windowSize`: (optional) default window size. Set a dimension like `640x480`. * * + options from [Nightmare configuration](https://github.com/segmentio/nightmare#api) * * ## Methods */ class Nightmare { /** * Get HAR * * ```js * let har = await I.grabHAR(); * fs.writeFileSync('sample.har', JSON.stringify({log: har})); * ``` */ grabHAR(): void; /** * Locate elements by different locator types, including strict locator. * Should be used in custom helpers. * * This method return promise with array of IDs of found elements. * Actual elements can be accessed inside `evaluate` by using `codeceptjs.fetchElement()` * client-side function: * * ```js * // get an inner text of an element * * let browser = this.helpers['Nightmare'].browser; * let value = this.helpers['Nightmare']._locate({name: 'password'}).then(function(els) { * return browser.evaluate(function(el) { * return codeceptjs.fetchElement(el).value; * }, els[0]); * }); * ``` */ _locate(): void; /** * Add a header override for all HTTP requests. If header is undefined, the header overrides will be reset. * * ```js * I.haveHeader('x-my-custom-header', 'some value'); * I.haveHeader(); // clear headers * ``` */ haveHeader(): void; /** * Opens a web page in a browser. Requires relative or absolute url. * If url starts with `/`, opens a web page of a site defined in `url` config parameter. * * ```js * I.amOnPage('/'); // opens main page of website * I.amOnPage('https://github.com'); // opens github * I.amOnPage('/login'); // opens a login page * ``` * @param url - url path or global url. * @param headers - list of request headers can be passed * @returns automatically synchronized promise with recorder #! */ amOnPage(url: string, headers: any): void; /** * Checks that title contains text. * * ```js * I.seeInTitle('Home Page'); * ``` * @param text - text value to check. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeInTitle(text: string): void; /** * Checks that title does not contain text. * * ```js * I.dontSeeInTitle('Error'); * ``` * @param text - value to check. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSeeInTitle(text: string): void; /** * Retrieves a page title and returns it to test. * Resumes test execution, so **should be used inside async with `await`** operator. * * ```js * let title = await I.grabTitle(); * ``` * @returns title */ grabTitle(): Promise; /** * Get current URL from browser. * Resumes test execution, so should be used inside an async function. * * ```js * let url = await I.grabCurrentUrl(); * console.log(`Current URL is [${url}]`); * ``` * @returns current URL */ grabCurrentUrl(): Promise; /** * Checks that current url contains a provided fragment. * * ```js * I.seeInCurrentUrl('/register'); // we are on registration page * ``` * @param url - a fragment to check * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeInCurrentUrl(url: string): void; /** * Checks that current url does not contain a provided fragment. * @param url - value to check. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSeeInCurrentUrl(url: string): void; /** * Checks that current url is equal to provided one. * If a relative url provided, a configured url will be prepended to it. * So both examples will work: * * ```js * I.seeCurrentUrlEquals('/register'); * I.seeCurrentUrlEquals('http://my.site.com/register'); * ``` * @param url - value to check. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeCurrentUrlEquals(url: string): void; /** * Checks that current url is not equal to provided one. * If a relative url provided, a configured url will be prepended to it. * * ```js * I.dontSeeCurrentUrlEquals('/login'); // relative url are ok * I.dontSeeCurrentUrlEquals('http://mysite.com/login'); // absolute urls are also ok * ``` * @param url - value to check. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSeeCurrentUrlEquals(url: string): void; /** * Checks that a page contains a visible text. * Use context parameter to narrow down the search. * * ```js * I.see('Welcome'); // text welcome on a page * I.see('Welcome', '.content'); // text inside .content div * I.see('Register', {css: 'form.register'}); // use strict locator * ``` * @param text - expected on page. * @param [context = null] - (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ see(text: string, context?: CodeceptJS.LocatorOrString): void; /** * Opposite to `see`. Checks that a text is not present on a page. * Use context parameter to narrow down the search. * * ```js * I.dontSee('Login'); // assume we are already logged in. * I.dontSee('Login', '.nav'); // no login inside .nav element * ``` * @param text - which is not present. * @param [context = null] - (optional) element located by CSS|XPath|strict locator in which to perfrom search. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSee(text: string, context?: CodeceptJS.LocatorOrString): void; /** * Checks that a given Element is visible * Element is located by CSS or XPath. * * ```js * I.seeElement('#modal'); * ``` * @param locator - located by CSS|XPath|strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeElement(locator: CodeceptJS.LocatorOrString): void; /** * Opposite to `seeElement`. Checks that element is not visible (or in DOM) * * ```js * I.dontSeeElement('.modal'); // modal is not shown * ``` * @param locator - located by CSS|XPath|Strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSeeElement(locator: CodeceptJS.LocatorOrString): void; /** * Checks that a given Element is present in the DOM * Element is located by CSS or XPath. * * ```js * I.seeElementInDOM('#modal'); * ``` * @param locator - element located by CSS|XPath|strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeElementInDOM(locator: CodeceptJS.LocatorOrString): void; /** * Opposite to `seeElementInDOM`. Checks that element is not on page. * * ```js * I.dontSeeElementInDOM('.nav'); // checks that element is not on page visible or not * ``` * @param locator - located by CSS|XPath|Strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSeeElementInDOM(locator: CodeceptJS.LocatorOrString): void; /** * Checks that the current page contains the given string in its raw source code. * * ```js * I.seeInSource('

Green eggs & ham

'); * ``` * @param text - value to check. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeInSource(text: string): void; /** * Checks that the current page does not contains the given string in its raw source code. * * ```js * I.dontSeeInSource(' * * #### Video Recording Customization * * By default, video is saved to `output/video` dir. You can customize this path by passing `dir` option to `recordVideo` option. * * `video`: enables video recording for failed tests; videos are saved into `output/videos` folder * * `keepVideoForPassedTests`: - save videos for passed tests * * `recordVideo`: [additional options for videos customization](https://playwright.dev/docs/next/api/class-browser#browser-new-context) * * #### Trace Recording Customization * * Trace recording provides a complete information on test execution and includes DOM snapshots, screenshots, and network requests logged during run. * Traces will be saved to `output/trace` * * * `trace`: enables trace recording for failed tests; trace are saved into `output/trace` folder * * `keepTraceForPassedTests`: - save trace for passed tests * * #### Example #1: Wait for 0 network connections. * * ```js * { * helpers: { * Playwright : { * url: "http://localhost", * restart: false, * waitForNavigation: "networkidle0", * waitForAction: 500 * } * } * } * ``` * * #### Example #2: Wait for DOMContentLoaded event * * ```js * { * helpers: { * Playwright : { * url: "http://localhost", * restart: false, * waitForNavigation: "domcontentloaded", * waitForAction: 500 * } * } * } * ``` * * #### Example #3: Debug in window mode * * ```js * { * helpers: { * Playwright : { * url: "http://localhost", * show: true * } * } * } * ``` * * #### Example #4: Connect to remote browser by specifying [websocket endpoint](https://playwright.dev/docs/api/class-browsertype#browsertypeconnectparams) * * ```js * { * helpers: { * Playwright: { * url: "http://localhost", * chromium: { * browserWSEndpoint: 'ws://localhost:9222/devtools/browser/c5aa6160-b5bc-4d53-bb49-6ecb36cd2e0a', * cdpConnection: false // default is false * } * } * } * } * ``` * * #### Example #5: Testing with Chromium extensions * * [official docs](https://github.com/microsoft/playwright/blob/v0.11.0/docs/api.md#working-with-chrome-extensions) * * ```js * { * helpers: { * Playwright: { * url: "http://localhost", * show: true // headless mode not supported for extensions * chromium: { * userDataDir: '/tmp/playwright-tmp', // necessary to launch the browser in normal mode instead of incognito, * args: [ * `--disable-extensions-except=${pathToExtension}`, * `--load-extension=${pathToExtension}` * ] * } * } * } * } * ``` * * #### Example #6: Launch tests emulating iPhone 6 * * * * ```js * const { devices } = require('playwright'); * * { * helpers: { * Playwright: { * url: "http://localhost", * emulate: devices['iPhone 6'], * } * } * } * ``` * * #### Example #7: Launch test with a specific user locale * * ```js * { * helpers: { * Playwright : { * url: "http://localhost", * locale: "fr-FR", * } * } * } * ``` * * * #### Example #8: Launch test with a specific color scheme * * ```js * { * helpers: { * Playwright : { * url: "http://localhost", * colorScheme: "dark", * } * } * } * ``` * * Note: When connecting to remote browser `show` and specific `chrome` options (e.g. `headless` or `devtools`) are ignored. * * ## Access From Helpers * * Receive Playwright client from a custom helper by accessing `browser` for the Browser object or `page` for the current Page object: * * ```js * const { browser } = this.helpers.Playwright; * await browser.pages(); // List of pages in the browser * * // get current page * const { page } = this.helpers.Playwright; * await page.url(); // Get the url of the current page * * const { browserContext } = this.helpers.Playwright; * await browserContext.cookies(); // get current browser context * ``` */ class Playwright { /** * Use Playwright API inside a test. * * First argument is a description of an action. * Second argument is async function that gets this helper as parameter. * * { [`page`](https://github.com/microsoft/playwright/blob/main/docs/src/api/class-page.md), [`browserContext`](https://github.com/microsoft/playwright/blob/main/docs/src/api/class-browsercontext.md) [`browser`](https://github.com/microsoft/playwright/blob/main/docs/src/api/class-browser.md) } objects from Playwright API are available. * * ```js * I.usePlaywrightTo('emulate offline mode', async ({ browserContext }) => { * await browserContext.setOffline(true); * }); * ``` * @param description - used to show in logs. * @param fn - async function that executed with Playwright helper as argumen */ usePlaywrightTo(description: string, fn: (...params: any[]) => any): void; /** * Set the automatic popup response to Accept. * This must be set before a popup is triggered. * * ```js * I.amAcceptingPopups(); * I.click('#triggerPopup'); * I.acceptPopup(); * ``` */ amAcceptingPopups(): void; /** * Accepts the active JavaScript native popup window, as created by window.alert|window.confirm|window.prompt. * Don't confuse popups with modal windows, as created by [various * libraries](http://jster.net/category/windows-modals-popups). */ acceptPopup(): void; /** * Set the automatic popup response to Cancel/Dismiss. * This must be set before a popup is triggered. * * ```js * I.amCancellingPopups(); * I.click('#triggerPopup'); * I.cancelPopup(); * ``` */ amCancellingPopups(): void; /** * Dismisses the active JavaScript popup, as created by window.alert|window.confirm|window.prompt. */ cancelPopup(): void; /** * Checks that the active JavaScript popup, as created by `window.alert|window.confirm|window.prompt`, contains the * given string. * * ```js * I.seeInPopup('Popup text'); * ``` * @param text - value to check. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeInPopup(text: string): void; /** * Set current page * @param page - page to set */ _setPage(page: any): void; /** * Add the 'dialog' event listener to a page */ _addPopupListener(): void; /** * Gets page URL including hash. */ _getPageUrl(): void; /** * Grab the text within the popup. If no popup is visible then it will return null * * ```js * await I.grabPopupText(); * ``` */ grabPopupText(): Promise; /** * Create a new browser context with a page. \ * Usually it should be run from a custom helper after call of `_startBrowser()` * @param [contextOptions] - See https://playwright.dev/docs/api/class-browser#browser-new-context */ _createContextPage(contextOptions?: any): void; /** * Opens a web page in a browser. Requires relative or absolute url. * If url starts with `/`, opens a web page of a site defined in `url` config parameter. * * ```js * I.amOnPage('/'); // opens main page of website * I.amOnPage('https://github.com'); // opens github * I.amOnPage('/login'); // opens a login page * ``` * @param url - url path or global url. * @returns automatically synchronized promise with recorder #! */ amOnPage(url: string): void; /** * Resize the current window to provided width and height. * First parameter can be set to `maximize`. * @param width - width in pixels or `maximize`. * @param height - height in pixels. * ⚠️ returns a _promise_ which is synchronized internally by recorder * * * Unlike other drivers Playwright changes the size of a viewport, not the window! * Playwright does not control the window of a browser so it can't adjust its real size. * It also can't maximize a window. * * Update configuration to change real window size on start: * * ```js * // inside codecept.conf.js * // @codeceptjs/configure package must be installed * { setWindowSize } = require('@codeceptjs/configure'); * ```` */ resizeWindow(width: number, height: number): void; /** * Set headers for all next requests * * ```js * I.haveRequestHeaders({ * 'X-Sent-By': 'CodeceptJS', * }); * ``` * @param customHeaders - headers to set */ haveRequestHeaders(customHeaders: any): void; /** * Moves cursor to element matched by locator. * Extra shift can be set with offsetX and offsetY options. * * ```js * I.moveCursorTo('.tooltip'); * I.moveCursorTo('#submit', 5,5); * ``` * @param locator - located by CSS|XPath|strict locator. * @param [offsetX = 0] - (optional, `0` by default) X-axis offset. * @param [offsetY = 0] - (optional, `0` by default) Y-axis offset. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ moveCursorTo(locator: CodeceptJS.LocatorOrString, offsetX?: number, offsetY?: number): void; /** * Drag an item to a destination element. * * ```js * I.dragAndDrop('#dragHandle', '#container'); * ``` * @param srcElement - located by CSS|XPath|strict locator. * @param destElement - located by CSS|XPath|strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder * @param [options] - [Additional options](https://playwright.dev/docs/api/class-page#page-drag-and-drop) can be passed as 3rd argument. * * ```js * // specify coordinates for source position * I.dragAndDrop('img.src', 'img.dst', { sourcePosition: {x: 10, y: 10} }) * ``` * * > By default option `force: true` is set */ dragAndDrop(srcElement: LocatorOrString, destElement: LocatorOrString, options?: any): void; /** * Restart browser with a new context and a new page * * ```js * // Restart browser and use a new timezone * I.restartBrowser({ timezoneId: 'America/Phoenix' }); * // Open URL in a new page in changed timezone * I.amOnPage('/'); * // Restart browser, allow reading/copying of text from/into clipboard in Chrome * I.restartBrowser({ permissions: ['clipboard-read', 'clipboard-write'] }); * ``` * @param [contextOptions] - [Options for browser context](https://playwright.dev/docs/api/class-browser#browser-new-context) when starting new browser */ restartBrowser(contextOptions?: any): void; /** * Reload the current page. * * ```js * I.refreshPage(); * ``` * ⚠️ returns a _promise_ which is synchronized internally by recorder */ refreshPage(): void; /** * Scroll page to the top. * * ```js * I.scrollPageToTop(); * ``` * ⚠️ returns a _promise_ which is synchronized internally by recorder */ scrollPageToTop(): void; /** * Scroll page to the bottom. * * ```js * I.scrollPageToBottom(); * ``` * ⚠️ returns a _promise_ which is synchronized internally by recorder */ scrollPageToBottom(): void; /** * Scrolls to element matched by locator. * Extra shift can be set with offsetX and offsetY options. * * ```js * I.scrollTo('footer'); * I.scrollTo('#submit', 5, 5); * ``` * @param locator - located by CSS|XPath|strict locator. * @param [offsetX = 0] - (optional, `0` by default) X-axis offset. * @param [offsetY = 0] - (optional, `0` by default) Y-axis offset. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ scrollTo(locator: CodeceptJS.LocatorOrString, offsetX?: number, offsetY?: number): void; /** * Checks that title contains text. * * ```js * I.seeInTitle('Home Page'); * ``` * @param text - text value to check. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeInTitle(text: string): void; /** * Retrieves a page scroll position and returns it to test. * Resumes test execution, so **should be used inside an async function with `await`** operator. * * ```js * let { x, y } = await I.grabPageScrollPosition(); * ``` * @returns scroll position */ grabPageScrollPosition(): Promise; /** * Checks that title is equal to provided one. * * ```js * I.seeTitleEquals('Test title.'); * ``` * @param text - value to check. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeTitleEquals(text: string): void; /** * Checks that title does not contain text. * * ```js * I.dontSeeInTitle('Error'); * ``` * @param text - value to check. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSeeInTitle(text: string): void; /** * Retrieves a page title and returns it to test. * Resumes test execution, so **should be used inside async with `await`** operator. * * ```js * let title = await I.grabTitle(); * ``` * @returns title */ grabTitle(): Promise; /** * Get elements by different locator types, including strict locator * Should be used in custom helpers: * * ```js * const elements = await this.helpers['Playwright']._locate({name: 'password'}); * ``` */ _locate(): void; /** * Find a checkbox by providing human readable text: * NOTE: Assumes the checkable element exists * * ```js * this.helpers['Playwright']._locateCheckable('I agree with terms and conditions').then // ... * ``` */ _locateCheckable(): void; /** * Find a clickable element by providing human readable text: * * ```js * this.helpers['Playwright']._locateClickable('Next page').then // ... * ``` */ _locateClickable(): void; /** * Find field elements by providing human readable text: * * ```js * this.helpers['Playwright']._locateFields('Your email').then // ... * ``` */ _locateFields(): void; /** * Switch focus to a particular tab by its number. It waits tabs loading and then switch tab * * ```js * I.switchToNextTab(); * I.switchToNextTab(2); * ``` */ switchToNextTab(num?: number): void; /** * Switch focus to a particular tab by its number. It waits tabs loading and then switch tab * * ```js * I.switchToPreviousTab(); * I.switchToPreviousTab(2); * ``` */ switchToPreviousTab(num?: number): void; /** * Close current tab and switches to previous. * * ```js * I.closeCurrentTab(); * ``` */ closeCurrentTab(): void; /** * Close all tabs except for the current one. * * ```js * I.closeOtherTabs(); * ``` */ closeOtherTabs(): void; /** * Open new tab and automatically switched to new tab * * ```js * I.openNewTab(); * ``` * * You can pass in [page options](https://github.com/microsoft/playwright/blob/main/docs/api.md#browsernewpageoptions) to emulate device on this page * * ```js * // enable mobile * I.openNewTab({ isMobile: true }); * ``` */ openNewTab(): void; /** * Grab number of open tabs. * Resumes test execution, so **should be used inside async function with `await`** operator. * * ```js * let tabs = await I.grabNumberOfOpenTabs(); * ``` * @returns number of open tabs */ grabNumberOfOpenTabs(): Promise; /** * Checks that a given Element is visible * Element is located by CSS or XPath. * * ```js * I.seeElement('#modal'); * ``` * @param locator - located by CSS|XPath|strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeElement(locator: CodeceptJS.LocatorOrString): void; /** * Opposite to `seeElement`. Checks that element is not visible (or in DOM) * * ```js * I.dontSeeElement('.modal'); // modal is not shown * ``` * @param locator - located by CSS|XPath|Strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSeeElement(locator: CodeceptJS.LocatorOrString): void; /** * Checks that a given Element is present in the DOM * Element is located by CSS or XPath. * * ```js * I.seeElementInDOM('#modal'); * ``` * @param locator - element located by CSS|XPath|strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeElementInDOM(locator: CodeceptJS.LocatorOrString): void; /** * Opposite to `seeElementInDOM`. Checks that element is not on page. * * ```js * I.dontSeeElementInDOM('.nav'); // checks that element is not on page visible or not * ``` * @param locator - located by CSS|XPath|Strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSeeElementInDOM(locator: CodeceptJS.LocatorOrString): void; /** * Handles a file download. A file name is required to save the file on disk. * Files are saved to "output" directory. * * Should be used with [FileSystem helper](https://codecept.io/helpers/FileSystem) to check that file were downloaded correctly. * * ```js * I.handleDownloads('downloads/avatar.jpg'); * I.click('Download Avatar'); * I.amInPath('output/downloads'); * I.waitForFile('avatar.jpg', 5); * * ``` * @param [fileName] - set filename for downloaded file */ handleDownloads(fileName?: string): Promise; /** * Perform a click on a link or a button, given by a locator. * If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string. * For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched. * For images, the "alt" attribute and inner text of any parent links are searched. * * The second parameter is a context (CSS or XPath locator) to narrow the search. * * ```js * // simple link * I.click('Logout'); * // button of form * I.click('Submit'); * // CSS button * I.click('#form input[type=submit]'); * // XPath * I.click('//form/*[@type=submit]'); * // link in context * I.click('Logout', '#nav'); * // using strict locator * I.click({css: 'nav a.login'}); * ``` * @param locator - clickable link or button located by text, or any element located by CSS|XPath|strict locator. * @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder * @param [opts] - [Additional options](https://playwright.dev/docs/api/class-page#page-click) for click available as 3rd argument. * * Examples: * * ```js * // click on element at position * I.click('canvas', '.model', { position: { x: 20, y: 40 } }) * * // make ctrl-click * I.click('.edit', null, { modifiers: ['Ctrl'] } ) * ``` */ click(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString | null, opts?: any): void; /** * Clicks link and waits for navigation (deprecated) */ clickLink(): void; /** * Perform an emulated click on a link or a button, given by a locator. * Unlike normal click instead of sending native event, emulates a click with JavaScript. * This works on hidden, animated or inactive elements as well. * * If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string. * For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched. * For images, the "alt" attribute and inner text of any parent links are searched. * * The second parameter is a context (CSS or XPath locator) to narrow the search. * * ```js * // simple link * I.forceClick('Logout'); * // button of form * I.forceClick('Submit'); * // CSS button * I.forceClick('#form input[type=submit]'); * // XPath * I.forceClick('//form/*[@type=submit]'); * // link in context * I.forceClick('Logout', '#nav'); * // using strict locator * I.forceClick({css: 'nav a.login'}); * ``` * @param locator - clickable link or button located by text, or any element located by CSS|XPath|strict locator. * @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ forceClick(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void; /** * Performs a double-click on an element matched by link|button|label|CSS or XPath. * Context can be specified as second parameter to narrow search. * * ```js * I.doubleClick('Edit'); * I.doubleClick('Edit', '.actions'); * I.doubleClick({css: 'button.accept'}); * I.doubleClick('.btn.edit'); * ``` * @param locator - clickable link or button located by text, or any element located by CSS|XPath|strict locator. * @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ doubleClick(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void; /** * Performs right click on a clickable element matched by semantic locator, CSS or XPath. * * ```js * // right click element with id el * I.rightClick('#el'); * // right click link or button with text "Click me" * I.rightClick('Click me'); * // right click button with text "Click me" inside .context * I.rightClick('Click me', '.context'); * ``` * @param locator - clickable element located by CSS|XPath|strict locator. * @param [context = null] - (optional, `null` by default) element located by CSS|XPath|strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ rightClick(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void; /** * Selects a checkbox or radio button. * Element is located by label or name or CSS or XPath. * * The second parameter is a context (CSS or XPath locator) to narrow the search. * * ```js * I.checkOption('#agree'); * I.checkOption('I Agree to Terms and Conditions'); * I.checkOption('agree', '//form'); * ``` * @param field - checkbox located by label | name | CSS | XPath | strict locator. * @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder * * * [Additional options](https://playwright.dev/docs/api/class-elementhandle#element-handle-check) for check available as 3rd argument. * * Examples: * * ```js * // click on element at position * I.checkOption('Agree', '.signup', { position: { x: 5, y: 5 } }) * ``` * > ⚠️ To avoid flakiness, option `force: true` is set by default */ checkOption(field: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void; /** * Unselects a checkbox or radio button. * Element is located by label or name or CSS or XPath. * * The second parameter is a context (CSS or XPath locator) to narrow the search. * * ```js * I.uncheckOption('#agree'); * I.uncheckOption('I Agree to Terms and Conditions'); * I.uncheckOption('agree', '//form'); * ``` * @param field - checkbox located by label | name | CSS | XPath | strict locator. * @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder * * * [Additional options](https://playwright.dev/docs/api/class-elementhandle#element-handle-uncheck) for uncheck available as 3rd argument. * * Examples: * * ```js * // click on element at position * I.uncheckOption('Agree', '.signup', { position: { x: 5, y: 5 } }) * ``` * > ⚠️ To avoid flakiness, option `force: true` is set by default */ uncheckOption(field: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void; /** * Verifies that the specified checkbox is checked. * * ```js * I.seeCheckboxIsChecked('Agree'); * I.seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms * I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'}); * ``` * @param field - located by label|name|CSS|XPath|strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ seeCheckboxIsChecked(field: CodeceptJS.LocatorOrString): void; /** * Verifies that the specified checkbox is not checked. * * ```js * I.dontSeeCheckboxIsChecked('#agree'); // located by ID * I.dontSeeCheckboxIsChecked('I agree to terms'); // located by label * I.dontSeeCheckboxIsChecked('agree'); // located by name * ``` * @param field - located by label|name|CSS|XPath|strict locator. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ dontSeeCheckboxIsChecked(field: CodeceptJS.LocatorOrString): void; /** * Presses a key in the browser and leaves it in a down state. * * To make combinations with modifier key and user operation (e.g. `'Control'` + [`click`](#click)). * * ```js * I.pressKeyDown('Control'); * I.click('#element'); * I.pressKeyUp('Control'); * ``` * @param key - name of key to press down. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ pressKeyDown(key: string): void; /** * Releases a key in the browser which was previously set to a down state. * * To make combinations with modifier key and user operation (e.g. `'Control'` + [`click`](#click)). * * ```js * I.pressKeyDown('Control'); * I.click('#element'); * I.pressKeyUp('Control'); * ``` * @param key - name of key to release. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ pressKeyUp(key: string): void; /** * Presses a key in the browser (on a focused element). * * _Hint:_ For populating text field or textarea, it is recommended to use [`fillField`](#fillfield). * * ```js * I.pressKey('Backspace'); * ``` * * To press a key in combination with modifier keys, pass the sequence as an array. All modifier keys (`'Alt'`, `'Control'`, `'Meta'`, `'Shift'`) will be released afterwards. * * ```js * I.pressKey(['Control', 'Z']); * ``` * * For specifying operation modifier key based on operating system it is suggested to use `'CommandOrControl'`. * This will press `'Command'` (also known as `'Meta'`) on macOS machines and `'Control'` on non-macOS machines. * * ```js * I.pressKey(['CommandOrControl', 'Z']); * ``` * * Some of the supported key names are: * - `'AltLeft'` or `'Alt'` * - `'AltRight'` * - `'ArrowDown'` * - `'ArrowLeft'` * - `'ArrowRight'` * - `'ArrowUp'` * - `'Backspace'` * - `'Clear'` * - `'ControlLeft'` or `'Control'` * - `'ControlRight'` * - `'Command'` * - `'CommandOrControl'` * - `'Delete'` * - `'End'` * - `'Enter'` * - `'Escape'` * - `'F1'` to `'F12'` * - `'Home'` * - `'Insert'` * - `'MetaLeft'` or `'Meta'` * - `'MetaRight'` * - `'Numpad0'` to `'Numpad9'` * - `'NumpadAdd'` * - `'NumpadDecimal'` * - `'NumpadDivide'` * - `'NumpadMultiply'` * - `'NumpadSubtract'` * - `'PageDown'` * - `'PageUp'` * - `'Pause'` * - `'Return'` * - `'ShiftLeft'` or `'Shift'` * - `'ShiftRight'` * - `'Space'` * - `'Tab'` * @param key - key or array of keys to press. * ⚠️ returns a _promise_ which is synchronized internally by recorder * * * _Note:_ Shortcuts like `'Meta'` + `'A'` do not work on macOS ([GoogleChrome/Puppeteer#1313](https://github.com/GoogleChrome/puppeteer/issues/1313)). */ pressKey(key: string | string[]): void; /** * Types out the given text into an active field. * To slow down typing use a second parameter, to set interval between key presses. * _Note:_ Should be used when [`fillField`](#fillfield) is not an option. * * ```js * // passing in a string * I.type('Type this out.'); * * // typing values with a 100ms interval * I.type('4141555311111111', 100); * * // passing in an array * I.type(['T', 'E', 'X', 'T']); * ``` * @param key - or array of keys to type. * @param [delay = null] - (optional) delay in ms between key presses * ⚠️ returns a _promise_ which is synchronized internally by recorder */ type(key: string | string[], delay?: number): void; /** * Fills a text field or textarea, after clearing its value, with the given string. * Field is located by name, label, CSS, or XPath. * * ```js * // by label * I.fillField('Email', 'hello@world.com'); * // by name * I.fillField('password', secret('123456')); * // by CSS * I.fillField('form#login input[name=username]', 'John'); * // or by strict locator * I.fillField({css: 'form#login input[name=username]'}, 'John'); * ``` * @param field - located by label|name|CSS|XPath|strict locator. * @param value - text value to fill. * ⚠️ returns a _promise_ which is synchronized internally by recorder */ fillField(field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret): void; /** * Clears a `