@kronoslive/codeceptjs
Version:
Supercharged End 2 End Testing Framework for NodeJS
1,384 lines • 419 kB
TypeScript
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 --save-dev
* ```
*
* Create a factory file for a resource.
*
* See the example for Posts factories:
*
* ```js
* // tests/factories/posts.js
*
* var Factory = require('rosie').Factory;
* var faker = require('faker');
*
* module.exports = new Factory()
* // no need to set id, it will be set by REST API
* .attr('author', () => faker.name.findName())
* .attr('title', () => faker.lorem.sentence())
* .attr('body', () => faker.lorem.paragraph());
* ```
* For more options see [rosie documentation](https://github.com/rosiejs/rosie).
*
* Then configure ApiDataHelper to match factories and REST API:
* ### Configuration
*
* ApiDataFactory has following config options:
*
* * `endpoint`: base URL for the API to send requests to.
* * `cleanup` (default: true): should inserted records be deleted up after tests
* * `factories`: list of defined factories
* * `returnId` (default: false): return id instead of a complete response when creating items.
* * `headers`: list of headers
* * `REST`: configuration for REST requests
*
* See the example:
*
* ```js
* ApiDataFactory: {
* endpoint: "http://user.com/api",
* cleanup: true,
* headers: {
* 'Content-Type': 'application/json',
* 'Accept': 'application/json',
* },
* factories: {
* post: {
* uri: "/posts",
* factory: "./factories/post",
* },
* comment: {
* factory: "./factories/comment",
* create: { post: "/comments/create" },
* delete: { post: "/comments/delete/{id}" },
* fetchId: (data) => data.result.id
* }
* }
* }
* ```
* It is required to set REST API `endpoint` which is the baseURL for all API requests.
* Factory file is expected to be passed via `factory` option.
*
* This Helper uses [REST](http://codecept.io/helpers/REST/) helper and accepts its configuration in "REST" section.
* For instance, to set timeout you should add:
*
* ```js
* "ApiDataFactory": {
* "REST": {
* "timeout": "100000",
* }
* }
* ```
*
* ### Requests
*
* By default to create a record ApiDataFactory will use endpoint and plural factory name:
*
* * create: `POST {endpoint}/{resource} data`
* * delete: `DELETE {endpoint}/{resource}/id`
*
* Example (`endpoint`: `http://app.com/api`):
*
* * create: POST request to `http://app.com/api/users`
* * delete: DELETE request to `http://app.com/api/users/1`
*
* This behavior can be configured with following options:
*
* * `uri`: set different resource uri. Example: `uri: account` => `http://app.com/api/account`.
* * `create`: override create options. Expected format: `{ method: uri }`. Example: `{ "post": "/users/create" }`
* * `delete`: override delete options. Expected format: `{ method: uri }`. Example: `{ "post": "/users/delete/{id}" }`
*
* Requests can also be overridden with a function which returns [axois request config](https://github.com/axios/axios#request-config).
*
* ```js
* create: (data) => ({ method: 'post', url: '/posts', data }),
* delete: (id) => ({ method: 'delete', url: '/posts', data: { id } })
*
* ```
*
* Requests can be updated on the fly by using `onRequest` function. For instance, you can pass in current session from a cookie.
*
* ```js
* onRequest: async (request) => {
* // using global codeceptjs instance
* let cookie = await codeceptjs.container.helpers('WebDriver').grabCookie('session');
* request.headers = { Cookie: `session=${cookie.value}` };
* }
* ```
*
* ### Responses
*
* By default `I.have()` returns a promise with a created data:
*
* ```js
* let client = await I.have('client');
* ```
*
* Ids of created records are collected and used in the end of a test for the cleanup.
* If you need to receive `id` instead of full response enable `returnId` in a helper config:
*
* ```js
* // returnId: false
* let clientId = await I.have('client');
* // clientId == 1
*
* // returnId: true
* let clientId = await I.have('client');
* // client == { name: 'John', email: 'john@snow.com' }
* ```
*
* By default `id` property of response is taken. This behavior can be changed by setting `fetchId` function in a factory config.
*
*
* ```js
* factories: {
* post: {
* uri: "/posts",
* factory: "./factories/post",
* fetchId: (data) => data.result.posts[0].id
* }
* }
* ```
*
*
* ## Methods
*/
class ApiDataFactory {
/**
* Generates a new record using factory and saves API request to store it.
*
* ```js
* // create a user
* I.have('user');
* // create user with defined email
* // and receive it when inside async function
* const user = await I.have('user', { email: 'user@user.com'});
* ```
* @param factory - factory to use
* @param params - predefined parameters
*/
have(factory: any, params: any): void;
/**
* 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' });
* ```
*/
haveMultiple(factory: any, times: any, params: 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 {
/**
* 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;
/**
* Check if an app is installed.
*
* ```js
* I.seeAppIsInstalled("com.example.android.apis");
* ```
* @param bundleId - String ID of bundled app
*
* Appium: support only Android
*/
seeAppIsInstalled(bundleId: string): void;
/**
* Check if an app is not installed.
*
* ```js
* I.seeAppIsNotInstalled("com.example.android.apis");
* ```
* @param bundleId - String ID of bundled app
*
* Appium: support only Android
*/
seeAppIsNotInstalled(bundleId: string): void;
/**
* Install an app on device.
*
* ```js
* I.installApp('/path/to/file.apk');
* ```
* @param path - path to apk file
*
* Appium: support only Android
*/
installApp(path: string): void;
/**
* Remove an app from the device.
*
* ```js
* I.removeApp('appName', 'com.example.android.apis');
* ```
* @param bundleId - String ID of bundle
*
* Appium: support only Android
*/
removeApp(appId: string, bundleId: string): void;
/**
* Check current activity on an Android device.
*
* ```js
* I.seeCurrentActivityIs(".HomeScreenActivity")
* ```
* @param currentActivity - Appium: support only Android
*/
seeCurrentActivityIs(currentActivity: string): void;
/**
* Check whether the device is locked.
*
* ```js
* I.seeDeviceIsLocked();
* ```
*
* Appium: support only Android
*/
seeDeviceIsLocked(): void;
/**
* Check whether the device is not locked.
*
* ```js
* I.seeDeviceIsUnlocked();
* ```
*
* Appium: support only Android
*/
seeDeviceIsUnlocked(): 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'): 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();
* ```
*
* Appium: support Android and iOS
*/
grabAllContexts(): void;
/**
* Retrieve current context
*
* ```js
* let context = await I.grabContext();
* ```
*
* Appium: support Android and iOS
*/
grabContext(): void;
/**
* Get current device activity.
*
* ```js
* let activity = await I.grabCurrentActivity();
* ```
*
* Appium: support only Android
*/
grabCurrentActivity(): void;
/**
* 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();
* ```
*
* Appium: support only Android
*/
grabNetworkConnection(): void;
/**
* Get current orientation.
*
* ```js
* let orientation = await I.grabOrientation();
* ```
*
* Appium: support Android and iOS
*/
grabOrientation(): void;
/**
* Get all the currently specified settings.
*
* ```js
* let settings = await I.grabSettings();
* ```
*
* Appium: support Android and iOS
*/
grabSettings(): void;
/**
* 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): 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): void;
/**
* Start an arbitrary Android activity during a session.
*
* ```js
* I.startActivity('io.selendroid.testapp', '.RegisterUserActivity');
* ```
*
* Appium: support only Android
*/
startActivity(): 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](http://webdriver.io/api/mobile/setNetworkConnection.html).
*
* Appium: support only Android
*/
setNetworkConnection(): void;
/**
* Update the current setting on the device
*
* ```js
* I.setSettings({cyberdelia: 'open'});
* ```
* @param settings - object
*
* Appium: support Android and iOS
*/
setSettings(settings: any): void;
/**
* Hide the keyboard.
*
* ```js
* // taps outside to hide keyboard per default
* I.hideDeviceKeyboard();
* I.hideDeviceKeyboard('tapOutside');
*
* // or by pressing key
* I.hideDeviceKeyboard('pressKey', 'Done');
* ```
* @param strategy - desired strategy to close keyboard (‘tapOutside’ or ‘pressKey’)
*
* Appium: support Android and iOS
*/
hideDeviceKeyboard(strategy: 'tapOutside' | 'pressKey'): 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
*
* Appium: support only Android
*/
sendDeviceKeyEvent(keyValue: number): void;
/**
* Open the notifications panel on the device.
*
* ```js
* I.openNotifications();
* ```
*
* Appium: support only Android
*/
openNotifications(): 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');
* ```
*
* Appium: support Android and iOS
*/
makeTouchAction(): void;
/**
* Taps on element.
*
* ```js
* I.tap("~buttonStartWebviewCD");
* ```
*
* Shortcut for `makeTouchAction`
*/
tap(locator: any): void;
/**
* Perform a swipe on the screen.
*
* ```js
* I.performswipe(100,200);
* ```
* @param to - Appium: support Android and iOS
*/
performSwipe(from: number, to: number): 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
*
* Appium: support Android and iOS
*/
swipeDown(locator: CodeceptJS.LocatorOrString, yoffset?: number, speed?: number): 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
*
* Appium: support Android and iOS
*/
swipeLeft(locator: CodeceptJS.LocatorOrString, xoffset?: number, speed?: number): 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
*
* Appium: support Android and iOS
*/
swipeRight(locator: CodeceptJS.LocatorOrString, xoffset?: number, speed?: number): 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
*
* Appium: support Android and iOS
*/
swipeUp(locator: CodeceptJS.LocatorOrString, yoffset?: number, speed?: number): 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);
* ```
* @param speed - Appium: support Android and iOS
*/
swipeTo(searchableLocator: string, scrollLocator: string, direction: string, timeout: number, offset: number, speed: number): 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
*/
touchPerform(): 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);
* ```
*
* Appium: support Android and iOS
*/
pullFile(): void;
/**
* Perform a shake action on the device.
*
* ```js
* I.shakeDevice();
* ```
*
* Appium: support only iOS
*/
shakeDevice(): 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).
*
* Appium: support only iOS
*/
rotate(): void;
/**
* Set immediate value in app.
*
* See corresponding [webdriverio reference](http://webdriver.io/api/mobile/setImmediateValue.html).
*
* Appium: support only iOS
*/
setImmediateValue(): 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
* ```
*
* Appium: support only iOS
* TODO: not tested
*/
simulateTouchId(): void;
/**
* Close the given application.
*
* ```js
* I.closeApp();
* ```
*
* Appium: support only iOS
*/
closeApp(): void;
/**
* Appends text to a input field or textarea.
* Field is located by name, label, CSS or XPath
*
* ```js
* I.appendField('#myTextField', 'appended');
* ```
* @param field - located by label|name|CSS|XPath|strict locator
* @param value - text value to append.
*/
appendField(field: CodeceptJS.LocatorOrString, value: string): void;
/**
* Selects a checkbox or radio button.
* Element is located by label or name or CSS or XPath.
*
* The second parameter is a context (CSS or XPath locator) to narrow the search.
*
* ```js
* I.checkOption('#agree');
* I.checkOption('I Agree to Terms and Conditions');
* I.checkOption('agree', '//form');
* ```
* @param field - checkbox located by label | name | CSS | XPath | strict locator.
* @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator.
*/
checkOption(field: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void;
/**
* Perform a click on a link or a button, given by a locator.
* If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
* For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched.
* For images, the "alt" attribute and inner text of any parent links are searched.
*
* The second parameter is a context (CSS or XPath locator) to narrow the search.
*
* ```js
* // simple link
* I.click('Logout');
* // button of form
* I.click('Submit');
* // CSS button
* I.click('#form input[type=submit]');
* // XPath
* I.click('//form/*[@type=submit]');
* // link in context
* I.click('Logout', '#nav');
* // using strict locator
* I.click({css: 'nav a.login'});
* ```
* @param locator - clickable link or button located by text, or any element located by CSS|XPath|strict locator.
* @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator.
*/
click(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void;
/**
* Verifies that the specified checkbox is not checked.
*
* ```js
* I.dontSeeCheckboxIsChecked('#agree'); // located by ID
* I.dontSeeCheckboxIsChecked('I agree to terms'); // located by label
* I.dontSeeCheckboxIsChecked('agree'); // located by name
* ```
* @param field - located by label|name|CSS|XPath|strict locator.
*/
dontSeeCheckboxIsChecked(field: CodeceptJS.LocatorOrString): void;
/**
* Opposite to `seeElement`. Checks that element is not visible (or in DOM)
*
* ```js
* I.dontSeeElement('.modal'); // modal is not shown
* ```
* @param locator - located by CSS|XPath|Strict locator.
*/
dontSeeElement(locator: CodeceptJS.LocatorOrString): void;
/**
* Checks that value of input field or textarea doesn't equal to given value
* Opposite to `seeInField`.
*
* ```js
* I.dontSeeInField('email', 'user@user.com'); // field by name
* I.dontSeeInField({ css: 'form input.email' }, 'user@user.com'); // field by CSS
* ```
* @param field - located by label|name|CSS|XPath|strict locator.
* @param value - value to check.
*/
dontSeeInField(field: CodeceptJS.LocatorOrString, value: string): void;
/**
* Opposite to `see`. Checks that a text is not present on a page.
* Use context parameter to narrow down the search.
*
* ```js
* I.dontSee('Login'); // assume we are already logged in.
* I.dontSee('Login', '.nav'); // no login inside .nav element
* ```
* @param text - which is not present.
* @param [context = null] - (optional) element located by CSS|XPath|strict locator in which to perfrom search.
*/
dontSee(text: string, context?: CodeceptJS.LocatorOrString): void;
/**
* Fills a text field or textarea, after clearing its value, with the given string.
* Field is located by name, label, CSS, or XPath.
*
* ```js
* // by label
* I.fillField('Email', 'hello@world.com');
* // by name
* I.fillField('password', secret('123456'));
* // by CSS
* I.fillField('form#login input[name=username]', 'John');
* // or by strict locator
* I.fillField({css: 'form#login input[name=username]'}, 'John');
* ```
* @param field - located by label|name|CSS|XPath|strict locator.
* @param value - text value to fill.
*/
fillField(field: CodeceptJS.LocatorOrString, value: string): 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>;
/**
* 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>;
/**
* Scroll element into viewport.
*
* ```js
* I.scrollIntoView('#submit');
* I.scrollIntoView('#submit', true);
* I.scrollIntoView('#submit', { behavior: "smooth", block: "center", inline: "center" });
* ```
* @param locator - located by CSS|XPath|strict locator.
* @param scrollIntoViewOptions - see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView.
*
*
* Supported only for web testing
*/
scrollIntoView(locator: LocatorOrString, scrollIntoViewOptions: ScrollIntoViewOptions): void;
/**
* Verifies that the specified checkbox is checked.
*
* ```js
* I.seeCheckboxIsChecked('Agree');
* I.seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms
* I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'});
* ```
* @param field - located by label|name|CSS|XPath|strict locator.
*/
seeCheckboxIsChecked(field: CodeceptJS.LocatorOrString): void;
/**
* Checks that a given Element is visible
* Element is located by CSS or XPath.
*
* ```js
* I.seeElement('#modal');
* ```
* @param locator - located by CSS|XPath|strict locator.
*/
seeElement(locator: CodeceptJS.LocatorOrString): void;
/**
* Checks that the given input field or textarea equals to given value.
* For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath.
*
* ```js
* I.seeInField('Username', 'davert');
* I.seeInField({css: 'form textarea'},'Type your comment here');
* I.seeInField('form input[type=hidden]','hidden_value');
* I.seeInField('#searchform input','Search');
* ```
* @param field - located by label|name|CSS|XPath|strict locator.
* @param value - value to check.
*/
seeInField(field: CodeceptJS.LocatorOrString, value: string): void;
/**
* Checks that a page contains a visible text.
* Use context parameter to narrow down the search.
*
* ```js
* I.see('Welcome'); // text welcome on a page
* I.see('Welcome', '.content'); // text inside .content div
* I.see('Register', {css: 'form.register'}); // use strict locator
* ```
* @param text - expected on page.
* @param [context = null] - (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text.
*/
see(text: string, context?: CodeceptJS.LocatorOrString): void;
/**
* Selects an option in a drop-down select.
* Field is searched by label | name | CSS | XPath.
* Option is selected by visible text or by value.
*
* ```js
* I.selectOption('Choose Plan', 'Monthly'); // select by label
* I.selectOption('subscription', 'Monthly'); // match option by text
* I.selectOption('subscription', '0'); // or by value
* I.selectOption('//form/select[@name=account]','Premium');
* I.selectOption('form select[name=account]', 'Premium');
* I.selectOption({css: 'form select[name=account]'}, 'Premium');
* ```
*
* Provide an array for the second argument to select multiple options.
*
* ```js
* I.selectOption('Which OS do you use?', ['Android', 'iOS']);
* ```
* @param select - field located by label|name|CSS|XPath|strict locator.
* @param option - visible text or value of option.
*
*
* Supported only for web testing
*/
selectOption(select: LocatorOrString, option: string | any[]): void;
/**
* Waits for element to be present on page (by default waits for 1sec).
* Element can be located by CSS or XPath.
*
* ```js
* I.waitForElement('.btn.continue');
* I.waitForElement('.btn.continue', 5); // wait for 5 secs
* ```
* @param locator - element located by CSS|XPath|strict locator.
* @param [sec = null] - (optional, `1` by default) time in seconds to wait
*/
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
*/
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
*/
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.
*/
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.json');
* I.seeInThisFile('FileSystem');
* I.dontSeeInThisFile("WebDriverIO");
* ```
*
* ## Methods
*/
class FileSystem {
/**
* Enters a directory In local filesystem.
* Starts from a current directory
*/
amInPath(openPath: string): void;
/**
* Writes test to file
*/
writeToFile(name: string, text: string): void;
/**
* Checks that file exists
*/
seeFile(name: string): void;
/**
* Waits for file to be present in current directory.
*
* ```js
* I.handleDownloads();
* I.click('Download large File');
* I.amInPath('output/downloads');
* I.waitForFile('largeFilesName.txt', 10); // wait 10 seconds for file
* ```
* @param [sec = 1] - seconds to wait
*/
waitForFile(name: string, sec?: number): void;
/**
* Checks that file with a name including given text exists in the current directory.
*
* ```js
* I.handleDownloads();
* I.click('Download as PDF');
* I.amInPath('output/downloads');
* I.seeFileNameMatching('.pdf');
* ```
*/
seeFileNameMatching(): void;
/**
* Checks that file found by `seeFile` includes a text.
*/
seeInThisFile(text: string, encoding?: string): void;
/**
* Checks that file found by `seeFile` doesn't include text.
*/
dontSeeInThisFile(text: string, encoding?: string): void;
/**
* Checks that contents of file found by `seeFile` equal to text.
*/
seeFileContentsEqual(text: string, encoding?: string): void;
/**
* Checks that contents of the file found by `seeFile` equal to contents of the file at `pathToReferenceFile`.
*/
seeFileContentsEqualReferenceFile(pathToReferenceFile: string, encoding?: string, encodingReference?: string): void;
/**
* Checks that contents of file found by `seeFile` doesn't equal to text.
*/
dontSeeFileContentsEqual(text: string, encoding?: string): void;
/**
* Returns file names in current directory.
*
* ```js
* I.handleDownloads();
* I.click('Download Files');
* I.amInPath('output/downloads');
* const downloadedFileNames = I.grabFileNames();
* ```
*/
grabFileNames(): void;
}
function getFileContents(file: string, encoding?: string): string;
function isFileExists(file: string, timeout: number): Promise<any>;
/**
* GraphQL helper allows to send additional requests to a GraphQl endpoint during acceptance tests.
* [Axios](https://github.com/axios/axios) library is used to perform requests.
*
* ## Configuration
*
* * endpoint: GraphQL base URL
* * timeout: timeout for requests in milliseconds. 10000ms by default
* * defaultHeaders: a list of default headers
* * onRequest: a async function which can update request object.
*
* ## Example
*
* ```js
* GraphQL: {
* endpoint: 'http://site.com/graphql/',
* onRequest: (request) => {
* request.headers.auth = '123';
* }
* }
* ```
*
* ## Access From Helpers
*
* Send GraphQL requests by accessing `_executeQuery` method:
*
* ```js
* this.helpers['GraphQL']._executeQuery({
* url,
* data,
* });
* ```
*
* ## Methods
*/
class GraphQL {
/**
* Executes query via axios call
*/
_executeQuery(request: any): void;
/**
* Prepares request for axios call
*/
_prepareGraphQLRequest(operation: any, headers: any): void;
/**
* 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): void;
/**
* 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): void;
}
/**
* 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 --save-dev
* ```
*
* Create a factory file for a resource.
*
* See the example for Users factories:
*
* ```js
* // tests/factories/users.js
*
* var Factory = require('rosie').Factory;
* var faker = require('faker');
*
* // Used with a constructor function passed to Factory, so that the final build
* // object matches the necessary pattern to be sent as the variables object.
* module.exports = new Factory((buildObj) => ({
* input: { ...buildObj },
* }))
* // 'attr'-id can be left out depending on the GraphQl resolvers
* .attr('name', () => faker.name.findName())
* .attr('email', () => faker.interact.email())
* ```
* For more options see [rosie documentation](https://github.com/rosiejs/rosie).
*
* Then configure GraphQLDataHelper to match factories and GraphQL schema:
* ### Configuration
*
* GraphQLDataFactory has following config options:
*
* * `endpoint`: URL for the GraphQL server.
* * `cleanup` (default: true): should inserted records be deleted up after tests
* * `factories`: list of defined factories
* * `headers`: list of headers
* * `GraphQL`: configuration for GraphQL requests.
*
*
* See the example:
*
* ```js
* GraphQLDataFactory: {
* endpoint: "http://user.com/graphql",
* cleanup: true,
* headers: {
* 'Content-Type': 'application/json',
* 'Accept': 'application/json',
* },
* factories: {
* createUser: {
* query: 'mutation createUser($input: UserInput!) { createUser(input: $input) { id name }}',
* factory: './factories/users',
* revert: (data) => ({
* query: 'mutation deleteUser($id: ID!) { deleteUser(id: $id) }',
* variables: { id : data.id},
* }),
* },
* }
* }
* ```
* It is required to set GraphQL `endpoint` which is the URL to which all the queries go to.
* Factory file is expected to be passed via `factory` option.
*
* This Helper uses [GraphQL](http://codecept.io/helpers/GraphQL/) helper and accepts its configuration in "GraphQL" section.
* For instance, to set timeout you should add:
*
* ```js
* "GraphQLDataFactory": {
* "GraphQL": {
* "timeout": "100000",
* }
* }
* ```
*
* ### Factory
*
* Factory contains operations -
*
* * `operation`: The operation/mutation that needs to be performed for creating a record in the backend.
*
* Each operation must have the following:
*
* * `query`: The mutation(query) string. It is expected to use variables to send data with the query.
* * `factory`: The path to factory file. The object built by the factory in this file will be passed
* as the 'variables' object to go along with the mutation.
* * `revert`: A function called with the data returned when an item is created. The object returned by
* this function is will be used to later delete the items created. So, make sure RELEVANT DATA IS RETURNED
* when a record is created by a mutation.
*
* ### Requests
*
* Requests can be updated on the fly by using `onRequest` function. For instance, you can pass in current session from a cookie.
*
* ```js
* onRequest: async (request) => {
* // using global codeceptjs instance
* let cookie = await codeceptjs.container.helpers('WebDriver').grabCookie('session');
* request.headers = { Cookie: `session=${cookie.value}` };
* }
* ```
*
* ### Responses
*
* By default `I.mutateData()` returns a promise with created data as specified in operation query string:
*
* ```js
* let client = await I.mutateData('createClient');
* ```
*
* Data of created records are collected and used in the end of a test for the cleanup.
*
* ## Methods
*/
class GraphQLDataFactory {
/**
* Generates a new record using factory, sends a GraphQL mutation to store it.
*
* ```js
* // create a user
* I.mutateData('createUser');
* // create user with defined email
* // and receive it when inside async function
* const user = await I.mutateData('createUser', { email: 'user@user.com'});
* ```
* @param operation - to be performed
* @param params - predefined parameters
*/
mutateData(operation: string, params: any): void;
/**
* Generates bunch of records and sends multiple GraphQL mutation requests to store them.
*
* ```js
* // crea