From 3d2baa751f02da34aa5f9390b66e576a3e1d7352 Mon Sep 17 00:00:00 2001 From: Vorobeyko Date: Wed, 24 Jul 2019 21:15:23 +0300 Subject: [PATCH 1/5] feat(ts-typing): add definition for internal objects --- lib/command/definitions.js | 134 +++++++++++++++++++++++++++++++++++++ test/runner/list_test.js | 32 +++++++++ 2 files changed, 166 insertions(+) diff --git a/lib/command/definitions.js b/lib/command/definitions.js index 380d19ed7..c897b8444 100644 --- a/lib/command/definitions.js +++ b/lib/command/definitions.js @@ -41,6 +41,134 @@ interface ILocator { type LocatorOrString = string | ILocator | Locator; +declare class Container { + create(config: Object, opts: Object): void + plugins(name?: string): Object + support(name?: string): Object + helpers(name?: string): Object + translation(): Object + mocha(): Object + append(newContainer: Object): void + clear(newHelpers: Object, newSupport: Object, newPlugins: Object): void +} + +declare class RecorderSession { + running: boolean + start(name: string): void + restore(name: string): void + catch(fn: CallableFunction): void +} + +declare class Recorder { + retries: Object[] + start(): void + isRunning(): boolean + startUnlessRunning(): void + errHandler(fn: CallableFunction): void + reset(): void + session: RecorderSession + add(taskName, fn?: CallableFunction, force?: boolean, retry?: boolean): Promise + retry(opts: Object): Promise + catch(customErrFn: CallableFunction): Promise + catchWithoutStop(customErrFn: CallableFunction ): Promise + throw(err: Error): Promise + saveFirstAsyncError(err: Error): void + getAsyncErr(): Promise + cleanAsyncErr(): void + stop():void + promise(): Promise + scheduled(): string[] + toString(): string + add(hookName: string, fn: CallableFunction, force?: boolean): void + catch(customErrFn: CallableFunction) +} + +declare class CodeceptJSEvent { + dispatcher: EventEmitter + test: { + started: string + before: string + after: string + passed: string + failed: string + finished: string + } + suite: { + before: string, + after: string, + } + hook: { + started: string, + passed: string, + } + step: { + before: string, + after: string, + started: string, + passed: string, + failed: string, + finished: string, + } + all: { + before: string, + after: string, + result: string, + } + multiple: { + before: string, + after: string, + } + emit(event: string, param: string) + cleanDispatcher(): void +} + +declare class Output { + colors: any + styles: { + error: any, + success: any, + scenario: any, + basic: any, + debug: any, + log: any, + } + + print(msg: string): void + stepShift: number + level(level: number): number + process(process: string): string + debug(msg: string): void + log(msg: string): void + error(msg: string): void + success(msg: string): void + plugin(name: string, msg: string): void + step(step: any): void + suite: { + started: Function + } + test: { + started(test: string): void + passed(test: string): void + failed(test: string): void + skipped(test: string): void + } + scenario: { + started(test: string): void + passed(test: string): void + failed(test: string): void + } + say(message: string, color?: string): void + result(passed: number, failed: number, skipped: number, duration: string): void +} + +declare class Config { + create(newConfig: Object): Object + load(configFile: string): Config + get(key: string, val: any): any + append(additionalConfig: Object): Object + reset(): Object +} + declare class Helper { /** Abstract method to provide required config options */ static _config(): any; @@ -140,6 +268,12 @@ declare function secret(secret: any): string; declare const codeceptjs: any; declare namespace CodeceptJS { + export const container: Container + export const recorder: Recorder + export const event: CodeceptJSEvent + export const output: Output + export const config: Config + export interface {{I}} { {{methods}} } diff --git a/test/runner/list_test.js b/test/runner/list_test.js index 90785d379..2c5aa7cc8 100644 --- a/test/runner/list_test.js +++ b/test/runner/list_test.js @@ -62,4 +62,36 @@ describe('list/def commands', () => { done(); }); }); + + it('def should create definition file with support object', (done) => { + try { + fs.unlinkSync(`${codecept_dir}/steps.d.ts`); + } catch (e) { + // continue regardless of error + } + exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.json`, () => { + const content = fs.readFileSync(`${codecept_dir}/steps.d.ts`).toString(); + content.should.include(' openDir() : void'); + content.should.include(' export interface MyPage {'); + content.should.include(' hasFile() : void'); + done(); + }); + }); + + it('def should create definition file with internal object', (done) => { + try { + fs.unlinkSync(`${codecept_dir}/steps.d.ts`); + } catch (e) { + // continue regardless of error + } + exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.json`, () => { + const content = fs.readFileSync(`${codecept_dir}/steps.d.ts`).toString(); + content.should.include(' export const recorder: Recorder'); + content.should.include(' export const event: CodeceptJSEvent'); + content.should.include(' export const output: Output'); + content.should.include(' export const config: Config'); + content.should.include(' export const container: Container'); + done(); + }); + }); }); From 6b3dfbb1046cae090e2e2cf1e4c392b2d50bfbc5 Mon Sep 17 00:00:00 2001 From: Vorobeyko Date: Wed, 24 Jul 2019 21:18:53 +0300 Subject: [PATCH 2/5] removed test --- test/runner/list_test.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/test/runner/list_test.js b/test/runner/list_test.js index 2c5aa7cc8..b76bb7857 100644 --- a/test/runner/list_test.js +++ b/test/runner/list_test.js @@ -63,21 +63,6 @@ describe('list/def commands', () => { }); }); - it('def should create definition file with support object', (done) => { - try { - fs.unlinkSync(`${codecept_dir}/steps.d.ts`); - } catch (e) { - // continue regardless of error - } - exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.json`, () => { - const content = fs.readFileSync(`${codecept_dir}/steps.d.ts`).toString(); - content.should.include(' openDir() : void'); - content.should.include(' export interface MyPage {'); - content.should.include(' hasFile() : void'); - done(); - }); - }); - it('def should create definition file with internal object', (done) => { try { fs.unlinkSync(`${codecept_dir}/steps.d.ts`); From 4dd671a488870e20161086af3afb2a696f22f445 Mon Sep 17 00:00:00 2001 From: Vorobeyko Date: Wed, 24 Jul 2019 22:08:58 +0300 Subject: [PATCH 3/5] add definition for support object from inject --- lib/command/definitions.js | 15 ++++++++++-- test/data/sandbox/codecept.inject.po.json | 3 ++- test/data/sandbox/support/second_page.js | 5 ++++ test/runner/list_test.js | 29 +++++++++++++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 test/data/sandbox/support/second_page.js diff --git a/lib/command/definitions.js b/lib/command/definitions.js index c897b8444..7bec3e52d 100644 --- a/lib/command/definitions.js +++ b/lib/command/definitions.js @@ -257,7 +257,9 @@ declare function BeforeSuite(callback: ICodeceptCallback): void; declare function After(callback: ICodeceptCallback): void; declare function AfterSuite(callback: ICodeceptCallback): void; -declare function inject(): { [key: string]: any }; +declare function inject(): { +{{injectPageObjects}} +}; declare function locate(selector: LocatorOrString): Locator; declare function within(selector: LocatorOrString, callback: Function): Promise; declare function session(selector: LocatorOrString, callback: Function): Promise; @@ -285,6 +287,8 @@ declare module "codeceptjs" { } `; +const injectSupportTemplate = ' {{name}}: CodeceptJS.{{name}}'; + const pageObjectTemplate = ` export interface {{name}} { {{methods}} @@ -315,20 +319,27 @@ module.exports = function (genPath, options) { const supports = container.support(); // return all support objects const exportPageObjects = []; + const injectPageObjects = []; const callbackParams = []; // See #1795 and #1799, there's no obvious way to use for-in with Proxies Reflect.ownKeys(supports).forEach((name) => { - if (name === 'I') return; + if (name === 'I') { + injectPageObjects.push(injectSupportTemplate.replace(/{{name}}/g, String(name))); + return; + } callbackParams.push(`${String(name)}:CodeceptJS.${String(name)}`); const pageObject = supports[name]; const pageMethods = addAllMethodsInObject(pageObject, {}, []); let pageObjectExport = pageObjectTemplate.replace('{{methods}}', pageMethods.join('')); pageObjectExport = pageObjectExport.replace('{{name}}', String(name)); + injectPageObjects.push(injectSupportTemplate.replace(/{{name}}/g, String(name))); exportPageObjects.push(pageObjectExport); }); let definitionsTemplate = template.replace('{{methods}}', methods.join('')); definitionsTemplate = definitionsTemplate.replace('{{exportPageObjects}}', exportPageObjects.join('\n')); + definitionsTemplate = definitionsTemplate.replace('{{injectPageObjects}}', injectPageObjects.join('\n')); + console.log(injectPageObjects); definitionsTemplate = definitionsTemplate.replace('{{callbackParams}}', `, ${[...callbackParams, '...args: any'].join(', ')}`); if (translations) { definitionsTemplate = definitionsTemplate.replace(/\{\{I\}\}/g, translations.I); diff --git a/test/data/sandbox/codecept.inject.po.json b/test/data/sandbox/codecept.inject.po.json index a914e7f34..5dde02132 100644 --- a/test/data/sandbox/codecept.inject.po.json +++ b/test/data/sandbox/codecept.inject.po.json @@ -7,7 +7,8 @@ }, "include": { "I": "./support/custom_steps.js", - "MyPage": "./support/my_page.js" + "MyPage": "./support/my_page.js", + "SecondPage": "./support/second_page.js" }, "bootstrap": false, "mocha": {}, diff --git a/test/data/sandbox/support/second_page.js b/test/data/sandbox/support/second_page.js new file mode 100644 index 000000000..adfd44c9e --- /dev/null +++ b/test/data/sandbox/support/second_page.js @@ -0,0 +1,5 @@ +module.exports = { + secondPageMethod() { + console.log('secondPageMethod'); + }, +}; diff --git a/test/runner/list_test.js b/test/runner/list_test.js index b76bb7857..56295b4be 100644 --- a/test/runner/list_test.js +++ b/test/runner/list_test.js @@ -79,4 +79,33 @@ describe('list/def commands', () => { done(); }); }); + + it('def should create definition file with inject which contains support objects', (done) => { + try { + fs.unlinkSync(`${codecept_dir}/steps.d.ts`); + } catch (e) { + // continue regardless of error + } + exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.json`, () => { + const content = fs.readFileSync(`${codecept_dir}/steps.d.ts`).toString(); + content.should.include('declare function inject(): {'); + content.should.include(' MyPage: CodeceptJS.MyPage'); + content.should.include(' SecondPage: CodeceptJS.SecondPage'); + done(); + }); + }); + + it('def should create definition file with inject which contains I object', (done) => { + try { + fs.unlinkSync(`${codecept_dir}/steps.d.ts`); + } catch (e) { + // continue regardless of error + } + exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.json`, () => { + const content = fs.readFileSync(`${codecept_dir}/steps.d.ts`).toString(); + content.should.include('declare function inject(): {'); + content.should.include(' I: CodeceptJS.I'); + done(); + }); + }); }); From 3e864ea91c3f4ffc4aafb234de798b2bf8800812 Mon Sep 17 00:00:00 2001 From: Vorobeyko Date: Wed, 24 Jul 2019 22:14:12 +0300 Subject: [PATCH 4/5] remove console.log --- lib/command/definitions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/command/definitions.js b/lib/command/definitions.js index 7bec3e52d..74734718c 100644 --- a/lib/command/definitions.js +++ b/lib/command/definitions.js @@ -339,7 +339,6 @@ module.exports = function (genPath, options) { let definitionsTemplate = template.replace('{{methods}}', methods.join('')); definitionsTemplate = definitionsTemplate.replace('{{exportPageObjects}}', exportPageObjects.join('\n')); definitionsTemplate = definitionsTemplate.replace('{{injectPageObjects}}', injectPageObjects.join('\n')); - console.log(injectPageObjects); definitionsTemplate = definitionsTemplate.replace('{{callbackParams}}', `, ${[...callbackParams, '...args: any'].join(', ')}`); if (translations) { definitionsTemplate = definitionsTemplate.replace(/\{\{I\}\}/g, translations.I); From 57fedb3e0970391cca5c56d7450340e9bc10f78f Mon Sep 17 00:00:00 2001 From: Vorobeyko Date: Thu, 25 Jul 2019 00:24:40 +0300 Subject: [PATCH 5/5] callback params is optional --- lib/command/definitions.js | 4 ++-- test/runner/list_test.js | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/command/definitions.js b/lib/command/definitions.js index 74734718c..72db5e583 100644 --- a/lib/command/definitions.js +++ b/lib/command/definitions.js @@ -9,7 +9,7 @@ const fs = require('fs'); const path = require('path'); const template = ` -type ICodeceptCallback = (i: CodeceptJS.{{I}}{{callbackParams}}) => void; +type ICodeceptCallback = (i?: CodeceptJS.{{I}}, current?:any{{callbackParams}}) => void; declare class FeatureConfig { retry(times: number): FeatureConfig @@ -327,7 +327,7 @@ module.exports = function (genPath, options) { injectPageObjects.push(injectSupportTemplate.replace(/{{name}}/g, String(name))); return; } - callbackParams.push(`${String(name)}:CodeceptJS.${String(name)}`); + callbackParams.push(`${String(name)}?:CodeceptJS.${String(name)}`); const pageObject = supports[name]; const pageMethods = addAllMethodsInObject(pageObject, {}, []); let pageObjectExport = pageObjectTemplate.replace('{{methods}}', pageMethods.join('')); diff --git a/test/runner/list_test.js b/test/runner/list_test.js index 56295b4be..825c26e0c 100644 --- a/test/runner/list_test.js +++ b/test/runner/list_test.js @@ -108,4 +108,17 @@ describe('list/def commands', () => { done(); }); }); + + it('def should create definition file with callback params', (done) => { + try { + fs.unlinkSync(`${codecept_dir}/steps.d.ts`); + } catch (e) { + // continue regardless of error + } + exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.json`, () => { + const content = fs.readFileSync(`${codecept_dir}/steps.d.ts`).toString(); + content.should.include('type ICodeceptCallback = (i?: CodeceptJS.I, current?:any, MyPage?:CodeceptJS.MyPage, SecondPage?:CodeceptJS.SecondPage, ...args: any) => void;'); + done(); + }); + }); });