From 169dc9da70d34aa453629feca82d0bf30a58051d Mon Sep 17 00:00:00 2001 From: George Cook Date: Fri, 12 May 2023 16:03:01 +0200 Subject: [PATCH] Feat/custom test scene (#225) * feat(core): adds custom test scene support * add docs * change TestsScene name * Fix test --- bsc-plugin/src/lib/rooibos/FileFactory.ts | 2 +- bsc-plugin/src/lib/rooibos/RooibosConfig.ts | 1 + bsc-plugin/src/lib/rooibos/RooibosSession.ts | 4 +- bsc-plugin/src/plugin.spec.ts | 53 +- bsc-plugin/src/plugin.ts | 3 + docs/Rooibos.brs.html | 751 +++++++++++- docs/index.md | 28 +- docs/module-rooibos.html | 1108 +++++++++++++----- framework/src/source/Rooibos.bs | 10 +- framework/src/source/RooibosScene.xml | 2 +- 10 files changed, 1605 insertions(+), 357 deletions(-) diff --git a/bsc-plugin/src/lib/rooibos/FileFactory.ts b/bsc-plugin/src/lib/rooibos/FileFactory.ts index e0e17c60..bfad941c 100644 --- a/bsc-plugin/src/lib/rooibos/FileFactory.ts +++ b/bsc-plugin/src/lib/rooibos/FileFactory.ts @@ -60,7 +60,7 @@ export class FileFactory { dest: s`${this.targetCompsPath}/RooibosScene.xml` }; this.addedFrameworkFiles.push( - program.setFile(entry, this.createTestXML('TestsScene', 'Scene')) + program.setFile(entry, this.createTestXML('RooibosScene', 'Scene')) ); } diff --git a/bsc-plugin/src/lib/rooibos/RooibosConfig.ts b/bsc-plugin/src/lib/rooibos/RooibosConfig.ts index bea56f1a..12bad25b 100644 --- a/bsc-plugin/src/lib/rooibos/RooibosConfig.ts +++ b/bsc-plugin/src/lib/rooibos/RooibosConfig.ts @@ -21,6 +21,7 @@ export interface RooibosConfig { catchCrashes?: boolean; sendHomeOnFinish?: boolean; keepAppOpen?: boolean; + testSceneName?: string; /** * The path to the folder where the rooibos framework roku files reside. diff --git a/bsc-plugin/src/lib/rooibos/RooibosSession.ts b/bsc-plugin/src/lib/rooibos/RooibosSession.ts index 8b38f26d..df415951 100644 --- a/bsc-plugin/src/lib/rooibos/RooibosSession.ts +++ b/bsc-plugin/src/lib/rooibos/RooibosSession.ts @@ -58,7 +58,7 @@ export class RooibosSession { } } if (mainFunction) { - editor.addToArray(mainFunction.func.body.statements, 0, new RawCodeStatement(`Rooibos_init()`)); + editor.addToArray(mainFunction.func.body.statements, 0, new RawCodeStatement(`Rooibos_init("${this.config?.testSceneName ?? 'RooibosScene'}")`)); } } public addLaunchHookFileIfNotPresent() { @@ -80,7 +80,7 @@ export class RooibosSession { diagnosticNoStagingDir(files[0]); } else { const filePath = path.join(this._builder.options.stagingDir ?? this._builder.options.stagingFolderPath, 'source/rooibosMain.brs'); - fsExtra.writeFileSync(filePath, `function main()\n Rooibos_init()\nend function`); + fsExtra.writeFileSync(filePath, `function main()\n Rooibos_init("${this.config?.testSceneName ?? 'RooibosScene'}")\nend function`); } } diff --git a/bsc-plugin/src/plugin.spec.ts b/bsc-plugin/src/plugin.spec.ts index bbc9269f..84d96ccd 100644 --- a/bsc-plugin/src/plugin.spec.ts +++ b/bsc-plugin/src/plugin.spec.ts @@ -385,7 +385,7 @@ describe('RooibosPlugin', () => { getContents('rooibosMain.brs') ).to.eql(undent` function main() - Rooibos_init() + Rooibos_init("RooibosScene") end function `); expect( @@ -501,7 +501,7 @@ describe('RooibosPlugin', () => { getContents('rooibosMain.brs') ).to.eql(undent` function main() - Rooibos_init() + Rooibos_init("RooibosScene") end function `); }); @@ -521,7 +521,54 @@ describe('RooibosPlugin', () => { getContents('main.brs') ).to.eql(undent` sub main() - Rooibos_init() + Rooibos_init("RooibosScene") + print "main" + end sub + `); + //the AST should not have been permanently modified + const statements = (file.parser.statements[0] as FunctionStatement).func.body.statements; + expect(statements).to.be.lengthOf(1); + expect(statements[0]).to.be.instanceof(PrintStatement); + }); + + + it('adds launch hook with custom scene', async () => { + options = { + rootDir: _rootDir, + stagingFolderPath: _stagingFolderPath, + stagingDir: _stagingFolderPath, + rooibos: { + testSceneName: 'CustomRooibosScene' + } + }; + plugin = new RooibosPlugin(); + fsExtra.ensureDirSync(_stagingFolderPath); + fsExtra.ensureDirSync(_rootDir); + fsExtra.ensureDirSync(tmpPath); + + builder = new ProgramBuilder(); + builder.options = util.normalizeAndResolveConfig(options); + builder.program = new Program(builder.options); + program = builder.program; + program.plugins.add(plugin); + program.createSourceScope(); //ensure source scope is created + plugin.beforeProgramCreate(builder); + plugin.fileFactory['options'].frameworkSourcePath = path.resolve(path.join('../framework/src/source')); + plugin.afterProgramCreate(program); + // program.validate(); + const file = program.setFile('source/main.bs', ` + sub main() + print "main" + end sub + `); + program.validate(); + await builder.transpile(); + + expect( + getContents('main.brs') + ).to.eql(undent` + sub main() + Rooibos_init("CustomRooibosScene") print "main" end sub `); diff --git a/bsc-plugin/src/plugin.ts b/bsc-plugin/src/plugin.ts index 0fed2e38..7e68121e 100644 --- a/bsc-plugin/src/plugin.ts +++ b/bsc-plugin/src/plugin.ts @@ -60,6 +60,9 @@ export class RooibosPlugin implements CompilerPlugin { if (config.keepAppOpen === undefined) { config.keepAppOpen = true; } + if (config.testSceneName === undefined) { + config.testSceneName = 'RooibosScene'; + } //ignore roku modules by default if (config.includeFilters === undefined) { config.includeFilters = [ diff --git a/docs/Rooibos.brs.html b/docs/Rooibos.brs.html index ad72b36b..f2bc4784 100644 --- a/docs/Rooibos.brs.html +++ b/docs/Rooibos.brs.html @@ -1,8 +1,8 @@ - - - + + + Rooibos.brs - Documentation @@ -10,36 +10,698 @@ - - - - - + + + + + + + - - + - + - +
+

Rooibos.brs

-
- -

Rooibos.brs

- - - - - - - -
+
-
' /**
+          
' /**
 '  * @module rooibos
 '  */
 ' /**
@@ -52,7 +714,7 @@ 

Rooibos.brs

' * @param {Dynamic} testUtilsDecorator - will be invoked, with the test case as a param - the function ' * can then compose/decorate any additional functionality, as required ' * Use this to add things like, rodash, common test utils, etc -' * @param testsSceneName as string - name of scene to create. All unit tests run in the scene thread +' * @param RooibosSceneName as string - name of scene to create. All unit tests run in the scene thread ' * and therefore require a screen and scene are created. ' * @param nodeContext as object - this is the global scope of your tests - so where anonymous methods will run from. This should be m ' */ @@ -68,15 +730,15 @@

Rooibos.brs

m.port = CreateObject("roMessagePort") screen.setMessagePort(m.port) if testSceneName = invalid then - testSceneName = "TestsScene" + testSceneName = "RooibosScene" end if - print "Starting test using test scene with name TestsScene" ; testSceneName + print "Starting test using test scene with name RooibosScene" ; testSceneName scene = screen.CreateScene(testSceneName) scene.id = "ROOT" screen.show() m.global = screen.getGlobalNode() m.global.addFields({ - "testsScene": scene + "RooibosScene": scene }) if (preTestSetup <> invalid) then preTestSetup(screen) @@ -167,20 +829,19 @@

Rooibos.brs

return 0 end function
-
- - - - -
+ +
-
+
-
- Generated by JSDoc 3.5.5 on Fri Jun 12 2020 17:30:52 GMT-0500 (-05) using the Minami theme. -
+
+ Generated by JSDoc 3.5.5 on + Fri Jun 12 2020 17:30:52 GMT-0500 (-05) using the Minami theme. +
- - - + + + diff --git a/docs/index.md b/docs/index.md index 4effc6f7..48211d46 100644 --- a/docs/index.md +++ b/docs/index.md @@ -134,15 +134,21 @@ e.g. The following options are supported: -- logLevel?: RooibosLogLevel - 0-4 (error, warn, info, debug) -- showOnlyFailures?: boolean - if true, then only failed tests are shown; but everything is show if no failures occurred -- printTestTimes?: boolean - if true then the time each test took is output -- lineWidth?: number - width of test output lines in columns -- catchCrashes? : boolean - if true, then any crashes will report CRASH statement, and note halt test execution - very useful for running a whole suite -- sendHomeOnFinish? : boolean - if true, then the app will exit upon finish. The default is true. Useful to set to false for local test suites. -- keepAppOpen? : boolean - when true, the app will remain open upon test completion. The default is true. Set false to return execution to Main. -- testsFilePattern?: string - the pattern to use to find tests, this is a glob, the default is "**/*.spec.bs" -- tags?: string[] - the tags listed here control what is run - you can use !tagname to indicated any tests/suites that are skipped, all other tags are ANDed. This is very useful for having a bsconfig to run, say tests including long, and slow integration tests, or just running a certain subset of your suite. +Here is the information converted into a Markdown table: + +| Property | Type | Description | +|-------------------|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| logLevel? | RooibosLogLevel | 0-4 (error, warn, info, debug) | +| showOnlyFailures? | boolean | If true, then only failed tests are shown; but everything is shown if no failures occurred | +| printTestTimes? | boolean | If true, then the time each test took is output | +| lineWidth? | number | Width of test output lines in columns | +| catchCrashes? | boolean | If true, then any crashes will report CRASH statement, and note halt test execution - very useful for running a whole suite | +| sendHomeOnFinish? | boolean | If true, then the app will exit upon finish. The default is true. Useful to set to false for local test suites | +| keepAppOpen? | boolean | When true, the app will remain open upon test completion. The default is true. Set false to return execution to Main | +| testsFilePattern? | string | The pattern to use to find tests. This is a glob. The default is "**/*.spec.bs" | +| tags? | string[] | The tags listed here control what is run. You can use !tagname to indicate any tests/suites that are skipped. All other tags are ANDed. This is useful for running specific subsets of your suite. | +| testSceneName | string | Test scene to use for the test run. Provide a different name here if you need custom setup in your scene. You should extend or duplicate the RooibosScene component (found in RooibosScene.xml) | + ## Creating test suites @@ -1055,14 +1061,14 @@ An example, using a json config file is : "!**/rLogComponents/**/*.*", "!**/rooibosDist.brs", "!**/rooibosFunctionMap.brs", - "!**/TestsScene.brs", + "!**/RooibosScene.brs", "!**/ThreadUtils.brs" ], "testsFilePattern": [ "**/tests/**/*.brs", "!**/rooibosDist.brs", "!**/rooibosFunctionMap.brs", - "!**/TestsScene.brs" + "!**/RooibosScene.brs" ], "isRecordingCodeCoverage": true } diff --git a/docs/module-rooibos.html b/docs/module-rooibos.html index a7f4dda8..459356b0 100644 --- a/docs/module-rooibos.html +++ b/docs/module-rooibos.html @@ -1,8 +1,8 @@ - - - + + + rooibos - Documentation @@ -10,294 +10,822 @@ - - - - - - - - - - - - - -
- -

rooibos

- - - - - - - -
- -
- - - -
- -
-
- - - - - + + + + + + + + + + + + +
+

rooibos

+ +
+
+ +
+
+ +

Methods

+ +
+

+ (static) Rooibos_init(preTestSetup, testUtilsDecorator, RooibosSceneName, + nodeContext) +

+ +
+

+ Entry point for rooibos unit testing framework. Will identify, + run, and report all tests in the app, before terminating the + application. +

+
+ +
+
Source:
+
+ +
+
+ +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
preTestSetup + Dynamic + +

+ called to do any initialization once the screen is created + Use this to configure anything such as globals, etc that + you need +

+
testUtilsDecorator + Dynamic + +

+ will be invoked, with the test case as a param - the + function can then compose/decorate any additional + functionality, as required Use this to add things like, + rodash, common test utils, etc +

+
RooibosSceneName +

+ as string - name of scene to create. All unit tests run in + the scene thread and therefore require a screen and scene + are created. +

+
nodeContext +

+ as object - this is the global scope of your tests - so + where anonymous methods will run from. This should be m +

+
+
+
+
- - - - - - - - - - - - - -

Methods

- - - -
- - - -

(static) Rooibos_init(preTestSetup, testUtilsDecorator, testsSceneName, nodeContext)

- - - - - -
-

Entry point for rooibos unit testing framework. Will identify, run, and report all tests in the app, before terminating the application.

-
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
preTestSetup - - -Dynamic - - - - -

called to do any initialization once the screen is created - Use this to configure anything such as globals, etc that you need

- -
testUtilsDecorator - - -Dynamic - - - - -

will be invoked, with the test case as a param - the function - can then compose/decorate any additional functionality, as required - Use this to add things like, rodash, common test utils, etc

- -
testsSceneName - - -

as string - name of scene to create. All unit tests run in the scene thread - and therefore require a screen and scene are created.

- -
nodeContext - - -

as object - this is the global scope of your tests - so where anonymous methods will run from. This should be m

- -
- - - - - - - - - - - - - - - - -
- - - - - - -
- -
- - - - -
- -
+
-
- Generated by JSDoc 3.5.5 on Fri Jun 12 2020 17:30:52 GMT-0500 (-05) using the Minami theme. -
+
+ Generated by JSDoc 3.5.5 on + Fri Jun 12 2020 17:30:52 GMT-0500 (-05) using the Minami theme. +
- - - - \ No newline at end of file + + + + diff --git a/framework/src/source/Rooibos.bs b/framework/src/source/Rooibos.bs index dbdb3d95..2234308e 100644 --- a/framework/src/source/Rooibos.bs +++ b/framework/src/source/Rooibos.bs @@ -1,5 +1,5 @@ namespace rooibos - function init() as void + function init(testSceneName = invalid) as void if createObject("roAPPInfo").IsDev() <> true ? " not running in dev mode! - rooibos tests only support sideloaded builds - aborting" return @@ -8,15 +8,17 @@ namespace rooibos screen = CreateObject("roSGScreen") m.port = CreateObject("roMessagePort") screen.setMessagePort(m.port) - testSceneName = "TestsScene" + if testSceneName = invalid or testSceneName = "" + testSceneName = "RooibosScene" + end if - ? "Starting test using test scene with name TestsScene" ; testSceneName + ? "Starting test using test scene with name RooibosScene" ; testSceneName scene = screen.CreateScene(testSceneName) scene.id = "ROOT" screen.show() m.global = screen.getGlobalNode() - m.global.addFields({ "testsScene": scene }) + m.global.addFields({ "RooibosScene": scene }) if scene.hasField("isReadyToStartTests") and scene.isReadyToStartTests = false ? "The scene is not ready yet - waiting for it to set isReadyToStartTests to true" diff --git a/framework/src/source/RooibosScene.xml b/framework/src/source/RooibosScene.xml index 9af58cb8..0dfd684b 100644 --- a/framework/src/source/RooibosScene.xml +++ b/framework/src/source/RooibosScene.xml @@ -1,5 +1,5 @@