UNPKG

codeceptjs

Version:

Supercharged End 2 End Testing Framework for NodeJS

1,268 lines 414 kB
declare namespace CodeceptJS { /** * Helper for managing remote data using REST API. * Uses data generators like [rosie](https://github.com/rosiejs/rosie) or factory girl to create new record. * * By defining a factory you set the rules of how data is generated. * This data will be saved on server via REST API and deleted in the end of a test. * * ## Use Case * * Acceptance tests interact with a websites using UI and real browser. * There is no way to create data for a specific test other than from user interface. * That makes tests slow and fragile. Instead of testing a single feature you need to follow all creation/removal process. * * This helper solves this problem. * Most of web application have API, and it can be used to create and delete test records. * By combining REST API with Factories you can easily create records for tests: * * ```js * I.have('user', { login: 'davert', email: 'davert@mail.com' }); * let id = await I.have('post', { title: 'My first post'}); * I.haveMultiple('comment', 3, {post_id: id}); * ``` * * To make this work you need * * 1. REST API endpoint which allows to perform create / delete requests and * 2. define data generation rules * * ### Setup * * Install [Rosie](https://github.com/rosiejs/rosie) and [Faker](https://www.npmjs.com/package/faker) libraries. * * ```sh * npm i rosie @faker-js/faker --save-dev * ``` * * Create a factory file for a resource. * * See the example for Posts factories: * * ```js * // tests/factories/posts.js * * const { Factory } = require('rosie'); * 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.person.findName()) * .attr('title', () => faker.lorem.sentence()) * .attr('body', () => faker.lorem.paragraph()); * ``` * For more options see [rosie documentation](https://github.com/rosiejs/rosie). * * Then configure ApiDataHelper to match factories and REST API: * ### Configuration * * ApiDataFactory has following config options: * * * `endpoint`: base URL for the API to send requests to. * * `cleanup` (default: true): should inserted records be deleted up after tests * * `factories`: list of defined factories * * `returnId` (default: false): return id instead of a complete response when creating items. * * `headers`: list of headers * * `REST`: configuration for REST requests * * See the example: * * ```js * ApiDataFactory: { * endpoint: "http://user.com/api", * cleanup: true, * headers: { * 'Content-Type': 'application/json', * 'Accept': 'application/json', * }, * factories: { * post: { * uri: "/posts", * factory: "./factories/post", * }, * comment: { * factory: "./factories/comment", * create: { post: "/comments/create" }, * delete: { post: "/comments/delete/{id}" }, * fetchId: (data) => data.result.id * } * } * } * ``` * It is required to set REST API `endpoint` which is the baseURL for all API requests. * Factory file is expected to be passed via `factory` option. * * This Helper uses [REST](http://codecept.io/helpers/REST/) helper and accepts its configuration in "REST" section. * For instance, to set timeout you should add: * * ```js * "ApiDataFactory": { * "REST": { * "timeout": "100000", * } * } * ``` * * ### Requests * * By default to create a record ApiDataFactory will use endpoint and plural factory name: * * * create: `POST {endpoint}/{resource} data` * * delete: `DELETE {endpoint}/{resource}/id` * * Example (`endpoint`: `http://app.com/api`): * * * create: POST request to `http://app.com/api/users` * * delete: DELETE request to `http://app.com/api/users/1` * * This behavior can be configured with following options: * * * `uri`: set different resource uri. Example: `uri: account` => `http://app.com/api/account`. * * `create`: override create options. Expected format: `{ method: uri }`. Example: `{ "post": "/users/create" }` * * `delete`: override delete options. Expected format: `{ method: uri }`. Example: `{ "post": "/users/delete/{id}" }` * * Requests can also be overridden with a function which returns [axois request config](https://github.com/axios/axios#request-config). * * ```js * create: (data) => ({ method: 'post', url: '/posts', data }), * delete: (id) => ({ method: 'delete', url: '/posts', data: { id } }) * * ``` * * Requests can be updated on the fly by using `onRequest` function. For instance, you can pass in current session from a cookie. * * ```js * onRequest: async (request) => { * // using global codeceptjs instance * let cookie = await codeceptjs.container.helpers('WebDriver').grabCookie('session'); * request.headers = { Cookie: `session=${cookie.value}` }; * } * ``` * * ### Responses * * By default `I.have()` returns a promise with a created data: * * ```js * let client = await I.have('client'); * ``` * * Ids of created records are collected and used in the end of a test for the cleanup. * If you need to receive `id` instead of full response enable `returnId` in a helper config: * * ```js * // returnId: false * let clientId = await I.have('client'); * // clientId == 1 * * // returnId: true * let clientId = await I.have('client'); * // client == { name: 'John', email: 'john@snow.com' } * ``` * * By default `id` property of response is taken. This behavior can be changed by setting `fetchId` function in a factory config. * * * ```js * factories: { * post: { * uri: "/posts", * factory: "./factories/post", * fetchId: (data) => data.result.posts[0].id * } * } * ``` * * * ## Methods */ class ApiDataFactory { /** * Generates a new record using factory and saves API request to store it. * * ```js * // create a user * I.have('user'); * // create user with defined email * // and receive it when inside async function * const user = await I.have('user', { email: 'user@user.com'}); * // create a user with options that will not be included in the final request * I.have('user', { }, { age: 33, height: 55 }) * ``` * @param factory - factory to use * @param [params] - predefined parameters * @param [options] - options for programmatically generate the attributes */ have(factory: any, params?: any, options?: any): Promise<any>; /** * Generates bunch of records and saves multiple API requests to store them. * * ```js * // create 3 posts * I.haveMultiple('post', 3); * * // create 3 posts by one author * I.haveMultiple('post', 3, { author: 'davert' }); * * // create 3 posts by one author with options * I.haveMultiple('post', 3, { author: 'davert' }, { publish_date: '01.01.1997' }); * ``` */ haveMultiple(factory: any, times: any, params?: any, options?: any): void; /** * Executes request to create a record in API. * Can be replaced from a in custom helper. */ _requestCreate(factory: any, data: any): void; /** * Executes request to delete a record in API * Can be replaced from a custom helper. */ _requestDelete(factory: any, id: any): void; } /** * Appium Special Methods for Mobile only */ class Appium extends WebDriver { /** * Execute code only on iOS * * ```js * I.runOnIOS(() => { * I.click('//UIAApplication[1]/UIAWindow[1]/UIAButton[1]'); * I.see('Hi, IOS', '~welcome'); * }); * ``` * * Additional filter can be applied by checking for capabilities. * For instance, this code will be executed only on iPhone 5s: * * * ```js * I.runOnIOS({deviceName: 'iPhone 5s'},() => { * // ... * }); * ``` * * Also capabilities can be checked by a function. * * ```js * I.runOnAndroid((caps) => { * // caps is current config of desiredCapabiliites * return caps.platformVersion >= 6 * },() => { * // ... * }); * ``` */ runOnIOS(caps: any, fn: any): void; /** * Execute code only on Android * * ```js * I.runOnAndroid(() => { * I.click('io.selendroid.testapp:id/buttonTest'); * }); * ``` * * Additional filter can be applied by checking for capabilities. * For instance, this code will be executed only on Android 6.0: * * * ```js * I.runOnAndroid({platformVersion: '6.0'},() => { * // ... * }); * ``` * * Also capabilities can be checked by a function. * In this case, code will be executed only on Android >= 6. * * ```js * I.runOnAndroid((caps) => { * // caps is current config of desiredCapabiliites * return caps.platformVersion >= 6 * },() => { * // ... * }); * ``` */ runOnAndroid(caps: any, fn: any): void; /** * Execute code only in Web mode. * * ```js * I.runInWeb(() => { * I.waitForElement('#data'); * I.seeInCurrentUrl('/data'); * }); * ``` */ runInWeb(): void; /** * Returns app installation status. * * ```js * I.checkIfAppIsInstalled("com.example.android.apis"); * ``` * @param bundleId - String ID of bundled app * @returns Appium: support only Android */ checkIfAppIsInstalled(bundleId: string): Promise<boolean>; /** * 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<void>; /** * 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<void>; /** * 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<void>; /** * Remove an app from the device. * * ```js * I.removeApp('appName', 'com.example.android.apis'); * ``` * * Appium: support only Android * @param [bundleId] - ID of bundle */ removeApp(appId: string, bundleId?: string): void; /** * Reset the currently running app for current session. * * ```js * I.resetApp(); * ``` */ resetApp(): void; /** * Check current activity on an Android device. * * ```js * I.seeCurrentActivityIs(".HomeScreenActivity") * ``` * @returns Appium: support only Android */ seeCurrentActivityIs(currentActivity: string): Promise<void>; /** * Check whether the device is locked. * * ```js * I.seeDeviceIsLocked(); * ``` * @returns Appium: support only Android */ seeDeviceIsLocked(): Promise<void>; /** * Check whether the device is not locked. * * ```js * I.seeDeviceIsUnlocked(); * ``` * @returns Appium: support only Android */ seeDeviceIsUnlocked(): Promise<void>; /** * 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<void>; /** * Set a device orientation. Will fail, if app will not set orientation * * ```js * I.setOrientation('PORTRAIT'); * I.setOrientation('LANDSCAPE') * ``` * @param orientation - LANDSCAPE or PORTRAIT * * Appium: support Android and iOS */ setOrientation(orientation: 'LANDSCAPE' | 'PORTRAIT'): void; /** * Get list of all available contexts * * ``` * let contexts = await I.grabAllContexts(); * ``` * @returns Appium: support Android and iOS */ grabAllContexts(): Promise<string[]>; /** * Retrieve current context * * ```js * let context = await I.grabContext(); * ``` * @returns Appium: support Android and iOS */ grabContext(): Promise<string | null>; /** * Get current device activity. * * ```js * let activity = await I.grabCurrentActivity(); * ``` * @returns Appium: support only Android */ grabCurrentActivity(): Promise<string>; /** * 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<string>; /** * Get all the currently specified settings. * * ```js * let settings = await I.grabSettings(); * ``` * @returns Appium: support Android and iOS */ grabSettings(): Promise<string>; /** * Switch to the specified context. * @param context - the context to switch to */ switchToContext(context: any): void; /** * Switches to web context. * If no context is provided switches to the first detected web context * * ```js * // switch to first web context * I.switchToWeb(); * * // or set the context explicitly * I.switchToWeb('WEBVIEW_io.selendroid.testapp'); * ``` */ switchToWeb(context?: string): Promise<void>; /** * 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<void>; /** * 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<void>; /** * 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<number>; /** * Update the current setting on the device * * ```js * I.setSettings({cyberdelia: 'open'}); * ``` * @param settings - object * * Appium: support Android and iOS */ setSettings(settings: any): void; /** * Hide the keyboard. * * ```js * // taps outside to hide keyboard per default * I.hideDeviceKeyboard(); * ``` * * Appium: support Android and iOS */ hideDeviceKeyboard(): void; /** * Send a key event to the device. * List of keys: https://developer.android.com/reference/android/view/KeyEvent.html * * ```js * I.sendDeviceKeyEvent(3); * ``` * @param keyValue - Device specific key value * @returns Appium: support only Android */ sendDeviceKeyEvent(keyValue: number): Promise<void>; /** * Open the notifications panel on the device. * * ```js * I.openNotifications(); * ``` * @returns Appium: support only Android */ openNotifications(): Promise<void>; /** * 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<void>; /** * Taps on element. * * ```js * I.tap("~buttonStartWebviewCD"); * ``` * * Shortcut for `makeTouchAction` */ tap(locator: any): Promise<void>; /** * Perform a swipe on the screen or an element. * * ```js * let locator = "#io.selendroid.testapp:id/LinearLayout1"; * I.swipe(locator, 800, 1200, 1000); * ``` * * [See complete reference](http://webdriver.io/api/mobile/swipe.html) * @param [speed = 1000] - (optional), 1000 by default * @returns Appium: support Android and iOS */ swipe(locator: CodeceptJS.LocatorOrString, xoffset: number, yoffset: number, speed?: number): Promise<void>; /** * Perform a swipe on the screen. * * ```js * I.performSwipe({ x: 300, y: 100 }, { x: 200, y: 100 }); * ``` * @param to - Appium: support Android and iOS */ performSwipe(from: any, to: any): void; /** * Perform a swipe down on an element. * * ```js * let locator = "#io.selendroid.testapp:id/LinearLayout1"; * I.swipeDown(locator); // simple swipe * I.swipeDown(locator, 500); // set speed * I.swipeDown(locator, 1200, 1000); // set offset and speed * ``` * @param [yoffset = 1000] - (optional) * @param [speed = 1000] - (optional), 1000 by default * @returns Appium: support Android and iOS */ swipeDown(locator: CodeceptJS.LocatorOrString, yoffset?: number, speed?: number): Promise<void>; /** * 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<void>; /** * 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<void>; /** * 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<void>; /** * 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<void>; /** * Performs a specific touch action. * The action object need to contain the action name, x/y coordinates * * ```js * I.touchPerform([{ * action: 'press', * options: { * x: 100, * y: 200 * } * }, {action: 'release'}]) * * I.touchPerform([{ * action: 'tap', * options: { * element: '1', // json web element was queried before * x: 10, // x offset * y: 20, // y offset * count: 1 // number of touches * } * }]); * ``` * * Appium: support Android and iOS * @param actions - Array of touch actions */ touchPerform(actions: any[]): void; /** * Pulls a file from the device. * * ```js * I.pullFile('/storage/emulated/0/DCIM/logo.png', 'my/path'); * // save file to output dir * I.pullFile('/storage/emulated/0/DCIM/logo.png', output_dir); * ``` * @returns Appium: support Android and iOS */ pullFile(path: string, dest: string): Promise<string>; /** * Perform a shake action on the device. * * ```js * I.shakeDevice(); * ``` * @returns Appium: support only iOS */ shakeDevice(): Promise<void>; /** * 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<void>; /** * Set immediate value in app. * * See corresponding [webdriverio reference](http://webdriver.io/api/mobile/setImmediateValue.html). * @returns Appium: support only iOS */ setImmediateValue(): Promise<void>; /** * 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<void>; /** * Close the given application. * * ```js * I.closeApp(); * ``` * @returns Appium: support both Android and iOS */ closeApp(): Promise<void>; /** * Appends text to a input field or textarea. * Field is located by name, label, CSS or XPath * * The third parameter is an optional context (CSS or XPath locator) to narrow the search. * * ```js * I.appendField('#myTextField', 'appended'); * // typing secret * I.appendField('password', secret('123456')); * // within a context * I.appendField('name', 'John', '.form-container'); * ``` * @param field - located by label|name|CSS|XPath|strict locator * @param value - text value to append. * @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator. * @returns automatically synchronized promise through #recorder */ appendField(field: CodeceptJS.LocatorOrString, value: string, context?: CodeceptJS.LocatorOrString): void; /** * Selects a checkbox or radio button. * Element is located by label or name or CSS or XPath. * * The second parameter is an optional context (CSS or XPath locator) to narrow the search. * * ```js * I.checkOption('#agree'); * I.checkOption('I Agree to Terms and Conditions'); * I.checkOption('agree', '//form'); * ``` * @param field - checkbox located by label | name | CSS | XPath | strict locator. * @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator. * @returns automatically synchronized promise through #recorder */ checkOption(field: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void; /** * Perform a click on a link or a button, given by a locator. * If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string. * For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched. * For images, the "alt" attribute and inner text of any parent links are searched. * * If no locator is provided, defaults to clicking the body element (`'//body'`). * * The second parameter is a context (CSS or XPath locator) to narrow the search. * * ```js * // click body element (default) * I.click(); * // 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'}); * // using ARIA role locator * I.click({role: 'button', name: 'Submit'}); * ``` * * > ℹ️ ARIA role locators (`{role, name}`) match elements the way assistive technology does and survive markup refactors. See [Locators](/locators#aria-locators). * @param [locator = '//body'] - (optional, `'//body'` by default) clickable link or button located by text, or any element located by CSS|XPath|strict locator. * @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator. * @returns automatically synchronized promise through #recorder */ click(locator?: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString | null): void; /** * Verifies that the specified checkbox is not checked. * * ```js * I.dontSeeCheckboxIsChecked('#agree'); // located by ID * I.dontSeeCheckboxIsChecked('I agree to terms'); // located by label * I.dontSeeCheckboxIsChecked('agree'); // located by name * ``` * @param field - located by label|name|CSS|XPath|strict locator. * @returns automatically synchronized promise through #recorder */ dontSeeCheckboxIsChecked(field: CodeceptJS.LocatorOrString): void; /** * Opposite to `seeElement`. Checks that element is not visible (or in DOM) * * The second parameter is a context (CSS or XPath locator) to narrow the search. * * ```js * I.dontSeeElement('.modal'); // modal is not shown * I.dontSeeElement('.modal', '#container'); * ``` * @param locator - located by CSS|XPath|Strict locator. * @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator. * @returns automatically synchronized promise through #recorder */ dontSeeElement(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void; /** * Checks that value of input field or textarea doesn't equal to given value * Opposite to `seeInField`. * * The third parameter is an optional context (CSS or XPath locator) to narrow the search. * * ```js * I.dontSeeInField('email', 'user@user.com'); // field by name * I.dontSeeInField({ css: 'form input.email' }, 'user@user.com'); // field by CSS * // within a context * I.dontSeeInField('Name', 'old_value', '.form-container'); * ``` * @param field - located by label|name|CSS|XPath|strict locator. * @param value - value to check. * @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator. * @returns automatically synchronized promise through #recorder */ dontSeeInField(field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret, context?: CodeceptJS.LocatorOrString): void; /** * Opposite to `see`. Checks that a text is not present on a page. * Use context parameter to narrow down the search. * * ```js * I.dontSee('Login'); // assume we are already logged in. * I.dontSee('Login', '.nav'); // no login inside .nav element * ``` * @param text - which is not present. * @param [context = null] - (optional) element located by CSS|XPath|strict locator in which to perfrom search. * @returns automatically synchronized promise through #recorder */ dontSee(text: string, context?: CodeceptJS.LocatorOrString): void; /** * Fills a text field or textarea, after clearing its value, with the given string. * Field is located by name, label, CSS, or XPath. * * The third parameter is an optional context (CSS or XPath locator) to narrow the search. * * ```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'); * // by ARIA role locator * I.fillField({role: 'textbox', name: 'Email'}, 'hello@world.com'); * // within a context * I.fillField('Name', 'John', '#section2'); * ``` * * > ℹ️ ARIA role locators (`{role, name}`) match fields by their accessible name and survive markup refactors. See [Locators](/locators#aria-locators). * @param field - located by label|name|CSS|XPath|strict locator. * @param value - text value to fill. * @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator. * @returns automatically synchronized promise through #recorder */ fillField(field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret, context?: CodeceptJS.LocatorOrString): void; /** * Retrieves all texts from an element located by CSS or XPath and returns it to test. * Resumes test execution, so **should be used inside async with `await`** operator. * * ```js * let pins = await I.grabTextFromAll('#pin li'); * ``` * @param locator - element located by CSS|XPath|strict locator. * @returns attribute value */ grabTextFromAll(locator: CodeceptJS.LocatorOrString): Promise<string[]>; /** * 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<string>; /** * 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<number>; /** * 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<string>; /** * 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<string[]>; /** * 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<string[]>; /** * 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<string>; /** * 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<void>; /** * 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. * @returns automatically synchronized promise through #recorder * * * Supported only for web testing */ scrollIntoView(locator: LocatorOrString, scrollIntoViewOptions: ScrollIntoViewOptions | boolean): void; /** * Verifies that the specified checkbox is checked. * * ```js * I.seeCheckboxIsChecked('Agree'); * I.seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms * I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'}); * ``` * @param field - located by label|name|CSS|XPath|strict locator. * @returns automatically synchronized promise through #recorder */ seeCheckboxIsChecked(field: CodeceptJS.LocatorOrString): void; /** * Checks that a given Element is visible * Element is located by CSS or XPath. * * The second parameter is a context (CSS or XPath locator) to narrow the search. * * ```js * I.seeElement('#modal'); * I.seeElement('#modal', '#container'); * // using ARIA role locator * I.seeElement({role: 'dialog'}); * ``` * * > ℹ️ ARIA role locators (`{role, name}`) match elements the way assistive technology does and survive markup refactors. See [Locators](/locators#aria-locators). * @param locator - located by CSS|XPath|strict locator. * @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator. * @returns automatically synchronized promise through #recorder */ seeElement(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void; /** * Checks that the given input field or textarea equals to given value. * For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath. * * The third parameter is an optional context (CSS or XPath locator) to narrow the search. * * ```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'); * // within a context * I.seeInField('Name', 'John', '.form-container'); * ``` * @param field - located by label|name|CSS|XPath|strict locator. * @param value - value to check. * @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator. * @returns automatically synchronized promise through #recorder */ seeInField(field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret, context?: CodeceptJS.LocatorOrString): void; /** * Checks that a page contains a visible text. * Use context parameter to narrow down the search. * * ```js * I.see('Welcome'); // text welcome on a page * I.see('Welcome', '.content'); // text inside .content div * I.see('Register', {css: 'form.register'}); // use strict locator * ``` * @param text - expected on page. * @param [context = null] - (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text. * @returns automatically synchronized promise through #recorder */ see(text: string, context?: CodeceptJS.LocatorOrString): void; /** * Selects an option in a drop-down select. * Field is searched by label | name | CSS | XPath. * Option is selected by visible text or by value. * * The third parameter is an optional context (CSS or XPath locator) to narrow the search. * * ```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'); * // within a context * I.selectOption('age', '21-60', '#section2'); * ``` * * 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. * @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator. * @returns automatically synchronized promise through #recorder * * * Supported only for web testing */ selectOption(select: LocatorOrString, option: string | any[], context?: CodeceptJS.LocatorOrString): void; /** * Waits for element to be present on page (by default waits for 1sec). * Element can be located by CSS or XPath. * * ```js * I.waitForElement('.btn.continue'); * I.waitForElement('.btn.continue', 5); // wait for 5 secs * ``` * @param locator - element located by CSS|XPath|strict locator. * @param [sec = null] - (optional, `1` by default) time in seconds to wait * @returns automatically synchronized promise through #recorder */ waitForElement(locator: CodeceptJS.LocatorOrString, sec?: number): void; /** * Waits for an element to become visible on a page (by default waits for 1sec). * Element can be located by CSS or XPath. * * ```js * I.waitForVisible('#popup'); * ``` * @param locator - element located by CSS|XPath|strict locator. * @param [sec = 1] - (optional, `1` by default) time in seconds to wait * @returns automatically synchronized promise through #recorder */ waitForVisible(locator: CodeceptJS.LocatorOrString, sec?: number): void; /** * Waits for an element to be removed or become invisible on a page (by default waits for 1sec). * Element can be located by CSS or XPath. * * ```js * I.waitForInvisible('#popup'); * ``` * @param locator - element located by CSS|XPath|strict locator. * @param [sec = 1] - (optional, `1` by default) time in seconds to wait * @returns automatically synchronized promise through #recorder */ waitForInvisible(locator: CodeceptJS.LocatorOrString, sec?: number): void; /** * Waits for a text to appear (by default waits for 1sec). * Element can be located by CSS or XPath. * Narrow down search results by providing context. * * ```js * I.waitForText('Thank you, form has been submitted'); * I.waitForText('Thank you, form has been submitted', 5, '#modal'); * ``` * @param text - to wait for. * @param [sec = 1] - (optional, `1` by default) time in seconds to wait * @param [context = null] - (optional) element located by CSS|XPath|strict locator. * @returns automatically synchronized promise through #recorder */ waitForText(text: string, sec?: number, context?: CodeceptJS.LocatorOrString): void; } /** * Helper for testing filesystem. * Can be easily used to check file structures: * * ```js * I.amInPath('test'); * I.seeFile('codecept.js'); * I.seeInThisFile('FileSystem'); * I.dontSeeInThisFile("WebDriver"); * ``` * * ## Configuration * * Enable helper in config file: * * ```js * helpers: { * FileSystem: {}, * } * ``` * * ## Methods */ class FileSystem { /** * Enters a directory In local filesystem. * Starts from a current directory */ amInPath(openPath: string): void; /** * Writes text to file */ writeToFile(name: string, text: string): void; /** * Checks that file exists */ seeFile(name: string): void; /** * 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): void; /** * Checks that file with a name including given text exists in the current directory. * * ```js * I.handleDownloads(); * I.click('Download as PDF'); * I.amInPath('output/downloads'); * I.seeFileNameMatching('.pdf'); * ``` */ seeFileNameMatching(text: string): void; /** * Checks that file found by `seeFile` includes a text. */ seeInThisFile(text: string, encoding?: string): void; /** * Checks that file found by `seeFile` doesn't include text. */ dontSeeInThisFile(text: string, encoding?: string): void; /** * Checks that contents of file found by `seeFile` equal to text. */ seeFileContentsEqual(text: string, encoding?: string): void; /** * Checks that contents of the file found by `seeFile` equal to contents of the file at `pathToReferenceFile`. */ seeFileContentsEqualReferenceFile(pathToReferenceFile: string, encoding?: string, encodingReference?: string): void; /** * Checks that contents of file found by `seeFile` doesn't equal to text. */ dontSee