diff --git a/.gitignore b/.gitignore index 899a0b988..73d10f377 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,4 @@ testpullfilecache* .DS_Store package-lock.json yarn.lock -/.vs -typings/types.d.ts -typings/promiseBasedTypes.d.ts \ No newline at end of file +/.vs \ No newline at end of file diff --git a/lib/command/run-rerun.js b/lib/command/run-rerun.js index 62f17bdae..ccb18bcfd 100644 --- a/lib/command/run-rerun.js +++ b/lib/command/run-rerun.js @@ -17,10 +17,6 @@ module.exports = async function (test, options) { const testRoot = getTestRoot(configFile) createOutputDir(config, testRoot) - function processError(err) { - printError(err) - process.exit(1) - } const codecept = new Codecept(config, options) try { diff --git a/lib/rerun.js b/lib/rerun.js index b39b0b62e..df4549209 100644 --- a/lib/rerun.js +++ b/lib/rerun.js @@ -70,6 +70,7 @@ class CodeceptRerunner extends BaseCodecept { await this.runTests(test); } catch (e) { output.error(e.stack); + throw e; } finally { event.emit(event.all.result, this); event.emit(event.all.after, this); diff --git a/test/data/sandbox/configs/run-rerun/codecept.conf.pass_all_test.js b/test/data/sandbox/configs/run-rerun/codecept.conf.pass_all_test.js new file mode 100644 index 000000000..3c2ef30d8 --- /dev/null +++ b/test/data/sandbox/configs/run-rerun/codecept.conf.pass_all_test.js @@ -0,0 +1,16 @@ +exports.config = { + tests: './*_ftest.js', + output: './output', + helpers: { + CustomHelper: { + require: './customHelper.js', + }, + }, + rerun: { + minSuccess: 3, + maxReruns: 3, + }, + bootstrap: null, + mocha: {}, + name: 'run-rerun', +}; diff --git a/test/runner/run_rerun_test.js b/test/runner/run_rerun_test.js index 75511583a..a38ba54af 100644 --- a/test/runner/run_rerun_test.js +++ b/test/runner/run_rerun_test.js @@ -83,7 +83,7 @@ describe('run-rerun command', () => { ) }) - it('should display success run if test was fail one time of two attepmts and 3 reruns', (done) => { + it('should display success run if test was fail one time of two attempts and 3 reruns', (done) => { exec( `FAIL_ATTEMPT=0 ${codecept_run_config('codecept.conf.fail_test.js', '@RunRerun - fail second test')} --debug`, (err, stdout) => { @@ -96,4 +96,18 @@ describe('run-rerun command', () => { }, ) }) + + it('should throw exit code 1 if all tests were supposed to pass', (done) => { + exec( + `FAIL_ATTEMPT=0 ${codecept_run_config('codecept.conf.pass_all_test.js', '@RunRerun - fail second test')} --debug`, + (err, stdout) => { + expect(stdout).toContain('Process run 1 of max 3, success runs 1/3') + expect(stdout).toContain('Fail run 2 of max 3, success runs 1/3') + expect(stdout).toContain('Process run 3 of max 3, success runs 2/3') + expect(stdout).toContain('Flaky tests detected!') + expect(err.code).toBe(1) + done() + }, + ) + }) }) diff --git a/typings/promiseBasedTypes.d.ts b/typings/promiseBasedTypes.d.ts new file mode 100644 index 000000000..2ebdf2074 --- /dev/null +++ b/typings/promiseBasedTypes.d.ts @@ -0,0 +1,11448 @@ +declare namespace CodeceptJS { + /** + * AI Helper for CodeceptJS. + * + * This helper class provides integration with the AI GPT-3.5 or 4 language model for generating responses to questions or prompts within the context of web pages. It allows you to interact with the GPT-3.5 model to obtain intelligent responses based on HTML fragments or general prompts. + * This helper should be enabled with any web helpers like Playwright or Puppeteer or WebDriver to ensure the HTML context is available. + * + * Use it only in development mode. It is recommended to run it only inside pause() mode. + * + * ## Configuration + * + * This helper should be configured in codecept.conf.{js|ts} + * + * * `chunkSize`: (optional, default: 80000) - The maximum number of characters to send to the AI API at once. We split HTML fragments by 8000 chars to not exceed token limit. Increase this value if you use GPT-4. + */ + class AITs { + /** + * Asks the AI GPT language model a question based on the provided prompt within the context of the current page's HTML. + * + * ```js + * I.askGptOnPage('what does this page do?'); + * ``` + * @param prompt - The question or prompt to ask the GPT model. + * @returns - A Promise that resolves to the generated responses from the GPT model, joined by newlines. + */ + askGptOnPage(prompt: string): Promise; + /** + * Asks the AI a question based on the provided prompt within the context of a specific HTML fragment on the current page. + * + * ```js + * I.askGptOnPageFragment('describe features of this screen', '.screen'); + * ``` + * @param prompt - The question or prompt to ask the GPT-3.5 model. + * @param locator - The locator or selector used to identify the HTML fragment on the page. + * @returns - A Promise that resolves to the generated response from the GPT model. + */ + askGptOnPageFragment(prompt: string, locator: string): Promise; + /** + * Send a general request to AI and return response. + * @returns - A Promise that resolves to the generated response from the GPT model. + */ + askGptGeneralPrompt(prompt: string): Promise; + /** + * Generates PageObject for current page using AI. + * + * It saves the PageObject to the output directory. You can review the page object and adjust it as needed and move to pages directory. + * Prompt can be customized in a global config file. + * + * ```js + * // create page object for whole page + * I.askForPageObject('home'); + * + * // create page object with extra prompt + * I.askForPageObject('home', 'implement signIn(username, password) method'); + * + * // create page object for a specific element + * I.askForPageObject('home', null, '.detail'); + * ``` + * + * Asks for a page object based on the provided page name, locator, and extra prompt. + * @param pageName - The name of the page to retrieve the object for. + * @param [extraPrompt = null] - An optional extra prompt for additional context or information. + * @param [locator = null] - An optional locator to find a specific element on the page. + * @returns A promise that resolves to the requested page object. + */ + askForPageObject(pageName: string, extraPrompt?: string | null, locator?: string | null): Promise; + } + /** + * 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'); + * 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 ApiDataFactoryTs { + /** + * 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): Promise; + /** + * Executes request to create a record in API. + * Can be replaced from a in custom helper. + */ + _requestCreate(factory: any, data: any): Promise; + /** + * Executes request to delete a record in API + * Can be replaced from a custom helper. + */ + _requestDelete(factory: any, id: any): Promise; + } + /** + * Appium Special Methods for Mobile only + */ + class AppiumTs extends WebDriverTs { + /** + * 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): Promise; + /** + * 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): Promise; + /** + * 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): Promise; + /** + * Reset the currently running app for current session. + * + * ```js + * I.resetApp(); + * ``` + */ + resetApp(): Promise; + /** + * 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'): Promise; + /** + * 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): Promise; + /** + * 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](https://webdriver.io/docs/api/chromium/#setnetworkconnection). + * + * Appium: support only Android + * @param value - The network connection mode bitmask + */ + setNetworkConnection(value: number): Promise; + /** + * Update the current setting on the device + * + * ```js + * I.setSettings({cyberdelia: 'open'}); + * ``` + * @param settings - object + * + * Appium: support Android and iOS + */ + setSettings(settings: any): Promise; + /** + * 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): Promise; + /** + * 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): Promise; + /** + * 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[]): Promise; + /** + * 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 both Android and 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'); + * // typing secret + * I.appendField('password', secret('123456')); + * ``` + * @param field - located by label|name|CSS|XPath|strict locator + * @param value - text value to append. + */ + appendField(field: CodeceptJS.LocatorOrString, value: string): Promise; + /** + * 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. + */ + checkOption(field: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): 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. + */ + click(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString | null): Promise; + /** + * 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. + */ + dontSeeCheckboxIsChecked(field: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + dontSeeElement(locator: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + dontSeeInField(field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret): Promise; + /** + * 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. + */ + dontSee(text: string, context?: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + fillField(field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret): Promise; + /** + * 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 - either alignToTop=true|false or scrollIntoViewOptions. See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView. + */ + scrollIntoView(locator: LocatorOrString, scrollIntoViewOptions: ScrollIntoViewOptions | boolean): Promise; + /** + * 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. + */ + seeCheckboxIsChecked(field: CodeceptJS.LocatorOrString): 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. + */ + seeElement(locator: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + seeInField(field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret): Promise; + /** + * 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. + */ + see(text: string, context?: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + selectOption(select: LocatorOrString, option: string | any[]): Promise; + /** + * 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 + */ + waitForElement(locator: CodeceptJS.LocatorOrString, sec?: number): Promise; + /** + * 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 + */ + waitForVisible(locator: CodeceptJS.LocatorOrString, sec?: number): Promise; + /** + * 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 + */ + waitForInvisible(locator: CodeceptJS.LocatorOrString, sec?: number): Promise; + /** + * 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. + */ + waitForText(text: string, sec?: number, context?: CodeceptJS.LocatorOrString): Promise; + } + /** + * This helper allows performing assertions based on Chai. + * + * ### Examples + * + * Zero-configuration when paired with other helpers like REST, Playwright: + * + * ```js + * // inside codecept.conf.js + * { + * helpers: { + * Playwright: {...}, + * ExpectHelper: {}, + * } + * } + * ``` + * + * ## Methods + */ + class ExpectHelper { + expectEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectNotEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectDeepEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectNotDeepEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectContain(actualValue: any, expectedValueToContain: any, customErrorMsg?: any): Promise; + expectNotContain(actualValue: any, expectedValueToNotContain: any, customErrorMsg?: any): Promise; + expectStartsWith(actualValue: any, expectedValueToStartWith: any, customErrorMsg?: any): Promise; + expectNotStartsWith(actualValue: any, expectedValueToNotStartWith: any, customErrorMsg?: any): Promise; + expectEndsWith(actualValue: any, expectedValueToEndWith: any, customErrorMsg?: any): Promise; + expectNotEndsWith(actualValue: any, expectedValueToNotEndWith: any, customErrorMsg?: any): Promise; + expectJsonSchema(targetData: any, jsonSchema: any, customErrorMsg?: any): Promise; + /** + * @param [ajvOptions] - Pass AJV options + */ + expectJsonSchemaUsingAJV(targetData: any, jsonSchema: any, customErrorMsg?: any, ajvOptions?: any): Promise; + expectHasProperty(targetData: any, propertyName: any, customErrorMsg?: any): Promise; + expectHasAProperty(targetData: any, propertyName: any, customErrorMsg?: any): Promise; + expectToBeA(targetData: any, type: any, customErrorMsg?: any): Promise; + expectToBeAn(targetData: any, type: any, customErrorMsg?: any): Promise; + expectMatchRegex(targetData: any, regex: any, customErrorMsg?: any): Promise; + expectLengthOf(targetData: any, length: any, customErrorMsg?: any): Promise; + expectEmpty(targetData: any, customErrorMsg?: any): Promise; + expectTrue(targetData: any, customErrorMsg?: any): Promise; + expectFalse(targetData: any, customErrorMsg?: any): Promise; + expectAbove(targetData: any, aboveThan: any, customErrorMsg?: any): Promise; + expectBelow(targetData: any, belowThan: any, customErrorMsg?: any): Promise; + expectLengthAboveThan(targetData: any, lengthAboveThan: any, customErrorMsg?: any): Promise; + expectLengthBelowThan(targetData: any, lengthBelowThan: any, customErrorMsg?: any): Promise; + expectEqualIgnoreCase(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + /** + * expects members of two arrays are deeply equal + */ + expectDeepMembers(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + /** + * expects an array to be a superset of another array + */ + expectDeepIncludeMembers(superset: any, set: any, customErrorMsg?: any): Promise; + /** + * expects members of two JSON objects are deeply equal excluding some properties + */ + expectDeepEqualExcluding(actualValue: any, expectedValue: any, fieldsToExclude: any, customErrorMsg?: any): Promise; + /** + * expects a JSON object matches a provided pattern + */ + expectMatchesPattern(actualValue: any, expectedPattern: any, customErrorMsg?: any): Promise; + expectEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectNotEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectDeepEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectNotDeepEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectContain(actualValue: any, expectedValueToContain: any, customErrorMsg?: any): Promise; + expectNotContain(actualValue: any, expectedValueToNotContain: any, customErrorMsg?: any): Promise; + expectStartsWith(actualValue: any, expectedValueToStartWith: any, customErrorMsg?: any): Promise; + expectNotStartsWith(actualValue: any, expectedValueToNotStartWith: any, customErrorMsg?: any): Promise; + expectEndsWith(actualValue: any, expectedValueToEndWith: any, customErrorMsg?: any): Promise; + expectNotEndsWith(actualValue: any, expectedValueToNotEndWith: any, customErrorMsg?: any): Promise; + expectJsonSchema(targetData: any, jsonSchema: any, customErrorMsg?: any): Promise; + /** + * @param [ajvOptions] - Pass AJV options + */ + expectJsonSchemaUsingAJV(targetData: any, jsonSchema: any, customErrorMsg?: any, ajvOptions?: any): Promise; + expectHasProperty(targetData: any, propertyName: any, customErrorMsg?: any): Promise; + expectHasAProperty(targetData: any, propertyName: any, customErrorMsg?: any): Promise; + expectToBeA(targetData: any, type: any, customErrorMsg?: any): Promise; + expectToBeAn(targetData: any, type: any, customErrorMsg?: any): Promise; + expectMatchRegex(targetData: any, regex: any, customErrorMsg?: any): Promise; + expectLengthOf(targetData: any, length: any, customErrorMsg?: any): Promise; + expectEmpty(targetData: any, customErrorMsg?: any): Promise; + expectTrue(targetData: any, customErrorMsg?: any): Promise; + expectFalse(targetData: any, customErrorMsg?: any): Promise; + expectAbove(targetData: any, aboveThan: any, customErrorMsg?: any): Promise; + expectBelow(targetData: any, belowThan: any, customErrorMsg?: any): Promise; + expectLengthAboveThan(targetData: any, lengthAboveThan: any, customErrorMsg?: any): Promise; + expectLengthBelowThan(targetData: any, lengthBelowThan: any, customErrorMsg?: any): Promise; + expectEqualIgnoreCase(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + /** + * expects members of two arrays are deeply equal + */ + expectDeepMembers(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + /** + * expects an array to be a superset of another array + */ + expectDeepIncludeMembers(superset: any, set: any, customErrorMsg?: any): Promise; + /** + * expects members of two JSON objects are deeply equal excluding some properties + */ + expectDeepEqualExcluding(actualValue: any, expectedValue: any, fieldsToExclude: any, customErrorMsg?: any): Promise; + /** + * expects a JSON object matches a provided pattern + */ + expectMatchesPattern(actualValue: any, expectedPattern: any, customErrorMsg?: any): Promise; + } + /** + * This helper allows performing assertions based on Chai. + * + * ### Examples + * + * Zero-configuration when paired with other helpers like REST, Playwright: + * + * ```js + * // inside codecept.conf.js + * { + * helpers: { + * Playwright: {...}, + * ExpectHelper: {}, + * } + * } + * ``` + * + * ## Methods + */ + class ExpectHelper { + expectEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectNotEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectDeepEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectNotDeepEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectContain(actualValue: any, expectedValueToContain: any, customErrorMsg?: any): Promise; + expectNotContain(actualValue: any, expectedValueToNotContain: any, customErrorMsg?: any): Promise; + expectStartsWith(actualValue: any, expectedValueToStartWith: any, customErrorMsg?: any): Promise; + expectNotStartsWith(actualValue: any, expectedValueToNotStartWith: any, customErrorMsg?: any): Promise; + expectEndsWith(actualValue: any, expectedValueToEndWith: any, customErrorMsg?: any): Promise; + expectNotEndsWith(actualValue: any, expectedValueToNotEndWith: any, customErrorMsg?: any): Promise; + expectJsonSchema(targetData: any, jsonSchema: any, customErrorMsg?: any): Promise; + /** + * @param [ajvOptions] - Pass AJV options + */ + expectJsonSchemaUsingAJV(targetData: any, jsonSchema: any, customErrorMsg?: any, ajvOptions?: any): Promise; + expectHasProperty(targetData: any, propertyName: any, customErrorMsg?: any): Promise; + expectHasAProperty(targetData: any, propertyName: any, customErrorMsg?: any): Promise; + expectToBeA(targetData: any, type: any, customErrorMsg?: any): Promise; + expectToBeAn(targetData: any, type: any, customErrorMsg?: any): Promise; + expectMatchRegex(targetData: any, regex: any, customErrorMsg?: any): Promise; + expectLengthOf(targetData: any, length: any, customErrorMsg?: any): Promise; + expectEmpty(targetData: any, customErrorMsg?: any): Promise; + expectTrue(targetData: any, customErrorMsg?: any): Promise; + expectFalse(targetData: any, customErrorMsg?: any): Promise; + expectAbove(targetData: any, aboveThan: any, customErrorMsg?: any): Promise; + expectBelow(targetData: any, belowThan: any, customErrorMsg?: any): Promise; + expectLengthAboveThan(targetData: any, lengthAboveThan: any, customErrorMsg?: any): Promise; + expectLengthBelowThan(targetData: any, lengthBelowThan: any, customErrorMsg?: any): Promise; + expectEqualIgnoreCase(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + /** + * expects members of two arrays are deeply equal + */ + expectDeepMembers(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + /** + * expects an array to be a superset of another array + */ + expectDeepIncludeMembers(superset: any, set: any, customErrorMsg?: any): Promise; + /** + * expects members of two JSON objects are deeply equal excluding some properties + */ + expectDeepEqualExcluding(actualValue: any, expectedValue: any, fieldsToExclude: any, customErrorMsg?: any): Promise; + /** + * expects a JSON object matches a provided pattern + */ + expectMatchesPattern(actualValue: any, expectedPattern: any, customErrorMsg?: any): Promise; + expectEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectNotEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectDeepEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectNotDeepEqual(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + expectContain(actualValue: any, expectedValueToContain: any, customErrorMsg?: any): Promise; + expectNotContain(actualValue: any, expectedValueToNotContain: any, customErrorMsg?: any): Promise; + expectStartsWith(actualValue: any, expectedValueToStartWith: any, customErrorMsg?: any): Promise; + expectNotStartsWith(actualValue: any, expectedValueToNotStartWith: any, customErrorMsg?: any): Promise; + expectEndsWith(actualValue: any, expectedValueToEndWith: any, customErrorMsg?: any): Promise; + expectNotEndsWith(actualValue: any, expectedValueToNotEndWith: any, customErrorMsg?: any): Promise; + expectJsonSchema(targetData: any, jsonSchema: any, customErrorMsg?: any): Promise; + /** + * @param [ajvOptions] - Pass AJV options + */ + expectJsonSchemaUsingAJV(targetData: any, jsonSchema: any, customErrorMsg?: any, ajvOptions?: any): Promise; + expectHasProperty(targetData: any, propertyName: any, customErrorMsg?: any): Promise; + expectHasAProperty(targetData: any, propertyName: any, customErrorMsg?: any): Promise; + expectToBeA(targetData: any, type: any, customErrorMsg?: any): Promise; + expectToBeAn(targetData: any, type: any, customErrorMsg?: any): Promise; + expectMatchRegex(targetData: any, regex: any, customErrorMsg?: any): Promise; + expectLengthOf(targetData: any, length: any, customErrorMsg?: any): Promise; + expectEmpty(targetData: any, customErrorMsg?: any): Promise; + expectTrue(targetData: any, customErrorMsg?: any): Promise; + expectFalse(targetData: any, customErrorMsg?: any): Promise; + expectAbove(targetData: any, aboveThan: any, customErrorMsg?: any): Promise; + expectBelow(targetData: any, belowThan: any, customErrorMsg?: any): Promise; + expectLengthAboveThan(targetData: any, lengthAboveThan: any, customErrorMsg?: any): Promise; + expectLengthBelowThan(targetData: any, lengthBelowThan: any, customErrorMsg?: any): Promise; + expectEqualIgnoreCase(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + /** + * expects members of two arrays are deeply equal + */ + expectDeepMembers(actualValue: any, expectedValue: any, customErrorMsg?: any): Promise; + /** + * expects an array to be a superset of another array + */ + expectDeepIncludeMembers(superset: any, set: any, customErrorMsg?: any): Promise; + /** + * expects members of two JSON objects are deeply equal excluding some properties + */ + expectDeepEqualExcluding(actualValue: any, expectedValue: any, fieldsToExclude: any, customErrorMsg?: any): Promise; + /** + * expects a JSON object matches a provided pattern + */ + expectMatchesPattern(actualValue: any, expectedPattern: any, customErrorMsg?: any): Promise; + } + /** + * 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 FileSystemTs { + /** + * Enters a directory In local filesystem. + * Starts from a current directory + */ + amInPath(openPath: string): Promise; + /** + * Writes text to file + */ + writeToFile(name: string, text: string): Promise; + /** + * Checks that file exists + */ + seeFile(name: string): Promise; + /** + * Waits for the file to be present in the current directory. + * + * ```js + * I.handleDownloads('downloads/largeFilesName.txt'); + * 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): Promise; + /** + * 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): Promise; + /** + * Checks that file found by `seeFile` includes a text. + */ + seeInThisFile(text: string, encoding?: string): Promise; + /** + * Checks that file found by `seeFile` doesn't include text. + */ + dontSeeInThisFile(text: string, encoding?: string): Promise; + /** + * Checks that contents of file found by `seeFile` equal to text. + */ + seeFileContentsEqual(text: string, encoding?: string): Promise; + /** + * Checks that contents of the file found by `seeFile` equal to contents of the file at `pathToReferenceFile`. + */ + seeFileContentsEqualReferenceFile(pathToReferenceFile: string, encoding?: string, encodingReference?: string): Promise; + /** + * Checks that contents of file found by `seeFile` doesn't equal to text. + */ + dontSeeFileContentsEqual(text: string, encoding?: string): Promise; + /** + * Returns file names in current directory. + * + * ```js + * I.handleDownloads(); + * I.click('Download Files'); + * I.amInPath('output/downloads'); + * const downloadedFileNames = I.grabFileNames(); + * ``` + */ + grabFileNames(): Promise; + } + /** + * 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 GraphQLTs { + /** + * Executes query via axios call + */ + _executeQuery(request: any): Promise; + /** + * Prepares request for axios call + */ + _prepareGraphQLRequest(operation: any, headers: any): Promise; + /** + * 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 + */ + sendQuery(query: string, variables?: any, options?: any, headers?: any): Promise; + /** + * 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 + */ + sendMutation(mutation: string, variables?: any, options?: any, headers?: any): Promise; + /** + * Sets request headers for all requests of this test + * @param headers - headers list + */ + haveRequestHeaders(headers: any): Promise; + /** + * Adds a header for Bearer authentication + * + * ```js + * // we use secret function to hide token from logs + * I.amBearerAuthenticated(secret('heregoestoken')) + * ``` + * @param accessToken - Bearer access token + */ + amBearerAuthenticated(accessToken: string | CodeceptJS.Secret): Promise; + } + /** + * 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 GraphQLDataFactoryTs { + /** + * 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): Promise; + /** + * 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): Promise; + /** + * 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): Promise; + /** + * 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): Promise; + } + /** + * 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 JSONResponseTs { + /** + * Checks that response code is equal to the provided one + * + * ```js + * I.seeResponseCodeIs(200); + * ``` + */ + seeResponseCodeIs(code: number): Promise; + /** + * Checks that response code is not equal to the provided one + * + * ```js + * I.dontSeeResponseCodeIs(500); + * ``` + */ + dontSeeResponseCodeIs(code: number): Promise; + /** + * Checks that the response code is 4xx + */ + seeResponseCodeIsClientError(): Promise; + /** + * Checks that the response code is 3xx + */ + seeResponseCodeIsRedirection(): Promise; + /** + * Checks that the response code is 5xx + */ + seeResponseCodeIsServerError(): Promise; + /** + * Checks that the response code is 2xx + * Use it instead of seeResponseCodeIs(200) if server can return 204 instead. + * + * ```js + * I.seeResponseCodeIsSuccessful(); + * ``` + */ + seeResponseCodeIsSuccessful(): Promise; + /** + * 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): Promise; + /** + * 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): Promise; + /** + * 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[]): Promise; + /** + * 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): Promise; + /** + * Checks that response data equals to expected: + * + * ```js + * // response.data is { error: 'Not allowed' } + * + * I.seeResponseEquals({ error: 'Not allowed' }) + * ``` + */ + seeResponseEquals(resp: any): Promise; + /** + * 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): Promise; + } + /** + * ## Configuration + * + * This helper should be configured in codecept.conf.(js|ts) + * @property [port = 9393] - Mock server port + * @property [host = "0.0.0.0"] - Mock server host + * @property [httpsOpts] - key & cert values are the paths to .key and .crt files + */ + type MockServerConfig = { + port?: number; + host?: string; + httpsOpts?: any; + }; + /** + * MockServer + * + * The MockServer Helper in CodeceptJS empowers you to mock any server or service via HTTP or HTTPS, making it an excellent tool for simulating REST endpoints and other HTTP-based APIs. + * + * + * + * #### Examples + * + * You can seamlessly integrate MockServer with other helpers like REST or Playwright. Here's a configuration example inside the `codecept.conf.js` file: + * + * ```javascript + * { + * helpers: { + * REST: {...}, + * MockServer: { + * // default mock server config + * port: 9393, + * host: '0.0.0.0', + * httpsOpts: { + * key: '', + * cert: '', + * }, + * }, + * } + * } + * ``` + * + * #### Adding Interactions + * + * Interactions add behavior to the mock server. Use the `I.addInteractionToMockServer()` method to include interactions. It takes an interaction object as an argument, containing request and response details. + * + * ```javascript + * I.addInteractionToMockServer({ + * request: { + * method: 'GET', + * path: '/api/hello' + * }, + * response: { + * status: 200, + * body: { + * 'say': 'hello to mock server' + * } + * } + * }); + * ``` + * + * #### Request Matching + * + * When a real request is sent to the mock server, it matches the received request with the interactions. If a match is found, it returns the specified response; otherwise, a 404 status code is returned. + * + * - Strong match on HTTP Method, Path, Query Params & JSON body. + * - Loose match on Headers. + * + * ##### Strong Match on Query Params + * + * You can send different responses based on query parameters: + * + * ```javascript + * I.addInteractionToMockServer({ + * request: { + * method: 'GET', + * path: '/api/users', + * queryParams: { + * id: 1 + * } + * }, + * response: { + * status: 200, + * body: 'user 1' + * } + * }); + * + * I.addInteractionToMockServer({ + * request: { + * method: 'GET', + * path: '/api/users', + * queryParams: { + * id: 2 + * } + * }, + * response: { + * status: 200, + * body: 'user 2' + * } + * }); + * ``` + * + * - GET to `/api/users?id=1` will return 'user 1'. + * - GET to `/api/users?id=2` will return 'user 2'. + * - For all other requests, it returns a 404 status code. + * + * ##### Loose Match on Body + * + * When `strict` is set to false, it performs a loose match on query params and response body: + * + * ```javascript + * I.addInteractionToMockServer({ + * strict: false, + * request: { + * method: 'POST', + * path: '/api/users', + * body: { + * name: 'john' + * } + * }, + * response: { + * status: 200 + * } + * }); + * ``` + * + * - POST to `/api/users` with the body containing `name` as 'john' will return a 200 status code. + * - POST to `/api/users` without the `name` property in the body will return a 404 status code. + * + * Happy testing with MockServer in CodeceptJS! 🚀 + * + * ## Methods + */ + class MockServer { + /** + * Start the mock server + * @param [port] - start the mock server with given port + */ + startMockServer(port?: number): Promise; + /** + * Stop the mock server + */ + stopMockServer(): Promise; + /** + * An interaction adds behavior to the mock server + * + * + * ```js + * I.addInteractionToMockServer({ + * request: { + * method: 'GET', + * path: '/api/hello' + * }, + * response: { + * status: 200, + * body: { + * 'say': 'hello to mock server' + * } + * } + * }); + * ``` + * ```js + * // with query params + * I.addInteractionToMockServer({ + * request: { + * method: 'GET', + * path: '/api/hello', + * queryParams: { + * id: 2 + * } + * }, + * response: { + * status: 200, + * body: { + * 'say': 'hello to mock server' + * } + * } + * }); + * ``` + * @param interaction - add behavior to the mock server + */ + addInteractionToMockServer(interaction: CodeceptJS.MockInteraction | any): Promise; + } + /** + * 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 NightmareTs { + /** + * Get HAR + * + * ```js + * let har = await I.grabHAR(); + * fs.writeFileSync('sample.har', JSON.stringify({log: har})); + * ``` + */ + grabHAR(): Promise; + /** + * 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(): Promise; + /** + * 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(): Promise; + /** + * 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 + */ + amOnPage(url: string, headers: any): Promise; + /** + * Checks that title contains text. + * + * ```js + * I.seeInTitle('Home Page'); + * ``` + * @param text - text value to check. + */ + seeInTitle(text: string): Promise; + /** + * Checks that title does not contain text. + * + * ```js + * I.dontSeeInTitle('Error'); + * ``` + * @param text - value to check. + */ + dontSeeInTitle(text: string): Promise; + /** + * 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 + */ + seeInCurrentUrl(url: string): Promise; + /** + * Checks that current url does not contain a provided fragment. + * @param url - value to check. + */ + dontSeeInCurrentUrl(url: string): Promise; + /** + * 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. + */ + seeCurrentUrlEquals(url: string): Promise; + /** + * 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. + */ + dontSeeCurrentUrlEquals(url: string): Promise; + /** + * 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. + */ + see(text: string, context?: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + dontSee(text: string, context?: CodeceptJS.LocatorOrString): 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. + */ + seeElement(locator: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + dontSeeElement(locator: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + seeElementInDOM(locator: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + dontSeeElementInDOM(locator: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + seeInSource(text: string): Promise; + /** + * 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 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 + * + * #### HAR Recording Customization + * + * A HAR file is an HTTP Archive file that contains a record of all the network requests that are made when a page is loaded. + * It contains information about the request and response headers, cookies, content, timings, and more. You can use HAR files to mock network requests in your tests. + * HAR will be saved to `output/har`. More info could be found here https://playwright.dev/docs/api/class-browser#browser-new-context-option-record-har. + * + * ``` + * ... + * recordHar: { + * mode: 'minimal', // possible values: 'minimal'|'full'. + * content: 'embed' // possible values: "omit"|"embed"|"attach". + * } + * ... + * ``` + * + * #### 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: { + * // Note: due to this would launch persistent context, so to avoid the error when running tests with run-workers a timestamp would be appended to the defined folder name. For instance: playwright-tmp_1692715649511 + * 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", + * } + * } + * } + * ``` + * + * * #### Example #9: Launch electron test + * + * ```js + * { + * helpers: { + * Playwright: { + * browser: 'electron', + * electron: { + * executablePath: require("electron"), + * args: [path.join('../', "main.js")], + * }, + * } + * }, + * } + * ``` + * + * 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 PlaywrightTs { + /** + * 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 arguments + */ + usePlaywrightTo(description: string, fn: (...params: any[]) => any): Promise; + /** + * 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(): Promise; + /** + * 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(): Promise; + /** + * 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(): Promise; + /** + * Dismisses the active JavaScript popup, as created by window.alert|window.confirm|window.prompt. + */ + cancelPopup(): Promise; + /** + * 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. + */ + seeInPopup(text: string): Promise; + /** + * Set current page + * @param page - page to set + */ + _setPage(page: any): Promise; + /** + * Add the 'dialog' event listener to a page + */ + _addPopupListener(): Promise; + /** + * Gets page URL including hash. + */ + _getPageUrl(): Promise; + /** + * 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): Promise; + /** + * 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. + */ + amOnPage(url: string): Promise; + /** + * 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'); + * ```` + * + * 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. + */ + resizeWindow(width: number, height: number): Promise; + /** + * Set headers for all next requests + * + * ```js + * I.setPlaywrightRequestHeaders({ + * 'X-Sent-By': 'CodeceptJS', + * }); + * ``` + * @param customHeaders - headers to set + */ + setPlaywrightRequestHeaders(customHeaders: any): Promise; + /** + * 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. + */ + moveCursorTo(locator: CodeceptJS.LocatorOrString, offsetX?: number, offsetY?: number): Promise; + /** + * Calls [focus](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) on the matching element. + * + * Examples: + * + * ```js + * I.dontSee('#add-to-cart-btn'); + * I.focus('#product-tile') + * I.see('#add-to-cart-bnt'); + * ``` + * @param locator - field located by label|name|CSS|XPath|strict locator. + * @param [options] - Playwright only: [Additional options](https://playwright.dev/docs/api/class-locator#locator-focus) for available options object as 2nd argument. + */ + focus(locator: CodeceptJS.LocatorOrString, options?: any): Promise; + /** + * Remove focus from a text input, button, etc. + * Calls [blur](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) on the element. + * + * Examples: + * + * ```js + * I.blur('.text-area') + * ``` + * ```js + * //element `#product-tile` is focused + * I.see('#add-to-cart-btn'); + * I.blur('#product-tile') + * I.dontSee('#add-to-cart-btn'); + * ``` + * @param locator - field located by label|name|CSS|XPath|strict locator. + * @param [options] - Playwright only: [Additional options](https://playwright.dev/docs/api/class-locator#locator-blur) for available options object as 2nd argument. + */ + blur(locator: CodeceptJS.LocatorOrString, options?: any): Promise; + /** + * Return the checked status of given element. + * @param locator - element located by CSS|XPath|strict locator. + * @param [options] - See https://playwright.dev/docs/api/class-locator#locator-is-checked + */ + grabCheckedElementStatus(locator: CodeceptJS.LocatorOrString, options?: any): Promise; + /** + * Return the disabled status of given element. + * @param locator - element located by CSS|XPath|strict locator. + * @param [options] - See https://playwright.dev/docs/api/class-locator#locator-is-disabled + */ + grabDisabledElementStatus(locator: CodeceptJS.LocatorOrString, options?: any): Promise; + /** + * ```js + * // specify coordinates for source position + * I.dragAndDrop('img.src', 'img.dst', { sourcePosition: {x: 10, y: 10} }) + * ``` + * + * > When no option is set, custom drag and drop would be used, to use the dragAndDrop API from Playwright, please set options, for example `force: true` + * + * 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. + * @param [options] - [Additional options](https://playwright.dev/docs/api/class-page#page-drag-and-drop) can be passed as 3rd argument. + */ + dragAndDrop(srcElement: LocatorOrString, destElement: LocatorOrString, options?: any): Promise; + /** + * 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): Promise; + /** + * Reload the current page. + * + * ```js + * I.refreshPage(); + * ``` + */ + refreshPage(): Promise; + /** + * Replaying from HAR + * + * ```js + * // Replay API requests from HAR. + * // Either use a matching response from the HAR, + * // or abort the request if nothing matches. + * I.replayFromHar('./output/har/something.har', { url: "*\/**\/api/v1/fruits" }); + * I.amOnPage('https://demo.playwright.dev/api-mocking'); + * I.see('CodeceptJS'); + * ``` + * @param harFilePath - Path to recorded HAR file + * @param [opts] - [Options for replaying from HAR](https://playwright.dev/docs/api/class-page#page-route-from-har) + */ + replayFromHar(harFilePath: string, opts?: any): Promise; + /** + * Scroll page to the top. + * + * ```js + * I.scrollPageToTop(); + * ``` + */ + scrollPageToTop(): Promise; + /** + * Scroll page to the bottom. + * + * ```js + * I.scrollPageToBottom(); + * ``` + */ + scrollPageToBottom(): Promise; + /** + * 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. + */ + scrollTo(locator: CodeceptJS.LocatorOrString, offsetX?: number, offsetY?: number): Promise; + /** + * Checks that title contains text. + * + * ```js + * I.seeInTitle('Home Page'); + * ``` + * @param text - text value to check. + */ + seeInTitle(text: string): Promise; + /** + * 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. + */ + seeTitleEquals(text: string): Promise; + /** + * Checks that title does not contain text. + * + * ```js + * I.dontSeeInTitle('Error'); + * ``` + * @param text - value to check. + */ + dontSeeInTitle(text: string): Promise; + /** + * 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(): Promise; + /** + * Get the first element by different locator types, including strict locator + * Should be used in custom helpers: + * + * ```js + * const element = await this.helpers['Playwright']._locateElement({name: 'password'}); + * ``` + */ + _locateElement(): Promise; + /** + * 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(): Promise; + /** + * Find a clickable element by providing human-readable text: + * + * ```js + * this.helpers['Playwright']._locateClickable('Next page').then // ... + * ``` + */ + _locateClickable(): Promise; + /** + * Find field elements by providing human-readable text: + * + * ```js + * this.helpers['Playwright']._locateFields('Your email').then // ... + * ``` + */ + _locateFields(): Promise; + /** + * Grab WebElements for given locator + * Resumes test execution, so **should be used inside an async function with `await`** operator. + * + * ```js + * const webElements = await I.grabWebElements('#button'); + * ``` + * @param locator - element located by CSS|XPath|strict locator. + * @returns WebElement of being used Web helper + */ + grabWebElements(locator: CodeceptJS.LocatorOrString): Promise; + /** + * Grab WebElement for given locator + * Resumes test execution, so **should be used inside an async function with `await`** operator. + * + * ```js + * const webElement = await I.grabWebElement('#button'); + * ``` + * @param locator - element located by CSS|XPath|strict locator. + * @returns WebElement of being used Web helper + */ + grabWebElement(locator: CodeceptJS.LocatorOrString): Promise; + /** + * 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): Promise; + /** + * 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): Promise; + /** + * Close current tab and switches to previous. + * + * ```js + * I.closeCurrentTab(); + * ``` + */ + closeCurrentTab(): Promise; + /** + * Close all tabs except for the current one. + * + * ```js + * I.closeOtherTabs(); + * ``` + */ + closeOtherTabs(): Promise; + /** + * 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(): Promise; + /** + * 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. + */ + seeElement(locator: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + dontSeeElement(locator: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + seeElementInDOM(locator: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + dontSeeElementInDOM(locator: CodeceptJS.LocatorOrString): Promise; + /** + * 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'}); + * ``` + * @example + * ```js + * // click on element at position + * I.click('canvas', '.model', { position: { x: 20, y: 40 } }) + * + * // make ctrl-click + * I.click('.edit', null, { modifiers: ['Ctrl'] } ) + * ``` + * @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. + * @param [options] - [Additional options](https://playwright.dev/docs/api/class-page#page-click) for click available as 3rd argument. + */ + click(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString | null, options?: any): Promise; + /** + * Clicks link and waits for navigation (deprecated) + */ + clickLink(): Promise; + /** + * 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. + */ + forceClick(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + doubleClick(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + rightClick(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise; + /** + * [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 + * + * 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. + */ + checkOption(field: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise; + /** + * [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 + * + * 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. + */ + uncheckOption(field: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + seeCheckboxIsChecked(field: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + dontSeeCheckboxIsChecked(field: CodeceptJS.LocatorOrString): Promise; + /** + * 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. + */ + pressKeyDown(key: string): Promise; + /** + * 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. + */ + pressKeyUp(key: string): Promise; + /** + * _Note:_ Shortcuts like `'Meta'` + `'A'` do not work on macOS ([GoogleChrome/Puppeteer#1313](https://github.com/GoogleChrome/puppeteer/issues/1313)). + * + * 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. + */ + pressKey(key: string | string[]): Promise; + /** + * 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']); + * + * // passing a secret + * I.type(secret('123456')); + * ``` + * @param key - or array of keys to type. + * @param [delay = null] - (optional) delay in ms between key presses + */ + type(key: string | string[], delay?: number): Promise; + /** + * 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. + */ + fillField(field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret): Promise; + /** + * Clears the text input element: ``, `