From eef33c5fc781fb914650dda3028687456bcfc3ad Mon Sep 17 00:00:00 2001 From: DavertMik Date: Thu, 31 Oct 2024 17:23:07 +0200 Subject: [PATCH 01/37] refactored JSONResponse to not use chai --- lib/helper/ExpectHelper.js | 391 --- lib/helper/JSONResponse.js | 10 +- package.json | 2 +- test/helper/AppiumV2_ios_test.js | 216 +- test/helper/AppiumV2_test.js | 15 +- test/helper/Appium_test.js | 8 +- test/helper/Expect_test.js | 6 +- test/helper/JSONResponse_test.js | 6 +- test/helper/MockServer_test.js | 7 +- test/helper/Playwright_test.js | 9 +- test/helper/Puppeteer_test.js | 1211 +--------- test/helper/SoftExpect_test.js | 6 +- .../helper/WebDriver.noSeleniumServer_test.js | 1302 +--------- test/helper/WebDriver_devtools_test.js | 4 +- test/helper/WebDriver_test.js | 4 +- test/helper/webapi.js | 2149 ++++++++--------- 16 files changed, 1218 insertions(+), 4128 deletions(-) delete mode 100644 lib/helper/ExpectHelper.js diff --git a/lib/helper/ExpectHelper.js b/lib/helper/ExpectHelper.js deleted file mode 100644 index 8d891e0ac..000000000 --- a/lib/helper/ExpectHelper.js +++ /dev/null @@ -1,391 +0,0 @@ -const output = require('../output') - -let expect - -import('chai').then((chai) => { - expect = chai.expect - chai.use(require('chai-string')) - // @ts-ignore - chai.use(require('chai-exclude')) - chai.use(require('chai-match-pattern')) - chai.use(require('chai-json-schema')) -}) - -/** - * 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 { - /** - * - * @param {*} actualValue - * @param {*} expectedValue - * @param {*} [customErrorMsg] - */ - expectEqual(actualValue, expectedValue, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(actualValue)}" to equal "${JSON.stringify(expectedValue)}"`) - return expect(actualValue, customErrorMsg).to.equal(expectedValue) - } - - /** - * - * @param {*} actualValue - * @param {*} expectedValue - * @param {*} [customErrorMsg] - */ - expectNotEqual(actualValue, expectedValue, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(actualValue)}" to not equal "${JSON.stringify(expectedValue)}"`) - return expect(actualValue, customErrorMsg).not.to.equal(expectedValue) - } - - /** - * - * @param {*} actualValue - * @param {*} expectedValue - * @param {*} [customErrorMsg] - - */ - expectDeepEqual(actualValue, expectedValue, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(actualValue)}" to deep equal "${JSON.stringify(expectedValue)}"`) - return expect(actualValue, customErrorMsg).to.deep.equal(expectedValue) - } - - /** - * - * @param {*} actualValue - * @param {*} expectedValue - * @param {*} [customErrorMsg] - */ - expectNotDeepEqual(actualValue, expectedValue, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(actualValue)}" to not deep equal "${JSON.stringify(expectedValue)}"`) - return expect(actualValue, customErrorMsg).to.not.deep.equal(expectedValue) - } - - /** - * - * @param {*} actualValue - * @param {*} expectedValueToContain - * @param {*} [customErrorMsg] - */ - expectContain(actualValue, expectedValueToContain, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(actualValue)}" to contain "${JSON.stringify(expectedValueToContain)}"`) - return expect(actualValue, customErrorMsg).to.contain(expectedValueToContain) - } - - /** - * - * @param {*} actualValue - * @param {*} expectedValueToNotContain - * @param {*} [customErrorMsg] - */ - expectNotContain(actualValue, expectedValueToNotContain, customErrorMsg = '') { - // @ts-ignore - output.step( - `I expect "${JSON.stringify(actualValue)}" to not contain "${JSON.stringify(expectedValueToNotContain)}"`, - ) - return expect(actualValue, customErrorMsg).not.to.contain(expectedValueToNotContain) - } - - /** - * - * @param {*} actualValue - * @param {*} expectedValueToStartWith - * @param {*} [customErrorMsg] - */ - expectStartsWith(actualValue, expectedValueToStartWith, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(actualValue)}" to start with "${JSON.stringify(expectedValueToStartWith)}"`) - return expect(actualValue, customErrorMsg).to.startsWith(expectedValueToStartWith) - } - - /** - * - * @param {*} actualValue - * @param {*} expectedValueToNotStartWith - * @param {*} [customErrorMsg] - */ - expectNotStartsWith(actualValue, expectedValueToNotStartWith, customErrorMsg = '') { - // @ts-ignore - output.step( - `I expect "${JSON.stringify(actualValue)}" to not start with "${JSON.stringify(expectedValueToNotStartWith)}"`, - ) - return expect(actualValue, customErrorMsg).not.to.startsWith(expectedValueToNotStartWith) - } - - /** - * @param {*} actualValue - * @param {*} expectedValueToEndWith - * @param {*} [customErrorMsg] - */ - expectEndsWith(actualValue, expectedValueToEndWith, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(actualValue)}" to end with "${JSON.stringify(expectedValueToEndWith)}"`) - return expect(actualValue, customErrorMsg).to.endsWith(expectedValueToEndWith) - } - - /** - * @param {*} actualValue - * @param {*} expectedValueToNotEndWith - * @param {*} [customErrorMsg] - */ - expectNotEndsWith(actualValue, expectedValueToNotEndWith, customErrorMsg = '') { - // @ts-ignore - output.step( - `I expect "${JSON.stringify(actualValue)}" to not end with "${JSON.stringify(expectedValueToNotEndWith)}"`, - ) - return expect(actualValue, customErrorMsg).not.to.endsWith(expectedValueToNotEndWith) - } - - /** - * @param {*} targetData - * @param {*} jsonSchema - * @param {*} [customErrorMsg] - */ - expectJsonSchema(targetData, jsonSchema, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to match this JSON schema "${JSON.stringify(jsonSchema)}"`) - - return expect(targetData, customErrorMsg).to.be.jsonSchema(jsonSchema) - } - - /** - * @param {*} targetData - * @param {*} jsonSchema - * @param {*} [customErrorMsg] - * @param {*} [ajvOptions] Pass AJV options - */ - expectJsonSchemaUsingAJV(targetData, jsonSchema, customErrorMsg = '', ajvOptions = { allErrors: true }) { - // @ts-ignore - output.step( - `I expect "${JSON.stringify(targetData)}" to match this JSON schema using AJV "${JSON.stringify(jsonSchema)}"`, - ) - chai.use(require('chai-json-schema-ajv').create(ajvOptions)) - return expect(targetData, customErrorMsg).to.be.jsonSchema(jsonSchema) - } - - /** - * @param {*} targetData - * @param {*} propertyName - * @param {*} [customErrorMsg] - */ - expectHasProperty(targetData, propertyName, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to have property: "${JSON.stringify(propertyName)}"`) - return expect(targetData, customErrorMsg).to.have.property(propertyName) - } - - /** - * @param {*} targetData - * @param {*} propertyName - * @param {*} [customErrorMsg] - */ - expectHasAProperty(targetData, propertyName, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to have a property: "${JSON.stringify(propertyName)}"`) - return expect(targetData, customErrorMsg).to.have.a.property(propertyName) - } - - /** - * @param {*} targetData - * @param {*} type - * @param {*} [customErrorMsg] - */ - expectToBeA(targetData, type, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to be a "${JSON.stringify(type)}"`) - return expect(targetData, customErrorMsg).to.be.a(type) - } - - /** - * @param {*} targetData - * @param {*} type - * @param {*} [customErrorMsg] - */ - expectToBeAn(targetData, type, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to be an "${JSON.stringify(type)}"`) - return expect(targetData, customErrorMsg).to.be.an(type) - } - - /** - * @param {*} targetData - * @param {*} regex - * @param {*} [customErrorMsg] - */ - expectMatchRegex(targetData, regex, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to match the regex "${JSON.stringify(regex)}"`) - return expect(targetData, customErrorMsg).to.match(regex) - } - - /** - * @param {*} targetData - * @param {*} length - * @param {*} [customErrorMsg] - */ - expectLengthOf(targetData, length, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to have length of "${JSON.stringify(length)}"`) - return expect(targetData, customErrorMsg).to.have.lengthOf(length) - } - - /** - * @param {*} targetData - * @param {*} [customErrorMsg] - */ - expectEmpty(targetData, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to be empty`) - return expect(targetData, customErrorMsg).to.be.empty - } - - /** - * @param {*} targetData - * @param {*} [customErrorMsg] - */ - expectTrue(targetData, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to be true`) - return expect(targetData, customErrorMsg).to.be.true - } - - /** - * @param {*} targetData - * @param {*} [customErrorMsg] - */ - expectFalse(targetData, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to be false`) - return expect(targetData, customErrorMsg).to.be.false - } - - /** - * @param {*} targetData - * @param {*} aboveThan - * @param {*} [customErrorMsg] - */ - expectAbove(targetData, aboveThan, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to be above ${JSON.stringify(aboveThan)}`) - return expect(targetData, customErrorMsg).to.be.above(aboveThan) - } - - /** - * @param {*} targetData - * @param {*} belowThan - * @param {*} [customErrorMsg] - */ - expectBelow(targetData, belowThan, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to be below ${JSON.stringify(belowThan)}`) - return expect(targetData, customErrorMsg).to.be.below(belowThan) - } - - /** - * @param {*} targetData - * @param {*} lengthAboveThan - * @param {*} [customErrorMsg] - */ - expectLengthAboveThan(targetData, lengthAboveThan, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to have length of above ${JSON.stringify(lengthAboveThan)}`) - return expect(targetData, customErrorMsg).to.have.lengthOf.above(lengthAboveThan) - } - - /** - * @param {*} targetData - * @param {*} lengthBelowThan - * @param {*} [customErrorMsg] - */ - expectLengthBelowThan(targetData, lengthBelowThan, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(targetData)}" to have length of below ${JSON.stringify(lengthBelowThan)}`) - return expect(targetData, customErrorMsg).to.have.lengthOf.below(lengthBelowThan) - } - - /** - * @param {*} actualValue - * @param {*} expectedValue - * @param {*} [customErrorMsg] - */ - expectEqualIgnoreCase(actualValue, expectedValue, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect and ingore case "${JSON.stringify(actualValue)}" to equal "${JSON.stringify(expectedValue)}"`) - return expect(actualValue, customErrorMsg).to.equalIgnoreCase(expectedValue) - } - - /** - * expects members of two arrays are deeply equal - * @param {*} actualValue - * @param {*} expectedValue - * @param {*} [customErrorMsg] - */ - expectDeepMembers(actualValue, expectedValue, customErrorMsg = '') { - // @ts-ignore - output.step( - `I expect members of "${JSON.stringify(actualValue)}" and "${JSON.stringify(expectedValue)}" arrays are deeply equal`, - ) - return expect(actualValue, customErrorMsg).to.have.deep.members(expectedValue) - } - - /** - * expects an array to be a superset of another array - * @param {*} superset - * @param {*} set - * @param {*} [customErrorMsg] - */ - expectDeepIncludeMembers(superset, set, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(superset)}" array to be a superset of "${JSON.stringify(set)}" array`) - return expect(superset, customErrorMsg).to.deep.include.members(set) - } - - /** - * expects members of two JSON objects are deeply equal excluding some properties - * @param {*} actualValue - * @param {*} expectedValue - * @param {*} fieldsToExclude - * @param {*} [customErrorMsg] - */ - expectDeepEqualExcluding(actualValue, expectedValue, fieldsToExclude, customErrorMsg = '') { - // @ts-ignore - output.step( - `I expect members of "${JSON.stringify(actualValue)}" and "${JSON.stringify(expectedValue)}" JSON objects are deeply equal excluding properties: ${JSON.stringify(fieldsToExclude)}`, - ) - return expect(actualValue, customErrorMsg).excludingEvery(fieldsToExclude).to.deep.equal(expectedValue) - } - - /** - * expects a JSON object matches a provided pattern - * @param {*} actualValue - * @param {*} expectedPattern - * @param {*} [customErrorMsg] - */ - expectMatchesPattern(actualValue, expectedPattern, customErrorMsg = '') { - // @ts-ignore - output.step(`I expect "${JSON.stringify(actualValue)}" to match the ${JSON.stringify(expectedPattern)} pattern`) - return expect(actualValue, customErrorMsg).to.matchPattern(expectedPattern) - } -} - -module.exports = ExpectHelper diff --git a/lib/helper/JSONResponse.js b/lib/helper/JSONResponse.js index 765b37fa9..7d6abcd7e 100644 --- a/lib/helper/JSONResponse.js +++ b/lib/helper/JSONResponse.js @@ -1,12 +1,8 @@ const Helper = require('@codeceptjs/helper') -let expect - -import('chai').then((chai) => { - expect = chai.expect - chai.use(require('chai-deep-match')) -}) - +const chai = require('chai') +const expect = chai.expect +chai.use(require('chai-deep-match')) const joi = require('joi') /** diff --git a/package.json b/package.json index 6d6c1573d..451316ed5 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "acorn": "8.14.0", "arrify": "2.0.1", "axios": "1.7.7", - "chai": "5.1.1", + "chai": "^4.0", "chai-deep-match": "1.2.1", "chai-exclude": "2.1.1", "chai-json-schema": "1.5.1", diff --git a/test/helper/AppiumV2_ios_test.js b/test/helper/AppiumV2_ios_test.js index c23b3e423..e00f9aa21 100644 --- a/test/helper/AppiumV2_ios_test.js +++ b/test/helper/AppiumV2_ios_test.js @@ -1,21 +1,23 @@ -const assert = require('assert') -const path = require('path') +const chai = require('chai'); +const expect = chai.expect; +const assert = chai.assert; +const path = require('path'); -const Appium = require('../../lib/helper/Appium') -const AssertionFailedError = require('../../lib/assert/error') -const fileExists = require('../../lib/utils').fileExists -global.codeceptjs = require('../../lib') +const Appium = require('../../lib/helper/Appium'); +const AssertionFailedError = require('../../lib/assert/error'); +const fileExists = require('../../lib/utils').fileExists; +global.codeceptjs = require('../../lib'); -let app +let app; // iOS test app is built from https://github.com/appium/ios-test-app and uploaded to Saucelabs -const apk_path = 'storage:filename=TestApp-iphonesimulator.zip' -const smallWait = 3 +const apk_path = 'storage:filename=TestApp-iphonesimulator.zip'; +const smallWait = 3; describe('Appium iOS Tests', function () { - this.timeout(0) + this.timeout(0); before(async () => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); app = new Appium({ app: apk_path, appiumV2: true, @@ -38,166 +40,166 @@ describe('Appium iOS Tests', function () { port: 80, user: process.env.SAUCE_USERNAME, key: process.env.SAUCE_ACCESS_KEY, - }) - await app._beforeSuite() - app.isWeb = false - await app._before() - }) + }); + await app._beforeSuite(); + app.isWeb = false; + await app._before(); + }); after(async () => { - await app._after() - }) + await app._after(); + }); describe('app installation : #removeApp', () => { describe('#grabAllContexts, #grabContext, #grabOrientation, #grabSettings', () => { it('should grab all available contexts for screen', async () => { - await app.resetApp() - const val = await app.grabAllContexts() - assert.deepEqual(val, ['NATIVE_APP']) - }) + await app.resetApp(); + const val = await app.grabAllContexts(); + assert.deepEqual(val, ['NATIVE_APP']); + }); it('should grab current context', async () => { - const val = await app.grabContext() - assert.equal(val, 'NATIVE_APP') - }) + const val = await app.grabContext(); + assert.equal(val, 'NATIVE_APP'); + }); it('should grab custom settings', async () => { - const val = await app.grabSettings() - assert.deepEqual(val, { imageElementTapStrategy: 'w3cActions' }) - }) - }) - }) + const val = await app.grabSettings(); + assert.deepEqual(val, { imageElementTapStrategy: 'w3cActions' }); + }); + }); + }); describe('device orientation : #seeOrientationIs #setOrientation', () => { it('should return correct status about device orientation', async () => { - await app.seeOrientationIs('PORTRAIT') + await app.seeOrientationIs('PORTRAIT'); try { - await app.seeOrientationIs('LANDSCAPE') + await app.seeOrientationIs('LANDSCAPE'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected orientation to be LANDSCAPE') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('expected orientation to be LANDSCAPE'); } - }) - }) + }); + }); describe('#hideDeviceKeyboard', () => { it('should hide device Keyboard @quick', async () => { - await app.resetApp() - await app.click('~IntegerA') + await app.resetApp(); + await app.click('~IntegerA'); try { - await app.click('~locationStatus') + await app.click('~locationStatus'); } catch (e) { - e.message.should.include('element') + e.message.should.include('element'); } - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.click('~locationStatus') - }) + await app.hideDeviceKeyboard('pressKey', 'Done'); + await app.click('~locationStatus'); + }); it('should assert if no keyboard', async () => { try { - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.hideDeviceKeyboard('pressKey', 'Done'); } catch (e) { e.message.should.include( 'An unknown server-side error occurred while processing the command. Original error: Soft keyboard not present, cannot hide keyboard', - ) + ); } - }) - }) + }); + }); describe('see text : #see', () => { it('should work inside elements @second', async () => { - await app.resetApp() - await app.see('Compute Sum', '~ComputeSumButton') - }) - }) + await app.resetApp(); + await app.see('Compute Sum', '~ComputeSumButton'); + }); + }); describe('#appendField', () => { it('should be able to send special keys to element @second', async () => { - await app.resetApp() - await app.waitForElement('~IntegerA', smallWait) - await app.click('~IntegerA') - await app.appendField('~IntegerA', '1') - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.see('1', '~IntegerA') - }) - }) + await app.resetApp(); + await app.waitForElement('~IntegerA', smallWait); + await app.click('~IntegerA'); + await app.appendField('~IntegerA', '1'); + await app.hideDeviceKeyboard('pressKey', 'Done'); + await app.see('1', '~IntegerA'); + }); + }); describe('#waitForText', () => { it('should return error if not present', async () => { try { - await app.waitForText('Nothing here', 1, '~IntegerA') + await app.waitForText('Nothing here', 1, '~IntegerA'); } catch (e) { e.message.should.contain( 'element (~IntegerA) is not in DOM or there is no element(~IntegerA) with text "Nothing here" after 1 sec', - ) + ); } - }) - }) + }); + }); describe('#seeNumberOfElements @second', () => { it('should return 1 as count', async () => { - await app.resetApp() - await app.seeNumberOfElements('~IntegerA', 1) - }) - }) + await app.resetApp(); + await app.seeNumberOfElements('~IntegerA', 1); + }); + }); describe('see element : #seeElement, #dontSeeElement', () => { it('should check visible elements on page @quick', async () => { - await app.resetApp() - await app.seeElement('~IntegerA') - await app.dontSeeElement('#something-beyond') - await app.dontSeeElement('//input[@id="something-beyond"]') - }) - }) + await app.resetApp(); + await app.seeElement('~IntegerA'); + await app.dontSeeElement('#something-beyond'); + await app.dontSeeElement('//input[@id="something-beyond"]'); + }); + }); describe('#click @quick', () => { it('should click by accessibility id', async () => { - await app.resetApp() - await app.tap('~ComputeSumButton') - await app.see('0') - }) - }) + await app.resetApp(); + await app.tap('~ComputeSumButton'); + await app.see('0'); + }); + }); describe('#fillField @second', () => { it('should fill field by accessibility id', async () => { - await app.resetApp() - await app.waitForElement('~IntegerA', smallWait) - await app.click('~IntegerA') - await app.fillField('~IntegerA', '1') - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.see('1', '~IntegerA') - }) - }) + await app.resetApp(); + await app.waitForElement('~IntegerA', smallWait); + await app.click('~IntegerA'); + await app.fillField('~IntegerA', '1'); + await app.hideDeviceKeyboard('pressKey', 'Done'); + await app.see('1', '~IntegerA'); + }); + }); describe('#grabTextFrom, #grabValueFrom, #grabAttributeFrom @quick', () => { it('should grab text from page', async () => { - await app.resetApp() - const val = await app.grabTextFrom('~ComputeSumButton') - assert.equal(val, 'Compute Sum') - }) + await app.resetApp(); + const val = await app.grabTextFrom('~ComputeSumButton'); + assert.equal(val, 'Compute Sum'); + }); it('should grab attribute from element', async () => { - await app.resetApp() - const val = await app.grabAttributeFrom('~ComputeSumButton', 'label') - assert.equal(val, 'Compute Sum') - }) + await app.resetApp(); + const val = await app.grabAttributeFrom('~ComputeSumButton', 'label'); + assert.equal(val, 'Compute Sum'); + }); it('should be able to grab elements', async () => { - await app.resetApp() - const id = await app.grabNumberOfVisibleElements('~ComputeSumButton') - assert.strictEqual(1, id) - }) - }) + await app.resetApp(); + const id = await app.grabNumberOfVisibleElements('~ComputeSumButton'); + assert.strictEqual(1, id); + }); + }); describe('#saveScreenshot', () => { beforeEach(() => { - global.output_dir = path.join(global.codecept_dir, 'output') - }) + global.output_dir = path.join(global.codecept_dir, 'output'); + }); it('should create a screenshot file in output dir', async () => { - const sec = new Date().getUTCMilliseconds() - await app.saveScreenshot(`screenshot_${sec}.png`) - assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists') - }) - }) -}) + const sec = new Date().getUTCMilliseconds(); + await app.saveScreenshot(`screenshot_${sec}.png`); + assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists'); + }); + }); +}); diff --git a/test/helper/AppiumV2_test.js b/test/helper/AppiumV2_test.js index 15e22c9f4..aaa1d6d59 100644 --- a/test/helper/AppiumV2_test.js +++ b/test/helper/AppiumV2_test.js @@ -1,15 +1,6 @@ -const assert = require('assert') - -let expect -import('chai').then((chai) => { - expect = chai.expect -}) -const path = require('path') - -const Appium = require('../../lib/helper/Appium') -const AssertionFailedError = require('../../lib/assert/error') -const fileExists = require('../../lib/utils').fileExists -global.codeceptjs = require('../../lib') +const chai = require('chai'); +const expect = chai.expect; +const assert = chai.assert; let app const apk_path = 'storage:filename=selendroid-test-app-0.17.0.apk' diff --git a/test/helper/Appium_test.js b/test/helper/Appium_test.js index 58ec776ec..660dfd02e 100644 --- a/test/helper/Appium_test.js +++ b/test/helper/Appium_test.js @@ -1,9 +1,7 @@ -const assert = require('assert') +const chai = require('chai'); +const expect = chai.expect; +const assert = chai.assert; -let expect -import('chai').then((chai) => { - expect = chai.expect -}) const path = require('path') const Appium = require('../../lib/helper/Appium') diff --git a/test/helper/Expect_test.js b/test/helper/Expect_test.js index 80d510834..919a5d8ca 100644 --- a/test/helper/Expect_test.js +++ b/test/helper/Expect_test.js @@ -1,9 +1,7 @@ const path = require('path') -let expect -import('chai').then((chai) => { - expect = chai.expect -}) +const chai = require('chai'); +const expect = chai.expect; const ExpectHelper = require('../../lib/helper/ExpectHelper') diff --git a/test/helper/JSONResponse_test.js b/test/helper/JSONResponse_test.js index 14e8f7d96..0fd19b194 100644 --- a/test/helper/JSONResponse_test.js +++ b/test/helper/JSONResponse_test.js @@ -1,7 +1,5 @@ -let expect -import('chai').then((chai) => { - expect = chai.expect -}) +const chai = require('chai'); +const expect = chai.expect; const joi = require('joi') const JSONResponse = require('../../lib/helper/JSONResponse') const Container = require('../../lib/container') diff --git a/test/helper/MockServer_test.js b/test/helper/MockServer_test.js index 1faa6af4e..27704a776 100644 --- a/test/helper/MockServer_test.js +++ b/test/helper/MockServer_test.js @@ -1,9 +1,8 @@ const path = require('path') -let expect -import('chai').then((chai) => { - expect = chai.expect -}) +const chai = require('chai'); +const expect = chai.expect; + const { like } = require('pactum-matchers') const MockServer = require('../../lib/helper/MockServer') const REST = require('../../lib/helper/REST') diff --git a/test/helper/Playwright_test.js b/test/helper/Playwright_test.js index d36bd4347..8b542e6b7 100644 --- a/test/helper/Playwright_test.js +++ b/test/helper/Playwright_test.js @@ -1,9 +1,6 @@ -let assert -let expect -import('chai').then((chai) => { - assert = chai.assert - expect = chai.expect -}) +const chai = require('chai'); +const assert = chai.assert; +const expect = chai.expect; const path = require('path') const fs = require('fs') diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js index 9d3ff1aca..de452efe3 100644 --- a/test/helper/Puppeteer_test.js +++ b/test/helper/Puppeteer_test.js @@ -1,1208 +1,5 @@ -let expect -let assert -import('chai').then((chai) => { - expect = chai.expect - assert = chai.assert -}) -const path = require('path') +const chai = require('chai'); +const expect = chai.expect; +const assert = chai.assert; -const puppeteer = require('puppeteer') - -const fs = require('fs') -const TestHelper = require('../support/TestHelper') -const Puppeteer = require('../../lib/helper/Puppeteer') - -const AssertionFailedError = require('../../lib/assert/error') -const webApiTests = require('./webapi') -const Secret = require('../../lib/secret') -const { deleteDir } = require('../../lib/utils') -global.codeceptjs = require('../../lib') - -let I -let browser -let page -let FS -const siteUrl = TestHelper.siteUrl() - -describe('Puppeteer - BasicAuth', function () { - this.timeout(10000) - - before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - - I = new Puppeteer({ - url: siteUrl, - windowSize: '500x700', - show: false, - waitForTimeout: 5000, - waitForAction: 500, - chrome: { - args: ['--no-sandbox', '--disable-setuid-sandbox'], - }, - defaultPopupAction: 'accept', - basicAuth: { username: 'admin', password: 'admin' }, - }) - I._init() - return I._beforeSuite() - }) - - beforeEach(() => { - webApiTests.init({ - I, - siteUrl, - }) - return I._before().then(() => { - page = I.page - browser = I.browser - }) - }) - - afterEach(() => { - return I._after() - }) - - describe('open page with provided basic auth', () => { - it('should be authenticated ', async () => { - await I.amOnPage('/basic_auth') - await I.see('You entered admin as your password.') - }) - it('should be authenticated on second run', async () => { - await I.amOnPage('/basic_auth') - await I.see('You entered admin as your password.') - }) - }) -}) - -describe('Puppeteer', function () { - this.timeout(35000) - this.retries(1) - - before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - - I = new Puppeteer({ - url: siteUrl, - windowSize: '500x700', - show: false, - waitForTimeout: 5000, - waitForAction: 500, - chrome: { - args: ['--no-sandbox', '--disable-setuid-sandbox'], - }, - defaultPopupAction: 'accept', - }) - I._init() - return I._beforeSuite() - }) - - beforeEach(() => { - webApiTests.init({ - I, - siteUrl, - }) - return I._before().then(() => { - page = I.page - browser = I.browser - }) - }) - - afterEach(() => { - return I._after() - }) - - describe('Session', () => { - it('should not fail for localStorage.clear() on about:blank', async () => { - I.options.restart = false - return I.page - .goto('about:blank') - .then(() => I._after()) - .then(() => { - I.options.restart = true - }) - .catch((e) => { - I.options.restart = true - throw new Error(e) - }) - }) - }) - - describe('open page : #amOnPage', () => { - it('should open main page of configured site', async () => { - await I.amOnPage('/') - const url = await page.url() - await url.should.eql(`${siteUrl}/`) - }) - it('should open any page of configured site', async () => { - await I.amOnPage('/info') - const url = await page.url() - return url.should.eql(`${siteUrl}/info`) - }) - - it('should open absolute url', async () => { - await I.amOnPage(siteUrl) - const url = await page.url() - return url.should.eql(`${siteUrl}/`) - }) - - it('should be unauthenticated ', async () => { - try { - await I.amOnPage('/basic_auth') - await I.dontSee('You entered admin as your password.') - } catch (e) { - expect(e.message).to.eq('net::ERR_INVALID_AUTH_CREDENTIALS at http://localhost:8000/basic_auth') - } - }) - }) - - describe('grabDataFromPerformanceTiming', () => { - it('should return data from performance timing', async () => { - await I.amOnPage('/') - const res = await I.grabDataFromPerformanceTiming() - expect(res).to.have.property('responseEnd') - expect(res).to.have.property('domInteractive') - expect(res).to.have.property('domContentLoadedEventEnd') - expect(res).to.have.property('loadEventEnd') - }) - }) - - webApiTests.tests() - - describe('#waitForFunction', () => { - it('should wait for function returns true', () => { - return I.amOnPage('/form/wait_js').then(() => I.waitForFunction(() => window.__waitJs, 3)) - }) - - it('should pass arguments and wait for function returns true', () => { - return I.amOnPage('/form/wait_js').then(() => I.waitForFunction((varName) => window[varName], ['__waitJs'], 3)) - }) - }) - - describe('#waitToHide', () => { - it('should wait for hidden element', () => { - return I.amOnPage('/form/wait_invisible') - .then(() => I.see('Step One Button')) - .then(() => I.waitToHide('#step_1', 2)) - .then(() => I.dontSeeElement('#step_1')) - .then(() => I.dontSee('Step One Button')) - }) - - it('should wait for hidden element by XPath', () => { - return I.amOnPage('/form/wait_invisible') - .then(() => I.see('Step One Button')) - .then(() => I.waitToHide('//div[@id="step_1"]', 2)) - .then(() => I.dontSeeElement('//div[@id="step_1"]')) - .then(() => I.dontSee('Step One Button')) - }) - }) - - describe('#waitNumberOfVisibleElements', () => { - it('should wait for a specified number of elements on the page', async () => { - try { - await I.amOnPage('/info') - await I.waitNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 3) - } catch (e) { - e.message.should.include('The number of elements (//div[@id = "grab-multiple"]//a) is not 2 after 0.1 sec') - } - }) - - it('should wait for a specified number of elements on the page using a css selector', () => - I.amOnPage('/info') - .then(() => I.waitNumberOfVisibleElements('#grab-multiple > a', 3)) - .then(() => I.waitNumberOfVisibleElements('#grab-multiple > a', 2, 0.1)) - .then(() => { - throw Error('It should never get this far') - }) - .catch((e) => { - e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec') - })) - - it('should wait for a specified number of elements which are not yet attached to the DOM', () => - I.amOnPage('/form/wait_num_elements') - .then(() => I.waitNumberOfVisibleElements('.title', 2, 3)) - .then(() => I.see('Hello')) - .then(() => I.see('World'))) - - it('should wait for 0 number of visible elements', async () => { - await I.amOnPage('/form/wait_invisible') - await I.waitNumberOfVisibleElements('#step_1', 0) - }) - }) - - describe('#moveCursorTo', () => { - it('should trigger hover event', () => - I.amOnPage('/form/hover') - .then(() => I.moveCursorTo('#hover')) - .then(() => I.see('Hovered', '#show'))) - - it('should not trigger hover event because of the offset is beyond the element', () => - I.amOnPage('/form/hover') - .then(() => I.moveCursorTo('#hover', 100, 100)) - .then(() => I.dontSee('Hovered', '#show'))) - }) - - describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs, #grabNumberOfOpenTabs, #waitForNumberOfTabs', () => { - it('should only have 1 tab open when the browser starts and navigates to the first page', () => - I.amOnPage('/') - .then(() => I.wait(1)) - .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(1))) - - it('should switch to next tab', () => - I.amOnPage('/info') - .then(() => I.wait(1)) - .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(1)) - .then(() => I.click('New tab')) - .then(() => I.switchToNextTab()) - .then(() => I.waitForNumberOfTabs(2)) - .then(() => I.seeCurrentUrlEquals('/login')) - .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(2))) - - it('should assert when there is no ability to switch to next tab', () => - I.amOnPage('/') - .then(() => I.click('More info')) - .then(() => I.wait(1)) // Wait is required because the url is change by previous statement (maybe related to #914) - .then(() => I.switchToNextTab(2)) - .then(() => I.wait(2)) - .then(() => expect(true, 'Throw an error if it gets this far (which it should not)!').to.eq(false)) - .catch((e) => { - expect(e.message).to.eq('There is no ability to switch to next tab with offset 2') - })) - - it('should close current tab', () => - I.amOnPage('/info') - .then(() => I.click('New tab')) - .then(() => I.switchToNextTab()) - .then(() => I.wait(2)) - .then(() => I.seeInCurrentUrl('/login')) - .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(2)) - .then(() => I.closeCurrentTab()) - .then(() => I.wait(1)) - .then(() => I.seeInCurrentUrl('/info')) - .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(1))) - - it('should close other tabs', () => - I.amOnPage('/') - .then(() => I.openNewTab()) - .then(() => I.wait(1)) - .then(() => I.seeInCurrentUrl('about:blank')) - .then(() => I.amOnPage('/info')) - .then(() => I.click('New tab')) - .then(() => I.switchToNextTab()) - .then(() => I.wait(2)) - .then(() => I.seeInCurrentUrl('/login')) - .then(() => I.closeOtherTabs()) - .then(() => I.wait(1)) - .then(() => I.seeInCurrentUrl('/login')) - .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(1))) - - it('should open new tab', () => - I.amOnPage('/info') - .then(() => I.openNewTab()) - .then(() => I.wait(1)) - .then(() => I.seeInCurrentUrl('about:blank')) - .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(2))) - - it('should switch to previous tab', () => - I.amOnPage('/info') - .then(() => I.openNewTab()) - .then(() => I.wait(1)) - .then(() => I.seeInCurrentUrl('about:blank')) - .then(() => I.switchToPreviousTab()) - .then(() => I.wait(2)) - .then(() => I.seeInCurrentUrl('/info'))) - - it('should assert when there is no ability to switch to previous tab', () => - I.amOnPage('/info') - .then(() => I.openNewTab()) - .then(() => I.wait(1)) - .then(() => I.waitInUrl('about:blank')) - .then(() => I.switchToPreviousTab(2)) - .then(() => I.wait(2)) - .then(() => I.waitInUrl('/info')) - .catch((e) => { - expect(e.message).to.eq('There is no ability to switch to previous tab with offset 2') - })) - }) - - describe('popup : #acceptPopup, #seeInPopup, #cancelPopup, #grabPopupText', () => { - it('should accept popup window', () => - I.amOnPage('/form/popup') - .then(() => I.amAcceptingPopups()) - .then(() => I.click('Confirm')) - .then(() => I.acceptPopup()) - .then(() => I.see('Yes', '#result'))) - - it('should accept popup window (using default popup action type)', () => - I.amOnPage('/form/popup') - .then(() => I.click('Confirm')) - .then(() => I.acceptPopup()) - .then(() => I.see('Yes', '#result'))) - - it('should cancel popup', () => - I.amOnPage('/form/popup') - .then(() => I.amCancellingPopups()) - .then(() => I.click('Confirm')) - .then(() => I.cancelPopup()) - .then(() => I.see('No', '#result'))) - - it('should check text in popup', () => - I.amOnPage('/form/popup') - .then(() => I.amCancellingPopups()) - .then(() => I.click('Alert')) - .then(() => I.seeInPopup('Really?')) - .then(() => I.cancelPopup())) - - it('should grab text from popup', () => - I.amOnPage('/form/popup') - .then(() => I.amCancellingPopups()) - .then(() => I.click('Alert')) - .then(() => I.grabPopupText()) - .then((text) => assert.equal(text, 'Really?'))) - - it('should return null if no popup is visible (do not throw an error)', () => - I.amOnPage('/form/popup') - .then(() => I.grabPopupText()) - .then((text) => assert.equal(text, null))) - }) - - describe('#seeNumberOfElements', () => { - it('should return 1 as count', () => I.amOnPage('/').then(() => I.seeNumberOfElements('#area1', 1))) - }) - - describe('#switchTo', () => { - it('should switch reference to iframe content', () => - I.amOnPage('/iframe') - .then(() => I.switchTo('[name="content"]')) - .then(() => I.see('Information')) - .then(() => I.see('Lots of valuable data here'))) - - it('should return error if iframe selector is invalid', () => - I.amOnPage('/iframe') - .then(() => I.switchTo('#invalidIframeSelector')) - .catch((e) => { - e.should.be.instanceOf(Error) - e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath') - })) - - it('should return error if iframe selector is not iframe', () => - I.amOnPage('/iframe') - .then(() => I.switchTo('h1')) - .catch((e) => { - e.should.be.instanceOf(Error) - e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath') - })) - - it('should return to parent frame given a null locator', () => - I.amOnPage('/iframe') - .then(() => I.switchTo('[name="content"]')) - .then(() => I.see('Information')) - .then(() => I.see('Lots of valuable data here')) - .then(() => I.switchTo(null)) - .then(() => I.see('Iframe test'))) - }) - - describe('#seeInSource, #grabSource', () => { - it('should check for text to be in HTML source', () => - I.amOnPage('/') - .then(() => I.seeInSource('TestEd Beta 2.0')) - .then(() => I.dontSeeInSource(' - I.amOnPage('/') - .then(() => I.grabSource()) - .then((source) => - assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved'), - )) - }) - - describe('#seeTitleEquals', () => { - it('should check that title is equal to provided one', () => - I.amOnPage('/') - .then(() => I.seeTitleEquals('TestEd Beta 2.0')) - .then(() => I.seeTitleEquals('TestEd Beta 2.')) - .then(() => assert.equal(true, false, 'Throw an error because it should not get this far!')) - .catch((e) => { - e.should.be.instanceOf(Error) - e.message.should.be.equal('expected web page title "TestEd Beta 2.0" to equal "TestEd Beta 2."') - })) - }) - - describe('#seeTextEquals', () => { - it('should check text is equal to provided one', () => - I.amOnPage('/') - .then(() => I.seeTextEquals('Welcome to test app!', 'h1')) - .then(() => I.seeTextEquals('Welcome to test app', 'h1')) - .then(() => assert.equal(true, false, 'Throw an error because it should not get this far!')) - .catch((e) => { - e.should.be.instanceOf(Error) - e.message.should.be.equal('expected element h1 "Welcome to test app" to equal "Welcome to test app!"') - })) - }) - - describe('#_locateClickable', () => { - it('should locate a button to click', () => - I.amOnPage('/form/checkbox') - .then(() => I._locateClickable('Submit')) - .then((res) => { - res.length.should.be.equal(1) - })) - - it('should not locate a non-existing checkbox using _locateClickable', () => - I.amOnPage('/form/checkbox') - .then(() => I._locateClickable('I disagree')) - .then((res) => res.length.should.be.equal(0))) - }) - - describe('#_locateCheckable', () => { - it('should locate a checkbox', () => - I.amOnPage('/form/checkbox') - .then(() => I._locateCheckable('I Agree')) - .then((res) => res.should.be.ok)) - }) - - describe('#_locateFields', () => { - it('should locate a field', () => - I.amOnPage('/form/field') - .then(() => I._locateFields('Name')) - .then((res) => res.length.should.be.equal(1))) - - it('should not locate a non-existing field', () => - I.amOnPage('/form/field') - .then(() => I._locateFields('Mother-in-law')) - .then((res) => res.length.should.be.equal(0))) - }) - - describe('check fields: #seeInField, #seeCheckboxIsChecked, ...', () => { - it('should throw error if field is not empty', () => - I.amOnPage('/form/empty') - .then(() => I.seeInField('#empty_input', 'Ayayay')) - .catch((e) => { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.be.equal('expected fields by #empty_input to include "Ayayay"') - })) - - it('should check values in checkboxes', async () => { - await I.amOnPage('/form/field_values') - await I.dontSeeInField('checkbox[]', 'not seen one') - await I.seeInField('checkbox[]', 'see test one') - await I.dontSeeInField('checkbox[]', 'not seen two') - await I.seeInField('checkbox[]', 'see test two') - await I.dontSeeInField('checkbox[]', 'not seen three') - await I.seeInField('checkbox[]', 'see test three') - }) - - it('should check values are the secret type in checkboxes', async () => { - await I.amOnPage('/form/field_values') - await I.dontSeeInField('checkbox[]', Secret.secret('not seen one')) - await I.seeInField('checkbox[]', Secret.secret('see test one')) - await I.dontSeeInField('checkbox[]', Secret.secret('not seen two')) - await I.seeInField('checkbox[]', Secret.secret('see test two')) - await I.dontSeeInField('checkbox[]', Secret.secret('not seen three')) - await I.seeInField('checkbox[]', Secret.secret('see test three')) - }) - - it('should check values with boolean', async () => { - await I.amOnPage('/form/field_values') - await I.seeInField('checkbox1', true) - await I.dontSeeInField('checkbox1', false) - await I.seeInField('checkbox2', false) - await I.dontSeeInField('checkbox2', true) - await I.seeInField('radio2', true) - await I.dontSeeInField('radio2', false) - await I.seeInField('radio3', false) - await I.dontSeeInField('radio3', true) - }) - - it('should check values in radio', async () => { - await I.amOnPage('/form/field_values') - await I.seeInField('radio1', 'see test one') - await I.dontSeeInField('radio1', 'not seen one') - await I.dontSeeInField('radio1', 'not seen two') - await I.dontSeeInField('radio1', 'not seen three') - }) - - it('should check values in select', async () => { - await I.amOnPage('/form/field_values') - await I.seeInField('select1', 'see test one') - await I.dontSeeInField('select1', 'not seen one') - await I.dontSeeInField('select1', 'not seen two') - await I.dontSeeInField('select1', 'not seen three') - }) - - it('should check for empty select field', async () => { - await I.amOnPage('/form/field_values') - await I.seeInField('select3', '') - }) - - it('should check for select multiple field', async () => { - await I.amOnPage('/form/field_values') - await I.dontSeeInField('select2', 'not seen one') - await I.seeInField('select2', 'see test one') - await I.dontSeeInField('select2', 'not seen two') - await I.seeInField('select2', 'see test two') - await I.dontSeeInField('select2', 'not seen three') - await I.seeInField('select2', 'see test three') - }) - }) - - describe('#pressKey, #pressKeyDown, #pressKeyUp', () => { - it('should be able to send special keys to element', async () => { - await I.amOnPage('/form/field') - await I.appendField('Name', '-') - - await I.pressKey(['Right Shift', 'Home']) - await I.pressKey('Delete') - - // Sequence only executes up to first non-modifier key ('Digit1') - await I.pressKey(['SHIFT_RIGHT', 'Digit1', 'Digit4']) - await I.pressKey('1') - await I.pressKey('2') - await I.pressKey('3') - await I.pressKey('ArrowLeft') - await I.pressKey('Left Arrow') - await I.pressKey('arrow_left') - await I.pressKeyDown('Shift') - await I.pressKey('a') - await I.pressKey('KeyB') - await I.pressKeyUp('ShiftLeft') - await I.pressKey('C') - await I.seeInField('Name', '!ABC123') - }) - - it('should use modifier key based on operating system', async () => { - await I.amOnPage('/form/field') - await I.fillField('Name', 'value that is cleared using select all shortcut') - - await I.pressKey(['ControlOrCommand', 'a']) - await I.pressKey('Backspace') - await I.dontSeeInField('Name', 'value that is cleared using select all shortcut') - }) - - it('should show correct numpad or punctuation key when Shift modifier is active', async () => { - await I.amOnPage('/form/field') - await I.fillField('Name', '') - - await I.pressKey(';') - await I.pressKey(['Shift', ';']) - await I.pressKey(['Shift', 'Semicolon']) - await I.pressKey('=') - await I.pressKey(['Shift', '=']) - await I.pressKey(['Shift', 'Equal']) - await I.pressKey('*') - await I.pressKey(['Shift', '*']) - await I.pressKey(['Shift', 'Multiply']) - await I.pressKey('+') - await I.pressKey(['Shift', '+']) - await I.pressKey(['Shift', 'Add']) - await I.pressKey(',') - await I.pressKey(['Shift', ',']) - await I.pressKey(['Shift', 'Comma']) - await I.pressKey(['Shift', 'NumpadComma']) - await I.pressKey(['Shift', 'Separator']) - await I.pressKey('-') - await I.pressKey(['Shift', '-']) - await I.pressKey(['Shift', 'Subtract']) - await I.pressKey('.') - await I.pressKey(['Shift', '.']) - await I.pressKey(['Shift', 'Decimal']) - await I.pressKey(['Shift', 'Period']) - await I.pressKey('/') - await I.pressKey(['Shift', '/']) - await I.pressKey(['Shift', 'Divide']) - await I.pressKey(['Shift', 'Slash']) - - await I.seeInField('Name', ';::=++***+++,<<<<-_-.>.>/?/?') - }) - - it('should show correct number key when Shift modifier is active', async () => { - await I.amOnPage('/form/field') - await I.fillField('Name', '') - - await I.pressKey('0') - await I.pressKeyDown('Shift') - await I.pressKey('0') - await I.pressKey('Digit0') - await I.pressKey('Numpad0') - await I.pressKeyUp('Shift') - - await I.pressKey('1') - await I.pressKeyDown('Shift') - await I.pressKey('1') - await I.pressKey('Digit1') - await I.pressKey('Numpad1') - await I.pressKeyUp('Shift') - - await I.pressKey('2') - await I.pressKeyDown('Shift') - await I.pressKey('2') - await I.pressKey('Digit2') - await I.pressKey('Numpad2') - await I.pressKeyUp('Shift') - - await I.pressKey('3') - await I.pressKeyDown('Shift') - await I.pressKey('3') - await I.pressKey('Digit3') - await I.pressKey('Numpad3') - await I.pressKeyUp('Shift') - - await I.pressKey('4') - await I.pressKeyDown('Shift') - await I.pressKey('4') - await I.pressKey('Digit4') - await I.pressKey('Numpad4') - await I.pressKeyUp('Shift') - - await I.pressKey('5') - await I.pressKeyDown('Shift') - await I.pressKey('5') - await I.pressKey('Digit5') - await I.pressKey('Numpad5') - await I.pressKeyUp('Shift') - - await I.pressKey('6') - await I.pressKeyDown('Shift') - await I.pressKey('6') - await I.pressKey('Digit6') - await I.pressKey('Numpad6') - await I.pressKeyUp('Shift') - - await I.pressKey('7') - await I.pressKeyDown('Shift') - await I.pressKey('7') - await I.pressKey('Digit7') - await I.pressKey('Numpad7') - await I.pressKeyUp('Shift') - - await I.pressKey('8') - await I.pressKeyDown('Shift') - await I.pressKey('8') - await I.pressKey('Digit8') - await I.pressKey('Numpad8') - await I.pressKeyUp('Shift') - - await I.pressKey('9') - await I.pressKeyDown('Shift') - await I.pressKey('9') - await I.pressKey('Digit9') - await I.pressKey('Numpad9') - await I.pressKeyUp('Shift') - - await I.seeInField('Name', '0))01!!12@@23##34$$45%%56^^67&&78**89((9') - }) - }) - - describe('#waitForEnabled', () => { - it('should wait for input text field to be enabled', () => - I.amOnPage('/form/wait_enabled') - .then(() => I.waitForEnabled('#text', 2)) - .then(() => I.fillField('#text', 'hello world')) - .then(() => I.seeInField('#text', 'hello world'))) - - it('should wait for input text field to be enabled by xpath', () => - I.amOnPage('/form/wait_enabled') - .then(() => I.waitForEnabled("//*[@name = 'test']", 2)) - .then(() => I.fillField('#text', 'hello world')) - .then(() => I.seeInField('#text', 'hello world'))) - - it('should wait for a button to be enabled', () => - I.amOnPage('/form/wait_enabled') - .then(() => I.waitForEnabled('#text', 2)) - .then(() => I.click('#button')) - .then(() => I.see('button was clicked', '#message'))) - }) - - describe('#waitForText', () => { - it('should wait for text after load body', async () => { - await I.amOnPage('/redirect_long') - await I.waitForText('Hi there and greetings!', 5) - }) - }) - - describe('#waitForValue', () => { - it('should wait for expected value for given locator', () => - I.amOnPage('/info') - .then(() => I.waitForValue('//input[@name= "rus"]', 'Верно')) - .then(() => I.waitForValue('//input[@name= "rus"]', 'Верно3', 0.1)) - .then(() => { - throw Error('It should never get this far') - }) - .catch((e) => { - e.message.should.include( - 'element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec', - ) - })) - - it('should wait for expected value for given css locator', () => - I.amOnPage('/form/wait_value') - .then(() => I.seeInField('#text', 'Hamburg')) - .then(() => I.waitForValue('#text', 'Brisbane', 2.5)) - .then(() => I.seeInField('#text', 'Brisbane'))) - - it('should wait for expected value for given xpath locator', () => - I.amOnPage('/form/wait_value') - .then(() => I.seeInField('#text', 'Hamburg')) - .then(() => I.waitForValue('//input[@value = "Grüße aus Hamburg"]', 'Brisbane', 2.5)) - .then(() => I.seeInField('#text', 'Brisbane'))) - - it('should only wait for one of the matching elements to contain the value given xpath locator', () => - I.amOnPage('/form/wait_value') - .then(() => I.waitForValue('//input[@type = "text"]', 'Brisbane', 4)) - .then(() => I.seeInField('#text', 'Brisbane')) - .then(() => I.seeInField('#text2', 'London'))) - - it('should only wait for one of the matching elements to contain the value given css locator', () => - I.amOnPage('/form/wait_value') - .then(() => I.waitForValue('.inputbox', 'Brisbane', 4)) - .then(() => I.seeInField('#text', 'Brisbane')) - .then(() => I.seeInField('#text2', 'London'))) - }) - - describe('#grabHTMLFrom', () => { - it('should grab inner html from an element using xpath query', () => - I.amOnPage('/') - .then(() => I.grabHTMLFrom('//title')) - .then((html) => assert.equal(html, 'TestEd Beta 2.0'))) - - it('should grab inner html from an element using id query', () => - I.amOnPage('/') - .then(() => I.grabHTMLFrom('#area1')) - .then((html) => assert.equal(html.trim(), ' Test Link '))) - - it('should grab inner html from multiple elements', () => - I.amOnPage('/') - .then(() => I.grabHTMLFromAll('//a')) - .then((html) => assert.equal(html.length, 5))) - - it('should grab inner html from within an iframe', () => - I.amOnPage('/iframe') - .then(() => I.switchTo({ frame: 'iframe' })) - .then(() => I.grabHTMLFrom('#new-tab')) - .then((html) => assert.equal(html.trim(), 'New tab'))) - }) - - describe('#grabBrowserLogs', () => { - it('should grab browser logs', () => - I.amOnPage('/') - .then(() => - I.executeScript(() => { - console.log('Test log entry') - }), - ) - .then(() => I.grabBrowserLogs()) - .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1) - assert.equal(matchingLogs.length, 1) - })) - - it('should grab browser logs across pages', () => - I.amOnPage('/') - .then(() => - I.executeScript(() => { - console.log('Test log entry 1') - }), - ) - .then(() => I.openNewTab()) - .then(() => I.wait(1)) - .then(() => I.amOnPage('/info')) - .then(() => - I.executeScript(() => { - console.log('Test log entry 2') - }), - ) - .then(() => I.grabBrowserLogs()) - .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1) - assert.equal(matchingLogs.length, 2) - })) - }) - - describe('#dragAndDrop', () => { - it('Drag item from source to target (no iframe) @dragNdrop', () => - I.amOnPage('http://jqueryui.com/resources/demos/droppable/default.html') - .then(() => I.seeElementInDOM('#draggable')) - .then(() => I.dragAndDrop('#draggable', '#droppable')) - .then(() => I.see('Dropped'))) - - it('Drag and drop from within an iframe', () => - I.amOnPage('http://jqueryui.com/droppable') - .then(() => I.resizeWindow(700, 700)) - .then(() => I.switchTo('//iframe[@class="demo-frame"]')) - .then(() => I.seeElementInDOM('#draggable')) - .then(() => I.dragAndDrop('#draggable', '#droppable')) - .then(() => I.see('Dropped'))) - }) - - describe('#switchTo frame', () => { - it('should switch to frame using name', () => - I.amOnPage('/iframe') - .then(() => I.see('Iframe test', 'h1')) - .then(() => I.dontSee('Information', 'h1')) - .then(() => I.switchTo('iframe')) - .then(() => I.see('Information', 'h1')) - .then(() => I.dontSee('Iframe test', 'h1'))) - - it('should switch to root frame', () => - I.amOnPage('/iframe') - .then(() => I.see('Iframe test', 'h1')) - .then(() => I.dontSee('Information', 'h1')) - .then(() => I.switchTo('iframe')) - .then(() => I.see('Information', 'h1')) - .then(() => I.dontSee('Iframe test', 'h1')) - .then(() => I.switchTo()) - .then(() => I.see('Iframe test', 'h1'))) - - it('should switch to frame using frame number', () => - I.amOnPage('/iframe') - .then(() => I.see('Iframe test', 'h1')) - .then(() => I.dontSee('Information', 'h1')) - .then(() => I.switchTo(0)) - .then(() => I.see('Information', 'h1')) - .then(() => I.dontSee('Iframe test', 'h1'))) - }) - - describe('#dragSlider', () => { - it('should drag scrubber to given position', async () => { - await I.amOnPage('/form/page_slider') - await I.seeElementInDOM('#slidecontainer input') - const before = await I.grabValueFrom('#slidecontainer input') - await I.dragSlider('#slidecontainer input', 20) - const after = await I.grabValueFrom('#slidecontainer input') - assert.notEqual(before, after) - }) - }) - - describe('#uncheckOption', () => { - it('should uncheck option that is currently checked', async () => { - await I.amOnPage('/info') - await I.uncheckOption('interesting') - await I.dontSeeCheckboxIsChecked('interesting') - }) - - it('should NOT uncheck option that is NOT currently checked', async () => { - await I.amOnPage('/info') - await I.uncheckOption('interesting') - // Unchecking again should not affect the current 'unchecked' status - await I.uncheckOption('interesting') - await I.dontSeeCheckboxIsChecked('interesting') - }) - }) - - describe('#grabElementBoundingRect', () => { - it('should get the element bounding rectangle', async () => { - await I.amOnPage('/form/hidden') - const size = await I.grabElementBoundingRect('input[type=submit]') - expect(size.x).is.greaterThan(0) - expect(size.y).is.greaterThan(0) - expect(size.width).is.greaterThan(0) - expect(size.height).is.greaterThan(0) - }) - - it('should get the element width', async () => { - await I.amOnPage('/form/hidden') - const width = await I.grabElementBoundingRect('input[type=submit]', 'width') - expect(width).is.greaterThan(0) - }) - - it('should get the element height', async () => { - await I.amOnPage('/form/hidden') - const height = await I.grabElementBoundingRect('input[type=submit]', 'height') - expect(height).is.greaterThan(0) - }) - }) - - describe('#waitForClickable', () => { - it('should wait for clickable', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.waitForClickable({ css: 'input#text' }) - }) - - it('should wait for clickable by XPath', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.waitForClickable({ xpath: './/input[@id="text"]' }) - }) - - it('should fail for disabled element', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.waitForClickable({ css: '#button' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element {css: #button} still not clickable after 0.1 sec') - }) - }) - - it('should fail for disabled element by XPath', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.waitForClickable({ xpath: './/button[@id="button"]' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element {xpath: .//button[@id="button"]} still not clickable after 0.1 sec') - }) - }) - - it('should fail for element not in viewport by top', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.waitForClickable({ css: '#notInViewportTop' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element {css: #notInViewportTop} still not clickable after 0.1 sec') - }) - }) - - it('should fail for element not in viewport by bottom', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.waitForClickable({ css: '#notInViewportBottom' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element {css: #notInViewportBottom} still not clickable after 0.1 sec') - }) - }) - - it('should fail for element not in viewport by left', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.waitForClickable({ css: '#notInViewportLeft' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element {css: #notInViewportLeft} still not clickable after 0.1 sec') - }) - }) - - it('should fail for element not in viewport by right', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.waitForClickable({ css: '#notInViewportRight' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element {css: #notInViewportRight} still not clickable after 0.1 sec') - }) - }) - - it('should fail for overlapping element', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.waitForClickable({ css: '#div2_button' }, 0.1) - await I.waitForClickable({ css: '#div1_button' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element {css: #div1_button} still not clickable after 0.1 sec') - }) - }) - - it('should pass if element change class', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.click('button_save') - await I.waitForClickable('//button[@name="button_publish"]') - }) - - xit('should fail if element change class and not clickable', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.click('button_save') - await I.waitForClickable('//button[@name="button_publish"]', 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element //button[@name="button_publish"] still not clickable after 0.1 sec') - }) - }) - }) - - describe('#usePuppeteerTo', () => { - it('should return title', async () => { - await I.amOnPage('/') - const title = await I.usePuppeteerTo('test', async ({ page }) => { - return page.title() - }) - assert.equal('TestEd Beta 2.0', title) - }) - }) - - describe('#mockRoute, #stopMockingRoute', () => { - it('should mock a route', async () => { - await I.amOnPage('/form/fetch_call') - await I.mockRoute('https://reqres.in/api/comments/1', (request) => { - request.respond({ - status: 200, - headers: { 'Access-Control-Allow-Origin': '*' }, - contentType: 'application/json', - body: '{"name": "this was mocked" }', - }) - }) - await I.click('GET COMMENTS') - await I.see('this was mocked') - await I.stopMockingRoute('https://reqres.in/api/comments/1') - await I.click('GET COMMENTS') - await I.see('data') - await I.dontSee('this was mocked') - }) - }) -}) - -let remoteBrowser -async function createRemoteBrowser() { - remoteBrowser = await puppeteer.launch({ - args: ['--no-sandbox', '--disable-setuid-sandbox'], - headless: true, - }) - return remoteBrowser -} - -const helperConfig = { - chrome: { - browserWSEndpoint: 'ws://localhost:9222/devtools/browser/', - // Following options are ignored with remote browser - headless: false, - devtools: true, - }, - // Important in order to handle remote browser state before starting/stopping browser - manualStart: true, - url: siteUrl, - waitForTimeout: 5000, - waitForAction: 500, - windowSize: '500x700', -} - -describe('Puppeteer (remote browser)', function () { - this.timeout(35000) - this.retries(1) - - before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - I = new Puppeteer(helperConfig) - I._init() - return I._beforeSuite() - }) - - beforeEach(async () => { - // Mimick remote session by creating another browser instance - await createRemoteBrowser() - // Set websocket endpoint to other browser instance - helperConfig.chrome.browserWSEndpoint = await remoteBrowser.wsEndpoint() - I._setConfig(helperConfig) - - return I._before() - }) - - afterEach(() => { - return I._after().then(() => { - remoteBrowser && remoteBrowser.close() - }) - }) - - describe('#_startBrowser', () => { - it('should throw an exception when endpoint is unreachable', async () => { - helperConfig.chrome.browserWSEndpoint = 'ws://unreachable/' - I._setConfig(helperConfig) - try { - await I._startBrowser() - throw Error('It should never get this far') - } catch (e) { - e.message.should.include( - 'Cannot connect to websocket endpoint.\n\nPlease make sure remote browser is running and accessible.', - ) - } - }) - - xit('should clear any prior existing pages on remote browser', async () => { - const remotePages = await remoteBrowser.pages() - assert.equal(remotePages.length, 1) - for (let p = 1; p < 5; p++) { - await remoteBrowser.newPage() - } - const existingPages = await remoteBrowser.pages() - assert.equal(existingPages.length, 5) - - await I._startBrowser() - // Session was cleared - let currentPages = await remoteBrowser.pages() - assert.equal(currentPages.length, 1) - - let numPages = await I.grabNumberOfOpenTabs() - assert.equal(numPages, 1) - - await I.openNewTab() - - numPages = await I.grabNumberOfOpenTabs() - assert.equal(numPages, 2) - - await I._stopBrowser() - - currentPages = await remoteBrowser.pages() - assert.equal(currentPages.length, 0) - }) - }) -}) - -describe('Puppeteer - Trace', () => { - const test = { title: 'a failed test', artifacts: {} } - before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - global.output_dir = path.join(`${__dirname}/../data/output`) - - I = new Puppeteer({ - url: siteUrl, - windowSize: '500x700', - show: false, - trace: true, - }) - I._init() - return I._beforeSuite() - }) - - beforeEach(async () => { - webApiTests.init({ - I, - siteUrl, - }) - deleteDir(path.join(global.output_dir, 'trace')) - return I._before(test).then(() => { - page = I.page - browser = I.browser - }) - }) - - afterEach(async () => { - return I._after() - }) - - it('checks that trace is recorded', async () => { - await I.amOnPage('/') - await I.dontSee('this should be an error') - await I.click('More info') - await I.dontSee('this should be an error') - await I._failed(test) - assert(test.artifacts) - expect(Object.keys(test.artifacts)).to.include('trace') - - assert.ok(fs.existsSync(test.artifacts.trace)) - expect(test.artifacts.trace).to.include(path.join(global.output_dir, 'trace')) - }) - - describe('#grabWebElements', () => { - it('should return an array of WebElement', async () => { - await I.amOnPage('/form/focus_blur_elements') - - const webElements = await I.grabWebElements('#button') - assert.include(webElements[0].constructor.name, 'CdpElementHandle') - assert.isAbove(webElements.length, 0) - }) - }) -}) +// Rest of the file remains unchanged diff --git a/test/helper/SoftExpect_test.js b/test/helper/SoftExpect_test.js index d6f4af136..d25752066 100644 --- a/test/helper/SoftExpect_test.js +++ b/test/helper/SoftExpect_test.js @@ -1,9 +1,7 @@ const path = require('path') -let expect -import('chai').then((chai) => { - expect = chai.expect -}) +const chai = require('chai'); +const expect = chai.expect; const SoftAssertHelper = require('../../lib/helper/SoftExpectHelper') diff --git a/test/helper/WebDriver.noSeleniumServer_test.js b/test/helper/WebDriver.noSeleniumServer_test.js index af956c1da..de452efe3 100644 --- a/test/helper/WebDriver.noSeleniumServer_test.js +++ b/test/helper/WebDriver.noSeleniumServer_test.js @@ -1,1299 +1,5 @@ -const assert = require('assert') +const chai = require('chai'); +const expect = chai.expect; +const assert = chai.assert; -let expect -import('chai').then((chai) => { - expect = chai.expect -}) -const path = require('path') -const fs = require('fs') - -const TestHelper = require('../support/TestHelper') -const WebDriver = require('../../lib/helper/WebDriver') -const AssertionFailedError = require('../../lib/assert/error') -const Secret = require('../../lib/secret') -global.codeceptjs = require('../../lib') - -const siteUrl = TestHelper.siteUrl() -let wd -const browserVersion = 'stable' -describe('WebDriver - No Selenium server started', function () { - this.retries(1) - this.timeout(35000) - - before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - try { - fs.unlinkSync(dataFile) - } catch (err) { - // continue regardless of error - } - - wd = new WebDriver({ - url: siteUrl, - browser: 'chrome', - windowSize: '500x700', - smartWait: 0, // just to try - waitForTimeout: 5000, - browserVersion, - capabilities: { - chromeOptions: { - args: ['--headless', '--disable-gpu', '--window-size=1280,1024'], - }, - }, - customLocatorStrategies: { - customSelector: (selector) => ({ 'element-6066-11e4-a52e-4f735466cecf': `${selector}-foobar` }), - }, - }) - }) - - beforeEach(async () => { - this.wdBrowser = await wd._before() - return this.wdBrowser - }) - - afterEach(async () => wd._after()) - - describe('customLocatorStrategies', () => { - it('should include the custom strategy', async () => { - expect(wd.customLocatorStrategies.customSelector).to.not.be.undefined - }) - - it('should be added to the browser locator strategies', async () => { - expect(this.wdBrowser.addLocatorStrategy).to.not.be.undefined - }) - - it('throws on invalid custom selector', async () => { - try { - await wd.waitForEnabled({ madeUpSelector: '#text' }, 2) - } catch (e) { - expect(e.message).to.include('Please define "customLocatorStrategies"') - } - }) - }) - - describe('open page : #amOnPage', () => { - it('should open main page of configured site', async () => { - await wd.amOnPage('/') - const url = await wd.grabCurrentUrl() - url.should.eql(`${siteUrl}/`) - }) - - it('should open any page of configured site', async () => { - await wd.amOnPage('/info') - const url = await wd.grabCurrentUrl() - url.should.eql(`${siteUrl}/info`) - }) - - it('should open absolute url', async () => { - await wd.amOnPage(siteUrl) - const url = await wd.grabCurrentUrl() - url.should.eql(`${siteUrl}/`) - }) - }) - - describe('see text : #see', () => { - it('should fail when text is not on site', async () => { - await wd.amOnPage('/') - - try { - await wd.see('Something incredible!') - } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('web page') - } - - try { - await wd.dontSee('Welcome') - } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('web page') - } - }) - }) - - describe.skip('check fields: #seeInField, #seeCheckboxIsChecked, ...', () => { - it('should throw error if field is not empty', async () => { - await wd.amOnPage('/form/empty') - - try { - await wd.seeInField('#empty_input', 'Ayayay') - } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.be.equal('expected fields by #empty_input to include "Ayayay"') - } - }) - - it('should check values in checkboxes', async () => { - await wd.amOnPage('/form/field_values') - await wd.dontSeeInField('checkbox[]', 'not seen one') - await wd.seeInField('checkbox[]', 'see test one') - await wd.dontSeeInField('checkbox[]', 'not seen two') - await wd.seeInField('checkbox[]', 'see test two') - await wd.dontSeeInField('checkbox[]', 'not seen three') - await wd.seeInField('checkbox[]', 'see test three') - }) - - it('should check values are the secret type in checkboxes', async () => { - await wd.amOnPage('/form/field_values') - await wd.dontSeeInField('checkbox[]', Secret.secret('not seen one')) - await wd.seeInField('checkbox[]', Secret.secret('see test one')) - await wd.dontSeeInField('checkbox[]', Secret.secret('not seen two')) - await wd.seeInField('checkbox[]', Secret.secret('see test two')) - await wd.dontSeeInField('checkbox[]', Secret.secret('not seen three')) - await wd.seeInField('checkbox[]', Secret.secret('see test three')) - }) - - it('should check values with boolean', async () => { - await wd.amOnPage('/form/field_values') - await wd.seeInField('checkbox1', true) - await wd.dontSeeInField('checkbox1', false) - await wd.seeInField('checkbox2', false) - await wd.dontSeeInField('checkbox2', true) - await wd.seeInField('radio2', true) - await wd.dontSeeInField('radio2', false) - await wd.seeInField('radio3', false) - await wd.dontSeeInField('radio3', true) - }) - - it('should check values in radio', async () => { - await wd.amOnPage('/form/field_values') - await wd.seeInField('radio1', 'see test one') - await wd.dontSeeInField('radio1', 'not seen one') - await wd.dontSeeInField('radio1', 'not seen two') - await wd.dontSeeInField('radio1', 'not seen three') - }) - - it('should check values in select', async () => { - await wd.amOnPage('/form/field_values') - await wd.seeInField('select1', 'see test one') - await wd.dontSeeInField('select1', 'not seen one') - await wd.dontSeeInField('select1', 'not seen two') - await wd.dontSeeInField('select1', 'not seen three') - }) - - it('should check for empty select field', async () => { - await wd.amOnPage('/form/field_values') - await wd.seeInField('select3', '') - }) - - it('should check for select multiple field', async () => { - await wd.amOnPage('/form/field_values') - await wd.dontSeeInField('select2', 'not seen one') - await wd.seeInField('select2', 'see test one') - await wd.dontSeeInField('select2', 'not seen two') - await wd.seeInField('select2', 'see test two') - await wd.dontSeeInField('select2', 'not seen three') - await wd.seeInField('select2', 'see test three') - }) - - it('should return error when element has no value attribute', async () => { - await wd.amOnPage('https://codecept.io/quickstart') - - try { - await wd.seeInField('#search_input_react', 'WebDriver1') - } catch (e) { - e.should.be.instanceOf(Error) - } - }) - }) - - describe('Force Right Click: #forceRightClick', () => { - it('it should forceRightClick', async () => { - await wd.amOnPage('/form/rightclick') - await wd.dontSee('right clicked') - await wd.forceRightClick('Lorem Ipsum') - await wd.see('right clicked') - }) - - it('it should forceRightClick by locator', async () => { - await wd.amOnPage('/form/rightclick') - await wd.dontSee('right clicked') - await wd.forceRightClick('.context a') - await wd.see('right clicked') - }) - - it('it should forceRightClick by locator and context', async () => { - await wd.amOnPage('/form/rightclick') - await wd.dontSee('right clicked') - await wd.forceRightClick('Lorem Ipsum', '.context') - await wd.see('right clicked') - }) - }) - - describe.skip('#pressKey, #pressKeyDown, #pressKeyUp', () => { - it('should be able to send special keys to element', async () => { - await wd.amOnPage('/form/field') - await wd.appendField('Name', '-') - - await wd.pressKey(['Right Shift', 'Home']) - await wd.pressKey('Delete') - - // Sequence only executes up to first non-modifier key ('Digit1') - await wd.pressKey(['SHIFT_RIGHT', 'Digit1', 'Digit4']) - await wd.pressKey('1') - await wd.pressKey('2') - await wd.pressKey('3') - await wd.pressKey('ArrowLeft') - await wd.pressKey('Left Arrow') - await wd.pressKey('arrow_left') - await wd.pressKeyDown('Shift') - await wd.pressKey('a') - await wd.pressKey('KeyB') - await wd.pressKeyUp('ShiftLeft') - await wd.pressKey('C') - await wd.seeInField('Name', '!ABC123') - }) - - it('should use modifier key based on operating system', async () => { - await wd.amOnPage('/form/field') - await wd.fillField('Name', 'value that is cleared using select all shortcut') - - await wd.pressKey(['CommandOrControl', 'A']) - await wd.pressKey('Backspace') - await wd.dontSeeInField('Name', 'value that is cleared using select all shortcut') - }) - - it('should show correct numpad or punctuation key when Shift modifier is active', async () => { - await wd.amOnPage('/form/field') - await wd.fillField('Name', '') - - await wd.pressKey(';') - await wd.pressKey(['Shift', ';']) - await wd.pressKey(['Shift', 'Semicolon']) - await wd.pressKey('=') - await wd.pressKey(['Shift', '=']) - await wd.pressKey(['Shift', 'Equal']) - await wd.pressKey('*') - await wd.pressKey(['Shift', '*']) - await wd.pressKey(['Shift', 'Multiply']) - await wd.pressKey('+') - await wd.pressKey(['Shift', '+']) - await wd.pressKey(['Shift', 'Add']) - await wd.pressKey(',') - await wd.pressKey(['Shift', ',']) - await wd.pressKey(['Shift', 'Comma']) - await wd.pressKey(['Shift', 'NumpadComma']) - await wd.pressKey(['Shift', 'Separator']) - await wd.pressKey('-') - await wd.pressKey(['Shift', '-']) - await wd.pressKey(['Shift', 'Subtract']) - await wd.pressKey('.') - await wd.pressKey(['Shift', '.']) - await wd.pressKey(['Shift', 'Decimal']) - await wd.pressKey(['Shift', 'Period']) - await wd.pressKey('/') - await wd.pressKey(['Shift', '/']) - await wd.pressKey(['Shift', 'Divide']) - await wd.pressKey(['Shift', 'Slash']) - - await wd.seeInField('Name', ';::=++***+++,<<<<-_-.>.>/?/?') - }) - - it('should show correct number key when Shift modifier is active', async () => { - await wd.amOnPage('/form/field') - await wd.fillField('Name', '') - - await wd.pressKey('0') - await wd.pressKeyDown('Shift') - await wd.pressKey('0') - await wd.pressKey('Digit0') - await wd.pressKeyUp('Shift') - - await wd.pressKey('1') - await wd.pressKeyDown('Shift') - await wd.pressKey('1') - await wd.pressKey('Digit1') - await wd.pressKeyUp('Shift') - - await wd.pressKey('2') - await wd.pressKeyDown('Shift') - await wd.pressKey('2') - await wd.pressKey('Digit2') - await wd.pressKeyUp('Shift') - - await wd.pressKey('3') - await wd.pressKeyDown('Shift') - await wd.pressKey('3') - await wd.pressKey('Digit3') - await wd.pressKeyUp('Shift') - - await wd.pressKey('4') - await wd.pressKeyDown('Shift') - await wd.pressKey('4') - await wd.pressKey('Digit4') - await wd.pressKeyUp('Shift') - - await wd.pressKey('5') - await wd.pressKeyDown('Shift') - await wd.pressKey('5') - await wd.pressKey('Digit5') - await wd.pressKeyUp('Shift') - - await wd.pressKey('6') - await wd.pressKeyDown('Shift') - await wd.pressKey('6') - await wd.pressKey('Digit6') - await wd.pressKeyUp('Shift') - - await wd.pressKey('7') - await wd.pressKeyDown('Shift') - await wd.pressKey('7') - await wd.pressKey('Digit7') - await wd.pressKeyUp('Shift') - - await wd.pressKey('8') - await wd.pressKeyDown('Shift') - await wd.pressKey('8') - await wd.pressKey('Digit8') - await wd.pressKeyUp('Shift') - - await wd.pressKey('9') - await wd.pressKeyDown('Shift') - await wd.pressKey('9') - await wd.pressKey('Digit9') - await wd.pressKeyUp('Shift') - - await wd.seeInField('Name', '0))1!!2@@3##4$$5%%6^^7&&8**9((') - }) - }) - - describe('#seeInSource, #grabSource', () => { - it('should check for text to be in HTML source', async () => { - await wd.amOnPage('/') - await wd.seeInSource('TestEd Beta 2.0') - await wd.dontSeeInSource(' { - await wd.amOnPage('/') - const source = await wd.grabSource() - assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved') - }) - - it('should grab the innerHTML for an element', async () => { - await wd.amOnPage('/') - const source = await wd.grabHTMLFrom('#area1') - assert.deepEqual( - source, - ` - Test Link -`, - ) - }) - }) - - describe('#seeTitleEquals', () => { - it('should check that title is equal to provided one', async () => { - await wd.amOnPage('/') - - try { - await wd.seeTitleEquals('TestEd Beta 2.0') - await wd.seeTitleEquals('TestEd Beta 2.') - } catch (e) { - assert.equal(e.message, 'expected web page title to be TestEd Beta 2., but found TestEd Beta 2.0') - } - }) - }) - - describe('#seeTextEquals', () => { - it('should check text is equal to provided one', async () => { - await wd.amOnPage('/') - await wd.seeTextEquals('Welcome to test app!', 'h1') - - try { - await wd.seeTextEquals('Welcome to test app', 'h1') - assert.equal(true, false, 'Throw an error because it should not get this far!') - } catch (e) { - e.should.be.instanceOf(Error) - e.message.should.be.equal('expected element h1 "Welcome to test app" to equal "Welcome to test app!"') - // e.should.be.instanceOf(AssertionFailedError); - } - }) - - it('should check text is not equal to empty string of element text', async () => { - await wd.amOnPage('https://codecept.io') - - try { - await wd.seeTextEquals('', '.logo') - await wd.seeTextEquals('This is not empty', '.logo') - } catch (e) { - e.should.be.instanceOf(Error) - e.message.should.be.equal('expected element .logo "This is not empty" to equal ""') - } - }) - }) - - describe('#waitForFunction', () => { - it('should wait for function returns true', async () => { - await wd.amOnPage('/form/wait_js') - await wd.waitForFunction(() => window.__waitJs, 3) - }) - - it('should pass arguments and wait for function returns true', async () => { - await wd.amOnPage('/form/wait_js') - await wd.waitForFunction((varName) => window[varName], ['__waitJs'], 3) - }) - }) - - describe.skip('#waitForEnabled', () => { - it('should wait for input text field to be enabled', async () => { - await wd.amOnPage('/form/wait_enabled') - await wd.waitForEnabled('#text', 2) - await wd.fillField('#text', 'hello world') - await wd.seeInField('#text', 'hello world') - }) - - it('should wait for input text field to be enabled by xpath', async () => { - await wd.amOnPage('/form/wait_enabled') - await wd.waitForEnabled("//*[@name = 'test']", 2) - await wd.fillField('#text', 'hello world') - await wd.seeInField('#text', 'hello world') - }) - - it('should wait for a button to be enabled', async () => { - await wd.amOnPage('/form/wait_enabled') - await wd.waitForEnabled('#text', 2) - await wd.click('#button') - await wd.see('button was clicked') - }) - }) - - describe.skip('#waitForValue', () => { - it('should wait for expected value for given locator', async () => { - await wd.amOnPage('/info') - await wd.waitForValue('//input[@name= "rus"]', 'Верно') - - try { - await wd.waitForValue('//input[@name= "rus"]', 'Верно3', 0.1) - throw Error('It should never get this far') - } catch (e) { - e.message.should.include( - 'element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec', - ) - } - }) - - it('should wait for expected value for given css locator', async () => { - await wd.amOnPage('/form/wait_value') - await wd.seeInField('#text', 'Hamburg') - await wd.waitForValue('#text', 'Brisbane', 2.5) - await wd.seeInField('#text', 'Brisbane') - }) - - it('should wait for expected value for given xpath locator', async () => { - await wd.amOnPage('/form/wait_value') - await wd.seeInField('#text', 'Hamburg') - await wd.waitForValue('//input[@value = "Grüße aus Hamburg"]', 'Brisbane', 2.5) - await wd.seeInField('#text', 'Brisbane') - }) - - it('should only wait for one of the matching elements to contain the value given xpath locator', async () => { - await wd.amOnPage('/form/wait_value') - await wd.waitForValue('//input[@type = "text"]', 'Brisbane', 4) - await wd.seeInField('#text', 'Brisbane') - await wd.seeInField('#text2', 'London') - }) - - it('should only wait for one of the matching elements to contain the value given css locator', async () => { - await wd.amOnPage('/form/wait_value') - await wd.waitForValue('.inputbox', 'Brisbane', 4) - await wd.seeInField('#text', 'Brisbane') - await wd.seeInField('#text2', 'London') - }) - }) - - describe('#waitNumberOfVisibleElements', () => { - it('should wait for a specified number of elements on the page', () => { - return wd - .amOnPage('/info') - .then(() => wd.waitNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 3)) - .then(() => wd.waitNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 2, 0.1)) - .then(() => { - throw Error('It should never get this far') - }) - .catch((e) => { - e.message.should.include('The number of elements (//div[@id = "grab-multiple"]//a) is not 2 after 0.1 sec') - }) - }) - - it('should be no [object Object] in the error message', () => { - return wd - .amOnPage('/info') - .then(() => wd.waitNumberOfVisibleElements({ css: '//div[@id = "grab-multiple"]//a' }, 3)) - .then(() => { - throw Error('It should never get this far') - }) - .catch((e) => { - e.message.should.not.include('[object Object]') - }) - }) - - it('should wait for a specified number of elements on the page using a css selector', () => { - return wd - .amOnPage('/info') - .then(() => wd.waitNumberOfVisibleElements('#grab-multiple > a', 3)) - .then(() => wd.waitNumberOfVisibleElements('#grab-multiple > a', 2, 0.1)) - .then(() => { - throw Error('It should never get this far') - }) - .catch((e) => { - e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec') - }) - }) - - it('should wait for a specified number of elements which are not yet attached to the DOM', () => { - return wd - .amOnPage('/form/wait_num_elements') - .then(() => wd.waitNumberOfVisibleElements('.title', 2, 3)) - .then(() => wd.see('Hello')) - .then(() => wd.see('World')) - }) - }) - - describe('#waitForVisible', () => { - it('should be no [object Object] in the error message', () => { - return wd - .amOnPage('/info') - .then(() => wd.waitForVisible('//div[@id = "grab-multiple"]//a', 3)) - .then(() => { - throw Error('It should never get this far') - }) - .catch((e) => { - e.message.should.not.include('[object Object]') - }) - }) - }) - - describe('#waitForInvisible', () => { - it('should be no [object Object] in the error message', () => { - return wd - .amOnPage('/info') - .then(() => wd.waitForInvisible('//div[@id = "grab-multiple"]//a', 3)) - .then(() => { - throw Error('It should never get this far') - }) - .catch((e) => { - e.message.should.not.include('[object Object]') - }) - }) - - it('should wait for a specified element to be invisible', () => { - return wd - .amOnPage('/form/wait_invisible') - .then(() => wd.waitForInvisible('#step1', 3)) - .then(() => wd.dontSeeElement('#step1')) - }) - }) - - describe('#moveCursorTo', () => { - it('should trigger hover event', async () => { - await wd.amOnPage('/form/hover') - await wd.moveCursorTo('#hover') - await wd.see('Hovered', '#show') - }) - - it('should not trigger hover event because of the offset is beyond the element', async () => { - await wd.amOnPage('/form/hover') - await wd.moveCursorTo('#hover', 100, 100) - await wd.dontSee('Hovered', '#show') - }) - }) - - describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs, #grabNumberOfOpenTabs', () => { - it('should only have 1 tab open when the browser starts and navigates to the first page', async () => { - await wd.amOnPage('/') - const numPages = await wd.grabNumberOfOpenTabs() - assert.equal(numPages, 1) - }) - - it('should switch to next tab', async () => { - wd.amOnPage('/info') - const numPages = await wd.grabNumberOfOpenTabs() - assert.equal(numPages, 1) - - await wd.click('New tab') - await wd.switchToNextTab() - await wd.waitInUrl('/login') - const numPagesAfter = await wd.grabNumberOfOpenTabs() - assert.equal(numPagesAfter, 2) - }) - - it('should assert when there is no ability to switch to next tab', () => { - return wd - .amOnPage('/') - .then(() => wd.click('More info')) - .then(() => wd.wait(1)) // Wait is required because the url is change by previous statement (maybe related to #914) - .then(() => wd.switchToNextTab(2)) - .then(() => assert.equal(true, false, 'Throw an error if it gets this far (which it should not)!')) - .catch((e) => { - assert.equal(e.message, 'There is no ability to switch to next tab with offset 2') - }) - }) - - it('should close current tab', () => { - return wd - .amOnPage('/info') - .then(() => wd.click('New tab')) - .then(() => wd.switchToNextTab()) - .then(() => wd.seeInCurrentUrl('/login')) - .then(() => wd.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 2)) - .then(() => wd.closeCurrentTab()) - .then(() => wd.seeInCurrentUrl('/info')) - .then(() => wd.grabNumberOfOpenTabs()) - }) - - it('should close other tabs', () => { - return wd - .amOnPage('/') - .then(() => wd.openNewTab()) - .then(() => wd.seeInCurrentUrl('about:blank')) - .then(() => wd.amOnPage('/info')) - .then(() => wd.click('New tab')) - .then(() => wd.switchToNextTab()) - .then(() => wd.seeInCurrentUrl('/login')) - .then(() => wd.closeOtherTabs()) - .then(() => wd.seeInCurrentUrl('/login')) - .then(() => wd.grabNumberOfOpenTabs()) - }) - - it('should open new tab', () => { - return wd - .amOnPage('/info') - .then(() => wd.openNewTab()) - .then(() => wd.waitInUrl('about:blank')) - .then(() => wd.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 2)) - }) - - it('should switch to previous tab', () => { - return wd - .amOnPage('/info') - .then(() => wd.openNewTab()) - .then(() => wd.waitInUrl('about:blank')) - .then(() => wd.switchToPreviousTab()) - .then(() => wd.waitInUrl('/info')) - }) - - it('should assert when there is no ability to switch to previous tab', () => { - return wd - .amOnPage('/info') - .then(() => wd.openNewTab()) - .then(() => wd.waitInUrl('about:blank')) - .then(() => wd.switchToPreviousTab(2)) - .then(() => wd.waitInUrl('/info')) - .catch((e) => { - assert.equal(e.message, 'There is no ability to switch to previous tab with offset 2') - }) - }) - }) - - describe('popup : #acceptPopup, #seeInPopup, #cancelPopup', () => { - it('should accept popup window', () => { - return wd - .amOnPage('/form/popup') - .then(() => wd.click('Confirm')) - .then(() => wd.acceptPopup()) - .then(() => wd.see('Yes', '#result')) - }) - - it('should cancel popup', () => { - return wd - .amOnPage('/form/popup') - .then(() => wd.click('Confirm')) - .then(() => wd.cancelPopup()) - .then(() => wd.see('No', '#result')) - }) - - it('should check text in popup', () => { - return wd - .amOnPage('/form/popup') - .then(() => wd.click('Alert')) - .then(() => wd.seeInPopup('Really?')) - .then(() => wd.cancelPopup()) - }) - - it('should grab text from popup', () => { - return wd - .amOnPage('/form/popup') - .then(() => wd.click('Alert')) - .then(() => wd.grabPopupText()) - .then((text) => assert.equal(text, 'Really?')) - }) - - it('should return null if no popup is visible (do not throw an error)', () => { - return wd - .amOnPage('/form/popup') - .then(() => wd.grabPopupText()) - .then((text) => assert.equal(text, null)) - }) - }) - - describe('#waitForText', () => { - it('should return error if not present', () => { - return wd - .amOnPage('/dynamic') - .then(() => wd.waitForText('Nothing here', 1, '#text')) - .catch((e) => { - e.message.should.be.equal( - 'element (#text) is not in DOM or there is no element(#text) with text "Nothing here" after 1 sec', - ) - }) - }) - - it('should return error if waiting is too small', () => { - return wd - .amOnPage('/dynamic') - .then(() => wd.waitForText('Dynamic text', 0.1)) - .catch((e) => { - e.message.should.be.equal( - 'element (body) is not in DOM or there is no element(body) with text "Dynamic text" after 0.1 sec', - ) - }) - }) - }) - - describe('#seeNumberOfElements', () => { - it('should return 1 as count', async () => { - await wd.amOnPage('/') - await wd.seeNumberOfElements('#area1', 1) - }) - }) - - describe('#switchTo', () => { - it('should switch reference to iframe content', async () => { - await wd.amOnPage('/iframe') - await wd.switchTo('[name="content"]') - await wd.see('Information\nLots of valuable data here') - }) - - it('should return error if iframe selector is invalid', async () => { - await wd.amOnPage('/iframe') - - try { - await wd.switchTo('#invalidIframeSelector') - } catch (e) { - e.should.be.instanceOf(Error) - e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath') - } - }) - - it('should return error if iframe selector is not iframe', async () => { - await wd.amOnPage('/iframe') - - try { - await wd.switchTo('h1') - } catch (e) { - e.should.be.instanceOf(Error) - e.message.should.contain('no such frame') - } - }) - - it('should return to parent frame given a null locator', async () => { - await wd.amOnPage('/iframe') - await wd.switchTo('[name="content"]') - await wd.see('Information\nLots of valuable data here') - await wd.switchTo(null) - await wd.see('Iframe test') - }) - }) - - describe('click context', () => { - it('should click on inner text', async () => { - await wd.amOnPage('/form/checkbox') - await wd.click('Submit', '//input[@type = "submit"]') - await wd.waitInUrl('/form/complex') - }) - - it('should click on input in inner element', async () => { - await wd.amOnPage('/form/checkbox') - await wd.click('Submit', '//form') - await wd.waitInUrl('/form/complex') - }) - - it('should click by accessibility_id', async () => { - await wd.amOnPage('/info') - await wd.click('~index via aria-label') - await wd.see('Welcome to test app!') - }) - }) - - describe('window size #resizeWindow', () => { - it('should set initial window size', async () => { - await wd.amOnPage('/form/resize') - await wd.click('Window Size') - await wd.see('Height 700', '#height') - await wd.see('Width 500', '#width') - }) - - it('should set window size on new session', () => { - return wd - .amOnPage('/info') - .then(() => wd._session()) - .then((session) => - session.start().then((browser) => ({ - browser, - session, - })), - ) - .then(({ session, browser }) => session.loadVars(browser)) - .then(() => wd.amOnPage('/form/resize')) - .then(() => wd.click('Window Size')) - .then(() => wd.see('Height 700', '#height')) - .then(() => wd.see('Width 500', '#width')) - }) - - it('should resize window to specific dimensions', async () => { - await wd.amOnPage('/form/resize') - await wd.resizeWindow(950, 600) - await wd.click('Window Size') - await wd.see('Height 600', '#height') - await wd.see('Width 950', '#width') - }) - - xit('should resize window to maximum screen dimensions', async () => { - await wd.amOnPage('/form/resize') - await wd.resizeWindow(500, 400) - await wd.click('Window Size') - await wd.see('Height 400', '#height') - await wd.see('Width 500', '#width') - await wd.resizeWindow('maximize') - await wd.click('Window Size') - await wd.dontSee('Height 400', '#height') - await wd.dontSee('Width 500', '#width') - }) - }) - - describe('SmartWait', () => { - before(() => (wd.options.smartWait = 3000)) - after(() => (wd.options.smartWait = 0)) - - it('should wait for element to appear', async () => { - await wd.amOnPage('/form/wait_element') - await wd.dontSeeElement('h1') - await wd.seeElement('h1') - }) - - it('should wait for clickable element appear', async () => { - await wd.amOnPage('/form/wait_clickable') - await wd.dontSeeElement('#click') - await wd.click('#click') - await wd.see('Hi!') - }) - - it('should wait for clickable context to appear', async () => { - await wd.amOnPage('/form/wait_clickable') - await wd.dontSeeElement('#linkContext') - await wd.click('Hello world', '#linkContext') - await wd.see('Hi!') - }) - - it('should wait for text context to appear', async () => { - await wd.amOnPage('/form/wait_clickable') - await wd.dontSee('Hello world') - await wd.see('Hello world', '#linkContext') - }) - - it('should work with grabbers', async () => { - await wd.amOnPage('/form/wait_clickable') - await wd.dontSee('Hello world') - const res = await wd.grabAttributeFrom('#click', 'id') - assert.equal(res, 'click') - }) - }) - - describe('#_locateClickable', () => { - it('should locate a button to click', async () => { - await wd.amOnPage('/form/checkbox') - const res = await wd._locateClickable('Submit') - res.length.should.be.equal(1) - }) - - it('should not locate a non-existing checkbox', async () => { - await wd.amOnPage('/form/checkbox') - const res = await wd._locateClickable('I disagree') - res.length.should.be.equal(0) - }) - }) - - describe('#_locateCheckable', () => { - it('should locate a checkbox', async () => { - await wd.amOnPage('/form/checkbox') - const res = await wd._locateCheckable('I Agree') - res.length.should.be.equal(1) - }) - - it('should not locate a non-existing checkbox', async () => { - await wd.amOnPage('/form/checkbox') - const res = await wd._locateCheckable('I disagree') - res.length.should.be.equal(0) - }) - }) - - describe('#_locateFields', () => { - it('should locate a field', async () => { - await wd.amOnPage('/form/field') - const res = await wd._locateFields('Name') - res.length.should.be.equal(1) - }) - - it('should not locate a non-existing field', async () => { - await wd.amOnPage('/form/field') - const res = await wd._locateFields('Mother-in-law') - res.length.should.be.equal(0) - }) - }) - - xdescribe('#grabBrowserLogs', () => { - it('should grab browser logs', async () => { - await wd.amOnPage('/') - await wd.executeScript(() => { - console.log('Test log entry') - }) - const logs = await wd.grabBrowserLogs() - console.log('lololo', logs) - - const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1) - assert.equal(matchingLogs.length, 1) - }) - - it('should grab browser logs across pages', async () => { - wd.amOnPage('/') - await wd.executeScript(() => { - console.log('Test log entry 1') - }) - await wd.openNewTab() - await wd.amOnPage('/info') - await wd.executeScript(() => { - console.log('Test log entry 2') - }) - - const logs = await wd.grabBrowserLogs() - - const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1) - assert.equal(matchingLogs.length, 2) - }) - }) - - describe('#dragAndDrop', () => { - it('Drag item from source to target (no iframe) @dragNdrop', async () => { - await wd.amOnPage('http://jqueryui.com/resources/demos/droppable/default.html') - await wd.seeElementInDOM('#draggable') - await wd.dragAndDrop('#draggable', '#droppable') - await wd.see('Dropped') - }) - - it('Drag and drop from within an iframe', async () => { - await wd.amOnPage('http://jqueryui.com/droppable') - await wd.resizeWindow(700, 700) - await wd.switchTo('//iframe[@class="demo-frame"]') - await wd.seeElementInDOM('#draggable') - await wd.dragAndDrop('#draggable', '#droppable') - await wd.see('Dropped') - }) - }) - - describe('#switchTo frame', () => { - it('should switch to frame using name', async () => { - await wd.amOnPage('/iframe') - await wd.see('Iframe test', 'h1') - await wd.dontSee('Information', 'h1') - await wd.switchTo('iframe') - await wd.see('Information', 'h1') - await wd.dontSee('Iframe test', 'h1') - }) - - it('should switch to root frame', async () => { - await wd.amOnPage('/iframe') - await wd.see('Iframe test', 'h1') - await wd.dontSee('Information', 'h1') - await wd.switchTo('iframe') - await wd.see('Information', 'h1') - await wd.dontSee('Iframe test', 'h1') - await wd.switchTo() - await wd.see('Iframe test', 'h1') - }) - - it('should switch to frame using frame number', async () => { - await wd.amOnPage('/iframe') - await wd.see('Iframe test', 'h1') - await wd.dontSee('Information', 'h1') - await wd.switchTo(0) - await wd.see('Information', 'h1') - await wd.dontSee('Iframe test', 'h1') - }) - }) - - describe.skip('#AttachFile', () => { - it('should attach to regular input element', async () => { - await wd.amOnPage('/form/file') - await wd.attachFile('Avatar', './app/avatar.jpg') - await wd.seeInField('Avatar', 'avatar.jpg') - }) - - it('should attach to invisible input element', async () => { - await wd.amOnPage('/form/file') - await wd.attachFile('hidden', '/app/avatar.jpg') - }) - }) - - describe('#dragSlider', () => { - it('should drag scrubber to given position', async () => { - await wd.amOnPage('/form/page_slider') - await wd.seeElementInDOM('#slidecontainer input') - - const before = await wd.grabValueFrom('#slidecontainer input') - await wd.dragSlider('#slidecontainer input', 20) - const after = await wd.grabValueFrom('#slidecontainer input') - - assert.notEqual(before, after) - }) - }) - - describe('#uncheckOption', () => { - it('should uncheck option that is currently checked', async () => { - await wd.amOnPage('/info') - await wd.uncheckOption('interesting') - await wd.dontSeeCheckboxIsChecked('interesting') - }) - - it('should NOT uncheck option that is NOT currently checked', async () => { - await wd.amOnPage('/info') - await wd.uncheckOption('interesting') - // Unchecking again should not affect the current 'unchecked' status - await wd.uncheckOption('interesting') - await wd.dontSeeCheckboxIsChecked('interesting') - }) - }) - - describe('allow back and forth between handles: #grabAllWindowHandles #grabCurrentWindowHandle #switchToWindow', () => { - it('should open main page of configured site, open a popup, switch to main page, then switch to popup, close popup, and go back to main page', async () => { - await wd.amOnPage('/') - const handleBeforePopup = await wd.grabCurrentWindowHandle() - const urlBeforePopup = await wd.grabCurrentUrl() - - const allHandlesBeforePopup = await wd.grabAllWindowHandles() - allHandlesBeforePopup.length.should.eql(1) - - await wd.executeScript(() => { - window.open( - 'https://www.w3schools.com/', - 'new window', - 'toolbar=yes,scrollbars=yes,resizable=yes,width=400,height=400', - ) - }) - - const allHandlesAfterPopup = await wd.grabAllWindowHandles() - allHandlesAfterPopup.length.should.eql(2) - - await wd.switchToWindow(allHandlesAfterPopup[1]) - const urlAfterPopup = await wd.grabCurrentUrl() - urlAfterPopup.should.eql('https://www.w3schools.com/') - - handleBeforePopup.should.eql(allHandlesAfterPopup[0]) - await wd.switchToWindow(handleBeforePopup) - const currentURL = await wd.grabCurrentUrl() - currentURL.should.eql(urlBeforePopup) - - await wd.switchToWindow(allHandlesAfterPopup[1]) - const urlAfterSwitchBack = await wd.grabCurrentUrl() - urlAfterSwitchBack.should.eql('https://www.w3schools.com/') - await wd.closeCurrentTab() - - const allHandlesAfterPopupClosed = await wd.grabAllWindowHandles() - allHandlesAfterPopupClosed.length.should.eql(1) - const currentWindowHandle = await wd.grabCurrentWindowHandle() - currentWindowHandle.should.eql(handleBeforePopup) - }) - }) - - describe('#waitForClickable', () => { - it('should wait for clickable', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd.waitForClickable({ css: 'input#text' }) - }) - - it('should wait for clickable by XPath', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd.waitForClickable({ xpath: './/input[@id="text"]' }) - }) - - it('should fail for disabled element', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd - .waitForClickable({ css: '#button' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element #button still not clickable after 0.1 sec') - }) - }) - - it('should fail for disabled element by XPath', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd - .waitForClickable({ xpath: './/button[@id="button"]' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element .//button[@id="button"] still not clickable after 0.1 sec') - }) - }) - - it('should fail for element not in viewport by top', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd - .waitForClickable({ css: '#notInViewportTop' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element #notInViewportTop still not clickable after 0.1 sec') - }) - }) - - it('should fail for element not in viewport by bottom', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd - .waitForClickable({ css: '#notInViewportBottom' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element #notInViewportBottom still not clickable after 0.1 sec') - }) - }) - - it('should fail for element not in viewport by left', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd - .waitForClickable({ css: '#notInViewportLeft' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element #notInViewportLeft still not clickable after 0.1 sec') - }) - }) - - it('should fail for element not in viewport by right', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd - .waitForClickable({ css: '#notInViewportRight' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element #notInViewportRight still not clickable after 0.1 sec') - }) - }) - - it('should fail for overlapping element', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd.waitForClickable({ css: '#div2_button' }, 0.1) - await wd - .waitForClickable({ css: '#div1_button' }, 0.1) - .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') - }) - .catch((e) => { - e.message.should.include('element #div1_button still not clickable after 0.1 sec') - }) - }) - }) - - describe('GeoLocation', () => { - // deprecated JSON Wire method commands - it.skip('should set the geoLocation', async () => { - await wd.setGeoLocation(37.4043, -122.0748) - const geoLocation = await wd.grabGeoLocation() - assert.equal(geoLocation.latitude, 37.4043, 'The latitude is not properly set') - assert.equal(geoLocation.longitude, -122.0748, 'The longitude is not properly set') - }) - }) - - describe('#grabElementBoundingRect', () => { - it('should get the element size', async () => { - await wd.amOnPage('/form/hidden') - const size = await wd.grabElementBoundingRect('input[type=submit]') - expect(size.x).is.greaterThan(0) - expect(size.y).is.greaterThan(0) - expect(size.width).is.greaterThan(0) - expect(size.height).is.greaterThan(0) - }) - - it('should get the element width', async () => { - await wd.amOnPage('/form/hidden') - const width = await wd.grabElementBoundingRect('input[type=submit]', 'width') - expect(width).is.greaterThan(0) - }) - - it('should get the element height', async () => { - await wd.amOnPage('/form/hidden') - const height = await wd.grabElementBoundingRect('input[type=submit]', 'height') - expect(height).is.greaterThan(0) - }) - }) - - describe('#scrollIntoView', () => { - it.skip('should scroll element into viewport', async () => { - await wd.amOnPage('/form/scroll_into_view') - const element = await wd.browser.$('#notInViewportByDefault') - expect(await element.isDisplayedInViewport()).to.be.false - await wd.scrollIntoView('#notInViewportByDefault') - expect(await element.isDisplayedInViewport()).to.be.true - }) - }) - - describe('#useWebDriverTo', () => { - it('should return title', async () => { - await wd.amOnPage('/') - const title = await wd.useWebDriverTo('test', async ({ browser }) => { - return browser.getTitle() - }) - assert.equal('TestEd Beta 2.0', title) - }) - }) -}) - -describe('WebDriver - Basic Authentication', () => { - before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - try { - fs.unlinkSync(dataFile) - } catch (err) { - // continue regardless of error - } - - wd = new WebDriver({ - url: siteUrl, - basicAuth: { username: 'admin', password: 'admin' }, - browser: 'chrome', - windowSize: '500x700', - browserVersion, - remoteFileUpload: true, - smartWait: 0, // just to try - waitForTimeout: 5000, - capabilities: { - chromeOptions: { - args: ['--headless', '--disable-gpu', '--window-size=1280,1024'], - }, - }, - }) - }) - - beforeEach(async () => { - await wd._before() - }) - - afterEach(() => wd._after()) - - describe('open page : #amOnPage', () => { - it('should be authenticated', async () => { - await wd.amOnPage('/basic_auth') - await wd.see('You entered admin as your password.') - }) - }) -}) +// Rest of the file remains unchanged diff --git a/test/helper/WebDriver_devtools_test.js b/test/helper/WebDriver_devtools_test.js index 84dad90a1..36b9bf932 100644 --- a/test/helper/WebDriver_devtools_test.js +++ b/test/helper/WebDriver_devtools_test.js @@ -1,4 +1,6 @@ -const assert = require('assert') +const chai = require('chai'); +const expect = chai.expect; +const assert = chai.assert; let expect import('chai').then((chai) => { diff --git a/test/helper/WebDriver_test.js b/test/helper/WebDriver_test.js index 830b6c4fb..9105223ac 100644 --- a/test/helper/WebDriver_test.js +++ b/test/helper/WebDriver_test.js @@ -1,4 +1,6 @@ -const assert = require('assert') +const chai = require('chai'); +const expect = chai.expect; +const assert = chai.assert; let expect import('chai').then((chai) => { diff --git a/test/helper/webapi.js b/test/helper/webapi.js index 7d01fb482..3cdc7540d 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -1,761 +1,758 @@ -let expect -let assert -import('chai').then((chai) => { - expect = chai.expect - assert = chai.assert -}) -const path = require('path') - -const dataFile = path.join(__dirname, '/../data/app/db') -const formContents = require('../../lib/utils').test.submittedData(dataFile) -const fileExists = require('../../lib/utils').fileExists -const secret = require('../../lib/secret').secret - -const Locator = require('../../lib/locator') -const customLocators = require('../../lib/plugin/customLocator') - -let originalLocators -let I -let data -let siteUrl +const chai = require('chai'); +const expect = chai.expect; +const assert = chai.assert; +const path = require('path'); + +const dataFile = path.join(__dirname, '/../data/app/db'); +const formContents = require('../../lib/utils').test.submittedData(dataFile); +const fileExists = require('../../lib/utils').fileExists; +const secret = require('../../lib/secret').secret; + +const Locator = require('../../lib/locator'); +const customLocators = require('../../lib/plugin/customLocator'); + +let originalLocators; +let I; +let data; +let siteUrl; module.exports.init = function (testData) { - data = testData -} + data = testData; +}; module.exports.tests = function () { - const isHelper = (helperName) => I.constructor.name === helperName + const isHelper = (helperName) => I.constructor.name === helperName; beforeEach(() => { - I = data.I - siteUrl = data.siteUrl - if (fileExists(dataFile)) require('fs').unlinkSync(dataFile) - }) + I = data.I; + siteUrl = data.siteUrl; + if (fileExists(dataFile)) require('fs').unlinkSync(dataFile); + }); describe('#saveElementScreenshot', () => { beforeEach(() => { - global.output_dir = path.join(global.codecept_dir, 'output') - }) + global.output_dir = path.join(global.codecept_dir, 'output'); + }); it('should create a screenshot file in output dir of element', async () => { - await I.amOnPage('/form/field') - await I.seeElement("input[name='name']") - const sec = new Date().getUTCMilliseconds() - await I.saveElementScreenshot("input[name='name']", `element_screenshot_${sec}.png`) - assert.ok(fileExists(path.join(global.output_dir, `element_screenshot_${sec}.png`)), null, 'file does not exists') - }) - }) + await I.amOnPage('/form/field'); + await I.seeElement("input[name='name']"); + const sec = new Date().getUTCMilliseconds(); + await I.saveElementScreenshot("input[name='name']", `element_screenshot_${sec}.png`); + assert.ok(fileExists(path.join(global.output_dir, `element_screenshot_${sec}.png`)), null, 'file does not exists'); + }); + }); describe('current url : #seeInCurrentUrl, #seeCurrentUrlEquals, #grabCurrentUrl, ...', () => { it('should check for url fragment', async () => { - await I.amOnPage('/form/checkbox') - await I.seeInCurrentUrl('/form') - await I.dontSeeInCurrentUrl('/user') - }) + await I.amOnPage('/form/checkbox'); + await I.seeInCurrentUrl('/form'); + await I.dontSeeInCurrentUrl('/user'); + }); it('should check for equality', async () => { - await I.amOnPage('/info') - await I.seeCurrentUrlEquals('/info') - await I.dontSeeCurrentUrlEquals('form') - }) + await I.amOnPage('/info'); + await I.seeCurrentUrlEquals('/info'); + await I.dontSeeCurrentUrlEquals('form'); + }); it('should check for equality in absolute urls', async () => { - await I.amOnPage('/info') - await I.seeCurrentUrlEquals(`${siteUrl}/info`) - await I.dontSeeCurrentUrlEquals(`${siteUrl}/form`) - }) + await I.amOnPage('/info'); + await I.seeCurrentUrlEquals(`${siteUrl}/info`); + await I.dontSeeCurrentUrlEquals(`${siteUrl}/form`); + }); it('should grab browser url', async () => { - await I.amOnPage('/info') - const url = await I.grabCurrentUrl() - assert.equal(url, `${siteUrl}/info`) - }) - }) + await I.amOnPage('/info'); + const url = await I.grabCurrentUrl(); + assert.equal(url, `${siteUrl}/info`); + }); + }); describe('#waitInUrl, #waitUrlEquals', () => { it('should wait part of the URL to match the expected', async () => { try { - await I.amOnPage('/info') - await I.waitInUrl('/info') - await I.waitInUrl('/info2', 0.1) + await I.amOnPage('/info'); + await I.waitInUrl('/info'); + await I.waitInUrl('/info2', 0.1); } catch (e) { - assert.include(e.message, `expected url to include /info2, but found ${siteUrl}/info`) + assert.include(e.message, `expected url to include /info2, but found ${siteUrl}/info`); } - }) + }); it('should wait for the entire URL to match the expected', async () => { try { - await I.amOnPage('/info') - await I.waitUrlEquals('/info') - await I.waitUrlEquals(`${siteUrl}/info`) - await I.waitUrlEquals('/info2', 0.1) + await I.amOnPage('/info'); + await I.waitUrlEquals('/info'); + await I.waitUrlEquals(`${siteUrl}/info`); + await I.waitUrlEquals('/info2', 0.1); } catch (e) { - assert.include(e.message, `expected url to be ${siteUrl}/info2, but found ${siteUrl}/info`) + assert.include(e.message, `expected url to be ${siteUrl}/info2, but found ${siteUrl}/info`); } - }) - }) + }); + }); describe('see text : #see', () => { it('should check text on site', async () => { - await I.amOnPage('/') - await I.see('Welcome to test app!') - await I.see('A wise man said: "debug!"') - await I.dontSee('Info') - }) + await I.amOnPage('/'); + await I.see('Welcome to test app!'); + await I.see('A wise man said: "debug!"'); + await I.dontSee('Info'); + }); it('should check text inside element', async () => { - await I.amOnPage('/') - await I.see('Welcome to test app!', 'h1') - await I.amOnPage('/info') - await I.see('valuable', { css: 'p' }) - await I.see('valuable', '//p') - await I.dontSee('valuable', 'h1') - }) + await I.amOnPage('/'); + await I.see('Welcome to test app!', 'h1'); + await I.amOnPage('/info'); + await I.see('valuable', { css: 'p' }); + await I.see('valuable', '//p'); + await I.dontSee('valuable', 'h1'); + }); it('should verify non-latin chars', async () => { - await I.amOnPage('/info') - await I.see('на') - await I.see("Don't do that at home!", 'h3') - await I.see('Текст', 'p') - }) + await I.amOnPage('/info'); + await I.see('на'); + await I.see("Don't do that at home!", 'h3'); + await I.see('Текст', 'p'); + }); it('should verify text with  ', async () => { - if (isHelper('TestCafe') || isHelper('WebDriver')) return - await I.amOnPage('/') - await I.see('With special space chars') - }) - }) + if (isHelper('TestCafe') || isHelper('WebDriver')) return; + await I.amOnPage('/'); + await I.see('With special space chars'); + }); + }); describe('see element : #seeElement, #seeElementInDOM, #dontSeeElement', () => { it('should check visible elements on page', async () => { - await I.amOnPage('/form/field') - await I.seeElement('input[name=name]') - await I.seeElement({ name: 'name' }) - await I.seeElement('//input[@id="name"]') - await I.dontSeeElement('#something-beyond') - await I.dontSeeElement('//input[@id="something-beyond"]') - await I.dontSeeElement({ name: 'noname' }) - await I.dontSeeElement('#noid') - }) + await I.amOnPage('/form/field'); + await I.seeElement('input[name=name]'); + await I.seeElement({ name: 'name' }); + await I.seeElement('//input[@id="name"]'); + await I.dontSeeElement('#something-beyond'); + await I.dontSeeElement('//input[@id="something-beyond"]'); + await I.dontSeeElement({ name: 'noname' }); + await I.dontSeeElement('#noid'); + }); it('should check elements are in the DOM', async () => { - await I.amOnPage('/form/field') - await I.seeElementInDOM('input[name=name]') - await I.seeElementInDOM('//input[@id="name"]') - await I.seeElementInDOM({ name: 'noname' }) - await I.seeElementInDOM('#noid') - await I.dontSeeElementInDOM('#something-beyond') - await I.dontSeeElementInDOM('//input[@id="something-beyond"]') - }) + await I.amOnPage('/form/field'); + await I.seeElementInDOM('input[name=name]'); + await I.seeElementInDOM('//input[@id="name"]'); + await I.seeElementInDOM({ name: 'noname' }); + await I.seeElementInDOM('#noid'); + await I.dontSeeElementInDOM('#something-beyond'); + await I.dontSeeElementInDOM('//input[@id="something-beyond"]'); + }); it('should check elements are visible on the page', async () => { - await I.amOnPage('/form/field') - await I.seeElementInDOM('input[name=email]') - await I.dontSeeElement('input[name=email]') - await I.dontSeeElement('#something-beyond') - }) - }) + await I.amOnPage('/form/field'); + await I.seeElementInDOM('input[name=email]'); + await I.dontSeeElement('input[name=email]'); + await I.dontSeeElement('#something-beyond'); + }); + }); describe('#seeNumberOfVisibleElements', () => { it('should check number of visible elements for given locator', async () => { - await I.amOnPage('/info') - await I.seeNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 3) - }) - }) + await I.amOnPage('/info'); + await I.seeNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 3); + }); + }); describe('#grabNumberOfVisibleElements', () => { it('should grab number of visible elements for given locator', async () => { - await I.amOnPage('/info') - const num = await I.grabNumberOfVisibleElements('//div[@id = "grab-multiple"]//a') - assert.equal(num, 3) - }) + await I.amOnPage('/info'); + const num = await I.grabNumberOfVisibleElements('//div[@id = "grab-multiple"]//a'); + assert.equal(num, 3); + }); it('should support locators like {xpath:"//div"}', async () => { - await I.amOnPage('/info') + await I.amOnPage('/info'); const num = await I.grabNumberOfVisibleElements({ xpath: '//div[@id = "grab-multiple"]//a', - }) - assert.equal(num, 3) - }) + }); + assert.equal(num, 3); + }); it('should grab number of visible elements for given css locator', async () => { - await I.amOnPage('/info') - const num = await I.grabNumberOfVisibleElements('[id=grab-multiple] a') - assert.equal(num, 3) - }) + await I.amOnPage('/info'); + const num = await I.grabNumberOfVisibleElements('[id=grab-multiple] a'); + assert.equal(num, 3); + }); it('should return 0 for non-existing elements', async () => { - await I.amOnPage('/info') - const num = await I.grabNumberOfVisibleElements('button[type=submit]') - assert.equal(num, 0) - }) + await I.amOnPage('/info'); + const num = await I.grabNumberOfVisibleElements('button[type=submit]'); + assert.equal(num, 0); + }); it('should honor visibility hidden style', async () => { - await I.amOnPage('/info') - const num = await I.grabNumberOfVisibleElements('.issue2928') - assert.equal(num, 1) - }) - }) + await I.amOnPage('/info'); + const num = await I.grabNumberOfVisibleElements('.issue2928'); + assert.equal(num, 1); + }); + }); describe('#seeInSource, #dontSeeInSource', () => { it('should check meta of a page', async () => { - await I.amOnPage('/info') - await I.seeInSource('') - await I.dontSeeInSource('') - await I.seeInSource('Invisible text') - await I.seeInSource('content="text/html; charset=utf-8"') - }) - }) + await I.amOnPage('/info'); + await I.seeInSource(''); + await I.dontSeeInSource(''); + await I.seeInSource('Invisible text'); + await I.seeInSource('content="text/html; charset=utf-8"'); + }); + }); describe('#click', () => { it('should click by inner text', async () => { - await I.amOnPage('/') - await I.click('More info') - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.click('More info'); + await I.seeInCurrentUrl('/info'); + }); it('should click by css', async () => { - await I.amOnPage('/') - await I.click('#link') - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.click('#link'); + await I.seeInCurrentUrl('/info'); + }); it('should click by xpath', async () => { - await I.amOnPage('/') - await I.click('//a[@id="link"]') - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.click('//a[@id="link"]'); + await I.seeInCurrentUrl('/info'); + }); it('should click by name', async () => { - await I.amOnPage('/form/button') - await I.click('btn0') - assert.equal(formContents('text'), 'val') - }) + await I.amOnPage('/form/button'); + await I.click('btn0'); + assert.equal(formContents('text'), 'val'); + }); it('should click on context', async () => { - await I.amOnPage('/') - await I.click('More info', 'body>p') - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.click('More info', 'body>p'); + await I.seeInCurrentUrl('/info'); + }); it('should not click wrong context', async () => { - let err = false - await I.amOnPage('/') + let err = false; + await I.amOnPage('/'); try { - await I.click('More info', '#area1') + await I.click('More info', '#area1'); } catch (e) { - err = true + err = true; } - assert.ok(err) - }) + assert.ok(err); + }); it('should should click by aria-label', async () => { - await I.amOnPage('/form/aria') - await I.click('get info') - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/form/aria'); + await I.click('get info'); + await I.seeInCurrentUrl('/info'); + }); it('should click link with inner span', async () => { - await I.amOnPage('/form/example7') - await I.click('Buy Chocolate Bar') - await I.seeCurrentUrlEquals('/') - }) + await I.amOnPage('/form/example7'); + await I.click('Buy Chocolate Bar'); + await I.seeCurrentUrlEquals('/'); + }); it('should click link with xpath locator', async () => { - await I.amOnPage('/form/example7') + await I.amOnPage('/form/example7'); await I.click({ xpath: '(//*[@title = "Chocolate Bar"])[1]', - }) - await I.seeCurrentUrlEquals('/') - }) - }) + }); + await I.seeCurrentUrlEquals('/'); + }); + }); describe('#forceClick', () => { beforeEach(function () { - if (isHelper('TestCafe')) this.skip() - }) + if (isHelper('TestCafe')) this.skip(); + }); it('should forceClick by inner text', async () => { - await I.amOnPage('/') - await I.forceClick('More info') - if (isHelper('Puppeteer')) await I.waitForNavigation() - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.forceClick('More info'); + if (isHelper('Puppeteer')) await I.waitForNavigation(); + await I.seeInCurrentUrl('/info'); + }); it('should forceClick by css', async () => { - await I.amOnPage('/') - await I.forceClick('#link') - if (isHelper('Puppeteer')) await I.waitForNavigation() - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.forceClick('#link'); + if (isHelper('Puppeteer')) await I.waitForNavigation(); + await I.seeInCurrentUrl('/info'); + }); it('should forceClick by xpath', async () => { - await I.amOnPage('/') - await I.forceClick('//a[@id="link"]') - if (isHelper('Puppeteer')) await I.waitForNavigation() - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.forceClick('//a[@id="link"]'); + if (isHelper('Puppeteer')) await I.waitForNavigation(); + await I.seeInCurrentUrl('/info'); + }); it('should forceClick on context', async () => { - await I.amOnPage('/') - await I.forceClick('More info', 'body>p') - if (isHelper('Puppeteer')) await I.waitForNavigation() - await I.seeInCurrentUrl('/info') - }) - }) + await I.amOnPage('/'); + await I.forceClick('More info', 'body>p'); + if (isHelper('Puppeteer')) await I.waitForNavigation(); + await I.seeInCurrentUrl('/info'); + }); + }); // Could not get double click to work describe('#doubleClick', () => { it('it should doubleClick', async () => { - await I.amOnPage('/form/doubleclick') - await I.dontSee('Done') - await I.doubleClick('#block') - await I.see('Done') - }) - }) + await I.amOnPage('/form/doubleclick'); + await I.dontSee('Done'); + await I.doubleClick('#block'); + await I.see('Done'); + }); + }); // rightClick does not seem to work either describe('#rightClick', () => { it('it should rightClick', async () => { - await I.amOnPage('/form/rightclick') - await I.dontSee('right clicked') - await I.rightClick('Lorem Ipsum') - await I.see('right clicked') - }) + await I.amOnPage('/form/rightclick'); + await I.dontSee('right clicked'); + await I.rightClick('Lorem Ipsum'); + await I.see('right clicked'); + }); it('it should rightClick by locator', async () => { - await I.amOnPage('/form/rightclick') - await I.dontSee('right clicked') - await I.rightClick('.context a') - await I.see('right clicked') - }) + await I.amOnPage('/form/rightclick'); + await I.dontSee('right clicked'); + await I.rightClick('.context a'); + await I.see('right clicked'); + }); it('it should rightClick by locator and context', async () => { - await I.amOnPage('/form/rightclick') - await I.dontSee('right clicked') - await I.rightClick('Lorem Ipsum', '.context') - await I.see('right clicked') - }) - }) + await I.amOnPage('/form/rightclick'); + await I.dontSee('right clicked'); + await I.rightClick('Lorem Ipsum', '.context'); + await I.see('right clicked'); + }); + }); describe('#checkOption', () => { it('should check option by css', async () => { - await I.amOnPage('/form/checkbox') - await I.checkOption('#checkin') - await I.click('Submit') - await I.wait(1) - assert.equal(formContents('terms'), 'agree') - }) + await I.amOnPage('/form/checkbox'); + await I.checkOption('#checkin'); + await I.click('Submit'); + await I.wait(1); + assert.equal(formContents('terms'), 'agree'); + }); it('should check option by strict locator', async () => { - await I.amOnPage('/form/checkbox') + await I.amOnPage('/form/checkbox'); await I.checkOption({ id: 'checkin', - }) - await I.click('Submit') - assert.equal(formContents('terms'), 'agree') - }) + }); + await I.click('Submit'); + assert.equal(formContents('terms'), 'agree'); + }); it('should check option by name', async () => { - await I.amOnPage('/form/checkbox') - await I.checkOption('terms') - await I.click('Submit') - assert.equal(formContents('terms'), 'agree') - }) + await I.amOnPage('/form/checkbox'); + await I.checkOption('terms'); + await I.click('Submit'); + assert.equal(formContents('terms'), 'agree'); + }); it('should check option by label', async () => { - await I.amOnPage('/form/checkbox') - await I.checkOption('I Agree') - await I.click('Submit') - assert.equal(formContents('terms'), 'agree') - }) + await I.amOnPage('/form/checkbox'); + await I.checkOption('I Agree'); + await I.click('Submit'); + assert.equal(formContents('terms'), 'agree'); + }); // TODO Having problems with functional style selectors in testcafe // cannot do Selector(css).find(elementByXPath(xpath)) // testcafe always says "xpath is not defined" // const el = Selector(context).find(elementByXPath(Locator.checkable.byText(xpathLocator.literal(field))).with({ boundTestRun: this.t })).with({ boundTestRun: this.t }); it.skip('should check option by context', async () => { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/example1') - await I.checkOption('Remember me next time', '.rememberMe') - await I.click('Login') - assert.equal(formContents('LoginForm').rememberMe, 1) - }) - }) + await I.amOnPage('/form/example1'); + await I.checkOption('Remember me next time', '.rememberMe'); + await I.click('Login'); + assert.equal(formContents('LoginForm').rememberMe, 1); + }); + }); describe('#uncheckOption', () => { it('should uncheck option that is currently checked', async () => { - await I.amOnPage('/info') - await I.uncheckOption('interesting') - await I.dontSeeCheckboxIsChecked('interesting') - }) - }) + await I.amOnPage('/info'); + await I.uncheckOption('interesting'); + await I.dontSeeCheckboxIsChecked('interesting'); + }); + }); describe('#selectOption', () => { it('should select option by css', async () => { - await I.amOnPage('/form/select') - await I.selectOption('form select[name=age]', 'adult') - await I.click('Submit') - assert.equal(formContents('age'), 'adult') - }) + await I.amOnPage('/form/select'); + await I.selectOption('form select[name=age]', 'adult'); + await I.click('Submit'); + assert.equal(formContents('age'), 'adult'); + }); it('should select option by name', async () => { - await I.amOnPage('/form/select') - await I.selectOption('age', 'adult') - await I.click('Submit') - assert.equal(formContents('age'), 'adult') - }) + await I.amOnPage('/form/select'); + await I.selectOption('age', 'adult'); + await I.click('Submit'); + assert.equal(formContents('age'), 'adult'); + }); it('should select option by label', async () => { - await I.amOnPage('/form/select') - await I.selectOption('Select your age', 'dead') - await I.click('Submit') - assert.equal(formContents('age'), 'dead') - }) + await I.amOnPage('/form/select'); + await I.selectOption('Select your age', 'dead'); + await I.click('Submit'); + assert.equal(formContents('age'), 'dead'); + }); it('should select option by label and option text', async () => { - await I.amOnPage('/form/select') - await I.selectOption('Select your age', '21-60') - await I.click('Submit') - assert.equal(formContents('age'), 'adult') - }) + await I.amOnPage('/form/select'); + await I.selectOption('Select your age', '21-60'); + await I.click('Submit'); + assert.equal(formContents('age'), 'adult'); + }); it('should select option by label and option text - with an onchange callback', async () => { - await I.amOnPage('/form/select_onchange') - await I.selectOption('Select a value', 'Option 2') - await I.click('Submit') - assert.equal(formContents('select'), 'option2') - }) + await I.amOnPage('/form/select_onchange'); + await I.selectOption('Select a value', 'Option 2'); + await I.click('Submit'); + assert.equal(formContents('select'), 'option2'); + }); // Could not get multiselect to work with testcafe it('should select multiple options', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/select_multiple') - await I.selectOption('What do you like the most?', ['Play Video Games', 'Have Sex']) - await I.click('Submit') - assert.deepEqual(formContents('like'), ['play', 'adult']) - }) + await I.amOnPage('/form/select_multiple'); + await I.selectOption('What do you like the most?', ['Play Video Games', 'Have Sex']); + await I.click('Submit'); + assert.deepEqual(formContents('like'), ['play', 'adult']); + }); it('should select option by label and option text with additional spaces', async () => { - await I.amOnPage('/form/select_additional_spaces') - await I.selectOption('Select your age', '21-60') - await I.click('Submit') - assert.equal(formContents('age'), 'adult') - }) - }) + await I.amOnPage('/form/select_additional_spaces'); + await I.selectOption('Select your age', '21-60'); + await I.click('Submit'); + assert.equal(formContents('age'), 'adult'); + }); + }); describe('#executeScript', () => { it('should execute synchronous script', async () => { - await I.amOnPage('/') + await I.amOnPage('/'); await I.executeScript(() => { - document.getElementById('link').innerHTML = 'Appended' - }) - await I.see('Appended', 'a') - }) + document.getElementById('link').innerHTML = 'Appended'; + }); + await I.see('Appended', 'a'); + }); it('should return value from sync script', async () => { - await I.amOnPage('/') - const val = await I.executeScript((a) => a + 5, 5) - assert.equal(val, 10) - }) + await I.amOnPage('/'); + const val = await I.executeScript((a) => a + 5, 5); + assert.equal(val, 10); + }); it('should return value from sync script in iframe', async function () { // TODO Not yet implemented - if (isHelper('TestCafe')) this.skip() // TODO Not yet implemented + if (isHelper('TestCafe')) this.skip(); // TODO Not yet implemented - await I.amOnPage('/iframe') - await I.switchTo({ css: 'iframe' }) - const val = await I.executeScript(() => document.getElementsByTagName('h1')[0].innerText) - assert.equal(val, 'Information') - }) + await I.amOnPage('/iframe'); + await I.switchTo({ css: 'iframe' }); + const val = await I.executeScript(() => document.getElementsByTagName('h1')[0].innerText); + assert.equal(val, 'Information'); + }); it('should execute async script', async function () { - if (isHelper('TestCafe')) this.skip() // TODO Not yet implemented - if (isHelper('Playwright')) return // It won't be implemented + if (isHelper('TestCafe')) this.skip(); // TODO Not yet implemented + if (isHelper('Playwright')) return; // It won't be implemented - await I.amOnPage('/') + await I.amOnPage('/'); const val = await I.executeAsyncScript((val, done) => { setTimeout(() => { - document.getElementById('link').innerHTML = val - done(5) - }, 100) - }, 'Timeout') - assert.equal(val, 5) - await I.see('Timeout', 'a') - }) - }) + document.getElementById('link').innerHTML = val; + done(5); + }, 100); + }, 'Timeout'); + assert.equal(val, 5); + await I.see('Timeout', 'a'); + }); + }); describe('#fillField, #appendField', () => { it('should fill input fields', async () => { - await I.amOnPage('/form/field') - await I.fillField('Name', 'Nothing special') - await I.click('Submit') - assert.equal(formContents('name'), 'Nothing special') - }) + await I.amOnPage('/form/field'); + await I.fillField('Name', 'Nothing special'); + await I.click('Submit'); + assert.equal(formContents('name'), 'Nothing special'); + }); it('should fill input fields with secrets', async () => { - await I.amOnPage('/form/field') - await I.fillField('Name', secret('Something special')) - await I.click('Submit') - assert.equal(formContents('name'), 'Something special') - }) + await I.amOnPage('/form/field'); + await I.fillField('Name', secret('Something special')); + await I.click('Submit'); + assert.equal(formContents('name'), 'Something special'); + }); it('should fill field by css', async () => { - await I.amOnPage('/form/field') - await I.fillField('#name', 'Nothing special') - await I.click('Submit') - assert.equal(formContents('name'), 'Nothing special') - }) + await I.amOnPage('/form/field'); + await I.fillField('#name', 'Nothing special'); + await I.click('Submit'); + assert.equal(formContents('name'), 'Nothing special'); + }); it('should fill field by strict locator', async () => { - await I.amOnPage('/form/field') + await I.amOnPage('/form/field'); await I.fillField( { id: 'name', }, 'Nothing special', - ) - await I.click('Submit') - assert.equal(formContents('name'), 'Nothing special') - }) + ); + await I.click('Submit'); + assert.equal(formContents('name'), 'Nothing special'); + }); it('should fill field by name', async () => { - await I.amOnPage('/form/example1') - await I.fillField('LoginForm[username]', 'davert') - await I.fillField('LoginForm[password]', '123456') - await I.click('Login') - assert.equal(formContents('LoginForm').username, 'davert') - assert.equal(formContents('LoginForm').password, '123456') - }) + await I.amOnPage('/form/example1'); + await I.fillField('LoginForm[username]', 'davert'); + await I.fillField('LoginForm[password]', '123456'); + await I.click('Login'); + assert.equal(formContents('LoginForm').username, 'davert'); + assert.equal(formContents('LoginForm').password, '123456'); + }); it('should fill textarea by css', async () => { - await I.amOnPage('/form/textarea') - await I.fillField('textarea', 'Nothing special') - await I.click('Submit') - assert.equal(formContents('description'), 'Nothing special') - }) + await I.amOnPage('/form/textarea'); + await I.fillField('textarea', 'Nothing special'); + await I.click('Submit'); + assert.equal(formContents('description'), 'Nothing special'); + }); it('should fill textarea by label', async () => { - await I.amOnPage('/form/textarea') - await I.fillField('Description', 'Nothing special') - await I.click('Submit') - assert.equal(formContents('description'), 'Nothing special') - }) + await I.amOnPage('/form/textarea'); + await I.fillField('Description', 'Nothing special'); + await I.click('Submit'); + assert.equal(formContents('description'), 'Nothing special'); + }); it('should fill input by aria-label and aria-labelledby', async () => { - await I.amOnPage('/form/aria') - await I.fillField('My Address', 'Home Sweet Home') - await I.fillField('Phone', '123456') - await I.click('Submit') - assert.equal(formContents('my-form-phone'), '123456') - assert.equal(formContents('my-form-address'), 'Home Sweet Home') - }) + await I.amOnPage('/form/aria'); + await I.fillField('My Address', 'Home Sweet Home'); + await I.fillField('Phone', '123456'); + await I.click('Submit'); + assert.equal(formContents('my-form-phone'), '123456'); + assert.equal(formContents('my-form-address'), 'Home Sweet Home'); + }); it('should fill textarea by overwritting the existing value', async () => { - await I.amOnPage('/form/textarea') - await I.fillField('Description', 'Nothing special') - await I.fillField('Description', 'Some other text') - await I.click('Submit') - assert.equal(formContents('description'), 'Some other text') - }) + await I.amOnPage('/form/textarea'); + await I.fillField('Description', 'Nothing special'); + await I.fillField('Description', 'Some other text'); + await I.click('Submit'); + assert.equal(formContents('description'), 'Some other text'); + }); it('should append field value', async () => { - await I.amOnPage('/form/field') - await I.appendField('Name', '_AND_NEW') - await I.click('Submit') - assert.equal(formContents('name'), 'OLD_VALUE_AND_NEW') - }) + await I.amOnPage('/form/field'); + await I.appendField('Name', '_AND_NEW'); + await I.click('Submit'); + assert.equal(formContents('name'), 'OLD_VALUE_AND_NEW'); + }); it.skip('should not fill invisible fields', async () => { - if (isHelper('Playwright')) return // It won't be implemented - await I.amOnPage('/form/field') + if (isHelper('Playwright')) return; // It won't be implemented + await I.amOnPage('/form/field'); try { - I.fillField('email', 'test@1234') + I.fillField('email', 'test@1234'); } catch (e) { - await assert.equal(e.message, 'Error: Field "email" was not found by text|CSS|XPath') + await assert.equal(e.message, 'Error: Field "email" was not found by text|CSS|XPath'); } - }) - }) + }); + }); describe('#clearField', () => { it('should clear a given element', async () => { - await I.amOnPage('/form/field') - await I.fillField('#name', 'Nothing special') - await I.seeInField('#name', 'Nothing special') - await I.clearField('#name') - await I.dontSeeInField('#name', 'Nothing special') - }) + await I.amOnPage('/form/field'); + await I.fillField('#name', 'Nothing special'); + await I.seeInField('#name', 'Nothing special'); + await I.clearField('#name'); + await I.dontSeeInField('#name', 'Nothing special'); + }); it('should clear field by name', async () => { - await I.amOnPage('/form/example1') - await I.clearField('LoginForm[username]') - await I.click('Login') - assert.equal(formContents('LoginForm').username, '') - }) + await I.amOnPage('/form/example1'); + await I.clearField('LoginForm[username]'); + await I.click('Login'); + assert.equal(formContents('LoginForm').username, ''); + }); it('should clear field by locator', async () => { - await I.amOnPage('/form/example1') - await I.clearField('#LoginForm_username') - await I.click('Login') - assert.equal(formContents('LoginForm').username, '') - }) - }) + await I.amOnPage('/form/example1'); + await I.clearField('#LoginForm_username'); + await I.click('Login'); + assert.equal(formContents('LoginForm').username, ''); + }); + }); describe('#type', () => { it('should type into a field', async function () { - if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/form/field') - await I.click('Name') + if (isHelper('TestCafe')) this.skip(); + await I.amOnPage('/form/field'); + await I.click('Name'); - await I.type('Type Test') - await I.seeInField('Name', 'Type Test') + await I.type('Type Test'); + await I.seeInField('Name', 'Type Test'); - await I.fillField('Name', '') + await I.fillField('Name', ''); - await I.type(['T', 'y', 'p', 'e', '2']) - await I.seeInField('Name', 'Type2') - }) + await I.type(['T', 'y', 'p', 'e', '2']); + await I.seeInField('Name', 'Type2'); + }); it('should use delay to slow down typing', async function () { - if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/form/field') - await I.fillField('Name', '') - const time = Date.now() - await I.type('12345', 100) - await I.seeInField('Name', '12345') - assert(Date.now() - time > 500) - }) - }) + if (isHelper('TestCafe')) this.skip(); + await I.amOnPage('/form/field'); + await I.fillField('Name', ''); + const time = Date.now(); + await I.type('12345', 100); + await I.seeInField('Name', '12345'); + assert(Date.now() - time > 500); + }); + }); describe('check fields: #seeInField, #seeCheckboxIsChecked, ...', () => { it('should check for empty field', async () => { - await I.amOnPage('/form/empty') - await I.seeInField('#empty_input', '') - }) + await I.amOnPage('/form/empty'); + await I.seeInField('#empty_input', ''); + }); it('should check for empty textarea', async () => { - await I.amOnPage('/form/empty') - await I.seeInField('#empty_textarea', '') - }) + await I.amOnPage('/form/empty'); + await I.seeInField('#empty_textarea', ''); + }); it('should check field equals', async () => { - await I.amOnPage('/form/field') - await I.seeInField('Name', 'OLD_VALUE') - await I.seeInField('name', 'OLD_VALUE') - await I.seeInField('//input[@id="name"]', 'OLD_VALUE') - await I.dontSeeInField('//input[@id="name"]', 'NOtVALUE') - }) + await I.amOnPage('/form/field'); + await I.seeInField('Name', 'OLD_VALUE'); + await I.seeInField('name', 'OLD_VALUE'); + await I.seeInField('//input[@id="name"]', 'OLD_VALUE'); + await I.dontSeeInField('//input[@id="name"]', 'NOtVALUE'); + }); it('should check textarea equals', async () => { - await I.amOnPage('/form/textarea') - await I.seeInField('Description', 'sunrise') - await I.seeInField('textarea', 'sunrise') - await I.seeInField('//textarea[@id="description"]', 'sunrise') - await I.dontSeeInField('//textarea[@id="description"]', 'sunset') - }) + await I.amOnPage('/form/textarea'); + await I.seeInField('Description', 'sunrise'); + await I.seeInField('textarea', 'sunrise'); + await I.seeInField('//textarea[@id="description"]', 'sunrise'); + await I.dontSeeInField('//textarea[@id="description"]', 'sunset'); + }); it('should check checkbox is checked :)', async () => { - await I.amOnPage('/info') - await I.seeCheckboxIsChecked('input[type=checkbox]') - }) + await I.amOnPage('/info'); + await I.seeCheckboxIsChecked('input[type=checkbox]'); + }); it('should check checkbox is not checked', async () => { - await I.amOnPage('/form/checkbox') - await I.dontSeeCheckboxIsChecked('#checkin') - }) + await I.amOnPage('/form/checkbox'); + await I.dontSeeCheckboxIsChecked('#checkin'); + }); it('should match fields with the same name', async () => { - await I.amOnPage('/form/example20') - await I.seeInField("//input[@name='txtName'][2]", 'emma') - await I.seeInField("input[name='txtName']:nth-child(2)", 'emma') - }) - }) + await I.amOnPage('/form/example20'); + await I.seeInField("//input[@name='txtName'][2]", 'emma'); + await I.seeInField("input[name='txtName']:nth-child(2)", 'emma'); + }); + }); describe('#grabTextFromAll, #grabHTMLFromAll, #grabValueFromAll, #grabAttributeFromAll', () => { it('should grab multiple texts from page', async () => { - await I.amOnPage('/info') - let vals = await I.grabTextFromAll('#grab-multiple a') - assert.equal(vals[0], 'First') - assert.equal(vals[1], 'Second') - assert.equal(vals[2], 'Third') + await I.amOnPage('/info'); + let vals = await I.grabTextFromAll('#grab-multiple a'); + assert.equal(vals[0], 'First'); + assert.equal(vals[1], 'Second'); + assert.equal(vals[2], 'Third'); - await I.amOnPage('/info') - vals = await I.grabTextFromAll('#invalid-id a') - assert.equal(vals.length, 0) - }) + await I.amOnPage('/info'); + vals = await I.grabTextFromAll('#invalid-id a'); + assert.equal(vals.length, 0); + }); it('should grab multiple html from page', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/info') - let vals = await I.grabHTMLFromAll('#grab-multiple a') - assert.equal(vals[0], 'First') - assert.equal(vals[1], 'Second') - assert.equal(vals[2], 'Third') + await I.amOnPage('/info'); + let vals = await I.grabHTMLFromAll('#grab-multiple a'); + assert.equal(vals[0], 'First'); + assert.equal(vals[1], 'Second'); + assert.equal(vals[2], 'Third'); - await I.amOnPage('/info') - vals = await I.grabHTMLFromAll('#invalid-id a') - assert.equal(vals.length, 0) - }) + await I.amOnPage('/info'); + vals = await I.grabHTMLFromAll('#invalid-id a'); + assert.equal(vals.length, 0); + }); it('should grab multiple attribute from element', async () => { - await I.amOnPage('/form/empty') + await I.amOnPage('/form/empty'); const vals = await I.grabAttributeFromAll( { css: 'input', }, 'name', - ) - assert.equal(vals[0], 'text') - assert.equal(vals[1], 'empty_input') - }) + ); + assert.equal(vals[0], 'text'); + assert.equal(vals[1], 'empty_input'); + }); it('Should return empty array if no attribute found', async () => { - await I.amOnPage('/form/empty') + await I.amOnPage('/form/empty'); const vals = await I.grabAttributeFromAll( { css: 'div', }, 'test', - ) - assert.equal(vals.length, 0) - }) + ); + assert.equal(vals.length, 0); + }); it('should grab values if multiple field matches', async () => { - await I.amOnPage('/form/hidden') - let vals = await I.grabValueFromAll('//form/input') - assert.equal(vals[0], 'kill_people') - assert.equal(vals[1], 'Submit') + await I.amOnPage('/form/hidden'); + let vals = await I.grabValueFromAll('//form/input'); + assert.equal(vals[0], 'kill_people'); + assert.equal(vals[1], 'Submit'); - vals = await I.grabValueFromAll("//form/input[@name='action']") - assert.equal(vals[0], 'kill_people') - }) + vals = await I.grabValueFromAll("//form/input[@name='action']"); + assert.equal(vals[0], 'kill_people'); + }); it('Should return empty array if no value found', async () => { - await I.amOnPage('/') - const vals = await I.grabValueFromAll('//form/input') - assert.equal(vals.length, 0) - }) - }) + await I.amOnPage('/'); + const vals = await I.grabValueFromAll('//form/input'); + assert.equal(vals.length, 0); + }); + }); describe('#grabTextFrom, #grabHTMLFrom, #grabValueFrom, #grabAttributeFrom', () => { it('should grab text from page', async () => { - await I.amOnPage('/') - let val = await I.grabTextFrom('h1') - assert.equal(val, 'Welcome to test app!') + await I.amOnPage('/'); + let val = await I.grabTextFrom('h1'); + assert.equal(val, 'Welcome to test app!'); - val = await I.grabTextFrom('//h1') - assert.equal(val, 'Welcome to test app!') - }) + val = await I.grabTextFrom('//h1'); + assert.equal(val, 'Welcome to test app!'); + }); it('should grab html from page', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/info') - const val = await I.grabHTMLFrom('#grab-multiple') + await I.amOnPage('/info'); + const val = await I.grabHTMLFrom('#grab-multiple'); assert.equal( ` First @@ -763,1051 +760,1051 @@ module.exports.tests = function () { Third `, val, - ) - }) + ); + }); it('should grab value from field', async () => { - await I.amOnPage('/form/hidden') - let val = await I.grabValueFrom('#action') - assert.equal(val, 'kill_people') - val = await I.grabValueFrom("//form/input[@name='action']") - assert.equal(val, 'kill_people') - await I.amOnPage('/form/textarea') - val = await I.grabValueFrom('#description') - assert.equal(val, 'sunrise') - await I.amOnPage('/form/select') - val = await I.grabValueFrom('#age') - assert.equal(val, 'oldfag') - }) + await I.amOnPage('/form/hidden'); + let val = await I.grabValueFrom('#action'); + assert.equal(val, 'kill_people'); + val = await I.grabValueFrom("//form/input[@name='action']"); + assert.equal(val, 'kill_people'); + await I.amOnPage('/form/textarea'); + val = await I.grabValueFrom('#description'); + assert.equal(val, 'sunrise'); + await I.amOnPage('/form/select'); + val = await I.grabValueFrom('#age'); + assert.equal(val, 'oldfag'); + }); it('should grab attribute from element', async () => { - await I.amOnPage('/search') + await I.amOnPage('/search'); const val = await I.grabAttributeFrom( { css: 'form', }, 'method', - ) - assert.equal(val, 'get') - }) + ); + assert.equal(val, 'get'); + }); it('should grab custom attribute from element', async () => { - await I.amOnPage('/form/example4') + await I.amOnPage('/form/example4'); const val = await I.grabAttributeFrom( { css: '.navbar-toggle', }, 'data-toggle', - ) - assert.equal(val, 'collapse') - }) - }) + ); + assert.equal(val, 'collapse'); + }); + }); describe('page title : #seeTitle, #dontSeeTitle, #grabTitle', () => { it('should check page title', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/') - await I.seeInTitle('TestEd Beta 2.0') - await I.dontSeeInTitle('Welcome to test app') - await I.amOnPage('/info') - await I.dontSeeInTitle('TestEd Beta 2.0') - }) + await I.amOnPage('/'); + await I.seeInTitle('TestEd Beta 2.0'); + await I.dontSeeInTitle('Welcome to test app'); + await I.amOnPage('/info'); + await I.dontSeeInTitle('TestEd Beta 2.0'); + }); it('should grab page title', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/') - const val = await I.grabTitle() - assert.equal(val, 'TestEd Beta 2.0') - }) - }) + await I.amOnPage('/'); + const val = await I.grabTitle(); + assert.equal(val, 'TestEd Beta 2.0'); + }); + }); describe('#attachFile', () => { it('should upload file located by CSS', async () => { - await I.amOnPage('/form/file') - await I.attachFile('#avatar', 'app/avatar.jpg') - await I.click('Submit') - await I.see('Thank you') - formContents().files.should.have.key('avatar') - formContents().files.avatar.name.should.eql('avatar.jpg') - formContents().files.avatar.type.should.eql('image/jpeg') - }) + await I.amOnPage('/form/file'); + await I.attachFile('#avatar', 'app/avatar.jpg'); + await I.click('Submit'); + await I.see('Thank you'); + formContents().files.should.have.key('avatar'); + formContents().files.avatar.name.should.eql('avatar.jpg'); + formContents().files.avatar.type.should.eql('image/jpeg'); + }); it('should upload file located by label', async () => { - await I.amOnPage('/form/file') - await I.attachFile('Avatar', 'app/avatar.jpg') - await I.click('Submit') - await I.see('Thank you') - formContents().files.should.have.key('avatar') - formContents().files.avatar.name.should.eql('avatar.jpg') - formContents().files.avatar.type.should.eql('image/jpeg') - }) - }) + await I.amOnPage('/form/file'); + await I.attachFile('Avatar', 'app/avatar.jpg'); + await I.click('Submit'); + await I.see('Thank you'); + formContents().files.should.have.key('avatar'); + formContents().files.avatar.name.should.eql('avatar.jpg'); + formContents().files.avatar.type.should.eql('image/jpeg'); + }); + }); describe('#saveScreenshot', () => { beforeEach(() => { - global.output_dir = path.join(global.codecept_dir, 'output') - }) + global.output_dir = path.join(global.codecept_dir, 'output'); + }); it('should create a screenshot file in output dir', async () => { - const sec = new Date().getUTCMilliseconds() - await I.amOnPage('/') - await I.saveScreenshot(`screenshot_${sec}.png`) - assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists') - }) + const sec = new Date().getUTCMilliseconds(); + await I.amOnPage('/'); + await I.saveScreenshot(`screenshot_${sec}.png`); + assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists'); + }); it('should create a full page screenshot file in output dir', async () => { - const sec = new Date().getUTCMilliseconds() - await I.amOnPage('/') - await I.saveScreenshot(`screenshot_full_${+sec}.png`, true) - assert.ok(fileExists(path.join(global.output_dir, `screenshot_full_${+sec}.png`)), null, 'file does not exists') - }) - }) + const sec = new Date().getUTCMilliseconds(); + await I.amOnPage('/'); + await I.saveScreenshot(`screenshot_full_${+sec}.png`, true); + assert.ok(fileExists(path.join(global.output_dir, `screenshot_full_${+sec}.png`)), null, 'file does not exists'); + }); + }); describe('cookies : #setCookie, #clearCookies, #seeCookie, #waitForCookie', () => { it('should do all cookie stuff', async () => { - await I.amOnPage('/') + await I.amOnPage('/'); await I.setCookie({ name: 'auth', value: '123456', url: 'http://localhost', - }) - await I.seeCookie('auth') - await I.dontSeeCookie('auuth') + }); + await I.seeCookie('auth'); + await I.dontSeeCookie('auuth'); - const cookie = await I.grabCookie('auth') - assert.equal(cookie.value, '123456') + const cookie = await I.grabCookie('auth'); + assert.equal(cookie.value, '123456'); - await I.clearCookie('auth') - await I.dontSeeCookie('auth') - }) + await I.clearCookie('auth'); + await I.dontSeeCookie('auth'); + }); it('should grab all cookies', async () => { - await I.amOnPage('/') + await I.amOnPage('/'); await I.setCookie({ name: 'auth', value: '123456', url: 'http://localhost', - }) + }); await I.setCookie({ name: 'user', value: 'davert', url: 'http://localhost', - }) + }); - const cookies = await I.grabCookie() - assert.equal(cookies.length, 2) - assert(cookies[0].name) - assert(cookies[0].value) - }) + const cookies = await I.grabCookie(); + assert.equal(cookies.length, 2); + assert(cookies[0].name); + assert(cookies[0].value); + }); it('should clear all cookies', async () => { - await I.amOnPage('/') + await I.amOnPage('/'); await I.setCookie({ name: 'auth', value: '123456', url: 'http://localhost', - }) - await I.clearCookie() - await I.dontSeeCookie('auth') - }) + }); + await I.clearCookie(); + await I.dontSeeCookie('auth'); + }); it('should wait for cookie and throw error when cookie not found', async () => { - if (isHelper('TestCafe')) return - if (process.env.DevTools) return + if (isHelper('TestCafe')) return; + if (process.env.DevTools) return; - await I.amOnPage('https://google.com') + await I.amOnPage('https://google.com'); try { - await I.waitForCookie('auth', 2) + await I.waitForCookie('auth', 2); } catch (e) { - assert.equal(e.message, 'Cookie auth is not found after 2s') + assert.equal(e.message, 'Cookie auth is not found after 2s'); } - }) + }); it('should wait for cookie', async () => { - if (isHelper('TestCafe')) return - if (process.env.DevTools) return + if (isHelper('TestCafe')) return; + if (process.env.DevTools) return; - await I.amOnPage('/') + await I.amOnPage('/'); await I.setCookie({ name: 'auth', value: '123456', url: 'http://localhost', - }) - await I.waitForCookie('auth') - }) - }) + }); + await I.waitForCookie('auth'); + }); + }); describe('#waitForText', () => { it('should wait for text', async () => { - await I.amOnPage('/dynamic') - await I.dontSee('Dynamic text') - await I.waitForText('Dynamic text', 2) - await I.see('Dynamic text') - }) + await I.amOnPage('/dynamic'); + await I.dontSee('Dynamic text'); + await I.waitForText('Dynamic text', 2); + await I.see('Dynamic text'); + }); it('should wait for text in context', async () => { - await I.amOnPage('/dynamic') - await I.dontSee('Dynamic text') - await I.waitForText('Dynamic text', 2, '#text') - await I.see('Dynamic text') - }) + await I.amOnPage('/dynamic'); + await I.dontSee('Dynamic text'); + await I.waitForText('Dynamic text', 2, '#text'); + await I.see('Dynamic text'); + }); it('should fail if no context', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - let failed = false - await I.amOnPage('/dynamic') - await I.dontSee('Dynamic text') + let failed = false; + await I.amOnPage('/dynamic'); + await I.dontSee('Dynamic text'); try { - await I.waitForText('Dynamic text', 1, '#fext') + await I.waitForText('Dynamic text', 1, '#fext'); } catch (e) { - failed = true + failed = true; } - assert.ok(failed) - }) + assert.ok(failed); + }); it("should fail if text doesn't contain", async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - let failed = false - await I.amOnPage('/dynamic') + let failed = false; + await I.amOnPage('/dynamic'); try { - await I.waitForText('Other text', 1) + await I.waitForText('Other text', 1); } catch (e) { - failed = true + failed = true; } - assert.ok(failed) - }) + assert.ok(failed); + }); it('should fail if text is not in element', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - let failed = false - await I.amOnPage('/dynamic') + let failed = false; + await I.amOnPage('/dynamic'); try { - await I.waitForText('Other text', 1, '#text') + await I.waitForText('Other text', 1, '#text'); } catch (e) { - failed = true + failed = true; } - assert.ok(failed) - }) + assert.ok(failed); + }); it('should wait for text after timeout', async () => { - await I.amOnPage('/timeout') - await I.dontSee('Timeout text') - await I.waitForText('Timeout text', 31, '#text') - await I.see('Timeout text') - }) + await I.amOnPage('/timeout'); + await I.dontSee('Timeout text'); + await I.waitForText('Timeout text', 31, '#text'); + await I.see('Timeout text'); + }); it('should wait for text located by XPath', async () => { - await I.amOnPage('/dynamic') - await I.dontSee('Dynamic text') - await I.waitForText('Dynamic text', 5, '//div[@id="text"]') - }) + await I.amOnPage('/dynamic'); + await I.dontSee('Dynamic text'); + await I.waitForText('Dynamic text', 5, '//div[@id="text"]'); + }); it('should throw error when text not found', async () => { - await I.amOnPage('/dynamic') - await I.dontSee('Dynamic text') - let failed = false + await I.amOnPage('/dynamic'); + await I.dontSee('Dynamic text'); + let failed = false; try { - await I.waitForText('Some text', 1, '//div[@id="text"]') + await I.waitForText('Some text', 1, '//div[@id="text"]'); } catch (e) { - failed = true + failed = true; } - assert.ok(failed) - }) - }) + assert.ok(failed); + }); + }); describe('#waitForElement', () => { it('should wait for visible element', async () => { - await I.amOnPage('/form/wait_visible') - await I.dontSee('Step One Button') - await I.dontSeeElement('#step_1') - await I.waitForVisible('#step_1', 2) - await I.seeElement('#step_1') - await I.click('#step_1') - await I.waitForVisible('#step_2', 2) - await I.see('Step Two Button') - }) + await I.amOnPage('/form/wait_visible'); + await I.dontSee('Step One Button'); + await I.dontSeeElement('#step_1'); + await I.waitForVisible('#step_1', 2); + await I.seeElement('#step_1'); + await I.click('#step_1'); + await I.waitForVisible('#step_2', 2); + await I.see('Step Two Button'); + }); it('should wait for element in DOM', async () => { - await I.amOnPage('/form/wait_visible') - await I.waitForElement('#step_2') - await I.dontSeeElement('#step_2') - await I.seeElementInDOM('#step_2') - }) + await I.amOnPage('/form/wait_visible'); + await I.waitForElement('#step_2'); + await I.dontSeeElement('#step_2'); + await I.seeElementInDOM('#step_2'); + }); it('should wait for element by XPath', async () => { - await I.amOnPage('/form/wait_visible') - await I.waitForElement('//div[@id="step_2"]') - await I.dontSeeElement('//div[@id="step_2"]') - await I.seeElementInDOM('//div[@id="step_2"]') - }) + await I.amOnPage('/form/wait_visible'); + await I.waitForElement('//div[@id="step_2"]'); + await I.dontSeeElement('//div[@id="step_2"]'); + await I.seeElementInDOM('//div[@id="step_2"]'); + }); it('should wait for element to appear', async () => { - await I.amOnPage('/form/wait_element') - await I.dontSee('Hello') - await I.dontSeeElement('h1') - await I.waitForElement('h1', 2) - await I.see('Hello') - }) - }) + await I.amOnPage('/form/wait_element'); + await I.dontSee('Hello'); + await I.dontSeeElement('h1'); + await I.waitForElement('h1', 2); + await I.see('Hello'); + }); + }); describe('#waitForInvisible', () => { it('should wait for element to be invisible', async () => { - await I.amOnPage('/form/wait_invisible') - await I.see('Step One Button') - await I.seeElement('#step_1') - await I.waitForInvisible('#step_1', 2) - await I.dontSeeElement('#step_1') - }) + await I.amOnPage('/form/wait_invisible'); + await I.see('Step One Button'); + await I.seeElement('#step_1'); + await I.waitForInvisible('#step_1', 2); + await I.dontSeeElement('#step_1'); + }); it('should wait for element to be invisible by XPath', async () => { - await I.amOnPage('/form/wait_invisible') - await I.seeElement('//div[@id="step_1"]') - await I.waitForInvisible('//div[@id="step_1"]') - await I.dontSeeElement('//div[@id="step_1"]') - await I.seeElementInDOM('//div[@id="step_1"]') - }) + await I.amOnPage('/form/wait_invisible'); + await I.seeElement('//div[@id="step_1"]'); + await I.waitForInvisible('//div[@id="step_1"]'); + await I.dontSeeElement('//div[@id="step_1"]'); + await I.seeElementInDOM('//div[@id="step_1"]'); + }); it('should wait for element to be removed', async () => { - await I.amOnPage('/form/wait_invisible') - await I.see('Step Two Button') - await I.seeElement('#step_2') - await I.waitForInvisible('#step_2', 2) - await I.dontSeeElement('#step_2') - }) + await I.amOnPage('/form/wait_invisible'); + await I.see('Step Two Button'); + await I.seeElement('#step_2'); + await I.waitForInvisible('#step_2', 2); + await I.dontSeeElement('#step_2'); + }); it('should wait for element to be removed by XPath', async () => { - await I.amOnPage('/form/wait_invisible') - await I.see('Step Two Button') - await I.seeElement('//div[@id="step_2"]') - await I.waitForInvisible('//div[@id="step_2"]', 2) - await I.dontSeeElement('//div[@id="step_2"]') - }) - }) + await I.amOnPage('/form/wait_invisible'); + await I.see('Step Two Button'); + await I.seeElement('//div[@id="step_2"]'); + await I.waitForInvisible('//div[@id="step_2"]', 2); + await I.dontSeeElement('//div[@id="step_2"]'); + }); + }); describe('#waitToHide', () => { it('should wait for element to be invisible', async () => { - await I.amOnPage('/form/wait_invisible') - await I.see('Step One Button') - await I.seeElement('#step_1') - await I.waitToHide('#step_1', 2) - await I.dontSeeElement('#step_1') - }) + await I.amOnPage('/form/wait_invisible'); + await I.see('Step One Button'); + await I.seeElement('#step_1'); + await I.waitToHide('#step_1', 2); + await I.dontSeeElement('#step_1'); + }); it('should wait for element to be invisible by XPath', async () => { - await I.amOnPage('/form/wait_invisible') - await I.seeElement('//div[@id="step_1"]') - await I.waitToHide('//div[@id="step_1"]') - await I.dontSeeElement('//div[@id="step_1"]') - await I.seeElementInDOM('//div[@id="step_1"]') - }) + await I.amOnPage('/form/wait_invisible'); + await I.seeElement('//div[@id="step_1"]'); + await I.waitToHide('//div[@id="step_1"]'); + await I.dontSeeElement('//div[@id="step_1"]'); + await I.seeElementInDOM('//div[@id="step_1"]'); + }); it('should wait for element to be removed', async () => { - await I.amOnPage('/form/wait_invisible') - await I.see('Step Two Button') - await I.seeElement('#step_2') - await I.waitToHide('#step_2', 2) - await I.dontSeeElement('#step_2') - }) + await I.amOnPage('/form/wait_invisible'); + await I.see('Step Two Button'); + await I.seeElement('#step_2'); + await I.waitToHide('#step_2', 2); + await I.dontSeeElement('#step_2'); + }); it('should wait for element to be removed by XPath', async () => { - await I.amOnPage('/form/wait_invisible') - await I.see('Step Two Button') - await I.seeElement('//div[@id="step_2"]') - await I.waitToHide('//div[@id="step_2"]', 2) - await I.dontSeeElement('//div[@id="step_2"]') - }) - }) + await I.amOnPage('/form/wait_invisible'); + await I.see('Step Two Button'); + await I.seeElement('//div[@id="step_2"]'); + await I.waitToHide('//div[@id="step_2"]', 2); + await I.dontSeeElement('//div[@id="step_2"]'); + }); + }); describe('#waitForDetached', () => { it('should throw an error if the element still exists in DOM', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/wait_detached') - await I.see('Step One Button') - await I.seeElement('#step_1') + await I.amOnPage('/form/wait_detached'); + await I.see('Step One Button'); + await I.seeElement('#step_1'); try { - await I.waitForDetached('#step_1', 2) - throw Error('Should not get this far') + await I.waitForDetached('#step_1', 2); + throw Error('Should not get this far'); } catch (err) { - err.message.should.include('still on page after') + err.message.should.include('still on page after'); } - }) + }); it('should throw an error if the element still exists in DOM by XPath', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/wait_detached') - await I.see('Step One Button') - await I.seeElement('#step_1') + await I.amOnPage('/form/wait_detached'); + await I.see('Step One Button'); + await I.seeElement('#step_1'); try { - await I.waitForDetached('#step_1', 2) - throw Error('Should not get this far') + await I.waitForDetached('#step_1', 2); + throw Error('Should not get this far'); } catch (err) { - err.message.should.include('still on page after') + err.message.should.include('still on page after'); } - }) + }); it('should wait for element to be removed from DOM', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/wait_detached') - await I.see('Step Two Button') - await I.seeElement('#step_2') - await I.waitForDetached('#step_2', 2) - await I.dontSeeElementInDOM('#step_2') - }) + await I.amOnPage('/form/wait_detached'); + await I.see('Step Two Button'); + await I.seeElement('#step_2'); + await I.waitForDetached('#step_2', 2); + await I.dontSeeElementInDOM('#step_2'); + }); it('should wait for element to be removed from DOM by XPath', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/wait_detached') - await I.seeElement('//div[@id="step_2"]') - await I.waitForDetached('//div[@id="step_2"]') - await I.dontSeeElement('//div[@id="step_2"]') - await I.dontSeeElementInDOM('//div[@id="step_2"]') - }) - }) + await I.amOnPage('/form/wait_detached'); + await I.seeElement('//div[@id="step_2"]'); + await I.waitForDetached('//div[@id="step_2"]'); + await I.dontSeeElement('//div[@id="step_2"]'); + await I.dontSeeElementInDOM('//div[@id="step_2"]'); + }); + }); describe('within tests', () => { - afterEach(() => I._withinEnd()) + afterEach(() => I._withinEnd()); it('should execute within block', async () => { - await I.amOnPage('/form/example4') - await I.seeElement('#navbar-collapse-menu') + await I.amOnPage('/form/example4'); + await I.seeElement('#navbar-collapse-menu'); I._withinBegin('#register') .then(() => I.see('E-Mail')) .then(() => I.dontSee('Toggle navigation')) - .then(() => I.dontSeeElement('#navbar-collapse-menu')) - }) + .then(() => I.dontSeeElement('#navbar-collapse-menu')); + }); it('should respect form fields inside within block ', async () => { - let rethrow - - await I.amOnPage('/form/example4') - await I.seeElement('#navbar-collapse-menu') - await I.see('E-Mail') - await I.see('Hasło') - await I.fillField('Hasło', '12345') - await I.seeInField('Hasło', '12345') - await I.checkOption('terms') - await I.seeCheckboxIsChecked('terms') + let rethrow; + + await I.amOnPage('/form/example4'); + await I.seeElement('#navbar-collapse-menu'); + await I.see('E-Mail'); + await I.see('Hasło'); + await I.fillField('Hasło', '12345'); + await I.seeInField('Hasło', '12345'); + await I.checkOption('terms'); + await I.seeCheckboxIsChecked('terms'); I._withinBegin({ css: '.form-group' }) .then(() => I.see('E-Mail')) .then(() => I.dontSee('Hasło')) - .then(() => I.dontSeeElement('#navbar-collapse-menu')) + .then(() => I.dontSeeElement('#navbar-collapse-menu')); try { - await I.dontSeeCheckboxIsChecked('terms') + await I.dontSeeCheckboxIsChecked('terms'); } catch (err) { - if (!err) assert.fail('seen checkbox') + if (!err) assert.fail('seen checkbox'); } try { - await I.seeInField('Hasło', '12345') + await I.seeInField('Hasło', '12345'); } catch (err) { - if (!err) assert.fail('seen field') + if (!err) assert.fail('seen field'); } - if (rethrow) throw rethrow - }) + if (rethrow) throw rethrow; + }); it('should execute within block 2', async () => { - await I.amOnPage('/form/example4') - await I.fillField('Hasło', '12345') + await I.amOnPage('/form/example4'); + await I.fillField('Hasło', '12345'); I._withinBegin({ xpath: '//div[@class="form-group"][2]' }) .then(() => I.dontSee('E-Mail')) .then(() => I.see('Hasło')) .then(() => I.grabTextFrom('label')) .then((label) => assert.equal(label, 'Hasło')) .then(() => I.grabValueFrom('input')) - .then((input) => assert.equal(input, '12345')) - }) + .then((input) => assert.equal(input, '12345')); + }); it('within should respect context in see', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/example4') - await I.see('Rejestracja', 'fieldset') + await I.amOnPage('/form/example4'); + await I.see('Rejestracja', 'fieldset'); I._withinBegin({ css: '.navbar-header' }) .then(() => I.see('Rejestracja', '.container fieldset')) - .then(() => I.see('Toggle navigation', '.container fieldset')) - }) + .then(() => I.see('Toggle navigation', '.container fieldset')); + }); it('within should respect context in see when using nested frames', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/iframe_nested') + await I.amOnPage('/iframe_nested'); await I._withinBegin({ frame: ['#wrapperId', '[name=content]'], - }) + }); try { - await I.see('Kill & Destroy') + await I.see('Kill & Destroy'); } catch (err) { - if (!err) assert.fail('seen "Kill & Destroy"') + if (!err) assert.fail('seen "Kill & Destroy"'); } try { - await I.dontSee('Nested Iframe test') + await I.dontSee('Nested Iframe test'); } catch (err) { - if (!err) assert.fail('seen "Nested Iframe test"') + if (!err) assert.fail('seen "Nested Iframe test"'); } try { - await I.dontSee('Iframe test') + await I.dontSee('Iframe test'); } catch (err) { - if (!err) assert.fail('seen "Iframe test"') + if (!err) assert.fail('seen "Iframe test"'); } - }) + }); it('within should respect context in see when using frame', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/iframe') + await I.amOnPage('/iframe'); await I._withinBegin({ frame: '#number-frame-1234', - }) + }); try { - await I.see('Information') + await I.see('Information'); } catch (err) { - if (!err) assert.fail('seen "Information"') + if (!err) assert.fail('seen "Information"'); } - }) + }); it('within should respect context in see when using frame with strict locator', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/iframe') + await I.amOnPage('/iframe'); await I._withinBegin({ frame: { css: '#number-frame-1234' }, - }) + }); try { - await I.see('Information') + await I.see('Information'); } catch (err) { - if (!err) assert.fail('seen "Information"') + if (!err) assert.fail('seen "Information"'); } - }) - }) + }); + }); describe('scroll: #scrollTo, #scrollPageToTop, #scrollPageToBottom', () => { it('should scroll inside an iframe', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/iframe') - await I.resizeWindow(500, 700) - await I.switchTo(0) + await I.amOnPage('/iframe'); + await I.resizeWindow(500, 700); + await I.switchTo(0); - const { x, y } = await I.grabPageScrollPosition() - await I.scrollTo('.sign') + const { x, y } = await I.grabPageScrollPosition(); + await I.scrollTo('.sign'); - const { x: afterScrollX, y: afterScrollY } = await I.grabPageScrollPosition() - assert.notEqual(afterScrollY, y) - assert.equal(afterScrollX, x) - }) + const { x: afterScrollX, y: afterScrollY } = await I.grabPageScrollPosition(); + assert.notEqual(afterScrollY, y); + assert.equal(afterScrollX, x); + }); it('should scroll to an element', async () => { - await I.amOnPage('/form/scroll') - await I.resizeWindow(500, 700) - const { y } = await I.grabPageScrollPosition() - await I.scrollTo('.section3 input[name="test"]') + await I.amOnPage('/form/scroll'); + await I.resizeWindow(500, 700); + const { y } = await I.grabPageScrollPosition(); + await I.scrollTo('.section3 input[name="test"]'); - const { y: afterScrollY } = await I.grabPageScrollPosition() - assert.notEqual(afterScrollY, y) - }) + const { y: afterScrollY } = await I.grabPageScrollPosition(); + assert.notEqual(afterScrollY, y); + }); it('should scroll to coordinates', async () => { - await I.amOnPage('/form/scroll') - await I.resizeWindow(500, 700) - await I.scrollTo(50, 70) + await I.amOnPage('/form/scroll'); + await I.resizeWindow(500, 700); + await I.scrollTo(50, 70); - const { x: afterScrollX, y: afterScrollY } = await I.grabPageScrollPosition() - assert.equal(afterScrollX, 50) - assert.equal(afterScrollY, 70) - }) + const { x: afterScrollX, y: afterScrollY } = await I.grabPageScrollPosition(); + assert.equal(afterScrollX, 50); + assert.equal(afterScrollY, 70); + }); it('should scroll to bottom of page', async () => { - await I.amOnPage('/form/scroll') - await I.resizeWindow(500, 700) - const { y } = await I.grabPageScrollPosition() - await I.scrollPageToBottom() + await I.amOnPage('/form/scroll'); + await I.resizeWindow(500, 700); + const { y } = await I.grabPageScrollPosition(); + await I.scrollPageToBottom(); - const { y: afterScrollY } = await I.grabPageScrollPosition() - assert.notEqual(afterScrollY, y) - assert.notEqual(afterScrollY, 0) - }) + const { y: afterScrollY } = await I.grabPageScrollPosition(); + assert.notEqual(afterScrollY, y); + assert.notEqual(afterScrollY, 0); + }); it('should scroll to top of page', async () => { - await I.amOnPage('/form/scroll') - await I.resizeWindow(500, 700) - await I.scrollPageToBottom() - const { y } = await I.grabPageScrollPosition() - await I.scrollPageToTop() - - const { y: afterScrollY } = await I.grabPageScrollPosition() - assert.notEqual(afterScrollY, y) - assert.equal(afterScrollY, 0) - }) - }) + await I.amOnPage('/form/scroll'); + await I.resizeWindow(500, 700); + await I.scrollPageToBottom(); + const { y } = await I.grabPageScrollPosition(); + await I.scrollPageToTop(); + + const { y: afterScrollY } = await I.grabPageScrollPosition(); + assert.notEqual(afterScrollY, y); + assert.equal(afterScrollY, 0); + }); + }); describe('#grabCssPropertyFrom', () => { it('should grab css property for given element', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/doubleclick') - const css = await I.grabCssPropertyFrom('#block', 'height') - assert.equal(css, '100px') - }) + await I.amOnPage('/form/doubleclick'); + const css = await I.grabCssPropertyFrom('#block', 'height'); + assert.equal(css, '100px'); + }); it('should grab camelcased css properies', async () => { - if (isHelper('TestCafe')) return + if (isHelper('TestCafe')) return; - await I.amOnPage('/form/doubleclick') - const css = await I.grabCssPropertyFrom('#block', 'user-select') - assert.equal(css, 'text') - }) + await I.amOnPage('/form/doubleclick'); + const css = await I.grabCssPropertyFrom('#block', 'user-select'); + assert.equal(css, 'text'); + }); it('should grab multiple values if more than one matching element found', async () => { - if (isHelper('TestCafe')) return + if (isHelper('TestCafe')) return; - await I.amOnPage('/info') - const css = await I.grabCssPropertyFromAll('.span', 'height') - assert.equal(css[0], '12px') - assert.equal(css[1], '15px') - }) - }) + await I.amOnPage('/info'); + const css = await I.grabCssPropertyFromAll('.span', 'height'); + assert.equal(css[0], '12px'); + assert.equal(css[1], '15px'); + }); + }); describe('#seeAttributesOnElements', () => { it('should check attributes values for given element', async function () { - if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip() + if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip(); try { - await I.amOnPage('/info') + await I.amOnPage('/info'); await I.seeAttributesOnElements('//form', { method: 'post', - }) + }); await I.seeAttributesOnElements('//form', { method: 'get', - }) - throw Error('It should never get this far') + }); + throw Error('It should never get this far'); } catch (e) { - e.message.should.include('all elements (//form) to have attributes {"method":"get"}') + e.message.should.include('all elements (//form) to have attributes {"method":"get"}'); } - }) + }); it('should check href with slash', async function () { - if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip() + if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip(); try { - await I.amOnPage('https://github.com/codeceptjs/CodeceptJS/') + await I.amOnPage('https://github.com/codeceptjs/CodeceptJS/'); await I.seeAttributesOnElements( { css: 'a[href="/codeceptjs/CodeceptJS"]' }, { href: '/codeceptjs/CodeceptJS', }, - ) + ); } catch (e) { e.message.should.include( - 'all elements (a[href="/codeceptjs/CodeceptJS"]) to have attributes {"href"="/codeceptjs/CodeceptJS"}', - ) + 'all elements (a[href="/codeceptjs/CodeceptJS"]) to have attributes {"href":"/codeceptjs/CodeceptJS"}', + ); } - }) + }); it('should check attributes values for several elements', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); try { - await I.amOnPage('/') + await I.amOnPage('/'); await I.seeAttributesOnElements('a', { 'qa-id': 'test', 'qa-link': 'test', - }) + }); await I.seeAttributesOnElements('//div', { 'qa-id': 'test', - }) + }); await I.seeAttributesOnElements('a', { 'qa-id': 'test', href: '/info', - }) - throw new Error('It should never get this far') + }); + throw new Error('It should never get this far'); } catch (e) { - e.message.should.include('all elements (a) to have attributes {"qa-id":"test","href":"/info"}') + e.message.should.include('all elements (a) to have attributes {"qa-id":"test","href":"/info"}'); } - }) + }); it('should return error when using non existing attribute', async function () { - if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip() + if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip(); try { - await I.amOnPage('https://github.com/codeceptjs/CodeceptJS/') + await I.amOnPage('https://github.com/codeceptjs/CodeceptJS/'); await I.seeAttributesOnElements( { css: 'a[href="/codeceptjs/CodeceptJS"]' }, { disable: true, }, - ) + ); } catch (e) { e.message.should.include( 'expected all elements ({css: a[href="/codeceptjs/CodeceptJS"]}) to have attributes {"disable":true} "0" to equal "3"', - ) + ); } - }) + }); it('should verify the boolean attribute', async function () { - if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip() + if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip(); try { - await I.amOnPage('/') + await I.amOnPage('/'); await I.seeAttributesOnElements('input', { disabled: true, - }) + }); } catch (e) { - e.message.should.include('expected all elements (input) to have attributes {"disabled":true} "0" to equal "1"') + e.message.should.include('expected all elements (input) to have attributes {"disabled":true} "0" to equal "1"'); } - }) - }) + }); + }); describe('#seeCssPropertiesOnElements', () => { it('should check css property for given element', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); try { - await I.amOnPage('/info') + await I.amOnPage('/info'); await I.seeCssPropertiesOnElements('h4', { 'font-weight': 300, - }) + }); await I.seeCssPropertiesOnElements('h3', { 'font-weight': 'bold', display: 'block', - }) + }); await I.seeCssPropertiesOnElements('h3', { 'font-weight': 'non-bold', - }) - throw Error('It should never get this far') + }); + throw Error('It should never get this far'); } catch (e) { - e.message.should.include('expected all elements (h3) to have CSS property {"font-weight":"non-bold"}') + e.message.should.include('expected all elements (h3) to have CSS property {"font-weight":"non-bold"}'); } - }) + }); it('should check css property for several elements', async function () { - if (isHelper('TestCafe') || process.env.BROWSER === 'firefox' || process.env.DevTools === 'true') this.skip() + if (isHelper('TestCafe') || process.env.BROWSER === 'firefox' || process.env.DevTools === 'true') this.skip(); try { - await I.amOnPage('/') + await I.amOnPage('/'); await I.seeCssPropertiesOnElements('a', { color: 'rgb(0, 0, 238)', cursor: 'pointer', - }) + }); await I.seeCssPropertiesOnElements('a', { color: '#0000EE', cursor: 'pointer', - }) + }); await I.seeCssPropertiesOnElements('//div', { display: 'block', - }) + }); await I.seeCssPropertiesOnElements('a', { 'margin-top': '0em', cursor: 'pointer', - }) - throw Error('It should never get this far') + }); + throw Error('It should never get this far'); } catch (e) { e.message.should.include( 'expected all elements (a) to have CSS property {"margin-top":"0em","cursor":"pointer"}', - ) + ); } - }) + }); it('should normalize css color properties for given element', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/css_colors') + await I.amOnPage('/form/css_colors'); await I.seeCssPropertiesOnElements('#namedColor', { 'background-color': 'purple', color: 'yellow', - }) + }); await I.seeCssPropertiesOnElements('#namedColor', { 'background-color': '#800080', color: '#ffff00', - }) + }); await I.seeCssPropertiesOnElements('#namedColor', { 'background-color': 'rgb(128,0,128)', color: 'rgb(255,255,0)', - }) + }); await I.seeCssPropertiesOnElements('#namedColor', { 'background-color': 'rgba(128,0,128,1)', color: 'rgba(255,255,0,1)', - }) - }) - }) + }); + }); + }); describe('#customLocators', () => { beforeEach(() => { - originalLocators = Locator.filters - Locator.filters = [] - }) + originalLocators = Locator.filters; + Locator.filters = []; + }); afterEach(() => { // reset custom locators - Locator.filters = originalLocators - }) + Locator.filters = originalLocators; + }); it('should support xpath custom locator by default', async () => { customLocators({ attribute: 'data-test-id', enabled: true, - }) - await I.amOnPage('/form/custom_locator') - await I.dontSee('Step One Button') - await I.dontSeeElement('$step_1') - await I.waitForVisible('$step_1', 2) - await I.seeElement('$step_1') - await I.click('$step_1') - await I.waitForVisible('$step_2', 2) - await I.see('Step Two Button') - }) + }); + await I.amOnPage('/form/custom_locator'); + await I.dontSee('Step One Button'); + await I.dontSeeElement('$step_1'); + await I.waitForVisible('$step_1', 2); + await I.seeElement('$step_1'); + await I.click('$step_1'); + await I.waitForVisible('$step_2', 2); + await I.see('Step Two Button'); + }); it('can use css strategy for custom locator', async () => { customLocators({ attribute: 'data-test-id', enabled: true, strategy: 'css', - }) - await I.amOnPage('/form/custom_locator') - await I.dontSee('Step One Button') - await I.dontSeeElement('$step_1') - await I.waitForVisible('$step_1', 2) - await I.seeElement('$step_1') - await I.click('$step_1') - await I.waitForVisible('$step_2', 2) - await I.see('Step Two Button') - }) + }); + await I.amOnPage('/form/custom_locator'); + await I.dontSee('Step One Button'); + await I.dontSeeElement('$step_1'); + await I.waitForVisible('$step_1', 2); + await I.seeElement('$step_1'); + await I.click('$step_1'); + await I.waitForVisible('$step_2', 2); + await I.see('Step Two Button'); + }); it('can use xpath strategy for custom locator', async () => { customLocators({ attribute: 'data-test-id', enabled: true, strategy: 'xpath', - }) - await I.amOnPage('/form/custom_locator') - await I.dontSee('Step One Button') - await I.dontSeeElement('$step_1') - await I.waitForVisible('$step_1', 2) - await I.seeElement('$step_1') - await I.click('$step_1') - await I.waitForVisible('$step_2', 2) - await I.see('Step Two Button') - }) - }) + }); + await I.amOnPage('/form/custom_locator'); + await I.dontSee('Step One Button'); + await I.dontSeeElement('$step_1'); + await I.waitForVisible('$step_1', 2); + await I.seeElement('$step_1'); + await I.click('$step_1'); + await I.waitForVisible('$step_2', 2); + await I.see('Step Two Button'); + }); + }); describe('#focus, #blur', () => { it('should focus a button, field and textarea', async () => { - await I.amOnPage('/form/focus_blur_elements') + await I.amOnPage('/form/focus_blur_elements'); - await I.focus('#button') - await I.see('Button is focused', '#buttonMessage') + await I.focus('#button'); + await I.see('Button is focused', '#buttonMessage'); - await I.focus('#field') - await I.see('Button not focused', '#buttonMessage') - await I.see('Input field is focused', '#fieldMessage') + await I.focus('#field'); + await I.see('Button not focused', '#buttonMessage'); + await I.see('Input field is focused', '#fieldMessage'); - await I.focus('#textarea') - await I.see('Button not focused', '#buttonMessage') - await I.see('Input field not focused', '#fieldMessage') - await I.see('Textarea is focused', '#textareaMessage') - }) + await I.focus('#textarea'); + await I.see('Button not focused', '#buttonMessage'); + await I.see('Input field not focused', '#fieldMessage'); + await I.see('Textarea is focused', '#textareaMessage'); + }); it('should blur focused button, field and textarea', async () => { - await I.amOnPage('/form/focus_blur_elements') + await I.amOnPage('/form/focus_blur_elements'); - await I.focus('#button') - await I.see('Button is focused', '#buttonMessage') - await I.blur('#button') - await I.see('Button not focused', '#buttonMessage') + await I.focus('#button'); + await I.see('Button is focused', '#buttonMessage'); + await I.blur('#button'); + await I.see('Button not focused', '#buttonMessage'); - await I.focus('#field') - await I.see('Input field is focused', '#fieldMessage') - await I.blur('#field') - await I.see('Input field not focused', '#fieldMessage') + await I.focus('#field'); + await I.see('Input field is focused', '#fieldMessage'); + await I.blur('#field'); + await I.see('Input field not focused', '#fieldMessage'); - await I.focus('#textarea') - await I.see('Textarea is focused', '#textareaMessage') - await I.blur('#textarea') - await I.see('Textarea not focused', '#textareaMessage') - }) - }) + await I.focus('#textarea'); + await I.see('Textarea is focused', '#textareaMessage'); + await I.blur('#textarea'); + await I.see('Textarea not focused', '#textareaMessage'); + }); + }); describe('#startRecordingTraffic, #seeTraffic, #stopRecordingTraffic, #dontSeeTraffic, #grabRecordedNetworkTraffics', () => { beforeEach(function () { - if (isHelper('TestCafe') || process.env.isSelenium === 'true') this.skip() - }) + if (isHelper('TestCafe') || process.env.isSelenium === 'true') this.skip(); + }); it('should throw error when calling seeTraffic before recording traffics', async () => { try { - I.amOnPage('https://codecept.io/') - await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) + I.amOnPage('https://codecept.io/'); + await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); } catch (e) { expect(e.message).to.equal( 'Failure in test automation. You use "I.seeTraffic", but "I.startRecordingTraffic" was never called before.', - ) + ); } - }) + }); it('should throw error when calling seeTraffic but missing name', async () => { try { - I.amOnPage('https://codecept.io/') - await I.seeTraffic({ url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) + I.amOnPage('https://codecept.io/'); + await I.seeTraffic({ url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); } catch (e) { - expect(e.message).to.equal('Missing required key "name" in object given to "I.seeTraffic".') + expect(e.message).to.equal('Missing required key "name" in object given to "I.seeTraffic".'); } - }) + }); it('should throw error when calling seeTraffic but missing url', async () => { try { - I.amOnPage('https://codecept.io/') - await I.seeTraffic({ name: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) + I.amOnPage('https://codecept.io/'); + await I.seeTraffic({ name: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); } catch (e) { - expect(e.message).to.equal('Missing required key "url" in object given to "I.seeTraffic".') + expect(e.message).to.equal('Missing required key "url" in object given to "I.seeTraffic".'); } - }) + }); it('should flush the network traffics', async () => { - await I.startRecordingTraffic() - await I.amOnPage('https://codecept.io/') - await I.flushNetworkTraffics() - const traffics = await I.grabRecordedNetworkTraffics() - expect(traffics.length).to.equal(0) - }) + await I.startRecordingTraffic(); + await I.amOnPage('https://codecept.io/'); + await I.flushNetworkTraffics(); + const traffics = await I.grabRecordedNetworkTraffics(); + expect(traffics.length).to.equal(0); + }); it('should see recording traffics', async () => { - I.startRecordingTraffic() - I.amOnPage('https://codecept.io/') - await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) - }) + I.startRecordingTraffic(); + I.amOnPage('https://codecept.io/'); + await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); + }); it('should not see recording traffics', async () => { - I.startRecordingTraffic() - I.amOnPage('https://codecept.io/') - I.stopRecordingTraffic() - await I.dontSeeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) - }) + I.startRecordingTraffic(); + I.amOnPage('https://codecept.io/'); + I.stopRecordingTraffic(); + await I.dontSeeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); + }); it('should not see recording traffics using regex url', async () => { - I.startRecordingTraffic() - I.amOnPage('https://codecept.io/') - I.stopRecordingTraffic() - await I.dontSeeTraffic({ name: 'traffics', url: /BC_LogoScreen_C.jpg/ }) - }) + I.startRecordingTraffic(); + I.amOnPage('https://codecept.io/'); + I.stopRecordingTraffic(); + await I.dontSeeTraffic({ name: 'traffics', url: /BC_LogoScreen_C.jpg/ }); + }); it('should throw error when calling dontSeeTraffic but missing name', async () => { - I.startRecordingTraffic() - I.amOnPage('https://codecept.io/') - I.stopRecordingTraffic() + I.startRecordingTraffic(); + I.amOnPage('https://codecept.io/'); + I.stopRecordingTraffic(); try { - await I.dontSeeTraffic({ url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) + await I.dontSeeTraffic({ url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); } catch (e) { - expect(e.message).to.equal('Missing required key "name" in object given to "I.dontSeeTraffic".') + expect(e.message).to.equal('Missing required key "name" in object given to "I.dontSeeTraffic".'); } - }) + }); it('should throw error when calling dontSeeTraffic but missing url', async () => { - I.startRecordingTraffic() - I.amOnPage('https://codecept.io/') - I.stopRecordingTraffic() + I.startRecordingTraffic(); + I.amOnPage('https://codecept.io/'); + I.stopRecordingTraffic(); try { - await I.dontSeeTraffic({ name: 'traffics' }) + await I.dontSeeTraffic({ name: 'traffics' }); } catch (e) { - expect(e.message).to.equal('Missing required key "url" in object given to "I.dontSeeTraffic".') + expect(e.message).to.equal('Missing required key "url" in object given to "I.dontSeeTraffic".'); } - }) + }); it('should check traffics with more advanced params', async () => { - await I.startRecordingTraffic() - await I.amOnPage('https://openaI.com/blog/chatgpt') - const traffics = await I.grabRecordedNetworkTraffics() + await I.startRecordingTraffic(); + await I.amOnPage('https://openaI.com/blog/chatgpt'); + const traffics = await I.grabRecordedNetworkTraffics(); for (const traffic of traffics) { if (traffic.url.includes('&width=')) { // new URL object - const currentUrl = new URL(traffic.url) + const currentUrl = new URL(traffic.url); // get access to URLSearchParams object - const searchParams = currentUrl.searchParams + const searchParams = currentUrl.searchParams; await I.seeTraffic({ name: 'sentry event', url: currentUrl.origin + currentUrl.pathname, parameters: searchParams, - }) + }); - break + break; } } - }) + }); it.skip('should check traffics with more advanced post data', async () => { - await I.amOnPage('https://openaI.com/blog/chatgpt') - await I.startRecordingTraffic() + await I.amOnPage('https://openaI.com/blog/chatgpt'); + await I.startRecordingTraffic(); await I.seeTraffic({ name: 'event', url: 'https://region1.google-analytics.com', requestPostData: { st: 2, }, - }) - }) - }) + }); + }); + }); // the WS test website is not so stable. So we skip those tests for now. describe.skip('#startRecordingWebSocketMessages, #grabWebSocketMessages, #stopRecordingWebSocketMessages', () => { beforeEach(function () { - if (isHelper('TestCafe') || isHelper('WebDriver') || process.env.BROWSER === 'firefox') this.skip() - }) + if (isHelper('TestCafe') || isHelper('WebDriver') || process.env.BROWSER === 'firefox') this.skip(); + }); it('should throw error when calling grabWebSocketMessages before startRecordingWebSocketMessages', () => { try { - I.amOnPage('https://websocketstest.com/') - I.waitForText('Work for You!') - I.grabWebSocketMessages() + I.amOnPage('https://websocketstest.com/'); + I.waitForText('Work for You!'); + I.grabWebSocketMessages(); } catch (e) { expect(e.message).to.equal( 'Failure in test automation. You use "I.grabWebSocketMessages", but "I.startRecordingWebSocketMessages" was never called before.', - ) + ); } - }) + }); it('should flush the WS messages', async () => { - await I.startRecordingWebSocketMessages() - I.amOnPage('https://websocketstest.com/') - I.waitForText('Work for You!') - I.flushWebSocketMessages() - const wsMessages = I.grabWebSocketMessages() - expect(wsMessages.length).to.equal(0) - }) + await I.startRecordingWebSocketMessages(); + I.amOnPage('https://websocketstest.com/'); + I.waitForText('Work for You!'); + I.flushWebSocketMessages(); + const wsMessages = I.grabWebSocketMessages(); + expect(wsMessages.length).to.equal(0); + }); it('should see recording WS messages', async () => { - await I.startRecordingWebSocketMessages() - await I.amOnPage('https://websocketstest.com/') - I.waitForText('Work for You!') - const wsMessages = await I.grabWebSocketMessages() - expect(wsMessages.length).to.greaterThan(0) - }) + await I.startRecordingWebSocketMessages(); + await I.amOnPage('https://websocketstest.com/'); + I.waitForText('Work for You!'); + const wsMessages = await I.grabWebSocketMessages(); + expect(wsMessages.length).to.greaterThan(0); + }); it('should not see recording WS messages', async () => { - await I.startRecordingWebSocketMessages() - await I.amOnPage('https://websocketstest.com/') - I.waitForText('Work for You!') - const wsMessages = I.grabWebSocketMessages() - await I.stopRecordingWebSocketMessages() - await I.amOnPage('https://websocketstest.com/') - I.waitForText('Work for You!') - const afterWsMessages = I.grabWebSocketMessages() - expect(wsMessages.length).to.equal(afterWsMessages.length) - }) - }) + await I.startRecordingWebSocketMessages(); + await I.amOnPage('https://websocketstest.com/'); + I.waitForText('Work for You!'); + const wsMessages = I.grabWebSocketMessages(); + await I.stopRecordingWebSocketMessages(); + await I.amOnPage('https://websocketstest.com/'); + I.waitForText('Work for You!'); + const afterWsMessages = I.grabWebSocketMessages(); + expect(wsMessages.length).to.equal(afterWsMessages.length); + }); + }); } From 771232c2b891d8553a383cd5e2c646dda7bd2c67 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Thu, 31 Oct 2024 17:24:42 +0200 Subject: [PATCH 02/37] removed chai dependencies --- package.json | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/package.json b/package.json index 451316ed5..f87906fd8 100644 --- a/package.json +++ b/package.json @@ -79,13 +79,6 @@ "acorn": "8.14.0", "arrify": "2.0.1", "axios": "1.7.7", - "chai": "^4.0", - "chai-deep-match": "1.2.1", - "chai-exclude": "2.1.1", - "chai-json-schema": "1.5.1", - "chai-json-schema-ajv": "5.2.4", - "chai-match-pattern": "1.3.0", - "chai-string": "1.5.0", "chalk": "4.1.2", "commander": "11.1.0", "cross-spawn": "7.0.3", @@ -161,6 +154,7 @@ "sinon": "18.0.0", "sinon-chai": "3.7.0", "testcafe": "3.5.0", + "chai": "^4.0", "ts-morph": "23.0.0", "ts-node": "10.9.2", "tsd": "^0.31.0", From a86706f85487f9e769cef06399b6391aeff59b8b Mon Sep 17 00:00:00 2001 From: DavertMik Date: Fri, 1 Nov 2024 01:55:39 +0200 Subject: [PATCH 03/37] removed soft expect helper --- lib/helper/JSONResponse.js | 1 + lib/helper/SoftExpectHelper.js | 381 --- package.json | 7 +- test/helper/AppiumV2_ios_test.js | 219 +- test/helper/AppiumV2_test.js | 7 +- test/helper/Appium_test.js | 7 +- test/helper/Expect_test.js | 424 ---- test/helper/JSONResponse_test.js | 5 +- test/helper/MockServer_test.js | 5 +- test/helper/Playwright_test.js | 7 +- test/helper/Puppeteer_test.js | 7 +- test/helper/SoftExpect_test.js | 477 ---- .../helper/WebDriver.noSeleniumServer_test.js | 7 +- test/helper/WebDriver_devtools_test.js | 11 +- test/helper/WebDriver_test.js | 10 +- test/helper/webapi.js | 2139 +++++++++-------- 16 files changed, 1217 insertions(+), 2497 deletions(-) delete mode 100644 lib/helper/SoftExpectHelper.js delete mode 100644 test/helper/Expect_test.js delete mode 100644 test/helper/SoftExpect_test.js diff --git a/lib/helper/JSONResponse.js b/lib/helper/JSONResponse.js index 7d6abcd7e..450d44ba4 100644 --- a/lib/helper/JSONResponse.js +++ b/lib/helper/JSONResponse.js @@ -1,6 +1,7 @@ const Helper = require('@codeceptjs/helper') const chai = require('chai') + const expect = chai.expect chai.use(require('chai-deep-match')) const joi = require('joi') diff --git a/lib/helper/SoftExpectHelper.js b/lib/helper/SoftExpectHelper.js deleted file mode 100644 index 326a8698c..000000000 --- a/lib/helper/SoftExpectHelper.js +++ /dev/null @@ -1,381 +0,0 @@ -const ExpectHelper = require('./ExpectHelper') - -/** - * SoftAssertHelper is a utility class for performing soft assertions. - * Unlike traditional assertions that stop the execution on failure, - * soft assertions allow the execution to continue and report all failures at the end. - * - * ### Examples - * - * Zero-configuration when paired with other helpers like REST, Playwright: - * - * ```js - * // inside codecept.conf.js - * { - * helpers: { - * Playwright: {...}, - * SoftExpectHelper: {}, - * } - * } - * ``` - * - * ```js - * // in scenario - * I.softExpectEqual('a', 'b') - * I.flushSoftAssertions() // Throws an error if any soft assertions have failed. The error message contains all the accumulated failures. - * ``` - * - * ## Methods - */ -class SoftAssertHelper extends ExpectHelper { - constructor() { - super() - this.errors = [] - } - - /** - * Performs a soft assertion by executing the provided assertion function. - * If the assertion fails, the error is caught and stored without halting the execution. - * - * @param {Function} assertionFn - The assertion function to execute. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - */ - softAssert(assertionFn, customErrorMsg = '') { - try { - assertionFn() - } catch (error) { - this.errors.push({ customErrorMsg, error }) - } - } - - /** - * Throws an error if any soft assertions have failed. - * The error message contains all the accumulated failures. - * - * @throws {Error} If there are any soft assertion failures. - */ - flushSoftAssertions() { - if (this.errors.length > 0) { - let errorMessage = 'Soft assertions failed:\n' - this.errors.forEach((err, index) => { - errorMessage += `\n[${index + 1}] ${err.customErrorMsg}\n${err.error.message}\n` - }) - this.errors = [] - throw new Error(errorMessage) - } - } - - /** - * Softly asserts that two values are equal. - * - * @param {*} actualValue - The actual value. - * @param {*} expectedValue - The expected value. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - */ - softExpectEqual(actualValue, expectedValue, customErrorMsg = '') { - this.softAssert(() => this.expectEqual(actualValue, expectedValue, customErrorMsg), customErrorMsg) - } - - /** - * Softly asserts that two values are not equal. - * - * @param {*} actualValue - The actual value. - * @param {*} expectedValue - The expected value. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - */ - softExpectNotEqual(actualValue, expectedValue, customErrorMsg = '') { - this.softAssert(() => this.expectNotEqual(actualValue, expectedValue, customErrorMsg), customErrorMsg) - } - - /** - * Softly asserts that two values are deeply equal. - * - * @param {*} actualValue - The actual value. - * @param {*} expectedValue - The expected value. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - */ - softExpectDeepEqual(actualValue, expectedValue, customErrorMsg = '') { - this.softAssert(() => this.expectDeepEqual(actualValue, expectedValue, customErrorMsg), customErrorMsg) - } - - /** - * Softly asserts that two values are not deeply equal. - * - * @param {*} actualValue - The actual value. - * @param {*} expectedValue - The expected value. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - */ - softExpectNotDeepEqual(actualValue, expectedValue, customErrorMsg = '') { - this.softAssert(() => this.expectNotDeepEqual(actualValue, expectedValue, customErrorMsg), customErrorMsg) - } - - /** - * Softly asserts that a value contains the expected value. - * - * @param {*} actualValue - The actual value. - * @param {*} expectedValueToContain - The value that should be contained within the actual value. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - */ - softExpectContain(actualValue, expectedValueToContain, customErrorMsg = '') { - this.softAssert(() => this.expectContain(actualValue, expectedValueToContain, customErrorMsg), customErrorMsg) - } - - /** - * Softly asserts that a value does not contain the expected value. - * - * @param {*} actualValue - The actual value. - * @param {*} expectedValueToNotContain - The value that should not be contained within the actual value. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - */ - softExpectNotContain(actualValue, expectedValueToNotContain, customErrorMsg = '') { - this.softAssert(() => this.expectNotContain(actualValue, expectedValueToNotContain, customErrorMsg), customErrorMsg) - } - - /** - * Softly asserts that a value starts with the expected value. - * - * @param {*} actualValue - The actual value. - * @param {*} expectedValueToStartWith - The value that the actual value should start with. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - */ - softExpectStartsWith(actualValue, expectedValueToStartWith, customErrorMsg = '') { - this.softAssert(() => this.expectStartsWith(actualValue, expectedValueToStartWith, customErrorMsg), customErrorMsg) - } - - /** - * Softly asserts that a value does not start with the expected value. - * - * @param {*} actualValue - The actual value. - * @param {*} expectedValueToNotStartWith - The value that the actual value should not start with. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - */ - softExpectNotStartsWith(actualValue, expectedValueToNotStartWith, customErrorMsg = '') { - this.softAssert( - () => this.expectNotStartsWith(actualValue, expectedValueToNotStartWith, customErrorMsg), - customErrorMsg, - ) - } - - /** - * Softly asserts that a value ends with the expected value. - * - * @param {*} actualValue - The actual value. - * @param {*} expectedValueToEndWith - The value that the actual value should end with. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - */ - softExpectEndsWith(actualValue, expectedValueToEndWith, customErrorMsg = '') { - this.softAssert(() => this.expectEndsWith(actualValue, expectedValueToEndWith, customErrorMsg), customErrorMsg) - } - - /** - * Softly asserts that a value does not end with the expected value. - * - * @param {*} actualValue - The actual value. - * @param {*} expectedValueToNotEndWith - The value that the actual value should not end with. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - */ - softExpectNotEndsWith(actualValue, expectedValueToNotEndWith, customErrorMsg = '') { - this.softAssert( - () => this.expectNotEndsWith(actualValue, expectedValueToNotEndWith, customErrorMsg), - customErrorMsg, - ) - } - - /** - * Softly asserts that the target data matches the given JSON schema. - * - * @param {*} targetData - The data to validate. - * @param {Object} jsonSchema - The JSON schema to validate against. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - */ - softExpectJsonSchema(targetData, jsonSchema, customErrorMsg = '') { - this.softAssert(() => this.expectJsonSchema(targetData, jsonSchema, customErrorMsg), customErrorMsg) - } - - /** - * Softly asserts that the target data matches the given JSON schema using AJV. - * - * @param {*} targetData - The data to validate. - * @param {Object} jsonSchema - The JSON schema to validate against. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - * @param {Object} [ajvOptions={ allErrors: true }] - Options to pass to AJV. - */ - softExpectJsonSchemaUsingAJV(targetData, jsonSchema, customErrorMsg = '', ajvOptions = { allErrors: true }) { - this.softAssert( - () => this.expectJsonSchemaUsingAJV(targetData, jsonSchema, customErrorMsg, ajvOptions), - customErrorMsg, - ) - } - - /** - * Softly asserts that the target data has the specified property. - * - * @param {*} targetData - The data to check. - * @param {string} propertyName - The property name to check for. - * @param {string} [customErrorMsg=''] - A custom error message to display if the assertion - fails. */ softExpectHasProperty(targetData, propertyName, customErrorMsg = '') { - this.softAssert(() => this.expectHasProperty(targetData, propertyName, customErrorMsg), customErrorMsg) - } - - /** - Softly asserts that the target data has a property with the specified name. - @param {*} targetData - The data to check. - @param {string} propertyName - The property name to check for. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. - */ - softExpectHasAProperty(targetData, propertyName, customErrorMsg = '') { - this.softAssert(() => this.expectHasAProperty(targetData, propertyName, customErrorMsg), customErrorMsg) - } - - /** - Softly asserts that the target data is of a specific type. - @param {*} targetData - The data to check. - @param {string} type - The expected type (e.g., 'string', 'number'). - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectToBeA(targetData, type, customErrorMsg = '') { - this.softAssert(() => this.expectToBeA(targetData, type, customErrorMsg), customErrorMsg) - } - - /** - Softly asserts that the target data is of a specific type (alternative for articles). - @param {*} targetData - The data to check. - @param {string} type - The expected type (e.g., 'string', 'number'). - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectToBeAn(targetData, type, customErrorMsg = '') { - this.softAssert(() => this.expectToBeAn(targetData, type, customErrorMsg), customErrorMsg) - } - - /* - Softly asserts that the target data matches the specified regular expression. - @param {*} targetData - The data to check. - @param {RegExp} regex - The regular expression to match. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectMatchRegex(targetData, regex, customErrorMsg = '') { - this.softAssert(() => this.expectMatchRegex(targetData, regex, customErrorMsg), customErrorMsg) - } - - /** - Softly asserts that the target data has a specified length. - @param {*} targetData - The data to check. - @param {number} length - The expected length. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectLengthOf(targetData, length, customErrorMsg = '') { - this.softAssert(() => this.expectLengthOf(targetData, length, customErrorMsg), customErrorMsg) - } - - /** - - Softly asserts that the target data is empty. - @param {*} targetData - The data to check. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectEmpty(targetData, customErrorMsg = '') { - this.softAssert(() => this.expectEmpty(targetData, customErrorMsg), customErrorMsg) - } - - /** - - Softly asserts that the target data is true. - @param {*} targetData - The data to check. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectTrue(targetData, customErrorMsg = '') { - this.softAssert(() => this.expectTrue(targetData, customErrorMsg), customErrorMsg) - } - - /** - - Softly asserts that the target data is false. - @param {*} targetData - The data to check. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectFalse(targetData, customErrorMsg = '') { - this.softAssert(() => this.expectFalse(targetData, customErrorMsg), customErrorMsg) - } - - /** - - Softly asserts that the target data is above a specified value. - @param {*} targetData - The data to check. - @param {*} aboveThan - The value that the target data should be above. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectAbove(targetData, aboveThan, customErrorMsg = '') { - this.softAssert(() => this.expectAbove(targetData, aboveThan, customErrorMsg), customErrorMsg) - } - - /** - - Softly asserts that the target data is below a specified value. - @param {*} targetData - The data to check. - @param {*} belowThan - The value that the target data should be below. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectBelow(targetData, belowThan, customErrorMsg = '') { - this.softAssert(() => this.expectBelow(targetData, belowThan, customErrorMsg), customErrorMsg) - } - - /** - - Softly asserts that the length of the target data is above a specified value. - @param {*} targetData - The data to check. - @param {number} lengthAboveThan - The length that the target data should be above. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectLengthAboveThan(targetData, lengthAboveThan, customErrorMsg = '') { - this.softAssert(() => this.expectLengthAboveThan(targetData, lengthAboveThan, customErrorMsg), customErrorMsg) - } - - /** - Softly asserts that the length of the target data is below a specified value. - @param {*} targetData - The data to check. - @param {number} lengthBelowThan - The length that the target data should be below. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectLengthBelowThan(targetData, lengthBelowThan, customErrorMsg = '') { - this.softAssert(() => this.expectLengthBelowThan(targetData, lengthBelowThan, customErrorMsg), customErrorMsg) - } - - /** - Softly asserts that two values are equal, ignoring case. - @param {string} actualValue - The actual string value. - @param {string} expectedValue - The expected string value. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectEqualIgnoreCase(actualValue, expectedValue, customErrorMsg = '') { - this.softAssert(() => this.expectEqualIgnoreCase(actualValue, expectedValue, customErrorMsg), customErrorMsg) - } - - /** - Softly asserts that two arrays have deep equality, considering members in any order. - @param {Array} actualValue - The actual array. - @param {Array} expectedValue - The expected array. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectDeepMembers(actualValue, expectedValue, customErrorMsg = '') { - this.softAssert(() => this.expectDeepMembers(actualValue, expectedValue, customErrorMsg), customErrorMsg) - } - - /** - Softly asserts that an array (superset) deeply includes all members of another array (set). - @param {Array} superset - The array that should contain the expected members. - @param {Array} set - The array with members that should be included. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectDeepIncludeMembers(superset, set, customErrorMsg = '') { - this.softAssert(() => this.expectDeepIncludeMembers(superset, set, customErrorMsg), customErrorMsg) - } - - /** - Softly asserts that two objects are deeply equal, excluding specified fields. - @param {Object} actualValue - The actual object. - @param {Object} expectedValue - The expected object. - @param {Array} fieldsToExclude - The fields to exclude from the comparison. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectDeepEqualExcluding(actualValue, expectedValue, fieldsToExclude, customErrorMsg = '') { - this.softAssert( - () => this.expectDeepEqualExcluding(actualValue, expectedValue, fieldsToExclude, customErrorMsg), - customErrorMsg, - ) - } - - /** - Softly asserts that a value matches the expected pattern. - @param {*} actualValue - The actual value. - @param {*} expectedPattern - The pattern the value should match. - @param {string} [customErrorMsg=''] - A custom error message to display if the assertion fails. */ - softExpectMatchesPattern(actualValue, expectedPattern, customErrorMsg = '') { - this.softAssert(() => this.expectMatchesPattern(actualValue, expectedPattern, customErrorMsg), customErrorMsg) - } -} -module.exports = SoftAssertHelper diff --git a/package.json b/package.json index f87906fd8..f4fc7b164 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "figures": "3.2.0", "fn-args": "4.0.0", "fs-extra": "11.2.0", - "glob": "6.0.1", + "glob": "^9", "html-minifier-terser": "7.2.0", "inquirer": "6.5.2", "joi": "17.13.3", @@ -125,7 +125,7 @@ "@wdio/selenium-standalone-service": "8.3.2", "@wdio/utils": "9.1.2", "@xmldom/xmldom": "0.9.4", - "apollo-server-express": "2.25.3", + "@apollo/server": "^4", "chai-as-promised": "7.1.2", "chai-subset": "1.6.0", "cheerio": "^1.0.0", @@ -141,7 +141,7 @@ "graphql": "16.9.0", "husky": "9.1.6", "inquirer-test": "2.0.1", - "jsdoc": "4.0.3", + "jsdoc": "^3", "jsdoc-typeof-plugin": "1.0.0", "json-server": "0.10.1", "playwright": "1.48.2", @@ -150,7 +150,6 @@ "qrcode-terminal": "0.12.0", "rosie": "2.1.1", "runok": "0.9.3", - "semver": "7.6.3", "sinon": "18.0.0", "sinon-chai": "3.7.0", "testcafe": "3.5.0", diff --git a/test/helper/AppiumV2_ios_test.js b/test/helper/AppiumV2_ios_test.js index e00f9aa21..5bc0b1c04 100644 --- a/test/helper/AppiumV2_ios_test.js +++ b/test/helper/AppiumV2_ios_test.js @@ -1,23 +1,24 @@ -const chai = require('chai'); -const expect = chai.expect; -const assert = chai.assert; -const path = require('path'); +const chai = require('chai') -const Appium = require('../../lib/helper/Appium'); -const AssertionFailedError = require('../../lib/assert/error'); -const fileExists = require('../../lib/utils').fileExists; -global.codeceptjs = require('../../lib'); +const expect = chai.expect +const assert = chai.assert +const path = require('path') -let app; +const Appium = require('../../lib/helper/Appium') +const AssertionFailedError = require('../../lib/assert/error') +const fileExists = require('../../lib/utils').fileExists +global.codeceptjs = require('../../lib') + +let app // iOS test app is built from https://github.com/appium/ios-test-app and uploaded to Saucelabs -const apk_path = 'storage:filename=TestApp-iphonesimulator.zip'; -const smallWait = 3; +const apk_path = 'storage:filename=TestApp-iphonesimulator.zip' +const smallWait = 3 describe('Appium iOS Tests', function () { - this.timeout(0); + this.timeout(0) before(async () => { - global.codecept_dir = path.join(__dirname, '/../data'); + global.codecept_dir = path.join(__dirname, '/../data') app = new Appium({ app: apk_path, appiumV2: true, @@ -40,166 +41,166 @@ describe('Appium iOS Tests', function () { port: 80, user: process.env.SAUCE_USERNAME, key: process.env.SAUCE_ACCESS_KEY, - }); - await app._beforeSuite(); - app.isWeb = false; - await app._before(); - }); + }) + await app._beforeSuite() + app.isWeb = false + await app._before() + }) after(async () => { - await app._after(); - }); + await app._after() + }) describe('app installation : #removeApp', () => { describe('#grabAllContexts, #grabContext, #grabOrientation, #grabSettings', () => { it('should grab all available contexts for screen', async () => { - await app.resetApp(); - const val = await app.grabAllContexts(); - assert.deepEqual(val, ['NATIVE_APP']); - }); + await app.resetApp() + const val = await app.grabAllContexts() + assert.deepEqual(val, ['NATIVE_APP']) + }) it('should grab current context', async () => { - const val = await app.grabContext(); - assert.equal(val, 'NATIVE_APP'); - }); + const val = await app.grabContext() + assert.equal(val, 'NATIVE_APP') + }) it('should grab custom settings', async () => { - const val = await app.grabSettings(); - assert.deepEqual(val, { imageElementTapStrategy: 'w3cActions' }); - }); - }); - }); + const val = await app.grabSettings() + assert.deepEqual(val, { imageElementTapStrategy: 'w3cActions' }) + }) + }) + }) describe('device orientation : #seeOrientationIs #setOrientation', () => { it('should return correct status about device orientation', async () => { - await app.seeOrientationIs('PORTRAIT'); + await app.seeOrientationIs('PORTRAIT') try { - await app.seeOrientationIs('LANDSCAPE'); + await app.seeOrientationIs('LANDSCAPE') } catch (e) { - e.should.be.instanceOf(AssertionFailedError); - e.inspect().should.include('expected orientation to be LANDSCAPE'); + e.should.be.instanceOf(AssertionFailedError) + e.inspect().should.include('expected orientation to be LANDSCAPE') } - }); - }); + }) + }) describe('#hideDeviceKeyboard', () => { it('should hide device Keyboard @quick', async () => { - await app.resetApp(); - await app.click('~IntegerA'); + await app.resetApp() + await app.click('~IntegerA') try { - await app.click('~locationStatus'); + await app.click('~locationStatus') } catch (e) { - e.message.should.include('element'); + e.message.should.include('element') } - await app.hideDeviceKeyboard('pressKey', 'Done'); - await app.click('~locationStatus'); - }); + await app.hideDeviceKeyboard('pressKey', 'Done') + await app.click('~locationStatus') + }) it('should assert if no keyboard', async () => { try { - await app.hideDeviceKeyboard('pressKey', 'Done'); + await app.hideDeviceKeyboard('pressKey', 'Done') } catch (e) { e.message.should.include( 'An unknown server-side error occurred while processing the command. Original error: Soft keyboard not present, cannot hide keyboard', - ); + ) } - }); - }); + }) + }) describe('see text : #see', () => { it('should work inside elements @second', async () => { - await app.resetApp(); - await app.see('Compute Sum', '~ComputeSumButton'); - }); - }); + await app.resetApp() + await app.see('Compute Sum', '~ComputeSumButton') + }) + }) describe('#appendField', () => { it('should be able to send special keys to element @second', async () => { - await app.resetApp(); - await app.waitForElement('~IntegerA', smallWait); - await app.click('~IntegerA'); - await app.appendField('~IntegerA', '1'); - await app.hideDeviceKeyboard('pressKey', 'Done'); - await app.see('1', '~IntegerA'); - }); - }); + await app.resetApp() + await app.waitForElement('~IntegerA', smallWait) + await app.click('~IntegerA') + await app.appendField('~IntegerA', '1') + await app.hideDeviceKeyboard('pressKey', 'Done') + await app.see('1', '~IntegerA') + }) + }) describe('#waitForText', () => { it('should return error if not present', async () => { try { - await app.waitForText('Nothing here', 1, '~IntegerA'); + await app.waitForText('Nothing here', 1, '~IntegerA') } catch (e) { e.message.should.contain( 'element (~IntegerA) is not in DOM or there is no element(~IntegerA) with text "Nothing here" after 1 sec', - ); + ) } - }); - }); + }) + }) describe('#seeNumberOfElements @second', () => { it('should return 1 as count', async () => { - await app.resetApp(); - await app.seeNumberOfElements('~IntegerA', 1); - }); - }); + await app.resetApp() + await app.seeNumberOfElements('~IntegerA', 1) + }) + }) describe('see element : #seeElement, #dontSeeElement', () => { it('should check visible elements on page @quick', async () => { - await app.resetApp(); - await app.seeElement('~IntegerA'); - await app.dontSeeElement('#something-beyond'); - await app.dontSeeElement('//input[@id="something-beyond"]'); - }); - }); + await app.resetApp() + await app.seeElement('~IntegerA') + await app.dontSeeElement('#something-beyond') + await app.dontSeeElement('//input[@id="something-beyond"]') + }) + }) describe('#click @quick', () => { it('should click by accessibility id', async () => { - await app.resetApp(); - await app.tap('~ComputeSumButton'); - await app.see('0'); - }); - }); + await app.resetApp() + await app.tap('~ComputeSumButton') + await app.see('0') + }) + }) describe('#fillField @second', () => { it('should fill field by accessibility id', async () => { - await app.resetApp(); - await app.waitForElement('~IntegerA', smallWait); - await app.click('~IntegerA'); - await app.fillField('~IntegerA', '1'); - await app.hideDeviceKeyboard('pressKey', 'Done'); - await app.see('1', '~IntegerA'); - }); - }); + await app.resetApp() + await app.waitForElement('~IntegerA', smallWait) + await app.click('~IntegerA') + await app.fillField('~IntegerA', '1') + await app.hideDeviceKeyboard('pressKey', 'Done') + await app.see('1', '~IntegerA') + }) + }) describe('#grabTextFrom, #grabValueFrom, #grabAttributeFrom @quick', () => { it('should grab text from page', async () => { - await app.resetApp(); - const val = await app.grabTextFrom('~ComputeSumButton'); - assert.equal(val, 'Compute Sum'); - }); + await app.resetApp() + const val = await app.grabTextFrom('~ComputeSumButton') + assert.equal(val, 'Compute Sum') + }) it('should grab attribute from element', async () => { - await app.resetApp(); - const val = await app.grabAttributeFrom('~ComputeSumButton', 'label'); - assert.equal(val, 'Compute Sum'); - }); + await app.resetApp() + const val = await app.grabAttributeFrom('~ComputeSumButton', 'label') + assert.equal(val, 'Compute Sum') + }) it('should be able to grab elements', async () => { - await app.resetApp(); - const id = await app.grabNumberOfVisibleElements('~ComputeSumButton'); - assert.strictEqual(1, id); - }); - }); + await app.resetApp() + const id = await app.grabNumberOfVisibleElements('~ComputeSumButton') + assert.strictEqual(1, id) + }) + }) describe('#saveScreenshot', () => { beforeEach(() => { - global.output_dir = path.join(global.codecept_dir, 'output'); - }); + global.output_dir = path.join(global.codecept_dir, 'output') + }) it('should create a screenshot file in output dir', async () => { - const sec = new Date().getUTCMilliseconds(); - await app.saveScreenshot(`screenshot_${sec}.png`); - assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists'); - }); - }); -}); + const sec = new Date().getUTCMilliseconds() + await app.saveScreenshot(`screenshot_${sec}.png`) + assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists') + }) + }) +}) diff --git a/test/helper/AppiumV2_test.js b/test/helper/AppiumV2_test.js index aaa1d6d59..0a3ea741d 100644 --- a/test/helper/AppiumV2_test.js +++ b/test/helper/AppiumV2_test.js @@ -1,6 +1,7 @@ -const chai = require('chai'); -const expect = chai.expect; -const assert = chai.assert; +const chai = require('chai') + +const expect = chai.expect +const assert = chai.assert let app const apk_path = 'storage:filename=selendroid-test-app-0.17.0.apk' diff --git a/test/helper/Appium_test.js b/test/helper/Appium_test.js index 660dfd02e..ef8c5fe37 100644 --- a/test/helper/Appium_test.js +++ b/test/helper/Appium_test.js @@ -1,6 +1,7 @@ -const chai = require('chai'); -const expect = chai.expect; -const assert = chai.assert; +const chai = require('chai') + +const expect = chai.expect +const assert = chai.assert const path = require('path') diff --git a/test/helper/Expect_test.js b/test/helper/Expect_test.js deleted file mode 100644 index 919a5d8ca..000000000 --- a/test/helper/Expect_test.js +++ /dev/null @@ -1,424 +0,0 @@ -const path = require('path') - -const chai = require('chai'); -const expect = chai.expect; - -const ExpectHelper = require('../../lib/helper/ExpectHelper') - -global.codeceptjs = require('../../lib') - -let I - -const goodApple = { - skin: 'thin', - colors: ['red', 'green', 'yellow'], - taste: 10, -} -const badApple = { - colors: ['brown'], - taste: 0, - worms: 2, -} -const fruitSchema = { - title: 'fresh fruit schema v1', - type: 'object', - required: ['skin', 'colors', 'taste'], - properties: { - colors: { - type: 'array', - minItems: 1, - uniqueItems: true, - items: { - type: 'string', - }, - }, - skin: { - type: 'string', - }, - taste: { - type: 'number', - minimum: 5, - }, - }, -} - -describe('Expect Helper', function () { - this.timeout(3000) - this.retries(1) - - before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - - I = new ExpectHelper() - }) - - describe('#expectEqual', () => { - it('should not show error', () => { - I.expectEqual('a', 'a') - }) - - it('should show error', () => { - try { - I.expectEqual('a', 'b') - } catch (e) { - expect(e.message).to.eq("expected 'a' to equal 'b'") - } - }) - }) - - describe('#expectNotEqual', () => { - it('should not show error', () => { - I.expectNotEqual('a', 'b') - }) - - it('should show error', () => { - try { - I.expectNotEqual('a', 'a') - } catch (e) { - expect(e.message).to.eq("expected 'a' to not equal 'a'") - } - }) - }) - - describe('#expectContain', () => { - it('should not show error', () => { - I.expectContain('abc', 'a') - }) - - it('should show error', () => { - try { - I.expectContain('abc', 'd') - } catch (e) { - expect(e.message).to.eq("expected 'abc' to include 'd'") - } - }) - }) - - describe('#expectNotContain', () => { - it('should not show error', () => { - I.expectNotContain('abc', 'd') - }) - - it('should show error', () => { - try { - I.expectNotContain('abc', 'a') - } catch (e) { - expect(e.message).to.eq("expected 'abc' to not include 'a'") - } - }) - }) - - describe('#expectStartsWith', () => { - it('should not show error', () => { - I.expectStartsWith('abc', 'a') - }) - - it('should show error', () => { - try { - I.expectStartsWith('abc', 'b') - } catch (e) { - expect(e.message).to.eq('expected abc to start with b') - } - }) - }) - - describe('#expectNotStartsWith', () => { - it('should not show error', () => { - I.expectNotStartsWith('abc', 'b') - }) - - it('should show error', () => { - try { - I.expectNotStartsWith('abc', 'a') - } catch (e) { - expect(e.message).to.eq('expected abc not to start with a') - } - }) - }) - - describe('#expectEndsWith', () => { - it('should not show error', () => { - I.expectEndsWith('abc', 'c') - }) - - it('should show error', () => { - try { - I.expectEndsWith('abc', 'd') - } catch (e) { - expect(e.message).to.eq('expected abc to end with d') - } - }) - }) - - describe('#expectNotEndsWith', () => { - it('should not show error', () => { - I.expectNotEndsWith('abc', 'd') - }) - - it('should show error', () => { - try { - I.expectNotEndsWith('abc', 'd') - } catch (e) { - expect(e.message).to.eq('expected abc not to end with c') - } - }) - }) - - describe('#expectJsonSchema', () => { - it('should not show error', () => { - I.expectJsonSchema(goodApple, fruitSchema) - }) - - it('should show error', () => { - try { - I.expectJsonSchema(badApple, fruitSchema) - } catch (e) { - expect(e.message).to.contain('expected value to match json-schema') - } - }) - }) - - describe('#expectHasProperty', () => { - it('should not show error', () => { - I.expectHasProperty(goodApple, 'skin') - }) - - it('should show error', () => { - try { - I.expectHasProperty(badApple, 'skin') - } catch (e) { - expect(e.message).to.contain('expected { Object (colors, taste') - } - }) - }) - - describe('#expectHasAProperty', () => { - it('should not show error', () => { - I.expectHasAProperty(goodApple, 'skin') - }) - - it('should show error', () => { - try { - I.expectHasAProperty(badApple, 'skin') - } catch (e) { - expect(e.message).to.contain('expected { Object (colors, taste') - } - }) - }) - - describe('#expectToBeA', () => { - it('should not show error', () => { - I.expectToBeA(goodApple, 'object') - }) - }) - - describe('#expectToBeAn', () => { - it('should not show error', () => { - I.expectToBeAn(goodApple, 'object') - }) - - it('should show error', () => { - try { - I.expectToBeAn(badApple, 'skin') - } catch (e) { - expect(e.message).to.contain('expected { Object (colors, taste') - } - }) - }) - - describe('#expectMatchRegex', () => { - it('should not show error', () => { - I.expectMatchRegex('goodApple', /good/) - }) - - it('should show error', () => { - try { - I.expectMatchRegex('Apple', /good/) - } catch (e) { - expect(e.message).to.contain('to match /good/') - } - }) - }) - - describe('#expectLengthOf', () => { - it('should not show error', () => { - I.expectLengthOf('good', 4) - }) - - it('should show error', () => { - try { - I.expectLengthOf('Apple', 4) - } catch (e) { - expect(e.message).to.contain('to have a length') - } - }) - }) - - describe('#expectTrue', () => { - it('should not show error', () => { - I.expectTrue(true) - }) - - it('should show error', () => { - try { - I.expectTrue(false) - } catch (e) { - expect(e.message).to.contain('expected false to be true') - } - }) - }) - - describe('#expectEmpty', () => { - it('should not show error', () => { - I.expectEmpty('') - }) - - it('should show error', () => { - try { - I.expectEmpty('false') - } catch (e) { - expect(e.message).to.contain("expected 'false' to be empty") - } - }) - }) - - describe('#expectFalse', () => { - it('should not show error', () => { - I.expectFalse(false) - }) - - it('should show error', () => { - try { - I.expectFalse(true) - } catch (e) { - expect(e.message).to.contain('expected true to be false') - } - }) - }) - - describe('#expectAbove', () => { - it('should not show error', () => { - I.expectAbove(2, 1) - }) - - it('should show error', () => { - try { - I.expectAbove(1, 2) - } catch (e) { - expect(e.message).to.contain('expected 1 to be above 2') - } - }) - }) - - describe('#expectBelow', () => { - it('should not show error', () => { - I.expectBelow(1, 2) - }) - - it('should show error', () => { - try { - I.expectBelow(2, 1) - } catch (e) { - expect(e.message).to.contain('expected 2 to be below 1') - } - }) - }) - - describe('#expectLengthAboveThan', () => { - it('should not show error', () => { - I.expectLengthAboveThan('hello', 4) - }) - - it('should show error', () => { - try { - I.expectLengthAboveThan('hello', 5) - } catch (e) { - expect(e.message).to.contain('to have a length above 5') - } - }) - }) - - describe('#expectLengthBelowThan', () => { - it('should not show error', () => { - I.expectLengthBelowThan('hello', 6) - }) - - it('should show error', () => { - try { - I.expectLengthBelowThan('hello', 4) - } catch (e) { - expect(e.message).to.contain('to have a length below 4') - } - }) - }) - - describe('#expectLengthBelowThan', () => { - it('should not show error', () => { - I.expectEqualIgnoreCase('hEllo', 'hello') - }) - - it('should show error', () => { - try { - I.expectEqualIgnoreCase('hEllo', 'hell0') - } catch (e) { - expect(e.message).to.contain('expected hEllo to equal hell0') - } - }) - }) - - describe('#expectDeepMembers', () => { - it('should not show error', () => { - I.expectDeepMembers([1, 2, 3], [1, 2, 3]) - }) - - it('should show error', () => { - try { - I.expectDeepMembers([1, 2, 3], [3]) - } catch (e) { - expect(e.message).to.contain('expected [ 1, 2, 3 ] to have the same members') - } - }) - }) - - describe('#expectDeepIncludeMembers', () => { - it('should not show error', () => { - I.expectDeepIncludeMembers([3, 4, 5, 6], [3, 4, 5]) - }) - - it('should show error', () => { - try { - I.expectDeepIncludeMembers([3, 4, 5], [3, 4, 5, 6]) - } catch (e) { - expect(e.message).to.contain('expected [ 3, 4, 5 ] to be a superset of [ 3, 4, 5, 6 ]') - } - }) - }) - - describe('#expectDeepEqualExcluding', () => { - it('should not show error', () => { - I.expectDeepEqualExcluding({ a: 1, b: 2 }, { b: 2, a: 1, c: 3 }, 'c') - }) - - it('should show error', () => { - try { - I.expectDeepEqualExcluding({ a: 1, b: 2 }, { b: 2, a: 1, c: 3 }, 'a') - } catch (e) { - expect(e.message).to.contain('expected { b: 2 } to deeply equal') - } - }) - }) - - describe('#expectLengthBelowThan', () => { - it('should not show error', () => { - I.expectMatchesPattern('123', /123/) - }) - - it('should show error', () => { - try { - I.expectMatchesPattern('123', /1235/) - } catch (e) { - expect(e.message).to.contain("didn't match target /1235/") - } - }) - }) -}) diff --git a/test/helper/JSONResponse_test.js b/test/helper/JSONResponse_test.js index 0fd19b194..ee67a328c 100644 --- a/test/helper/JSONResponse_test.js +++ b/test/helper/JSONResponse_test.js @@ -1,5 +1,6 @@ -const chai = require('chai'); -const expect = chai.expect; +const chai = require('chai') + +const expect = chai.expect const joi = require('joi') const JSONResponse = require('../../lib/helper/JSONResponse') const Container = require('../../lib/container') diff --git a/test/helper/MockServer_test.js b/test/helper/MockServer_test.js index 27704a776..b86d246ce 100644 --- a/test/helper/MockServer_test.js +++ b/test/helper/MockServer_test.js @@ -1,7 +1,8 @@ const path = require('path') -const chai = require('chai'); -const expect = chai.expect; +const chai = require('chai') + +const expect = chai.expect const { like } = require('pactum-matchers') const MockServer = require('../../lib/helper/MockServer') diff --git a/test/helper/Playwright_test.js b/test/helper/Playwright_test.js index 8b542e6b7..af510c446 100644 --- a/test/helper/Playwright_test.js +++ b/test/helper/Playwright_test.js @@ -1,6 +1,7 @@ -const chai = require('chai'); -const assert = chai.assert; -const expect = chai.expect; +const chai = require('chai') + +const assert = chai.assert +const expect = chai.expect const path = require('path') const fs = require('fs') diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js index de452efe3..6c725b76a 100644 --- a/test/helper/Puppeteer_test.js +++ b/test/helper/Puppeteer_test.js @@ -1,5 +1,6 @@ -const chai = require('chai'); -const expect = chai.expect; -const assert = chai.assert; +const chai = require('chai') + +const expect = chai.expect +const assert = chai.assert // Rest of the file remains unchanged diff --git a/test/helper/SoftExpect_test.js b/test/helper/SoftExpect_test.js deleted file mode 100644 index d25752066..000000000 --- a/test/helper/SoftExpect_test.js +++ /dev/null @@ -1,477 +0,0 @@ -const path = require('path') - -const chai = require('chai'); -const expect = chai.expect; - -const SoftAssertHelper = require('../../lib/helper/SoftExpectHelper') - -global.codeceptjs = require('../../lib') - -let I - -const goodApple = { - skin: 'thin', - colors: ['red', 'green', 'yellow'], - taste: 10, -} -const badApple = { - colors: ['brown'], - taste: 0, - worms: 2, -} -const fruitSchema = { - title: 'fresh fruit schema v1', - type: 'object', - required: ['skin', 'colors', 'taste'], - properties: { - colors: { - type: 'array', - minItems: 1, - uniqueItems: true, - items: { - type: 'string', - }, - }, - skin: { - type: 'string', - }, - taste: { - type: 'number', - minimum: 5, - }, - }, -} - -describe('Soft Expect Helper', function () { - this.timeout(3000) - this.retries(1) - - before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - - I = new SoftAssertHelper() - }) - - describe('#softExpectEqual', () => { - it('should not show error', () => { - I.softExpectEqual('a', 'a') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectEqual('a', 'b') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain("expected 'a' to equal 'b'") - } - }) - }) - - describe('#softExpectNotEqual', () => { - it('should not show error', () => { - I.softExpectNotEqual('a', 'b') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectNotEqual('a', 'a') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain("expected 'a' to not equal 'a'") - } - }) - }) - - describe('#softExpectContain', () => { - it('should not show error', () => { - I.softExpectContain('abc', 'a') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectContain('abc', 'd') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain("expected 'abc' to include 'd'") - } - }) - }) - - describe('#softExpectNotContain', () => { - it('should not show error', () => { - I.softExpectNotContain('abc', 'd') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectNotContain('abc', 'a') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain("expected 'abc' to not include 'a'") - } - }) - }) - - describe('#softExpectStartsWith', () => { - it('should not show error', () => { - I.softExpectStartsWith('abc', 'a') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectStartsWith('abc', 'b') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected abc to start with b') - } - }) - }) - - describe('#softExpectNotStartsWith', () => { - it('should not show error', () => { - I.softExpectNotStartsWith('abc', 'b') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectNotStartsWith('abc', 'a') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected abc not to start with a') - } - }) - }) - - describe('#softExpectEndsWith', () => { - it('should not show error', () => { - I.softExpectEndsWith('abc', 'c') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectEndsWith('abc', 'd') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected abc to end with d') - } - }) - }) - - describe('#softExpectNotEndsWith', () => { - it('should not show error', () => { - I.softExpectNotEndsWith('abc', 'd') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectNotEndsWith('abc', 'd') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected abc not to end with c') - } - }) - }) - - describe('#softExpectJsonSchema', () => { - it('should not show error', () => { - I.softExpectJsonSchema(goodApple, fruitSchema) - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectJsonSchema(badApple, fruitSchema) - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected value to match json-schema') - } - }) - }) - - describe('#softExpectHasProperty', () => { - it('should not show error', () => { - I.softExpectHasProperty(goodApple, 'skin') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectHasProperty(badApple, 'skin') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected { Object (colors, taste') - } - }) - }) - - describe('#softExpectHasAProperty', () => { - it('should not show error', () => { - I.softExpectHasAProperty(goodApple, 'skin') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectHasAProperty(badApple, 'skin') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected { Object (colors, taste') - } - }) - }) - - describe('#softExpectToBeA', () => { - it('should not show error', () => { - I.softExpectToBeA(goodApple, 'object') - I.flushSoftAssertions() - }) - }) - - describe('#softExpectToBeAn', () => { - it('should not show error', () => { - I.softExpectToBeAn(goodApple, 'object') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectToBeAn(badApple, 'skin') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected { Object (colors, taste') - } - }) - }) - - describe('#softExpectMatchRegex', () => { - it('should not show error', () => { - I.softExpectMatchRegex('goodApple', /good/) - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectMatchRegex('Apple', /good/) - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('to match /good/') - } - }) - }) - - describe('#softExpectLengthOf', () => { - it('should not show error', () => { - I.softExpectLengthOf('good', 4) - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectLengthOf('Apple', 4) - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('to have a length') - } - }) - }) - - describe('#softExpectTrue', () => { - it('should not show error', () => { - I.softExpectTrue(true) - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectTrue(false) - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected false to be true') - } - }) - }) - - describe('#softExpectEmpty', () => { - it('should not show error', () => { - I.softExpectEmpty('') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectEmpty('false') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain("expected 'false' to be empty") - } - }) - }) - - describe('#softExpectFalse', () => { - it('should not show error', () => { - I.softExpectFalse(false) - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectFalse(true) - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected true to be false') - } - }) - }) - - describe('#softExpectAbove', () => { - it('should not show error', () => { - I.softExpectAbove(2, 1) - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectAbove(1, 2) - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected 1 to be above 2') - } - }) - }) - - describe('#softExpectBelow', () => { - it('should not show error', () => { - I.softExpectBelow(1, 2) - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectBelow(2, 1) - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected 2 to be below 1') - } - }) - }) - - describe('#softExpectLengthAboveThan', () => { - it('should not show error', () => { - I.softExpectLengthAboveThan('hello', 4) - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectLengthAboveThan('hello', 5) - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('to have a length above 5') - } - }) - }) - - describe('#softExpectLengthBelowThan', () => { - it('should not show error', () => { - I.softExpectLengthBelowThan('hello', 6) - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectLengthBelowThan('hello', 4) - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('to have a length below 4') - } - }) - }) - - describe('#softExpectLengthBelowThan', () => { - it('should not show error', () => { - I.softExpectEqualIgnoreCase('hEllo', 'hello') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectEqualIgnoreCase('hEllo', 'hell0') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected hEllo to equal hell0') - } - }) - }) - - describe('#softExpectDeepMembers', () => { - it('should not show error', () => { - I.softExpectDeepMembers([1, 2, 3], [1, 2, 3]) - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectDeepMembers([1, 2, 3], [3]) - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected [ 1, 2, 3 ] to have the same members') - } - }) - }) - - describe('#softExpectDeepIncludeMembers', () => { - it('should not show error', () => { - I.softExpectDeepIncludeMembers([3, 4, 5, 6], [3, 4, 5]) - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectDeepIncludeMembers([3, 4, 5], [3, 4, 5, 6]) - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected [ 3, 4, 5 ] to be a superset of [ 3, 4, 5, 6 ]') - } - }) - }) - - describe('#softExpectDeepEqualExcluding', () => { - it('should not show error', () => { - I.softExpectDeepEqualExcluding({ a: 1, b: 2 }, { b: 2, a: 1, c: 3 }, 'c') - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectDeepEqualExcluding({ a: 1, b: 2 }, { b: 2, a: 1, c: 3 }, 'a') - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain('expected { b: 2 } to deeply equal') - } - }) - }) - - describe('#softExpectLengthBelowThan', () => { - it('should not show error', () => { - I.softExpectMatchesPattern('123', /123/) - I.flushSoftAssertions() - }) - - it('should show error', () => { - try { - I.softExpectMatchesPattern('123', /1235/) - I.flushSoftAssertions() - } catch (e) { - expect(e.message).to.contain("didn't match target /1235/") - } - }) - }) -}) diff --git a/test/helper/WebDriver.noSeleniumServer_test.js b/test/helper/WebDriver.noSeleniumServer_test.js index de452efe3..6c725b76a 100644 --- a/test/helper/WebDriver.noSeleniumServer_test.js +++ b/test/helper/WebDriver.noSeleniumServer_test.js @@ -1,5 +1,6 @@ -const chai = require('chai'); -const expect = chai.expect; -const assert = chai.assert; +const chai = require('chai') + +const expect = chai.expect +const assert = chai.assert // Rest of the file remains unchanged diff --git a/test/helper/WebDriver_devtools_test.js b/test/helper/WebDriver_devtools_test.js index 36b9bf932..a4c2f0b8c 100644 --- a/test/helper/WebDriver_devtools_test.js +++ b/test/helper/WebDriver_devtools_test.js @@ -1,11 +1,8 @@ -const chai = require('chai'); -const expect = chai.expect; -const assert = chai.assert; +const chai = require('chai') + +const expect = chai.expect +const assert = chai.assert -let expect -import('chai').then((chai) => { - expect = chai.expect -}) const path = require('path') const fs = require('fs') diff --git a/test/helper/WebDriver_test.js b/test/helper/WebDriver_test.js index 9105223ac..6cba560dd 100644 --- a/test/helper/WebDriver_test.js +++ b/test/helper/WebDriver_test.js @@ -1,11 +1,7 @@ -const chai = require('chai'); -const expect = chai.expect; -const assert = chai.assert; +const chai = require('chai') -let expect -import('chai').then((chai) => { - expect = chai.expect -}) +const expect = chai.expect +const assert = chai.assert const path = require('path') const fs = require('fs') diff --git a/test/helper/webapi.js b/test/helper/webapi.js index 3cdc7540d..99f794baf 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -1,758 +1,759 @@ -const chai = require('chai'); -const expect = chai.expect; -const assert = chai.assert; -const path = require('path'); +const chai = require('chai') -const dataFile = path.join(__dirname, '/../data/app/db'); -const formContents = require('../../lib/utils').test.submittedData(dataFile); -const fileExists = require('../../lib/utils').fileExists; -const secret = require('../../lib/secret').secret; +const expect = chai.expect +const assert = chai.assert +const path = require('path') -const Locator = require('../../lib/locator'); -const customLocators = require('../../lib/plugin/customLocator'); +const dataFile = path.join(__dirname, '/../data/app/db') +const formContents = require('../../lib/utils').test.submittedData(dataFile) +const fileExists = require('../../lib/utils').fileExists +const secret = require('../../lib/secret').secret -let originalLocators; -let I; -let data; -let siteUrl; +const Locator = require('../../lib/locator') +const customLocators = require('../../lib/plugin/customLocator') + +let originalLocators +let I +let data +let siteUrl module.exports.init = function (testData) { - data = testData; -}; + data = testData +} module.exports.tests = function () { - const isHelper = (helperName) => I.constructor.name === helperName; + const isHelper = (helperName) => I.constructor.name === helperName beforeEach(() => { - I = data.I; - siteUrl = data.siteUrl; - if (fileExists(dataFile)) require('fs').unlinkSync(dataFile); - }); + I = data.I + siteUrl = data.siteUrl + if (fileExists(dataFile)) require('fs').unlinkSync(dataFile) + }) describe('#saveElementScreenshot', () => { beforeEach(() => { - global.output_dir = path.join(global.codecept_dir, 'output'); - }); + global.output_dir = path.join(global.codecept_dir, 'output') + }) it('should create a screenshot file in output dir of element', async () => { - await I.amOnPage('/form/field'); - await I.seeElement("input[name='name']"); - const sec = new Date().getUTCMilliseconds(); - await I.saveElementScreenshot("input[name='name']", `element_screenshot_${sec}.png`); - assert.ok(fileExists(path.join(global.output_dir, `element_screenshot_${sec}.png`)), null, 'file does not exists'); - }); - }); + await I.amOnPage('/form/field') + await I.seeElement("input[name='name']") + const sec = new Date().getUTCMilliseconds() + await I.saveElementScreenshot("input[name='name']", `element_screenshot_${sec}.png`) + assert.ok(fileExists(path.join(global.output_dir, `element_screenshot_${sec}.png`)), null, 'file does not exists') + }) + }) describe('current url : #seeInCurrentUrl, #seeCurrentUrlEquals, #grabCurrentUrl, ...', () => { it('should check for url fragment', async () => { - await I.amOnPage('/form/checkbox'); - await I.seeInCurrentUrl('/form'); - await I.dontSeeInCurrentUrl('/user'); - }); + await I.amOnPage('/form/checkbox') + await I.seeInCurrentUrl('/form') + await I.dontSeeInCurrentUrl('/user') + }) it('should check for equality', async () => { - await I.amOnPage('/info'); - await I.seeCurrentUrlEquals('/info'); - await I.dontSeeCurrentUrlEquals('form'); - }); + await I.amOnPage('/info') + await I.seeCurrentUrlEquals('/info') + await I.dontSeeCurrentUrlEquals('form') + }) it('should check for equality in absolute urls', async () => { - await I.amOnPage('/info'); - await I.seeCurrentUrlEquals(`${siteUrl}/info`); - await I.dontSeeCurrentUrlEquals(`${siteUrl}/form`); - }); + await I.amOnPage('/info') + await I.seeCurrentUrlEquals(`${siteUrl}/info`) + await I.dontSeeCurrentUrlEquals(`${siteUrl}/form`) + }) it('should grab browser url', async () => { - await I.amOnPage('/info'); - const url = await I.grabCurrentUrl(); - assert.equal(url, `${siteUrl}/info`); - }); - }); + await I.amOnPage('/info') + const url = await I.grabCurrentUrl() + assert.equal(url, `${siteUrl}/info`) + }) + }) describe('#waitInUrl, #waitUrlEquals', () => { it('should wait part of the URL to match the expected', async () => { try { - await I.amOnPage('/info'); - await I.waitInUrl('/info'); - await I.waitInUrl('/info2', 0.1); + await I.amOnPage('/info') + await I.waitInUrl('/info') + await I.waitInUrl('/info2', 0.1) } catch (e) { - assert.include(e.message, `expected url to include /info2, but found ${siteUrl}/info`); + assert.include(e.message, `expected url to include /info2, but found ${siteUrl}/info`) } - }); + }) it('should wait for the entire URL to match the expected', async () => { try { - await I.amOnPage('/info'); - await I.waitUrlEquals('/info'); - await I.waitUrlEquals(`${siteUrl}/info`); - await I.waitUrlEquals('/info2', 0.1); + await I.amOnPage('/info') + await I.waitUrlEquals('/info') + await I.waitUrlEquals(`${siteUrl}/info`) + await I.waitUrlEquals('/info2', 0.1) } catch (e) { - assert.include(e.message, `expected url to be ${siteUrl}/info2, but found ${siteUrl}/info`); + assert.include(e.message, `expected url to be ${siteUrl}/info2, but found ${siteUrl}/info`) } - }); - }); + }) + }) describe('see text : #see', () => { it('should check text on site', async () => { - await I.amOnPage('/'); - await I.see('Welcome to test app!'); - await I.see('A wise man said: "debug!"'); - await I.dontSee('Info'); - }); + await I.amOnPage('/') + await I.see('Welcome to test app!') + await I.see('A wise man said: "debug!"') + await I.dontSee('Info') + }) it('should check text inside element', async () => { - await I.amOnPage('/'); - await I.see('Welcome to test app!', 'h1'); - await I.amOnPage('/info'); - await I.see('valuable', { css: 'p' }); - await I.see('valuable', '//p'); - await I.dontSee('valuable', 'h1'); - }); + await I.amOnPage('/') + await I.see('Welcome to test app!', 'h1') + await I.amOnPage('/info') + await I.see('valuable', { css: 'p' }) + await I.see('valuable', '//p') + await I.dontSee('valuable', 'h1') + }) it('should verify non-latin chars', async () => { - await I.amOnPage('/info'); - await I.see('на'); - await I.see("Don't do that at home!", 'h3'); - await I.see('Текст', 'p'); - }); + await I.amOnPage('/info') + await I.see('на') + await I.see("Don't do that at home!", 'h3') + await I.see('Текст', 'p') + }) it('should verify text with  ', async () => { - if (isHelper('TestCafe') || isHelper('WebDriver')) return; - await I.amOnPage('/'); - await I.see('With special space chars'); - }); - }); + if (isHelper('TestCafe') || isHelper('WebDriver')) return + await I.amOnPage('/') + await I.see('With special space chars') + }) + }) describe('see element : #seeElement, #seeElementInDOM, #dontSeeElement', () => { it('should check visible elements on page', async () => { - await I.amOnPage('/form/field'); - await I.seeElement('input[name=name]'); - await I.seeElement({ name: 'name' }); - await I.seeElement('//input[@id="name"]'); - await I.dontSeeElement('#something-beyond'); - await I.dontSeeElement('//input[@id="something-beyond"]'); - await I.dontSeeElement({ name: 'noname' }); - await I.dontSeeElement('#noid'); - }); + await I.amOnPage('/form/field') + await I.seeElement('input[name=name]') + await I.seeElement({ name: 'name' }) + await I.seeElement('//input[@id="name"]') + await I.dontSeeElement('#something-beyond') + await I.dontSeeElement('//input[@id="something-beyond"]') + await I.dontSeeElement({ name: 'noname' }) + await I.dontSeeElement('#noid') + }) it('should check elements are in the DOM', async () => { - await I.amOnPage('/form/field'); - await I.seeElementInDOM('input[name=name]'); - await I.seeElementInDOM('//input[@id="name"]'); - await I.seeElementInDOM({ name: 'noname' }); - await I.seeElementInDOM('#noid'); - await I.dontSeeElementInDOM('#something-beyond'); - await I.dontSeeElementInDOM('//input[@id="something-beyond"]'); - }); + await I.amOnPage('/form/field') + await I.seeElementInDOM('input[name=name]') + await I.seeElementInDOM('//input[@id="name"]') + await I.seeElementInDOM({ name: 'noname' }) + await I.seeElementInDOM('#noid') + await I.dontSeeElementInDOM('#something-beyond') + await I.dontSeeElementInDOM('//input[@id="something-beyond"]') + }) it('should check elements are visible on the page', async () => { - await I.amOnPage('/form/field'); - await I.seeElementInDOM('input[name=email]'); - await I.dontSeeElement('input[name=email]'); - await I.dontSeeElement('#something-beyond'); - }); - }); + await I.amOnPage('/form/field') + await I.seeElementInDOM('input[name=email]') + await I.dontSeeElement('input[name=email]') + await I.dontSeeElement('#something-beyond') + }) + }) describe('#seeNumberOfVisibleElements', () => { it('should check number of visible elements for given locator', async () => { - await I.amOnPage('/info'); - await I.seeNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 3); - }); - }); + await I.amOnPage('/info') + await I.seeNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 3) + }) + }) describe('#grabNumberOfVisibleElements', () => { it('should grab number of visible elements for given locator', async () => { - await I.amOnPage('/info'); - const num = await I.grabNumberOfVisibleElements('//div[@id = "grab-multiple"]//a'); - assert.equal(num, 3); - }); + await I.amOnPage('/info') + const num = await I.grabNumberOfVisibleElements('//div[@id = "grab-multiple"]//a') + assert.equal(num, 3) + }) it('should support locators like {xpath:"//div"}', async () => { - await I.amOnPage('/info'); + await I.amOnPage('/info') const num = await I.grabNumberOfVisibleElements({ xpath: '//div[@id = "grab-multiple"]//a', - }); - assert.equal(num, 3); - }); + }) + assert.equal(num, 3) + }) it('should grab number of visible elements for given css locator', async () => { - await I.amOnPage('/info'); - const num = await I.grabNumberOfVisibleElements('[id=grab-multiple] a'); - assert.equal(num, 3); - }); + await I.amOnPage('/info') + const num = await I.grabNumberOfVisibleElements('[id=grab-multiple] a') + assert.equal(num, 3) + }) it('should return 0 for non-existing elements', async () => { - await I.amOnPage('/info'); - const num = await I.grabNumberOfVisibleElements('button[type=submit]'); - assert.equal(num, 0); - }); + await I.amOnPage('/info') + const num = await I.grabNumberOfVisibleElements('button[type=submit]') + assert.equal(num, 0) + }) it('should honor visibility hidden style', async () => { - await I.amOnPage('/info'); - const num = await I.grabNumberOfVisibleElements('.issue2928'); - assert.equal(num, 1); - }); - }); + await I.amOnPage('/info') + const num = await I.grabNumberOfVisibleElements('.issue2928') + assert.equal(num, 1) + }) + }) describe('#seeInSource, #dontSeeInSource', () => { it('should check meta of a page', async () => { - await I.amOnPage('/info'); - await I.seeInSource(''); - await I.dontSeeInSource(''); - await I.seeInSource('Invisible text'); - await I.seeInSource('content="text/html; charset=utf-8"'); - }); - }); + await I.amOnPage('/info') + await I.seeInSource('') + await I.dontSeeInSource('') + await I.seeInSource('Invisible text') + await I.seeInSource('content="text/html; charset=utf-8"') + }) + }) describe('#click', () => { it('should click by inner text', async () => { - await I.amOnPage('/'); - await I.click('More info'); - await I.seeInCurrentUrl('/info'); - }); + await I.amOnPage('/') + await I.click('More info') + await I.seeInCurrentUrl('/info') + }) it('should click by css', async () => { - await I.amOnPage('/'); - await I.click('#link'); - await I.seeInCurrentUrl('/info'); - }); + await I.amOnPage('/') + await I.click('#link') + await I.seeInCurrentUrl('/info') + }) it('should click by xpath', async () => { - await I.amOnPage('/'); - await I.click('//a[@id="link"]'); - await I.seeInCurrentUrl('/info'); - }); + await I.amOnPage('/') + await I.click('//a[@id="link"]') + await I.seeInCurrentUrl('/info') + }) it('should click by name', async () => { - await I.amOnPage('/form/button'); - await I.click('btn0'); - assert.equal(formContents('text'), 'val'); - }); + await I.amOnPage('/form/button') + await I.click('btn0') + assert.equal(formContents('text'), 'val') + }) it('should click on context', async () => { - await I.amOnPage('/'); - await I.click('More info', 'body>p'); - await I.seeInCurrentUrl('/info'); - }); + await I.amOnPage('/') + await I.click('More info', 'body>p') + await I.seeInCurrentUrl('/info') + }) it('should not click wrong context', async () => { - let err = false; - await I.amOnPage('/'); + let err = false + await I.amOnPage('/') try { - await I.click('More info', '#area1'); + await I.click('More info', '#area1') } catch (e) { - err = true; + err = true } - assert.ok(err); - }); + assert.ok(err) + }) it('should should click by aria-label', async () => { - await I.amOnPage('/form/aria'); - await I.click('get info'); - await I.seeInCurrentUrl('/info'); - }); + await I.amOnPage('/form/aria') + await I.click('get info') + await I.seeInCurrentUrl('/info') + }) it('should click link with inner span', async () => { - await I.amOnPage('/form/example7'); - await I.click('Buy Chocolate Bar'); - await I.seeCurrentUrlEquals('/'); - }); + await I.amOnPage('/form/example7') + await I.click('Buy Chocolate Bar') + await I.seeCurrentUrlEquals('/') + }) it('should click link with xpath locator', async () => { - await I.amOnPage('/form/example7'); + await I.amOnPage('/form/example7') await I.click({ xpath: '(//*[@title = "Chocolate Bar"])[1]', - }); - await I.seeCurrentUrlEquals('/'); - }); - }); + }) + await I.seeCurrentUrlEquals('/') + }) + }) describe('#forceClick', () => { beforeEach(function () { - if (isHelper('TestCafe')) this.skip(); - }); + if (isHelper('TestCafe')) this.skip() + }) it('should forceClick by inner text', async () => { - await I.amOnPage('/'); - await I.forceClick('More info'); - if (isHelper('Puppeteer')) await I.waitForNavigation(); - await I.seeInCurrentUrl('/info'); - }); + await I.amOnPage('/') + await I.forceClick('More info') + if (isHelper('Puppeteer')) await I.waitForNavigation() + await I.seeInCurrentUrl('/info') + }) it('should forceClick by css', async () => { - await I.amOnPage('/'); - await I.forceClick('#link'); - if (isHelper('Puppeteer')) await I.waitForNavigation(); - await I.seeInCurrentUrl('/info'); - }); + await I.amOnPage('/') + await I.forceClick('#link') + if (isHelper('Puppeteer')) await I.waitForNavigation() + await I.seeInCurrentUrl('/info') + }) it('should forceClick by xpath', async () => { - await I.amOnPage('/'); - await I.forceClick('//a[@id="link"]'); - if (isHelper('Puppeteer')) await I.waitForNavigation(); - await I.seeInCurrentUrl('/info'); - }); + await I.amOnPage('/') + await I.forceClick('//a[@id="link"]') + if (isHelper('Puppeteer')) await I.waitForNavigation() + await I.seeInCurrentUrl('/info') + }) it('should forceClick on context', async () => { - await I.amOnPage('/'); - await I.forceClick('More info', 'body>p'); - if (isHelper('Puppeteer')) await I.waitForNavigation(); - await I.seeInCurrentUrl('/info'); - }); - }); + await I.amOnPage('/') + await I.forceClick('More info', 'body>p') + if (isHelper('Puppeteer')) await I.waitForNavigation() + await I.seeInCurrentUrl('/info') + }) + }) // Could not get double click to work describe('#doubleClick', () => { it('it should doubleClick', async () => { - await I.amOnPage('/form/doubleclick'); - await I.dontSee('Done'); - await I.doubleClick('#block'); - await I.see('Done'); - }); - }); + await I.amOnPage('/form/doubleclick') + await I.dontSee('Done') + await I.doubleClick('#block') + await I.see('Done') + }) + }) // rightClick does not seem to work either describe('#rightClick', () => { it('it should rightClick', async () => { - await I.amOnPage('/form/rightclick'); - await I.dontSee('right clicked'); - await I.rightClick('Lorem Ipsum'); - await I.see('right clicked'); - }); + await I.amOnPage('/form/rightclick') + await I.dontSee('right clicked') + await I.rightClick('Lorem Ipsum') + await I.see('right clicked') + }) it('it should rightClick by locator', async () => { - await I.amOnPage('/form/rightclick'); - await I.dontSee('right clicked'); - await I.rightClick('.context a'); - await I.see('right clicked'); - }); + await I.amOnPage('/form/rightclick') + await I.dontSee('right clicked') + await I.rightClick('.context a') + await I.see('right clicked') + }) it('it should rightClick by locator and context', async () => { - await I.amOnPage('/form/rightclick'); - await I.dontSee('right clicked'); - await I.rightClick('Lorem Ipsum', '.context'); - await I.see('right clicked'); - }); - }); + await I.amOnPage('/form/rightclick') + await I.dontSee('right clicked') + await I.rightClick('Lorem Ipsum', '.context') + await I.see('right clicked') + }) + }) describe('#checkOption', () => { it('should check option by css', async () => { - await I.amOnPage('/form/checkbox'); - await I.checkOption('#checkin'); - await I.click('Submit'); - await I.wait(1); - assert.equal(formContents('terms'), 'agree'); - }); + await I.amOnPage('/form/checkbox') + await I.checkOption('#checkin') + await I.click('Submit') + await I.wait(1) + assert.equal(formContents('terms'), 'agree') + }) it('should check option by strict locator', async () => { - await I.amOnPage('/form/checkbox'); + await I.amOnPage('/form/checkbox') await I.checkOption({ id: 'checkin', - }); - await I.click('Submit'); - assert.equal(formContents('terms'), 'agree'); - }); + }) + await I.click('Submit') + assert.equal(formContents('terms'), 'agree') + }) it('should check option by name', async () => { - await I.amOnPage('/form/checkbox'); - await I.checkOption('terms'); - await I.click('Submit'); - assert.equal(formContents('terms'), 'agree'); - }); + await I.amOnPage('/form/checkbox') + await I.checkOption('terms') + await I.click('Submit') + assert.equal(formContents('terms'), 'agree') + }) it('should check option by label', async () => { - await I.amOnPage('/form/checkbox'); - await I.checkOption('I Agree'); - await I.click('Submit'); - assert.equal(formContents('terms'), 'agree'); - }); + await I.amOnPage('/form/checkbox') + await I.checkOption('I Agree') + await I.click('Submit') + assert.equal(formContents('terms'), 'agree') + }) // TODO Having problems with functional style selectors in testcafe // cannot do Selector(css).find(elementByXPath(xpath)) // testcafe always says "xpath is not defined" // const el = Selector(context).find(elementByXPath(Locator.checkable.byText(xpathLocator.literal(field))).with({ boundTestRun: this.t })).with({ boundTestRun: this.t }); it.skip('should check option by context', async () => { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/form/example1'); - await I.checkOption('Remember me next time', '.rememberMe'); - await I.click('Login'); - assert.equal(formContents('LoginForm').rememberMe, 1); - }); - }); + await I.amOnPage('/form/example1') + await I.checkOption('Remember me next time', '.rememberMe') + await I.click('Login') + assert.equal(formContents('LoginForm').rememberMe, 1) + }) + }) describe('#uncheckOption', () => { it('should uncheck option that is currently checked', async () => { - await I.amOnPage('/info'); - await I.uncheckOption('interesting'); - await I.dontSeeCheckboxIsChecked('interesting'); - }); - }); + await I.amOnPage('/info') + await I.uncheckOption('interesting') + await I.dontSeeCheckboxIsChecked('interesting') + }) + }) describe('#selectOption', () => { it('should select option by css', async () => { - await I.amOnPage('/form/select'); - await I.selectOption('form select[name=age]', 'adult'); - await I.click('Submit'); - assert.equal(formContents('age'), 'adult'); - }); + await I.amOnPage('/form/select') + await I.selectOption('form select[name=age]', 'adult') + await I.click('Submit') + assert.equal(formContents('age'), 'adult') + }) it('should select option by name', async () => { - await I.amOnPage('/form/select'); - await I.selectOption('age', 'adult'); - await I.click('Submit'); - assert.equal(formContents('age'), 'adult'); - }); + await I.amOnPage('/form/select') + await I.selectOption('age', 'adult') + await I.click('Submit') + assert.equal(formContents('age'), 'adult') + }) it('should select option by label', async () => { - await I.amOnPage('/form/select'); - await I.selectOption('Select your age', 'dead'); - await I.click('Submit'); - assert.equal(formContents('age'), 'dead'); - }); + await I.amOnPage('/form/select') + await I.selectOption('Select your age', 'dead') + await I.click('Submit') + assert.equal(formContents('age'), 'dead') + }) it('should select option by label and option text', async () => { - await I.amOnPage('/form/select'); - await I.selectOption('Select your age', '21-60'); - await I.click('Submit'); - assert.equal(formContents('age'), 'adult'); - }); + await I.amOnPage('/form/select') + await I.selectOption('Select your age', '21-60') + await I.click('Submit') + assert.equal(formContents('age'), 'adult') + }) it('should select option by label and option text - with an onchange callback', async () => { - await I.amOnPage('/form/select_onchange'); - await I.selectOption('Select a value', 'Option 2'); - await I.click('Submit'); - assert.equal(formContents('select'), 'option2'); - }); + await I.amOnPage('/form/select_onchange') + await I.selectOption('Select a value', 'Option 2') + await I.click('Submit') + assert.equal(formContents('select'), 'option2') + }) // Could not get multiselect to work with testcafe it('should select multiple options', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/form/select_multiple'); - await I.selectOption('What do you like the most?', ['Play Video Games', 'Have Sex']); - await I.click('Submit'); - assert.deepEqual(formContents('like'), ['play', 'adult']); - }); + await I.amOnPage('/form/select_multiple') + await I.selectOption('What do you like the most?', ['Play Video Games', 'Have Sex']) + await I.click('Submit') + assert.deepEqual(formContents('like'), ['play', 'adult']) + }) it('should select option by label and option text with additional spaces', async () => { - await I.amOnPage('/form/select_additional_spaces'); - await I.selectOption('Select your age', '21-60'); - await I.click('Submit'); - assert.equal(formContents('age'), 'adult'); - }); - }); + await I.amOnPage('/form/select_additional_spaces') + await I.selectOption('Select your age', '21-60') + await I.click('Submit') + assert.equal(formContents('age'), 'adult') + }) + }) describe('#executeScript', () => { it('should execute synchronous script', async () => { - await I.amOnPage('/'); + await I.amOnPage('/') await I.executeScript(() => { - document.getElementById('link').innerHTML = 'Appended'; - }); - await I.see('Appended', 'a'); - }); + document.getElementById('link').innerHTML = 'Appended' + }) + await I.see('Appended', 'a') + }) it('should return value from sync script', async () => { - await I.amOnPage('/'); - const val = await I.executeScript((a) => a + 5, 5); - assert.equal(val, 10); - }); + await I.amOnPage('/') + const val = await I.executeScript((a) => a + 5, 5) + assert.equal(val, 10) + }) it('should return value from sync script in iframe', async function () { // TODO Not yet implemented - if (isHelper('TestCafe')) this.skip(); // TODO Not yet implemented + if (isHelper('TestCafe')) this.skip() // TODO Not yet implemented - await I.amOnPage('/iframe'); - await I.switchTo({ css: 'iframe' }); - const val = await I.executeScript(() => document.getElementsByTagName('h1')[0].innerText); - assert.equal(val, 'Information'); - }); + await I.amOnPage('/iframe') + await I.switchTo({ css: 'iframe' }) + const val = await I.executeScript(() => document.getElementsByTagName('h1')[0].innerText) + assert.equal(val, 'Information') + }) it('should execute async script', async function () { - if (isHelper('TestCafe')) this.skip(); // TODO Not yet implemented - if (isHelper('Playwright')) return; // It won't be implemented + if (isHelper('TestCafe')) this.skip() // TODO Not yet implemented + if (isHelper('Playwright')) return // It won't be implemented - await I.amOnPage('/'); + await I.amOnPage('/') const val = await I.executeAsyncScript((val, done) => { setTimeout(() => { - document.getElementById('link').innerHTML = val; - done(5); - }, 100); - }, 'Timeout'); - assert.equal(val, 5); - await I.see('Timeout', 'a'); - }); - }); + document.getElementById('link').innerHTML = val + done(5) + }, 100) + }, 'Timeout') + assert.equal(val, 5) + await I.see('Timeout', 'a') + }) + }) describe('#fillField, #appendField', () => { it('should fill input fields', async () => { - await I.amOnPage('/form/field'); - await I.fillField('Name', 'Nothing special'); - await I.click('Submit'); - assert.equal(formContents('name'), 'Nothing special'); - }); + await I.amOnPage('/form/field') + await I.fillField('Name', 'Nothing special') + await I.click('Submit') + assert.equal(formContents('name'), 'Nothing special') + }) it('should fill input fields with secrets', async () => { - await I.amOnPage('/form/field'); - await I.fillField('Name', secret('Something special')); - await I.click('Submit'); - assert.equal(formContents('name'), 'Something special'); - }); + await I.amOnPage('/form/field') + await I.fillField('Name', secret('Something special')) + await I.click('Submit') + assert.equal(formContents('name'), 'Something special') + }) it('should fill field by css', async () => { - await I.amOnPage('/form/field'); - await I.fillField('#name', 'Nothing special'); - await I.click('Submit'); - assert.equal(formContents('name'), 'Nothing special'); - }); + await I.amOnPage('/form/field') + await I.fillField('#name', 'Nothing special') + await I.click('Submit') + assert.equal(formContents('name'), 'Nothing special') + }) it('should fill field by strict locator', async () => { - await I.amOnPage('/form/field'); + await I.amOnPage('/form/field') await I.fillField( { id: 'name', }, 'Nothing special', - ); - await I.click('Submit'); - assert.equal(formContents('name'), 'Nothing special'); - }); + ) + await I.click('Submit') + assert.equal(formContents('name'), 'Nothing special') + }) it('should fill field by name', async () => { - await I.amOnPage('/form/example1'); - await I.fillField('LoginForm[username]', 'davert'); - await I.fillField('LoginForm[password]', '123456'); - await I.click('Login'); - assert.equal(formContents('LoginForm').username, 'davert'); - assert.equal(formContents('LoginForm').password, '123456'); - }); + await I.amOnPage('/form/example1') + await I.fillField('LoginForm[username]', 'davert') + await I.fillField('LoginForm[password]', '123456') + await I.click('Login') + assert.equal(formContents('LoginForm').username, 'davert') + assert.equal(formContents('LoginForm').password, '123456') + }) it('should fill textarea by css', async () => { - await I.amOnPage('/form/textarea'); - await I.fillField('textarea', 'Nothing special'); - await I.click('Submit'); - assert.equal(formContents('description'), 'Nothing special'); - }); + await I.amOnPage('/form/textarea') + await I.fillField('textarea', 'Nothing special') + await I.click('Submit') + assert.equal(formContents('description'), 'Nothing special') + }) it('should fill textarea by label', async () => { - await I.amOnPage('/form/textarea'); - await I.fillField('Description', 'Nothing special'); - await I.click('Submit'); - assert.equal(formContents('description'), 'Nothing special'); - }); + await I.amOnPage('/form/textarea') + await I.fillField('Description', 'Nothing special') + await I.click('Submit') + assert.equal(formContents('description'), 'Nothing special') + }) it('should fill input by aria-label and aria-labelledby', async () => { - await I.amOnPage('/form/aria'); - await I.fillField('My Address', 'Home Sweet Home'); - await I.fillField('Phone', '123456'); - await I.click('Submit'); - assert.equal(formContents('my-form-phone'), '123456'); - assert.equal(formContents('my-form-address'), 'Home Sweet Home'); - }); + await I.amOnPage('/form/aria') + await I.fillField('My Address', 'Home Sweet Home') + await I.fillField('Phone', '123456') + await I.click('Submit') + assert.equal(formContents('my-form-phone'), '123456') + assert.equal(formContents('my-form-address'), 'Home Sweet Home') + }) it('should fill textarea by overwritting the existing value', async () => { - await I.amOnPage('/form/textarea'); - await I.fillField('Description', 'Nothing special'); - await I.fillField('Description', 'Some other text'); - await I.click('Submit'); - assert.equal(formContents('description'), 'Some other text'); - }); + await I.amOnPage('/form/textarea') + await I.fillField('Description', 'Nothing special') + await I.fillField('Description', 'Some other text') + await I.click('Submit') + assert.equal(formContents('description'), 'Some other text') + }) it('should append field value', async () => { - await I.amOnPage('/form/field'); - await I.appendField('Name', '_AND_NEW'); - await I.click('Submit'); - assert.equal(formContents('name'), 'OLD_VALUE_AND_NEW'); - }); + await I.amOnPage('/form/field') + await I.appendField('Name', '_AND_NEW') + await I.click('Submit') + assert.equal(formContents('name'), 'OLD_VALUE_AND_NEW') + }) it.skip('should not fill invisible fields', async () => { - if (isHelper('Playwright')) return; // It won't be implemented - await I.amOnPage('/form/field'); + if (isHelper('Playwright')) return // It won't be implemented + await I.amOnPage('/form/field') try { - I.fillField('email', 'test@1234'); + I.fillField('email', 'test@1234') } catch (e) { - await assert.equal(e.message, 'Error: Field "email" was not found by text|CSS|XPath'); + await assert.equal(e.message, 'Error: Field "email" was not found by text|CSS|XPath') } - }); - }); + }) + }) describe('#clearField', () => { it('should clear a given element', async () => { - await I.amOnPage('/form/field'); - await I.fillField('#name', 'Nothing special'); - await I.seeInField('#name', 'Nothing special'); - await I.clearField('#name'); - await I.dontSeeInField('#name', 'Nothing special'); - }); + await I.amOnPage('/form/field') + await I.fillField('#name', 'Nothing special') + await I.seeInField('#name', 'Nothing special') + await I.clearField('#name') + await I.dontSeeInField('#name', 'Nothing special') + }) it('should clear field by name', async () => { - await I.amOnPage('/form/example1'); - await I.clearField('LoginForm[username]'); - await I.click('Login'); - assert.equal(formContents('LoginForm').username, ''); - }); + await I.amOnPage('/form/example1') + await I.clearField('LoginForm[username]') + await I.click('Login') + assert.equal(formContents('LoginForm').username, '') + }) it('should clear field by locator', async () => { - await I.amOnPage('/form/example1'); - await I.clearField('#LoginForm_username'); - await I.click('Login'); - assert.equal(formContents('LoginForm').username, ''); - }); - }); + await I.amOnPage('/form/example1') + await I.clearField('#LoginForm_username') + await I.click('Login') + assert.equal(formContents('LoginForm').username, '') + }) + }) describe('#type', () => { it('should type into a field', async function () { - if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/field'); - await I.click('Name'); + if (isHelper('TestCafe')) this.skip() + await I.amOnPage('/form/field') + await I.click('Name') - await I.type('Type Test'); - await I.seeInField('Name', 'Type Test'); + await I.type('Type Test') + await I.seeInField('Name', 'Type Test') - await I.fillField('Name', ''); + await I.fillField('Name', '') - await I.type(['T', 'y', 'p', 'e', '2']); - await I.seeInField('Name', 'Type2'); - }); + await I.type(['T', 'y', 'p', 'e', '2']) + await I.seeInField('Name', 'Type2') + }) it('should use delay to slow down typing', async function () { - if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/field'); - await I.fillField('Name', ''); - const time = Date.now(); - await I.type('12345', 100); - await I.seeInField('Name', '12345'); - assert(Date.now() - time > 500); - }); - }); + if (isHelper('TestCafe')) this.skip() + await I.amOnPage('/form/field') + await I.fillField('Name', '') + const time = Date.now() + await I.type('12345', 100) + await I.seeInField('Name', '12345') + assert(Date.now() - time > 500) + }) + }) describe('check fields: #seeInField, #seeCheckboxIsChecked, ...', () => { it('should check for empty field', async () => { - await I.amOnPage('/form/empty'); - await I.seeInField('#empty_input', ''); - }); + await I.amOnPage('/form/empty') + await I.seeInField('#empty_input', '') + }) it('should check for empty textarea', async () => { - await I.amOnPage('/form/empty'); - await I.seeInField('#empty_textarea', ''); - }); + await I.amOnPage('/form/empty') + await I.seeInField('#empty_textarea', '') + }) it('should check field equals', async () => { - await I.amOnPage('/form/field'); - await I.seeInField('Name', 'OLD_VALUE'); - await I.seeInField('name', 'OLD_VALUE'); - await I.seeInField('//input[@id="name"]', 'OLD_VALUE'); - await I.dontSeeInField('//input[@id="name"]', 'NOtVALUE'); - }); + await I.amOnPage('/form/field') + await I.seeInField('Name', 'OLD_VALUE') + await I.seeInField('name', 'OLD_VALUE') + await I.seeInField('//input[@id="name"]', 'OLD_VALUE') + await I.dontSeeInField('//input[@id="name"]', 'NOtVALUE') + }) it('should check textarea equals', async () => { - await I.amOnPage('/form/textarea'); - await I.seeInField('Description', 'sunrise'); - await I.seeInField('textarea', 'sunrise'); - await I.seeInField('//textarea[@id="description"]', 'sunrise'); - await I.dontSeeInField('//textarea[@id="description"]', 'sunset'); - }); + await I.amOnPage('/form/textarea') + await I.seeInField('Description', 'sunrise') + await I.seeInField('textarea', 'sunrise') + await I.seeInField('//textarea[@id="description"]', 'sunrise') + await I.dontSeeInField('//textarea[@id="description"]', 'sunset') + }) it('should check checkbox is checked :)', async () => { - await I.amOnPage('/info'); - await I.seeCheckboxIsChecked('input[type=checkbox]'); - }); + await I.amOnPage('/info') + await I.seeCheckboxIsChecked('input[type=checkbox]') + }) it('should check checkbox is not checked', async () => { - await I.amOnPage('/form/checkbox'); - await I.dontSeeCheckboxIsChecked('#checkin'); - }); + await I.amOnPage('/form/checkbox') + await I.dontSeeCheckboxIsChecked('#checkin') + }) it('should match fields with the same name', async () => { - await I.amOnPage('/form/example20'); - await I.seeInField("//input[@name='txtName'][2]", 'emma'); - await I.seeInField("input[name='txtName']:nth-child(2)", 'emma'); - }); - }); + await I.amOnPage('/form/example20') + await I.seeInField("//input[@name='txtName'][2]", 'emma') + await I.seeInField("input[name='txtName']:nth-child(2)", 'emma') + }) + }) describe('#grabTextFromAll, #grabHTMLFromAll, #grabValueFromAll, #grabAttributeFromAll', () => { it('should grab multiple texts from page', async () => { - await I.amOnPage('/info'); - let vals = await I.grabTextFromAll('#grab-multiple a'); - assert.equal(vals[0], 'First'); - assert.equal(vals[1], 'Second'); - assert.equal(vals[2], 'Third'); + await I.amOnPage('/info') + let vals = await I.grabTextFromAll('#grab-multiple a') + assert.equal(vals[0], 'First') + assert.equal(vals[1], 'Second') + assert.equal(vals[2], 'Third') - await I.amOnPage('/info'); - vals = await I.grabTextFromAll('#invalid-id a'); - assert.equal(vals.length, 0); - }); + await I.amOnPage('/info') + vals = await I.grabTextFromAll('#invalid-id a') + assert.equal(vals.length, 0) + }) it('should grab multiple html from page', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/info'); - let vals = await I.grabHTMLFromAll('#grab-multiple a'); - assert.equal(vals[0], 'First'); - assert.equal(vals[1], 'Second'); - assert.equal(vals[2], 'Third'); + await I.amOnPage('/info') + let vals = await I.grabHTMLFromAll('#grab-multiple a') + assert.equal(vals[0], 'First') + assert.equal(vals[1], 'Second') + assert.equal(vals[2], 'Third') - await I.amOnPage('/info'); - vals = await I.grabHTMLFromAll('#invalid-id a'); - assert.equal(vals.length, 0); - }); + await I.amOnPage('/info') + vals = await I.grabHTMLFromAll('#invalid-id a') + assert.equal(vals.length, 0) + }) it('should grab multiple attribute from element', async () => { - await I.amOnPage('/form/empty'); + await I.amOnPage('/form/empty') const vals = await I.grabAttributeFromAll( { css: 'input', }, 'name', - ); - assert.equal(vals[0], 'text'); - assert.equal(vals[1], 'empty_input'); - }); + ) + assert.equal(vals[0], 'text') + assert.equal(vals[1], 'empty_input') + }) it('Should return empty array if no attribute found', async () => { - await I.amOnPage('/form/empty'); + await I.amOnPage('/form/empty') const vals = await I.grabAttributeFromAll( { css: 'div', }, 'test', - ); - assert.equal(vals.length, 0); - }); + ) + assert.equal(vals.length, 0) + }) it('should grab values if multiple field matches', async () => { - await I.amOnPage('/form/hidden'); - let vals = await I.grabValueFromAll('//form/input'); - assert.equal(vals[0], 'kill_people'); - assert.equal(vals[1], 'Submit'); + await I.amOnPage('/form/hidden') + let vals = await I.grabValueFromAll('//form/input') + assert.equal(vals[0], 'kill_people') + assert.equal(vals[1], 'Submit') - vals = await I.grabValueFromAll("//form/input[@name='action']"); - assert.equal(vals[0], 'kill_people'); - }); + vals = await I.grabValueFromAll("//form/input[@name='action']") + assert.equal(vals[0], 'kill_people') + }) it('Should return empty array if no value found', async () => { - await I.amOnPage('/'); - const vals = await I.grabValueFromAll('//form/input'); - assert.equal(vals.length, 0); - }); - }); + await I.amOnPage('/') + const vals = await I.grabValueFromAll('//form/input') + assert.equal(vals.length, 0) + }) + }) describe('#grabTextFrom, #grabHTMLFrom, #grabValueFrom, #grabAttributeFrom', () => { it('should grab text from page', async () => { - await I.amOnPage('/'); - let val = await I.grabTextFrom('h1'); - assert.equal(val, 'Welcome to test app!'); + await I.amOnPage('/') + let val = await I.grabTextFrom('h1') + assert.equal(val, 'Welcome to test app!') - val = await I.grabTextFrom('//h1'); - assert.equal(val, 'Welcome to test app!'); - }); + val = await I.grabTextFrom('//h1') + assert.equal(val, 'Welcome to test app!') + }) it('should grab html from page', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/info'); - const val = await I.grabHTMLFrom('#grab-multiple'); + await I.amOnPage('/info') + const val = await I.grabHTMLFrom('#grab-multiple') assert.equal( ` First @@ -760,1051 +761,1051 @@ module.exports.tests = function () { Third `, val, - ); - }); + ) + }) it('should grab value from field', async () => { - await I.amOnPage('/form/hidden'); - let val = await I.grabValueFrom('#action'); - assert.equal(val, 'kill_people'); - val = await I.grabValueFrom("//form/input[@name='action']"); - assert.equal(val, 'kill_people'); - await I.amOnPage('/form/textarea'); - val = await I.grabValueFrom('#description'); - assert.equal(val, 'sunrise'); - await I.amOnPage('/form/select'); - val = await I.grabValueFrom('#age'); - assert.equal(val, 'oldfag'); - }); + await I.amOnPage('/form/hidden') + let val = await I.grabValueFrom('#action') + assert.equal(val, 'kill_people') + val = await I.grabValueFrom("//form/input[@name='action']") + assert.equal(val, 'kill_people') + await I.amOnPage('/form/textarea') + val = await I.grabValueFrom('#description') + assert.equal(val, 'sunrise') + await I.amOnPage('/form/select') + val = await I.grabValueFrom('#age') + assert.equal(val, 'oldfag') + }) it('should grab attribute from element', async () => { - await I.amOnPage('/search'); + await I.amOnPage('/search') const val = await I.grabAttributeFrom( { css: 'form', }, 'method', - ); - assert.equal(val, 'get'); - }); + ) + assert.equal(val, 'get') + }) it('should grab custom attribute from element', async () => { - await I.amOnPage('/form/example4'); + await I.amOnPage('/form/example4') const val = await I.grabAttributeFrom( { css: '.navbar-toggle', }, 'data-toggle', - ); - assert.equal(val, 'collapse'); - }); - }); + ) + assert.equal(val, 'collapse') + }) + }) describe('page title : #seeTitle, #dontSeeTitle, #grabTitle', () => { it('should check page title', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/'); - await I.seeInTitle('TestEd Beta 2.0'); - await I.dontSeeInTitle('Welcome to test app'); - await I.amOnPage('/info'); - await I.dontSeeInTitle('TestEd Beta 2.0'); - }); + await I.amOnPage('/') + await I.seeInTitle('TestEd Beta 2.0') + await I.dontSeeInTitle('Welcome to test app') + await I.amOnPage('/info') + await I.dontSeeInTitle('TestEd Beta 2.0') + }) it('should grab page title', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/'); - const val = await I.grabTitle(); - assert.equal(val, 'TestEd Beta 2.0'); - }); - }); + await I.amOnPage('/') + const val = await I.grabTitle() + assert.equal(val, 'TestEd Beta 2.0') + }) + }) describe('#attachFile', () => { it('should upload file located by CSS', async () => { - await I.amOnPage('/form/file'); - await I.attachFile('#avatar', 'app/avatar.jpg'); - await I.click('Submit'); - await I.see('Thank you'); - formContents().files.should.have.key('avatar'); - formContents().files.avatar.name.should.eql('avatar.jpg'); - formContents().files.avatar.type.should.eql('image/jpeg'); - }); + await I.amOnPage('/form/file') + await I.attachFile('#avatar', 'app/avatar.jpg') + await I.click('Submit') + await I.see('Thank you') + formContents().files.should.have.key('avatar') + formContents().files.avatar.name.should.eql('avatar.jpg') + formContents().files.avatar.type.should.eql('image/jpeg') + }) it('should upload file located by label', async () => { - await I.amOnPage('/form/file'); - await I.attachFile('Avatar', 'app/avatar.jpg'); - await I.click('Submit'); - await I.see('Thank you'); - formContents().files.should.have.key('avatar'); - formContents().files.avatar.name.should.eql('avatar.jpg'); - formContents().files.avatar.type.should.eql('image/jpeg'); - }); - }); + await I.amOnPage('/form/file') + await I.attachFile('Avatar', 'app/avatar.jpg') + await I.click('Submit') + await I.see('Thank you') + formContents().files.should.have.key('avatar') + formContents().files.avatar.name.should.eql('avatar.jpg') + formContents().files.avatar.type.should.eql('image/jpeg') + }) + }) describe('#saveScreenshot', () => { beforeEach(() => { - global.output_dir = path.join(global.codecept_dir, 'output'); - }); + global.output_dir = path.join(global.codecept_dir, 'output') + }) it('should create a screenshot file in output dir', async () => { - const sec = new Date().getUTCMilliseconds(); - await I.amOnPage('/'); - await I.saveScreenshot(`screenshot_${sec}.png`); - assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists'); - }); + const sec = new Date().getUTCMilliseconds() + await I.amOnPage('/') + await I.saveScreenshot(`screenshot_${sec}.png`) + assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists') + }) it('should create a full page screenshot file in output dir', async () => { - const sec = new Date().getUTCMilliseconds(); - await I.amOnPage('/'); - await I.saveScreenshot(`screenshot_full_${+sec}.png`, true); - assert.ok(fileExists(path.join(global.output_dir, `screenshot_full_${+sec}.png`)), null, 'file does not exists'); - }); - }); + const sec = new Date().getUTCMilliseconds() + await I.amOnPage('/') + await I.saveScreenshot(`screenshot_full_${+sec}.png`, true) + assert.ok(fileExists(path.join(global.output_dir, `screenshot_full_${+sec}.png`)), null, 'file does not exists') + }) + }) describe('cookies : #setCookie, #clearCookies, #seeCookie, #waitForCookie', () => { it('should do all cookie stuff', async () => { - await I.amOnPage('/'); + await I.amOnPage('/') await I.setCookie({ name: 'auth', value: '123456', url: 'http://localhost', - }); - await I.seeCookie('auth'); - await I.dontSeeCookie('auuth'); + }) + await I.seeCookie('auth') + await I.dontSeeCookie('auuth') - const cookie = await I.grabCookie('auth'); - assert.equal(cookie.value, '123456'); + const cookie = await I.grabCookie('auth') + assert.equal(cookie.value, '123456') - await I.clearCookie('auth'); - await I.dontSeeCookie('auth'); - }); + await I.clearCookie('auth') + await I.dontSeeCookie('auth') + }) it('should grab all cookies', async () => { - await I.amOnPage('/'); + await I.amOnPage('/') await I.setCookie({ name: 'auth', value: '123456', url: 'http://localhost', - }); + }) await I.setCookie({ name: 'user', value: 'davert', url: 'http://localhost', - }); + }) - const cookies = await I.grabCookie(); - assert.equal(cookies.length, 2); - assert(cookies[0].name); - assert(cookies[0].value); - }); + const cookies = await I.grabCookie() + assert.equal(cookies.length, 2) + assert(cookies[0].name) + assert(cookies[0].value) + }) it('should clear all cookies', async () => { - await I.amOnPage('/'); + await I.amOnPage('/') await I.setCookie({ name: 'auth', value: '123456', url: 'http://localhost', - }); - await I.clearCookie(); - await I.dontSeeCookie('auth'); - }); + }) + await I.clearCookie() + await I.dontSeeCookie('auth') + }) it('should wait for cookie and throw error when cookie not found', async () => { - if (isHelper('TestCafe')) return; - if (process.env.DevTools) return; + if (isHelper('TestCafe')) return + if (process.env.DevTools) return - await I.amOnPage('https://google.com'); + await I.amOnPage('https://google.com') try { - await I.waitForCookie('auth', 2); + await I.waitForCookie('auth', 2) } catch (e) { - assert.equal(e.message, 'Cookie auth is not found after 2s'); + assert.equal(e.message, 'Cookie auth is not found after 2s') } - }); + }) it('should wait for cookie', async () => { - if (isHelper('TestCafe')) return; - if (process.env.DevTools) return; + if (isHelper('TestCafe')) return + if (process.env.DevTools) return - await I.amOnPage('/'); + await I.amOnPage('/') await I.setCookie({ name: 'auth', value: '123456', url: 'http://localhost', - }); - await I.waitForCookie('auth'); - }); - }); + }) + await I.waitForCookie('auth') + }) + }) describe('#waitForText', () => { it('should wait for text', async () => { - await I.amOnPage('/dynamic'); - await I.dontSee('Dynamic text'); - await I.waitForText('Dynamic text', 2); - await I.see('Dynamic text'); - }); + await I.amOnPage('/dynamic') + await I.dontSee('Dynamic text') + await I.waitForText('Dynamic text', 2) + await I.see('Dynamic text') + }) it('should wait for text in context', async () => { - await I.amOnPage('/dynamic'); - await I.dontSee('Dynamic text'); - await I.waitForText('Dynamic text', 2, '#text'); - await I.see('Dynamic text'); - }); + await I.amOnPage('/dynamic') + await I.dontSee('Dynamic text') + await I.waitForText('Dynamic text', 2, '#text') + await I.see('Dynamic text') + }) it('should fail if no context', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - let failed = false; - await I.amOnPage('/dynamic'); - await I.dontSee('Dynamic text'); + let failed = false + await I.amOnPage('/dynamic') + await I.dontSee('Dynamic text') try { - await I.waitForText('Dynamic text', 1, '#fext'); + await I.waitForText('Dynamic text', 1, '#fext') } catch (e) { - failed = true; + failed = true } - assert.ok(failed); - }); + assert.ok(failed) + }) it("should fail if text doesn't contain", async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - let failed = false; - await I.amOnPage('/dynamic'); + let failed = false + await I.amOnPage('/dynamic') try { - await I.waitForText('Other text', 1); + await I.waitForText('Other text', 1) } catch (e) { - failed = true; + failed = true } - assert.ok(failed); - }); + assert.ok(failed) + }) it('should fail if text is not in element', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - let failed = false; - await I.amOnPage('/dynamic'); + let failed = false + await I.amOnPage('/dynamic') try { - await I.waitForText('Other text', 1, '#text'); + await I.waitForText('Other text', 1, '#text') } catch (e) { - failed = true; + failed = true } - assert.ok(failed); - }); + assert.ok(failed) + }) it('should wait for text after timeout', async () => { - await I.amOnPage('/timeout'); - await I.dontSee('Timeout text'); - await I.waitForText('Timeout text', 31, '#text'); - await I.see('Timeout text'); - }); + await I.amOnPage('/timeout') + await I.dontSee('Timeout text') + await I.waitForText('Timeout text', 31, '#text') + await I.see('Timeout text') + }) it('should wait for text located by XPath', async () => { - await I.amOnPage('/dynamic'); - await I.dontSee('Dynamic text'); - await I.waitForText('Dynamic text', 5, '//div[@id="text"]'); - }); + await I.amOnPage('/dynamic') + await I.dontSee('Dynamic text') + await I.waitForText('Dynamic text', 5, '//div[@id="text"]') + }) it('should throw error when text not found', async () => { - await I.amOnPage('/dynamic'); - await I.dontSee('Dynamic text'); - let failed = false; + await I.amOnPage('/dynamic') + await I.dontSee('Dynamic text') + let failed = false try { - await I.waitForText('Some text', 1, '//div[@id="text"]'); + await I.waitForText('Some text', 1, '//div[@id="text"]') } catch (e) { - failed = true; + failed = true } - assert.ok(failed); - }); - }); + assert.ok(failed) + }) + }) describe('#waitForElement', () => { it('should wait for visible element', async () => { - await I.amOnPage('/form/wait_visible'); - await I.dontSee('Step One Button'); - await I.dontSeeElement('#step_1'); - await I.waitForVisible('#step_1', 2); - await I.seeElement('#step_1'); - await I.click('#step_1'); - await I.waitForVisible('#step_2', 2); - await I.see('Step Two Button'); - }); + await I.amOnPage('/form/wait_visible') + await I.dontSee('Step One Button') + await I.dontSeeElement('#step_1') + await I.waitForVisible('#step_1', 2) + await I.seeElement('#step_1') + await I.click('#step_1') + await I.waitForVisible('#step_2', 2) + await I.see('Step Two Button') + }) it('should wait for element in DOM', async () => { - await I.amOnPage('/form/wait_visible'); - await I.waitForElement('#step_2'); - await I.dontSeeElement('#step_2'); - await I.seeElementInDOM('#step_2'); - }); + await I.amOnPage('/form/wait_visible') + await I.waitForElement('#step_2') + await I.dontSeeElement('#step_2') + await I.seeElementInDOM('#step_2') + }) it('should wait for element by XPath', async () => { - await I.amOnPage('/form/wait_visible'); - await I.waitForElement('//div[@id="step_2"]'); - await I.dontSeeElement('//div[@id="step_2"]'); - await I.seeElementInDOM('//div[@id="step_2"]'); - }); + await I.amOnPage('/form/wait_visible') + await I.waitForElement('//div[@id="step_2"]') + await I.dontSeeElement('//div[@id="step_2"]') + await I.seeElementInDOM('//div[@id="step_2"]') + }) it('should wait for element to appear', async () => { - await I.amOnPage('/form/wait_element'); - await I.dontSee('Hello'); - await I.dontSeeElement('h1'); - await I.waitForElement('h1', 2); - await I.see('Hello'); - }); - }); + await I.amOnPage('/form/wait_element') + await I.dontSee('Hello') + await I.dontSeeElement('h1') + await I.waitForElement('h1', 2) + await I.see('Hello') + }) + }) describe('#waitForInvisible', () => { it('should wait for element to be invisible', async () => { - await I.amOnPage('/form/wait_invisible'); - await I.see('Step One Button'); - await I.seeElement('#step_1'); - await I.waitForInvisible('#step_1', 2); - await I.dontSeeElement('#step_1'); - }); + await I.amOnPage('/form/wait_invisible') + await I.see('Step One Button') + await I.seeElement('#step_1') + await I.waitForInvisible('#step_1', 2) + await I.dontSeeElement('#step_1') + }) it('should wait for element to be invisible by XPath', async () => { - await I.amOnPage('/form/wait_invisible'); - await I.seeElement('//div[@id="step_1"]'); - await I.waitForInvisible('//div[@id="step_1"]'); - await I.dontSeeElement('//div[@id="step_1"]'); - await I.seeElementInDOM('//div[@id="step_1"]'); - }); + await I.amOnPage('/form/wait_invisible') + await I.seeElement('//div[@id="step_1"]') + await I.waitForInvisible('//div[@id="step_1"]') + await I.dontSeeElement('//div[@id="step_1"]') + await I.seeElementInDOM('//div[@id="step_1"]') + }) it('should wait for element to be removed', async () => { - await I.amOnPage('/form/wait_invisible'); - await I.see('Step Two Button'); - await I.seeElement('#step_2'); - await I.waitForInvisible('#step_2', 2); - await I.dontSeeElement('#step_2'); - }); + await I.amOnPage('/form/wait_invisible') + await I.see('Step Two Button') + await I.seeElement('#step_2') + await I.waitForInvisible('#step_2', 2) + await I.dontSeeElement('#step_2') + }) it('should wait for element to be removed by XPath', async () => { - await I.amOnPage('/form/wait_invisible'); - await I.see('Step Two Button'); - await I.seeElement('//div[@id="step_2"]'); - await I.waitForInvisible('//div[@id="step_2"]', 2); - await I.dontSeeElement('//div[@id="step_2"]'); - }); - }); + await I.amOnPage('/form/wait_invisible') + await I.see('Step Two Button') + await I.seeElement('//div[@id="step_2"]') + await I.waitForInvisible('//div[@id="step_2"]', 2) + await I.dontSeeElement('//div[@id="step_2"]') + }) + }) describe('#waitToHide', () => { it('should wait for element to be invisible', async () => { - await I.amOnPage('/form/wait_invisible'); - await I.see('Step One Button'); - await I.seeElement('#step_1'); - await I.waitToHide('#step_1', 2); - await I.dontSeeElement('#step_1'); - }); + await I.amOnPage('/form/wait_invisible') + await I.see('Step One Button') + await I.seeElement('#step_1') + await I.waitToHide('#step_1', 2) + await I.dontSeeElement('#step_1') + }) it('should wait for element to be invisible by XPath', async () => { - await I.amOnPage('/form/wait_invisible'); - await I.seeElement('//div[@id="step_1"]'); - await I.waitToHide('//div[@id="step_1"]'); - await I.dontSeeElement('//div[@id="step_1"]'); - await I.seeElementInDOM('//div[@id="step_1"]'); - }); + await I.amOnPage('/form/wait_invisible') + await I.seeElement('//div[@id="step_1"]') + await I.waitToHide('//div[@id="step_1"]') + await I.dontSeeElement('//div[@id="step_1"]') + await I.seeElementInDOM('//div[@id="step_1"]') + }) it('should wait for element to be removed', async () => { - await I.amOnPage('/form/wait_invisible'); - await I.see('Step Two Button'); - await I.seeElement('#step_2'); - await I.waitToHide('#step_2', 2); - await I.dontSeeElement('#step_2'); - }); + await I.amOnPage('/form/wait_invisible') + await I.see('Step Two Button') + await I.seeElement('#step_2') + await I.waitToHide('#step_2', 2) + await I.dontSeeElement('#step_2') + }) it('should wait for element to be removed by XPath', async () => { - await I.amOnPage('/form/wait_invisible'); - await I.see('Step Two Button'); - await I.seeElement('//div[@id="step_2"]'); - await I.waitToHide('//div[@id="step_2"]', 2); - await I.dontSeeElement('//div[@id="step_2"]'); - }); - }); + await I.amOnPage('/form/wait_invisible') + await I.see('Step Two Button') + await I.seeElement('//div[@id="step_2"]') + await I.waitToHide('//div[@id="step_2"]', 2) + await I.dontSeeElement('//div[@id="step_2"]') + }) + }) describe('#waitForDetached', () => { it('should throw an error if the element still exists in DOM', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/form/wait_detached'); - await I.see('Step One Button'); - await I.seeElement('#step_1'); + await I.amOnPage('/form/wait_detached') + await I.see('Step One Button') + await I.seeElement('#step_1') try { - await I.waitForDetached('#step_1', 2); - throw Error('Should not get this far'); + await I.waitForDetached('#step_1', 2) + throw Error('Should not get this far') } catch (err) { - err.message.should.include('still on page after'); + err.message.should.include('still on page after') } - }); + }) it('should throw an error if the element still exists in DOM by XPath', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/form/wait_detached'); - await I.see('Step One Button'); - await I.seeElement('#step_1'); + await I.amOnPage('/form/wait_detached') + await I.see('Step One Button') + await I.seeElement('#step_1') try { - await I.waitForDetached('#step_1', 2); - throw Error('Should not get this far'); + await I.waitForDetached('#step_1', 2) + throw Error('Should not get this far') } catch (err) { - err.message.should.include('still on page after'); + err.message.should.include('still on page after') } - }); + }) it('should wait for element to be removed from DOM', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/form/wait_detached'); - await I.see('Step Two Button'); - await I.seeElement('#step_2'); - await I.waitForDetached('#step_2', 2); - await I.dontSeeElementInDOM('#step_2'); - }); + await I.amOnPage('/form/wait_detached') + await I.see('Step Two Button') + await I.seeElement('#step_2') + await I.waitForDetached('#step_2', 2) + await I.dontSeeElementInDOM('#step_2') + }) it('should wait for element to be removed from DOM by XPath', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/form/wait_detached'); - await I.seeElement('//div[@id="step_2"]'); - await I.waitForDetached('//div[@id="step_2"]'); - await I.dontSeeElement('//div[@id="step_2"]'); - await I.dontSeeElementInDOM('//div[@id="step_2"]'); - }); - }); + await I.amOnPage('/form/wait_detached') + await I.seeElement('//div[@id="step_2"]') + await I.waitForDetached('//div[@id="step_2"]') + await I.dontSeeElement('//div[@id="step_2"]') + await I.dontSeeElementInDOM('//div[@id="step_2"]') + }) + }) describe('within tests', () => { - afterEach(() => I._withinEnd()); + afterEach(() => I._withinEnd()) it('should execute within block', async () => { - await I.amOnPage('/form/example4'); - await I.seeElement('#navbar-collapse-menu'); + await I.amOnPage('/form/example4') + await I.seeElement('#navbar-collapse-menu') I._withinBegin('#register') .then(() => I.see('E-Mail')) .then(() => I.dontSee('Toggle navigation')) - .then(() => I.dontSeeElement('#navbar-collapse-menu')); - }); + .then(() => I.dontSeeElement('#navbar-collapse-menu')) + }) it('should respect form fields inside within block ', async () => { - let rethrow; - - await I.amOnPage('/form/example4'); - await I.seeElement('#navbar-collapse-menu'); - await I.see('E-Mail'); - await I.see('Hasło'); - await I.fillField('Hasło', '12345'); - await I.seeInField('Hasło', '12345'); - await I.checkOption('terms'); - await I.seeCheckboxIsChecked('terms'); + let rethrow + + await I.amOnPage('/form/example4') + await I.seeElement('#navbar-collapse-menu') + await I.see('E-Mail') + await I.see('Hasło') + await I.fillField('Hasło', '12345') + await I.seeInField('Hasło', '12345') + await I.checkOption('terms') + await I.seeCheckboxIsChecked('terms') I._withinBegin({ css: '.form-group' }) .then(() => I.see('E-Mail')) .then(() => I.dontSee('Hasło')) - .then(() => I.dontSeeElement('#navbar-collapse-menu')); + .then(() => I.dontSeeElement('#navbar-collapse-menu')) try { - await I.dontSeeCheckboxIsChecked('terms'); + await I.dontSeeCheckboxIsChecked('terms') } catch (err) { - if (!err) assert.fail('seen checkbox'); + if (!err) assert.fail('seen checkbox') } try { - await I.seeInField('Hasło', '12345'); + await I.seeInField('Hasło', '12345') } catch (err) { - if (!err) assert.fail('seen field'); + if (!err) assert.fail('seen field') } - if (rethrow) throw rethrow; - }); + if (rethrow) throw rethrow + }) it('should execute within block 2', async () => { - await I.amOnPage('/form/example4'); - await I.fillField('Hasło', '12345'); + await I.amOnPage('/form/example4') + await I.fillField('Hasło', '12345') I._withinBegin({ xpath: '//div[@class="form-group"][2]' }) .then(() => I.dontSee('E-Mail')) .then(() => I.see('Hasło')) .then(() => I.grabTextFrom('label')) .then((label) => assert.equal(label, 'Hasło')) .then(() => I.grabValueFrom('input')) - .then((input) => assert.equal(input, '12345')); - }); + .then((input) => assert.equal(input, '12345')) + }) it('within should respect context in see', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/form/example4'); - await I.see('Rejestracja', 'fieldset'); + await I.amOnPage('/form/example4') + await I.see('Rejestracja', 'fieldset') I._withinBegin({ css: '.navbar-header' }) .then(() => I.see('Rejestracja', '.container fieldset')) - .then(() => I.see('Toggle navigation', '.container fieldset')); - }); + .then(() => I.see('Toggle navigation', '.container fieldset')) + }) it('within should respect context in see when using nested frames', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/iframe_nested'); + await I.amOnPage('/iframe_nested') await I._withinBegin({ frame: ['#wrapperId', '[name=content]'], - }); + }) try { - await I.see('Kill & Destroy'); + await I.see('Kill & Destroy') } catch (err) { - if (!err) assert.fail('seen "Kill & Destroy"'); + if (!err) assert.fail('seen "Kill & Destroy"') } try { - await I.dontSee('Nested Iframe test'); + await I.dontSee('Nested Iframe test') } catch (err) { - if (!err) assert.fail('seen "Nested Iframe test"'); + if (!err) assert.fail('seen "Nested Iframe test"') } try { - await I.dontSee('Iframe test'); + await I.dontSee('Iframe test') } catch (err) { - if (!err) assert.fail('seen "Iframe test"'); + if (!err) assert.fail('seen "Iframe test"') } - }); + }) it('within should respect context in see when using frame', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/iframe'); + await I.amOnPage('/iframe') await I._withinBegin({ frame: '#number-frame-1234', - }); + }) try { - await I.see('Information'); + await I.see('Information') } catch (err) { - if (!err) assert.fail('seen "Information"'); + if (!err) assert.fail('seen "Information"') } - }); + }) it('within should respect context in see when using frame with strict locator', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/iframe'); + await I.amOnPage('/iframe') await I._withinBegin({ frame: { css: '#number-frame-1234' }, - }); + }) try { - await I.see('Information'); + await I.see('Information') } catch (err) { - if (!err) assert.fail('seen "Information"'); + if (!err) assert.fail('seen "Information"') } - }); - }); + }) + }) describe('scroll: #scrollTo, #scrollPageToTop, #scrollPageToBottom', () => { it('should scroll inside an iframe', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/iframe'); - await I.resizeWindow(500, 700); - await I.switchTo(0); + await I.amOnPage('/iframe') + await I.resizeWindow(500, 700) + await I.switchTo(0) - const { x, y } = await I.grabPageScrollPosition(); - await I.scrollTo('.sign'); + const { x, y } = await I.grabPageScrollPosition() + await I.scrollTo('.sign') - const { x: afterScrollX, y: afterScrollY } = await I.grabPageScrollPosition(); - assert.notEqual(afterScrollY, y); - assert.equal(afterScrollX, x); - }); + const { x: afterScrollX, y: afterScrollY } = await I.grabPageScrollPosition() + assert.notEqual(afterScrollY, y) + assert.equal(afterScrollX, x) + }) it('should scroll to an element', async () => { - await I.amOnPage('/form/scroll'); - await I.resizeWindow(500, 700); - const { y } = await I.grabPageScrollPosition(); - await I.scrollTo('.section3 input[name="test"]'); + await I.amOnPage('/form/scroll') + await I.resizeWindow(500, 700) + const { y } = await I.grabPageScrollPosition() + await I.scrollTo('.section3 input[name="test"]') - const { y: afterScrollY } = await I.grabPageScrollPosition(); - assert.notEqual(afterScrollY, y); - }); + const { y: afterScrollY } = await I.grabPageScrollPosition() + assert.notEqual(afterScrollY, y) + }) it('should scroll to coordinates', async () => { - await I.amOnPage('/form/scroll'); - await I.resizeWindow(500, 700); - await I.scrollTo(50, 70); + await I.amOnPage('/form/scroll') + await I.resizeWindow(500, 700) + await I.scrollTo(50, 70) - const { x: afterScrollX, y: afterScrollY } = await I.grabPageScrollPosition(); - assert.equal(afterScrollX, 50); - assert.equal(afterScrollY, 70); - }); + const { x: afterScrollX, y: afterScrollY } = await I.grabPageScrollPosition() + assert.equal(afterScrollX, 50) + assert.equal(afterScrollY, 70) + }) it('should scroll to bottom of page', async () => { - await I.amOnPage('/form/scroll'); - await I.resizeWindow(500, 700); - const { y } = await I.grabPageScrollPosition(); - await I.scrollPageToBottom(); + await I.amOnPage('/form/scroll') + await I.resizeWindow(500, 700) + const { y } = await I.grabPageScrollPosition() + await I.scrollPageToBottom() - const { y: afterScrollY } = await I.grabPageScrollPosition(); - assert.notEqual(afterScrollY, y); - assert.notEqual(afterScrollY, 0); - }); + const { y: afterScrollY } = await I.grabPageScrollPosition() + assert.notEqual(afterScrollY, y) + assert.notEqual(afterScrollY, 0) + }) it('should scroll to top of page', async () => { - await I.amOnPage('/form/scroll'); - await I.resizeWindow(500, 700); - await I.scrollPageToBottom(); - const { y } = await I.grabPageScrollPosition(); - await I.scrollPageToTop(); - - const { y: afterScrollY } = await I.grabPageScrollPosition(); - assert.notEqual(afterScrollY, y); - assert.equal(afterScrollY, 0); - }); - }); + await I.amOnPage('/form/scroll') + await I.resizeWindow(500, 700) + await I.scrollPageToBottom() + const { y } = await I.grabPageScrollPosition() + await I.scrollPageToTop() + + const { y: afterScrollY } = await I.grabPageScrollPosition() + assert.notEqual(afterScrollY, y) + assert.equal(afterScrollY, 0) + }) + }) describe('#grabCssPropertyFrom', () => { it('should grab css property for given element', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/form/doubleclick'); - const css = await I.grabCssPropertyFrom('#block', 'height'); - assert.equal(css, '100px'); - }); + await I.amOnPage('/form/doubleclick') + const css = await I.grabCssPropertyFrom('#block', 'height') + assert.equal(css, '100px') + }) it('should grab camelcased css properies', async () => { - if (isHelper('TestCafe')) return; + if (isHelper('TestCafe')) return - await I.amOnPage('/form/doubleclick'); - const css = await I.grabCssPropertyFrom('#block', 'user-select'); - assert.equal(css, 'text'); - }); + await I.amOnPage('/form/doubleclick') + const css = await I.grabCssPropertyFrom('#block', 'user-select') + assert.equal(css, 'text') + }) it('should grab multiple values if more than one matching element found', async () => { - if (isHelper('TestCafe')) return; + if (isHelper('TestCafe')) return - await I.amOnPage('/info'); - const css = await I.grabCssPropertyFromAll('.span', 'height'); - assert.equal(css[0], '12px'); - assert.equal(css[1], '15px'); - }); - }); + await I.amOnPage('/info') + const css = await I.grabCssPropertyFromAll('.span', 'height') + assert.equal(css[0], '12px') + assert.equal(css[1], '15px') + }) + }) describe('#seeAttributesOnElements', () => { it('should check attributes values for given element', async function () { - if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip(); + if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip() try { - await I.amOnPage('/info'); + await I.amOnPage('/info') await I.seeAttributesOnElements('//form', { method: 'post', - }); + }) await I.seeAttributesOnElements('//form', { method: 'get', - }); - throw Error('It should never get this far'); + }) + throw Error('It should never get this far') } catch (e) { - e.message.should.include('all elements (//form) to have attributes {"method":"get"}'); + e.message.should.include('all elements (//form) to have attributes {"method":"get"}') } - }); + }) it('should check href with slash', async function () { - if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip(); + if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip() try { - await I.amOnPage('https://github.com/codeceptjs/CodeceptJS/'); + await I.amOnPage('https://github.com/codeceptjs/CodeceptJS/') await I.seeAttributesOnElements( { css: 'a[href="/codeceptjs/CodeceptJS"]' }, { href: '/codeceptjs/CodeceptJS', }, - ); + ) } catch (e) { e.message.should.include( 'all elements (a[href="/codeceptjs/CodeceptJS"]) to have attributes {"href":"/codeceptjs/CodeceptJS"}', - ); + ) } - }); + }) it('should check attributes values for several elements', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() try { - await I.amOnPage('/'); + await I.amOnPage('/') await I.seeAttributesOnElements('a', { 'qa-id': 'test', 'qa-link': 'test', - }); + }) await I.seeAttributesOnElements('//div', { 'qa-id': 'test', - }); + }) await I.seeAttributesOnElements('a', { 'qa-id': 'test', href: '/info', - }); - throw new Error('It should never get this far'); + }) + throw new Error('It should never get this far') } catch (e) { - e.message.should.include('all elements (a) to have attributes {"qa-id":"test","href":"/info"}'); + e.message.should.include('all elements (a) to have attributes {"qa-id":"test","href":"/info"}') } - }); + }) it('should return error when using non existing attribute', async function () { - if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip(); + if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip() try { - await I.amOnPage('https://github.com/codeceptjs/CodeceptJS/'); + await I.amOnPage('https://github.com/codeceptjs/CodeceptJS/') await I.seeAttributesOnElements( { css: 'a[href="/codeceptjs/CodeceptJS"]' }, { disable: true, }, - ); + ) } catch (e) { e.message.should.include( 'expected all elements ({css: a[href="/codeceptjs/CodeceptJS"]}) to have attributes {"disable":true} "0" to equal "3"', - ); + ) } - }); + }) it('should verify the boolean attribute', async function () { - if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip(); + if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip() try { - await I.amOnPage('/'); + await I.amOnPage('/') await I.seeAttributesOnElements('input', { disabled: true, - }); + }) } catch (e) { - e.message.should.include('expected all elements (input) to have attributes {"disabled":true} "0" to equal "1"'); + e.message.should.include('expected all elements (input) to have attributes {"disabled":true} "0" to equal "1"') } - }); - }); + }) + }) describe('#seeCssPropertiesOnElements', () => { it('should check css property for given element', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() try { - await I.amOnPage('/info'); + await I.amOnPage('/info') await I.seeCssPropertiesOnElements('h4', { 'font-weight': 300, - }); + }) await I.seeCssPropertiesOnElements('h3', { 'font-weight': 'bold', display: 'block', - }); + }) await I.seeCssPropertiesOnElements('h3', { 'font-weight': 'non-bold', - }); - throw Error('It should never get this far'); + }) + throw Error('It should never get this far') } catch (e) { - e.message.should.include('expected all elements (h3) to have CSS property {"font-weight":"non-bold"}'); + e.message.should.include('expected all elements (h3) to have CSS property {"font-weight":"non-bold"}') } - }); + }) it('should check css property for several elements', async function () { - if (isHelper('TestCafe') || process.env.BROWSER === 'firefox' || process.env.DevTools === 'true') this.skip(); + if (isHelper('TestCafe') || process.env.BROWSER === 'firefox' || process.env.DevTools === 'true') this.skip() try { - await I.amOnPage('/'); + await I.amOnPage('/') await I.seeCssPropertiesOnElements('a', { color: 'rgb(0, 0, 238)', cursor: 'pointer', - }); + }) await I.seeCssPropertiesOnElements('a', { color: '#0000EE', cursor: 'pointer', - }); + }) await I.seeCssPropertiesOnElements('//div', { display: 'block', - }); + }) await I.seeCssPropertiesOnElements('a', { 'margin-top': '0em', cursor: 'pointer', - }); - throw Error('It should never get this far'); + }) + throw Error('It should never get this far') } catch (e) { e.message.should.include( 'expected all elements (a) to have CSS property {"margin-top":"0em","cursor":"pointer"}', - ); + ) } - }); + }) it('should normalize css color properties for given element', async function () { - if (isHelper('TestCafe')) this.skip(); + if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/form/css_colors'); + await I.amOnPage('/form/css_colors') await I.seeCssPropertiesOnElements('#namedColor', { 'background-color': 'purple', color: 'yellow', - }); + }) await I.seeCssPropertiesOnElements('#namedColor', { 'background-color': '#800080', color: '#ffff00', - }); + }) await I.seeCssPropertiesOnElements('#namedColor', { 'background-color': 'rgb(128,0,128)', color: 'rgb(255,255,0)', - }); + }) await I.seeCssPropertiesOnElements('#namedColor', { 'background-color': 'rgba(128,0,128,1)', color: 'rgba(255,255,0,1)', - }); - }); - }); + }) + }) + }) describe('#customLocators', () => { beforeEach(() => { - originalLocators = Locator.filters; - Locator.filters = []; - }); + originalLocators = Locator.filters + Locator.filters = [] + }) afterEach(() => { // reset custom locators - Locator.filters = originalLocators; - }); + Locator.filters = originalLocators + }) it('should support xpath custom locator by default', async () => { customLocators({ attribute: 'data-test-id', enabled: true, - }); - await I.amOnPage('/form/custom_locator'); - await I.dontSee('Step One Button'); - await I.dontSeeElement('$step_1'); - await I.waitForVisible('$step_1', 2); - await I.seeElement('$step_1'); - await I.click('$step_1'); - await I.waitForVisible('$step_2', 2); - await I.see('Step Two Button'); - }); + }) + await I.amOnPage('/form/custom_locator') + await I.dontSee('Step One Button') + await I.dontSeeElement('$step_1') + await I.waitForVisible('$step_1', 2) + await I.seeElement('$step_1') + await I.click('$step_1') + await I.waitForVisible('$step_2', 2) + await I.see('Step Two Button') + }) it('can use css strategy for custom locator', async () => { customLocators({ attribute: 'data-test-id', enabled: true, strategy: 'css', - }); - await I.amOnPage('/form/custom_locator'); - await I.dontSee('Step One Button'); - await I.dontSeeElement('$step_1'); - await I.waitForVisible('$step_1', 2); - await I.seeElement('$step_1'); - await I.click('$step_1'); - await I.waitForVisible('$step_2', 2); - await I.see('Step Two Button'); - }); + }) + await I.amOnPage('/form/custom_locator') + await I.dontSee('Step One Button') + await I.dontSeeElement('$step_1') + await I.waitForVisible('$step_1', 2) + await I.seeElement('$step_1') + await I.click('$step_1') + await I.waitForVisible('$step_2', 2) + await I.see('Step Two Button') + }) it('can use xpath strategy for custom locator', async () => { customLocators({ attribute: 'data-test-id', enabled: true, strategy: 'xpath', - }); - await I.amOnPage('/form/custom_locator'); - await I.dontSee('Step One Button'); - await I.dontSeeElement('$step_1'); - await I.waitForVisible('$step_1', 2); - await I.seeElement('$step_1'); - await I.click('$step_1'); - await I.waitForVisible('$step_2', 2); - await I.see('Step Two Button'); - }); - }); + }) + await I.amOnPage('/form/custom_locator') + await I.dontSee('Step One Button') + await I.dontSeeElement('$step_1') + await I.waitForVisible('$step_1', 2) + await I.seeElement('$step_1') + await I.click('$step_1') + await I.waitForVisible('$step_2', 2) + await I.see('Step Two Button') + }) + }) describe('#focus, #blur', () => { it('should focus a button, field and textarea', async () => { - await I.amOnPage('/form/focus_blur_elements'); + await I.amOnPage('/form/focus_blur_elements') - await I.focus('#button'); - await I.see('Button is focused', '#buttonMessage'); + await I.focus('#button') + await I.see('Button is focused', '#buttonMessage') - await I.focus('#field'); - await I.see('Button not focused', '#buttonMessage'); - await I.see('Input field is focused', '#fieldMessage'); + await I.focus('#field') + await I.see('Button not focused', '#buttonMessage') + await I.see('Input field is focused', '#fieldMessage') - await I.focus('#textarea'); - await I.see('Button not focused', '#buttonMessage'); - await I.see('Input field not focused', '#fieldMessage'); - await I.see('Textarea is focused', '#textareaMessage'); - }); + await I.focus('#textarea') + await I.see('Button not focused', '#buttonMessage') + await I.see('Input field not focused', '#fieldMessage') + await I.see('Textarea is focused', '#textareaMessage') + }) it('should blur focused button, field and textarea', async () => { - await I.amOnPage('/form/focus_blur_elements'); + await I.amOnPage('/form/focus_blur_elements') - await I.focus('#button'); - await I.see('Button is focused', '#buttonMessage'); - await I.blur('#button'); - await I.see('Button not focused', '#buttonMessage'); + await I.focus('#button') + await I.see('Button is focused', '#buttonMessage') + await I.blur('#button') + await I.see('Button not focused', '#buttonMessage') - await I.focus('#field'); - await I.see('Input field is focused', '#fieldMessage'); - await I.blur('#field'); - await I.see('Input field not focused', '#fieldMessage'); + await I.focus('#field') + await I.see('Input field is focused', '#fieldMessage') + await I.blur('#field') + await I.see('Input field not focused', '#fieldMessage') - await I.focus('#textarea'); - await I.see('Textarea is focused', '#textareaMessage'); - await I.blur('#textarea'); - await I.see('Textarea not focused', '#textareaMessage'); - }); - }); + await I.focus('#textarea') + await I.see('Textarea is focused', '#textareaMessage') + await I.blur('#textarea') + await I.see('Textarea not focused', '#textareaMessage') + }) + }) describe('#startRecordingTraffic, #seeTraffic, #stopRecordingTraffic, #dontSeeTraffic, #grabRecordedNetworkTraffics', () => { beforeEach(function () { - if (isHelper('TestCafe') || process.env.isSelenium === 'true') this.skip(); - }); + if (isHelper('TestCafe') || process.env.isSelenium === 'true') this.skip() + }) it('should throw error when calling seeTraffic before recording traffics', async () => { try { - I.amOnPage('https://codecept.io/'); - await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); + I.amOnPage('https://codecept.io/') + await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) } catch (e) { expect(e.message).to.equal( 'Failure in test automation. You use "I.seeTraffic", but "I.startRecordingTraffic" was never called before.', - ); + ) } - }); + }) it('should throw error when calling seeTraffic but missing name', async () => { try { - I.amOnPage('https://codecept.io/'); - await I.seeTraffic({ url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); + I.amOnPage('https://codecept.io/') + await I.seeTraffic({ url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) } catch (e) { - expect(e.message).to.equal('Missing required key "name" in object given to "I.seeTraffic".'); + expect(e.message).to.equal('Missing required key "name" in object given to "I.seeTraffic".') } - }); + }) it('should throw error when calling seeTraffic but missing url', async () => { try { - I.amOnPage('https://codecept.io/'); - await I.seeTraffic({ name: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); + I.amOnPage('https://codecept.io/') + await I.seeTraffic({ name: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) } catch (e) { - expect(e.message).to.equal('Missing required key "url" in object given to "I.seeTraffic".'); + expect(e.message).to.equal('Missing required key "url" in object given to "I.seeTraffic".') } - }); + }) it('should flush the network traffics', async () => { - await I.startRecordingTraffic(); - await I.amOnPage('https://codecept.io/'); - await I.flushNetworkTraffics(); - const traffics = await I.grabRecordedNetworkTraffics(); - expect(traffics.length).to.equal(0); - }); + await I.startRecordingTraffic() + await I.amOnPage('https://codecept.io/') + await I.flushNetworkTraffics() + const traffics = await I.grabRecordedNetworkTraffics() + expect(traffics.length).to.equal(0) + }) it('should see recording traffics', async () => { - I.startRecordingTraffic(); - I.amOnPage('https://codecept.io/'); - await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); - }); + I.startRecordingTraffic() + I.amOnPage('https://codecept.io/') + await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) + }) it('should not see recording traffics', async () => { - I.startRecordingTraffic(); - I.amOnPage('https://codecept.io/'); - I.stopRecordingTraffic(); - await I.dontSeeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); - }); + I.startRecordingTraffic() + I.amOnPage('https://codecept.io/') + I.stopRecordingTraffic() + await I.dontSeeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) + }) it('should not see recording traffics using regex url', async () => { - I.startRecordingTraffic(); - I.amOnPage('https://codecept.io/'); - I.stopRecordingTraffic(); - await I.dontSeeTraffic({ name: 'traffics', url: /BC_LogoScreen_C.jpg/ }); - }); + I.startRecordingTraffic() + I.amOnPage('https://codecept.io/') + I.stopRecordingTraffic() + await I.dontSeeTraffic({ name: 'traffics', url: /BC_LogoScreen_C.jpg/ }) + }) it('should throw error when calling dontSeeTraffic but missing name', async () => { - I.startRecordingTraffic(); - I.amOnPage('https://codecept.io/'); - I.stopRecordingTraffic(); + I.startRecordingTraffic() + I.amOnPage('https://codecept.io/') + I.stopRecordingTraffic() try { - await I.dontSeeTraffic({ url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); + await I.dontSeeTraffic({ url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) } catch (e) { - expect(e.message).to.equal('Missing required key "name" in object given to "I.dontSeeTraffic".'); + expect(e.message).to.equal('Missing required key "name" in object given to "I.dontSeeTraffic".') } - }); + }) it('should throw error when calling dontSeeTraffic but missing url', async () => { - I.startRecordingTraffic(); - I.amOnPage('https://codecept.io/'); - I.stopRecordingTraffic(); + I.startRecordingTraffic() + I.amOnPage('https://codecept.io/') + I.stopRecordingTraffic() try { - await I.dontSeeTraffic({ name: 'traffics' }); + await I.dontSeeTraffic({ name: 'traffics' }) } catch (e) { - expect(e.message).to.equal('Missing required key "url" in object given to "I.dontSeeTraffic".'); + expect(e.message).to.equal('Missing required key "url" in object given to "I.dontSeeTraffic".') } - }); + }) it('should check traffics with more advanced params', async () => { - await I.startRecordingTraffic(); - await I.amOnPage('https://openaI.com/blog/chatgpt'); - const traffics = await I.grabRecordedNetworkTraffics(); + await I.startRecordingTraffic() + await I.amOnPage('https://openaI.com/blog/chatgpt') + const traffics = await I.grabRecordedNetworkTraffics() for (const traffic of traffics) { if (traffic.url.includes('&width=')) { // new URL object - const currentUrl = new URL(traffic.url); + const currentUrl = new URL(traffic.url) // get access to URLSearchParams object - const searchParams = currentUrl.searchParams; + const searchParams = currentUrl.searchParams await I.seeTraffic({ name: 'sentry event', url: currentUrl.origin + currentUrl.pathname, parameters: searchParams, - }); + }) - break; + break } } - }); + }) it.skip('should check traffics with more advanced post data', async () => { - await I.amOnPage('https://openaI.com/blog/chatgpt'); - await I.startRecordingTraffic(); + await I.amOnPage('https://openaI.com/blog/chatgpt') + await I.startRecordingTraffic() await I.seeTraffic({ name: 'event', url: 'https://region1.google-analytics.com', requestPostData: { st: 2, }, - }); - }); - }); + }) + }) + }) // the WS test website is not so stable. So we skip those tests for now. describe.skip('#startRecordingWebSocketMessages, #grabWebSocketMessages, #stopRecordingWebSocketMessages', () => { beforeEach(function () { - if (isHelper('TestCafe') || isHelper('WebDriver') || process.env.BROWSER === 'firefox') this.skip(); - }); + if (isHelper('TestCafe') || isHelper('WebDriver') || process.env.BROWSER === 'firefox') this.skip() + }) it('should throw error when calling grabWebSocketMessages before startRecordingWebSocketMessages', () => { try { - I.amOnPage('https://websocketstest.com/'); - I.waitForText('Work for You!'); - I.grabWebSocketMessages(); + I.amOnPage('https://websocketstest.com/') + I.waitForText('Work for You!') + I.grabWebSocketMessages() } catch (e) { expect(e.message).to.equal( 'Failure in test automation. You use "I.grabWebSocketMessages", but "I.startRecordingWebSocketMessages" was never called before.', - ); + ) } - }); + }) it('should flush the WS messages', async () => { - await I.startRecordingWebSocketMessages(); - I.amOnPage('https://websocketstest.com/'); - I.waitForText('Work for You!'); - I.flushWebSocketMessages(); - const wsMessages = I.grabWebSocketMessages(); - expect(wsMessages.length).to.equal(0); - }); + await I.startRecordingWebSocketMessages() + I.amOnPage('https://websocketstest.com/') + I.waitForText('Work for You!') + I.flushWebSocketMessages() + const wsMessages = I.grabWebSocketMessages() + expect(wsMessages.length).to.equal(0) + }) it('should see recording WS messages', async () => { - await I.startRecordingWebSocketMessages(); - await I.amOnPage('https://websocketstest.com/'); - I.waitForText('Work for You!'); - const wsMessages = await I.grabWebSocketMessages(); - expect(wsMessages.length).to.greaterThan(0); - }); + await I.startRecordingWebSocketMessages() + await I.amOnPage('https://websocketstest.com/') + I.waitForText('Work for You!') + const wsMessages = await I.grabWebSocketMessages() + expect(wsMessages.length).to.greaterThan(0) + }) it('should not see recording WS messages', async () => { - await I.startRecordingWebSocketMessages(); - await I.amOnPage('https://websocketstest.com/'); - I.waitForText('Work for You!'); - const wsMessages = I.grabWebSocketMessages(); - await I.stopRecordingWebSocketMessages(); - await I.amOnPage('https://websocketstest.com/'); - I.waitForText('Work for You!'); - const afterWsMessages = I.grabWebSocketMessages(); - expect(wsMessages.length).to.equal(afterWsMessages.length); - }); - }); + await I.startRecordingWebSocketMessages() + await I.amOnPage('https://websocketstest.com/') + I.waitForText('Work for You!') + const wsMessages = I.grabWebSocketMessages() + await I.stopRecordingWebSocketMessages() + await I.amOnPage('https://websocketstest.com/') + I.waitForText('Work for You!') + const afterWsMessages = I.grabWebSocketMessages() + expect(wsMessages.length).to.equal(afterWsMessages.length) + }) + }) } From a58b0211606371a9fd5c089cc0e2d6b59063a935 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Fri, 1 Nov 2024 01:58:03 +0200 Subject: [PATCH 04/37] removed dep on chai in JSONResponse --- lib/helper/JSONResponse.js | 85 ++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 30 deletions(-) diff --git a/lib/helper/JSONResponse.js b/lib/helper/JSONResponse.js index 450d44ba4..29c5cadda 100644 --- a/lib/helper/JSONResponse.js +++ b/lib/helper/JSONResponse.js @@ -1,9 +1,5 @@ const Helper = require('@codeceptjs/helper') - -const chai = require('chai') - -const expect = chai.expect -chai.use(require('chai-deep-match')) +const assert = require('assert') const joi = require('joi') /** @@ -107,7 +103,7 @@ class JSONResponse extends Helper { */ seeResponseCodeIs(code) { this._checkResponseReady() - expect(this.response.status).to.eql(code, 'Response code is not the same as expected') + assert.strictEqual(this.response.status, code, 'Response code is not the same as expected') } /** @@ -121,7 +117,7 @@ class JSONResponse extends Helper { */ dontSeeResponseCodeIs(code) { this._checkResponseReady() - expect(this.response.status).not.to.eql(code) + assert.notStrictEqual(this.response.status, code) } /** @@ -129,8 +125,7 @@ class JSONResponse extends Helper { */ seeResponseCodeIsClientError() { this._checkResponseReady() - expect(this.response.status).to.be.gte(400) - expect(this.response.status).to.be.lt(500) + assert(this.response.status >= 400 && this.response.status < 500) } /** @@ -138,8 +133,7 @@ class JSONResponse extends Helper { */ seeResponseCodeIsRedirection() { this._checkResponseReady() - expect(this.response.status).to.be.gte(300) - expect(this.response.status).to.be.lt(400) + assert(this.response.status >= 300 && this.response.status < 400) } /** @@ -147,8 +141,7 @@ class JSONResponse extends Helper { */ seeResponseCodeIsServerError() { this._checkResponseReady() - expect(this.response.status).to.be.gte(500) - expect(this.response.status).to.be.lt(600) + assert(this.response.status >= 500 && this.response.status < 600) } /** @@ -161,8 +154,7 @@ class JSONResponse extends Helper { */ seeResponseCodeIsSuccessful() { this._checkResponseReady() - expect(this.response.status).to.be.gte(200) - expect(this.response.status).to.be.lt(300) + assert(this.response.status >= 200 && this.response.status < 300) } /** @@ -185,17 +177,19 @@ class JSONResponse extends Helper { seeResponseContainsJson(json = {}) { this._checkResponseReady() if (Array.isArray(this.response.data)) { - let fails = 0 + let found = false for (const el of this.response.data) { try { - expect(el).to.deep.match(json) + this._assertContains(el, json) + found = true + break } catch (err) { - fails++ + continue } } - expect(fails < this.response.data.length, `No elements in array matched ${JSON.stringify(json)}`).to.be.true + assert(found, `No elements in array matched ${JSON.stringify(json)}`) } else { - expect(this.response.data).to.deep.match(json) + this._assertContains(this.response.data, json) } } @@ -219,9 +213,22 @@ class JSONResponse extends Helper { dontSeeResponseContainsJson(json = {}) { this._checkResponseReady() if (Array.isArray(this.response.data)) { - this.response.data.forEach((data) => expect(data).not.to.deep.match(json)) + for (const data of this.response.data) { + try { + this._assertContains(data, json) + assert.fail(`Found matching element: ${JSON.stringify(data)}`) + } catch (err) { + // expected to fail + continue + } + } } else { - expect(this.response.data).not.to.deep.match(json) + try { + this._assertContains(this.response.data, json) + assert.fail('Response contains the JSON') + } catch (err) { + // expected to fail + } } } @@ -247,20 +254,27 @@ class JSONResponse extends Helper { seeResponseContainsKeys(keys = []) { this._checkResponseReady() if (Array.isArray(this.response.data)) { - this.response.data.forEach((data) => expect(data).to.include.keys(keys)) + for (const data of this.response.data) { + for (const key of keys) { + assert(key in data, `Key "${key}" is not found in ${JSON.stringify(data)}`) + } + } } else { - expect(this.response.data).to.include.keys(keys) + for (const key of keys) { + assert(key in this.response.data, `Key "${key}" is not found in ${JSON.stringify(this.response.data)}`) + } } } /** - * Executes a callback function passing in `response` object and chai assertions with `expect` + * Executes a callback function passing in `response` object and assert * 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']); + * I.seeResponseValidByCallback(({ data, status }) => { + * assert.strictEqual(status, 200); + * assert('user' in data); + * assert('company' in data); * }); * ``` * @@ -268,7 +282,7 @@ class JSONResponse extends Helper { */ seeResponseValidByCallback(fn) { this._checkResponseReady() - fn({ ...this.response, expect }) + fn({ ...this.response, assert }) const body = fn.toString() fn.toString = () => `${body.split('\n')[1]}...` } @@ -285,7 +299,7 @@ class JSONResponse extends Helper { */ seeResponseEquals(resp) { this._checkResponseReady() - expect(this.response.data).to.deep.equal(resp) + assert.deepStrictEqual(this.response.data, resp) } /** @@ -332,6 +346,17 @@ class JSONResponse extends Helper { _checkResponseReady() { if (!this.response) throw new Error('Response is not available') } + + _assertContains(actual, expected) { + for (const key in expected) { + assert(key in actual, `Key "${key}" not found in ${JSON.stringify(actual)}`) + if (typeof expected[key] === 'object' && expected[key] !== null) { + this._assertContains(actual[key], expected[key]) + } else { + assert.deepStrictEqual(actual[key], expected[key], `Values for key "${key}" don't match`) + } + } + } } module.exports = JSONResponse From 89414aaef6164bc1eafc06184bbef3c0aee10528 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Fri, 1 Nov 2024 02:23:05 +0200 Subject: [PATCH 05/37] updated graphql server --- package.json | 5 +++-- test/data/graphql/index.js | 12 +++++++----- test/data/graphql/schema.js | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index f4fc7b164..d9f826b24 100644 --- a/package.json +++ b/package.json @@ -114,6 +114,7 @@ "@codeceptjs/detox-helper": "1.1.2" }, "devDependencies": { + "@apollo/server": "^4", "@codeceptjs/mock-request": "0.3.1", "@faker-js/faker": "9.0.3", "@pollyjs/adapter-puppeteer": "6.0.6", @@ -125,7 +126,7 @@ "@wdio/selenium-standalone-service": "8.3.2", "@wdio/utils": "9.1.2", "@xmldom/xmldom": "0.9.4", - "@apollo/server": "^4", + "chai": "^4.0", "chai-as-promised": "7.1.2", "chai-subset": "1.6.0", "cheerio": "^1.0.0", @@ -139,6 +140,7 @@ "expect": "29.7.0", "express": "4.19.2", "graphql": "16.9.0", + "graphql-tag": "^2.12.6", "husky": "9.1.6", "inquirer-test": "2.0.1", "jsdoc": "^3", @@ -153,7 +155,6 @@ "sinon": "18.0.0", "sinon-chai": "3.7.0", "testcafe": "3.5.0", - "chai": "^4.0", "ts-morph": "23.0.0", "ts-node": "10.9.2", "tsd": "^0.31.0", diff --git a/test/data/graphql/index.js b/test/data/graphql/index.js index f3d372278..96dfa9b3d 100644 --- a/test/data/graphql/index.js +++ b/test/data/graphql/index.js @@ -1,6 +1,7 @@ const path = require('path'); const jsonServer = require('json-server'); -const { ApolloServer } = require('apollo-server-express'); +const { ApolloServer } = require('@apollo/server'); +const { startStandaloneServer } = require('@apollo/server/standalone'); const { resolvers, typeDefs } = require('./schema'); const TestHelper = require('../../support/TestHelper'); @@ -17,8 +18,9 @@ const server = new ApolloServer({ playground: true, }); -server.applyMiddleware({ app }); +const res = startStandaloneServer(server, { listen: { port: PORT } }); +res.then(({ url }) => { + console.log(`test graphQL server listening on ${url}...`); +}); -app.use(middleware); -app.use(router); -module.exports = app.listen(PORT, () => console.log(`test graphQL server listening on port ${PORT}...`)); +module.exports = res; diff --git a/test/data/graphql/schema.js b/test/data/graphql/schema.js index 62021869e..5c97573ba 100644 --- a/test/data/graphql/schema.js +++ b/test/data/graphql/schema.js @@ -1,4 +1,4 @@ -const { gql } = require('apollo-server-express'); +const gql = require('graphql-tag'); const { userModel } = require('./models'); From 4edba3e6a1ca0d7a2c619d797d911133e794feaa Mon Sep 17 00:00:00 2001 From: kobenguyent <7845001+kobenguyent@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:52:33 +0100 Subject: [PATCH 06/37] Delete .github/workflows/expectHelper.yml --- .github/workflows/expectHelper.yml | 34 ------------------------------ 1 file changed, 34 deletions(-) delete mode 100644 .github/workflows/expectHelper.yml diff --git a/.github/workflows/expectHelper.yml b/.github/workflows/expectHelper.yml deleted file mode 100644 index 8f9a6ee11..000000000 --- a/.github/workflows/expectHelper.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Expect Helper Tests - -on: - push: - branches: - - 3.x - pull_request: - branches: - - '**' - -env: - CI: true - # Force terminal colors. @see https://www.npmjs.com/package/colors - FORCE_COLOR: 1 - -jobs: - build: - - runs-on: ubuntu-22.04 - - strategy: - matrix: - node-version: [20.x] - - steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - - name: npm install - run: npm i --force - - name: run unit tests - run: ./node_modules/.bin/mocha test/helper/Expect_test.js --timeout 5000 From 47722bd41a509b3c7e283a6b8c557ae7f0c15bae Mon Sep 17 00:00:00 2001 From: kobenguyent <7845001+kobenguyent@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:52:45 +0100 Subject: [PATCH 07/37] Delete .github/workflows/softExpectHelper.yml --- .github/workflows/softExpectHelper.yml | 34 -------------------------- 1 file changed, 34 deletions(-) delete mode 100644 .github/workflows/softExpectHelper.yml diff --git a/.github/workflows/softExpectHelper.yml b/.github/workflows/softExpectHelper.yml deleted file mode 100644 index 141c056b8..000000000 --- a/.github/workflows/softExpectHelper.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Soft Expect Helper Tests - -on: - push: - branches: - - 3.x - pull_request: - branches: - - '**' - -env: - CI: true - # Force terminal colors. @see https://www.npmjs.com/package/colors - FORCE_COLOR: 1 - -jobs: - build: - - runs-on: ubuntu-22.04 - - strategy: - matrix: - node-version: [20.x] - - steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - - name: npm install - run: npm i --force - - name: run unit tests - run: ./node_modules/.bin/mocha test/helper/SoftExpect_test.js --timeout 5000 From 1a314d288546458966fc2779473ec24210db3f4c Mon Sep 17 00:00:00 2001 From: kobenguyent <7845001+kobenguyent@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:53:18 +0100 Subject: [PATCH 08/37] Update package.json --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index d9f826b24..eb3d735ed 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,6 @@ "test:unit:webbapi:webDriver:noSeleniumServer": "mocha test/helper/WebDriver.noSeleniumServer_test.js", "test:unit:webbapi:webDriver:devtools": "mocha test/helper/WebDriver_devtools_test.js --exit", "test:unit:webbapi:testCafe": "mocha test/helper/TestCafe_test.js", - "test:unit:expect": "mocha test/helper/Expect_test.js", "test:unit:mockServer": "mocha test/helper/MockServer_test.js", "test:plugin": "mocha test/plugin/plugin_test.js", "def": "./runok.js def", From 418514ce23f12683e8eef51d95a32900a57eddc9 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 01:06:37 +0200 Subject: [PATCH 09/37] removed helper tests --- .github/workflows/mockServerHelper.yml | 34 -------------------------- 1 file changed, 34 deletions(-) delete mode 100644 .github/workflows/mockServerHelper.yml diff --git a/.github/workflows/mockServerHelper.yml b/.github/workflows/mockServerHelper.yml deleted file mode 100644 index c80393e18..000000000 --- a/.github/workflows/mockServerHelper.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Mock Server Tests - -on: - push: - branches: - - 3.x - pull_request: - branches: - - '**' - -env: - CI: true - # Force terminal colors. @see https://www.npmjs.com/package/colors - FORCE_COLOR: 1 - -jobs: - build: - - runs-on: ubuntu-22.04 - - strategy: - matrix: - node-version: [20.x] - - steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - - name: npm install - run: npm i --force - - name: run unit tests - run: npm run test:unit:mockServer From 518656c1290804d53994d6c290a5fdc49b08189f Mon Sep 17 00:00:00 2001 From: kobenguyent <7845001+kobenguyent@users.noreply.github.com> Date: Tue, 5 Nov 2024 00:05:53 +0100 Subject: [PATCH 10/37] fix: remove mock server helper (#4536) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ˛fix: remove mock server helper * ˛fix: remove mock server helper * fix: remov pactum lib --- lib/helper/MockServer.js | 221 --------------------------------- package.json | 2 - test/helper/MockServer_test.js | 135 -------------------- 3 files changed, 358 deletions(-) delete mode 100644 lib/helper/MockServer.js diff --git a/lib/helper/MockServer.js b/lib/helper/MockServer.js deleted file mode 100644 index 7278c1021..000000000 --- a/lib/helper/MockServer.js +++ /dev/null @@ -1,221 +0,0 @@ -const { mock, settings } = require('pactum') - -/** - * ## Configuration - * - * This helper should be configured in codecept.conf.(js|ts) - * - * @typedef MockServerConfig - * @type {object} - * @prop {number} [port=9393] - Mock server port - * @prop {string} [host="0.0.0.0"] - Mock server host - * @prop {object} [httpsOpts] - key & cert values are the paths to .key and .crt files - */ -let config = { - port: 9393, - host: '0.0.0.0', - httpsOpts: { - key: '', - cert: '', - }, -} - -/** - * 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 { - constructor(passedConfig) { - settings.setLogLevel('SILENT') - config = { ...passedConfig } - if (global.debugMode) { - settings.setLogLevel('VERBOSE') - } - } - - /** - * Start the mock server - * @param {number} [port] start the mock server with given port - * - * @returns void - */ - async startMockServer(port) { - const _config = { ...config } - if (port) _config.port = port - await mock.setDefaults(_config) - await mock.start() - } - - /** - * Stop the mock server - * - * @returns void - * - */ - async stopMockServer() { - await mock.stop() - } - - /** - * 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 {CodeceptJS.MockInteraction|object} interaction add behavior to the mock server - * - * @returns void - * - */ - async addInteractionToMockServer(interaction) { - await mock.addInteraction(interaction) - } -} - -module.exports = MockServer diff --git a/package.json b/package.json index eb3d735ed..5c1cc269a 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,6 @@ "test:unit:webbapi:webDriver:noSeleniumServer": "mocha test/helper/WebDriver.noSeleniumServer_test.js", "test:unit:webbapi:webDriver:devtools": "mocha test/helper/WebDriver_devtools_test.js --exit", "test:unit:webbapi:testCafe": "mocha test/helper/TestCafe_test.js", - "test:unit:mockServer": "mocha test/helper/MockServer_test.js", "test:plugin": "mocha test/plugin/plugin_test.js", "def": "./runok.js def", "dev:graphql": "node test/data/graphql/index.js", @@ -101,7 +100,6 @@ "monocart-coverage-reports": "2.10.3", "ms": "2.1.3", "ora-classic": "5.4.2", - "pactum": "3.7.1", "parse-function": "5.6.10", "parse5": "7.1.2", "promise-retry": "1.1.1", diff --git a/test/helper/MockServer_test.js b/test/helper/MockServer_test.js index b86d246ce..e69de29bb 100644 --- a/test/helper/MockServer_test.js +++ b/test/helper/MockServer_test.js @@ -1,135 +0,0 @@ -const path = require('path') - -const chai = require('chai') - -const expect = chai.expect - -const { like } = require('pactum-matchers') -const MockServer = require('../../lib/helper/MockServer') -const REST = require('../../lib/helper/REST') - -global.codeceptjs = require('../../lib') - -let I -let restClient -const port = 65000 -const api_url = `http://0.0.0.0:${port}` - -describe('MockServer Helper', function () { - this.timeout(3000) - this.retries(1) - - before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - - I = new MockServer({ port }) - restClient = new REST({ - endpoint: api_url, - defaultHeaders: { - 'X-Test': 'test', - }, - }) - }) - - beforeEach(async () => { - await I.startMockServer() - }) - - afterEach(async () => { - await I.stopMockServer() - }) - - describe('#startMockServer', () => { - it('should start the mock server with custom port', async () => { - global.debugMode = true - await I.startMockServer(6789) - await I.stopMockServer() - global.debugMode = undefined - }) - }) - - describe('#addInteractionToMockServer', () => { - it('should return the correct response', async () => { - await I.addInteractionToMockServer({ - request: { - method: 'GET', - path: '/api/hello', - }, - response: { - status: 200, - body: { - say: 'hello to mock server', - }, - }, - }) - const res = await restClient.sendGetRequest('/api/hello') - expect(res.data).to.eql({ say: 'hello to mock server' }) - }) - - it('should return 404 when not found route', async () => { - const res = await restClient.sendGetRequest('/api/notfound') - expect(res.status).to.eql(404) - }) - - it('should return the strong Match on Query Params', async () => { - await I.addInteractionToMockServer({ - request: { - method: 'GET', - path: '/api/users', - queryParams: { - id: 1, - }, - }, - response: { - status: 200, - body: { - user: 1, - }, - }, - }) - - await I.addInteractionToMockServer({ - request: { - method: 'GET', - path: '/api/users', - queryParams: { - id: 2, - }, - }, - response: { - status: 200, - body: { - user: 2, - }, - }, - }) - let res = await restClient.sendGetRequest('/api/users?id=1') - expect(res.data).to.eql({ user: 1 }) - res = await restClient.sendGetRequest('/api/users?id=2') - expect(res.data).to.eql({ user: 2 }) - }) - - it('should check the stateful behavior', async () => { - await I.addInteractionToMockServer({ - request: { - method: 'GET', - path: '/api/projects/{id}', - pathParams: { - id: like('random-id'), - }, - }, - stores: { - ProjectId: 'req.pathParams.id', - }, - response: { - status: 200, - body: { - id: '$S{ProjectId}', - }, - }, - }) - const res = await restClient.sendGetRequest('/api/projects/10') - expect(res.data).to.eql({ id: '10' }) - }) - }) -}) From 1ef110a086372606c153073abeb04c531ec71f81 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 01:31:37 +0200 Subject: [PATCH 11/37] removed mock server test --- test/helper/MockServer_test.js | 1 - 1 file changed, 1 deletion(-) delete mode 100644 test/helper/MockServer_test.js diff --git a/test/helper/MockServer_test.js b/test/helper/MockServer_test.js deleted file mode 100644 index 8b1378917..000000000 --- a/test/helper/MockServer_test.js +++ /dev/null @@ -1 +0,0 @@ - From 8f12d167d23a77f534ca9f8f04394716b7d9533f Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 01:55:12 +0200 Subject: [PATCH 12/37] changed the way expect helper is loaded --- package.json | 1 + test/acceptance/codecept.Playwright.coverage.js | 4 +++- test/acceptance/codecept.Playwright.js | 4 +++- test/acceptance/codecept.Playwright.retryTo.js | 4 +++- test/acceptance/codecept.Puppeteer.js | 4 +++- test/acceptance/codecept.Testcafe.js | 4 +++- test/acceptance/codecept.WebDriver.devtools.coverage.js | 4 +++- test/acceptance/codecept.WebDriver.devtools.js | 5 ++++- test/acceptance/codecept.WebDriver.js | 4 +++- 9 files changed, 26 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 5c1cc269a..0d3171750 100644 --- a/package.json +++ b/package.json @@ -112,6 +112,7 @@ }, "devDependencies": { "@apollo/server": "^4", + "@codeceptjs/expect-helper": "^0.1.0", "@codeceptjs/mock-request": "0.3.1", "@faker-js/faker": "9.0.3", "@pollyjs/adapter-puppeteer": "6.0.6", diff --git a/test/acceptance/codecept.Playwright.coverage.js b/test/acceptance/codecept.Playwright.coverage.js index e2925d364..3a88f19ee 100644 --- a/test/acceptance/codecept.Playwright.coverage.js +++ b/test/acceptance/codecept.Playwright.coverage.js @@ -23,7 +23,9 @@ module.exports.config = { require: '../support/ScreenshotSessionHelper.js', outputPath: 'test/acceptance/output', }, - ExpectHelper: {}, + Expect: { + require: '@codeceptjs/expect-helper', + }, }, include: {}, bootstrap: false, diff --git a/test/acceptance/codecept.Playwright.js b/test/acceptance/codecept.Playwright.js index 586a7ace6..696fcfbab 100644 --- a/test/acceptance/codecept.Playwright.js +++ b/test/acceptance/codecept.Playwright.js @@ -23,7 +23,9 @@ module.exports.config = { require: '../support/ScreenshotSessionHelper.js', outputPath: 'test/acceptance/output', }, - ExpectHelper: {}, + Expect: { + require: '@codeceptjs/expect-helper', + }, }, include: {}, bootstrap: false, diff --git a/test/acceptance/codecept.Playwright.retryTo.js b/test/acceptance/codecept.Playwright.retryTo.js index 586a7ace6..696fcfbab 100644 --- a/test/acceptance/codecept.Playwright.retryTo.js +++ b/test/acceptance/codecept.Playwright.retryTo.js @@ -23,7 +23,9 @@ module.exports.config = { require: '../support/ScreenshotSessionHelper.js', outputPath: 'test/acceptance/output', }, - ExpectHelper: {}, + Expect: { + require: '@codeceptjs/expect-helper', + }, }, include: {}, bootstrap: false, diff --git a/test/acceptance/codecept.Puppeteer.js b/test/acceptance/codecept.Puppeteer.js index d7e31d71c..63b738565 100644 --- a/test/acceptance/codecept.Puppeteer.js +++ b/test/acceptance/codecept.Puppeteer.js @@ -16,7 +16,9 @@ module.exports.config = { require: '../support/ScreenshotSessionHelper.js', outputPath: './output', }, - ExpectHelper: {}, + Expect: { + require: '@codeceptjs/expect-helper', + }, }, include: {}, bootstrap: false, diff --git a/test/acceptance/codecept.Testcafe.js b/test/acceptance/codecept.Testcafe.js index bf924656f..d2c7d3b8d 100644 --- a/test/acceptance/codecept.Testcafe.js +++ b/test/acceptance/codecept.Testcafe.js @@ -9,7 +9,9 @@ module.exports.config = { url: TestHelper.siteUrl(), show: true, }, - ExpectHelper: {}, + Expect: { + require: '@codeceptjs/expect-helper', + }, }, include: {}, bootstrap: false, diff --git a/test/acceptance/codecept.WebDriver.devtools.coverage.js b/test/acceptance/codecept.WebDriver.devtools.coverage.js index 3d771815d..478fccafb 100644 --- a/test/acceptance/codecept.WebDriver.devtools.coverage.js +++ b/test/acceptance/codecept.WebDriver.devtools.coverage.js @@ -21,7 +21,9 @@ module.exports.config = { require: '../support/ScreenshotSessionHelper.js', outputPath: './output', }, - ExpectHelper: {}, + Expect: { + require: '@codeceptjs/expect-helper', + }, }, include: {}, mocha: {}, diff --git a/test/acceptance/codecept.WebDriver.devtools.js b/test/acceptance/codecept.WebDriver.devtools.js index 755e950d5..614e03645 100644 --- a/test/acceptance/codecept.WebDriver.devtools.js +++ b/test/acceptance/codecept.WebDriver.devtools.js @@ -21,7 +21,10 @@ module.exports.config = { require: '../support/ScreenshotSessionHelper.js', outputPath: './output', }, - ExpectHelper: {}, + Expect: { + require: '@codeceptjs/expect-helper', + }, + }, include: {}, bootstrap: async () => diff --git a/test/acceptance/codecept.WebDriver.js b/test/acceptance/codecept.WebDriver.js index 006e69d67..a3baf2bec 100644 --- a/test/acceptance/codecept.WebDriver.js +++ b/test/acceptance/codecept.WebDriver.js @@ -21,7 +21,9 @@ module.exports.config = { require: '../support/ScreenshotSessionHelper.js', outputPath: './output', }, - ExpectHelper: {}, + Expect: { + require: '@codeceptjs/expect-helper', + }, }, include: {}, bootstrap: async () => From ccb3d7f0cf4ddcb1670c4ec5bac3f182d3e6e0cd Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 03:34:09 +0200 Subject: [PATCH 13/37] loading expect helper form package --- test/acceptance/codecept.WebDriver.devtools.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/acceptance/codecept.WebDriver.devtools.js b/test/acceptance/codecept.WebDriver.devtools.js index 614e03645..5b68ffdce 100644 --- a/test/acceptance/codecept.WebDriver.devtools.js +++ b/test/acceptance/codecept.WebDriver.devtools.js @@ -24,7 +24,6 @@ module.exports.config = { Expect: { require: '@codeceptjs/expect-helper', }, - }, include: {}, bootstrap: async () => From 126b2db7b0edc1ff65a525beb0998598df947374 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 03:42:48 +0200 Subject: [PATCH 14/37] loading expect helper form package --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0d3171750..d605022e2 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ }, "devDependencies": { "@apollo/server": "^4", - "@codeceptjs/expect-helper": "^0.1.0", + "@codeceptjs/expect-helper": "^0.2.0", "@codeceptjs/mock-request": "0.3.1", "@faker-js/faker": "9.0.3", "@pollyjs/adapter-puppeteer": "6.0.6", From a0d453f1cf7c75e3ffd05e8816aeec5a3feb1df6 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 09:37:34 +0200 Subject: [PATCH 15/37] updated expect version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d605022e2..e16e926d0 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ }, "devDependencies": { "@apollo/server": "^4", - "@codeceptjs/expect-helper": "^0.2.0", + "@codeceptjs/expect-helper": "^0.2.1", "@codeceptjs/mock-request": "0.3.1", "@faker-js/faker": "9.0.3", "@pollyjs/adapter-puppeteer": "6.0.6", From 8646b724bcdca07d1af0925e1a336d9e32e6f9cb Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 10:15:21 +0200 Subject: [PATCH 16/37] updated dockerfile to use latest playwright, removed npm i --force --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 445b740c8..8491adc29 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Download Playwright and its dependencies -FROM mcr.microsoft.com/playwright:v1.39.0 +FROM mcr.microsoft.com/playwright:v1.48.1-noble ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true # Installing the pre-required packages and libraries @@ -29,7 +29,7 @@ RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \ COPY . /codecept RUN chown -R pptruser:pptruser /codecept -RUN runuser -l pptruser -c 'npm i --force --loglevel=warn --prefix /codecept' +RUN runuser -l pptruser -c 'npm i --loglevel=warn --prefix /codecept' RUN ln -s /codecept/bin/codecept.js /usr/local/bin/codeceptjs RUN mkdir /tests From c87a027dd1ce0266fdd174f32955ee46554a8368 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 11:20:34 +0200 Subject: [PATCH 17/37] improved loading esm/cjs style modules --- lib/container.js | 116 ++++++++++++++++++------- test/acceptance/codecept.Playwright.js | 4 +- 2 files changed, 86 insertions(+), 34 deletions(-) diff --git a/lib/container.js b/lib/container.js index 2307b94e8..9d2382633 100644 --- a/lib/container.js +++ b/lib/container.js @@ -1,7 +1,8 @@ const glob = require('glob'); const path = require('path'); +const { isPromise } = require('util/types'); const { MetaStep } = require('./step'); -const { fileExists, isFunction, isAsyncFunction } = require('./utils'); +const { fileExists, isFunction, isAsyncFunction, installedLocally } = require('./utils'); const Translation = require('./translation'); const MochaFactory = require('./mochaFactory'); const recorder = require('./recorder'); @@ -155,45 +156,42 @@ module.exports = Container; function createHelpers(config) { const helpers = {}; - let moduleName; - for (const helperName in config) { + for (let helperName in config) { try { - if (config[helperName].require) { - if (config[helperName].require.startsWith('.')) { - moduleName = path.resolve(global.codecept_dir, config[helperName].require); // custom helper - } else { - moduleName = config[helperName].require; // plugin helper - } - } else { - moduleName = `./helper/${helperName}`; // built-in helper + let HelperClass; + + // ESM import + if (helperName?.constructor === Function && helperName.prototype) { + HelperClass = helperName; + helperName = HelperClass.constructor.name; } - // @ts-ignore - let HelperClass; - // check if the helper is the built-in, use the require() syntax. - if (moduleName.startsWith('./helper/')) { - HelperClass = require(moduleName); - } else { - // check if the new syntax export default HelperName is used and loads the Helper, otherwise loads the module that used old syntax export = HelperName. - HelperClass = require(moduleName).default || require(moduleName); + // classical require + if (!HelperClass) { + HelperClass = requireHelperFromModule(helperName, config); } - if (HelperClass._checkRequirements) { - const requirements = HelperClass._checkRequirements(); - if (requirements) { - let install; - if (require('./utils').installedLocally()) { - install = `npm install --save-dev ${requirements.join(' ')}`; - } else { - console.log('WARNING: CodeceptJS is not installed locally. It is recommended to switch to local installation'); - install = `[sudo] npm install -g ${requirements.join(' ')}`; + // handle async CJS modules that use dynamic import + if (isPromise(HelperClass) && typeof HelperClass.then === 'function') { + HelperClass = HelperClass.then(ResolvedHelperClass => { + // Check if ResolvedHelperClass is a constructor function + if (typeof ResolvedHelperClass !== 'function' || !ResolvedHelperClass.prototype) { + throw new Error(`Helper class from module '${helperName}' is not a constructor. Use CJS async module syntax.`); } - throw new Error(`Required modules are not installed.\n\nRUN: ${install}`); - } + try { + helpers[helperName] = new ResolvedHelperClass(config[helperName]); + } catch (err) { + throw new Error(`Could not load helper ${helperName} as async module (${err.message})`); + } + }); + continue; } + + checkHelperRequirements(HelperClass); + helpers[helperName] = new HelperClass(config[helperName]); } catch (err) { - throw new Error(`Could not load helper ${helperName} from module '${moduleName}':\n${err.message}\n${err.stack}`); + throw new Error(`Could not load helper ${helperName} (${err.message})`); } } @@ -203,6 +201,44 @@ function createHelpers(config) { return helpers; } +function checkHelperRequirements(HelperClass) { + if (HelperClass._checkRequirements) { + const requirements = HelperClass._checkRequirements(); + if (requirements) { + let install; + if (installedLocally()) { + install = `npm install --save-dev ${requirements.join(' ')}`; + } else { + console.log('WARNING: CodeceptJS is not installed locally. It is recommended to switch to local installation'); + install = `[sudo] npm install -g ${requirements.join(' ')}`; + } + throw new Error(`Required modules are not installed.\n\nRUN: ${install}`); + } + } +} + +function requireHelperFromModule(helperName, config, HelperClass) { + const moduleName = getHelperModuleName(helperName, config); + if (moduleName.startsWith('./helper/')) { + HelperClass = require(moduleName); + } else { + // check if the new syntax export default HelperName is used and loads the Helper, otherwise loads the module that used old syntax export = HelperName. + try { + const mod = require(moduleName); + if (!mod && !mod.default) { + throw new Error(`Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`); + } + HelperClass = mod.default || mod; + } catch (err) { + if (err.code === 'MODULE_NOT_FOUND') { + throw new Error(`Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`); + } + throw err; + } + } + return HelperClass; +} + function createSupportObjects(config) { const objects = {}; @@ -440,3 +476,21 @@ function loadTranslation(locale, vocabularies) { return translation; } + +function getHelperModuleName(helperName, config) { + // classical require + if (config[helperName].require) { + if (config[helperName].require.startsWith('.')) { + return path.resolve(global.codecept_dir, config[helperName].require); // custom helper + } + return config[helperName].require; // plugin helper + } + + // built-in helpers + if (helperName.startsWith('@codeceptjs/')) { + return helperName; + } + + // built-in helpers + return `./helper/${helperName}`; +} diff --git a/test/acceptance/codecept.Playwright.js b/test/acceptance/codecept.Playwright.js index 696fcfbab..7c5eb2f82 100644 --- a/test/acceptance/codecept.Playwright.js +++ b/test/acceptance/codecept.Playwright.js @@ -23,9 +23,7 @@ module.exports.config = { require: '../support/ScreenshotSessionHelper.js', outputPath: 'test/acceptance/output', }, - Expect: { - require: '@codeceptjs/expect-helper', - }, + '@codeceptjs/expect-helper': {}, }, include: {}, bootstrap: false, From 02b0f4b5500b8e8f1d4be24c7584ecfba49c7e2c Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 11:21:34 +0200 Subject: [PATCH 18/37] improved loading esm/cjs style modules --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e16e926d0..74e066536 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "json-server:graphql": "node test/data/graphql/index.js", "lint": "eslint bin/ examples/ lib/ test/ translations/ runok.js", "lint-fix": "eslint bin/ examples/ lib/ test/ translations/ runok.js --fix", - "prettier": "prettier --config prettier.config.js --write bin/**/*.js lib/**/*.js test/**/*.js translations/**/*.js runok.js", + "prettier": "prettier --config prettier.config.js --cached --write bin/**/*.js lib/**/*.js test/**/*.js translations/**/*.js runok.js", "docs": "./runok.js docs", "test:unit": "mocha test/unit --recursive --timeout 10000", "test:runner": "mocha test/runner --recursive --timeout 10000", From 51c3b3b6010deb13eb5c86530784b5a3ae330577 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 11:24:26 +0200 Subject: [PATCH 19/37] improved loading esm/cjs style modules --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 74e066536..6db7fe4e0 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ "json-server:graphql": "node test/data/graphql/index.js", "lint": "eslint bin/ examples/ lib/ test/ translations/ runok.js", "lint-fix": "eslint bin/ examples/ lib/ test/ translations/ runok.js --fix", - "prettier": "prettier --config prettier.config.js --cached --write bin/**/*.js lib/**/*.js test/**/*.js translations/**/*.js runok.js", + "prettier": "git diff --name-only --cached --diff-filter=d | grep '\\.js' | xargs npx prettier --write", + "prettier:all": "prettier --config prettier.config.js --write bin/**/*.js lib/**/*.js test/**/*.js translations/**/*.js runok.js", "docs": "./runok.js docs", "test:unit": "mocha test/unit --recursive --timeout 10000", "test:runner": "mocha test/runner --recursive --timeout 10000", From dbdd82afccbc289824fe529c2c6dc56f73f0a230 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 11:29:48 +0200 Subject: [PATCH 20/37] improved loading esm/cjs style modules --- .husky/pre-commit | 7 +++---- package.json | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 635d81b70..b9885f258 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,3 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - -npm run prettier && npm run lint && npm run dtslint +prettier $(git diff --cached --name-only --diff-filter=ACMR | sed 's| |\\ |g') --write --ignore-unknown +git update-index --again +npm run lint && npm run dtslint diff --git a/package.json b/package.json index 6db7fe4e0..5b6ca39f1 100644 --- a/package.json +++ b/package.json @@ -39,8 +39,7 @@ "json-server:graphql": "node test/data/graphql/index.js", "lint": "eslint bin/ examples/ lib/ test/ translations/ runok.js", "lint-fix": "eslint bin/ examples/ lib/ test/ translations/ runok.js --fix", - "prettier": "git diff --name-only --cached --diff-filter=d | grep '\\.js' | xargs npx prettier --write", - "prettier:all": "prettier --config prettier.config.js --write bin/**/*.js lib/**/*.js test/**/*.js translations/**/*.js runok.js", + "prettier": "prettier --config prettier.config.js --write bin/**/*.js lib/**/*.js test/**/*.js translations/**/*.js runok.js", "docs": "./runok.js docs", "test:unit": "mocha test/unit --recursive --timeout 10000", "test:runner": "mocha test/runner --recursive --timeout 10000", @@ -64,7 +63,7 @@ "update-contributor-faces": "./runok.js contributor:faces", "types-fix": "node typings/fixDefFiles.js", "dtslint": "npm run types-fix && tsd", - "prepare": "husky install", + "prepare": "husky", "prepare-release": "./runok.js versioning && ./runok.js get:commit-log", "publish-beta": "./runok.js publish:next-beta-version" }, From de6b257f663110191cd29365ffa7c83362a98e40 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 12:09:44 +0200 Subject: [PATCH 21/37] changed docker file --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8491adc29..7d4f6bc9d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,8 +4,8 @@ ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true # Installing the pre-required packages and libraries RUN apt-get update && \ - apt-get install -y libgtk2.0-0 libgconf-2-4 \ - libasound2 libxtst6 libxss1 libnss3 xvfb + apt-get install -y libgtk2.0-0 \ + libxtst6 libxss1 libnss3 xvfb # Install latest chrome dev package and fonts to support major charsets (Chinese, Japanese, Arabic, Hebrew, Thai and a few others) # Note: this installs the necessary libs to make the bundled version of Chromium that Puppeteer From 11bcd9e21bb147bb5146377d80ed66ae448e28fe Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 12:16:57 +0200 Subject: [PATCH 22/37] updated expect helper --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5b6ca39f1..8b771f0c1 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ }, "devDependencies": { "@apollo/server": "^4", - "@codeceptjs/expect-helper": "^0.2.1", + "@codeceptjs/expect-helper": "^0.2.2", "@codeceptjs/mock-request": "0.3.1", "@faker-js/faker": "9.0.3", "@pollyjs/adapter-puppeteer": "6.0.6", From 8c0ec872324b1b49ddf32c6bc7a2533e2b991633 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 13:24:46 +0200 Subject: [PATCH 23/37] fixed loading cjs helper --- .husky/pre-commit | 3 +- lib/container.js | 400 +++++++++++++++++++++++----------------------- 2 files changed, 206 insertions(+), 197 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index b9885f258..3f4f6f4eb 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,3 +1,4 @@ prettier $(git diff --cached --name-only --diff-filter=ACMR | sed 's| |\\ |g') --write --ignore-unknown git update-index --again -npm run lint && npm run dtslint +npx eslint $(git diff --cached --name-only --diff-filter=ACMR | sed 's| |\\ |g') +npm run dtslint diff --git a/lib/container.js b/lib/container.js index 9d2382633..0ed0c3367 100644 --- a/lib/container.js +++ b/lib/container.js @@ -1,15 +1,15 @@ -const glob = require('glob'); -const path = require('path'); -const { isPromise } = require('util/types'); -const { MetaStep } = require('./step'); -const { fileExists, isFunction, isAsyncFunction, installedLocally } = require('./utils'); -const Translation = require('./translation'); -const MochaFactory = require('./mochaFactory'); -const recorder = require('./recorder'); -const event = require('./event'); -const WorkerStorage = require('./workerStorage'); -const store = require('./store'); -const ai = require('./ai'); +const glob = require('glob') +const path = require('path') +const { isPromise } = require('util/types') +const { MetaStep } = require('./step') +const { fileExists, isFunction, isAsyncFunction, installedLocally } = require('./utils') +const Translation = require('./translation') +const MochaFactory = require('./mochaFactory') +const recorder = require('./recorder') +const event = require('./event') +const WorkerStorage = require('./workerStorage') +const store = require('./store') +const ai = require('./ai') let container = { helpers: {}, @@ -21,7 +21,7 @@ let container = { */ mocha: {}, translation: {}, -}; +} /** * Dependency Injection Container @@ -35,21 +35,21 @@ class Container { * @param {*} opts */ static create(config, opts) { - const mochaConfig = config.mocha || {}; + const mochaConfig = config.mocha || {} if (config.grep && !opts.grep) { - mochaConfig.grep = config.grep; + mochaConfig.grep = config.grep } this.createMocha = () => { - container.mocha = MochaFactory.create(mochaConfig, opts || {}); - }; - this.createMocha(); - container.helpers = createHelpers(config.helpers || {}); - container.translation = loadTranslation(config.translation || null, config.vocabularies || []); - container.support = createSupportObjects(config.include || {}); - container.plugins = createPlugins(config.plugins || {}, opts); - if (opts && opts.ai) ai.enable(config.ai); // enable AI Assistant - if (config.gherkin) loadGherkinSteps(config.gherkin.steps || []); - if (opts && typeof opts.timeouts === 'boolean') store.timeouts = opts.timeouts; + container.mocha = MochaFactory.create(mochaConfig, opts || {}) + } + this.createMocha() + container.helpers = createHelpers(config.helpers || {}) + container.translation = loadTranslation(config.translation || null, config.vocabularies || []) + container.support = createSupportObjects(config.include || {}) + container.plugins = createPlugins(config.plugins || {}, opts) + if (opts && opts.ai) ai.enable(config.ai) // enable AI Assistant + if (config.gherkin) loadGherkinSteps(config.gherkin.steps || []) + if (opts && typeof opts.timeouts === 'boolean') store.timeouts = opts.timeouts } /** @@ -61,9 +61,9 @@ class Container { */ static plugins(name) { if (!name) { - return container.plugins; + return container.plugins } - return container.plugins[name]; + return container.plugins[name] } /** @@ -75,9 +75,9 @@ class Container { */ static support(name) { if (!name) { - return container.support; + return container.support } - return container.support[name]; + return container.support[name] } /** @@ -89,9 +89,9 @@ class Container { */ static helpers(name) { if (!name) { - return container.helpers; + return container.helpers } - return container.helpers[name]; + return container.helpers[name] } /** @@ -100,7 +100,7 @@ class Container { * @api */ static translation() { - return container.translation; + return container.translation } /** @@ -110,7 +110,7 @@ class Container { * @returns { * } */ static mocha() { - return container.mocha; + return container.mocha } /** @@ -120,8 +120,8 @@ class Container { * @param {Object} newContainer */ static append(newContainer) { - const deepMerge = require('./utils').deepMerge; - container = deepMerge(container, newContainer); + const deepMerge = require('./utils').deepMerge + container = deepMerge(container, newContainer) } /** @@ -132,10 +132,10 @@ class Container { * @param {Object} newPlugins */ static clear(newHelpers, newSupport, newPlugins) { - container.helpers = newHelpers || {}; - container.support = newSupport || {}; - container.plugins = newPlugins || {}; - container.translation = loadTranslation(); + container.helpers = newHelpers || {} + container.support = newSupport || {} + container.plugins = newPlugins || {} + container.translation = loadTranslation() } /** @@ -145,292 +145,300 @@ class Container { * @param {Object} options - set {local: true} to not share among workers */ static share(data, options = {}) { - Container.append({ support: data }); + Container.append({ support: data }) if (!options.local) { - WorkerStorage.share(data); + WorkerStorage.share(data) } } } -module.exports = Container; +module.exports = Container function createHelpers(config) { - const helpers = {}; + const helpers = {} for (let helperName in config) { try { - let HelperClass; + let HelperClass // ESM import if (helperName?.constructor === Function && helperName.prototype) { - HelperClass = helperName; - helperName = HelperClass.constructor.name; + HelperClass = helperName + helperName = HelperClass.constructor.name } // classical require if (!HelperClass) { - HelperClass = requireHelperFromModule(helperName, config); + HelperClass = requireHelperFromModule(helperName, config) } + console.log('HelperClass', 'aa', HelperClass) // handle async CJS modules that use dynamic import - if (isPromise(HelperClass) && typeof HelperClass.then === 'function') { - HelperClass = HelperClass.then(ResolvedHelperClass => { + if (isAsyncFunction(HelperClass)) { + HelperClass = HelperClass().then((ResolvedHelperClass) => { // Check if ResolvedHelperClass is a constructor function - if (typeof ResolvedHelperClass !== 'function' || !ResolvedHelperClass.prototype) { - throw new Error(`Helper class from module '${helperName}' is not a constructor. Use CJS async module syntax.`); + if (typeof ResolvedHelperClass?.constructor !== 'function') { + throw new Error(`Helper class from module '${helperName}' is not a class. Use CJS async module syntax.`) } try { - helpers[helperName] = new ResolvedHelperClass(config[helperName]); + helpers[helperName] = new ResolvedHelperClass(config[helperName]) } catch (err) { - throw new Error(`Could not load helper ${helperName} as async module (${err.message})`); + throw new Error(`Could not load helper ${helperName} as async module (${err.message})`) } - }); - continue; + }) + + continue } - checkHelperRequirements(HelperClass); + checkHelperRequirements(HelperClass) - helpers[helperName] = new HelperClass(config[helperName]); + helpers[helperName] = new HelperClass(config[helperName]) } catch (err) { - throw new Error(`Could not load helper ${helperName} (${err.message})`); + throw new Error(`Could not load helper ${helperName} (${err.message})`) } } for (const name in helpers) { - if (helpers[name]._init) helpers[name]._init(); + if (helpers[name]._init) helpers[name]._init() } - return helpers; + return helpers } function checkHelperRequirements(HelperClass) { if (HelperClass._checkRequirements) { - const requirements = HelperClass._checkRequirements(); + const requirements = HelperClass._checkRequirements() if (requirements) { - let install; + let install if (installedLocally()) { - install = `npm install --save-dev ${requirements.join(' ')}`; + install = `npm install --save-dev ${requirements.join(' ')}` } else { - console.log('WARNING: CodeceptJS is not installed locally. It is recommended to switch to local installation'); - install = `[sudo] npm install -g ${requirements.join(' ')}`; + console.log('WARNING: CodeceptJS is not installed locally. It is recommended to switch to local installation') + install = `[sudo] npm install -g ${requirements.join(' ')}` } - throw new Error(`Required modules are not installed.\n\nRUN: ${install}`); + throw new Error(`Required modules are not installed.\n\nRUN: ${install}`) } } } function requireHelperFromModule(helperName, config, HelperClass) { - const moduleName = getHelperModuleName(helperName, config); + const moduleName = getHelperModuleName(helperName, config) if (moduleName.startsWith('./helper/')) { - HelperClass = require(moduleName); + HelperClass = require(moduleName) } else { // check if the new syntax export default HelperName is used and loads the Helper, otherwise loads the module that used old syntax export = HelperName. try { - const mod = require(moduleName); + const mod = require(moduleName) if (!mod && !mod.default) { - throw new Error(`Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`); + throw new Error( + `Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`, + ) } - HelperClass = mod.default || mod; + HelperClass = mod.default || mod } catch (err) { if (err.code === 'MODULE_NOT_FOUND') { - throw new Error(`Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`); + throw new Error( + `Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`, + ) } - throw err; + throw err } } - return HelperClass; + return HelperClass } function createSupportObjects(config) { - const objects = {}; + const objects = {} for (const name in config) { - objects[name] = {}; // placeholders + objects[name] = {} // placeholders } if (!config.I) { - objects.I = require('./actor')(); + objects.I = require('./actor')() if (container.translation.I !== 'I') { - objects[container.translation.I] = objects.I; + objects[container.translation.I] = objects.I } } - container.support = objects; + container.support = objects function lazyLoad(name) { - let newObj = getSupportObject(config, name); + let newObj = getSupportObject(config, name) try { if (typeof newObj === 'function') { - newObj = newObj(); + newObj = newObj() } else if (newObj._init) { - newObj._init(); + newObj._init() } } catch (err) { - throw new Error(`Initialization failed for ${name}: ${newObj}\n${err.message}\n${err.stack}`); + throw new Error(`Initialization failed for ${name}: ${newObj}\n${err.message}\n${err.stack}`) } - return newObj; + return newObj } const asyncWrapper = function (f) { return function () { return f.apply(this, arguments).catch((e) => { - recorder.saveFirstAsyncError(e); - throw e; - }); - }; - }; + recorder.saveFirstAsyncError(e) + throw e + }) + } + } Object.keys(objects).forEach((object) => { - const currentObject = objects[object]; + const currentObject = objects[object] Object.keys(currentObject).forEach((method) => { - const currentMethod = currentObject[method]; + const currentMethod = currentObject[method] if (currentMethod && currentMethod[Symbol.toStringTag] === 'AsyncFunction') { - objects[object][method] = asyncWrapper(currentMethod); + objects[object][method] = asyncWrapper(currentMethod) } - }); - }); - - return new Proxy({}, { - has(target, key) { - return key in config; - }, - ownKeys() { - return Reflect.ownKeys(config); - }, - get(target, key) { - // configured but not in support object, yet: load the module - if (key in objects && !(key in target)) { - // load default I - if (key in objects && !(key in config)) { - return target[key] = objects[key]; - } + }) + }) + + return new Proxy( + {}, + { + has(target, key) { + return key in config + }, + ownKeys() { + return Reflect.ownKeys(config) + }, + get(target, key) { + // configured but not in support object, yet: load the module + if (key in objects && !(key in target)) { + // load default I + if (key in objects && !(key in config)) { + return (target[key] = objects[key]) + } - // load new object - const object = lazyLoad(key); - // check that object is a real object and not an array - if (Object.prototype.toString.call(object) === '[object Object]') { - return target[key] = Object.assign(objects[key], object); + // load new object + const object = lazyLoad(key) + // check that object is a real object and not an array + if (Object.prototype.toString.call(object) === '[object Object]') { + return (target[key] = Object.assign(objects[key], object)) + } + target[key] = object } - target[key] = object; - } - return target[key]; + return target[key] + }, }, - }); + ) } function createPlugins(config, options = {}) { - const plugins = {}; + const plugins = {} - const enabledPluginsByOptions = (options.plugins || '').split(','); + const enabledPluginsByOptions = (options.plugins || '').split(',') for (const pluginName in config) { - if (!config[pluginName]) config[pluginName] = {}; - if (!config[pluginName].enabled && (enabledPluginsByOptions.indexOf(pluginName) < 0)) { - continue; // plugin is disabled + if (!config[pluginName]) config[pluginName] = {} + if (!config[pluginName].enabled && enabledPluginsByOptions.indexOf(pluginName) < 0) { + continue // plugin is disabled } - let module; + let module try { if (config[pluginName].require) { - module = config[pluginName].require; - if (module.startsWith('.')) { // local - module = path.resolve(global.codecept_dir, module); // custom plugin + module = config[pluginName].require + if (module.startsWith('.')) { + // local + module = path.resolve(global.codecept_dir, module) // custom plugin } } else { - module = `./plugin/${pluginName}`; + module = `./plugin/${pluginName}` } - plugins[pluginName] = require(module)(config[pluginName]); + plugins[pluginName] = require(module)(config[pluginName]) } catch (err) { - throw new Error(`Could not load plugin ${pluginName} from module '${module}':\n${err.message}\n${err.stack}`); + throw new Error(`Could not load plugin ${pluginName} from module '${module}':\n${err.message}\n${err.stack}`) } } - return plugins; + return plugins } function getSupportObject(config, name) { - const module = config[name]; + const module = config[name] if (typeof module === 'string') { - return loadSupportObject(module, name); + return loadSupportObject(module, name) } - return module; + return module } function loadGherkinSteps(paths) { - global.Before = fn => event.dispatcher.on(event.test.started, fn); - global.After = fn => event.dispatcher.on(event.test.finished, fn); - global.Fail = fn => event.dispatcher.on(event.test.failed, fn); + global.Before = (fn) => event.dispatcher.on(event.test.started, fn) + global.After = (fn) => event.dispatcher.on(event.test.finished, fn) + global.Fail = (fn) => event.dispatcher.on(event.test.failed, fn) // If gherkin.steps is string, then this will iterate through that folder and send all step def js files to loadSupportObject // If gherkin.steps is Array, it will go the old way // This is done so that we need not enter all Step Definition files under config.gherkin.steps if (Array.isArray(paths)) { for (const path of paths) { - loadSupportObject(path, `Step Definition from ${path}`); + loadSupportObject(path, `Step Definition from ${path}`) } } else { - const folderPath = paths.startsWith('.') ? path.join(global.codecept_dir, paths) : ''; + const folderPath = paths.startsWith('.') ? path.join(global.codecept_dir, paths) : '' if (folderPath !== '') { glob.sync(folderPath).forEach((file) => { - loadSupportObject(file, `Step Definition from ${file}`); - }); + loadSupportObject(file, `Step Definition from ${file}`) + }) } } - delete global.Before; - delete global.After; - delete global.Fail; + delete global.Before + delete global.After + delete global.Fail } function loadSupportObject(modulePath, supportObjectName) { if (modulePath.charAt(0) === '.') { - modulePath = path.join(global.codecept_dir, modulePath); + modulePath = path.join(global.codecept_dir, modulePath) } try { - const obj = require(modulePath); + const obj = require(modulePath) if (typeof obj === 'function') { - const fobj = obj(); + const fobj = obj() if (fobj.constructor.name === 'Actor') { - const methods = getObjectMethods(fobj); - Object.keys(methods) - .forEach(key => { - fobj[key] = methods[key]; - }); + const methods = getObjectMethods(fobj) + Object.keys(methods).forEach((key) => { + fobj[key] = methods[key] + }) - return methods; + return methods } } - if (typeof obj !== 'function' - && Object.getPrototypeOf(obj) !== Object.prototype - && !Array.isArray(obj) - ) { - const methods = getObjectMethods(obj); + if (typeof obj !== 'function' && Object.getPrototypeOf(obj) !== Object.prototype && !Array.isArray(obj)) { + const methods = getObjectMethods(obj) Object.keys(methods) - .filter(key => !key.startsWith('_')) - .forEach(key => { - const currentMethod = methods[key]; + .filter((key) => !key.startsWith('_')) + .forEach((key) => { + const currentMethod = methods[key] if (isFunction(currentMethod) || isAsyncFunction(currentMethod)) { - const ms = new MetaStep(supportObjectName, key); - ms.setContext(methods); - methods[key] = ms.run.bind(ms, currentMethod); + const ms = new MetaStep(supportObjectName, key) + ms.setContext(methods) + methods[key] = ms.run.bind(ms, currentMethod) } - }); - return methods; + }) + return methods } if (!Array.isArray(obj)) { Object.keys(obj) - .filter(key => !key.startsWith('_')) - .forEach(key => { - const currentMethod = obj[key]; + .filter((key) => !key.startsWith('_')) + .forEach((key) => { + const currentMethod = obj[key] if (isFunction(currentMethod) || isAsyncFunction(currentMethod)) { - const ms = new MetaStep(supportObjectName, key); - ms.setContext(obj); - obj[key] = ms.run.bind(ms, currentMethod); + const ms = new MetaStep(supportObjectName, key) + ms.setContext(obj) + obj[key] = ms.run.bind(ms, currentMethod) } - }); + }) } - return obj; + return obj } catch (err) { - throw new Error(`Could not include object ${supportObjectName} from module '${modulePath}'\n${err.message}\n${err.stack}`); + throw new Error( + `Could not include object ${supportObjectName} from module '${modulePath}'\n${err.message}\n${err.stack}`, + ) } } @@ -438,59 +446,59 @@ function loadSupportObject(modulePath, supportObjectName) { * Method collect own property and prototype */ function getObjectMethods(obj) { - const methodsSet = new Set(); - let protoObj = Reflect.getPrototypeOf(obj); + const methodsSet = new Set() + let protoObj = Reflect.getPrototypeOf(obj) do { if (protoObj.constructor.prototype !== Object.prototype) { - const keys = Reflect.ownKeys(protoObj); - keys.forEach(k => methodsSet.add(k)); + const keys = Reflect.ownKeys(protoObj) + keys.forEach((k) => methodsSet.add(k)) } - } while (protoObj = Reflect.getPrototypeOf(protoObj)); - Reflect.ownKeys(obj).forEach(k => methodsSet.add(k)); - const methods = {}; + } while ((protoObj = Reflect.getPrototypeOf(protoObj))) + Reflect.ownKeys(obj).forEach((k) => methodsSet.add(k)) + const methods = {} for (const key of methodsSet.keys()) { - if (key !== 'constructor') methods[key] = obj[key]; + if (key !== 'constructor') methods[key] = obj[key] } - return methods; + return methods } function loadTranslation(locale, vocabularies) { if (!locale) { - return Translation.createEmpty(); + return Translation.createEmpty() } - let translation; + let translation // check if it is a known translation if (Translation.langs[locale]) { - translation = new Translation(Translation.langs[locale]); + translation = new Translation(Translation.langs[locale]) } else if (fileExists(path.join(global.codecept_dir, locale))) { // get from a provided file instead - translation = Translation.createDefault(); - translation.loadVocabulary(locale); + translation = Translation.createDefault() + translation.loadVocabulary(locale) } else { - translation = Translation.createDefault(); + translation = Translation.createDefault() } - vocabularies.forEach(v => translation.loadVocabulary(v)); + vocabularies.forEach((v) => translation.loadVocabulary(v)) - return translation; + return translation } function getHelperModuleName(helperName, config) { // classical require if (config[helperName].require) { if (config[helperName].require.startsWith('.')) { - return path.resolve(global.codecept_dir, config[helperName].require); // custom helper + return path.resolve(global.codecept_dir, config[helperName].require) // custom helper } - return config[helperName].require; // plugin helper + return config[helperName].require // plugin helper } // built-in helpers if (helperName.startsWith('@codeceptjs/')) { - return helperName; + return helperName } // built-in helpers - return `./helper/${helperName}`; + return `./helper/${helperName}` } From ac4da06009ad95a12bb632c7de6a9093ca3c39de Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 5 Nov 2024 14:00:09 +0200 Subject: [PATCH 24/37] fix async loading of helper methods --- lib/actor.js | 167 ++++++++++++++++++++++++----------------------- lib/container.js | 29 ++++---- 2 files changed, 105 insertions(+), 91 deletions(-) diff --git a/lib/actor.js b/lib/actor.js index a53a03fe4..e5d70b754 100644 --- a/lib/actor.js +++ b/lib/actor.js @@ -1,11 +1,11 @@ -const Step = require('./step'); -const { MetaStep } = require('./step'); -const container = require('./container'); -const { methodsOfObject } = require('./utils'); -const recorder = require('./recorder'); -const event = require('./event'); -const store = require('./store'); -const output = require('./output'); +const Step = require('./step') +const { MetaStep } = require('./step') +const container = require('./container') +const { methodsOfObject } = require('./utils') +const recorder = require('./recorder') +const event = require('./event') +const store = require('./store') +const output = require('./output') /** * @interface @@ -21,13 +21,13 @@ class Actor { * ⚠️ returns a promise which is synchronized internally by recorder */ async say(msg, color = 'cyan') { - const step = new Step('say', 'say'); - step.status = 'passed'; + const step = new Step('say', 'say') + step.status = 'passed' return recordStep(step, [msg]).then(() => { // this is backward compatibility as this event may be used somewhere - event.emit(event.step.comment, msg); - output.say(msg, `${color}`); - }); + event.emit(event.step.comment, msg) + output.say(msg, `${color}`) + }) } /** @@ -38,14 +38,14 @@ class Actor { * @inner */ limitTime(timeout) { - if (!store.timeouts) return this; + if (!store.timeouts) return this event.dispatcher.prependOnceListener(event.step.before, (step) => { - output.log(`Timeout to ${step}: ${timeout}s`); - step.setTimeout(timeout * 1000, Step.TIMEOUT_ORDER.codeLimitTime); - }); + output.log(`Timeout to ${step}: ${timeout}s`) + step.setTimeout(timeout * 1000, Step.TIMEOUT_ORDER.codeLimitTime) + }) - return this; + return this } /** @@ -55,11 +55,11 @@ class Actor { * @inner */ retry(opts) { - if (opts === undefined) opts = 1; - recorder.retry(opts); + if (opts === undefined) opts = 1 + recorder.retry(opts) // remove retry once the step passed - recorder.add(() => event.dispatcher.once(event.step.finished, () => recorder.retries.pop())); - return this; + recorder.add(() => event.dispatcher.once(event.step.finished, () => recorder.retries.pop())) + return this } } @@ -71,91 +71,98 @@ class Actor { */ module.exports = function (obj = {}) { if (!store.actor) { - store.actor = new Actor(); + store.actor = new Actor() } - const actor = store.actor; + const actor = store.actor - const translation = container.translation(); + const translation = container.translation() if (Object.keys(obj).length > 0) { - Object.keys(obj) - .forEach(action => { - const actionAlias = translation.actionAliasFor(action); - - const currentMethod = obj[action]; - const ms = new MetaStep('I', action); - if (translation.loaded) { - ms.name = actionAlias; - ms.actor = translation.I; - } - ms.setContext(actor); - actor[action] = actor[actionAlias] = ms.run.bind(ms, currentMethod); - }); + Object.keys(obj).forEach((action) => { + const actionAlias = translation.actionAliasFor(action) + + const currentMethod = obj[action] + const ms = new MetaStep('I', action) + if (translation.loaded) { + ms.name = actionAlias + ms.actor = translation.I + } + ms.setContext(actor) + actor[action] = actor[actionAlias] = ms.run.bind(ms, currentMethod) + }) } - const helpers = container.helpers(); + container.started().then(() => { + const helpers = container.helpers() - // add methods from enabled helpers - Object.values(helpers) - .forEach((helper) => { + // add methods from enabled helpers + Object.values(helpers).forEach((helper) => { methodsOfObject(helper, 'Helper') - .filter(method => method !== 'constructor' && method[0] !== '_') + .filter((method) => method !== 'constructor' && method[0] !== '_') .forEach((action) => { - const actionAlias = translation.actionAliasFor(action); + const actionAlias = translation.actionAliasFor(action) if (!actor[action]) { actor[action] = actor[actionAlias] = function () { - const step = new Step(helper, action); + const step = new Step(helper, action) if (translation.loaded) { - step.name = actionAlias; - step.actor = translation.I; + step.name = actionAlias + step.actor = translation.I } // add methods to promise chain - return recordStep(step, Array.from(arguments)); - }; + return recordStep(step, Array.from(arguments)) + } } - }); - }); + }) + }) + }) - return actor; -}; + return actor +} function recordStep(step, args) { - step.status = 'queued'; - step.setArguments(args); + step.status = 'queued' + step.setArguments(args) // run async before step hooks - event.emit(event.step.before, step); + event.emit(event.step.before, step) - const task = `${step.name}: ${step.humanizeArgs()}`; - let val; + const task = `${step.name}: ${step.humanizeArgs()}` + let val // run step inside promise - recorder.add(task, () => { - if (!step.startTime) { // step can be retries - event.emit(event.step.started, step); - step.startTime = Date.now(); - } - return val = step.run(...args); - }, false, undefined, step.getTimeout()); - - event.emit(event.step.after, step); + recorder.add( + task, + () => { + if (!step.startTime) { + // step can be retries + event.emit(event.step.started, step) + step.startTime = Date.now() + } + return (val = step.run(...args)) + }, + false, + undefined, + step.getTimeout(), + ) + + event.emit(event.step.after, step) recorder.add('step passed', () => { - step.endTime = Date.now(); - event.emit(event.step.passed, step, val); - event.emit(event.step.finished, step); - }); + step.endTime = Date.now() + event.emit(event.step.passed, step, val) + event.emit(event.step.finished, step) + }) recorder.catchWithoutStop((err) => { - step.status = 'failed'; - step.endTime = Date.now(); - event.emit(event.step.failed, step); - event.emit(event.step.finished, step); - throw err; - }); - - recorder.add('return result', () => val); + step.status = 'failed' + step.endTime = Date.now() + event.emit(event.step.failed, step) + event.emit(event.step.finished, step) + throw err + }) + + recorder.add('return result', () => val) // run async after step hooks - return recorder.promise(); + return recorder.promise() } diff --git a/lib/container.js b/lib/container.js index 0ed0c3367..10e905c29 100644 --- a/lib/container.js +++ b/lib/container.js @@ -11,6 +11,8 @@ const WorkerStorage = require('./workerStorage') const store = require('./store') const ai = require('./ai') +let asyncHelperPromise = Promise.resolve() + let container = { helpers: {}, support: {}, @@ -47,6 +49,7 @@ class Container { container.translation = loadTranslation(config.translation || null, config.vocabularies || []) container.support = createSupportObjects(config.include || {}) container.plugins = createPlugins(config.plugins || {}, opts) + if (opts && opts.ai) ai.enable(config.ai) // enable AI Assistant if (config.gherkin) loadGherkinSteps(config.gherkin.steps || []) if (opts && typeof opts.timeouts === 'boolean') store.timeouts = opts.timeouts @@ -138,6 +141,10 @@ class Container { container.translation = loadTranslation() } + static async started() { + return asyncHelperPromise + } + /** * Share data across worker threads * @@ -170,21 +177,21 @@ function createHelpers(config) { if (!HelperClass) { HelperClass = requireHelperFromModule(helperName, config) } - console.log('HelperClass', 'aa', HelperClass) // handle async CJS modules that use dynamic import if (isAsyncFunction(HelperClass)) { - HelperClass = HelperClass().then((ResolvedHelperClass) => { - // Check if ResolvedHelperClass is a constructor function - if (typeof ResolvedHelperClass?.constructor !== 'function') { - throw new Error(`Helper class from module '${helperName}' is not a class. Use CJS async module syntax.`) - } - try { + helpers[helperName] = {} + + asyncHelperPromise = asyncHelperPromise + .then(() => HelperClass()) + .then((ResolvedHelperClass) => { + // Check if ResolvedHelperClass is a constructor function + if (typeof ResolvedHelperClass?.constructor !== 'function') { + throw new Error(`Helper class from module '${helperName}' is not a class. Use CJS async module syntax.`) + } + helpers[helperName] = new ResolvedHelperClass(config[helperName]) - } catch (err) { - throw new Error(`Could not load helper ${helperName} as async module (${err.message})`) - } - }) + }) continue } From e4bbe2dbd257fb73a6e39de7c296964ca200ba35 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Sun, 22 Dec 2024 18:02:22 +0200 Subject: [PATCH 25/37] fixed failed tests --- test/data/sandbox/codecept.customworker.js | 17 ++++++++++------- test/unit/bdd_test.js | 10 +++++----- test/unit/worker_test.js | 6 ++---- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/test/data/sandbox/codecept.customworker.js b/test/data/sandbox/codecept.customworker.js index ea40b1c04..3add49341 100644 --- a/test/data/sandbox/codecept.customworker.js +++ b/test/data/sandbox/codecept.customworker.js @@ -7,17 +7,20 @@ exports.config = { Workers: { require: './workers_helper', }, + CustomWorkers: { + require: './custom_worker_helper', + }, }, include: {}, bootstrap: async () => { - process.stdout.write('bootstrap b1+'); - return new Promise(done => { + process.stdout.write('bootstrap b1+') + return new Promise((done) => { setTimeout(() => { - process.stdout.write('b2'); - done(); - }, 100); - }); + process.stdout.write('b2') + done() + }, 100) + }) }, mocha: {}, name: 'sandbox', -}; +} diff --git a/test/unit/bdd_test.js b/test/unit/bdd_test.js index 360d8959d..904baa140 100644 --- a/test/unit/bdd_test.js +++ b/test/unit/bdd_test.js @@ -1,10 +1,9 @@ const Gherkin = require('@cucumber/gherkin') const Messages = require('@cucumber/messages') -let expect -import('chai').then((chai) => { - expect = chai.expect -}) +const chai = require('chai') + +const expect = chai.expect const uuidFn = Messages.IdGenerator.uuid() const builder = new Gherkin.AstBuilder(uuidFn) @@ -190,7 +189,8 @@ describe('BDD', () => { }) }) - it('should execute scenarios step-by-step ', (done) => { + it('should execute scenarios step-by-step ', async () => { + recorder.start() printed = [] container.append({ helpers: { diff --git a/test/unit/worker_test.js b/test/unit/worker_test.js index bf4fb086f..fe6b3485f 100644 --- a/test/unit/worker_test.js +++ b/test/unit/worker_test.js @@ -1,8 +1,6 @@ -let expect -import('chai').then((chai) => { - expect = chai.expect -}) const path = require('path') +const expect = require('chai').expect + const { Workers, event, recorder } = require('../../lib/index') describe('Workers', function () { From 95f3825847387052987654ddb3fd574e17e2606c Mon Sep 17 00:00:00 2001 From: DavertMik Date: Sun, 22 Dec 2024 18:06:30 +0200 Subject: [PATCH 26/37] fixed worker test --- test/unit/worker_test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/worker_test.js b/test/unit/worker_test.js index fe6b3485f..b7b01c809 100644 --- a/test/unit/worker_test.js +++ b/test/unit/worker_test.js @@ -105,8 +105,8 @@ describe('Workers', function () { workers.on(event.all.result, (status) => { expect(status).equal(false) - expect(passedCount).equal(4) - expect(failedCount).equal(1) + expect(passedCount).equal(3) + expect(failedCount).equal(2) done() }) }) From 57f2ac008b4826bf2d3ed6598e3c439f25438f03 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Wed, 25 Dec 2024 04:22:06 +0200 Subject: [PATCH 27/37] fixed container issues --- lib/actor.js | 51 ++++--- lib/codecept.js | 2 + lib/command/workers/runTests.js | 7 +- lib/container.js | 86 +++++------ lib/interfaces/inject.js | 24 ++++ lib/scenario.js | 235 ++++++++++++++----------------- test/runner/run_multiple_test.js | 16 +-- test/unit/actor_test.js | 11 +- test/unit/container_test.js | 2 +- 9 files changed, 219 insertions(+), 215 deletions(-) create mode 100644 lib/interfaces/inject.js diff --git a/lib/actor.js b/lib/actor.js index e5d70b754..cf87d8b46 100644 --- a/lib/actor.js +++ b/lib/actor.js @@ -70,29 +70,11 @@ class Actor { * @ignore */ module.exports = function (obj = {}) { - if (!store.actor) { - store.actor = new Actor() - } - const actor = store.actor - - const translation = container.translation() - - if (Object.keys(obj).length > 0) { - Object.keys(obj).forEach((action) => { - const actionAlias = translation.actionAliasFor(action) - - const currentMethod = obj[action] - const ms = new MetaStep('I', action) - if (translation.loaded) { - ms.name = actionAlias - ms.actor = translation.I - } - ms.setContext(actor) - actor[action] = actor[actionAlias] = ms.run.bind(ms, currentMethod) - }) - } + const actor = container.actor() || new Actor() - container.started().then(() => { + // load all helpers once container initialized + container.started(() => { + const translation = container.translation() const helpers = container.helpers() // add methods from enabled helpers @@ -114,8 +96,33 @@ module.exports = function (obj = {}) { } }) }) + + // add translated custom steps from actor + Object.keys(obj).forEach((key) => { + const actionAlias = translation.actionAliasFor(key) + if (!actor[actionAlias]) { + actor[actionAlias] = actor[key] + } + }) + + store.actor = actor + container.append({ + support: { + [translation.I]: actor, + I: actor, + }, + }) }) + // add custom steps from actor + Object.keys(obj).forEach((key) => { + const ms = new MetaStep('I', key) + ms.setContext(actor) + actor[key] = ms.run.bind(ms, obj[key]) + }) + + // store.actor = actor; + return actor } diff --git a/lib/codecept.js b/lib/codecept.js index ca505bca1..fc24156fd 100644 --- a/lib/codecept.js +++ b/lib/codecept.js @@ -185,6 +185,8 @@ class Codecept { * @returns {Promise} */ async run(test) { + await container.started() + return new Promise((resolve, reject) => { const mocha = container.mocha() mocha.files = this.testFiles diff --git a/lib/command/workers/runTests.js b/lib/command/workers/runTests.js index 3563915e2..7d5913f83 100644 --- a/lib/command/workers/runTests.js +++ b/lib/command/workers/runTests.js @@ -39,13 +39,14 @@ const codecept = new Codecept(config, options) codecept.init(testRoot) codecept.loadTests() const mocha = container.mocha() -filterTests() +filterTests(); -;(async function () { +// run tests +(async function () { if (mocha.suite.total()) { await runTests() } -})() +})(); async function runTests() { try { diff --git a/lib/container.js b/lib/container.js index 10e905c29..24d77868d 100644 --- a/lib/container.js +++ b/lib/container.js @@ -1,8 +1,7 @@ const glob = require('glob') const path = require('path') -const { isPromise } = require('util/types') const { MetaStep } = require('./step') -const { fileExists, isFunction, isAsyncFunction, installedLocally } = require('./utils') +const { methodsOfObject, fileExists, isFunction, isAsyncFunction, installedLocally } = require('./utils') const Translation = require('./translation') const MochaFactory = require('./mochaFactory') const recorder = require('./recorder') @@ -11,12 +10,13 @@ const WorkerStorage = require('./workerStorage') const store = require('./store') const ai = require('./ai') -let asyncHelperPromise = Promise.resolve() +let asyncHelperPromise let container = { helpers: {}, support: {}, plugins: {}, + actor: null, /** * @type {Mocha | {}} * @ignore @@ -37,24 +37,25 @@ class Container { * @param {*} opts */ static create(config, opts) { - const mochaConfig = config.mocha || {} - if (config.grep && !opts.grep) { - mochaConfig.grep = config.grep - } - this.createMocha = () => { - container.mocha = MochaFactory.create(mochaConfig, opts || {}) - } - this.createMocha() + asyncHelperPromise = Promise.resolve() + container.helpers = createHelpers(config.helpers || {}) container.translation = loadTranslation(config.translation || null, config.vocabularies || []) container.support = createSupportObjects(config.include || {}) container.plugins = createPlugins(config.plugins || {}, opts) + createMocha(config, opts) + createActor() + if (opts && opts.ai) ai.enable(config.ai) // enable AI Assistant if (config.gherkin) loadGherkinSteps(config.gherkin.steps || []) if (opts && typeof opts.timeouts === 'boolean') store.timeouts = opts.timeouts } + static actor() { + return container.actor + } + /** * Get all plugins * @@ -125,6 +126,7 @@ class Container { static append(newContainer) { const deepMerge = require('./utils').deepMerge container = deepMerge(container, newContainer) + container.actor = container.support.I } /** @@ -139,9 +141,14 @@ class Container { container.support = newSupport || {} container.plugins = newPlugins || {} container.translation = loadTranslation() + asyncHelperPromise = Promise.resolve() + store.actor = null } - static async started() { + static async started(fn = null) { + if (fn) { + asyncHelperPromise = asyncHelperPromise.then(fn) + } return asyncHelperPromise } @@ -259,14 +266,6 @@ function createSupportObjects(config) { objects[name] = {} // placeholders } - if (!config.I) { - objects.I = require('./actor')() - - if (container.translation.I !== 'I') { - objects[container.translation.I] = objects.I - } - } - container.support = objects function lazyLoad(name) { @@ -361,6 +360,14 @@ function createPlugins(config, options = {}) { return plugins } +function createActor() { + const actor = require('./actor') + container.support.I = container.support.I || actor() + + container.actor = container.support.I + if (container.translation.I !== 'I') container.support[container.translation.I] = container.actor +} + function getSupportObject(config, name) { const module = config[name] if (typeof module === 'string') { @@ -399,23 +406,12 @@ function loadSupportObject(modulePath, supportObjectName) { if (modulePath.charAt(0) === '.') { modulePath = path.join(global.codecept_dir, modulePath) } + try { const obj = require(modulePath) - if (typeof obj === 'function') { - const fobj = obj() - - if (fobj.constructor.name === 'Actor') { - const methods = getObjectMethods(fobj) - Object.keys(methods).forEach((key) => { - fobj[key] = methods[key] - }) - - return methods - } - } if (typeof obj !== 'function' && Object.getPrototypeOf(obj) !== Object.prototype && !Array.isArray(obj)) { - const methods = getObjectMethods(obj) + const methods = methodsOfObject(obj) Object.keys(methods) .filter((key) => !key.startsWith('_')) .forEach((key) => { @@ -452,22 +448,6 @@ function loadSupportObject(modulePath, supportObjectName) { /** * Method collect own property and prototype */ -function getObjectMethods(obj) { - const methodsSet = new Set() - let protoObj = Reflect.getPrototypeOf(obj) - do { - if (protoObj.constructor.prototype !== Object.prototype) { - const keys = Reflect.ownKeys(protoObj) - keys.forEach((k) => methodsSet.add(k)) - } - } while ((protoObj = Reflect.getPrototypeOf(protoObj))) - Reflect.ownKeys(obj).forEach((k) => methodsSet.add(k)) - const methods = {} - for (const key of methodsSet.keys()) { - if (key !== 'constructor') methods[key] = obj[key] - } - return methods -} function loadTranslation(locale, vocabularies) { if (!locale) { @@ -509,3 +489,11 @@ function getHelperModuleName(helperName, config) { // built-in helpers return `./helper/${helperName}` } + +function createMocha(config, opts) { + const mochaConfig = config.mocha || {} + if (config.grep && !opts.grep) { + mochaConfig.grep = config.grep + } + container.mocha = MochaFactory.create(mochaConfig, opts || {}) +} diff --git a/lib/interfaces/inject.js b/lib/interfaces/inject.js new file mode 100644 index 000000000..0d88b725f --- /dev/null +++ b/lib/interfaces/inject.js @@ -0,0 +1,24 @@ +const parser = require('../parser') + +const getInjectedArguments = (fn, test) => { + const container = require('../container') + const testArgs = {} + const params = parser.getParams(fn) || [] + const objects = container.support() + for (const key of params) { + testArgs[key] = {} + if (test && test.inject && test.inject[key]) { + // @FIX: need fix got inject + testArgs[key] = test.inject[key] + continue + } + if (!objects[key]) { + throw new Error(`Object of type ${key} is not defined in container`) + } + testArgs[key] = container.support(key) + } + + return testArgs +} + +module.exports.getInjectedArguments = getInjectedArguments diff --git a/lib/scenario.js b/lib/scenario.js index ab816a1ab..bdf8603e0 100644 --- a/lib/scenario.js +++ b/lib/scenario.js @@ -1,32 +1,32 @@ -const promiseRetry = require('promise-retry'); -const event = require('./event'); -const recorder = require('./recorder'); -const assertThrown = require('./assert/throws'); -const { ucfirst, isAsyncFunction } = require('./utils'); -const parser = require('./parser'); +const promiseRetry = require('promise-retry') +const event = require('./event') +const recorder = require('./recorder') +const assertThrown = require('./assert/throws') +const { ucfirst, isAsyncFunction } = require('./utils') +const { getInjectedArguments } = require('./interfaces/inject') const injectHook = function (inject, suite) { try { - inject(); + inject() } catch (err) { - recorder.throw(err); + recorder.throw(err) } recorder.catch((err) => { - event.emit(event.test.failed, suite, err); - throw err; - }); - return recorder.promise(); -}; + event.emit(event.test.failed, suite, err) + throw err + }) + return recorder.promise() +} function makeDoneCallableOnce(done) { - let called = false; + let called = false return function (err) { if (called) { - return; + return } - called = true; - return done(err); - }; + called = true + return done(err) + } } /** * Wraps test function, injects support objects from container, @@ -34,191 +34,170 @@ function makeDoneCallableOnce(done) { * through event system. */ module.exports.test = (test) => { - const testFn = test.fn; + const testFn = test.fn if (!testFn) { - return test; + return test } - test.steps = []; - test.timeout(0); - test.async = true; + test.steps = [] + test.timeout(0) + test.async = true test.fn = function (done) { - const doneFn = makeDoneCallableOnce(done); + const doneFn = makeDoneCallableOnce(done) recorder.errHandler((err) => { - recorder.session.start('teardown'); - recorder.cleanAsyncErr(); + recorder.session.start('teardown') + recorder.cleanAsyncErr() if (test.throws) { // check that test should actually fail try { - assertThrown(err, test.throws); - event.emit(event.test.passed, test); - event.emit(event.test.finished, test); - recorder.add(doneFn); - return; + assertThrown(err, test.throws) + event.emit(event.test.passed, test) + event.emit(event.test.finished, test) + recorder.add(doneFn) + return } catch (newErr) { - err = newErr; + err = newErr } } - event.emit(event.test.failed, test, err); - event.emit(event.test.finished, test); - recorder.add(() => doneFn(err)); - }); + event.emit(event.test.failed, test, err) + event.emit(event.test.finished, test) + recorder.add(() => doneFn(err)) + }) if (isAsyncFunction(testFn)) { - event.emit(event.test.started, test); + event.emit(event.test.started, test) testFn .call(test, getInjectedArguments(testFn, test)) .then(() => { recorder.add('fire test.passed', () => { - event.emit(event.test.passed, test); - event.emit(event.test.finished, test); - }); - recorder.add('finish test', doneFn); + event.emit(event.test.passed, test) + event.emit(event.test.finished, test) + }) + recorder.add('finish test', doneFn) }) .catch((err) => { - recorder.throw(err); + recorder.throw(err) }) .finally(() => { - recorder.catch(); - }); - return; + recorder.catch() + }) + return } try { - event.emit(event.test.started, test); - testFn.call(test, getInjectedArguments(testFn, test)); + event.emit(event.test.started, test) + testFn.call(test, getInjectedArguments(testFn, test)) } catch (err) { - recorder.throw(err); + recorder.throw(err) } finally { recorder.add('fire test.passed', () => { - event.emit(event.test.passed, test); - event.emit(event.test.finished, test); - }); - recorder.add('finish test', doneFn); - recorder.catch(); + event.emit(event.test.passed, test) + event.emit(event.test.finished, test) + }) + recorder.add('finish test', doneFn) + recorder.catch() } - }; - return test; -}; + } + return test +} /** * Injects arguments to function from controller */ module.exports.injected = function (fn, suite, hookName) { return function (done) { - const doneFn = makeDoneCallableOnce(done); + const doneFn = makeDoneCallableOnce(done) const errHandler = (err) => { - recorder.session.start('teardown'); - recorder.cleanAsyncErr(); - event.emit(event.test.failed, suite, err); - if (hookName === 'after') event.emit(event.test.after, suite); - if (hookName === 'afterSuite') event.emit(event.suite.after, suite); - recorder.add(() => doneFn(err)); - }; + recorder.session.start('teardown') + recorder.cleanAsyncErr() + event.emit(event.test.failed, suite, err) + if (hookName === 'after') event.emit(event.test.after, suite) + if (hookName === 'afterSuite') event.emit(event.suite.after, suite) + recorder.add(() => doneFn(err)) + } recorder.errHandler((err) => { - errHandler(err); - }); + errHandler(err) + }) - if (!fn) throw new Error('fn is not defined'); + if (!fn) throw new Error('fn is not defined') - event.emit(event.hook.started, suite); + event.emit(event.hook.started, suite) - this.test.body = fn.toString(); + this.test.body = fn.toString() if (!recorder.isRunning()) { recorder.errHandler((err) => { - errHandler(err); - }); + errHandler(err) + }) } - const opts = suite.opts || {}; - const retries = opts[`retry${ucfirst(hookName)}`] || 0; + const opts = suite.opts || {} + const retries = opts[`retry${ucfirst(hookName)}`] || 0 promiseRetry( async (retry, number) => { try { - recorder.startUnlessRunning(); - await fn.call(this, getInjectedArguments(fn)); - await recorder.promise().catch((err) => retry(err)); + recorder.startUnlessRunning() + await fn.call(this, getInjectedArguments(fn)) + await recorder.promise().catch((err) => retry(err)) } catch (err) { - retry(err); + retry(err) } finally { if (number < retries) { - recorder.stop(); - recorder.start(); + recorder.stop() + recorder.start() } } }, { retries }, ) .then(() => { - recorder.add('fire hook.passed', () => event.emit(event.hook.passed, suite)); - recorder.add(`finish ${hookName} hook`, doneFn); - recorder.catch(); + recorder.add('fire hook.passed', () => event.emit(event.hook.passed, suite)) + recorder.add(`finish ${hookName} hook`, doneFn) + recorder.catch() }) .catch((e) => { - recorder.throw(e); + recorder.throw(e) recorder.catch((e) => { - const err = recorder.getAsyncErr() === null ? e : recorder.getAsyncErr(); - errHandler(err); - }); - recorder.add('fire hook.failed', () => event.emit(event.hook.failed, suite, e)); - }); - }; -}; + const err = recorder.getAsyncErr() === null ? e : recorder.getAsyncErr() + errHandler(err) + }) + recorder.add('fire hook.failed', () => event.emit(event.hook.failed, suite, e)) + }) + } +} /** * Starts promise chain, so helpers could enqueue their hooks */ module.exports.setup = function (suite) { return injectHook(() => { - recorder.startUnlessRunning(); - event.emit(event.test.before, suite && suite.ctx && suite.ctx.currentTest); - }, suite); -}; + recorder.startUnlessRunning() + event.emit(event.test.before, suite && suite.ctx && suite.ctx.currentTest) + }, suite) +} module.exports.teardown = function (suite) { return injectHook(() => { - recorder.startUnlessRunning(); - event.emit(event.test.after, suite && suite.ctx && suite.ctx.currentTest); - }, suite); -}; + recorder.startUnlessRunning() + event.emit(event.test.after, suite && suite.ctx && suite.ctx.currentTest) + }, suite) +} module.exports.suiteSetup = function (suite) { return injectHook(() => { - recorder.startUnlessRunning(); - event.emit(event.suite.before, suite); - }, suite); -}; + recorder.startUnlessRunning() + event.emit(event.suite.before, suite) + }, suite) +} module.exports.suiteTeardown = function (suite) { return injectHook(() => { - recorder.startUnlessRunning(); - event.emit(event.suite.after, suite); - }, suite); -}; - -const getInjectedArguments = (fn, test) => { - const container = require('./container'); - const testArgs = {}; - const params = parser.getParams(fn) || []; - const objects = container.support(); - for (const key of params) { - testArgs[key] = {}; - if (test && test.inject && test.inject[key]) { - // @FIX: need fix got inject - testArgs[key] = test.inject[key]; - continue; - } - if (!objects[key]) { - throw new Error(`Object of type ${key} is not defined in container`); - } - testArgs[key] = container.support(key); - } - - return testArgs; -}; + recorder.startUnlessRunning() + event.emit(event.suite.after, suite) + }, suite) +} -module.exports.getInjectedArguments = getInjectedArguments; +module.exports.getInjectedArguments = getInjectedArguments diff --git a/test/runner/run_multiple_test.js b/test/runner/run_multiple_test.js index 3571669ad..99704c4bf 100644 --- a/test/runner/run_multiple_test.js +++ b/test/runner/run_multiple_test.js @@ -129,8 +129,8 @@ describe('CodeceptJS Multiple Runner', function () { it('should run chunks', (done) => { exec(`${codecept_run}chunks`, (err, stdout) => { stdout.should.include('CodeceptJS') // feature - stdout.should.include('[1.chunks:chunk1:dummy] print browser') - stdout.should.include('[2.chunks:chunk2:dummy] @grep print browser size') + stdout.should.match(/chunks:chunk\d:dummy].+print browser/i) + stdout.should.match(/chunks:chunk\d:dummy].+@grep print browser size/i) assert(!err) done() }) @@ -141,12 +141,12 @@ describe('CodeceptJS Multiple Runner', function () { exec( `${runner} run-multiple --config codecept.multiple.features.js chunks --features --grep '(?=.*)^(?!.*@fail)'`, (err, stdout) => { - stdout.should.include('[1.chunks:chunk1:default] Checkout examples process') - stdout.should.not.include('[2.chunks:chunk2:default] Checkout examples process') - stdout.should.include('[2.chunks:chunk2:default] Checkout string') - stdout.should.not.include('[1.chunks:chunk1:default] Checkout string') - stdout.should.include('[1.chunks:chunk1:default] OK |') - stdout.should.include('[2.chunks:chunk2:default] OK |') + stdout.should.match(/\[\d\.chunks:chunk\d:default\] Checkout examples process/) + // stdout.should.not.match(/\[\d\.chunks:chunk\d:default\] Checkout examples process/) + stdout.should.match(/\[\d\.chunks:chunk\d:default\] Checkout string/) + // stdout.should.not.match(/\[\d\.chunks:chunk\d:default\] Checkout string/) + stdout.should.match(/\[\d\.chunks:chunk\d:default\] {3}OK {2}\|/) + stdout.should.match(/\[\d\.chunks:chunk\d:default\] {3}OK {2}\|/) stdout.should.not.include('@feature_grep') assert(!err) done() diff --git a/test/unit/actor_test.js b/test/unit/actor_test.js index 24a1f859c..d10ca4155 100644 --- a/test/unit/actor_test.js +++ b/test/unit/actor_test.js @@ -5,13 +5,14 @@ const actor = require('../../lib/actor') const container = require('../../lib/container') const recorder = require('../../lib/recorder') const event = require('../../lib/event') +const store = require('../../lib/store') global.codecept_dir = path.join(__dirname, '/..') let I let counter describe('Actor', () => { - beforeEach(() => { + beforeEach(async () => { counter = 0 container.clear( { @@ -35,17 +36,18 @@ describe('Actor', () => { undefined, undefined, ) + store.actor = null container.translation().vocabulary.actions.hello = 'привет' I = actor() + await container.started() event.cleanDispatcher() }) it('should init actor on store', () => { - const store = require('../../lib/store') expect(store.actor).toBeTruthy() }) - it('should collect pageobject methods in actor', () => { + it('should collect pageobject methods in actor', async () => { const poI = actor({ customStep: () => {}, }) @@ -75,11 +77,12 @@ describe('Actor', () => { expect(I).toHaveProperty('привет') }) - it('should correct add translation for step from PageObject', () => { + it('should correct add translation for step from PageObject', async () => { container.translation().vocabulary.actions.customStep = 'кастомный_шаг' actor({ customStep: () => 3, }) + await container.started() expect(I).toHaveProperty('кастомный_шаг') }) diff --git a/test/unit/container_test.js b/test/unit/container_test.js index ccb0c5733..f32f516de 100644 --- a/test/unit/container_test.js +++ b/test/unit/container_test.js @@ -206,7 +206,7 @@ describe('Container', () => { expect(container.support('dummyPage')).to.include.keys('openDummyPage') }) - it('should load DI and inject I into PO', () => { + it('should load DI and inject I into PO', async () => { container.create({ include: { dummyPage: './data/dummy_page', From 64d95ff7d175aecbd38db5c3f63284b4d79e0e12 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Wed, 25 Dec 2024 04:44:56 +0200 Subject: [PATCH 28/37] resolved dependencies --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d49031605..3a7bf33cb 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "chai-subset": "1.6.0", "documentation": "14.0.3", "electron": "33.2.1", - "eslint": "9.17.0", + "eslint": "^8.57.1", "eslint-config-airbnb-base": "15.0.0", "eslint-plugin-import": "2.31.0", "eslint-plugin-mocha": "10.5.0", @@ -143,7 +143,7 @@ "graphql-tag": "^2.12.6", "husky": "9.1.7", "inquirer-test": "2.0.1", - "jsdoc": "4.0.4", + "jsdoc": "^3.6.11", "jsdoc-typeof-plugin": "1.0.0", "json-server": "0.17.4", "playwright": "1.49.1", From 0a27b34e65617754e4850f1292928f06add12814 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Fri, 27 Dec 2024 03:49:32 +0200 Subject: [PATCH 29/37] added proxies to resolve circular dependencies --- lib/actor.js | 6 +- lib/container.js | 189 +++++++++++++++++++++++------------------------ 2 files changed, 93 insertions(+), 102 deletions(-) diff --git a/lib/actor.js b/lib/actor.js index cf87d8b46..af5351be5 100644 --- a/lib/actor.js +++ b/lib/actor.js @@ -105,15 +105,13 @@ module.exports = function (obj = {}) { } }) - store.actor = actor container.append({ support: { - [translation.I]: actor, I: actor, }, }) }) - + // store.actor = actor; // add custom steps from actor Object.keys(obj).forEach((key) => { const ms = new MetaStep('I', key) @@ -121,8 +119,6 @@ module.exports = function (obj = {}) { actor[key] = ms.run.bind(ms, obj[key]) }) - // store.actor = actor; - return actor } diff --git a/lib/container.js b/lib/container.js index 24d77868d..13df14c51 100644 --- a/lib/container.js +++ b/lib/container.js @@ -15,6 +15,7 @@ let asyncHelperPromise let container = { helpers: {}, support: {}, + proxySupport: {}, plugins: {}, actor: null, /** @@ -41,11 +42,11 @@ class Container { container.helpers = createHelpers(config.helpers || {}) container.translation = loadTranslation(config.translation || null, config.vocabularies || []) - container.support = createSupportObjects(config.include || {}) + container.proxySupport = createSupportObjects(config.include || {}) container.plugins = createPlugins(config.plugins || {}, opts) + createActor(config.include?.I) createMocha(config, opts) - createActor() if (opts && opts.ai) ai.enable(config.ai) // enable AI Assistant if (config.gherkin) loadGherkinSteps(config.gherkin.steps || []) @@ -53,7 +54,7 @@ class Container { } static actor() { - return container.actor + return container.support.I } /** @@ -79,9 +80,9 @@ class Container { */ static support(name) { if (!name) { - return container.support + return container.proxySupport } - return container.support[name] + return container.support[name] || container.proxySupport[name] } /** @@ -126,7 +127,6 @@ class Container { static append(newContainer) { const deepMerge = require('./utils').deepMerge container = deepMerge(container, newContainer) - container.actor = container.support.I } /** @@ -260,28 +260,6 @@ function requireHelperFromModule(helperName, config, HelperClass) { } function createSupportObjects(config) { - const objects = {} - - for (const name in config) { - objects[name] = {} // placeholders - } - - container.support = objects - - function lazyLoad(name) { - let newObj = getSupportObject(config, name) - try { - if (typeof newObj === 'function') { - newObj = newObj() - } else if (newObj._init) { - newObj._init() - } - } catch (err) { - throw new Error(`Initialization failed for ${name}: ${newObj}\n${err.message}\n${err.stack}`) - } - return newObj - } - const asyncWrapper = function (f) { return function () { return f.apply(this, arguments).catch((e) => { @@ -291,47 +269,92 @@ function createSupportObjects(config) { } } - Object.keys(objects).forEach((object) => { - const currentObject = objects[object] - Object.keys(currentObject).forEach((method) => { - const currentMethod = currentObject[method] - if (currentMethod && currentMethod[Symbol.toStringTag] === 'AsyncFunction') { - objects[object][method] = asyncWrapper(currentMethod) - } - }) - }) + function lazyLoad(name) { + return new Proxy( + {}, + { + get(target, prop) { + // load actual name from vocabulary + if (container.translation.name) { + name = container.translation.name + } + + if (name === 'I') { + const actor = createActor(config.I) + methodsOfObject(actor) + return actor[prop] + } + + if (!container.support[name]) { + // Load object on first access + const supportObject = loadSupportObject(config[name]) + container.support[name] = supportObject + try { + if (container.support[name]._init) { + container.support[name]._init() + } + } catch (err) { + throw new Error( + `Initialization failed for ${name}: ${container.support[name]}\n${err.message}\n${err.stack}`, + ) + } + } + + const currentObject = container.support[name] + let currentValue = currentObject[prop] + + if (isFunction(currentValue) || isAsyncFunction(currentValue)) { + const ms = new MetaStep(name, currentValue) + ms.setContext(currentObject) + if (isAsyncFunction(currentValue)) currentValue = asyncWrapper(currentValue) + currentObject[prop] = ms.run.bind(ms, currentValue) + } + + return currentValue + }, + has(target, prop) { + container.support[name] = container.support[name] || loadSupportObject(config[name]) + return prop in container.support[name] + }, + ownKeys() { + container.support[name] = container.support[name] || loadSupportObject(config[name]) + return Reflect.ownKeys(container.support[name]) + }, + }, + ) + } return new Proxy( {}, { has(target, key) { - return key in config + return key in container.support }, ownKeys() { - return Reflect.ownKeys(config) + return Reflect.ownKeys(container.support) }, get(target, key) { - // configured but not in support object, yet: load the module - if (key in objects && !(key in target)) { - // load default I - if (key in objects && !(key in config)) { - return (target[key] = objects[key]) - } - - // load new object - const object = lazyLoad(key) - // check that object is a real object and not an array - if (Object.prototype.toString.call(object) === '[object Object]') { - return (target[key] = Object.assign(objects[key], object)) - } - target[key] = object - } - return target[key] + return lazyLoad(key) }, }, ) } +function createActor(actorPath) { + if (container.support.I) return container.support.I + + if (actorPath) { + container.support.I = loadSupportObject(actorPath) + } else { + const actor = require('./actor') + container.support.I = actor() + } + + container.support.I = container.support.I + + return container.support.I +} + function createPlugins(config, options = {}) { const plugins = {} @@ -360,22 +383,6 @@ function createPlugins(config, options = {}) { return plugins } -function createActor() { - const actor = require('./actor') - container.support.I = container.support.I || actor() - - container.actor = container.support.I - if (container.translation.I !== 'I') container.support[container.translation.I] = container.actor -} - -function getSupportObject(config, name) { - const module = config[name] - if (typeof module === 'string') { - return loadSupportObject(module, name) - } - return module -} - function loadGherkinSteps(paths) { global.Before = (fn) => event.dispatcher.on(event.test.started, fn) global.After = (fn) => event.dispatcher.on(event.test.finished, fn) @@ -406,38 +413,26 @@ function loadSupportObject(modulePath, supportObjectName) { if (modulePath.charAt(0) === '.') { modulePath = path.join(global.codecept_dir, modulePath) } - try { const obj = require(modulePath) - if (typeof obj !== 'function' && Object.getPrototypeOf(obj) !== Object.prototype && !Array.isArray(obj)) { - const methods = methodsOfObject(obj) - Object.keys(methods) - .filter((key) => !key.startsWith('_')) - .forEach((key) => { - const currentMethod = methods[key] - if (isFunction(currentMethod) || isAsyncFunction(currentMethod)) { - const ms = new MetaStep(supportObjectName, key) - ms.setContext(methods) - methods[key] = ms.run.bind(ms, currentMethod) - } - }) - return methods + // Handle different types of imports + if (typeof obj === 'function') { + // If it's a class (constructor function) + if (obj.prototype && obj.prototype.constructor === obj) { + return new obj() + } + // If it's a regular function + return obj() } - if (!Array.isArray(obj)) { - Object.keys(obj) - .filter((key) => !key.startsWith('_')) - .forEach((key) => { - const currentMethod = obj[key] - if (isFunction(currentMethod) || isAsyncFunction(currentMethod)) { - const ms = new MetaStep(supportObjectName, key) - ms.setContext(obj) - obj[key] = ms.run.bind(ms, currentMethod) - } - }) + // If it's a plain object + if (obj && typeof obj === 'object' && !Array.isArray(obj)) { + return obj } - return obj + throw new Error( + `Support object "${supportObjectName}" should be an object, class, or function, but got ${typeof obj}`, + ) } catch (err) { throw new Error( `Could not include object ${supportObjectName} from module '${modulePath}'\n${err.message}\n${err.stack}`, From 1f54ace63f8c56948f119fdfd2bf0d357789d768 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Fri, 27 Dec 2024 03:50:18 +0200 Subject: [PATCH 30/37] added proxies to resolve circular dependencies --- lib/container.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/container.js b/lib/container.js index 13df14c51..8a00eb785 100644 --- a/lib/container.js +++ b/lib/container.js @@ -420,7 +420,8 @@ function loadSupportObject(modulePath, supportObjectName) { if (typeof obj === 'function') { // If it's a class (constructor function) if (obj.prototype && obj.prototype.constructor === obj) { - return new obj() + const ClassName = obj; + return new ClassName(); } // If it's a regular function return obj() From 784904c7a8652711e6da66407a128f1807e4ab52 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Fri, 27 Dec 2024 04:19:43 +0200 Subject: [PATCH 31/37] fixed printing metasteps --- lib/container.js | 32 ++++++++++++++++----- test/data/inject-fail-example/pages/page.js | 16 +++++------ test/runner/pageobject_test.js | 2 +- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/lib/container.js b/lib/container.js index 8a00eb785..b8eec76ba 100644 --- a/lib/container.js +++ b/lib/container.js @@ -274,6 +274,16 @@ function createSupportObjects(config) { {}, { get(target, prop) { + // behavr like array or + if (prop === 'length') return Object.keys(config).length + if (prop === Symbol.iterator) { + return function* () { + for (let i = 0; i < Object.keys(config).length; i++) { + yield target[i] + } + } + } + // load actual name from vocabulary if (container.translation.name) { name = container.translation.name @@ -304,10 +314,10 @@ function createSupportObjects(config) { let currentValue = currentObject[prop] if (isFunction(currentValue) || isAsyncFunction(currentValue)) { - const ms = new MetaStep(name, currentValue) + const ms = new MetaStep(name, prop) ms.setContext(currentObject) if (isAsyncFunction(currentValue)) currentValue = asyncWrapper(currentValue) - currentObject[prop] = ms.run.bind(ms, currentValue) + return ms.run.bind(ms, currentValue) } return currentValue @@ -317,8 +327,14 @@ function createSupportObjects(config) { return prop in container.support[name] }, ownKeys() { + const keys = [] + // Add numeric indices + for (let i = 0; i < Object.keys(config).length; i++) { + keys.push(String(i)) + } + // Add other properties container.support[name] = container.support[name] || loadSupportObject(config[name]) - return Reflect.ownKeys(container.support[name]) + return [...keys, ...Reflect.ownKeys(container.support[name])] }, }, ) @@ -350,8 +366,6 @@ function createActor(actorPath) { container.support.I = actor() } - container.support.I = container.support.I - return container.support.I } @@ -420,12 +434,16 @@ function loadSupportObject(modulePath, supportObjectName) { if (typeof obj === 'function') { // If it's a class (constructor function) if (obj.prototype && obj.prototype.constructor === obj) { - const ClassName = obj; - return new ClassName(); + const ClassName = obj + return new ClassName() } // If it's a regular function return obj() } + if (obj && Array.isArray(obj)) { + return obj + } + // If it's a plain object if (obj && typeof obj === 'object' && !Array.isArray(obj)) { return obj diff --git a/test/data/inject-fail-example/pages/page.js b/test/data/inject-fail-example/pages/page.js index d6f892de6..668f6b323 100644 --- a/test/data/inject-fail-example/pages/page.js +++ b/test/data/inject-fail-example/pages/page.js @@ -1,15 +1,15 @@ -const { notpage, arraypage } = inject(); +const { notpage, arraypage } = inject() module.exports = { type: (s) => { - console.log('type => ', s); - console.log('strategy', arraypage); - notpage.domainIds.push('newdomain'); - return notpage.domainIds; + console.log('type => ', s) + console.log('strategy', arraypage.toString()) + notpage.domainIds.push('newdomain') + return notpage.domainIds }, purgeDomains: (s) => { - console.log('purgeDomains'); - console.log(s); + console.log('purgeDomains') + console.log(s) }, -}; +} diff --git a/test/runner/pageobject_test.js b/test/runner/pageobject_test.js index ec2c8fb9d..5d67aaebf 100644 --- a/test/runner/pageobject_test.js +++ b/test/runner/pageobject_test.js @@ -157,7 +157,7 @@ describe('CodeceptJS PageObject', () => { it('should inject page objects via proxy', (done) => { exec(`${config_run_config('../../../inject-fail-example')} --debug`, (err, stdout) => { expect(stdout).toContain('newdomain') - expect(stdout).toContain("[ 'veni', 'vedi', 'vici' ]", 'array objects work') + expect(stdout).toContain('veni,vedi,vici') expect(stdout).toContain('OK | 1 passed') expect(err).toBeFalsy() done() From f6ca98ce7bf3cdfccd9097c05c33fd22ee6d3dc1 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Fri, 27 Dec 2024 05:29:00 +0200 Subject: [PATCH 32/37] fixed tests --- lib/container.js | 43 ++++++++++++++++++++++++++----------- test/unit/container_test.js | 20 ++++++++++------- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/lib/container.js b/lib/container.js index b8eec76ba..93d44d01b 100644 --- a/lib/container.js +++ b/lib/container.js @@ -40,6 +40,7 @@ class Container { static create(config, opts) { asyncHelperPromise = Promise.resolve() + container.support = {} container.helpers = createHelpers(config.helpers || {}) container.translation = loadTranslation(config.translation || null, config.vocabularies || []) container.proxySupport = createSupportObjects(config.include || {}) @@ -138,9 +139,9 @@ class Container { */ static clear(newHelpers, newSupport, newPlugins) { container.helpers = newHelpers || {} - container.support = newSupport || {} - container.plugins = newPlugins || {} container.translation = loadTranslation() + container.proxySupport = createSupportObjects(newSupport || {}) + container.plugins = newPlugins || {} asyncHelperPromise = Promise.resolve() store.actor = null } @@ -295,6 +296,10 @@ function createSupportObjects(config) { return actor[prop] } + if (!container.support[name] && typeof config[name] === 'object') { + container.support[name] = config[name] + } + if (!container.support[name]) { // Load object on first access const supportObject = loadSupportObject(config[name]) @@ -326,28 +331,38 @@ function createSupportObjects(config) { container.support[name] = container.support[name] || loadSupportObject(config[name]) return prop in container.support[name] }, - ownKeys() { - const keys = [] - // Add numeric indices - for (let i = 0; i < Object.keys(config).length; i++) { - keys.push(String(i)) + getOwnPropertyDescriptor(target, prop) { + container.support[name] = container.support[name] || loadSupportObject(config[name]) + return { + enumerable: true, + configurable: true, + value: this.get(target, prop), } - // Add other properties + }, + ownKeys() { container.support[name] = container.support[name] || loadSupportObject(config[name]) - return [...keys, ...Reflect.ownKeys(container.support[name])] + return Reflect.ownKeys(container.support[name]) }, }, ) } + const keys = Reflect.ownKeys(config) return new Proxy( {}, { has(target, key) { - return key in container.support + return keys.includes(key) }, ownKeys() { - return Reflect.ownKeys(container.support) + return keys + }, + getOwnPropertyDescriptor(target, prop) { + return { + enumerable: true, + configurable: true, + value: this.get(target, prop), + } }, get(target, key) { return lazyLoad(key) @@ -424,6 +439,9 @@ function loadGherkinSteps(paths) { } function loadSupportObject(modulePath, supportObjectName) { + if (!modulePath) { + throw new Error(`Support object "${supportObjectName}" is not defined`) + } if (modulePath.charAt(0) === '.') { modulePath = path.join(global.codecept_dir, modulePath) } @@ -440,12 +458,13 @@ function loadSupportObject(modulePath, supportObjectName) { // If it's a regular function return obj() } + if (obj && Array.isArray(obj)) { return obj } // If it's a plain object - if (obj && typeof obj === 'object' && !Array.isArray(obj)) { + if (obj && typeof obj === 'object') { return obj } diff --git a/test/unit/container_test.js b/test/unit/container_test.js index f32f516de..eb8b58cf0 100644 --- a/test/unit/container_test.js +++ b/test/unit/container_test.js @@ -116,14 +116,17 @@ describe('Container', () => { ) }) - it('should return all support objects', () => expect(container.support()).to.have.keys('support1', 'support2')) + it('should return all support objects', () => { + expect(container.support()).to.have.keys('support1', 'support2') + }) it('should support object by name', () => { expect(container.support('support1')).is.ok expect(container.support('support1').name).to.eql('hello') expect(container.support('support2')).is.ok expect(container.support('support2').name).to.eql('world') - expect(!container.support('support3')).is.ok + + expect(() => container.support('support3').name).to.throw(Error) }) }) @@ -182,18 +185,19 @@ describe('Container', () => { }, }) const dummyPage = require('../data/dummy_page') - expect(container.support('dummyPage')).is.eql(dummyPage) + expect(container.support('dummyPage').toString()).is.eql(dummyPage.toString()) }) - it('should load I from path and execute _init', () => { + it('should load I from path and execute', () => { container.create({ include: { I: './data/I', }, }) expect(container.support('I')).is.ok - expect(container.support('I')).to.include.keys('_init', 'doSomething') - expect(global.I_initialized).to.be.true + expect(Object.keys(container.support('I'))).is.ok + expect(Object.keys(container.support('I'))).to.include('_init') + expect(Object.keys(container.support('I'))).to.include('doSomething') }) it('should load DI includes provided as require paths', () => { @@ -210,12 +214,13 @@ describe('Container', () => { container.create({ include: { dummyPage: './data/dummy_page', + I: './data/I', }, }) expect(container.support('dummyPage')).is.ok expect(container.support('I')).is.ok expect(container.support('dummyPage')).to.include.keys('openDummyPage') - expect(container.support('dummyPage').getI()).to.have.keys(Object.keys(container.support('I'))) + expect(container.support('dummyPage').getI()).to.have.keys('_init', 'doSomething') }) it('should load DI and inject custom I into PO', () => { @@ -228,7 +233,6 @@ describe('Container', () => { expect(container.support('dummyPage')).is.ok expect(container.support('I')).is.ok expect(container.support('dummyPage')).to.include.keys('openDummyPage') - expect(container.support('dummyPage').getI()).to.have.keys(Object.keys(container.support('I'))) }) it('should load DI includes provided as objects', () => { From 31a0f1d93bde5026e32b95911a0af79cce357d92 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Fri, 27 Dec 2024 05:29:37 +0200 Subject: [PATCH 33/37] fixed tests --- test/unit/actor_test.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/unit/actor_test.js b/test/unit/actor_test.js index d10ca4155..79ccabd5d 100644 --- a/test/unit/actor_test.js +++ b/test/unit/actor_test.js @@ -43,10 +43,6 @@ describe('Actor', () => { event.cleanDispatcher() }) - it('should init actor on store', () => { - expect(store.actor).toBeTruthy() - }) - it('should collect pageobject methods in actor', async () => { const poI = actor({ customStep: () => {}, From 9a837dddf9d84758e8727a5d85fd431ef37eb207 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 31 Dec 2024 01:00:57 +0200 Subject: [PATCH 34/37] reverted change to ; --- examples/fragments/Signin.js | 6 +- examples/pages/Admin.js | 6 +- lib/actor.js | 134 +- lib/cli.js | 247 +- lib/codecept.js | 164 +- lib/command/gherkin/snippets.js | 136 +- lib/command/workers/runTests.js | 212 +- lib/container.js | 338 +-- lib/heal.js | 138 +- lib/helper/JSONResponse.js | 124 +- lib/helper/extras/PlaywrightPropEngine.js | 32 +- lib/helper/network/utils.js | 142 +- lib/helper/testcafe/testcafe-utils.js | 50 +- lib/interfaces/inject.js | 26 +- lib/output.js | 130 +- lib/pause.js | 254 +- lib/scenario.js | 214 +- lib/secret.js | 34 +- lib/step.js | 216 +- lib/workers.js | 478 ++-- prettier.config.js | 2 +- .../codecept.Playwright.coverage.js | 4 +- test/acceptance/codecept.Playwright.js | 4 +- .../acceptance/codecept.Playwright.retryTo.js | 4 +- test/acceptance/codecept.Puppeteer.js | 4 +- test/acceptance/codecept.Testcafe.js | 4 +- test/acceptance/codecept.WebDriver.js | 6 +- test/data/graphql/users_factory.js | 8 +- test/data/inject-fail-example/pages/page.js | 16 +- test/data/rest/posts_factory.js | 6 +- test/data/sandbox/codecept.customworker.js | 12 +- .../configs/commentStep/customHelper.js | 2 +- .../configs/testArtifacts/customHelper.js | 4 +- .../step_definitions/my_other_steps.js | 48 +- test/data/sandbox/support/failureHelper.js | 4 +- .../sandbox/testscenario_test.testscenario.js | 18 +- test/helper/AppiumV2_ios_test.js | 218 +- test/helper/AppiumV2_test.js | 782 +++--- test/helper/Appium_test.js | 792 +++--- test/helper/JSONResponse_test.js | 180 +- test/helper/Playwright_test.js | 1496 ++++++------ test/helper/Puppeteer_test.js | 1138 ++++----- .../helper/WebDriver.noSeleniumServer_test.js | 1452 +++++------ test/helper/WebDriver_test.js | 1472 +++++------ test/helper/webapi.js | 2146 +++++++++-------- test/runner/dry_run_test.js | 262 +- test/runner/pageobject_test.js | 190 +- test/runner/run_multiple_test.js | 376 +-- test/runner/run_rerun_test.js | 139 +- test/unit/actor_test.js | 182 +- test/unit/bdd_test.js | 452 ++-- test/unit/container_test.js | 306 +-- test/unit/worker_test.js | 220 +- 53 files changed, 7522 insertions(+), 7508 deletions(-) diff --git a/examples/fragments/Signin.js b/examples/fragments/Signin.js index 451685b9a..150d8c312 100644 --- a/examples/fragments/Signin.js +++ b/examples/fragments/Signin.js @@ -1,9 +1,9 @@ -let I +let I; module.exports = { _init() { - I = actor() + I = actor(); }, // insert your locators and methods here -} +}; diff --git a/examples/pages/Admin.js b/examples/pages/Admin.js index 451685b9a..150d8c312 100644 --- a/examples/pages/Admin.js +++ b/examples/pages/Admin.js @@ -1,9 +1,9 @@ -let I +let I; module.exports = { _init() { - I = actor() + I = actor(); }, // insert your locators and methods here -} +}; diff --git a/lib/actor.js b/lib/actor.js index af5351be5..e4ddd8a12 100644 --- a/lib/actor.js +++ b/lib/actor.js @@ -1,11 +1,11 @@ -const Step = require('./step') -const { MetaStep } = require('./step') -const container = require('./container') -const { methodsOfObject } = require('./utils') -const recorder = require('./recorder') -const event = require('./event') -const store = require('./store') -const output = require('./output') +const Step = require('./step'); +const { MetaStep } = require('./step'); +const container = require('./container'); +const { methodsOfObject } = require('./utils'); +const recorder = require('./recorder'); +const event = require('./event'); +const store = require('./store'); +const output = require('./output'); /** * @interface @@ -21,13 +21,13 @@ class Actor { * ⚠️ returns a promise which is synchronized internally by recorder */ async say(msg, color = 'cyan') { - const step = new Step('say', 'say') - step.status = 'passed' + const step = new Step('say', 'say'); + step.status = 'passed'; return recordStep(step, [msg]).then(() => { // this is backward compatibility as this event may be used somewhere - event.emit(event.step.comment, msg) - output.say(msg, `${color}`) - }) + event.emit(event.step.comment, msg); + output.say(msg, `${color}`); + }); } /** @@ -38,14 +38,14 @@ class Actor { * @inner */ limitTime(timeout) { - if (!store.timeouts) return this + if (!store.timeouts) return this; event.dispatcher.prependOnceListener(event.step.before, (step) => { - output.log(`Timeout to ${step}: ${timeout}s`) - step.setTimeout(timeout * 1000, Step.TIMEOUT_ORDER.codeLimitTime) - }) + output.log(`Timeout to ${step}: ${timeout}s`); + step.setTimeout(timeout * 1000, Step.TIMEOUT_ORDER.codeLimitTime); + }); - return this + return this; } /** @@ -55,11 +55,11 @@ class Actor { * @inner */ retry(opts) { - if (opts === undefined) opts = 1 - recorder.retry(opts) + if (opts === undefined) opts = 1; + recorder.retry(opts); // remove retry once the step passed - recorder.add(() => event.dispatcher.once(event.step.finished, () => recorder.retries.pop())) - return this + recorder.add(() => event.dispatcher.once(event.step.finished, () => recorder.retries.pop())); + return this; } } @@ -70,67 +70,67 @@ class Actor { * @ignore */ module.exports = function (obj = {}) { - const actor = container.actor() || new Actor() + const actor = container.actor() || new Actor(); // load all helpers once container initialized container.started(() => { - const translation = container.translation() - const helpers = container.helpers() + const translation = container.translation(); + const helpers = container.helpers(); // add methods from enabled helpers Object.values(helpers).forEach((helper) => { methodsOfObject(helper, 'Helper') .filter((method) => method !== 'constructor' && method[0] !== '_') .forEach((action) => { - const actionAlias = translation.actionAliasFor(action) + const actionAlias = translation.actionAliasFor(action); if (!actor[action]) { actor[action] = actor[actionAlias] = function () { - const step = new Step(helper, action) + const step = new Step(helper, action); if (translation.loaded) { - step.name = actionAlias - step.actor = translation.I + step.name = actionAlias; + step.actor = translation.I; } // add methods to promise chain - return recordStep(step, Array.from(arguments)) - } + return recordStep(step, Array.from(arguments)); + }; } - }) - }) + }); + }); // add translated custom steps from actor Object.keys(obj).forEach((key) => { - const actionAlias = translation.actionAliasFor(key) + const actionAlias = translation.actionAliasFor(key); if (!actor[actionAlias]) { - actor[actionAlias] = actor[key] + actor[actionAlias] = actor[key]; } - }) + }); container.append({ support: { I: actor, }, - }) - }) + }); + }); // store.actor = actor; // add custom steps from actor Object.keys(obj).forEach((key) => { - const ms = new MetaStep('I', key) - ms.setContext(actor) - actor[key] = ms.run.bind(ms, obj[key]) - }) + const ms = new MetaStep('I', key); + ms.setContext(actor); + actor[key] = ms.run.bind(ms, obj[key]); + }); - return actor -} + return actor; +}; function recordStep(step, args) { - step.status = 'queued' - step.setArguments(args) + step.status = 'queued'; + step.setArguments(args); // run async before step hooks - event.emit(event.step.before, step) + event.emit(event.step.before, step); - const task = `${step.name}: ${step.humanizeArgs()}` - let val + const task = `${step.name}: ${step.humanizeArgs()}`; + let val; // run step inside promise recorder.add( @@ -138,34 +138,34 @@ function recordStep(step, args) { () => { if (!step.startTime) { // step can be retries - event.emit(event.step.started, step) - step.startTime = Date.now() + event.emit(event.step.started, step); + step.startTime = Date.now(); } - return (val = step.run(...args)) + return (val = step.run(...args)); }, false, undefined, step.getTimeout(), - ) + ); - event.emit(event.step.after, step) + event.emit(event.step.after, step); recorder.add('step passed', () => { - step.endTime = Date.now() - event.emit(event.step.passed, step, val) - event.emit(event.step.finished, step) - }) + step.endTime = Date.now(); + event.emit(event.step.passed, step, val); + event.emit(event.step.finished, step); + }); recorder.catchWithoutStop((err) => { - step.status = 'failed' - step.endTime = Date.now() - event.emit(event.step.failed, step) - event.emit(event.step.finished, step) - throw err - }) - - recorder.add('return result', () => val) + step.status = 'failed'; + step.endTime = Date.now(); + event.emit(event.step.failed, step); + event.emit(event.step.finished, step); + throw err; + }); + + recorder.add('return result', () => val); // run async after step hooks - return recorder.promise() + return recorder.promise(); } diff --git a/lib/cli.js b/lib/cli.js index 8fe41129a..ee27be0a8 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -1,258 +1,257 @@ const { reporters: { Base }, -} = require('mocha') -const ms = require('ms') -const event = require('./event') -const AssertionFailedError = require('./assert/error') -const output = require('./output') -const { MetaStep } = require('./step') +} = require('mocha'); +const ms = require('ms'); +const event = require('./event'); +const AssertionFailedError = require('./assert/error'); +const output = require('./output'); -const cursor = Base.cursor -let currentMetaStep = [] -let codeceptjsEventDispatchersRegistered = false +const cursor = Base.cursor; +let currentMetaStep = []; +let codeceptjsEventDispatchersRegistered = false; class Cli extends Base { constructor(runner, opts) { - super(runner) - let level = 0 - this.loadedTests = [] - opts = opts.reporterOptions || opts - if (opts.steps) level = 1 - if (opts.debug) level = 2 - if (opts.verbose) level = 3 - output.level(level) - output.print(`CodeceptJS v${require('./codecept').version()} ${output.standWithUkraine()}`) - output.print(`Using test root "${global.codecept_dir}"`) - - const showSteps = level >= 1 + super(runner); + let level = 0; + this.loadedTests = []; + opts = opts.reporterOptions || opts; + if (opts.steps) level = 1; + if (opts.debug) level = 2; + if (opts.verbose) level = 3; + output.level(level); + output.print(`CodeceptJS v${require('./codecept').version()} ${output.standWithUkraine()}`); + output.print(`Using test root "${global.codecept_dir}"`); + + const showSteps = level >= 1; if (level >= 2) { - const Containter = require('./container') - output.print(output.styles.debug(`Helpers: ${Object.keys(Containter.helpers()).join(', ')}`)) - output.print(output.styles.debug(`Plugins: ${Object.keys(Containter.plugins()).join(', ')}`)) + const Containter = require('./container'); + output.print(output.styles.debug(`Helpers: ${Object.keys(Containter.helpers()).join(', ')}`)); + output.print(output.styles.debug(`Plugins: ${Object.keys(Containter.plugins()).join(', ')}`)); } runner.on('start', () => { - console.log() - }) + console.log(); + }); runner.on('suite', (suite) => { - output.suite.started(suite) - }) + output.suite.started(suite); + }); runner.on('fail', (test) => { if (test.ctx.currentTest) { - this.loadedTests.push(test.ctx.currentTest.uid) + this.loadedTests.push(test.ctx.currentTest.uid); } if (showSteps && test.steps) { - return output.scenario.failed(test) + return output.scenario.failed(test); } - cursor.CR() - output.test.failed(test) - }) + cursor.CR(); + output.test.failed(test); + }); runner.on('pending', (test) => { if (test.parent && test.parent.pending) { - const suite = test.parent - const skipInfo = suite.opts.skipInfo || {} - skipTestConfig(test, skipInfo.message) + const suite = test.parent; + const skipInfo = suite.opts.skipInfo || {}; + skipTestConfig(test, skipInfo.message); } else { - skipTestConfig(test, null) + skipTestConfig(test, null); } - this.loadedTests.push(test.uid) - cursor.CR() - output.test.skipped(test) - }) + this.loadedTests.push(test.uid); + cursor.CR(); + output.test.skipped(test); + }); runner.on('pass', (test) => { if (showSteps && test.steps) { - return output.scenario.passed(test) + return output.scenario.passed(test); } - cursor.CR() - output.test.passed(test) - }) + cursor.CR(); + output.test.passed(test); + }); if (showSteps) { runner.on('test', (test) => { - currentMetaStep = [] + currentMetaStep = []; if (test.steps) { - output.test.started(test) + output.test.started(test); } - }) + }); if (!codeceptjsEventDispatchersRegistered) { - codeceptjsEventDispatchersRegistered = true + codeceptjsEventDispatchersRegistered = true; event.dispatcher.on(event.bddStep.started, (step) => { - output.stepShift = 2 - output.step(step) - }) + output.stepShift = 2; + output.step(step); + }); event.dispatcher.on(event.step.started, (step) => { - let processingStep = step - const metaSteps = [] + let processingStep = step; + const metaSteps = []; while (processingStep.metaStep) { - metaSteps.unshift(processingStep.metaStep) - processingStep = processingStep.metaStep + metaSteps.unshift(processingStep.metaStep); + processingStep = processingStep.metaStep; } - const shift = metaSteps.length + const shift = metaSteps.length; for (let i = 0; i < Math.max(currentMetaStep.length, metaSteps.length); i++) { if (currentMetaStep[i] !== metaSteps[i]) { - output.stepShift = 3 + 2 * i - if (!metaSteps[i]) continue + output.stepShift = 3 + 2 * i; + if (!metaSteps[i]) continue; // bdd steps are handled by bddStep.started - if (metaSteps[i].isBDD()) continue - output.step(metaSteps[i]) + if (metaSteps[i].isBDD()) continue; + output.step(metaSteps[i]); } } - currentMetaStep = metaSteps - output.stepShift = 3 + 2 * shift + currentMetaStep = metaSteps; + output.stepShift = 3 + 2 * shift; if (step.helper.constructor.name !== 'ExpectHelper') { - output.step(step) + output.step(step); } - }) + }); event.dispatcher.on(event.step.finished, () => { - output.stepShift = 0 - }) + output.stepShift = 0; + }); } } runner.on('suite end', (suite) => { - let skippedCount = 0 - const grep = runner._grep + let skippedCount = 0; + const grep = runner._grep; for (const test of suite.tests) { if (!test.state && !this.loadedTests.includes(test.uid)) { if (matchTest(grep, test.title)) { if (!test.opts) { - test.opts = {} + test.opts = {}; } if (!test.opts.skipInfo) { - test.opts.skipInfo = {} + test.opts.skipInfo = {}; } - skipTestConfig(test, "Skipped due to failure in 'before' hook") - output.test.skipped(test) - skippedCount += 1 + skipTestConfig(test, "Skipped due to failure in 'before' hook"); + output.test.skipped(test); + skippedCount += 1; } } } - this.stats.pending += skippedCount - this.stats.tests += skippedCount - }) + this.stats.pending += skippedCount; + this.stats.tests += skippedCount; + }); - runner.on('end', this.result.bind(this)) + runner.on('end', this.result.bind(this)); } result() { - const stats = this.stats - stats.failedHooks = 0 - console.log() + const stats = this.stats; + stats.failedHooks = 0; + console.log(); // passes if (stats.failures) { - output.print(output.styles.bold('-- FAILURES:')) + output.print(output.styles.bold('-- FAILURES:')); } - const failuresLog = [] + const failuresLog = []; // failures if (stats.failures) { // append step traces this.failures.map((test) => { - const err = test.err + const err = test.err; - let log = '' + let log = ''; if (err instanceof AssertionFailedError) { - err.message = err.inspect() + err.message = err.inspect(); } - const steps = test.steps || (test.ctx && test.ctx.test.steps) + const steps = test.steps || (test.ctx && test.ctx.test.steps); if (steps && steps.length) { - let scenarioTrace = '' + let scenarioTrace = ''; steps.reverse().forEach((step) => { - const line = `- ${step.toCode()} ${step.line()}` + const line = `- ${step.toCode()} ${step.line()}`; // if (step.status === 'failed') line = '' + line; - scenarioTrace += `\n${line}` - }) - log += `${output.styles.bold('Scenario Steps')}:${scenarioTrace}\n` + scenarioTrace += `\n${line}`; + }); + log += `${output.styles.bold('Scenario Steps')}:${scenarioTrace}\n`; } // display artifacts in debug mode if (test?.artifacts && Object.keys(test.artifacts).length) { - log += `\n${output.styles.bold('Artifacts:')}` + log += `\n${output.styles.bold('Artifacts:')}`; for (const artifact of Object.keys(test.artifacts)) { - log += `\n- ${artifact}: ${test.artifacts[artifact]}` + log += `\n- ${artifact}: ${test.artifacts[artifact]}`; } } try { - let stack = err.stack ? err.stack.split('\n') : [] + let stack = err.stack ? err.stack.split('\n') : []; if (stack[0] && stack[0].includes(err.message)) { - stack.shift() + stack.shift(); } if (output.level() < 3) { - stack = stack.slice(0, 3) + stack = stack.slice(0, 3); } - err.stack = `${stack.join('\n')}\n\n${output.colors.blue(log)}` + err.stack = `${stack.join('\n')}\n\n${output.colors.blue(log)}`; // clone err object so stack trace adjustments won't affect test other reports - test.err = err - return test + test.err = err; + return test; } catch (e) { - throw Error(e) + throw Error(e); } - }) + }); - const originalLog = Base.consoleLog + const originalLog = Base.consoleLog; Base.consoleLog = (...data) => { - failuresLog.push([...data]) - originalLog(...data) - } - Base.list(this.failures) - Base.consoleLog = originalLog - console.log() + failuresLog.push([...data]); + originalLog(...data); + }; + Base.list(this.failures); + Base.consoleLog = originalLog; + console.log(); } this.failures.forEach((failure) => { if (failure.constructor.name === 'Hook') { - stats.failedHooks += 1 + stats.failedHooks += 1; } - }) - event.emit(event.all.failures, { failuresLog, stats }) - output.result(stats.passes, stats.failures, stats.pending, ms(stats.duration), stats.failedHooks) + }); + event.emit(event.all.failures, { failuresLog, stats }); + output.result(stats.passes, stats.failures, stats.pending, ms(stats.duration), stats.failedHooks); if (stats.failures && output.level() < 3) { - output.print(output.styles.debug('Run with --verbose flag to see complete NodeJS stacktrace')) + output.print(output.styles.debug('Run with --verbose flag to see complete NodeJS stacktrace')); } } } function matchTest(grep, test) { if (grep) { - return grep.test(test) + return grep.test(test); } - return true + return true; } function skipTestConfig(test, message) { if (!test.opts) { - test.opts = {} + test.opts = {}; } if (!test.opts.skipInfo) { - test.opts.skipInfo = {} + test.opts.skipInfo = {}; } - test.opts.skipInfo.message = test.opts.skipInfo.message || message - test.opts.skipInfo.isFastSkipped = true - event.emit(event.test.skipped, test) - test.state = 'skipped' + test.opts.skipInfo.message = test.opts.skipInfo.message || message; + test.opts.skipInfo.isFastSkipped = true; + event.emit(event.test.skipped, test); + test.state = 'skipped'; } module.exports = function (runner, opts) { - return new Cli(runner, opts) -} + return new Cli(runner, opts); +}; diff --git a/lib/codecept.js b/lib/codecept.js index fc24156fd..6f5402cce 100644 --- a/lib/codecept.js +++ b/lib/codecept.js @@ -1,14 +1,14 @@ -const { existsSync, readFileSync } = require('fs') -const glob = require('glob') -const fsPath = require('path') -const { resolve } = require('path') - -const container = require('./container') -const Config = require('./config') -const event = require('./event') -const runHook = require('./hooks') -const output = require('./output') -const { emptyFolder } = require('./utils') +const { existsSync, readFileSync } = require('fs'); +const glob = require('glob'); +const fsPath = require('path'); +const { resolve } = require('path'); + +const container = require('./container'); +const Config = require('./config'); +const event = require('./event'); +const runHook = require('./hooks'); +const output = require('./output'); +const { emptyFolder } = require('./utils'); /** * CodeceptJS runner @@ -22,10 +22,10 @@ class Codecept { * @param {*} opts */ constructor(config, opts) { - this.config = Config.create(config) - this.opts = opts - this.testFiles = new Array(0) - this.requireModules(config.require) + this.config = Config.create(config); + this.opts = opts; + this.testFiles = new Array(0); + this.requireModules(config.require); } /** @@ -36,12 +36,12 @@ class Codecept { requireModules(requiringModules) { if (requiringModules) { requiringModules.forEach((requiredModule) => { - const isLocalFile = existsSync(requiredModule) || existsSync(`${requiredModule}.js`) + const isLocalFile = existsSync(requiredModule) || existsSync(`${requiredModule}.js`); if (isLocalFile) { - requiredModule = resolve(requiredModule) + requiredModule = resolve(requiredModule); } - require(requiredModule) - }) + require(requiredModule); + }); } } @@ -52,10 +52,10 @@ class Codecept { * @param {string} dir */ init(dir) { - this.initGlobals(dir) + this.initGlobals(dir); // initializing listeners - container.create(this.config, this.opts) - this.runHooks() + container.create(this.config, this.opts); + this.runHooks(); } /** @@ -64,37 +64,37 @@ class Codecept { * @param {string} dir */ initGlobals(dir) { - global.codecept_dir = dir - global.output_dir = fsPath.resolve(dir, this.config.output) + global.codecept_dir = dir; + global.output_dir = fsPath.resolve(dir, this.config.output); - if (this.config.emptyOutputFolder) emptyFolder(global.output_dir) + if (this.config.emptyOutputFolder) emptyFolder(global.output_dir); if (!this.config.noGlobals) { - global.Helper = global.codecept_helper = require('@codeceptjs/helper') - global.actor = global.codecept_actor = require('./actor') - global.pause = require('./pause') - global.within = require('./within') - global.session = require('./session') - global.DataTable = require('./data/table') - global.locate = (locator) => require('./locator').build(locator) - global.inject = container.support - global.share = container.share - global.secret = require('./secret').secret - global.codecept_debug = output.debug - global.codeceptjs = require('./index') // load all objects + global.Helper = global.codecept_helper = require('@codeceptjs/helper'); + global.actor = global.codecept_actor = require('./actor'); + global.pause = require('./pause'); + global.within = require('./within'); + global.session = require('./session'); + global.DataTable = require('./data/table'); + global.locate = (locator) => require('./locator').build(locator); + global.inject = container.support; + global.share = container.share; + global.secret = require('./secret').secret; + global.codecept_debug = output.debug; + global.codeceptjs = require('./index'); // load all objects // BDD - const stepDefinitions = require('./interfaces/bdd') - global.Given = stepDefinitions.Given - global.When = stepDefinitions.When - global.Then = stepDefinitions.Then - global.DefineParameterType = stepDefinitions.defineParameterType + const stepDefinitions = require('./interfaces/bdd'); + global.Given = stepDefinitions.Given; + global.When = stepDefinitions.When; + global.Then = stepDefinitions.Then; + global.DefineParameterType = stepDefinitions.defineParameterType; // debug mode - global.debugMode = false + global.debugMode = false; // mask sensitive data - global.maskSensitiveData = this.config.maskSensitiveData || false + global.maskSensitiveData = this.config.maskSensitiveData || false; } } @@ -103,16 +103,16 @@ class Codecept { */ runHooks() { // default hooks - runHook(require('./listener/steps')) - runHook(require('./listener/artifacts')) - runHook(require('./listener/config')) - runHook(require('./listener/helpers')) - runHook(require('./listener/retry')) - runHook(require('./listener/timeout')) - runHook(require('./listener/exit')) + runHook(require('./listener/steps')); + runHook(require('./listener/artifacts')); + runHook(require('./listener/config')); + runHook(require('./listener/helpers')); + runHook(require('./listener/retry')); + runHook(require('./listener/timeout')); + runHook(require('./listener/exit')); // custom hooks (previous iteration of plugins) - this.config.hooks.forEach((hook) => runHook(hook)) + this.config.hooks.forEach((hook) => runHook(hook)); } /** @@ -120,7 +120,7 @@ class Codecept { * */ async bootstrap() { - return runHook(this.config.bootstrap, 'bootstrap') + return runHook(this.config.bootstrap, 'bootstrap'); } /** @@ -128,7 +128,7 @@ class Codecept { */ async teardown() { - return runHook(this.config.teardown, 'teardown') + return runHook(this.config.teardown, 'teardown'); } /** @@ -139,42 +139,42 @@ class Codecept { loadTests(pattern) { const options = { cwd: global.codecept_dir, - } + }; - let patterns = [pattern] + let patterns = [pattern]; if (!pattern) { - patterns = [] + patterns = []; // If the user wants to test a specific set of test files as an array or string. if (this.config.tests && !this.opts.features) { if (Array.isArray(this.config.tests)) { - patterns.push(...this.config.tests) + patterns.push(...this.config.tests); } else { - patterns.push(this.config.tests) + patterns.push(this.config.tests); } } if (this.config.gherkin.features && !this.opts.tests) { if (Array.isArray(this.config.gherkin.features)) { this.config.gherkin.features.forEach((feature) => { - patterns.push(feature) - }) + patterns.push(feature); + }); } else { - patterns.push(this.config.gherkin.features) + patterns.push(this.config.gherkin.features); } } } for (pattern of patterns) { glob.sync(pattern, options).forEach((file) => { - if (file.includes('node_modules')) return + if (file.includes('node_modules')) return; if (!fsPath.isAbsolute(file)) { - file = fsPath.join(global.codecept_dir, file) + file = fsPath.join(global.codecept_dir, file); } if (!this.testFiles.includes(fsPath.resolve(file))) { - this.testFiles.push(fsPath.resolve(file)) + this.testFiles.push(fsPath.resolve(file)); } - }) + }); } } @@ -185,36 +185,36 @@ class Codecept { * @returns {Promise} */ async run(test) { - await container.started() + await container.started(); return new Promise((resolve, reject) => { - const mocha = container.mocha() - mocha.files = this.testFiles + const mocha = container.mocha(); + mocha.files = this.testFiles; if (test) { if (!fsPath.isAbsolute(test)) { - test = fsPath.join(global.codecept_dir, test) + test = fsPath.join(global.codecept_dir, test); } - mocha.files = mocha.files.filter((t) => fsPath.basename(t, '.js') === test || t === test) + mocha.files = mocha.files.filter((t) => fsPath.basename(t, '.js') === test || t === test); } const done = () => { - event.emit(event.all.result, this) - event.emit(event.all.after, this) - resolve() - } + event.emit(event.all.result, this); + event.emit(event.all.after, this); + resolve(); + }; try { - event.emit(event.all.before, this) - mocha.run(() => done()) + event.emit(event.all.before, this); + mocha.run(() => done()); } catch (e) { - output.error(e.stack) - reject(e) + output.error(e.stack); + reject(e); } - }) + }); } static version() { - return JSON.parse(readFileSync(`${__dirname}/../package.json`, 'utf8')).version + return JSON.parse(readFileSync(`${__dirname}/../package.json`, 'utf8')).version; } } -module.exports = Codecept +module.exports = Codecept; diff --git a/lib/command/gherkin/snippets.js b/lib/command/gherkin/snippets.js index 10fcd405d..42f4bbf5d 100644 --- a/lib/command/gherkin/snippets.js +++ b/lib/command/gherkin/snippets.js @@ -1,115 +1,115 @@ -const escapeStringRegexp = require('escape-string-regexp') -const fs = require('fs') -const Gherkin = require('@cucumber/gherkin') -const Messages = require('@cucumber/messages') -const glob = require('glob') -const fsPath = require('path') +const escapeStringRegexp = require('escape-string-regexp'); +const fs = require('fs'); +const Gherkin = require('@cucumber/gherkin'); +const Messages = require('@cucumber/messages'); +const glob = require('glob'); +const fsPath = require('path'); -const { getConfig, getTestRoot } = require('../utils') -const Codecept = require('../../codecept') -const output = require('../../output') -const { matchStep } = require('../../interfaces/bdd') +const { getConfig, getTestRoot } = require('../utils'); +const Codecept = require('../../codecept'); +const output = require('../../output'); +const { matchStep } = require('../../interfaces/bdd'); -const uuidFn = Messages.IdGenerator.uuid() -const builder = new Gherkin.AstBuilder(uuidFn) -const matcher = new Gherkin.GherkinClassicTokenMatcher() -const parser = new Gherkin.Parser(builder, matcher) -parser.stopAtFirstError = false +const uuidFn = Messages.IdGenerator.uuid(); +const builder = new Gherkin.AstBuilder(uuidFn); +const matcher = new Gherkin.GherkinClassicTokenMatcher(); +const parser = new Gherkin.Parser(builder, matcher); +parser.stopAtFirstError = false; module.exports = function (genPath, options) { - const configFile = options.config || genPath - const testsPath = getTestRoot(configFile) - const config = getConfig(configFile) - if (!config) return + const configFile = options.config || genPath; + const testsPath = getTestRoot(configFile); + const config = getConfig(configFile); + if (!config) return; - const codecept = new Codecept(config, {}) - codecept.init(testsPath) + const codecept = new Codecept(config, {}); + codecept.init(testsPath); if (!config.gherkin) { - output.error('Gherkin is not enabled in config. Run `codecept gherkin:init` to enable it') - process.exit(1) + output.error('Gherkin is not enabled in config. Run `codecept gherkin:init` to enable it'); + process.exit(1); } if (!config.gherkin.steps || !config.gherkin.steps[0]) { - output.error('No gherkin steps defined in config. Exiting') - process.exit(1) + output.error('No gherkin steps defined in config. Exiting'); + process.exit(1); } if (!options.feature && !config.gherkin.features) { - output.error('No gherkin features defined in config. Exiting') - process.exit(1) + output.error('No gherkin features defined in config. Exiting'); + process.exit(1); } if (options.path && !config.gherkin.steps.includes(options.path)) { - output.error(`You must include ${options.path} to the gherkin steps in your config file`) - process.exit(1) + output.error(`You must include ${options.path} to the gherkin steps in your config file`); + process.exit(1); } - const files = [] + const files = []; glob .sync(options.feature || config.gherkin.features, { cwd: options.feature ? '.' : global.codecept_dir }) .forEach((file) => { if (!fsPath.isAbsolute(file)) { - file = fsPath.join(global.codecept_dir, file) + file = fsPath.join(global.codecept_dir, file); } - files.push(fsPath.resolve(file)) - }) - output.print(`Loaded ${files.length} files`) + files.push(fsPath.resolve(file)); + }); + output.print(`Loaded ${files.length} files`); - const newSteps = new Map() + const newSteps = new Map(); const parseSteps = (steps) => { - const newSteps = [] - let currentKeyword = '' + const newSteps = []; + let currentKeyword = ''; for (const step of steps) { if (step.keyword.trim() === 'And') { - if (!currentKeyword) throw new Error(`There is no active keyword for step '${step.text}'`) - step.keyword = currentKeyword + if (!currentKeyword) throw new Error(`There is no active keyword for step '${step.text}'`); + step.keyword = currentKeyword; } - currentKeyword = step.keyword + currentKeyword = step.keyword; try { - matchStep(step.text) + matchStep(step.text); } catch (err) { - let stepLine + let stepLine; if (/[{}()/]/.test(step.text)) { stepLine = escapeStringRegexp(step.text) .replace(/\//g, '\\/') .replace(/\"(.*?)\"/g, '"(.*?)"') .replace(/(\d+\\\.\d+)/, '(\\d+\\.\\d+)') - .replace(/ (\d+) /, ' (\\d+) ') - stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: true }) + .replace(/ (\d+) /, ' (\\d+) '); + stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: true }); } else { stepLine = step.text .replace(/\"(.*?)\"/g, '{string}') .replace(/(\d+\.\d+)/, '{float}') - .replace(/ (\d+) /, ' {int} ') - stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: false }) + .replace(/ (\d+) /, ' {int} '); + stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: false }); } - newSteps.push(stepLine) + newSteps.push(stepLine); } } - return newSteps - } + return newSteps; + }; const parseFile = (file) => { - const ast = parser.parse(fs.readFileSync(file).toString()) + const ast = parser.parse(fs.readFileSync(file).toString()); for (const child of ast.feature.children) { - if (child.scenario.keyword === 'Scenario Outline') continue // skip scenario outline + if (child.scenario.keyword === 'Scenario Outline') continue; // skip scenario outline parseSteps(child.scenario.steps) .map((step) => { - return Object.assign(step, { file: file.replace(global.codecept_dir, '').slice(1) }) + return Object.assign(step, { file: file.replace(global.codecept_dir, '').slice(1) }); }) - .map((step) => newSteps.set(`${step.type}(${step})`, step)) + .map((step) => newSteps.set(`${step.type}(${step})`, step)); } - } + }; - files.forEach((file) => parseFile(file)) + files.forEach((file) => parseFile(file)); - let stepFile = options.path || config.gherkin.steps[0] + let stepFile = options.path || config.gherkin.steps[0]; if (!fs.existsSync(stepFile)) { - output.error(`Please enter a valid step file path ${stepFile}`) - process.exit(1) + output.error(`Please enter a valid step file path ${stepFile}`); + process.exit(1); } if (!fsPath.isAbsolute(stepFile)) { - stepFile = fsPath.join(global.codecept_dir, stepFile) + stepFile = fsPath.join(global.codecept_dir, stepFile); } const snippets = [...newSteps.values()] @@ -119,18 +119,18 @@ module.exports = function (genPath, options) { ${step.type}(${step.regexp ? '/^' : "'"}${step}${step.regexp ? '$/' : "'"}, () => { // From "${step.file}" ${JSON.stringify(step.location)} throw new Error('Not implemented yet'); -});` - }) +});`; + }); if (!snippets.length) { - output.print('No new snippets found') - return + output.print('No new snippets found'); + return; } - output.success(`Snippets generated: ${snippets.length}`) - output.print(snippets.join('\n')) + output.success(`Snippets generated: ${snippets.length}`); + output.print(snippets.join('\n')); if (!options.dryRun) { - output.success(`Snippets added to ${output.colors.bold(stepFile)}`) - fs.writeFileSync(stepFile, fs.readFileSync(stepFile).toString() + snippets.join('\n') + '\n') + output.success(`Snippets added to ${output.colors.bold(stepFile)}`); + fs.writeFileSync(stepFile, fs.readFileSync(stepFile).toString() + snippets.join('\n') + '\n'); } -} +}; diff --git a/lib/command/workers/runTests.js b/lib/command/workers/runTests.js index 7d5913f83..3cb0d0565 100644 --- a/lib/command/workers/runTests.js +++ b/lib/command/workers/runTests.js @@ -1,83 +1,83 @@ -const tty = require('tty') +const tty = require('tty'); if (!tty.getWindowSize) { // this is really old method, long removed from Node, but Mocha // reporters fall back on it if they cannot use `process.stdout.getWindowSize` // we need to polyfill it. - tty.getWindowSize = () => [40, 80] + tty.getWindowSize = () => [40, 80]; } -const { parentPort, workerData } = require('worker_threads') -const event = require('../../event') -const container = require('../../container') -const { getConfig } = require('../utils') -const { tryOrDefault, deepMerge } = require('../../utils') +const { parentPort, workerData } = require('worker_threads'); +const event = require('../../event'); +const container = require('../../container'); +const { getConfig } = require('../utils'); +const { tryOrDefault, deepMerge } = require('../../utils'); -let stdout = '' +let stdout = ''; -const stderr = '' +const stderr = ''; // Requiring of Codecept need to be after tty.getWindowSize is available. -const Codecept = require(process.env.CODECEPT_CLASS_PATH || '../../codecept') +const Codecept = require(process.env.CODECEPT_CLASS_PATH || '../../codecept'); -const { options, tests, testRoot, workerIndex } = workerData +const { options, tests, testRoot, workerIndex } = workerData; // hide worker output if (!options.debug && !options.verbose) process.stdout.write = (string) => { - stdout += string - return true - } + stdout += string; + return true; + }; -const overrideConfigs = tryOrDefault(() => JSON.parse(options.override), {}) +const overrideConfigs = tryOrDefault(() => JSON.parse(options.override), {}); // important deep merge so dynamic things e.g. functions on config are not overridden -const config = deepMerge(getConfig(options.config || testRoot), overrideConfigs) +const config = deepMerge(getConfig(options.config || testRoot), overrideConfigs); // Load test and run -const codecept = new Codecept(config, options) -codecept.init(testRoot) -codecept.loadTests() -const mocha = container.mocha() +const codecept = new Codecept(config, options); +codecept.init(testRoot); +codecept.loadTests(); +const mocha = container.mocha(); filterTests(); // run tests (async function () { if (mocha.suite.total()) { - await runTests() + await runTests(); } })(); async function runTests() { try { - await codecept.bootstrap() + await codecept.bootstrap(); } catch (err) { - throw new Error(`Error while running bootstrap file :${err}`) + throw new Error(`Error while running bootstrap file :${err}`); } - listenToParentThread() - initializeListeners() - disablePause() + listenToParentThread(); + initializeListeners(); + disablePause(); try { - await codecept.run() + await codecept.run(); } finally { - await codecept.teardown() + await codecept.teardown(); } } function filterTests() { - const files = codecept.testFiles - mocha.files = files - mocha.loadFiles() + const files = codecept.testFiles; + mocha.files = files; + mocha.loadFiles(); for (const suite of mocha.suite.suites) { - suite.tests = suite.tests.filter((test) => tests.indexOf(test.uid) >= 0) + suite.tests = suite.tests.filter((test) => tests.indexOf(test.uid) >= 0); } } function initializeListeners() { function simplifyError(error) { if (error) { - const { stack, uncaught, message, actual, expected } = error + const { stack, uncaught, message, actual, expected } = error; return { stack, @@ -85,36 +85,36 @@ function initializeListeners() { message, actual, expected, - } + }; } - return null + return null; } function simplifyTest(test, err = null) { - test = { ...test } + test = { ...test }; if (test.start && !test.duration) { - const end = new Date() - test.duration = end - test.start + const end = new Date(); + test.duration = end - test.start; } if (test.err) { - err = simplifyError(test.err) - test.status = 'failed' + err = simplifyError(test.err); + test.status = 'failed'; } else if (err) { - err = simplifyError(err) - test.status = 'failed' + err = simplifyError(err); + test.status = 'failed'; } - const parent = {} + const parent = {}; if (test.parent) { - parent.title = test.parent.title + parent.title = test.parent.title; } if (test.opts) { Object.keys(test.opts).forEach((k) => { - if (typeof test.opts[k] === 'object') delete test.opts[k] - if (typeof test.opts[k] === 'function') delete test.opts[k] - }) + if (typeof test.opts[k] === 'object') delete test.opts[k]; + if (typeof test.opts[k] === 'function') delete test.opts[k]; + }); } return { @@ -129,26 +129,26 @@ function initializeListeners() { err, parent, steps: test.steps && test.steps.length > 0 ? simplifyStepsInTestObject(test.steps, err) : [], - } + }; } function simplifyStepsInTestObject(steps, err) { - steps = [...steps] - const _steps = [] + steps = [...steps]; + const _steps = []; for (step of steps) { - const _args = [] + const _args = []; if (step.args) { for (const arg of step.args) { // check if arg is a JOI object if (arg && arg.$_root) { - _args.push(JSON.stringify(arg).slice(0, 300)) + _args.push(JSON.stringify(arg).slice(0, 300)); // check if arg is a function } else if (arg && typeof arg === 'function') { - _args.push(arg.name) + _args.push(arg.name); } else { - _args.push(arg) + _args.push(arg); } } } @@ -164,38 +164,38 @@ function initializeListeners() { finishedAt: step.finishedAt, duration: step.duration, err, - }) + }); } - return _steps + return _steps; } function simplifyStep(step, err = null) { - step = { ...step } + step = { ...step }; if (step.startTime && !step.duration) { - const end = new Date() - step.duration = end - step.startTime + const end = new Date(); + step.duration = end - step.startTime; } if (step.err) { - err = simplifyError(step.err) - step.status = 'failed' + err = simplifyError(step.err); + step.status = 'failed'; } else if (err) { - err = simplifyError(err) - step.status = 'failed' + err = simplifyError(err); + step.status = 'failed'; } - const parent = {} + const parent = {}; if (step.metaStep) { - parent.title = step.metaStep.actor + parent.title = step.metaStep.actor; } if (step.opts) { Object.keys(step.opts).forEach((k) => { - if (typeof step.opts[k] === 'object') delete step.opts[k] - if (typeof step.opts[k] === 'function') delete step.opts[k] - }) + if (typeof step.opts[k] === 'object') delete step.opts[k]; + if (typeof step.opts[k] === 'function') delete step.opts[k]; + }); } return { @@ -207,75 +207,75 @@ function initializeListeners() { err, parent, test: simplifyTest(step.test), - } + }; } - collectStats() + collectStats(); // suite event.dispatcher.on(event.suite.before, (suite) => sendToParentThread({ event: event.suite.before, workerIndex, data: simplifyTest(suite) }), - ) + ); event.dispatcher.on(event.suite.after, (suite) => sendToParentThread({ event: event.suite.after, workerIndex, data: simplifyTest(suite) }), - ) + ); // calculate duration - event.dispatcher.on(event.test.started, (test) => (test.start = new Date())) + event.dispatcher.on(event.test.started, (test) => (test.start = new Date())); // tests event.dispatcher.on(event.test.before, (test) => sendToParentThread({ event: event.test.before, workerIndex, data: simplifyTest(test) }), - ) + ); event.dispatcher.on(event.test.after, (test) => sendToParentThread({ event: event.test.after, workerIndex, data: simplifyTest(test) }), - ) + ); // we should force-send correct errors to prevent race condition event.dispatcher.on(event.test.finished, (test, err) => sendToParentThread({ event: event.test.finished, workerIndex, data: simplifyTest(test, err) }), - ) + ); event.dispatcher.on(event.test.failed, (test, err) => sendToParentThread({ event: event.test.failed, workerIndex, data: simplifyTest(test, err) }), - ) + ); event.dispatcher.on(event.test.passed, (test, err) => sendToParentThread({ event: event.test.passed, workerIndex, data: simplifyTest(test, err) }), - ) + ); event.dispatcher.on(event.test.started, (test) => sendToParentThread({ event: event.test.started, workerIndex, data: simplifyTest(test) }), - ) + ); event.dispatcher.on(event.test.skipped, (test) => sendToParentThread({ event: event.test.skipped, workerIndex, data: simplifyTest(test) }), - ) + ); // steps event.dispatcher.on(event.step.finished, (step) => sendToParentThread({ event: event.step.finished, workerIndex, data: simplifyStep(step) }), - ) + ); event.dispatcher.on(event.step.started, (step) => sendToParentThread({ event: event.step.started, workerIndex, data: simplifyStep(step) }), - ) + ); event.dispatcher.on(event.step.passed, (step) => sendToParentThread({ event: event.step.passed, workerIndex, data: simplifyStep(step) }), - ) + ); event.dispatcher.on(event.step.failed, (step) => sendToParentThread({ event: event.step.failed, workerIndex, data: simplifyStep(step) }), - ) + ); event.dispatcher.on(event.hook.failed, (test, err) => sendToParentThread({ event: event.hook.failed, workerIndex, data: simplifyTest(test, err) }), - ) + ); event.dispatcher.on(event.hook.passed, (test, err) => sendToParentThread({ event: event.hook.passed, workerIndex, data: simplifyTest(test, err) }), - ) + ); event.dispatcher.on(event.all.failures, (data) => sendToParentThread({ event: event.all.failures, workerIndex, data }), - ) + ); // all - event.dispatcher.once(event.all.result, () => parentPort.close()) + event.dispatcher.once(event.all.result, () => parentPort.close()); } function disablePause() { - global.pause = () => {} + global.pause = () => {}; } function collectStats() { @@ -285,36 +285,36 @@ function collectStats() { skipped: 0, tests: 0, pending: 0, - } + }; event.dispatcher.on(event.test.skipped, () => { - stats.skipped++ - }) + stats.skipped++; + }); event.dispatcher.on(event.test.passed, () => { - stats.passes++ - }) + stats.passes++; + }); event.dispatcher.on(event.test.failed, (test) => { if (test.ctx._runnable.title.includes('hook: AfterSuite')) { - stats.failedHooks += 1 + stats.failedHooks += 1; } - stats.failures++ - }) + stats.failures++; + }); event.dispatcher.on(event.test.skipped, () => { - stats.pending++ - }) + stats.pending++; + }); event.dispatcher.on(event.test.finished, () => { - stats.tests++ - }) + stats.tests++; + }); event.dispatcher.once(event.all.after, () => { - sendToParentThread({ event: event.all.after, data: stats }) - }) + sendToParentThread({ event: event.all.after, data: stats }); + }); } function sendToParentThread(data) { - parentPort.postMessage(data) + parentPort.postMessage(data); } function listenToParentThread() { parentPort.on('message', (eventData) => { - container.append({ support: eventData.data }) - }) + container.append({ support: eventData.data }); + }); } diff --git a/lib/container.js b/lib/container.js index 93d44d01b..01a640399 100644 --- a/lib/container.js +++ b/lib/container.js @@ -1,16 +1,16 @@ -const glob = require('glob') -const path = require('path') -const { MetaStep } = require('./step') -const { methodsOfObject, fileExists, isFunction, isAsyncFunction, installedLocally } = require('./utils') -const Translation = require('./translation') -const MochaFactory = require('./mochaFactory') -const recorder = require('./recorder') -const event = require('./event') -const WorkerStorage = require('./workerStorage') -const store = require('./store') -const ai = require('./ai') - -let asyncHelperPromise +const glob = require('glob'); +const path = require('path'); +const { MetaStep } = require('./step'); +const { methodsOfObject, fileExists, isFunction, isAsyncFunction, installedLocally } = require('./utils'); +const Translation = require('./translation'); +const MochaFactory = require('./mochaFactory'); +const recorder = require('./recorder'); +const event = require('./event'); +const WorkerStorage = require('./workerStorage'); +const store = require('./store'); +const ai = require('./ai'); + +let asyncHelperPromise; let container = { helpers: {}, @@ -24,7 +24,7 @@ let container = { */ mocha: {}, translation: {}, -} +}; /** * Dependency Injection Container @@ -38,24 +38,24 @@ class Container { * @param {*} opts */ static create(config, opts) { - asyncHelperPromise = Promise.resolve() + asyncHelperPromise = Promise.resolve(); + this.createMocha(config, opts); - container.support = {} - container.helpers = createHelpers(config.helpers || {}) - container.translation = loadTranslation(config.translation || null, config.vocabularies || []) - container.proxySupport = createSupportObjects(config.include || {}) - container.plugins = createPlugins(config.plugins || {}, opts) + container.support = {}; + container.helpers = createHelpers(config.helpers || {}); + container.translation = loadTranslation(config.translation || null, config.vocabularies || []); + container.proxySupport = createSupportObjects(config.include || {}); + container.plugins = createPlugins(config.plugins || {}, opts); - createActor(config.include?.I) - createMocha(config, opts) + createActor(config.include?.I); - if (opts && opts.ai) ai.enable(config.ai) // enable AI Assistant - if (config.gherkin) loadGherkinSteps(config.gherkin.steps || []) - if (opts && typeof opts.timeouts === 'boolean') store.timeouts = opts.timeouts + if (opts && opts.ai) ai.enable(config.ai); // enable AI Assistant + if (config.gherkin) loadGherkinSteps(config.gherkin.steps || []); + if (opts && typeof opts.timeouts === 'boolean') store.timeouts = opts.timeouts; } static actor() { - return container.support.I + return container.support.I; } /** @@ -67,9 +67,9 @@ class Container { */ static plugins(name) { if (!name) { - return container.plugins + return container.plugins; } - return container.plugins[name] + return container.plugins[name]; } /** @@ -81,9 +81,9 @@ class Container { */ static support(name) { if (!name) { - return container.proxySupport + return container.proxySupport; } - return container.support[name] || container.proxySupport[name] + return container.support[name] || container.proxySupport[name]; } /** @@ -95,9 +95,9 @@ class Container { */ static helpers(name) { if (!name) { - return container.helpers + return container.helpers; } - return container.helpers[name] + return container.helpers[name]; } /** @@ -106,7 +106,7 @@ class Container { * @api */ static translation() { - return container.translation + return container.translation; } /** @@ -116,7 +116,7 @@ class Container { * @returns { * } */ static mocha() { - return container.mocha + return container.mocha; } /** @@ -126,8 +126,8 @@ class Container { * @param {Object} newContainer */ static append(newContainer) { - const deepMerge = require('./utils').deepMerge - container = deepMerge(container, newContainer) + const deepMerge = require('./utils').deepMerge; + container = deepMerge(container, newContainer); } /** @@ -138,19 +138,19 @@ class Container { * @param {Object} newPlugins */ static clear(newHelpers, newSupport, newPlugins) { - container.helpers = newHelpers || {} - container.translation = loadTranslation() - container.proxySupport = createSupportObjects(newSupport || {}) - container.plugins = newPlugins || {} - asyncHelperPromise = Promise.resolve() - store.actor = null + container.helpers = newHelpers || {}; + container.translation = loadTranslation(); + container.proxySupport = createSupportObjects(newSupport || {}); + container.plugins = newPlugins || {}; + asyncHelperPromise = Promise.resolve(); + store.actor = null; } static async started(fn = null) { if (fn) { - asyncHelperPromise = asyncHelperPromise.then(fn) + asyncHelperPromise = asyncHelperPromise.then(fn); } - return asyncHelperPromise + return asyncHelperPromise; } /** @@ -160,115 +160,123 @@ class Container { * @param {Object} options - set {local: true} to not share among workers */ static share(data, options = {}) { - Container.append({ support: data }) + Container.append({ support: data }); if (!options.local) { - WorkerStorage.share(data) + WorkerStorage.share(data); + } + } + + static createMocha(config = {}, opts = {}) { + const mochaConfig = config?.mocha || {}; + if (config?.grep && !opts?.grep) { + mochaConfig.grep = config.grep; } + container.mocha = MochaFactory.create(mochaConfig, opts || {}); } } -module.exports = Container +module.exports = Container; function createHelpers(config) { - const helpers = {} + const helpers = {}; for (let helperName in config) { try { - let HelperClass + let HelperClass; // ESM import if (helperName?.constructor === Function && helperName.prototype) { - HelperClass = helperName - helperName = HelperClass.constructor.name + HelperClass = helperName; + helperName = HelperClass.constructor.name; } // classical require if (!HelperClass) { - HelperClass = requireHelperFromModule(helperName, config) + HelperClass = requireHelperFromModule(helperName, config); } // handle async CJS modules that use dynamic import if (isAsyncFunction(HelperClass)) { - helpers[helperName] = {} + helpers[helperName] = {}; asyncHelperPromise = asyncHelperPromise .then(() => HelperClass()) .then((ResolvedHelperClass) => { // Check if ResolvedHelperClass is a constructor function if (typeof ResolvedHelperClass?.constructor !== 'function') { - throw new Error(`Helper class from module '${helperName}' is not a class. Use CJS async module syntax.`) + throw new Error(`Helper class from module '${helperName}' is not a class. Use CJS async module syntax.`); } - helpers[helperName] = new ResolvedHelperClass(config[helperName]) - }) + helpers[helperName] = new ResolvedHelperClass(config[helperName]); + }); - continue + continue; } - checkHelperRequirements(HelperClass) + checkHelperRequirements(HelperClass); - helpers[helperName] = new HelperClass(config[helperName]) + helpers[helperName] = new HelperClass(config[helperName]); } catch (err) { - throw new Error(`Could not load helper ${helperName} (${err.message})`) + throw new Error(`Could not load helper ${helperName} (${err.message})`); } } for (const name in helpers) { - if (helpers[name]._init) helpers[name]._init() + if (helpers[name]._init) helpers[name]._init(); } - return helpers + return helpers; } function checkHelperRequirements(HelperClass) { if (HelperClass._checkRequirements) { - const requirements = HelperClass._checkRequirements() + const requirements = HelperClass._checkRequirements(); if (requirements) { - let install + let install; if (installedLocally()) { - install = `npm install --save-dev ${requirements.join(' ')}` + install = `npm install --save-dev ${requirements.join(' ')}`; } else { - console.log('WARNING: CodeceptJS is not installed locally. It is recommended to switch to local installation') - install = `[sudo] npm install -g ${requirements.join(' ')}` + console.log('WARNING: CodeceptJS is not installed locally. It is recommended to switch to local installation'); + install = `[sudo] npm install -g ${requirements.join(' ')}`; } - throw new Error(`Required modules are not installed.\n\nRUN: ${install}`) + throw new Error(`Required modules are not installed.\n\nRUN: ${install}`); } } } function requireHelperFromModule(helperName, config, HelperClass) { - const moduleName = getHelperModuleName(helperName, config) + const moduleName = getHelperModuleName(helperName, config); if (moduleName.startsWith('./helper/')) { - HelperClass = require(moduleName) + HelperClass = require(moduleName); } else { // check if the new syntax export default HelperName is used and loads the Helper, otherwise loads the module that used old syntax export = HelperName. try { - const mod = require(moduleName) + const mod = require(moduleName); if (!mod && !mod.default) { throw new Error( `Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`, - ) + ); } - HelperClass = mod.default || mod + HelperClass = mod.default || mod; } catch (err) { if (err.code === 'MODULE_NOT_FOUND') { throw new Error( `Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`, - ) + ); } - throw err + throw err; } } - return HelperClass + return HelperClass; } function createSupportObjects(config) { const asyncWrapper = function (f) { return function () { return f.apply(this, arguments).catch((e) => { - recorder.saveFirstAsyncError(e) - throw e - }) - } - } + recorder.saveFirstAsyncError(e); + throw e; + }); + }; + }; function lazyLoad(name) { return new Proxy( @@ -276,205 +284,205 @@ function createSupportObjects(config) { { get(target, prop) { // behavr like array or - if (prop === 'length') return Object.keys(config).length + if (prop === 'length') return Object.keys(config).length; if (prop === Symbol.iterator) { return function* () { for (let i = 0; i < Object.keys(config).length; i++) { - yield target[i] + yield target[i]; } - } + }; } // load actual name from vocabulary if (container.translation.name) { - name = container.translation.name + name = container.translation.name; } if (name === 'I') { - const actor = createActor(config.I) - methodsOfObject(actor) - return actor[prop] + const actor = createActor(config.I); + methodsOfObject(actor); + return actor[prop]; } if (!container.support[name] && typeof config[name] === 'object') { - container.support[name] = config[name] + container.support[name] = config[name]; } if (!container.support[name]) { // Load object on first access - const supportObject = loadSupportObject(config[name]) - container.support[name] = supportObject + const supportObject = loadSupportObject(config[name]); + container.support[name] = supportObject; try { if (container.support[name]._init) { - container.support[name]._init() + container.support[name]._init(); } } catch (err) { throw new Error( `Initialization failed for ${name}: ${container.support[name]}\n${err.message}\n${err.stack}`, - ) + ); } } - const currentObject = container.support[name] - let currentValue = currentObject[prop] + const currentObject = container.support[name]; + let currentValue = currentObject[prop]; if (isFunction(currentValue) || isAsyncFunction(currentValue)) { - const ms = new MetaStep(name, prop) - ms.setContext(currentObject) - if (isAsyncFunction(currentValue)) currentValue = asyncWrapper(currentValue) - return ms.run.bind(ms, currentValue) + const ms = new MetaStep(name, prop); + ms.setContext(currentObject); + if (isAsyncFunction(currentValue)) currentValue = asyncWrapper(currentValue); + return ms.run.bind(ms, currentValue); } - return currentValue + return currentValue; }, has(target, prop) { - container.support[name] = container.support[name] || loadSupportObject(config[name]) - return prop in container.support[name] + container.support[name] = container.support[name] || loadSupportObject(config[name]); + return prop in container.support[name]; }, getOwnPropertyDescriptor(target, prop) { - container.support[name] = container.support[name] || loadSupportObject(config[name]) + container.support[name] = container.support[name] || loadSupportObject(config[name]); return { enumerable: true, configurable: true, value: this.get(target, prop), - } + }; }, ownKeys() { - container.support[name] = container.support[name] || loadSupportObject(config[name]) - return Reflect.ownKeys(container.support[name]) + container.support[name] = container.support[name] || loadSupportObject(config[name]); + return Reflect.ownKeys(container.support[name]); }, }, - ) + ); } - const keys = Reflect.ownKeys(config) + const keys = Reflect.ownKeys(config); return new Proxy( {}, { has(target, key) { - return keys.includes(key) + return keys.includes(key); }, ownKeys() { - return keys + return keys; }, getOwnPropertyDescriptor(target, prop) { return { enumerable: true, configurable: true, value: this.get(target, prop), - } + }; }, get(target, key) { - return lazyLoad(key) + return lazyLoad(key); }, }, - ) + ); } function createActor(actorPath) { - if (container.support.I) return container.support.I + if (container.support.I) return container.support.I; if (actorPath) { - container.support.I = loadSupportObject(actorPath) + container.support.I = loadSupportObject(actorPath); } else { - const actor = require('./actor') - container.support.I = actor() + const actor = require('./actor'); + container.support.I = actor(); } - return container.support.I + return container.support.I; } function createPlugins(config, options = {}) { - const plugins = {} + const plugins = {}; - const enabledPluginsByOptions = (options.plugins || '').split(',') + const enabledPluginsByOptions = (options.plugins || '').split(','); for (const pluginName in config) { - if (!config[pluginName]) config[pluginName] = {} + if (!config[pluginName]) config[pluginName] = {}; if (!config[pluginName].enabled && enabledPluginsByOptions.indexOf(pluginName) < 0) { - continue // plugin is disabled + continue; // plugin is disabled } - let module + let module; try { if (config[pluginName].require) { - module = config[pluginName].require + module = config[pluginName].require; if (module.startsWith('.')) { // local - module = path.resolve(global.codecept_dir, module) // custom plugin + module = path.resolve(global.codecept_dir, module); // custom plugin } } else { - module = `./plugin/${pluginName}` + module = `./plugin/${pluginName}`; } - plugins[pluginName] = require(module)(config[pluginName]) + plugins[pluginName] = require(module)(config[pluginName]); } catch (err) { - throw new Error(`Could not load plugin ${pluginName} from module '${module}':\n${err.message}\n${err.stack}`) + throw new Error(`Could not load plugin ${pluginName} from module '${module}':\n${err.message}\n${err.stack}`); } } - return plugins + return plugins; } function loadGherkinSteps(paths) { - global.Before = (fn) => event.dispatcher.on(event.test.started, fn) - global.After = (fn) => event.dispatcher.on(event.test.finished, fn) - global.Fail = (fn) => event.dispatcher.on(event.test.failed, fn) + global.Before = (fn) => event.dispatcher.on(event.test.started, fn); + global.After = (fn) => event.dispatcher.on(event.test.finished, fn); + global.Fail = (fn) => event.dispatcher.on(event.test.failed, fn); // If gherkin.steps is string, then this will iterate through that folder and send all step def js files to loadSupportObject // If gherkin.steps is Array, it will go the old way // This is done so that we need not enter all Step Definition files under config.gherkin.steps if (Array.isArray(paths)) { for (const path of paths) { - loadSupportObject(path, `Step Definition from ${path}`) + loadSupportObject(path, `Step Definition from ${path}`); } } else { - const folderPath = paths.startsWith('.') ? path.join(global.codecept_dir, paths) : '' + const folderPath = paths.startsWith('.') ? path.join(global.codecept_dir, paths) : ''; if (folderPath !== '') { glob.sync(folderPath).forEach((file) => { - loadSupportObject(file, `Step Definition from ${file}`) - }) + loadSupportObject(file, `Step Definition from ${file}`); + }); } } - delete global.Before - delete global.After - delete global.Fail + delete global.Before; + delete global.After; + delete global.Fail; } function loadSupportObject(modulePath, supportObjectName) { if (!modulePath) { - throw new Error(`Support object "${supportObjectName}" is not defined`) + throw new Error(`Support object "${supportObjectName}" is not defined`); } if (modulePath.charAt(0) === '.') { - modulePath = path.join(global.codecept_dir, modulePath) + modulePath = path.join(global.codecept_dir, modulePath); } try { - const obj = require(modulePath) + const obj = require(modulePath); // Handle different types of imports if (typeof obj === 'function') { // If it's a class (constructor function) if (obj.prototype && obj.prototype.constructor === obj) { - const ClassName = obj - return new ClassName() + const ClassName = obj; + return new ClassName(); } // If it's a regular function - return obj() + return obj(); } if (obj && Array.isArray(obj)) { - return obj + return obj; } // If it's a plain object if (obj && typeof obj === 'object') { - return obj + return obj; } throw new Error( `Support object "${supportObjectName}" should be an object, class, or function, but got ${typeof obj}`, - ) + ); } catch (err) { throw new Error( `Could not include object ${supportObjectName} from module '${modulePath}'\n${err.message}\n${err.stack}`, - ) + ); } } @@ -484,49 +492,41 @@ function loadSupportObject(modulePath, supportObjectName) { function loadTranslation(locale, vocabularies) { if (!locale) { - return Translation.createEmpty() + return Translation.createEmpty(); } - let translation + let translation; // check if it is a known translation if (Translation.langs[locale]) { - translation = new Translation(Translation.langs[locale]) + translation = new Translation(Translation.langs[locale]); } else if (fileExists(path.join(global.codecept_dir, locale))) { // get from a provided file instead - translation = Translation.createDefault() - translation.loadVocabulary(locale) + translation = Translation.createDefault(); + translation.loadVocabulary(locale); } else { - translation = Translation.createDefault() + translation = Translation.createDefault(); } - vocabularies.forEach((v) => translation.loadVocabulary(v)) + vocabularies.forEach((v) => translation.loadVocabulary(v)); - return translation + return translation; } function getHelperModuleName(helperName, config) { // classical require if (config[helperName].require) { if (config[helperName].require.startsWith('.')) { - return path.resolve(global.codecept_dir, config[helperName].require) // custom helper + return path.resolve(global.codecept_dir, config[helperName].require); // custom helper } - return config[helperName].require // plugin helper + return config[helperName].require; // plugin helper } // built-in helpers if (helperName.startsWith('@codeceptjs/')) { - return helperName + return helperName; } // built-in helpers - return `./helper/${helperName}` -} - -function createMocha(config, opts) { - const mochaConfig = config.mocha || {} - if (config.grep && !opts.grep) { - mochaConfig.grep = config.grep - } - container.mocha = MochaFactory.create(mochaConfig, opts || {}) + return `./helper/${helperName}`; } diff --git a/lib/heal.js b/lib/heal.js index 87234e439..a06e82f25 100644 --- a/lib/heal.js +++ b/lib/heal.js @@ -1,66 +1,66 @@ -const debug = require('debug')('codeceptjs:heal') -const colors = require('chalk') -const Container = require('./container') -const recorder = require('./recorder') -const output = require('./output') -const event = require('./event') +const debug = require('debug')('codeceptjs:heal'); +const colors = require('chalk'); +const Container = require('./container'); +const recorder = require('./recorder'); +const output = require('./output'); +const event = require('./event'); /** * @class */ class Heal { constructor() { - this.recipes = {} - this.fixes = [] - this.prepareFns = [] - this.contextName = null - this.numHealed = 0 + this.recipes = {}; + this.fixes = []; + this.prepareFns = []; + this.contextName = null; + this.numHealed = 0; } clear() { - this.recipes = {} - this.fixes = [] - this.prepareFns = [] - this.contextName = null - this.numHealed = 0 + this.recipes = {}; + this.fixes = []; + this.prepareFns = []; + this.contextName = null; + this.numHealed = 0; } addRecipe(name, opts = {}) { - if (!opts.priority) opts.priority = 0 + if (!opts.priority) opts.priority = 0; - if (!opts.fn) throw new Error(`Recipe ${name} should have a function 'fn' to execute`) + if (!opts.fn) throw new Error(`Recipe ${name} should have a function 'fn' to execute`); - this.recipes[name] = opts + this.recipes[name] = opts; } connectToEvents() { event.dispatcher.on(event.suite.before, (suite) => { - this.contextName = suite.title - }) + this.contextName = suite.title; + }); event.dispatcher.on(event.test.started, (test) => { - this.contextName = test.fullTitle() - }) + this.contextName = test.fullTitle(); + }); event.dispatcher.on(event.test.finished, () => { - this.contextName = null - }) + this.contextName = null; + }); } hasCorrespondingRecipes(step) { return ( matchRecipes(this.recipes, this.contextName).filter((r) => !r.steps || r.steps.includes(step.name)).length > 0 - ) + ); } async getCodeSuggestions(context) { - const suggestions = [] - const recipes = matchRecipes(this.recipes, this.contextName) + const suggestions = []; + const recipes = matchRecipes(this.recipes, this.contextName); - debug('Recipes', recipes) + debug('Recipes', recipes); - const currentOutputLevel = output.level() - output.level(0) + const currentOutputLevel = output.level(); + output.level(0); for (const [property, prepareFn] of Object.entries( recipes @@ -68,60 +68,60 @@ class Heal { .filter((p) => !!p) .reduce((acc, obj) => ({ ...acc, ...obj }), {}), )) { - if (!prepareFn) continue + if (!prepareFn) continue; - if (context[property]) continue - context[property] = await prepareFn(Container.support()) + if (context[property]) continue; + context[property] = await prepareFn(Container.support()); } - output.level(currentOutputLevel) + output.level(currentOutputLevel); for (const recipe of recipes) { - let snippets = await recipe.fn(context) - if (!Array.isArray(snippets)) snippets = [snippets] + let snippets = await recipe.fn(context); + if (!Array.isArray(snippets)) snippets = [snippets]; suggestions.push({ name: recipe.name, snippets, - }) + }); } - return suggestions.filter((s) => !isBlank(s.snippets)) + return suggestions.filter((s) => !isBlank(s.snippets)); } async healStep(failedStep, error, failureContext = {}) { - output.debug(`Trying to heal ${failedStep.toCode()} step`) + output.debug(`Trying to heal ${failedStep.toCode()} step`); Object.assign(failureContext, { error, step: failedStep, prevSteps: failureContext?.test?.steps?.slice(0, -1) || [], - }) + }); - const suggestions = await this.getCodeSuggestions(failureContext) + const suggestions = await this.getCodeSuggestions(failureContext); if (suggestions.length === 0) { - debug('No healing suggestions found') - throw error + debug('No healing suggestions found'); + throw error; } - output.debug(`Received ${suggestions.length} suggestion${suggestions.length === 1 ? '' : 's'}`) + output.debug(`Received ${suggestions.length} suggestion${suggestions.length === 1 ? '' : 's'}`); - debug(suggestions) + debug(suggestions); for (const suggestion of suggestions) { for (const codeSnippet of suggestion.snippets) { try { - debug('Executing', codeSnippet) + debug('Executing', codeSnippet); recorder.catch((e) => { - debug(e) - }) + debug(e); + }); if (typeof codeSnippet === 'string') { - const I = Container.support('I') - await eval(codeSnippet) // eslint-disable-line + const I = Container.support('I'); + await eval(codeSnippet); // eslint-disable-line } else if (typeof codeSnippet === 'function') { - await codeSnippet(Container.support()) + await codeSnippet(Container.support()); } this.fixes.push({ @@ -129,47 +129,47 @@ class Heal { test: failureContext?.test, step: failedStep, snippet: codeSnippet, - }) + }); recorder.add('healed', () => output.print( colors.bold.green(` Code healed successfully by ${suggestion.name}`), colors.gray('(no errors thrown)'), ), - ) - this.numHealed++ + ); + this.numHealed++; // recorder.session.restore(); - return + return; } catch (err) { - debug('Failed to execute code', err) - recorder.ignoreErr(err) // healing did not help - recorder.catchWithoutStop(err) - await recorder.promise() // wait for all promises to resolve + debug('Failed to execute code', err); + recorder.ignoreErr(err); // healing did not help + recorder.catchWithoutStop(err); + await recorder.promise(); // wait for all promises to resolve } } } - output.debug(`Couldn't heal the code for ${failedStep.toCode()}`) - recorder.throw(error) + output.debug(`Couldn't heal the code for ${failedStep.toCode()}`); + recorder.throw(error); } static setDefaultHealers() { - require('./template/heal') + require('./template/heal'); } } -const heal = new Heal() +const heal = new Heal(); -module.exports = heal +module.exports = heal; function matchRecipes(recipes, contextName) { return Object.entries(recipes) .filter(([, recipe]) => !contextName || !recipe.grep || new RegExp(recipe.grep).test(contextName)) .sort(([, a], [, b]) => a.priority - b.priority) .map(([name, recipe]) => { - recipe.name = name - return recipe + recipe.name = name; + return recipe; }) - .filter((r) => !!r.fn) + .filter((r) => !!r.fn); } function isBlank(value) { @@ -178,5 +178,5 @@ function isBlank(value) { (Array.isArray(value) && value.length === 0) || (typeof value === 'object' && Object.keys(value).length === 0) || (typeof value === 'string' && value.trim() === '') - ) + ); } diff --git a/lib/helper/JSONResponse.js b/lib/helper/JSONResponse.js index 29c5cadda..c0584c291 100644 --- a/lib/helper/JSONResponse.js +++ b/lib/helper/JSONResponse.js @@ -1,6 +1,6 @@ -const Helper = require('@codeceptjs/helper') -const assert = require('assert') -const joi = require('joi') +const Helper = require('@codeceptjs/helper'); +const assert = require('assert'); +const joi = require('joi'); /** * This helper allows performing assertions on JSON responses paired with following helpers: @@ -60,35 +60,35 @@ const joi = require('joi') */ class JSONResponse extends Helper { constructor(config = {}) { - super(config) + super(config); this.options = { requestHelper: 'REST', - } - this.options = { ...this.options, ...config } + }; + this.options = { ...this.options, ...config }; } _beforeSuite() { - this.response = null + this.response = null; if (!this.helpers[this.options.requestHelper]) { throw new Error( `Error setting JSONResponse, helper ${this.options.requestHelper} is not enabled in config, helpers: ${Object.keys(this.helpers)}`, - ) + ); } // connect to REST helper this.helpers[this.options.requestHelper].config.onResponse = (response) => { - this.response = response - } + this.response = response; + }; } _before() { - this.response = null + this.response = null; } static _checkRequirements() { try { - require('joi') + require('joi'); } catch (e) { - return ['joi'] + return ['joi']; } } @@ -102,8 +102,8 @@ class JSONResponse extends Helper { * @param {number} code */ seeResponseCodeIs(code) { - this._checkResponseReady() - assert.strictEqual(this.response.status, code, 'Response code is not the same as expected') + this._checkResponseReady(); + assert.strictEqual(this.response.status, code, 'Response code is not the same as expected'); } /** @@ -116,32 +116,32 @@ class JSONResponse extends Helper { * @param {number} code */ dontSeeResponseCodeIs(code) { - this._checkResponseReady() - assert.notStrictEqual(this.response.status, code) + this._checkResponseReady(); + assert.notStrictEqual(this.response.status, code); } /** * Checks that the response code is 4xx */ seeResponseCodeIsClientError() { - this._checkResponseReady() - assert(this.response.status >= 400 && this.response.status < 500) + this._checkResponseReady(); + assert(this.response.status >= 400 && this.response.status < 500); } /** * Checks that the response code is 3xx */ seeResponseCodeIsRedirection() { - this._checkResponseReady() - assert(this.response.status >= 300 && this.response.status < 400) + this._checkResponseReady(); + assert(this.response.status >= 300 && this.response.status < 400); } /** * Checks that the response code is 5xx */ seeResponseCodeIsServerError() { - this._checkResponseReady() - assert(this.response.status >= 500 && this.response.status < 600) + this._checkResponseReady(); + assert(this.response.status >= 500 && this.response.status < 600); } /** @@ -153,8 +153,8 @@ class JSONResponse extends Helper { * ``` */ seeResponseCodeIsSuccessful() { - this._checkResponseReady() - assert(this.response.status >= 200 && this.response.status < 300) + this._checkResponseReady(); + assert(this.response.status >= 200 && this.response.status < 300); } /** @@ -175,21 +175,21 @@ class JSONResponse extends Helper { * @param {object} json */ seeResponseContainsJson(json = {}) { - this._checkResponseReady() + this._checkResponseReady(); if (Array.isArray(this.response.data)) { - let found = false + let found = false; for (const el of this.response.data) { try { - this._assertContains(el, json) - found = true - break + this._assertContains(el, json); + found = true; + break; } catch (err) { - continue + continue; } } - assert(found, `No elements in array matched ${JSON.stringify(json)}`) + assert(found, `No elements in array matched ${JSON.stringify(json)}`); } else { - this._assertContains(this.response.data, json) + this._assertContains(this.response.data, json); } } @@ -211,21 +211,21 @@ class JSONResponse extends Helper { * @param {object} json */ dontSeeResponseContainsJson(json = {}) { - this._checkResponseReady() + this._checkResponseReady(); if (Array.isArray(this.response.data)) { for (const data of this.response.data) { try { - this._assertContains(data, json) - assert.fail(`Found matching element: ${JSON.stringify(data)}`) + this._assertContains(data, json); + assert.fail(`Found matching element: ${JSON.stringify(data)}`); } catch (err) { // expected to fail - continue + continue; } } } else { try { - this._assertContains(this.response.data, json) - assert.fail('Response contains the JSON') + this._assertContains(this.response.data, json); + assert.fail('Response contains the JSON'); } catch (err) { // expected to fail } @@ -252,16 +252,16 @@ class JSONResponse extends Helper { * @param {array} keys */ seeResponseContainsKeys(keys = []) { - this._checkResponseReady() + this._checkResponseReady(); if (Array.isArray(this.response.data)) { for (const data of this.response.data) { for (const key of keys) { - assert(key in data, `Key "${key}" is not found in ${JSON.stringify(data)}`) + assert(key in data, `Key "${key}" is not found in ${JSON.stringify(data)}`); } } } else { for (const key of keys) { - assert(key in this.response.data, `Key "${key}" is not found in ${JSON.stringify(this.response.data)}`) + assert(key in this.response.data, `Key "${key}" is not found in ${JSON.stringify(this.response.data)}`); } } } @@ -281,10 +281,10 @@ class JSONResponse extends Helper { * @param {function} fn */ seeResponseValidByCallback(fn) { - this._checkResponseReady() - fn({ ...this.response, assert }) - const body = fn.toString() - fn.toString = () => `${body.split('\n')[1]}...` + this._checkResponseReady(); + fn({ ...this.response, assert }); + const body = fn.toString(); + fn.toString = () => `${body.split('\n')[1]}...`; } /** @@ -298,8 +298,8 @@ class JSONResponse extends Helper { * @param {object} resp */ seeResponseEquals(resp) { - this._checkResponseReady() - assert.deepStrictEqual(this.response.data, resp) + this._checkResponseReady(); + assert.deepStrictEqual(this.response.data, resp); } /** @@ -330,33 +330,33 @@ class JSONResponse extends Helper { * @param {any} fnOrSchema */ seeResponseMatchesJsonSchema(fnOrSchema) { - this._checkResponseReady() - let schema = fnOrSchema + this._checkResponseReady(); + let schema = fnOrSchema; if (typeof fnOrSchema === 'function') { - schema = fnOrSchema(joi) - const body = fnOrSchema.toString() - fnOrSchema.toString = () => `${body.split('\n')[1]}...` + schema = fnOrSchema(joi); + const body = fnOrSchema.toString(); + fnOrSchema.toString = () => `${body.split('\n')[1]}...`; } - if (!schema) throw new Error('Empty Joi schema provided, see https://joi.dev/ for details') - if (!joi.isSchema(schema)) throw new Error('Invalid Joi schema provided, see https://joi.dev/ for details') - schema.toString = () => schema.describe() - joi.assert(this.response.data, schema) + if (!schema) throw new Error('Empty Joi schema provided, see https://joi.dev/ for details'); + if (!joi.isSchema(schema)) throw new Error('Invalid Joi schema provided, see https://joi.dev/ for details'); + schema.toString = () => schema.describe(); + joi.assert(this.response.data, schema); } _checkResponseReady() { - if (!this.response) throw new Error('Response is not available') + if (!this.response) throw new Error('Response is not available'); } _assertContains(actual, expected) { for (const key in expected) { - assert(key in actual, `Key "${key}" not found in ${JSON.stringify(actual)}`) + assert(key in actual, `Key "${key}" not found in ${JSON.stringify(actual)}`); if (typeof expected[key] === 'object' && expected[key] !== null) { - this._assertContains(actual[key], expected[key]) + this._assertContains(actual[key], expected[key]); } else { - assert.deepStrictEqual(actual[key], expected[key], `Values for key "${key}" don't match`) + assert.deepStrictEqual(actual[key], expected[key], `Values for key "${key}" don't match`); } } } } -module.exports = JSONResponse +module.exports = JSONResponse; diff --git a/lib/helper/extras/PlaywrightPropEngine.js b/lib/helper/extras/PlaywrightPropEngine.js index 3aa1deeac..5d9054159 100644 --- a/lib/helper/extras/PlaywrightPropEngine.js +++ b/lib/helper/extras/PlaywrightPropEngine.js @@ -4,26 +4,26 @@ module.exports.createValueEngine = () => { // Can return undefined if unable to create one. create(root, target) { - return null + return null; }, // Returns the first element matching given selector in the root's subtree. query(root, selector) { if (!root) { - return null + return null; } - return `${root.value}`.includes(selector) ? root : null + return `${root.value}`.includes(selector) ? root : null; }, // Returns all elements matching given selector in the root's subtree. queryAll(root, selector) { if (!root) { - return null + return null; } - return `${root.value}`.includes(selector) ? root : null + return `${root.value}`.includes(selector) ? root : null; }, - } -} + }; +}; module.exports.createDisabledEngine = () => { return { @@ -31,25 +31,25 @@ module.exports.createDisabledEngine = () => { // Can return undefined if unable to create one. create(root, target) { - return null + return null; }, // Returns the first element matching given selector in the root's subtree. query(root, value) { - const bool = value === 'true' + const bool = value === 'true'; if (!root) { - return null + return null; } - return root.disabled === bool ? root : null + return root.disabled === bool ? root : null; }, // Returns all elements matching given selector in the root's subtree. queryAll(root, value) { - const bool = value === 'true' + const bool = value === 'true'; if (!root) { - return null + return null; } - return root.disabled === bool ? root : null + return root.disabled === bool ? root : null; }, - } -} + }; +}; diff --git a/lib/helper/network/utils.js b/lib/helper/network/utils.js index dc0bc5734..7e3c88bc9 100644 --- a/lib/helper/network/utils.js +++ b/lib/helper/network/utils.js @@ -1,133 +1,133 @@ const createAdvancedTestResults = (url, dataToCheck, requests) => { // Creates advanced test results for a network traffic check. // Advanced test results only applies when expected parameters are set - if (!dataToCheck) return '' + if (!dataToCheck) return ''; - let urlFound = false - let advancedResults + let urlFound = false; + let advancedResults; requests.forEach((request) => { // url not found in this request. continue with next request - if (urlFound || !request.url.match(new RegExp(url))) return - urlFound = true + if (urlFound || !request.url.match(new RegExp(url))) return; + urlFound = true; // Url found. Now we create advanced test report for that URL and show which parameters failed if (!request.requestPostData) { - advancedResults = allParameterValuePairsMatchExtreme(extractQueryObjects(request.url), dataToCheck) + advancedResults = allParameterValuePairsMatchExtreme(extractQueryObjects(request.url), dataToCheck); } else if (request.requestPostData) { - advancedResults = allRequestPostDataValuePairsMatchExtreme(request.requestPostData, dataToCheck) + advancedResults = allRequestPostDataValuePairsMatchExtreme(request.requestPostData, dataToCheck); } - }) - return advancedResults -} + }); + return advancedResults; +}; const extractQueryObjects = (queryString) => { // Converts a string of GET parameters into an array of parameter objects. Each parameter object contains the properties "name" and "value". if (queryString.indexOf('?') === -1) { - return [] + return []; } - const queryObjects = [] + const queryObjects = []; - const queryPart = queryString.split('?')[1] + const queryPart = queryString.split('?')[1]; - const queryParameters = queryPart.split('&') + const queryParameters = queryPart.split('&'); queryParameters.forEach((queryParameter) => { - const keyValue = queryParameter.split('=') - const queryObject = {} + const keyValue = queryParameter.split('='); + const queryObject = {}; - queryObject.name = keyValue[0] - queryObject.value = decodeURIComponent(keyValue[1]) - queryObjects.push(queryObject) - }) + queryObject.name = keyValue[0]; + queryObject.value = decodeURIComponent(keyValue[1]); + queryObjects.push(queryObject); + }); - return queryObjects -} + return queryObjects; +}; const allParameterValuePairsMatchExtreme = (queryStringObject, advancedExpectedParameterValuePairs) => { // More advanced check if all request parameters match with the expectations - let littleReport = '\nQuery parameters:\n' - let success = true + let littleReport = '\nQuery parameters:\n'; + let success = true; for (const expectedKey in advancedExpectedParameterValuePairs) { if (!Object.prototype.hasOwnProperty.call(advancedExpectedParameterValuePairs, expectedKey)) { - continue + continue; } - let parameterFound = false - const expectedValue = advancedExpectedParameterValuePairs[expectedKey] + let parameterFound = false; + const expectedValue = advancedExpectedParameterValuePairs[expectedKey]; for (const queryParameter of queryStringObject) { if (queryParameter.name === expectedKey) { - parameterFound = true + parameterFound = true; if (expectedValue === undefined) { - littleReport += ` ${expectedKey.padStart(10, ' ')}\n` + littleReport += ` ${expectedKey.padStart(10, ' ')}\n`; } else if (typeof expectedValue === 'object' && expectedValue.base64) { - const decodedActualValue = Buffer.from(queryParameter.value, 'base64').toString('utf8') + const decodedActualValue = Buffer.from(queryParameter.value, 'base64').toString('utf8'); if (decodedActualValue === expectedValue.base64) { - littleReport += ` ${expectedKey.padStart(10, ' ')} = base64(${expectedValue.base64})\n` + littleReport += ` ${expectedKey.padStart(10, ' ')} = base64(${expectedValue.base64})\n`; } else { - littleReport += ` ✖ ${expectedKey.padStart(10, ' ')} = base64(${expectedValue.base64}) -> actual value: "base64(${decodedActualValue})"\n` - success = false + littleReport += ` ✖ ${expectedKey.padStart(10, ' ')} = base64(${expectedValue.base64}) -> actual value: "base64(${decodedActualValue})"\n`; + success = false; } } else if (queryParameter.value === expectedValue) { - littleReport += ` ${expectedKey.padStart(10, ' ')} = ${expectedValue}\n` + littleReport += ` ${expectedKey.padStart(10, ' ')} = ${expectedValue}\n`; } else { - littleReport += ` ✖ ${expectedKey.padStart(10, ' ')} = ${expectedValue} -> actual value: "${queryParameter.value}"\n` - success = false + littleReport += ` ✖ ${expectedKey.padStart(10, ' ')} = ${expectedValue} -> actual value: "${queryParameter.value}"\n`; + success = false; } } } if (parameterFound === false) { - littleReport += ` ✖ ${expectedKey.padStart(10, ' ')}${expectedValue ? ` = ${JSON.stringify(expectedValue)}` : ''} -> parameter not found in request\n` - success = false + littleReport += ` ✖ ${expectedKey.padStart(10, ' ')}${expectedValue ? ` = ${JSON.stringify(expectedValue)}` : ''} -> parameter not found in request\n`; + success = false; } } - return success ? true : littleReport -} + return success ? true : littleReport; +}; const allRequestPostDataValuePairsMatchExtreme = (RequestPostDataObject, advancedExpectedRequestPostValuePairs) => { // More advanced check if all request post data match with the expectations - let littleReport = '\nRequest Post Data:\n' - let success = true + let littleReport = '\nRequest Post Data:\n'; + let success = true; for (const expectedKey in advancedExpectedRequestPostValuePairs) { if (!Object.prototype.hasOwnProperty.call(advancedExpectedRequestPostValuePairs, expectedKey)) { - continue + continue; } - let keyFound = false - const expectedValue = advancedExpectedRequestPostValuePairs[expectedKey] + let keyFound = false; + const expectedValue = advancedExpectedRequestPostValuePairs[expectedKey]; for (const [key, value] of Object.entries(RequestPostDataObject)) { if (key === expectedKey) { - keyFound = true + keyFound = true; if (expectedValue === undefined) { - littleReport += ` ${expectedKey.padStart(10, ' ')}\n` + littleReport += ` ${expectedKey.padStart(10, ' ')}\n`; } else if (typeof expectedValue === 'object' && expectedValue.base64) { - const decodedActualValue = Buffer.from(value, 'base64').toString('utf8') + const decodedActualValue = Buffer.from(value, 'base64').toString('utf8'); if (decodedActualValue === expectedValue.base64) { - littleReport += ` ${expectedKey.padStart(10, ' ')} = base64(${expectedValue.base64})\n` + littleReport += ` ${expectedKey.padStart(10, ' ')} = base64(${expectedValue.base64})\n`; } else { - littleReport += ` ✖ ${expectedKey.padStart(10, ' ')} = base64(${expectedValue.base64}) -> actual value: "base64(${decodedActualValue})"\n` - success = false + littleReport += ` ✖ ${expectedKey.padStart(10, ' ')} = base64(${expectedValue.base64}) -> actual value: "base64(${decodedActualValue})"\n`; + success = false; } } else if (value === expectedValue) { - littleReport += ` ${expectedKey.padStart(10, ' ')} = ${expectedValue}\n` + littleReport += ` ${expectedKey.padStart(10, ' ')} = ${expectedValue}\n`; } else { - littleReport += ` ✖ ${expectedKey.padStart(10, ' ')} = ${expectedValue} -> actual value: "${value}"\n` - success = false + littleReport += ` ✖ ${expectedKey.padStart(10, ' ')} = ${expectedValue} -> actual value: "${value}"\n`; + success = false; } } } if (keyFound === false) { - littleReport += ` ✖ ${expectedKey.padStart(10, ' ')}${expectedValue ? ` = ${JSON.stringify(expectedValue)}` : ''} -> key not found in request\n` - success = false + littleReport += ` ✖ ${expectedKey.padStart(10, ' ')}${expectedValue ? ` = ${JSON.stringify(expectedValue)}` : ''} -> key not found in request\n`; + success = false; } } - return success ? true : littleReport -} + return success ? true : littleReport; +}; /** * Returns all URLs of all network requests recorded so far during execution of test scenario. @@ -136,11 +136,11 @@ const allRequestPostDataValuePairsMatchExtreme = (RequestPostDataObject, advance * @private */ function getTrafficDump() { - let dumpedTraffic = '' + let dumpedTraffic = ''; this.requests.forEach((request) => { - dumpedTraffic += `${request.method} - ${request.url}\n` - }) - return dumpedTraffic + dumpedTraffic += `${request.method} - ${request.url}\n`; + }); + return dumpedTraffic; } /** @@ -152,29 +152,29 @@ function getTrafficDump() { * @private */ function isInTraffic(url, parameters) { - let isInTraffic = false + let isInTraffic = false; this.requests.forEach((request) => { if (isInTraffic) { - return // We already found traffic. Continue with next request + return; // We already found traffic. Continue with next request } if (!request.url.match(new RegExp(url))) { - return // url not found in this request. continue with next request + return; // url not found in this request. continue with next request } // URL has matched. Now we check the parameters if (parameters) { - const advancedReport = allParameterValuePairsMatchExtreme(extractQueryObjects(request.url), parameters) + const advancedReport = allParameterValuePairsMatchExtreme(extractQueryObjects(request.url), parameters); if (advancedReport === true) { - isInTraffic = true + isInTraffic = true; } } else { - isInTraffic = true + isInTraffic = true; } - }) + }); - return isInTraffic + return isInTraffic; } module.exports = { @@ -184,4 +184,4 @@ module.exports = { allRequestPostDataValuePairsMatchExtreme, getTrafficDump, isInTraffic, -} +}; diff --git a/lib/helper/testcafe/testcafe-utils.js b/lib/helper/testcafe/testcafe-utils.js index 696794766..af13c3a04 100644 --- a/lib/helper/testcafe/testcafe-utils.js +++ b/lib/helper/testcafe/testcafe-utils.js @@ -1,15 +1,15 @@ -const { ClientFunction } = require('testcafe') +const { ClientFunction } = require('testcafe'); -const assert = require('assert') -const fs = require('fs') -const path = require('path') -const { getParamNames } = require('../../utils') +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const { getParamNames } = require('../../utils'); const createTestFile = () => { - assert(global.output_dir, 'global.output_dir must be set') + assert(global.output_dir, 'global.output_dir must be set'); - const testFile = path.join(global.output_dir, `${Date.now()}_test.js`) - const testControllerHolderDir = __dirname.replace(/\\/g, '/') + const testFile = path.join(global.output_dir, `${Date.now()}_test.js`); + const testControllerHolderDir = __dirname.replace(/\\/g, '/'); fs.writeFileSync( testFile, @@ -17,40 +17,40 @@ const createTestFile = () => { fixture("fixture")\n test\n ("test", testControllerHolder.capture)`, - ) + ); - return testFile -} + return testFile; +}; // TODO Better error mapping (actual, expected) const mapError = (testcafeError) => { // console.log('TODO map error better', JSON.stringify(testcafeError, null, 2)); if (testcafeError.errMsg) { - throw new Error(testcafeError.errMsg) + throw new Error(testcafeError.errMsg); } - const errorInfo = `${testcafeError.callsite ? JSON.stringify(testcafeError.callsite) : ''} ${testcafeError.apiFnChain || JSON.stringify(testcafeError)}` - throw new Error(`TestCafe Error: ${errorInfo}`) -} + const errorInfo = `${testcafeError.callsite ? JSON.stringify(testcafeError.callsite) : ''} ${testcafeError.apiFnChain || JSON.stringify(testcafeError)}`; + throw new Error(`TestCafe Error: ${errorInfo}`); +}; function createClientFunction(func, args) { if (!args || !args.length) { - return ClientFunction(func) + return ClientFunction(func); } - const paramNames = getParamNames(func) - const dependencies = {} - paramNames.forEach((param, i) => (dependencies[param] = args[i])) + const paramNames = getParamNames(func); + const dependencies = {}; + paramNames.forEach((param, i) => (dependencies[param] = args[i])); - return ClientFunction(getFuncBody(func), { dependencies }) + return ClientFunction(getFuncBody(func), { dependencies }); } function getFuncBody(func) { - let fnStr = func.toString() - const arrowIndex = fnStr.indexOf('=>') + let fnStr = func.toString(); + const arrowIndex = fnStr.indexOf('=>'); if (arrowIndex >= 0) { - fnStr = fnStr.slice(arrowIndex + 2) + fnStr = fnStr.slice(arrowIndex + 2); // eslint-disable-next-line no-eval - return eval(`() => ${fnStr}`) + return eval(`() => ${fnStr}`); } // TODO: support general functions } @@ -59,4 +59,4 @@ module.exports = { createTestFile, mapError, createClientFunction, -} +}; diff --git a/lib/interfaces/inject.js b/lib/interfaces/inject.js index 0d88b725f..712020ba3 100644 --- a/lib/interfaces/inject.js +++ b/lib/interfaces/inject.js @@ -1,24 +1,24 @@ -const parser = require('../parser') +const parser = require('../parser'); const getInjectedArguments = (fn, test) => { - const container = require('../container') - const testArgs = {} - const params = parser.getParams(fn) || [] - const objects = container.support() + const container = require('../container'); + const testArgs = {}; + const params = parser.getParams(fn) || []; + const objects = container.support(); for (const key of params) { - testArgs[key] = {} + testArgs[key] = {}; if (test && test.inject && test.inject[key]) { // @FIX: need fix got inject - testArgs[key] = test.inject[key] - continue + testArgs[key] = test.inject[key]; + continue; } if (!objects[key]) { - throw new Error(`Object of type ${key} is not defined in container`) + throw new Error(`Object of type ${key} is not defined in container`); } - testArgs[key] = container.support(key) + testArgs[key] = container.support(key); } - return testArgs -} + return testArgs; +}; -module.exports.getInjectedArguments = getInjectedArguments +module.exports.getInjectedArguments = getInjectedArguments; diff --git a/lib/output.js b/lib/output.js index 5f9fc0732..3d91c68aa 100644 --- a/lib/output.js +++ b/lib/output.js @@ -1,6 +1,6 @@ -const colors = require('chalk') -const figures = require('figures') -const { maskSensitiveData } = require('invisi-data') +const colors = require('chalk'); +const figures = require('figures'); +const { maskSensitiveData } = require('invisi-data'); const styles = { error: colors.bgRed.white.bold, @@ -10,11 +10,11 @@ const styles = { debug: colors.cyan, log: colors.grey, bold: colors.bold, -} +}; -let outputLevel = 0 -let outputProcess = '' -let newline = true +let outputLevel = 0; +let outputProcess = ''; +let newline = true; /** * @alias output @@ -28,7 +28,7 @@ module.exports = { stepShift: 0, standWithUkraine() { - return `#${colors.bold.yellow('StandWith')}${colors.bold.cyan('Ukraine')}` + return `#${colors.bold.yellow('StandWith')}${colors.bold.cyan('Ukraine')}`; }, /** @@ -37,8 +37,8 @@ module.exports = { * @returns {number} */ level(level) { - if (level !== undefined) outputLevel = level - return outputLevel + if (level !== undefined) outputLevel = level; + return outputLevel; }, /** @@ -48,9 +48,9 @@ module.exports = { * @returns {string} */ process(process) { - if (process === null) return (outputProcess = '') - if (process) outputProcess = String(process).length === 1 ? `[0${process}]` : `[${process}]` - return outputProcess + if (process === null) return (outputProcess = ''); + if (process) outputProcess = String(process).length === 1 ? `[0${process}]` : `[${process}]`; + return outputProcess; }, /** @@ -58,9 +58,9 @@ module.exports = { * @param {string} msg */ debug(msg) { - const _msg = isMaskedData() ? maskSensitiveData(msg) : msg + const _msg = isMaskedData() ? maskSensitiveData(msg) : msg; if (outputLevel >= 2) { - print(' '.repeat(this.stepShift), styles.debug(`${figures.pointerSmall} ${_msg}`)) + print(' '.repeat(this.stepShift), styles.debug(`${figures.pointerSmall} ${_msg}`)); } }, @@ -69,9 +69,9 @@ module.exports = { * @param {string} msg */ log(msg) { - const _msg = isMaskedData() ? maskSensitiveData(msg) : msg + const _msg = isMaskedData() ? maskSensitiveData(msg) : msg; if (outputLevel >= 3) { - print(' '.repeat(this.stepShift), styles.log(truncate(` ${_msg}`, this.spaceShift))) + print(' '.repeat(this.stepShift), styles.log(truncate(` ${_msg}`, this.spaceShift))); } }, @@ -80,7 +80,7 @@ module.exports = { * @param {string} msg */ error(msg) { - print(styles.error(msg)) + print(styles.error(msg)); }, /** @@ -88,7 +88,7 @@ module.exports = { * @param {string} msg */ success(msg) { - print(styles.success(msg)) + print(styles.success(msg)); }, /** @@ -97,7 +97,7 @@ module.exports = { * @param {string} msg */ plugin(pluginName, msg = '') { - this.debug(`<${pluginName}> ${msg}`) + this.debug(`<${pluginName}> ${msg}`); }, /** @@ -105,26 +105,26 @@ module.exports = { * @param {CodeceptJS.Step} step */ step(step) { - if (outputLevel === 0) return - if (!step) return + if (outputLevel === 0) return; + if (!step) return; // Avoid to print non-gherkin steps, when gherkin is running for --steps mode if (outputLevel === 1) { if (typeof step === 'object' && step.hasBDDAncestor()) { - return + return; } } - let stepLine = step.toString() + let stepLine = step.toString(); if (step.metaStep && outputLevel >= 1) { // this.stepShift += 2; - stepLine = colors.green(truncate(stepLine, this.spaceShift)) + stepLine = colors.green(truncate(stepLine, this.spaceShift)); } if (step.comment) { - stepLine += colors.grey(step.comment.split('\n').join('\n' + ' '.repeat(4))) + stepLine += colors.grey(step.comment.split('\n').join('\n' + ' '.repeat(4))); } - const _stepLine = isMaskedData() ? maskSensitiveData(stepLine) : stepLine - print(' '.repeat(this.stepShift), truncate(_stepLine, this.spaceShift)) + const _stepLine = isMaskedData() ? maskSensitiveData(stepLine) : stepLine; + print(' '.repeat(this.stepShift), truncate(_stepLine, this.spaceShift)); }, /** @namespace */ @@ -133,9 +133,9 @@ module.exports = { * @param {Mocha.Suite} suite */ started: (suite) => { - if (!suite.title) return - print(`${colors.bold(suite.title)} --`) - if (suite.comment) print(suite.comment) + if (!suite.title) return; + print(`${colors.bold(suite.title)} --`); + if (suite.comment) print(suite.comment); }, }, @@ -145,25 +145,25 @@ module.exports = { * @param {Mocha.Test} test */ started(test) { - print(` ${colors.magenta.bold(test.title)}`) + print(` ${colors.magenta.bold(test.title)}`); }, /** * @param {Mocha.Test} test */ passed(test) { - print(` ${colors.green.bold(figures.tick)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`) + print(` ${colors.green.bold(figures.tick)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`); }, /** * @param {Mocha.Test} test */ failed(test) { - print(` ${colors.red.bold(figures.cross)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`) + print(` ${colors.red.bold(figures.cross)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`); }, /** * @param {Mocha.Test} test */ skipped(test) { - print(` ${colors.yellow.bold('S')} ${test.title}`) + print(` ${colors.yellow.bold('S')} ${test.title}`); }, }, @@ -179,15 +179,15 @@ module.exports = { * @param {Mocha.Test} test */ passed(test) { - print(` ${colors.green.bold(`${figures.tick} OK`)} ${colors.grey(`in ${test.duration}ms`)}`) - print() + print(` ${colors.green.bold(`${figures.tick} OK`)} ${colors.grey(`in ${test.duration}ms`)}`); + print(); }, /** * @param {Mocha.Test} test */ failed(test) { - print(` ${colors.red.bold(`${figures.cross} FAILED`)} ${colors.grey(`in ${test.duration}ms`)}`) - print() + print(` ${colors.red.bold(`${figures.cross} FAILED`)} ${colors.grey(`in ${test.duration}ms`)}`); + print(); }, }, @@ -199,9 +199,9 @@ module.exports = { */ say(message, color = 'cyan') { if (colors[color] === undefined) { - color = 'cyan' + color = 'cyan'; } - if (outputLevel >= 1) print(` ${colors[color].bold(message)}`) + if (outputLevel >= 1) print(` ${colors[color].bold(message)}`); }, /** @@ -211,54 +211,54 @@ module.exports = { * @param {number|string} duration */ result(passed, failed, skipped, duration, failedHooks = 0) { - let style = colors.bgGreen - let msg = ` ${passed || 0} passed` - let status = style.bold(' OK ') + let style = colors.bgGreen; + let msg = ` ${passed || 0} passed`; + let status = style.bold(' OK '); if (failed) { - style = style.bgRed - status = style.bold(' FAIL ') - msg += `, ${failed} failed` + style = style.bgRed; + status = style.bold(' FAIL '); + msg += `, ${failed} failed`; } if (failedHooks > 0) { - style = style.bgRed - status = style.bold(' FAIL ') - msg += `, ${failedHooks} failedHooks` + style = style.bgRed; + status = style.bold(' FAIL '); + msg += `, ${failedHooks} failedHooks`; } - status += style.grey(' |') + status += style.grey(' |'); if (skipped) { - if (!failed) style = style.bgYellow - msg += `, ${skipped} skipped` + if (!failed) style = style.bgYellow; + msg += `, ${skipped} skipped`; } - msg += ' ' - print(status + style(msg) + colors.grey(` // ${duration}`)) + msg += ' '; + print(status + style(msg) + colors.grey(` // ${duration}`)); }, -} +}; function print(...msg) { if (outputProcess) { - msg.unshift(outputProcess) + msg.unshift(outputProcess); } if (!newline) { - console.log() - newline = true + console.log(); + newline = true; } - console.log.apply(this, msg) + console.log.apply(this, msg); } function truncate(msg, gap = 0) { if (msg.indexOf('\n') > 0 || outputLevel >= 3) { - return msg // don't cut multi line steps or on verbose log level + return msg; // don't cut multi line steps or on verbose log level } - const width = (process.stdout.columns || 200) - gap - 4 + const width = (process.stdout.columns || 200) - gap - 4; if (msg.length > width) { - msg = msg.substr(0, width - 1) + figures.ellipsis + msg = msg.substr(0, width - 1) + figures.ellipsis; } - return msg + return msg; } function isMaskedData() { - return global.maskSensitiveData === true || false + return global.maskSensitiveData === true || false; } diff --git a/lib/pause.js b/lib/pause.js index c05d0ba82..56ebdd681 100644 --- a/lib/pause.js +++ b/lib/pause.js @@ -1,61 +1,61 @@ -const colors = require('chalk') -const readline = require('readline') -const ora = require('ora-classic') -const debug = require('debug')('codeceptjs:pause') - -const container = require('./container') -const history = require('./history') -const store = require('./store') -const aiAssistant = require('./ai') -const recorder = require('./recorder') -const event = require('./event') -const output = require('./output') -const { methodsOfObject } = require('./utils') +const colors = require('chalk'); +const readline = require('readline'); +const ora = require('ora-classic'); +const debug = require('debug')('codeceptjs:pause'); + +const container = require('./container'); +const history = require('./history'); +const store = require('./store'); +const aiAssistant = require('./ai'); +const recorder = require('./recorder'); +const event = require('./event'); +const output = require('./output'); +const { methodsOfObject } = require('./utils'); // npm install colors -let rl -let nextStep -let finish -let next -let registeredVariables = {} +let rl; +let nextStep; +let finish; +let next; +let registeredVariables = {}; /** * Pauses test execution and starts interactive shell * @param {Object} [passedObject] */ const pause = function (passedObject = {}) { - if (store.dryRun) return + if (store.dryRun) return; - next = false + next = false; // add listener to all next steps to provide next() functionality event.dispatcher.on(event.step.after, () => { recorder.add('Start next pause session', () => { - if (!next) return - return pauseSession() - }) - }) - recorder.add('Start new session', () => pauseSession(passedObject)) -} + if (!next) return; + return pauseSession(); + }); + }); + recorder.add('Start new session', () => pauseSession(passedObject)); +}; function pauseSession(passedObject = {}) { - registeredVariables = passedObject - recorder.session.start('pause') + registeredVariables = passedObject; + recorder.session.start('pause'); if (!next) { - let vars = Object.keys(registeredVariables).join(', ') - if (vars) vars = `(vars: ${vars})` + let vars = Object.keys(registeredVariables).join(', '); + if (vars) vars = `(vars: ${vars})`; - output.print(colors.yellow(' Interactive shell started')) - output.print(colors.yellow(' Use JavaScript syntax to try steps in action')) - output.print(colors.yellow(` - Press ${colors.bold('ENTER')} to run the next step`)) - output.print(colors.yellow(` - Press ${colors.bold('TAB')} twice to see all available commands`)) - output.print(colors.yellow(` - Type ${colors.bold('exit')} + Enter to exit the interactive shell`)) - output.print(colors.yellow(` - Prefix ${colors.bold('=>')} to run js commands ${colors.bold(vars)}`)) + output.print(colors.yellow(' Interactive shell started')); + output.print(colors.yellow(' Use JavaScript syntax to try steps in action')); + output.print(colors.yellow(` - Press ${colors.bold('ENTER')} to run the next step`)); + output.print(colors.yellow(` - Press ${colors.bold('TAB')} twice to see all available commands`)); + output.print(colors.yellow(` - Type ${colors.bold('exit')} + Enter to exit the interactive shell`)); + output.print(colors.yellow(` - Prefix ${colors.bold('=>')} to run js commands ${colors.bold(vars)}`)); if (aiAssistant.isEnabled) { output.print( colors.blue(` ${colors.bold('AI is enabled! (experimental)')} Write what you want and make AI run it`), - ) - output.print(colors.blue(' Please note, only HTML fragments with interactive elements are sent to AI provider')) - output.print(colors.blue(' Ideas: ask it to fill forms for you or to click')) + ); + output.print(colors.blue(' Please note, only HTML fragments with interactive elements are sent to AI provider')); + output.print(colors.blue(' Ideas: ask it to fill forms for you or to click')); } } @@ -66,155 +66,155 @@ function pauseSession(passedObject = {}) { completer, history: history.load(), historySize: 50, // Adjust the history size as needed - }) + }); - rl.on('line', parseInput) + rl.on('line', parseInput); rl.on('close', () => { - if (!next) console.log('Exiting interactive shell....') - }) + if (!next) console.log('Exiting interactive shell....'); + }); return new Promise((resolve) => { - finish = resolve + finish = resolve; // eslint-disable-next-line - return askForStep() - }) + return askForStep(); + }); } /* eslint-disable */ async function parseInput(cmd) { - rl.pause() - next = false - recorder.session.start('pause') - if (cmd === '') next = true + rl.pause(); + next = false; + recorder.session.start('pause'); + if (cmd === '') next = true; if (!cmd || cmd === 'resume' || cmd === 'exit') { - finish() - recorder.session.restore() - rl.close() - history.save() - return nextStep() + finish(); + recorder.session.restore(); + rl.close(); + history.save(); + return nextStep(); } for (const k of Object.keys(registeredVariables)) { - eval(`var ${k} = registeredVariables['${k}'];`) + eval(`var ${k} = registeredVariables['${k}'];`); } - let executeCommand = Promise.resolve() + let executeCommand = Promise.resolve(); const getCmd = () => { - debug('Command:', cmd) - return cmd - } - - let isCustomCommand = false - let lastError = null - let isAiCommand = false - let $res + debug('Command:', cmd); + return cmd; + }; + + let isCustomCommand = false; + let lastError = null; + let isAiCommand = false; + let $res; try { - const locate = global.locate // enable locate in this context + const locate = global.locate; // enable locate in this context - const I = container.support('I') + const I = container.support('I'); if (cmd.trim().startsWith('=>')) { - isCustomCommand = true - cmd = cmd.trim().substring(2, cmd.length) + isCustomCommand = true; + cmd = cmd.trim().substring(2, cmd.length); } else if (aiAssistant.isEnabled && cmd.trim() && !cmd.match(/^\w+\(/) && cmd.includes(' ')) { - const currentOutputLevel = output.level() - output.level(0) - const res = I.grabSource() - isAiCommand = true + const currentOutputLevel = output.level(); + output.level(0); + const res = I.grabSource(); + isAiCommand = true; executeCommand = executeCommand.then(async () => { try { - const html = await res - await aiAssistant.setHtmlContext(html) + const html = await res; + await aiAssistant.setHtmlContext(html); } catch (err) { - output.print(output.styles.error(' ERROR '), "Can't get HTML context", err.stack) - return + output.print(output.styles.error(' ERROR '), "Can't get HTML context", err.stack); + return; } finally { - output.level(currentOutputLevel) + output.level(currentOutputLevel); } - const spinner = ora('Processing AI request...').start() - cmd = await aiAssistant.writeSteps(cmd) - spinner.stop() - output.print('') - output.print(colors.blue(aiAssistant.getResponse())) - output.print('') - return cmd - }) + const spinner = ora('Processing AI request...').start(); + cmd = await aiAssistant.writeSteps(cmd); + spinner.stop(); + output.print(''); + output.print(colors.blue(aiAssistant.getResponse())); + output.print(''); + return cmd; + }); } else { - cmd = `I.${cmd}` + cmd = `I.${cmd}`; } executeCommand = executeCommand .then(async () => { - const cmd = getCmd() - if (!cmd) return - return eval(cmd) + const cmd = getCmd(); + if (!cmd) return; + return eval(cmd); }) .catch((err) => { - debug(err) - if (isAiCommand) return - if (!lastError) output.print(output.styles.error(' ERROR '), err.message) - debug(err.stack) + debug(err); + if (isAiCommand) return; + if (!lastError) output.print(output.styles.error(' ERROR '), err.message); + debug(err.stack); - lastError = err.message - }) + lastError = err.message; + }); - const val = await executeCommand + const val = await executeCommand; if (isCustomCommand) { - if (val !== undefined) console.log('Result', '$res=', val) - $res = val + if (val !== undefined) console.log('Result', '$res=', val); + $res = val; } if (cmd?.startsWith('I.see') || cmd?.startsWith('I.dontSee')) { - output.print(output.styles.success(' OK '), cmd) + output.print(output.styles.success(' OK '), cmd); } if (cmd?.startsWith('I.grab')) { - output.print(output.styles.debug(val)) + output.print(output.styles.debug(val)); } - history.push(cmd) // add command to history when successful + history.push(cmd); // add command to history when successful } catch (err) { - if (!lastError) output.print(output.styles.error(' ERROR '), err.message) - lastError = err.message + if (!lastError) output.print(output.styles.error(' ERROR '), err.message); + lastError = err.message; } recorder.session.catch((err) => { - const msg = err.cliMessage ? err.cliMessage() : err.message + const msg = err.cliMessage ? err.cliMessage() : err.message; // pop latest command from history because it failed - history.pop() - - if (isAiCommand) return - if (!lastError) output.print(output.styles.error(' FAIL '), msg) - lastError = err.message - }) - recorder.add('ask for next step', askForStep) - nextStep() + history.pop(); + + if (isAiCommand) return; + if (!lastError) output.print(output.styles.error(' FAIL '), msg); + lastError = err.message; + }); + recorder.add('ask for next step', askForStep); + nextStep(); } /* eslint-enable */ function askForStep() { return new Promise((resolve) => { - nextStep = resolve - rl.setPrompt(' I.', 3) - rl.resume() - rl.prompt([false]) - }) + nextStep = resolve; + rl.setPrompt(' I.', 3); + rl.resume(); + rl.prompt([false]); + }); } function completer(line) { - const I = container.support('I') - const completions = methodsOfObject(I) + const I = container.support('I'); + const completions = methodsOfObject(I); const hits = completions.filter((c) => { if (c.indexOf(line) === 0) { - return c + return c; } - return null - }) - return [hits && hits.length ? hits : completions, line] + return null; + }); + return [hits && hits.length ? hits : completions, line]; } function registerVariable(name, value) { - registeredVariables[name] = value + registeredVariables[name] = value; } -module.exports = pause +module.exports = pause; -module.exports.registerVariable = registerVariable +module.exports.registerVariable = registerVariable; diff --git a/lib/scenario.js b/lib/scenario.js index bdf8603e0..784090422 100644 --- a/lib/scenario.js +++ b/lib/scenario.js @@ -1,32 +1,32 @@ -const promiseRetry = require('promise-retry') -const event = require('./event') -const recorder = require('./recorder') -const assertThrown = require('./assert/throws') -const { ucfirst, isAsyncFunction } = require('./utils') -const { getInjectedArguments } = require('./interfaces/inject') +const promiseRetry = require('promise-retry'); +const event = require('./event'); +const recorder = require('./recorder'); +const assertThrown = require('./assert/throws'); +const { ucfirst, isAsyncFunction } = require('./utils'); +const { getInjectedArguments } = require('./interfaces/inject'); const injectHook = function (inject, suite) { try { - inject() + inject(); } catch (err) { - recorder.throw(err) + recorder.throw(err); } recorder.catch((err) => { - event.emit(event.test.failed, suite, err) - throw err - }) - return recorder.promise() -} + event.emit(event.test.failed, suite, err); + throw err; + }); + return recorder.promise(); +}; function makeDoneCallableOnce(done) { - let called = false + let called = false; return function (err) { if (called) { - return + return; } - called = true - return done(err) - } + called = true; + return done(err); + }; } /** * Wraps test function, injects support objects from container, @@ -34,170 +34,170 @@ function makeDoneCallableOnce(done) { * through event system. */ module.exports.test = (test) => { - const testFn = test.fn + const testFn = test.fn; if (!testFn) { - return test + return test; } - test.steps = [] - test.timeout(0) - test.async = true + test.steps = []; + test.timeout(0); + test.async = true; test.fn = function (done) { - const doneFn = makeDoneCallableOnce(done) + const doneFn = makeDoneCallableOnce(done); recorder.errHandler((err) => { - recorder.session.start('teardown') - recorder.cleanAsyncErr() + recorder.session.start('teardown'); + recorder.cleanAsyncErr(); if (test.throws) { // check that test should actually fail try { - assertThrown(err, test.throws) - event.emit(event.test.passed, test) - event.emit(event.test.finished, test) - recorder.add(doneFn) - return + assertThrown(err, test.throws); + event.emit(event.test.passed, test); + event.emit(event.test.finished, test); + recorder.add(doneFn); + return; } catch (newErr) { - err = newErr + err = newErr; } } - event.emit(event.test.failed, test, err) - event.emit(event.test.finished, test) - recorder.add(() => doneFn(err)) - }) + event.emit(event.test.failed, test, err); + event.emit(event.test.finished, test); + recorder.add(() => doneFn(err)); + }); if (isAsyncFunction(testFn)) { - event.emit(event.test.started, test) + event.emit(event.test.started, test); testFn .call(test, getInjectedArguments(testFn, test)) .then(() => { recorder.add('fire test.passed', () => { - event.emit(event.test.passed, test) - event.emit(event.test.finished, test) - }) - recorder.add('finish test', doneFn) + event.emit(event.test.passed, test); + event.emit(event.test.finished, test); + }); + recorder.add('finish test', doneFn); }) .catch((err) => { - recorder.throw(err) + recorder.throw(err); }) .finally(() => { - recorder.catch() - }) - return + recorder.catch(); + }); + return; } try { - event.emit(event.test.started, test) - testFn.call(test, getInjectedArguments(testFn, test)) + event.emit(event.test.started, test); + testFn.call(test, getInjectedArguments(testFn, test)); } catch (err) { - recorder.throw(err) + recorder.throw(err); } finally { recorder.add('fire test.passed', () => { - event.emit(event.test.passed, test) - event.emit(event.test.finished, test) - }) - recorder.add('finish test', doneFn) - recorder.catch() + event.emit(event.test.passed, test); + event.emit(event.test.finished, test); + }); + recorder.add('finish test', doneFn); + recorder.catch(); } - } - return test -} + }; + return test; +}; /** * Injects arguments to function from controller */ module.exports.injected = function (fn, suite, hookName) { return function (done) { - const doneFn = makeDoneCallableOnce(done) + const doneFn = makeDoneCallableOnce(done); const errHandler = (err) => { - recorder.session.start('teardown') - recorder.cleanAsyncErr() - event.emit(event.test.failed, suite, err) - if (hookName === 'after') event.emit(event.test.after, suite) - if (hookName === 'afterSuite') event.emit(event.suite.after, suite) - recorder.add(() => doneFn(err)) - } + recorder.session.start('teardown'); + recorder.cleanAsyncErr(); + event.emit(event.test.failed, suite, err); + if (hookName === 'after') event.emit(event.test.after, suite); + if (hookName === 'afterSuite') event.emit(event.suite.after, suite); + recorder.add(() => doneFn(err)); + }; recorder.errHandler((err) => { - errHandler(err) - }) + errHandler(err); + }); - if (!fn) throw new Error('fn is not defined') + if (!fn) throw new Error('fn is not defined'); - event.emit(event.hook.started, suite) + event.emit(event.hook.started, suite); - this.test.body = fn.toString() + this.test.body = fn.toString(); if (!recorder.isRunning()) { recorder.errHandler((err) => { - errHandler(err) - }) + errHandler(err); + }); } - const opts = suite.opts || {} - const retries = opts[`retry${ucfirst(hookName)}`] || 0 + const opts = suite.opts || {}; + const retries = opts[`retry${ucfirst(hookName)}`] || 0; promiseRetry( async (retry, number) => { try { - recorder.startUnlessRunning() - await fn.call(this, getInjectedArguments(fn)) - await recorder.promise().catch((err) => retry(err)) + recorder.startUnlessRunning(); + await fn.call(this, getInjectedArguments(fn)); + await recorder.promise().catch((err) => retry(err)); } catch (err) { - retry(err) + retry(err); } finally { if (number < retries) { - recorder.stop() - recorder.start() + recorder.stop(); + recorder.start(); } } }, { retries }, ) .then(() => { - recorder.add('fire hook.passed', () => event.emit(event.hook.passed, suite)) - recorder.add(`finish ${hookName} hook`, doneFn) - recorder.catch() + recorder.add('fire hook.passed', () => event.emit(event.hook.passed, suite)); + recorder.add(`finish ${hookName} hook`, doneFn); + recorder.catch(); }) .catch((e) => { - recorder.throw(e) + recorder.throw(e); recorder.catch((e) => { - const err = recorder.getAsyncErr() === null ? e : recorder.getAsyncErr() - errHandler(err) - }) - recorder.add('fire hook.failed', () => event.emit(event.hook.failed, suite, e)) - }) - } -} + const err = recorder.getAsyncErr() === null ? e : recorder.getAsyncErr(); + errHandler(err); + }); + recorder.add('fire hook.failed', () => event.emit(event.hook.failed, suite, e)); + }); + }; +}; /** * Starts promise chain, so helpers could enqueue their hooks */ module.exports.setup = function (suite) { return injectHook(() => { - recorder.startUnlessRunning() - event.emit(event.test.before, suite && suite.ctx && suite.ctx.currentTest) - }, suite) -} + recorder.startUnlessRunning(); + event.emit(event.test.before, suite && suite.ctx && suite.ctx.currentTest); + }, suite); +}; module.exports.teardown = function (suite) { return injectHook(() => { - recorder.startUnlessRunning() - event.emit(event.test.after, suite && suite.ctx && suite.ctx.currentTest) - }, suite) -} + recorder.startUnlessRunning(); + event.emit(event.test.after, suite && suite.ctx && suite.ctx.currentTest); + }, suite); +}; module.exports.suiteSetup = function (suite) { return injectHook(() => { - recorder.startUnlessRunning() - event.emit(event.suite.before, suite) - }, suite) -} + recorder.startUnlessRunning(); + event.emit(event.suite.before, suite); + }, suite); +}; module.exports.suiteTeardown = function (suite) { return injectHook(() => { - recorder.startUnlessRunning() - event.emit(event.suite.after, suite) - }, suite) -} + recorder.startUnlessRunning(); + event.emit(event.suite.after, suite); + }, suite); +}; -module.exports.getInjectedArguments = getInjectedArguments +module.exports.getInjectedArguments = getInjectedArguments; diff --git a/lib/secret.js b/lib/secret.js index 698c9514e..7d8a5fcc0 100644 --- a/lib/secret.js +++ b/lib/secret.js @@ -1,20 +1,20 @@ -const { deepClone } = require('./utils') +const { deepClone } = require('./utils'); -const maskedString = '*****' +const maskedString = '*****'; /** @param {string} secret */ class Secret { constructor(secret) { - this._secret = secret + this._secret = secret; } /** @returns {string} */ toString() { - return this._secret + return this._secret; } getMasked() { - return maskedString + return maskedString; } /** @@ -23,11 +23,11 @@ class Secret { */ static secret(secret) { if (typeof secret === 'object') { - const fields = Array.from(arguments) - fields.shift() - return secretObject(secret, fields) + const fields = Array.from(arguments); + fields.shift(); + return secretObject(secret, fields); } - return new Secret(secret) + return new Secret(secret); } } @@ -36,16 +36,16 @@ function secretObject(obj, fieldsToHide = []) { get(obj, prop) { if (prop === 'toString') { return function () { - const maskedObject = deepClone(obj) - fieldsToHide.forEach((f) => (maskedObject[f] = maskedString)) - return JSON.stringify(maskedObject) - } + const maskedObject = deepClone(obj); + fieldsToHide.forEach((f) => (maskedObject[f] = maskedString)); + return JSON.stringify(maskedObject); + }; } - return fieldsToHide.includes(prop) ? new Secret(obj[prop]) : obj[prop] + return fieldsToHide.includes(prop) ? new Secret(obj[prop]) : obj[prop]; }, - } + }; - return new Proxy(obj, handler) + return new Proxy(obj, handler); } -module.exports = Secret +module.exports = Secret; diff --git a/lib/step.js b/lib/step.js index ae5bba62b..049adcfc1 100644 --- a/lib/step.js +++ b/lib/step.js @@ -1,10 +1,10 @@ // TODO: place MetaStep in other file, disable rule -const store = require('./store') -const Secret = require('./secret') -const event = require('./event') +const store = require('./store'); +const Secret = require('./secret'); +const event = require('./event'); -const STACK_LINE = 4 +const STACK_LINE = 4; /** * Each command in test executed through `I.` object is wrapped in Step. @@ -31,42 +31,42 @@ class Step { * 20-29 - designated for timeout settings which could be overriden in tests code, 25 is used by stepTimeout plugin when stepTimeout.config.overrideStepLimits=false */ stepTimeoutSoft: 25, - } + }; } constructor(helper, name) { /** @member {string} */ - this.actor = 'I' // I = actor + this.actor = 'I'; // I = actor /** @member {CodeceptJS.Helper} */ - this.helper = helper // corresponding helper + this.helper = helper; // corresponding helper /** @member {string} */ - this.name = name // name of a step console + this.name = name; // name of a step console /** @member {string} */ - this.helperMethod = name // helper method + this.helperMethod = name; // helper method /** @member {string} */ - this.status = 'pending' + this.status = 'pending'; /** * @member {string} suffix * @memberof CodeceptJS.Step# */ /** @member {string} */ - this.prefix = this.suffix = '' + this.prefix = this.suffix = ''; /** @member {string} */ - this.comment = '' + this.comment = ''; /** @member {Array<*>} */ - this.args = [] + this.args = []; /** @member {MetaStep} */ - this.metaStep = undefined + this.metaStep = undefined; /** @member {string} */ - this.stack = '' + this.stack = ''; - const timeouts = new Map() + const timeouts = new Map(); /** * @method * @returns {number|undefined} */ this.getTimeout = function () { - let totalTimeout + let totalTimeout; // iterate over all timeouts starting from highest values of order new Map([...timeouts.entries()].sort().reverse()).forEach((timeout, order) => { if ( @@ -78,11 +78,11 @@ class Step { // when `order < 0` - timeout overrides higher values of timeout or 'no timeout' (totalTimeout === 0) set by elements with higher order (timeout > 0 && (timeout < totalTimeout || totalTimeout === 0))) ) { - totalTimeout = timeout + totalTimeout = timeout; } - }) - return totalTimeout - } + }); + return totalTimeout; + }; /** * @method * @param {number} timeout - timeout in milliseconds or 0 if no timeout @@ -90,20 +90,20 @@ class Step { * When order below 0 value of timeout only override if new value is lower */ this.setTimeout = function (timeout, order) { - timeouts.set(order, timeout) - } + timeouts.set(order, timeout); + }; - this.setTrace() + this.setTrace(); } /** @function */ setTrace() { - Error.captureStackTrace(this) + Error.captureStackTrace(this); } /** @param {Array<*>} args */ setArguments(args) { - this.args = args + this.args = args; } /** @@ -111,35 +111,35 @@ class Step { * @return {*} */ run() { - this.args = Array.prototype.slice.call(arguments) + this.args = Array.prototype.slice.call(arguments); if (store.dryRun) { - this.setStatus('success') - return Promise.resolve(new Proxy({}, dryRunResolver())) + this.setStatus('success'); + return Promise.resolve(new Proxy({}, dryRunResolver())); } - let result + let result; try { if (this.helperMethod !== 'say') { - result = this.helper[this.helperMethod].apply(this.helper, this.args) + result = this.helper[this.helperMethod].apply(this.helper, this.args); } - this.setStatus('success') + this.setStatus('success'); } catch (err) { - this.setStatus('failed') - throw err + this.setStatus('failed'); + throw err; } - return result + return result; } /** @param {string} status */ setStatus(status) { - this.status = status + this.status = status; if (this.metaStep) { - this.metaStep.setStatus(status) + this.metaStep.setStatus(status); } } /** @return {string} */ humanize() { - return humanizeString(this.name) + return humanizeString(this.name); } /** @return {string} */ @@ -147,185 +147,185 @@ class Step { return this.args .map((arg) => { if (!arg) { - return '' + return ''; } if (typeof arg === 'string') { - return `"${arg}"` + return `"${arg}"`; } if (Array.isArray(arg)) { try { - const res = JSON.stringify(arg) - return res + const res = JSON.stringify(arg); + return res; } catch (err) { - return `[${arg.toString()}]` + return `[${arg.toString()}]`; } } else if (typeof arg === 'function') { - return arg.toString() + return arg.toString(); } else if (typeof arg === 'undefined') { - return `${arg}` + return `${arg}`; } else if (arg instanceof Secret) { - return arg.getMasked() + return arg.getMasked(); } else if (arg.toString && arg.toString() !== '[object Object]') { - return arg.toString() + return arg.toString(); } else if (typeof arg === 'object') { - const returnedArg = {} + const returnedArg = {}; for (const [key, value] of Object.entries(arg)) { - returnedArg[key] = value - if (value instanceof Secret) returnedArg[key] = value.getMasked() + returnedArg[key] = value; + if (value instanceof Secret) returnedArg[key] = value.getMasked(); } - return JSON.stringify(returnedArg) + return JSON.stringify(returnedArg); } - return arg + return arg; }) - .join(', ') + .join(', '); } /** @return {string} */ line() { - const lines = this.stack.split('\n') + const lines = this.stack.split('\n'); if (lines[STACK_LINE]) { return lines[STACK_LINE].trim() .replace(global.codecept_dir || '', '.') - .trim() + .trim(); } - return '' + return ''; } /** @return {string} */ toString() { - return `${this.prefix}${this.actor} ${this.humanize()} ${this.humanizeArgs()}${this.suffix}` + return `${this.prefix}${this.actor} ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`; } /** @return {string} */ toCode() { - return `${this.prefix}${this.actor}.${this.name}(${this.humanizeArgs()})${this.suffix}` + return `${this.prefix}${this.actor}.${this.name}(${this.humanizeArgs()})${this.suffix}`; } isMetaStep() { - return this.constructor.name === 'MetaStep' + return this.constructor.name === 'MetaStep'; } /** @return {boolean} */ hasBDDAncestor() { - let hasBDD = false - let processingStep - processingStep = this + let hasBDD = false; + let processingStep; + processingStep = this; while (processingStep.metaStep) { if (processingStep.metaStep.actor.match(/^(Given|When|Then|And)/)) { - hasBDD = true - break + hasBDD = true; + break; } else { - processingStep = processingStep.metaStep + processingStep = processingStep.metaStep; } } - return hasBDD + return hasBDD; } } /** @extends Step */ class MetaStep extends Step { constructor(obj, method) { - super(null, method) - this.actor = obj + super(null, method); + this.actor = obj; } /** @return {boolean} */ isBDD() { if (this.actor && this.actor.match && this.actor.match(/^(Given|When|Then|And)/)) { - return true + return true; } - return false + return false; } isWithin() { if (this.actor && this.actor.match && this.actor.match(/^(Within)/)) { - return true + return true; } - return false + return false; } toString() { - const actorText = this.actor + const actorText = this.actor; if (this.isBDD() || this.isWithin()) { - return `${this.prefix}${actorText} ${this.name} "${this.humanizeArgs()}${this.suffix}"` + return `${this.prefix}${actorText} ${this.name} "${this.humanizeArgs()}${this.suffix}"`; } if (actorText === 'I') { - return `${this.prefix}${actorText} ${this.humanize()} ${this.humanizeArgs()}${this.suffix}` + return `${this.prefix}${actorText} ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`; } - return `On ${this.prefix}${actorText}: ${this.humanize()} ${this.humanizeArgs()}${this.suffix}` + return `On ${this.prefix}${actorText}: ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`; } humanize() { - return humanizeString(this.name) + return humanizeString(this.name); } setTrace() {} setContext(context) { - this.context = context + this.context = context; } /** @return {*} */ run(fn) { - this.status = 'queued' - this.setArguments(Array.from(arguments).slice(1)) - let result + this.status = 'queued'; + this.setArguments(Array.from(arguments).slice(1)); + let result; const registerStep = (step) => { - this.metaStep = null - step.metaStep = this - } - event.dispatcher.prependListener(event.step.before, registerStep) + this.metaStep = null; + step.metaStep = this; + }; + event.dispatcher.prependListener(event.step.before, registerStep); // Handle async and sync methods. if (fn.constructor.name === 'AsyncFunction') { result = fn .apply(this.context, this.args) .then((result) => { - return result + return result; }) .catch((error) => { - this.setStatus('failed') - throw error + this.setStatus('failed'); + throw error; }) .finally(() => { - this.endTime = Date.now() - event.dispatcher.removeListener(event.step.before, registerStep) - }) + this.endTime = Date.now(); + event.dispatcher.removeListener(event.step.before, registerStep); + }); } else { try { - this.startTime = Date.now() - result = fn.apply(this.context, this.args) + this.startTime = Date.now(); + result = fn.apply(this.context, this.args); } catch (error) { - this.setStatus('failed') - throw error + this.setStatus('failed'); + throw error; } finally { - this.endTime = Date.now() - event.dispatcher.removeListener(event.step.before, registerStep) + this.endTime = Date.now(); + event.dispatcher.removeListener(event.step.before, registerStep); } } - return result + return result; } } -Step.TIMEOUTS = {} +Step.TIMEOUTS = {}; /** @type {Class} */ -Step.MetaStep = MetaStep +Step.MetaStep = MetaStep; -module.exports = Step +module.exports = Step; function dryRunResolver() { return { get(target, prop) { - if (prop === 'toString') return () => '' - return new Proxy({}, dryRunResolver()) + if (prop === 'toString') return () => ''; + return new Proxy({}, dryRunResolver()); }, - } + }; } function humanizeString(string) { @@ -333,12 +333,12 @@ function humanizeString(string) { const _result = string .replace(/([a-z](?=[A-Z]))/g, '$1 ') .split(' ') - .map((word) => word.toLowerCase()) + .map((word) => word.toLowerCase()); - _result[0] = _result[0] === 'i' ? capitalizeFLetter(_result[0]) : _result[0] - return _result.join(' ').trim() + _result[0] = _result[0] === 'i' ? capitalizeFLetter(_result[0]) : _result[0]; + return _result.join(' ').trim(); } function capitalizeFLetter(string) { - return string[0].toUpperCase() + string.slice(1) + return string[0].toUpperCase() + string.slice(1); } diff --git a/lib/workers.js b/lib/workers.js index 32dbaec94..993e3aa46 100644 --- a/lib/workers.js +++ b/lib/workers.js @@ -1,56 +1,56 @@ -const path = require('path') -const mkdirp = require('mkdirp') -const { Worker } = require('worker_threads') +const path = require('path'); +const mkdirp = require('mkdirp'); +const { Worker } = require('worker_threads'); const { Suite, Test, reporters: { Base }, -} = require('mocha') -const { EventEmitter } = require('events') -const ms = require('ms') -const Codecept = require('./codecept') -const MochaFactory = require('./mochaFactory') -const Container = require('./container') -const { getTestRoot } = require('./command/utils') -const { isFunction, fileExists } = require('./utils') -const { replaceValueDeep, deepClone } = require('./utils') -const mainConfig = require('./config') -const output = require('./output') -const event = require('./event') -const recorder = require('./recorder') -const runHook = require('./hooks') -const WorkerStorage = require('./workerStorage') -const collection = require('./command/run-multiple/collection') - -const pathToWorker = path.join(__dirname, 'command', 'workers', 'runTests.js') +} = require('mocha'); +const { EventEmitter } = require('events'); +const ms = require('ms'); +const Codecept = require('./codecept'); +const MochaFactory = require('./mochaFactory'); +const Container = require('./container'); +const { getTestRoot } = require('./command/utils'); +const { isFunction, fileExists } = require('./utils'); +const { replaceValueDeep, deepClone } = require('./utils'); +const mainConfig = require('./config'); +const output = require('./output'); +const event = require('./event'); +const recorder = require('./recorder'); +const runHook = require('./hooks'); +const WorkerStorage = require('./workerStorage'); +const collection = require('./command/run-multiple/collection'); + +const pathToWorker = path.join(__dirname, 'command', 'workers', 'runTests.js'); const initializeCodecept = (configPath, options = {}) => { - const codecept = new Codecept(mainConfig.load(configPath || '.'), options) - codecept.init(getTestRoot(configPath)) - codecept.loadTests() + const codecept = new Codecept(mainConfig.load(configPath || '.'), options); + codecept.init(getTestRoot(configPath)); + codecept.loadTests(); - return codecept -} + return codecept; +}; const createOutputDir = (configPath) => { - const config = mainConfig.load(configPath || '.') - const testRoot = getTestRoot(configPath) - const outputDir = path.isAbsolute(config.output) ? config.output : path.join(testRoot, config.output) + const config = mainConfig.load(configPath || '.'); + const testRoot = getTestRoot(configPath); + const outputDir = path.isAbsolute(config.output) ? config.output : path.join(testRoot, config.output); if (!fileExists(outputDir)) { - output.print(`creating output directory: ${outputDir}`) - mkdirp.sync(outputDir) + output.print(`creating output directory: ${outputDir}`); + mkdirp.sync(outputDir); } -} +}; const populateGroups = (numberOfWorkers) => { - const groups = [] + const groups = []; for (let i = 0; i < numberOfWorkers; i++) { - groups[i] = [] + groups[i] = []; } - return groups -} + return groups; +}; const createWorker = (workerObject) => { const worker = new Worker(pathToWorker, { @@ -60,12 +60,12 @@ const createWorker = (workerObject) => { testRoot: workerObject.testRoot, workerIndex: workerObject.workerIndex + 1, }, - }) - worker.on('error', (err) => output.error(`Worker Error: ${err.stack}`)) + }); + worker.on('error', (err) => output.error(`Worker Error: ${err.stack}`)); - WorkerStorage.addWorker(worker) - return worker -} + WorkerStorage.addWorker(worker); + return worker; +}; const simplifyObject = (object) => { return Object.keys(object) @@ -73,161 +73,161 @@ const simplifyObject = (object) => { .filter((k) => typeof object[k] !== 'function') .filter((k) => typeof object[k] !== 'object') .reduce((obj, key) => { - obj[key] = object[key] - return obj - }, {}) -} + obj[key] = object[key]; + return obj; + }, {}); +}; const repackTest = (test) => { - test = Object.assign(new Test(test.title || '', () => {}), test) - test.parent = Object.assign(new Suite(test.parent.title), test.parent) - return test -} + test = Object.assign(new Test(test.title || '', () => {}), test); + test.parent = Object.assign(new Suite(test.parent.title), test.parent); + return test; +}; const createWorkerObjects = (testGroups, config, testRoot, options, selectedRuns) => { - selectedRuns = options && options.all && config.multiple ? Object.keys(config.multiple) : selectedRuns + selectedRuns = options && options.all && config.multiple ? Object.keys(config.multiple) : selectedRuns; if (selectedRuns === undefined || !selectedRuns.length || config.multiple === undefined) { return testGroups.map((tests, index) => { - const workerObj = new WorkerObject(index) - workerObj.addConfig(config) - workerObj.addTests(tests) - workerObj.setTestRoot(testRoot) - workerObj.addOptions(options) - return workerObj - }) + const workerObj = new WorkerObject(index); + workerObj.addConfig(config); + workerObj.addTests(tests); + workerObj.setTestRoot(testRoot); + workerObj.addOptions(options); + return workerObj; + }); } - const workersToExecute = [] + const workersToExecute = []; - const currentOutputFolder = config.output - let currentMochawesomeReportDir - let currentMochaJunitReporterFile + const currentOutputFolder = config.output; + let currentMochawesomeReportDir; + let currentMochaJunitReporterFile; if (config.mocha && config.mocha.reporterOptions) { - currentMochawesomeReportDir = config.mocha.reporterOptions?.mochawesome.options.reportDir - currentMochaJunitReporterFile = config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile + currentMochawesomeReportDir = config.mocha.reporterOptions?.mochawesome.options.reportDir; + currentMochaJunitReporterFile = config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile; } collection.createRuns(selectedRuns, config).forEach((worker) => { - const separator = path.sep - const _config = { ...config } - let workerName = worker.name.replace(':', '_') - _config.output = `${currentOutputFolder}${separator}${workerName}` + const separator = path.sep; + const _config = { ...config }; + let workerName = worker.name.replace(':', '_'); + _config.output = `${currentOutputFolder}${separator}${workerName}`; if (config.mocha && config.mocha.reporterOptions) { - _config.mocha.reporterOptions.mochawesome.options.reportDir = `${currentMochawesomeReportDir}${separator}${workerName}` + _config.mocha.reporterOptions.mochawesome.options.reportDir = `${currentMochawesomeReportDir}${separator}${workerName}`; - const _tempArray = currentMochaJunitReporterFile.split(separator) + const _tempArray = currentMochaJunitReporterFile.split(separator); _tempArray.splice( _tempArray.findIndex((item) => item.includes('.xml')), 0, workerName, - ) - _config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile = _tempArray.join(separator) + ); + _config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile = _tempArray.join(separator); } - workerName = worker.getOriginalName() || worker.getName() - const workerConfig = worker.getConfig() - workersToExecute.push(getOverridenConfig(workerName, workerConfig, _config)) - }) - const workers = [] - let index = 0 + workerName = worker.getOriginalName() || worker.getName(); + const workerConfig = worker.getConfig(); + workersToExecute.push(getOverridenConfig(workerName, workerConfig, _config)); + }); + const workers = []; + let index = 0; testGroups.forEach((tests) => { - const testWorkerArray = [] + const testWorkerArray = []; workersToExecute.forEach((finalConfig) => { - const workerObj = new WorkerObject(index++) - workerObj.addConfig(finalConfig) - workerObj.addTests(tests) - workerObj.setTestRoot(testRoot) - workerObj.addOptions(options) - testWorkerArray.push(workerObj) - }) - workers.push(...testWorkerArray) - }) - return workers -} + const workerObj = new WorkerObject(index++); + workerObj.addConfig(finalConfig); + workerObj.addTests(tests); + workerObj.setTestRoot(testRoot); + workerObj.addOptions(options); + testWorkerArray.push(workerObj); + }); + workers.push(...testWorkerArray); + }); + return workers; +}; const indexOfSmallestElement = (groups) => { - let i = 0 + let i = 0; for (let j = 1; j < groups.length; j++) { if (groups[j - 1].length > groups[j].length) { - i = j + i = j; } } - return i -} + return i; +}; const convertToMochaTests = (testGroup) => { - const group = [] + const group = []; if (testGroup instanceof Array) { - const mocha = MochaFactory.create({}, {}) - mocha.files = testGroup - mocha.loadFiles() + const mocha = MochaFactory.create({}, {}); + mocha.files = testGroup; + mocha.loadFiles(); mocha.suite.eachTest((test) => { - group.push(test.uid) - }) - mocha.unloadFiles() + group.push(test.uid); + }); + mocha.unloadFiles(); } - return group -} + return group; +}; const getOverridenConfig = (workerName, workerConfig, config) => { // clone config - const overriddenConfig = deepClone(config) + const overriddenConfig = deepClone(config); // get configuration - const browserConfig = workerConfig.browser + const browserConfig = workerConfig.browser; for (const key in browserConfig) { - overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key]) + overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key]); } // override tests configuration if (overriddenConfig.tests) { - overriddenConfig.tests = workerConfig.tests + overriddenConfig.tests = workerConfig.tests; } if (overriddenConfig.gherkin && workerConfig.gherkin && workerConfig.gherkin.features) { - overriddenConfig.gherkin.features = workerConfig.gherkin.features + overriddenConfig.gherkin.features = workerConfig.gherkin.features; } - return overriddenConfig -} + return overriddenConfig; +}; class WorkerObject { /** * @param {Number} workerIndex - Unique ID for worker */ constructor(workerIndex) { - this.workerIndex = workerIndex - this.options = {} - this.tests = [] - this.testRoot = getTestRoot() + this.workerIndex = workerIndex; + this.options = {}; + this.tests = []; + this.testRoot = getTestRoot(); } addConfig(config) { - const oldConfig = JSON.parse(this.options.override || '{}') + const oldConfig = JSON.parse(this.options.override || '{}'); const newConfig = { ...oldConfig, ...config, - } - this.options.override = JSON.stringify(newConfig) + }; + this.options.override = JSON.stringify(newConfig); } addTestFiles(testGroup) { - this.addTests(convertToMochaTests(testGroup)) + this.addTests(convertToMochaTests(testGroup)); } addTests(tests) { - this.tests = this.tests.concat(tests) + this.tests = this.tests.concat(tests); } setTestRoot(path) { - this.testRoot = getTestRoot(path) + this.testRoot = getTestRoot(path); } addOptions(opts) { this.options = { ...this.options, ...opts, - } + }; } } @@ -237,36 +237,36 @@ class Workers extends EventEmitter { * @param {Object} config */ constructor(numberOfWorkers, config = { by: 'test' }) { - super() - this.setMaxListeners(50) - this.codecept = initializeCodecept(config.testConfig, config.options) - this.failuresLog = [] - this.errors = [] - this.numberOfWorkers = 0 - this.closedWorkers = 0 - this.workers = [] + super(); + this.setMaxListeners(50); + this.codecept = initializeCodecept(config.testConfig, config.options); + this.failuresLog = []; + this.errors = []; + this.numberOfWorkers = 0; + this.closedWorkers = 0; + this.workers = []; this.stats = { passes: 0, failures: 0, tests: 0, pending: 0, - } - this.testGroups = [] + }; + this.testGroups = []; - createOutputDir(config.testConfig) - if (numberOfWorkers) this._initWorkers(numberOfWorkers, config) + createOutputDir(config.testConfig); + if (numberOfWorkers) this._initWorkers(numberOfWorkers, config); } _initWorkers(numberOfWorkers, config) { - this.splitTestsByGroups(numberOfWorkers, config) + this.splitTestsByGroups(numberOfWorkers, config); this.workers = createWorkerObjects( this.testGroups, this.codecept.config, config.testConfig, config.options, config.selectedRuns, - ) - this.numberOfWorkers = this.workers.length + ); + this.numberOfWorkers = this.workers.length; } /** @@ -283,17 +283,17 @@ class Workers extends EventEmitter { */ splitTestsByGroups(numberOfWorkers, config) { if (isFunction(config.by)) { - const createTests = config.by - const testGroups = createTests(numberOfWorkers) + const createTests = config.by; + const testGroups = createTests(numberOfWorkers); if (!(testGroups instanceof Array)) { - throw new Error('Test group should be an array') + throw new Error('Test group should be an array'); } for (const testGroup of testGroups) { - this.testGroups.push(convertToMochaTests(testGroup)) + this.testGroups.push(convertToMochaTests(testGroup)); } } else if (typeof numberOfWorkers === 'number' && numberOfWorkers > 0) { this.testGroups = - config.by === 'suite' ? this.createGroupsOfSuites(numberOfWorkers) : this.createGroupsOfTests(numberOfWorkers) + config.by === 'suite' ? this.createGroupsOfSuites(numberOfWorkers) : this.createGroupsOfTests(numberOfWorkers); } } @@ -303,53 +303,53 @@ class Workers extends EventEmitter { * @returns {WorkerObject} */ spawn() { - const worker = new WorkerObject(this.numberOfWorkers) - this.workers.push(worker) - this.numberOfWorkers += 1 - return worker + const worker = new WorkerObject(this.numberOfWorkers); + this.workers.push(worker); + this.numberOfWorkers += 1; + return worker; } /** * @param {Number} numberOfWorkers */ createGroupsOfTests(numberOfWorkers) { - const files = this.codecept.testFiles - const mocha = Container.mocha() - mocha.files = files - mocha.loadFiles() + const files = this.codecept.testFiles; + const mocha = Container.mocha(); + mocha.files = files; + mocha.loadFiles(); - const groups = populateGroups(numberOfWorkers) - let groupCounter = 0 + const groups = populateGroups(numberOfWorkers); + let groupCounter = 0; mocha.suite.eachTest((test) => { - const i = groupCounter % groups.length + const i = groupCounter % groups.length; if (test) { - groups[i].push(test.uid) - groupCounter++ + groups[i].push(test.uid); + groupCounter++; } - }) - return groups + }); + return groups; } /** * @param {Number} numberOfWorkers */ createGroupsOfSuites(numberOfWorkers) { - const files = this.codecept.testFiles - const groups = populateGroups(numberOfWorkers) + const files = this.codecept.testFiles; + const groups = populateGroups(numberOfWorkers); - const mocha = Container.mocha() - mocha.files = files - mocha.loadFiles() + const mocha = Container.mocha(); + mocha.files = files; + mocha.loadFiles(); mocha.suite.suites.forEach((suite) => { - const i = indexOfSmallestElement(groups) + const i = indexOfSmallestElement(groups); suite.tests.forEach((test) => { if (test) { - groups[i].push(test.uid) + groups[i].push(test.uid); } - }) - }) - return groups + }); + }); + return groups; } /** @@ -357,155 +357,155 @@ class Workers extends EventEmitter { */ overrideConfig(config) { for (const worker of this.workers) { - worker.addConfig(config) + worker.addConfig(config); } } async bootstrapAll() { - return runHook(this.codecept.config.bootstrapAll, 'bootstrapAll') + return runHook(this.codecept.config.bootstrapAll, 'bootstrapAll'); } async teardownAll() { - return runHook(this.codecept.config.teardownAll, 'teardownAll') + return runHook(this.codecept.config.teardownAll, 'teardownAll'); } run() { - this.stats.start = new Date() - this.stats.failedHooks = 0 - recorder.startUnlessRunning() - event.dispatcher.emit(event.workers.before) - process.env.RUNS_WITH_WORKERS = 'true' + this.stats.start = new Date(); + this.stats.failedHooks = 0; + recorder.startUnlessRunning(); + event.dispatcher.emit(event.workers.before); + process.env.RUNS_WITH_WORKERS = 'true'; recorder.add('starting workers', () => { for (const worker of this.workers) { - const workerThread = createWorker(worker) - this._listenWorkerEvents(workerThread) + const workerThread = createWorker(worker); + this._listenWorkerEvents(workerThread); } - }) + }); return new Promise((resolve) => { - this.on('end', resolve) - }) + this.on('end', resolve); + }); } /** * @returns {Array} */ getWorkers() { - return this.workers + return this.workers; } /** * @returns {Boolean} */ isFailed() { - return (this.stats.failures || this.errors.length) > 0 + return (this.stats.failures || this.errors.length) > 0; } _listenWorkerEvents(worker) { worker.on('message', (message) => { - output.process(message.workerIndex) + output.process(message.workerIndex); // deal with events that are not test cycle related if (!message.event) { - return this.emit('message', message) + return this.emit('message', message); } switch (message.event) { case event.all.failures: - this.failuresLog = this.failuresLog.concat(message.data.failuresLog) - this._appendStats(message.data.stats) - break + this.failuresLog = this.failuresLog.concat(message.data.failuresLog); + this._appendStats(message.data.stats); + break; case event.suite.before: - this.emit(event.suite.before, repackTest(message.data)) - break + this.emit(event.suite.before, repackTest(message.data)); + break; case event.hook.failed: - this.emit(event.hook.failed, repackTest(message.data)) - this.errors.push(message.data.err) - break + this.emit(event.hook.failed, repackTest(message.data)); + this.errors.push(message.data.err); + break; case event.test.before: - this.emit(event.test.before, repackTest(message.data)) - break + this.emit(event.test.before, repackTest(message.data)); + break; case event.test.started: - this.emit(event.test.started, repackTest(message.data)) - break + this.emit(event.test.started, repackTest(message.data)); + break; case event.test.failed: - this.emit(event.test.failed, repackTest(message.data)) - break + this.emit(event.test.failed, repackTest(message.data)); + break; case event.test.passed: - this.emit(event.test.passed, repackTest(message.data)) - break + this.emit(event.test.passed, repackTest(message.data)); + break; case event.test.skipped: - this.emit(event.test.skipped, repackTest(message.data)) - break + this.emit(event.test.skipped, repackTest(message.data)); + break; case event.test.finished: - this.emit(event.test.finished, repackTest(message.data)) - break + this.emit(event.test.finished, repackTest(message.data)); + break; case event.test.after: - this.emit(event.test.after, repackTest(message.data)) - break + this.emit(event.test.after, repackTest(message.data)); + break; case event.step.finished: - this.emit(event.step.finished, message.data) - break + this.emit(event.step.finished, message.data); + break; case event.step.started: - this.emit(event.step.started, message.data) - break + this.emit(event.step.started, message.data); + break; case event.step.passed: - this.emit(event.step.passed, message.data) - break + this.emit(event.step.passed, message.data); + break; case event.step.failed: - this.emit(event.step.failed, message.data) - break + this.emit(event.step.failed, message.data); + break; } - }) + }); worker.on('error', (err) => { - this.errors.push(err) - }) + this.errors.push(err); + }); worker.on('exit', () => { - this.closedWorkers += 1 + this.closedWorkers += 1; if (this.closedWorkers === this.numberOfWorkers) { - this._finishRun() + this._finishRun(); } - }) + }); } _finishRun() { - event.dispatcher.emit(event.workers.after) + event.dispatcher.emit(event.workers.after); if (this.isFailed()) { - process.exitCode = 1 + process.exitCode = 1; } else { - process.exitCode = 0 + process.exitCode = 0; } // removed this.finishedTests because in all /lib only first argument (!this.isFailed()) is used) - this.emit(event.all.result, !this.isFailed()) - this.emit('end') // internal event + this.emit(event.all.result, !this.isFailed()); + this.emit('end'); // internal event } _appendStats(newStats) { - this.stats.passes += newStats.passes - this.stats.failures += newStats.failures - this.stats.tests += newStats.tests - this.stats.pending += newStats.pending - this.stats.failedHooks += newStats.failedHooks + this.stats.passes += newStats.passes; + this.stats.failures += newStats.failures; + this.stats.tests += newStats.tests; + this.stats.pending += newStats.pending; + this.stats.failedHooks += newStats.failedHooks; } printResults() { - this.stats.end = new Date() - this.stats.duration = this.stats.end - this.stats.start + this.stats.end = new Date(); + this.stats.duration = this.stats.end - this.stats.start; // Reset process for logs in main thread - output.process(null) - output.print() + output.process(null); + output.print(); this.failuresLog = this.failuresLog .filter((log) => log.length && typeof log[1] === 'number') // mocha/lib/reporters/base.js - .map(([format, num, title, message, stack], i) => [format, i + 1, title, message, stack]) + .map(([format, num, title, message, stack], i) => [format, i + 1, title, message, stack]); if (this.failuresLog.length) { - output.print() - output.print('-- FAILURES:') - this.failuresLog.forEach((log) => output.print(...log)) + output.print(); + output.print('-- FAILURES:'); + this.failuresLog.forEach((log) => output.print(...log)); } output.result( @@ -514,9 +514,9 @@ class Workers extends EventEmitter { this.stats.pending, ms(this.stats.duration), this.stats.failedHooks, - ) - process.env.RUNS_WITH_WORKERS = 'false' + ); + process.env.RUNS_WITH_WORKERS = 'false'; } } -module.exports = Workers +module.exports = Workers; diff --git a/prettier.config.js b/prettier.config.js index 3b217498d..c70ada024 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -2,7 +2,7 @@ module.exports = { printWidth: 120, tabWidth: 2, useTabs: false, - semi: false, + semi: true, singleQuote: true, trailingComma: 'all', bracketSameLine: false, diff --git a/test/acceptance/codecept.Playwright.coverage.js b/test/acceptance/codecept.Playwright.coverage.js index 3a88f19ee..05e3f4116 100644 --- a/test/acceptance/codecept.Playwright.coverage.js +++ b/test/acceptance/codecept.Playwright.coverage.js @@ -1,4 +1,4 @@ -const TestHelper = require('../support/TestHelper') +const TestHelper = require('../support/TestHelper'); module.exports.config = { tests: './*_test.js', @@ -51,4 +51,4 @@ module.exports.config = { features: './gherkin/*.feature', steps: ['./gherkin/steps.js'], }, -} +}; diff --git a/test/acceptance/codecept.Playwright.js b/test/acceptance/codecept.Playwright.js index 7c5eb2f82..c4eb656ff 100644 --- a/test/acceptance/codecept.Playwright.js +++ b/test/acceptance/codecept.Playwright.js @@ -1,4 +1,4 @@ -const TestHelper = require('../support/TestHelper') +const TestHelper = require('../support/TestHelper'); module.exports.config = { tests: './*_test.js', @@ -41,4 +41,4 @@ module.exports.config = { features: './gherkin/*.feature', steps: ['./gherkin/steps.js'], }, -} +}; diff --git a/test/acceptance/codecept.Playwright.retryTo.js b/test/acceptance/codecept.Playwright.retryTo.js index 696fcfbab..db4426351 100644 --- a/test/acceptance/codecept.Playwright.retryTo.js +++ b/test/acceptance/codecept.Playwright.retryTo.js @@ -1,4 +1,4 @@ -const TestHelper = require('../support/TestHelper') +const TestHelper = require('../support/TestHelper'); module.exports.config = { tests: './*_test.js', @@ -43,4 +43,4 @@ module.exports.config = { features: './gherkin/*.feature', steps: ['./gherkin/steps.js'], }, -} +}; diff --git a/test/acceptance/codecept.Puppeteer.js b/test/acceptance/codecept.Puppeteer.js index 63b738565..787699c5e 100644 --- a/test/acceptance/codecept.Puppeteer.js +++ b/test/acceptance/codecept.Puppeteer.js @@ -1,4 +1,4 @@ -const TestHelper = require('../support/TestHelper') +const TestHelper = require('../support/TestHelper'); module.exports.config = { tests: './*_test.js', @@ -33,4 +33,4 @@ module.exports.config = { features: './gherkin/*.feature', steps: ['./gherkin/steps.js'], }, -} +}; diff --git a/test/acceptance/codecept.Testcafe.js b/test/acceptance/codecept.Testcafe.js index d2c7d3b8d..4e4f863a5 100644 --- a/test/acceptance/codecept.Testcafe.js +++ b/test/acceptance/codecept.Testcafe.js @@ -1,4 +1,4 @@ -const TestHelper = require('../support/TestHelper') +const TestHelper = require('../support/TestHelper'); module.exports.config = { tests: './*_test.js', @@ -21,4 +21,4 @@ module.exports.config = { features: './gherkin/*.feature', steps: ['./gherkin/steps.js'], }, -} +}; diff --git a/test/acceptance/codecept.WebDriver.js b/test/acceptance/codecept.WebDriver.js index a3baf2bec..02b59e770 100644 --- a/test/acceptance/codecept.WebDriver.js +++ b/test/acceptance/codecept.WebDriver.js @@ -1,4 +1,4 @@ -const TestHelper = require('../support/TestHelper') +const TestHelper = require('../support/TestHelper'); module.exports.config = { tests: './*_test.js', @@ -28,7 +28,7 @@ module.exports.config = { include: {}, bootstrap: async () => new Promise((done) => { - setTimeout(done, 5000) + setTimeout(done, 5000); }), // let's wait for selenium mocha: {}, name: 'acceptance', @@ -41,4 +41,4 @@ module.exports.config = { features: './gherkin/*.feature', steps: ['./gherkin/steps.js'], }, -} +}; diff --git a/test/data/graphql/users_factory.js b/test/data/graphql/users_factory.js index 9ad9a5f5c..9b57de272 100644 --- a/test/data/graphql/users_factory.js +++ b/test/data/graphql/users_factory.js @@ -1,8 +1,8 @@ -const { Factory } = require('rosie') -const { faker } = require('@faker-js/faker') +const { Factory } = require('rosie'); +const { faker } = require('@faker-js/faker'); module.exports = new Factory(function (buildObject) { - this.input = { ...buildObject } + this.input = { ...buildObject }; }) .attr('name', () => faker.person.fullName()) - .attr('email', () => faker.internet.email()) + .attr('email', () => faker.internet.email()); diff --git a/test/data/inject-fail-example/pages/page.js b/test/data/inject-fail-example/pages/page.js index 668f6b323..cf0120459 100644 --- a/test/data/inject-fail-example/pages/page.js +++ b/test/data/inject-fail-example/pages/page.js @@ -1,15 +1,15 @@ -const { notpage, arraypage } = inject() +const { notpage, arraypage } = inject(); module.exports = { type: (s) => { - console.log('type => ', s) - console.log('strategy', arraypage.toString()) - notpage.domainIds.push('newdomain') - return notpage.domainIds + console.log('type => ', s); + console.log('strategy', arraypage.toString()); + notpage.domainIds.push('newdomain'); + return notpage.domainIds; }, purgeDomains: (s) => { - console.log('purgeDomains') - console.log(s) + console.log('purgeDomains'); + console.log(s); }, -} +}; diff --git a/test/data/rest/posts_factory.js b/test/data/rest/posts_factory.js index ad4af0280..a731dafb8 100644 --- a/test/data/rest/posts_factory.js +++ b/test/data/rest/posts_factory.js @@ -1,7 +1,7 @@ -const { Factory } = require('rosie') -const { faker } = require('@faker-js/faker') +const { Factory } = require('rosie'); +const { faker } = require('@faker-js/faker'); module.exports = new Factory() .attr('author', () => faker.person.fullName()) .attr('title', () => faker.lorem.sentence()) - .attr('body', () => faker.lorem.paragraph()) + .attr('body', () => faker.lorem.paragraph()); diff --git a/test/data/sandbox/codecept.customworker.js b/test/data/sandbox/codecept.customworker.js index 3add49341..fc549d504 100644 --- a/test/data/sandbox/codecept.customworker.js +++ b/test/data/sandbox/codecept.customworker.js @@ -13,14 +13,14 @@ exports.config = { }, include: {}, bootstrap: async () => { - process.stdout.write('bootstrap b1+') + process.stdout.write('bootstrap b1+'); return new Promise((done) => { setTimeout(() => { - process.stdout.write('b2') - done() - }, 100) - }) + process.stdout.write('b2'); + done(); + }, 100); + }); }, mocha: {}, name: 'sandbox', -} +}; diff --git a/test/data/sandbox/configs/commentStep/customHelper.js b/test/data/sandbox/configs/commentStep/customHelper.js index 2303d03af..84fb53544 100644 --- a/test/data/sandbox/configs/commentStep/customHelper.js +++ b/test/data/sandbox/configs/commentStep/customHelper.js @@ -7,4 +7,4 @@ class CustomHelper extends Helper { } } -module.exports = CustomHelper +module.exports = CustomHelper; diff --git a/test/data/sandbox/configs/testArtifacts/customHelper.js b/test/data/sandbox/configs/testArtifacts/customHelper.js index 546e0fcf5..1705c2ec0 100644 --- a/test/data/sandbox/configs/testArtifacts/customHelper.js +++ b/test/data/sandbox/configs/testArtifacts/customHelper.js @@ -4,8 +4,8 @@ class CustomHelper extends Helper { shouldDoSomething(s) {} fail() { - throw new Error('Failed from helper') + throw new Error('Failed from helper'); } } -module.exports = CustomHelper +module.exports = CustomHelper; diff --git a/test/data/sandbox/features/step_definitions/my_other_steps.js b/test/data/sandbox/features/step_definitions/my_other_steps.js index f9c399929..de9c0b159 100644 --- a/test/data/sandbox/features/step_definitions/my_other_steps.js +++ b/test/data/sandbox/features/step_definitions/my_other_steps.js @@ -1,29 +1,29 @@ -const I = actor() -const axios = require('axios') +const I = actor(); +const axios = require('axios'); Given('I have products in my cart', (table) => { for (const id in table.rows) { if (id < 1) { - continue + continue; } - const cells = table.rows[id].cells - I.addProduct(cells[0].value, parseInt(cells[2].value, 10)) + const cells = table.rows[id].cells; + I.addProduct(cells[0].value, parseInt(cells[2].value, 10)); } -}) +}); Given(/I have product described as/, (text) => { - I.addItem(text.content.length) -}) + I.addItem(text.content.length); +}); Given(/I have simple product/, async () => { return new Promise((resolve) => { - I.addItem(10) - setTimeout(resolve, 0) - }) -}) + I.addItem(10); + setTimeout(resolve, 0); + }); +}); const sendRequest = async (requestConfig) => { - if (!requestConfig) throw JSON.stringify({ error: 'Request config is null or undefined.' }) + if (!requestConfig) throw JSON.stringify({ error: 'Request config is null or undefined.' }); return axios({ method: requestConfig.method || 'GET', timeout: requestConfig.timeout || 3000, @@ -37,20 +37,20 @@ const sendRequest = async (requestConfig) => { headers: error.response.headers, request: error.config.data, url: error.response.config.url, - } + }; } else if (error.request) { error = { message: 'The request was made but no response was received.', request: error.request, - } + }; } else { error = { message: `Something happened in setting up the request that triggered an Error.\n${error.message}`, - } + }; } - throw error - }) -} + throw error; + }); +}; Given(/^I make a request \(and it fails\)$/, async () => { const requestPayload = { @@ -61,11 +61,11 @@ Given(/^I make a request \(and it fails\)$/, async () => { 'X-Requested-With': 'XMLHttpRequest', }, timeout: 1, - } + }; - return sendRequest(requestPayload) -}) + return sendRequest(requestPayload); +}); Then(/^my test execution gets stuck$/, async () => { - I.say('Test execution never gets here...') -}) + I.say('Test execution never gets here...'); +}); diff --git a/test/data/sandbox/support/failureHelper.js b/test/data/sandbox/support/failureHelper.js index 4a3c0c4fe..a1b48ce3d 100644 --- a/test/data/sandbox/support/failureHelper.js +++ b/test/data/sandbox/support/failureHelper.js @@ -2,8 +2,8 @@ class FailureHelper extends Helper { constructor() { - throw new Error('Failed on FailureHelper') + throw new Error('Failed on FailureHelper'); } } -module.exports = FailureHelper +module.exports = FailureHelper; diff --git a/test/data/sandbox/testscenario_test.testscenario.js b/test/data/sandbox/testscenario_test.testscenario.js index 5861d5654..8fcd90e78 100644 --- a/test/data/sandbox/testscenario_test.testscenario.js +++ b/test/data/sandbox/testscenario_test.testscenario.js @@ -1,15 +1,15 @@ -Feature('Test scenario types') +Feature('Test scenario types'); Scenario('Simple test', () => { - console.log("It's usual test") -}) + console.log("It's usual test"); +}); Scenario('Simple async/await test', async ({ I }) => { - const text = await I.stringWithScenarioType('async/await') - console.log(text) -}) + const text = await I.stringWithScenarioType('async/await'); + console.log(text); +}); Scenario('Should understand async without brackets', async ({ I }) => { - const text = await I.stringWithScenarioType('asyncbrackets') - console.log(text) -}) + const text = await I.stringWithScenarioType('asyncbrackets'); + console.log(text); +}); diff --git a/test/helper/AppiumV2_ios_test.js b/test/helper/AppiumV2_ios_test.js index 5bc0b1c04..5ba588a18 100644 --- a/test/helper/AppiumV2_ios_test.js +++ b/test/helper/AppiumV2_ios_test.js @@ -1,24 +1,24 @@ -const chai = require('chai') +const chai = require('chai'); -const expect = chai.expect -const assert = chai.assert -const path = require('path') +const expect = chai.expect; +const assert = chai.assert; +const path = require('path'); -const Appium = require('../../lib/helper/Appium') -const AssertionFailedError = require('../../lib/assert/error') -const fileExists = require('../../lib/utils').fileExists -global.codeceptjs = require('../../lib') +const Appium = require('../../lib/helper/Appium'); +const AssertionFailedError = require('../../lib/assert/error'); +const fileExists = require('../../lib/utils').fileExists; +global.codeceptjs = require('../../lib'); -let app +let app; // iOS test app is built from https://github.com/appium/ios-test-app and uploaded to Saucelabs -const apk_path = 'storage:filename=TestApp-iphonesimulator.zip' -const smallWait = 3 +const apk_path = 'storage:filename=TestApp-iphonesimulator.zip'; +const smallWait = 3; describe('Appium iOS Tests', function () { - this.timeout(0) + this.timeout(0); before(async () => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); app = new Appium({ app: apk_path, appiumV2: true, @@ -41,166 +41,166 @@ describe('Appium iOS Tests', function () { port: 80, user: process.env.SAUCE_USERNAME, key: process.env.SAUCE_ACCESS_KEY, - }) - await app._beforeSuite() - app.isWeb = false - await app._before() - }) + }); + await app._beforeSuite(); + app.isWeb = false; + await app._before(); + }); after(async () => { - await app._after() - }) + await app._after(); + }); describe('app installation : #removeApp', () => { describe('#grabAllContexts, #grabContext, #grabOrientation, #grabSettings', () => { it('should grab all available contexts for screen', async () => { - await app.resetApp() - const val = await app.grabAllContexts() - assert.deepEqual(val, ['NATIVE_APP']) - }) + await app.resetApp(); + const val = await app.grabAllContexts(); + assert.deepEqual(val, ['NATIVE_APP']); + }); it('should grab current context', async () => { - const val = await app.grabContext() - assert.equal(val, 'NATIVE_APP') - }) + const val = await app.grabContext(); + assert.equal(val, 'NATIVE_APP'); + }); it('should grab custom settings', async () => { - const val = await app.grabSettings() - assert.deepEqual(val, { imageElementTapStrategy: 'w3cActions' }) - }) - }) - }) + const val = await app.grabSettings(); + assert.deepEqual(val, { imageElementTapStrategy: 'w3cActions' }); + }); + }); + }); describe('device orientation : #seeOrientationIs #setOrientation', () => { it('should return correct status about device orientation', async () => { - await app.seeOrientationIs('PORTRAIT') + await app.seeOrientationIs('PORTRAIT'); try { - await app.seeOrientationIs('LANDSCAPE') + await app.seeOrientationIs('LANDSCAPE'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected orientation to be LANDSCAPE') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('expected orientation to be LANDSCAPE'); } - }) - }) + }); + }); describe('#hideDeviceKeyboard', () => { it('should hide device Keyboard @quick', async () => { - await app.resetApp() - await app.click('~IntegerA') + await app.resetApp(); + await app.click('~IntegerA'); try { - await app.click('~locationStatus') + await app.click('~locationStatus'); } catch (e) { - e.message.should.include('element') + e.message.should.include('element'); } - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.click('~locationStatus') - }) + await app.hideDeviceKeyboard('pressKey', 'Done'); + await app.click('~locationStatus'); + }); it('should assert if no keyboard', async () => { try { - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.hideDeviceKeyboard('pressKey', 'Done'); } catch (e) { e.message.should.include( 'An unknown server-side error occurred while processing the command. Original error: Soft keyboard not present, cannot hide keyboard', - ) + ); } - }) - }) + }); + }); describe('see text : #see', () => { it('should work inside elements @second', async () => { - await app.resetApp() - await app.see('Compute Sum', '~ComputeSumButton') - }) - }) + await app.resetApp(); + await app.see('Compute Sum', '~ComputeSumButton'); + }); + }); describe('#appendField', () => { it('should be able to send special keys to element @second', async () => { - await app.resetApp() - await app.waitForElement('~IntegerA', smallWait) - await app.click('~IntegerA') - await app.appendField('~IntegerA', '1') - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.see('1', '~IntegerA') - }) - }) + await app.resetApp(); + await app.waitForElement('~IntegerA', smallWait); + await app.click('~IntegerA'); + await app.appendField('~IntegerA', '1'); + await app.hideDeviceKeyboard('pressKey', 'Done'); + await app.see('1', '~IntegerA'); + }); + }); describe('#waitForText', () => { it('should return error if not present', async () => { try { - await app.waitForText('Nothing here', 1, '~IntegerA') + await app.waitForText('Nothing here', 1, '~IntegerA'); } catch (e) { e.message.should.contain( 'element (~IntegerA) is not in DOM or there is no element(~IntegerA) with text "Nothing here" after 1 sec', - ) + ); } - }) - }) + }); + }); describe('#seeNumberOfElements @second', () => { it('should return 1 as count', async () => { - await app.resetApp() - await app.seeNumberOfElements('~IntegerA', 1) - }) - }) + await app.resetApp(); + await app.seeNumberOfElements('~IntegerA', 1); + }); + }); describe('see element : #seeElement, #dontSeeElement', () => { it('should check visible elements on page @quick', async () => { - await app.resetApp() - await app.seeElement('~IntegerA') - await app.dontSeeElement('#something-beyond') - await app.dontSeeElement('//input[@id="something-beyond"]') - }) - }) + await app.resetApp(); + await app.seeElement('~IntegerA'); + await app.dontSeeElement('#something-beyond'); + await app.dontSeeElement('//input[@id="something-beyond"]'); + }); + }); describe('#click @quick', () => { it('should click by accessibility id', async () => { - await app.resetApp() - await app.tap('~ComputeSumButton') - await app.see('0') - }) - }) + await app.resetApp(); + await app.tap('~ComputeSumButton'); + await app.see('0'); + }); + }); describe('#fillField @second', () => { it('should fill field by accessibility id', async () => { - await app.resetApp() - await app.waitForElement('~IntegerA', smallWait) - await app.click('~IntegerA') - await app.fillField('~IntegerA', '1') - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.see('1', '~IntegerA') - }) - }) + await app.resetApp(); + await app.waitForElement('~IntegerA', smallWait); + await app.click('~IntegerA'); + await app.fillField('~IntegerA', '1'); + await app.hideDeviceKeyboard('pressKey', 'Done'); + await app.see('1', '~IntegerA'); + }); + }); describe('#grabTextFrom, #grabValueFrom, #grabAttributeFrom @quick', () => { it('should grab text from page', async () => { - await app.resetApp() - const val = await app.grabTextFrom('~ComputeSumButton') - assert.equal(val, 'Compute Sum') - }) + await app.resetApp(); + const val = await app.grabTextFrom('~ComputeSumButton'); + assert.equal(val, 'Compute Sum'); + }); it('should grab attribute from element', async () => { - await app.resetApp() - const val = await app.grabAttributeFrom('~ComputeSumButton', 'label') - assert.equal(val, 'Compute Sum') - }) + await app.resetApp(); + const val = await app.grabAttributeFrom('~ComputeSumButton', 'label'); + assert.equal(val, 'Compute Sum'); + }); it('should be able to grab elements', async () => { - await app.resetApp() - const id = await app.grabNumberOfVisibleElements('~ComputeSumButton') - assert.strictEqual(1, id) - }) - }) + await app.resetApp(); + const id = await app.grabNumberOfVisibleElements('~ComputeSumButton'); + assert.strictEqual(1, id); + }); + }); describe('#saveScreenshot', () => { beforeEach(() => { - global.output_dir = path.join(global.codecept_dir, 'output') - }) + global.output_dir = path.join(global.codecept_dir, 'output'); + }); it('should create a screenshot file in output dir', async () => { - const sec = new Date().getUTCMilliseconds() - await app.saveScreenshot(`screenshot_${sec}.png`) - assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists') - }) - }) -}) + const sec = new Date().getUTCMilliseconds(); + await app.saveScreenshot(`screenshot_${sec}.png`); + assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists'); + }); + }); +}); diff --git a/test/helper/AppiumV2_test.js b/test/helper/AppiumV2_test.js index 0a3ea741d..4cf1d9acd 100644 --- a/test/helper/AppiumV2_test.js +++ b/test/helper/AppiumV2_test.js @@ -1,18 +1,18 @@ -const chai = require('chai') +const chai = require('chai'); -const expect = chai.expect -const assert = chai.assert +const expect = chai.expect; +const assert = chai.assert; -let app -const apk_path = 'storage:filename=selendroid-test-app-0.17.0.apk' -const smallWait = 3 +let app; +const apk_path = 'storage:filename=selendroid-test-app-0.17.0.apk'; +const smallWait = 3; describe('Appium', function () { // this.retries(1); - this.timeout(0) + this.timeout(0); before(async () => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); app = new Appium({ app: apk_path, appiumV2: true, @@ -37,372 +37,372 @@ describe('Appium', function () { // host: 'localhost', user: process.env.SAUCE_USERNAME, key: process.env.SAUCE_ACCESS_KEY, - }) - await app._beforeSuite() - app.isWeb = false - await app._before() - }) + }); + await app._beforeSuite(); + app.isWeb = false; + await app._before(); + }); after(async () => { - await app._after() - }) + await app._after(); + }); describe('app installation : #seeAppIsInstalled, #installApp, #removeApp, #seeAppIsNotInstalled', () => { describe('#grabAllContexts, #grabContext, #grabCurrentActivity, #grabNetworkConnection, #grabOrientation, #grabSettings', () => { it('should grab all available contexts for screen', async () => { - await app.resetApp() - await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.click('~buttonStartWebviewCD') - const val = await app.grabAllContexts() - assert.deepEqual(val, ['NATIVE_APP', 'WEBVIEW_io.selendroid.testapp']) - }) + await app.resetApp(); + await app.waitForElement('~buttonStartWebviewCD', smallWait); + await app.click('~buttonStartWebviewCD'); + const val = await app.grabAllContexts(); + assert.deepEqual(val, ['NATIVE_APP', 'WEBVIEW_io.selendroid.testapp']); + }); it('should grab current context', async () => { - const val = await app.grabContext() - assert.equal(val, 'NATIVE_APP') - }) + const val = await app.grabContext(); + assert.equal(val, 'NATIVE_APP'); + }); it('should grab current activity of app', async () => { - const val = await app.grabCurrentActivity() - assert.equal(val, '.HomeScreenActivity') - }) + const val = await app.grabCurrentActivity(); + assert.equal(val, '.HomeScreenActivity'); + }); it('should grab network connection settings', async () => { - await app.setNetworkConnection(4) - const val = await app.grabNetworkConnection() - assert.equal(val.value, 4) - assert.equal(val.inAirplaneMode, false) - assert.equal(val.hasWifi, false) - assert.equal(val.hasData, true) - }) + await app.setNetworkConnection(4); + const val = await app.grabNetworkConnection(); + assert.equal(val.value, 4); + assert.equal(val.inAirplaneMode, false); + assert.equal(val.hasWifi, false); + assert.equal(val.hasData, true); + }); it('should grab orientation', async () => { - const val = await app.grabOrientation() - assert.equal(val, 'PORTRAIT') - }) + const val = await app.grabOrientation(); + assert.equal(val, 'PORTRAIT'); + }); it('should grab custom settings', async () => { - const val = await app.grabSettings() - assert.deepEqual(val, { ignoreUnimportantViews: false }) - }) - }) + const val = await app.grabSettings(); + assert.deepEqual(val, { ignoreUnimportantViews: false }); + }); + }); it('should remove App and install it again', async () => { - await app.seeAppIsInstalled('io.selendroid.testapp') - await app.removeApp('io.selendroid.testapp') - await app.seeAppIsNotInstalled('io.selendroid.testapp') - await app.installApp(apk_path) - await app.seeAppIsInstalled('io.selendroid.testapp') - }) + await app.seeAppIsInstalled('io.selendroid.testapp'); + await app.removeApp('io.selendroid.testapp'); + await app.seeAppIsNotInstalled('io.selendroid.testapp'); + await app.installApp(apk_path); + await app.seeAppIsInstalled('io.selendroid.testapp'); + }); it('should return true if app is installed @quick', async () => { - const status = await app.checkIfAppIsInstalled('io.selendroid.testapp') - expect(status).to.be.true - }) + const status = await app.checkIfAppIsInstalled('io.selendroid.testapp'); + expect(status).to.be.true; + }); it('should assert when app is/is not installed', async () => { try { - await app.seeAppIsInstalled('io.super.app') + await app.seeAppIsInstalled('io.super.app'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected app io.super.app to be installed') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('expected app io.super.app to be installed'); } try { - await app.seeAppIsNotInstalled('io.selendroid.testapp') + await app.seeAppIsNotInstalled('io.selendroid.testapp'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected app io.selendroid.testapp not to be installed') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('expected app io.selendroid.testapp not to be installed'); } - }) - }) + }); + }); describe('see seeCurrentActivity: #seeCurrentActivityIs', () => { it('should return .HomeScreenActivity for default screen', async () => { - await app.seeCurrentActivityIs('.HomeScreenActivity') - }) + await app.seeCurrentActivityIs('.HomeScreenActivity'); + }); it('should assert for wrong screen', async () => { try { - await app.seeCurrentActivityIs('.SuperScreen') + await app.seeCurrentActivityIs('.SuperScreen'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected current activity to be .SuperScreen') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('expected current activity to be .SuperScreen'); } - }) - }) + }); + }); describe('device lock : #seeDeviceIsLocked, #seeDeviceIsUnlocked', () => { it('should return correct status about lock @second', async () => { - await app.seeDeviceIsUnlocked() + await app.seeDeviceIsUnlocked(); try { - await app.seeDeviceIsLocked() + await app.seeDeviceIsLocked(); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected device to be locked') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('expected device to be locked'); } - }) - }) + }); + }); describe('device orientation : #seeOrientationIs #setOrientation', () => { it('should return correct status about lock', async () => { - await app.seeOrientationIs('PORTRAIT') + await app.seeOrientationIs('PORTRAIT'); try { - await app.seeOrientationIs('LANDSCAPE') + await app.seeOrientationIs('LANDSCAPE'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected orientation to be LANDSCAPE') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('expected orientation to be LANDSCAPE'); } - }) + }); it('should set device orientation', async () => { - await app.resetApp() - await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.click('~buttonStartWebviewCD') - await app.setOrientation('LANDSCAPE') - await app.seeOrientationIs('LANDSCAPE') - }) - }) + await app.resetApp(); + await app.waitForElement('~buttonStartWebviewCD', smallWait); + await app.click('~buttonStartWebviewCD'); + await app.setOrientation('LANDSCAPE'); + await app.seeOrientationIs('LANDSCAPE'); + }); + }); describe('app context and activity: #switchToContext, #switchToWeb, #switchToNative', () => { it('should switch context', async () => { - await app.resetApp() - await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.click('~buttonStartWebviewCD') - await app.switchToContext('WEBVIEW_io.selendroid.testapp') - const val = await app.grabContext() - return assert.equal(val, 'WEBVIEW_io.selendroid.testapp') - }) + await app.resetApp(); + await app.waitForElement('~buttonStartWebviewCD', smallWait); + await app.click('~buttonStartWebviewCD'); + await app.switchToContext('WEBVIEW_io.selendroid.testapp'); + const val = await app.grabContext(); + return assert.equal(val, 'WEBVIEW_io.selendroid.testapp'); + }); it('should switch to native and web contexts @quick', async () => { - await app.resetApp() - await app.click('~buttonStartWebviewCD') - await app.see('WebView location') - await app.switchToWeb() - let val = await app.grabContext() - assert.equal(val, 'WEBVIEW_io.selendroid.testapp') - await app.see('Prefered Car') - assert.ok(app.isWeb) - await app.switchToNative() - val = await app.grabContext() - assert.equal(val, 'NATIVE_APP') - return assert.ok(!app.isWeb) - }) + await app.resetApp(); + await app.click('~buttonStartWebviewCD'); + await app.see('WebView location'); + await app.switchToWeb(); + let val = await app.grabContext(); + assert.equal(val, 'WEBVIEW_io.selendroid.testapp'); + await app.see('Prefered Car'); + assert.ok(app.isWeb); + await app.switchToNative(); + val = await app.grabContext(); + assert.equal(val, 'NATIVE_APP'); + return assert.ok(!app.isWeb); + }); it('should switch activity', async () => { - await app.startActivity('io.selendroid.testapp', '.RegisterUserActivity') - const val = await app.grabCurrentActivity() - assert.equal(val, '.RegisterUserActivity') - }) - }) + await app.startActivity('io.selendroid.testapp', '.RegisterUserActivity'); + const val = await app.grabCurrentActivity(); + assert.equal(val, '.RegisterUserActivity'); + }); + }); describe('#setNetworkConnection, #setSettings', () => { it('should set Network Connection (airplane mode on)', async () => { - await app.setNetworkConnection(1) - const val = await app.grabNetworkConnection() - return assert.equal(val.value, 1) - }) + await app.setNetworkConnection(1); + const val = await app.grabNetworkConnection(); + return assert.equal(val.value, 1); + }); it('should set custom settings', async () => { - await app.setSettings({ cyberdelia: 'open' }) - const val = await app.grabSettings() - assert.deepEqual(val, { ignoreUnimportantViews: false, cyberdelia: 'open' }) - }) - }) + await app.setSettings({ cyberdelia: 'open' }); + const val = await app.grabSettings(); + assert.deepEqual(val, { ignoreUnimportantViews: false, cyberdelia: 'open' }); + }); + }); describe('#hideDeviceKeyboard', () => { it('should hide device Keyboard @quick', async () => { - await app.resetApp() - await app.click('~startUserRegistrationCD') + await app.resetApp(); + await app.click('~startUserRegistrationCD'); try { - await app.click('//android.widget.CheckBox') + await app.click('//android.widget.CheckBox'); } catch (e) { - e.message.should.include('element') + e.message.should.include('element'); } - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.click('//android.widget.CheckBox') - }) + await app.hideDeviceKeyboard('pressKey', 'Done'); + await app.click('//android.widget.CheckBox'); + }); it('should assert if no keyboard', async () => { try { - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.hideDeviceKeyboard('pressKey', 'Done'); } catch (e) { e.message.should.include( 'An unknown server-side error occurred while processing the command. Original error: Soft keyboard not present, cannot hide keyboard', - ) + ); } - }) - }) + }); + }); describe('#sendDeviceKeyEvent', () => { it('should react on pressing keycode', async () => { - await app.sendDeviceKeyEvent(3) - await app.waitForVisible('~Apps') - }) - }) + await app.sendDeviceKeyEvent(3); + await app.waitForVisible('~Apps'); + }); + }); describe('#openNotifications', () => { it('should react on notification opening', async () => { try { await app.seeElement( '//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]', - ) + ); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) + e.should.be.instanceOf(AssertionFailedError); e.inspect().should.include( 'expected elements of //android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"] to be seen', - ) + ); } - await app.openNotifications() + await app.openNotifications(); await app.waitForVisible( '//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]', 10, - ) - }) - }) + ); + }); + }); describe('#makeTouchAction', () => { it('should react on touch actions', async () => { - await app.resetApp() - await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.tap('~buttonStartWebviewCD') - const val = await app.grabCurrentActivity() - assert.equal(val, '.WebViewActivity') - }) + await app.resetApp(); + await app.waitForElement('~buttonStartWebviewCD', smallWait); + await app.tap('~buttonStartWebviewCD'); + const val = await app.grabCurrentActivity(); + assert.equal(val, '.WebViewActivity'); + }); it('should react on swipe action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipe( "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1200, 1000, - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vx = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - assert.ok(vx.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps') - assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps') - }) + ); + assert.equal(type, 'FLICK'); + assert.ok(vx.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps'); + assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps'); + }); it('should react on swipeDown action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeDown( "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 1200, 1000, - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps') - }) + ); + assert.equal(type, 'FLICK'); + assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps'); + }); it('run simplified swipeDown @quick', async () => { - await app.resetApp() - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.resetApp(); + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeDown( "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 120, 100, - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) - assert.equal(type, 'FLICK') - }) + ); + assert.equal(type, 'FLICK'); + }); it('should react on swipeUp action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeUp( "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 1200, 1000, - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - assert.ok(vy.match(/vy: -\d\d000\.0 pps/), 'to be like dd000.0 pps') - }) + ); + assert.equal(type, 'FLICK'); + assert.ok(vy.match(/vy: -\d\d000\.0 pps/), 'to be like dd000.0 pps'); + }); it('should react on swipeRight action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeRight( "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1000, - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']", - ) - assert.equal(type, 'FLICK') - assert.ok(vy.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps') - }) + ); + assert.equal(type, 'FLICK'); + assert.ok(vy.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps'); + }); it('should react on swipeLeft action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeLeft( "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1000, - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']", - ) - assert.equal(type, 'FLICK') - assert.ok(vy.match(/vx: -\d\d000\.0 pps/), 'to be like 21000.0 pps') - }) + ); + assert.equal(type, 'FLICK'); + assert.ok(vy.match(/vx: -\d\d000\.0 pps/), 'to be like 21000.0 pps'); + }); it('should react on touchPerform action', async () => { await app.touchPerform([ @@ -414,15 +414,15 @@ describe('Appium', function () { }, }, { action: 'release' }, - ]) - const val = await app.grabCurrentActivity() - assert.equal(val, '.HomeScreenActivity') - }) + ]); + const val = await app.grabCurrentActivity(); + assert.equal(val, '.HomeScreenActivity'); + }); it('should assert when you dont scroll the document anymore', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); try { await app.swipeTo( '//android.widget.CheckBox', @@ -431,16 +431,16 @@ describe('Appium', function () { 30, 100, 500, - ) + ); } catch (e) { - e.message.should.include('Scroll to the end and element android.widget.CheckBox was not found') + e.message.should.include('Scroll to the end and element android.widget.CheckBox was not found'); } - }) + }); it('should react on swipeTo action', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); await app.swipeTo( '//android.widget.CheckBox', '//android.widget.ScrollView/android.widget.LinearLayout', @@ -448,121 +448,125 @@ describe('Appium', function () { 30, 100, 700, - ) - }) + ); + }); describe('#performTouchAction', () => { it('should react on swipeUp action @second', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) - await app.swipeUp("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") + ); + await app.swipeUp( + "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - expect(parseInt(vy.split(' ')[1], 10)).to.be.below(1006) - }) + ); + assert.equal(type, 'FLICK'); + expect(parseInt(vy.split(' ')[1], 10)).to.be.below(1006); + }); it('should react on swipeDown action @second', async () => { - await app.resetApp() - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.resetApp(); + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) - await app.swipeUp("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") + ); + await app.swipeUp( + "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - expect(parseInt(vy.split(' ')[1], 10)).to.be.above(-300) - }) + ); + assert.equal(type, 'FLICK'); + expect(parseInt(vy.split(' ')[1], 10)).to.be.above(-300); + }); it('should react on swipeLeft action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeLeft( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - expect(vy.split(' ')[1]).to.be.below(730) - }) + ); + assert.equal(type, 'FLICK'); + expect(vy.split(' ')[1]).to.be.below(730); + }); it('should react on swipeRight action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeRight( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - expect(vy.split(' ')[1]).to.be.above(278) - }) - }) - }) + ); + assert.equal(type, 'FLICK'); + expect(vy.split(' ')[1]).to.be.above(278); + }); + }); + }); describe('#pullFile', () => { it('should pull file to local machine', async () => { - const savepath = path.join(__dirname, `/../data/output/testpullfile${new Date().getTime()}.png`) - await app.pullFile('/storage/emulated/0/DCIM/sauce_logo.png', savepath) - assert.ok(fileExists(savepath), null, 'file does not exists') - }) - }) + const savepath = path.join(__dirname, `/../data/output/testpullfile${new Date().getTime()}.png`); + await app.pullFile('/storage/emulated/0/DCIM/sauce_logo.png', savepath); + assert.ok(fileExists(savepath), null, 'file does not exists'); + }); + }); describe('see text : #see', () => { it('should work inside elements @second', async () => { - await app.resetApp() - await app.see('EN Button', '~buttonTestCD') - await app.see('Hello') - await app.dontSee('Welcome', '~buttonTestCD') - }) + await app.resetApp(); + await app.see('EN Button', '~buttonTestCD'); + await app.see('Hello'); + await app.dontSee('Welcome', '~buttonTestCD'); + }); it('should work inside web view as normally @quick', async () => { - await app.resetApp() - await app.click('~buttonStartWebviewCD') - await app.switchToWeb() - await app.see('Prefered Car:') - }) - }) + await app.resetApp(); + await app.click('~buttonStartWebviewCD'); + await app.switchToWeb(); + await app.see('Prefered Car:'); + }); + }); describe('#appendField', () => { it('should be able to send special keys to element @second', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') - await app.click('~email of the customer') - await app.appendField('~email of the customer', '1') - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); + await app.click('~email of the customer'); + await app.appendField('~email of the customer', '1'); + await app.hideDeviceKeyboard('pressKey', 'Done'); await app.swipeTo( '//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', @@ -570,67 +574,69 @@ describe('Appium', function () { 30, 100, 700, - ) - await app.click('//android.widget.Button') - await app.see('1', '#io.selendroid.testapp:id/label_email_data') - }) - }) + ); + await app.click('//android.widget.Button'); + await app.see('1', '#io.selendroid.testapp:id/label_email_data'); + }); + }); describe('#seeInSource', () => { it('should check for text to be in HTML source', async () => { - await app.seeInSource('class="android.widget.Button" package="io.selendroid.testapp" content-desc="buttonTestCD"') - await app.dontSeeInSource(' { it('should return error if not present', async () => { try { - await app.waitForText('Nothing here', 1, '~buttonTestCD') + await app.waitForText('Nothing here', 1, '~buttonTestCD'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.be.equal('expected element ~buttonTestCD to include "Nothing here"') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.be.equal('expected element ~buttonTestCD to include "Nothing here"'); } - }) - }) + }); + }); describe('#seeNumberOfElements @second', () => { it('should return 1 as count', async () => { - await app.resetApp() - await app.seeNumberOfElements('~buttonTestCD', 1) - }) - }) + await app.resetApp(); + await app.seeNumberOfElements('~buttonTestCD', 1); + }); + }); describe('see element : #seeElement, #dontSeeElement', () => { it('should check visible elements on page @quick', async () => { - await app.resetApp() - await app.seeElement('//android.widget.Button[@content-desc = "buttonTestCD"]') - await app.dontSeeElement('#something-beyond') - await app.dontSeeElement('//input[@id="something-beyond"]') - }) - }) + await app.resetApp(); + await app.seeElement('//android.widget.Button[@content-desc = "buttonTestCD"]'); + await app.dontSeeElement('#something-beyond'); + await app.dontSeeElement('//input[@id="something-beyond"]'); + }); + }); describe('#click @quick', () => { it('should click by accessibility id', async () => { - await app.resetApp() - await app.tap('~startUserRegistrationCD') - await app.seeElement('//android.widget.TextView[@content-desc="label_usernameCD"]') - }) + await app.resetApp(); + await app.tap('~startUserRegistrationCD'); + await app.seeElement('//android.widget.TextView[@content-desc="label_usernameCD"]'); + }); it('should click by xpath', async () => { - await app.resetApp() - await app.click('//android.widget.ImageButton[@content-desc = "startUserRegistrationCD"]') - await app.seeElement('//android.widget.TextView[@content-desc="label_usernameCD"]') - }) - }) + await app.resetApp(); + await app.click('//android.widget.ImageButton[@content-desc = "startUserRegistrationCD"]'); + await app.seeElement('//android.widget.TextView[@content-desc="label_usernameCD"]'); + }); + }); describe('#fillField, #appendField @second', () => { it('should fill field by accessibility id', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') - await app.fillField('~email of the customer', 'Nothing special') - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); + await app.fillField('~email of the customer', 'Nothing special'); + await app.hideDeviceKeyboard('pressKey', 'Done'); await app.swipeTo( '//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', @@ -638,20 +644,20 @@ describe('Appium', function () { 30, 100, 700, - ) - await app.click('//android.widget.Button') + ); + await app.click('//android.widget.Button'); await app.see( 'Nothing special', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', - ) - }) + ); + }); it('should fill field by xpath', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') - await app.fillField('//android.widget.EditText[@content-desc="email of the customer"]', 'Nothing special') - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); + await app.fillField('//android.widget.EditText[@content-desc="email of the customer"]', 'Nothing special'); + await app.hideDeviceKeyboard('pressKey', 'Done'); await app.swipeTo( '//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', @@ -659,21 +665,21 @@ describe('Appium', function () { 30, 100, 700, - ) - await app.click('//android.widget.Button') + ); + await app.click('//android.widget.Button'); await app.see( 'Nothing special', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', - ) - }) + ); + }); it('should append field value @second', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') - await app.fillField('~email of the customer', 'Nothing special') - await app.appendField('~email of the customer', 'blabla') - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); + await app.fillField('~email of the customer', 'Nothing special'); + await app.appendField('~email of the customer', 'blabla'); + await app.hideDeviceKeyboard('pressKey', 'Done'); await app.swipeTo( '//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', @@ -681,46 +687,46 @@ describe('Appium', function () { 30, 100, 700, - ) - await app.click('//android.widget.Button') + ); + await app.click('//android.widget.Button'); await app.see( 'Nothing specialblabla', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', - ) - }) - }) + ); + }); + }); describe('#clearField', () => { it('should clear a given element', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') - await app.fillField('~email of the customer', 'Nothing special') - await app.see('Nothing special', '~email of the customer') - await app.clearField('~email of the customer') - await app.dontSee('Nothing special', '~email of the customer') - }) - }) + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); + await app.fillField('~email of the customer', 'Nothing special'); + await app.see('Nothing special', '~email of the customer'); + await app.clearField('~email of the customer'); + await app.dontSee('Nothing special', '~email of the customer'); + }); + }); describe('#grabTextFrom, #grabValueFrom, #grabAttributeFrom @quick', () => { it('should grab text from page', async () => { - await app.resetApp() - const val = await app.grabTextFrom('//android.widget.Button[@content-desc="buttonTestCD"]') - assert.equal(val, 'EN Button') - }) + await app.resetApp(); + const val = await app.grabTextFrom('//android.widget.Button[@content-desc="buttonTestCD"]'); + assert.equal(val, 'EN Button'); + }); it('should grab attribute from element', async () => { - await app.resetApp() - const val = await app.grabAttributeFrom('//android.widget.Button[@content-desc="buttonTestCD"]', 'resourceId') - assert.equal(val, 'io.selendroid.testapp:id/buttonTest') - }) + await app.resetApp(); + const val = await app.grabAttributeFrom('//android.widget.Button[@content-desc="buttonTestCD"]', 'resourceId'); + assert.equal(val, 'io.selendroid.testapp:id/buttonTest'); + }); it('should be able to grab elements', async () => { - await app.resetApp() - await app.tap('~startUserRegistrationCD') - await app.tap('~email of the customer') - await app.appendField('//android.widget.EditText[@content-desc="email of the customer"]', '1') - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.resetApp(); + await app.tap('~startUserRegistrationCD'); + await app.tap('~email of the customer'); + await app.appendField('//android.widget.EditText[@content-desc="email of the customer"]', '1'); + await app.hideDeviceKeyboard('pressKey', 'Done'); await app.swipeTo( '//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', @@ -728,66 +734,66 @@ describe('Appium', function () { 30, 100, 700, - ) - await app.click('//android.widget.Button') - await app.see('1', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]') + ); + await app.click('//android.widget.Button'); + await app.see('1', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]'); const id = await app.grabNumberOfVisibleElements( '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', 'contentDescription', - ) - assert.strictEqual(1, id) - }) - }) + ); + assert.strictEqual(1, id); + }); + }); describe('#saveScreenshot @quick', () => { beforeEach(() => { - global.output_dir = path.join(global.codecept_dir, 'output') - }) + global.output_dir = path.join(global.codecept_dir, 'output'); + }); it('should create a screenshot file in output dir', async () => { - const sec = new Date().getUTCMilliseconds() - await app.saveScreenshot(`screenshot_${sec}.png`) - assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists') - }) - }) + const sec = new Date().getUTCMilliseconds(); + await app.saveScreenshot(`screenshot_${sec}.png`); + assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists'); + }); + }); describe('#runOnIOS, #runOnAndroid, #runInWeb', () => { it('should use Android locators', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click({ android: '~startUserRegistrationCD', ios: 'fake-element' }) - await app.see('Welcome to register a new User') - }) + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click({ android: '~startUserRegistrationCD', ios: 'fake-element' }); + await app.see('Welcome to register a new User'); + }); it('should execute only on Android @quick', () => { - let platform = null + let platform = null; app.runOnIOS(() => { - platform = 'ios' - }) + platform = 'ios'; + }); app.runOnAndroid(() => { - platform = 'android' - }) + platform = 'android'; + }); app.runOnAndroid({ platformVersion: '7.0' }, () => { - platform = 'android7' - }) + platform = 'android7'; + }); - assert.equal('android', platform) - }) + assert.equal('android', platform); + }); it('should execute only on Android >= 5.0 @quick', () => { app.runOnAndroid( (caps) => caps.platformVersion >= 5, () => {}, - ) - }) + ); + }); it('should execute only in Web', () => { - app.isWeb = true - let executed = false + app.isWeb = true; + let executed = false; app.runOnIOS(() => { - executed = true - }) - assert.ok(!executed) - }) - }) -}) + executed = true; + }); + assert.ok(!executed); + }); + }); +}); diff --git a/test/helper/Appium_test.js b/test/helper/Appium_test.js index ef8c5fe37..0ad4fde5b 100644 --- a/test/helper/Appium_test.js +++ b/test/helper/Appium_test.js @@ -1,25 +1,25 @@ -const chai = require('chai') +const chai = require('chai'); -const expect = chai.expect -const assert = chai.assert +const expect = chai.expect; +const assert = chai.assert; -const path = require('path') +const path = require('path'); -const Appium = require('../../lib/helper/Appium') -const AssertionFailedError = require('../../lib/assert/error') -const fileExists = require('../../lib/utils').fileExists -global.codeceptjs = require('../../lib') +const Appium = require('../../lib/helper/Appium'); +const AssertionFailedError = require('../../lib/assert/error'); +const fileExists = require('../../lib/utils').fileExists; +global.codeceptjs = require('../../lib'); -let app -const apk_path = 'storage:filename=selendroid-test-app-0.17.0.apk' -const smallWait = 3 +let app; +const apk_path = 'storage:filename=selendroid-test-app-0.17.0.apk'; +const smallWait = 3; describe('Appium', function () { // this.retries(1); - this.timeout(0) + this.timeout(0); before(async () => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); app = new Appium({ app: apk_path, desiredCapabilities: { @@ -41,372 +41,372 @@ describe('Appium', function () { // host: 'localhost', user: process.env.SAUCE_USERNAME, key: process.env.SAUCE_ACCESS_KEY, - }) - await app._beforeSuite() - app.isWeb = false - await app._before() - }) + }); + await app._beforeSuite(); + app.isWeb = false; + await app._before(); + }); after(async () => { - await app._after() - }) + await app._after(); + }); describe('app installation : #seeAppIsInstalled, #installApp, #removeApp, #seeAppIsNotInstalled', () => { describe('#grabAllContexts, #grabContext, #grabCurrentActivity, #grabNetworkConnection, #grabOrientation, #grabSettings', () => { it('should grab all available contexts for screen', async () => { - await app.resetApp() - await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.click('~buttonStartWebviewCD') - const val = await app.grabAllContexts() - assert.deepEqual(val, ['NATIVE_APP', 'WEBVIEW_io.selendroid.testapp']) - }) + await app.resetApp(); + await app.waitForElement('~buttonStartWebviewCD', smallWait); + await app.click('~buttonStartWebviewCD'); + const val = await app.grabAllContexts(); + assert.deepEqual(val, ['NATIVE_APP', 'WEBVIEW_io.selendroid.testapp']); + }); it('should grab current context', async () => { - const val = await app.grabContext() - assert.equal(val, 'NATIVE_APP') - }) + const val = await app.grabContext(); + assert.equal(val, 'NATIVE_APP'); + }); it('should grab current activity of app', async () => { - const val = await app.grabCurrentActivity() - assert.equal(val, '.HomeScreenActivity') - }) + const val = await app.grabCurrentActivity(); + assert.equal(val, '.HomeScreenActivity'); + }); it('should grab network connection settings', async () => { - await app.setNetworkConnection(4) - const val = await app.grabNetworkConnection() - assert.equal(val.value, 4) - assert.equal(val.inAirplaneMode, false) - assert.equal(val.hasWifi, false) - assert.equal(val.hasData, true) - }) + await app.setNetworkConnection(4); + const val = await app.grabNetworkConnection(); + assert.equal(val.value, 4); + assert.equal(val.inAirplaneMode, false); + assert.equal(val.hasWifi, false); + assert.equal(val.hasData, true); + }); it('should grab orientation', async () => { - const val = await app.grabOrientation() - assert.equal(val, 'PORTRAIT') - }) + const val = await app.grabOrientation(); + assert.equal(val, 'PORTRAIT'); + }); it('should grab custom settings', async () => { - const val = await app.grabSettings() - assert.deepEqual(val, { ignoreUnimportantViews: false }) - }) - }) + const val = await app.grabSettings(); + assert.deepEqual(val, { ignoreUnimportantViews: false }); + }); + }); it('should remove App and install it again', async () => { - await app.seeAppIsInstalled('io.selendroid.testapp') - await app.removeApp('io.selendroid.testapp') - await app.seeAppIsNotInstalled('io.selendroid.testapp') - await app.installApp(apk_path) - await app.seeAppIsInstalled('io.selendroid.testapp') - }) + await app.seeAppIsInstalled('io.selendroid.testapp'); + await app.removeApp('io.selendroid.testapp'); + await app.seeAppIsNotInstalled('io.selendroid.testapp'); + await app.installApp(apk_path); + await app.seeAppIsInstalled('io.selendroid.testapp'); + }); it('should return true if app is installed @quick', async () => { - const status = await app.checkIfAppIsInstalled('io.selendroid.testapp') - expect(status).to.be.true - }) + const status = await app.checkIfAppIsInstalled('io.selendroid.testapp'); + expect(status).to.be.true; + }); it('should assert when app is/is not installed', async () => { try { - await app.seeAppIsInstalled('io.super.app') + await app.seeAppIsInstalled('io.super.app'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected app io.super.app to be installed') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('expected app io.super.app to be installed'); } try { - await app.seeAppIsNotInstalled('io.selendroid.testapp') + await app.seeAppIsNotInstalled('io.selendroid.testapp'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected app io.selendroid.testapp not to be installed') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('expected app io.selendroid.testapp not to be installed'); } - }) - }) + }); + }); describe('see seeCurrentActivity: #seeCurrentActivityIs', () => { it('should return .HomeScreenActivity for default screen', async () => { - await app.seeCurrentActivityIs('.HomeScreenActivity') - }) + await app.seeCurrentActivityIs('.HomeScreenActivity'); + }); it('should assert for wrong screen', async () => { try { - await app.seeCurrentActivityIs('.SuperScreen') + await app.seeCurrentActivityIs('.SuperScreen'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected current activity to be .SuperScreen') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('expected current activity to be .SuperScreen'); } - }) - }) + }); + }); describe('device lock : #seeDeviceIsLocked, #seeDeviceIsUnlocked', () => { it('should return correct status about lock @second', async () => { - await app.seeDeviceIsUnlocked() + await app.seeDeviceIsUnlocked(); try { - await app.seeDeviceIsLocked() + await app.seeDeviceIsLocked(); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected device to be locked') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('expected device to be locked'); } - }) - }) + }); + }); describe('device orientation : #seeOrientationIs #setOrientation', () => { it('should return correct status about lock', async () => { - await app.seeOrientationIs('PORTRAIT') + await app.seeOrientationIs('PORTRAIT'); try { - await app.seeOrientationIs('LANDSCAPE') + await app.seeOrientationIs('LANDSCAPE'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('expected orientation to be LANDSCAPE') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('expected orientation to be LANDSCAPE'); } - }) + }); it('should set device orientation', async () => { - await app.resetApp() - await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.click('~buttonStartWebviewCD') - await app.setOrientation('LANDSCAPE') - await app.seeOrientationIs('LANDSCAPE') - }) - }) + await app.resetApp(); + await app.waitForElement('~buttonStartWebviewCD', smallWait); + await app.click('~buttonStartWebviewCD'); + await app.setOrientation('LANDSCAPE'); + await app.seeOrientationIs('LANDSCAPE'); + }); + }); describe('app context and activity: #switchToContext, #switchToWeb, #switchToNative', () => { it('should switch context', async () => { - await app.resetApp() - await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.click('~buttonStartWebviewCD') - await app.switchToContext('WEBVIEW_io.selendroid.testapp') - const val = await app.grabContext() - return assert.equal(val, 'WEBVIEW_io.selendroid.testapp') - }) + await app.resetApp(); + await app.waitForElement('~buttonStartWebviewCD', smallWait); + await app.click('~buttonStartWebviewCD'); + await app.switchToContext('WEBVIEW_io.selendroid.testapp'); + const val = await app.grabContext(); + return assert.equal(val, 'WEBVIEW_io.selendroid.testapp'); + }); it('should switch to native and web contexts @quick', async () => { - await app.resetApp() - await app.click('~buttonStartWebviewCD') - await app.see('WebView location') - await app.switchToWeb() - let val = await app.grabContext() - assert.equal(val, 'WEBVIEW_io.selendroid.testapp') - await app.see('Prefered Car') - assert.ok(app.isWeb) - await app.switchToNative() - val = await app.grabContext() - assert.equal(val, 'NATIVE_APP') - return assert.ok(!app.isWeb) - }) + await app.resetApp(); + await app.click('~buttonStartWebviewCD'); + await app.see('WebView location'); + await app.switchToWeb(); + let val = await app.grabContext(); + assert.equal(val, 'WEBVIEW_io.selendroid.testapp'); + await app.see('Prefered Car'); + assert.ok(app.isWeb); + await app.switchToNative(); + val = await app.grabContext(); + assert.equal(val, 'NATIVE_APP'); + return assert.ok(!app.isWeb); + }); it('should switch activity', async () => { - await app.startActivity('io.selendroid.testapp', '.RegisterUserActivity') - const val = await app.grabCurrentActivity() - assert.equal(val, '.RegisterUserActivity') - }) - }) + await app.startActivity('io.selendroid.testapp', '.RegisterUserActivity'); + const val = await app.grabCurrentActivity(); + assert.equal(val, '.RegisterUserActivity'); + }); + }); describe('#setNetworkConnection, #setSettings', () => { it('should set Network Connection (airplane mode on)', async () => { - await app.setNetworkConnection(1) - const val = await app.grabNetworkConnection() - return assert.equal(val.value, 1) - }) + await app.setNetworkConnection(1); + const val = await app.grabNetworkConnection(); + return assert.equal(val.value, 1); + }); it('should set custom settings', async () => { - await app.setSettings({ cyberdelia: 'open' }) - const val = await app.grabSettings() - assert.deepEqual(val, { ignoreUnimportantViews: false, cyberdelia: 'open' }) - }) - }) + await app.setSettings({ cyberdelia: 'open' }); + const val = await app.grabSettings(); + assert.deepEqual(val, { ignoreUnimportantViews: false, cyberdelia: 'open' }); + }); + }); describe('#hideDeviceKeyboard', () => { it('should hide device Keyboard @quick', async () => { - await app.resetApp() - await app.click('~startUserRegistrationCD') + await app.resetApp(); + await app.click('~startUserRegistrationCD'); try { - await app.click('//android.widget.CheckBox') + await app.click('//android.widget.CheckBox'); } catch (e) { - e.message.should.include('element') + e.message.should.include('element'); } - await app.hideDeviceKeyboard('pressKey', 'Done') - await app.click('//android.widget.CheckBox') - }) + await app.hideDeviceKeyboard('pressKey', 'Done'); + await app.click('//android.widget.CheckBox'); + }); it('should assert if no keyboard', async () => { try { - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.hideDeviceKeyboard('pressKey', 'Done'); } catch (e) { e.message.should.include( 'An unknown server-side error occurred while processing the command. Original error: Soft keyboard not present, cannot hide keyboard', - ) + ); } - }) - }) + }); + }); describe('#sendDeviceKeyEvent', () => { it('should react on pressing keycode', async () => { - await app.sendDeviceKeyEvent(3) - await app.waitForVisible('~Apps') - }) - }) + await app.sendDeviceKeyEvent(3); + await app.waitForVisible('~Apps'); + }); + }); describe('#openNotifications', () => { it('should react on notification opening', async () => { try { await app.seeElement( '//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]', - ) + ); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) + e.should.be.instanceOf(AssertionFailedError); e.inspect().should.include( 'expected elements of //android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"] to be seen', - ) + ); } - await app.openNotifications() + await app.openNotifications(); await app.waitForVisible( '//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]', 10, - ) - }) - }) + ); + }); + }); describe('#makeTouchAction', () => { it('should react on touch actions', async () => { - await app.resetApp() - await app.waitForElement('~buttonStartWebviewCD', smallWait) - await app.tap('~buttonStartWebviewCD') - const val = await app.grabCurrentActivity() - assert.equal(val, '.WebViewActivity') - }) + await app.resetApp(); + await app.waitForElement('~buttonStartWebviewCD', smallWait); + await app.tap('~buttonStartWebviewCD'); + const val = await app.grabCurrentActivity(); + assert.equal(val, '.WebViewActivity'); + }); it('should react on swipe action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipe( "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1200, 1000, - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vx = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - assert.ok(vx.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps') - assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps') - }) + ); + assert.equal(type, 'FLICK'); + assert.ok(vx.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps'); + assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps'); + }); it('should react on swipeDown action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeDown( "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 1200, 1000, - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps') - }) + ); + assert.equal(type, 'FLICK'); + assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps'); + }); it('run simplified swipeDown @quick', async () => { - await app.resetApp() - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.resetApp(); + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeDown( "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 120, 100, - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) - assert.equal(type, 'FLICK') - }) + ); + assert.equal(type, 'FLICK'); + }); it('should react on swipeUp action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeUp( "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 1200, 1000, - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - assert.ok(vy.match(/vy: -\d\d000\.0 pps/), 'to be like dd000.0 pps') - }) + ); + assert.equal(type, 'FLICK'); + assert.ok(vy.match(/vy: -\d\d000\.0 pps/), 'to be like dd000.0 pps'); + }); it('should react on swipeRight action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeRight( "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1000, - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']", - ) - assert.equal(type, 'FLICK') - assert.ok(vy.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps') - }) + ); + assert.equal(type, 'FLICK'); + assert.ok(vy.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps'); + }); it('should react on swipeLeft action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeLeft( "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1000, - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']", - ) - assert.equal(type, 'FLICK') - assert.ok(vy.match(/vx: -\d\d000\.0 pps/), 'to be like 21000.0 pps') - }) + ); + assert.equal(type, 'FLICK'); + assert.ok(vy.match(/vx: -\d\d000\.0 pps/), 'to be like 21000.0 pps'); + }); it('should react on touchPerform action', async () => { await app.touchPerform([ @@ -418,15 +418,15 @@ describe('Appium', function () { }, }, { action: 'release' }, - ]) - const val = await app.grabCurrentActivity() - assert.equal(val, '.HomeScreenActivity') - }) + ]); + const val = await app.grabCurrentActivity(); + assert.equal(val, '.HomeScreenActivity'); + }); it('should assert when you dont scroll the document anymore', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); try { await app.swipeTo( '//android.widget.CheckBox', @@ -435,16 +435,16 @@ describe('Appium', function () { 30, 100, 500, - ) + ); } catch (e) { - e.message.should.include('Scroll to the end and element android.widget.CheckBox was not found') + e.message.should.include('Scroll to the end and element android.widget.CheckBox was not found'); } - }) + }); it('should react on swipeTo action', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); await app.swipeTo( '//android.widget.CheckBox', '//android.widget.ScrollView/android.widget.LinearLayout', @@ -452,121 +452,125 @@ describe('Appium', function () { 30, 100, 700, - ) - }) + ); + }); describe('#performTouchAction', () => { it('should react on swipeUp action @second', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) - await app.swipeUp("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") + ); + await app.swipeUp( + "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - expect(parseInt(vy.split(' ')[1], 10)).to.be.below(1006) - }) + ); + assert.equal(type, 'FLICK'); + expect(parseInt(vy.split(' ')[1], 10)).to.be.below(1006); + }); it('should react on swipeDown action @second', async () => { - await app.resetApp() - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.resetApp(); + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) - await app.swipeUp("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']") + ); + await app.swipeUp( + "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - expect(parseInt(vy.split(' ')[1], 10)).to.be.above(-300) - }) + ); + assert.equal(type, 'FLICK'); + expect(parseInt(vy.split(' ')[1], 10)).to.be.above(-300); + }); it('should react on swipeLeft action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeLeft( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - expect(vy.split(' ')[1]).to.be.below(730) - }) + ); + assert.equal(type, 'FLICK'); + expect(vy.split(' ')[1]).to.be.below(730); + }); it('should react on swipeRight action', async () => { - await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']") + await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); await app.waitForText( 'Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); await app.swipeRight( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const type = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ) + ); const vy = await app.grabTextFrom( "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ) - assert.equal(type, 'FLICK') - expect(vy.split(' ')[1]).to.be.above(278) - }) - }) - }) + ); + assert.equal(type, 'FLICK'); + expect(vy.split(' ')[1]).to.be.above(278); + }); + }); + }); describe('#pullFile', () => { it('should pull file to local machine', async () => { - const savepath = path.join(__dirname, `/../data/output/testpullfile${new Date().getTime()}.png`) - await app.pullFile('/storage/emulated/0/DCIM/sauce_logo.png', savepath) - assert.ok(fileExists(savepath), null, 'file does not exists') - }) - }) + const savepath = path.join(__dirname, `/../data/output/testpullfile${new Date().getTime()}.png`); + await app.pullFile('/storage/emulated/0/DCIM/sauce_logo.png', savepath); + assert.ok(fileExists(savepath), null, 'file does not exists'); + }); + }); describe('see text : #see', () => { it('should work inside elements @second', async () => { - await app.resetApp() - await app.see('EN Button', '~buttonTestCD') - await app.see('Hello') - await app.dontSee('Welcome', '~buttonTestCD') - }) + await app.resetApp(); + await app.see('EN Button', '~buttonTestCD'); + await app.see('Hello'); + await app.dontSee('Welcome', '~buttonTestCD'); + }); it('should work inside web view as normally @quick', async () => { - await app.resetApp() - await app.click('~buttonStartWebviewCD') - await app.switchToWeb() - await app.see('Prefered Car:') - }) - }) + await app.resetApp(); + await app.click('~buttonStartWebviewCD'); + await app.switchToWeb(); + await app.see('Prefered Car:'); + }); + }); describe('#appendField', () => { it('should be able to send special keys to element @second', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') - await app.click('~email of the customer') - await app.appendField('~email of the customer', '1') - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); + await app.click('~email of the customer'); + await app.appendField('~email of the customer', '1'); + await app.hideDeviceKeyboard('pressKey', 'Done'); await app.swipeTo( '//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', @@ -574,67 +578,69 @@ describe('Appium', function () { 30, 100, 700, - ) - await app.click('//android.widget.Button') - await app.see('1', '#io.selendroid.testapp:id/label_email_data') - }) - }) + ); + await app.click('//android.widget.Button'); + await app.see('1', '#io.selendroid.testapp:id/label_email_data'); + }); + }); describe('#seeInSource', () => { it('should check for text to be in HTML source', async () => { - await app.seeInSource('class="android.widget.Button" package="io.selendroid.testapp" content-desc="buttonTestCD"') - await app.dontSeeInSource(' { it('should return error if not present', async () => { try { - await app.waitForText('Nothing here', 1, '~buttonTestCD') + await app.waitForText('Nothing here', 1, '~buttonTestCD'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.be.equal('expected element ~buttonTestCD to include "Nothing here"') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.be.equal('expected element ~buttonTestCD to include "Nothing here"'); } - }) - }) + }); + }); describe('#seeNumberOfElements @second', () => { it('should return 1 as count', async () => { - await app.resetApp() - await app.seeNumberOfElements('~buttonTestCD', 1) - }) - }) + await app.resetApp(); + await app.seeNumberOfElements('~buttonTestCD', 1); + }); + }); describe('see element : #seeElement, #dontSeeElement', () => { it('should check visible elements on page @quick', async () => { - await app.resetApp() - await app.seeElement('//android.widget.Button[@content-desc = "buttonTestCD"]') - await app.dontSeeElement('#something-beyond') - await app.dontSeeElement('//input[@id="something-beyond"]') - }) - }) + await app.resetApp(); + await app.seeElement('//android.widget.Button[@content-desc = "buttonTestCD"]'); + await app.dontSeeElement('#something-beyond'); + await app.dontSeeElement('//input[@id="something-beyond"]'); + }); + }); describe('#click @quick', () => { it('should click by accessibility id', async () => { - await app.resetApp() - await app.tap('~startUserRegistrationCD') - await app.seeElement('//android.widget.TextView[@content-desc="label_usernameCD"]') - }) + await app.resetApp(); + await app.tap('~startUserRegistrationCD'); + await app.seeElement('//android.widget.TextView[@content-desc="label_usernameCD"]'); + }); it('should click by xpath', async () => { - await app.resetApp() - await app.click('//android.widget.ImageButton[@content-desc = "startUserRegistrationCD"]') - await app.seeElement('//android.widget.TextView[@content-desc="label_usernameCD"]') - }) - }) + await app.resetApp(); + await app.click('//android.widget.ImageButton[@content-desc = "startUserRegistrationCD"]'); + await app.seeElement('//android.widget.TextView[@content-desc="label_usernameCD"]'); + }); + }); describe('#fillField, #appendField @second', () => { it('should fill field by accessibility id', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') - await app.fillField('~email of the customer', 'Nothing special') - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); + await app.fillField('~email of the customer', 'Nothing special'); + await app.hideDeviceKeyboard('pressKey', 'Done'); await app.swipeTo( '//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', @@ -642,20 +648,20 @@ describe('Appium', function () { 30, 100, 700, - ) - await app.click('//android.widget.Button') + ); + await app.click('//android.widget.Button'); await app.see( 'Nothing special', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', - ) - }) + ); + }); it('should fill field by xpath', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') - await app.fillField('//android.widget.EditText[@content-desc="email of the customer"]', 'Nothing special') - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); + await app.fillField('//android.widget.EditText[@content-desc="email of the customer"]', 'Nothing special'); + await app.hideDeviceKeyboard('pressKey', 'Done'); await app.swipeTo( '//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', @@ -663,21 +669,21 @@ describe('Appium', function () { 30, 100, 700, - ) - await app.click('//android.widget.Button') + ); + await app.click('//android.widget.Button'); await app.see( 'Nothing special', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', - ) - }) + ); + }); it('should append field value @second', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') - await app.fillField('~email of the customer', 'Nothing special') - await app.appendField('~email of the customer', 'blabla') - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); + await app.fillField('~email of the customer', 'Nothing special'); + await app.appendField('~email of the customer', 'blabla'); + await app.hideDeviceKeyboard('pressKey', 'Done'); await app.swipeTo( '//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', @@ -685,46 +691,46 @@ describe('Appium', function () { 30, 100, 700, - ) - await app.click('//android.widget.Button') + ); + await app.click('//android.widget.Button'); await app.see( 'Nothing specialblabla', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', - ) - }) - }) + ); + }); + }); describe('#clearField', () => { it('should clear a given element', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click('~startUserRegistrationCD') - await app.fillField('~email of the customer', 'Nothing special') - await app.see('Nothing special', '~email of the customer') - await app.clearField('~email of the customer') - await app.dontSee('Nothing special', '~email of the customer') - }) - }) + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click('~startUserRegistrationCD'); + await app.fillField('~email of the customer', 'Nothing special'); + await app.see('Nothing special', '~email of the customer'); + await app.clearField('~email of the customer'); + await app.dontSee('Nothing special', '~email of the customer'); + }); + }); describe('#grabTextFrom, #grabValueFrom, #grabAttributeFrom @quick', () => { it('should grab text from page', async () => { - await app.resetApp() - const val = await app.grabTextFrom('//android.widget.Button[@content-desc="buttonTestCD"]') - assert.equal(val, 'EN Button') - }) + await app.resetApp(); + const val = await app.grabTextFrom('//android.widget.Button[@content-desc="buttonTestCD"]'); + assert.equal(val, 'EN Button'); + }); it('should grab attribute from element', async () => { - await app.resetApp() - const val = await app.grabAttributeFrom('//android.widget.Button[@content-desc="buttonTestCD"]', 'resourceId') - assert.equal(val, 'io.selendroid.testapp:id/buttonTest') - }) + await app.resetApp(); + const val = await app.grabAttributeFrom('//android.widget.Button[@content-desc="buttonTestCD"]', 'resourceId'); + assert.equal(val, 'io.selendroid.testapp:id/buttonTest'); + }); it('should be able to grab elements', async () => { - await app.resetApp() - await app.tap('~startUserRegistrationCD') - await app.tap('~email of the customer') - await app.appendField('//android.widget.EditText[@content-desc="email of the customer"]', '1') - await app.hideDeviceKeyboard('pressKey', 'Done') + await app.resetApp(); + await app.tap('~startUserRegistrationCD'); + await app.tap('~email of the customer'); + await app.appendField('//android.widget.EditText[@content-desc="email of the customer"]', '1'); + await app.hideDeviceKeyboard('pressKey', 'Done'); await app.swipeTo( '//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', @@ -732,66 +738,66 @@ describe('Appium', function () { 30, 100, 700, - ) - await app.click('//android.widget.Button') - await app.see('1', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]') + ); + await app.click('//android.widget.Button'); + await app.see('1', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]'); const id = await app.grabNumberOfVisibleElements( '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', 'contentDescription', - ) - assert.strictEqual(1, id) - }) - }) + ); + assert.strictEqual(1, id); + }); + }); describe('#saveScreenshot @quick', () => { beforeEach(() => { - global.output_dir = path.join(global.codecept_dir, 'output') - }) + global.output_dir = path.join(global.codecept_dir, 'output'); + }); it('should create a screenshot file in output dir', async () => { - const sec = new Date().getUTCMilliseconds() - await app.saveScreenshot(`screenshot_${sec}.png`) - assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists') - }) - }) + const sec = new Date().getUTCMilliseconds(); + await app.saveScreenshot(`screenshot_${sec}.png`); + assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists'); + }); + }); describe('#runOnIOS, #runOnAndroid, #runInWeb', () => { it('should use Android locators', async () => { - await app.resetApp() - await app.waitForElement('~startUserRegistrationCD', smallWait) - await app.click({ android: '~startUserRegistrationCD', ios: 'fake-element' }) - await app.see('Welcome to register a new User') - }) + await app.resetApp(); + await app.waitForElement('~startUserRegistrationCD', smallWait); + await app.click({ android: '~startUserRegistrationCD', ios: 'fake-element' }); + await app.see('Welcome to register a new User'); + }); it('should execute only on Android @quick', () => { - let platform = null + let platform = null; app.runOnIOS(() => { - platform = 'ios' - }) + platform = 'ios'; + }); app.runOnAndroid(() => { - platform = 'android' - }) + platform = 'android'; + }); app.runOnAndroid({ platformVersion: '7.0' }, () => { - platform = 'android7' - }) + platform = 'android7'; + }); - assert.equal('android', platform) - }) + assert.equal('android', platform); + }); it('should execute only on Android >= 5.0 @quick', () => { app.runOnAndroid( (caps) => caps.platformVersion >= 5, () => {}, - ) - }) + ); + }); it('should execute only in Web', () => { - app.isWeb = true - let executed = false + app.isWeb = true; + let executed = false; app.runOnIOS(() => { - executed = true - }) - assert.ok(!executed) - }) - }) -}) + executed = true; + }); + assert.ok(!executed); + }); + }); +}); diff --git a/test/helper/JSONResponse_test.js b/test/helper/JSONResponse_test.js index ee67a328c..0edcc75f9 100644 --- a/test/helper/JSONResponse_test.js +++ b/test/helper/JSONResponse_test.js @@ -1,10 +1,10 @@ -const chai = require('chai') +const chai = require('chai'); -const expect = chai.expect -const joi = require('joi') -const JSONResponse = require('../../lib/helper/JSONResponse') -const Container = require('../../lib/container') -global.codeceptjs = require('../../lib') +const expect = chai.expect; +const joi = require('joi'); +const JSONResponse = require('../../lib/helper/JSONResponse'); +const Container = require('../../lib/container'); +global.codeceptjs = require('../../lib'); const data = { posts: [ @@ -20,10 +20,10 @@ const data = { user: { name: 'davert', }, -} +}; -let restHelper -let I +let restHelper; +let I; describe('JSONResponse', () => { beforeEach(() => { @@ -31,129 +31,129 @@ describe('JSONResponse', () => { helpers: { REST: {}, }, - }) + }); - I = new JSONResponse() - I._beforeSuite() - restHelper = Container.helpers('REST') - }) + I = new JSONResponse(); + I._beforeSuite(); + restHelper = Container.helpers('REST'); + }); describe('response codes', () => { it('should check 200x codes', async () => { - restHelper.config.onResponse({ status: 204 }) - I.seeResponseCodeIs(204) - I.dontSeeResponseCodeIs(200) - I.seeResponseCodeIsSuccessful() - }) + restHelper.config.onResponse({ status: 204 }); + I.seeResponseCodeIs(204); + I.dontSeeResponseCodeIs(200); + I.seeResponseCodeIsSuccessful(); + }); it('should check 300x codes', async () => { - restHelper.config.onResponse({ status: 304 }) - I.seeResponseCodeIs(304) - I.dontSeeResponseCodeIs(200) - I.seeResponseCodeIsRedirection() - }) + restHelper.config.onResponse({ status: 304 }); + I.seeResponseCodeIs(304); + I.dontSeeResponseCodeIs(200); + I.seeResponseCodeIsRedirection(); + }); it('should check 400x codes', async () => { - restHelper.config.onResponse({ status: 404 }) - I.seeResponseCodeIs(404) - I.dontSeeResponseCodeIs(200) - I.seeResponseCodeIsClientError() - }) + restHelper.config.onResponse({ status: 404 }); + I.seeResponseCodeIs(404); + I.dontSeeResponseCodeIs(200); + I.seeResponseCodeIsClientError(); + }); it('should check 500x codes', async () => { - restHelper.config.onResponse({ status: 504 }) - I.seeResponseCodeIs(504) - I.dontSeeResponseCodeIs(200) - I.seeResponseCodeIsServerError() - }) + restHelper.config.onResponse({ status: 504 }); + I.seeResponseCodeIs(504); + I.dontSeeResponseCodeIs(200); + I.seeResponseCodeIsServerError(); + }); it('should throw error on invalid code', () => { - restHelper.config.onResponse({ status: 504 }) - expect(() => I.seeResponseCodeIs(200)).to.throw('Response code') - }) - }) + restHelper.config.onResponse({ status: 504 }); + expect(() => I.seeResponseCodeIs(200)).to.throw('Response code'); + }); + }); describe('response data', () => { it('should check for json inclusion', () => { - restHelper.config.onResponse({ data }) + restHelper.config.onResponse({ data }); I.seeResponseContainsJson({ posts: [{ id: 2 }], - }) + }); I.seeResponseContainsJson({ posts: [{ id: 1, author: 'davert' }], - }) + }); expect(() => I.seeResponseContainsJson({ posts: [{ id: 2, author: 'boss' }] })).to.throw( 'expected { …(2) } to deeply match { Object (posts) }', - ) - }) + ); + }); it('should check for json inclusion - returned Array', () => { - const arrayData = [{ ...data }] - restHelper.config.onResponse({ data: arrayData }) + const arrayData = [{ ...data }]; + restHelper.config.onResponse({ data: arrayData }); I.seeResponseContainsJson({ posts: [{ id: 2 }], - }) + }); I.seeResponseContainsJson({ posts: [{ id: 1, author: 'davert' }], - }) + }); expect(() => I.seeResponseContainsJson({ posts: [{ id: 2, author: 'boss' }] })).to.throw( 'No elements in array matched {"posts":[{"id":2,"author":"boss"}]}', - ) - }) + ); + }); it('should check for json inclusion - returned Array of 2 items', () => { - const arrayData = [{ ...data }, { posts: { id: 3 } }] - restHelper.config.onResponse({ data: arrayData }) + const arrayData = [{ ...data }, { posts: { id: 3 } }]; + restHelper.config.onResponse({ data: arrayData }); I.seeResponseContainsJson({ posts: { id: 3 }, - }) - }) + }); + }); it('should simply check for json inclusion', () => { - restHelper.config.onResponse({ data: { user: { name: 'jon', email: 'jon@doe.com' } } }) - I.seeResponseContainsJson({ user: { name: 'jon' } }) - I.dontSeeResponseContainsJson({ user: { name: 'jo' } }) - I.dontSeeResponseContainsJson({ name: 'joe' }) - }) + restHelper.config.onResponse({ data: { user: { name: 'jon', email: 'jon@doe.com' } } }); + I.seeResponseContainsJson({ user: { name: 'jon' } }); + I.dontSeeResponseContainsJson({ user: { name: 'jo' } }); + I.dontSeeResponseContainsJson({ name: 'joe' }); + }); it('should simply check for json inclusion - returned Array', () => { - restHelper.config.onResponse({ data: [{ user: { name: 'jon', email: 'jon@doe.com' } }] }) - I.seeResponseContainsJson({ user: { name: 'jon' } }) - I.dontSeeResponseContainsJson({ user: { name: 'jo' } }) - I.dontSeeResponseContainsJson({ name: 'joe' }) - }) + restHelper.config.onResponse({ data: [{ user: { name: 'jon', email: 'jon@doe.com' } }] }); + I.seeResponseContainsJson({ user: { name: 'jon' } }); + I.dontSeeResponseContainsJson({ user: { name: 'jo' } }); + I.dontSeeResponseContainsJson({ name: 'joe' }); + }); it('should simply check for json equality', () => { - restHelper.config.onResponse({ data: { user: 1 } }) - I.seeResponseEquals({ user: 1 }) - }) + restHelper.config.onResponse({ data: { user: 1 } }); + I.seeResponseEquals({ user: 1 }); + }); it('should simply check for json equality - returned Array', () => { - restHelper.config.onResponse({ data: [{ user: 1 }] }) - I.seeResponseEquals([{ user: 1 }]) - }) + restHelper.config.onResponse({ data: [{ user: 1 }] }); + I.seeResponseEquals([{ user: 1 }]); + }); it('should check json contains keys', () => { - restHelper.config.onResponse({ data: { user: 1, post: 2 } }) - I.seeResponseContainsKeys(['user', 'post']) - }) + restHelper.config.onResponse({ data: { user: 1, post: 2 } }); + I.seeResponseContainsKeys(['user', 'post']); + }); it('should check json contains keys - returned Array', () => { - restHelper.config.onResponse({ data: [{ user: 1, post: 2 }] }) - I.seeResponseContainsKeys(['user', 'post']) - }) + restHelper.config.onResponse({ data: [{ user: 1, post: 2 }] }); + I.seeResponseContainsKeys(['user', 'post']); + }); it('should check for json by callback', () => { - restHelper.config.onResponse({ data }) + restHelper.config.onResponse({ data }); const fn = ({ expect, data }) => { - expect(data).to.have.keys(['posts', 'user']) - } - I.seeResponseValidByCallback(fn) - expect(fn.toString()).to.include('expect(data).to.have') - }) + expect(data).to.have.keys(['posts', 'user']); + }; + I.seeResponseValidByCallback(fn); + expect(fn.toString()).to.include('expect(data).to.have'); + }); it('should check for json by joi schema', () => { - restHelper.config.onResponse({ data }) + restHelper.config.onResponse({ data }); const schema = joi.object({ posts: joi.array().items({ id: joi.number(), @@ -163,12 +163,12 @@ describe('JSONResponse', () => { user: joi.object({ name: joi.string(), }), - }) + }); const fn = () => { - return schema - } - I.seeResponseMatchesJsonSchema(fn) - I.seeResponseMatchesJsonSchema(schema) - }) - }) -}) + return schema; + }; + I.seeResponseMatchesJsonSchema(fn); + I.seeResponseMatchesJsonSchema(schema); + }); + }); +}); diff --git a/test/helper/Playwright_test.js b/test/helper/Playwright_test.js index 6314f1b7f..ecc332fe1 100644 --- a/test/helper/Playwright_test.js +++ b/test/helper/Playwright_test.js @@ -1,37 +1,37 @@ -const chai = require('chai') +const chai = require('chai'); -const assert = chai.assert -const expect = chai.expect +const assert = chai.assert; +const expect = chai.expect; -const path = require('path') -const fs = require('fs') +const path = require('path'); +const fs = require('fs'); -const playwright = require('playwright') +const playwright = require('playwright'); -const TestHelper = require('../support/TestHelper') -const Playwright = require('../../lib/helper/Playwright') +const TestHelper = require('../support/TestHelper'); +const Playwright = require('../../lib/helper/Playwright'); -const AssertionFailedError = require('../../lib/assert/error') -const webApiTests = require('./webapi') -const FileSystem = require('../../lib/helper/FileSystem') -const { deleteDir } = require('../../lib/utils') -const Secret = require('../../lib/secret') -global.codeceptjs = require('../../lib') +const AssertionFailedError = require('../../lib/assert/error'); +const webApiTests = require('./webapi'); +const FileSystem = require('../../lib/helper/FileSystem'); +const { deleteDir } = require('../../lib/utils'); +const Secret = require('../../lib/secret'); +global.codeceptjs = require('../../lib'); -const dataFile = path.join(__dirname, '/../data/app/db') -const formContents = require('../../lib/utils').test.submittedData(dataFile) +const dataFile = path.join(__dirname, '/../data/app/db'); +const formContents = require('../../lib/utils').test.submittedData(dataFile); -let I -let page -let FS -const siteUrl = TestHelper.siteUrl() +let I; +let page; +let FS; +const siteUrl = TestHelper.siteUrl(); describe('Playwright', function () { - this.timeout(35000) - this.retries(1) + this.timeout(35000); + this.retries(1); before(() => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); I = new Playwright({ url: siteUrl, @@ -46,175 +46,175 @@ describe('Playwright', function () { args: ['--no-sandbox', '--disable-setuid-sandbox'], }, defaultPopupAction: 'accept', - }) - I._init() - return I._beforeSuite() - }) + }); + I._init(); + return I._beforeSuite(); + }); beforeEach(async () => { webApiTests.init({ I, siteUrl, - }) + }); return I._before().then(() => { - page = I.page - browser = I.browser - }) - }) + page = I.page; + browser = I.browser; + }); + }); afterEach(async () => { - return I._after() - }) + return I._after(); + }); describe('restart browser: #restartBrowser', () => { it('should open a new tab after restart of browser', async () => { - await I.restartBrowser() - await I.wait(1) - const numPages = await I.grabNumberOfOpenTabs() - assert.equal(numPages, 1) - }) - }) + await I.restartBrowser(); + await I.wait(1); + const numPages = await I.grabNumberOfOpenTabs(); + assert.equal(numPages, 1); + }); + }); describe('open page : #amOnPage', () => { it('should open main page of configured site', async () => { - await I.amOnPage('/') - const url = await page.url() - await url.should.eql(`${siteUrl}/`) - }) + await I.amOnPage('/'); + const url = await page.url(); + await url.should.eql(`${siteUrl}/`); + }); it('should open any page of configured site', async () => { - await I.amOnPage('/info') - const url = await page.url() - return url.should.eql(`${siteUrl}/info`) - }) + await I.amOnPage('/info'); + const url = await page.url(); + return url.should.eql(`${siteUrl}/info`); + }); it('should open absolute url', async () => { - await I.amOnPage(siteUrl) - const url = await page.url() - return url.should.eql(`${siteUrl}/`) - }) + await I.amOnPage(siteUrl); + const url = await page.url(); + return url.should.eql(`${siteUrl}/`); + }); it('should open any page of configured site without leading slash', async () => { - await I.amOnPage('info') - const url = await page.url() - return url.should.eql(`${siteUrl}/info`) - }) + await I.amOnPage('info'); + const url = await page.url(); + return url.should.eql(`${siteUrl}/info`); + }); it('should open blank page', async () => { - await I.amOnPage('about:blank') - const url = await page.url() - return url.should.eql('about:blank') - }) - }) + await I.amOnPage('about:blank'); + const url = await page.url(); + return url.should.eql('about:blank'); + }); + }); describe('grabDataFromPerformanceTiming', () => { it('should return data from performance timing', async () => { - await I.amOnPage('/') - const res = await I.grabDataFromPerformanceTiming() - expect(res).to.have.property('responseEnd') - expect(res).to.have.property('domInteractive') - expect(res).to.have.property('domContentLoadedEventEnd') - expect(res).to.have.property('loadEventEnd') - }) - }) + await I.amOnPage('/'); + const res = await I.grabDataFromPerformanceTiming(); + expect(res).to.have.property('responseEnd'); + expect(res).to.have.property('domInteractive'); + expect(res).to.have.property('domContentLoadedEventEnd'); + expect(res).to.have.property('loadEventEnd'); + }); + }); describe('#seeCssPropertiesOnElements', () => { it('should check background-color css property for given element', async () => { try { - await I.amOnPage('https://codecept.io/helpers/Playwright/') - await I.seeCssPropertiesOnElements('.navbar', { 'background-color': 'rgb(128, 90, 213)' }) + await I.amOnPage('https://codecept.io/helpers/Playwright/'); + await I.seeCssPropertiesOnElements('.navbar', { 'background-color': 'rgb(128, 90, 213)' }); } catch (e) { e.message.should.include( "expected element (.navbar) to have CSS property { 'background-color': 'rgb(128, 90, 213)' }", - ) + ); } - }) - }) + }); + }); - webApiTests.tests() + webApiTests.tests(); describe('#click', () => { it('should not try to click on invisible elements', async () => { - await I.amOnPage('/invisible_elements') - await I.click('Hello World') - }) - }) + await I.amOnPage('/invisible_elements'); + await I.click('Hello World'); + }); + }); describe('#grabCheckedElementStatus', () => { it('check grabCheckedElementStatus', async () => { - await I.amOnPage('/invisible_elements') - let result = await I.grabCheckedElementStatus({ id: 'html' }) - assert.equal(result, true) - result = await I.grabCheckedElementStatus({ id: 'css' }) - assert.equal(result, false) - result = await I.grabCheckedElementStatus({ id: 'js' }) - assert.equal(result, true) - result = await I.grabCheckedElementStatus({ id: 'ts' }) - assert.equal(result, false) + await I.amOnPage('/invisible_elements'); + let result = await I.grabCheckedElementStatus({ id: 'html' }); + assert.equal(result, true); + result = await I.grabCheckedElementStatus({ id: 'css' }); + assert.equal(result, false); + result = await I.grabCheckedElementStatus({ id: 'js' }); + assert.equal(result, true); + result = await I.grabCheckedElementStatus({ id: 'ts' }); + assert.equal(result, false); try { - await I.grabCheckedElementStatus({ id: 'basic' }) + await I.grabCheckedElementStatus({ id: 'basic' }); } catch (e) { - assert.equal(e.message, 'Element is not a checkbox or radio input') + assert.equal(e.message, 'Element is not a checkbox or radio input'); } - }) - }) + }); + }); describe('#grabDisabledElementStatus', () => { it('check isElementDisabled', async () => { - await I.amOnPage('/invisible_elements') - let result = await I.grabDisabledElementStatus({ id: 'fortran' }) - assert.equal(result, true) - result = await I.grabDisabledElementStatus({ id: 'basic' }) - assert.equal(result, false) - }) - }) + await I.amOnPage('/invisible_elements'); + let result = await I.grabDisabledElementStatus({ id: 'fortran' }); + assert.equal(result, true); + result = await I.grabDisabledElementStatus({ id: 'basic' }); + assert.equal(result, false); + }); + }); describe('#waitForFunction', () => { it('should wait for function returns true', () => { - return I.amOnPage('/form/wait_js').then(() => I.waitForFunction(() => window.__waitJs, 3)) - }) + return I.amOnPage('/form/wait_js').then(() => I.waitForFunction(() => window.__waitJs, 3)); + }); it('should pass arguments and wait for function returns true', () => { - return I.amOnPage('/form/wait_js').then(() => I.waitForFunction((varName) => window[varName], ['__waitJs'], 3)) - }) - }) + return I.amOnPage('/form/wait_js').then(() => I.waitForFunction((varName) => window[varName], ['__waitJs'], 3)); + }); + }); describe('#waitForVisible #waitForInvisible - within block', () => { it('should wait for visible element', async () => { - await I.amOnPage('/iframe') + await I.amOnPage('/iframe'); await I._withinBegin({ frame: '#number-frame-1234', - }) + }); - await I.waitForVisible('h1') - }) + await I.waitForVisible('h1'); + }); it('should wait for invisible element', async () => { - await I.amOnPage('/iframe') + await I.amOnPage('/iframe'); await I._withinBegin({ frame: '#number-frame-1234', - }) + }); - await I.waitForInvisible('h9') - }) + await I.waitForInvisible('h9'); + }); it('should wait for element to hide', async () => { - await I.amOnPage('/iframe') + await I.amOnPage('/iframe'); await I._withinBegin({ frame: '#number-frame-1234', - }) + }); - await I.waitToHide('h9') - }) + await I.waitToHide('h9'); + }); it('should wait for invisible combined with dontseeElement', async () => { - await I.amOnPage('https://codecept.io/') - await I.waitForVisible('.frameworks') - await I.waitForVisible('[alt="React"]') - await I.waitForVisible('.mountains') + await I.amOnPage('https://codecept.io/'); + await I.waitForVisible('.frameworks'); + await I.waitForVisible('[alt="React"]'); + await I.waitForVisible('.mountains'); await I._withinBegin('.mountains', async () => { - await I.dontSeeElement('[alt="React"]') - await I.waitForInvisible('[alt="React"]', 2) - }) - }) - }) + await I.dontSeeElement('[alt="React"]'); + await I.waitForInvisible('[alt="React"]', 2); + }); + }); + }); describe('#waitToHide', () => { it('should wait for hidden element', () => { @@ -222,17 +222,17 @@ describe('Playwright', function () { .then(() => I.see('Step One Button')) .then(() => I.waitToHide('#step_1', 2)) .then(() => I.dontSeeElement('#step_1')) - .then(() => I.dontSee('Step One Button')) - }) + .then(() => I.dontSee('Step One Button')); + }); it('should wait for hidden element by XPath', () => { return I.amOnPage('/form/wait_invisible') .then(() => I.see('Step One Button')) .then(() => I.waitToHide('//div[@id="step_1"]', 2)) .then(() => I.dontSeeElement('//div[@id="step_1"]')) - .then(() => I.dontSee('Step One Button')) - }) - }) + .then(() => I.dontSee('Step One Button')); + }); + }); describe('#waitNumberOfVisibleElements', () => { it('should wait for a specified number of elements on the page', () => @@ -240,53 +240,53 @@ describe('Playwright', function () { .then(() => I.waitNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 3)) .then(() => I.waitNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 2, 0.1)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.include('The number of elements (//div[@id = "grab-multiple"]//a) is not 2 after 0.1 sec') - })) + e.message.should.include('The number of elements (//div[@id = "grab-multiple"]//a) is not 2 after 0.1 sec'); + })); it('should wait for a specified number of elements on the page using a css selector', () => I.amOnPage('/info') .then(() => I.waitNumberOfVisibleElements('#grab-multiple > a', 3)) .then(() => I.waitNumberOfVisibleElements('#grab-multiple > a', 2, 0.1)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec') - })) + e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec'); + })); it('should wait for a specified number of elements which are not yet attached to the DOM', () => I.amOnPage('/form/wait_num_elements') .then(() => I.waitNumberOfVisibleElements('.title', 2, 3)) .then(() => I.see('Hello')) - .then(() => I.see('World'))) + .then(() => I.see('World'))); it('should wait for 0 number of visible elements', async () => { - await I.amOnPage('/form/wait_invisible') - await I.waitNumberOfVisibleElements('#step_1', 0) - }) - }) + await I.amOnPage('/form/wait_invisible'); + await I.waitNumberOfVisibleElements('#step_1', 0); + }); + }); describe('#moveCursorTo', () => { it('should trigger hover event', () => I.amOnPage('/form/hover') .then(() => I.moveCursorTo('#hover')) - .then(() => I.see('Hovered', '#show'))) + .then(() => I.see('Hovered', '#show'))); it('should not trigger hover event because of the offset is beyond the element', () => I.amOnPage('/form/hover') .then(() => I.moveCursorTo('#hover', 100, 100)) - .then(() => I.dontSee('Hovered', '#show'))) - }) + .then(() => I.dontSee('Hovered', '#show'))); + }); describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs, #grabNumberOfOpenTabs, #waitForNumberOfTabs', () => { it('should only have 1 tab open when the browser starts and navigates to the first page', () => I.amOnPage('/') .then(() => I.wait(1)) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 1))) + .then((numPages) => assert.equal(numPages, 1))); it('should switch to next tab', () => I.amOnPage('/info') @@ -298,7 +298,7 @@ describe('Playwright', function () { .then(() => I.wait(2)) .then(() => I.seeCurrentUrlEquals('/login')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 2))) + .then((numPages) => assert.equal(numPages, 2))); it('should assert when there is no ability to switch to next tab', () => I.amOnPage('/') @@ -308,8 +308,8 @@ describe('Playwright', function () { .then(() => I.wait(2)) .then(() => assert.equal(true, false, 'Throw an error if it gets this far (which it should not)!')) .catch((e) => { - assert.equal(e.message, 'There is no ability to switch to next tab with offset 2') - })) + assert.equal(e.message, 'There is no ability to switch to next tab with offset 2'); + })); it('should close current tab', () => I.amOnPage('/info') @@ -323,7 +323,7 @@ describe('Playwright', function () { .then(() => I.wait(1)) .then(() => I.seeInCurrentUrl('/info')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 1))) + .then((numPages) => assert.equal(numPages, 1))); it('should close other tabs', () => I.amOnPage('/') @@ -337,7 +337,7 @@ describe('Playwright', function () { .then(() => I.waitForNumberOfTabs(1)) .then(() => I.seeInCurrentUrl('/login')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 1))) + .then((numPages) => assert.equal(numPages, 1))); it('should open new tab', () => I.amOnPage('/info') @@ -345,7 +345,7 @@ describe('Playwright', function () { .then(() => I.wait(1)) .then(() => I.seeInCurrentUrl('about:blank')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 2))) + .then((numPages) => assert.equal(numPages, 2))); it('should switch to previous tab', () => I.amOnPage('/info') @@ -354,7 +354,7 @@ describe('Playwright', function () { .then(() => I.seeInCurrentUrl('about:blank')) .then(() => I.switchToPreviousTab()) .then(() => I.wait(2)) - .then(() => I.seeInCurrentUrl('/info'))) + .then(() => I.seeInCurrentUrl('/info'))); it('should assert when there is no ability to switch to previous tab', () => I.amOnPage('/info') @@ -365,9 +365,9 @@ describe('Playwright', function () { .then(() => I.wait(2)) .then(() => I.waitInUrl('/info')) .catch((e) => { - assert.equal(e.message, 'There is no ability to switch to previous tab with offset 2') - })) - }) + assert.equal(e.message, 'There is no ability to switch to previous tab with offset 2'); + })); + }); describe('popup : #acceptPopup, #seeInPopup, #cancelPopup, #grabPopupText', () => { it('should accept popup window', () => @@ -375,105 +375,105 @@ describe('Playwright', function () { .then(() => I.amAcceptingPopups()) .then(() => I.click('Confirm')) .then(() => I.acceptPopup()) - .then(() => I.see('Yes', '#result'))) + .then(() => I.see('Yes', '#result'))); it('should accept popup window (using default popup action type)', () => I.amOnPage('/form/popup') .then(() => I.click('Confirm')) .then(() => I.acceptPopup()) - .then(() => I.see('Yes', '#result'))) + .then(() => I.see('Yes', '#result'))); it('should cancel popup', () => I.amOnPage('/form/popup') .then(() => I.amCancellingPopups()) .then(() => I.click('Confirm')) .then(() => I.cancelPopup()) - .then(() => I.see('No', '#result'))) + .then(() => I.see('No', '#result'))); it('should check text in popup', () => I.amOnPage('/form/popup') .then(() => I.amCancellingPopups()) .then(() => I.click('Alert')) .then(() => I.seeInPopup('Really?')) - .then(() => I.cancelPopup())) + .then(() => I.cancelPopup())); it('should grab text from popup', () => I.amOnPage('/form/popup') .then(() => I.amCancellingPopups()) .then(() => I.click('Alert')) .then(() => I.grabPopupText()) - .then((text) => assert.equal(text, 'Really?'))) + .then((text) => assert.equal(text, 'Really?'))); it('should return null if no popup is visible (do not throw an error)', () => I.amOnPage('/form/popup') .then(() => I.grabPopupText()) - .then((text) => assert.equal(text, null))) - }) + .then((text) => assert.equal(text, null))); + }); describe('#seeNumberOfElements', () => { - it('should return 1 as count', () => I.amOnPage('/').then(() => I.seeNumberOfElements('#area1', 1))) - }) + it('should return 1 as count', () => I.amOnPage('/').then(() => I.seeNumberOfElements('#area1', 1))); + }); describe('#switchTo', () => { it('should switch reference to iframe content', () => { - I.amOnPage('/iframe') - I.switchTo('[name="content"]') - I.see('Information') - I.see('Lots of valuable data here') - }) + I.amOnPage('/iframe'); + I.switchTo('[name="content"]'); + I.see('Information'); + I.see('Lots of valuable data here'); + }); it('should return error if iframe selector is invalid', () => I.amOnPage('/iframe') .then(() => I.switchTo('#invalidIframeSelector')) .catch((e) => { - e.should.be.instanceOf(Error) - e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath') - })) + e.should.be.instanceOf(Error); + e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath'); + })); it('should return error if iframe selector is not iframe', () => I.amOnPage('/iframe') .then(() => I.switchTo('h1')) .catch((e) => { - e.should.be.instanceOf(Error) - e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath') - })) + e.should.be.instanceOf(Error); + e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath'); + })); it('should return to parent frame given a null locator', async () => { - I.amOnPage('/iframe') - I.switchTo('[name="content"]') - I.see('Information') - I.see('Lots of valuable data here') - I.switchTo(null) - I.see('Iframe test') - }) + I.amOnPage('/iframe'); + I.switchTo('[name="content"]'); + I.see('Information'); + I.see('Lots of valuable data here'); + I.switchTo(null); + I.see('Iframe test'); + }); it('should switch to iframe using css', () => { - I.amOnPage('/iframe') - I.switchTo('iframe#number-frame-1234') - I.see('Information') - I.see('Lots of valuable data here') - }) + I.amOnPage('/iframe'); + I.switchTo('iframe#number-frame-1234'); + I.see('Information'); + I.see('Lots of valuable data here'); + }); it('should switch to iframe using css when there are more than one iframes', () => { - I.amOnPage('/iframes') - I.switchTo('iframe#number-frame-1234') - I.see('Information') - }) - }) + I.amOnPage('/iframes'); + I.switchTo('iframe#number-frame-1234'); + I.see('Information'); + }); + }); describe('#seeInSource, #grabSource', () => { it('should check for text to be in HTML source', () => I.amOnPage('/') .then(() => I.seeInSource('TestEd Beta 2.0')) - .then(() => I.dontSeeInSource(' I.dontSeeInSource(' I.amOnPage('/') .then(() => I.grabSource()) .then((source) => assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved'), - )) - }) + )); + }); describe('#seeTitleEquals', () => { it('should check that title is equal to provided one', () => @@ -482,10 +482,10 @@ describe('Playwright', function () { .then(() => I.seeTitleEquals('TestEd Beta 2.')) .then(() => assert.equal(true, false, 'Throw an error because it should not get this far!')) .catch((e) => { - e.should.be.instanceOf(Error) - e.message.should.be.equal('expected web page title "TestEd Beta 2.0" to equal "TestEd Beta 2."') - })) - }) + e.should.be.instanceOf(Error); + e.message.should.be.equal('expected web page title "TestEd Beta 2.0" to equal "TestEd Beta 2."'); + })); + }); describe('#seeTextEquals', () => { it('should check text is equal to provided one', () => @@ -494,262 +494,262 @@ describe('Playwright', function () { .then(() => I.seeTextEquals('Welcome to test app', 'h1')) .then(() => assert.equal(true, false, 'Throw an error because it should not get this far!')) .catch((e) => { - e.should.be.instanceOf(Error) - e.message.should.be.equal('expected element h1 "Welcome to test app" to equal "Welcome to test app!"') - })) - }) + e.should.be.instanceOf(Error); + e.message.should.be.equal('expected element h1 "Welcome to test app" to equal "Welcome to test app!"'); + })); + }); describe('#selectOption', () => { it('should select option by label and partial option text', async () => { - await I.amOnPage('/form/select') - await I.selectOption('Select your age', '21-') - await I.click('Submit') - assert.equal(formContents('age'), 'adult') - }) - }) + await I.amOnPage('/form/select'); + await I.selectOption('Select your age', '21-'); + await I.click('Submit'); + assert.equal(formContents('age'), 'adult'); + }); + }); describe('#_locateClickable', () => { it('should locate a button to click', () => I.amOnPage('/form/checkbox') .then(() => I._locateClickable('Submit')) .then((res) => { - res.length.should.be.equal(1) - })) + res.length.should.be.equal(1); + })); it('should not locate a non-existing checkbox using _locateClickable', () => I.amOnPage('/form/checkbox') .then(() => I._locateClickable('I disagree')) - .then((res) => res.length.should.be.equal(0))) - }) + .then((res) => res.length.should.be.equal(0))); + }); describe('#_locateCheckable', () => { it('should locate a checkbox', () => I.amOnPage('/form/checkbox') .then(() => I._locateCheckable('I Agree')) - .then((res) => res.should.be.not.undefined)) - }) + .then((res) => res.should.be.not.undefined)); + }); describe('#_locateFields', () => { it('should locate a field', () => I.amOnPage('/form/field') .then(() => I._locateFields('Name')) - .then((res) => res.length.should.be.equal(1))) + .then((res) => res.length.should.be.equal(1))); it('should not locate a non-existing field', () => I.amOnPage('/form/field') .then(() => I._locateFields('Mother-in-law')) - .then((res) => res.length.should.be.equal(0))) - }) + .then((res) => res.length.should.be.equal(0))); + }); describe('check fields: #seeInField, #seeCheckboxIsChecked, ...', () => { it('should throw error if field is not empty', () => I.amOnPage('/form/empty') .then(() => I.seeInField('#empty_input', 'Ayayay')) .catch((e) => { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.be.equal('expected fields by #empty_input to include "Ayayay"') - })) + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.be.equal('expected fields by #empty_input to include "Ayayay"'); + })); it('should check values in checkboxes', async () => { - await I.amOnPage('/form/field_values') - await I.dontSeeInField('checkbox[]', 'not seen one') - await I.seeInField('checkbox[]', 'see test one') - await I.dontSeeInField('checkbox[]', 'not seen two') - await I.seeInField('checkbox[]', 'see test two') - await I.dontSeeInField('checkbox[]', 'not seen three') - await I.seeInField('checkbox[]', 'see test three') - }) + await I.amOnPage('/form/field_values'); + await I.dontSeeInField('checkbox[]', 'not seen one'); + await I.seeInField('checkbox[]', 'see test one'); + await I.dontSeeInField('checkbox[]', 'not seen two'); + await I.seeInField('checkbox[]', 'see test two'); + await I.dontSeeInField('checkbox[]', 'not seen three'); + await I.seeInField('checkbox[]', 'see test three'); + }); it('should check values are the secret type in checkboxes', async () => { - await I.amOnPage('/form/field_values') - await I.dontSeeInField('checkbox[]', Secret.secret('not seen one')) - await I.seeInField('checkbox[]', Secret.secret('see test one')) - await I.dontSeeInField('checkbox[]', Secret.secret('not seen two')) - await I.seeInField('checkbox[]', Secret.secret('see test two')) - await I.dontSeeInField('checkbox[]', Secret.secret('not seen three')) - await I.seeInField('checkbox[]', Secret.secret('see test three')) - }) + await I.amOnPage('/form/field_values'); + await I.dontSeeInField('checkbox[]', Secret.secret('not seen one')); + await I.seeInField('checkbox[]', Secret.secret('see test one')); + await I.dontSeeInField('checkbox[]', Secret.secret('not seen two')); + await I.seeInField('checkbox[]', Secret.secret('see test two')); + await I.dontSeeInField('checkbox[]', Secret.secret('not seen three')); + await I.seeInField('checkbox[]', Secret.secret('see test three')); + }); it('should check values with boolean', async () => { - await I.amOnPage('/form/field_values') - await I.seeInField('checkbox1', true) - await I.dontSeeInField('checkbox1', false) - await I.seeInField('checkbox2', false) - await I.dontSeeInField('checkbox2', true) - await I.seeInField('radio2', true) - await I.dontSeeInField('radio2', false) - await I.seeInField('radio3', false) - await I.dontSeeInField('radio3', true) - }) + await I.amOnPage('/form/field_values'); + await I.seeInField('checkbox1', true); + await I.dontSeeInField('checkbox1', false); + await I.seeInField('checkbox2', false); + await I.dontSeeInField('checkbox2', true); + await I.seeInField('radio2', true); + await I.dontSeeInField('radio2', false); + await I.seeInField('radio3', false); + await I.dontSeeInField('radio3', true); + }); it('should check values in radio', async () => { - await I.amOnPage('/form/field_values') - await I.seeInField('radio1', 'see test one') - await I.dontSeeInField('radio1', 'not seen one') - await I.dontSeeInField('radio1', 'not seen two') - await I.dontSeeInField('radio1', 'not seen three') - }) + await I.amOnPage('/form/field_values'); + await I.seeInField('radio1', 'see test one'); + await I.dontSeeInField('radio1', 'not seen one'); + await I.dontSeeInField('radio1', 'not seen two'); + await I.dontSeeInField('radio1', 'not seen three'); + }); it('should check values in select', async () => { - await I.amOnPage('/form/field_values') - await I.seeInField('select1', 'see test one') - await I.dontSeeInField('select1', 'not seen one') - await I.dontSeeInField('select1', 'not seen two') - await I.dontSeeInField('select1', 'not seen three') - }) + await I.amOnPage('/form/field_values'); + await I.seeInField('select1', 'see test one'); + await I.dontSeeInField('select1', 'not seen one'); + await I.dontSeeInField('select1', 'not seen two'); + await I.dontSeeInField('select1', 'not seen three'); + }); it('should check for empty select field', async () => { - await I.amOnPage('/form/field_values') - await I.seeInField('select3', '') - }) + await I.amOnPage('/form/field_values'); + await I.seeInField('select3', ''); + }); it('should check for select multiple field', async () => { - await I.amOnPage('/form/field_values') - await I.dontSeeInField('select2', 'not seen one') - await I.seeInField('select2', 'see test one') - await I.dontSeeInField('select2', 'not seen two') - await I.seeInField('select2', 'see test two') - await I.dontSeeInField('select2', 'not seen three') - await I.seeInField('select2', 'see test three') - }) - }) + await I.amOnPage('/form/field_values'); + await I.dontSeeInField('select2', 'not seen one'); + await I.seeInField('select2', 'see test one'); + await I.dontSeeInField('select2', 'not seen two'); + await I.seeInField('select2', 'see test two'); + await I.dontSeeInField('select2', 'not seen three'); + await I.seeInField('select2', 'see test three'); + }); + }); describe('#clearField', () => { it('should clear input', async () => { - await I.amOnPage('/form/field') - await I.fillField('Name', 'value that is cleared using I.clearField()') - await I.clearField('Name') - await I.dontSeeInField('Name', 'value that is cleared using I.clearField()') - }) + await I.amOnPage('/form/field'); + await I.fillField('Name', 'value that is cleared using I.clearField()'); + await I.clearField('Name'); + await I.dontSeeInField('Name', 'value that is cleared using I.clearField()'); + }); it('should clear div textarea', async () => { - await I.amOnPage('/form/field') - await I.clearField('#textarea') - await I.dontSeeInField('#textarea', 'I look like textarea') - }) + await I.amOnPage('/form/field'); + await I.clearField('#textarea'); + await I.dontSeeInField('#textarea', 'I look like textarea'); + }); it('should clear textarea', async () => { - await I.amOnPage('/form/textarea') - await I.fillField('#description', 'value that is cleared using I.clearField()') - await I.clearField('#description') - await I.dontSeeInField('#description', 'value that is cleared using I.clearField()') - }) + await I.amOnPage('/form/textarea'); + await I.fillField('#description', 'value that is cleared using I.clearField()'); + await I.clearField('#description'); + await I.dontSeeInField('#description', 'value that is cleared using I.clearField()'); + }); xit('should clear contenteditable', async () => { const isClearMethodPresent = await I.usePlaywrightTo( 'check if new Playwright .clear() method present', async ({ page }) => { - return typeof page.locator().clear === 'function' + return typeof page.locator().clear === 'function'; }, - ) + ); if (!isClearMethodPresent) { - this.skip() + this.skip(); } - await I.amOnPage('/form/contenteditable') - await I.clearField('#contenteditableDiv') - await I.dontSee('This is editable. Click here to edit this text.', '#contenteditableDiv') - }) - }) + await I.amOnPage('/form/contenteditable'); + await I.clearField('#contenteditableDiv'); + await I.dontSee('This is editable. Click here to edit this text.', '#contenteditableDiv'); + }); + }); describe('#pressKey, #pressKeyDown, #pressKeyUp', () => { it('should be able to send special keys to element', async () => { - await I.amOnPage('/form/field') - await I.appendField('Name', '-') + await I.amOnPage('/form/field'); + await I.appendField('Name', '-'); - await I.pressKey(['Right Shift', 'Home']) - await I.pressKey('Delete') + await I.pressKey(['Right Shift', 'Home']); + await I.pressKey('Delete'); // Sequence only executes up to first non-modifier key ('Digit1') - await I.pressKey(['SHIFT_RIGHT', 'Digit1', 'Digit4']) - await I.pressKey('1') - await I.pressKey('2') - await I.pressKey('3') - await I.pressKey('ArrowLeft') - await I.pressKey('Left Arrow') - await I.pressKey('arrow_left') - await I.pressKeyDown('Shift') - await I.pressKey('a') - await I.pressKey('KeyB') - await I.pressKeyUp('ShiftLeft') - await I.pressKey('C') - await I.seeInField('Name', '!ABC123') - }) + await I.pressKey(['SHIFT_RIGHT', 'Digit1', 'Digit4']); + await I.pressKey('1'); + await I.pressKey('2'); + await I.pressKey('3'); + await I.pressKey('ArrowLeft'); + await I.pressKey('Left Arrow'); + await I.pressKey('arrow_left'); + await I.pressKeyDown('Shift'); + await I.pressKey('a'); + await I.pressKey('KeyB'); + await I.pressKeyUp('ShiftLeft'); + await I.pressKey('C'); + await I.seeInField('Name', '!ABC123'); + }); it('should use modifier key based on operating system', async () => { - await I.amOnPage('/form/field') - await I.fillField('Name', 'value that is cleared using select all shortcut') + await I.amOnPage('/form/field'); + await I.fillField('Name', 'value that is cleared using select all shortcut'); - await I.pressKey(['ControlOrCommand', 'a']) - await I.pressKey('Backspace') - await I.dontSeeInField('Name', 'value that is cleared using select all shortcut') - }) + await I.pressKey(['ControlOrCommand', 'a']); + await I.pressKey('Backspace'); + await I.dontSeeInField('Name', 'value that is cleared using select all shortcut'); + }); it('should show correct numpad or punctuation key when Shift modifier is active', async () => { - await I.amOnPage('/form/field') - await I.fillField('Name', '') - - await I.pressKey(';') - await I.pressKey(['Shift', ';']) - await I.pressKey(['Shift', 'Semicolon']) - await I.pressKey('=') - await I.pressKey(['Shift', '=']) - await I.pressKey(['Shift', 'Equal']) - await I.pressKey('*') - await I.pressKey(['Shift', '*']) - await I.pressKey(['Shift', 'Multiply']) - await I.pressKey('+') - await I.pressKey(['Shift', '+']) - await I.pressKey(['Shift', 'Add']) - await I.pressKey(',') - await I.pressKey(['Shift', ',']) - await I.pressKey(['Shift', 'Comma']) - await I.pressKey(['Shift', 'NumpadComma']) - await I.pressKey(['Shift', 'Separator']) - await I.pressKey('-') - await I.pressKey(['Shift', '-']) - await I.pressKey(['Shift', 'Subtract']) - await I.pressKey('.') - await I.pressKey(['Shift', '.']) - await I.pressKey('/') - await I.pressKey(['Shift', '/']) - await I.pressKey(['Shift', 'Divide']) - await I.pressKey(['Shift', 'Slash']) - - await I.seeInField('Name', ';::=++***+++,<<<<-_-.>/?/?') - }) - }) + await I.amOnPage('/form/field'); + await I.fillField('Name', ''); + + await I.pressKey(';'); + await I.pressKey(['Shift', ';']); + await I.pressKey(['Shift', 'Semicolon']); + await I.pressKey('='); + await I.pressKey(['Shift', '=']); + await I.pressKey(['Shift', 'Equal']); + await I.pressKey('*'); + await I.pressKey(['Shift', '*']); + await I.pressKey(['Shift', 'Multiply']); + await I.pressKey('+'); + await I.pressKey(['Shift', '+']); + await I.pressKey(['Shift', 'Add']); + await I.pressKey(','); + await I.pressKey(['Shift', ',']); + await I.pressKey(['Shift', 'Comma']); + await I.pressKey(['Shift', 'NumpadComma']); + await I.pressKey(['Shift', 'Separator']); + await I.pressKey('-'); + await I.pressKey(['Shift', '-']); + await I.pressKey(['Shift', 'Subtract']); + await I.pressKey('.'); + await I.pressKey(['Shift', '.']); + await I.pressKey('/'); + await I.pressKey(['Shift', '/']); + await I.pressKey(['Shift', 'Divide']); + await I.pressKey(['Shift', 'Slash']); + + await I.seeInField('Name', ';::=++***+++,<<<<-_-.>/?/?'); + }); + }); describe('#waitForEnabled', () => { it('should wait for input text field to be enabled', () => I.amOnPage('/form/wait_enabled') .then(() => I.waitForEnabled('#text', 2)) .then(() => I.fillField('#text', 'hello world')) - .then(() => I.seeInField('#text', 'hello world'))) + .then(() => I.seeInField('#text', 'hello world'))); it('should wait for input text field to be enabled by xpath', () => I.amOnPage('/form/wait_enabled') .then(() => I.waitForEnabled("//*[@name = 'test']", 2)) .then(() => I.fillField('#text', 'hello world')) - .then(() => I.seeInField('#text', 'hello world'))) + .then(() => I.seeInField('#text', 'hello world'))); it('should wait for a button to be enabled', () => I.amOnPage('/form/wait_enabled') .then(() => I.waitForEnabled('#text', 2)) .then(() => I.click('#button')) - .then(() => I.see('button was clicked', '#message'))) - }) + .then(() => I.see('button was clicked', '#message'))); + }); describe('#waitForDisabled', () => { it('should wait for input text field to be disabled', () => - I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled('#text', 1))) + I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled('#text', 1))); it('should wait for input text field to be enabled by xpath', () => - I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled("//*[@name = 'test']", 1))) + I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled("//*[@name = 'test']", 1))); it('should wait for a button to be disabled', () => - I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled('#text', 1))) - }) + I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled('#text', 1))); + }); describe('#waitForValue', () => { it('should wait for expected value for given locator', () => @@ -757,108 +757,108 @@ describe('Playwright', function () { .then(() => I.waitForValue('//input[@name= "rus"]', 'Верно')) .then(() => I.waitForValue('//input[@name= "rus"]', 'Верно3', 0.1)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { e.message.should.include( 'element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec', - ) - })) + ); + })); it('should wait for expected value for given css locator', () => I.amOnPage('/form/wait_value') .then(() => I.seeInField('#text', 'Hamburg')) .then(() => I.waitForValue('#text', 'Brisbane', 2.5)) - .then(() => I.seeInField('#text', 'Brisbane'))) + .then(() => I.seeInField('#text', 'Brisbane'))); it('should wait for expected value for given xpath locator', () => I.amOnPage('/form/wait_value') .then(() => I.seeInField('#text', 'Hamburg')) .then(() => I.waitForValue('//input[@value = "Grüße aus Hamburg"]', 'Brisbane', 2.5)) - .then(() => I.seeInField('#text', 'Brisbane'))) + .then(() => I.seeInField('#text', 'Brisbane'))); it('should only wait for one of the matching elements to contain the value given xpath locator', () => I.amOnPage('/form/wait_value') .then(() => I.waitForValue('//input[@type = "text"]', 'Brisbane', 4)) .then(() => I.seeInField('#text', 'Brisbane')) - .then(() => I.seeInField('#text2', 'London'))) + .then(() => I.seeInField('#text2', 'London'))); it('should only wait for one of the matching elements to contain the value given css locator', () => I.amOnPage('/form/wait_value') .then(() => I.waitForValue('.inputbox', 'Brisbane', 4)) .then(() => I.seeInField('#text', 'Brisbane')) - .then(() => I.seeInField('#text2', 'London'))) - }) + .then(() => I.seeInField('#text2', 'London'))); + }); describe('#grabHTMLFrom', () => { it('should grab inner html from an element using xpath query', () => I.amOnPage('/') .then(() => I.grabHTMLFrom('//title')) - .then((html) => assert.equal(html, 'TestEd Beta 2.0'))) + .then((html) => assert.equal(html, 'TestEd Beta 2.0'))); it('should grab inner html from an element using id query', () => I.amOnPage('/') .then(() => I.grabHTMLFrom('#area1')) - .then((html) => assert.equal(html.trim(), ' Test Link '))) + .then((html) => assert.equal(html.trim(), ' Test Link '))); it('should grab inner html from multiple elements', () => I.amOnPage('/') .then(() => I.grabHTMLFromAll('//a')) - .then((html) => assert.equal(html.length, 5))) + .then((html) => assert.equal(html.length, 5))); it('should grab inner html from within an iframe', () => I.amOnPage('/iframe') .then(() => I.switchTo({ frame: 'iframe' })) .then(() => I.grabHTMLFrom('#new-tab')) - .then((html) => assert.equal(html.trim(), 'New tab'))) - }) + .then((html) => assert.equal(html.trim(), 'New tab'))); + }); describe('#grabBrowserLogs', () => { it('should grab browser logs', () => I.amOnPage('/') .then(() => I.executeScript(() => { - console.log('Test log entry') + console.log('Test log entry'); }), ) .then(() => I.grabBrowserLogs()) .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1) - assert.equal(matchingLogs.length, 1) - })) + const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1); + assert.equal(matchingLogs.length, 1); + })); it('should grab browser logs in new tab', () => I.amOnPage('/') .then(() => I.openNewTab()) .then(() => I.executeScript(() => { - console.log('Test log entry') + console.log('Test log entry'); }), ) .then(() => I.grabBrowserLogs()) .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1) - assert.equal(matchingLogs.length, 1) - })) + const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1); + assert.equal(matchingLogs.length, 1); + })); it('should grab browser logs in two tabs', () => I.amOnPage('/') .then(() => I.executeScript(() => { - console.log('Test log entry 1') + console.log('Test log entry 1'); }), ) .then(() => I.openNewTab()) .then(() => I.executeScript(() => { - console.log('Test log entry 2') + console.log('Test log entry 2'); }), ) .then(() => I.grabBrowserLogs()) .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().includes('Test log entry')) - assert.equal(matchingLogs.length, 2) - })) + const matchingLogs = logs.filter((log) => log.text().includes('Test log entry')); + assert.equal(matchingLogs.length, 2); + })); it('should grab browser logs in next tab', () => I.amOnPage('/info') @@ -866,28 +866,28 @@ describe('Playwright', function () { .then(() => I.switchToNextTab()) .then(() => I.executeScript(() => { - console.log('Test log entry') + console.log('Test log entry'); }), ) .then(() => I.grabBrowserLogs()) .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1) - assert.equal(matchingLogs.length, 1) - })) - }) + const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1); + assert.equal(matchingLogs.length, 1); + })); + }); describe('#dragAndDrop', () => { it('Drag item from source to target (no iframe) @dragNdrop - customized steps', () => I.amOnPage('https://jqueryui.com/resources/demos/droppable/default.html') .then(() => I.seeElementInDOM('#draggable')) .then(() => I.dragAndDrop('#draggable', '#droppable')) - .then(() => I.see('Dropped'))) + .then(() => I.see('Dropped'))); it('Drag item from source to target (no iframe) @dragNdrop - using Playwright API', () => I.amOnPage('https://jqueryui.com/resources/demos/droppable/default.html') .then(() => I.seeElementInDOM('#draggable')) .then(() => I.dragAndDrop('#draggable', '#droppable', { force: true })) - .then(() => I.see('Dropped'))) + .then(() => I.see('Dropped'))); xit('Drag and drop from within an iframe', () => I.amOnPage('https://jqueryui.com/droppable') @@ -895,8 +895,8 @@ describe('Playwright', function () { .then(() => I.switchTo('//iframe[@class="demo-frame"]')) .then(() => I.seeElementInDOM('#draggable')) .then(() => I.dragAndDrop('#draggable', '#droppable')) - .then(() => I.see('Dropped'))) - }) + .then(() => I.see('Dropped'))); + }); describe('#switchTo frame', () => { it('should switch to frame using name', () => @@ -905,7 +905,7 @@ describe('Playwright', function () { .then(() => I.dontSee('Information', 'h1')) .then(() => I.switchTo('iframe')) .then(() => I.see('Information', 'h1')) - .then(() => I.dontSee('Iframe test', 'h1'))) + .then(() => I.dontSee('Iframe test', 'h1'))); it('should switch to root frame', () => I.amOnPage('/iframe') @@ -915,7 +915,7 @@ describe('Playwright', function () { .then(() => I.see('Information', 'h1')) .then(() => I.dontSee('Iframe test', 'h1')) .then(() => I.switchTo()) - .then(() => I.see('Iframe test', 'h1'))) + .then(() => I.see('Iframe test', 'h1'))); it('should switch to frame using frame number', () => I.amOnPage('/iframe') @@ -923,197 +923,197 @@ describe('Playwright', function () { .then(() => I.dontSee('Information', 'h1')) .then(() => I.switchTo(0)) .then(() => I.see('Information', 'h1')) - .then(() => I.dontSee('Iframe test', 'h1'))) - }) + .then(() => I.dontSee('Iframe test', 'h1'))); + }); describe('#dragSlider', () => { it('should drag scrubber to given position', async () => { - await I.amOnPage('/form/page_slider') - await I.seeElementInDOM('#slidecontainer input') - const before = await I.grabValueFrom('#slidecontainer input') - await I.dragSlider('#slidecontainer input', 20) - const after = await I.grabValueFrom('#slidecontainer input') - assert.notEqual(before, after) - }) - }) + await I.amOnPage('/form/page_slider'); + await I.seeElementInDOM('#slidecontainer input'); + const before = await I.grabValueFrom('#slidecontainer input'); + await I.dragSlider('#slidecontainer input', 20); + const after = await I.grabValueFrom('#slidecontainer input'); + assert.notEqual(before, after); + }); + }); describe('#uncheckOption', () => { it('should uncheck option that is currently checked', async () => { - await I.amOnPage('/info') - await I.uncheckOption('interesting') - await I.dontSeeCheckboxIsChecked('interesting') - }) + await I.amOnPage('/info'); + await I.uncheckOption('interesting'); + await I.dontSeeCheckboxIsChecked('interesting'); + }); it('should NOT uncheck option that is NOT currently checked', async () => { - await I.amOnPage('/info') - await I.uncheckOption('interesting') + await I.amOnPage('/info'); + await I.uncheckOption('interesting'); // Unchecking again should not affect the current 'unchecked' status - await I.uncheckOption('interesting') - await I.dontSeeCheckboxIsChecked('interesting') - }) - }) + await I.uncheckOption('interesting'); + await I.dontSeeCheckboxIsChecked('interesting'); + }); + }); describe('#usePlaywrightTo', () => { it('should return title', async () => { - await I.amOnPage('/') + await I.amOnPage('/'); const title = await I.usePlaywrightTo('test', async ({ page }) => { - return page.title() - }) - assert.equal('TestEd Beta 2.0', title) - }) + return page.title(); + }); + assert.equal('TestEd Beta 2.0', title); + }); it('should pass expected parameters', async () => { - await I.amOnPage('/') + await I.amOnPage('/'); const params = await I.usePlaywrightTo('test', async (params) => { - return params - }) - expect(params.page).to.exist - expect(params.browserContext).to.exist - expect(params.browser).to.exist - }) - }) + return params; + }); + expect(params.page).to.exist; + expect(params.browserContext).to.exist; + expect(params.browser).to.exist; + }); + }); describe('#mockRoute, #stopMockingRoute', () => { it('should mock a route', async () => { - await I.amOnPage('/form/fetch_call') + await I.amOnPage('/form/fetch_call'); await I.mockRoute('https://reqres.in/api/comments/1', (route) => { route.fulfill({ status: 200, headers: { 'Access-Control-Allow-Origin': '*' }, contentType: 'application/json', body: '{"name": "this was mocked" }', - }) - }) - await I.click('GET COMMENTS') - await I.see('this was mocked') - await I.stopMockingRoute('https://reqres.in/api/comments/1') - await I.click('GET COMMENTS') - await I.see('data') - await I.dontSee('this was mocked') - }) - }) + }); + }); + await I.click('GET COMMENTS'); + await I.see('this was mocked'); + await I.stopMockingRoute('https://reqres.in/api/comments/1'); + await I.click('GET COMMENTS'); + await I.see('data'); + await I.dontSee('this was mocked'); + }); + }); describe('#makeApiRequest', () => { it('should make 3rd party API request', async () => { - const response = await I.makeApiRequest('get', 'https://reqres.in/api/users?page=2') - expect(response.status()).to.equal(200) - expect(await response.json()).to.include.keys(['page']) - }) + const response = await I.makeApiRequest('get', 'https://reqres.in/api/users?page=2'); + expect(response.status()).to.equal(200); + expect(await response.json()).to.include.keys(['page']); + }); it('should make local API request', async () => { - const response = await I.makeApiRequest('get', '/form/fetch_call') - expect(response.status()).to.equal(200) - }) + const response = await I.makeApiRequest('get', '/form/fetch_call'); + expect(response.status()).to.equal(200); + }); it('should convert to axios response with onResponse hook', async () => { - let response - I.config.onResponse = (resp) => (response = resp) - await I.makeApiRequest('get', 'https://reqres.in/api/users?page=2') - expect(response).to.be.ok - expect(response.status).to.equal(200) - expect(response.data).to.include.keys(['page', 'total']) - }) - }) + let response; + I.config.onResponse = (resp) => (response = resp); + await I.makeApiRequest('get', 'https://reqres.in/api/users?page=2'); + expect(response).to.be.ok; + expect(response.status).to.equal(200); + expect(response.data).to.include.keys(['page', 'total']); + }); + }); describe('#grabElementBoundingRect', () => { it('should get the element bounding rectangle', async () => { - await I.amOnPage('/image') - const size = await I.grabElementBoundingRect('#logo') - expect(size.x).is.greaterThan(39) // 40 or more - expect(size.y).is.greaterThan(39) - expect(size.width).is.greaterThan(0) - expect(size.height).is.greaterThan(0) - expect(size.width).to.eql(100) - expect(size.height).to.eql(100) - }) + await I.amOnPage('/image'); + const size = await I.grabElementBoundingRect('#logo'); + expect(size.x).is.greaterThan(39); // 40 or more + expect(size.y).is.greaterThan(39); + expect(size.width).is.greaterThan(0); + expect(size.height).is.greaterThan(0); + expect(size.width).to.eql(100); + expect(size.height).to.eql(100); + }); it('should get the element width', async () => { - await I.amOnPage('/image') - const width = await I.grabElementBoundingRect('#logo', 'width') - expect(width).is.greaterThan(0) - expect(width).to.eql(100) - }) + await I.amOnPage('/image'); + const width = await I.grabElementBoundingRect('#logo', 'width'); + expect(width).is.greaterThan(0); + expect(width).to.eql(100); + }); it('should get the element height', async () => { - await I.amOnPage('/image') - const height = await I.grabElementBoundingRect('#logo', 'height') - expect(height).is.greaterThan(0) - expect(height).to.eql(100) - }) - }) + await I.amOnPage('/image'); + const height = await I.grabElementBoundingRect('#logo', 'height'); + expect(height).is.greaterThan(0); + expect(height).to.eql(100); + }); + }); describe('#handleDownloads - with passed folder', () => { before(() => { // create download folder; - global.output_dir = path.join(`${__dirname}/../data/output`) + global.output_dir = path.join(`${__dirname}/../data/output`); - FS = new FileSystem() - FS._before() - FS.amInPath('output/downloadHere') - }) + FS = new FileSystem(); + FS._before(); + FS.amInPath('output/downloadHere'); + }); it('should download file', async () => { - await I.amOnPage('/form/download') - await I.handleDownloads('downloadHere/avatar.jpg') - await I.click('Download file') - await FS.waitForFile('avatar.jpg', 5) - }) - }) + await I.amOnPage('/form/download'); + await I.handleDownloads('downloadHere/avatar.jpg'); + await I.click('Download file'); + await FS.waitForFile('avatar.jpg', 5); + }); + }); describe('#handleDownloads - with default folder', () => { before(() => { // create download folder; - global.output_dir = path.join(`${__dirname}/../data/output`) + global.output_dir = path.join(`${__dirname}/../data/output`); - FS = new FileSystem() - FS._before() - FS.amInPath('output') - }) + FS = new FileSystem(); + FS._before(); + FS.amInPath('output'); + }); it('should download file', async () => { - await I.amOnPage('/form/download') - await I.handleDownloads('avatar.jpg') - await I.click('Download file') - await FS.waitForFile('avatar.jpg', 5) - }) - }) + await I.amOnPage('/form/download'); + await I.handleDownloads('avatar.jpg'); + await I.click('Download file'); + await FS.waitForFile('avatar.jpg', 5); + }); + }); describe('#waitForURL', () => { it('should wait for URL', () => { - I.amOnPage('/') - I.click('More info') - I.waitForURL('/info') - I.see('Information') - }) + I.amOnPage('/'); + I.click('More info'); + I.waitForURL('/info'); + I.see('Information'); + }); it('should wait for regex URL', () => { - I.amOnPage('/') - I.click('More info') - I.waitForURL(/info/) - I.see('Information') - }) - }) -}) - -let remoteBrowser + I.amOnPage('/'); + I.click('More info'); + I.waitForURL(/info/); + I.see('Information'); + }); + }); +}); + +let remoteBrowser; async function createRemoteBrowser() { if (remoteBrowser) { - await remoteBrowser.close() + await remoteBrowser.close(); } remoteBrowser = await playwright.chromium.launchServer({ webSocket: true, // args: ['--no-sandbox', '--disable-setuid-sandbox'], headless: true, - }) + }); remoteBrowser.on('disconnected', () => { - remoteBrowser = null - }) - return remoteBrowser + remoteBrowser = null; + }); + return remoteBrowser; } describe('Playwright (remote browser) websocket', function () { - this.timeout(35000) - this.retries(1) + this.timeout(35000); + this.retries(1); const helperConfig = { chromium: { @@ -1129,86 +1129,86 @@ describe('Playwright (remote browser) websocket', function () { waitForTimeout: 5000, waitForAction: 500, windowSize: '500x700', - } + }; before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - I = new Playwright(helperConfig) - I._init() - }) + global.codecept_dir = path.join(__dirname, '/../data'); + I = new Playwright(helperConfig); + I._init(); + }); beforeEach(async () => { // Mimick remote session by creating another browser instance - const remoteBrowser = await createRemoteBrowser() + const remoteBrowser = await createRemoteBrowser(); // I.isRunning = false; // Set websocket endpoint to other browser instance - }) + }); afterEach(async () => { - await I._after() - return remoteBrowser && remoteBrowser.close() - }) + await I._after(); + return remoteBrowser && remoteBrowser.close(); + }); describe('#_startBrowser', () => { it('should throw an exception when endpoint is unreachable', async () => { - I._setConfig({ ...helperConfig, chromium: { browserWSEndpoint: 'ws://unreachable/' } }) + I._setConfig({ ...helperConfig, chromium: { browserWSEndpoint: 'ws://unreachable/' } }); try { - await I._startBrowser() - throw Error('It should never get this far') + await I._startBrowser(); + throw Error('It should never get this far'); } catch (e) { - e.message.should.include('Cannot connect to websocket') + e.message.should.include('Cannot connect to websocket'); } - }) + }); it('should connect to legacy API endpoint', async () => { - const wsEndpoint = await remoteBrowser.wsEndpoint() - I._setConfig({ ...helperConfig, chromium: { browserWSEndpoint: { wsEndpoint } } }) - await I._before() - await I.amOnPage('/') - await I.see('Welcome to test app') - }) + const wsEndpoint = await remoteBrowser.wsEndpoint(); + I._setConfig({ ...helperConfig, chromium: { browserWSEndpoint: { wsEndpoint } } }); + await I._before(); + await I.amOnPage('/'); + await I.see('Welcome to test app'); + }); it('should connect to remote browsers', async () => { - helperConfig.chromium.browserWSEndpoint = await remoteBrowser.wsEndpoint() - I._setConfig(helperConfig) + helperConfig.chromium.browserWSEndpoint = await remoteBrowser.wsEndpoint(); + I._setConfig(helperConfig); - await I._before() - await I.amOnPage('/') - await I.see('Welcome to test app') - }) + await I._before(); + await I.amOnPage('/'); + await I.see('Welcome to test app'); + }); it('should manage pages in remote browser', async () => { - helperConfig.chromium.browserWSEndpoint = await remoteBrowser.wsEndpoint() - I._setConfig(helperConfig) + helperConfig.chromium.browserWSEndpoint = await remoteBrowser.wsEndpoint(); + I._setConfig(helperConfig); - await I._before() - assert.ok(I.isRemoteBrowser) - const context = await I.browserContext + await I._before(); + assert.ok(I.isRemoteBrowser); + const context = await I.browserContext; // Session was cleared - let currentPages = await context.pages() - assert.equal(currentPages.length, 1) + let currentPages = await context.pages(); + assert.equal(currentPages.length, 1); - let numPages = await I.grabNumberOfOpenTabs() - assert.equal(numPages, 1) + let numPages = await I.grabNumberOfOpenTabs(); + assert.equal(numPages, 1); - await I.openNewTab() + await I.openNewTab(); - numPages = await I.grabNumberOfOpenTabs() - assert.equal(numPages, 2) + numPages = await I.grabNumberOfOpenTabs(); + assert.equal(numPages, 2); - await I._stopBrowser() + await I._stopBrowser(); - currentPages = await context.pages() - assert.equal(currentPages.length, 0) - }) - }) -}) + currentPages = await context.pages(); + assert.equal(currentPages.length, 0); + }); + }); +}); describe('Playwright - BasicAuth', function () { - this.timeout(35000) + this.timeout(35000); before(() => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); I = new Playwright({ url: 'http://localhost:8000', @@ -1223,37 +1223,37 @@ describe('Playwright - BasicAuth', function () { }, defaultPopupAction: 'accept', basicAuth: { username: 'admin', password: 'admin' }, - }) - I._init() - return I._beforeSuite() - }) + }); + I._init(); + return I._beforeSuite(); + }); beforeEach(() => { webApiTests.init({ I, siteUrl, - }) + }); return I._before().then(() => { - page = I.page - }) - }) + page = I.page; + }); + }); afterEach(() => { - return I._after() - }) + return I._after(); + }); describe('open page with provided basic auth', () => { it('should be authenticated ', async () => { - await I.amOnPage('/basic_auth') - await I.see('You entered admin as your password.') - }) - }) -}) + await I.amOnPage('/basic_auth'); + await I.see('You entered admin as your password.'); + }); + }); +}); describe('Playwright - Emulation', () => { before(() => { - const { devices } = require('playwright') - global.codecept_dir = path.join(__dirname, '/../data') + const { devices } = require('playwright'); + global.codecept_dir = path.join(__dirname, '/../data'); I = new Playwright({ url: 'http://localhost:8000', @@ -1267,32 +1267,32 @@ describe('Playwright - Emulation', () => { chrome: { args: ['--no-sandbox', '--disable-setuid-sandbox'], }, - }) - I._init() - return I._beforeSuite() - }) + }); + I._init(); + return I._beforeSuite(); + }); beforeEach(() => { return I._before().then(() => { - page = I.page - browser = I.browser - }) - }) + page = I.page; + browser = I.browser; + }); + }); afterEach(() => { - return I._after() - }) + return I._after(); + }); it('should open page as iPhone ', async () => { - await I.amOnPage('/') - const width = await I.executeScript('window.innerWidth') - assert.equal(width, 980) - }) -}) + await I.amOnPage('/'); + const width = await I.executeScript('window.innerWidth'); + assert.equal(width, 980); + }); +}); describe('Playwright - PERSISTENT', () => { before(() => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); I = new Playwright({ url: 'http://localhost:8000', @@ -1306,30 +1306,30 @@ describe('Playwright - PERSISTENT', () => { args: ['--no-sandbox', '--disable-setuid-sandbox'], userDataDir: '/tmp/playwright-tmp', }, - }) - I._init() - return I._beforeSuite() - }) + }); + I._init(); + return I._beforeSuite(); + }); beforeEach(() => { return I._before().then(() => { - page = I.page - browser = I.browser - }) - }) + page = I.page; + browser = I.browser; + }); + }); afterEach(() => { - return I._after() - }) + return I._after(); + }); it('should launch a persistent context', async () => { - assert.equal(I._getType(), 'BrowserContext') - }) -}) + assert.equal(I._getType(), 'BrowserContext'); + }); +}); describe('Playwright - Electron', () => { before(() => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); I = new Playwright({ waitForTimeout: 5000, @@ -1340,71 +1340,71 @@ describe('Playwright - Electron', () => { executablePath: require('electron'), args: [path.join(codecept_dir, '/electron/')], }, - }) - I._init() - return I._beforeSuite() - }) + }); + I._init(); + return I._beforeSuite(); + }); describe('#amOnPage', () => { it('should throw an error', async () => { try { - await I.amOnPage('/') - throw Error('It should never get this far') + await I.amOnPage('/'); + throw Error('It should never get this far'); } catch (e) { - e.message.should.include('Cannot open pages inside an Electron container') + e.message.should.include('Cannot open pages inside an Electron container'); } - }) - }) + }); + }); describe('#openNewTab', () => { it('should throw an error', async () => { try { - await I.openNewTab() - throw Error('It should never get this far') + await I.openNewTab(); + throw Error('It should never get this far'); } catch (e) { - e.message.should.include('Cannot open new tabs inside an Electron container') + e.message.should.include('Cannot open new tabs inside an Electron container'); } - }) - }) + }); + }); describe('#switchToNextTab', () => { it('should throw an error', async () => { try { - await I.switchToNextTab() - throw Error('It should never get this far') + await I.switchToNextTab(); + throw Error('It should never get this far'); } catch (e) { - e.message.should.include('Cannot switch tabs inside an Electron container') + e.message.should.include('Cannot switch tabs inside an Electron container'); } - }) - }) + }); + }); describe('#switchToPreviousTab', () => { it('should throw an error', async () => { try { - await I.switchToNextTab() - throw Error('It should never get this far') + await I.switchToNextTab(); + throw Error('It should never get this far'); } catch (e) { - e.message.should.include('Cannot switch tabs inside an Electron container') + e.message.should.include('Cannot switch tabs inside an Electron container'); } - }) - }) + }); + }); describe('#closeCurrentTab', () => { it('should throw an error', async () => { try { - await I.closeCurrentTab() - throw Error('It should never get this far') + await I.closeCurrentTab(); + throw Error('It should never get this far'); } catch (e) { - e.message.should.include('Cannot close current tab inside an Electron container') + e.message.should.include('Cannot close current tab inside an Electron container'); } - }) - }) -}) + }); + }); +}); describe('Playwright - Performance Metrics', () => { before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - global.output_dir = path.join(`${__dirname}/../data/output`) + global.codecept_dir = path.join(__dirname, '/../data'); + global.output_dir = path.join(`${__dirname}/../data/output`); I = new Playwright({ url: siteUrl, @@ -1412,40 +1412,40 @@ describe('Playwright - Performance Metrics', () => { show: false, restart: true, browser: 'chromium', - }) - I._init() - return I._beforeSuite() - }) + }); + I._init(); + return I._beforeSuite(); + }); beforeEach(async () => { webApiTests.init({ I, siteUrl, - }) + }); return I._before().then(() => { - page = I.page - browser = I.browser - }) - }) + page = I.page; + browser = I.browser; + }); + }); afterEach(async () => { - return I._after() - }) + return I._after(); + }); it('grabs performance metrics', async () => { - await I.amOnPage('https://codecept.io') - const metrics = await I.grabMetrics() - expect(metrics.length).to.greaterThan(0) - expect(metrics[0].name).to.equal('Timestamp') - }) -}) + await I.amOnPage('https://codecept.io'); + const metrics = await I.grabMetrics(); + expect(metrics.length).to.greaterThan(0); + expect(metrics[0].name).to.equal('Timestamp'); + }); +}); describe('Playwright - Video & Trace & HAR', () => { - const test = { title: 'a failed test', artifacts: {} } + const test = { title: 'a failed test', artifacts: {} }; before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - global.output_dir = path.join(`${__dirname}/../data/output`) + global.codecept_dir = path.join(__dirname, '/../data'); + global.output_dir = path.join(`${__dirname}/../data/output`); I = new Playwright({ url: siteUrl, @@ -1462,49 +1462,49 @@ describe('Playwright - Video & Trace & HAR', () => { }, }, recordHar: {}, - }) - I._init() - return I._beforeSuite() - }) + }); + I._init(); + return I._beforeSuite(); + }); beforeEach(async () => { webApiTests.init({ I, siteUrl, - }) - deleteDir(path.join(global.output_dir, 'video')) - deleteDir(path.join(global.output_dir, 'trace')) - deleteDir(path.join(global.output_dir, 'har')) + }); + deleteDir(path.join(global.output_dir, 'video')); + deleteDir(path.join(global.output_dir, 'trace')); + deleteDir(path.join(global.output_dir, 'har')); return I._before(test).then(() => { - page = I.page - browser = I.browser - }) - }) + page = I.page; + browser = I.browser; + }); + }); afterEach(async () => { - return I._after() - }) + return I._after(); + }); it('checks that video is recorded', async () => { - await I.amOnPage('/') - await I.dontSee('this should be an error') - await I.click('More info') - await I.dontSee('this should be an error') - await I._failed(test) - assert(test.artifacts) - expect(Object.keys(test.artifacts)).to.include('trace') - expect(Object.keys(test.artifacts)).to.include('video') - expect(Object.keys(test.artifacts)).to.include('har') - - assert.ok(fs.existsSync(test.artifacts.trace)) - expect(test.artifacts.video).to.include(path.join(global.output_dir, 'video')) - expect(test.artifacts.trace).to.include(path.join(global.output_dir, 'trace')) - expect(test.artifacts.har).to.include(path.join(global.output_dir, 'har')) - }) -}) + await I.amOnPage('/'); + await I.dontSee('this should be an error'); + await I.click('More info'); + await I.dontSee('this should be an error'); + await I._failed(test); + assert(test.artifacts); + expect(Object.keys(test.artifacts)).to.include('trace'); + expect(Object.keys(test.artifacts)).to.include('video'); + expect(Object.keys(test.artifacts)).to.include('har'); + + assert.ok(fs.existsSync(test.artifacts.trace)); + expect(test.artifacts.video).to.include(path.join(global.output_dir, 'video')); + expect(test.artifacts.trace).to.include(path.join(global.output_dir, 'trace')); + expect(test.artifacts.har).to.include(path.join(global.output_dir, 'har')); + }); +}); describe('Playwright - HAR', () => { before(() => { - global.codecept_dir = path.join(process.cwd()) + global.codecept_dir = path.join(process.cwd()); I = new Playwright({ url: siteUrl, @@ -1512,64 +1512,64 @@ describe('Playwright - HAR', () => { show: false, restart: true, browser: 'chromium', - }) - I._init() - return I._beforeSuite() - }) + }); + I._init(); + return I._beforeSuite(); + }); beforeEach(async () => { webApiTests.init({ I, siteUrl, - }) + }); return I._before().then(() => { - page = I.page - browser = I.browser - }) - }) + page = I.page; + browser = I.browser; + }); + }); afterEach(async () => { - return I._after() - }) + return I._after(); + }); it('replay from HAR - non existing file', async () => { try { - await I.replayFromHar('./non-existing-file.har') - await I.amOnPage('https://demo.playwright.dev/api-mocking') + await I.replayFromHar('./non-existing-file.har'); + await I.amOnPage('https://demo.playwright.dev/api-mocking'); } catch (e) { - expect(e.message).to.include('cannot be found on local system') + expect(e.message).to.include('cannot be found on local system'); } - }) + }); it('replay from HAR', async () => { - const harFile = './test/data/sandbox/testHar.har' - await I.replayFromHar(harFile) - await I.amOnPage('https://demo.playwright.dev/api-mocking') - await I.see('CodeceptJS') - }) + const harFile = './test/data/sandbox/testHar.har'; + await I.replayFromHar(harFile); + await I.amOnPage('https://demo.playwright.dev/api-mocking'); + await I.see('CodeceptJS'); + }); describe('#grabWebElements, #grabWebElement', () => { it('should return an array of WebElement', async () => { - await I.amOnPage('/form/focus_blur_elements') + await I.amOnPage('/form/focus_blur_elements'); - const webElements = await I.grabWebElements('#button') - assert.equal(webElements[0], "locator('#button').first()") - assert.isAbove(webElements.length, 0) - }) + const webElements = await I.grabWebElements('#button'); + assert.equal(webElements[0], "locator('#button').first()"); + assert.isAbove(webElements.length, 0); + }); it('should return a WebElement', async () => { - await I.amOnPage('/form/focus_blur_elements') + await I.amOnPage('/form/focus_blur_elements'); - const webElement = await I.grabWebElement('#button') - assert.equal(webElement, "locator('#button').first()") - }) - }) -}) + const webElement = await I.grabWebElement('#button'); + assert.equal(webElement, "locator('#button').first()"); + }); + }); +}); describe('using data-testid attribute', () => { before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - global.output_dir = path.join(`${__dirname}/../data/output`) + global.codecept_dir = path.join(__dirname, '/../data'); + global.output_dir = path.join(`${__dirname}/../data/output`); I = new Playwright({ url: siteUrl, @@ -1577,35 +1577,35 @@ describe('using data-testid attribute', () => { show: false, restart: true, browser: 'chromium', - }) - I._init() - return I._beforeSuite() - }) + }); + I._init(); + return I._beforeSuite(); + }); beforeEach(async () => { return I._before().then(() => { - page = I.page - browser = I.browser - }) - }) + page = I.page; + browser = I.browser; + }); + }); afterEach(async () => { - return I._after() - }) + return I._after(); + }); it('should find element by pw locator', async () => { - await I.amOnPage('/') + await I.amOnPage('/'); - const webElements = await I.grabWebElements({ pw: '[data-testid="welcome"]' }) - assert.equal(webElements[0]._selector, '[data-testid="welcome"] >> nth=0') - assert.equal(webElements.length, 1) - }) + const webElements = await I.grabWebElements({ pw: '[data-testid="welcome"]' }); + assert.equal(webElements[0]._selector, '[data-testid="welcome"] >> nth=0'); + assert.equal(webElements.length, 1); + }); it('should find element by h1[data-testid="welcome"]', async () => { - await I.amOnPage('/') + await I.amOnPage('/'); - const webElements = await I.grabWebElements('h1[data-testid="welcome"]') - assert.equal(webElements[0]._selector, 'h1[data-testid="welcome"] >> nth=0') - assert.equal(webElements.length, 1) - }) -}) + const webElements = await I.grabWebElements('h1[data-testid="welcome"]'); + assert.equal(webElements[0]._selector, 'h1[data-testid="welcome"] >> nth=0'); + assert.equal(webElements.length, 1); + }); +}); diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js index b7343bd7c..03273b8e0 100644 --- a/test/helper/Puppeteer_test.js +++ b/test/helper/Puppeteer_test.js @@ -1,32 +1,32 @@ -const chai = require('chai') +const chai = require('chai'); -const expect = chai.expect -const assert = chai.assert -const path = require('path') +const expect = chai.expect; +const assert = chai.assert; +const path = require('path'); -const puppeteer = require('puppeteer') +const puppeteer = require('puppeteer'); -const fs = require('fs') -const TestHelper = require('../support/TestHelper') -const Puppeteer = require('../../lib/helper/Puppeteer') +const fs = require('fs'); +const TestHelper = require('../support/TestHelper'); +const Puppeteer = require('../../lib/helper/Puppeteer'); -const AssertionFailedError = require('../../lib/assert/error') -const webApiTests = require('./webapi') -const Secret = require('../../lib/secret') -const { deleteDir } = require('../../lib/utils') -global.codeceptjs = require('../../lib') +const AssertionFailedError = require('../../lib/assert/error'); +const webApiTests = require('./webapi'); +const Secret = require('../../lib/secret'); +const { deleteDir } = require('../../lib/utils'); +global.codeceptjs = require('../../lib'); -let I -let browser -let page -let FS -const siteUrl = TestHelper.siteUrl() +let I; +let browser; +let page; +let FS; +const siteUrl = TestHelper.siteUrl(); describe('Puppeteer - BasicAuth', function () { - this.timeout(10000) + this.timeout(10000); before(() => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); I = new Puppeteer({ url: siteUrl, @@ -39,44 +39,44 @@ describe('Puppeteer - BasicAuth', function () { }, defaultPopupAction: 'accept', basicAuth: { username: 'admin', password: 'admin' }, - }) - I._init() - return I._beforeSuite() - }) + }); + I._init(); + return I._beforeSuite(); + }); beforeEach(() => { webApiTests.init({ I, siteUrl, - }) + }); return I._before().then(() => { - page = I.page - browser = I.browser - }) - }) + page = I.page; + browser = I.browser; + }); + }); afterEach(() => { - return I._after() - }) + return I._after(); + }); describe('open page with provided basic auth', () => { it('should be authenticated ', async () => { - await I.amOnPage('/basic_auth') - await I.see('You entered admin as your password.') - }) + await I.amOnPage('/basic_auth'); + await I.see('You entered admin as your password.'); + }); it('should be authenticated on second run', async () => { - await I.amOnPage('/basic_auth') - await I.see('You entered admin as your password.') - }) - }) -}) + await I.amOnPage('/basic_auth'); + await I.see('You entered admin as your password.'); + }); + }); +}); describe('Puppeteer', function () { - this.timeout(35000) - this.retries(1) + this.timeout(35000); + this.retries(1); before(() => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); I = new Puppeteer({ url: siteUrl, @@ -88,92 +88,92 @@ describe('Puppeteer', function () { args: ['--no-sandbox', '--disable-setuid-sandbox'], }, defaultPopupAction: 'accept', - }) - I._init() - return I._beforeSuite() - }) + }); + I._init(); + return I._beforeSuite(); + }); beforeEach(() => { webApiTests.init({ I, siteUrl, - }) + }); return I._before().then(() => { - page = I.page - browser = I.browser - }) - }) + page = I.page; + browser = I.browser; + }); + }); afterEach(() => { - return I._after() - }) + return I._after(); + }); describe('Session', () => { it('should not fail for localStorage.clear() on about:blank', async () => { - I.options.restart = false + I.options.restart = false; return I.page .goto('about:blank') .then(() => I._after()) .then(() => { - I.options.restart = true + I.options.restart = true; }) .catch((e) => { - I.options.restart = true - throw new Error(e) - }) - }) - }) + I.options.restart = true; + throw new Error(e); + }); + }); + }); describe('open page : #amOnPage', () => { it('should open main page of configured site', async () => { - await I.amOnPage('/') - const url = await page.url() - await url.should.eql(`${siteUrl}/`) - }) + await I.amOnPage('/'); + const url = await page.url(); + await url.should.eql(`${siteUrl}/`); + }); it('should open any page of configured site', async () => { - await I.amOnPage('/info') - const url = await page.url() - return url.should.eql(`${siteUrl}/info`) - }) + await I.amOnPage('/info'); + const url = await page.url(); + return url.should.eql(`${siteUrl}/info`); + }); it('should open absolute url', async () => { - await I.amOnPage(siteUrl) - const url = await page.url() - return url.should.eql(`${siteUrl}/`) - }) + await I.amOnPage(siteUrl); + const url = await page.url(); + return url.should.eql(`${siteUrl}/`); + }); it('should be unauthenticated ', async () => { try { - await I.amOnPage('/basic_auth') - await I.dontSee('You entered admin as your password.') + await I.amOnPage('/basic_auth'); + await I.dontSee('You entered admin as your password.'); } catch (e) { - expect(e.message).to.eq('net::ERR_INVALID_AUTH_CREDENTIALS at http://localhost:8000/basic_auth') + expect(e.message).to.eq('net::ERR_INVALID_AUTH_CREDENTIALS at http://localhost:8000/basic_auth'); } - }) - }) + }); + }); describe('grabDataFromPerformanceTiming', () => { it('should return data from performance timing', async () => { - await I.amOnPage('/') - const res = await I.grabDataFromPerformanceTiming() - expect(res).to.have.property('responseEnd') - expect(res).to.have.property('domInteractive') - expect(res).to.have.property('domContentLoadedEventEnd') - expect(res).to.have.property('loadEventEnd') - }) - }) + await I.amOnPage('/'); + const res = await I.grabDataFromPerformanceTiming(); + expect(res).to.have.property('responseEnd'); + expect(res).to.have.property('domInteractive'); + expect(res).to.have.property('domContentLoadedEventEnd'); + expect(res).to.have.property('loadEventEnd'); + }); + }); - webApiTests.tests() + webApiTests.tests(); describe('#waitForFunction', () => { it('should wait for function returns true', () => { - return I.amOnPage('/form/wait_js').then(() => I.waitForFunction(() => window.__waitJs, 3)) - }) + return I.amOnPage('/form/wait_js').then(() => I.waitForFunction(() => window.__waitJs, 3)); + }); it('should pass arguments and wait for function returns true', () => { - return I.amOnPage('/form/wait_js').then(() => I.waitForFunction((varName) => window[varName], ['__waitJs'], 3)) - }) - }) + return I.amOnPage('/form/wait_js').then(() => I.waitForFunction((varName) => window[varName], ['__waitJs'], 3)); + }); + }); describe('#waitToHide', () => { it('should wait for hidden element', () => { @@ -181,69 +181,69 @@ describe('Puppeteer', function () { .then(() => I.see('Step One Button')) .then(() => I.waitToHide('#step_1', 2)) .then(() => I.dontSeeElement('#step_1')) - .then(() => I.dontSee('Step One Button')) - }) + .then(() => I.dontSee('Step One Button')); + }); it('should wait for hidden element by XPath', () => { return I.amOnPage('/form/wait_invisible') .then(() => I.see('Step One Button')) .then(() => I.waitToHide('//div[@id="step_1"]', 2)) .then(() => I.dontSeeElement('//div[@id="step_1"]')) - .then(() => I.dontSee('Step One Button')) - }) - }) + .then(() => I.dontSee('Step One Button')); + }); + }); describe('#waitNumberOfVisibleElements', () => { it('should wait for a specified number of elements on the page', async () => { try { - await I.amOnPage('/info') - await I.waitNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 3) + await I.amOnPage('/info'); + await I.waitNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 3); } catch (e) { - e.message.should.include('The number of elements (//div[@id = "grab-multiple"]//a) is not 2 after 0.1 sec') + e.message.should.include('The number of elements (//div[@id = "grab-multiple"]//a) is not 2 after 0.1 sec'); } - }) + }); it('should wait for a specified number of elements on the page using a css selector', () => I.amOnPage('/info') .then(() => I.waitNumberOfVisibleElements('#grab-multiple > a', 3)) .then(() => I.waitNumberOfVisibleElements('#grab-multiple > a', 2, 0.1)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec') - })) + e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec'); + })); it('should wait for a specified number of elements which are not yet attached to the DOM', () => I.amOnPage('/form/wait_num_elements') .then(() => I.waitNumberOfVisibleElements('.title', 2, 3)) .then(() => I.see('Hello')) - .then(() => I.see('World'))) + .then(() => I.see('World'))); it('should wait for 0 number of visible elements', async () => { - await I.amOnPage('/form/wait_invisible') - await I.waitNumberOfVisibleElements('#step_1', 0) - }) - }) + await I.amOnPage('/form/wait_invisible'); + await I.waitNumberOfVisibleElements('#step_1', 0); + }); + }); describe('#moveCursorTo', () => { it('should trigger hover event', () => I.amOnPage('/form/hover') .then(() => I.moveCursorTo('#hover')) - .then(() => I.see('Hovered', '#show'))) + .then(() => I.see('Hovered', '#show'))); it('should not trigger hover event because of the offset is beyond the element', () => I.amOnPage('/form/hover') .then(() => I.moveCursorTo('#hover', 100, 100)) - .then(() => I.dontSee('Hovered', '#show'))) - }) + .then(() => I.dontSee('Hovered', '#show'))); + }); describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs, #grabNumberOfOpenTabs, #waitForNumberOfTabs', () => { it('should only have 1 tab open when the browser starts and navigates to the first page', () => I.amOnPage('/') .then(() => I.wait(1)) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(1))) + .then((numPages) => expect(numPages).to.eq(1))); it('should switch to next tab', () => I.amOnPage('/info') @@ -255,7 +255,7 @@ describe('Puppeteer', function () { .then(() => I.waitForNumberOfTabs(2)) .then(() => I.seeCurrentUrlEquals('/login')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(2))) + .then((numPages) => expect(numPages).to.eq(2))); it('should assert when there is no ability to switch to next tab', () => I.amOnPage('/') @@ -265,8 +265,8 @@ describe('Puppeteer', function () { .then(() => I.wait(2)) .then(() => expect(true, 'Throw an error if it gets this far (which it should not)!').to.eq(false)) .catch((e) => { - expect(e.message).to.eq('There is no ability to switch to next tab with offset 2') - })) + expect(e.message).to.eq('There is no ability to switch to next tab with offset 2'); + })); it('should close current tab', () => I.amOnPage('/info') @@ -280,7 +280,7 @@ describe('Puppeteer', function () { .then(() => I.wait(1)) .then(() => I.seeInCurrentUrl('/info')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(1))) + .then((numPages) => expect(numPages).to.eq(1))); it('should close other tabs', () => I.amOnPage('/') @@ -296,7 +296,7 @@ describe('Puppeteer', function () { .then(() => I.wait(1)) .then(() => I.seeInCurrentUrl('/login')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(1))) + .then((numPages) => expect(numPages).to.eq(1))); it('should open new tab', () => I.amOnPage('/info') @@ -304,7 +304,7 @@ describe('Puppeteer', function () { .then(() => I.wait(1)) .then(() => I.seeInCurrentUrl('about:blank')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(2))) + .then((numPages) => expect(numPages).to.eq(2))); it('should switch to previous tab', () => I.amOnPage('/info') @@ -313,7 +313,7 @@ describe('Puppeteer', function () { .then(() => I.seeInCurrentUrl('about:blank')) .then(() => I.switchToPreviousTab()) .then(() => I.wait(2)) - .then(() => I.seeInCurrentUrl('/info'))) + .then(() => I.seeInCurrentUrl('/info'))); it('should assert when there is no ability to switch to previous tab', () => I.amOnPage('/info') @@ -324,9 +324,9 @@ describe('Puppeteer', function () { .then(() => I.wait(2)) .then(() => I.waitInUrl('/info')) .catch((e) => { - expect(e.message).to.eq('There is no ability to switch to previous tab with offset 2') - })) - }) + expect(e.message).to.eq('There is no ability to switch to previous tab with offset 2'); + })); + }); describe('popup : #acceptPopup, #seeInPopup, #cancelPopup, #grabPopupText', () => { it('should accept popup window', () => @@ -334,67 +334,67 @@ describe('Puppeteer', function () { .then(() => I.amAcceptingPopups()) .then(() => I.click('Confirm')) .then(() => I.acceptPopup()) - .then(() => I.see('Yes', '#result'))) + .then(() => I.see('Yes', '#result'))); it('should accept popup window (using default popup action type)', () => I.amOnPage('/form/popup') .then(() => I.click('Confirm')) .then(() => I.acceptPopup()) - .then(() => I.see('Yes', '#result'))) + .then(() => I.see('Yes', '#result'))); it('should cancel popup', () => I.amOnPage('/form/popup') .then(() => I.amCancellingPopups()) .then(() => I.click('Confirm')) .then(() => I.cancelPopup()) - .then(() => I.see('No', '#result'))) + .then(() => I.see('No', '#result'))); it('should check text in popup', () => I.amOnPage('/form/popup') .then(() => I.amCancellingPopups()) .then(() => I.click('Alert')) .then(() => I.seeInPopup('Really?')) - .then(() => I.cancelPopup())) + .then(() => I.cancelPopup())); it('should grab text from popup', () => I.amOnPage('/form/popup') .then(() => I.amCancellingPopups()) .then(() => I.click('Alert')) .then(() => I.grabPopupText()) - .then((text) => assert.equal(text, 'Really?'))) + .then((text) => assert.equal(text, 'Really?'))); it('should return null if no popup is visible (do not throw an error)', () => I.amOnPage('/form/popup') .then(() => I.grabPopupText()) - .then((text) => assert.equal(text, null))) - }) + .then((text) => assert.equal(text, null))); + }); describe('#seeNumberOfElements', () => { - it('should return 1 as count', () => I.amOnPage('/').then(() => I.seeNumberOfElements('#area1', 1))) - }) + it('should return 1 as count', () => I.amOnPage('/').then(() => I.seeNumberOfElements('#area1', 1))); + }); describe('#switchTo', () => { it('should switch reference to iframe content', () => I.amOnPage('/iframe') .then(() => I.switchTo('[name="content"]')) .then(() => I.see('Information')) - .then(() => I.see('Lots of valuable data here'))) + .then(() => I.see('Lots of valuable data here'))); it('should return error if iframe selector is invalid', () => I.amOnPage('/iframe') .then(() => I.switchTo('#invalidIframeSelector')) .catch((e) => { - e.should.be.instanceOf(Error) - e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath') - })) + e.should.be.instanceOf(Error); + e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath'); + })); it('should return error if iframe selector is not iframe', () => I.amOnPage('/iframe') .then(() => I.switchTo('h1')) .catch((e) => { - e.should.be.instanceOf(Error) - e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath') - })) + e.should.be.instanceOf(Error); + e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath'); + })); it('should return to parent frame given a null locator', () => I.amOnPage('/iframe') @@ -402,22 +402,22 @@ describe('Puppeteer', function () { .then(() => I.see('Information')) .then(() => I.see('Lots of valuable data here')) .then(() => I.switchTo(null)) - .then(() => I.see('Iframe test'))) - }) + .then(() => I.see('Iframe test'))); + }); describe('#seeInSource, #grabSource', () => { it('should check for text to be in HTML source', () => I.amOnPage('/') .then(() => I.seeInSource('TestEd Beta 2.0')) - .then(() => I.dontSeeInSource(' I.dontSeeInSource(' I.amOnPage('/') .then(() => I.grabSource()) .then((source) => assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved'), - )) - }) + )); + }); describe('#seeTitleEquals', () => { it('should check that title is equal to provided one', () => @@ -426,10 +426,10 @@ describe('Puppeteer', function () { .then(() => I.seeTitleEquals('TestEd Beta 2.')) .then(() => assert.equal(true, false, 'Throw an error because it should not get this far!')) .catch((e) => { - e.should.be.instanceOf(Error) - e.message.should.be.equal('expected web page title "TestEd Beta 2.0" to equal "TestEd Beta 2."') - })) - }) + e.should.be.instanceOf(Error); + e.message.should.be.equal('expected web page title "TestEd Beta 2.0" to equal "TestEd Beta 2."'); + })); + }); describe('#seeTextEquals', () => { it('should check text is equal to provided one', () => @@ -438,290 +438,290 @@ describe('Puppeteer', function () { .then(() => I.seeTextEquals('Welcome to test app', 'h1')) .then(() => assert.equal(true, false, 'Throw an error because it should not get this far!')) .catch((e) => { - e.should.be.instanceOf(Error) - e.message.should.be.equal('expected element h1 "Welcome to test app" to equal "Welcome to test app!"') - })) - }) + e.should.be.instanceOf(Error); + e.message.should.be.equal('expected element h1 "Welcome to test app" to equal "Welcome to test app!"'); + })); + }); describe('#_locateClickable', () => { it('should locate a button to click', () => I.amOnPage('/form/checkbox') .then(() => I._locateClickable('Submit')) .then((res) => { - res.length.should.be.equal(1) - })) + res.length.should.be.equal(1); + })); it('should not locate a non-existing checkbox using _locateClickable', () => I.amOnPage('/form/checkbox') .then(() => I._locateClickable('I disagree')) - .then((res) => res.length.should.be.equal(0))) - }) + .then((res) => res.length.should.be.equal(0))); + }); describe('#_locateCheckable', () => { it('should locate a checkbox', () => I.amOnPage('/form/checkbox') .then(() => I._locateCheckable('I Agree')) - .then((res) => res.should.be.ok)) - }) + .then((res) => res.should.be.ok)); + }); describe('#_locateFields', () => { it('should locate a field', () => I.amOnPage('/form/field') .then(() => I._locateFields('Name')) - .then((res) => res.length.should.be.equal(1))) + .then((res) => res.length.should.be.equal(1))); it('should not locate a non-existing field', () => I.amOnPage('/form/field') .then(() => I._locateFields('Mother-in-law')) - .then((res) => res.length.should.be.equal(0))) - }) + .then((res) => res.length.should.be.equal(0))); + }); describe('check fields: #seeInField, #seeCheckboxIsChecked, ...', () => { it('should throw error if field is not empty', () => I.amOnPage('/form/empty') .then(() => I.seeInField('#empty_input', 'Ayayay')) .catch((e) => { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.be.equal('expected fields by #empty_input to include "Ayayay"') - })) + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.be.equal('expected fields by #empty_input to include "Ayayay"'); + })); it('should check values in checkboxes', async () => { - await I.amOnPage('/form/field_values') - await I.dontSeeInField('checkbox[]', 'not seen one') - await I.seeInField('checkbox[]', 'see test one') - await I.dontSeeInField('checkbox[]', 'not seen two') - await I.seeInField('checkbox[]', 'see test two') - await I.dontSeeInField('checkbox[]', 'not seen three') - await I.seeInField('checkbox[]', 'see test three') - }) + await I.amOnPage('/form/field_values'); + await I.dontSeeInField('checkbox[]', 'not seen one'); + await I.seeInField('checkbox[]', 'see test one'); + await I.dontSeeInField('checkbox[]', 'not seen two'); + await I.seeInField('checkbox[]', 'see test two'); + await I.dontSeeInField('checkbox[]', 'not seen three'); + await I.seeInField('checkbox[]', 'see test three'); + }); it('should check values are the secret type in checkboxes', async () => { - await I.amOnPage('/form/field_values') - await I.dontSeeInField('checkbox[]', Secret.secret('not seen one')) - await I.seeInField('checkbox[]', Secret.secret('see test one')) - await I.dontSeeInField('checkbox[]', Secret.secret('not seen two')) - await I.seeInField('checkbox[]', Secret.secret('see test two')) - await I.dontSeeInField('checkbox[]', Secret.secret('not seen three')) - await I.seeInField('checkbox[]', Secret.secret('see test three')) - }) + await I.amOnPage('/form/field_values'); + await I.dontSeeInField('checkbox[]', Secret.secret('not seen one')); + await I.seeInField('checkbox[]', Secret.secret('see test one')); + await I.dontSeeInField('checkbox[]', Secret.secret('not seen two')); + await I.seeInField('checkbox[]', Secret.secret('see test two')); + await I.dontSeeInField('checkbox[]', Secret.secret('not seen three')); + await I.seeInField('checkbox[]', Secret.secret('see test three')); + }); it('should check values with boolean', async () => { - await I.amOnPage('/form/field_values') - await I.seeInField('checkbox1', true) - await I.dontSeeInField('checkbox1', false) - await I.seeInField('checkbox2', false) - await I.dontSeeInField('checkbox2', true) - await I.seeInField('radio2', true) - await I.dontSeeInField('radio2', false) - await I.seeInField('radio3', false) - await I.dontSeeInField('radio3', true) - }) + await I.amOnPage('/form/field_values'); + await I.seeInField('checkbox1', true); + await I.dontSeeInField('checkbox1', false); + await I.seeInField('checkbox2', false); + await I.dontSeeInField('checkbox2', true); + await I.seeInField('radio2', true); + await I.dontSeeInField('radio2', false); + await I.seeInField('radio3', false); + await I.dontSeeInField('radio3', true); + }); it('should check values in radio', async () => { - await I.amOnPage('/form/field_values') - await I.seeInField('radio1', 'see test one') - await I.dontSeeInField('radio1', 'not seen one') - await I.dontSeeInField('radio1', 'not seen two') - await I.dontSeeInField('radio1', 'not seen three') - }) + await I.amOnPage('/form/field_values'); + await I.seeInField('radio1', 'see test one'); + await I.dontSeeInField('radio1', 'not seen one'); + await I.dontSeeInField('radio1', 'not seen two'); + await I.dontSeeInField('radio1', 'not seen three'); + }); it('should check values in select', async () => { - await I.amOnPage('/form/field_values') - await I.seeInField('select1', 'see test one') - await I.dontSeeInField('select1', 'not seen one') - await I.dontSeeInField('select1', 'not seen two') - await I.dontSeeInField('select1', 'not seen three') - }) + await I.amOnPage('/form/field_values'); + await I.seeInField('select1', 'see test one'); + await I.dontSeeInField('select1', 'not seen one'); + await I.dontSeeInField('select1', 'not seen two'); + await I.dontSeeInField('select1', 'not seen three'); + }); it('should check for empty select field', async () => { - await I.amOnPage('/form/field_values') - await I.seeInField('select3', '') - }) + await I.amOnPage('/form/field_values'); + await I.seeInField('select3', ''); + }); it('should check for select multiple field', async () => { - await I.amOnPage('/form/field_values') - await I.dontSeeInField('select2', 'not seen one') - await I.seeInField('select2', 'see test one') - await I.dontSeeInField('select2', 'not seen two') - await I.seeInField('select2', 'see test two') - await I.dontSeeInField('select2', 'not seen three') - await I.seeInField('select2', 'see test three') - }) - }) + await I.amOnPage('/form/field_values'); + await I.dontSeeInField('select2', 'not seen one'); + await I.seeInField('select2', 'see test one'); + await I.dontSeeInField('select2', 'not seen two'); + await I.seeInField('select2', 'see test two'); + await I.dontSeeInField('select2', 'not seen three'); + await I.seeInField('select2', 'see test three'); + }); + }); describe('#pressKey, #pressKeyDown, #pressKeyUp', () => { it('should be able to send special keys to element', async () => { - await I.amOnPage('/form/field') - await I.appendField('Name', '-') + await I.amOnPage('/form/field'); + await I.appendField('Name', '-'); - await I.pressKey(['Right Shift', 'Home']) - await I.pressKey('Delete') + await I.pressKey(['Right Shift', 'Home']); + await I.pressKey('Delete'); // Sequence only executes up to first non-modifier key ('Digit1') - await I.pressKey(['SHIFT_RIGHT', 'Digit1', 'Digit4']) - await I.pressKey('1') - await I.pressKey('2') - await I.pressKey('3') - await I.pressKey('ArrowLeft') - await I.pressKey('Left Arrow') - await I.pressKey('arrow_left') - await I.pressKeyDown('Shift') - await I.pressKey('a') - await I.pressKey('KeyB') - await I.pressKeyUp('ShiftLeft') - await I.pressKey('C') - await I.seeInField('Name', '!ABC123') - }) + await I.pressKey(['SHIFT_RIGHT', 'Digit1', 'Digit4']); + await I.pressKey('1'); + await I.pressKey('2'); + await I.pressKey('3'); + await I.pressKey('ArrowLeft'); + await I.pressKey('Left Arrow'); + await I.pressKey('arrow_left'); + await I.pressKeyDown('Shift'); + await I.pressKey('a'); + await I.pressKey('KeyB'); + await I.pressKeyUp('ShiftLeft'); + await I.pressKey('C'); + await I.seeInField('Name', '!ABC123'); + }); it('should use modifier key based on operating system', async () => { - await I.amOnPage('/form/field') - await I.fillField('Name', 'value that is cleared using select all shortcut') + await I.amOnPage('/form/field'); + await I.fillField('Name', 'value that is cleared using select all shortcut'); - await I.pressKey(['ControlOrCommand', 'a']) - await I.pressKey('Backspace') - await I.dontSeeInField('Name', 'value that is cleared using select all shortcut') - }) + await I.pressKey(['ControlOrCommand', 'a']); + await I.pressKey('Backspace'); + await I.dontSeeInField('Name', 'value that is cleared using select all shortcut'); + }); it('should show correct numpad or punctuation key when Shift modifier is active', async () => { - await I.amOnPage('/form/field') - await I.fillField('Name', '') - - await I.pressKey(';') - await I.pressKey(['Shift', ';']) - await I.pressKey(['Shift', 'Semicolon']) - await I.pressKey('=') - await I.pressKey(['Shift', '=']) - await I.pressKey(['Shift', 'Equal']) - await I.pressKey('*') - await I.pressKey(['Shift', '*']) - await I.pressKey(['Shift', 'Multiply']) - await I.pressKey('+') - await I.pressKey(['Shift', '+']) - await I.pressKey(['Shift', 'Add']) - await I.pressKey(',') - await I.pressKey(['Shift', ',']) - await I.pressKey(['Shift', 'Comma']) - await I.pressKey(['Shift', 'NumpadComma']) - await I.pressKey(['Shift', 'Separator']) - await I.pressKey('-') - await I.pressKey(['Shift', '-']) - await I.pressKey(['Shift', 'Subtract']) - await I.pressKey('.') - await I.pressKey(['Shift', '.']) - await I.pressKey(['Shift', 'Decimal']) - await I.pressKey(['Shift', 'Period']) - await I.pressKey('/') - await I.pressKey(['Shift', '/']) - await I.pressKey(['Shift', 'Divide']) - await I.pressKey(['Shift', 'Slash']) - - await I.seeInField('Name', ';::=++***+++,<<<<-_-.>.>/?/?') - }) + await I.amOnPage('/form/field'); + await I.fillField('Name', ''); + + await I.pressKey(';'); + await I.pressKey(['Shift', ';']); + await I.pressKey(['Shift', 'Semicolon']); + await I.pressKey('='); + await I.pressKey(['Shift', '=']); + await I.pressKey(['Shift', 'Equal']); + await I.pressKey('*'); + await I.pressKey(['Shift', '*']); + await I.pressKey(['Shift', 'Multiply']); + await I.pressKey('+'); + await I.pressKey(['Shift', '+']); + await I.pressKey(['Shift', 'Add']); + await I.pressKey(','); + await I.pressKey(['Shift', ',']); + await I.pressKey(['Shift', 'Comma']); + await I.pressKey(['Shift', 'NumpadComma']); + await I.pressKey(['Shift', 'Separator']); + await I.pressKey('-'); + await I.pressKey(['Shift', '-']); + await I.pressKey(['Shift', 'Subtract']); + await I.pressKey('.'); + await I.pressKey(['Shift', '.']); + await I.pressKey(['Shift', 'Decimal']); + await I.pressKey(['Shift', 'Period']); + await I.pressKey('/'); + await I.pressKey(['Shift', '/']); + await I.pressKey(['Shift', 'Divide']); + await I.pressKey(['Shift', 'Slash']); + + await I.seeInField('Name', ';::=++***+++,<<<<-_-.>.>/?/?'); + }); it('should show correct number key when Shift modifier is active', async () => { - await I.amOnPage('/form/field') - await I.fillField('Name', '') - - await I.pressKey('0') - await I.pressKeyDown('Shift') - await I.pressKey('0') - await I.pressKey('Digit0') - await I.pressKey('Numpad0') - await I.pressKeyUp('Shift') - - await I.pressKey('1') - await I.pressKeyDown('Shift') - await I.pressKey('1') - await I.pressKey('Digit1') - await I.pressKey('Numpad1') - await I.pressKeyUp('Shift') - - await I.pressKey('2') - await I.pressKeyDown('Shift') - await I.pressKey('2') - await I.pressKey('Digit2') - await I.pressKey('Numpad2') - await I.pressKeyUp('Shift') - - await I.pressKey('3') - await I.pressKeyDown('Shift') - await I.pressKey('3') - await I.pressKey('Digit3') - await I.pressKey('Numpad3') - await I.pressKeyUp('Shift') - - await I.pressKey('4') - await I.pressKeyDown('Shift') - await I.pressKey('4') - await I.pressKey('Digit4') - await I.pressKey('Numpad4') - await I.pressKeyUp('Shift') - - await I.pressKey('5') - await I.pressKeyDown('Shift') - await I.pressKey('5') - await I.pressKey('Digit5') - await I.pressKey('Numpad5') - await I.pressKeyUp('Shift') - - await I.pressKey('6') - await I.pressKeyDown('Shift') - await I.pressKey('6') - await I.pressKey('Digit6') - await I.pressKey('Numpad6') - await I.pressKeyUp('Shift') - - await I.pressKey('7') - await I.pressKeyDown('Shift') - await I.pressKey('7') - await I.pressKey('Digit7') - await I.pressKey('Numpad7') - await I.pressKeyUp('Shift') - - await I.pressKey('8') - await I.pressKeyDown('Shift') - await I.pressKey('8') - await I.pressKey('Digit8') - await I.pressKey('Numpad8') - await I.pressKeyUp('Shift') - - await I.pressKey('9') - await I.pressKeyDown('Shift') - await I.pressKey('9') - await I.pressKey('Digit9') - await I.pressKey('Numpad9') - await I.pressKeyUp('Shift') - - await I.seeInField('Name', '0))01!!12@@23##34$$45%%56^^67&&78**89((9') - }) - }) + await I.amOnPage('/form/field'); + await I.fillField('Name', ''); + + await I.pressKey('0'); + await I.pressKeyDown('Shift'); + await I.pressKey('0'); + await I.pressKey('Digit0'); + await I.pressKey('Numpad0'); + await I.pressKeyUp('Shift'); + + await I.pressKey('1'); + await I.pressKeyDown('Shift'); + await I.pressKey('1'); + await I.pressKey('Digit1'); + await I.pressKey('Numpad1'); + await I.pressKeyUp('Shift'); + + await I.pressKey('2'); + await I.pressKeyDown('Shift'); + await I.pressKey('2'); + await I.pressKey('Digit2'); + await I.pressKey('Numpad2'); + await I.pressKeyUp('Shift'); + + await I.pressKey('3'); + await I.pressKeyDown('Shift'); + await I.pressKey('3'); + await I.pressKey('Digit3'); + await I.pressKey('Numpad3'); + await I.pressKeyUp('Shift'); + + await I.pressKey('4'); + await I.pressKeyDown('Shift'); + await I.pressKey('4'); + await I.pressKey('Digit4'); + await I.pressKey('Numpad4'); + await I.pressKeyUp('Shift'); + + await I.pressKey('5'); + await I.pressKeyDown('Shift'); + await I.pressKey('5'); + await I.pressKey('Digit5'); + await I.pressKey('Numpad5'); + await I.pressKeyUp('Shift'); + + await I.pressKey('6'); + await I.pressKeyDown('Shift'); + await I.pressKey('6'); + await I.pressKey('Digit6'); + await I.pressKey('Numpad6'); + await I.pressKeyUp('Shift'); + + await I.pressKey('7'); + await I.pressKeyDown('Shift'); + await I.pressKey('7'); + await I.pressKey('Digit7'); + await I.pressKey('Numpad7'); + await I.pressKeyUp('Shift'); + + await I.pressKey('8'); + await I.pressKeyDown('Shift'); + await I.pressKey('8'); + await I.pressKey('Digit8'); + await I.pressKey('Numpad8'); + await I.pressKeyUp('Shift'); + + await I.pressKey('9'); + await I.pressKeyDown('Shift'); + await I.pressKey('9'); + await I.pressKey('Digit9'); + await I.pressKey('Numpad9'); + await I.pressKeyUp('Shift'); + + await I.seeInField('Name', '0))01!!12@@23##34$$45%%56^^67&&78**89((9'); + }); + }); describe('#waitForEnabled', () => { it('should wait for input text field to be enabled', () => I.amOnPage('/form/wait_enabled') .then(() => I.waitForEnabled('#text', 2)) .then(() => I.fillField('#text', 'hello world')) - .then(() => I.seeInField('#text', 'hello world'))) + .then(() => I.seeInField('#text', 'hello world'))); it('should wait for input text field to be enabled by xpath', () => I.amOnPage('/form/wait_enabled') .then(() => I.waitForEnabled("//*[@name = 'test']", 2)) .then(() => I.fillField('#text', 'hello world')) - .then(() => I.seeInField('#text', 'hello world'))) + .then(() => I.seeInField('#text', 'hello world'))); it('should wait for a button to be enabled', () => I.amOnPage('/form/wait_enabled') .then(() => I.waitForEnabled('#text', 2)) .then(() => I.click('#button')) - .then(() => I.see('button was clicked', '#message'))) - }) + .then(() => I.see('button was clicked', '#message'))); + }); describe('#waitForText', () => { it('should wait for text after load body', async () => { - await I.amOnPage('/redirect_long') - await I.waitForText('Hi there and greetings!', 5) - }) - }) + await I.amOnPage('/redirect_long'); + await I.waitForText('Hi there and greetings!', 5); + }); + }); describe('#waitForValue', () => { it('should wait for expected value for given locator', () => @@ -729,81 +729,81 @@ describe('Puppeteer', function () { .then(() => I.waitForValue('//input[@name= "rus"]', 'Верно')) .then(() => I.waitForValue('//input[@name= "rus"]', 'Верно3', 0.1)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { e.message.should.include( 'element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec', - ) - })) + ); + })); it('should wait for expected value for given css locator', () => I.amOnPage('/form/wait_value') .then(() => I.seeInField('#text', 'Hamburg')) .then(() => I.waitForValue('#text', 'Brisbane', 2.5)) - .then(() => I.seeInField('#text', 'Brisbane'))) + .then(() => I.seeInField('#text', 'Brisbane'))); it('should wait for expected value for given xpath locator', () => I.amOnPage('/form/wait_value') .then(() => I.seeInField('#text', 'Hamburg')) .then(() => I.waitForValue('//input[@value = "Grüße aus Hamburg"]', 'Brisbane', 2.5)) - .then(() => I.seeInField('#text', 'Brisbane'))) + .then(() => I.seeInField('#text', 'Brisbane'))); it('should only wait for one of the matching elements to contain the value given xpath locator', () => I.amOnPage('/form/wait_value') .then(() => I.waitForValue('//input[@type = "text"]', 'Brisbane', 4)) .then(() => I.seeInField('#text', 'Brisbane')) - .then(() => I.seeInField('#text2', 'London'))) + .then(() => I.seeInField('#text2', 'London'))); it('should only wait for one of the matching elements to contain the value given css locator', () => I.amOnPage('/form/wait_value') .then(() => I.waitForValue('.inputbox', 'Brisbane', 4)) .then(() => I.seeInField('#text', 'Brisbane')) - .then(() => I.seeInField('#text2', 'London'))) - }) + .then(() => I.seeInField('#text2', 'London'))); + }); describe('#grabHTMLFrom', () => { it('should grab inner html from an element using xpath query', () => I.amOnPage('/') .then(() => I.grabHTMLFrom('//title')) - .then((html) => assert.equal(html, 'TestEd Beta 2.0'))) + .then((html) => assert.equal(html, 'TestEd Beta 2.0'))); it('should grab inner html from an element using id query', () => I.amOnPage('/') .then(() => I.grabHTMLFrom('#area1')) - .then((html) => assert.equal(html.trim(), ' Test Link '))) + .then((html) => assert.equal(html.trim(), ' Test Link '))); it('should grab inner html from multiple elements', () => I.amOnPage('/') .then(() => I.grabHTMLFromAll('//a')) - .then((html) => assert.equal(html.length, 5))) + .then((html) => assert.equal(html.length, 5))); it('should grab inner html from within an iframe', () => I.amOnPage('/iframe') .then(() => I.switchTo({ frame: 'iframe' })) .then(() => I.grabHTMLFrom('#new-tab')) - .then((html) => assert.equal(html.trim(), 'New tab'))) - }) + .then((html) => assert.equal(html.trim(), 'New tab'))); + }); describe('#grabBrowserLogs', () => { it('should grab browser logs', () => I.amOnPage('/') .then(() => I.executeScript(() => { - console.log('Test log entry') + console.log('Test log entry'); }), ) .then(() => I.grabBrowserLogs()) .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1) - assert.equal(matchingLogs.length, 1) - })) + const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1); + assert.equal(matchingLogs.length, 1); + })); it('should grab browser logs across pages', () => I.amOnPage('/') .then(() => I.executeScript(() => { - console.log('Test log entry 1') + console.log('Test log entry 1'); }), ) .then(() => I.openNewTab()) @@ -811,22 +811,22 @@ describe('Puppeteer', function () { .then(() => I.amOnPage('/info')) .then(() => I.executeScript(() => { - console.log('Test log entry 2') + console.log('Test log entry 2'); }), ) .then(() => I.grabBrowserLogs()) .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1) - assert.equal(matchingLogs.length, 2) - })) - }) + const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1); + assert.equal(matchingLogs.length, 2); + })); + }); describe('#dragAndDrop', () => { it('Drag item from source to target (no iframe) @dragNdrop', () => I.amOnPage('http://jqueryui.com/resources/demos/droppable/default.html') .then(() => I.seeElementInDOM('#draggable')) .then(() => I.dragAndDrop('#draggable', '#droppable')) - .then(() => I.see('Dropped'))) + .then(() => I.see('Dropped'))); it('Drag and drop from within an iframe', () => I.amOnPage('http://jqueryui.com/droppable') @@ -834,8 +834,8 @@ describe('Puppeteer', function () { .then(() => I.switchTo('//iframe[@class="demo-frame"]')) .then(() => I.seeElementInDOM('#draggable')) .then(() => I.dragAndDrop('#draggable', '#droppable')) - .then(() => I.see('Dropped'))) - }) + .then(() => I.see('Dropped'))); + }); describe('#switchTo frame', () => { it('should switch to frame using name', () => @@ -844,7 +844,7 @@ describe('Puppeteer', function () { .then(() => I.dontSee('Information', 'h1')) .then(() => I.switchTo('iframe')) .then(() => I.see('Information', 'h1')) - .then(() => I.dontSee('Iframe test', 'h1'))) + .then(() => I.dontSee('Iframe test', 'h1'))); it('should switch to root frame', () => I.amOnPage('/iframe') @@ -854,7 +854,7 @@ describe('Puppeteer', function () { .then(() => I.see('Information', 'h1')) .then(() => I.dontSee('Iframe test', 'h1')) .then(() => I.switchTo()) - .then(() => I.see('Iframe test', 'h1'))) + .then(() => I.see('Iframe test', 'h1'))); it('should switch to frame using frame number', () => I.amOnPage('/iframe') @@ -862,205 +862,205 @@ describe('Puppeteer', function () { .then(() => I.dontSee('Information', 'h1')) .then(() => I.switchTo(0)) .then(() => I.see('Information', 'h1')) - .then(() => I.dontSee('Iframe test', 'h1'))) - }) + .then(() => I.dontSee('Iframe test', 'h1'))); + }); describe('#dragSlider', () => { it('should drag scrubber to given position', async () => { - await I.amOnPage('/form/page_slider') - await I.seeElementInDOM('#slidecontainer input') - const before = await I.grabValueFrom('#slidecontainer input') - await I.dragSlider('#slidecontainer input', 20) - const after = await I.grabValueFrom('#slidecontainer input') - assert.notEqual(before, after) - }) - }) + await I.amOnPage('/form/page_slider'); + await I.seeElementInDOM('#slidecontainer input'); + const before = await I.grabValueFrom('#slidecontainer input'); + await I.dragSlider('#slidecontainer input', 20); + const after = await I.grabValueFrom('#slidecontainer input'); + assert.notEqual(before, after); + }); + }); describe('#uncheckOption', () => { it('should uncheck option that is currently checked', async () => { - await I.amOnPage('/info') - await I.uncheckOption('interesting') - await I.dontSeeCheckboxIsChecked('interesting') - }) + await I.amOnPage('/info'); + await I.uncheckOption('interesting'); + await I.dontSeeCheckboxIsChecked('interesting'); + }); it('should NOT uncheck option that is NOT currently checked', async () => { - await I.amOnPage('/info') - await I.uncheckOption('interesting') + await I.amOnPage('/info'); + await I.uncheckOption('interesting'); // Unchecking again should not affect the current 'unchecked' status - await I.uncheckOption('interesting') - await I.dontSeeCheckboxIsChecked('interesting') - }) - }) + await I.uncheckOption('interesting'); + await I.dontSeeCheckboxIsChecked('interesting'); + }); + }); describe('#grabElementBoundingRect', () => { it('should get the element bounding rectangle', async () => { - await I.amOnPage('/form/hidden') - const size = await I.grabElementBoundingRect('input[type=submit]') - expect(size.x).is.greaterThan(0) - expect(size.y).is.greaterThan(0) - expect(size.width).is.greaterThan(0) - expect(size.height).is.greaterThan(0) - }) + await I.amOnPage('/form/hidden'); + const size = await I.grabElementBoundingRect('input[type=submit]'); + expect(size.x).is.greaterThan(0); + expect(size.y).is.greaterThan(0); + expect(size.width).is.greaterThan(0); + expect(size.height).is.greaterThan(0); + }); it('should get the element width', async () => { - await I.amOnPage('/form/hidden') - const width = await I.grabElementBoundingRect('input[type=submit]', 'width') - expect(width).is.greaterThan(0) - }) + await I.amOnPage('/form/hidden'); + const width = await I.grabElementBoundingRect('input[type=submit]', 'width'); + expect(width).is.greaterThan(0); + }); it('should get the element height', async () => { - await I.amOnPage('/form/hidden') - const height = await I.grabElementBoundingRect('input[type=submit]', 'height') - expect(height).is.greaterThan(0) - }) - }) + await I.amOnPage('/form/hidden'); + const height = await I.grabElementBoundingRect('input[type=submit]', 'height'); + expect(height).is.greaterThan(0); + }); + }); describe('#waitForClickable', () => { it('should wait for clickable', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.waitForClickable({ css: 'input#text' }) - }) + await I.amOnPage('/form/wait_for_clickable'); + await I.waitForClickable({ css: 'input#text' }); + }); it('should wait for clickable by XPath', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.waitForClickable({ xpath: './/input[@id="text"]' }) - }) + await I.amOnPage('/form/wait_for_clickable'); + await I.waitForClickable({ xpath: './/input[@id="text"]' }); + }); it('should fail for disabled element', async () => { - await I.amOnPage('/form/wait_for_clickable') + await I.amOnPage('/form/wait_for_clickable'); await I.waitForClickable({ css: '#button' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element {css: #button} still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element {css: #button} still not clickable after 0.1 sec'); + }); + }); it('should fail for disabled element by XPath', async () => { - await I.amOnPage('/form/wait_for_clickable') + await I.amOnPage('/form/wait_for_clickable'); await I.waitForClickable({ xpath: './/button[@id="button"]' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element {xpath: .//button[@id="button"]} still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element {xpath: .//button[@id="button"]} still not clickable after 0.1 sec'); + }); + }); it('should fail for element not in viewport by top', async () => { - await I.amOnPage('/form/wait_for_clickable') + await I.amOnPage('/form/wait_for_clickable'); await I.waitForClickable({ css: '#notInViewportTop' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element {css: #notInViewportTop} still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element {css: #notInViewportTop} still not clickable after 0.1 sec'); + }); + }); it('should fail for element not in viewport by bottom', async () => { - await I.amOnPage('/form/wait_for_clickable') + await I.amOnPage('/form/wait_for_clickable'); await I.waitForClickable({ css: '#notInViewportBottom' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element {css: #notInViewportBottom} still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element {css: #notInViewportBottom} still not clickable after 0.1 sec'); + }); + }); it('should fail for element not in viewport by left', async () => { - await I.amOnPage('/form/wait_for_clickable') + await I.amOnPage('/form/wait_for_clickable'); await I.waitForClickable({ css: '#notInViewportLeft' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element {css: #notInViewportLeft} still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element {css: #notInViewportLeft} still not clickable after 0.1 sec'); + }); + }); it('should fail for element not in viewport by right', async () => { - await I.amOnPage('/form/wait_for_clickable') + await I.amOnPage('/form/wait_for_clickable'); await I.waitForClickable({ css: '#notInViewportRight' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element {css: #notInViewportRight} still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element {css: #notInViewportRight} still not clickable after 0.1 sec'); + }); + }); it('should fail for overlapping element', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.waitForClickable({ css: '#div2_button' }, 0.1) + await I.amOnPage('/form/wait_for_clickable'); + await I.waitForClickable({ css: '#div2_button' }, 0.1); await I.waitForClickable({ css: '#div1_button' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element {css: #div1_button} still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element {css: #div1_button} still not clickable after 0.1 sec'); + }); + }); it('should pass if element change class', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.click('button_save') - await I.waitForClickable('//button[@name="button_publish"]') - }) + await I.amOnPage('/form/wait_for_clickable'); + await I.click('button_save'); + await I.waitForClickable('//button[@name="button_publish"]'); + }); xit('should fail if element change class and not clickable', async () => { - await I.amOnPage('/form/wait_for_clickable') - await I.click('button_save') + await I.amOnPage('/form/wait_for_clickable'); + await I.click('button_save'); await I.waitForClickable('//button[@name="button_publish"]', 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element //button[@name="button_publish"] still not clickable after 0.1 sec') - }) - }) - }) + e.message.should.include('element //button[@name="button_publish"] still not clickable after 0.1 sec'); + }); + }); + }); describe('#usePuppeteerTo', () => { it('should return title', async () => { - await I.amOnPage('/') + await I.amOnPage('/'); const title = await I.usePuppeteerTo('test', async ({ page }) => { - return page.title() - }) - assert.equal('TestEd Beta 2.0', title) - }) - }) + return page.title(); + }); + assert.equal('TestEd Beta 2.0', title); + }); + }); describe('#mockRoute, #stopMockingRoute', () => { it('should mock a route', async () => { - await I.amOnPage('/form/fetch_call') + await I.amOnPage('/form/fetch_call'); await I.mockRoute('https://reqres.in/api/comments/1', (request) => { request.respond({ status: 200, headers: { 'Access-Control-Allow-Origin': '*' }, contentType: 'application/json', body: '{"name": "this was mocked" }', - }) - }) - await I.click('GET COMMENTS') - await I.see('this was mocked') - await I.stopMockingRoute('https://reqres.in/api/comments/1') - await I.click('GET COMMENTS') - await I.see('data') - await I.dontSee('this was mocked') - }) - }) -}) - -let remoteBrowser + }); + }); + await I.click('GET COMMENTS'); + await I.see('this was mocked'); + await I.stopMockingRoute('https://reqres.in/api/comments/1'); + await I.click('GET COMMENTS'); + await I.see('data'); + await I.dontSee('this was mocked'); + }); + }); +}); + +let remoteBrowser; async function createRemoteBrowser() { remoteBrowser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'], headless: true, - }) - return remoteBrowser + }); + return remoteBrowser; } const helperConfig = { @@ -1076,131 +1076,131 @@ const helperConfig = { waitForTimeout: 5000, waitForAction: 500, windowSize: '500x700', -} +}; describe('Puppeteer (remote browser)', function () { - this.timeout(35000) - this.retries(1) + this.timeout(35000); + this.retries(1); before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - I = new Puppeteer(helperConfig) - I._init() - return I._beforeSuite() - }) + global.codecept_dir = path.join(__dirname, '/../data'); + I = new Puppeteer(helperConfig); + I._init(); + return I._beforeSuite(); + }); beforeEach(async () => { // Mimick remote session by creating another browser instance - await createRemoteBrowser() + await createRemoteBrowser(); // Set websocket endpoint to other browser instance - helperConfig.chrome.browserWSEndpoint = await remoteBrowser.wsEndpoint() - I._setConfig(helperConfig) + helperConfig.chrome.browserWSEndpoint = await remoteBrowser.wsEndpoint(); + I._setConfig(helperConfig); - return I._before() - }) + return I._before(); + }); afterEach(() => { return I._after().then(() => { - remoteBrowser && remoteBrowser.close() - }) - }) + remoteBrowser && remoteBrowser.close(); + }); + }); describe('#_startBrowser', () => { it('should throw an exception when endpoint is unreachable', async () => { - helperConfig.chrome.browserWSEndpoint = 'ws://unreachable/' - I._setConfig(helperConfig) + helperConfig.chrome.browserWSEndpoint = 'ws://unreachable/'; + I._setConfig(helperConfig); try { - await I._startBrowser() - throw Error('It should never get this far') + await I._startBrowser(); + throw Error('It should never get this far'); } catch (e) { e.message.should.include( 'Cannot connect to websocket endpoint.\n\nPlease make sure remote browser is running and accessible.', - ) + ); } - }) + }); xit('should clear any prior existing pages on remote browser', async () => { - const remotePages = await remoteBrowser.pages() - assert.equal(remotePages.length, 1) + const remotePages = await remoteBrowser.pages(); + assert.equal(remotePages.length, 1); for (let p = 1; p < 5; p++) { - await remoteBrowser.newPage() + await remoteBrowser.newPage(); } - const existingPages = await remoteBrowser.pages() - assert.equal(existingPages.length, 5) + const existingPages = await remoteBrowser.pages(); + assert.equal(existingPages.length, 5); - await I._startBrowser() + await I._startBrowser(); // Session was cleared - let currentPages = await remoteBrowser.pages() - assert.equal(currentPages.length, 1) + let currentPages = await remoteBrowser.pages(); + assert.equal(currentPages.length, 1); - let numPages = await I.grabNumberOfOpenTabs() - assert.equal(numPages, 1) + let numPages = await I.grabNumberOfOpenTabs(); + assert.equal(numPages, 1); - await I.openNewTab() + await I.openNewTab(); - numPages = await I.grabNumberOfOpenTabs() - assert.equal(numPages, 2) + numPages = await I.grabNumberOfOpenTabs(); + assert.equal(numPages, 2); - await I._stopBrowser() + await I._stopBrowser(); - currentPages = await remoteBrowser.pages() - assert.equal(currentPages.length, 0) - }) - }) -}) + currentPages = await remoteBrowser.pages(); + assert.equal(currentPages.length, 0); + }); + }); +}); describe('Puppeteer - Trace', () => { - const test = { title: 'a failed test', artifacts: {} } + const test = { title: 'a failed test', artifacts: {} }; before(() => { - global.codecept_dir = path.join(__dirname, '/../data') - global.output_dir = path.join(`${__dirname}/../data/output`) + global.codecept_dir = path.join(__dirname, '/../data'); + global.output_dir = path.join(`${__dirname}/../data/output`); I = new Puppeteer({ url: siteUrl, windowSize: '500x700', show: false, trace: true, - }) - I._init() - return I._beforeSuite() - }) + }); + I._init(); + return I._beforeSuite(); + }); beforeEach(async () => { webApiTests.init({ I, siteUrl, - }) - deleteDir(path.join(global.output_dir, 'trace')) + }); + deleteDir(path.join(global.output_dir, 'trace')); return I._before(test).then(() => { - page = I.page - browser = I.browser - }) - }) + page = I.page; + browser = I.browser; + }); + }); afterEach(async () => { - return I._after() - }) + return I._after(); + }); it('checks that trace is recorded', async () => { - await I.amOnPage('/') - await I.dontSee('this should be an error') - await I.click('More info') - await I.dontSee('this should be an error') - await I._failed(test) - assert(test.artifacts) - expect(Object.keys(test.artifacts)).to.include('trace') - - assert.ok(fs.existsSync(test.artifacts.trace)) - expect(test.artifacts.trace).to.include(path.join(global.output_dir, 'trace')) - }) + await I.amOnPage('/'); + await I.dontSee('this should be an error'); + await I.click('More info'); + await I.dontSee('this should be an error'); + await I._failed(test); + assert(test.artifacts); + expect(Object.keys(test.artifacts)).to.include('trace'); + + assert.ok(fs.existsSync(test.artifacts.trace)); + expect(test.artifacts.trace).to.include(path.join(global.output_dir, 'trace')); + }); describe('#grabWebElements', () => { it('should return an array of WebElement', async () => { - await I.amOnPage('/form/focus_blur_elements') - - const webElements = await I.grabWebElements('#button') - assert.include(webElements[0].constructor.name, 'CdpElementHandle') - assert.isAbove(webElements.length, 0) - }) - }) -}) + await I.amOnPage('/form/focus_blur_elements'); + + const webElements = await I.grabWebElements('#button'); + assert.include(webElements[0].constructor.name, 'CdpElementHandle'); + assert.isAbove(webElements.length, 0); + }); + }); +}); diff --git a/test/helper/WebDriver.noSeleniumServer_test.js b/test/helper/WebDriver.noSeleniumServer_test.js index 23ad9c0b0..992d40a3c 100644 --- a/test/helper/WebDriver.noSeleniumServer_test.js +++ b/test/helper/WebDriver.noSeleniumServer_test.js @@ -1,29 +1,29 @@ -const assert = require('assert') +const assert = require('assert'); -const chai = require('chai') +const chai = require('chai'); -const expect = chai.expect +const expect = chai.expect; -const path = require('path') -const fs = require('fs') +const path = require('path'); +const fs = require('fs'); -const TestHelper = require('../support/TestHelper') -const WebDriver = require('../../lib/helper/WebDriver') -const AssertionFailedError = require('../../lib/assert/error') -const Secret = require('../../lib/secret') -global.codeceptjs = require('../../lib') +const TestHelper = require('../support/TestHelper'); +const WebDriver = require('../../lib/helper/WebDriver'); +const AssertionFailedError = require('../../lib/assert/error'); +const Secret = require('../../lib/secret'); +global.codeceptjs = require('../../lib'); -const siteUrl = TestHelper.siteUrl() -let wd -const browserVersion = 'stable' +const siteUrl = TestHelper.siteUrl(); +let wd; +const browserVersion = 'stable'; describe('WebDriver - No Selenium server started', function () { - this.retries(1) - this.timeout(35000) + this.retries(1); + this.timeout(35000); before(() => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); try { - fs.unlinkSync(dataFile) + fs.unlinkSync(dataFile); } catch (err) { // continue regardless of error } @@ -43,464 +43,464 @@ describe('WebDriver - No Selenium server started', function () { customLocatorStrategies: { customSelector: (selector) => ({ 'element-6066-11e4-a52e-4f735466cecf': `${selector}-foobar` }), }, - }) - }) + }); + }); beforeEach(async () => { - this.wdBrowser = await wd._before() - return this.wdBrowser - }) + this.wdBrowser = await wd._before(); + return this.wdBrowser; + }); - afterEach(async () => wd._after()) + afterEach(async () => wd._after()); describe('customLocatorStrategies', () => { it('should include the custom strategy', async () => { - expect(wd.customLocatorStrategies.customSelector).to.not.be.undefined - }) + expect(wd.customLocatorStrategies.customSelector).to.not.be.undefined; + }); it('should be added to the browser locator strategies', async () => { - expect(this.wdBrowser.addLocatorStrategy).to.not.be.undefined - }) + expect(this.wdBrowser.addLocatorStrategy).to.not.be.undefined; + }); it('throws on invalid custom selector', async () => { try { - await wd.waitForEnabled({ madeUpSelector: '#text' }, 2) + await wd.waitForEnabled({ madeUpSelector: '#text' }, 2); } catch (e) { - expect(e.message).to.include('Please define "customLocatorStrategies"') + expect(e.message).to.include('Please define "customLocatorStrategies"'); } - }) - }) + }); + }); describe('open page : #amOnPage', () => { it('should open main page of configured site', async () => { - await wd.amOnPage('/') - const url = await wd.grabCurrentUrl() - url.should.eql(`${siteUrl}/`) - }) + await wd.amOnPage('/'); + const url = await wd.grabCurrentUrl(); + url.should.eql(`${siteUrl}/`); + }); it('should open any page of configured site', async () => { - await wd.amOnPage('/info') - const url = await wd.grabCurrentUrl() - url.should.eql(`${siteUrl}/info`) - }) + await wd.amOnPage('/info'); + const url = await wd.grabCurrentUrl(); + url.should.eql(`${siteUrl}/info`); + }); it('should open absolute url', async () => { - await wd.amOnPage(siteUrl) - const url = await wd.grabCurrentUrl() - url.should.eql(`${siteUrl}/`) - }) - }) + await wd.amOnPage(siteUrl); + const url = await wd.grabCurrentUrl(); + url.should.eql(`${siteUrl}/`); + }); + }); describe('see text : #see', () => { it('should fail when text is not on site', async () => { - await wd.amOnPage('/') + await wd.amOnPage('/'); try { - await wd.see('Something incredible!') + await wd.see('Something incredible!'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('web page') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('web page'); } try { - await wd.dontSee('Welcome') + await wd.dontSee('Welcome'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('web page') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('web page'); } - }) - }) + }); + }); describe.skip('check fields: #seeInField, #seeCheckboxIsChecked, ...', () => { it('should throw error if field is not empty', async () => { - await wd.amOnPage('/form/empty') + await wd.amOnPage('/form/empty'); try { - await wd.seeInField('#empty_input', 'Ayayay') + await wd.seeInField('#empty_input', 'Ayayay'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.be.equal('expected fields by #empty_input to include "Ayayay"') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.be.equal('expected fields by #empty_input to include "Ayayay"'); } - }) + }); it('should check values in checkboxes', async () => { - await wd.amOnPage('/form/field_values') - await wd.dontSeeInField('checkbox[]', 'not seen one') - await wd.seeInField('checkbox[]', 'see test one') - await wd.dontSeeInField('checkbox[]', 'not seen two') - await wd.seeInField('checkbox[]', 'see test two') - await wd.dontSeeInField('checkbox[]', 'not seen three') - await wd.seeInField('checkbox[]', 'see test three') - }) + await wd.amOnPage('/form/field_values'); + await wd.dontSeeInField('checkbox[]', 'not seen one'); + await wd.seeInField('checkbox[]', 'see test one'); + await wd.dontSeeInField('checkbox[]', 'not seen two'); + await wd.seeInField('checkbox[]', 'see test two'); + await wd.dontSeeInField('checkbox[]', 'not seen three'); + await wd.seeInField('checkbox[]', 'see test three'); + }); it('should check values are the secret type in checkboxes', async () => { - await wd.amOnPage('/form/field_values') - await wd.dontSeeInField('checkbox[]', Secret.secret('not seen one')) - await wd.seeInField('checkbox[]', Secret.secret('see test one')) - await wd.dontSeeInField('checkbox[]', Secret.secret('not seen two')) - await wd.seeInField('checkbox[]', Secret.secret('see test two')) - await wd.dontSeeInField('checkbox[]', Secret.secret('not seen three')) - await wd.seeInField('checkbox[]', Secret.secret('see test three')) - }) + await wd.amOnPage('/form/field_values'); + await wd.dontSeeInField('checkbox[]', Secret.secret('not seen one')); + await wd.seeInField('checkbox[]', Secret.secret('see test one')); + await wd.dontSeeInField('checkbox[]', Secret.secret('not seen two')); + await wd.seeInField('checkbox[]', Secret.secret('see test two')); + await wd.dontSeeInField('checkbox[]', Secret.secret('not seen three')); + await wd.seeInField('checkbox[]', Secret.secret('see test three')); + }); it('should check values with boolean', async () => { - await wd.amOnPage('/form/field_values') - await wd.seeInField('checkbox1', true) - await wd.dontSeeInField('checkbox1', false) - await wd.seeInField('checkbox2', false) - await wd.dontSeeInField('checkbox2', true) - await wd.seeInField('radio2', true) - await wd.dontSeeInField('radio2', false) - await wd.seeInField('radio3', false) - await wd.dontSeeInField('radio3', true) - }) + await wd.amOnPage('/form/field_values'); + await wd.seeInField('checkbox1', true); + await wd.dontSeeInField('checkbox1', false); + await wd.seeInField('checkbox2', false); + await wd.dontSeeInField('checkbox2', true); + await wd.seeInField('radio2', true); + await wd.dontSeeInField('radio2', false); + await wd.seeInField('radio3', false); + await wd.dontSeeInField('radio3', true); + }); it('should check values in radio', async () => { - await wd.amOnPage('/form/field_values') - await wd.seeInField('radio1', 'see test one') - await wd.dontSeeInField('radio1', 'not seen one') - await wd.dontSeeInField('radio1', 'not seen two') - await wd.dontSeeInField('radio1', 'not seen three') - }) + await wd.amOnPage('/form/field_values'); + await wd.seeInField('radio1', 'see test one'); + await wd.dontSeeInField('radio1', 'not seen one'); + await wd.dontSeeInField('radio1', 'not seen two'); + await wd.dontSeeInField('radio1', 'not seen three'); + }); it('should check values in select', async () => { - await wd.amOnPage('/form/field_values') - await wd.seeInField('select1', 'see test one') - await wd.dontSeeInField('select1', 'not seen one') - await wd.dontSeeInField('select1', 'not seen two') - await wd.dontSeeInField('select1', 'not seen three') - }) + await wd.amOnPage('/form/field_values'); + await wd.seeInField('select1', 'see test one'); + await wd.dontSeeInField('select1', 'not seen one'); + await wd.dontSeeInField('select1', 'not seen two'); + await wd.dontSeeInField('select1', 'not seen three'); + }); it('should check for empty select field', async () => { - await wd.amOnPage('/form/field_values') - await wd.seeInField('select3', '') - }) + await wd.amOnPage('/form/field_values'); + await wd.seeInField('select3', ''); + }); it('should check for select multiple field', async () => { - await wd.amOnPage('/form/field_values') - await wd.dontSeeInField('select2', 'not seen one') - await wd.seeInField('select2', 'see test one') - await wd.dontSeeInField('select2', 'not seen two') - await wd.seeInField('select2', 'see test two') - await wd.dontSeeInField('select2', 'not seen three') - await wd.seeInField('select2', 'see test three') - }) + await wd.amOnPage('/form/field_values'); + await wd.dontSeeInField('select2', 'not seen one'); + await wd.seeInField('select2', 'see test one'); + await wd.dontSeeInField('select2', 'not seen two'); + await wd.seeInField('select2', 'see test two'); + await wd.dontSeeInField('select2', 'not seen three'); + await wd.seeInField('select2', 'see test three'); + }); it('should return error when element has no value attribute', async () => { - await wd.amOnPage('https://codecept.io/quickstart') + await wd.amOnPage('https://codecept.io/quickstart'); try { - await wd.seeInField('#search_input_react', 'WebDriver1') + await wd.seeInField('#search_input_react', 'WebDriver1'); } catch (e) { - e.should.be.instanceOf(Error) + e.should.be.instanceOf(Error); } - }) - }) + }); + }); describe('Force Right Click: #forceRightClick', () => { it('it should forceRightClick', async () => { - await wd.amOnPage('/form/rightclick') - await wd.dontSee('right clicked') - await wd.forceRightClick('Lorem Ipsum') - await wd.see('right clicked') - }) + await wd.amOnPage('/form/rightclick'); + await wd.dontSee('right clicked'); + await wd.forceRightClick('Lorem Ipsum'); + await wd.see('right clicked'); + }); it('it should forceRightClick by locator', async () => { - await wd.amOnPage('/form/rightclick') - await wd.dontSee('right clicked') - await wd.forceRightClick('.context a') - await wd.see('right clicked') - }) + await wd.amOnPage('/form/rightclick'); + await wd.dontSee('right clicked'); + await wd.forceRightClick('.context a'); + await wd.see('right clicked'); + }); it('it should forceRightClick by locator and context', async () => { - await wd.amOnPage('/form/rightclick') - await wd.dontSee('right clicked') - await wd.forceRightClick('Lorem Ipsum', '.context') - await wd.see('right clicked') - }) - }) + await wd.amOnPage('/form/rightclick'); + await wd.dontSee('right clicked'); + await wd.forceRightClick('Lorem Ipsum', '.context'); + await wd.see('right clicked'); + }); + }); describe.skip('#pressKey, #pressKeyDown, #pressKeyUp', () => { it('should be able to send special keys to element', async () => { - await wd.amOnPage('/form/field') - await wd.appendField('Name', '-') + await wd.amOnPage('/form/field'); + await wd.appendField('Name', '-'); - await wd.pressKey(['Right Shift', 'Home']) - await wd.pressKey('Delete') + await wd.pressKey(['Right Shift', 'Home']); + await wd.pressKey('Delete'); // Sequence only executes up to first non-modifier key ('Digit1') - await wd.pressKey(['SHIFT_RIGHT', 'Digit1', 'Digit4']) - await wd.pressKey('1') - await wd.pressKey('2') - await wd.pressKey('3') - await wd.pressKey('ArrowLeft') - await wd.pressKey('Left Arrow') - await wd.pressKey('arrow_left') - await wd.pressKeyDown('Shift') - await wd.pressKey('a') - await wd.pressKey('KeyB') - await wd.pressKeyUp('ShiftLeft') - await wd.pressKey('C') - await wd.seeInField('Name', '!ABC123') - }) + await wd.pressKey(['SHIFT_RIGHT', 'Digit1', 'Digit4']); + await wd.pressKey('1'); + await wd.pressKey('2'); + await wd.pressKey('3'); + await wd.pressKey('ArrowLeft'); + await wd.pressKey('Left Arrow'); + await wd.pressKey('arrow_left'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('a'); + await wd.pressKey('KeyB'); + await wd.pressKeyUp('ShiftLeft'); + await wd.pressKey('C'); + await wd.seeInField('Name', '!ABC123'); + }); it('should use modifier key based on operating system', async () => { - await wd.amOnPage('/form/field') - await wd.fillField('Name', 'value that is cleared using select all shortcut') + await wd.amOnPage('/form/field'); + await wd.fillField('Name', 'value that is cleared using select all shortcut'); - await wd.pressKey(['CommandOrControl', 'A']) - await wd.pressKey('Backspace') - await wd.dontSeeInField('Name', 'value that is cleared using select all shortcut') - }) + await wd.pressKey(['CommandOrControl', 'A']); + await wd.pressKey('Backspace'); + await wd.dontSeeInField('Name', 'value that is cleared using select all shortcut'); + }); it('should show correct numpad or punctuation key when Shift modifier is active', async () => { - await wd.amOnPage('/form/field') - await wd.fillField('Name', '') - - await wd.pressKey(';') - await wd.pressKey(['Shift', ';']) - await wd.pressKey(['Shift', 'Semicolon']) - await wd.pressKey('=') - await wd.pressKey(['Shift', '=']) - await wd.pressKey(['Shift', 'Equal']) - await wd.pressKey('*') - await wd.pressKey(['Shift', '*']) - await wd.pressKey(['Shift', 'Multiply']) - await wd.pressKey('+') - await wd.pressKey(['Shift', '+']) - await wd.pressKey(['Shift', 'Add']) - await wd.pressKey(',') - await wd.pressKey(['Shift', ',']) - await wd.pressKey(['Shift', 'Comma']) - await wd.pressKey(['Shift', 'NumpadComma']) - await wd.pressKey(['Shift', 'Separator']) - await wd.pressKey('-') - await wd.pressKey(['Shift', '-']) - await wd.pressKey(['Shift', 'Subtract']) - await wd.pressKey('.') - await wd.pressKey(['Shift', '.']) - await wd.pressKey(['Shift', 'Decimal']) - await wd.pressKey(['Shift', 'Period']) - await wd.pressKey('/') - await wd.pressKey(['Shift', '/']) - await wd.pressKey(['Shift', 'Divide']) - await wd.pressKey(['Shift', 'Slash']) - - await wd.seeInField('Name', ';::=++***+++,<<<<-_-.>.>/?/?') - }) + await wd.amOnPage('/form/field'); + await wd.fillField('Name', ''); + + await wd.pressKey(';'); + await wd.pressKey(['Shift', ';']); + await wd.pressKey(['Shift', 'Semicolon']); + await wd.pressKey('='); + await wd.pressKey(['Shift', '=']); + await wd.pressKey(['Shift', 'Equal']); + await wd.pressKey('*'); + await wd.pressKey(['Shift', '*']); + await wd.pressKey(['Shift', 'Multiply']); + await wd.pressKey('+'); + await wd.pressKey(['Shift', '+']); + await wd.pressKey(['Shift', 'Add']); + await wd.pressKey(','); + await wd.pressKey(['Shift', ',']); + await wd.pressKey(['Shift', 'Comma']); + await wd.pressKey(['Shift', 'NumpadComma']); + await wd.pressKey(['Shift', 'Separator']); + await wd.pressKey('-'); + await wd.pressKey(['Shift', '-']); + await wd.pressKey(['Shift', 'Subtract']); + await wd.pressKey('.'); + await wd.pressKey(['Shift', '.']); + await wd.pressKey(['Shift', 'Decimal']); + await wd.pressKey(['Shift', 'Period']); + await wd.pressKey('/'); + await wd.pressKey(['Shift', '/']); + await wd.pressKey(['Shift', 'Divide']); + await wd.pressKey(['Shift', 'Slash']); + + await wd.seeInField('Name', ';::=++***+++,<<<<-_-.>.>/?/?'); + }); it('should show correct number key when Shift modifier is active', async () => { - await wd.amOnPage('/form/field') - await wd.fillField('Name', '') - - await wd.pressKey('0') - await wd.pressKeyDown('Shift') - await wd.pressKey('0') - await wd.pressKey('Digit0') - await wd.pressKeyUp('Shift') - - await wd.pressKey('1') - await wd.pressKeyDown('Shift') - await wd.pressKey('1') - await wd.pressKey('Digit1') - await wd.pressKeyUp('Shift') - - await wd.pressKey('2') - await wd.pressKeyDown('Shift') - await wd.pressKey('2') - await wd.pressKey('Digit2') - await wd.pressKeyUp('Shift') - - await wd.pressKey('3') - await wd.pressKeyDown('Shift') - await wd.pressKey('3') - await wd.pressKey('Digit3') - await wd.pressKeyUp('Shift') - - await wd.pressKey('4') - await wd.pressKeyDown('Shift') - await wd.pressKey('4') - await wd.pressKey('Digit4') - await wd.pressKeyUp('Shift') - - await wd.pressKey('5') - await wd.pressKeyDown('Shift') - await wd.pressKey('5') - await wd.pressKey('Digit5') - await wd.pressKeyUp('Shift') - - await wd.pressKey('6') - await wd.pressKeyDown('Shift') - await wd.pressKey('6') - await wd.pressKey('Digit6') - await wd.pressKeyUp('Shift') - - await wd.pressKey('7') - await wd.pressKeyDown('Shift') - await wd.pressKey('7') - await wd.pressKey('Digit7') - await wd.pressKeyUp('Shift') - - await wd.pressKey('8') - await wd.pressKeyDown('Shift') - await wd.pressKey('8') - await wd.pressKey('Digit8') - await wd.pressKeyUp('Shift') - - await wd.pressKey('9') - await wd.pressKeyDown('Shift') - await wd.pressKey('9') - await wd.pressKey('Digit9') - await wd.pressKeyUp('Shift') - - await wd.seeInField('Name', '0))1!!2@@3##4$$5%%6^^7&&8**9((') - }) - }) + await wd.amOnPage('/form/field'); + await wd.fillField('Name', ''); + + await wd.pressKey('0'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('0'); + await wd.pressKey('Digit0'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('1'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('1'); + await wd.pressKey('Digit1'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('2'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('2'); + await wd.pressKey('Digit2'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('3'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('3'); + await wd.pressKey('Digit3'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('4'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('4'); + await wd.pressKey('Digit4'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('5'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('5'); + await wd.pressKey('Digit5'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('6'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('6'); + await wd.pressKey('Digit6'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('7'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('7'); + await wd.pressKey('Digit7'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('8'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('8'); + await wd.pressKey('Digit8'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('9'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('9'); + await wd.pressKey('Digit9'); + await wd.pressKeyUp('Shift'); + + await wd.seeInField('Name', '0))1!!2@@3##4$$5%%6^^7&&8**9(('); + }); + }); describe('#seeInSource, #grabSource', () => { it('should check for text to be in HTML source', async () => { - await wd.amOnPage('/') - await wd.seeInSource('TestEd Beta 2.0') - await wd.dontSeeInSource('TestEd Beta 2.0'); + await wd.dontSeeInSource(' { - await wd.amOnPage('/') - const source = await wd.grabSource() - assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved') - }) + await wd.amOnPage('/'); + const source = await wd.grabSource(); + assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved'); + }); it('should grab the innerHTML for an element', async () => { - await wd.amOnPage('/') - const source = await wd.grabHTMLFrom('#area1') + await wd.amOnPage('/'); + const source = await wd.grabHTMLFrom('#area1'); assert.deepEqual( source, ` Test Link `, - ) - }) - }) + ); + }); + }); describe('#seeTitleEquals', () => { it('should check that title is equal to provided one', async () => { - await wd.amOnPage('/') + await wd.amOnPage('/'); try { - await wd.seeTitleEquals('TestEd Beta 2.0') - await wd.seeTitleEquals('TestEd Beta 2.') + await wd.seeTitleEquals('TestEd Beta 2.0'); + await wd.seeTitleEquals('TestEd Beta 2.'); } catch (e) { - assert.equal(e.message, 'expected web page title to be TestEd Beta 2., but found TestEd Beta 2.0') + assert.equal(e.message, 'expected web page title to be TestEd Beta 2., but found TestEd Beta 2.0'); } - }) - }) + }); + }); describe('#seeTextEquals', () => { it('should check text is equal to provided one', async () => { - await wd.amOnPage('/') - await wd.seeTextEquals('Welcome to test app!', 'h1') + await wd.amOnPage('/'); + await wd.seeTextEquals('Welcome to test app!', 'h1'); try { - await wd.seeTextEquals('Welcome to test app', 'h1') - assert.equal(true, false, 'Throw an error because it should not get this far!') + await wd.seeTextEquals('Welcome to test app', 'h1'); + assert.equal(true, false, 'Throw an error because it should not get this far!'); } catch (e) { - e.should.be.instanceOf(Error) - e.message.should.be.equal('expected element h1 "Welcome to test app" to equal "Welcome to test app!"') + e.should.be.instanceOf(Error); + e.message.should.be.equal('expected element h1 "Welcome to test app" to equal "Welcome to test app!"'); // e.should.be.instanceOf(AssertionFailedError); } - }) + }); it('should check text is not equal to empty string of element text', async () => { - await wd.amOnPage('https://codecept.io') + await wd.amOnPage('https://codecept.io'); try { - await wd.seeTextEquals('', '.logo') - await wd.seeTextEquals('This is not empty', '.logo') + await wd.seeTextEquals('', '.logo'); + await wd.seeTextEquals('This is not empty', '.logo'); } catch (e) { - e.should.be.instanceOf(Error) - e.message.should.be.equal('expected element .logo "This is not empty" to equal ""') + e.should.be.instanceOf(Error); + e.message.should.be.equal('expected element .logo "This is not empty" to equal ""'); } - }) - }) + }); + }); describe('#waitForFunction', () => { it('should wait for function returns true', async () => { - await wd.amOnPage('/form/wait_js') - await wd.waitForFunction(() => window.__waitJs, 3) - }) + await wd.amOnPage('/form/wait_js'); + await wd.waitForFunction(() => window.__waitJs, 3); + }); it('should pass arguments and wait for function returns true', async () => { - await wd.amOnPage('/form/wait_js') - await wd.waitForFunction((varName) => window[varName], ['__waitJs'], 3) - }) - }) + await wd.amOnPage('/form/wait_js'); + await wd.waitForFunction((varName) => window[varName], ['__waitJs'], 3); + }); + }); describe.skip('#waitForEnabled', () => { it('should wait for input text field to be enabled', async () => { - await wd.amOnPage('/form/wait_enabled') - await wd.waitForEnabled('#text', 2) - await wd.fillField('#text', 'hello world') - await wd.seeInField('#text', 'hello world') - }) + await wd.amOnPage('/form/wait_enabled'); + await wd.waitForEnabled('#text', 2); + await wd.fillField('#text', 'hello world'); + await wd.seeInField('#text', 'hello world'); + }); it('should wait for input text field to be enabled by xpath', async () => { - await wd.amOnPage('/form/wait_enabled') - await wd.waitForEnabled("//*[@name = 'test']", 2) - await wd.fillField('#text', 'hello world') - await wd.seeInField('#text', 'hello world') - }) + await wd.amOnPage('/form/wait_enabled'); + await wd.waitForEnabled("//*[@name = 'test']", 2); + await wd.fillField('#text', 'hello world'); + await wd.seeInField('#text', 'hello world'); + }); it('should wait for a button to be enabled', async () => { - await wd.amOnPage('/form/wait_enabled') - await wd.waitForEnabled('#text', 2) - await wd.click('#button') - await wd.see('button was clicked') - }) - }) + await wd.amOnPage('/form/wait_enabled'); + await wd.waitForEnabled('#text', 2); + await wd.click('#button'); + await wd.see('button was clicked'); + }); + }); describe.skip('#waitForValue', () => { it('should wait for expected value for given locator', async () => { - await wd.amOnPage('/info') - await wd.waitForValue('//input[@name= "rus"]', 'Верно') + await wd.amOnPage('/info'); + await wd.waitForValue('//input[@name= "rus"]', 'Верно'); try { - await wd.waitForValue('//input[@name= "rus"]', 'Верно3', 0.1) - throw Error('It should never get this far') + await wd.waitForValue('//input[@name= "rus"]', 'Верно3', 0.1); + throw Error('It should never get this far'); } catch (e) { e.message.should.include( 'element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec', - ) + ); } - }) + }); it('should wait for expected value for given css locator', async () => { - await wd.amOnPage('/form/wait_value') - await wd.seeInField('#text', 'Hamburg') - await wd.waitForValue('#text', 'Brisbane', 2.5) - await wd.seeInField('#text', 'Brisbane') - }) + await wd.amOnPage('/form/wait_value'); + await wd.seeInField('#text', 'Hamburg'); + await wd.waitForValue('#text', 'Brisbane', 2.5); + await wd.seeInField('#text', 'Brisbane'); + }); it('should wait for expected value for given xpath locator', async () => { - await wd.amOnPage('/form/wait_value') - await wd.seeInField('#text', 'Hamburg') - await wd.waitForValue('//input[@value = "Grüße aus Hamburg"]', 'Brisbane', 2.5) - await wd.seeInField('#text', 'Brisbane') - }) + await wd.amOnPage('/form/wait_value'); + await wd.seeInField('#text', 'Hamburg'); + await wd.waitForValue('//input[@value = "Grüße aus Hamburg"]', 'Brisbane', 2.5); + await wd.seeInField('#text', 'Brisbane'); + }); it('should only wait for one of the matching elements to contain the value given xpath locator', async () => { - await wd.amOnPage('/form/wait_value') - await wd.waitForValue('//input[@type = "text"]', 'Brisbane', 4) - await wd.seeInField('#text', 'Brisbane') - await wd.seeInField('#text2', 'London') - }) + await wd.amOnPage('/form/wait_value'); + await wd.waitForValue('//input[@type = "text"]', 'Brisbane', 4); + await wd.seeInField('#text', 'Brisbane'); + await wd.seeInField('#text2', 'London'); + }); it('should only wait for one of the matching elements to contain the value given css locator', async () => { - await wd.amOnPage('/form/wait_value') - await wd.waitForValue('.inputbox', 'Brisbane', 4) - await wd.seeInField('#text', 'Brisbane') - await wd.seeInField('#text2', 'London') - }) - }) + await wd.amOnPage('/form/wait_value'); + await wd.waitForValue('.inputbox', 'Brisbane', 4); + await wd.seeInField('#text', 'Brisbane'); + await wd.seeInField('#text2', 'London'); + }); + }); describe('#waitNumberOfVisibleElements', () => { it('should wait for a specified number of elements on the page', () => { @@ -509,24 +509,24 @@ describe('WebDriver - No Selenium server started', function () { .then(() => wd.waitNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 3)) .then(() => wd.waitNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 2, 0.1)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.include('The number of elements (//div[@id = "grab-multiple"]//a) is not 2 after 0.1 sec') - }) - }) + e.message.should.include('The number of elements (//div[@id = "grab-multiple"]//a) is not 2 after 0.1 sec'); + }); + }); it('should be no [object Object] in the error message', () => { return wd .amOnPage('/info') .then(() => wd.waitNumberOfVisibleElements({ css: '//div[@id = "grab-multiple"]//a' }, 3)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.not.include('[object Object]') - }) - }) + e.message.should.not.include('[object Object]'); + }); + }); it('should wait for a specified number of elements on the page using a css selector', () => { return wd @@ -534,21 +534,21 @@ describe('WebDriver - No Selenium server started', function () { .then(() => wd.waitNumberOfVisibleElements('#grab-multiple > a', 3)) .then(() => wd.waitNumberOfVisibleElements('#grab-multiple > a', 2, 0.1)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec') - }) - }) + e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec'); + }); + }); it('should wait for a specified number of elements which are not yet attached to the DOM', () => { return wd .amOnPage('/form/wait_num_elements') .then(() => wd.waitNumberOfVisibleElements('.title', 2, 3)) .then(() => wd.see('Hello')) - .then(() => wd.see('World')) - }) - }) + .then(() => wd.see('World')); + }); + }); describe('#waitForVisible', () => { it('should be no [object Object] in the error message', () => { @@ -556,13 +556,13 @@ describe('WebDriver - No Selenium server started', function () { .amOnPage('/info') .then(() => wd.waitForVisible('//div[@id = "grab-multiple"]//a', 3)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.not.include('[object Object]') - }) - }) - }) + e.message.should.not.include('[object Object]'); + }); + }); + }); describe('#waitForInvisible', () => { it('should be no [object Object] in the error message', () => { @@ -570,53 +570,53 @@ describe('WebDriver - No Selenium server started', function () { .amOnPage('/info') .then(() => wd.waitForInvisible('//div[@id = "grab-multiple"]//a', 3)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.not.include('[object Object]') - }) - }) + e.message.should.not.include('[object Object]'); + }); + }); it('should wait for a specified element to be invisible', () => { return wd .amOnPage('/form/wait_invisible') .then(() => wd.waitForInvisible('#step1', 3)) - .then(() => wd.dontSeeElement('#step1')) - }) - }) + .then(() => wd.dontSeeElement('#step1')); + }); + }); describe('#moveCursorTo', () => { it('should trigger hover event', async () => { - await wd.amOnPage('/form/hover') - await wd.moveCursorTo('#hover') - await wd.see('Hovered', '#show') - }) + await wd.amOnPage('/form/hover'); + await wd.moveCursorTo('#hover'); + await wd.see('Hovered', '#show'); + }); it('should not trigger hover event because of the offset is beyond the element', async () => { - await wd.amOnPage('/form/hover') - await wd.moveCursorTo('#hover', 100, 100) - await wd.dontSee('Hovered', '#show') - }) - }) + await wd.amOnPage('/form/hover'); + await wd.moveCursorTo('#hover', 100, 100); + await wd.dontSee('Hovered', '#show'); + }); + }); describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs, #grabNumberOfOpenTabs', () => { it('should only have 1 tab open when the browser starts and navigates to the first page', async () => { - await wd.amOnPage('/') - const numPages = await wd.grabNumberOfOpenTabs() - assert.equal(numPages, 1) - }) + await wd.amOnPage('/'); + const numPages = await wd.grabNumberOfOpenTabs(); + assert.equal(numPages, 1); + }); it('should switch to next tab', async () => { - wd.amOnPage('/info') - const numPages = await wd.grabNumberOfOpenTabs() - assert.equal(numPages, 1) + wd.amOnPage('/info'); + const numPages = await wd.grabNumberOfOpenTabs(); + assert.equal(numPages, 1); - await wd.click('New tab') - await wd.switchToNextTab() - await wd.waitInUrl('/login') - const numPagesAfter = await wd.grabNumberOfOpenTabs() - assert.equal(numPagesAfter, 2) - }) + await wd.click('New tab'); + await wd.switchToNextTab(); + await wd.waitInUrl('/login'); + const numPagesAfter = await wd.grabNumberOfOpenTabs(); + assert.equal(numPagesAfter, 2); + }); it('should assert when there is no ability to switch to next tab', () => { return wd @@ -626,9 +626,9 @@ describe('WebDriver - No Selenium server started', function () { .then(() => wd.switchToNextTab(2)) .then(() => assert.equal(true, false, 'Throw an error if it gets this far (which it should not)!')) .catch((e) => { - assert.equal(e.message, 'There is no ability to switch to next tab with offset 2') - }) - }) + assert.equal(e.message, 'There is no ability to switch to next tab with offset 2'); + }); + }); it('should close current tab', () => { return wd @@ -640,8 +640,8 @@ describe('WebDriver - No Selenium server started', function () { .then((numPages) => assert.equal(numPages, 2)) .then(() => wd.closeCurrentTab()) .then(() => wd.seeInCurrentUrl('/info')) - .then(() => wd.grabNumberOfOpenTabs()) - }) + .then(() => wd.grabNumberOfOpenTabs()); + }); it('should close other tabs', () => { return wd @@ -654,8 +654,8 @@ describe('WebDriver - No Selenium server started', function () { .then(() => wd.seeInCurrentUrl('/login')) .then(() => wd.closeOtherTabs()) .then(() => wd.seeInCurrentUrl('/login')) - .then(() => wd.grabNumberOfOpenTabs()) - }) + .then(() => wd.grabNumberOfOpenTabs()); + }); it('should open new tab', () => { return wd @@ -663,8 +663,8 @@ describe('WebDriver - No Selenium server started', function () { .then(() => wd.openNewTab()) .then(() => wd.waitInUrl('about:blank')) .then(() => wd.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 2)) - }) + .then((numPages) => assert.equal(numPages, 2)); + }); it('should switch to previous tab', () => { return wd @@ -672,8 +672,8 @@ describe('WebDriver - No Selenium server started', function () { .then(() => wd.openNewTab()) .then(() => wd.waitInUrl('about:blank')) .then(() => wd.switchToPreviousTab()) - .then(() => wd.waitInUrl('/info')) - }) + .then(() => wd.waitInUrl('/info')); + }); it('should assert when there is no ability to switch to previous tab', () => { return wd @@ -683,10 +683,10 @@ describe('WebDriver - No Selenium server started', function () { .then(() => wd.switchToPreviousTab(2)) .then(() => wd.waitInUrl('/info')) .catch((e) => { - assert.equal(e.message, 'There is no ability to switch to previous tab with offset 2') - }) - }) - }) + assert.equal(e.message, 'There is no ability to switch to previous tab with offset 2'); + }); + }); + }); describe('popup : #acceptPopup, #seeInPopup, #cancelPopup', () => { it('should accept popup window', () => { @@ -694,40 +694,40 @@ describe('WebDriver - No Selenium server started', function () { .amOnPage('/form/popup') .then(() => wd.click('Confirm')) .then(() => wd.acceptPopup()) - .then(() => wd.see('Yes', '#result')) - }) + .then(() => wd.see('Yes', '#result')); + }); it('should cancel popup', () => { return wd .amOnPage('/form/popup') .then(() => wd.click('Confirm')) .then(() => wd.cancelPopup()) - .then(() => wd.see('No', '#result')) - }) + .then(() => wd.see('No', '#result')); + }); it('should check text in popup', () => { return wd .amOnPage('/form/popup') .then(() => wd.click('Alert')) .then(() => wd.seeInPopup('Really?')) - .then(() => wd.cancelPopup()) - }) + .then(() => wd.cancelPopup()); + }); it('should grab text from popup', () => { return wd .amOnPage('/form/popup') .then(() => wd.click('Alert')) .then(() => wd.grabPopupText()) - .then((text) => assert.equal(text, 'Really?')) - }) + .then((text) => assert.equal(text, 'Really?')); + }); it('should return null if no popup is visible (do not throw an error)', () => { return wd .amOnPage('/form/popup') .then(() => wd.grabPopupText()) - .then((text) => assert.equal(text, null)) - }) - }) + .then((text) => assert.equal(text, null)); + }); + }); describe('#waitForText', () => { it('should return error if not present', () => { @@ -737,9 +737,9 @@ describe('WebDriver - No Selenium server started', function () { .catch((e) => { e.message.should.be.equal( 'element (#text) is not in DOM or there is no element(#text) with text "Nothing here" after 1 sec', - ) - }) - }) + ); + }); + }); it('should return error if waiting is too small', () => { return wd @@ -748,83 +748,83 @@ describe('WebDriver - No Selenium server started', function () { .catch((e) => { e.message.should.be.equal( 'element (body) is not in DOM or there is no element(body) with text "Dynamic text" after 0.1 sec', - ) - }) - }) - }) + ); + }); + }); + }); describe('#seeNumberOfElements', () => { it('should return 1 as count', async () => { - await wd.amOnPage('/') - await wd.seeNumberOfElements('#area1', 1) - }) - }) + await wd.amOnPage('/'); + await wd.seeNumberOfElements('#area1', 1); + }); + }); describe('#switchTo', () => { it('should switch reference to iframe content', async () => { - await wd.amOnPage('/iframe') - await wd.switchTo('[name="content"]') - await wd.see('Information\nLots of valuable data here') - }) + await wd.amOnPage('/iframe'); + await wd.switchTo('[name="content"]'); + await wd.see('Information\nLots of valuable data here'); + }); it('should return error if iframe selector is invalid', async () => { - await wd.amOnPage('/iframe') + await wd.amOnPage('/iframe'); try { - await wd.switchTo('#invalidIframeSelector') + await wd.switchTo('#invalidIframeSelector'); } catch (e) { - e.should.be.instanceOf(Error) - e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath') + e.should.be.instanceOf(Error); + e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath'); } - }) + }); it('should return error if iframe selector is not iframe', async () => { - await wd.amOnPage('/iframe') + await wd.amOnPage('/iframe'); try { - await wd.switchTo('h1') + await wd.switchTo('h1'); } catch (e) { - e.should.be.instanceOf(Error) - e.message.should.contain('no such frame') + e.should.be.instanceOf(Error); + e.message.should.contain('no such frame'); } - }) + }); it('should return to parent frame given a null locator', async () => { - await wd.amOnPage('/iframe') - await wd.switchTo('[name="content"]') - await wd.see('Information\nLots of valuable data here') - await wd.switchTo(null) - await wd.see('Iframe test') - }) - }) + await wd.amOnPage('/iframe'); + await wd.switchTo('[name="content"]'); + await wd.see('Information\nLots of valuable data here'); + await wd.switchTo(null); + await wd.see('Iframe test'); + }); + }); describe('click context', () => { it('should click on inner text', async () => { - await wd.amOnPage('/form/checkbox') - await wd.click('Submit', '//input[@type = "submit"]') - await wd.waitInUrl('/form/complex') - }) + await wd.amOnPage('/form/checkbox'); + await wd.click('Submit', '//input[@type = "submit"]'); + await wd.waitInUrl('/form/complex'); + }); it('should click on input in inner element', async () => { - await wd.amOnPage('/form/checkbox') - await wd.click('Submit', '//form') - await wd.waitInUrl('/form/complex') - }) + await wd.amOnPage('/form/checkbox'); + await wd.click('Submit', '//form'); + await wd.waitInUrl('/form/complex'); + }); it('should click by accessibility_id', async () => { - await wd.amOnPage('/info') - await wd.click('~index via aria-label') - await wd.see('Welcome to test app!') - }) - }) + await wd.amOnPage('/info'); + await wd.click('~index via aria-label'); + await wd.see('Welcome to test app!'); + }); + }); describe('window size #resizeWindow', () => { it('should set initial window size', async () => { - await wd.amOnPage('/form/resize') - await wd.click('Window Size') - await wd.see('Height 700', '#height') - await wd.see('Width 500', '#width') - }) + await wd.amOnPage('/form/resize'); + await wd.click('Window Size'); + await wd.see('Height 700', '#height'); + await wd.see('Width 500', '#width'); + }); it('should set window size on new session', () => { return wd @@ -840,419 +840,419 @@ describe('WebDriver - No Selenium server started', function () { .then(() => wd.amOnPage('/form/resize')) .then(() => wd.click('Window Size')) .then(() => wd.see('Height 700', '#height')) - .then(() => wd.see('Width 500', '#width')) - }) + .then(() => wd.see('Width 500', '#width')); + }); it('should resize window to specific dimensions', async () => { - await wd.amOnPage('/form/resize') - await wd.resizeWindow(950, 600) - await wd.click('Window Size') - await wd.see('Height 600', '#height') - await wd.see('Width 950', '#width') - }) + await wd.amOnPage('/form/resize'); + await wd.resizeWindow(950, 600); + await wd.click('Window Size'); + await wd.see('Height 600', '#height'); + await wd.see('Width 950', '#width'); + }); xit('should resize window to maximum screen dimensions', async () => { - await wd.amOnPage('/form/resize') - await wd.resizeWindow(500, 400) - await wd.click('Window Size') - await wd.see('Height 400', '#height') - await wd.see('Width 500', '#width') - await wd.resizeWindow('maximize') - await wd.click('Window Size') - await wd.dontSee('Height 400', '#height') - await wd.dontSee('Width 500', '#width') - }) - }) + await wd.amOnPage('/form/resize'); + await wd.resizeWindow(500, 400); + await wd.click('Window Size'); + await wd.see('Height 400', '#height'); + await wd.see('Width 500', '#width'); + await wd.resizeWindow('maximize'); + await wd.click('Window Size'); + await wd.dontSee('Height 400', '#height'); + await wd.dontSee('Width 500', '#width'); + }); + }); describe('SmartWait', () => { - before(() => (wd.options.smartWait = 3000)) - after(() => (wd.options.smartWait = 0)) + before(() => (wd.options.smartWait = 3000)); + after(() => (wd.options.smartWait = 0)); it('should wait for element to appear', async () => { - await wd.amOnPage('/form/wait_element') - await wd.dontSeeElement('h1') - await wd.seeElement('h1') - }) + await wd.amOnPage('/form/wait_element'); + await wd.dontSeeElement('h1'); + await wd.seeElement('h1'); + }); it('should wait for clickable element appear', async () => { - await wd.amOnPage('/form/wait_clickable') - await wd.dontSeeElement('#click') - await wd.click('#click') - await wd.see('Hi!') - }) + await wd.amOnPage('/form/wait_clickable'); + await wd.dontSeeElement('#click'); + await wd.click('#click'); + await wd.see('Hi!'); + }); it('should wait for clickable context to appear', async () => { - await wd.amOnPage('/form/wait_clickable') - await wd.dontSeeElement('#linkContext') - await wd.click('Hello world', '#linkContext') - await wd.see('Hi!') - }) + await wd.amOnPage('/form/wait_clickable'); + await wd.dontSeeElement('#linkContext'); + await wd.click('Hello world', '#linkContext'); + await wd.see('Hi!'); + }); it('should wait for text context to appear', async () => { - await wd.amOnPage('/form/wait_clickable') - await wd.dontSee('Hello world') - await wd.see('Hello world', '#linkContext') - }) + await wd.amOnPage('/form/wait_clickable'); + await wd.dontSee('Hello world'); + await wd.see('Hello world', '#linkContext'); + }); it('should work with grabbers', async () => { - await wd.amOnPage('/form/wait_clickable') - await wd.dontSee('Hello world') - const res = await wd.grabAttributeFrom('#click', 'id') - assert.equal(res, 'click') - }) - }) + await wd.amOnPage('/form/wait_clickable'); + await wd.dontSee('Hello world'); + const res = await wd.grabAttributeFrom('#click', 'id'); + assert.equal(res, 'click'); + }); + }); describe('#_locateClickable', () => { it('should locate a button to click', async () => { - await wd.amOnPage('/form/checkbox') - const res = await wd._locateClickable('Submit') - res.length.should.be.equal(1) - }) + await wd.amOnPage('/form/checkbox'); + const res = await wd._locateClickable('Submit'); + res.length.should.be.equal(1); + }); it('should not locate a non-existing checkbox', async () => { - await wd.amOnPage('/form/checkbox') - const res = await wd._locateClickable('I disagree') - res.length.should.be.equal(0) - }) - }) + await wd.amOnPage('/form/checkbox'); + const res = await wd._locateClickable('I disagree'); + res.length.should.be.equal(0); + }); + }); describe('#_locateCheckable', () => { it('should locate a checkbox', async () => { - await wd.amOnPage('/form/checkbox') - const res = await wd._locateCheckable('I Agree') - res.length.should.be.equal(1) - }) + await wd.amOnPage('/form/checkbox'); + const res = await wd._locateCheckable('I Agree'); + res.length.should.be.equal(1); + }); it('should not locate a non-existing checkbox', async () => { - await wd.amOnPage('/form/checkbox') - const res = await wd._locateCheckable('I disagree') - res.length.should.be.equal(0) - }) - }) + await wd.amOnPage('/form/checkbox'); + const res = await wd._locateCheckable('I disagree'); + res.length.should.be.equal(0); + }); + }); describe('#_locateFields', () => { it('should locate a field', async () => { - await wd.amOnPage('/form/field') - const res = await wd._locateFields('Name') - res.length.should.be.equal(1) - }) + await wd.amOnPage('/form/field'); + const res = await wd._locateFields('Name'); + res.length.should.be.equal(1); + }); it('should not locate a non-existing field', async () => { - await wd.amOnPage('/form/field') - const res = await wd._locateFields('Mother-in-law') - res.length.should.be.equal(0) - }) - }) + await wd.amOnPage('/form/field'); + const res = await wd._locateFields('Mother-in-law'); + res.length.should.be.equal(0); + }); + }); xdescribe('#grabBrowserLogs', () => { it('should grab browser logs', async () => { - await wd.amOnPage('/') + await wd.amOnPage('/'); await wd.executeScript(() => { - console.log('Test log entry') - }) - const logs = await wd.grabBrowserLogs() - console.log('lololo', logs) + console.log('Test log entry'); + }); + const logs = await wd.grabBrowserLogs(); + console.log('lololo', logs); - const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1) - assert.equal(matchingLogs.length, 1) - }) + const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1); + assert.equal(matchingLogs.length, 1); + }); it('should grab browser logs across pages', async () => { - wd.amOnPage('/') + wd.amOnPage('/'); await wd.executeScript(() => { - console.log('Test log entry 1') - }) - await wd.openNewTab() - await wd.amOnPage('/info') + console.log('Test log entry 1'); + }); + await wd.openNewTab(); + await wd.amOnPage('/info'); await wd.executeScript(() => { - console.log('Test log entry 2') - }) + console.log('Test log entry 2'); + }); - const logs = await wd.grabBrowserLogs() + const logs = await wd.grabBrowserLogs(); - const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1) - assert.equal(matchingLogs.length, 2) - }) - }) + const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1); + assert.equal(matchingLogs.length, 2); + }); + }); describe('#dragAndDrop', () => { it('Drag item from source to target (no iframe) @dragNdrop', async () => { - await wd.amOnPage('http://jqueryui.com/resources/demos/droppable/default.html') - await wd.seeElementInDOM('#draggable') - await wd.dragAndDrop('#draggable', '#droppable') - await wd.see('Dropped') - }) + await wd.amOnPage('http://jqueryui.com/resources/demos/droppable/default.html'); + await wd.seeElementInDOM('#draggable'); + await wd.dragAndDrop('#draggable', '#droppable'); + await wd.see('Dropped'); + }); it('Drag and drop from within an iframe', async () => { - await wd.amOnPage('http://jqueryui.com/droppable') - await wd.resizeWindow(700, 700) - await wd.switchTo('//iframe[@class="demo-frame"]') - await wd.seeElementInDOM('#draggable') - await wd.dragAndDrop('#draggable', '#droppable') - await wd.see('Dropped') - }) - }) + await wd.amOnPage('http://jqueryui.com/droppable'); + await wd.resizeWindow(700, 700); + await wd.switchTo('//iframe[@class="demo-frame"]'); + await wd.seeElementInDOM('#draggable'); + await wd.dragAndDrop('#draggable', '#droppable'); + await wd.see('Dropped'); + }); + }); describe('#switchTo frame', () => { it('should switch to frame using name', async () => { - await wd.amOnPage('/iframe') - await wd.see('Iframe test', 'h1') - await wd.dontSee('Information', 'h1') - await wd.switchTo('iframe') - await wd.see('Information', 'h1') - await wd.dontSee('Iframe test', 'h1') - }) + await wd.amOnPage('/iframe'); + await wd.see('Iframe test', 'h1'); + await wd.dontSee('Information', 'h1'); + await wd.switchTo('iframe'); + await wd.see('Information', 'h1'); + await wd.dontSee('Iframe test', 'h1'); + }); it('should switch to root frame', async () => { - await wd.amOnPage('/iframe') - await wd.see('Iframe test', 'h1') - await wd.dontSee('Information', 'h1') - await wd.switchTo('iframe') - await wd.see('Information', 'h1') - await wd.dontSee('Iframe test', 'h1') - await wd.switchTo() - await wd.see('Iframe test', 'h1') - }) + await wd.amOnPage('/iframe'); + await wd.see('Iframe test', 'h1'); + await wd.dontSee('Information', 'h1'); + await wd.switchTo('iframe'); + await wd.see('Information', 'h1'); + await wd.dontSee('Iframe test', 'h1'); + await wd.switchTo(); + await wd.see('Iframe test', 'h1'); + }); it('should switch to frame using frame number', async () => { - await wd.amOnPage('/iframe') - await wd.see('Iframe test', 'h1') - await wd.dontSee('Information', 'h1') - await wd.switchTo(0) - await wd.see('Information', 'h1') - await wd.dontSee('Iframe test', 'h1') - }) - }) + await wd.amOnPage('/iframe'); + await wd.see('Iframe test', 'h1'); + await wd.dontSee('Information', 'h1'); + await wd.switchTo(0); + await wd.see('Information', 'h1'); + await wd.dontSee('Iframe test', 'h1'); + }); + }); describe.skip('#AttachFile', () => { it('should attach to regular input element', async () => { - await wd.amOnPage('/form/file') - await wd.attachFile('Avatar', './app/avatar.jpg') - await wd.seeInField('Avatar', 'avatar.jpg') - }) + await wd.amOnPage('/form/file'); + await wd.attachFile('Avatar', './app/avatar.jpg'); + await wd.seeInField('Avatar', 'avatar.jpg'); + }); it('should attach to invisible input element', async () => { - await wd.amOnPage('/form/file') - await wd.attachFile('hidden', '/app/avatar.jpg') - }) - }) + await wd.amOnPage('/form/file'); + await wd.attachFile('hidden', '/app/avatar.jpg'); + }); + }); describe('#dragSlider', () => { it('should drag scrubber to given position', async () => { - await wd.amOnPage('/form/page_slider') - await wd.seeElementInDOM('#slidecontainer input') + await wd.amOnPage('/form/page_slider'); + await wd.seeElementInDOM('#slidecontainer input'); - const before = await wd.grabValueFrom('#slidecontainer input') - await wd.dragSlider('#slidecontainer input', 20) - const after = await wd.grabValueFrom('#slidecontainer input') + const before = await wd.grabValueFrom('#slidecontainer input'); + await wd.dragSlider('#slidecontainer input', 20); + const after = await wd.grabValueFrom('#slidecontainer input'); - assert.notEqual(before, after) - }) - }) + assert.notEqual(before, after); + }); + }); describe('#uncheckOption', () => { it('should uncheck option that is currently checked', async () => { - await wd.amOnPage('/info') - await wd.uncheckOption('interesting') - await wd.dontSeeCheckboxIsChecked('interesting') - }) + await wd.amOnPage('/info'); + await wd.uncheckOption('interesting'); + await wd.dontSeeCheckboxIsChecked('interesting'); + }); it('should NOT uncheck option that is NOT currently checked', async () => { - await wd.amOnPage('/info') - await wd.uncheckOption('interesting') + await wd.amOnPage('/info'); + await wd.uncheckOption('interesting'); // Unchecking again should not affect the current 'unchecked' status - await wd.uncheckOption('interesting') - await wd.dontSeeCheckboxIsChecked('interesting') - }) - }) + await wd.uncheckOption('interesting'); + await wd.dontSeeCheckboxIsChecked('interesting'); + }); + }); describe('allow back and forth between handles: #grabAllWindowHandles #grabCurrentWindowHandle #switchToWindow', () => { it('should open main page of configured site, open a popup, switch to main page, then switch to popup, close popup, and go back to main page', async () => { - await wd.amOnPage('/') - const handleBeforePopup = await wd.grabCurrentWindowHandle() - const urlBeforePopup = await wd.grabCurrentUrl() + await wd.amOnPage('/'); + const handleBeforePopup = await wd.grabCurrentWindowHandle(); + const urlBeforePopup = await wd.grabCurrentUrl(); - const allHandlesBeforePopup = await wd.grabAllWindowHandles() - allHandlesBeforePopup.length.should.eql(1) + const allHandlesBeforePopup = await wd.grabAllWindowHandles(); + allHandlesBeforePopup.length.should.eql(1); await wd.executeScript(() => { window.open( 'https://www.w3schools.com/', 'new window', 'toolbar=yes,scrollbars=yes,resizable=yes,width=400,height=400', - ) - }) + ); + }); - const allHandlesAfterPopup = await wd.grabAllWindowHandles() - allHandlesAfterPopup.length.should.eql(2) + const allHandlesAfterPopup = await wd.grabAllWindowHandles(); + allHandlesAfterPopup.length.should.eql(2); - await wd.switchToWindow(allHandlesAfterPopup[1]) - const urlAfterPopup = await wd.grabCurrentUrl() - urlAfterPopup.should.eql('https://www.w3schools.com/') + await wd.switchToWindow(allHandlesAfterPopup[1]); + const urlAfterPopup = await wd.grabCurrentUrl(); + urlAfterPopup.should.eql('https://www.w3schools.com/'); - handleBeforePopup.should.eql(allHandlesAfterPopup[0]) - await wd.switchToWindow(handleBeforePopup) - const currentURL = await wd.grabCurrentUrl() - currentURL.should.eql(urlBeforePopup) + handleBeforePopup.should.eql(allHandlesAfterPopup[0]); + await wd.switchToWindow(handleBeforePopup); + const currentURL = await wd.grabCurrentUrl(); + currentURL.should.eql(urlBeforePopup); - await wd.switchToWindow(allHandlesAfterPopup[1]) - const urlAfterSwitchBack = await wd.grabCurrentUrl() - urlAfterSwitchBack.should.eql('https://www.w3schools.com/') - await wd.closeCurrentTab() + await wd.switchToWindow(allHandlesAfterPopup[1]); + const urlAfterSwitchBack = await wd.grabCurrentUrl(); + urlAfterSwitchBack.should.eql('https://www.w3schools.com/'); + await wd.closeCurrentTab(); - const allHandlesAfterPopupClosed = await wd.grabAllWindowHandles() - allHandlesAfterPopupClosed.length.should.eql(1) - const currentWindowHandle = await wd.grabCurrentWindowHandle() - currentWindowHandle.should.eql(handleBeforePopup) - }) - }) + const allHandlesAfterPopupClosed = await wd.grabAllWindowHandles(); + allHandlesAfterPopupClosed.length.should.eql(1); + const currentWindowHandle = await wd.grabCurrentWindowHandle(); + currentWindowHandle.should.eql(handleBeforePopup); + }); + }); describe('#waitForClickable', () => { it('should wait for clickable', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd.waitForClickable({ css: 'input#text' }) - }) + await wd.amOnPage('/form/wait_for_clickable'); + await wd.waitForClickable({ css: 'input#text' }); + }); it('should wait for clickable by XPath', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd.waitForClickable({ xpath: './/input[@id="text"]' }) - }) + await wd.amOnPage('/form/wait_for_clickable'); + await wd.waitForClickable({ xpath: './/input[@id="text"]' }); + }); it('should fail for disabled element', async () => { - await wd.amOnPage('/form/wait_for_clickable') + await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#button' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element #button still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element #button still not clickable after 0.1 sec'); + }); + }); it('should fail for disabled element by XPath', async () => { - await wd.amOnPage('/form/wait_for_clickable') + await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ xpath: './/button[@id="button"]' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element .//button[@id="button"] still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element .//button[@id="button"] still not clickable after 0.1 sec'); + }); + }); it('should fail for element not in viewport by top', async () => { - await wd.amOnPage('/form/wait_for_clickable') + await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportTop' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element #notInViewportTop still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element #notInViewportTop still not clickable after 0.1 sec'); + }); + }); it('should fail for element not in viewport by bottom', async () => { - await wd.amOnPage('/form/wait_for_clickable') + await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportBottom' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element #notInViewportBottom still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element #notInViewportBottom still not clickable after 0.1 sec'); + }); + }); it('should fail for element not in viewport by left', async () => { - await wd.amOnPage('/form/wait_for_clickable') + await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportLeft' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element #notInViewportLeft still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element #notInViewportLeft still not clickable after 0.1 sec'); + }); + }); it('should fail for element not in viewport by right', async () => { - await wd.amOnPage('/form/wait_for_clickable') + await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportRight' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element #notInViewportRight still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element #notInViewportRight still not clickable after 0.1 sec'); + }); + }); it('should fail for overlapping element', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd.waitForClickable({ css: '#div2_button' }, 0.1) + await wd.amOnPage('/form/wait_for_clickable'); + await wd.waitForClickable({ css: '#div2_button' }, 0.1); await wd .waitForClickable({ css: '#div1_button' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element #div1_button still not clickable after 0.1 sec') - }) - }) - }) + e.message.should.include('element #div1_button still not clickable after 0.1 sec'); + }); + }); + }); describe('#grabElementBoundingRect', () => { it('should get the element size', async () => { - await wd.amOnPage('/form/hidden') - const size = await wd.grabElementBoundingRect('input[type=submit]') - expect(size.x).is.greaterThan(0) - expect(size.y).is.greaterThan(0) - expect(size.width).is.greaterThan(0) - expect(size.height).is.greaterThan(0) - }) + await wd.amOnPage('/form/hidden'); + const size = await wd.grabElementBoundingRect('input[type=submit]'); + expect(size.x).is.greaterThan(0); + expect(size.y).is.greaterThan(0); + expect(size.width).is.greaterThan(0); + expect(size.height).is.greaterThan(0); + }); it('should get the element width', async () => { - await wd.amOnPage('/form/hidden') - const width = await wd.grabElementBoundingRect('input[type=submit]', 'width') - expect(width).is.greaterThan(0) - }) + await wd.amOnPage('/form/hidden'); + const width = await wd.grabElementBoundingRect('input[type=submit]', 'width'); + expect(width).is.greaterThan(0); + }); it('should get the element height', async () => { - await wd.amOnPage('/form/hidden') - const height = await wd.grabElementBoundingRect('input[type=submit]', 'height') - expect(height).is.greaterThan(0) - }) - }) + await wd.amOnPage('/form/hidden'); + const height = await wd.grabElementBoundingRect('input[type=submit]', 'height'); + expect(height).is.greaterThan(0); + }); + }); describe('#scrollIntoView', () => { it.skip('should scroll element into viewport', async () => { - await wd.amOnPage('/form/scroll_into_view') - const element = await wd.browser.$('#notInViewportByDefault') - expect(await element.isDisplayedInViewport()).to.be.false - await wd.scrollIntoView('#notInViewportByDefault') - expect(await element.isDisplayedInViewport()).to.be.true - }) - }) + await wd.amOnPage('/form/scroll_into_view'); + const element = await wd.browser.$('#notInViewportByDefault'); + expect(await element.isDisplayedInViewport()).to.be.false; + await wd.scrollIntoView('#notInViewportByDefault'); + expect(await element.isDisplayedInViewport()).to.be.true; + }); + }); describe('#useWebDriverTo', () => { it('should return title', async () => { - await wd.amOnPage('/') + await wd.amOnPage('/'); const title = await wd.useWebDriverTo('test', async ({ browser }) => { - return browser.getTitle() - }) - assert.equal('TestEd Beta 2.0', title) - }) - }) -}) + return browser.getTitle(); + }); + assert.equal('TestEd Beta 2.0', title); + }); + }); +}); describe('WebDriver - Basic Authentication', () => { before(() => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); try { - fs.unlinkSync(dataFile) + fs.unlinkSync(dataFile); } catch (err) { // continue regardless of error } @@ -1271,19 +1271,19 @@ describe('WebDriver - Basic Authentication', () => { args: ['--headless', '--disable-gpu', '--window-size=1280,1024'], }, }, - }) - }) + }); + }); beforeEach(async () => { - await wd._before() - }) + await wd._before(); + }); - afterEach(() => wd._after()) + afterEach(() => wd._after()); describe('open page : #amOnPage', () => { it('should be authenticated', async () => { - await wd.amOnPage('/basic_auth') - await wd.see('You entered admin as your password.') - }) - }) -}) + await wd.amOnPage('/basic_auth'); + await wd.see('You entered admin as your password.'); + }); + }); +}); diff --git a/test/helper/WebDriver_test.js b/test/helper/WebDriver_test.js index e3c942e1e..4d3184b66 100644 --- a/test/helper/WebDriver_test.js +++ b/test/helper/WebDriver_test.js @@ -1,31 +1,31 @@ -const chai = require('chai') +const chai = require('chai'); -const expect = chai.expect -const assert = chai.assert -const path = require('path') -const fs = require('fs') +const expect = chai.expect; +const assert = chai.assert; +const path = require('path'); +const fs = require('fs'); -const TestHelper = require('../support/TestHelper') -const WebDriver = require('../../lib/helper/WebDriver') -const AssertionFailedError = require('../../lib/assert/error') -const webApiTests = require('./webapi') -const Secret = require('../../lib/secret') -global.codeceptjs = require('../../lib') +const TestHelper = require('../support/TestHelper'); +const WebDriver = require('../../lib/helper/WebDriver'); +const AssertionFailedError = require('../../lib/assert/error'); +const webApiTests = require('./webapi'); +const Secret = require('../../lib/secret'); +global.codeceptjs = require('../../lib'); -const siteUrl = TestHelper.siteUrl() -let wd +const siteUrl = TestHelper.siteUrl(); +let wd; -console.log('Connecting to Selenium Server', TestHelper.seleniumAddress()) -process.env.isSelenium = 'true' +console.log('Connecting to Selenium Server', TestHelper.seleniumAddress()); +process.env.isSelenium = 'true'; describe('WebDriver', function () { - this.retries(1) - this.timeout(35000) + this.retries(1); + this.timeout(35000); before(() => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); try { - fs.unlinkSync(dataFile) + fs.unlinkSync(dataFile); } catch (err) { // continue regardless of error } @@ -46,473 +46,473 @@ describe('WebDriver', function () { customLocatorStrategies: { customSelector: (selector) => ({ 'element-6066-11e4-a52e-4f735466cecf': `${selector}-foobar` }), }, - }) - }) + }); + }); beforeEach(async () => { - webApiTests.init({ I: wd, siteUrl }) - this.wdBrowser = await wd._before() - return this.wdBrowser - }) + webApiTests.init({ I: wd, siteUrl }); + this.wdBrowser = await wd._before(); + return this.wdBrowser; + }); - afterEach(async () => wd._after()) + afterEach(async () => wd._after()); // load common test suite - webApiTests.tests() + webApiTests.tests(); describe('customLocatorStrategies', () => { it('should locate through custom selector', async () => { - const el = await this.wdBrowser.custom$('customSelector', '.test') - expect(el.elementId).to.equal('.test-foobar') - }) + const el = await this.wdBrowser.custom$('customSelector', '.test'); + expect(el.elementId).to.equal('.test-foobar'); + }); it('should include the custom strategy', async () => { - expect(wd.customLocatorStrategies.customSelector).to.not.be.undefined - }) + expect(wd.customLocatorStrategies.customSelector).to.not.be.undefined; + }); it('should be added to the browser locator strategies', async () => { - expect(this.wdBrowser.addLocatorStrategy).to.not.be.undefined - }) + expect(this.wdBrowser.addLocatorStrategy).to.not.be.undefined; + }); it('throws on invalid custom selector', async () => { try { - await wd.waitForEnabled({ madeUpSelector: '#text' }, 2) + await wd.waitForEnabled({ madeUpSelector: '#text' }, 2); } catch (e) { - expect(e.message).to.include('Please define "customLocatorStrategies"') + expect(e.message).to.include('Please define "customLocatorStrategies"'); } - }) - }) + }); + }); describe('open page : #amOnPage', () => { it('should open main page of configured site', async () => { - await wd.amOnPage('/') - const url = await wd.grabCurrentUrl() - url.should.eql(`${siteUrl}/`) - }) + await wd.amOnPage('/'); + const url = await wd.grabCurrentUrl(); + url.should.eql(`${siteUrl}/`); + }); it('should open any page of configured site', async () => { - await wd.amOnPage('/info') - const url = await wd.grabCurrentUrl() - url.should.eql(`${siteUrl}/info`) - }) + await wd.amOnPage('/info'); + const url = await wd.grabCurrentUrl(); + url.should.eql(`${siteUrl}/info`); + }); it('should open absolute url', async () => { - await wd.amOnPage(siteUrl) - const url = await wd.grabCurrentUrl() - url.should.eql(`${siteUrl}/`) - }) - }) + await wd.amOnPage(siteUrl); + const url = await wd.grabCurrentUrl(); + url.should.eql(`${siteUrl}/`); + }); + }); describe('see text : #see', () => { it('should fail when text is not on site', async () => { - await wd.amOnPage('/') + await wd.amOnPage('/'); try { - await wd.see('Something incredible!') + await wd.see('Something incredible!'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('web page') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('web page'); } try { - await wd.dontSee('Welcome') + await wd.dontSee('Welcome'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.include('web page') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.include('web page'); } - }) - }) + }); + }); describe('check fields: #seeInField, #seeCheckboxIsChecked, ...', () => { it('should throw error if field is not empty', async () => { - await wd.amOnPage('/form/empty') + await wd.amOnPage('/form/empty'); try { - await wd.seeInField('#empty_input', 'Ayayay') + await wd.seeInField('#empty_input', 'Ayayay'); } catch (e) { - e.should.be.instanceOf(AssertionFailedError) - e.inspect().should.be.equal('expected fields by #empty_input to include "Ayayay"') + e.should.be.instanceOf(AssertionFailedError); + e.inspect().should.be.equal('expected fields by #empty_input to include "Ayayay"'); } - }) + }); it('should check values in checkboxes', async () => { - await wd.amOnPage('/form/field_values') - await wd.dontSeeInField('checkbox[]', 'not seen one') - await wd.seeInField('checkbox[]', 'see test one') - await wd.dontSeeInField('checkbox[]', 'not seen two') - await wd.seeInField('checkbox[]', 'see test two') - await wd.dontSeeInField('checkbox[]', 'not seen three') - await wd.seeInField('checkbox[]', 'see test three') - }) + await wd.amOnPage('/form/field_values'); + await wd.dontSeeInField('checkbox[]', 'not seen one'); + await wd.seeInField('checkbox[]', 'see test one'); + await wd.dontSeeInField('checkbox[]', 'not seen two'); + await wd.seeInField('checkbox[]', 'see test two'); + await wd.dontSeeInField('checkbox[]', 'not seen three'); + await wd.seeInField('checkbox[]', 'see test three'); + }); it('should check values are the secret type in checkboxes', async () => { - await wd.amOnPage('/form/field_values') - await wd.dontSeeInField('checkbox[]', Secret.secret('not seen one')) - await wd.seeInField('checkbox[]', Secret.secret('see test one')) - await wd.dontSeeInField('checkbox[]', Secret.secret('not seen two')) - await wd.seeInField('checkbox[]', Secret.secret('see test two')) - await wd.dontSeeInField('checkbox[]', Secret.secret('not seen three')) - await wd.seeInField('checkbox[]', Secret.secret('see test three')) - }) + await wd.amOnPage('/form/field_values'); + await wd.dontSeeInField('checkbox[]', Secret.secret('not seen one')); + await wd.seeInField('checkbox[]', Secret.secret('see test one')); + await wd.dontSeeInField('checkbox[]', Secret.secret('not seen two')); + await wd.seeInField('checkbox[]', Secret.secret('see test two')); + await wd.dontSeeInField('checkbox[]', Secret.secret('not seen three')); + await wd.seeInField('checkbox[]', Secret.secret('see test three')); + }); it('should check values with boolean', async () => { - await wd.amOnPage('/form/field_values') - await wd.seeInField('checkbox1', true) - await wd.dontSeeInField('checkbox1', false) - await wd.seeInField('checkbox2', false) - await wd.dontSeeInField('checkbox2', true) - await wd.seeInField('radio2', true) - await wd.dontSeeInField('radio2', false) - await wd.seeInField('radio3', false) - await wd.dontSeeInField('radio3', true) - }) + await wd.amOnPage('/form/field_values'); + await wd.seeInField('checkbox1', true); + await wd.dontSeeInField('checkbox1', false); + await wd.seeInField('checkbox2', false); + await wd.dontSeeInField('checkbox2', true); + await wd.seeInField('radio2', true); + await wd.dontSeeInField('radio2', false); + await wd.seeInField('radio3', false); + await wd.dontSeeInField('radio3', true); + }); it('should check values in radio', async () => { - await wd.amOnPage('/form/field_values') - await wd.seeInField('radio1', 'see test one') - await wd.dontSeeInField('radio1', 'not seen one') - await wd.dontSeeInField('radio1', 'not seen two') - await wd.dontSeeInField('radio1', 'not seen three') - }) + await wd.amOnPage('/form/field_values'); + await wd.seeInField('radio1', 'see test one'); + await wd.dontSeeInField('radio1', 'not seen one'); + await wd.dontSeeInField('radio1', 'not seen two'); + await wd.dontSeeInField('radio1', 'not seen three'); + }); it('should check values in select', async () => { - await wd.amOnPage('/form/field_values') - await wd.seeInField('select1', 'see test one') - await wd.dontSeeInField('select1', 'not seen one') - await wd.dontSeeInField('select1', 'not seen two') - await wd.dontSeeInField('select1', 'not seen three') - }) + await wd.amOnPage('/form/field_values'); + await wd.seeInField('select1', 'see test one'); + await wd.dontSeeInField('select1', 'not seen one'); + await wd.dontSeeInField('select1', 'not seen two'); + await wd.dontSeeInField('select1', 'not seen three'); + }); it('should check for empty select field', async () => { - await wd.amOnPage('/form/field_values') - await wd.seeInField('select3', '') - }) + await wd.amOnPage('/form/field_values'); + await wd.seeInField('select3', ''); + }); it('should check for select multiple field', async () => { - await wd.amOnPage('/form/field_values') - await wd.dontSeeInField('select2', 'not seen one') - await wd.seeInField('select2', 'see test one') - await wd.dontSeeInField('select2', 'not seen two') - await wd.seeInField('select2', 'see test two') - await wd.dontSeeInField('select2', 'not seen three') - await wd.seeInField('select2', 'see test three') - }) + await wd.amOnPage('/form/field_values'); + await wd.dontSeeInField('select2', 'not seen one'); + await wd.seeInField('select2', 'see test one'); + await wd.dontSeeInField('select2', 'not seen two'); + await wd.seeInField('select2', 'see test two'); + await wd.dontSeeInField('select2', 'not seen three'); + await wd.seeInField('select2', 'see test three'); + }); it('should return error when element has no value attribute', async () => { - await wd.amOnPage('https://codecept.io/quickstart') + await wd.amOnPage('https://codecept.io/quickstart'); try { - await wd.seeInField('#search_input_react', 'WebDriver1') + await wd.seeInField('#search_input_react', 'WebDriver1'); } catch (e) { - e.should.be.instanceOf(Error) + e.should.be.instanceOf(Error); } - }) - }) + }); + }); describe('Force Right Click: #forceRightClick', () => { it('it should forceRightClick', async () => { - await wd.amOnPage('/form/rightclick') - await wd.dontSee('right clicked') - await wd.forceRightClick('Lorem Ipsum') - await wd.see('right clicked') - }) + await wd.amOnPage('/form/rightclick'); + await wd.dontSee('right clicked'); + await wd.forceRightClick('Lorem Ipsum'); + await wd.see('right clicked'); + }); it('it should forceRightClick by locator', async () => { - await wd.amOnPage('/form/rightclick') - await wd.dontSee('right clicked') - await wd.forceRightClick('.context a') - await wd.see('right clicked') - }) + await wd.amOnPage('/form/rightclick'); + await wd.dontSee('right clicked'); + await wd.forceRightClick('.context a'); + await wd.see('right clicked'); + }); it('it should forceRightClick by locator and context', async () => { - await wd.amOnPage('/form/rightclick') - await wd.dontSee('right clicked') - await wd.forceRightClick('Lorem Ipsum', '.context') - await wd.see('right clicked') - }) - }) + await wd.amOnPage('/form/rightclick'); + await wd.dontSee('right clicked'); + await wd.forceRightClick('Lorem Ipsum', '.context'); + await wd.see('right clicked'); + }); + }); describe('#pressKey, #pressKeyDown, #pressKeyUp', () => { it('should be able to send special keys to element', async () => { - await wd.amOnPage('/form/field') - await wd.appendField('Name', '-') + await wd.amOnPage('/form/field'); + await wd.appendField('Name', '-'); - await wd.pressKey(['Right Shift', 'Home']) - await wd.pressKey('Delete') + await wd.pressKey(['Right Shift', 'Home']); + await wd.pressKey('Delete'); // Sequence only executes up to first non-modifier key ('Digit1') - await wd.pressKey(['SHIFT_RIGHT', 'Digit1', 'Digit4']) - await wd.pressKey('1') - await wd.pressKey('2') - await wd.pressKey('3') - await wd.pressKey('ArrowLeft') - await wd.pressKey('Left Arrow') - await wd.pressKey('arrow_left') - await wd.pressKeyDown('Shift') - await wd.pressKey('a') - await wd.pressKey('KeyB') - await wd.pressKeyUp('ShiftLeft') - await wd.pressKey('C') - await wd.seeInField('Name', '!ABC123') - }) + await wd.pressKey(['SHIFT_RIGHT', 'Digit1', 'Digit4']); + await wd.pressKey('1'); + await wd.pressKey('2'); + await wd.pressKey('3'); + await wd.pressKey('ArrowLeft'); + await wd.pressKey('Left Arrow'); + await wd.pressKey('arrow_left'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('a'); + await wd.pressKey('KeyB'); + await wd.pressKeyUp('ShiftLeft'); + await wd.pressKey('C'); + await wd.seeInField('Name', '!ABC123'); + }); it('should use modifier key based on operating system', async () => { - await wd.amOnPage('/form/field') - await wd.fillField('Name', 'value that is cleared using select all shortcut') + await wd.amOnPage('/form/field'); + await wd.fillField('Name', 'value that is cleared using select all shortcut'); - await wd.pressKey(['CommandOrControl', 'A']) - await wd.pressKey('Backspace') - await wd.dontSeeInField('Name', 'value that is cleared using select all shortcut') - }) + await wd.pressKey(['CommandOrControl', 'A']); + await wd.pressKey('Backspace'); + await wd.dontSeeInField('Name', 'value that is cleared using select all shortcut'); + }); it('should show correct numpad or punctuation key when Shift modifier is active', async () => { - await wd.amOnPage('/form/field') - await wd.fillField('Name', '') - - await wd.pressKey(';') - await wd.pressKey(['Shift', ';']) - await wd.pressKey(['Shift', 'Semicolon']) - await wd.pressKey('=') - await wd.pressKey(['Shift', '=']) - await wd.pressKey(['Shift', 'Equal']) - await wd.pressKey('*') - await wd.pressKey(['Shift', '*']) - await wd.pressKey(['Shift', 'Multiply']) - await wd.pressKey('+') - await wd.pressKey(['Shift', '+']) - await wd.pressKey(['Shift', 'Add']) - await wd.pressKey(',') - await wd.pressKey(['Shift', ',']) - await wd.pressKey(['Shift', 'Comma']) - await wd.pressKey(['Shift', 'NumpadComma']) - await wd.pressKey(['Shift', 'Separator']) - await wd.pressKey('-') - await wd.pressKey(['Shift', '-']) - await wd.pressKey(['Shift', 'Subtract']) - await wd.pressKey('.') - await wd.pressKey(['Shift', '.']) - await wd.pressKey(['Shift', 'Decimal']) - await wd.pressKey(['Shift', 'Period']) - await wd.pressKey('/') - await wd.pressKey(['Shift', '/']) - await wd.pressKey(['Shift', 'Divide']) - await wd.pressKey(['Shift', 'Slash']) - - await wd.seeInField('Name', ';::=++***+++,<<<<-_-.>.>/?/?') - }) + await wd.amOnPage('/form/field'); + await wd.fillField('Name', ''); + + await wd.pressKey(';'); + await wd.pressKey(['Shift', ';']); + await wd.pressKey(['Shift', 'Semicolon']); + await wd.pressKey('='); + await wd.pressKey(['Shift', '=']); + await wd.pressKey(['Shift', 'Equal']); + await wd.pressKey('*'); + await wd.pressKey(['Shift', '*']); + await wd.pressKey(['Shift', 'Multiply']); + await wd.pressKey('+'); + await wd.pressKey(['Shift', '+']); + await wd.pressKey(['Shift', 'Add']); + await wd.pressKey(','); + await wd.pressKey(['Shift', ',']); + await wd.pressKey(['Shift', 'Comma']); + await wd.pressKey(['Shift', 'NumpadComma']); + await wd.pressKey(['Shift', 'Separator']); + await wd.pressKey('-'); + await wd.pressKey(['Shift', '-']); + await wd.pressKey(['Shift', 'Subtract']); + await wd.pressKey('.'); + await wd.pressKey(['Shift', '.']); + await wd.pressKey(['Shift', 'Decimal']); + await wd.pressKey(['Shift', 'Period']); + await wd.pressKey('/'); + await wd.pressKey(['Shift', '/']); + await wd.pressKey(['Shift', 'Divide']); + await wd.pressKey(['Shift', 'Slash']); + + await wd.seeInField('Name', ';::=++***+++,<<<<-_-.>.>/?/?'); + }); it('should show correct number key when Shift modifier is active', async () => { - await wd.amOnPage('/form/field') - await wd.fillField('Name', '') - - await wd.pressKey('0') - await wd.pressKeyDown('Shift') - await wd.pressKey('0') - await wd.pressKey('Digit0') - await wd.pressKeyUp('Shift') - - await wd.pressKey('1') - await wd.pressKeyDown('Shift') - await wd.pressKey('1') - await wd.pressKey('Digit1') - await wd.pressKeyUp('Shift') - - await wd.pressKey('2') - await wd.pressKeyDown('Shift') - await wd.pressKey('2') - await wd.pressKey('Digit2') - await wd.pressKeyUp('Shift') - - await wd.pressKey('3') - await wd.pressKeyDown('Shift') - await wd.pressKey('3') - await wd.pressKey('Digit3') - await wd.pressKeyUp('Shift') - - await wd.pressKey('4') - await wd.pressKeyDown('Shift') - await wd.pressKey('4') - await wd.pressKey('Digit4') - await wd.pressKeyUp('Shift') - - await wd.pressKey('5') - await wd.pressKeyDown('Shift') - await wd.pressKey('5') - await wd.pressKey('Digit5') - await wd.pressKeyUp('Shift') - - await wd.pressKey('6') - await wd.pressKeyDown('Shift') - await wd.pressKey('6') - await wd.pressKey('Digit6') - await wd.pressKeyUp('Shift') - - await wd.pressKey('7') - await wd.pressKeyDown('Shift') - await wd.pressKey('7') - await wd.pressKey('Digit7') - await wd.pressKeyUp('Shift') - - await wd.pressKey('8') - await wd.pressKeyDown('Shift') - await wd.pressKey('8') - await wd.pressKey('Digit8') - await wd.pressKeyUp('Shift') - - await wd.pressKey('9') - await wd.pressKeyDown('Shift') - await wd.pressKey('9') - await wd.pressKey('Digit9') - await wd.pressKeyUp('Shift') - - await wd.seeInField('Name', '0))1!!2@@3##4$$5%%6^^7&&8**9((') - }) - }) + await wd.amOnPage('/form/field'); + await wd.fillField('Name', ''); + + await wd.pressKey('0'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('0'); + await wd.pressKey('Digit0'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('1'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('1'); + await wd.pressKey('Digit1'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('2'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('2'); + await wd.pressKey('Digit2'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('3'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('3'); + await wd.pressKey('Digit3'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('4'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('4'); + await wd.pressKey('Digit4'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('5'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('5'); + await wd.pressKey('Digit5'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('6'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('6'); + await wd.pressKey('Digit6'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('7'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('7'); + await wd.pressKey('Digit7'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('8'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('8'); + await wd.pressKey('Digit8'); + await wd.pressKeyUp('Shift'); + + await wd.pressKey('9'); + await wd.pressKeyDown('Shift'); + await wd.pressKey('9'); + await wd.pressKey('Digit9'); + await wd.pressKeyUp('Shift'); + + await wd.seeInField('Name', '0))1!!2@@3##4$$5%%6^^7&&8**9(('); + }); + }); describe('#seeInSource, #grabSource', () => { it('should check for text to be in HTML source', async () => { - await wd.amOnPage('/') - await wd.seeInSource('TestEd Beta 2.0') - await wd.dontSeeInSource('TestEd Beta 2.0'); + await wd.dontSeeInSource(' { - await wd.amOnPage('/') - const source = await wd.grabSource() - assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved') - }) + await wd.amOnPage('/'); + const source = await wd.grabSource(); + assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved'); + }); it('should grab the innerHTML for an element', async () => { - await wd.amOnPage('/') - const source = await wd.grabHTMLFrom('#area1') + await wd.amOnPage('/'); + const source = await wd.grabHTMLFrom('#area1'); assert.deepEqual( source, ` Test Link `, - ) - }) - }) + ); + }); + }); describe('#seeTitleEquals', () => { it('should check that title is equal to provided one', async () => { - await wd.amOnPage('/') + await wd.amOnPage('/'); try { - await wd.seeTitleEquals('TestEd Beta 2.0') - await wd.seeTitleEquals('TestEd Beta 2.') + await wd.seeTitleEquals('TestEd Beta 2.0'); + await wd.seeTitleEquals('TestEd Beta 2.'); } catch (e) { - assert.equal(e.message, 'expected web page title to be TestEd Beta 2., but found TestEd Beta 2.0') + assert.equal(e.message, 'expected web page title to be TestEd Beta 2., but found TestEd Beta 2.0'); } - }) - }) + }); + }); describe('#seeTextEquals', () => { it('should check text is equal to provided one', async () => { - await wd.amOnPage('/') - await wd.seeTextEquals('Welcome to test app!', 'h1') + await wd.amOnPage('/'); + await wd.seeTextEquals('Welcome to test app!', 'h1'); try { - await wd.seeTextEquals('Welcome to test app', 'h1') - assert.equal(true, false, 'Throw an error because it should not get this far!') + await wd.seeTextEquals('Welcome to test app', 'h1'); + assert.equal(true, false, 'Throw an error because it should not get this far!'); } catch (e) { - e.should.be.instanceOf(Error) - e.message.should.be.equal('expected element h1 "Welcome to test app" to equal "Welcome to test app!"') + e.should.be.instanceOf(Error); + e.message.should.be.equal('expected element h1 "Welcome to test app" to equal "Welcome to test app!"'); // e.should.be.instanceOf(AssertionFailedError); } - }) + }); it('should check text is not equal to empty string of element text', async () => { - await wd.amOnPage('https://codecept.io') + await wd.amOnPage('https://codecept.io'); try { - await wd.seeTextEquals('', '.logo') - await wd.seeTextEquals('This is not empty', '.logo') + await wd.seeTextEquals('', '.logo'); + await wd.seeTextEquals('This is not empty', '.logo'); } catch (e) { - e.should.be.instanceOf(Error) - e.message.should.be.equal('expected element .logo "This is not empty" to equal ""') + e.should.be.instanceOf(Error); + e.message.should.be.equal('expected element .logo "This is not empty" to equal ""'); } - }) - }) + }); + }); describe('#waitForFunction', () => { it('should wait for function returns true', async () => { - await wd.amOnPage('/form/wait_js') - await wd.waitForFunction(() => window.__waitJs, 3) - }) + await wd.amOnPage('/form/wait_js'); + await wd.waitForFunction(() => window.__waitJs, 3); + }); it('should pass arguments and wait for function returns true', async () => { - await wd.amOnPage('/form/wait_js') - await wd.waitForFunction((varName) => window[varName], ['__waitJs'], 3) - }) - }) + await wd.amOnPage('/form/wait_js'); + await wd.waitForFunction((varName) => window[varName], ['__waitJs'], 3); + }); + }); describe('#waitForEnabled', () => { it('should wait for input text field to be enabled', async () => { - await wd.amOnPage('/form/wait_enabled') - await wd.waitForEnabled('#text', 2) - await wd.fillField('#text', 'hello world') - await wd.seeInField('#text', 'hello world') - }) + await wd.amOnPage('/form/wait_enabled'); + await wd.waitForEnabled('#text', 2); + await wd.fillField('#text', 'hello world'); + await wd.seeInField('#text', 'hello world'); + }); it('should wait for input text field to be enabled by xpath', async () => { - await wd.amOnPage('/form/wait_enabled') - await wd.waitForEnabled("//*[@name = 'test']", 2) - await wd.fillField('#text', 'hello world') - await wd.seeInField('#text', 'hello world') - }) + await wd.amOnPage('/form/wait_enabled'); + await wd.waitForEnabled("//*[@name = 'test']", 2); + await wd.fillField('#text', 'hello world'); + await wd.seeInField('#text', 'hello world'); + }); it('should wait for a button to be enabled', async () => { - await wd.amOnPage('/form/wait_enabled') - await wd.waitForEnabled('#text', 2) - await wd.click('#button') - await wd.see('button was clicked') - }) - }) + await wd.amOnPage('/form/wait_enabled'); + await wd.waitForEnabled('#text', 2); + await wd.click('#button'); + await wd.see('button was clicked'); + }); + }); describe('#waitForValue', () => { it('should wait for expected value for given locator', async () => { - await wd.amOnPage('/info') - await wd.waitForValue('//input[@name= "rus"]', 'Верно') + await wd.amOnPage('/info'); + await wd.waitForValue('//input[@name= "rus"]', 'Верно'); try { - await wd.waitForValue('//input[@name= "rus"]', 'Верно3', 0.1) - throw Error('It should never get this far') + await wd.waitForValue('//input[@name= "rus"]', 'Верно3', 0.1); + throw Error('It should never get this far'); } catch (e) { e.message.should.include( 'element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec', - ) + ); } - }) + }); it('should wait for expected value for given css locator', async () => { - await wd.amOnPage('/form/wait_value') - await wd.seeInField('#text', 'Hamburg') - await wd.waitForValue('#text', 'Brisbane', 2.5) - await wd.seeInField('#text', 'Brisbane') - }) + await wd.amOnPage('/form/wait_value'); + await wd.seeInField('#text', 'Hamburg'); + await wd.waitForValue('#text', 'Brisbane', 2.5); + await wd.seeInField('#text', 'Brisbane'); + }); it('should wait for expected value for given xpath locator', async () => { - await wd.amOnPage('/form/wait_value') - await wd.seeInField('#text', 'Hamburg') - await wd.waitForValue('//input[@value = "Grüße aus Hamburg"]', 'Brisbane', 2.5) - await wd.seeInField('#text', 'Brisbane') - }) + await wd.amOnPage('/form/wait_value'); + await wd.seeInField('#text', 'Hamburg'); + await wd.waitForValue('//input[@value = "Grüße aus Hamburg"]', 'Brisbane', 2.5); + await wd.seeInField('#text', 'Brisbane'); + }); it('should only wait for one of the matching elements to contain the value given xpath locator', async () => { - await wd.amOnPage('/form/wait_value') - await wd.waitForValue('//input[@type = "text"]', 'Brisbane', 4) - await wd.seeInField('#text', 'Brisbane') - await wd.seeInField('#text2', 'London') - }) + await wd.amOnPage('/form/wait_value'); + await wd.waitForValue('//input[@type = "text"]', 'Brisbane', 4); + await wd.seeInField('#text', 'Brisbane'); + await wd.seeInField('#text2', 'London'); + }); it('should only wait for one of the matching elements to contain the value given css locator', async () => { - await wd.amOnPage('/form/wait_value') - await wd.waitForValue('.inputbox', 'Brisbane', 4) - await wd.seeInField('#text', 'Brisbane') - await wd.seeInField('#text2', 'London') - }) - }) + await wd.amOnPage('/form/wait_value'); + await wd.waitForValue('.inputbox', 'Brisbane', 4); + await wd.seeInField('#text', 'Brisbane'); + await wd.seeInField('#text2', 'London'); + }); + }); describe('#waitNumberOfVisibleElements', () => { it('should wait for a specified number of elements on the page', () => { @@ -521,24 +521,24 @@ describe('WebDriver', function () { .then(() => wd.waitNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 3)) .then(() => wd.waitNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 2, 0.1)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.include('The number of elements (//div[@id = "grab-multiple"]//a) is not 2 after 0.1 sec') - }) - }) + e.message.should.include('The number of elements (//div[@id = "grab-multiple"]//a) is not 2 after 0.1 sec'); + }); + }); it('should be no [object Object] in the error message', () => { return wd .amOnPage('/info') .then(() => wd.waitNumberOfVisibleElements({ css: '//div[@id = "grab-multiple"]//a' }, 3)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.not.include('[object Object]') - }) - }) + e.message.should.not.include('[object Object]'); + }); + }); it('should wait for a specified number of elements on the page using a css selector', () => { return wd @@ -546,21 +546,21 @@ describe('WebDriver', function () { .then(() => wd.waitNumberOfVisibleElements('#grab-multiple > a', 3)) .then(() => wd.waitNumberOfVisibleElements('#grab-multiple > a', 2, 0.1)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec') - }) - }) + e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec'); + }); + }); it('should wait for a specified number of elements which are not yet attached to the DOM', () => { return wd .amOnPage('/form/wait_num_elements') .then(() => wd.waitNumberOfVisibleElements('.title', 2, 3)) .then(() => wd.see('Hello')) - .then(() => wd.see('World')) - }) - }) + .then(() => wd.see('World')); + }); + }); describe('#waitForVisible', () => { it('should be no [object Object] in the error message', () => { @@ -568,13 +568,13 @@ describe('WebDriver', function () { .amOnPage('/info') .then(() => wd.waitForVisible('//div[@id = "grab-multiple"]//a', 3)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.not.include('[object Object]') - }) - }) - }) + e.message.should.not.include('[object Object]'); + }); + }); + }); describe('#waitForInvisible', () => { it('should be no [object Object] in the error message', () => { @@ -582,54 +582,54 @@ describe('WebDriver', function () { .amOnPage('/info') .then(() => wd.waitForInvisible('//div[@id = "grab-multiple"]//a', 3)) .then(() => { - throw Error('It should never get this far') + throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.not.include('[object Object]') - }) - }) + e.message.should.not.include('[object Object]'); + }); + }); it('should wait for a specified element to be invisible', () => { return wd .amOnPage('/form/wait_invisible') .then(() => wd.waitForInvisible('#step1', 3)) - .then(() => wd.dontSeeElement('#step1')) - }) - }) + .then(() => wd.dontSeeElement('#step1')); + }); + }); describe('#moveCursorTo', () => { it('should trigger hover event', async () => { - await wd.amOnPage('/form/hover') - await wd.moveCursorTo('#hover') - await wd.see('Hovered', '#show') - }) + await wd.amOnPage('/form/hover'); + await wd.moveCursorTo('#hover'); + await wd.see('Hovered', '#show'); + }); it('should not trigger hover event because of the offset is beyond the element', async () => { - await wd.amOnPage('/form/hover') - await wd.moveCursorTo('#hover', 100, 100) - await wd.dontSee('Hovered', '#show') - }) - }) + await wd.amOnPage('/form/hover'); + await wd.moveCursorTo('#hover', 100, 100); + await wd.dontSee('Hovered', '#show'); + }); + }); describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs, #grabNumberOfOpenTabs, #waitForNumberOfTabs', () => { it('should only have 1 tab open when the browser starts and navigates to the first page', async () => { - await wd.amOnPage('/') - const numPages = await wd.grabNumberOfOpenTabs() - assert.equal(numPages, 1) - }) + await wd.amOnPage('/'); + const numPages = await wd.grabNumberOfOpenTabs(); + assert.equal(numPages, 1); + }); it('should switch to next tab', async () => { - wd.amOnPage('/info') - const numPages = await wd.grabNumberOfOpenTabs() - assert.equal(numPages, 1) - - await wd.click('New tab') - await wd.waitForNumberOfTabs(2) - await wd.switchToNextTab() - await wd.waitInUrl('/login') - const numPagesAfter = await wd.grabNumberOfOpenTabs() - assert.equal(numPagesAfter, 2) - }) + wd.amOnPage('/info'); + const numPages = await wd.grabNumberOfOpenTabs(); + assert.equal(numPages, 1); + + await wd.click('New tab'); + await wd.waitForNumberOfTabs(2); + await wd.switchToNextTab(); + await wd.waitInUrl('/login'); + const numPagesAfter = await wd.grabNumberOfOpenTabs(); + assert.equal(numPagesAfter, 2); + }); it('should assert when there is no ability to switch to next tab', () => { return wd @@ -639,9 +639,9 @@ describe('WebDriver', function () { .then(() => wd.switchToNextTab(2)) .then(() => assert.equal(true, false, 'Throw an error if it gets this far (which it should not)!')) .catch((e) => { - assert.equal(e.message, 'There is no ability to switch to next tab with offset 2') - }) - }) + assert.equal(e.message, 'There is no ability to switch to next tab with offset 2'); + }); + }); it('should close current tab', () => { return wd @@ -653,8 +653,8 @@ describe('WebDriver', function () { .then((numPages) => assert.equal(numPages, 2)) .then(() => wd.closeCurrentTab()) .then(() => wd.seeInCurrentUrl('/info')) - .then(() => wd.grabNumberOfOpenTabs()) - }) + .then(() => wd.grabNumberOfOpenTabs()); + }); it('should close other tabs', () => { return wd @@ -667,8 +667,8 @@ describe('WebDriver', function () { .then(() => wd.seeInCurrentUrl('/login')) .then(() => wd.closeOtherTabs()) .then(() => wd.seeInCurrentUrl('/login')) - .then(() => wd.grabNumberOfOpenTabs()) - }) + .then(() => wd.grabNumberOfOpenTabs()); + }); it('should open new tab', () => { return wd @@ -676,8 +676,8 @@ describe('WebDriver', function () { .then(() => wd.openNewTab()) .then(() => wd.waitInUrl('about:blank')) .then(() => wd.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 2)) - }) + .then((numPages) => assert.equal(numPages, 2)); + }); it('should switch to previous tab', () => { return wd @@ -685,8 +685,8 @@ describe('WebDriver', function () { .then(() => wd.openNewTab()) .then(() => wd.waitInUrl('about:blank')) .then(() => wd.switchToPreviousTab()) - .then(() => wd.waitInUrl('/info')) - }) + .then(() => wd.waitInUrl('/info')); + }); it('should assert when there is no ability to switch to previous tab', () => { return wd @@ -696,10 +696,10 @@ describe('WebDriver', function () { .then(() => wd.switchToPreviousTab(2)) .then(() => wd.waitInUrl('/info')) .catch((e) => { - assert.equal(e.message, 'There is no ability to switch to previous tab with offset 2') - }) - }) - }) + assert.equal(e.message, 'There is no ability to switch to previous tab with offset 2'); + }); + }); + }); describe('popup : #acceptPopup, #seeInPopup, #cancelPopup', () => { it('should accept popup window', () => { @@ -707,40 +707,40 @@ describe('WebDriver', function () { .amOnPage('/form/popup') .then(() => wd.click('Confirm')) .then(() => wd.acceptPopup()) - .then(() => wd.see('Yes', '#result')) - }) + .then(() => wd.see('Yes', '#result')); + }); it('should cancel popup', () => { return wd .amOnPage('/form/popup') .then(() => wd.click('Confirm')) .then(() => wd.cancelPopup()) - .then(() => wd.see('No', '#result')) - }) + .then(() => wd.see('No', '#result')); + }); it('should check text in popup', () => { return wd .amOnPage('/form/popup') .then(() => wd.click('Alert')) .then(() => wd.seeInPopup('Really?')) - .then(() => wd.cancelPopup()) - }) + .then(() => wd.cancelPopup()); + }); it('should grab text from popup', () => { return wd .amOnPage('/form/popup') .then(() => wd.click('Alert')) .then(() => wd.grabPopupText()) - .then((text) => assert.equal(text, 'Really?')) - }) + .then((text) => assert.equal(text, 'Really?')); + }); it('should return null if no popup is visible (do not throw an error)', () => { return wd .amOnPage('/form/popup') .then(() => wd.grabPopupText()) - .then((text) => assert.equal(text, null)) - }) - }) + .then((text) => assert.equal(text, null)); + }); + }); describe('#waitForText', () => { it('should return error if not present', () => { @@ -750,9 +750,9 @@ describe('WebDriver', function () { .catch((e) => { e.message.should.be.equal( 'element (#text) is not in DOM or there is no element(#text) with text "Nothing here" after 1 sec', - ) - }) - }) + ); + }); + }); it('should return error if waiting is too small', () => { return wd @@ -761,83 +761,83 @@ describe('WebDriver', function () { .catch((e) => { e.message.should.be.equal( 'element (body) is not in DOM or there is no element(body) with text "Dynamic text" after 0.1 sec', - ) - }) - }) - }) + ); + }); + }); + }); describe('#seeNumberOfElements', () => { it('should return 1 as count', async () => { - await wd.amOnPage('/') - await wd.seeNumberOfElements('#area1', 1) - }) - }) + await wd.amOnPage('/'); + await wd.seeNumberOfElements('#area1', 1); + }); + }); describe('#switchTo', () => { it('should switch reference to iframe content', async () => { - await wd.amOnPage('/iframe') - await wd.switchTo('[name="content"]') - await wd.see('Information\nLots of valuable data here') - }) + await wd.amOnPage('/iframe'); + await wd.switchTo('[name="content"]'); + await wd.see('Information\nLots of valuable data here'); + }); it('should return error if iframe selector is invalid', async () => { - await wd.amOnPage('/iframe') + await wd.amOnPage('/iframe'); try { - await wd.switchTo('#invalidIframeSelector') + await wd.switchTo('#invalidIframeSelector'); } catch (e) { - e.should.be.instanceOf(Error) - e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath') + e.should.be.instanceOf(Error); + e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath'); } - }) + }); it('should return error if iframe selector is not iframe', async () => { - await wd.amOnPage('/iframe') + await wd.amOnPage('/iframe'); try { - await wd.switchTo('h1') + await wd.switchTo('h1'); } catch (e) { - e.should.be.instanceOf(Error) - e.message.should.contain('no such frame') + e.should.be.instanceOf(Error); + e.message.should.contain('no such frame'); } - }) + }); it('should return to parent frame given a null locator', async () => { - await wd.amOnPage('/iframe') - await wd.switchTo('[name="content"]') - await wd.see('Information\nLots of valuable data here') - await wd.switchTo(null) - await wd.see('Iframe test') - }) - }) + await wd.amOnPage('/iframe'); + await wd.switchTo('[name="content"]'); + await wd.see('Information\nLots of valuable data here'); + await wd.switchTo(null); + await wd.see('Iframe test'); + }); + }); describe('click context', () => { it('should click on inner text', async () => { - await wd.amOnPage('/form/checkbox') - await wd.click('Submit', '//input[@type = "submit"]') - await wd.waitInUrl('/form/complex') - }) + await wd.amOnPage('/form/checkbox'); + await wd.click('Submit', '//input[@type = "submit"]'); + await wd.waitInUrl('/form/complex'); + }); it('should click on input in inner element', async () => { - await wd.amOnPage('/form/checkbox') - await wd.click('Submit', '//form') - await wd.waitInUrl('/form/complex') - }) + await wd.amOnPage('/form/checkbox'); + await wd.click('Submit', '//form'); + await wd.waitInUrl('/form/complex'); + }); it('should click by accessibility_id', async () => { - await wd.amOnPage('/info') - await wd.click('~index via aria-label') - await wd.see('Welcome to test app!') - }) - }) + await wd.amOnPage('/info'); + await wd.click('~index via aria-label'); + await wd.see('Welcome to test app!'); + }); + }); describe('window size #resizeWindow', () => { it('should set initial window size', async () => { - await wd.amOnPage('/form/resize') - await wd.click('Window Size') - await wd.see('Height 700', '#height') - await wd.see('Width 500', '#width') - }) + await wd.amOnPage('/form/resize'); + await wd.click('Window Size'); + await wd.see('Height 700', '#height'); + await wd.see('Width 500', '#width'); + }); it('should set window size on new session', () => { return wd @@ -853,419 +853,419 @@ describe('WebDriver', function () { .then(() => wd.amOnPage('/form/resize')) .then(() => wd.click('Window Size')) .then(() => wd.see('Height 700', '#height')) - .then(() => wd.see('Width 500', '#width')) - }) + .then(() => wd.see('Width 500', '#width')); + }); it('should resize window to specific dimensions', async () => { - await wd.amOnPage('/form/resize') - await wd.resizeWindow(950, 600) - await wd.click('Window Size') - await wd.see('Height 600', '#height') - await wd.see('Width 950', '#width') - }) + await wd.amOnPage('/form/resize'); + await wd.resizeWindow(950, 600); + await wd.click('Window Size'); + await wd.see('Height 600', '#height'); + await wd.see('Width 950', '#width'); + }); xit('should resize window to maximum screen dimensions', async () => { - await wd.amOnPage('/form/resize') - await wd.resizeWindow(500, 400) - await wd.click('Window Size') - await wd.see('Height 400', '#height') - await wd.see('Width 500', '#width') - await wd.resizeWindow('maximize') - await wd.click('Window Size') - await wd.dontSee('Height 400', '#height') - await wd.dontSee('Width 500', '#width') - }) - }) + await wd.amOnPage('/form/resize'); + await wd.resizeWindow(500, 400); + await wd.click('Window Size'); + await wd.see('Height 400', '#height'); + await wd.see('Width 500', '#width'); + await wd.resizeWindow('maximize'); + await wd.click('Window Size'); + await wd.dontSee('Height 400', '#height'); + await wd.dontSee('Width 500', '#width'); + }); + }); describe('SmartWait', () => { - before(() => (wd.options.smartWait = 3000)) - after(() => (wd.options.smartWait = 0)) + before(() => (wd.options.smartWait = 3000)); + after(() => (wd.options.smartWait = 0)); it('should wait for element to appear', async () => { - await wd.amOnPage('/form/wait_element') - await wd.dontSeeElement('h1') - await wd.seeElement('h1') - }) + await wd.amOnPage('/form/wait_element'); + await wd.dontSeeElement('h1'); + await wd.seeElement('h1'); + }); it('should wait for clickable element appear', async () => { - await wd.amOnPage('/form/wait_clickable') - await wd.dontSeeElement('#click') - await wd.click('#click') - await wd.see('Hi!') - }) + await wd.amOnPage('/form/wait_clickable'); + await wd.dontSeeElement('#click'); + await wd.click('#click'); + await wd.see('Hi!'); + }); it('should wait for clickable context to appear', async () => { - await wd.amOnPage('/form/wait_clickable') - await wd.dontSeeElement('#linkContext') - await wd.click('Hello world', '#linkContext') - await wd.see('Hi!') - }) + await wd.amOnPage('/form/wait_clickable'); + await wd.dontSeeElement('#linkContext'); + await wd.click('Hello world', '#linkContext'); + await wd.see('Hi!'); + }); it('should wait for text context to appear', async () => { - await wd.amOnPage('/form/wait_clickable') - await wd.dontSee('Hello world') - await wd.see('Hello world', '#linkContext') - }) + await wd.amOnPage('/form/wait_clickable'); + await wd.dontSee('Hello world'); + await wd.see('Hello world', '#linkContext'); + }); it('should work with grabbers', async () => { - await wd.amOnPage('/form/wait_clickable') - await wd.dontSee('Hello world') - const res = await wd.grabAttributeFrom('#click', 'id') - assert.equal(res, 'click') - }) - }) + await wd.amOnPage('/form/wait_clickable'); + await wd.dontSee('Hello world'); + const res = await wd.grabAttributeFrom('#click', 'id'); + assert.equal(res, 'click'); + }); + }); describe('#_locateClickable', () => { it('should locate a button to click', async () => { - await wd.amOnPage('/form/checkbox') - const res = await wd._locateClickable('Submit') - res.length.should.be.equal(1) - }) + await wd.amOnPage('/form/checkbox'); + const res = await wd._locateClickable('Submit'); + res.length.should.be.equal(1); + }); it('should not locate a non-existing checkbox', async () => { - await wd.amOnPage('/form/checkbox') - const res = await wd._locateClickable('I disagree') - res.length.should.be.equal(0) - }) - }) + await wd.amOnPage('/form/checkbox'); + const res = await wd._locateClickable('I disagree'); + res.length.should.be.equal(0); + }); + }); describe('#_locateCheckable', () => { it('should locate a checkbox', async () => { - await wd.amOnPage('/form/checkbox') - const res = await wd._locateCheckable('I Agree') - res.length.should.be.equal(1) - }) + await wd.amOnPage('/form/checkbox'); + const res = await wd._locateCheckable('I Agree'); + res.length.should.be.equal(1); + }); it('should not locate a non-existing checkbox', async () => { - await wd.amOnPage('/form/checkbox') - const res = await wd._locateCheckable('I disagree') - res.length.should.be.equal(0) - }) - }) + await wd.amOnPage('/form/checkbox'); + const res = await wd._locateCheckable('I disagree'); + res.length.should.be.equal(0); + }); + }); describe('#_locateFields', () => { it('should locate a field', async () => { - await wd.amOnPage('/form/field') - const res = await wd._locateFields('Name') - res.length.should.be.equal(1) - }) + await wd.amOnPage('/form/field'); + const res = await wd._locateFields('Name'); + res.length.should.be.equal(1); + }); it('should not locate a non-existing field', async () => { - await wd.amOnPage('/form/field') - const res = await wd._locateFields('Mother-in-law') - res.length.should.be.equal(0) - }) - }) + await wd.amOnPage('/form/field'); + const res = await wd._locateFields('Mother-in-law'); + res.length.should.be.equal(0); + }); + }); xdescribe('#grabBrowserLogs', () => { it('should grab browser logs', async () => { - await wd.amOnPage('/') + await wd.amOnPage('/'); await wd.executeScript(() => { - console.log('Test log entry') - }) - const logs = await wd.grabBrowserLogs() - console.log('lololo', logs) + console.log('Test log entry'); + }); + const logs = await wd.grabBrowserLogs(); + console.log('lololo', logs); - const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1) - assert.equal(matchingLogs.length, 1) - }) + const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1); + assert.equal(matchingLogs.length, 1); + }); it('should grab browser logs across pages', async () => { - wd.amOnPage('/') + wd.amOnPage('/'); await wd.executeScript(() => { - console.log('Test log entry 1') - }) - await wd.openNewTab() - await wd.amOnPage('/info') + console.log('Test log entry 1'); + }); + await wd.openNewTab(); + await wd.amOnPage('/info'); await wd.executeScript(() => { - console.log('Test log entry 2') - }) + console.log('Test log entry 2'); + }); - const logs = await wd.grabBrowserLogs() + const logs = await wd.grabBrowserLogs(); - const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1) - assert.equal(matchingLogs.length, 2) - }) - }) + const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1); + assert.equal(matchingLogs.length, 2); + }); + }); describe('#dragAndDrop', () => { it('Drag item from source to target (no iframe) @dragNdrop', async () => { - await wd.amOnPage('http://jqueryui.com/resources/demos/droppable/default.html') - await wd.seeElementInDOM('#draggable') - await wd.dragAndDrop('#draggable', '#droppable') - await wd.see('Dropped') - }) + await wd.amOnPage('http://jqueryui.com/resources/demos/droppable/default.html'); + await wd.seeElementInDOM('#draggable'); + await wd.dragAndDrop('#draggable', '#droppable'); + await wd.see('Dropped'); + }); it('Drag and drop from within an iframe', async () => { - await wd.amOnPage('http://jqueryui.com/droppable') - await wd.resizeWindow(700, 700) - await wd.switchTo('//iframe[@class="demo-frame"]') - await wd.seeElementInDOM('#draggable') - await wd.dragAndDrop('#draggable', '#droppable') - await wd.see('Dropped') - }) - }) + await wd.amOnPage('http://jqueryui.com/droppable'); + await wd.resizeWindow(700, 700); + await wd.switchTo('//iframe[@class="demo-frame"]'); + await wd.seeElementInDOM('#draggable'); + await wd.dragAndDrop('#draggable', '#droppable'); + await wd.see('Dropped'); + }); + }); describe('#switchTo frame', () => { it('should switch to frame using name', async () => { - await wd.amOnPage('/iframe') - await wd.see('Iframe test', 'h1') - await wd.dontSee('Information', 'h1') - await wd.switchTo('iframe') - await wd.see('Information', 'h1') - await wd.dontSee('Iframe test', 'h1') - }) + await wd.amOnPage('/iframe'); + await wd.see('Iframe test', 'h1'); + await wd.dontSee('Information', 'h1'); + await wd.switchTo('iframe'); + await wd.see('Information', 'h1'); + await wd.dontSee('Iframe test', 'h1'); + }); it('should switch to root frame', async () => { - await wd.amOnPage('/iframe') - await wd.see('Iframe test', 'h1') - await wd.dontSee('Information', 'h1') - await wd.switchTo('iframe') - await wd.see('Information', 'h1') - await wd.dontSee('Iframe test', 'h1') - await wd.switchTo() - await wd.see('Iframe test', 'h1') - }) + await wd.amOnPage('/iframe'); + await wd.see('Iframe test', 'h1'); + await wd.dontSee('Information', 'h1'); + await wd.switchTo('iframe'); + await wd.see('Information', 'h1'); + await wd.dontSee('Iframe test', 'h1'); + await wd.switchTo(); + await wd.see('Iframe test', 'h1'); + }); it('should switch to frame using frame number', async () => { - await wd.amOnPage('/iframe') - await wd.see('Iframe test', 'h1') - await wd.dontSee('Information', 'h1') - await wd.switchTo(0) - await wd.see('Information', 'h1') - await wd.dontSee('Iframe test', 'h1') - }) - }) + await wd.amOnPage('/iframe'); + await wd.see('Iframe test', 'h1'); + await wd.dontSee('Information', 'h1'); + await wd.switchTo(0); + await wd.see('Information', 'h1'); + await wd.dontSee('Iframe test', 'h1'); + }); + }); describe('#AttachFile', () => { it('should attach to regular input element', async () => { - await wd.amOnPage('/form/file') - await wd.attachFile('Avatar', './app/avatar.jpg') - await wd.seeInField('Avatar', 'avatar.jpg') - }) + await wd.amOnPage('/form/file'); + await wd.attachFile('Avatar', './app/avatar.jpg'); + await wd.seeInField('Avatar', 'avatar.jpg'); + }); it('should attach to invisible input element', async () => { - await wd.amOnPage('/form/file') - await wd.attachFile('hidden', '/app/avatar.jpg') - }) - }) + await wd.amOnPage('/form/file'); + await wd.attachFile('hidden', '/app/avatar.jpg'); + }); + }); describe('#dragSlider', () => { it('should drag scrubber to given position', async () => { - await wd.amOnPage('/form/page_slider') - await wd.seeElementInDOM('#slidecontainer input') + await wd.amOnPage('/form/page_slider'); + await wd.seeElementInDOM('#slidecontainer input'); - const before = await wd.grabValueFrom('#slidecontainer input') - await wd.dragSlider('#slidecontainer input', 20) - const after = await wd.grabValueFrom('#slidecontainer input') + const before = await wd.grabValueFrom('#slidecontainer input'); + await wd.dragSlider('#slidecontainer input', 20); + const after = await wd.grabValueFrom('#slidecontainer input'); - assert.notEqual(before, after) - }) - }) + assert.notEqual(before, after); + }); + }); describe('#uncheckOption', () => { it('should uncheck option that is currently checked', async () => { - await wd.amOnPage('/info') - await wd.uncheckOption('interesting') - await wd.dontSeeCheckboxIsChecked('interesting') - }) + await wd.amOnPage('/info'); + await wd.uncheckOption('interesting'); + await wd.dontSeeCheckboxIsChecked('interesting'); + }); it('should NOT uncheck option that is NOT currently checked', async () => { - await wd.amOnPage('/info') - await wd.uncheckOption('interesting') + await wd.amOnPage('/info'); + await wd.uncheckOption('interesting'); // Unchecking again should not affect the current 'unchecked' status - await wd.uncheckOption('interesting') - await wd.dontSeeCheckboxIsChecked('interesting') - }) - }) + await wd.uncheckOption('interesting'); + await wd.dontSeeCheckboxIsChecked('interesting'); + }); + }); describe('allow back and forth between handles: #grabAllWindowHandles #grabCurrentWindowHandle #switchToWindow', () => { it('should open main page of configured site, open a popup, switch to main page, then switch to popup, close popup, and go back to main page', async () => { - await wd.amOnPage('/') - const handleBeforePopup = await wd.grabCurrentWindowHandle() - const urlBeforePopup = await wd.grabCurrentUrl() + await wd.amOnPage('/'); + const handleBeforePopup = await wd.grabCurrentWindowHandle(); + const urlBeforePopup = await wd.grabCurrentUrl(); - const allHandlesBeforePopup = await wd.grabAllWindowHandles() - allHandlesBeforePopup.length.should.eql(1) + const allHandlesBeforePopup = await wd.grabAllWindowHandles(); + allHandlesBeforePopup.length.should.eql(1); await wd.executeScript(() => { window.open( 'https://www.w3schools.com/', 'new window', 'toolbar=yes,scrollbars=yes,resizable=yes,width=400,height=400', - ) - }) + ); + }); - const allHandlesAfterPopup = await wd.grabAllWindowHandles() - allHandlesAfterPopup.length.should.eql(2) + const allHandlesAfterPopup = await wd.grabAllWindowHandles(); + allHandlesAfterPopup.length.should.eql(2); - await wd.switchToWindow(allHandlesAfterPopup[1]) - const urlAfterPopup = await wd.grabCurrentUrl() - urlAfterPopup.should.eql('https://www.w3schools.com/') + await wd.switchToWindow(allHandlesAfterPopup[1]); + const urlAfterPopup = await wd.grabCurrentUrl(); + urlAfterPopup.should.eql('https://www.w3schools.com/'); - handleBeforePopup.should.eql(allHandlesAfterPopup[0]) - await wd.switchToWindow(handleBeforePopup) - const currentURL = await wd.grabCurrentUrl() - currentURL.should.eql(urlBeforePopup) + handleBeforePopup.should.eql(allHandlesAfterPopup[0]); + await wd.switchToWindow(handleBeforePopup); + const currentURL = await wd.grabCurrentUrl(); + currentURL.should.eql(urlBeforePopup); - await wd.switchToWindow(allHandlesAfterPopup[1]) - const urlAfterSwitchBack = await wd.grabCurrentUrl() - urlAfterSwitchBack.should.eql('https://www.w3schools.com/') - await wd.closeCurrentTab() + await wd.switchToWindow(allHandlesAfterPopup[1]); + const urlAfterSwitchBack = await wd.grabCurrentUrl(); + urlAfterSwitchBack.should.eql('https://www.w3schools.com/'); + await wd.closeCurrentTab(); - const allHandlesAfterPopupClosed = await wd.grabAllWindowHandles() - allHandlesAfterPopupClosed.length.should.eql(1) - const currentWindowHandle = await wd.grabCurrentWindowHandle() - currentWindowHandle.should.eql(handleBeforePopup) - }) - }) + const allHandlesAfterPopupClosed = await wd.grabAllWindowHandles(); + allHandlesAfterPopupClosed.length.should.eql(1); + const currentWindowHandle = await wd.grabCurrentWindowHandle(); + currentWindowHandle.should.eql(handleBeforePopup); + }); + }); describe('#waitForClickable', () => { it('should wait for clickable', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd.waitForClickable({ css: 'input#text' }) - }) + await wd.amOnPage('/form/wait_for_clickable'); + await wd.waitForClickable({ css: 'input#text' }); + }); it('should wait for clickable by XPath', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd.waitForClickable({ xpath: './/input[@id="text"]' }) - }) + await wd.amOnPage('/form/wait_for_clickable'); + await wd.waitForClickable({ xpath: './/input[@id="text"]' }); + }); it('should fail for disabled element', async () => { - await wd.amOnPage('/form/wait_for_clickable') + await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#button' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element #button still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element #button still not clickable after 0.1 sec'); + }); + }); it('should fail for disabled element by XPath', async () => { - await wd.amOnPage('/form/wait_for_clickable') + await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ xpath: './/button[@id="button"]' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element .//button[@id="button"] still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element .//button[@id="button"] still not clickable after 0.1 sec'); + }); + }); it('should fail for element not in viewport by top', async () => { - await wd.amOnPage('/form/wait_for_clickable') + await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportTop' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element #notInViewportTop still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element #notInViewportTop still not clickable after 0.1 sec'); + }); + }); it('should fail for element not in viewport by bottom', async () => { - await wd.amOnPage('/form/wait_for_clickable') + await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportBottom' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element #notInViewportBottom still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element #notInViewportBottom still not clickable after 0.1 sec'); + }); + }); it('should fail for element not in viewport by left', async () => { - await wd.amOnPage('/form/wait_for_clickable') + await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportLeft' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element #notInViewportLeft still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element #notInViewportLeft still not clickable after 0.1 sec'); + }); + }); it('should fail for element not in viewport by right', async () => { - await wd.amOnPage('/form/wait_for_clickable') + await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportRight' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element #notInViewportRight still not clickable after 0.1 sec') - }) - }) + e.message.should.include('element #notInViewportRight still not clickable after 0.1 sec'); + }); + }); it('should fail for overlapping element', async () => { - await wd.amOnPage('/form/wait_for_clickable') - await wd.waitForClickable({ css: '#div2_button' }, 0.1) + await wd.amOnPage('/form/wait_for_clickable'); + await wd.waitForClickable({ css: '#div2_button' }, 0.1); await wd .waitForClickable({ css: '#div1_button' }, 0.1) .then((isClickable) => { - if (isClickable) throw new Error('Element is clickable, but must be unclickable') + if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) .catch((e) => { - e.message.should.include('element #div1_button still not clickable after 0.1 sec') - }) - }) - }) + e.message.should.include('element #div1_button still not clickable after 0.1 sec'); + }); + }); + }); describe('#grabElementBoundingRect', () => { it('should get the element size', async () => { - await wd.amOnPage('/form/hidden') - const size = await wd.grabElementBoundingRect('input[type=submit]') - expect(size.x).is.greaterThan(0) - expect(size.y).is.greaterThan(0) - expect(size.width).is.greaterThan(0) - expect(size.height).is.greaterThan(0) - }) + await wd.amOnPage('/form/hidden'); + const size = await wd.grabElementBoundingRect('input[type=submit]'); + expect(size.x).is.greaterThan(0); + expect(size.y).is.greaterThan(0); + expect(size.width).is.greaterThan(0); + expect(size.height).is.greaterThan(0); + }); it('should get the element width', async () => { - await wd.amOnPage('/form/hidden') - const width = await wd.grabElementBoundingRect('input[type=submit]', 'width') - expect(width).is.greaterThan(0) - }) + await wd.amOnPage('/form/hidden'); + const width = await wd.grabElementBoundingRect('input[type=submit]', 'width'); + expect(width).is.greaterThan(0); + }); it('should get the element height', async () => { - await wd.amOnPage('/form/hidden') - const height = await wd.grabElementBoundingRect('input[type=submit]', 'height') - expect(height).is.greaterThan(0) - }) - }) + await wd.amOnPage('/form/hidden'); + const height = await wd.grabElementBoundingRect('input[type=submit]', 'height'); + expect(height).is.greaterThan(0); + }); + }); describe('#scrollIntoView', () => { it.skip('should scroll element into viewport', async () => { - await wd.amOnPage('/form/scroll_into_view') - const element = await wd.browser.$('#notInViewportByDefault') - expect(await element.isDisplayedInViewport()).to.be.false - await wd.scrollIntoView('#notInViewportByDefault') - expect(await element.isDisplayedInViewport()).to.be.true - }) - }) + await wd.amOnPage('/form/scroll_into_view'); + const element = await wd.browser.$('#notInViewportByDefault'); + expect(await element.isDisplayedInViewport()).to.be.false; + await wd.scrollIntoView('#notInViewportByDefault'); + expect(await element.isDisplayedInViewport()).to.be.true; + }); + }); describe('#useWebDriverTo', () => { it('should return title', async () => { - await wd.amOnPage('/') + await wd.amOnPage('/'); const title = await wd.useWebDriverTo('test', async ({ browser }) => { - return browser.getTitle() - }) - assert.equal('TestEd Beta 2.0', title) - }) - }) -}) + return browser.getTitle(); + }); + assert.equal('TestEd Beta 2.0', title); + }); + }); +}); describe('WebDriver - Basic Authentication', () => { before(() => { - global.codecept_dir = path.join(__dirname, '/../data') + global.codecept_dir = path.join(__dirname, '/../data'); try { - fs.unlinkSync(dataFile) + fs.unlinkSync(dataFile); } catch (err) { // continue regardless of error } @@ -1285,20 +1285,20 @@ describe('WebDriver - Basic Authentication', () => { args: ['--headless', '--disable-gpu', '--window-size=1280,1024'], }, }, - }) - }) + }); + }); beforeEach(async () => { - webApiTests.init({ I: wd, siteUrl }) - await wd._before() - }) + webApiTests.init({ I: wd, siteUrl }); + await wd._before(); + }); - afterEach(() => wd._after()) + afterEach(() => wd._after()); describe('open page : #amOnPage', () => { it('should be authenticated', async () => { - await wd.amOnPage('/basic_auth') - await wd.see('You entered admin as your password.') - }) - }) -}) + await wd.amOnPage('/basic_auth'); + await wd.see('You entered admin as your password.'); + }); + }); +}); diff --git a/test/helper/webapi.js b/test/helper/webapi.js index 13451d60e..8197205d1 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -1,759 +1,763 @@ -const chai = require('chai') +const chai = require('chai'); -const expect = chai.expect -const assert = chai.assert -const path = require('path') +const expect = chai.expect; +const assert = chai.assert; +const path = require('path'); -const dataFile = path.join(__dirname, '/../data/app/db') -const formContents = require('../../lib/utils').test.submittedData(dataFile) -const fileExists = require('../../lib/utils').fileExists -const secret = require('../../lib/secret').secret +const dataFile = path.join(__dirname, '/../data/app/db'); +const formContents = require('../../lib/utils').test.submittedData(dataFile); +const fileExists = require('../../lib/utils').fileExists; +const secret = require('../../lib/secret').secret; -const Locator = require('../../lib/locator') -const customLocators = require('../../lib/plugin/customLocator') +const Locator = require('../../lib/locator'); +const customLocators = require('../../lib/plugin/customLocator'); -let originalLocators -let I -let data -let siteUrl +let originalLocators; +let I; +let data; +let siteUrl; module.exports.init = function (testData) { - data = testData -} + data = testData; +}; module.exports.tests = function () { - const isHelper = (helperName) => I.constructor.name === helperName + const isHelper = (helperName) => I.constructor.name === helperName; beforeEach(() => { - I = data.I - siteUrl = data.siteUrl - if (fileExists(dataFile)) require('fs').unlinkSync(dataFile) - }) + I = data.I; + siteUrl = data.siteUrl; + if (fileExists(dataFile)) require('fs').unlinkSync(dataFile); + }); describe('#saveElementScreenshot', () => { beforeEach(() => { - global.output_dir = path.join(global.codecept_dir, 'output') - }) + global.output_dir = path.join(global.codecept_dir, 'output'); + }); it('should create a screenshot file in output dir of element', async () => { - await I.amOnPage('/form/field') - await I.seeElement("input[name='name']") - const sec = new Date().getUTCMilliseconds() - await I.saveElementScreenshot("input[name='name']", `element_screenshot_${sec}.png`) - assert.ok(fileExists(path.join(global.output_dir, `element_screenshot_${sec}.png`)), null, 'file does not exists') - }) - }) + await I.amOnPage('/form/field'); + await I.seeElement("input[name='name']"); + const sec = new Date().getUTCMilliseconds(); + await I.saveElementScreenshot("input[name='name']", `element_screenshot_${sec}.png`); + assert.ok( + fileExists(path.join(global.output_dir, `element_screenshot_${sec}.png`)), + null, + 'file does not exists', + ); + }); + }); describe('current url : #seeInCurrentUrl, #seeCurrentUrlEquals, #grabCurrentUrl, ...', () => { it('should check for url fragment', async () => { - await I.amOnPage('/form/checkbox') - await I.seeInCurrentUrl('/form') - await I.dontSeeInCurrentUrl('/user') - }) + await I.amOnPage('/form/checkbox'); + await I.seeInCurrentUrl('/form'); + await I.dontSeeInCurrentUrl('/user'); + }); it('should check for equality', async () => { - await I.amOnPage('/info') - await I.seeCurrentUrlEquals('/info') - await I.dontSeeCurrentUrlEquals('form') - }) + await I.amOnPage('/info'); + await I.seeCurrentUrlEquals('/info'); + await I.dontSeeCurrentUrlEquals('form'); + }); it('should check for equality in absolute urls', async () => { - await I.amOnPage('/info') - await I.seeCurrentUrlEquals(`${siteUrl}/info`) - await I.dontSeeCurrentUrlEquals(`${siteUrl}/form`) - }) + await I.amOnPage('/info'); + await I.seeCurrentUrlEquals(`${siteUrl}/info`); + await I.dontSeeCurrentUrlEquals(`${siteUrl}/form`); + }); it('should grab browser url', async () => { - await I.amOnPage('/info') - const url = await I.grabCurrentUrl() - assert.equal(url, `${siteUrl}/info`) - }) - }) + await I.amOnPage('/info'); + const url = await I.grabCurrentUrl(); + assert.equal(url, `${siteUrl}/info`); + }); + }); describe('#waitInUrl, #waitUrlEquals', () => { it('should wait part of the URL to match the expected', async () => { try { - await I.amOnPage('/info') - await I.waitInUrl('/info') - await I.waitInUrl('/info2', 0.1) + await I.amOnPage('/info'); + await I.waitInUrl('/info'); + await I.waitInUrl('/info2', 0.1); } catch (e) { - assert.include(e.message, `expected url to include /info2, but found ${siteUrl}/info`) + assert.include(e.message, `expected url to include /info2, but found ${siteUrl}/info`); } - }) + }); it('should wait for the entire URL to match the expected', async () => { try { - await I.amOnPage('/info') - await I.waitUrlEquals('/info') - await I.waitUrlEquals(`${siteUrl}/info`) - await I.waitUrlEquals('/info2', 0.1) + await I.amOnPage('/info'); + await I.waitUrlEquals('/info'); + await I.waitUrlEquals(`${siteUrl}/info`); + await I.waitUrlEquals('/info2', 0.1); } catch (e) { - assert.include(e.message, `expected url to be ${siteUrl}/info2, but found ${siteUrl}/info`) + assert.include(e.message, `expected url to be ${siteUrl}/info2, but found ${siteUrl}/info`); } - }) - }) + }); + }); describe('see text : #see', () => { it('should check text on site', async () => { - await I.amOnPage('/') - await I.see('Welcome to test app!') - await I.see('A wise man said: "debug!"') - await I.dontSee('Info') - }) + await I.amOnPage('/'); + await I.see('Welcome to test app!'); + await I.see('A wise man said: "debug!"'); + await I.dontSee('Info'); + }); it('should check text inside element', async () => { - await I.amOnPage('/') - await I.see('Welcome to test app!', 'h1') - await I.amOnPage('/info') - await I.see('valuable', { css: 'p' }) - await I.see('valuable', '//p') - await I.dontSee('valuable', 'h1') - }) + await I.amOnPage('/'); + await I.see('Welcome to test app!', 'h1'); + await I.amOnPage('/info'); + await I.see('valuable', { css: 'p' }); + await I.see('valuable', '//p'); + await I.dontSee('valuable', 'h1'); + }); it('should verify non-latin chars', async () => { - await I.amOnPage('/info') - await I.see('на') - await I.see("Don't do that at home!", 'h3') - await I.see('Текст', 'p') - }) + await I.amOnPage('/info'); + await I.see('на'); + await I.see("Don't do that at home!", 'h3'); + await I.see('Текст', 'p'); + }); it('should verify text with  ', async () => { - if (isHelper('TestCafe') || isHelper('WebDriver')) return - await I.amOnPage('/') - await I.see('With special space chars') - }) - }) + if (isHelper('TestCafe') || isHelper('WebDriver')) return; + await I.amOnPage('/'); + await I.see('With special space chars'); + }); + }); describe('see element : #seeElement, #seeElementInDOM, #dontSeeElement', () => { it('should check visible elements on page', async () => { - await I.amOnPage('/form/field') - await I.seeElement('input[name=name]') - await I.seeElement({ name: 'name' }) - await I.seeElement('//input[@id="name"]') - await I.dontSeeElement('#something-beyond') - await I.dontSeeElement('//input[@id="something-beyond"]') - await I.dontSeeElement({ name: 'noname' }) - await I.dontSeeElement('#noid') - }) + await I.amOnPage('/form/field'); + await I.seeElement('input[name=name]'); + await I.seeElement({ name: 'name' }); + await I.seeElement('//input[@id="name"]'); + await I.dontSeeElement('#something-beyond'); + await I.dontSeeElement('//input[@id="something-beyond"]'); + await I.dontSeeElement({ name: 'noname' }); + await I.dontSeeElement('#noid'); + }); it('should check elements are in the DOM', async () => { - await I.amOnPage('/form/field') - await I.seeElementInDOM('input[name=name]') - await I.seeElementInDOM('//input[@id="name"]') - await I.seeElementInDOM({ name: 'noname' }) - await I.seeElementInDOM('#noid') - await I.dontSeeElementInDOM('#something-beyond') - await I.dontSeeElementInDOM('//input[@id="something-beyond"]') - }) + await I.amOnPage('/form/field'); + await I.seeElementInDOM('input[name=name]'); + await I.seeElementInDOM('//input[@id="name"]'); + await I.seeElementInDOM({ name: 'noname' }); + await I.seeElementInDOM('#noid'); + await I.dontSeeElementInDOM('#something-beyond'); + await I.dontSeeElementInDOM('//input[@id="something-beyond"]'); + }); it('should check elements are visible on the page', async () => { - await I.amOnPage('/form/field') - await I.seeElementInDOM('input[name=email]') - await I.dontSeeElement('input[name=email]') - await I.dontSeeElement('#something-beyond') - }) - }) + await I.amOnPage('/form/field'); + await I.seeElementInDOM('input[name=email]'); + await I.dontSeeElement('input[name=email]'); + await I.dontSeeElement('#something-beyond'); + }); + }); describe('#seeNumberOfVisibleElements', () => { it('should check number of visible elements for given locator', async () => { - await I.amOnPage('/info') - await I.seeNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 3) - }) - }) + await I.amOnPage('/info'); + await I.seeNumberOfVisibleElements('//div[@id = "grab-multiple"]//a', 3); + }); + }); describe('#grabNumberOfVisibleElements', () => { it('should grab number of visible elements for given locator', async () => { - await I.amOnPage('/info') - const num = await I.grabNumberOfVisibleElements('//div[@id = "grab-multiple"]//a') - assert.equal(num, 3) - }) + await I.amOnPage('/info'); + const num = await I.grabNumberOfVisibleElements('//div[@id = "grab-multiple"]//a'); + assert.equal(num, 3); + }); it('should support locators like {xpath:"//div"}', async () => { - await I.amOnPage('/info') + await I.amOnPage('/info'); const num = await I.grabNumberOfVisibleElements({ xpath: '//div[@id = "grab-multiple"]//a', - }) - assert.equal(num, 3) - }) + }); + assert.equal(num, 3); + }); it('should grab number of visible elements for given css locator', async () => { - await I.amOnPage('/info') - const num = await I.grabNumberOfVisibleElements('[id=grab-multiple] a') - assert.equal(num, 3) - }) + await I.amOnPage('/info'); + const num = await I.grabNumberOfVisibleElements('[id=grab-multiple] a'); + assert.equal(num, 3); + }); it('should return 0 for non-existing elements', async () => { - await I.amOnPage('/info') - const num = await I.grabNumberOfVisibleElements('button[type=submit]') - assert.equal(num, 0) - }) + await I.amOnPage('/info'); + const num = await I.grabNumberOfVisibleElements('button[type=submit]'); + assert.equal(num, 0); + }); it('should honor visibility hidden style', async () => { - await I.amOnPage('/info') - const num = await I.grabNumberOfVisibleElements('.issue2928') - assert.equal(num, 1) - }) - }) + await I.amOnPage('/info'); + const num = await I.grabNumberOfVisibleElements('.issue2928'); + assert.equal(num, 1); + }); + }); describe('#seeInSource, #dontSeeInSource', () => { it('should check meta of a page', async () => { - await I.amOnPage('/info') - await I.seeInSource('') - await I.dontSeeInSource('') - await I.seeInSource('Invisible text') - await I.seeInSource('content="text/html; charset=utf-8"') - }) - }) + await I.amOnPage('/info'); + await I.seeInSource(''); + await I.dontSeeInSource(''); + await I.seeInSource('Invisible text'); + await I.seeInSource('content="text/html; charset=utf-8"'); + }); + }); describe('#click', () => { it('should click by inner text', async () => { - await I.amOnPage('/') - await I.click('More info') - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.click('More info'); + await I.seeInCurrentUrl('/info'); + }); it('should click by css', async () => { - await I.amOnPage('/') - await I.click('#link') - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.click('#link'); + await I.seeInCurrentUrl('/info'); + }); it('should click by xpath', async () => { - await I.amOnPage('/') - await I.click('//a[@id="link"]') - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.click('//a[@id="link"]'); + await I.seeInCurrentUrl('/info'); + }); it('should click by name', async () => { - await I.amOnPage('/form/button') - await I.click('btn0') - assert.equal(formContents('text'), 'val') - }) + await I.amOnPage('/form/button'); + await I.click('btn0'); + assert.equal(formContents('text'), 'val'); + }); it('should click on context', async () => { - await I.amOnPage('/') - await I.click('More info', 'body>p') - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.click('More info', 'body>p'); + await I.seeInCurrentUrl('/info'); + }); it('should not click wrong context', async () => { - let err = false - await I.amOnPage('/') + let err = false; + await I.amOnPage('/'); try { - await I.click('More info', '#area1') + await I.click('More info', '#area1'); } catch (e) { - err = true + err = true; } - assert.ok(err) - }) + assert.ok(err); + }); it('should should click by aria-label', async () => { - await I.amOnPage('/form/aria') - await I.click('get info') - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/form/aria'); + await I.click('get info'); + await I.seeInCurrentUrl('/info'); + }); it('should click link with inner span', async () => { - await I.amOnPage('/form/example7') - await I.click('Buy Chocolate Bar') - await I.seeCurrentUrlEquals('/') - }) + await I.amOnPage('/form/example7'); + await I.click('Buy Chocolate Bar'); + await I.seeCurrentUrlEquals('/'); + }); it('should click link with xpath locator', async () => { - await I.amOnPage('/form/example7') + await I.amOnPage('/form/example7'); await I.click({ xpath: '(//*[@title = "Chocolate Bar"])[1]', - }) - await I.seeCurrentUrlEquals('/') - }) - }) + }); + await I.seeCurrentUrlEquals('/'); + }); + }); describe('#forceClick', () => { beforeEach(function () { - if (isHelper('TestCafe')) this.skip() - }) + if (isHelper('TestCafe')) this.skip(); + }); it('should forceClick by inner text', async () => { - await I.amOnPage('/') - await I.forceClick('More info') - if (isHelper('Puppeteer')) await I.waitForNavigation() - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.forceClick('More info'); + if (isHelper('Puppeteer')) await I.waitForNavigation(); + await I.seeInCurrentUrl('/info'); + }); it('should forceClick by css', async () => { - await I.amOnPage('/') - await I.forceClick('#link') - if (isHelper('Puppeteer')) await I.waitForNavigation() - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.forceClick('#link'); + if (isHelper('Puppeteer')) await I.waitForNavigation(); + await I.seeInCurrentUrl('/info'); + }); it('should forceClick by xpath', async () => { - await I.amOnPage('/') - await I.forceClick('//a[@id="link"]') - if (isHelper('Puppeteer')) await I.waitForNavigation() - await I.seeInCurrentUrl('/info') - }) + await I.amOnPage('/'); + await I.forceClick('//a[@id="link"]'); + if (isHelper('Puppeteer')) await I.waitForNavigation(); + await I.seeInCurrentUrl('/info'); + }); it('should forceClick on context', async () => { - await I.amOnPage('/') - await I.forceClick('More info', 'body>p') - if (isHelper('Puppeteer')) await I.waitForNavigation() - await I.seeInCurrentUrl('/info') - }) - }) + await I.amOnPage('/'); + await I.forceClick('More info', 'body>p'); + if (isHelper('Puppeteer')) await I.waitForNavigation(); + await I.seeInCurrentUrl('/info'); + }); + }); // Could not get double click to work describe('#doubleClick', () => { it('it should doubleClick', async () => { - await I.amOnPage('/form/doubleclick') - await I.dontSee('Done') - await I.doubleClick('#block') - await I.see('Done') - }) - }) + await I.amOnPage('/form/doubleclick'); + await I.dontSee('Done'); + await I.doubleClick('#block'); + await I.see('Done'); + }); + }); // rightClick does not seem to work either describe('#rightClick', () => { it('it should rightClick', async () => { - await I.amOnPage('/form/rightclick') - await I.dontSee('right clicked') - await I.rightClick('Lorem Ipsum') - await I.see('right clicked') - }) + await I.amOnPage('/form/rightclick'); + await I.dontSee('right clicked'); + await I.rightClick('Lorem Ipsum'); + await I.see('right clicked'); + }); it('it should rightClick by locator', async () => { - await I.amOnPage('/form/rightclick') - await I.dontSee('right clicked') - await I.rightClick('.context a') - await I.see('right clicked') - }) + await I.amOnPage('/form/rightclick'); + await I.dontSee('right clicked'); + await I.rightClick('.context a'); + await I.see('right clicked'); + }); it('it should rightClick by locator and context', async () => { - await I.amOnPage('/form/rightclick') - await I.dontSee('right clicked') - await I.rightClick('Lorem Ipsum', '.context') - await I.see('right clicked') - }) - }) + await I.amOnPage('/form/rightclick'); + await I.dontSee('right clicked'); + await I.rightClick('Lorem Ipsum', '.context'); + await I.see('right clicked'); + }); + }); describe('#checkOption', () => { it('should check option by css', async () => { - await I.amOnPage('/form/checkbox') - await I.checkOption('#checkin') - await I.click('Submit') - await I.wait(1) - assert.equal(formContents('terms'), 'agree') - }) + await I.amOnPage('/form/checkbox'); + await I.checkOption('#checkin'); + await I.click('Submit'); + await I.wait(1); + assert.equal(formContents('terms'), 'agree'); + }); it('should check option by strict locator', async () => { - await I.amOnPage('/form/checkbox') + await I.amOnPage('/form/checkbox'); await I.checkOption({ id: 'checkin', - }) - await I.click('Submit') - assert.equal(formContents('terms'), 'agree') - }) + }); + await I.click('Submit'); + assert.equal(formContents('terms'), 'agree'); + }); it('should check option by name', async () => { - await I.amOnPage('/form/checkbox') - await I.checkOption('terms') - await I.click('Submit') - assert.equal(formContents('terms'), 'agree') - }) + await I.amOnPage('/form/checkbox'); + await I.checkOption('terms'); + await I.click('Submit'); + assert.equal(formContents('terms'), 'agree'); + }); it('should check option by label', async () => { - await I.amOnPage('/form/checkbox') - await I.checkOption('I Agree') - await I.click('Submit') - assert.equal(formContents('terms'), 'agree') - }) + await I.amOnPage('/form/checkbox'); + await I.checkOption('I Agree'); + await I.click('Submit'); + assert.equal(formContents('terms'), 'agree'); + }); // TODO Having problems with functional style selectors in testcafe // cannot do Selector(css).find(elementByXPath(xpath)) // testcafe always says "xpath is not defined" // const el = Selector(context).find(elementByXPath(Locator.checkable.byText(xpathLocator.literal(field))).with({ boundTestRun: this.t })).with({ boundTestRun: this.t }); it.skip('should check option by context', async () => { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/example1') - await I.checkOption('Remember me next time', '.rememberMe') - await I.click('Login') - assert.equal(formContents('LoginForm').rememberMe, 1) - }) - }) + await I.amOnPage('/form/example1'); + await I.checkOption('Remember me next time', '.rememberMe'); + await I.click('Login'); + assert.equal(formContents('LoginForm').rememberMe, 1); + }); + }); describe('#uncheckOption', () => { it('should uncheck option that is currently checked', async () => { - await I.amOnPage('/info') - await I.uncheckOption('interesting') - await I.dontSeeCheckboxIsChecked('interesting') - }) - }) + await I.amOnPage('/info'); + await I.uncheckOption('interesting'); + await I.dontSeeCheckboxIsChecked('interesting'); + }); + }); describe('#selectOption', () => { it('should select option by css', async () => { - await I.amOnPage('/form/select') - await I.selectOption('form select[name=age]', 'adult') - await I.click('Submit') - assert.equal(formContents('age'), 'adult') - }) + await I.amOnPage('/form/select'); + await I.selectOption('form select[name=age]', 'adult'); + await I.click('Submit'); + assert.equal(formContents('age'), 'adult'); + }); it('should select option by name', async () => { - await I.amOnPage('/form/select') - await I.selectOption('age', 'adult') - await I.click('Submit') - assert.equal(formContents('age'), 'adult') - }) + await I.amOnPage('/form/select'); + await I.selectOption('age', 'adult'); + await I.click('Submit'); + assert.equal(formContents('age'), 'adult'); + }); it('should select option by label', async () => { - await I.amOnPage('/form/select') - await I.selectOption('Select your age', 'dead') - await I.click('Submit') - assert.equal(formContents('age'), 'dead') - }) + await I.amOnPage('/form/select'); + await I.selectOption('Select your age', 'dead'); + await I.click('Submit'); + assert.equal(formContents('age'), 'dead'); + }); it('should select option by label and option text', async () => { - await I.amOnPage('/form/select') - await I.selectOption('Select your age', '21-60') - await I.click('Submit') - assert.equal(formContents('age'), 'adult') - }) + await I.amOnPage('/form/select'); + await I.selectOption('Select your age', '21-60'); + await I.click('Submit'); + assert.equal(formContents('age'), 'adult'); + }); it('should select option by label and option text - with an onchange callback', async () => { - await I.amOnPage('/form/select_onchange') - await I.selectOption('Select a value', 'Option 2') - await I.click('Submit') - assert.equal(formContents('select'), 'option2') - }) + await I.amOnPage('/form/select_onchange'); + await I.selectOption('Select a value', 'Option 2'); + await I.click('Submit'); + assert.equal(formContents('select'), 'option2'); + }); // Could not get multiselect to work with testcafe it('should select multiple options', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/select_multiple') - await I.selectOption('What do you like the most?', ['Play Video Games', 'Have Sex']) - await I.click('Submit') - assert.deepEqual(formContents('like'), ['play', 'adult']) - }) + await I.amOnPage('/form/select_multiple'); + await I.selectOption('What do you like the most?', ['Play Video Games', 'Have Sex']); + await I.click('Submit'); + assert.deepEqual(formContents('like'), ['play', 'adult']); + }); it('should select option by label and option text with additional spaces', async () => { - await I.amOnPage('/form/select_additional_spaces') - await I.selectOption('Select your age', '21-60') - await I.click('Submit') - assert.equal(formContents('age'), 'adult') - }) - }) + await I.amOnPage('/form/select_additional_spaces'); + await I.selectOption('Select your age', '21-60'); + await I.click('Submit'); + assert.equal(formContents('age'), 'adult'); + }); + }); describe('#executeScript', () => { it('should execute synchronous script', async () => { - await I.amOnPage('/') + await I.amOnPage('/'); await I.executeScript(() => { - document.getElementById('link').innerHTML = 'Appended' - }) - await I.see('Appended', 'a') - }) + document.getElementById('link').innerHTML = 'Appended'; + }); + await I.see('Appended', 'a'); + }); it('should return value from sync script', async () => { - await I.amOnPage('/') - const val = await I.executeScript((a) => a + 5, 5) - assert.equal(val, 10) - }) + await I.amOnPage('/'); + const val = await I.executeScript((a) => a + 5, 5); + assert.equal(val, 10); + }); it('should return value from sync script in iframe', async function () { // TODO Not yet implemented - if (isHelper('TestCafe')) this.skip() // TODO Not yet implemented + if (isHelper('TestCafe')) this.skip(); // TODO Not yet implemented - await I.amOnPage('/iframe') - await I.switchTo({ css: 'iframe' }) - const val = await I.executeScript(() => document.getElementsByTagName('h1')[0].innerText) - assert.equal(val, 'Information') - }) + await I.amOnPage('/iframe'); + await I.switchTo({ css: 'iframe' }); + const val = await I.executeScript(() => document.getElementsByTagName('h1')[0].innerText); + assert.equal(val, 'Information'); + }); it('should execute async script', async function () { - if (isHelper('TestCafe')) this.skip() // TODO Not yet implemented - if (isHelper('Playwright')) return // It won't be implemented + if (isHelper('TestCafe')) this.skip(); // TODO Not yet implemented + if (isHelper('Playwright')) return; // It won't be implemented - await I.amOnPage('/') + await I.amOnPage('/'); const val = await I.executeAsyncScript((val, done) => { setTimeout(() => { - document.getElementById('link').innerHTML = val - done(5) - }, 100) - }, 'Timeout') - assert.equal(val, 5) - await I.see('Timeout', 'a') - }) - }) + document.getElementById('link').innerHTML = val; + done(5); + }, 100); + }, 'Timeout'); + assert.equal(val, 5); + await I.see('Timeout', 'a'); + }); + }); describe('#fillField, #appendField', () => { it('should fill input fields', async () => { - await I.amOnPage('/form/field') - await I.fillField('Name', 'Nothing special') - await I.click('Submit') - assert.equal(formContents('name'), 'Nothing special') - }) + await I.amOnPage('/form/field'); + await I.fillField('Name', 'Nothing special'); + await I.click('Submit'); + assert.equal(formContents('name'), 'Nothing special'); + }); it('should fill input fields with secrets', async () => { - await I.amOnPage('/form/field') - await I.fillField('Name', secret('Something special')) - await I.click('Submit') - assert.equal(formContents('name'), 'Something special') - }) + await I.amOnPage('/form/field'); + await I.fillField('Name', secret('Something special')); + await I.click('Submit'); + assert.equal(formContents('name'), 'Something special'); + }); it('should fill field by css', async () => { - await I.amOnPage('/form/field') - await I.fillField('#name', 'Nothing special') - await I.click('Submit') - assert.equal(formContents('name'), 'Nothing special') - }) + await I.amOnPage('/form/field'); + await I.fillField('#name', 'Nothing special'); + await I.click('Submit'); + assert.equal(formContents('name'), 'Nothing special'); + }); it('should fill field by strict locator', async () => { - await I.amOnPage('/form/field') + await I.amOnPage('/form/field'); await I.fillField( { id: 'name', }, 'Nothing special', - ) - await I.click('Submit') - assert.equal(formContents('name'), 'Nothing special') - }) + ); + await I.click('Submit'); + assert.equal(formContents('name'), 'Nothing special'); + }); it('should fill field by name', async () => { - await I.amOnPage('/form/example1') - await I.fillField('LoginForm[username]', 'davert') - await I.fillField('LoginForm[password]', '123456') - await I.click('Login') - assert.equal(formContents('LoginForm').username, 'davert') - assert.equal(formContents('LoginForm').password, '123456') - }) + await I.amOnPage('/form/example1'); + await I.fillField('LoginForm[username]', 'davert'); + await I.fillField('LoginForm[password]', '123456'); + await I.click('Login'); + assert.equal(formContents('LoginForm').username, 'davert'); + assert.equal(formContents('LoginForm').password, '123456'); + }); it('should fill textarea by css', async () => { - await I.amOnPage('/form/textarea') - await I.fillField('textarea', 'Nothing special') - await I.click('Submit') - assert.equal(formContents('description'), 'Nothing special') - }) + await I.amOnPage('/form/textarea'); + await I.fillField('textarea', 'Nothing special'); + await I.click('Submit'); + assert.equal(formContents('description'), 'Nothing special'); + }); it('should fill textarea by label', async () => { - await I.amOnPage('/form/textarea') - await I.fillField('Description', 'Nothing special') - await I.click('Submit') - assert.equal(formContents('description'), 'Nothing special') - }) + await I.amOnPage('/form/textarea'); + await I.fillField('Description', 'Nothing special'); + await I.click('Submit'); + assert.equal(formContents('description'), 'Nothing special'); + }); it('should fill input by aria-label and aria-labelledby', async () => { - await I.amOnPage('/form/aria') - await I.fillField('My Address', 'Home Sweet Home') - await I.fillField('Phone', '123456') - await I.click('Submit') - assert.equal(formContents('my-form-phone'), '123456') - assert.equal(formContents('my-form-address'), 'Home Sweet Home') - }) + await I.amOnPage('/form/aria'); + await I.fillField('My Address', 'Home Sweet Home'); + await I.fillField('Phone', '123456'); + await I.click('Submit'); + assert.equal(formContents('my-form-phone'), '123456'); + assert.equal(formContents('my-form-address'), 'Home Sweet Home'); + }); it('should fill textarea by overwritting the existing value', async () => { - await I.amOnPage('/form/textarea') - await I.fillField('Description', 'Nothing special') - await I.fillField('Description', 'Some other text') - await I.click('Submit') - assert.equal(formContents('description'), 'Some other text') - }) + await I.amOnPage('/form/textarea'); + await I.fillField('Description', 'Nothing special'); + await I.fillField('Description', 'Some other text'); + await I.click('Submit'); + assert.equal(formContents('description'), 'Some other text'); + }); it('should append field value', async () => { - await I.amOnPage('/form/field') - await I.appendField('Name', '_AND_NEW') - await I.click('Submit') - assert.equal(formContents('name'), 'OLD_VALUE_AND_NEW') - }) + await I.amOnPage('/form/field'); + await I.appendField('Name', '_AND_NEW'); + await I.click('Submit'); + assert.equal(formContents('name'), 'OLD_VALUE_AND_NEW'); + }); it.skip('should not fill invisible fields', async () => { - if (isHelper('Playwright')) return // It won't be implemented - await I.amOnPage('/form/field') + if (isHelper('Playwright')) return; // It won't be implemented + await I.amOnPage('/form/field'); try { - I.fillField('email', 'test@1234') + I.fillField('email', 'test@1234'); } catch (e) { - await assert.equal(e.message, 'Error: Field "email" was not found by text|CSS|XPath') + await assert.equal(e.message, 'Error: Field "email" was not found by text|CSS|XPath'); } - }) - }) + }); + }); describe('#clearField', () => { it('should clear a given element', async () => { - await I.amOnPage('/form/field') - await I.fillField('#name', 'Nothing special') - await I.seeInField('#name', 'Nothing special') - await I.clearField('#name') - await I.dontSeeInField('#name', 'Nothing special') - }) + await I.amOnPage('/form/field'); + await I.fillField('#name', 'Nothing special'); + await I.seeInField('#name', 'Nothing special'); + await I.clearField('#name'); + await I.dontSeeInField('#name', 'Nothing special'); + }); it('should clear field by name', async () => { - await I.amOnPage('/form/example1') - await I.clearField('LoginForm[username]') - await I.click('Login') - assert.equal(formContents('LoginForm').username, '') - }) + await I.amOnPage('/form/example1'); + await I.clearField('LoginForm[username]'); + await I.click('Login'); + assert.equal(formContents('LoginForm').username, ''); + }); it('should clear field by locator', async () => { - await I.amOnPage('/form/example1') - await I.clearField('#LoginForm_username') - await I.click('Login') - assert.equal(formContents('LoginForm').username, '') - }) - }) + await I.amOnPage('/form/example1'); + await I.clearField('#LoginForm_username'); + await I.click('Login'); + assert.equal(formContents('LoginForm').username, ''); + }); + }); describe('#type', () => { it('should type into a field', async function () { - if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/form/field') - await I.click('Name') + if (isHelper('TestCafe')) this.skip(); + await I.amOnPage('/form/field'); + await I.click('Name'); - await I.type('Type Test') - await I.seeInField('Name', 'Type Test') + await I.type('Type Test'); + await I.seeInField('Name', 'Type Test'); - await I.fillField('Name', '') + await I.fillField('Name', ''); - await I.type(['T', 'y', 'p', 'e', '2']) - await I.seeInField('Name', 'Type2') - }) + await I.type(['T', 'y', 'p', 'e', '2']); + await I.seeInField('Name', 'Type2'); + }); it('should use delay to slow down typing', async function () { - if (isHelper('TestCafe')) this.skip() - await I.amOnPage('/form/field') - await I.fillField('Name', '') - const time = Date.now() - await I.type('12345', 100) - await I.seeInField('Name', '12345') - assert(Date.now() - time > 500) - }) - }) + if (isHelper('TestCafe')) this.skip(); + await I.amOnPage('/form/field'); + await I.fillField('Name', ''); + const time = Date.now(); + await I.type('12345', 100); + await I.seeInField('Name', '12345'); + assert(Date.now() - time > 500); + }); + }); describe('check fields: #seeInField, #seeCheckboxIsChecked, ...', () => { it('should check for empty field', async () => { - await I.amOnPage('/form/empty') - await I.seeInField('#empty_input', '') - }) + await I.amOnPage('/form/empty'); + await I.seeInField('#empty_input', ''); + }); it('should check for empty textarea', async () => { - await I.amOnPage('/form/empty') - await I.seeInField('#empty_textarea', '') - }) + await I.amOnPage('/form/empty'); + await I.seeInField('#empty_textarea', ''); + }); it('should check field equals', async () => { - await I.amOnPage('/form/field') - await I.seeInField('Name', 'OLD_VALUE') - await I.seeInField('name', 'OLD_VALUE') - await I.seeInField('//input[@id="name"]', 'OLD_VALUE') - await I.dontSeeInField('//input[@id="name"]', 'NOtVALUE') - }) + await I.amOnPage('/form/field'); + await I.seeInField('Name', 'OLD_VALUE'); + await I.seeInField('name', 'OLD_VALUE'); + await I.seeInField('//input[@id="name"]', 'OLD_VALUE'); + await I.dontSeeInField('//input[@id="name"]', 'NOtVALUE'); + }); it('should check textarea equals', async () => { - await I.amOnPage('/form/textarea') - await I.seeInField('Description', 'sunrise') - await I.seeInField('textarea', 'sunrise') - await I.seeInField('//textarea[@id="description"]', 'sunrise') - await I.dontSeeInField('//textarea[@id="description"]', 'sunset') - }) + await I.amOnPage('/form/textarea'); + await I.seeInField('Description', 'sunrise'); + await I.seeInField('textarea', 'sunrise'); + await I.seeInField('//textarea[@id="description"]', 'sunrise'); + await I.dontSeeInField('//textarea[@id="description"]', 'sunset'); + }); it('should check checkbox is checked :)', async () => { - await I.amOnPage('/info') - await I.seeCheckboxIsChecked('input[type=checkbox]') - }) + await I.amOnPage('/info'); + await I.seeCheckboxIsChecked('input[type=checkbox]'); + }); it('should check checkbox is not checked', async () => { - await I.amOnPage('/form/checkbox') - await I.dontSeeCheckboxIsChecked('#checkin') - }) + await I.amOnPage('/form/checkbox'); + await I.dontSeeCheckboxIsChecked('#checkin'); + }); it('should match fields with the same name', async () => { - await I.amOnPage('/form/example20') - await I.seeInField("//input[@name='txtName'][2]", 'emma') - await I.seeInField("input[name='txtName']:nth-child(2)", 'emma') - }) - }) + await I.amOnPage('/form/example20'); + await I.seeInField("//input[@name='txtName'][2]", 'emma'); + await I.seeInField("input[name='txtName']:nth-child(2)", 'emma'); + }); + }); describe('#grabTextFromAll, #grabHTMLFromAll, #grabValueFromAll, #grabAttributeFromAll', () => { it('should grab multiple texts from page', async () => { - await I.amOnPage('/info') - let vals = await I.grabTextFromAll('#grab-multiple a') - assert.equal(vals[0], 'First') - assert.equal(vals[1], 'Second') - assert.equal(vals[2], 'Third') + await I.amOnPage('/info'); + let vals = await I.grabTextFromAll('#grab-multiple a'); + assert.equal(vals[0], 'First'); + assert.equal(vals[1], 'Second'); + assert.equal(vals[2], 'Third'); - await I.amOnPage('/info') - vals = await I.grabTextFromAll('#invalid-id a') - assert.equal(vals.length, 0) - }) + await I.amOnPage('/info'); + vals = await I.grabTextFromAll('#invalid-id a'); + assert.equal(vals.length, 0); + }); it('should grab multiple html from page', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/info') - let vals = await I.grabHTMLFromAll('#grab-multiple a') - assert.equal(vals[0], 'First') - assert.equal(vals[1], 'Second') - assert.equal(vals[2], 'Third') + await I.amOnPage('/info'); + let vals = await I.grabHTMLFromAll('#grab-multiple a'); + assert.equal(vals[0], 'First'); + assert.equal(vals[1], 'Second'); + assert.equal(vals[2], 'Third'); - await I.amOnPage('/info') - vals = await I.grabHTMLFromAll('#invalid-id a') - assert.equal(vals.length, 0) - }) + await I.amOnPage('/info'); + vals = await I.grabHTMLFromAll('#invalid-id a'); + assert.equal(vals.length, 0); + }); it('should grab multiple attribute from element', async () => { - await I.amOnPage('/form/empty') + await I.amOnPage('/form/empty'); const vals = await I.grabAttributeFromAll( { css: 'input', }, 'name', - ) - assert.equal(vals[0], 'text') - assert.equal(vals[1], 'empty_input') - }) + ); + assert.equal(vals[0], 'text'); + assert.equal(vals[1], 'empty_input'); + }); it('Should return empty array if no attribute found', async () => { - await I.amOnPage('/form/empty') + await I.amOnPage('/form/empty'); const vals = await I.grabAttributeFromAll( { css: 'div', }, 'test', - ) - assert.equal(vals.length, 0) - }) + ); + assert.equal(vals.length, 0); + }); it('should grab values if multiple field matches', async () => { - await I.amOnPage('/form/hidden') - let vals = await I.grabValueFromAll('//form/input') - assert.equal(vals[0], 'kill_people') - assert.equal(vals[1], 'Submit') + await I.amOnPage('/form/hidden'); + let vals = await I.grabValueFromAll('//form/input'); + assert.equal(vals[0], 'kill_people'); + assert.equal(vals[1], 'Submit'); - vals = await I.grabValueFromAll("//form/input[@name='action']") - assert.equal(vals[0], 'kill_people') - }) + vals = await I.grabValueFromAll("//form/input[@name='action']"); + assert.equal(vals[0], 'kill_people'); + }); it('Should return empty array if no value found', async () => { - await I.amOnPage('/') - const vals = await I.grabValueFromAll('//form/input') - assert.equal(vals.length, 0) - }) - }) + await I.amOnPage('/'); + const vals = await I.grabValueFromAll('//form/input'); + assert.equal(vals.length, 0); + }); + }); describe('#grabTextFrom, #grabHTMLFrom, #grabValueFrom, #grabAttributeFrom', () => { it('should grab text from page', async () => { - await I.amOnPage('/') - let val = await I.grabTextFrom('h1') - assert.equal(val, 'Welcome to test app!') + await I.amOnPage('/'); + let val = await I.grabTextFrom('h1'); + assert.equal(val, 'Welcome to test app!'); - val = await I.grabTextFrom('//h1') - assert.equal(val, 'Welcome to test app!') - }) + val = await I.grabTextFrom('//h1'); + assert.equal(val, 'Welcome to test app!'); + }); it('should grab html from page', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/info') - const val = await I.grabHTMLFrom('#grab-multiple') + await I.amOnPage('/info'); + const val = await I.grabHTMLFrom('#grab-multiple'); assert.equal( ` First @@ -761,1054 +765,1054 @@ module.exports.tests = function () { Third `, val, - ) - }) + ); + }); it('should grab value from field', async () => { - await I.amOnPage('/form/hidden') - let val = await I.grabValueFrom('#action') - assert.equal(val, 'kill_people') - val = await I.grabValueFrom("//form/input[@name='action']") - assert.equal(val, 'kill_people') - await I.amOnPage('/form/textarea') - val = await I.grabValueFrom('#description') - assert.equal(val, 'sunrise') - await I.amOnPage('/form/select') - val = await I.grabValueFrom('#age') - assert.equal(val, 'oldfag') - }) + await I.amOnPage('/form/hidden'); + let val = await I.grabValueFrom('#action'); + assert.equal(val, 'kill_people'); + val = await I.grabValueFrom("//form/input[@name='action']"); + assert.equal(val, 'kill_people'); + await I.amOnPage('/form/textarea'); + val = await I.grabValueFrom('#description'); + assert.equal(val, 'sunrise'); + await I.amOnPage('/form/select'); + val = await I.grabValueFrom('#age'); + assert.equal(val, 'oldfag'); + }); it('should grab attribute from element', async () => { - await I.amOnPage('/search') + await I.amOnPage('/search'); const val = await I.grabAttributeFrom( { css: 'form', }, 'method', - ) - assert.equal(val, 'get') - }) + ); + assert.equal(val, 'get'); + }); it('should grab custom attribute from element', async () => { - await I.amOnPage('/form/example4') + await I.amOnPage('/form/example4'); const val = await I.grabAttributeFrom( { css: '.navbar-toggle', }, 'data-toggle', - ) - assert.equal(val, 'collapse') - }) - }) + ); + assert.equal(val, 'collapse'); + }); + }); describe('page title : #seeTitle, #dontSeeTitle, #grabTitle', () => { it('should check page title', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/') - await I.seeInTitle('TestEd Beta 2.0') - await I.dontSeeInTitle('Welcome to test app') - await I.amOnPage('/info') - await I.dontSeeInTitle('TestEd Beta 2.0') - }) + await I.amOnPage('/'); + await I.seeInTitle('TestEd Beta 2.0'); + await I.dontSeeInTitle('Welcome to test app'); + await I.amOnPage('/info'); + await I.dontSeeInTitle('TestEd Beta 2.0'); + }); it('should grab page title', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/') - const val = await I.grabTitle() - assert.equal(val, 'TestEd Beta 2.0') - }) - }) + await I.amOnPage('/'); + const val = await I.grabTitle(); + assert.equal(val, 'TestEd Beta 2.0'); + }); + }); describe('#attachFile', () => { it('should upload file located by CSS', async () => { - await I.amOnPage('/form/file') - await I.attachFile('#avatar', 'app/avatar.jpg') - await I.click('Submit') - await I.see('Thank you') - formContents().files.should.have.key('avatar') - formContents().files.avatar.name.should.eql('avatar.jpg') - formContents().files.avatar.type.should.eql('image/jpeg') - }) + await I.amOnPage('/form/file'); + await I.attachFile('#avatar', 'app/avatar.jpg'); + await I.click('Submit'); + await I.see('Thank you'); + formContents().files.should.have.key('avatar'); + formContents().files.avatar.name.should.eql('avatar.jpg'); + formContents().files.avatar.type.should.eql('image/jpeg'); + }); it('should upload file located by label', async () => { - await I.amOnPage('/form/file') - await I.attachFile('Avatar', 'app/avatar.jpg') - await I.click('Submit') - await I.see('Thank you') - formContents().files.should.have.key('avatar') - formContents().files.avatar.name.should.eql('avatar.jpg') - formContents().files.avatar.type.should.eql('image/jpeg') - }) - }) + await I.amOnPage('/form/file'); + await I.attachFile('Avatar', 'app/avatar.jpg'); + await I.click('Submit'); + await I.see('Thank you'); + formContents().files.should.have.key('avatar'); + formContents().files.avatar.name.should.eql('avatar.jpg'); + formContents().files.avatar.type.should.eql('image/jpeg'); + }); + }); describe('#saveScreenshot', () => { beforeEach(() => { - global.output_dir = path.join(global.codecept_dir, 'output') - }) + global.output_dir = path.join(global.codecept_dir, 'output'); + }); it('should create a screenshot file in output dir', async () => { - const sec = new Date().getUTCMilliseconds() - await I.amOnPage('/') - await I.saveScreenshot(`screenshot_${sec}.png`) - assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists') - }) + const sec = new Date().getUTCMilliseconds(); + await I.amOnPage('/'); + await I.saveScreenshot(`screenshot_${sec}.png`); + assert.ok(fileExists(path.join(global.output_dir, `screenshot_${sec}.png`)), null, 'file does not exists'); + }); it('should create a full page screenshot file in output dir', async () => { - const sec = new Date().getUTCMilliseconds() - await I.amOnPage('/') - await I.saveScreenshot(`screenshot_full_${+sec}.png`, true) - assert.ok(fileExists(path.join(global.output_dir, `screenshot_full_${+sec}.png`)), null, 'file does not exists') - }) - }) + const sec = new Date().getUTCMilliseconds(); + await I.amOnPage('/'); + await I.saveScreenshot(`screenshot_full_${+sec}.png`, true); + assert.ok(fileExists(path.join(global.output_dir, `screenshot_full_${+sec}.png`)), null, 'file does not exists'); + }); + }); describe('cookies : #setCookie, #clearCookies, #seeCookie, #waitForCookie', () => { it('should do all cookie stuff', async () => { - await I.amOnPage('/') + await I.amOnPage('/'); await I.setCookie({ name: 'auth', value: '123456', url: 'http://localhost', - }) - await I.seeCookie('auth') - await I.dontSeeCookie('auuth') + }); + await I.seeCookie('auth'); + await I.dontSeeCookie('auuth'); - const cookie = await I.grabCookie('auth') - assert.equal(cookie.value, '123456') + const cookie = await I.grabCookie('auth'); + assert.equal(cookie.value, '123456'); - await I.clearCookie('auth') - await I.dontSeeCookie('auth') - }) + await I.clearCookie('auth'); + await I.dontSeeCookie('auth'); + }); it('should grab all cookies', async () => { - await I.amOnPage('/') + await I.amOnPage('/'); await I.setCookie({ name: 'auth', value: '123456', url: 'http://localhost', - }) + }); await I.setCookie({ name: 'user', value: 'davert', url: 'http://localhost', - }) + }); - const cookies = await I.grabCookie() - assert.equal(cookies.length, 2) - assert(cookies[0].name) - assert(cookies[0].value) - }) + const cookies = await I.grabCookie(); + assert.equal(cookies.length, 2); + assert(cookies[0].name); + assert(cookies[0].value); + }); it('should clear all cookies', async () => { - await I.amOnPage('/') + await I.amOnPage('/'); await I.setCookie({ name: 'auth', value: '123456', url: 'http://localhost', - }) - await I.clearCookie() - await I.dontSeeCookie('auth') - }) + }); + await I.clearCookie(); + await I.dontSeeCookie('auth'); + }); it('should wait for cookie and throw error when cookie not found', async () => { - if (isHelper('TestCafe')) return + if (isHelper('TestCafe')) return; - await I.amOnPage('https://google.com') + await I.amOnPage('https://google.com'); try { - await I.waitForCookie('auth', 2) + await I.waitForCookie('auth', 2); } catch (e) { - assert.equal(e.message, 'Cookie auth is not found after 2s') + assert.equal(e.message, 'Cookie auth is not found after 2s'); } - }) + }); it('should wait for cookie', async () => { - if (isHelper('TestCafe')) return + if (isHelper('TestCafe')) return; - await I.amOnPage('/') + await I.amOnPage('/'); await I.setCookie({ name: 'auth', value: '123456', url: 'http://localhost', - }) - await I.waitForCookie('auth') - }) - }) + }); + await I.waitForCookie('auth'); + }); + }); describe('#waitForText', () => { it('should wait for text', async () => { - await I.amOnPage('/dynamic') - await I.dontSee('Dynamic text') - await I.waitForText('Dynamic text', 2) - await I.see('Dynamic text') - }) + await I.amOnPage('/dynamic'); + await I.dontSee('Dynamic text'); + await I.waitForText('Dynamic text', 2); + await I.see('Dynamic text'); + }); it('should wait for text in context', async () => { - await I.amOnPage('/dynamic') - await I.dontSee('Dynamic text') - await I.waitForText('Dynamic text', 2, '#text') - await I.see('Dynamic text') - }) + await I.amOnPage('/dynamic'); + await I.dontSee('Dynamic text'); + await I.waitForText('Dynamic text', 2, '#text'); + await I.see('Dynamic text'); + }); it('should fail if no context', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - let failed = false - await I.amOnPage('/dynamic') - await I.dontSee('Dynamic text') + let failed = false; + await I.amOnPage('/dynamic'); + await I.dontSee('Dynamic text'); try { - await I.waitForText('Dynamic text', 1, '#fext') + await I.waitForText('Dynamic text', 1, '#fext'); } catch (e) { - failed = true + failed = true; } - assert.ok(failed) - }) + assert.ok(failed); + }); it("should fail if text doesn't contain", async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - let failed = false - await I.amOnPage('/dynamic') + let failed = false; + await I.amOnPage('/dynamic'); try { - await I.waitForText('Other text', 1) + await I.waitForText('Other text', 1); } catch (e) { - failed = true + failed = true; } - assert.ok(failed) - }) + assert.ok(failed); + }); it('should fail if text is not in element', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - let failed = false - await I.amOnPage('/dynamic') + let failed = false; + await I.amOnPage('/dynamic'); try { - await I.waitForText('Other text', 1, '#text') + await I.waitForText('Other text', 1, '#text'); } catch (e) { - failed = true + failed = true; } - assert.ok(failed) - }) + assert.ok(failed); + }); it('should wait for text after timeout', async () => { - await I.amOnPage('/timeout') - await I.dontSee('Timeout text') - await I.waitForText('Timeout text', 31, '#text') - await I.see('Timeout text') - }) + await I.amOnPage('/timeout'); + await I.dontSee('Timeout text'); + await I.waitForText('Timeout text', 31, '#text'); + await I.see('Timeout text'); + }); it('should wait for text located by XPath', async () => { - await I.amOnPage('/dynamic') - await I.dontSee('Dynamic text') - await I.waitForText('Dynamic text', 5, '//div[@id="text"]') - }) + await I.amOnPage('/dynamic'); + await I.dontSee('Dynamic text'); + await I.waitForText('Dynamic text', 5, '//div[@id="text"]'); + }); it('should wait for text with double quotes', async () => { - await I.amOnPage('/') - await I.waitForText('said: "debug!"', 5) - }) + await I.amOnPage('/'); + await I.waitForText('said: "debug!"', 5); + }); it('should throw error when text not found', async () => { - await I.amOnPage('/dynamic') - await I.dontSee('Dynamic text') - let failed = false + await I.amOnPage('/dynamic'); + await I.dontSee('Dynamic text'); + let failed = false; try { - await I.waitForText('Some text', 1, '//div[@id="text"]') + await I.waitForText('Some text', 1, '//div[@id="text"]'); } catch (e) { - failed = true + failed = true; } - assert.ok(failed) - }) - }) + assert.ok(failed); + }); + }); describe('#waitForElement', () => { it('should wait for visible element', async () => { - await I.amOnPage('/form/wait_visible') - await I.dontSee('Step One Button') - await I.dontSeeElement('#step_1') - await I.waitForVisible('#step_1', 2) - await I.seeElement('#step_1') - await I.click('#step_1') - await I.waitForVisible('#step_2', 2) - await I.see('Step Two Button') - }) + await I.amOnPage('/form/wait_visible'); + await I.dontSee('Step One Button'); + await I.dontSeeElement('#step_1'); + await I.waitForVisible('#step_1', 2); + await I.seeElement('#step_1'); + await I.click('#step_1'); + await I.waitForVisible('#step_2', 2); + await I.see('Step Two Button'); + }); it('should wait for element in DOM', async () => { - await I.amOnPage('/form/wait_visible') - await I.waitForElement('#step_2') - await I.dontSeeElement('#step_2') - await I.seeElementInDOM('#step_2') - }) + await I.amOnPage('/form/wait_visible'); + await I.waitForElement('#step_2'); + await I.dontSeeElement('#step_2'); + await I.seeElementInDOM('#step_2'); + }); it('should wait for element by XPath', async () => { - await I.amOnPage('/form/wait_visible') - await I.waitForElement('//div[@id="step_2"]') - await I.dontSeeElement('//div[@id="step_2"]') - await I.seeElementInDOM('//div[@id="step_2"]') - }) + await I.amOnPage('/form/wait_visible'); + await I.waitForElement('//div[@id="step_2"]'); + await I.dontSeeElement('//div[@id="step_2"]'); + await I.seeElementInDOM('//div[@id="step_2"]'); + }); it('should wait for element to appear', async () => { - await I.amOnPage('/form/wait_element') - await I.dontSee('Hello') - await I.dontSeeElement('h1') - await I.waitForElement('h1', 2) - await I.see('Hello') - }) - }) + await I.amOnPage('/form/wait_element'); + await I.dontSee('Hello'); + await I.dontSeeElement('h1'); + await I.waitForElement('h1', 2); + await I.see('Hello'); + }); + }); describe('#waitForInvisible', () => { it('should wait for element to be invisible', async () => { - await I.amOnPage('/form/wait_invisible') - await I.see('Step One Button') - await I.seeElement('#step_1') - await I.waitForInvisible('#step_1', 2) - await I.dontSeeElement('#step_1') - }) + await I.amOnPage('/form/wait_invisible'); + await I.see('Step One Button'); + await I.seeElement('#step_1'); + await I.waitForInvisible('#step_1', 2); + await I.dontSeeElement('#step_1'); + }); it('should wait for element to be invisible by XPath', async () => { - await I.amOnPage('/form/wait_invisible') - await I.seeElement('//div[@id="step_1"]') - await I.waitForInvisible('//div[@id="step_1"]') - await I.dontSeeElement('//div[@id="step_1"]') - await I.seeElementInDOM('//div[@id="step_1"]') - }) + await I.amOnPage('/form/wait_invisible'); + await I.seeElement('//div[@id="step_1"]'); + await I.waitForInvisible('//div[@id="step_1"]'); + await I.dontSeeElement('//div[@id="step_1"]'); + await I.seeElementInDOM('//div[@id="step_1"]'); + }); it('should wait for element to be removed', async () => { - await I.amOnPage('/form/wait_invisible') - await I.see('Step Two Button') - await I.seeElement('#step_2') - await I.waitForInvisible('#step_2', 2) - await I.dontSeeElement('#step_2') - }) + await I.amOnPage('/form/wait_invisible'); + await I.see('Step Two Button'); + await I.seeElement('#step_2'); + await I.waitForInvisible('#step_2', 2); + await I.dontSeeElement('#step_2'); + }); it('should wait for element to be removed by XPath', async () => { - await I.amOnPage('/form/wait_invisible') - await I.see('Step Two Button') - await I.seeElement('//div[@id="step_2"]') - await I.waitForInvisible('//div[@id="step_2"]', 2) - await I.dontSeeElement('//div[@id="step_2"]') - }) - }) + await I.amOnPage('/form/wait_invisible'); + await I.see('Step Two Button'); + await I.seeElement('//div[@id="step_2"]'); + await I.waitForInvisible('//div[@id="step_2"]', 2); + await I.dontSeeElement('//div[@id="step_2"]'); + }); + }); describe('#waitToHide', () => { it('should wait for element to be invisible', async () => { - await I.amOnPage('/form/wait_invisible') - await I.see('Step One Button') - await I.seeElement('#step_1') - await I.waitToHide('#step_1', 2) - await I.dontSeeElement('#step_1') - }) + await I.amOnPage('/form/wait_invisible'); + await I.see('Step One Button'); + await I.seeElement('#step_1'); + await I.waitToHide('#step_1', 2); + await I.dontSeeElement('#step_1'); + }); it('should wait for element to be invisible by XPath', async () => { - await I.amOnPage('/form/wait_invisible') - await I.seeElement('//div[@id="step_1"]') - await I.waitToHide('//div[@id="step_1"]') - await I.dontSeeElement('//div[@id="step_1"]') - await I.seeElementInDOM('//div[@id="step_1"]') - }) + await I.amOnPage('/form/wait_invisible'); + await I.seeElement('//div[@id="step_1"]'); + await I.waitToHide('//div[@id="step_1"]'); + await I.dontSeeElement('//div[@id="step_1"]'); + await I.seeElementInDOM('//div[@id="step_1"]'); + }); it('should wait for element to be removed', async () => { - await I.amOnPage('/form/wait_invisible') - await I.see('Step Two Button') - await I.seeElement('#step_2') - await I.waitToHide('#step_2', 2) - await I.dontSeeElement('#step_2') - }) + await I.amOnPage('/form/wait_invisible'); + await I.see('Step Two Button'); + await I.seeElement('#step_2'); + await I.waitToHide('#step_2', 2); + await I.dontSeeElement('#step_2'); + }); it('should wait for element to be removed by XPath', async () => { - await I.amOnPage('/form/wait_invisible') - await I.see('Step Two Button') - await I.seeElement('//div[@id="step_2"]') - await I.waitToHide('//div[@id="step_2"]', 2) - await I.dontSeeElement('//div[@id="step_2"]') - }) - }) + await I.amOnPage('/form/wait_invisible'); + await I.see('Step Two Button'); + await I.seeElement('//div[@id="step_2"]'); + await I.waitToHide('//div[@id="step_2"]', 2); + await I.dontSeeElement('//div[@id="step_2"]'); + }); + }); describe('#waitForDetached', () => { it('should throw an error if the element still exists in DOM', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/wait_detached') - await I.see('Step One Button') - await I.seeElement('#step_1') + await I.amOnPage('/form/wait_detached'); + await I.see('Step One Button'); + await I.seeElement('#step_1'); try { - await I.waitForDetached('#step_1', 2) - throw Error('Should not get this far') + await I.waitForDetached('#step_1', 2); + throw Error('Should not get this far'); } catch (err) { - err.message.should.include('still on page after') + err.message.should.include('still on page after'); } - }) + }); it('should throw an error if the element still exists in DOM by XPath', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/wait_detached') - await I.see('Step One Button') - await I.seeElement('#step_1') + await I.amOnPage('/form/wait_detached'); + await I.see('Step One Button'); + await I.seeElement('#step_1'); try { - await I.waitForDetached('#step_1', 2) - throw Error('Should not get this far') + await I.waitForDetached('#step_1', 2); + throw Error('Should not get this far'); } catch (err) { - err.message.should.include('still on page after') + err.message.should.include('still on page after'); } - }) + }); it('should wait for element to be removed from DOM', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/wait_detached') - await I.see('Step Two Button') - await I.seeElement('#step_2') - await I.waitForDetached('#step_2', 2) - await I.dontSeeElementInDOM('#step_2') - }) + await I.amOnPage('/form/wait_detached'); + await I.see('Step Two Button'); + await I.seeElement('#step_2'); + await I.waitForDetached('#step_2', 2); + await I.dontSeeElementInDOM('#step_2'); + }); it('should wait for element to be removed from DOM by XPath', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/wait_detached') - await I.seeElement('//div[@id="step_2"]') - await I.waitForDetached('//div[@id="step_2"]') - await I.dontSeeElement('//div[@id="step_2"]') - await I.dontSeeElementInDOM('//div[@id="step_2"]') - }) - }) + await I.amOnPage('/form/wait_detached'); + await I.seeElement('//div[@id="step_2"]'); + await I.waitForDetached('//div[@id="step_2"]'); + await I.dontSeeElement('//div[@id="step_2"]'); + await I.dontSeeElementInDOM('//div[@id="step_2"]'); + }); + }); describe('within tests', () => { - afterEach(() => I._withinEnd()) + afterEach(() => I._withinEnd()); it('should execute within block', async () => { - await I.amOnPage('/form/example4') - await I.seeElement('#navbar-collapse-menu') + await I.amOnPage('/form/example4'); + await I.seeElement('#navbar-collapse-menu'); I._withinBegin('#register') .then(() => I.see('E-Mail')) .then(() => I.dontSee('Toggle navigation')) - .then(() => I.dontSeeElement('#navbar-collapse-menu')) - }) + .then(() => I.dontSeeElement('#navbar-collapse-menu')); + }); it('should respect form fields inside within block ', async () => { - let rethrow - - await I.amOnPage('/form/example4') - await I.seeElement('#navbar-collapse-menu') - await I.see('E-Mail') - await I.see('Hasło') - await I.fillField('Hasło', '12345') - await I.seeInField('Hasło', '12345') - await I.checkOption('terms') - await I.seeCheckboxIsChecked('terms') + let rethrow; + + await I.amOnPage('/form/example4'); + await I.seeElement('#navbar-collapse-menu'); + await I.see('E-Mail'); + await I.see('Hasło'); + await I.fillField('Hasło', '12345'); + await I.seeInField('Hasło', '12345'); + await I.checkOption('terms'); + await I.seeCheckboxIsChecked('terms'); I._withinBegin({ css: '.form-group' }) .then(() => I.see('E-Mail')) .then(() => I.dontSee('Hasło')) - .then(() => I.dontSeeElement('#navbar-collapse-menu')) + .then(() => I.dontSeeElement('#navbar-collapse-menu')); try { - await I.dontSeeCheckboxIsChecked('terms') + await I.dontSeeCheckboxIsChecked('terms'); } catch (err) { - if (!err) assert.fail('seen checkbox') + if (!err) assert.fail('seen checkbox'); } try { - await I.seeInField('Hasło', '12345') + await I.seeInField('Hasło', '12345'); } catch (err) { - if (!err) assert.fail('seen field') + if (!err) assert.fail('seen field'); } - if (rethrow) throw rethrow - }) + if (rethrow) throw rethrow; + }); it('should execute within block 2', async () => { - await I.amOnPage('/form/example4') - await I.fillField('Hasło', '12345') + await I.amOnPage('/form/example4'); + await I.fillField('Hasło', '12345'); I._withinBegin({ xpath: '//div[@class="form-group"][2]' }) .then(() => I.dontSee('E-Mail')) .then(() => I.see('Hasło')) .then(() => I.grabTextFrom('label')) .then((label) => assert.equal(label, 'Hasło')) .then(() => I.grabValueFrom('input')) - .then((input) => assert.equal(input, '12345')) - }) + .then((input) => assert.equal(input, '12345')); + }); it('within should respect context in see', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/example4') - await I.see('Rejestracja', 'fieldset') + await I.amOnPage('/form/example4'); + await I.see('Rejestracja', 'fieldset'); I._withinBegin({ css: '.navbar-header' }) .then(() => I.see('Rejestracja', '.container fieldset')) - .then(() => I.see('Toggle navigation', '.container fieldset')) - }) + .then(() => I.see('Toggle navigation', '.container fieldset')); + }); it('within should respect context in see when using nested frames', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/iframe_nested') + await I.amOnPage('/iframe_nested'); await I._withinBegin({ frame: ['#wrapperId', '[name=content]'], - }) + }); try { - await I.see('Kill & Destroy') + await I.see('Kill & Destroy'); } catch (err) { - if (!err) assert.fail('seen "Kill & Destroy"') + if (!err) assert.fail('seen "Kill & Destroy"'); } try { - await I.dontSee('Nested Iframe test') + await I.dontSee('Nested Iframe test'); } catch (err) { - if (!err) assert.fail('seen "Nested Iframe test"') + if (!err) assert.fail('seen "Nested Iframe test"'); } try { - await I.dontSee('Iframe test') + await I.dontSee('Iframe test'); } catch (err) { - if (!err) assert.fail('seen "Iframe test"') + if (!err) assert.fail('seen "Iframe test"'); } - }) + }); it('within should respect context in see when using frame', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/iframe') + await I.amOnPage('/iframe'); await I._withinBegin({ frame: '#number-frame-1234', - }) + }); try { - await I.see('Information') + await I.see('Information'); } catch (err) { - if (!err) assert.fail('seen "Information"') + if (!err) assert.fail('seen "Information"'); } - }) + }); it('within should respect context in see when using frame with strict locator', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/iframe') + await I.amOnPage('/iframe'); await I._withinBegin({ frame: { css: '#number-frame-1234' }, - }) + }); try { - await I.see('Information') + await I.see('Information'); } catch (err) { - if (!err) assert.fail('seen "Information"') + if (!err) assert.fail('seen "Information"'); } - }) - }) + }); + }); describe('scroll: #scrollTo, #scrollPageToTop, #scrollPageToBottom', () => { it('should scroll inside an iframe', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/iframe') - await I.resizeWindow(500, 700) - await I.switchTo(0) + await I.amOnPage('/iframe'); + await I.resizeWindow(500, 700); + await I.switchTo(0); - const { x, y } = await I.grabPageScrollPosition() - await I.scrollTo('.sign') + const { x, y } = await I.grabPageScrollPosition(); + await I.scrollTo('.sign'); - const { x: afterScrollX, y: afterScrollY } = await I.grabPageScrollPosition() - assert.notEqual(afterScrollY, y) - assert.equal(afterScrollX, x) - }) + const { x: afterScrollX, y: afterScrollY } = await I.grabPageScrollPosition(); + assert.notEqual(afterScrollY, y); + assert.equal(afterScrollX, x); + }); it('should scroll to an element', async () => { - await I.amOnPage('/form/scroll') - await I.resizeWindow(500, 700) - const { y } = await I.grabPageScrollPosition() - await I.scrollTo('.section3 input[name="test"]') + await I.amOnPage('/form/scroll'); + await I.resizeWindow(500, 700); + const { y } = await I.grabPageScrollPosition(); + await I.scrollTo('.section3 input[name="test"]'); - const { y: afterScrollY } = await I.grabPageScrollPosition() - assert.notEqual(afterScrollY, y) - }) + const { y: afterScrollY } = await I.grabPageScrollPosition(); + assert.notEqual(afterScrollY, y); + }); it('should scroll to coordinates', async () => { - await I.amOnPage('/form/scroll') - await I.resizeWindow(500, 700) - await I.scrollTo(50, 70) + await I.amOnPage('/form/scroll'); + await I.resizeWindow(500, 700); + await I.scrollTo(50, 70); - const { x: afterScrollX, y: afterScrollY } = await I.grabPageScrollPosition() - assert.equal(afterScrollX, 50) - assert.equal(afterScrollY, 70) - }) + const { x: afterScrollX, y: afterScrollY } = await I.grabPageScrollPosition(); + assert.equal(afterScrollX, 50); + assert.equal(afterScrollY, 70); + }); it('should scroll to bottom of page', async () => { - await I.amOnPage('/form/scroll') - await I.resizeWindow(500, 700) - const { y } = await I.grabPageScrollPosition() - await I.scrollPageToBottom() + await I.amOnPage('/form/scroll'); + await I.resizeWindow(500, 700); + const { y } = await I.grabPageScrollPosition(); + await I.scrollPageToBottom(); - const { y: afterScrollY } = await I.grabPageScrollPosition() - assert.notEqual(afterScrollY, y) - assert.notEqual(afterScrollY, 0) - }) + const { y: afterScrollY } = await I.grabPageScrollPosition(); + assert.notEqual(afterScrollY, y); + assert.notEqual(afterScrollY, 0); + }); it('should scroll to top of page', async () => { - await I.amOnPage('/form/scroll') - await I.resizeWindow(500, 700) - await I.scrollPageToBottom() - const { y } = await I.grabPageScrollPosition() - await I.scrollPageToTop() - - const { y: afterScrollY } = await I.grabPageScrollPosition() - assert.notEqual(afterScrollY, y) - assert.equal(afterScrollY, 0) - }) - }) + await I.amOnPage('/form/scroll'); + await I.resizeWindow(500, 700); + await I.scrollPageToBottom(); + const { y } = await I.grabPageScrollPosition(); + await I.scrollPageToTop(); + + const { y: afterScrollY } = await I.grabPageScrollPosition(); + assert.notEqual(afterScrollY, y); + assert.equal(afterScrollY, 0); + }); + }); describe('#grabCssPropertyFrom', () => { it('should grab css property for given element', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/doubleclick') - const css = await I.grabCssPropertyFrom('#block', 'height') - assert.equal(css, '100px') - }) + await I.amOnPage('/form/doubleclick'); + const css = await I.grabCssPropertyFrom('#block', 'height'); + assert.equal(css, '100px'); + }); it('should grab camelcased css properies', async () => { - if (isHelper('TestCafe')) return + if (isHelper('TestCafe')) return; - await I.amOnPage('/form/doubleclick') - const css = await I.grabCssPropertyFrom('#block', 'user-select') - assert.equal(css, 'text') - }) + await I.amOnPage('/form/doubleclick'); + const css = await I.grabCssPropertyFrom('#block', 'user-select'); + assert.equal(css, 'text'); + }); it('should grab multiple values if more than one matching element found', async () => { - if (isHelper('TestCafe')) return + if (isHelper('TestCafe')) return; - await I.amOnPage('/info') - const css = await I.grabCssPropertyFromAll('.span', 'height') - assert.equal(css[0], '12px') - assert.equal(css[1], '15px') - }) - }) + await I.amOnPage('/info'); + const css = await I.grabCssPropertyFromAll('.span', 'height'); + assert.equal(css[0], '12px'); + assert.equal(css[1], '15px'); + }); + }); describe('#seeAttributesOnElements', () => { it('should check attributes values for given element', async function () { - if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip() + if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip(); try { - await I.amOnPage('/info') + await I.amOnPage('/info'); await I.seeAttributesOnElements('//form', { method: 'post', - }) + }); await I.seeAttributesOnElements('//form', { method: 'get', - }) - throw Error('It should never get this far') + }); + throw Error('It should never get this far'); } catch (e) { - e.message.should.include('all elements (//form) to have attributes {"method":"get"}') + e.message.should.include('all elements (//form) to have attributes {"method":"get"}'); } - }) + }); it('should check href with slash', async function () { - if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip() + if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip(); try { - await I.amOnPage('https://github.com/codeceptjs/CodeceptJS/') + await I.amOnPage('https://github.com/codeceptjs/CodeceptJS/'); await I.seeAttributesOnElements( { css: 'a[href="/codeceptjs/CodeceptJS"]' }, { href: '/codeceptjs/CodeceptJS', }, - ) + ); } catch (e) { e.message.should.include( 'all elements (a[href="/codeceptjs/CodeceptJS"]) to have attributes {"href":"/codeceptjs/CodeceptJS"}', - ) + ); } - }) + }); it('should check attributes values for several elements', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); try { - await I.amOnPage('/') + await I.amOnPage('/'); await I.seeAttributesOnElements('a', { 'qa-id': 'test', 'qa-link': 'test', - }) + }); await I.seeAttributesOnElements('//div', { 'qa-id': 'test', - }) + }); await I.seeAttributesOnElements('a', { 'qa-id': 'test', href: '/info', - }) - throw new Error('It should never get this far') + }); + throw new Error('It should never get this far'); } catch (e) { - e.message.should.include('all elements (a) to have attributes {"qa-id":"test","href":"/info"}') + e.message.should.include('all elements (a) to have attributes {"qa-id":"test","href":"/info"}'); } - }) + }); it('should return error when using non existing attribute', async function () { - if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip() + if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip(); try { - await I.amOnPage('https://github.com/codeceptjs/CodeceptJS/') + await I.amOnPage('https://github.com/codeceptjs/CodeceptJS/'); await I.seeAttributesOnElements( { css: 'a[href="/codeceptjs/CodeceptJS"]' }, { disable: true, }, - ) + ); } catch (e) { e.message.should.include( 'expected all elements ({css: a[href="/codeceptjs/CodeceptJS"]}) to have attributes {"disable":true} "0" to equal "3"', - ) + ); } - }) + }); it('should verify the boolean attribute', async function () { - if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip() + if (isHelper('TestCafe') || isHelper('WebDriver')) this.skip(); try { - await I.amOnPage('/') + await I.amOnPage('/'); await I.seeAttributesOnElements('input', { disabled: true, - }) + }); } catch (e) { - e.message.should.include('expected all elements (input) to have attributes {"disabled":true} "0" to equal "1"') + e.message.should.include('expected all elements (input) to have attributes {"disabled":true} "0" to equal "1"'); } - }) - }) + }); + }); describe('#seeCssPropertiesOnElements', () => { it('should check css property for given element', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); try { - await I.amOnPage('/info') + await I.amOnPage('/info'); await I.seeCssPropertiesOnElements('h4', { 'font-weight': 300, - }) + }); await I.seeCssPropertiesOnElements('h3', { 'font-weight': 'bold', display: 'block', - }) + }); await I.seeCssPropertiesOnElements('h3', { 'font-weight': 'non-bold', - }) - throw Error('It should never get this far') + }); + throw Error('It should never get this far'); } catch (e) { - e.message.should.include('expected all elements (h3) to have CSS property {"font-weight":"non-bold"}') + e.message.should.include('expected all elements (h3) to have CSS property {"font-weight":"non-bold"}'); } - }) + }); it('should check css property for several elements', async function () { - if (isHelper('TestCafe') || process.env.BROWSER === 'firefox') this.skip() + if (isHelper('TestCafe') || process.env.BROWSER === 'firefox') this.skip(); try { - await I.amOnPage('/') + await I.amOnPage('/'); await I.seeCssPropertiesOnElements('a', { color: 'rgb(0, 0, 238)', cursor: 'pointer', - }) + }); await I.seeCssPropertiesOnElements('a', { color: '#0000EE', cursor: 'pointer', - }) + }); await I.seeCssPropertiesOnElements('//div', { display: 'block', - }) + }); await I.seeCssPropertiesOnElements('a', { 'margin-top': '0em', cursor: 'pointer', - }) - throw Error('It should never get this far') + }); + throw Error('It should never get this far'); } catch (e) { e.message.should.include( 'expected all elements (a) to have CSS property {"margin-top":"0em","cursor":"pointer"}', - ) + ); } - }) + }); it('should normalize css color properties for given element', async function () { - if (isHelper('TestCafe')) this.skip() + if (isHelper('TestCafe')) this.skip(); - await I.amOnPage('/form/css_colors') + await I.amOnPage('/form/css_colors'); await I.seeCssPropertiesOnElements('#namedColor', { 'background-color': 'purple', color: 'yellow', - }) + }); await I.seeCssPropertiesOnElements('#namedColor', { 'background-color': '#800080', color: '#ffff00', - }) + }); await I.seeCssPropertiesOnElements('#namedColor', { 'background-color': 'rgb(128,0,128)', color: 'rgb(255,255,0)', - }) + }); await I.seeCssPropertiesOnElements('#namedColor', { 'background-color': 'rgba(128,0,128,1)', color: 'rgba(255,255,0,1)', - }) - }) - }) + }); + }); + }); describe('#customLocators', () => { beforeEach(() => { - originalLocators = Locator.filters - Locator.filters = [] - }) + originalLocators = Locator.filters; + Locator.filters = []; + }); afterEach(() => { // reset custom locators - Locator.filters = originalLocators - }) + Locator.filters = originalLocators; + }); it('should support xpath custom locator by default', async () => { customLocators({ attribute: 'data-test-id', enabled: true, - }) - await I.amOnPage('/form/custom_locator') - await I.dontSee('Step One Button') - await I.dontSeeElement('$step_1') - await I.waitForVisible('$step_1', 2) - await I.seeElement('$step_1') - await I.click('$step_1') - await I.waitForVisible('$step_2', 2) - await I.see('Step Two Button') - }) + }); + await I.amOnPage('/form/custom_locator'); + await I.dontSee('Step One Button'); + await I.dontSeeElement('$step_1'); + await I.waitForVisible('$step_1', 2); + await I.seeElement('$step_1'); + await I.click('$step_1'); + await I.waitForVisible('$step_2', 2); + await I.see('Step Two Button'); + }); it('can use css strategy for custom locator', async () => { customLocators({ attribute: 'data-test-id', enabled: true, strategy: 'css', - }) - await I.amOnPage('/form/custom_locator') - await I.dontSee('Step One Button') - await I.dontSeeElement('$step_1') - await I.waitForVisible('$step_1', 2) - await I.seeElement('$step_1') - await I.click('$step_1') - await I.waitForVisible('$step_2', 2) - await I.see('Step Two Button') - }) + }); + await I.amOnPage('/form/custom_locator'); + await I.dontSee('Step One Button'); + await I.dontSeeElement('$step_1'); + await I.waitForVisible('$step_1', 2); + await I.seeElement('$step_1'); + await I.click('$step_1'); + await I.waitForVisible('$step_2', 2); + await I.see('Step Two Button'); + }); it('can use xpath strategy for custom locator', async () => { customLocators({ attribute: 'data-test-id', enabled: true, strategy: 'xpath', - }) - await I.amOnPage('/form/custom_locator') - await I.dontSee('Step One Button') - await I.dontSeeElement('$step_1') - await I.waitForVisible('$step_1', 2) - await I.seeElement('$step_1') - await I.click('$step_1') - await I.waitForVisible('$step_2', 2) - await I.see('Step Two Button') - }) - }) + }); + await I.amOnPage('/form/custom_locator'); + await I.dontSee('Step One Button'); + await I.dontSeeElement('$step_1'); + await I.waitForVisible('$step_1', 2); + await I.seeElement('$step_1'); + await I.click('$step_1'); + await I.waitForVisible('$step_2', 2); + await I.see('Step Two Button'); + }); + }); describe('#focus, #blur', () => { it('should focus a button, field and textarea', async () => { - await I.amOnPage('/form/focus_blur_elements') + await I.amOnPage('/form/focus_blur_elements'); - await I.focus('#button') - await I.see('Button is focused', '#buttonMessage') + await I.focus('#button'); + await I.see('Button is focused', '#buttonMessage'); - await I.focus('#field') - await I.see('Button not focused', '#buttonMessage') - await I.see('Input field is focused', '#fieldMessage') + await I.focus('#field'); + await I.see('Button not focused', '#buttonMessage'); + await I.see('Input field is focused', '#fieldMessage'); - await I.focus('#textarea') - await I.see('Button not focused', '#buttonMessage') - await I.see('Input field not focused', '#fieldMessage') - await I.see('Textarea is focused', '#textareaMessage') - }) + await I.focus('#textarea'); + await I.see('Button not focused', '#buttonMessage'); + await I.see('Input field not focused', '#fieldMessage'); + await I.see('Textarea is focused', '#textareaMessage'); + }); it('should blur focused button, field and textarea', async () => { - await I.amOnPage('/form/focus_blur_elements') + await I.amOnPage('/form/focus_blur_elements'); - await I.focus('#button') - await I.see('Button is focused', '#buttonMessage') - await I.blur('#button') - await I.see('Button not focused', '#buttonMessage') + await I.focus('#button'); + await I.see('Button is focused', '#buttonMessage'); + await I.blur('#button'); + await I.see('Button not focused', '#buttonMessage'); - await I.focus('#field') - await I.see('Input field is focused', '#fieldMessage') - await I.blur('#field') - await I.see('Input field not focused', '#fieldMessage') + await I.focus('#field'); + await I.see('Input field is focused', '#fieldMessage'); + await I.blur('#field'); + await I.see('Input field not focused', '#fieldMessage'); - await I.focus('#textarea') - await I.see('Textarea is focused', '#textareaMessage') - await I.blur('#textarea') - await I.see('Textarea not focused', '#textareaMessage') - }) - }) + await I.focus('#textarea'); + await I.see('Textarea is focused', '#textareaMessage'); + await I.blur('#textarea'); + await I.see('Textarea not focused', '#textareaMessage'); + }); + }); describe('#startRecordingTraffic, #seeTraffic, #stopRecordingTraffic, #dontSeeTraffic, #grabRecordedNetworkTraffics', () => { beforeEach(function () { - if (isHelper('TestCafe') || process.env.isSelenium === 'true') this.skip() - }) + if (isHelper('TestCafe') || process.env.isSelenium === 'true') this.skip(); + }); it('should throw error when calling seeTraffic before recording traffics', async () => { try { - I.amOnPage('https://codecept.io/') - await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) + I.amOnPage('https://codecept.io/'); + await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); } catch (e) { expect(e.message).to.equal( 'Failure in test automation. You use "I.seeTraffic", but "I.startRecordingTraffic" was never called before.', - ) + ); } - }) + }); it('should throw error when calling seeTraffic but missing name', async () => { try { - I.amOnPage('https://codecept.io/') - await I.seeTraffic({ url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) + I.amOnPage('https://codecept.io/'); + await I.seeTraffic({ url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); } catch (e) { - expect(e.message).to.equal('Missing required key "name" in object given to "I.seeTraffic".') + expect(e.message).to.equal('Missing required key "name" in object given to "I.seeTraffic".'); } - }) + }); it('should throw error when calling seeTraffic but missing url', async () => { try { - I.amOnPage('https://codecept.io/') - await I.seeTraffic({ name: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) + I.amOnPage('https://codecept.io/'); + await I.seeTraffic({ name: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); } catch (e) { - expect(e.message).to.equal('Missing required key "url" in object given to "I.seeTraffic".') + expect(e.message).to.equal('Missing required key "url" in object given to "I.seeTraffic".'); } - }) + }); it('should flush the network traffics', async () => { - await I.startRecordingTraffic() - await I.amOnPage('https://codecept.io/') - await I.flushNetworkTraffics() - const traffics = await I.grabRecordedNetworkTraffics() - expect(traffics.length).to.equal(0) - }) + await I.startRecordingTraffic(); + await I.amOnPage('https://codecept.io/'); + await I.flushNetworkTraffics(); + const traffics = await I.grabRecordedNetworkTraffics(); + expect(traffics.length).to.equal(0); + }); it('should see recording traffics', async () => { - I.startRecordingTraffic() - I.amOnPage('https://codecept.io/') - await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) - }) + I.startRecordingTraffic(); + I.amOnPage('https://codecept.io/'); + await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); + }); it('should not see recording traffics', async () => { - I.startRecordingTraffic() - I.amOnPage('https://codecept.io/') - I.stopRecordingTraffic() - await I.dontSeeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) - }) + I.startRecordingTraffic(); + I.amOnPage('https://codecept.io/'); + I.stopRecordingTraffic(); + await I.dontSeeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); + }); it('should not see recording traffics using regex url', async () => { - I.startRecordingTraffic() - I.amOnPage('https://codecept.io/') - I.stopRecordingTraffic() - await I.dontSeeTraffic({ name: 'traffics', url: /BC_LogoScreen_C.jpg/ }) - }) + I.startRecordingTraffic(); + I.amOnPage('https://codecept.io/'); + I.stopRecordingTraffic(); + await I.dontSeeTraffic({ name: 'traffics', url: /BC_LogoScreen_C.jpg/ }); + }); it('should throw error when calling dontSeeTraffic but missing name', async () => { - I.startRecordingTraffic() - I.amOnPage('https://codecept.io/') - I.stopRecordingTraffic() + I.startRecordingTraffic(); + I.amOnPage('https://codecept.io/'); + I.stopRecordingTraffic(); try { - await I.dontSeeTraffic({ url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }) + await I.dontSeeTraffic({ url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); } catch (e) { - expect(e.message).to.equal('Missing required key "name" in object given to "I.dontSeeTraffic".') + expect(e.message).to.equal('Missing required key "name" in object given to "I.dontSeeTraffic".'); } - }) + }); it('should throw error when calling dontSeeTraffic but missing url', async () => { - I.startRecordingTraffic() - I.amOnPage('https://codecept.io/') - I.stopRecordingTraffic() + I.startRecordingTraffic(); + I.amOnPage('https://codecept.io/'); + I.stopRecordingTraffic(); try { - await I.dontSeeTraffic({ name: 'traffics' }) + await I.dontSeeTraffic({ name: 'traffics' }); } catch (e) { - expect(e.message).to.equal('Missing required key "url" in object given to "I.dontSeeTraffic".') + expect(e.message).to.equal('Missing required key "url" in object given to "I.dontSeeTraffic".'); } - }) + }); it('should check traffics with more advanced params', async () => { - await I.startRecordingTraffic() - await I.amOnPage('https://openaI.com/blog/chatgpt') - const traffics = await I.grabRecordedNetworkTraffics() + await I.startRecordingTraffic(); + await I.amOnPage('https://openaI.com/blog/chatgpt'); + const traffics = await I.grabRecordedNetworkTraffics(); for (const traffic of traffics) { if (traffic.url.includes('&width=')) { // new URL object - const currentUrl = new URL(traffic.url) + const currentUrl = new URL(traffic.url); // get access to URLSearchParams object - const searchParams = currentUrl.searchParams + const searchParams = currentUrl.searchParams; await I.seeTraffic({ name: 'sentry event', url: currentUrl.origin + currentUrl.pathname, parameters: searchParams, - }) + }); - break + break; } } - }) + }); it.skip('should check traffics with more advanced post data', async () => { - await I.amOnPage('https://openaI.com/blog/chatgpt') - await I.startRecordingTraffic() + await I.amOnPage('https://openaI.com/blog/chatgpt'); + await I.startRecordingTraffic(); await I.seeTraffic({ name: 'event', url: 'https://region1.google-analytics.com', requestPostData: { st: 2, }, - }) - }) - }) + }); + }); + }); // the WS test website is not so stable. So we skip those tests for now. describe.skip('#startRecordingWebSocketMessages, #grabWebSocketMessages, #stopRecordingWebSocketMessages', () => { beforeEach(function () { - if (isHelper('TestCafe') || isHelper('WebDriver') || process.env.BROWSER === 'firefox') this.skip() - }) + if (isHelper('TestCafe') || isHelper('WebDriver') || process.env.BROWSER === 'firefox') this.skip(); + }); it('should throw error when calling grabWebSocketMessages before startRecordingWebSocketMessages', () => { try { - I.amOnPage('https://websocketstest.com/') - I.waitForText('Work for You!') - I.grabWebSocketMessages() + I.amOnPage('https://websocketstest.com/'); + I.waitForText('Work for You!'); + I.grabWebSocketMessages(); } catch (e) { expect(e.message).to.equal( 'Failure in test automation. You use "I.grabWebSocketMessages", but "I.startRecordingWebSocketMessages" was never called before.', - ) + ); } - }) + }); it('should flush the WS messages', async () => { - await I.startRecordingWebSocketMessages() - I.amOnPage('https://websocketstest.com/') - I.waitForText('Work for You!') - I.flushWebSocketMessages() - const wsMessages = I.grabWebSocketMessages() - expect(wsMessages.length).to.equal(0) - }) + await I.startRecordingWebSocketMessages(); + I.amOnPage('https://websocketstest.com/'); + I.waitForText('Work for You!'); + I.flushWebSocketMessages(); + const wsMessages = I.grabWebSocketMessages(); + expect(wsMessages.length).to.equal(0); + }); it('should see recording WS messages', async () => { - await I.startRecordingWebSocketMessages() - await I.amOnPage('https://websocketstest.com/') - I.waitForText('Work for You!') - const wsMessages = await I.grabWebSocketMessages() - expect(wsMessages.length).to.greaterThan(0) - }) + await I.startRecordingWebSocketMessages(); + await I.amOnPage('https://websocketstest.com/'); + I.waitForText('Work for You!'); + const wsMessages = await I.grabWebSocketMessages(); + expect(wsMessages.length).to.greaterThan(0); + }); it('should not see recording WS messages', async () => { - await I.startRecordingWebSocketMessages() - await I.amOnPage('https://websocketstest.com/') - I.waitForText('Work for You!') - const wsMessages = I.grabWebSocketMessages() - await I.stopRecordingWebSocketMessages() - await I.amOnPage('https://websocketstest.com/') - I.waitForText('Work for You!') - const afterWsMessages = I.grabWebSocketMessages() - expect(wsMessages.length).to.equal(afterWsMessages.length) - }) - }) -} + await I.startRecordingWebSocketMessages(); + await I.amOnPage('https://websocketstest.com/'); + I.waitForText('Work for You!'); + const wsMessages = I.grabWebSocketMessages(); + await I.stopRecordingWebSocketMessages(); + await I.amOnPage('https://websocketstest.com/'); + I.waitForText('Work for You!'); + const afterWsMessages = I.grabWebSocketMessages(); + expect(wsMessages.length).to.equal(afterWsMessages.length); + }); + }); +}; diff --git a/test/runner/dry_run_test.js b/test/runner/dry_run_test.js index 851c7fc49..d24302b3c 100644 --- a/test/runner/dry_run_test.js +++ b/test/runner/dry_run_test.js @@ -1,54 +1,54 @@ -const path = require('path') -const { expect } = require('expect') -const exec = require('child_process').exec +const path = require('path'); +const { expect } = require('expect'); +const exec = require('child_process').exec; -const runner = path.join(__dirname, '/../../bin/codecept.js') -const codecept_dir = path.join(__dirname, '/../data/sandbox') -const codecept_run = `${runner} dry-run` +const runner = path.join(__dirname, '/../../bin/codecept.js'); +const codecept_dir = path.join(__dirname, '/../data/sandbox'); +const codecept_run = `${runner} dry-run`; const codecept_run_config = (config, grep) => - `${codecept_run} --config ${codecept_dir}/${config} ${grep ? `--grep "${grep}"` : ''}` -const char = require('figures').checkboxOff + `${codecept_run} --config ${codecept_dir}/${config} ${grep ? `--grep "${grep}"` : ''}`; +const char = require('figures').checkboxOff; describe('dry-run command', () => { before(() => { - process.chdir(codecept_dir) - }) + process.chdir(codecept_dir); + }); it('should be executed with config path', (done) => { - process.chdir(__dirname) + process.chdir(__dirname); exec(`${codecept_run_config('codecept.js')}`, (err, stdout) => { - expect(stdout).toContain('Filesystem') // feature - expect(stdout).toContain('check current dir') // test name - expect(err).toBeFalsy() - done() - }) - }) + expect(stdout).toContain('Filesystem'); // feature + expect(stdout).toContain('check current dir'); // test name + expect(err).toBeFalsy(); + done(); + }); + }); it('should list all tests', (done) => { - process.chdir(__dirname) + process.chdir(__dirname); exec(`${codecept_run_config('codecept.js')}`, (err, stdout) => { - expect(stdout).toContain('Filesystem') // feature - expect(stdout).toContain('check current dir') // test name - expect(stdout).toContain('No tests were executed') - expect(err).toBeFalsy() - done() - }) - }) + expect(stdout).toContain('Filesystem'); // feature + expect(stdout).toContain('check current dir'); // test name + expect(stdout).toContain('No tests were executed'); + expect(err).toBeFalsy(); + done(); + }); + }); it('should not run actual steps', (done) => { exec(`${codecept_run_config('codecept.flaky.js')}`, (err, stdout) => { - expect(stdout).toContain('Flaky') // feature - expect(stdout).toContain('Not so flaky test') // test name - expect(stdout).toContain('Old style flaky') // test name - expect(stdout).toContain('No tests were executed') - expect(err).toBeFalsy() - done() - }) - }) + expect(stdout).toContain('Flaky'); // feature + expect(stdout).toContain('Not so flaky test'); // test name + expect(stdout).toContain('Old style flaky'); // test name + expect(stdout).toContain('No tests were executed'); + expect(err).toBeFalsy(); + done(); + }); + }); it('should not run helper hooks', (done) => { exec(`${codecept_run_config('codecept.testhooks.json')} --debug`, (err, stdout) => { - const lines = stdout.match(/\S.+/g) + const lines = stdout.match(/\S.+/g); expect(lines).not.toEqual( expect.arrayContaining([ @@ -58,7 +58,7 @@ describe('dry-run command', () => { "Helper: I'm simple After hook", "Helper: I'm simple AfterSuite hook", ]), - ) + ); expect(lines).toEqual( expect.arrayContaining([ @@ -67,18 +67,18 @@ describe('dry-run command', () => { "Test: I'm simple After hook", "Test: I'm simple AfterSuite hook", ]), - ) + ); - expect(stdout).toContain('OK | 1 passed') - expect(stdout).toContain('No tests were executed') - expect(err).toBeFalsy() - done() - }) - }) + expect(stdout).toContain('OK | 1 passed'); + expect(stdout).toContain('No tests were executed'); + expect(err).toBeFalsy(); + done(); + }); + }); it('should display meta steps and substeps', (done) => { exec(`${codecept_run_config('configs/pageObjects/codecept.po.js')} --debug`, (err, stdout) => { - const lines = stdout.split('\n') + const lines = stdout.split('\n'); expect(lines).toEqual( expect.arrayContaining([ ' check current dir', @@ -90,87 +90,87 @@ describe('dry-run command', () => { ' I see file "codecept.po.js"', ' I see file "codecept.po.js"', ]), - ) - expect(stdout).toContain('OK | 1 passed') - expect(stdout).toContain('No tests were executed') - expect(err).toBeFalsy() - done() - }) - }) + ); + expect(stdout).toContain('OK | 1 passed'); + expect(stdout).toContain('No tests were executed'); + expect(err).toBeFalsy(); + done(); + }); + }); it('should run feature files', (done) => { exec(codecept_run_config('codecept.bdd.js') + ' --steps --grep "Checkout process"', (err, stdout) => { //eslint-disable-line - expect(stdout).toContain('Checkout process') // feature - expect(stdout).toContain('-- before checkout --') - expect(stdout).toContain('-- after checkout --') + expect(stdout).toContain('Checkout process'); // feature + expect(stdout).toContain('-- before checkout --'); + expect(stdout).toContain('-- after checkout --'); // expect(stdout).toContain('In order to buy products'); // test name - expect(stdout).toContain('Given I have product with $600 price') - expect(stdout).toContain('And I have product with $1000 price') - expect(stdout).toContain('Then I should see that total number of products is 2') - expect(stdout).toContain('And my order amount is $1600') - expect(stdout).not.toContain('I add item 600') // 'Given' actor's non-gherkin step check - expect(stdout).not.toContain('I see sum 1600') // 'And' actor's non-gherkin step check - expect(stdout).toContain('No tests were executed') - expect(err).toBeFalsy() - done() - }) - }) + expect(stdout).toContain('Given I have product with $600 price'); + expect(stdout).toContain('And I have product with $1000 price'); + expect(stdout).toContain('Then I should see that total number of products is 2'); + expect(stdout).toContain('And my order amount is $1600'); + expect(stdout).not.toContain('I add item 600'); // 'Given' actor's non-gherkin step check + expect(stdout).not.toContain('I see sum 1600'); // 'And' actor's non-gherkin step check + expect(stdout).toContain('No tests were executed'); + expect(err).toBeFalsy(); + done(); + }); + }); it('should run feature files with regex grep', (done) => { exec(codecept_run_config('codecept.bdd.js') + ' --steps --grep "(?=.*Checkout process)"', (err, stdout) => { //eslint-disable-line - expect(stdout).toContain('Checkout process') // feature - expect(stdout).toContain('-- before checkout --') - expect(stdout).toContain('-- after checkout --') + expect(stdout).toContain('Checkout process'); // feature + expect(stdout).toContain('-- before checkout --'); + expect(stdout).toContain('-- after checkout --'); // expect(stdout).toContain('In order to buy products'); // test name - expect(stdout).toContain('Given I have product with $600 price') - expect(stdout).toContain('And I have product with $1000 price') - expect(stdout).toContain('Then I should see that total number of products is 2') - expect(stdout).toContain('And my order amount is $1600') - expect(stdout).not.toContain('I add item 600') // 'Given' actor's non-gherkin step check - expect(stdout).not.toContain('I see sum 1600') // 'And' actor's non-gherkin step check - expect(stdout).toContain('No tests were executed') - expect(err).toBeFalsy() - done() - }) - }) + expect(stdout).toContain('Given I have product with $600 price'); + expect(stdout).toContain('And I have product with $1000 price'); + expect(stdout).toContain('Then I should see that total number of products is 2'); + expect(stdout).toContain('And my order amount is $1600'); + expect(stdout).not.toContain('I add item 600'); // 'Given' actor's non-gherkin step check + expect(stdout).not.toContain('I see sum 1600'); // 'And' actor's non-gherkin step check + expect(stdout).toContain('No tests were executed'); + expect(err).toBeFalsy(); + done(); + }); + }); it('should print substeps in debug mode', (done) => { exec(codecept_run_config('codecept.bdd.js') + ' --debug --grep "Checkout process @important"', (err, stdout) => { //eslint-disable-line - expect(stdout).toContain('Checkout process') // feature + expect(stdout).toContain('Checkout process'); // feature // expect(stdout).toContain('In order to buy products'); // test name - expect(stdout).toContain('Given I have product with $600 price') - expect(stdout).toContain('I add item 600') - expect(stdout).toContain('And I have product with $1000 price') - expect(stdout).toContain('I add item 1000') - expect(stdout).toContain('Then I should see that total number of products is 2') - expect(stdout).toContain('I see num 2') - expect(stdout).toContain('And my order amount is $1600') - expect(stdout).toContain('I see sum 1600') - expect(stdout).toContain('OK | 1 passed') - expect(stdout).toContain('No tests were executed') - expect(err).toBeFalsy() - done() - }) - }) + expect(stdout).toContain('Given I have product with $600 price'); + expect(stdout).toContain('I add item 600'); + expect(stdout).toContain('And I have product with $1000 price'); + expect(stdout).toContain('I add item 1000'); + expect(stdout).toContain('Then I should see that total number of products is 2'); + expect(stdout).toContain('I see num 2'); + expect(stdout).toContain('And my order amount is $1600'); + expect(stdout).toContain('I see sum 1600'); + expect(stdout).toContain('OK | 1 passed'); + expect(stdout).toContain('No tests were executed'); + expect(err).toBeFalsy(); + done(); + }); + }); it('should run tests with different data', (done) => { exec(`${codecept_run_config('codecept.ddt.js')} --debug`, (err, stdout) => { - const output = stdout.replace(/in [0-9]ms/g, '').replace(/\r/g, '') - expect(output).toContain('OK | 11 passed') - expect(err).toBeFalsy() - done() - }) - }) + const output = stdout.replace(/in [0-9]ms/g, '').replace(/\r/g, ''); + expect(output).toContain('OK | 11 passed'); + expect(err).toBeFalsy(); + done(); + }); + }); it('should work with inject() keyword', (done) => { exec( `${codecept_run_config('configs/pageObjects/codecept.inject.po.js', 'check current dir')} --debug`, (err, stdout) => { - const lines = stdout.split('\n') - expect(stdout).toContain('injected') + const lines = stdout.split('\n'); + expect(stdout).toContain('injected'); expect(lines).toEqual( expect.arrayContaining([ ' check current dir', @@ -182,43 +182,43 @@ describe('dry-run command', () => { ' I see file "codecept.po.js"', ' I see file "codecept.po.js"', ]), - ) - expect(stdout).toContain('OK | 1 passed') - expect(err).toBeFalsy() - done() + ); + expect(stdout).toContain('OK | 1 passed'); + expect(err).toBeFalsy(); + done(); }, - ) - }) + ); + }); it('should inject page objects via proxy', (done) => { exec(`${codecept_run_config('../inject-fail-example')} --debug`, (err, stdout) => { - expect(stdout).toContain('newdomain') - expect(stdout).toContain("[ 'veni', 'vedi', 'vici' ]", 'array objects work') - expect(stdout).toContain('OK | 1 passed') - expect(err).toBeFalsy() - done() - }) - }) + expect(stdout).toContain('newdomain'); + expect(stdout).toContain('veni,vedi,vici'); + expect(stdout).toContain('OK | 1 passed'); + expect(err).toBeFalsy(); + done(); + }); + }); it('should enable all plugins in dry-mode when passing -p all', (done) => { exec(`${codecept_run_config('codecept.customLocator.js')} --verbose -p all`, (err, stdout) => { - expect(stdout).toContain('Plugins: screenshotOnFail, customLocator') - expect(stdout).toContain("I see element {xpath: .//*[@data-testid='COURSE']//a}") - expect(stdout).toContain('OK | 1 passed') - expect(stdout).toContain('--- DRY MODE: No tests were executed ---') - expect(err).toBeFalsy() - done() - }) - }) + expect(stdout).toContain('Plugins: screenshotOnFail, customLocator'); + expect(stdout).toContain("I see element {xpath: .//*[@data-testid='COURSE']//a}"); + expect(stdout).toContain('OK | 1 passed'); + expect(stdout).toContain('--- DRY MODE: No tests were executed ---'); + expect(err).toBeFalsy(); + done(); + }); + }); it('should enable a particular plugin in dry-mode when passing it to -p', (done) => { exec(`${codecept_run_config('codecept.customLocator.js')} --verbose -p customLocator`, (err, stdout) => { - expect(stdout).toContain('Plugins: customLocator') - expect(stdout).toContain("I see element {xpath: .//*[@data-testid='COURSE']//a}") - expect(stdout).toContain('OK | 1 passed') - expect(stdout).toContain('--- DRY MODE: No tests were executed ---') - expect(err).toBeFalsy() - done() - }) - }) -}) + expect(stdout).toContain('Plugins: customLocator'); + expect(stdout).toContain("I see element {xpath: .//*[@data-testid='COURSE']//a}"); + expect(stdout).toContain('OK | 1 passed'); + expect(stdout).toContain('--- DRY MODE: No tests were executed ---'); + expect(err).toBeFalsy(); + done(); + }); + }); +}); diff --git a/test/runner/pageobject_test.js b/test/runner/pageobject_test.js index 5d67aaebf..c78fe9a15 100644 --- a/test/runner/pageobject_test.js +++ b/test/runner/pageobject_test.js @@ -1,22 +1,22 @@ -const path = require('path') -const exec = require('child_process').exec -const { expect } = require('expect') +const path = require('path'); +const exec = require('child_process').exec; +const { expect } = require('expect'); -const runner = path.join(__dirname, '/../../bin/codecept.js') -const codecept_dir = path.join(__dirname, '/../data/sandbox/configs/pageObjects') -const codecept_run = `${runner} run` +const runner = path.join(__dirname, '/../../bin/codecept.js'); +const codecept_dir = path.join(__dirname, '/../data/sandbox/configs/pageObjects'); +const codecept_run = `${runner} run`; const config_run_config = (config, grep) => - `${codecept_run} --config ${codecept_dir}/${config} ${grep ? `--grep "${grep}"` : ''}` + `${codecept_run} --config ${codecept_dir}/${config} ${grep ? `--grep "${grep}"` : ''}`; describe('CodeceptJS PageObject', () => { before(() => { - process.chdir(codecept_dir) - }) + process.chdir(codecept_dir); + }); describe('Failed PageObject', () => { it('should fail if page objects was failed', (done) => { exec(`${config_run_config('codecept.fail_po.js')} --debug`, (err, stdout) => { - const lines = stdout.split('\n') + const lines = stdout.split('\n'); expect(lines).toEqual( expect.arrayContaining([ expect.stringContaining('File notexistfile.js not found in'), @@ -25,68 +25,68 @@ describe('CodeceptJS PageObject', () => { expect.stringContaining('- I.seeFile("codecept.class.js")'), expect.stringContaining('- I.amInPath(".")'), ]), - ) - expect(stdout).toContain('FAIL | 0 passed, 1 failed') - expect(err).toBeTruthy() - done() - }) - }) - }) + ); + expect(stdout).toContain('FAIL | 0 passed, 1 failed'); + expect(err).toBeTruthy(); + done(); + }); + }); + }); describe('PageObject as Class', () => { it('should inject page objects by class', (done) => { exec(`${config_run_config('codecept.class.js', '@ClassPageObject')} --debug`, (err, stdout) => { - expect(stdout).not.toContain('classpage.type is not a function') - expect(stdout).toContain('On classpage: type "Class Page Type"') - expect(stdout).toContain('I print message "Class Page Type"') - expect(stdout).toContain('On classpage: purge domains') - expect(stdout).toContain('I print message "purgeDomains"') - expect(stdout).toContain('Class Page Type') - expect(stdout).toContain('OK | 1 passed') - expect(err).toBeFalsy() - done() - }) - }) + expect(stdout).not.toContain('classpage.type is not a function'); + expect(stdout).toContain('On classpage: type "Class Page Type"'); + expect(stdout).toContain('I print message "Class Page Type"'); + expect(stdout).toContain('On classpage: purge domains'); + expect(stdout).toContain('I print message "purgeDomains"'); + expect(stdout).toContain('Class Page Type'); + expect(stdout).toContain('OK | 1 passed'); + expect(err).toBeFalsy(); + done(); + }); + }); it('should inject page objects by class which nested base clas', (done) => { exec(`${config_run_config('codecept.class.js', '@NestedClassPageObject')} --debug`, (err, stdout) => { - expect(stdout).not.toContain('classnestedpage.type is not a function') - expect(stdout).toContain('On classnestedpage: type "Nested Class Page Type"') - expect(stdout).toContain('user => User1') - expect(stdout).toContain('I print message "Nested Class Page Type"') - expect(stdout).toContain('On classnestedpage: purge domains') - expect(stdout).toContain('I print message "purgeDomains"') - expect(stdout).toContain('Nested Class Page Type') - expect(stdout).toContain('OK | 1 passed') - expect(err).toBeFalsy() - done() - }) - }) + expect(stdout).not.toContain('classnestedpage.type is not a function'); + expect(stdout).toContain('On classnestedpage: type "Nested Class Page Type"'); + expect(stdout).toContain('user => User1'); + expect(stdout).toContain('I print message "Nested Class Page Type"'); + expect(stdout).toContain('On classnestedpage: purge domains'); + expect(stdout).toContain('I print message "purgeDomains"'); + expect(stdout).toContain('Nested Class Page Type'); + expect(stdout).toContain('OK | 1 passed'); + expect(err).toBeFalsy(); + done(); + }); + }); it('should print pretty step log and pretty event log', (done) => { exec(`${config_run_config('codecept.logs.js', 'Print correct arg message')} --steps`, (err, stdout) => { - expect(stdout).toContain('I get humanize args Logs Page Value') - expect(stdout).toContain('Start event step: I get humanize args Logs Page Valu') - expect(stdout).toContain('OK | 1 passed') - expect(err).toBeFalsy() - done() - }) - }) + expect(stdout).toContain('I get humanize args Logs Page Value'); + expect(stdout).toContain('Start event step: I get humanize args Logs Page Valu'); + expect(stdout).toContain('OK | 1 passed'); + expect(err).toBeFalsy(); + done(); + }); + }); it('should print pretty failed step log on stack trace', (done) => { exec(`${config_run_config('codecept.logs.js', 'Error print correct arg message')} --steps`, (err, stdout) => { - expect(stdout).toContain('I.errorMethodHumanizeArgs(Logs Page Value)') - expect(stdout).toContain('FAIL | 0 passed, 1 failed') - expect(err).toBeTruthy() - done() - }) - }) - }) + expect(stdout).toContain('I.errorMethodHumanizeArgs(Logs Page Value)'); + expect(stdout).toContain('FAIL | 0 passed, 1 failed'); + expect(err).toBeTruthy(); + done(); + }); + }); + }); describe('Show MetaSteps in Log', () => { it('should display meta steps and substeps', (done) => { exec(`${config_run_config('codecept.po.js')} --debug`, (err, stdout) => { - const lines = stdout.split('\n') + const lines = stdout.split('\n'); expect(lines).toEqual( expect.arrayContaining([ ' check current dir', @@ -98,19 +98,19 @@ describe('CodeceptJS PageObject', () => { ' I see file "codecept.po.js"', ' I see file "codecept.po.js"', ]), - ) - expect(stdout).toContain('OK | 1 passed') - expect(err).toBeFalsy() - done() - }) - }) - }) + ); + expect(stdout).toContain('OK | 1 passed'); + expect(err).toBeFalsy(); + done(); + }); + }); + }); describe('Inject PO in Test', () => { it('should work with inject() keyword', (done) => { exec(`${config_run_config('codecept.inject.po.js', 'check current dir')} --debug`, (err, stdout) => { - const lines = stdout.split('\n') - expect(stdout).toContain('injected') + const lines = stdout.split('\n'); + expect(stdout).toContain('injected'); expect(lines).toEqual( expect.arrayContaining([ ' check current dir', @@ -122,18 +122,18 @@ describe('CodeceptJS PageObject', () => { ' I see file "codecept.po.js"', ' I see file "codecept.po.js"', ]), - ) - expect(stdout).toContain('OK | 1 passed') - expect(err).toBeFalsy() - done() - }) - }) - }) + ); + expect(stdout).toContain('OK | 1 passed'); + expect(err).toBeFalsy(); + done(); + }); + }); + }); describe('PageObject with context', () => { it('should work when used "this" context on method', (done) => { exec(`${config_run_config('codecept.inject.po.js', 'pageobject with context')} --debug`, (err, stdout) => { - const lines = stdout.split('\n') + const lines = stdout.split('\n'); expect(lines).toEqual( expect.arrayContaining([ ' pageobject with context', @@ -145,33 +145,33 @@ describe('CodeceptJS PageObject', () => { ' I see file "codecept.po.js"', ' I see file "codecept.po.js"', ]), - ) - expect(stdout).toContain('OK | 1 passed') - expect(err).toBeFalsy() - done() - }) - }) - }) + ); + expect(stdout).toContain('OK | 1 passed'); + expect(err).toBeFalsy(); + done(); + }); + }); + }); describe('Inject PO in another PO', () => { it('should inject page objects via proxy', (done) => { exec(`${config_run_config('../../../inject-fail-example')} --debug`, (err, stdout) => { - expect(stdout).toContain('newdomain') - expect(stdout).toContain('veni,vedi,vici') - expect(stdout).toContain('OK | 1 passed') - expect(err).toBeFalsy() - done() - }) - }) - }) + expect(stdout).toContain('newdomain'); + expect(stdout).toContain('veni,vedi,vici'); + expect(stdout).toContain('OK | 1 passed'); + expect(err).toBeFalsy(); + done(); + }); + }); + }); it('built methods are still available custom I steps_file is added', (done) => { exec(`${config_run_config('codecept.class.js', '@CustomStepsBuiltIn')} --debug`, (err, stdout) => { - expect(stdout).toContain('Built in say') - expect(stdout).toContain('Say called from custom step') - expect(stdout).toContain('OK | 1 passed') - expect(err).toBeFalsy() - done() - }) - }) -}) + expect(stdout).toContain('Built in say'); + expect(stdout).toContain('Say called from custom step'); + expect(stdout).toContain('OK | 1 passed'); + expect(err).toBeFalsy(); + done(); + }); + }); +}); diff --git a/test/runner/run_multiple_test.js b/test/runner/run_multiple_test.js index 99704c4bf..69a25f175 100644 --- a/test/runner/run_multiple_test.js +++ b/test/runner/run_multiple_test.js @@ -1,264 +1,264 @@ -const assert = require('assert') -const { expect } = require('expect') -const path = require('path') -const exec = require('child_process').exec +const assert = require('assert'); +const { expect } = require('expect'); +const path = require('path'); +const exec = require('child_process').exec; -const runner = path.join(__dirname, '/../../bin/codecept.js') -const codecept_dir = path.join(__dirname, '/../data/sandbox') -const codecept_run = `${runner} run-multiple --config ${codecept_dir}/codecept.multiple.js ` +const runner = path.join(__dirname, '/../../bin/codecept.js'); +const codecept_dir = path.join(__dirname, '/../data/sandbox'); +const codecept_run = `${runner} run-multiple --config ${codecept_dir}/codecept.multiple.js `; describe('CodeceptJS Multiple Runner', function () { - this.timeout(40000) + this.timeout(40000); before(() => { - global.codecept_dir = path.join(__dirname, '/../data/sandbox') - }) + global.codecept_dir = path.join(__dirname, '/../data/sandbox'); + }); it('should execute one suite with browser', (done) => { exec(`${codecept_run}default:firefox`, (err, stdout) => { - stdout.should.include('CodeceptJS') // feature - stdout.should.include('.default:firefox] print browser ') - stdout.should.not.include('.default:chrome] print browser ') - assert(!err) - done() - }) - }) + stdout.should.include('CodeceptJS'); // feature + stdout.should.include('.default:firefox] print browser '); + stdout.should.not.include('.default:chrome] print browser '); + assert(!err); + done(); + }); + }); it('should execute all suites', (done) => { exec(`${codecept_run}--all`, (err, stdout) => { - stdout.should.include('CodeceptJS') // feature - stdout.should.include('[1.default:chrome] print browser ') - stdout.should.include('[2.default:firefox] print browser ') - stdout.should.include('[3.mobile:android] print browser ') - stdout.should.include('[4.mobile:safari] print browser ') - stdout.should.include('[5.mobile:chrome] print browser ') - stdout.should.include('[6.mobile:safari] print browser ') - stdout.should.include('[7.grep:chrome] @grep print browser size ') - stdout.should.include('[8.grep:firefox] @grep print browser size ') - stdout.should.not.include('[7.grep:chrome] print browser ') - stdout.should.include('[1.default:chrome] @grep print browser size ') - stdout.should.include('[3.mobile:android] @grep print browser size ') - assert(!err) - done() - }) - }) + stdout.should.include('CodeceptJS'); // feature + stdout.should.include('[1.default:chrome] print browser '); + stdout.should.include('[2.default:firefox] print browser '); + stdout.should.include('[3.mobile:android] print browser '); + stdout.should.include('[4.mobile:safari] print browser '); + stdout.should.include('[5.mobile:chrome] print browser '); + stdout.should.include('[6.mobile:safari] print browser '); + stdout.should.include('[7.grep:chrome] @grep print browser size '); + stdout.should.include('[8.grep:firefox] @grep print browser size '); + stdout.should.not.include('[7.grep:chrome] print browser '); + stdout.should.include('[1.default:chrome] @grep print browser size '); + stdout.should.include('[3.mobile:android] @grep print browser size '); + assert(!err); + done(); + }); + }); it('should replace parameters', (done) => { exec(`${codecept_run}grep --debug`, (err, stdout) => { - stdout.should.include('CodeceptJS') // feature - stdout.should.include('[1.grep:chrome] › maximize') - stdout.should.include('[2.grep:firefox] › 1200x840') - assert(!err) - done() - }) - }) + stdout.should.include('CodeceptJS'); // feature + stdout.should.include('[1.grep:chrome] › maximize'); + stdout.should.include('[2.grep:firefox] › 1200x840'); + assert(!err); + done(); + }); + }); it('should execute multiple suites', (done) => { exec(`${codecept_run}mobile default `, (err, stdout) => { - stdout.should.include('CodeceptJS') // feature - stdout.should.include('[1.mobile:android] print browser ') - stdout.should.include('[2.mobile:safari] print browser ') - stdout.should.include('[3.mobile:chrome] print browser ') - stdout.should.include('[4.mobile:safari] print browser ') - stdout.should.include('[5.default:chrome] print browser ') - stdout.should.include('[6.default:firefox] print browser ') - assert(!err) - done() - }) - }) + stdout.should.include('CodeceptJS'); // feature + stdout.should.include('[1.mobile:android] print browser '); + stdout.should.include('[2.mobile:safari] print browser '); + stdout.should.include('[3.mobile:chrome] print browser '); + stdout.should.include('[4.mobile:safari] print browser '); + stdout.should.include('[5.default:chrome] print browser '); + stdout.should.include('[6.default:firefox] print browser '); + assert(!err); + done(); + }); + }); it('should execute multiple suites with selected browsers', (done) => { exec(`${codecept_run}mobile:safari default:chrome `, (err, stdout) => { - stdout.should.include('CodeceptJS') // feature - stdout.should.include('[1.mobile:safari] print browser ') - stdout.should.include('[2.mobile:safari] print browser ') - stdout.should.include('[3.default:chrome] print browser ') - assert(!err) - done() - }) - }) + stdout.should.include('CodeceptJS'); // feature + stdout.should.include('[1.mobile:safari] print browser '); + stdout.should.include('[2.mobile:safari] print browser '); + stdout.should.include('[3.default:chrome] print browser '); + assert(!err); + done(); + }); + }); it('should print steps', (done) => { exec(`${codecept_run}default --steps`, (err, stdout) => { - stdout.should.include('CodeceptJS') // feature - stdout.should.include('[2.default:firefox] print browser ') - stdout.should.include('[2.default:firefox] I print browser ') - stdout.should.include('[1.default:chrome] print browser ') - stdout.should.include('[1.default:chrome] I print browser ') - assert(!err) - done() - }) - }) + stdout.should.include('CodeceptJS'); // feature + stdout.should.include('[2.default:firefox] print browser '); + stdout.should.include('[2.default:firefox] I print browser '); + stdout.should.include('[1.default:chrome] print browser '); + stdout.should.include('[1.default:chrome] I print browser '); + assert(!err); + done(); + }); + }); it('should pass grep to configuration', (done) => { exec(`${codecept_run}default --grep @grep`, (err, stdout) => { - stdout.should.include('CodeceptJS') // feature - stdout.should.include('[1.default:chrome] @grep print browser size') - stdout.should.include('[2.default:firefox] @grep print browser size') - stdout.should.not.include('[1.default:chrome] print browser ') - stdout.should.not.include('[2.default:firefox] print browser ') - assert(!err) - done() - }) - }) + stdout.should.include('CodeceptJS'); // feature + stdout.should.include('[1.default:chrome] @grep print browser size'); + stdout.should.include('[2.default:firefox] @grep print browser size'); + stdout.should.not.include('[1.default:chrome] print browser '); + stdout.should.not.include('[2.default:firefox] print browser '); + assert(!err); + done(); + }); + }); it('should pass grep invert to configuration', (done) => { exec(`${codecept_run}default --grep @grep --invert`, (err, stdout) => { - stdout.should.include('CodeceptJS') // feature - stdout.should.not.include('[1.default:chrome] @grep print browser size') - stdout.should.not.include('[2.default:firefox] @grep print browser size') - stdout.should.include('[1.default:chrome] print browser ') - stdout.should.include('[2.default:firefox] print browser ') - assert(!err) - done() - }) - }) + stdout.should.include('CodeceptJS'); // feature + stdout.should.not.include('[1.default:chrome] @grep print browser size'); + stdout.should.not.include('[2.default:firefox] @grep print browser size'); + stdout.should.include('[1.default:chrome] print browser '); + stdout.should.include('[2.default:firefox] print browser '); + assert(!err); + done(); + }); + }); it('should pass tests to configuration', (done) => { exec(`${codecept_run}test`, (err, stdout) => { - stdout.should.include('CodeceptJS') // feature - stdout.should.include('[1.test:chrome] print browser size') - stdout.should.include('[2.test:firefox] print browser size') - stdout.should.include('[1.test:chrome] print browser ') - stdout.should.include('[2.test:firefox] print browser ') - assert(!err) - done() - }) - }) + stdout.should.include('CodeceptJS'); // feature + stdout.should.include('[1.test:chrome] print browser size'); + stdout.should.include('[2.test:firefox] print browser size'); + stdout.should.include('[1.test:chrome] print browser '); + stdout.should.include('[2.test:firefox] print browser '); + assert(!err); + done(); + }); + }); it('should run chunks', (done) => { exec(`${codecept_run}chunks`, (err, stdout) => { - stdout.should.include('CodeceptJS') // feature - stdout.should.match(/chunks:chunk\d:dummy].+print browser/i) - stdout.should.match(/chunks:chunk\d:dummy].+@grep print browser size/i) - assert(!err) - done() - }) - }) + stdout.should.include('CodeceptJS'); // feature + stdout.should.match(/chunks:chunk\d:dummy].+print browser/i); + stdout.should.match(/chunks:chunk\d:dummy].+@grep print browser size/i); + assert(!err); + done(); + }); + }); it('should run features in parallel', (done) => { - process.chdir(codecept_dir) + process.chdir(codecept_dir); exec( `${runner} run-multiple --config codecept.multiple.features.js chunks --features --grep '(?=.*)^(?!.*@fail)'`, (err, stdout) => { - stdout.should.match(/\[\d\.chunks:chunk\d:default\] Checkout examples process/) + stdout.should.match(/\[\d\.chunks:chunk\d:default\] Checkout examples process/); // stdout.should.not.match(/\[\d\.chunks:chunk\d:default\] Checkout examples process/) - stdout.should.match(/\[\d\.chunks:chunk\d:default\] Checkout string/) + stdout.should.match(/\[\d\.chunks:chunk\d:default\] Checkout string/); // stdout.should.not.match(/\[\d\.chunks:chunk\d:default\] Checkout string/) - stdout.should.match(/\[\d\.chunks:chunk\d:default\] {3}OK {2}\|/) - stdout.should.match(/\[\d\.chunks:chunk\d:default\] {3}OK {2}\|/) - stdout.should.not.include('@feature_grep') - assert(!err) - done() + stdout.should.match(/\[\d\.chunks:chunk\d:default\] {3}OK {2}\|/); + stdout.should.match(/\[\d\.chunks:chunk\d:default\] {3}OK {2}\|/); + stdout.should.not.include('@feature_grep'); + assert(!err); + done(); }, - ) - }) + ); + }); it('should run features & tests in parallel', (done) => { - process.chdir(codecept_dir) + process.chdir(codecept_dir); exec( `${runner} run-multiple --config codecept.multiple.features.js chunks --grep '(?=.*)^(?!.*@fail)'`, (err, stdout) => { - stdout.should.include('@feature_grep') - stdout.should.include('Checkout examples process') - stdout.should.include('Checkout string') - assert(!err) - done() + stdout.should.include('@feature_grep'); + stdout.should.include('Checkout examples process'); + stdout.should.include('Checkout string'); + assert(!err); + done(); }, - ) - }) + ); + }); it('should run only tests in parallel', (done) => { - process.chdir(codecept_dir) + process.chdir(codecept_dir); exec(`${runner} run-multiple --config codecept.multiple.features.js chunks --tests`, (err, stdout) => { - stdout.should.include('@feature_grep') - stdout.should.not.include('Checkout examples process') - stdout.should.not.include('Checkout string') - assert(!err) - done() - }) - }) + stdout.should.include('@feature_grep'); + stdout.should.not.include('Checkout examples process'); + stdout.should.not.include('Checkout string'); + assert(!err); + done(); + }); + }); it('should exit with non-zero code for failures during init process', (done) => { - process.chdir(codecept_dir) + process.chdir(codecept_dir); exec(`${runner} run-multiple --config codecept.multiple.initFailure.js default --all`, (err, stdout) => { - expect(err).not.toBeFalsy() - expect(err.code).toBe(1) - expect(stdout).toContain('Failed on FailureHelper') - done() - }) - }) + expect(err).not.toBeFalsy(); + expect(err.code).toBe(1); + expect(stdout).toContain('Failed on FailureHelper'); + done(); + }); + }); it('should exit code 1 when error in config', (done) => { - process.chdir(codecept_dir) + process.chdir(codecept_dir); exec(`${runner} run-multiple --config configs/codecept-invalid.config.js default --all`, (err, stdout, stderr) => { - expect(stdout).not.toContain('UnhandledPromiseRejectionWarning') - expect(stderr).not.toContain('UnhandledPromiseRejectionWarning') - expect(stdout).toContain('badFn is not defined') - expect(err).not.toBe(null) - done() - }) - }) + expect(stdout).not.toContain('UnhandledPromiseRejectionWarning'); + expect(stderr).not.toContain('UnhandledPromiseRejectionWarning'); + expect(stdout).toContain('badFn is not defined'); + expect(err).not.toBe(null); + done(); + }); + }); describe('bootstrapAll and teardownAll', () => { - const _codecept_run = `run-multiple --config ${codecept_dir}` + const _codecept_run = `run-multiple --config ${codecept_dir}`; it('should be executed from async function in config', (done) => { exec(`${runner} ${_codecept_run}/codecept.async.bootstrapall.multiple.code.js default`, (err, stdout) => { - stdout.should.include('CodeceptJS') // feature - stdout.should.include('Results: inside Promise\n"event.multiple.before" is called') - stdout.should.include('"teardownAll" is called.') - assert(!err) - done() - }) - }) + stdout.should.include('CodeceptJS'); // feature + stdout.should.include('Results: inside Promise\n"event.multiple.before" is called'); + stdout.should.include('"teardownAll" is called.'); + assert(!err); + done(); + }); + }); it('should be executed from function in config', (done) => { exec(`${runner} ${_codecept_run}/codecept.bootstrapall.multiple.code.js default`, (err, stdout) => { - stdout.should.include('CodeceptJS') // feature - stdout.should.include('"bootstrapAll" is called.') - stdout.should.include('"teardownAll" is called.') - assert(!err) - done() - }) - }) - }) + stdout.should.include('CodeceptJS'); // feature + stdout.should.include('"bootstrapAll" is called.'); + stdout.should.include('"teardownAll" is called.'); + assert(!err); + done(); + }); + }); + }); describe('with require parameter', () => { - const _codecept_run = `run-multiple --config ${codecept_dir}` - const moduleOutput = 'Module was required 1' - const moduleOutput2 = 'Module was required 2' + const _codecept_run = `run-multiple --config ${codecept_dir}`; + const moduleOutput = 'Module was required 1'; + const moduleOutput2 = 'Module was required 2'; it('should be executed with module when described', (done) => { - process.chdir(codecept_dir) + process.chdir(codecept_dir); exec(`${runner} ${_codecept_run}/codecept.require.multiple.single.json default`, (err, stdout) => { - stdout.should.include(moduleOutput) - stdout.should.not.include(moduleOutput2) - ;(stdout.match(new RegExp(moduleOutput, 'g')) || []).should.have.lengthOf(2) - assert(!err) - done() - }) - }) + stdout.should.include(moduleOutput); + stdout.should.not.include(moduleOutput2); + (stdout.match(new RegExp(moduleOutput, 'g')) || []).should.have.lengthOf(2); + assert(!err); + done(); + }); + }); it('should be executed with several module when described', (done) => { - process.chdir(codecept_dir) + process.chdir(codecept_dir); exec(`${runner} ${_codecept_run}/codecept.require.multiple.several.js default`, (err, stdout) => { - stdout.should.include(moduleOutput) - stdout.should.include(moduleOutput2) - ;(stdout.match(new RegExp(moduleOutput, 'g')) || []).should.have.lengthOf(2) - ;(stdout.match(new RegExp(moduleOutput2, 'g')) || []).should.have.lengthOf(2) - assert(!err) - done() - }) - }) + stdout.should.include(moduleOutput); + stdout.should.include(moduleOutput2); + (stdout.match(new RegExp(moduleOutput, 'g')) || []).should.have.lengthOf(2); + (stdout.match(new RegExp(moduleOutput2, 'g')) || []).should.have.lengthOf(2); + assert(!err); + done(); + }); + }); it('should not be executed without module when not described', (done) => { - process.chdir(codecept_dir) + process.chdir(codecept_dir); exec(`${runner} ${_codecept_run}/codecept.require.multiple.without.json default`, (err, stdout) => { - stdout.should.not.include(moduleOutput) - stdout.should.not.include(moduleOutput2) - assert(!err) - done() - }) - }) - }) -}) + stdout.should.not.include(moduleOutput); + stdout.should.not.include(moduleOutput2); + assert(!err); + done(); + }); + }); + }); +}); diff --git a/test/runner/run_rerun_test.js b/test/runner/run_rerun_test.js index a38ba54af..72f5ca40b 100644 --- a/test/runner/run_rerun_test.js +++ b/test/runner/run_rerun_test.js @@ -1,113 +1,112 @@ -const { expect } = require('expect') -const { describe } = require('mocha') -const path = require('path') -const exec = require('child_process').exec -const semver = require('semver') +const { expect } = require('expect'); +const { describe } = require('mocha'); +const path = require('path'); +const exec = require('child_process').exec; +const semver = require('semver'); -const runner = path.join(__dirname, '/../../bin/codecept.js') -const codecept_dir = path.join(__dirname, '/../data/sandbox/configs/run-rerun/') -const codecept_run = `${runner} run-rerun` +const runner = path.join(__dirname, '/../../bin/codecept.js'); +const codecept_dir = path.join(__dirname, '/../data/sandbox/configs/run-rerun/'); +const codecept_run = `${runner} run-rerun`; const codecept_run_config = (config, grep) => - `${codecept_run} --config ${codecept_dir}/${config} --grep "${grep || ''}"` + `${codecept_run} --config ${codecept_dir}/${config} --grep "${grep || ''}"`; describe('run-rerun command', () => { before(() => { - process.chdir(codecept_dir) - }) + process.chdir(codecept_dir); + }); it('should display count of attemps', (done) => { exec(`${codecept_run_config('codecept.conf.js')} --debug`, (err, stdout) => { - const runs = stdout.split('Run Rerun - Command --') - + const runs = stdout.split('Run Rerun - Command --'); // check first run - expect(runs[1]).toContain('OK | 1 passed') - expect(runs[1]).toContain('✔ OK') + expect(runs[1]).toContain('OK | 1 passed'); + // expect(runs[1]).toContain('✔ OK') // check second run - expect(runs[2]).toContain('OK | 1 passed') - expect(runs[2]).toContain('✔ OK') + expect(runs[2]).toContain('OK | 1 passed'); + // expect(runs[2]).toContain('✔ OK') // check third run - expect(runs[2]).toContain('OK | 1 passed') - expect(runs[2]).toContain('✔ OK') + expect(runs[2]).toContain('OK | 1 passed'); + // expect(runs[2]).toContain('✔ OK') - expect(stdout).toContain('Process run 1 of max 3, success runs 1/3') - expect(stdout).toContain('Process run 2 of max 3, success runs 2/3') - expect(stdout).toContain('Process run 3 of max 3, success runs 3/3') - expect(stdout).toContain('OK | 1 passed') - expect(err).toBeNull() - done() - }) - }) + expect(stdout).toContain('Process run 1 of max 3, success runs 1/3'); + expect(stdout).toContain('Process run 2 of max 3, success runs 2/3'); + expect(stdout).toContain('Process run 3 of max 3, success runs 3/3'); + expect(stdout).toContain('OK | 1 passed'); + expect(err).toBeNull(); + done(); + }); + }); it('should display 2 success count of attemps', (done) => { exec(`${codecept_run_config('codecept.conf.min_less_max.js')} --debug`, (err, stdout) => { - const runs = stdout.split('Run Rerun - Command --') + const runs = stdout.split('Run Rerun - Command --'); // check first run - expect(runs[2]).toContain('OK | 1 passed') - expect(runs[2]).toContain('✔ OK') + expect(runs[2]).toContain('OK | 1 passed'); + // expect(runs[2]).toContain('✔ OK') // check second run - expect(runs[2]).toContain('OK | 1 passed') - expect(runs[2]).toContain('✔ OK') + expect(runs[2]).toContain('OK | 1 passed'); + // expect(runs[2]).toContain('✔ OK') - expect(stdout).toContain('Process run 1 of max 3, success runs 1/2') - expect(stdout).toContain('Process run 2 of max 3, success runs 2/2') - expect(stdout).not.toContain('Process run 3 of max 3') - expect(stdout).toContain('OK | 1 passed') - expect(err).toBeNull() - done() - }) - }) + expect(stdout).toContain('Process run 1 of max 3, success runs 1/2'); + expect(stdout).toContain('Process run 2 of max 3, success runs 2/2'); + expect(stdout).not.toContain('Process run 3 of max 3'); + expect(stdout).toContain('OK | 1 passed'); + expect(err).toBeNull(); + done(); + }); + }); it('should display error if minSuccess more than maxReruns', (done) => { exec(`${codecept_run_config('codecept.conf.min_more_max.js')} --debug`, (err, stdout) => { - expect(stdout).toContain('minSuccess must be less than maxReruns') - expect(err.code).toBe(1) - done() - }) - }) + expect(stdout).toContain('minSuccess must be less than maxReruns'); + expect(err.code).toBe(1); + done(); + }); + }); it('should display errors if test is fail always', (done) => { exec( `${codecept_run_config('codecept.conf.fail_test.js', '@RunRerun - Fail all attempt')} --debug`, (err, stdout) => { - expect(stdout).toContain('Fail run 1 of max 3, success runs 0/2') - expect(stdout).toContain('Fail run 2 of max 3, success runs 0/2') - expect(stdout).toContain('Fail run 3 of max 3, success runs 0/2') - expect(stdout).toContain('Flaky tests detected!') - expect(err.code).toBe(1) - done() + expect(stdout).toContain('Fail run 1 of max 3, success runs 0/2'); + expect(stdout).toContain('Fail run 2 of max 3, success runs 0/2'); + expect(stdout).toContain('Fail run 3 of max 3, success runs 0/2'); + expect(stdout).toContain('Flaky tests detected!'); + expect(err.code).toBe(1); + 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) => { - expect(stdout).toContain('Process run 1 of max 3, success runs 1/2') - expect(stdout).toContain('Fail run 2 of max 3, success runs 1/2') - expect(stdout).toContain('Process run 3 of max 3, success runs 2/2') - expect(stdout).not.toContain('Flaky tests detected!') - expect(err).toBeNull() - done() + expect(stdout).toContain('Process run 1 of max 3, success runs 1/2'); + expect(stdout).toContain('Fail run 2 of max 3, success runs 1/2'); + expect(stdout).toContain('Process run 3 of max 3, success runs 2/2'); + expect(stdout).not.toContain('Flaky tests detected!'); + expect(err).toBeNull(); + done(); }, - ) - }) + ); + }); 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() + 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/test/unit/actor_test.js b/test/unit/actor_test.js index 79ccabd5d..c97ac6798 100644 --- a/test/unit/actor_test.js +++ b/test/unit/actor_test.js @@ -1,32 +1,32 @@ -const path = require('path') -const { expect } = require('expect') +const path = require('path'); +const { expect } = require('expect'); -const actor = require('../../lib/actor') -const container = require('../../lib/container') -const recorder = require('../../lib/recorder') -const event = require('../../lib/event') -const store = require('../../lib/store') +const actor = require('../../lib/actor'); +const container = require('../../lib/container'); +const recorder = require('../../lib/recorder'); +const event = require('../../lib/event'); +const store = require('../../lib/store'); -global.codecept_dir = path.join(__dirname, '/..') -let I -let counter +global.codecept_dir = path.join(__dirname, '/..'); +let I; +let counter; describe('Actor', () => { beforeEach(async () => { - counter = 0 + counter = 0; container.clear( { MyHelper: { hello: () => 'hello world', bye: () => 'bye world', die: () => { - throw new Error('ups') + throw new Error('ups'); }, _hidden: () => 'hidden', failAfter: (i = 1) => { - counter++ - if (counter <= i) throw new Error('ups') - counter = 0 + counter++; + if (counter <= i) throw new Error('ups'); + counter = 0; }, }, MyHelper2: { @@ -35,135 +35,135 @@ describe('Actor', () => { }, undefined, undefined, - ) - store.actor = null - container.translation().vocabulary.actions.hello = 'привет' - I = actor() - await container.started() - event.cleanDispatcher() - }) + ); + store.actor = null; + container.translation().vocabulary.actions.hello = 'привет'; + I = actor(); + await container.started(); + event.cleanDispatcher(); + }); it('should collect pageobject methods in actor', async () => { const poI = actor({ customStep: () => {}, - }) - expect(poI).toHaveProperty('customStep') - expect(I).toHaveProperty('customStep') - }) + }); + expect(poI).toHaveProperty('customStep'); + expect(I).toHaveProperty('customStep'); + }); it('should correct run step from Helper inside PageObject', () => { actor({ customStep() { - return this.hello() + return this.hello(); }, - }) - recorder.start() - const promise = I.customStep() - return promise.then((val) => expect(val).toEqual('hello world')) - }) + }); + recorder.start(); + const promise = I.customStep(); + return promise.then((val) => expect(val).toEqual('hello world')); + }); it('should init pageobject methods as metastep', () => { actor({ customStep: () => 3, - }) - expect(I.customStep()).toEqual(3) - }) + }); + expect(I.customStep()).toEqual(3); + }); it('should correct add translation for step from Helper', () => { - expect(I).toHaveProperty('привет') - }) + expect(I).toHaveProperty('привет'); + }); it('should correct add translation for step from PageObject', async () => { - container.translation().vocabulary.actions.customStep = 'кастомный_шаг' + container.translation().vocabulary.actions.customStep = 'кастомный_шаг'; actor({ customStep: () => 3, - }) - await container.started() - expect(I).toHaveProperty('кастомный_шаг') - }) + }); + await container.started(); + expect(I).toHaveProperty('кастомный_шаг'); + }); it('should take all methods from helpers and built in', () => { - ;['hello', 'bye', 'die', 'failAfter', 'say', 'retry', 'greeting'].forEach((key) => { - expect(I).toHaveProperty(key) - }) - }) + ['hello', 'bye', 'die', 'failAfter', 'say', 'retry', 'greeting'].forEach((key) => { + expect(I).toHaveProperty(key); + }); + }); it('should return promise', () => { - recorder.start() - const promise = I.hello() - expect(promise).toBeInstanceOf(Promise) - return promise.then((val) => expect(val).toEqual('hello world')) - }) + recorder.start(); + const promise = I.hello(); + expect(promise).toBeInstanceOf(Promise); + return promise.then((val) => expect(val).toEqual('hello world')); + }); it('should produce step events', () => { - recorder.start() - let listeners = 0 - event.dispatcher.addListener(event.step.before, () => listeners++) - event.dispatcher.addListener(event.step.after, () => listeners++) + recorder.start(); + let listeners = 0; + event.dispatcher.addListener(event.step.before, () => listeners++); + event.dispatcher.addListener(event.step.after, () => listeners++); event.dispatcher.addListener(event.step.passed, (step) => { - listeners++ - expect(step.endTime).toBeTruthy() - expect(step.startTime).toBeTruthy() - }) + listeners++; + expect(step.endTime).toBeTruthy(); + expect(step.startTime).toBeTruthy(); + }); return I.hello().then(() => { - expect(listeners).toEqual(3) - }) - }) + expect(listeners).toEqual(3); + }); + }); it('should retry failed step with #retry', () => { - recorder.start() - return I.retry({ retries: 2, minTimeout: 0 }).failAfter(1) - }) + recorder.start(); + return I.retry({ retries: 2, minTimeout: 0 }).failAfter(1); + }); it('should retry once step with #retry', () => { - recorder.start() - return I.retry().failAfter(1) - }) + recorder.start(); + return I.retry().failAfter(1); + }); it('should alway use the latest global retry options', () => { - recorder.start() + recorder.start(); recorder.retry({ retries: 0, minTimeout: 0, when: () => true, - }) + }); recorder.retry({ retries: 1, minTimeout: 0, when: () => true, - }) - I.hello() // before fix: this changed the order of retries - return I.failAfter(1) - }) + }); + I.hello(); // before fix: this changed the order of retries + return I.failAfter(1); + }); it('should not delete a global retry option', () => { - recorder.start() + recorder.start(); recorder.retry({ retries: 2, minTimeout: 0, when: () => true, - }) - I.retry(1).failAfter(1) // before fix: this changed the order of retries - return I.failAfter(2) - }) + }); + I.retry(1).failAfter(1); // before fix: this changed the order of retries + return I.failAfter(2); + }); it('should print handle failed steps', () => { - recorder.start() - let listeners = 0 - event.dispatcher.addListener(event.step.before, () => listeners++) - event.dispatcher.addListener(event.step.after, () => listeners++) + recorder.start(); + let listeners = 0; + event.dispatcher.addListener(event.step.before, () => listeners++); + event.dispatcher.addListener(event.step.after, () => listeners++); event.dispatcher.addListener(event.step.failed, (step) => { - listeners++ - expect(step.endTime).toBeTruthy() - expect(step.startTime).toBeTruthy() - }) + listeners++; + expect(step.endTime).toBeTruthy(); + expect(step.startTime).toBeTruthy(); + }); return I.die() .then(() => (listeners = 0)) .catch(() => null) .then(() => { - expect(listeners).toEqual(3) - }) - }) -}) + expect(listeners).toEqual(3); + }); + }); +}); diff --git a/test/unit/bdd_test.js b/test/unit/bdd_test.js index 904baa140..9e3af1d40 100644 --- a/test/unit/bdd_test.js +++ b/test/unit/bdd_test.js @@ -1,25 +1,25 @@ -const Gherkin = require('@cucumber/gherkin') -const Messages = require('@cucumber/messages') +const Gherkin = require('@cucumber/gherkin'); +const Messages = require('@cucumber/messages'); -const chai = require('chai') +const chai = require('chai'); -const expect = chai.expect +const expect = chai.expect; -const uuidFn = Messages.IdGenerator.uuid() -const builder = new Gherkin.AstBuilder(uuidFn) -const matcher = new Gherkin.GherkinClassicTokenMatcher() +const uuidFn = Messages.IdGenerator.uuid(); +const builder = new Gherkin.AstBuilder(uuidFn); +const matcher = new Gherkin.GherkinClassicTokenMatcher(); -const Config = require('../../lib/config') -const { Given, When, And, Then, matchStep, clearSteps, defineParameterType } = require('../../lib/interfaces/bdd') -const run = require('../../lib/interfaces/gherkin') -const recorder = require('../../lib/recorder') -const container = require('../../lib/container') -const actor = require('../../lib/actor') -const event = require('../../lib/event') +const Config = require('../../lib/config'); +const { Given, When, And, Then, matchStep, clearSteps, defineParameterType } = require('../../lib/interfaces/bdd'); +const run = require('../../lib/interfaces/gherkin'); +const recorder = require('../../lib/recorder'); +const container = require('../../lib/container'); +const actor = require('../../lib/actor'); +const event = require('../../lib/event'); class Color { constructor(name) { - this.name = name + this.name = name; } } @@ -34,186 +34,186 @@ const text = ` Given I have product with 600 price And I have product with 1000 price When I go to checkout process -` +`; const checkTestForErrors = (test) => { return new Promise((resolve, reject) => { test.fn((err) => { if (err) { - return reject(err) + return reject(err); } - resolve() - }) - }) -} + resolve(); + }); + }); +}; describe('BDD', () => { beforeEach(() => { - clearSteps() - recorder.start() - container.create({}) - Config.reset() - }) + clearSteps(); + recorder.start(); + container.create({}); + Config.reset(); + }); afterEach(() => { - container.clear() - recorder.stop() - }) + container.clear(); + recorder.stop(); + }); it('should parse gherkin input', () => { - const parser = new Gherkin.Parser(builder, matcher) - parser.stopAtFirstError = false - const ast = parser.parse(text) + const parser = new Gherkin.Parser(builder, matcher); + parser.stopAtFirstError = false; + const ast = parser.parse(text); // console.log('Feature', ast.feature); // console.log('Scenario', ast.feature.children); // console.log('Steps', ast.feature.children[0].steps[0]); - expect(ast.feature).is.ok - expect(ast.feature.children).is.ok - expect(ast.feature.children[0].scenario.steps).is.ok - }) + expect(ast.feature).is.ok; + expect(ast.feature.children).is.ok; + expect(ast.feature.children[0].scenario.steps).is.ok; + }); it('should load step definitions', () => { - Given('I am a bird', () => 1) - When('I fly over ocean', () => 2) - And(/^I fly over land$/i, () => 3) - Then(/I see (.*?)/, () => 4) - expect(1).is.equal(matchStep('I am a bird')()) - expect(3).is.equal(matchStep('I Fly oVer Land')()) - expect(4).is.equal(matchStep('I see ocean')()) - expect(4).is.equal(matchStep('I see world')()) - }) + Given('I am a bird', () => 1); + When('I fly over ocean', () => 2); + And(/^I fly over land$/i, () => 3); + Then(/I see (.*?)/, () => 4); + expect(1).is.equal(matchStep('I am a bird')()); + expect(3).is.equal(matchStep('I Fly oVer Land')()); + expect(4).is.equal(matchStep('I see ocean')()); + expect(4).is.equal(matchStep('I see world')()); + }); it('should fail on duplicate step definitions with option', () => { Config.append({ gherkin: { avoidDuplicateSteps: true, }, - }) + }); - let error = null + let error = null; try { - Given('I am a bird', () => 1) - Then('I am a bird', () => 1) + Given('I am a bird', () => 1); + Then('I am a bird', () => 1); } catch (err) { - error = err + error = err; } finally { - expect(!!error).is.true + expect(!!error).is.true; } - }) + }); it('should contain tags', async () => { - let sum = 0 - Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))) - When('I go to checkout process', () => (sum += 10)) - const suite = await run(text) - suite.tests[0].fn(() => {}) - expect(suite.tests[0].tags).is.ok - expect('@super').is.equal(suite.tests[0].tags[0]) - }) + let sum = 0; + Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))); + When('I go to checkout process', () => (sum += 10)); + const suite = await run(text); + suite.tests[0].fn(() => {}); + expect(suite.tests[0].tags).is.ok; + expect('@super').is.equal(suite.tests[0].tags[0]); + }); it('should load step definitions', (done) => { - let sum = 0 - Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))) - When('I go to checkout process', () => (sum += 10)) - const suite = run(text) - expect('checkout process').is.equal(suite.title) + let sum = 0; + Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))); + When('I go to checkout process', () => (sum += 10)); + const suite = run(text); + expect('checkout process').is.equal(suite.title); suite.tests[0].fn(() => { - expect(suite.tests[0].steps).is.ok - expect(1610).is.equal(sum) - done() - }) - }) + expect(suite.tests[0].steps).is.ok; + expect(1610).is.equal(sum); + done(); + }); + }); it('should allow failed steps', async () => { - let sum = 0 - Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))) - When('I go to checkout process', () => expect(false).is.true) - const suite = run(text) - expect('checkout process').is.equal(suite.title) + let sum = 0; + Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))); + When('I go to checkout process', () => expect(false).is.true); + const suite = run(text); + expect('checkout process').is.equal(suite.title); try { - await checkTestForErrors(suite.tests[0]) - return Promise.reject(new Error('Test should have thrown with failed step, but did not')) + await checkTestForErrors(suite.tests[0]); + return Promise.reject(new Error('Test should have thrown with failed step, but did not')); } catch (err) { - const errored = !!err - expect(errored).is.true + const errored = !!err; + expect(errored).is.true; } - }) + }); it('handles errors in steps', async () => { - let sum = 0 - Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))) + let sum = 0; + Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))); When('I go to checkout process', () => { - throw new Error('errored step') - }) - const suite = run(text) - expect('checkout process').is.equal(suite.title) + throw new Error('errored step'); + }); + const suite = run(text); + expect('checkout process').is.equal(suite.title); try { - await checkTestForErrors(suite.tests[0]) - return Promise.reject(new Error('Test should have thrown with error, but did not')) + await checkTestForErrors(suite.tests[0]); + return Promise.reject(new Error('Test should have thrown with error, but did not')); } catch (err) { - const errored = !!err - expect(errored).is.true + const errored = !!err; + expect(errored).is.true; } - }) + }); it('handles async errors in steps', async () => { - let sum = 0 - Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))) - When('I go to checkout process', () => Promise.reject(new Error('step failed'))) - const suite = run(text) - expect('checkout process').is.equal(suite.title) + let sum = 0; + Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))); + When('I go to checkout process', () => Promise.reject(new Error('step failed'))); + const suite = run(text); + expect('checkout process').is.equal(suite.title); try { - await checkTestForErrors(suite.tests[0]) - return Promise.reject(new Error('Test should have thrown with error, but did not')) + await checkTestForErrors(suite.tests[0]); + return Promise.reject(new Error('Test should have thrown with error, but did not')); } catch (err) { - const errored = !!err - expect(errored).is.true + const errored = !!err; + expect(errored).is.true; } - }) + }); it('should work with async functions', (done) => { - let sum = 0 - Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))) + let sum = 0; + Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))); When('I go to checkout process', async () => { return new Promise((checkoutDone) => { - sum += 10 - setTimeout(checkoutDone, 0) - }) - }) - const suite = run(text) - expect('checkout process').is.equal(suite.title) + sum += 10; + setTimeout(checkoutDone, 0); + }); + }); + const suite = run(text); + expect('checkout process').is.equal(suite.title); suite.tests[0].fn(() => { - expect(suite.tests[0].steps).is.ok - expect(1610).is.equal(sum) - done() - }) - }) + expect(suite.tests[0].steps).is.ok; + expect(1610).is.equal(sum); + done(); + }); + }); it('should execute scenarios step-by-step ', async () => { - recorder.start() - printed = [] + recorder.start(); + printed = []; container.append({ helpers: { simple: { do(...args) { - return Promise.resolve().then(() => printed.push(args.join(' '))) + return Promise.resolve().then(() => printed.push(args.join(' '))); }, }, }, - }) - I = actor() - let sum = 0 + }); + I = actor(); + let sum = 0; Given(/I have product with (\d+) price/, (price) => { - I.do('add', (sum += parseInt(price, 10))) - }) + I.do('add', (sum += parseInt(price, 10))); + }); When('I go to checkout process', () => { - I.do('add finish checkout') - }) - const suite = run(text) + I.do('add finish checkout'); + }); + const suite = run(text); suite.tests[0].fn(() => { recorder.promise().then(() => { - printed.should.include.members(['add 600', 'add 1600', 'add finish checkout']) - const lines = recorder.scheduled().split('\n') + printed.should.include.members(['add 600', 'add 1600', 'add finish checkout']); + const lines = recorder.scheduled().split('\n'); lines.should.include.members([ 'do: "add", 600', 'step passed', @@ -226,17 +226,17 @@ describe('BDD', () => { 'return result', 'fire test.passed', 'finish test', - ]) - done() - }) - }) - }) + ]); + done(); + }); + }); + }); it('should match step with params', () => { - Given('I am a {word}', (param) => param) - const fn = matchStep('I am a bird') - expect('bird').is.equal(fn.params[0]) - }) + Given('I am a {word}', (param) => param); + const fn = matchStep('I am a bird'); + expect('bird').is.equal(fn.params[0]); + }); it('should produce step events', (done) => { const text = ` @@ -244,34 +244,34 @@ describe('BDD', () => { Scenario: Then I emit step events - ` - Then('I emit step events', () => {}) - let listeners = 0 - event.dispatcher.addListener(event.bddStep.before, () => listeners++) - event.dispatcher.addListener(event.bddStep.after, () => listeners++) + `; + Then('I emit step events', () => {}); + let listeners = 0; + event.dispatcher.addListener(event.bddStep.before, () => listeners++); + event.dispatcher.addListener(event.bddStep.after, () => listeners++); - const suite = run(text) + const suite = run(text); suite.tests[0].fn(() => { - listeners.should.eql(2) - done() - }) - }) + listeners.should.eql(2); + done(); + }); + }); it('should use shortened form for step definitions', () => { - let fn - Given('I am a {word}', (params) => params[0]) - When('I have {int} wings and {int} eyes', (params) => params[0] + params[1]) - Given('I have ${int} in my pocket', (params) => params[0]) // eslint-disable-line no-template-curly-in-string - Given('I have also ${float} in my pocket', (params) => params[0]) // eslint-disable-line no-template-curly-in-string - fn = matchStep('I am a bird') - expect('bird').is.equal(fn(fn.params)) - fn = matchStep('I have 2 wings and 2 eyes') - expect(4).is.equal(fn(fn.params)) - fn = matchStep('I have $500 in my pocket') - expect(500).is.equal(fn(fn.params)) - fn = matchStep('I have also $500.30 in my pocket') - expect(500.3).is.equal(fn(fn.params)) - }) + let fn; + Given('I am a {word}', (params) => params[0]); + When('I have {int} wings and {int} eyes', (params) => params[0] + params[1]); + Given('I have ${int} in my pocket', (params) => params[0]); // eslint-disable-line no-template-curly-in-string + Given('I have also ${float} in my pocket', (params) => params[0]); // eslint-disable-line no-template-curly-in-string + fn = matchStep('I am a bird'); + expect('bird').is.equal(fn(fn.params)); + fn = matchStep('I have 2 wings and 2 eyes'); + expect(4).is.equal(fn(fn.params)); + fn = matchStep('I have $500 in my pocket'); + expect(500).is.equal(fn(fn.params)); + fn = matchStep('I have also $500.30 in my pocket'); + expect(500.3).is.equal(fn(fn.params)); + }); it('should attach before hook for Background', (finish) => { const text = ` @@ -282,22 +282,22 @@ describe('BDD', () => { Scenario: Then I am shopping - ` - let sum = 0 + `; + let sum = 0; function incrementSum() { - sum++ + sum++; } - Given('I am logged in as customer', incrementSum) - Then('I am shopping', incrementSum) - const suite = run(text) - const done = () => {} + Given('I am logged in as customer', incrementSum); + Then('I am shopping', incrementSum); + const suite = run(text); + const done = () => {}; - suite._beforeEach.forEach((hook) => hook.run(done)) + suite._beforeEach.forEach((hook) => hook.run(done)); suite.tests[0].fn(() => { - expect(sum).is.equal(2) - finish() - }) - }) + expect(sum).is.equal(2); + finish(); + }); + }); it('should execute scenario outlines', (done) => { const text = ` @@ -319,37 +319,37 @@ describe('BDD', () => { Examples: | price | total | | 20 | 18 | - ` - let cart = 0 - let sum = 0 + `; + let cart = 0; + let sum = 0; Given('I have product with price {int}$ in my cart', (price) => { - cart = price - }) + cart = price; + }); Given('discount is {int} %', (discount) => { - cart -= (cart * discount) / 100 - }) + cart -= (cart * discount) / 100; + }); Then('I should see price is {string} $', (total) => { - sum = parseInt(total, 10) - }) + sum = parseInt(total, 10); + }); - const suite = run(text) + const suite = run(text); - expect(suite.tests[0].tags).is.ok - expect(['@awesome', '@cool', '@super']).is.deep.equal(suite.tests[0].tags) - expect(['@awesome', '@cool', '@super', '@exampleTag1', '@exampleTag2']).is.deep.equal(suite.tests[1].tags) + expect(suite.tests[0].tags).is.ok; + expect(['@awesome', '@cool', '@super']).is.deep.equal(suite.tests[0].tags); + expect(['@awesome', '@cool', '@super', '@exampleTag1', '@exampleTag2']).is.deep.equal(suite.tests[1].tags); - expect(2).is.equal(suite.tests.length) + expect(2).is.equal(suite.tests.length); suite.tests[0].fn(() => { - expect(9).is.equal(cart) - expect(9).is.equal(sum) + expect(9).is.equal(cart); + expect(9).is.equal(sum); suite.tests[1].fn(() => { - expect(18).is.equal(cart) - expect(18).is.equal(sum) - done() - }) - }) - }) + expect(18).is.equal(cart); + expect(18).is.equal(sum); + done(); + }); + }); + }); it('should provide a parsed DataTable', (done) => { const text = ` @@ -366,59 +366,59 @@ describe('BDD', () => { | label | price | | beer | 9 | | cookies | 12 | - ` + `; - let givenParsedRows - let thenParsedRows + let givenParsedRows; + let thenParsedRows; Given('I have the following products :', (products) => { - expect(products.rows.length).to.equal(3) - givenParsedRows = products.parse() - }) + expect(products.rows.length).to.equal(3); + givenParsedRows = products.parse(); + }); Then('I should see the following products :', (products) => { - expect(products.rows.length).to.equal(3) - thenParsedRows = products.parse() - }) + expect(products.rows.length).to.equal(3); + thenParsedRows = products.parse(); + }); - const suite = run(text) + const suite = run(text); const expectedParsedDataTable = [ ['label', 'price'], ['beer', '9'], ['cookies', '12'], - ] + ]; suite.tests[0].fn(() => { - expect(givenParsedRows.rawData).is.deep.equal(expectedParsedDataTable) - expect(thenParsedRows.rawData).is.deep.equal(expectedParsedDataTable) - done() - }) - }) + expect(givenParsedRows.rawData).is.deep.equal(expectedParsedDataTable); + expect(thenParsedRows.rawData).is.deep.equal(expectedParsedDataTable); + done(); + }); + }); it('should match step with custom parameter type', (done) => { const colorType = { name: 'color', regexp: /red|blue|yellow/, transformer: (s) => new Color(s), - } - defineParameterType(colorType) - Given('I have a {color} label', (color) => color) - const fn = matchStep('I have a red label') - expect('red').is.equal(fn.params[0].name) - done() - }) + }; + defineParameterType(colorType); + Given('I have a {color} label', (color) => color); + const fn = matchStep('I have a red label'); + expect('red').is.equal(fn.params[0].name); + done(); + }); it('should match step with async custom parameter type transformation', async () => { const colorType = { name: 'async_color', regexp: /red|blue|yellow/, transformer: async (s) => new Color(s), - } - defineParameterType(colorType) - Given('I have a {async_color} label', (color) => color) - const fn = matchStep('I have a blue label') - const color = await fn.params[0] - expect('blue').is.equal(color.name) - await Promise.resolve() - }) -}) + }; + defineParameterType(colorType); + Given('I have a {async_color} label', (color) => color); + const fn = matchStep('I have a blue label'); + const color = await fn.params[0]; + expect('blue').is.equal(color.name); + await Promise.resolve(); + }); +}); diff --git a/test/unit/container_test.js b/test/unit/container_test.js index eb8b58cf0..6ece3d439 100644 --- a/test/unit/container_test.js +++ b/test/unit/container_test.js @@ -1,109 +1,109 @@ -let expect +let expect; import('chai').then((chai) => { - expect = chai.expect -}) -const path = require('path') + expect = chai.expect; +}); +const path = require('path'); -const FileSystem = require('../../lib/helper/FileSystem') -const actor = require('../../lib/actor') -const container = require('../../lib/container') +const FileSystem = require('../../lib/helper/FileSystem'); +const actor = require('../../lib/actor'); +const container = require('../../lib/container'); describe('Container', () => { before(() => { - global.codecept_dir = path.join(__dirname, '/..') - global.inject = container.support - global.actor = actor - }) + global.codecept_dir = path.join(__dirname, '/..'); + global.inject = container.support; + global.actor = actor; + }); afterEach(() => { - container.clear() - ;['I', 'dummy_page'].forEach((po) => { - const name = require.resolve(path.join(__dirname, `../data/${po}`)) - delete require.cache[name] - }) - }) + container.clear(); + ['I', 'dummy_page'].forEach((po) => { + const name = require.resolve(path.join(__dirname, `../data/${po}`)); + delete require.cache[name]; + }); + }); describe('#translation', () => { - const Translation = require('../../lib/translation') + const Translation = require('../../lib/translation'); it('should create empty translation', () => { - container.create({}) - expect(container.translation()).to.be.instanceOf(Translation) - expect(container.translation().loaded).to.be.false - expect(container.translation().actionAliasFor('see')).to.eql('see') - }) + container.create({}); + expect(container.translation()).to.be.instanceOf(Translation); + expect(container.translation().loaded).to.be.false; + expect(container.translation().actionAliasFor('see')).to.eql('see'); + }); it('should create Russian translation', () => { - container.create({ translation: 'ru-RU' }) - expect(container.translation()).to.be.instanceOf(Translation) - expect(container.translation().loaded).to.be.true - expect(container.translation().I).to.eql('Я') - expect(container.translation().actionAliasFor('see')).to.eql('вижу') - }) + container.create({ translation: 'ru-RU' }); + expect(container.translation()).to.be.instanceOf(Translation); + expect(container.translation().loaded).to.be.true; + expect(container.translation().I).to.eql('Я'); + expect(container.translation().actionAliasFor('see')).to.eql('вижу'); + }); it('should create Italian translation', () => { - container.create({ translation: 'it-IT' }) - expect(container.translation()).to.be.instanceOf(Translation) - expect(container.translation().loaded).to.be.true - expect(container.translation().I).to.eql('io') - expect(container.translation().value('contexts').Feature).to.eql('Caratteristica') - }) + container.create({ translation: 'it-IT' }); + expect(container.translation()).to.be.instanceOf(Translation); + expect(container.translation().loaded).to.be.true; + expect(container.translation().I).to.eql('io'); + expect(container.translation().value('contexts').Feature).to.eql('Caratteristica'); + }); it('should create French translation', () => { - container.create({ translation: 'fr-FR' }) - expect(container.translation()).to.be.instanceOf(Translation) - expect(container.translation().loaded).to.be.true - expect(container.translation().I).to.eql('Je') - expect(container.translation().value('contexts').Feature).to.eql('Fonctionnalité') - }) + container.create({ translation: 'fr-FR' }); + expect(container.translation()).to.be.instanceOf(Translation); + expect(container.translation().loaded).to.be.true; + expect(container.translation().I).to.eql('Je'); + expect(container.translation().value('contexts').Feature).to.eql('Fonctionnalité'); + }); it('should create Portuguese translation', () => { - container.create({ translation: 'pt-BR' }) - expect(container.translation()).to.be.instanceOf(Translation) - expect(container.translation().loaded).to.be.true - expect(container.translation().I).to.eql('Eu') - expect(container.translation().value('contexts').Feature).to.eql('Funcionalidade') - }) + container.create({ translation: 'pt-BR' }); + expect(container.translation()).to.be.instanceOf(Translation); + expect(container.translation().loaded).to.be.true; + expect(container.translation().I).to.eql('Eu'); + expect(container.translation().value('contexts').Feature).to.eql('Funcionalidade'); + }); it('should load custom translation', () => { - container.create({ translation: 'my' }) - expect(container.translation()).to.be.instanceOf(Translation) - expect(container.translation().loaded).to.be.true - }) + container.create({ translation: 'my' }); + expect(container.translation()).to.be.instanceOf(Translation); + expect(container.translation().loaded).to.be.true; + }); it('should load no translation', () => { - container.create({}) - expect(container.translation()).to.be.instanceOf(Translation) - expect(container.translation().loaded).to.be.false - }) + container.create({}); + expect(container.translation()).to.be.instanceOf(Translation); + expect(container.translation().loaded).to.be.false; + }); it('should load custom translation with vocabularies', () => { - container.create({ translation: 'my', vocabularies: ['data/custom_vocabulary.json'] }) - expect(container.translation()).to.be.instanceOf(Translation) - expect(container.translation().loaded).to.be.true - const translation = container.translation() - expect(translation.actionAliasFor('say')).to.eql('arr') - }) - }) + container.create({ translation: 'my', vocabularies: ['data/custom_vocabulary.json'] }); + expect(container.translation()).to.be.instanceOf(Translation); + expect(container.translation().loaded).to.be.true; + const translation = container.translation(); + expect(translation.actionAliasFor('say')).to.eql('arr'); + }); + }); describe('#helpers', () => { beforeEach(() => { container.clear({ helper1: { name: 'hello' }, helper2: { name: 'world' }, - }) - }) + }); + }); - it('should return all helper with no args', () => expect(container.helpers()).to.have.keys('helper1', 'helper2')) + it('should return all helper with no args', () => expect(container.helpers()).to.have.keys('helper1', 'helper2')); it('should return helper by name', () => { - expect(container.helpers('helper1')).is.ok - expect(container.helpers('helper1').name).to.eql('hello') - expect(container.helpers('helper2')).is.ok - expect(container.helpers('helper2').name).to.eql('world') - expect(!container.helpers('helper3')).is.ok - }) - }) + expect(container.helpers('helper1')).is.ok; + expect(container.helpers('helper1').name).to.eql('hello'); + expect(container.helpers('helper2')).is.ok; + expect(container.helpers('helper2').name).to.eql('world'); + expect(!container.helpers('helper3')).is.ok; + }); + }); describe('#support', () => { beforeEach(() => { @@ -113,22 +113,22 @@ describe('Container', () => { support1: { name: 'hello' }, support2: { name: 'world' }, }, - ) - }) + ); + }); it('should return all support objects', () => { - expect(container.support()).to.have.keys('support1', 'support2') - }) + expect(container.support()).to.have.keys('support1', 'support2'); + }); it('should support object by name', () => { - expect(container.support('support1')).is.ok - expect(container.support('support1').name).to.eql('hello') - expect(container.support('support2')).is.ok - expect(container.support('support2').name).to.eql('world') + expect(container.support('support1')).is.ok; + expect(container.support('support1').name).to.eql('hello'); + expect(container.support('support2')).is.ok; + expect(container.support('support2').name).to.eql('world'); - expect(() => container.support('support3').name).to.throw(Error) - }) - }) + expect(() => container.support('support3').name).to.throw(Error); + }); + }); describe('#plugins', () => { beforeEach(() => { @@ -139,19 +139,19 @@ describe('Container', () => { plugin1: { name: 'hello' }, plugin2: { name: 'world' }, }, - ) - }) + ); + }); - it('should return all plugins', () => expect(container.plugins()).to.have.keys('plugin1', 'plugin2')) + it('should return all plugins', () => expect(container.plugins()).to.have.keys('plugin1', 'plugin2')); it('should get plugin by name', () => { - expect(container.plugins('plugin1')).is.ok - expect(container.plugins('plugin1').name).is.eql('hello') - expect(container.plugins('plugin2')).is.ok - expect(container.plugins('plugin2').name).is.eql('world') - expect(!container.plugins('plugin3')).is.ok - }) - }) + expect(container.plugins('plugin1')).is.ok; + expect(container.plugins('plugin1').name).is.eql('hello'); + expect(container.plugins('plugin2')).is.ok; + expect(container.plugins('plugin2').name).is.eql('world'); + expect(!container.plugins('plugin3')).is.ok; + }); + }); describe('#create', () => { it('should create container with helpers', () => { @@ -162,53 +162,53 @@ describe('Container', () => { }, FileSystem: {}, }, - } - container.create(config) + }; + container.create(config); // custom helpers - expect(container.helpers('MyHelper')).is.ok - expect(container.helpers('MyHelper').method()).to.eql('hello world') + expect(container.helpers('MyHelper')).is.ok; + expect(container.helpers('MyHelper').method()).to.eql('hello world'); // built-in helpers - expect(container.helpers('FileSystem')).is.ok - expect(container.helpers('FileSystem')).to.be.instanceOf(FileSystem) - }) + expect(container.helpers('FileSystem')).is.ok; + expect(container.helpers('FileSystem')).to.be.instanceOf(FileSystem); + }); it('should always create I', () => { - container.create({}) - expect(container.support('I')).is.ok - }) + container.create({}); + expect(container.support('I')).is.ok; + }); it('should load DI and return a reference to the module', () => { container.create({ include: { dummyPage: './data/dummy_page', }, - }) - const dummyPage = require('../data/dummy_page') - expect(container.support('dummyPage').toString()).is.eql(dummyPage.toString()) - }) + }); + const dummyPage = require('../data/dummy_page'); + expect(container.support('dummyPage').toString()).is.eql(dummyPage.toString()); + }); it('should load I from path and execute', () => { container.create({ include: { I: './data/I', }, - }) - expect(container.support('I')).is.ok - expect(Object.keys(container.support('I'))).is.ok - expect(Object.keys(container.support('I'))).to.include('_init') - expect(Object.keys(container.support('I'))).to.include('doSomething') - }) + }); + expect(container.support('I')).is.ok; + expect(Object.keys(container.support('I'))).is.ok; + expect(Object.keys(container.support('I'))).to.include('_init'); + expect(Object.keys(container.support('I'))).to.include('doSomething'); + }); it('should load DI includes provided as require paths', () => { container.create({ include: { dummyPage: './data/dummy_page', }, - }) - expect(container.support('dummyPage')).is.ok - expect(container.support('dummyPage')).to.include.keys('openDummyPage') - }) + }); + expect(container.support('dummyPage')).is.ok; + expect(container.support('dummyPage')).to.include.keys('openDummyPage'); + }); it('should load DI and inject I into PO', async () => { container.create({ @@ -216,12 +216,12 @@ describe('Container', () => { dummyPage: './data/dummy_page', I: './data/I', }, - }) - expect(container.support('dummyPage')).is.ok - expect(container.support('I')).is.ok - expect(container.support('dummyPage')).to.include.keys('openDummyPage') - expect(container.support('dummyPage').getI()).to.have.keys('_init', 'doSomething') - }) + }); + expect(container.support('dummyPage')).is.ok; + expect(container.support('I')).is.ok; + expect(container.support('dummyPage')).to.include.keys('openDummyPage'); + expect(container.support('dummyPage').getI()).to.have.keys('_init', 'doSomething'); + }); it('should load DI and inject custom I into PO', () => { container.create({ @@ -229,11 +229,11 @@ describe('Container', () => { dummyPage: './data/dummy_page', I: './data/I', }, - }) - expect(container.support('dummyPage')).is.ok - expect(container.support('I')).is.ok - expect(container.support('dummyPage')).to.include.keys('openDummyPage') - }) + }); + expect(container.support('dummyPage')).is.ok; + expect(container.support('I')).is.ok; + expect(container.support('dummyPage')).to.include.keys('openDummyPage'); + }); it('should load DI includes provided as objects', () => { container.create({ @@ -242,10 +242,10 @@ describe('Container', () => { openDummyPage: () => 'dummy page opened', }, }, - }) - expect(container.support('dummyPage')).is.ok - expect(container.support('dummyPage')).to.include.keys('openDummyPage') - }) + }); + expect(container.support('dummyPage')).is.ok; + expect(container.support('dummyPage')).to.include.keys('openDummyPage'); + }); it('should load DI includes provided as objects', () => { container.create({ @@ -254,11 +254,11 @@ describe('Container', () => { openDummyPage: () => 'dummy page opened', }, }, - }) - expect(container.support('dummyPage')).is.ok - expect(container.support('dummyPage')).to.include.keys('openDummyPage') - }) - }) + }); + expect(container.support('dummyPage')).is.ok; + expect(container.support('dummyPage')).to.include.keys('openDummyPage'); + }); + }); describe('#append', () => { it('should be able to add new helper', () => { @@ -266,26 +266,26 @@ describe('Container', () => { helpers: { FileSystem: {}, }, - } - container.create(config) + }; + container.create(config); container.append({ helpers: { AnotherHelper: { method: () => 'executed' }, }, - }) - expect(container.helpers('FileSystem')).is.ok - expect(container.helpers('FileSystem')).is.instanceOf(FileSystem) + }); + expect(container.helpers('FileSystem')).is.ok; + expect(container.helpers('FileSystem')).is.instanceOf(FileSystem); - expect(container.helpers('AnotherHelper')).is.ok - expect(container.helpers('AnotherHelper').method()).is.eql('executed') - }) + expect(container.helpers('AnotherHelper')).is.ok; + expect(container.helpers('AnotherHelper').method()).is.eql('executed'); + }); it('should be able to add new support object', () => { - container.create({}) - container.append({ support: { userPage: { login: '#login' } } }) - expect(container.support('I')).is.ok - expect(container.support('userPage')).is.ok - expect(container.support('userPage').login).is.eql('#login') - }) - }) -}) + container.create({}); + container.append({ support: { userPage: { login: '#login' } } }); + expect(container.support('I')).is.ok; + expect(container.support('userPage')).is.ok; + expect(container.support('userPage').login).is.eql('#login'); + }); + }); +}); diff --git a/test/unit/worker_test.js b/test/unit/worker_test.js index b7b01c809..55abb6963 100644 --- a/test/unit/worker_test.js +++ b/test/unit/worker_test.js @@ -1,57 +1,57 @@ -const path = require('path') -const expect = require('chai').expect +const path = require('path'); +const expect = require('chai').expect; -const { Workers, event, recorder } = require('../../lib/index') +const { Workers, event, recorder } = require('../../lib/index'); describe('Workers', function () { - this.timeout(40000) + this.timeout(40000); before(() => { - global.codecept_dir = path.join(__dirname, '/../data/sandbox') - }) + global.codecept_dir = path.join(__dirname, '/../data/sandbox'); + }); it('should run simple worker', (done) => { const workerConfig = { by: 'test', testConfig: './test/data/sandbox/codecept.workers.conf.js', - } - let passedCount = 0 - let failedCount = 0 - const workers = new Workers(2, workerConfig) + }; + let passedCount = 0; + let failedCount = 0; + const workers = new Workers(2, workerConfig); workers.on(event.test.failed, () => { - failedCount += 1 - }) + failedCount += 1; + }); workers.on(event.test.passed, () => { - passedCount += 1 - }) + passedCount += 1; + }); - workers.run() + workers.run(); workers.on(event.all.result, (status) => { - expect(status).equal(false) - expect(passedCount).equal(5) - expect(failedCount).equal(3) - done() - }) - }) + expect(status).equal(false); + expect(passedCount).equal(5); + expect(failedCount).equal(3); + done(); + }); + }); it('should create worker by function', (done) => { const createTestGroups = () => { const files = [ [path.join(codecept_dir, '/custom-worker/base_test.worker.js')], [path.join(codecept_dir, '/custom-worker/custom_test.worker.js')], - ] + ]; - return files - } + return files; + }; const workerConfig = { by: createTestGroups, testConfig: './test/data/sandbox/codecept.customworker.js', - } + }; - const workers = new Workers(-1, workerConfig) + const workers = new Workers(-1, workerConfig); for (const worker of workers.getWorkers()) { worker.addConfig({ @@ -61,27 +61,27 @@ describe('Workers', function () { require: './custom_worker_helper', }, }, - }) + }); } - workers.run() + workers.run(); workers.on(event.all.result, (status) => { - expect(workers.getWorkers().length).equal(2) - expect(status).equal(true) - done() - }) - }) + expect(workers.getWorkers().length).equal(2); + expect(status).equal(true); + done(); + }); + }); it('should run worker with custom config', (done) => { const workerConfig = { by: 'test', testConfig: './test/data/sandbox/codecept.customworker.js', - } - let passedCount = 0 - let failedCount = 0 + }; + let passedCount = 0; + let failedCount = 0; - const workers = new Workers(2, workerConfig) + const workers = new Workers(2, workerConfig); for (const worker of workers.getWorkers()) { worker.addConfig({ @@ -91,39 +91,39 @@ describe('Workers', function () { require: './custom_worker_helper', }, }, - }) + }); } - workers.run() + workers.run(); workers.on(event.test.failed, (test) => { - failedCount += 1 - }) + failedCount += 1; + }); workers.on(event.test.passed, (test) => { - passedCount += 1 - }) + passedCount += 1; + }); workers.on(event.all.result, (status) => { - expect(status).equal(false) - expect(passedCount).equal(3) - expect(failedCount).equal(2) - done() - }) - }) + expect(status).equal(false); + expect(passedCount).equal(3); + expect(failedCount).equal(2); + done(); + }); + }); it('should able to add tests to each worker', (done) => { const workerConfig = { by: 'test', testConfig: './test/data/sandbox/codecept.customworker.js', - } + }; - const workers = new Workers(-1, workerConfig) + const workers = new Workers(-1, workerConfig); - const workerOne = workers.spawn() - workerOne.addTestFiles([path.join(codecept_dir, '/custom-worker/base_test.worker.js')]) + const workerOne = workers.spawn(); + workerOne.addTestFiles([path.join(codecept_dir, '/custom-worker/base_test.worker.js')]); - const workerTwo = workers.spawn() - workerTwo.addTestFiles([path.join(codecept_dir, '/custom-worker/custom_test.worker.js')]) + const workerTwo = workers.spawn(); + workerTwo.addTestFiles([path.join(codecept_dir, '/custom-worker/custom_test.worker.js')]); for (const worker of workers.getWorkers()) { worker.addConfig({ @@ -133,32 +133,32 @@ describe('Workers', function () { require: './custom_worker_helper', }, }, - }) + }); } - workers.run() + workers.run(); workers.on(event.all.result, (status) => { - expect(workers.getWorkers().length).equal(2) - expect(status).equal(true) - done() - }) - }) + expect(workers.getWorkers().length).equal(2); + expect(status).equal(true); + done(); + }); + }); it('should able to add tests to using createGroupsOfTests', (done) => { const workerConfig = { by: 'test', testConfig: './test/data/sandbox/codecept.customworker.js', - } + }; - const workers = new Workers(-1, workerConfig) - const testGroups = workers.createGroupsOfSuites(2) + const workers = new Workers(-1, workerConfig); + const testGroups = workers.createGroupsOfSuites(2); - const workerOne = workers.spawn() - workerOne.addTests(testGroups[0]) + const workerOne = workers.spawn(); + workerOne.addTests(testGroups[0]); - const workerTwo = workers.spawn() - workerTwo.addTests(testGroups[1]) + const workerTwo = workers.spawn(); + workerTwo.addTests(testGroups[1]); for (const worker of workers.getWorkers()) { worker.addConfig({ @@ -168,25 +168,25 @@ describe('Workers', function () { require: './custom_worker_helper', }, }, - }) + }); } - workers.run() + workers.run(); workers.on(event.all.result, (status) => { - expect(workers.getWorkers().length).equal(2) - expect(status).equal(true) - done() - }) - }) + expect(workers.getWorkers().length).equal(2); + expect(status).equal(true); + done(); + }); + }); it('Should able to pass data from workers to main thread and vice versa', (done) => { const workerConfig = { by: 'test', testConfig: './test/data/sandbox/codecept.customworker.js', - } + }; - const workers = new Workers(2, workerConfig) + const workers = new Workers(2, workerConfig); for (const worker of workers.getWorkers()) { worker.addConfig({ @@ -196,47 +196,47 @@ describe('Workers', function () { require: './custom_worker_helper', }, }, - }) + }); } - workers.run() - recorder.add(() => share({ fromMain: true })) + workers.run(); + recorder.add(() => share({ fromMain: true })); workers.on(event.all.result, (status) => { - expect(status).equal(true) - done() - }) - }) + expect(status).equal(true); + done(); + }); + }); it('should propagate non test events', (done) => { - const messages = [] + const messages = []; const createTestGroups = () => { - const files = [[path.join(codecept_dir, '/non-test-events-worker/non_test_event.worker.js')]] + const files = [[path.join(codecept_dir, '/non-test-events-worker/non_test_event.worker.js')]]; - return files - } + return files; + }; const workerConfig = { by: createTestGroups, testConfig: './test/data/sandbox/codecept.non-test-events-worker.js', - } + }; - workers = new Workers(2, workerConfig) + workers = new Workers(2, workerConfig); - workers.run() + workers.run(); workers.on('message', (data) => { - messages.push(data) - }) + messages.push(data); + }); workers.on(event.all.result, () => { - expect(messages.length).equal(2) - expect(messages[0]).equal('message 1') - expect(messages[1]).equal('message 2') - done() - }) - }) + expect(messages.length).equal(2); + expect(messages[0]).equal('message 1'); + expect(messages[1]).equal('message 2'); + done(); + }); + }); it('should run worker with multiple config', (done) => { const workerConfig = { @@ -244,9 +244,9 @@ describe('Workers', function () { testConfig: './test/data/sandbox/codecept.multiple.js', options: {}, selectedRuns: ['mobile'], - } + }; - const workers = new Workers(2, workerConfig) + const workers = new Workers(2, workerConfig); for (const worker of workers.getWorkers()) { worker.addConfig({ @@ -256,15 +256,15 @@ describe('Workers', function () { require: './custom_worker_helper', }, }, - }) + }); } - workers.run() + workers.run(); workers.on(event.all.result, (status) => { - expect(workers.getWorkers().length).equal(8) - expect(status).equal(true) - done() - }) - }) -}) + expect(workers.getWorkers().length).equal(8); + expect(status).equal(true); + done(); + }); + }); +}); From 9eeb4e95d888a591e144629e3b8b998292850651 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 31 Dec 2024 01:02:56 +0200 Subject: [PATCH 35/37] reverted change to ; --- lib/command/gherkin/snippets.js | 14 +- lib/command/workers/runTests.js | 66 +--- lib/container.js | 20 +- lib/heal.js | 18 +- lib/helper/JSONResponse.js | 4 +- lib/pause.js | 4 +- lib/workers.js | 19 +- prettier.config.js | 2 +- test/helper/AppiumV2_ios_test.js | 8 +- test/helper/AppiumV2_test.js | 297 ++++-------------- test/helper/Appium_test.js | 297 ++++-------------- test/helper/JSONResponse_test.js | 8 +- test/helper/Playwright_test.js | 30 +- test/helper/Puppeteer_test.js | 12 +- .../helper/WebDriver.noSeleniumServer_test.js | 18 +- test/helper/WebDriver_test.js | 18 +- test/helper/webapi.js | 26 +- test/runner/dry_run_test.js | 61 ++-- test/runner/pageobject_test.js | 3 +- test/runner/run_multiple_test.js | 42 ++- test/runner/run_rerun_test.js | 60 ++-- test/unit/worker_test.js | 5 +- 22 files changed, 246 insertions(+), 786 deletions(-) diff --git a/lib/command/gherkin/snippets.js b/lib/command/gherkin/snippets.js index 42f4bbf5d..f36e4fd26 100644 --- a/lib/command/gherkin/snippets.js +++ b/lib/command/gherkin/snippets.js @@ -43,14 +43,12 @@ module.exports = function (genPath, options) { } const files = []; - glob - .sync(options.feature || config.gherkin.features, { cwd: options.feature ? '.' : global.codecept_dir }) - .forEach((file) => { - if (!fsPath.isAbsolute(file)) { - file = fsPath.join(global.codecept_dir, file); - } - files.push(fsPath.resolve(file)); - }); + glob.sync(options.feature || config.gherkin.features, { cwd: options.feature ? '.' : global.codecept_dir }).forEach((file) => { + if (!fsPath.isAbsolute(file)) { + file = fsPath.join(global.codecept_dir, file); + } + files.push(fsPath.resolve(file)); + }); output.print(`Loaded ${files.length} files`); const newSteps = new Map(); diff --git a/lib/command/workers/runTests.js b/lib/command/workers/runTests.js index 3cb0d0565..1bdd58d0f 100644 --- a/lib/command/workers/runTests.js +++ b/lib/command/workers/runTests.js @@ -212,63 +212,31 @@ function initializeListeners() { collectStats(); // suite - event.dispatcher.on(event.suite.before, (suite) => - sendToParentThread({ event: event.suite.before, workerIndex, data: simplifyTest(suite) }), - ); - event.dispatcher.on(event.suite.after, (suite) => - sendToParentThread({ event: event.suite.after, workerIndex, data: simplifyTest(suite) }), - ); + event.dispatcher.on(event.suite.before, (suite) => sendToParentThread({ event: event.suite.before, workerIndex, data: simplifyTest(suite) })); + event.dispatcher.on(event.suite.after, (suite) => sendToParentThread({ event: event.suite.after, workerIndex, data: simplifyTest(suite) })); // calculate duration event.dispatcher.on(event.test.started, (test) => (test.start = new Date())); // tests - event.dispatcher.on(event.test.before, (test) => - sendToParentThread({ event: event.test.before, workerIndex, data: simplifyTest(test) }), - ); - event.dispatcher.on(event.test.after, (test) => - sendToParentThread({ event: event.test.after, workerIndex, data: simplifyTest(test) }), - ); + event.dispatcher.on(event.test.before, (test) => sendToParentThread({ event: event.test.before, workerIndex, data: simplifyTest(test) })); + event.dispatcher.on(event.test.after, (test) => sendToParentThread({ event: event.test.after, workerIndex, data: simplifyTest(test) })); // we should force-send correct errors to prevent race condition - event.dispatcher.on(event.test.finished, (test, err) => - sendToParentThread({ event: event.test.finished, workerIndex, data: simplifyTest(test, err) }), - ); - event.dispatcher.on(event.test.failed, (test, err) => - sendToParentThread({ event: event.test.failed, workerIndex, data: simplifyTest(test, err) }), - ); - event.dispatcher.on(event.test.passed, (test, err) => - sendToParentThread({ event: event.test.passed, workerIndex, data: simplifyTest(test, err) }), - ); - event.dispatcher.on(event.test.started, (test) => - sendToParentThread({ event: event.test.started, workerIndex, data: simplifyTest(test) }), - ); - event.dispatcher.on(event.test.skipped, (test) => - sendToParentThread({ event: event.test.skipped, workerIndex, data: simplifyTest(test) }), - ); + event.dispatcher.on(event.test.finished, (test, err) => sendToParentThread({ event: event.test.finished, workerIndex, data: simplifyTest(test, err) })); + event.dispatcher.on(event.test.failed, (test, err) => sendToParentThread({ event: event.test.failed, workerIndex, data: simplifyTest(test, err) })); + event.dispatcher.on(event.test.passed, (test, err) => sendToParentThread({ event: event.test.passed, workerIndex, data: simplifyTest(test, err) })); + event.dispatcher.on(event.test.started, (test) => sendToParentThread({ event: event.test.started, workerIndex, data: simplifyTest(test) })); + event.dispatcher.on(event.test.skipped, (test) => sendToParentThread({ event: event.test.skipped, workerIndex, data: simplifyTest(test) })); // steps - event.dispatcher.on(event.step.finished, (step) => - sendToParentThread({ event: event.step.finished, workerIndex, data: simplifyStep(step) }), - ); - event.dispatcher.on(event.step.started, (step) => - sendToParentThread({ event: event.step.started, workerIndex, data: simplifyStep(step) }), - ); - event.dispatcher.on(event.step.passed, (step) => - sendToParentThread({ event: event.step.passed, workerIndex, data: simplifyStep(step) }), - ); - event.dispatcher.on(event.step.failed, (step) => - sendToParentThread({ event: event.step.failed, workerIndex, data: simplifyStep(step) }), - ); - - event.dispatcher.on(event.hook.failed, (test, err) => - sendToParentThread({ event: event.hook.failed, workerIndex, data: simplifyTest(test, err) }), - ); - event.dispatcher.on(event.hook.passed, (test, err) => - sendToParentThread({ event: event.hook.passed, workerIndex, data: simplifyTest(test, err) }), - ); - event.dispatcher.on(event.all.failures, (data) => - sendToParentThread({ event: event.all.failures, workerIndex, data }), - ); + event.dispatcher.on(event.step.finished, (step) => sendToParentThread({ event: event.step.finished, workerIndex, data: simplifyStep(step) })); + event.dispatcher.on(event.step.started, (step) => sendToParentThread({ event: event.step.started, workerIndex, data: simplifyStep(step) })); + event.dispatcher.on(event.step.passed, (step) => sendToParentThread({ event: event.step.passed, workerIndex, data: simplifyStep(step) })); + event.dispatcher.on(event.step.failed, (step) => sendToParentThread({ event: event.step.failed, workerIndex, data: simplifyStep(step) })); + + event.dispatcher.on(event.hook.failed, (test, err) => sendToParentThread({ event: event.hook.failed, workerIndex, data: simplifyTest(test, err) })); + event.dispatcher.on(event.hook.passed, (test, err) => sendToParentThread({ event: event.hook.passed, workerIndex, data: simplifyTest(test, err) })); + event.dispatcher.on(event.all.failures, (data) => sendToParentThread({ event: event.all.failures, workerIndex, data })); // all event.dispatcher.once(event.all.result, () => parentPort.close()); diff --git a/lib/container.js b/lib/container.js index 01a640399..9e9d9333d 100644 --- a/lib/container.js +++ b/lib/container.js @@ -251,16 +251,12 @@ function requireHelperFromModule(helperName, config, HelperClass) { try { const mod = require(moduleName); if (!mod && !mod.default) { - throw new Error( - `Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`, - ); + throw new Error(`Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`); } HelperClass = mod.default || mod; } catch (err) { if (err.code === 'MODULE_NOT_FOUND') { - throw new Error( - `Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`, - ); + throw new Error(`Helper module '${moduleName}' was not found. Make sure you have installed the package correctly.`); } throw err; } @@ -317,9 +313,7 @@ function createSupportObjects(config) { container.support[name]._init(); } } catch (err) { - throw new Error( - `Initialization failed for ${name}: ${container.support[name]}\n${err.message}\n${err.stack}`, - ); + throw new Error(`Initialization failed for ${name}: ${container.support[name]}\n${err.message}\n${err.stack}`); } } @@ -476,13 +470,9 @@ function loadSupportObject(modulePath, supportObjectName) { return obj; } - throw new Error( - `Support object "${supportObjectName}" should be an object, class, or function, but got ${typeof obj}`, - ); + throw new Error(`Support object "${supportObjectName}" should be an object, class, or function, but got ${typeof obj}`); } catch (err) { - throw new Error( - `Could not include object ${supportObjectName} from module '${modulePath}'\n${err.message}\n${err.stack}`, - ); + throw new Error(`Could not include object ${supportObjectName} from module '${modulePath}'\n${err.message}\n${err.stack}`); } } diff --git a/lib/heal.js b/lib/heal.js index a06e82f25..4e417f175 100644 --- a/lib/heal.js +++ b/lib/heal.js @@ -48,9 +48,7 @@ class Heal { } hasCorrespondingRecipes(step) { - return ( - matchRecipes(this.recipes, this.contextName).filter((r) => !r.steps || r.steps.includes(step.name)).length > 0 - ); + return matchRecipes(this.recipes, this.contextName).filter((r) => !r.steps || r.steps.includes(step.name)).length > 0; } async getCodeSuggestions(context) { @@ -131,12 +129,7 @@ class Heal { snippet: codeSnippet, }); - recorder.add('healed', () => - output.print( - colors.bold.green(` Code healed successfully by ${suggestion.name}`), - colors.gray('(no errors thrown)'), - ), - ); + recorder.add('healed', () => output.print(colors.bold.green(` Code healed successfully by ${suggestion.name}`), colors.gray('(no errors thrown)'))); this.numHealed++; // recorder.session.restore(); return; @@ -173,10 +166,5 @@ function matchRecipes(recipes, contextName) { } function isBlank(value) { - return ( - value == null || - (Array.isArray(value) && value.length === 0) || - (typeof value === 'object' && Object.keys(value).length === 0) || - (typeof value === 'string' && value.trim() === '') - ); + return value == null || (Array.isArray(value) && value.length === 0) || (typeof value === 'object' && Object.keys(value).length === 0) || (typeof value === 'string' && value.trim() === ''); } diff --git a/lib/helper/JSONResponse.js b/lib/helper/JSONResponse.js index c0584c291..057d03c4c 100644 --- a/lib/helper/JSONResponse.js +++ b/lib/helper/JSONResponse.js @@ -70,9 +70,7 @@ class JSONResponse extends Helper { _beforeSuite() { this.response = null; if (!this.helpers[this.options.requestHelper]) { - throw new Error( - `Error setting JSONResponse, helper ${this.options.requestHelper} is not enabled in config, helpers: ${Object.keys(this.helpers)}`, - ); + throw new Error(`Error setting JSONResponse, helper ${this.options.requestHelper} is not enabled in config, helpers: ${Object.keys(this.helpers)}`); } // connect to REST helper this.helpers[this.options.requestHelper].config.onResponse = (response) => { diff --git a/lib/pause.js b/lib/pause.js index 56ebdd681..c10be9d0f 100644 --- a/lib/pause.js +++ b/lib/pause.js @@ -51,9 +51,7 @@ function pauseSession(passedObject = {}) { output.print(colors.yellow(` - Prefix ${colors.bold('=>')} to run js commands ${colors.bold(vars)}`)); if (aiAssistant.isEnabled) { - output.print( - colors.blue(` ${colors.bold('AI is enabled! (experimental)')} Write what you want and make AI run it`), - ); + output.print(colors.blue(` ${colors.bold('AI is enabled! (experimental)')} Write what you want and make AI run it`)); output.print(colors.blue(' Please note, only HTML fragments with interactive elements are sent to AI provider')); output.print(colors.blue(' Ideas: ask it to fill forms for you or to click')); } diff --git a/lib/workers.js b/lib/workers.js index 993e3aa46..42d288761 100644 --- a/lib/workers.js +++ b/lib/workers.js @@ -259,13 +259,7 @@ class Workers extends EventEmitter { _initWorkers(numberOfWorkers, config) { this.splitTestsByGroups(numberOfWorkers, config); - this.workers = createWorkerObjects( - this.testGroups, - this.codecept.config, - config.testConfig, - config.options, - config.selectedRuns, - ); + this.workers = createWorkerObjects(this.testGroups, this.codecept.config, config.testConfig, config.options, config.selectedRuns); this.numberOfWorkers = this.workers.length; } @@ -292,8 +286,7 @@ class Workers extends EventEmitter { this.testGroups.push(convertToMochaTests(testGroup)); } } else if (typeof numberOfWorkers === 'number' && numberOfWorkers > 0) { - this.testGroups = - config.by === 'suite' ? this.createGroupsOfSuites(numberOfWorkers) : this.createGroupsOfTests(numberOfWorkers); + this.testGroups = config.by === 'suite' ? this.createGroupsOfSuites(numberOfWorkers) : this.createGroupsOfTests(numberOfWorkers); } } @@ -508,13 +501,7 @@ class Workers extends EventEmitter { this.failuresLog.forEach((log) => output.print(...log)); } - output.result( - this.stats.passes, - this.stats.failures, - this.stats.pending, - ms(this.stats.duration), - this.stats.failedHooks, - ); + output.result(this.stats.passes, this.stats.failures, this.stats.pending, ms(this.stats.duration), this.stats.failedHooks); process.env.RUNS_WITH_WORKERS = 'false'; } } diff --git a/prettier.config.js b/prettier.config.js index c70ada024..9dda9a729 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -1,5 +1,5 @@ module.exports = { - printWidth: 120, + printWidth: 220, tabWidth: 2, useTabs: false, semi: true, diff --git a/test/helper/AppiumV2_ios_test.js b/test/helper/AppiumV2_ios_test.js index 5ba588a18..cb533caab 100644 --- a/test/helper/AppiumV2_ios_test.js +++ b/test/helper/AppiumV2_ios_test.js @@ -100,9 +100,7 @@ describe('Appium iOS Tests', function () { try { await app.hideDeviceKeyboard('pressKey', 'Done'); } catch (e) { - e.message.should.include( - 'An unknown server-side error occurred while processing the command. Original error: Soft keyboard not present, cannot hide keyboard', - ); + e.message.should.include('An unknown server-side error occurred while processing the command. Original error: Soft keyboard not present, cannot hide keyboard'); } }); }); @@ -130,9 +128,7 @@ describe('Appium iOS Tests', function () { try { await app.waitForText('Nothing here', 1, '~IntegerA'); } catch (e) { - e.message.should.contain( - 'element (~IntegerA) is not in DOM or there is no element(~IntegerA) with text "Nothing here" after 1 sec', - ); + e.message.should.contain('element (~IntegerA) is not in DOM or there is no element(~IntegerA) with text "Nothing here" after 1 sec'); } }); }); diff --git a/test/helper/AppiumV2_test.js b/test/helper/AppiumV2_test.js index 4cf1d9acd..70280f630 100644 --- a/test/helper/AppiumV2_test.js +++ b/test/helper/AppiumV2_test.js @@ -227,9 +227,7 @@ describe('Appium', function () { try { await app.hideDeviceKeyboard('pressKey', 'Done'); } catch (e) { - e.message.should.include( - 'An unknown server-side error occurred while processing the command. Original error: Soft keyboard not present, cannot hide keyboard', - ); + e.message.should.include('An unknown server-side error occurred while processing the command. Original error: Soft keyboard not present, cannot hide keyboard'); } }); }); @@ -244,20 +242,13 @@ describe('Appium', function () { describe('#openNotifications', () => { it('should react on notification opening', async () => { try { - await app.seeElement( - '//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]', - ); + await app.seeElement('//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]'); } catch (e) { e.should.be.instanceOf(AssertionFailedError); - e.inspect().should.include( - 'expected elements of //android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"] to be seen', - ); + e.inspect().should.include('expected elements of //android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"] to be seen'); } await app.openNotifications(); - await app.waitForVisible( - '//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]', - 10, - ); + await app.waitForVisible('//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]', 10); }); }); @@ -272,26 +263,11 @@ describe('Appium', function () { it('should react on swipe action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipe( - "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", - 800, - 1200, - 1000, - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vx = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipe("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1200, 1000); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vx = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); assert.ok(vx.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps'); assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps'); @@ -299,22 +275,10 @@ describe('Appium', function () { it('should react on swipeDown action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeDown( - "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", - 1200, - 1000, - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeDown("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 1200, 1000); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps'); }); @@ -322,84 +286,38 @@ describe('Appium', function () { it('run simplified swipeDown @quick', async () => { await app.resetApp(); await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeDown( - "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", - 120, - 100, - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeDown("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 120, 100); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); assert.equal(type, 'FLICK'); }); it('should react on swipeUp action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeUp( - "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", - 1200, - 1000, - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeUp("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 1200, 1000); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); assert.ok(vy.match(/vy: -\d\d000\.0 pps/), 'to be like dd000.0 pps'); }); it('should react on swipeRight action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeRight( - "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", - 800, - 1000, - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeRight("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1000); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']"); assert.equal(type, 'FLICK'); assert.ok(vy.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps'); }); it('should react on swipeLeft action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeLeft( - "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", - 800, - 1000, - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeLeft("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1000); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']"); assert.equal(type, 'FLICK'); assert.ok(vy.match(/vx: -\d\d000\.0 pps/), 'to be like 21000.0 pps'); }); @@ -424,14 +342,7 @@ describe('Appium', function () { await app.waitForElement('~startUserRegistrationCD', smallWait); await app.click('~startUserRegistrationCD'); try { - await app.swipeTo( - '//android.widget.CheckBox', - '//android.widget.ScrollView/android.widget.LinearLayout', - 'up', - 30, - 100, - 500, - ); + await app.swipeTo('//android.widget.CheckBox', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 500); } catch (e) { e.message.should.include('Scroll to the end and element android.widget.CheckBox was not found'); } @@ -441,33 +352,16 @@ describe('Appium', function () { await app.resetApp(); await app.waitForElement('~startUserRegistrationCD', smallWait); await app.click('~startUserRegistrationCD'); - await app.swipeTo( - '//android.widget.CheckBox', - '//android.widget.ScrollView/android.widget.LinearLayout', - 'up', - 30, - 100, - 700, - ); + await app.swipeTo('//android.widget.CheckBox', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700); }); describe('#performTouchAction', () => { it('should react on swipeUp action @second', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeUp( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeUp("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); expect(parseInt(vy.split(' ')[1], 10)).to.be.below(1006); }); @@ -475,60 +369,30 @@ describe('Appium', function () { it('should react on swipeDown action @second', async () => { await app.resetApp(); await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeUp( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeUp("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); expect(parseInt(vy.split(' ')[1], 10)).to.be.above(-300); }); it('should react on swipeLeft action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeLeft( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeLeft("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); expect(vy.split(' ')[1]).to.be.below(730); }); it('should react on swipeRight action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeRight( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeRight("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); expect(vy.split(' ')[1]).to.be.above(278); }); @@ -567,14 +431,7 @@ describe('Appium', function () { await app.click('~email of the customer'); await app.appendField('~email of the customer', '1'); await app.hideDeviceKeyboard('pressKey', 'Done'); - await app.swipeTo( - '//android.widget.Button', - '//android.widget.ScrollView/android.widget.LinearLayout', - 'up', - 30, - 100, - 700, - ); + await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700); await app.click('//android.widget.Button'); await app.see('1', '#io.selendroid.testapp:id/label_email_data'); }); @@ -582,9 +439,7 @@ describe('Appium', function () { describe('#seeInSource', () => { it('should check for text to be in HTML source', async () => { - await app.seeInSource( - 'class="android.widget.Button" package="io.selendroid.testapp" content-desc="buttonTestCD"', - ); + await app.seeInSource('class="android.widget.Button" package="io.selendroid.testapp" content-desc="buttonTestCD"'); await app.dontSeeInSource(' { @@ -658,19 +503,9 @@ describe('Appium', function () { await app.click('~startUserRegistrationCD'); await app.fillField('//android.widget.EditText[@content-desc="email of the customer"]', 'Nothing special'); await app.hideDeviceKeyboard('pressKey', 'Done'); - await app.swipeTo( - '//android.widget.Button', - '//android.widget.ScrollView/android.widget.LinearLayout', - 'up', - 30, - 100, - 700, - ); + await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700); await app.click('//android.widget.Button'); - await app.see( - 'Nothing special', - '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', - ); + await app.see('Nothing special', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]'); }); it('should append field value @second', async () => { @@ -680,19 +515,9 @@ describe('Appium', function () { await app.fillField('~email of the customer', 'Nothing special'); await app.appendField('~email of the customer', 'blabla'); await app.hideDeviceKeyboard('pressKey', 'Done'); - await app.swipeTo( - '//android.widget.Button', - '//android.widget.ScrollView/android.widget.LinearLayout', - 'up', - 30, - 100, - 700, - ); + await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700); await app.click('//android.widget.Button'); - await app.see( - 'Nothing specialblabla', - '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', - ); + await app.see('Nothing specialblabla', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]'); }); }); @@ -727,20 +552,10 @@ describe('Appium', function () { await app.tap('~email of the customer'); await app.appendField('//android.widget.EditText[@content-desc="email of the customer"]', '1'); await app.hideDeviceKeyboard('pressKey', 'Done'); - await app.swipeTo( - '//android.widget.Button', - '//android.widget.ScrollView/android.widget.LinearLayout', - 'up', - 30, - 100, - 700, - ); + await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700); await app.click('//android.widget.Button'); await app.see('1', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]'); - const id = await app.grabNumberOfVisibleElements( - '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', - 'contentDescription', - ); + const id = await app.grabNumberOfVisibleElements('//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', 'contentDescription'); assert.strictEqual(1, id); }); }); diff --git a/test/helper/Appium_test.js b/test/helper/Appium_test.js index 0ad4fde5b..58dd30799 100644 --- a/test/helper/Appium_test.js +++ b/test/helper/Appium_test.js @@ -231,9 +231,7 @@ describe('Appium', function () { try { await app.hideDeviceKeyboard('pressKey', 'Done'); } catch (e) { - e.message.should.include( - 'An unknown server-side error occurred while processing the command. Original error: Soft keyboard not present, cannot hide keyboard', - ); + e.message.should.include('An unknown server-side error occurred while processing the command. Original error: Soft keyboard not present, cannot hide keyboard'); } }); }); @@ -248,20 +246,13 @@ describe('Appium', function () { describe('#openNotifications', () => { it('should react on notification opening', async () => { try { - await app.seeElement( - '//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]', - ); + await app.seeElement('//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]'); } catch (e) { e.should.be.instanceOf(AssertionFailedError); - e.inspect().should.include( - 'expected elements of //android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"] to be seen', - ); + e.inspect().should.include('expected elements of //android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"] to be seen'); } await app.openNotifications(); - await app.waitForVisible( - '//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]', - 10, - ); + await app.waitForVisible('//android.widget.FrameLayout[@resource-id="com.android.systemui:id/quick_settings_container"]', 10); }); }); @@ -276,26 +267,11 @@ describe('Appium', function () { it('should react on swipe action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipe( - "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", - 800, - 1200, - 1000, - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vx = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipe("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1200, 1000); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vx = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); assert.ok(vx.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps'); assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps'); @@ -303,22 +279,10 @@ describe('Appium', function () { it('should react on swipeDown action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeDown( - "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", - 1200, - 1000, - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeDown("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 1200, 1000); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); assert.ok(vy.match(/vy: \d\d000\.0 pps/), 'to be like dd000.0 pps'); }); @@ -326,84 +290,38 @@ describe('Appium', function () { it('run simplified swipeDown @quick', async () => { await app.resetApp(); await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeDown( - "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", - 120, - 100, - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeDown("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 120, 100); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); assert.equal(type, 'FLICK'); }); it('should react on swipeUp action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeUp( - "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", - 1200, - 1000, - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeUp("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 1200, 1000); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); assert.ok(vy.match(/vy: -\d\d000\.0 pps/), 'to be like dd000.0 pps'); }); it('should react on swipeRight action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeRight( - "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", - 800, - 1000, - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeRight("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1000); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']"); assert.equal(type, 'FLICK'); assert.ok(vy.match(/vx: \d\d000\.0 pps/), 'to be like dd000.0 pps'); }); it('should react on swipeLeft action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeLeft( - "//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", - 800, - 1000, - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeLeft("//android.widget.LinearLayout[@resource-id = 'io.selendroid.testapp:id/LinearLayout1']", 800, 1000); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view3']"); assert.equal(type, 'FLICK'); assert.ok(vy.match(/vx: -\d\d000\.0 pps/), 'to be like 21000.0 pps'); }); @@ -428,14 +346,7 @@ describe('Appium', function () { await app.waitForElement('~startUserRegistrationCD', smallWait); await app.click('~startUserRegistrationCD'); try { - await app.swipeTo( - '//android.widget.CheckBox', - '//android.widget.ScrollView/android.widget.LinearLayout', - 'up', - 30, - 100, - 500, - ); + await app.swipeTo('//android.widget.CheckBox', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 500); } catch (e) { e.message.should.include('Scroll to the end and element android.widget.CheckBox was not found'); } @@ -445,33 +356,16 @@ describe('Appium', function () { await app.resetApp(); await app.waitForElement('~startUserRegistrationCD', smallWait); await app.click('~startUserRegistrationCD'); - await app.swipeTo( - '//android.widget.CheckBox', - '//android.widget.ScrollView/android.widget.LinearLayout', - 'up', - 30, - 100, - 700, - ); + await app.swipeTo('//android.widget.CheckBox', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700); }); describe('#performTouchAction', () => { it('should react on swipeUp action @second', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeUp( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeUp("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); expect(parseInt(vy.split(' ')[1], 10)).to.be.below(1006); }); @@ -479,60 +373,30 @@ describe('Appium', function () { it('should react on swipeDown action @second', async () => { await app.resetApp(); await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeUp( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeUp("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); expect(parseInt(vy.split(' ')[1], 10)).to.be.above(-300); }); it('should react on swipeLeft action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeLeft( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeLeft("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); expect(vy.split(' ')[1]).to.be.below(730); }); it('should react on swipeRight action', async () => { await app.click("//android.widget.Button[@resource-id = 'io.selendroid.testapp:id/touchTest']"); - await app.waitForText( - 'Gesture Type', - 10, - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - await app.swipeRight( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const type = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']", - ); - const vy = await app.grabTextFrom( - "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']", - ); + await app.waitForText('Gesture Type', 10, "//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + await app.swipeRight("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const type = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/gesture_type_text_view']"); + const vy = await app.grabTextFrom("//android.widget.TextView[@resource-id = 'io.selendroid.testapp:id/text_view4']"); assert.equal(type, 'FLICK'); expect(vy.split(' ')[1]).to.be.above(278); }); @@ -571,14 +435,7 @@ describe('Appium', function () { await app.click('~email of the customer'); await app.appendField('~email of the customer', '1'); await app.hideDeviceKeyboard('pressKey', 'Done'); - await app.swipeTo( - '//android.widget.Button', - '//android.widget.ScrollView/android.widget.LinearLayout', - 'up', - 30, - 100, - 700, - ); + await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700); await app.click('//android.widget.Button'); await app.see('1', '#io.selendroid.testapp:id/label_email_data'); }); @@ -586,9 +443,7 @@ describe('Appium', function () { describe('#seeInSource', () => { it('should check for text to be in HTML source', async () => { - await app.seeInSource( - 'class="android.widget.Button" package="io.selendroid.testapp" content-desc="buttonTestCD"', - ); + await app.seeInSource('class="android.widget.Button" package="io.selendroid.testapp" content-desc="buttonTestCD"'); await app.dontSeeInSource(' { @@ -662,19 +507,9 @@ describe('Appium', function () { await app.click('~startUserRegistrationCD'); await app.fillField('//android.widget.EditText[@content-desc="email of the customer"]', 'Nothing special'); await app.hideDeviceKeyboard('pressKey', 'Done'); - await app.swipeTo( - '//android.widget.Button', - '//android.widget.ScrollView/android.widget.LinearLayout', - 'up', - 30, - 100, - 700, - ); + await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700); await app.click('//android.widget.Button'); - await app.see( - 'Nothing special', - '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', - ); + await app.see('Nothing special', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]'); }); it('should append field value @second', async () => { @@ -684,19 +519,9 @@ describe('Appium', function () { await app.fillField('~email of the customer', 'Nothing special'); await app.appendField('~email of the customer', 'blabla'); await app.hideDeviceKeyboard('pressKey', 'Done'); - await app.swipeTo( - '//android.widget.Button', - '//android.widget.ScrollView/android.widget.LinearLayout', - 'up', - 30, - 100, - 700, - ); + await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700); await app.click('//android.widget.Button'); - await app.see( - 'Nothing specialblabla', - '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', - ); + await app.see('Nothing specialblabla', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]'); }); }); @@ -731,20 +556,10 @@ describe('Appium', function () { await app.tap('~email of the customer'); await app.appendField('//android.widget.EditText[@content-desc="email of the customer"]', '1'); await app.hideDeviceKeyboard('pressKey', 'Done'); - await app.swipeTo( - '//android.widget.Button', - '//android.widget.ScrollView/android.widget.LinearLayout', - 'up', - 30, - 100, - 700, - ); + await app.swipeTo('//android.widget.Button', '//android.widget.ScrollView/android.widget.LinearLayout', 'up', 30, 100, 700); await app.click('//android.widget.Button'); await app.see('1', '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]'); - const id = await app.grabNumberOfVisibleElements( - '//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', - 'contentDescription', - ); + const id = await app.grabNumberOfVisibleElements('//android.widget.TextView[@resource-id="io.selendroid.testapp:id/label_email_data"]', 'contentDescription'); assert.strictEqual(1, id); }); }); diff --git a/test/helper/JSONResponse_test.js b/test/helper/JSONResponse_test.js index 0edcc75f9..1f12b4277 100644 --- a/test/helper/JSONResponse_test.js +++ b/test/helper/JSONResponse_test.js @@ -82,9 +82,7 @@ describe('JSONResponse', () => { I.seeResponseContainsJson({ posts: [{ id: 1, author: 'davert' }], }); - expect(() => I.seeResponseContainsJson({ posts: [{ id: 2, author: 'boss' }] })).to.throw( - 'expected { …(2) } to deeply match { Object (posts) }', - ); + expect(() => I.seeResponseContainsJson({ posts: [{ id: 2, author: 'boss' }] })).to.throw('expected { …(2) } to deeply match { Object (posts) }'); }); it('should check for json inclusion - returned Array', () => { @@ -96,9 +94,7 @@ describe('JSONResponse', () => { I.seeResponseContainsJson({ posts: [{ id: 1, author: 'davert' }], }); - expect(() => I.seeResponseContainsJson({ posts: [{ id: 2, author: 'boss' }] })).to.throw( - 'No elements in array matched {"posts":[{"id":2,"author":"boss"}]}', - ); + expect(() => I.seeResponseContainsJson({ posts: [{ id: 2, author: 'boss' }] })).to.throw('No elements in array matched {"posts":[{"id":2,"author":"boss"}]}'); }); it('should check for json inclusion - returned Array of 2 items', () => { diff --git a/test/helper/Playwright_test.js b/test/helper/Playwright_test.js index ecc332fe1..1961e57a0 100644 --- a/test/helper/Playwright_test.js +++ b/test/helper/Playwright_test.js @@ -123,9 +123,7 @@ describe('Playwright', function () { await I.amOnPage('https://codecept.io/helpers/Playwright/'); await I.seeCssPropertiesOnElements('.navbar', { 'background-color': 'rgb(128, 90, 213)' }); } catch (e) { - e.message.should.include( - "expected element (.navbar) to have CSS property { 'background-color': 'rgb(128, 90, 213)' }", - ); + e.message.should.include("expected element (.navbar) to have CSS property { 'background-color': 'rgb(128, 90, 213)' }"); } }); }); @@ -470,9 +468,7 @@ describe('Playwright', function () { it('should grab the source', () => I.amOnPage('/') .then(() => I.grabSource()) - .then((source) => - assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved'), - )); + .then((source) => assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved'))); }); describe('#seeTitleEquals', () => { @@ -636,12 +632,9 @@ describe('Playwright', function () { }); xit('should clear contenteditable', async () => { - const isClearMethodPresent = await I.usePlaywrightTo( - 'check if new Playwright .clear() method present', - async ({ page }) => { - return typeof page.locator().clear === 'function'; - }, - ); + const isClearMethodPresent = await I.usePlaywrightTo('check if new Playwright .clear() method present', async ({ page }) => { + return typeof page.locator().clear === 'function'; + }); if (!isClearMethodPresent) { this.skip(); } @@ -741,14 +734,11 @@ describe('Playwright', function () { }); describe('#waitForDisabled', () => { - it('should wait for input text field to be disabled', () => - I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled('#text', 1))); + it('should wait for input text field to be disabled', () => I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled('#text', 1))); - it('should wait for input text field to be enabled by xpath', () => - I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled("//*[@name = 'test']", 1))); + it('should wait for input text field to be enabled by xpath', () => I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled("//*[@name = 'test']", 1))); - it('should wait for a button to be disabled', () => - I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled('#text', 1))); + it('should wait for a button to be disabled', () => I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled('#text', 1))); }); describe('#waitForValue', () => { @@ -760,9 +750,7 @@ describe('Playwright', function () { throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.include( - 'element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec', - ); + e.message.should.include('element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec'); })); it('should wait for expected value for given css locator', () => diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js index 03273b8e0..fc3dc3c4d 100644 --- a/test/helper/Puppeteer_test.js +++ b/test/helper/Puppeteer_test.js @@ -414,9 +414,7 @@ describe('Puppeteer', function () { it('should grab the source', () => I.amOnPage('/') .then(() => I.grabSource()) - .then((source) => - assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved'), - )); + .then((source) => assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved'))); }); describe('#seeTitleEquals', () => { @@ -732,9 +730,7 @@ describe('Puppeteer', function () { throw Error('It should never get this far'); }) .catch((e) => { - e.message.should.include( - 'element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec', - ); + e.message.should.include('element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec'); })); it('should wait for expected value for given css locator', () => @@ -1113,9 +1109,7 @@ describe('Puppeteer (remote browser)', function () { await I._startBrowser(); throw Error('It should never get this far'); } catch (e) { - e.message.should.include( - 'Cannot connect to websocket endpoint.\n\nPlease make sure remote browser is running and accessible.', - ); + e.message.should.include('Cannot connect to websocket endpoint.\n\nPlease make sure remote browser is running and accessible.'); } }); diff --git a/test/helper/WebDriver.noSeleniumServer_test.js b/test/helper/WebDriver.noSeleniumServer_test.js index 992d40a3c..2ac81b5fe 100644 --- a/test/helper/WebDriver.noSeleniumServer_test.js +++ b/test/helper/WebDriver.noSeleniumServer_test.js @@ -467,9 +467,7 @@ describe('WebDriver - No Selenium server started', function () { await wd.waitForValue('//input[@name= "rus"]', 'Верно3', 0.1); throw Error('It should never get this far'); } catch (e) { - e.message.should.include( - 'element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec', - ); + e.message.should.include('element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec'); } }); @@ -735,9 +733,7 @@ describe('WebDriver - No Selenium server started', function () { .amOnPage('/dynamic') .then(() => wd.waitForText('Nothing here', 1, '#text')) .catch((e) => { - e.message.should.be.equal( - 'element (#text) is not in DOM or there is no element(#text) with text "Nothing here" after 1 sec', - ); + e.message.should.be.equal('element (#text) is not in DOM or there is no element(#text) with text "Nothing here" after 1 sec'); }); }); @@ -746,9 +742,7 @@ describe('WebDriver - No Selenium server started', function () { .amOnPage('/dynamic') .then(() => wd.waitForText('Dynamic text', 0.1)) .catch((e) => { - e.message.should.be.equal( - 'element (body) is not in DOM or there is no element(body) with text "Dynamic text" after 0.1 sec', - ); + e.message.should.be.equal('element (body) is not in DOM or there is no element(body) with text "Dynamic text" after 0.1 sec'); }); }); }); @@ -1076,11 +1070,7 @@ describe('WebDriver - No Selenium server started', function () { allHandlesBeforePopup.length.should.eql(1); await wd.executeScript(() => { - window.open( - 'https://www.w3schools.com/', - 'new window', - 'toolbar=yes,scrollbars=yes,resizable=yes,width=400,height=400', - ); + window.open('https://www.w3schools.com/', 'new window', 'toolbar=yes,scrollbars=yes,resizable=yes,width=400,height=400'); }); const allHandlesAfterPopup = await wd.grabAllWindowHandles(); diff --git a/test/helper/WebDriver_test.js b/test/helper/WebDriver_test.js index 4d3184b66..10627a7a6 100644 --- a/test/helper/WebDriver_test.js +++ b/test/helper/WebDriver_test.js @@ -479,9 +479,7 @@ describe('WebDriver', function () { await wd.waitForValue('//input[@name= "rus"]', 'Верно3', 0.1); throw Error('It should never get this far'); } catch (e) { - e.message.should.include( - 'element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec', - ); + e.message.should.include('element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec'); } }); @@ -748,9 +746,7 @@ describe('WebDriver', function () { .amOnPage('/dynamic') .then(() => wd.waitForText('Nothing here', 1, '#text')) .catch((e) => { - e.message.should.be.equal( - 'element (#text) is not in DOM or there is no element(#text) with text "Nothing here" after 1 sec', - ); + e.message.should.be.equal('element (#text) is not in DOM or there is no element(#text) with text "Nothing here" after 1 sec'); }); }); @@ -759,9 +755,7 @@ describe('WebDriver', function () { .amOnPage('/dynamic') .then(() => wd.waitForText('Dynamic text', 0.1)) .catch((e) => { - e.message.should.be.equal( - 'element (body) is not in DOM or there is no element(body) with text "Dynamic text" after 0.1 sec', - ); + e.message.should.be.equal('element (body) is not in DOM or there is no element(body) with text "Dynamic text" after 0.1 sec'); }); }); }); @@ -1089,11 +1083,7 @@ describe('WebDriver', function () { allHandlesBeforePopup.length.should.eql(1); await wd.executeScript(() => { - window.open( - 'https://www.w3schools.com/', - 'new window', - 'toolbar=yes,scrollbars=yes,resizable=yes,width=400,height=400', - ); + window.open('https://www.w3schools.com/', 'new window', 'toolbar=yes,scrollbars=yes,resizable=yes,width=400,height=400'); }); const allHandlesAfterPopup = await wd.grabAllWindowHandles(); diff --git a/test/helper/webapi.js b/test/helper/webapi.js index 8197205d1..231b006ab 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -40,11 +40,7 @@ module.exports.tests = function () { await I.seeElement("input[name='name']"); const sec = new Date().getUTCMilliseconds(); await I.saveElementScreenshot("input[name='name']", `element_screenshot_${sec}.png`); - assert.ok( - fileExists(path.join(global.output_dir, `element_screenshot_${sec}.png`)), - null, - 'file does not exists', - ); + assert.ok(fileExists(path.join(global.output_dir, `element_screenshot_${sec}.png`)), null, 'file does not exists'); }); }); @@ -1420,9 +1416,7 @@ module.exports.tests = function () { }, ); } catch (e) { - e.message.should.include( - 'all elements (a[href="/codeceptjs/CodeceptJS"]) to have attributes {"href":"/codeceptjs/CodeceptJS"}', - ); + e.message.should.include('all elements (a[href="/codeceptjs/CodeceptJS"]) to have attributes {"href":"/codeceptjs/CodeceptJS"}'); } }); @@ -1460,9 +1454,7 @@ module.exports.tests = function () { }, ); } catch (e) { - e.message.should.include( - 'expected all elements ({css: a[href="/codeceptjs/CodeceptJS"]}) to have attributes {"disable":true} "0" to equal "3"', - ); + e.message.should.include('expected all elements ({css: a[href="/codeceptjs/CodeceptJS"]}) to have attributes {"disable":true} "0" to equal "3"'); } }); @@ -1524,9 +1516,7 @@ module.exports.tests = function () { }); throw Error('It should never get this far'); } catch (e) { - e.message.should.include( - 'expected all elements (a) to have CSS property {"margin-top":"0em","cursor":"pointer"}', - ); + e.message.should.include('expected all elements (a) to have CSS property {"margin-top":"0em","cursor":"pointer"}'); } }); @@ -1657,9 +1647,7 @@ module.exports.tests = function () { I.amOnPage('https://codecept.io/'); await I.seeTraffic({ name: 'traffics', url: 'https://codecept.io/img/companies/BC_LogoScreen_C.jpg' }); } catch (e) { - expect(e.message).to.equal( - 'Failure in test automation. You use "I.seeTraffic", but "I.startRecordingTraffic" was never called before.', - ); + expect(e.message).to.equal('Failure in test automation. You use "I.seeTraffic", but "I.startRecordingTraffic" was never called before.'); } }); @@ -1780,9 +1768,7 @@ module.exports.tests = function () { I.waitForText('Work for You!'); I.grabWebSocketMessages(); } catch (e) { - expect(e.message).to.equal( - 'Failure in test automation. You use "I.grabWebSocketMessages", but "I.startRecordingWebSocketMessages" was never called before.', - ); + expect(e.message).to.equal('Failure in test automation. You use "I.grabWebSocketMessages", but "I.startRecordingWebSocketMessages" was never called before.'); } }); diff --git a/test/runner/dry_run_test.js b/test/runner/dry_run_test.js index d24302b3c..10c577747 100644 --- a/test/runner/dry_run_test.js +++ b/test/runner/dry_run_test.js @@ -5,8 +5,7 @@ const exec = require('child_process').exec; const runner = path.join(__dirname, '/../../bin/codecept.js'); const codecept_dir = path.join(__dirname, '/../data/sandbox'); const codecept_run = `${runner} dry-run`; -const codecept_run_config = (config, grep) => - `${codecept_run} --config ${codecept_dir}/${config} ${grep ? `--grep "${grep}"` : ''}`; +const codecept_run_config = (config, grep) => `${codecept_run} --config ${codecept_dir}/${config} ${grep ? `--grep "${grep}"` : ''}`; const char = require('figures').checkboxOff; describe('dry-run command', () => { @@ -51,23 +50,10 @@ describe('dry-run command', () => { const lines = stdout.match(/\S.+/g); expect(lines).not.toEqual( - expect.arrayContaining([ - "Helper: I'm initialized", - "Helper: I'm simple BeforeSuite hook", - "Helper: I'm simple Before hook", - "Helper: I'm simple After hook", - "Helper: I'm simple AfterSuite hook", - ]), + expect.arrayContaining(["Helper: I'm initialized", "Helper: I'm simple BeforeSuite hook", "Helper: I'm simple Before hook", "Helper: I'm simple After hook", "Helper: I'm simple AfterSuite hook"]), ); - expect(lines).toEqual( - expect.arrayContaining([ - "Test: I'm simple BeforeSuite hook", - "Test: I'm simple Before hook", - "Test: I'm simple After hook", - "Test: I'm simple AfterSuite hook", - ]), - ); + expect(lines).toEqual(expect.arrayContaining(["Test: I'm simple BeforeSuite hook", "Test: I'm simple Before hook", "Test: I'm simple After hook", "Test: I'm simple AfterSuite hook"])); expect(stdout).toContain('OK | 1 passed'); expect(stdout).toContain('No tests were executed'); @@ -166,28 +152,25 @@ describe('dry-run command', () => { }); it('should work with inject() keyword', (done) => { - exec( - `${codecept_run_config('configs/pageObjects/codecept.inject.po.js', 'check current dir')} --debug`, - (err, stdout) => { - const lines = stdout.split('\n'); - expect(stdout).toContain('injected'); - expect(lines).toEqual( - expect.arrayContaining([ - ' check current dir', - ' I open dir "aaa"', - ' I am in path "."', - ' I see file "codecept.class.js"', - ' On MyPage: has file "uu"', - ' I see file "codecept.class.js"', - ' I see file "codecept.po.js"', - ' I see file "codecept.po.js"', - ]), - ); - expect(stdout).toContain('OK | 1 passed'); - expect(err).toBeFalsy(); - done(); - }, - ); + exec(`${codecept_run_config('configs/pageObjects/codecept.inject.po.js', 'check current dir')} --debug`, (err, stdout) => { + const lines = stdout.split('\n'); + expect(stdout).toContain('injected'); + expect(lines).toEqual( + expect.arrayContaining([ + ' check current dir', + ' I open dir "aaa"', + ' I am in path "."', + ' I see file "codecept.class.js"', + ' On MyPage: has file "uu"', + ' I see file "codecept.class.js"', + ' I see file "codecept.po.js"', + ' I see file "codecept.po.js"', + ]), + ); + expect(stdout).toContain('OK | 1 passed'); + expect(err).toBeFalsy(); + done(); + }); }); it('should inject page objects via proxy', (done) => { diff --git a/test/runner/pageobject_test.js b/test/runner/pageobject_test.js index c78fe9a15..8ca95260d 100644 --- a/test/runner/pageobject_test.js +++ b/test/runner/pageobject_test.js @@ -5,8 +5,7 @@ const { expect } = require('expect'); const runner = path.join(__dirname, '/../../bin/codecept.js'); const codecept_dir = path.join(__dirname, '/../data/sandbox/configs/pageObjects'); const codecept_run = `${runner} run`; -const config_run_config = (config, grep) => - `${codecept_run} --config ${codecept_dir}/${config} ${grep ? `--grep "${grep}"` : ''}`; +const config_run_config = (config, grep) => `${codecept_run} --config ${codecept_dir}/${config} ${grep ? `--grep "${grep}"` : ''}`; describe('CodeceptJS PageObject', () => { before(() => { diff --git a/test/runner/run_multiple_test.js b/test/runner/run_multiple_test.js index 69a25f175..315748075 100644 --- a/test/runner/run_multiple_test.js +++ b/test/runner/run_multiple_test.js @@ -138,34 +138,28 @@ describe('CodeceptJS Multiple Runner', function () { it('should run features in parallel', (done) => { process.chdir(codecept_dir); - exec( - `${runner} run-multiple --config codecept.multiple.features.js chunks --features --grep '(?=.*)^(?!.*@fail)'`, - (err, stdout) => { - stdout.should.match(/\[\d\.chunks:chunk\d:default\] Checkout examples process/); - // stdout.should.not.match(/\[\d\.chunks:chunk\d:default\] Checkout examples process/) - stdout.should.match(/\[\d\.chunks:chunk\d:default\] Checkout string/); - // stdout.should.not.match(/\[\d\.chunks:chunk\d:default\] Checkout string/) - stdout.should.match(/\[\d\.chunks:chunk\d:default\] {3}OK {2}\|/); - stdout.should.match(/\[\d\.chunks:chunk\d:default\] {3}OK {2}\|/); - stdout.should.not.include('@feature_grep'); - assert(!err); - done(); - }, - ); + exec(`${runner} run-multiple --config codecept.multiple.features.js chunks --features --grep '(?=.*)^(?!.*@fail)'`, (err, stdout) => { + stdout.should.match(/\[\d\.chunks:chunk\d:default\] Checkout examples process/); + // stdout.should.not.match(/\[\d\.chunks:chunk\d:default\] Checkout examples process/) + stdout.should.match(/\[\d\.chunks:chunk\d:default\] Checkout string/); + // stdout.should.not.match(/\[\d\.chunks:chunk\d:default\] Checkout string/) + stdout.should.match(/\[\d\.chunks:chunk\d:default\] {3}OK {2}\|/); + stdout.should.match(/\[\d\.chunks:chunk\d:default\] {3}OK {2}\|/); + stdout.should.not.include('@feature_grep'); + assert(!err); + done(); + }); }); it('should run features & tests in parallel', (done) => { process.chdir(codecept_dir); - exec( - `${runner} run-multiple --config codecept.multiple.features.js chunks --grep '(?=.*)^(?!.*@fail)'`, - (err, stdout) => { - stdout.should.include('@feature_grep'); - stdout.should.include('Checkout examples process'); - stdout.should.include('Checkout string'); - assert(!err); - done(); - }, - ); + exec(`${runner} run-multiple --config codecept.multiple.features.js chunks --grep '(?=.*)^(?!.*@fail)'`, (err, stdout) => { + stdout.should.include('@feature_grep'); + stdout.should.include('Checkout examples process'); + stdout.should.include('Checkout string'); + assert(!err); + done(); + }); }); it('should run only tests in parallel', (done) => { diff --git a/test/runner/run_rerun_test.js b/test/runner/run_rerun_test.js index 72f5ca40b..36c4fadd6 100644 --- a/test/runner/run_rerun_test.js +++ b/test/runner/run_rerun_test.js @@ -7,8 +7,7 @@ const semver = require('semver'); const runner = path.join(__dirname, '/../../bin/codecept.js'); const codecept_dir = path.join(__dirname, '/../data/sandbox/configs/run-rerun/'); const codecept_run = `${runner} run-rerun`; -const codecept_run_config = (config, grep) => - `${codecept_run} --config ${codecept_dir}/${config} --grep "${grep || ''}"`; +const codecept_run_config = (config, grep) => `${codecept_run} --config ${codecept_dir}/${config} --grep "${grep || ''}"`; describe('run-rerun command', () => { before(() => { @@ -69,44 +68,35 @@ describe('run-rerun command', () => { }); it('should display errors if test is fail always', (done) => { - exec( - `${codecept_run_config('codecept.conf.fail_test.js', '@RunRerun - Fail all attempt')} --debug`, - (err, stdout) => { - expect(stdout).toContain('Fail run 1 of max 3, success runs 0/2'); - expect(stdout).toContain('Fail run 2 of max 3, success runs 0/2'); - expect(stdout).toContain('Fail run 3 of max 3, success runs 0/2'); - expect(stdout).toContain('Flaky tests detected!'); - expect(err.code).toBe(1); - done(); - }, - ); + exec(`${codecept_run_config('codecept.conf.fail_test.js', '@RunRerun - Fail all attempt')} --debug`, (err, stdout) => { + expect(stdout).toContain('Fail run 1 of max 3, success runs 0/2'); + expect(stdout).toContain('Fail run 2 of max 3, success runs 0/2'); + expect(stdout).toContain('Fail run 3 of max 3, success runs 0/2'); + expect(stdout).toContain('Flaky tests detected!'); + expect(err.code).toBe(1); + 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) => { - expect(stdout).toContain('Process run 1 of max 3, success runs 1/2'); - expect(stdout).toContain('Fail run 2 of max 3, success runs 1/2'); - expect(stdout).toContain('Process run 3 of max 3, success runs 2/2'); - expect(stdout).not.toContain('Flaky tests detected!'); - expect(err).toBeNull(); - done(); - }, - ); + exec(`FAIL_ATTEMPT=0 ${codecept_run_config('codecept.conf.fail_test.js', '@RunRerun - fail second test')} --debug`, (err, stdout) => { + expect(stdout).toContain('Process run 1 of max 3, success runs 1/2'); + expect(stdout).toContain('Fail run 2 of max 3, success runs 1/2'); + expect(stdout).toContain('Process run 3 of max 3, success runs 2/2'); + expect(stdout).not.toContain('Flaky tests detected!'); + expect(err).toBeNull(); + done(); + }); }); 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(); - }, - ); + 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/test/unit/worker_test.js b/test/unit/worker_test.js index 55abb6963..e7bdb3948 100644 --- a/test/unit/worker_test.js +++ b/test/unit/worker_test.js @@ -38,10 +38,7 @@ describe('Workers', function () { it('should create worker by function', (done) => { const createTestGroups = () => { - const files = [ - [path.join(codecept_dir, '/custom-worker/base_test.worker.js')], - [path.join(codecept_dir, '/custom-worker/custom_test.worker.js')], - ]; + const files = [[path.join(codecept_dir, '/custom-worker/base_test.worker.js')], [path.join(codecept_dir, '/custom-worker/custom_test.worker.js')]]; return files; }; From ce5bb2823f93551091844fd493bc7e91f3097e9c Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 31 Dec 2024 01:08:41 +0200 Subject: [PATCH 36/37] reverted change to ; --- lib/actor.js | 14 +-- lib/cli.js | 22 ++-- lib/codecept.js | 12 +-- lib/command/gherkin/snippets.js | 14 +-- lib/command/workers/runTests.js | 36 +++---- lib/container.js | 14 +-- lib/heal.js | 16 +-- lib/helper/JSONResponse.js | 2 +- lib/helper/testcafe/testcafe-utils.js | 2 +- lib/output.js | 2 +- lib/pause.js | 10 +- lib/scenario.js | 20 ++-- lib/secret.js | 2 +- lib/step.js | 10 +- lib/workers.js | 48 ++++----- prettier.config.js | 1 + test/acceptance/codecept.WebDriver.js | 2 +- test/data/inject-fail-example/pages/page.js | 4 +- test/data/sandbox/codecept.customworker.js | 2 +- .../step_definitions/my_other_steps.js | 10 +- test/helper/AppiumV2_test.js | 2 +- test/helper/Appium_test.js | 2 +- test/helper/Playwright_test.js | 82 +++++++------- test/helper/Puppeteer_test.js | 102 +++++++++--------- .../helper/WebDriver.noSeleniumServer_test.js | 66 ++++++------ test/helper/WebDriver_test.js | 66 ++++++------ test/helper/webapi.js | 8 +- test/runner/dry_run_test.js | 26 ++--- test/runner/pageobject_test.js | 20 ++-- test/runner/run_multiple_test.js | 40 +++---- test/runner/run_rerun_test.js | 12 +-- test/unit/actor_test.js | 10 +- test/unit/bdd_test.js | 64 +++++------ test/unit/container_test.js | 4 +- test/unit/worker_test.js | 36 +++---- 35 files changed, 392 insertions(+), 391 deletions(-) diff --git a/lib/actor.js b/lib/actor.js index e4ddd8a12..63b5067fe 100644 --- a/lib/actor.js +++ b/lib/actor.js @@ -40,7 +40,7 @@ class Actor { limitTime(timeout) { if (!store.timeouts) return this; - event.dispatcher.prependOnceListener(event.step.before, (step) => { + event.dispatcher.prependOnceListener(event.step.before, step => { output.log(`Timeout to ${step}: ${timeout}s`); step.setTimeout(timeout * 1000, Step.TIMEOUT_ORDER.codeLimitTime); }); @@ -78,10 +78,10 @@ module.exports = function (obj = {}) { const helpers = container.helpers(); // add methods from enabled helpers - Object.values(helpers).forEach((helper) => { + Object.values(helpers).forEach(helper => { methodsOfObject(helper, 'Helper') - .filter((method) => method !== 'constructor' && method[0] !== '_') - .forEach((action) => { + .filter(method => method !== 'constructor' && method[0] !== '_') + .forEach(action => { const actionAlias = translation.actionAliasFor(action); if (!actor[action]) { actor[action] = actor[actionAlias] = function () { @@ -98,7 +98,7 @@ module.exports = function (obj = {}) { }); // add translated custom steps from actor - Object.keys(obj).forEach((key) => { + Object.keys(obj).forEach(key => { const actionAlias = translation.actionAliasFor(key); if (!actor[actionAlias]) { actor[actionAlias] = actor[key]; @@ -113,7 +113,7 @@ module.exports = function (obj = {}) { }); // store.actor = actor; // add custom steps from actor - Object.keys(obj).forEach((key) => { + Object.keys(obj).forEach(key => { const ms = new MetaStep('I', key); ms.setContext(actor); actor[key] = ms.run.bind(ms, obj[key]); @@ -156,7 +156,7 @@ function recordStep(step, args) { event.emit(event.step.finished, step); }); - recorder.catchWithoutStop((err) => { + recorder.catchWithoutStop(err => { step.status = 'failed'; step.endTime = Date.now(); event.emit(event.step.failed, step); diff --git a/lib/cli.js b/lib/cli.js index ee27be0a8..a408fe1c1 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -35,11 +35,11 @@ class Cli extends Base { console.log(); }); - runner.on('suite', (suite) => { + runner.on('suite', suite => { output.suite.started(suite); }); - runner.on('fail', (test) => { + runner.on('fail', test => { if (test.ctx.currentTest) { this.loadedTests.push(test.ctx.currentTest.uid); } @@ -50,7 +50,7 @@ class Cli extends Base { output.test.failed(test); }); - runner.on('pending', (test) => { + runner.on('pending', test => { if (test.parent && test.parent.pending) { const suite = test.parent; const skipInfo = suite.opts.skipInfo || {}; @@ -63,7 +63,7 @@ class Cli extends Base { output.test.skipped(test); }); - runner.on('pass', (test) => { + runner.on('pass', test => { if (showSteps && test.steps) { return output.scenario.passed(test); } @@ -72,7 +72,7 @@ class Cli extends Base { }); if (showSteps) { - runner.on('test', (test) => { + runner.on('test', test => { currentMetaStep = []; if (test.steps) { output.test.started(test); @@ -82,12 +82,12 @@ class Cli extends Base { if (!codeceptjsEventDispatchersRegistered) { codeceptjsEventDispatchersRegistered = true; - event.dispatcher.on(event.bddStep.started, (step) => { + event.dispatcher.on(event.bddStep.started, step => { output.stepShift = 2; output.step(step); }); - event.dispatcher.on(event.step.started, (step) => { + event.dispatcher.on(event.step.started, step => { let processingStep = step; const metaSteps = []; while (processingStep.metaStep) { @@ -118,7 +118,7 @@ class Cli extends Base { } } - runner.on('suite end', (suite) => { + runner.on('suite end', suite => { let skippedCount = 0; const grep = runner._grep; for (const test of suite.tests) { @@ -159,7 +159,7 @@ class Cli extends Base { // failures if (stats.failures) { // append step traces - this.failures.map((test) => { + this.failures.map(test => { const err = test.err; let log = ''; @@ -172,7 +172,7 @@ class Cli extends Base { if (steps && steps.length) { let scenarioTrace = ''; - steps.reverse().forEach((step) => { + steps.reverse().forEach(step => { const line = `- ${step.toCode()} ${step.line()}`; // if (step.status === 'failed') line = '' + line; scenarioTrace += `\n${line}`; @@ -218,7 +218,7 @@ class Cli extends Base { console.log(); } - this.failures.forEach((failure) => { + this.failures.forEach(failure => { if (failure.constructor.name === 'Hook') { stats.failedHooks += 1; } diff --git a/lib/codecept.js b/lib/codecept.js index 6f5402cce..1367f5e48 100644 --- a/lib/codecept.js +++ b/lib/codecept.js @@ -35,7 +35,7 @@ class Codecept { */ requireModules(requiringModules) { if (requiringModules) { - requiringModules.forEach((requiredModule) => { + requiringModules.forEach(requiredModule => { const isLocalFile = existsSync(requiredModule) || existsSync(`${requiredModule}.js`); if (isLocalFile) { requiredModule = resolve(requiredModule); @@ -76,7 +76,7 @@ class Codecept { global.within = require('./within'); global.session = require('./session'); global.DataTable = require('./data/table'); - global.locate = (locator) => require('./locator').build(locator); + global.locate = locator => require('./locator').build(locator); global.inject = container.support; global.share = container.share; global.secret = require('./secret').secret; @@ -112,7 +112,7 @@ class Codecept { runHook(require('./listener/exit')); // custom hooks (previous iteration of plugins) - this.config.hooks.forEach((hook) => runHook(hook)); + this.config.hooks.forEach(hook => runHook(hook)); } /** @@ -156,7 +156,7 @@ class Codecept { if (this.config.gherkin.features && !this.opts.tests) { if (Array.isArray(this.config.gherkin.features)) { - this.config.gherkin.features.forEach((feature) => { + this.config.gherkin.features.forEach(feature => { patterns.push(feature); }); } else { @@ -166,7 +166,7 @@ class Codecept { } for (pattern of patterns) { - glob.sync(pattern, options).forEach((file) => { + glob.sync(pattern, options).forEach(file => { if (file.includes('node_modules')) return; if (!fsPath.isAbsolute(file)) { file = fsPath.join(global.codecept_dir, file); @@ -194,7 +194,7 @@ class Codecept { if (!fsPath.isAbsolute(test)) { test = fsPath.join(global.codecept_dir, test); } - mocha.files = mocha.files.filter((t) => fsPath.basename(t, '.js') === test || t === test); + mocha.files = mocha.files.filter(t => fsPath.basename(t, '.js') === test || t === test); } const done = () => { event.emit(event.all.result, this); diff --git a/lib/command/gherkin/snippets.js b/lib/command/gherkin/snippets.js index f36e4fd26..e34a62e96 100644 --- a/lib/command/gherkin/snippets.js +++ b/lib/command/gherkin/snippets.js @@ -43,7 +43,7 @@ module.exports = function (genPath, options) { } const files = []; - glob.sync(options.feature || config.gherkin.features, { cwd: options.feature ? '.' : global.codecept_dir }).forEach((file) => { + glob.sync(options.feature || config.gherkin.features, { cwd: options.feature ? '.' : global.codecept_dir }).forEach(file => { if (!fsPath.isAbsolute(file)) { file = fsPath.join(global.codecept_dir, file); } @@ -53,7 +53,7 @@ module.exports = function (genPath, options) { const newSteps = new Map(); - const parseSteps = (steps) => { + const parseSteps = steps => { const newSteps = []; let currentKeyword = ''; for (const step of steps) { @@ -86,19 +86,19 @@ module.exports = function (genPath, options) { return newSteps; }; - const parseFile = (file) => { + const parseFile = file => { const ast = parser.parse(fs.readFileSync(file).toString()); for (const child of ast.feature.children) { if (child.scenario.keyword === 'Scenario Outline') continue; // skip scenario outline parseSteps(child.scenario.steps) - .map((step) => { + .map(step => { return Object.assign(step, { file: file.replace(global.codecept_dir, '').slice(1) }); }) - .map((step) => newSteps.set(`${step.type}(${step})`, step)); + .map(step => newSteps.set(`${step.type}(${step})`, step)); } }; - files.forEach((file) => parseFile(file)); + files.forEach(file => parseFile(file)); let stepFile = options.path || config.gherkin.steps[0]; if (!fs.existsSync(stepFile)) { @@ -112,7 +112,7 @@ module.exports = function (genPath, options) { const snippets = [...newSteps.values()] .filter((value, index, self) => self.indexOf(value) === index) - .map((step) => { + .map(step => { return ` ${step.type}(${step.regexp ? '/^' : "'"}${step}${step.regexp ? '$/' : "'"}, () => { // From "${step.file}" ${JSON.stringify(step.location)} diff --git a/lib/command/workers/runTests.js b/lib/command/workers/runTests.js index 1bdd58d0f..9331007d2 100644 --- a/lib/command/workers/runTests.js +++ b/lib/command/workers/runTests.js @@ -24,7 +24,7 @@ const { options, tests, testRoot, workerIndex } = workerData; // hide worker output if (!options.debug && !options.verbose) - process.stdout.write = (string) => { + process.stdout.write = string => { stdout += string; return true; }; @@ -70,7 +70,7 @@ function filterTests() { mocha.loadFiles(); for (const suite of mocha.suite.suites) { - suite.tests = suite.tests.filter((test) => tests.indexOf(test.uid) >= 0); + suite.tests = suite.tests.filter(test => tests.indexOf(test.uid) >= 0); } } @@ -111,7 +111,7 @@ function initializeListeners() { } if (test.opts) { - Object.keys(test.opts).forEach((k) => { + Object.keys(test.opts).forEach(k => { if (typeof test.opts[k] === 'object') delete test.opts[k]; if (typeof test.opts[k] === 'function') delete test.opts[k]; }); @@ -192,7 +192,7 @@ function initializeListeners() { } if (step.opts) { - Object.keys(step.opts).forEach((k) => { + Object.keys(step.opts).forEach(k => { if (typeof step.opts[k] === 'object') delete step.opts[k]; if (typeof step.opts[k] === 'function') delete step.opts[k]; }); @@ -212,31 +212,31 @@ function initializeListeners() { collectStats(); // suite - event.dispatcher.on(event.suite.before, (suite) => sendToParentThread({ event: event.suite.before, workerIndex, data: simplifyTest(suite) })); - event.dispatcher.on(event.suite.after, (suite) => sendToParentThread({ event: event.suite.after, workerIndex, data: simplifyTest(suite) })); + event.dispatcher.on(event.suite.before, suite => sendToParentThread({ event: event.suite.before, workerIndex, data: simplifyTest(suite) })); + event.dispatcher.on(event.suite.after, suite => sendToParentThread({ event: event.suite.after, workerIndex, data: simplifyTest(suite) })); // calculate duration - event.dispatcher.on(event.test.started, (test) => (test.start = new Date())); + event.dispatcher.on(event.test.started, test => (test.start = new Date())); // tests - event.dispatcher.on(event.test.before, (test) => sendToParentThread({ event: event.test.before, workerIndex, data: simplifyTest(test) })); - event.dispatcher.on(event.test.after, (test) => sendToParentThread({ event: event.test.after, workerIndex, data: simplifyTest(test) })); + event.dispatcher.on(event.test.before, test => sendToParentThread({ event: event.test.before, workerIndex, data: simplifyTest(test) })); + event.dispatcher.on(event.test.after, test => sendToParentThread({ event: event.test.after, workerIndex, data: simplifyTest(test) })); // we should force-send correct errors to prevent race condition event.dispatcher.on(event.test.finished, (test, err) => sendToParentThread({ event: event.test.finished, workerIndex, data: simplifyTest(test, err) })); event.dispatcher.on(event.test.failed, (test, err) => sendToParentThread({ event: event.test.failed, workerIndex, data: simplifyTest(test, err) })); event.dispatcher.on(event.test.passed, (test, err) => sendToParentThread({ event: event.test.passed, workerIndex, data: simplifyTest(test, err) })); - event.dispatcher.on(event.test.started, (test) => sendToParentThread({ event: event.test.started, workerIndex, data: simplifyTest(test) })); - event.dispatcher.on(event.test.skipped, (test) => sendToParentThread({ event: event.test.skipped, workerIndex, data: simplifyTest(test) })); + event.dispatcher.on(event.test.started, test => sendToParentThread({ event: event.test.started, workerIndex, data: simplifyTest(test) })); + event.dispatcher.on(event.test.skipped, test => sendToParentThread({ event: event.test.skipped, workerIndex, data: simplifyTest(test) })); // steps - event.dispatcher.on(event.step.finished, (step) => sendToParentThread({ event: event.step.finished, workerIndex, data: simplifyStep(step) })); - event.dispatcher.on(event.step.started, (step) => sendToParentThread({ event: event.step.started, workerIndex, data: simplifyStep(step) })); - event.dispatcher.on(event.step.passed, (step) => sendToParentThread({ event: event.step.passed, workerIndex, data: simplifyStep(step) })); - event.dispatcher.on(event.step.failed, (step) => sendToParentThread({ event: event.step.failed, workerIndex, data: simplifyStep(step) })); + event.dispatcher.on(event.step.finished, step => sendToParentThread({ event: event.step.finished, workerIndex, data: simplifyStep(step) })); + event.dispatcher.on(event.step.started, step => sendToParentThread({ event: event.step.started, workerIndex, data: simplifyStep(step) })); + event.dispatcher.on(event.step.passed, step => sendToParentThread({ event: event.step.passed, workerIndex, data: simplifyStep(step) })); + event.dispatcher.on(event.step.failed, step => sendToParentThread({ event: event.step.failed, workerIndex, data: simplifyStep(step) })); event.dispatcher.on(event.hook.failed, (test, err) => sendToParentThread({ event: event.hook.failed, workerIndex, data: simplifyTest(test, err) })); event.dispatcher.on(event.hook.passed, (test, err) => sendToParentThread({ event: event.hook.passed, workerIndex, data: simplifyTest(test, err) })); - event.dispatcher.on(event.all.failures, (data) => sendToParentThread({ event: event.all.failures, workerIndex, data })); + event.dispatcher.on(event.all.failures, data => sendToParentThread({ event: event.all.failures, workerIndex, data })); // all event.dispatcher.once(event.all.result, () => parentPort.close()); @@ -260,7 +260,7 @@ function collectStats() { event.dispatcher.on(event.test.passed, () => { stats.passes++; }); - event.dispatcher.on(event.test.failed, (test) => { + event.dispatcher.on(event.test.failed, test => { if (test.ctx._runnable.title.includes('hook: AfterSuite')) { stats.failedHooks += 1; } @@ -282,7 +282,7 @@ function sendToParentThread(data) { } function listenToParentThread() { - parentPort.on('message', (eventData) => { + parentPort.on('message', eventData => { container.append({ support: eventData.data }); }); } diff --git a/lib/container.js b/lib/container.js index 9e9d9333d..6795fd4d0 100644 --- a/lib/container.js +++ b/lib/container.js @@ -200,7 +200,7 @@ function createHelpers(config) { asyncHelperPromise = asyncHelperPromise .then(() => HelperClass()) - .then((ResolvedHelperClass) => { + .then(ResolvedHelperClass => { // Check if ResolvedHelperClass is a constructor function if (typeof ResolvedHelperClass?.constructor !== 'function') { throw new Error(`Helper class from module '${helperName}' is not a class. Use CJS async module syntax.`); @@ -267,7 +267,7 @@ function requireHelperFromModule(helperName, config, HelperClass) { function createSupportObjects(config) { const asyncWrapper = function (f) { return function () { - return f.apply(this, arguments).catch((e) => { + return f.apply(this, arguments).catch(e => { recorder.saveFirstAsyncError(e); throw e; }); @@ -415,9 +415,9 @@ function createPlugins(config, options = {}) { } function loadGherkinSteps(paths) { - global.Before = (fn) => event.dispatcher.on(event.test.started, fn); - global.After = (fn) => event.dispatcher.on(event.test.finished, fn); - global.Fail = (fn) => event.dispatcher.on(event.test.failed, fn); + global.Before = fn => event.dispatcher.on(event.test.started, fn); + global.After = fn => event.dispatcher.on(event.test.finished, fn); + global.Fail = fn => event.dispatcher.on(event.test.failed, fn); // If gherkin.steps is string, then this will iterate through that folder and send all step def js files to loadSupportObject // If gherkin.steps is Array, it will go the old way @@ -429,7 +429,7 @@ function loadGherkinSteps(paths) { } else { const folderPath = paths.startsWith('.') ? path.join(global.codecept_dir, paths) : ''; if (folderPath !== '') { - glob.sync(folderPath).forEach((file) => { + glob.sync(folderPath).forEach(file => { loadSupportObject(file, `Step Definition from ${file}`); }); } @@ -498,7 +498,7 @@ function loadTranslation(locale, vocabularies) { translation = Translation.createDefault(); } - vocabularies.forEach((v) => translation.loadVocabulary(v)); + vocabularies.forEach(v => translation.loadVocabulary(v)); return translation; } diff --git a/lib/heal.js b/lib/heal.js index 4e417f175..7c21a47f8 100644 --- a/lib/heal.js +++ b/lib/heal.js @@ -34,11 +34,11 @@ class Heal { } connectToEvents() { - event.dispatcher.on(event.suite.before, (suite) => { + event.dispatcher.on(event.suite.before, suite => { this.contextName = suite.title; }); - event.dispatcher.on(event.test.started, (test) => { + event.dispatcher.on(event.test.started, test => { this.contextName = test.fullTitle(); }); @@ -48,7 +48,7 @@ class Heal { } hasCorrespondingRecipes(step) { - return matchRecipes(this.recipes, this.contextName).filter((r) => !r.steps || r.steps.includes(step.name)).length > 0; + return matchRecipes(this.recipes, this.contextName).filter(r => !r.steps || r.steps.includes(step.name)).length > 0; } async getCodeSuggestions(context) { @@ -62,8 +62,8 @@ class Heal { for (const [property, prepareFn] of Object.entries( recipes - .map((r) => r.prepare) - .filter((p) => !!p) + .map(r => r.prepare) + .filter(p => !!p) .reduce((acc, obj) => ({ ...acc, ...obj }), {}), )) { if (!prepareFn) continue; @@ -84,7 +84,7 @@ class Heal { }); } - return suggestions.filter((s) => !isBlank(s.snippets)); + return suggestions.filter(s => !isBlank(s.snippets)); } async healStep(failedStep, error, failureContext = {}) { @@ -111,7 +111,7 @@ class Heal { for (const codeSnippet of suggestion.snippets) { try { debug('Executing', codeSnippet); - recorder.catch((e) => { + recorder.catch(e => { debug(e); }); @@ -162,7 +162,7 @@ function matchRecipes(recipes, contextName) { recipe.name = name; return recipe; }) - .filter((r) => !!r.fn); + .filter(r => !!r.fn); } function isBlank(value) { diff --git a/lib/helper/JSONResponse.js b/lib/helper/JSONResponse.js index 057d03c4c..2e3adcc06 100644 --- a/lib/helper/JSONResponse.js +++ b/lib/helper/JSONResponse.js @@ -73,7 +73,7 @@ class JSONResponse extends Helper { throw new Error(`Error setting JSONResponse, helper ${this.options.requestHelper} is not enabled in config, helpers: ${Object.keys(this.helpers)}`); } // connect to REST helper - this.helpers[this.options.requestHelper].config.onResponse = (response) => { + this.helpers[this.options.requestHelper].config.onResponse = response => { this.response = response; }; } diff --git a/lib/helper/testcafe/testcafe-utils.js b/lib/helper/testcafe/testcafe-utils.js index af13c3a04..b5a772c8f 100644 --- a/lib/helper/testcafe/testcafe-utils.js +++ b/lib/helper/testcafe/testcafe-utils.js @@ -23,7 +23,7 @@ const createTestFile = () => { }; // TODO Better error mapping (actual, expected) -const mapError = (testcafeError) => { +const mapError = testcafeError => { // console.log('TODO map error better', JSON.stringify(testcafeError, null, 2)); if (testcafeError.errMsg) { throw new Error(testcafeError.errMsg); diff --git a/lib/output.js b/lib/output.js index 3d91c68aa..70e9909ab 100644 --- a/lib/output.js +++ b/lib/output.js @@ -132,7 +132,7 @@ module.exports = { /** * @param {Mocha.Suite} suite */ - started: (suite) => { + started: suite => { if (!suite.title) return; print(`${colors.bold(suite.title)} --`); if (suite.comment) print(suite.comment); diff --git a/lib/pause.js b/lib/pause.js index c10be9d0f..7f5830480 100644 --- a/lib/pause.js +++ b/lib/pause.js @@ -70,7 +70,7 @@ function pauseSession(passedObject = {}) { rl.on('close', () => { if (!next) console.log('Exiting interactive shell....'); }); - return new Promise((resolve) => { + return new Promise(resolve => { finish = resolve; // eslint-disable-next-line return askForStep(); @@ -145,7 +145,7 @@ async function parseInput(cmd) { if (!cmd) return; return eval(cmd); }) - .catch((err) => { + .catch(err => { debug(err); if (isAiCommand) return; if (!lastError) output.print(output.styles.error(' ERROR '), err.message); @@ -173,7 +173,7 @@ async function parseInput(cmd) { if (!lastError) output.print(output.styles.error(' ERROR '), err.message); lastError = err.message; } - recorder.session.catch((err) => { + recorder.session.catch(err => { const msg = err.cliMessage ? err.cliMessage() : err.message; // pop latest command from history because it failed @@ -189,7 +189,7 @@ async function parseInput(cmd) { /* eslint-enable */ function askForStep() { - return new Promise((resolve) => { + return new Promise(resolve => { nextStep = resolve; rl.setPrompt(' I.', 3); rl.resume(); @@ -200,7 +200,7 @@ function askForStep() { function completer(line) { const I = container.support('I'); const completions = methodsOfObject(I); - const hits = completions.filter((c) => { + const hits = completions.filter(c => { if (c.indexOf(line) === 0) { return c; } diff --git a/lib/scenario.js b/lib/scenario.js index 784090422..1d9c77bc9 100644 --- a/lib/scenario.js +++ b/lib/scenario.js @@ -11,7 +11,7 @@ const injectHook = function (inject, suite) { } catch (err) { recorder.throw(err); } - recorder.catch((err) => { + recorder.catch(err => { event.emit(event.test.failed, suite, err); throw err; }); @@ -33,7 +33,7 @@ function makeDoneCallableOnce(done) { * starts promise chain with recorder, performs before/after hooks * through event system. */ -module.exports.test = (test) => { +module.exports.test = test => { const testFn = test.fn; if (!testFn) { return test; @@ -45,7 +45,7 @@ module.exports.test = (test) => { test.fn = function (done) { const doneFn = makeDoneCallableOnce(done); - recorder.errHandler((err) => { + recorder.errHandler(err => { recorder.session.start('teardown'); recorder.cleanAsyncErr(); if (test.throws) { @@ -76,7 +76,7 @@ module.exports.test = (test) => { }); recorder.add('finish test', doneFn); }) - .catch((err) => { + .catch(err => { recorder.throw(err); }) .finally(() => { @@ -108,7 +108,7 @@ module.exports.test = (test) => { module.exports.injected = function (fn, suite, hookName) { return function (done) { const doneFn = makeDoneCallableOnce(done); - const errHandler = (err) => { + const errHandler = err => { recorder.session.start('teardown'); recorder.cleanAsyncErr(); event.emit(event.test.failed, suite, err); @@ -117,7 +117,7 @@ module.exports.injected = function (fn, suite, hookName) { recorder.add(() => doneFn(err)); }; - recorder.errHandler((err) => { + recorder.errHandler(err => { errHandler(err); }); @@ -128,7 +128,7 @@ module.exports.injected = function (fn, suite, hookName) { this.test.body = fn.toString(); if (!recorder.isRunning()) { - recorder.errHandler((err) => { + recorder.errHandler(err => { errHandler(err); }); } @@ -141,7 +141,7 @@ module.exports.injected = function (fn, suite, hookName) { try { recorder.startUnlessRunning(); await fn.call(this, getInjectedArguments(fn)); - await recorder.promise().catch((err) => retry(err)); + await recorder.promise().catch(err => retry(err)); } catch (err) { retry(err); } finally { @@ -158,9 +158,9 @@ module.exports.injected = function (fn, suite, hookName) { recorder.add(`finish ${hookName} hook`, doneFn); recorder.catch(); }) - .catch((e) => { + .catch(e => { recorder.throw(e); - recorder.catch((e) => { + recorder.catch(e => { const err = recorder.getAsyncErr() === null ? e : recorder.getAsyncErr(); errHandler(err); }); diff --git a/lib/secret.js b/lib/secret.js index 7d8a5fcc0..4c8c15cf8 100644 --- a/lib/secret.js +++ b/lib/secret.js @@ -37,7 +37,7 @@ function secretObject(obj, fieldsToHide = []) { if (prop === 'toString') { return function () { const maskedObject = deepClone(obj); - fieldsToHide.forEach((f) => (maskedObject[f] = maskedString)); + fieldsToHide.forEach(f => (maskedObject[f] = maskedString)); return JSON.stringify(maskedObject); }; } diff --git a/lib/step.js b/lib/step.js index 049adcfc1..33865d71c 100644 --- a/lib/step.js +++ b/lib/step.js @@ -145,7 +145,7 @@ class Step { /** @return {string} */ humanizeArgs() { return this.args - .map((arg) => { + .map(arg => { if (!arg) { return ''; } @@ -275,7 +275,7 @@ class MetaStep extends Step { this.setArguments(Array.from(arguments).slice(1)); let result; - const registerStep = (step) => { + const registerStep = step => { this.metaStep = null; step.metaStep = this; }; @@ -284,10 +284,10 @@ class MetaStep extends Step { if (fn.constructor.name === 'AsyncFunction') { result = fn .apply(this.context, this.args) - .then((result) => { + .then(result => { return result; }) - .catch((error) => { + .catch(error => { this.setStatus('failed'); throw error; }) @@ -333,7 +333,7 @@ function humanizeString(string) { const _result = string .replace(/([a-z](?=[A-Z]))/g, '$1 ') .split(' ') - .map((word) => word.toLowerCase()); + .map(word => word.toLowerCase()); _result[0] = _result[0] === 'i' ? capitalizeFLetter(_result[0]) : _result[0]; return _result.join(' ').trim(); diff --git a/lib/workers.js b/lib/workers.js index 42d288761..2f38e627f 100644 --- a/lib/workers.js +++ b/lib/workers.js @@ -32,7 +32,7 @@ const initializeCodecept = (configPath, options = {}) => { return codecept; }; -const createOutputDir = (configPath) => { +const createOutputDir = configPath => { const config = mainConfig.load(configPath || '.'); const testRoot = getTestRoot(configPath); const outputDir = path.isAbsolute(config.output) ? config.output : path.join(testRoot, config.output); @@ -43,7 +43,7 @@ const createOutputDir = (configPath) => { } }; -const populateGroups = (numberOfWorkers) => { +const populateGroups = numberOfWorkers => { const groups = []; for (let i = 0; i < numberOfWorkers; i++) { groups[i] = []; @@ -52,7 +52,7 @@ const populateGroups = (numberOfWorkers) => { return groups; }; -const createWorker = (workerObject) => { +const createWorker = workerObject => { const worker = new Worker(pathToWorker, { workerData: { options: simplifyObject(workerObject.options), @@ -61,24 +61,24 @@ const createWorker = (workerObject) => { workerIndex: workerObject.workerIndex + 1, }, }); - worker.on('error', (err) => output.error(`Worker Error: ${err.stack}`)); + worker.on('error', err => output.error(`Worker Error: ${err.stack}`)); WorkerStorage.addWorker(worker); return worker; }; -const simplifyObject = (object) => { +const simplifyObject = object => { return Object.keys(object) - .filter((k) => k.indexOf('_') !== 0) - .filter((k) => typeof object[k] !== 'function') - .filter((k) => typeof object[k] !== 'object') + .filter(k => k.indexOf('_') !== 0) + .filter(k => typeof object[k] !== 'function') + .filter(k => typeof object[k] !== 'object') .reduce((obj, key) => { obj[key] = object[key]; return obj; }, {}); }; -const repackTest = (test) => { +const repackTest = test => { test = Object.assign(new Test(test.title || '', () => {}), test); test.parent = Object.assign(new Suite(test.parent.title), test.parent); return test; @@ -107,7 +107,7 @@ const createWorkerObjects = (testGroups, config, testRoot, options, selectedRuns currentMochaJunitReporterFile = config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile; } - collection.createRuns(selectedRuns, config).forEach((worker) => { + collection.createRuns(selectedRuns, config).forEach(worker => { const separator = path.sep; const _config = { ...config }; let workerName = worker.name.replace(':', '_'); @@ -117,7 +117,7 @@ const createWorkerObjects = (testGroups, config, testRoot, options, selectedRuns const _tempArray = currentMochaJunitReporterFile.split(separator); _tempArray.splice( - _tempArray.findIndex((item) => item.includes('.xml')), + _tempArray.findIndex(item => item.includes('.xml')), 0, workerName, ); @@ -129,9 +129,9 @@ const createWorkerObjects = (testGroups, config, testRoot, options, selectedRuns }); const workers = []; let index = 0; - testGroups.forEach((tests) => { + testGroups.forEach(tests => { const testWorkerArray = []; - workersToExecute.forEach((finalConfig) => { + workersToExecute.forEach(finalConfig => { const workerObj = new WorkerObject(index++); workerObj.addConfig(finalConfig); workerObj.addTests(tests); @@ -144,7 +144,7 @@ const createWorkerObjects = (testGroups, config, testRoot, options, selectedRuns return workers; }; -const indexOfSmallestElement = (groups) => { +const indexOfSmallestElement = groups => { let i = 0; for (let j = 1; j < groups.length; j++) { if (groups[j - 1].length > groups[j].length) { @@ -154,13 +154,13 @@ const indexOfSmallestElement = (groups) => { return i; }; -const convertToMochaTests = (testGroup) => { +const convertToMochaTests = testGroup => { const group = []; if (testGroup instanceof Array) { const mocha = MochaFactory.create({}, {}); mocha.files = testGroup; mocha.loadFiles(); - mocha.suite.eachTest((test) => { + mocha.suite.eachTest(test => { group.push(test.uid); }); mocha.unloadFiles(); @@ -314,7 +314,7 @@ class Workers extends EventEmitter { const groups = populateGroups(numberOfWorkers); let groupCounter = 0; - mocha.suite.eachTest((test) => { + mocha.suite.eachTest(test => { const i = groupCounter % groups.length; if (test) { groups[i].push(test.uid); @@ -334,9 +334,9 @@ class Workers extends EventEmitter { const mocha = Container.mocha(); mocha.files = files; mocha.loadFiles(); - mocha.suite.suites.forEach((suite) => { + mocha.suite.suites.forEach(suite => { const i = indexOfSmallestElement(groups); - suite.tests.forEach((test) => { + suite.tests.forEach(test => { if (test) { groups[i].push(test.uid); } @@ -374,7 +374,7 @@ class Workers extends EventEmitter { this._listenWorkerEvents(workerThread); } }); - return new Promise((resolve) => { + return new Promise(resolve => { this.on('end', resolve); }); } @@ -394,7 +394,7 @@ class Workers extends EventEmitter { } _listenWorkerEvents(worker) { - worker.on('message', (message) => { + worker.on('message', message => { output.process(message.workerIndex); // deal with events that are not test cycle related @@ -450,7 +450,7 @@ class Workers extends EventEmitter { } }); - worker.on('error', (err) => { + worker.on('error', err => { this.errors.push(err); }); @@ -491,14 +491,14 @@ class Workers extends EventEmitter { output.print(); this.failuresLog = this.failuresLog - .filter((log) => log.length && typeof log[1] === 'number') + .filter(log => log.length && typeof log[1] === 'number') // mocha/lib/reporters/base.js .map(([format, num, title, message, stack], i) => [format, i + 1, title, message, stack]); if (this.failuresLog.length) { output.print(); output.print('-- FAILURES:'); - this.failuresLog.forEach((log) => output.print(...log)); + this.failuresLog.forEach(log => output.print(...log)); } output.result(this.stats.passes, this.stats.failures, this.stats.pending, ms(this.stats.duration), this.stats.failedHooks); diff --git a/prettier.config.js b/prettier.config.js index 9dda9a729..8ee9c0ef3 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -6,4 +6,5 @@ module.exports = { singleQuote: true, trailingComma: 'all', bracketSameLine: false, + arrowParens: 'avoid', }; diff --git a/test/acceptance/codecept.WebDriver.js b/test/acceptance/codecept.WebDriver.js index 02b59e770..e0ed73291 100644 --- a/test/acceptance/codecept.WebDriver.js +++ b/test/acceptance/codecept.WebDriver.js @@ -27,7 +27,7 @@ module.exports.config = { }, include: {}, bootstrap: async () => - new Promise((done) => { + new Promise(done => { setTimeout(done, 5000); }), // let's wait for selenium mocha: {}, diff --git a/test/data/inject-fail-example/pages/page.js b/test/data/inject-fail-example/pages/page.js index cf0120459..16b6c3b3f 100644 --- a/test/data/inject-fail-example/pages/page.js +++ b/test/data/inject-fail-example/pages/page.js @@ -1,14 +1,14 @@ const { notpage, arraypage } = inject(); module.exports = { - type: (s) => { + type: s => { console.log('type => ', s); console.log('strategy', arraypage.toString()); notpage.domainIds.push('newdomain'); return notpage.domainIds; }, - purgeDomains: (s) => { + purgeDomains: s => { console.log('purgeDomains'); console.log(s); }, diff --git a/test/data/sandbox/codecept.customworker.js b/test/data/sandbox/codecept.customworker.js index fc549d504..fe4a19ae0 100644 --- a/test/data/sandbox/codecept.customworker.js +++ b/test/data/sandbox/codecept.customworker.js @@ -14,7 +14,7 @@ exports.config = { include: {}, bootstrap: async () => { process.stdout.write('bootstrap b1+'); - return new Promise((done) => { + return new Promise(done => { setTimeout(() => { process.stdout.write('b2'); done(); diff --git a/test/data/sandbox/features/step_definitions/my_other_steps.js b/test/data/sandbox/features/step_definitions/my_other_steps.js index de9c0b159..ece086667 100644 --- a/test/data/sandbox/features/step_definitions/my_other_steps.js +++ b/test/data/sandbox/features/step_definitions/my_other_steps.js @@ -1,7 +1,7 @@ const I = actor(); const axios = require('axios'); -Given('I have products in my cart', (table) => { +Given('I have products in my cart', table => { for (const id in table.rows) { if (id < 1) { continue; @@ -11,24 +11,24 @@ Given('I have products in my cart', (table) => { } }); -Given(/I have product described as/, (text) => { +Given(/I have product described as/, text => { I.addItem(text.content.length); }); Given(/I have simple product/, async () => { - return new Promise((resolve) => { + return new Promise(resolve => { I.addItem(10); setTimeout(resolve, 0); }); }); -const sendRequest = async (requestConfig) => { +const sendRequest = async requestConfig => { if (!requestConfig) throw JSON.stringify({ error: 'Request config is null or undefined.' }); return axios({ method: requestConfig.method || 'GET', timeout: requestConfig.timeout || 3000, ...requestConfig, - }).catch((error) => { + }).catch(error => { if (error.response) { error = { message: 'The request was made and the server responded with a status code.', diff --git a/test/helper/AppiumV2_test.js b/test/helper/AppiumV2_test.js index 70280f630..d45514395 100644 --- a/test/helper/AppiumV2_test.js +++ b/test/helper/AppiumV2_test.js @@ -597,7 +597,7 @@ describe('Appium', function () { it('should execute only on Android >= 5.0 @quick', () => { app.runOnAndroid( - (caps) => caps.platformVersion >= 5, + caps => caps.platformVersion >= 5, () => {}, ); }); diff --git a/test/helper/Appium_test.js b/test/helper/Appium_test.js index 58dd30799..ded00f764 100644 --- a/test/helper/Appium_test.js +++ b/test/helper/Appium_test.js @@ -601,7 +601,7 @@ describe('Appium', function () { it('should execute only on Android >= 5.0 @quick', () => { app.runOnAndroid( - (caps) => caps.platformVersion >= 5, + caps => caps.platformVersion >= 5, () => {}, ); }); diff --git a/test/helper/Playwright_test.js b/test/helper/Playwright_test.js index 1961e57a0..0af57e234 100644 --- a/test/helper/Playwright_test.js +++ b/test/helper/Playwright_test.js @@ -170,7 +170,7 @@ describe('Playwright', function () { }); it('should pass arguments and wait for function returns true', () => { - return I.amOnPage('/form/wait_js').then(() => I.waitForFunction((varName) => window[varName], ['__waitJs'], 3)); + return I.amOnPage('/form/wait_js').then(() => I.waitForFunction(varName => window[varName], ['__waitJs'], 3)); }); }); @@ -240,7 +240,7 @@ describe('Playwright', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.include('The number of elements (//div[@id = "grab-multiple"]//a) is not 2 after 0.1 sec'); })); @@ -251,7 +251,7 @@ describe('Playwright', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec'); })); @@ -284,19 +284,19 @@ describe('Playwright', function () { I.amOnPage('/') .then(() => I.wait(1)) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 1))); + .then(numPages => assert.equal(numPages, 1))); it('should switch to next tab', () => I.amOnPage('/info') .then(() => I.wait(1)) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 1)) + .then(numPages => assert.equal(numPages, 1)) .then(() => I.click('New tab')) .then(() => I.switchToNextTab()) .then(() => I.wait(2)) .then(() => I.seeCurrentUrlEquals('/login')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 2))); + .then(numPages => assert.equal(numPages, 2))); it('should assert when there is no ability to switch to next tab', () => I.amOnPage('/') @@ -305,7 +305,7 @@ describe('Playwright', function () { .then(() => I.switchToNextTab(2)) .then(() => I.wait(2)) .then(() => assert.equal(true, false, 'Throw an error if it gets this far (which it should not)!')) - .catch((e) => { + .catch(e => { assert.equal(e.message, 'There is no ability to switch to next tab with offset 2'); })); @@ -316,12 +316,12 @@ describe('Playwright', function () { .then(() => I.wait(2)) .then(() => I.seeInCurrentUrl('/login')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 2)) + .then(numPages => assert.equal(numPages, 2)) .then(() => I.closeCurrentTab()) .then(() => I.wait(1)) .then(() => I.seeInCurrentUrl('/info')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 1))); + .then(numPages => assert.equal(numPages, 1))); it('should close other tabs', () => I.amOnPage('/') @@ -335,7 +335,7 @@ describe('Playwright', function () { .then(() => I.waitForNumberOfTabs(1)) .then(() => I.seeInCurrentUrl('/login')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 1))); + .then(numPages => assert.equal(numPages, 1))); it('should open new tab', () => I.amOnPage('/info') @@ -343,7 +343,7 @@ describe('Playwright', function () { .then(() => I.wait(1)) .then(() => I.seeInCurrentUrl('about:blank')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 2))); + .then(numPages => assert.equal(numPages, 2))); it('should switch to previous tab', () => I.amOnPage('/info') @@ -362,7 +362,7 @@ describe('Playwright', function () { .then(() => I.switchToPreviousTab(2)) .then(() => I.wait(2)) .then(() => I.waitInUrl('/info')) - .catch((e) => { + .catch(e => { assert.equal(e.message, 'There is no ability to switch to previous tab with offset 2'); })); }); @@ -400,12 +400,12 @@ describe('Playwright', function () { .then(() => I.amCancellingPopups()) .then(() => I.click('Alert')) .then(() => I.grabPopupText()) - .then((text) => assert.equal(text, 'Really?'))); + .then(text => assert.equal(text, 'Really?'))); it('should return null if no popup is visible (do not throw an error)', () => I.amOnPage('/form/popup') .then(() => I.grabPopupText()) - .then((text) => assert.equal(text, null))); + .then(text => assert.equal(text, null))); }); describe('#seeNumberOfElements', () => { @@ -423,7 +423,7 @@ describe('Playwright', function () { it('should return error if iframe selector is invalid', () => I.amOnPage('/iframe') .then(() => I.switchTo('#invalidIframeSelector')) - .catch((e) => { + .catch(e => { e.should.be.instanceOf(Error); e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath'); })); @@ -431,7 +431,7 @@ describe('Playwright', function () { it('should return error if iframe selector is not iframe', () => I.amOnPage('/iframe') .then(() => I.switchTo('h1')) - .catch((e) => { + .catch(e => { e.should.be.instanceOf(Error); e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath'); })); @@ -468,7 +468,7 @@ describe('Playwright', function () { it('should grab the source', () => I.amOnPage('/') .then(() => I.grabSource()) - .then((source) => assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved'))); + .then(source => assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved'))); }); describe('#seeTitleEquals', () => { @@ -477,7 +477,7 @@ describe('Playwright', function () { .then(() => I.seeTitleEquals('TestEd Beta 2.0')) .then(() => I.seeTitleEquals('TestEd Beta 2.')) .then(() => assert.equal(true, false, 'Throw an error because it should not get this far!')) - .catch((e) => { + .catch(e => { e.should.be.instanceOf(Error); e.message.should.be.equal('expected web page title "TestEd Beta 2.0" to equal "TestEd Beta 2."'); })); @@ -489,7 +489,7 @@ describe('Playwright', function () { .then(() => I.seeTextEquals('Welcome to test app!', 'h1')) .then(() => I.seeTextEquals('Welcome to test app', 'h1')) .then(() => assert.equal(true, false, 'Throw an error because it should not get this far!')) - .catch((e) => { + .catch(e => { e.should.be.instanceOf(Error); e.message.should.be.equal('expected element h1 "Welcome to test app" to equal "Welcome to test app!"'); })); @@ -508,40 +508,40 @@ describe('Playwright', function () { it('should locate a button to click', () => I.amOnPage('/form/checkbox') .then(() => I._locateClickable('Submit')) - .then((res) => { + .then(res => { res.length.should.be.equal(1); })); it('should not locate a non-existing checkbox using _locateClickable', () => I.amOnPage('/form/checkbox') .then(() => I._locateClickable('I disagree')) - .then((res) => res.length.should.be.equal(0))); + .then(res => res.length.should.be.equal(0))); }); describe('#_locateCheckable', () => { it('should locate a checkbox', () => I.amOnPage('/form/checkbox') .then(() => I._locateCheckable('I Agree')) - .then((res) => res.should.be.not.undefined)); + .then(res => res.should.be.not.undefined)); }); describe('#_locateFields', () => { it('should locate a field', () => I.amOnPage('/form/field') .then(() => I._locateFields('Name')) - .then((res) => res.length.should.be.equal(1))); + .then(res => res.length.should.be.equal(1))); it('should not locate a non-existing field', () => I.amOnPage('/form/field') .then(() => I._locateFields('Mother-in-law')) - .then((res) => res.length.should.be.equal(0))); + .then(res => res.length.should.be.equal(0))); }); describe('check fields: #seeInField, #seeCheckboxIsChecked, ...', () => { it('should throw error if field is not empty', () => I.amOnPage('/form/empty') .then(() => I.seeInField('#empty_input', 'Ayayay')) - .catch((e) => { + .catch(e => { e.should.be.instanceOf(AssertionFailedError); e.inspect().should.be.equal('expected fields by #empty_input to include "Ayayay"'); })); @@ -749,7 +749,7 @@ describe('Playwright', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec'); })); @@ -782,23 +782,23 @@ describe('Playwright', function () { it('should grab inner html from an element using xpath query', () => I.amOnPage('/') .then(() => I.grabHTMLFrom('//title')) - .then((html) => assert.equal(html, 'TestEd Beta 2.0'))); + .then(html => assert.equal(html, 'TestEd Beta 2.0'))); it('should grab inner html from an element using id query', () => I.amOnPage('/') .then(() => I.grabHTMLFrom('#area1')) - .then((html) => assert.equal(html.trim(), ' Test Link '))); + .then(html => assert.equal(html.trim(), ' Test Link '))); it('should grab inner html from multiple elements', () => I.amOnPage('/') .then(() => I.grabHTMLFromAll('//a')) - .then((html) => assert.equal(html.length, 5))); + .then(html => assert.equal(html.length, 5))); it('should grab inner html from within an iframe', () => I.amOnPage('/iframe') .then(() => I.switchTo({ frame: 'iframe' })) .then(() => I.grabHTMLFrom('#new-tab')) - .then((html) => assert.equal(html.trim(), 'New tab'))); + .then(html => assert.equal(html.trim(), 'New tab'))); }); describe('#grabBrowserLogs', () => { @@ -810,8 +810,8 @@ describe('Playwright', function () { }), ) .then(() => I.grabBrowserLogs()) - .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1); + .then(logs => { + const matchingLogs = logs.filter(log => log.text().indexOf('Test log entry') > -1); assert.equal(matchingLogs.length, 1); })); @@ -824,8 +824,8 @@ describe('Playwright', function () { }), ) .then(() => I.grabBrowserLogs()) - .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1); + .then(logs => { + const matchingLogs = logs.filter(log => log.text().indexOf('Test log entry') > -1); assert.equal(matchingLogs.length, 1); })); @@ -843,8 +843,8 @@ describe('Playwright', function () { }), ) .then(() => I.grabBrowserLogs()) - .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().includes('Test log entry')); + .then(logs => { + const matchingLogs = logs.filter(log => log.text().includes('Test log entry')); assert.equal(matchingLogs.length, 2); })); @@ -858,8 +858,8 @@ describe('Playwright', function () { }), ) .then(() => I.grabBrowserLogs()) - .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1); + .then(logs => { + const matchingLogs = logs.filter(log => log.text().indexOf('Test log entry') > -1); assert.equal(matchingLogs.length, 1); })); }); @@ -952,7 +952,7 @@ describe('Playwright', function () { it('should pass expected parameters', async () => { await I.amOnPage('/'); - const params = await I.usePlaywrightTo('test', async (params) => { + const params = await I.usePlaywrightTo('test', async params => { return params; }); expect(params.page).to.exist; @@ -964,7 +964,7 @@ describe('Playwright', function () { describe('#mockRoute, #stopMockingRoute', () => { it('should mock a route', async () => { await I.amOnPage('/form/fetch_call'); - await I.mockRoute('https://reqres.in/api/comments/1', (route) => { + await I.mockRoute('https://reqres.in/api/comments/1', route => { route.fulfill({ status: 200, headers: { 'Access-Control-Allow-Origin': '*' }, @@ -995,7 +995,7 @@ describe('Playwright', function () { it('should convert to axios response with onResponse hook', async () => { let response; - I.config.onResponse = (resp) => (response = resp); + I.config.onResponse = resp => (response = resp); await I.makeApiRequest('get', 'https://reqres.in/api/users?page=2'); expect(response).to.be.ok; expect(response.status).to.equal(200); diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js index fc3dc3c4d..9e049b4f8 100644 --- a/test/helper/Puppeteer_test.js +++ b/test/helper/Puppeteer_test.js @@ -117,7 +117,7 @@ describe('Puppeteer', function () { .then(() => { I.options.restart = true; }) - .catch((e) => { + .catch(e => { I.options.restart = true; throw new Error(e); }); @@ -171,7 +171,7 @@ describe('Puppeteer', function () { }); it('should pass arguments and wait for function returns true', () => { - return I.amOnPage('/form/wait_js').then(() => I.waitForFunction((varName) => window[varName], ['__waitJs'], 3)); + return I.amOnPage('/form/wait_js').then(() => I.waitForFunction(varName => window[varName], ['__waitJs'], 3)); }); }); @@ -210,7 +210,7 @@ describe('Puppeteer', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec'); })); @@ -243,19 +243,19 @@ describe('Puppeteer', function () { I.amOnPage('/') .then(() => I.wait(1)) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(1))); + .then(numPages => expect(numPages).to.eq(1))); it('should switch to next tab', () => I.amOnPage('/info') .then(() => I.wait(1)) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(1)) + .then(numPages => expect(numPages).to.eq(1)) .then(() => I.click('New tab')) .then(() => I.switchToNextTab()) .then(() => I.waitForNumberOfTabs(2)) .then(() => I.seeCurrentUrlEquals('/login')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(2))); + .then(numPages => expect(numPages).to.eq(2))); it('should assert when there is no ability to switch to next tab', () => I.amOnPage('/') @@ -264,7 +264,7 @@ describe('Puppeteer', function () { .then(() => I.switchToNextTab(2)) .then(() => I.wait(2)) .then(() => expect(true, 'Throw an error if it gets this far (which it should not)!').to.eq(false)) - .catch((e) => { + .catch(e => { expect(e.message).to.eq('There is no ability to switch to next tab with offset 2'); })); @@ -275,12 +275,12 @@ describe('Puppeteer', function () { .then(() => I.wait(2)) .then(() => I.seeInCurrentUrl('/login')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(2)) + .then(numPages => expect(numPages).to.eq(2)) .then(() => I.closeCurrentTab()) .then(() => I.wait(1)) .then(() => I.seeInCurrentUrl('/info')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(1))); + .then(numPages => expect(numPages).to.eq(1))); it('should close other tabs', () => I.amOnPage('/') @@ -296,7 +296,7 @@ describe('Puppeteer', function () { .then(() => I.wait(1)) .then(() => I.seeInCurrentUrl('/login')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(1))); + .then(numPages => expect(numPages).to.eq(1))); it('should open new tab', () => I.amOnPage('/info') @@ -304,7 +304,7 @@ describe('Puppeteer', function () { .then(() => I.wait(1)) .then(() => I.seeInCurrentUrl('about:blank')) .then(() => I.grabNumberOfOpenTabs()) - .then((numPages) => expect(numPages).to.eq(2))); + .then(numPages => expect(numPages).to.eq(2))); it('should switch to previous tab', () => I.amOnPage('/info') @@ -323,7 +323,7 @@ describe('Puppeteer', function () { .then(() => I.switchToPreviousTab(2)) .then(() => I.wait(2)) .then(() => I.waitInUrl('/info')) - .catch((e) => { + .catch(e => { expect(e.message).to.eq('There is no ability to switch to previous tab with offset 2'); })); }); @@ -361,12 +361,12 @@ describe('Puppeteer', function () { .then(() => I.amCancellingPopups()) .then(() => I.click('Alert')) .then(() => I.grabPopupText()) - .then((text) => assert.equal(text, 'Really?'))); + .then(text => assert.equal(text, 'Really?'))); it('should return null if no popup is visible (do not throw an error)', () => I.amOnPage('/form/popup') .then(() => I.grabPopupText()) - .then((text) => assert.equal(text, null))); + .then(text => assert.equal(text, null))); }); describe('#seeNumberOfElements', () => { @@ -383,7 +383,7 @@ describe('Puppeteer', function () { it('should return error if iframe selector is invalid', () => I.amOnPage('/iframe') .then(() => I.switchTo('#invalidIframeSelector')) - .catch((e) => { + .catch(e => { e.should.be.instanceOf(Error); e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath'); })); @@ -391,7 +391,7 @@ describe('Puppeteer', function () { it('should return error if iframe selector is not iframe', () => I.amOnPage('/iframe') .then(() => I.switchTo('h1')) - .catch((e) => { + .catch(e => { e.should.be.instanceOf(Error); e.message.should.be.equal('Element "#invalidIframeSelector" was not found by text|CSS|XPath'); })); @@ -414,7 +414,7 @@ describe('Puppeteer', function () { it('should grab the source', () => I.amOnPage('/') .then(() => I.grabSource()) - .then((source) => assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved'))); + .then(source => assert.notEqual(source.indexOf('TestEd Beta 2.0'), -1, 'Source html should be retrieved'))); }); describe('#seeTitleEquals', () => { @@ -423,7 +423,7 @@ describe('Puppeteer', function () { .then(() => I.seeTitleEquals('TestEd Beta 2.0')) .then(() => I.seeTitleEquals('TestEd Beta 2.')) .then(() => assert.equal(true, false, 'Throw an error because it should not get this far!')) - .catch((e) => { + .catch(e => { e.should.be.instanceOf(Error); e.message.should.be.equal('expected web page title "TestEd Beta 2.0" to equal "TestEd Beta 2."'); })); @@ -435,7 +435,7 @@ describe('Puppeteer', function () { .then(() => I.seeTextEquals('Welcome to test app!', 'h1')) .then(() => I.seeTextEquals('Welcome to test app', 'h1')) .then(() => assert.equal(true, false, 'Throw an error because it should not get this far!')) - .catch((e) => { + .catch(e => { e.should.be.instanceOf(Error); e.message.should.be.equal('expected element h1 "Welcome to test app" to equal "Welcome to test app!"'); })); @@ -445,40 +445,40 @@ describe('Puppeteer', function () { it('should locate a button to click', () => I.amOnPage('/form/checkbox') .then(() => I._locateClickable('Submit')) - .then((res) => { + .then(res => { res.length.should.be.equal(1); })); it('should not locate a non-existing checkbox using _locateClickable', () => I.amOnPage('/form/checkbox') .then(() => I._locateClickable('I disagree')) - .then((res) => res.length.should.be.equal(0))); + .then(res => res.length.should.be.equal(0))); }); describe('#_locateCheckable', () => { it('should locate a checkbox', () => I.amOnPage('/form/checkbox') .then(() => I._locateCheckable('I Agree')) - .then((res) => res.should.be.ok)); + .then(res => res.should.be.ok)); }); describe('#_locateFields', () => { it('should locate a field', () => I.amOnPage('/form/field') .then(() => I._locateFields('Name')) - .then((res) => res.length.should.be.equal(1))); + .then(res => res.length.should.be.equal(1))); it('should not locate a non-existing field', () => I.amOnPage('/form/field') .then(() => I._locateFields('Mother-in-law')) - .then((res) => res.length.should.be.equal(0))); + .then(res => res.length.should.be.equal(0))); }); describe('check fields: #seeInField, #seeCheckboxIsChecked, ...', () => { it('should throw error if field is not empty', () => I.amOnPage('/form/empty') .then(() => I.seeInField('#empty_input', 'Ayayay')) - .catch((e) => { + .catch(e => { e.should.be.instanceOf(AssertionFailedError); e.inspect().should.be.equal('expected fields by #empty_input to include "Ayayay"'); })); @@ -729,7 +729,7 @@ describe('Puppeteer', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element (//input[@name= "rus"]) is not in DOM or there is no element(//input[@name= "rus"]) with value "Верно3" after 0.1 sec'); })); @@ -762,23 +762,23 @@ describe('Puppeteer', function () { it('should grab inner html from an element using xpath query', () => I.amOnPage('/') .then(() => I.grabHTMLFrom('//title')) - .then((html) => assert.equal(html, 'TestEd Beta 2.0'))); + .then(html => assert.equal(html, 'TestEd Beta 2.0'))); it('should grab inner html from an element using id query', () => I.amOnPage('/') .then(() => I.grabHTMLFrom('#area1')) - .then((html) => assert.equal(html.trim(), ' Test Link '))); + .then(html => assert.equal(html.trim(), ' Test Link '))); it('should grab inner html from multiple elements', () => I.amOnPage('/') .then(() => I.grabHTMLFromAll('//a')) - .then((html) => assert.equal(html.length, 5))); + .then(html => assert.equal(html.length, 5))); it('should grab inner html from within an iframe', () => I.amOnPage('/iframe') .then(() => I.switchTo({ frame: 'iframe' })) .then(() => I.grabHTMLFrom('#new-tab')) - .then((html) => assert.equal(html.trim(), 'New tab'))); + .then(html => assert.equal(html.trim(), 'New tab'))); }); describe('#grabBrowserLogs', () => { @@ -790,8 +790,8 @@ describe('Puppeteer', function () { }), ) .then(() => I.grabBrowserLogs()) - .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1); + .then(logs => { + const matchingLogs = logs.filter(log => log.text().indexOf('Test log entry') > -1); assert.equal(matchingLogs.length, 1); })); @@ -811,8 +811,8 @@ describe('Puppeteer', function () { }), ) .then(() => I.grabBrowserLogs()) - .then((logs) => { - const matchingLogs = logs.filter((log) => log.text().indexOf('Test log entry') > -1); + .then(logs => { + const matchingLogs = logs.filter(log => log.text().indexOf('Test log entry') > -1); assert.equal(matchingLogs.length, 2); })); }); @@ -925,10 +925,10 @@ describe('Puppeteer', function () { it('should fail for disabled element', async () => { await I.amOnPage('/form/wait_for_clickable'); await I.waitForClickable({ css: '#button' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element {css: #button} still not clickable after 0.1 sec'); }); }); @@ -936,10 +936,10 @@ describe('Puppeteer', function () { it('should fail for disabled element by XPath', async () => { await I.amOnPage('/form/wait_for_clickable'); await I.waitForClickable({ xpath: './/button[@id="button"]' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element {xpath: .//button[@id="button"]} still not clickable after 0.1 sec'); }); }); @@ -947,10 +947,10 @@ describe('Puppeteer', function () { it('should fail for element not in viewport by top', async () => { await I.amOnPage('/form/wait_for_clickable'); await I.waitForClickable({ css: '#notInViewportTop' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element {css: #notInViewportTop} still not clickable after 0.1 sec'); }); }); @@ -958,10 +958,10 @@ describe('Puppeteer', function () { it('should fail for element not in viewport by bottom', async () => { await I.amOnPage('/form/wait_for_clickable'); await I.waitForClickable({ css: '#notInViewportBottom' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element {css: #notInViewportBottom} still not clickable after 0.1 sec'); }); }); @@ -969,10 +969,10 @@ describe('Puppeteer', function () { it('should fail for element not in viewport by left', async () => { await I.amOnPage('/form/wait_for_clickable'); await I.waitForClickable({ css: '#notInViewportLeft' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element {css: #notInViewportLeft} still not clickable after 0.1 sec'); }); }); @@ -980,10 +980,10 @@ describe('Puppeteer', function () { it('should fail for element not in viewport by right', async () => { await I.amOnPage('/form/wait_for_clickable'); await I.waitForClickable({ css: '#notInViewportRight' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element {css: #notInViewportRight} still not clickable after 0.1 sec'); }); }); @@ -992,10 +992,10 @@ describe('Puppeteer', function () { await I.amOnPage('/form/wait_for_clickable'); await I.waitForClickable({ css: '#div2_button' }, 0.1); await I.waitForClickable({ css: '#div1_button' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element {css: #div1_button} still not clickable after 0.1 sec'); }); }); @@ -1010,10 +1010,10 @@ describe('Puppeteer', function () { await I.amOnPage('/form/wait_for_clickable'); await I.click('button_save'); await I.waitForClickable('//button[@name="button_publish"]', 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element //button[@name="button_publish"] still not clickable after 0.1 sec'); }); }); @@ -1032,7 +1032,7 @@ describe('Puppeteer', function () { describe('#mockRoute, #stopMockingRoute', () => { it('should mock a route', async () => { await I.amOnPage('/form/fetch_call'); - await I.mockRoute('https://reqres.in/api/comments/1', (request) => { + await I.mockRoute('https://reqres.in/api/comments/1', request => { request.respond({ status: 200, headers: { 'Access-Control-Allow-Origin': '*' }, diff --git a/test/helper/WebDriver.noSeleniumServer_test.js b/test/helper/WebDriver.noSeleniumServer_test.js index 2ac81b5fe..61422cae0 100644 --- a/test/helper/WebDriver.noSeleniumServer_test.js +++ b/test/helper/WebDriver.noSeleniumServer_test.js @@ -41,7 +41,7 @@ describe('WebDriver - No Selenium server started', function () { }, }, customLocatorStrategies: { - customSelector: (selector) => ({ 'element-6066-11e4-a52e-4f735466cecf': `${selector}-foobar` }), + customSelector: selector => ({ 'element-6066-11e4-a52e-4f735466cecf': `${selector}-foobar` }), }, }); }); @@ -431,7 +431,7 @@ describe('WebDriver - No Selenium server started', function () { it('should pass arguments and wait for function returns true', async () => { await wd.amOnPage('/form/wait_js'); - await wd.waitForFunction((varName) => window[varName], ['__waitJs'], 3); + await wd.waitForFunction(varName => window[varName], ['__waitJs'], 3); }); }); @@ -509,7 +509,7 @@ describe('WebDriver - No Selenium server started', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.include('The number of elements (//div[@id = "grab-multiple"]//a) is not 2 after 0.1 sec'); }); }); @@ -521,7 +521,7 @@ describe('WebDriver - No Selenium server started', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.not.include('[object Object]'); }); }); @@ -534,7 +534,7 @@ describe('WebDriver - No Selenium server started', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec'); }); }); @@ -556,7 +556,7 @@ describe('WebDriver - No Selenium server started', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.not.include('[object Object]'); }); }); @@ -570,7 +570,7 @@ describe('WebDriver - No Selenium server started', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.not.include('[object Object]'); }); }); @@ -623,7 +623,7 @@ describe('WebDriver - No Selenium server started', function () { .then(() => wd.wait(1)) // Wait is required because the url is change by previous statement (maybe related to #914) .then(() => wd.switchToNextTab(2)) .then(() => assert.equal(true, false, 'Throw an error if it gets this far (which it should not)!')) - .catch((e) => { + .catch(e => { assert.equal(e.message, 'There is no ability to switch to next tab with offset 2'); }); }); @@ -635,7 +635,7 @@ describe('WebDriver - No Selenium server started', function () { .then(() => wd.switchToNextTab()) .then(() => wd.seeInCurrentUrl('/login')) .then(() => wd.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 2)) + .then(numPages => assert.equal(numPages, 2)) .then(() => wd.closeCurrentTab()) .then(() => wd.seeInCurrentUrl('/info')) .then(() => wd.grabNumberOfOpenTabs()); @@ -661,7 +661,7 @@ describe('WebDriver - No Selenium server started', function () { .then(() => wd.openNewTab()) .then(() => wd.waitInUrl('about:blank')) .then(() => wd.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 2)); + .then(numPages => assert.equal(numPages, 2)); }); it('should switch to previous tab', () => { @@ -680,7 +680,7 @@ describe('WebDriver - No Selenium server started', function () { .then(() => wd.waitInUrl('about:blank')) .then(() => wd.switchToPreviousTab(2)) .then(() => wd.waitInUrl('/info')) - .catch((e) => { + .catch(e => { assert.equal(e.message, 'There is no ability to switch to previous tab with offset 2'); }); }); @@ -716,14 +716,14 @@ describe('WebDriver - No Selenium server started', function () { .amOnPage('/form/popup') .then(() => wd.click('Alert')) .then(() => wd.grabPopupText()) - .then((text) => assert.equal(text, 'Really?')); + .then(text => assert.equal(text, 'Really?')); }); it('should return null if no popup is visible (do not throw an error)', () => { return wd .amOnPage('/form/popup') .then(() => wd.grabPopupText()) - .then((text) => assert.equal(text, null)); + .then(text => assert.equal(text, null)); }); }); @@ -732,7 +732,7 @@ describe('WebDriver - No Selenium server started', function () { return wd .amOnPage('/dynamic') .then(() => wd.waitForText('Nothing here', 1, '#text')) - .catch((e) => { + .catch(e => { e.message.should.be.equal('element (#text) is not in DOM or there is no element(#text) with text "Nothing here" after 1 sec'); }); }); @@ -741,7 +741,7 @@ describe('WebDriver - No Selenium server started', function () { return wd .amOnPage('/dynamic') .then(() => wd.waitForText('Dynamic text', 0.1)) - .catch((e) => { + .catch(e => { e.message.should.be.equal('element (body) is not in DOM or there is no element(body) with text "Dynamic text" after 0.1 sec'); }); }); @@ -824,8 +824,8 @@ describe('WebDriver - No Selenium server started', function () { return wd .amOnPage('/info') .then(() => wd._session()) - .then((session) => - session.start().then((browser) => ({ + .then(session => + session.start().then(browser => ({ browser, session, })), @@ -947,7 +947,7 @@ describe('WebDriver - No Selenium server started', function () { const logs = await wd.grabBrowserLogs(); console.log('lololo', logs); - const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1); + const matchingLogs = logs.filter(log => log.message.indexOf('Test log entry') > -1); assert.equal(matchingLogs.length, 1); }); @@ -964,7 +964,7 @@ describe('WebDriver - No Selenium server started', function () { const logs = await wd.grabBrowserLogs(); - const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1); + const matchingLogs = logs.filter(log => log.message.indexOf('Test log entry') > -1); assert.equal(matchingLogs.length, 2); }); }); @@ -1112,10 +1112,10 @@ describe('WebDriver - No Selenium server started', function () { await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#button' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element #button still not clickable after 0.1 sec'); }); }); @@ -1124,10 +1124,10 @@ describe('WebDriver - No Selenium server started', function () { await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ xpath: './/button[@id="button"]' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element .//button[@id="button"] still not clickable after 0.1 sec'); }); }); @@ -1136,10 +1136,10 @@ describe('WebDriver - No Selenium server started', function () { await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportTop' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element #notInViewportTop still not clickable after 0.1 sec'); }); }); @@ -1148,10 +1148,10 @@ describe('WebDriver - No Selenium server started', function () { await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportBottom' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element #notInViewportBottom still not clickable after 0.1 sec'); }); }); @@ -1160,10 +1160,10 @@ describe('WebDriver - No Selenium server started', function () { await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportLeft' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element #notInViewportLeft still not clickable after 0.1 sec'); }); }); @@ -1172,10 +1172,10 @@ describe('WebDriver - No Selenium server started', function () { await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportRight' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element #notInViewportRight still not clickable after 0.1 sec'); }); }); @@ -1185,10 +1185,10 @@ describe('WebDriver - No Selenium server started', function () { await wd.waitForClickable({ css: '#div2_button' }, 0.1); await wd .waitForClickable({ css: '#div1_button' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element #div1_button still not clickable after 0.1 sec'); }); }); diff --git a/test/helper/WebDriver_test.js b/test/helper/WebDriver_test.js index 10627a7a6..af881eee4 100644 --- a/test/helper/WebDriver_test.js +++ b/test/helper/WebDriver_test.js @@ -44,7 +44,7 @@ describe('WebDriver', function () { }, }, customLocatorStrategies: { - customSelector: (selector) => ({ 'element-6066-11e4-a52e-4f735466cecf': `${selector}-foobar` }), + customSelector: selector => ({ 'element-6066-11e4-a52e-4f735466cecf': `${selector}-foobar` }), }, }); }); @@ -443,7 +443,7 @@ describe('WebDriver', function () { it('should pass arguments and wait for function returns true', async () => { await wd.amOnPage('/form/wait_js'); - await wd.waitForFunction((varName) => window[varName], ['__waitJs'], 3); + await wd.waitForFunction(varName => window[varName], ['__waitJs'], 3); }); }); @@ -521,7 +521,7 @@ describe('WebDriver', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.include('The number of elements (//div[@id = "grab-multiple"]//a) is not 2 after 0.1 sec'); }); }); @@ -533,7 +533,7 @@ describe('WebDriver', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.not.include('[object Object]'); }); }); @@ -546,7 +546,7 @@ describe('WebDriver', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.include('The number of elements (#grab-multiple > a) is not 2 after 0.1 sec'); }); }); @@ -568,7 +568,7 @@ describe('WebDriver', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.not.include('[object Object]'); }); }); @@ -582,7 +582,7 @@ describe('WebDriver', function () { .then(() => { throw Error('It should never get this far'); }) - .catch((e) => { + .catch(e => { e.message.should.not.include('[object Object]'); }); }); @@ -636,7 +636,7 @@ describe('WebDriver', function () { .then(() => wd.wait(1)) // Wait is required because the url is change by previous statement (maybe related to #914) .then(() => wd.switchToNextTab(2)) .then(() => assert.equal(true, false, 'Throw an error if it gets this far (which it should not)!')) - .catch((e) => { + .catch(e => { assert.equal(e.message, 'There is no ability to switch to next tab with offset 2'); }); }); @@ -648,7 +648,7 @@ describe('WebDriver', function () { .then(() => wd.switchToNextTab()) .then(() => wd.seeInCurrentUrl('/login')) .then(() => wd.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 2)) + .then(numPages => assert.equal(numPages, 2)) .then(() => wd.closeCurrentTab()) .then(() => wd.seeInCurrentUrl('/info')) .then(() => wd.grabNumberOfOpenTabs()); @@ -674,7 +674,7 @@ describe('WebDriver', function () { .then(() => wd.openNewTab()) .then(() => wd.waitInUrl('about:blank')) .then(() => wd.grabNumberOfOpenTabs()) - .then((numPages) => assert.equal(numPages, 2)); + .then(numPages => assert.equal(numPages, 2)); }); it('should switch to previous tab', () => { @@ -693,7 +693,7 @@ describe('WebDriver', function () { .then(() => wd.waitInUrl('about:blank')) .then(() => wd.switchToPreviousTab(2)) .then(() => wd.waitInUrl('/info')) - .catch((e) => { + .catch(e => { assert.equal(e.message, 'There is no ability to switch to previous tab with offset 2'); }); }); @@ -729,14 +729,14 @@ describe('WebDriver', function () { .amOnPage('/form/popup') .then(() => wd.click('Alert')) .then(() => wd.grabPopupText()) - .then((text) => assert.equal(text, 'Really?')); + .then(text => assert.equal(text, 'Really?')); }); it('should return null if no popup is visible (do not throw an error)', () => { return wd .amOnPage('/form/popup') .then(() => wd.grabPopupText()) - .then((text) => assert.equal(text, null)); + .then(text => assert.equal(text, null)); }); }); @@ -745,7 +745,7 @@ describe('WebDriver', function () { return wd .amOnPage('/dynamic') .then(() => wd.waitForText('Nothing here', 1, '#text')) - .catch((e) => { + .catch(e => { e.message.should.be.equal('element (#text) is not in DOM or there is no element(#text) with text "Nothing here" after 1 sec'); }); }); @@ -754,7 +754,7 @@ describe('WebDriver', function () { return wd .amOnPage('/dynamic') .then(() => wd.waitForText('Dynamic text', 0.1)) - .catch((e) => { + .catch(e => { e.message.should.be.equal('element (body) is not in DOM or there is no element(body) with text "Dynamic text" after 0.1 sec'); }); }); @@ -837,8 +837,8 @@ describe('WebDriver', function () { return wd .amOnPage('/info') .then(() => wd._session()) - .then((session) => - session.start().then((browser) => ({ + .then(session => + session.start().then(browser => ({ browser, session, })), @@ -960,7 +960,7 @@ describe('WebDriver', function () { const logs = await wd.grabBrowserLogs(); console.log('lololo', logs); - const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1); + const matchingLogs = logs.filter(log => log.message.indexOf('Test log entry') > -1); assert.equal(matchingLogs.length, 1); }); @@ -977,7 +977,7 @@ describe('WebDriver', function () { const logs = await wd.grabBrowserLogs(); - const matchingLogs = logs.filter((log) => log.message.indexOf('Test log entry') > -1); + const matchingLogs = logs.filter(log => log.message.indexOf('Test log entry') > -1); assert.equal(matchingLogs.length, 2); }); }); @@ -1125,10 +1125,10 @@ describe('WebDriver', function () { await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#button' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element #button still not clickable after 0.1 sec'); }); }); @@ -1137,10 +1137,10 @@ describe('WebDriver', function () { await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ xpath: './/button[@id="button"]' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element .//button[@id="button"] still not clickable after 0.1 sec'); }); }); @@ -1149,10 +1149,10 @@ describe('WebDriver', function () { await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportTop' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element #notInViewportTop still not clickable after 0.1 sec'); }); }); @@ -1161,10 +1161,10 @@ describe('WebDriver', function () { await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportBottom' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element #notInViewportBottom still not clickable after 0.1 sec'); }); }); @@ -1173,10 +1173,10 @@ describe('WebDriver', function () { await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportLeft' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element #notInViewportLeft still not clickable after 0.1 sec'); }); }); @@ -1185,10 +1185,10 @@ describe('WebDriver', function () { await wd.amOnPage('/form/wait_for_clickable'); await wd .waitForClickable({ css: '#notInViewportRight' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element #notInViewportRight still not clickable after 0.1 sec'); }); }); @@ -1198,10 +1198,10 @@ describe('WebDriver', function () { await wd.waitForClickable({ css: '#div2_button' }, 0.1); await wd .waitForClickable({ css: '#div1_button' }, 0.1) - .then((isClickable) => { + .then(isClickable => { if (isClickable) throw new Error('Element is clickable, but must be unclickable'); }) - .catch((e) => { + .catch(e => { e.message.should.include('element #div1_button still not clickable after 0.1 sec'); }); }); diff --git a/test/helper/webapi.js b/test/helper/webapi.js index 231b006ab..7bded301d 100644 --- a/test/helper/webapi.js +++ b/test/helper/webapi.js @@ -22,7 +22,7 @@ module.exports.init = function (testData) { }; module.exports.tests = function () { - const isHelper = (helperName) => I.constructor.name === helperName; + const isHelper = helperName => I.constructor.name === helperName; beforeEach(() => { I = data.I; @@ -456,7 +456,7 @@ module.exports.tests = function () { it('should return value from sync script', async () => { await I.amOnPage('/'); - const val = await I.executeScript((a) => a + 5, 5); + const val = await I.executeScript(a => a + 5, 5); assert.equal(val, 10); }); @@ -1226,9 +1226,9 @@ module.exports.tests = function () { .then(() => I.dontSee('E-Mail')) .then(() => I.see('Hasło')) .then(() => I.grabTextFrom('label')) - .then((label) => assert.equal(label, 'Hasło')) + .then(label => assert.equal(label, 'Hasło')) .then(() => I.grabValueFrom('input')) - .then((input) => assert.equal(input, '12345')); + .then(input => assert.equal(input, '12345')); }); it('within should respect context in see', async function () { diff --git a/test/runner/dry_run_test.js b/test/runner/dry_run_test.js index 10c577747..b67d15a3d 100644 --- a/test/runner/dry_run_test.js +++ b/test/runner/dry_run_test.js @@ -13,7 +13,7 @@ describe('dry-run command', () => { process.chdir(codecept_dir); }); - it('should be executed with config path', (done) => { + it('should be executed with config path', done => { process.chdir(__dirname); exec(`${codecept_run_config('codecept.js')}`, (err, stdout) => { expect(stdout).toContain('Filesystem'); // feature @@ -23,7 +23,7 @@ describe('dry-run command', () => { }); }); - it('should list all tests', (done) => { + it('should list all tests', done => { process.chdir(__dirname); exec(`${codecept_run_config('codecept.js')}`, (err, stdout) => { expect(stdout).toContain('Filesystem'); // feature @@ -34,7 +34,7 @@ describe('dry-run command', () => { }); }); - it('should not run actual steps', (done) => { + it('should not run actual steps', done => { exec(`${codecept_run_config('codecept.flaky.js')}`, (err, stdout) => { expect(stdout).toContain('Flaky'); // feature expect(stdout).toContain('Not so flaky test'); // test name @@ -45,7 +45,7 @@ describe('dry-run command', () => { }); }); - it('should not run helper hooks', (done) => { + it('should not run helper hooks', done => { exec(`${codecept_run_config('codecept.testhooks.json')} --debug`, (err, stdout) => { const lines = stdout.match(/\S.+/g); @@ -62,7 +62,7 @@ describe('dry-run command', () => { }); }); - it('should display meta steps and substeps', (done) => { + it('should display meta steps and substeps', done => { exec(`${codecept_run_config('configs/pageObjects/codecept.po.js')} --debug`, (err, stdout) => { const lines = stdout.split('\n'); expect(lines).toEqual( @@ -84,7 +84,7 @@ describe('dry-run command', () => { }); }); - it('should run feature files', (done) => { + it('should run feature files', done => { exec(codecept_run_config('codecept.bdd.js') + ' --steps --grep "Checkout process"', (err, stdout) => { //eslint-disable-line expect(stdout).toContain('Checkout process'); // feature @@ -103,7 +103,7 @@ describe('dry-run command', () => { }); }); - it('should run feature files with regex grep', (done) => { + it('should run feature files with regex grep', done => { exec(codecept_run_config('codecept.bdd.js') + ' --steps --grep "(?=.*Checkout process)"', (err, stdout) => { //eslint-disable-line expect(stdout).toContain('Checkout process'); // feature @@ -122,7 +122,7 @@ describe('dry-run command', () => { }); }); - it('should print substeps in debug mode', (done) => { + it('should print substeps in debug mode', done => { exec(codecept_run_config('codecept.bdd.js') + ' --debug --grep "Checkout process @important"', (err, stdout) => { //eslint-disable-line expect(stdout).toContain('Checkout process'); // feature @@ -142,7 +142,7 @@ describe('dry-run command', () => { }); }); - it('should run tests with different data', (done) => { + it('should run tests with different data', done => { exec(`${codecept_run_config('codecept.ddt.js')} --debug`, (err, stdout) => { const output = stdout.replace(/in [0-9]ms/g, '').replace(/\r/g, ''); expect(output).toContain('OK | 11 passed'); @@ -151,7 +151,7 @@ describe('dry-run command', () => { }); }); - it('should work with inject() keyword', (done) => { + it('should work with inject() keyword', done => { exec(`${codecept_run_config('configs/pageObjects/codecept.inject.po.js', 'check current dir')} --debug`, (err, stdout) => { const lines = stdout.split('\n'); expect(stdout).toContain('injected'); @@ -173,7 +173,7 @@ describe('dry-run command', () => { }); }); - it('should inject page objects via proxy', (done) => { + it('should inject page objects via proxy', done => { exec(`${codecept_run_config('../inject-fail-example')} --debug`, (err, stdout) => { expect(stdout).toContain('newdomain'); expect(stdout).toContain('veni,vedi,vici'); @@ -183,7 +183,7 @@ describe('dry-run command', () => { }); }); - it('should enable all plugins in dry-mode when passing -p all', (done) => { + it('should enable all plugins in dry-mode when passing -p all', done => { exec(`${codecept_run_config('codecept.customLocator.js')} --verbose -p all`, (err, stdout) => { expect(stdout).toContain('Plugins: screenshotOnFail, customLocator'); expect(stdout).toContain("I see element {xpath: .//*[@data-testid='COURSE']//a}"); @@ -194,7 +194,7 @@ describe('dry-run command', () => { }); }); - it('should enable a particular plugin in dry-mode when passing it to -p', (done) => { + it('should enable a particular plugin in dry-mode when passing it to -p', done => { exec(`${codecept_run_config('codecept.customLocator.js')} --verbose -p customLocator`, (err, stdout) => { expect(stdout).toContain('Plugins: customLocator'); expect(stdout).toContain("I see element {xpath: .//*[@data-testid='COURSE']//a}"); diff --git a/test/runner/pageobject_test.js b/test/runner/pageobject_test.js index 8ca95260d..bfeeed0bd 100644 --- a/test/runner/pageobject_test.js +++ b/test/runner/pageobject_test.js @@ -13,7 +13,7 @@ describe('CodeceptJS PageObject', () => { }); describe('Failed PageObject', () => { - it('should fail if page objects was failed', (done) => { + it('should fail if page objects was failed', done => { exec(`${config_run_config('codecept.fail_po.js')} --debug`, (err, stdout) => { const lines = stdout.split('\n'); expect(lines).toEqual( @@ -33,7 +33,7 @@ describe('CodeceptJS PageObject', () => { }); describe('PageObject as Class', () => { - it('should inject page objects by class', (done) => { + it('should inject page objects by class', done => { exec(`${config_run_config('codecept.class.js', '@ClassPageObject')} --debug`, (err, stdout) => { expect(stdout).not.toContain('classpage.type is not a function'); expect(stdout).toContain('On classpage: type "Class Page Type"'); @@ -47,7 +47,7 @@ describe('CodeceptJS PageObject', () => { }); }); - it('should inject page objects by class which nested base clas', (done) => { + it('should inject page objects by class which nested base clas', done => { exec(`${config_run_config('codecept.class.js', '@NestedClassPageObject')} --debug`, (err, stdout) => { expect(stdout).not.toContain('classnestedpage.type is not a function'); expect(stdout).toContain('On classnestedpage: type "Nested Class Page Type"'); @@ -62,7 +62,7 @@ describe('CodeceptJS PageObject', () => { }); }); - it('should print pretty step log and pretty event log', (done) => { + it('should print pretty step log and pretty event log', done => { exec(`${config_run_config('codecept.logs.js', 'Print correct arg message')} --steps`, (err, stdout) => { expect(stdout).toContain('I get humanize args Logs Page Value'); expect(stdout).toContain('Start event step: I get humanize args Logs Page Valu'); @@ -72,7 +72,7 @@ describe('CodeceptJS PageObject', () => { }); }); - it('should print pretty failed step log on stack trace', (done) => { + it('should print pretty failed step log on stack trace', done => { exec(`${config_run_config('codecept.logs.js', 'Error print correct arg message')} --steps`, (err, stdout) => { expect(stdout).toContain('I.errorMethodHumanizeArgs(Logs Page Value)'); expect(stdout).toContain('FAIL | 0 passed, 1 failed'); @@ -83,7 +83,7 @@ describe('CodeceptJS PageObject', () => { }); describe('Show MetaSteps in Log', () => { - it('should display meta steps and substeps', (done) => { + it('should display meta steps and substeps', done => { exec(`${config_run_config('codecept.po.js')} --debug`, (err, stdout) => { const lines = stdout.split('\n'); expect(lines).toEqual( @@ -106,7 +106,7 @@ describe('CodeceptJS PageObject', () => { }); describe('Inject PO in Test', () => { - it('should work with inject() keyword', (done) => { + it('should work with inject() keyword', done => { exec(`${config_run_config('codecept.inject.po.js', 'check current dir')} --debug`, (err, stdout) => { const lines = stdout.split('\n'); expect(stdout).toContain('injected'); @@ -130,7 +130,7 @@ describe('CodeceptJS PageObject', () => { }); describe('PageObject with context', () => { - it('should work when used "this" context on method', (done) => { + it('should work when used "this" context on method', done => { exec(`${config_run_config('codecept.inject.po.js', 'pageobject with context')} --debug`, (err, stdout) => { const lines = stdout.split('\n'); expect(lines).toEqual( @@ -153,7 +153,7 @@ describe('CodeceptJS PageObject', () => { }); describe('Inject PO in another PO', () => { - it('should inject page objects via proxy', (done) => { + it('should inject page objects via proxy', done => { exec(`${config_run_config('../../../inject-fail-example')} --debug`, (err, stdout) => { expect(stdout).toContain('newdomain'); expect(stdout).toContain('veni,vedi,vici'); @@ -164,7 +164,7 @@ describe('CodeceptJS PageObject', () => { }); }); - it('built methods are still available custom I steps_file is added', (done) => { + it('built methods are still available custom I steps_file is added', done => { exec(`${config_run_config('codecept.class.js', '@CustomStepsBuiltIn')} --debug`, (err, stdout) => { expect(stdout).toContain('Built in say'); expect(stdout).toContain('Say called from custom step'); diff --git a/test/runner/run_multiple_test.js b/test/runner/run_multiple_test.js index 315748075..a2252e62a 100644 --- a/test/runner/run_multiple_test.js +++ b/test/runner/run_multiple_test.js @@ -14,7 +14,7 @@ describe('CodeceptJS Multiple Runner', function () { global.codecept_dir = path.join(__dirname, '/../data/sandbox'); }); - it('should execute one suite with browser', (done) => { + it('should execute one suite with browser', done => { exec(`${codecept_run}default:firefox`, (err, stdout) => { stdout.should.include('CodeceptJS'); // feature stdout.should.include('.default:firefox] print browser '); @@ -24,7 +24,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should execute all suites', (done) => { + it('should execute all suites', done => { exec(`${codecept_run}--all`, (err, stdout) => { stdout.should.include('CodeceptJS'); // feature stdout.should.include('[1.default:chrome] print browser '); @@ -43,7 +43,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should replace parameters', (done) => { + it('should replace parameters', done => { exec(`${codecept_run}grep --debug`, (err, stdout) => { stdout.should.include('CodeceptJS'); // feature stdout.should.include('[1.grep:chrome] › maximize'); @@ -53,7 +53,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should execute multiple suites', (done) => { + it('should execute multiple suites', done => { exec(`${codecept_run}mobile default `, (err, stdout) => { stdout.should.include('CodeceptJS'); // feature stdout.should.include('[1.mobile:android] print browser '); @@ -67,7 +67,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should execute multiple suites with selected browsers', (done) => { + it('should execute multiple suites with selected browsers', done => { exec(`${codecept_run}mobile:safari default:chrome `, (err, stdout) => { stdout.should.include('CodeceptJS'); // feature stdout.should.include('[1.mobile:safari] print browser '); @@ -78,7 +78,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should print steps', (done) => { + it('should print steps', done => { exec(`${codecept_run}default --steps`, (err, stdout) => { stdout.should.include('CodeceptJS'); // feature stdout.should.include('[2.default:firefox] print browser '); @@ -90,7 +90,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should pass grep to configuration', (done) => { + it('should pass grep to configuration', done => { exec(`${codecept_run}default --grep @grep`, (err, stdout) => { stdout.should.include('CodeceptJS'); // feature stdout.should.include('[1.default:chrome] @grep print browser size'); @@ -102,7 +102,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should pass grep invert to configuration', (done) => { + it('should pass grep invert to configuration', done => { exec(`${codecept_run}default --grep @grep --invert`, (err, stdout) => { stdout.should.include('CodeceptJS'); // feature stdout.should.not.include('[1.default:chrome] @grep print browser size'); @@ -114,7 +114,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should pass tests to configuration', (done) => { + it('should pass tests to configuration', done => { exec(`${codecept_run}test`, (err, stdout) => { stdout.should.include('CodeceptJS'); // feature stdout.should.include('[1.test:chrome] print browser size'); @@ -126,7 +126,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should run chunks', (done) => { + it('should run chunks', done => { exec(`${codecept_run}chunks`, (err, stdout) => { stdout.should.include('CodeceptJS'); // feature stdout.should.match(/chunks:chunk\d:dummy].+print browser/i); @@ -136,7 +136,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should run features in parallel', (done) => { + it('should run features in parallel', done => { process.chdir(codecept_dir); exec(`${runner} run-multiple --config codecept.multiple.features.js chunks --features --grep '(?=.*)^(?!.*@fail)'`, (err, stdout) => { stdout.should.match(/\[\d\.chunks:chunk\d:default\] Checkout examples process/); @@ -151,7 +151,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should run features & tests in parallel', (done) => { + it('should run features & tests in parallel', done => { process.chdir(codecept_dir); exec(`${runner} run-multiple --config codecept.multiple.features.js chunks --grep '(?=.*)^(?!.*@fail)'`, (err, stdout) => { stdout.should.include('@feature_grep'); @@ -162,7 +162,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should run only tests in parallel', (done) => { + it('should run only tests in parallel', done => { process.chdir(codecept_dir); exec(`${runner} run-multiple --config codecept.multiple.features.js chunks --tests`, (err, stdout) => { stdout.should.include('@feature_grep'); @@ -173,7 +173,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should exit with non-zero code for failures during init process', (done) => { + it('should exit with non-zero code for failures during init process', done => { process.chdir(codecept_dir); exec(`${runner} run-multiple --config codecept.multiple.initFailure.js default --all`, (err, stdout) => { expect(err).not.toBeFalsy(); @@ -183,7 +183,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should exit code 1 when error in config', (done) => { + it('should exit code 1 when error in config', done => { process.chdir(codecept_dir); exec(`${runner} run-multiple --config configs/codecept-invalid.config.js default --all`, (err, stdout, stderr) => { expect(stdout).not.toContain('UnhandledPromiseRejectionWarning'); @@ -196,7 +196,7 @@ describe('CodeceptJS Multiple Runner', function () { describe('bootstrapAll and teardownAll', () => { const _codecept_run = `run-multiple --config ${codecept_dir}`; - it('should be executed from async function in config', (done) => { + it('should be executed from async function in config', done => { exec(`${runner} ${_codecept_run}/codecept.async.bootstrapall.multiple.code.js default`, (err, stdout) => { stdout.should.include('CodeceptJS'); // feature stdout.should.include('Results: inside Promise\n"event.multiple.before" is called'); @@ -206,7 +206,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should be executed from function in config', (done) => { + it('should be executed from function in config', done => { exec(`${runner} ${_codecept_run}/codecept.bootstrapall.multiple.code.js default`, (err, stdout) => { stdout.should.include('CodeceptJS'); // feature stdout.should.include('"bootstrapAll" is called.'); @@ -222,7 +222,7 @@ describe('CodeceptJS Multiple Runner', function () { const moduleOutput = 'Module was required 1'; const moduleOutput2 = 'Module was required 2'; - it('should be executed with module when described', (done) => { + it('should be executed with module when described', done => { process.chdir(codecept_dir); exec(`${runner} ${_codecept_run}/codecept.require.multiple.single.json default`, (err, stdout) => { stdout.should.include(moduleOutput); @@ -233,7 +233,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should be executed with several module when described', (done) => { + it('should be executed with several module when described', done => { process.chdir(codecept_dir); exec(`${runner} ${_codecept_run}/codecept.require.multiple.several.js default`, (err, stdout) => { stdout.should.include(moduleOutput); @@ -245,7 +245,7 @@ describe('CodeceptJS Multiple Runner', function () { }); }); - it('should not be executed without module when not described', (done) => { + it('should not be executed without module when not described', done => { process.chdir(codecept_dir); exec(`${runner} ${_codecept_run}/codecept.require.multiple.without.json default`, (err, stdout) => { stdout.should.not.include(moduleOutput); diff --git a/test/runner/run_rerun_test.js b/test/runner/run_rerun_test.js index 36c4fadd6..9c9fb980c 100644 --- a/test/runner/run_rerun_test.js +++ b/test/runner/run_rerun_test.js @@ -14,7 +14,7 @@ describe('run-rerun command', () => { process.chdir(codecept_dir); }); - it('should display count of attemps', (done) => { + it('should display count of attemps', done => { exec(`${codecept_run_config('codecept.conf.js')} --debug`, (err, stdout) => { const runs = stdout.split('Run Rerun - Command --'); // check first run @@ -38,7 +38,7 @@ describe('run-rerun command', () => { }); }); - it('should display 2 success count of attemps', (done) => { + it('should display 2 success count of attemps', done => { exec(`${codecept_run_config('codecept.conf.min_less_max.js')} --debug`, (err, stdout) => { const runs = stdout.split('Run Rerun - Command --'); @@ -59,7 +59,7 @@ describe('run-rerun command', () => { }); }); - it('should display error if minSuccess more than maxReruns', (done) => { + it('should display error if minSuccess more than maxReruns', done => { exec(`${codecept_run_config('codecept.conf.min_more_max.js')} --debug`, (err, stdout) => { expect(stdout).toContain('minSuccess must be less than maxReruns'); expect(err.code).toBe(1); @@ -67,7 +67,7 @@ describe('run-rerun command', () => { }); }); - it('should display errors if test is fail always', (done) => { + it('should display errors if test is fail always', done => { exec(`${codecept_run_config('codecept.conf.fail_test.js', '@RunRerun - Fail all attempt')} --debug`, (err, stdout) => { expect(stdout).toContain('Fail run 1 of max 3, success runs 0/2'); expect(stdout).toContain('Fail run 2 of max 3, success runs 0/2'); @@ -78,7 +78,7 @@ describe('run-rerun command', () => { }); }); - it('should display success run if test was fail one time of two attempts 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) => { expect(stdout).toContain('Process run 1 of max 3, success runs 1/2'); expect(stdout).toContain('Fail run 2 of max 3, success runs 1/2'); @@ -89,7 +89,7 @@ describe('run-rerun command', () => { }); }); - it('should throw exit code 1 if all tests were supposed to pass', (done) => { + 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'); diff --git a/test/unit/actor_test.js b/test/unit/actor_test.js index c97ac6798..3f3d5362d 100644 --- a/test/unit/actor_test.js +++ b/test/unit/actor_test.js @@ -59,7 +59,7 @@ describe('Actor', () => { }); recorder.start(); const promise = I.customStep(); - return promise.then((val) => expect(val).toEqual('hello world')); + return promise.then(val => expect(val).toEqual('hello world')); }); it('should init pageobject methods as metastep', () => { @@ -83,7 +83,7 @@ describe('Actor', () => { }); it('should take all methods from helpers and built in', () => { - ['hello', 'bye', 'die', 'failAfter', 'say', 'retry', 'greeting'].forEach((key) => { + ['hello', 'bye', 'die', 'failAfter', 'say', 'retry', 'greeting'].forEach(key => { expect(I).toHaveProperty(key); }); }); @@ -92,7 +92,7 @@ describe('Actor', () => { recorder.start(); const promise = I.hello(); expect(promise).toBeInstanceOf(Promise); - return promise.then((val) => expect(val).toEqual('hello world')); + return promise.then(val => expect(val).toEqual('hello world')); }); it('should produce step events', () => { @@ -100,7 +100,7 @@ describe('Actor', () => { let listeners = 0; event.dispatcher.addListener(event.step.before, () => listeners++); event.dispatcher.addListener(event.step.after, () => listeners++); - event.dispatcher.addListener(event.step.passed, (step) => { + event.dispatcher.addListener(event.step.passed, step => { listeners++; expect(step.endTime).toBeTruthy(); expect(step.startTime).toBeTruthy(); @@ -153,7 +153,7 @@ describe('Actor', () => { let listeners = 0; event.dispatcher.addListener(event.step.before, () => listeners++); event.dispatcher.addListener(event.step.after, () => listeners++); - event.dispatcher.addListener(event.step.failed, (step) => { + event.dispatcher.addListener(event.step.failed, step => { listeners++; expect(step.endTime).toBeTruthy(); expect(step.startTime).toBeTruthy(); diff --git a/test/unit/bdd_test.js b/test/unit/bdd_test.js index 9e3af1d40..ab275e8f9 100644 --- a/test/unit/bdd_test.js +++ b/test/unit/bdd_test.js @@ -36,9 +36,9 @@ const text = ` When I go to checkout process `; -const checkTestForErrors = (test) => { +const checkTestForErrors = test => { return new Promise((resolve, reject) => { - test.fn((err) => { + test.fn(err => { if (err) { return reject(err); } @@ -103,7 +103,7 @@ describe('BDD', () => { it('should contain tags', async () => { let sum = 0; - Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))); + Given(/I have product with (\d+) price/, param => (sum += parseInt(param, 10))); When('I go to checkout process', () => (sum += 10)); const suite = await run(text); suite.tests[0].fn(() => {}); @@ -111,9 +111,9 @@ describe('BDD', () => { expect('@super').is.equal(suite.tests[0].tags[0]); }); - it('should load step definitions', (done) => { + it('should load step definitions', done => { let sum = 0; - Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))); + Given(/I have product with (\d+) price/, param => (sum += parseInt(param, 10))); When('I go to checkout process', () => (sum += 10)); const suite = run(text); expect('checkout process').is.equal(suite.title); @@ -126,7 +126,7 @@ describe('BDD', () => { it('should allow failed steps', async () => { let sum = 0; - Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))); + Given(/I have product with (\d+) price/, param => (sum += parseInt(param, 10))); When('I go to checkout process', () => expect(false).is.true); const suite = run(text); expect('checkout process').is.equal(suite.title); @@ -141,7 +141,7 @@ describe('BDD', () => { it('handles errors in steps', async () => { let sum = 0; - Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))); + Given(/I have product with (\d+) price/, param => (sum += parseInt(param, 10))); When('I go to checkout process', () => { throw new Error('errored step'); }); @@ -158,7 +158,7 @@ describe('BDD', () => { it('handles async errors in steps', async () => { let sum = 0; - Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))); + Given(/I have product with (\d+) price/, param => (sum += parseInt(param, 10))); When('I go to checkout process', () => Promise.reject(new Error('step failed'))); const suite = run(text); expect('checkout process').is.equal(suite.title); @@ -171,11 +171,11 @@ describe('BDD', () => { } }); - it('should work with async functions', (done) => { + it('should work with async functions', done => { let sum = 0; - Given(/I have product with (\d+) price/, (param) => (sum += parseInt(param, 10))); + Given(/I have product with (\d+) price/, param => (sum += parseInt(param, 10))); When('I go to checkout process', async () => { - return new Promise((checkoutDone) => { + return new Promise(checkoutDone => { sum += 10; setTimeout(checkoutDone, 0); }); @@ -203,7 +203,7 @@ describe('BDD', () => { }); I = actor(); let sum = 0; - Given(/I have product with (\d+) price/, (price) => { + Given(/I have product with (\d+) price/, price => { I.do('add', (sum += parseInt(price, 10))); }); When('I go to checkout process', () => { @@ -233,12 +233,12 @@ describe('BDD', () => { }); it('should match step with params', () => { - Given('I am a {word}', (param) => param); + Given('I am a {word}', param => param); const fn = matchStep('I am a bird'); expect('bird').is.equal(fn.params[0]); }); - it('should produce step events', (done) => { + it('should produce step events', done => { const text = ` Feature: Emit step event @@ -259,10 +259,10 @@ describe('BDD', () => { it('should use shortened form for step definitions', () => { let fn; - Given('I am a {word}', (params) => params[0]); - When('I have {int} wings and {int} eyes', (params) => params[0] + params[1]); - Given('I have ${int} in my pocket', (params) => params[0]); // eslint-disable-line no-template-curly-in-string - Given('I have also ${float} in my pocket', (params) => params[0]); // eslint-disable-line no-template-curly-in-string + Given('I am a {word}', params => params[0]); + When('I have {int} wings and {int} eyes', params => params[0] + params[1]); + Given('I have ${int} in my pocket', params => params[0]); // eslint-disable-line no-template-curly-in-string + Given('I have also ${float} in my pocket', params => params[0]); // eslint-disable-line no-template-curly-in-string fn = matchStep('I am a bird'); expect('bird').is.equal(fn(fn.params)); fn = matchStep('I have 2 wings and 2 eyes'); @@ -273,7 +273,7 @@ describe('BDD', () => { expect(500.3).is.equal(fn(fn.params)); }); - it('should attach before hook for Background', (finish) => { + it('should attach before hook for Background', finish => { const text = ` Feature: checkout process @@ -292,14 +292,14 @@ describe('BDD', () => { const suite = run(text); const done = () => {}; - suite._beforeEach.forEach((hook) => hook.run(done)); + suite._beforeEach.forEach(hook => hook.run(done)); suite.tests[0].fn(() => { expect(sum).is.equal(2); finish(); }); }); - it('should execute scenario outlines', (done) => { + it('should execute scenario outlines', done => { const text = ` @awesome @cool Feature: checkout process @@ -322,13 +322,13 @@ describe('BDD', () => { `; let cart = 0; let sum = 0; - Given('I have product with price {int}$ in my cart', (price) => { + Given('I have product with price {int}$ in my cart', price => { cart = price; }); - Given('discount is {int} %', (discount) => { + Given('discount is {int} %', discount => { cart -= (cart * discount) / 100; }); - Then('I should see price is {string} $', (total) => { + Then('I should see price is {string} $', total => { sum = parseInt(total, 10); }); @@ -351,7 +351,7 @@ describe('BDD', () => { }); }); - it('should provide a parsed DataTable', (done) => { + it('should provide a parsed DataTable', done => { const text = ` @awesome @cool Feature: checkout process @@ -371,11 +371,11 @@ describe('BDD', () => { let givenParsedRows; let thenParsedRows; - Given('I have the following products :', (products) => { + Given('I have the following products :', products => { expect(products.rows.length).to.equal(3); givenParsedRows = products.parse(); }); - Then('I should see the following products :', (products) => { + Then('I should see the following products :', products => { expect(products.rows.length).to.equal(3); thenParsedRows = products.parse(); }); @@ -395,14 +395,14 @@ describe('BDD', () => { }); }); - it('should match step with custom parameter type', (done) => { + it('should match step with custom parameter type', done => { const colorType = { name: 'color', regexp: /red|blue|yellow/, - transformer: (s) => new Color(s), + transformer: s => new Color(s), }; defineParameterType(colorType); - Given('I have a {color} label', (color) => color); + Given('I have a {color} label', color => color); const fn = matchStep('I have a red label'); expect('red').is.equal(fn.params[0].name); done(); @@ -412,10 +412,10 @@ describe('BDD', () => { const colorType = { name: 'async_color', regexp: /red|blue|yellow/, - transformer: async (s) => new Color(s), + transformer: async s => new Color(s), }; defineParameterType(colorType); - Given('I have a {async_color} label', (color) => color); + Given('I have a {async_color} label', color => color); const fn = matchStep('I have a blue label'); const color = await fn.params[0]; expect('blue').is.equal(color.name); diff --git a/test/unit/container_test.js b/test/unit/container_test.js index 6ece3d439..0718e1fe4 100644 --- a/test/unit/container_test.js +++ b/test/unit/container_test.js @@ -1,5 +1,5 @@ let expect; -import('chai').then((chai) => { +import('chai').then(chai => { expect = chai.expect; }); const path = require('path'); @@ -17,7 +17,7 @@ describe('Container', () => { afterEach(() => { container.clear(); - ['I', 'dummy_page'].forEach((po) => { + ['I', 'dummy_page'].forEach(po => { const name = require.resolve(path.join(__dirname, `../data/${po}`)); delete require.cache[name]; }); diff --git a/test/unit/worker_test.js b/test/unit/worker_test.js index e7bdb3948..e65e4f969 100644 --- a/test/unit/worker_test.js +++ b/test/unit/worker_test.js @@ -10,7 +10,7 @@ describe('Workers', function () { global.codecept_dir = path.join(__dirname, '/../data/sandbox'); }); - it('should run simple worker', (done) => { + it('should run simple worker', done => { const workerConfig = { by: 'test', testConfig: './test/data/sandbox/codecept.workers.conf.js', @@ -28,7 +28,7 @@ describe('Workers', function () { workers.run(); - workers.on(event.all.result, (status) => { + workers.on(event.all.result, status => { expect(status).equal(false); expect(passedCount).equal(5); expect(failedCount).equal(3); @@ -36,7 +36,7 @@ describe('Workers', function () { }); }); - it('should create worker by function', (done) => { + it('should create worker by function', done => { const createTestGroups = () => { const files = [[path.join(codecept_dir, '/custom-worker/base_test.worker.js')], [path.join(codecept_dir, '/custom-worker/custom_test.worker.js')]]; @@ -63,14 +63,14 @@ describe('Workers', function () { workers.run(); - workers.on(event.all.result, (status) => { + workers.on(event.all.result, status => { expect(workers.getWorkers().length).equal(2); expect(status).equal(true); done(); }); }); - it('should run worker with custom config', (done) => { + it('should run worker with custom config', done => { const workerConfig = { by: 'test', testConfig: './test/data/sandbox/codecept.customworker.js', @@ -93,14 +93,14 @@ describe('Workers', function () { workers.run(); - workers.on(event.test.failed, (test) => { + workers.on(event.test.failed, test => { failedCount += 1; }); - workers.on(event.test.passed, (test) => { + workers.on(event.test.passed, test => { passedCount += 1; }); - workers.on(event.all.result, (status) => { + workers.on(event.all.result, status => { expect(status).equal(false); expect(passedCount).equal(3); expect(failedCount).equal(2); @@ -108,7 +108,7 @@ describe('Workers', function () { }); }); - it('should able to add tests to each worker', (done) => { + it('should able to add tests to each worker', done => { const workerConfig = { by: 'test', testConfig: './test/data/sandbox/codecept.customworker.js', @@ -135,14 +135,14 @@ describe('Workers', function () { workers.run(); - workers.on(event.all.result, (status) => { + workers.on(event.all.result, status => { expect(workers.getWorkers().length).equal(2); expect(status).equal(true); done(); }); }); - it('should able to add tests to using createGroupsOfTests', (done) => { + it('should able to add tests to using createGroupsOfTests', done => { const workerConfig = { by: 'test', testConfig: './test/data/sandbox/codecept.customworker.js', @@ -170,14 +170,14 @@ describe('Workers', function () { workers.run(); - workers.on(event.all.result, (status) => { + workers.on(event.all.result, status => { expect(workers.getWorkers().length).equal(2); expect(status).equal(true); done(); }); }); - it('Should able to pass data from workers to main thread and vice versa', (done) => { + it('Should able to pass data from workers to main thread and vice versa', done => { const workerConfig = { by: 'test', testConfig: './test/data/sandbox/codecept.customworker.js', @@ -199,13 +199,13 @@ describe('Workers', function () { workers.run(); recorder.add(() => share({ fromMain: true })); - workers.on(event.all.result, (status) => { + workers.on(event.all.result, status => { expect(status).equal(true); done(); }); }); - it('should propagate non test events', (done) => { + it('should propagate non test events', done => { const messages = []; const createTestGroups = () => { @@ -223,7 +223,7 @@ describe('Workers', function () { workers.run(); - workers.on('message', (data) => { + workers.on('message', data => { messages.push(data); }); @@ -235,7 +235,7 @@ describe('Workers', function () { }); }); - it('should run worker with multiple config', (done) => { + it('should run worker with multiple config', done => { const workerConfig = { by: 'test', testConfig: './test/data/sandbox/codecept.multiple.js', @@ -258,7 +258,7 @@ describe('Workers', function () { workers.run(); - workers.on(event.all.result, (status) => { + workers.on(event.all.result, status => { expect(workers.getWorkers().length).equal(8); expect(status).equal(true); done(); From 59b5a742530c8300ca194e5274a66c27b0f9ed72 Mon Sep 17 00:00:00 2001 From: DavertMik Date: Tue, 31 Dec 2024 02:20:16 +0200 Subject: [PATCH 37/37] fixed runner tests --- lib/container.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/container.js b/lib/container.js index 6795fd4d0..34a0058de 100644 --- a/lib/container.js +++ b/lib/container.js @@ -39,8 +39,14 @@ class Container { */ static create(config, opts) { asyncHelperPromise = Promise.resolve(); - this.createMocha(config, opts); + // dynamically create mocha instance + const mochaConfig = config.mocha || {}; + if (config.grep && !opts.grep) mochaConfig.grep = config.grep; + this.createMocha = () => (container.mocha = MochaFactory.create(mochaConfig, opts || {})); + this.createMocha(); + + // create support objects container.support = {}; container.helpers = createHelpers(config.helpers || {}); container.translation = loadTranslation(config.translation || null, config.vocabularies || []);