diff --git a/.gitignore b/.gitignore
index 74e2f27d9..899a0b988 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,4 +21,5 @@ testpullfilecache*
package-lock.json
yarn.lock
/.vs
-typings/types.d.ts
\ No newline at end of file
+typings/types.d.ts
+typings/promiseBasedTypes.d.ts
\ No newline at end of file
diff --git a/docs/typescript.md b/docs/typescript.md
index eb8ac6b31..593875c05 100644
--- a/docs/typescript.md
+++ b/docs/typescript.md
@@ -138,3 +138,15 @@ declare namespace CodeceptJS {
}
}
```
+
+## Full promise-based methods
+
+All CodeceptJS methods return a promise; however, some of its are not typed as accordingly.
+This feature, which is enabled by [configuration](https://codecept.io/configuration/), refers to alternative typescript definitions transforming all methods to asynchronous actions.
+
+How to enable it?
+- Add required configuration
+```ts
+ fullPromiseBased: true;
+```
+- Refresh internal TypeScript definitions by running following command: `npx codeceptjs def`
\ No newline at end of file
diff --git a/lib/command/definitions.js b/lib/command/definitions.js
index c3c09fcdb..07edaf815 100644
--- a/lib/command/definitions.js
+++ b/lib/command/definitions.js
@@ -138,7 +138,8 @@ module.exports = function (genPath, options) {
helperPaths[name] = require;
helperNames.push(name);
} else {
- helperNames.push(name);
+ const fullBasedPromised = codecept.config.fullPromiseBased;
+ helperNames.push(fullBasedPromised === true ? `${name}Ts` : name);
}
if (!actingHelpers.includes(name)) {
diff --git a/package.json b/package.json
index 4d550e9ea..8e5ff18b8 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
"lint-fix": "eslint bin/ examples/ lib/ test/ translations/ runok.js --fix",
"docs": "./runok.js docs",
"test:unit": "mocha test/unit --recursive",
- "test:runner": "mocha test/runner --recursive",
+ "test:runner": "mocha test/runner --recursive --timeout 5000",
"test": "npm run test:unit && npm run test:runner",
"test:appium-quick": "mocha test/helper/Appium_test.js --grep 'quick'",
"test:appium-other": "mocha test/helper/Appium_test.js --grep 'second'",
diff --git a/runok.js b/runok.js
index a94bb6a41..193950185 100755
--- a/runok.js
+++ b/runok.js
@@ -32,6 +32,10 @@ module.exports = {
async defTypings() {
console.log('Generate TypeScript definition');
+ // Generate definitions for promised-based helper methods
+ await npx('jsdoc -c typings/jsdocPromiseBased.conf.js');
+ fs.renameSync('typings/types.d.ts', 'typings/promiseBasedTypes.d.ts');
+ // Generate all other regular definitions
await npx('jsdoc -c typings/jsdoc.conf.js');
},
diff --git a/test/data/sandbox/configs/definitions/codecept.promise.based.js b/test/data/sandbox/configs/definitions/codecept.promise.based.js
new file mode 100644
index 000000000..8514d8e8e
--- /dev/null
+++ b/test/data/sandbox/configs/definitions/codecept.promise.based.js
@@ -0,0 +1,13 @@
+exports.config = {
+ tests: './*_test.js',
+ timeout: 10000,
+ output: './output',
+ helpers: {
+ FileSystem: {},
+ },
+ include: {},
+ bootstrap: false,
+ mocha: {},
+ name: 'sandbox',
+ fullPromiseBased: true,
+};
diff --git a/test/runner/bdd_test.js b/test/runner/bdd_test.js
index 9fe462022..201381587 100644
--- a/test/runner/bdd_test.js
+++ b/test/runner/bdd_test.js
@@ -193,7 +193,7 @@ describe('BDD Gherkin', () => {
});
it('should show all available steps', (done) => {
- exec(`${runner} gherkin:steps --config ${codecept_dir}/codecept.bdd.json`, (err, stdout, stderr) => { //eslint-disable-line
+ exec(`${runner} gherkin:steps --config ${codecept_dir}/codecept.bdd.js`, (err, stdout, stderr) => { //eslint-disable-line
stdout.should.include('Gherkin');
stdout.should.include('/I have product with \\$(\\d+) price/');
stdout.should.include('step_definitions/my_steps.js:3:1');
@@ -206,7 +206,7 @@ describe('BDD Gherkin', () => {
});
it('should generate snippets for missing steps', (done) => {
- exec(`${runner} gherkin:snippets --dry-run --config ${codecept_dir}/codecept.dummy.bdd.json`, (err, stdout, stderr) => { //eslint-disable-line
+ exec(`${runner} gherkin:snippets --dry-run --config ${codecept_dir}/codecept.dummy.bdd.js`, (err, stdout, stderr) => { //eslint-disable-line
stdout.should.include(`Given('I open a browser on a site', () => {
// From "support/dummy.feature" {"line":4,"column":5}
throw new Error('Not implemented yet');
@@ -277,7 +277,7 @@ When(/^I define a step with a \\( paren and a "(.*?)" string$/, () => {
});
it('should not generate duplicated steps', (done) => {
- exec(`${runner} gherkin:snippets --dry-run --config ${codecept_dir}/codecept.duplicate.bdd.json`, (err, stdout, stderr) => { //eslint-disable-line
+ exec(`${runner} gherkin:snippets --dry-run --config ${codecept_dir}/codecept.duplicate.bdd.js`, (err, stdout, stderr) => { //eslint-disable-line
assert.equal(stdout.match(/I open a browser on a site/g).length, 1);
assert(!err);
done();
diff --git a/test/runner/before_failure_test.js b/test/runner/before_failure_test.js
index 9263ceafb..fee680070 100644
--- a/test/runner/before_failure_test.js
+++ b/test/runner/before_failure_test.js
@@ -3,7 +3,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} run --config ${codecept_dir}/codecept.beforetest.failure.json `;
+const codecept_run = `${runner} run --config ${codecept_dir}/codecept.beforetest.failure.js `;
describe('Failure in before', function () {
this.timeout(5000);
diff --git a/test/runner/definitions_test.js b/test/runner/definitions_test.js
index 21ef4cfc9..170f2b499 100644
--- a/test/runner/definitions_test.js
+++ b/test/runner/definitions_test.js
@@ -34,7 +34,7 @@ describe('Definitions', function () {
describe('Static files', () => {
it('should have internal object that is available as variable codeceptjs', (done) => {
- exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.json`, () => {
+ exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.js`, () => {
const types = typesFrom(`${codecept_dir}/steps.d.ts`);
types.should.be.valid;
@@ -79,7 +79,7 @@ describe('Definitions', function () {
});
it('def should create definition file with correct page def', (done) => {
- exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.json`, (err, stdout) => {
+ exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.js`, (err, stdout) => {
stdout.should.include('Definitions were generated in steps.d.ts');
const types = typesFrom(`${codecept_dir}/steps.d.ts`);
types.should.be.valid;
@@ -94,7 +94,7 @@ describe('Definitions', function () {
});
it('def should create definition file given a config file', (done) => {
- exec(`${runner} def --config ${codecept_dir}/../../codecept.ddt.json`, (err, stdout) => {
+ exec(`${runner} def --config ${codecept_dir}/../../codecept.ddt.js`, (err, stdout) => {
stdout.should.include('Definitions were generated in steps.d.ts');
const types = typesFrom(`${codecept_dir}/../../steps.d.ts`);
types.should.be.valid;
@@ -104,7 +104,7 @@ describe('Definitions', function () {
});
it('def should create definition file with support object', (done) => {
- exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.json`, () => {
+ exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.js`, () => {
const types = typesFrom(`${codecept_dir}/steps.d.ts`);
types.should.be.valid;
@@ -128,7 +128,7 @@ describe('Definitions', function () {
});
it('def should create definition file with inject which contains support objects', (done) => {
- exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.json`, () => {
+ exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.js`, () => {
const types = typesFrom(`${codecept_dir}/steps.d.ts`);
types.should.be.valid;
@@ -145,7 +145,7 @@ describe('Definitions', function () {
});
it('def should create definition file with inject which contains I object', (done) => {
- exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.json`, (err) => {
+ exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.js`, (err) => {
assert(!err);
const types = typesFrom(`${codecept_dir}/steps.d.ts`);
types.should.be.valid;
@@ -165,7 +165,7 @@ describe('Definitions', function () {
});
it('def should create definition file with inject which contains I object from helpers', (done) => {
- exec(`${runner} def --config ${codecept_dir}//codecept.inject.powi.json`, () => {
+ exec(`${runner} def --config ${codecept_dir}/codecept.inject.powi.js`, () => {
const types = typesFrom(`${codecept_dir}/steps.d.ts`);
types.should.be.valid;
@@ -179,7 +179,7 @@ describe('Definitions', function () {
});
it('def should create definition file with callback params', (done) => {
- exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.json`, () => {
+ exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.js`, () => {
const types = typesFrom(`${codecept_dir}/steps.d.ts`);
types.should.be.valid;
@@ -193,6 +193,30 @@ describe('Definitions', function () {
done();
});
});
+
+ it('def should create definition file with promise-based feature', (done) => {
+ exec(`${runner} def --config ${codecept_dir}/codecept.promise.based.js`, (err, stdout) => {
+ stdout.should.include('Definitions were generated in steps.d.ts');
+ const types = typesFrom(`${codecept_dir}/steps.d.ts`);
+ types.should.be.valid;
+
+ const definitionFile = types.getSourceFileOrThrow(`${codecept_dir}/steps.d.ts`);
+ const extend = getExtends(definitionFile.getNamespaceOrThrow('CodeceptJS').getInterfaceOrThrow('I'));
+ extend.should.containSubset([{
+ methods: [{
+ name: 'amInPath',
+ returnType: 'Promise',
+ parameters: [{ name: 'openPath', type: 'string' }],
+ }, {
+ name: 'seeFile',
+ returnType: 'Promise',
+ parameters: [{ name: 'name', type: 'string' }],
+ }],
+ }]);
+ assert(!err);
+ done();
+ });
+ });
});
/** @type {Chai.ChaiPlugin */
diff --git a/test/runner/init_test.js b/test/runner/init_test.js
index 5bbc1842b..5c1d0ee31 100644
--- a/test/runner/init_test.js
+++ b/test/runner/init_test.js
@@ -35,13 +35,13 @@ describe('Init Command', function () {
});
it('init - Where should logs, screenshots, and reports to be stored? (./output)', async () => {
- const result = await run([runner, 'init'], ['Y', ENTER, ENTER, DOWN, DOWN, DOWN, ENTER]);
+ const result = await run([runner, 'init'], ['Y', ENTER, ENTER, DOWN, DOWN, DOWN, ENTER, ENTER]);
result.should.include('? What helpers do you want to use? REST');
result.should.include('Where should logs, screenshots, and reports to be stored? (./output)');
});
it('init - Do you want localization for tests? (See https://codecept.io/translation/)', async () => {
- const result = await run([runner, 'init'], ['Y', ENTER, ENTER, DOWN, DOWN, DOWN, ENTER, ENTER]);
+ const result = await run([runner, 'init'], ['Y', ENTER, ENTER, DOWN, DOWN, DOWN, ENTER, ENTER, ENTER]);
result.should.include('? Do you want localization for tests? (See https://codecept.io/translation/)');
result.should.include('❯ English (no localization)');
for (const item of ['de-DE', 'it-IT', 'fr-FR', 'ja-JP', 'pl-PL', 'pt-BR']) {
@@ -51,7 +51,7 @@ describe('Init Command', function () {
});
it('init - [REST] Endpoint of API you are going to test (http://localhost:3000/api)', async () => {
- const result = await run([runner, 'init'], ['Y', ENTER, ENTER, DOWN, DOWN, DOWN, ENTER, ENTER, ENTER]);
+ const result = await run([runner, 'init'], ['Y', ENTER, ENTER, DOWN, DOWN, DOWN, ENTER, ENTER, ENTER, ENTER]);
result.should.include('Do you want localization for tests? (See https://codecept.io/translation/) Eng');
result.should.include('Configure helpers...');
result.should.include('? [REST] Endpoint of API you are going to test (http://localhost:3000/api)');
diff --git a/test/runner/run_multiple_test.js b/test/runner/run_multiple_test.js
index e56615eb3..7fc4cc33a 100644
--- a/test/runner/run_multiple_test.js
+++ b/test/runner/run_multiple_test.js
@@ -5,7 +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} run-multiple --config ${codecept_dir}/codecept.multiple.json `;
+const codecept_run = `${runner} run-multiple --config ${codecept_dir}/codecept.multiple.js `;
describe('CodeceptJS Multiple Runner', function () {
this.timeout(40000);
@@ -175,7 +175,7 @@ describe('CodeceptJS Multiple Runner', function () {
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.json default --all`, (err, stdout) => {
+ 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');
@@ -235,7 +235,7 @@ describe('CodeceptJS Multiple Runner', function () {
it('should be executed with several module when described', (done) => {
process.chdir(codecept_dir);
- exec(`${runner} ${_codecept_run}/codecept.require.multiple.several.json default`, (err, stdout) => {
+ 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);
diff --git a/test/runner/timeout_test.js b/test/runner/timeout_test.js
index 208203401..f6aa46854 100644
--- a/test/runner/timeout_test.js
+++ b/test/runner/timeout_test.js
@@ -6,7 +6,7 @@ const debug_this_test = false;
const config_run_config = (config, grep, verbose = false) => `${codecept_run} ${verbose || debug_this_test ? '--verbose' : ''} --config ${codecept_dir}/configs/timeouts/${config} ${grep ? `--grep "${grep}"` : ''}`;
-describe.only('CodeceptJS Timeouts', function () {
+describe('CodeceptJS Timeouts', function () {
this.timeout(10000);
it('should stop test when timeout exceeded', (done) => {
diff --git a/typings/index.d.ts b/typings/index.d.ts
index f8bc4ff33..d0becc55d 100644
--- a/typings/index.d.ts
+++ b/typings/index.d.ts
@@ -1,5 +1,6 @@
// Project: https://github.com/codeception/codeceptjs/
///
+///
///
///
///
@@ -260,6 +261,13 @@ declare namespace CodeceptJS {
steps: Array
};
+ /**
+ * Enable full promise-based helper methods for [TypeScript](https://codecept.io/typescript/) project.
+ * If true, all helper methods are typed as asynchronous;
+ * Otherwise, it remains as it works in versions prior to 3.3.6
+ */
+ fullPromiseBased?: boolean;
+
[key: string]: any;
};
diff --git a/typings/jsdoc.promiseBased.js b/typings/jsdoc.promiseBased.js
new file mode 100644
index 000000000..95003a4ed
--- /dev/null
+++ b/typings/jsdoc.promiseBased.js
@@ -0,0 +1,35 @@
+// Helps tsd-jsdoc to exports all helpers methods as Promise
+// - Before parsing JS file, change class name and remove configuration already exported
+// - For each method set by default 'Promise' if there is no returns tag or if the returns tag doesn't handle a promise
+
+const isHelper = (path) => path.includes('docs/build');
+const isDocumentedMethod = (doclet) => doclet.undocumented !== true
+ && doclet.kind === 'function'
+ && doclet.scope === 'instance';
+const shouldOverrideReturns = (doclet) => !doclet.returns
+ || !doclet.returns[0].type
+ || !doclet.returns[0].type.names[0].includes('Promise');
+
+module.exports = {
+ handlers: {
+ beforeParse(e) {
+ if (isHelper(e.filename)) {
+ e.source = e.source
+ // add 'Ts' suffix to generate promise-based helpers definition
+ .replace(/class (.*) extends/, 'class $1Ts extends')
+ // rename parent class to fix the inheritance
+ .replace(/(@augments \w+)/, '$1Ts')
+ // do not export twice the configuration of the helpers
+ .replace(/\/\*\*(.+?(?=config))config = \{\};/s, '');
+ }
+ },
+ newDoclet: ({ doclet }) => {
+ if (isHelper(doclet.meta.path)
+ && isDocumentedMethod(doclet)
+ && shouldOverrideReturns(doclet)) {
+ doclet.returns = [];
+ doclet.addTag('returns', '{Promise}');
+ }
+ },
+ },
+};
diff --git a/typings/jsdocPromiseBased.conf.js b/typings/jsdocPromiseBased.conf.js
new file mode 100644
index 000000000..05f660273
--- /dev/null
+++ b/typings/jsdocPromiseBased.conf.js
@@ -0,0 +1,13 @@
+module.exports = {
+ source: {
+ include: [
+ './docs/build',
+ ],
+ },
+ opts: {
+ template: 'node_modules/tsd-jsdoc/dist',
+ recurse: true,
+ destination: './typings/',
+ },
+ plugins: ['jsdoc.promiseBased.js', 'jsdoc.namespace.js', 'jsdoc-typeof-plugin'],
+};
diff --git a/typings/tests/helpers/Appium.types.ts b/typings/tests/helpers/Appium.types.ts
index 917f67e86..068d89b03 100644
--- a/typings/tests/helpers/Appium.types.ts
+++ b/typings/tests/helpers/Appium.types.ts
@@ -1,7 +1,9 @@
+export {}; // mark the file as external module to redeclare variables in the same block
+
const appium = new CodeceptJS.Appium();
-const str_ap = "text";
-const num_ap = 1;
+const str = "text";
+const num = 1;
const appPackage = "com.example.android.apis";
appium.touchPerform(); // $ExpectError
@@ -20,13 +22,13 @@ appium.removeApp("appName"); // $ExpectType void
appium.removeApp("appName", appPackage); // $ExpectType void
appium.removeApp("appName", appPackage, "remove"); // $ExpectError
-appium.runOnIOS(str_ap, () => {}); // $ExpectType void
-appium.runOnAndroid(str_ap, () => {}); // $ExpectType void
-appium.seeAppIsInstalled(str_ap); // $ExpectType Promise
-appium.seeAppIsNotInstalled(str_ap); // $ExpectType Promise
-appium.installApp(str_ap); // $ExpectType Promise
-appium.removeApp(str_ap); // $ExpectType void
-appium.seeCurrentActivityIs(str_ap); // $ExpectType Promise
+appium.runOnIOS(str, () => {}); // $ExpectType void
+appium.runOnAndroid(str, () => {}); // $ExpectType void
+appium.seeAppIsInstalled(str); // $ExpectType Promise
+appium.seeAppIsNotInstalled(str); // $ExpectType Promise
+appium.installApp(str); // $ExpectType Promise
+appium.removeApp(str); // $ExpectType void
+appium.seeCurrentActivityIs(str); // $ExpectType Promise
appium.seeDeviceIsLocked(); // $ExpectType Promise
appium.seeDeviceIsUnlocked(); // $ExpectType Promise
appium.seeOrientationIs("LANDSCAPE"); // $ExpectType Promise
@@ -37,56 +39,56 @@ appium.grabCurrentActivity(); // $ExpectType Promise
appium.grabNetworkConnection(); // $ExpectType Promise<{}>
appium.grabOrientation(); // $ExpectType Promise
appium.grabSettings(); // $ExpectType Promise
-appium._switchToContext(str_ap); // $ExpectType void
+appium._switchToContext(str); // $ExpectType void
appium.switchToWeb(); // $ExpectType Promise
appium.switchToNative(); // $ExpectType Promise
-appium.switchToNative(str_ap); // $ExpectType Promise
+appium.switchToNative(str); // $ExpectType Promise
appium.startActivity(); // $ExpectError
appium.startActivity(appPackage); // $ExpectError
appium.startActivity(appPackage, '.RegisterUserActivity'); // $ExpectType Promise
appium.setNetworkConnection(); // $ExpectType Promise<{}>
-appium.setSettings(str_ap); // $ExpectType void
+appium.setSettings(str); // $ExpectType void
appium.hideDeviceKeyboard(); // $ExpectType void
-appium.sendDeviceKeyEvent(num_ap); // $ExpectType Promise
+appium.sendDeviceKeyEvent(num); // $ExpectType Promise
appium.openNotifications(); // $ExpectType Promise
appium.makeTouchAction(); // $ExpectType Promise
-appium.tap(str_ap); // $ExpectType Promise
-appium.performSwipe(str_ap, str_ap); // $ExpectType void
-appium.swipeDown(str_ap); // $ExpectType Promise
-appium.swipeLeft(str_ap); // $ExpectType Promise
-appium.swipeRight(str_ap); // $ExpectType Promise
-appium.swipeUp(str_ap); // $ExpectType Promise
-appium.swipeTo(str_ap, str_ap, str_ap, num_ap, num_ap, num_ap); // $ExpectType Promise
+appium.tap(str); // $ExpectType Promise
+appium.performSwipe(str, str); // $ExpectType void
+appium.swipeDown(str); // $ExpectType Promise
+appium.swipeLeft(str); // $ExpectType Promise
+appium.swipeRight(str); // $ExpectType Promise
+appium.swipeUp(str); // $ExpectType Promise
+appium.swipeTo(str, str, str, num, num, num); // $ExpectType Promise
appium.touchPerform([]); // $ExpectType void
-appium.pullFile(str_ap, str_ap); // $ExpectType Promise
+appium.pullFile(str, str); // $ExpectType Promise
appium.shakeDevice(); // $ExpectType Promise
appium.rotate(); // $ExpectType Promise
appium.setImmediateValue(); // $ExpectType Promise
appium.simulateTouchId(); // $ExpectType Promise
appium.closeApp(); // $ExpectType Promise
-appium.appendField(str_ap, str_ap); // $ExpectType void
-appium.checkOption(str_ap); // $ExpectType void
-appium.click(str_ap); // $ExpectType void
-appium.dontSeeCheckboxIsChecked(str_ap); // $ExpectType void
-appium.dontSeeElement(str_ap); // $ExpectType void
-appium.dontSeeInField(str_ap, str_ap); // $ExpectType void
-appium.dontSee(str_ap); // $ExpectType void
-appium.fillField(str_ap, str_ap); // $ExpectType void
-appium.grabTextFromAll(str_ap); // $ExpectType Promise
-appium.grabTextFrom(str_ap); // $ExpectType Promise
-appium.grabNumberOfVisibleElements(str_ap); // $ExpectType Promise
-appium.grabAttributeFrom(str_ap, str_ap); // $ExpectType Promise
-appium.grabAttributeFromAll(str_ap, str_ap); // $ExpectType Promise
-appium.grabValueFromAll(str_ap); // $ExpectType Promise
-appium.grabValueFrom(str_ap); // $ExpectType Promise
-appium.saveScreenshot(str_ap); // $ExpectType Promise
-appium.scrollIntoView(str_ap, {}); // $ExpectType void
-appium.seeCheckboxIsChecked(str_ap); // $ExpectType void
-appium.seeElement(str_ap); // $ExpectType void
-appium.seeInField(str_ap, str_ap); // $ExpectType void
-appium.see(str_ap); // $ExpectType void
-appium.selectOption(str_ap, str_ap); // $ExpectType void
-appium.waitForElement(str_ap); // $ExpectType void
-appium.waitForVisible(str_ap); // $ExpectType void
-appium.waitForInvisible(str_ap); // $ExpectType void
-appium.waitForText(str_ap); // $ExpectType void
+appium.appendField(str, str); // $ExpectType void
+appium.checkOption(str); // $ExpectType void
+appium.click(str); // $ExpectType void
+appium.dontSeeCheckboxIsChecked(str); // $ExpectType void
+appium.dontSeeElement(str); // $ExpectType void
+appium.dontSeeInField(str, str); // $ExpectType void
+appium.dontSee(str); // $ExpectType void
+appium.fillField(str, str); // $ExpectType void
+appium.grabTextFromAll(str); // $ExpectType Promise
+appium.grabTextFrom(str); // $ExpectType Promise
+appium.grabNumberOfVisibleElements(str); // $ExpectType Promise
+appium.grabAttributeFrom(str, str); // $ExpectType Promise
+appium.grabAttributeFromAll(str, str); // $ExpectType Promise
+appium.grabValueFromAll(str); // $ExpectType Promise
+appium.grabValueFrom(str); // $ExpectType Promise
+appium.saveScreenshot(str); // $ExpectType Promise
+appium.scrollIntoView(str, {}); // $ExpectType void
+appium.seeCheckboxIsChecked(str); // $ExpectType void
+appium.seeElement(str); // $ExpectType void
+appium.seeInField(str, str); // $ExpectType void
+appium.see(str); // $ExpectType void
+appium.selectOption(str, str); // $ExpectType void
+appium.waitForElement(str); // $ExpectType void
+appium.waitForVisible(str); // $ExpectType void
+appium.waitForInvisible(str); // $ExpectType void
+appium.waitForText(str); // $ExpectType void
diff --git a/typings/tests/helpers/AppiumTs.types.ts b/typings/tests/helpers/AppiumTs.types.ts
new file mode 100644
index 000000000..0a3e9d9ca
--- /dev/null
+++ b/typings/tests/helpers/AppiumTs.types.ts
@@ -0,0 +1,94 @@
+export {}; // mark the file as external module to redeclare variables in the same block
+
+const appium = new CodeceptJS.AppiumTs();
+
+const str = "text";
+const num = 1;
+const appPackage = "com.example.android.apis";
+
+appium.touchPerform(); // $ExpectError
+appium.touchPerform("press"); // $ExpectError
+appium.touchPerform([{ action: "press" }]); // $ExpectType Promise
+appium.touchPerform([{ action: "press" }, { action: "release" }]); // $ExpectType Promise
+appium.touchPerform([{ action: "press" }], [{ action: "release" }]); // $ExpectError
+
+appium.hideDeviceKeyboard(); // $ExpectType Promise
+appium.hideDeviceKeyboard("tapOutside"); // $ExpectType Promise
+appium.hideDeviceKeyboard("pressKey", "Done"); // $ExpectType Promise
+appium.hideDeviceKeyboard("pressKey", "Done", "Done"); // $ExpectError
+
+appium.removeApp(); // $ExpectError
+appium.removeApp("appName"); // $ExpectType Promise
+appium.removeApp("appName", appPackage); // $ExpectType Promise
+appium.removeApp("appName", appPackage, "remove"); // $ExpectError
+
+appium.runOnIOS(str, () => {}); // $ExpectType Promise
+appium.runOnAndroid(str, () => {}); // $ExpectType Promise
+appium.seeAppIsInstalled(str); // $ExpectType Promise
+appium.seeAppIsNotInstalled(str); // $ExpectType Promise
+appium.installApp(str); // $ExpectType Promise
+appium.removeApp(str); // $ExpectType Promise
+appium.seeCurrentActivityIs(str); // $ExpectType Promise
+appium.seeDeviceIsLocked(); // $ExpectType Promise
+appium.seeDeviceIsUnlocked(); // $ExpectType Promise
+appium.seeOrientationIs("LANDSCAPE"); // $ExpectType Promise
+appium.setOrientation("LANDSCAPE"); // $ExpectType Promise
+appium.grabAllContexts(); // $ExpectType Promise
+appium.grabContext(); // $ExpectType Promise
+appium.grabCurrentActivity(); // $ExpectType Promise
+appium.grabNetworkConnection(); // $ExpectType Promise<{}>
+appium.grabOrientation(); // $ExpectType Promise
+appium.grabSettings(); // $ExpectType Promise
+appium._switchToContext(str); // $ExpectType Promise
+appium.switchToWeb(); // $ExpectType Promise
+appium.switchToNative(); // $ExpectType Promise
+appium.switchToNative(str); // $ExpectType Promise
+appium.startActivity(); // $ExpectError
+appium.startActivity(appPackage); // $ExpectError
+appium.startActivity(appPackage, '.RegisterUserActivity'); // $ExpectType Promise
+appium.setNetworkConnection(); // $ExpectType Promise<{}>
+appium.setSettings(str); // $ExpectType Promise
+appium.hideDeviceKeyboard(); // $ExpectType Promise
+appium.sendDeviceKeyEvent(num); // $ExpectType Promise
+appium.openNotifications(); // $ExpectType Promise
+appium.makeTouchAction(); // $ExpectType Promise
+appium.tap(str); // $ExpectType Promise
+appium.performSwipe(str, str); // $ExpectType Promise
+appium.swipeDown(str); // $ExpectType Promise
+appium.swipeLeft(str); // $ExpectType Promise
+appium.swipeRight(str); // $ExpectType Promise
+appium.swipeUp(str); // $ExpectType Promise
+appium.swipeTo(str, str, str, num, num, num); // $ExpectType Promise
+appium.touchPerform([]); // $ExpectType Promise
+appium.pullFile(str, str); // $ExpectType Promise
+appium.shakeDevice(); // $ExpectType Promise
+appium.rotate(); // $ExpectType Promise
+appium.setImmediateValue(); // $ExpectType Promise
+appium.simulateTouchId(); // $ExpectType Promise
+appium.closeApp(); // $ExpectType Promise
+appium.appendField(str, str); // $ExpectType Promise
+appium.checkOption(str); // $ExpectType Promise
+appium.click(str); // $ExpectType Promise
+appium.dontSeeCheckboxIsChecked(str); // $ExpectType Promise
+appium.dontSeeElement(str); // $ExpectType Promise
+appium.dontSeeInField(str, str); // $ExpectType Promise
+appium.dontSee(str); // $ExpectType Promise
+appium.fillField(str, str); // $ExpectType Promise
+appium.grabTextFromAll(str); // $ExpectType Promise
+appium.grabTextFrom(str); // $ExpectType Promise
+appium.grabNumberOfVisibleElements(str); // $ExpectType Promise
+appium.grabAttributeFrom(str, str); // $ExpectType Promise
+appium.grabAttributeFromAll(str, str); // $ExpectType Promise
+appium.grabValueFromAll(str); // $ExpectType Promise
+appium.grabValueFrom(str); // $ExpectType Promise
+appium.saveScreenshot(str); // $ExpectType Promise
+appium.scrollIntoView(str, {}); // $ExpectType Promise
+appium.seeCheckboxIsChecked(str); // $ExpectType Promise
+appium.seeElement(str); // $ExpectType Promise
+appium.seeInField(str, str); // $ExpectType Promise
+appium.see(str); // $ExpectType Promise
+appium.selectOption(str, str); // $ExpectType Promise
+appium.waitForElement(str); // $ExpectType Promise
+appium.waitForVisible(str); // $ExpectType Promise
+appium.waitForInvisible(str); // $ExpectType Promise
+appium.waitForText(str); // $ExpectType Promise
diff --git a/typings/tests/helpers/Playwright.types.ts b/typings/tests/helpers/Playwright.types.ts
index 41a37c926..29b3c0a9a 100644
--- a/typings/tests/helpers/Playwright.types.ts
+++ b/typings/tests/helpers/Playwright.types.ts
@@ -1,36 +1,38 @@
+export {}; // mark the file as external module to redeclare variables in the same block
+
const playwright = new CodeceptJS.Playwright();
-const str_pl = 'text';
-const num_pl = 1;
+const str = 'text';
+const num = 1;
const position = { x: 100, y: 200 };
const sourcePosition = { x: 10, y: 20 };
const targetPosition = { x: 20, y: 30 };
-playwright.usePlaywrightTo(str_pl, () => {}); // $ExpectType void
+playwright.usePlaywrightTo(str, () => {}); // $ExpectType void
playwright.amAcceptingPopups(); // $ExpectType void
playwright.acceptPopup(); // $ExpectType void
playwright.amCancellingPopups(); // $ExpectType void
playwright.cancelPopup(); // $ExpectType void
-playwright.seeInPopup(str_pl); // $ExpectType void
-playwright._setPage(str_pl); // $ExpectType void
+playwright.seeInPopup(str); // $ExpectType void
+playwright._setPage(str); // $ExpectType void
playwright._addPopupListener(); // $ExpectType void
playwright._getPageUrl(); // $ExpectType void
playwright.grabPopupText(); // $ExpectType Promise
-playwright.amOnPage(str_pl); // $ExpectType void
-playwright.resizeWindow(num_pl, num_pl); // $ExpectType void
-playwright.haveRequestHeaders(str_pl); // $ExpectType void
-playwright.moveCursorTo(str_pl, num_pl, num_pl); // $ExpectType void
-playwright.dragAndDrop(str_pl); // $ExpectError
-playwright.dragAndDrop(str_pl, str_pl); // $ExpectType void
-playwright.dragAndDrop(str_pl, str_pl, { sourcePosition, targetPosition }); // $ExpectType void
+playwright.amOnPage(str); // $ExpectType void
+playwright.resizeWindow(num, num); // $ExpectType void
+playwright.haveRequestHeaders(str); // $ExpectType void
+playwright.moveCursorTo(str, num, num); // $ExpectType void
+playwright.dragAndDrop(str); // $ExpectError
+playwright.dragAndDrop(str, str); // $ExpectType void
+playwright.dragAndDrop(str, str, { sourcePosition, targetPosition }); // $ExpectType void
playwright.refreshPage(); // $ExpectType void
playwright.scrollPageToTop(); // $ExpectType void
playwright.scrollPageToBottom(); // $ExpectType void
-playwright.scrollTo(str_pl, num_pl, num_pl); // $ExpectType void
-playwright.seeInTitle(str_pl); // $ExpectType void
+playwright.scrollTo(str, num, num); // $ExpectType void
+playwright.seeInTitle(str); // $ExpectType void
playwright.grabPageScrollPosition(); // $ExpectType Promise
-playwright.seeTitleEquals(str_pl); // $ExpectType void
-playwright.dontSeeInTitle(str_pl); // $ExpectType void
+playwright.seeTitleEquals(str); // $ExpectType void
+playwright.dontSeeInTitle(str); // $ExpectType void
playwright.grabTitle(); // $ExpectType Promise
playwright._locate(); // $ExpectType void
playwright._locateCheckable(); // $ExpectType void
@@ -42,89 +44,89 @@ playwright.closeCurrentTab(); // $ExpectType void
playwright.closeOtherTabs(); // $ExpectType void
playwright.openNewTab(); // $ExpectType void
playwright.grabNumberOfOpenTabs(); // $ExpectType Promise
-playwright.seeElement(str_pl); // $ExpectType void
-playwright.dontSeeElement(str_pl); // $ExpectType void
-playwright.seeElementInDOM(str_pl); // $ExpectType void
-playwright.dontSeeElementInDOM(str_pl); // $ExpectType void
+playwright.seeElement(str); // $ExpectType void
+playwright.dontSeeElement(str); // $ExpectType void
+playwright.seeElementInDOM(str); // $ExpectType void
+playwright.dontSeeElementInDOM(str); // $ExpectType void
playwright.handleDownloads(); // $ExpectType Promise
-playwright.click(str_pl); // $ExpectType void
-playwright.click(str_pl, str_pl); // $ExpectType void
-playwright.click(str_pl, null, { position }); // $ExpectType void
+playwright.click(str); // $ExpectType void
+playwright.click(str, str); // $ExpectType void
+playwright.click(str, null, { position }); // $ExpectType void
playwright.clickLink(); // $ExpectType void
-playwright.forceClick(str_pl); // $ExpectType void
-playwright.doubleClick(str_pl); // $ExpectType void
-playwright.rightClick(str_pl); // $ExpectType void
-playwright.checkOption(str_pl); // $ExpectType void
-playwright.uncheckOption(str_pl); // $ExpectType void
-playwright.seeCheckboxIsChecked(str_pl); // $ExpectType void
-playwright.dontSeeCheckboxIsChecked(str_pl); // $ExpectType void
-playwright.pressKeyDown(str_pl); // $ExpectType void
-playwright.pressKeyUp(str_pl); // $ExpectType void
-playwright.pressKey(str_pl); // $ExpectType void
-playwright.type(str_pl); // $ExpectType void
-playwright.fillField(str_pl, str_pl); // $ExpectType void
-playwright.clearField(str_pl); // $ExpectType void
-playwright.appendField(str_pl, str_pl); // $ExpectType void
-playwright.seeInField(str_pl, str_pl); // $ExpectType void
-playwright.dontSeeInField(str_pl, str_pl); // $ExpectType void
-playwright.attachFile(str_pl, str_pl); // $ExpectType void
-playwright.selectOption(str_pl, str_pl); // $ExpectType void
-playwright.grabNumberOfVisibleElements(str_pl); // $ExpectType Promise
-playwright.seeInCurrentUrl(str_pl); // $ExpectType void
-playwright.dontSeeInCurrentUrl(str_pl); // $ExpectType void
-playwright.seeCurrentUrlEquals(str_pl); // $ExpectType void
-playwright.dontSeeCurrentUrlEquals(str_pl); // $ExpectType void
-playwright.see(str_pl); // $ExpectType void
-playwright.seeTextEquals(str_pl); // $ExpectType void
-playwright.dontSee(str_pl); // $ExpectType void
+playwright.forceClick(str); // $ExpectType void
+playwright.doubleClick(str); // $ExpectType void
+playwright.rightClick(str); // $ExpectType void
+playwright.checkOption(str); // $ExpectType void
+playwright.uncheckOption(str); // $ExpectType void
+playwright.seeCheckboxIsChecked(str); // $ExpectType void
+playwright.dontSeeCheckboxIsChecked(str); // $ExpectType void
+playwright.pressKeyDown(str); // $ExpectType void
+playwright.pressKeyUp(str); // $ExpectType void
+playwright.pressKey(str); // $ExpectType void
+playwright.type(str); // $ExpectType void
+playwright.fillField(str, str); // $ExpectType void
+playwright.clearField(str); // $ExpectType void
+playwright.appendField(str, str); // $ExpectType void
+playwright.seeInField(str, str); // $ExpectType void
+playwright.dontSeeInField(str, str); // $ExpectType void
+playwright.attachFile(str, str); // $ExpectType void
+playwright.selectOption(str, str); // $ExpectType void
+playwright.grabNumberOfVisibleElements(str); // $ExpectType Promise
+playwright.seeInCurrentUrl(str); // $ExpectType void
+playwright.dontSeeInCurrentUrl(str); // $ExpectType void
+playwright.seeCurrentUrlEquals(str); // $ExpectType void
+playwright.dontSeeCurrentUrlEquals(str); // $ExpectType void
+playwright.see(str); // $ExpectType void
+playwright.seeTextEquals(str); // $ExpectType void
+playwright.dontSee(str); // $ExpectType void
playwright.grabSource(); // $ExpectType Promise
playwright.grabBrowserLogs(); // $ExpectType Promise
playwright.grabCurrentUrl(); // $ExpectType Promise
-playwright.seeInSource(str_pl); // $ExpectType void
-playwright.dontSeeInSource(str_pl); // $ExpectType void
-playwright.seeNumberOfElements(str_pl, num_pl); // $ExpectType void
-playwright.seeNumberOfVisibleElements(str_pl, num_pl); // $ExpectType void
-playwright.setCookie({ name: str_pl, value: str_pl}); // $ExpectType void
-playwright.seeCookie(str_pl); // $ExpectType void
-playwright.dontSeeCookie(str_pl); // $ExpectType void
+playwright.seeInSource(str); // $ExpectType void
+playwright.dontSeeInSource(str); // $ExpectType void
+playwright.seeNumberOfElements(str, num); // $ExpectType void
+playwright.seeNumberOfVisibleElements(str, num); // $ExpectType void
+playwright.setCookie({ name: str, value: str}); // $ExpectType void
+playwright.seeCookie(str); // $ExpectType void
+playwright.dontSeeCookie(str); // $ExpectType void
playwright.grabCookie(); // $ExpectType Promise | Promise
playwright.clearCookie(); // $ExpectType void
playwright.executeScript(() => {}); // $ExpectType Promise
-playwright.grabTextFrom(str_pl); // $ExpectType Promise
-playwright.grabTextFromAll(str_pl); // $ExpectType Promise
-playwright.grabValueFrom(str_pl); // $ExpectType Promise
-playwright.grabValueFromAll(str_pl); // $ExpectType Promise
-playwright.grabHTMLFrom(str_pl); // $ExpectType Promise
-playwright.grabHTMLFromAll(str_pl); // $ExpectType Promise
-playwright.grabCssPropertyFrom(str_pl, str_pl); // $ExpectType Promise
-playwright.grabCssPropertyFromAll(str_pl, str_pl); // $ExpectType Promise
-playwright.seeCssPropertiesOnElements(str_pl, str_pl); // $ExpectType void
-playwright.seeAttributesOnElements(str_pl, str_pl); // $ExpectType void
-playwright.dragSlider(str_pl, num_pl); // $ExpectType void
-playwright.grabAttributeFrom(str_pl, str_pl); // $ExpectType Promise
-playwright.grabAttributeFromAll(str_pl, str_pl); // $ExpectType Promise
-playwright.saveElementScreenshot(str_pl, str_pl); // $ExpectType void
-playwright.saveScreenshot(str_pl); // $ExpectType void
-playwright.makeApiRequest(str_pl, str_pl, str_pl); // $ExpectType Promise