rooibos-roku 5.16.4 → 5.16.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mocharc.cjs +15 -0
- package/CHANGELOG.md +42 -0
- package/README.md +10 -0
- package/audit-ci.jsonc +1 -9
- package/dist/cli.js +43 -16
- package/dist/lib/framework/source/roku_modules/rooibos_promises/promises.brs +2 -2
- package/dist/lib/framework/source/roku_modules/rooibos_promises/promises.d.bs +31 -31
- package/dist/lib/framework/source/rooibos/ConsoleTestReporter.bs +2 -2
- package/dist/lib/framework/source/rooibos/Rooibos.bs +1 -1
- package/dist/lib/rooibos/Annotation.js +9 -14
- package/dist/lib/rooibos/CodeCoverageProcessor.js +20 -3
- package/dist/lib/rooibos/MockUtil.js +22 -2
- package/dist/lib/rooibos/RooibosSession.js +2 -1
- package/dist/lib/rooibos/TestCase.js +1 -18
- package/dist/lib/rooibos/TestGroup.js +23 -2
- package/dist/lib/rooibos/TestSuite.js +11 -1
- package/dist/lib/rooibos/Utils.js +75 -3
- package/dist/plugin.js +16 -3
- package/package.json +14 -18
package/.mocharc.cjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const nodeVersion = +process.versions.node.split('.')[0];
|
|
2
|
+
const config = {
|
|
3
|
+
spec: 'src/**/*.spec.ts',
|
|
4
|
+
require: [
|
|
5
|
+
'source-map-support/register',
|
|
6
|
+
'ts-node/register'
|
|
7
|
+
],
|
|
8
|
+
fullTrace: true,
|
|
9
|
+
timeout: 2000,
|
|
10
|
+
watchExtensions: ['ts']
|
|
11
|
+
};
|
|
12
|
+
if (nodeVersion >= 22) {
|
|
13
|
+
config['node-option'] = ['no-experimental-strip-types'];
|
|
14
|
+
}
|
|
15
|
+
module.exports = config;
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,48 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
## [5.16.6](https://github.com/rokucommunity/rooibos/compare/5.16.5...v5.16.6) - 2026-10-01
|
|
10
|
+
### Changed
|
|
11
|
+
- Process every test suite in a file, not just the first ([#441](https://github.com/rokucommunity/rooibos/pull/441))
|
|
12
|
+
- Support enums and constants in @params annotations ([#438](https://github.com/rokucommunity/rooibos/pull/438))
|
|
13
|
+
- Security enhancements ([#426](https://github.com/rokucommunity/rooibos/pull/426), [#429](https://github.com/rokucommunity/rooibos/pull/429), [#439](https://github.com/rokucommunity/rooibos/pull/439))
|
|
14
|
+
- upgrade to [brighterscript@0.73.5](https://github.com/rokucommunity/brighterscript/blob/v0.73.5/CHANGELOG.md#0735---2026-09-15). Notable changes since 0.73.3:
|
|
15
|
+
- Fix crash stripping sourceMappingURL comment from non-transpiled files ([#1821](https://github.com/rokucommunity/brighterscript/pull/1821))
|
|
16
|
+
- Tolerate older BrsTranspileState in continue back-transpile ([#1812](https://github.com/rokucommunity/brighterscript/pull/1812))
|
|
17
|
+
- Security enhancements ([#1804](https://github.com/rokucommunity/brighterscript/pull/1804), [#1805](https://github.com/rokucommunity/brighterscript/pull/1805))
|
|
18
|
+
- Locate the super() call when injecting field initializers ([#1803](https://github.com/rokucommunity/brighterscript/pull/1803))
|
|
19
|
+
- upgrade to [roku-debug@0.24.6](https://github.com/rokucommunity/roku-debug/blob/v0.24.6/CHANGELOG.md#0246---2026-10-01). Notable changes since 0.24.3:
|
|
20
|
+
- Security enhancements ([#419](https://github.com/rokucommunity/roku-debug/pull/419), [#427](https://github.com/rokucommunity/roku-debug/pull/427))
|
|
21
|
+
- upgrade to [roku-deploy@4.0.0-alpha.9](https://github.com/rokucommunity/roku-deploy/blob/v4.0.0-alpha.9/CHANGELOG.md#400-alpha9---2026-09-28). Notable changes since 4.0.0-alpha.5:
|
|
22
|
+
- Security enhancements ([#422](https://github.com/rokucommunity/roku-deploy/pull/422))
|
|
23
|
+
- upgrade to [@rokucommunity/logger@0.4.2](https://github.com/rokucommunity/logger/blob/master/CHANGELOG.md#042---2026-09-02). Notable changes since 0.4.1:
|
|
24
|
+
- Security enhancements ([#38](https://github.com/rokucommunity/logger/pull/38), [#39](https://github.com/rokucommunity/logger/pull/39))
|
|
25
|
+
### Fixed
|
|
26
|
+
- Fixed ignored tests count reporting in the summary output ([#435](https://github.com/rokucommunity/rooibos/pull/435))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## [5.16.5](https://github.com/rokucommunity/rooibos/compare/5.16.4...v5.16.5) - 2026-09-09
|
|
31
|
+
### Changed
|
|
32
|
+
- Security enhancements ([#405](https://github.com/rokucommunity/rooibos/pull/405), [#406](https://github.com/rokucommunity/rooibos/pull/406), [#407](https://github.com/rokucommunity/rooibos/pull/407), [#409](https://github.com/rokucommunity/rooibos/pull/409), [#410](https://github.com/rokucommunity/rooibos/pull/410), [#411](https://github.com/rokucommunity/rooibos/pull/411), [#412](https://github.com/rokucommunity/rooibos/pull/412), [#414](https://github.com/rokucommunity/rooibos/pull/414), [#421](https://github.com/rokucommunity/rooibos/pull/421))
|
|
33
|
+
- Make before-exit sleep duration configurable ([#418](https://github.com/rokucommunity/rooibos/pull/418))
|
|
34
|
+
- Run stubCall/expectCalled/expectNotCalled rewrites in setUp/tearDown/beforeEach/afterEach hooks ([#403](https://github.com/rokucommunity/rooibos/pull/403))
|
|
35
|
+
- upgrade to [brighterscript@0.73.3](https://github.com/rokucommunity/brighterscript/blob/master/CHANGELOG.md#0733---2026-09-09). Notable changes since 0.72.5:
|
|
36
|
+
- Security enhancements ([#1733](https://github.com/rokucommunity/brighterscript/pull/1733), [#1763](https://github.com/rokucommunity/brighterscript/pull/1763), [#1764](https://github.com/rokucommunity/brighterscript/pull/1764), [#1766](https://github.com/rokucommunity/brighterscript/pull/1766), [#1773](https://github.com/rokucommunity/brighterscript/pull/1773), [#1774](https://github.com/rokucommunity/brighterscript/pull/1774), [#1775](https://github.com/rokucommunity/brighterscript/pull/1775), [#1782](https://github.com/rokucommunity/brighterscript/pull/1782), [#1796](https://github.com/rokucommunity/brighterscript/pull/1796))
|
|
37
|
+
- upgrade to [roku-debug@0.24.3](https://github.com/rokucommunity/roku-debug/blob/master/CHANGELOG.md#0243---2026-09-09). Notable changes since 0.23.11:
|
|
38
|
+
- Security enhancements ([#369](https://github.com/rokucommunity/roku-debug/pull/369), [#372](https://github.com/rokucommunity/roku-debug/pull/372), [#387](https://github.com/rokucommunity/roku-debug/pull/387), [#402](https://github.com/rokucommunity/roku-debug/pull/402), [#403](https://github.com/rokucommunity/roku-debug/pull/403), [#407](https://github.com/rokucommunity/roku-debug/pull/407), [#412](https://github.com/rokucommunity/roku-debug/pull/412), [#414](https://github.com/rokucommunity/roku-debug/pull/414), [#417](https://github.com/rokucommunity/roku-debug/pull/417))
|
|
39
|
+
- upgrade to [roku-deploy@3.18.4](https://github.com/rokucommunity/roku-deploy/blob/master/CHANGELOG.md#3184---2026-09-02). Notable changes since 3.17.6:
|
|
40
|
+
- Security enhancements ([#293](https://github.com/rokucommunity/roku-deploy/pull/293), [#345](https://github.com/rokucommunity/roku-deploy/pull/345))
|
|
41
|
+
- upgrade to [@rokucommunity/bslint@0.8.46](https://github.com/rokucommunity/bslint/blob/master/CHANGELOG.md#0846---2026-09-09). Notable changes since 0.8.43:
|
|
42
|
+
- Security enhancements ([#186](https://github.com/rokucommunity/bslint/pull/186), [#196](https://github.com/rokucommunity/bslint/pull/196), [#198](https://github.com/rokucommunity/bslint/pull/198), [#203](https://github.com/rokucommunity/bslint/pull/203))
|
|
43
|
+
- upgrade to [ropm@0.11.11](https://github.com/rokucommunity/ropm/blob/master/CHANGELOG.md#01111---2026-09-09). Notable changes since 0.11.8:
|
|
44
|
+
- Security enhancements ([#147](https://github.com/rokucommunity/ropm/pull/147), [#152](https://github.com/rokucommunity/ropm/pull/152), [#154](https://github.com/rokucommunity/ropm/pull/154), [#156](https://github.com/rokucommunity/ropm/pull/156), [#159](https://github.com/rokucommunity/ropm/pull/159))
|
|
45
|
+
### Fixed
|
|
46
|
+
- Fix coverage instrumentation changing constructor execution order ([#355](https://github.com/rokucommunity/rooibos/pull/355))
|
|
47
|
+
- fix: skip assertion tracking injection for namespace function calls ([#385](https://github.com/rokucommunity/rooibos/pull/385))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
9
51
|
## [5.16.4](https://github.com/rokucommunity/rooibos/compare/5.16.3...v5.16.4) - 2026-06-10
|
|
10
52
|
### Changed
|
|
11
53
|
- Make tests less brittle - removes full transpile string checks ([#396](https://github.com/rokucommunity/rooibos/pull/396))
|
package/README.md
CHANGED
|
@@ -30,6 +30,16 @@ Rooibos is an independent open-source project maintained exclusively by voluntee
|
|
|
30
30
|
|
|
31
31
|
You might want to help! Get in touch via the [slack group](https://join.slack.com/t/rokudevelopers/shared_invite/zt-4vw7rg6v-NH46oY7hTktpRIBM_zGvwA) or [raise issues](https://github.com/rokucommunity/rooibos/issues/new).
|
|
32
32
|
|
|
33
|
+
To work on Rooibos locally:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install
|
|
37
|
+
npx ropm copy # copies the framework's ropm dependencies into framework/src
|
|
38
|
+
npm test
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`npx ropm copy` is required because `npm install` alone doesn't copy the ropm modules the framework depends on. `npm run build` also runs it for you, and the test/device scripts will tell you if you've forgotten it.
|
|
42
|
+
|
|
33
43
|
## Sample project
|
|
34
44
|
|
|
35
45
|
https://github.com/rokucommunity/rooibos-roku-sample
|
package/audit-ci.jsonc
CHANGED
|
@@ -3,13 +3,5 @@
|
|
|
3
3
|
// why each allowlisted entry is safe to defer.
|
|
4
4
|
"$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json",
|
|
5
5
|
"high": true,
|
|
6
|
-
"allowlist": [
|
|
7
|
-
{
|
|
8
|
-
"GHSA-w5hq-g745-h8pq": {
|
|
9
|
-
// Added: 2026-05-22
|
|
10
|
-
"active": true,
|
|
11
|
-
"notes": "`uuid` <11.1.1 (via `postman-request` and dev-only `nyc>istanbul-lib-processinfo`): vulnerable code path is `v3()`/`v5()`/`v6()` when a caller-provided buffer is passed. All consumers in this dep graph call only `v4()` (no buffer arg), so the vulnerable path is unreachable."
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
]
|
|
6
|
+
"allowlist": []
|
|
15
7
|
}
|
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,33 @@ const brighterscript_1 = require("brighterscript");
|
|
|
6
6
|
const yargs = require("yargs");
|
|
7
7
|
const roku_deploy_1 = require("roku-deploy");
|
|
8
8
|
const fs = require("fs");
|
|
9
|
+
const path = require("path");
|
|
10
|
+
/**
|
|
11
|
+
* Load simple `KEY=value` pairs from a .env file into process.env, without
|
|
12
|
+
* overwriting variables that are already set in the real environment.
|
|
13
|
+
*/
|
|
14
|
+
function loadDotEnv(envPath = '.env') {
|
|
15
|
+
var _a;
|
|
16
|
+
var _b, _c;
|
|
17
|
+
if (!fs.existsSync(envPath)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const contents = fs.readFileSync(envPath, 'utf8');
|
|
21
|
+
for (const line of contents.split(/\r?\n/)) {
|
|
22
|
+
const match = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(line);
|
|
23
|
+
if (!match) {
|
|
24
|
+
//skip blanks and comments
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
let value = match[2].trim();
|
|
28
|
+
//strip matching surrounding quotes
|
|
29
|
+
if (/^"(.*)"$/.test(value) || /^'(.*)'$/.test(value)) {
|
|
30
|
+
value = value.slice(1, -1);
|
|
31
|
+
}
|
|
32
|
+
(_a = (_b = process.env)[_c = match[1]]) !== null && _a !== void 0 ? _a : (_b[_c] = value);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
loadDotEnv();
|
|
9
36
|
let options = yargs
|
|
10
37
|
.usage('$0', 'Rooibos: a simple, flexible, fun Brightscript test framework for Roku Scenegraph apps')
|
|
11
38
|
.help('help', 'View help information about this tool.')
|
|
@@ -15,11 +42,11 @@ let options = yargs
|
|
|
15
42
|
.option('log-level', { type: 'string', defaultDescription: '"log"', description: 'The log level. Value can be "error", "warn", "log", "info", "debug".' })
|
|
16
43
|
.check((argv) => {
|
|
17
44
|
var _a;
|
|
18
|
-
if (!argv.host) {
|
|
19
|
-
return new Error('You must provide a host. (--host)');
|
|
45
|
+
if (!argv.host && !process.env.ROKU_HOST) {
|
|
46
|
+
return new Error('You must provide a host. (--host, or ROKU_HOST in .env)');
|
|
20
47
|
}
|
|
21
|
-
if (!argv.password) {
|
|
22
|
-
return new Error('You must provide a password. (--password)');
|
|
48
|
+
if (!argv.password && !process.env.ROKU_PASSWORD) {
|
|
49
|
+
return new Error('You must provide a password. (--password, or ROKU_PASSWORD in .env)');
|
|
23
50
|
}
|
|
24
51
|
if (!argv.project) {
|
|
25
52
|
console.log('No project file specified. Using "./bsconfig.json"');
|
|
@@ -32,22 +59,23 @@ let options = yargs
|
|
|
32
59
|
})
|
|
33
60
|
.argv;
|
|
34
61
|
async function main() {
|
|
35
|
-
var _a, _b, _c, _d;
|
|
62
|
+
var _a, _b, _c, _d, _e, _f;
|
|
36
63
|
let currentErrorCode = 0;
|
|
37
64
|
let bsconfigPath = (_a = options.project) !== null && _a !== void 0 ? _a : 'bsconfig.json';
|
|
38
65
|
console.log(`Using bsconfig: ${bsconfigPath}`);
|
|
39
66
|
const rawConfig = brighterscript_1.util.loadConfigFile(bsconfigPath);
|
|
40
67
|
const bsConfig = brighterscript_1.util.normalizeConfig(rawConfig);
|
|
41
|
-
const host = (_b = options.host) !== null && _b !== void 0 ? _b : bsConfig.host;
|
|
42
|
-
const password = (
|
|
43
|
-
const logLevel = (
|
|
68
|
+
const host = (_c = (_b = options.host) !== null && _b !== void 0 ? _b : bsConfig.host) !== null && _c !== void 0 ? _c : process.env.ROKU_HOST;
|
|
69
|
+
const password = (_e = (_d = options.password) !== null && _d !== void 0 ? _d : bsConfig.password) !== null && _e !== void 0 ? _e : process.env.ROKU_PASSWORD;
|
|
70
|
+
const logLevel = (_f = brighterscript_1.LogLevel[options['log-level']]) !== null && _f !== void 0 ? _f : bsConfig.logLevel;
|
|
44
71
|
const builder = new brighterscript_1.ProgramBuilder();
|
|
45
72
|
builder.logger.logLevel = logLevel;
|
|
46
73
|
await builder.run(Object.assign(Object.assign({}, options), { retainStagingDir: true, createPackage: true }));
|
|
74
|
+
const device = { host: host };
|
|
47
75
|
const rokuDeploy = new roku_deploy_1.RokuDeploy();
|
|
48
|
-
const deviceInfo = await rokuDeploy.getDeviceInfo({
|
|
49
|
-
const rendezvousTracker = new roku_debug_1.RendezvousTracker({ softwareVersion: deviceInfo['software-version'] }, {
|
|
50
|
-
const telnet = new roku_debug_1.TelnetAdapter({
|
|
76
|
+
const deviceInfo = await rokuDeploy.getDeviceInfo({ device: device });
|
|
77
|
+
const rendezvousTracker = new roku_debug_1.RendezvousTracker({ softwareVersion: deviceInfo['software-version'] }, { device: device, remotePort: 8085 });
|
|
78
|
+
const telnet = new roku_debug_1.TelnetAdapter({ device: device }, rendezvousTracker);
|
|
51
79
|
telnet.logger.logLevel = logLevel;
|
|
52
80
|
await telnet.activate();
|
|
53
81
|
await telnet.connect();
|
|
@@ -57,7 +85,7 @@ async function main() {
|
|
|
57
85
|
if (emitAppExit) {
|
|
58
86
|
telnet.beginAppExit();
|
|
59
87
|
}
|
|
60
|
-
await rokuDeploy.
|
|
88
|
+
await rokuDeploy.keyPress({ device: device, key: 'Home' });
|
|
61
89
|
process.exit(currentErrorCode);
|
|
62
90
|
}
|
|
63
91
|
telnet.on('console-output', (output) => {
|
|
@@ -96,11 +124,10 @@ async function main() {
|
|
|
96
124
|
async function deployBuiltFiles() {
|
|
97
125
|
const outFile = bsConfig.outFile;
|
|
98
126
|
console.log(`Deploying ${outFile} to ${host}`);
|
|
99
|
-
await rokuDeploy.
|
|
127
|
+
await rokuDeploy.sideload({
|
|
100
128
|
password: password,
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
outDir: process.cwd()
|
|
129
|
+
device: device,
|
|
130
|
+
zip: path.resolve(process.cwd(), outFile)
|
|
104
131
|
});
|
|
105
132
|
}
|
|
106
133
|
await deployBuiltFiles();
|
|
@@ -685,7 +685,7 @@ sub rooibos_promises_internal_delay(callback as Function, context as dynamic, du
|
|
|
685
685
|
end sub
|
|
686
686
|
|
|
687
687
|
' Observes a node field using observeFieldScoped
|
|
688
|
-
' @param {roSGNode} node - The node to apply the observer
|
|
688
|
+
' @param {rooibos.promises.roSGNode} node - The node to apply the observer
|
|
689
689
|
' @param {String} field - The name of the field to be monitored.
|
|
690
690
|
' @param {Dynamic} callback - The name or message port to be executed when the value of the field changes.
|
|
691
691
|
' @return true if field could be observed, false if not
|
|
@@ -704,7 +704,7 @@ function rooibos_promises_internal_observeFieldScoped(node as object, field as s
|
|
|
704
704
|
end function
|
|
705
705
|
|
|
706
706
|
' Unobserve a node field using unobserveFieldScoped
|
|
707
|
-
' @param {roSGNode} node - The node to remove the observer from
|
|
707
|
+
' @param {rooibos.promises.roSGNode} node - The node to remove the observer from
|
|
708
708
|
' @param {String} field - The name of the field to no longer be monitored.
|
|
709
709
|
' @return true if field could be unobserved, false if not
|
|
710
710
|
function rooibos_promises_internal_unobserveFieldScoped(node as object, field as string)
|
|
@@ -1,49 +1,49 @@
|
|
|
1
|
+
namespace rooibos.promises
|
|
1
2
|
' @rokucommunity/promises v0.5.0
|
|
2
3
|
' Create a new promise
|
|
3
|
-
|
|
4
|
-
function create() as dynamic
|
|
4
|
+
function create() as dynamic
|
|
5
5
|
end function
|
|
6
6
|
end namespace
|
|
7
|
-
' TODO rename this to `then` once BrighterScript supports using keywords as namespaced function names
|
|
8
7
|
namespace rooibos.promises
|
|
9
|
-
|
|
8
|
+
' TODO rename this to `then` once BrighterScript supports using keywords as namespaced function names
|
|
9
|
+
function onThen(promise as dynamic, callback as function, context = "__INVALID__" as object) as dynamic
|
|
10
10
|
end function
|
|
11
11
|
end namespace
|
|
12
|
-
' TODO rename this to `catch` once BrighterScript supports using keywords as namespaced function names
|
|
13
12
|
namespace rooibos.promises
|
|
14
|
-
|
|
13
|
+
' TODO rename this to `catch` once BrighterScript supports using keywords as namespaced function names
|
|
14
|
+
function onCatch(promise as dynamic, callback as function, context = "__INVALID__" as object) as dynamic
|
|
15
15
|
end function
|
|
16
16
|
end namespace
|
|
17
|
-
' TODO rename this to `finally` once BrighterScript supports using keywords as namespaced function names
|
|
18
17
|
namespace rooibos.promises
|
|
19
|
-
|
|
18
|
+
' TODO rename this to `finally` once BrighterScript supports using keywords as namespaced function names
|
|
19
|
+
function onFinally(promise as dynamic, callback as function, context = "__INVALID__" as object) as dynamic
|
|
20
20
|
end function
|
|
21
21
|
end namespace
|
|
22
|
-
|
|
22
|
+
namespace rooibos.promises
|
|
23
|
+
' Takes an array of promises as input and returns a single Promise.
|
|
23
24
|
' This returned promise fulfills when all of the input's promises fulfill (including when an empty array is passed), with an array of the fulfillment values.
|
|
24
25
|
' It rejects when any of the input's promises rejects, with this first rejection reason.
|
|
25
|
-
|
|
26
|
-
function all(promiseArray as dynamic) as dynamic
|
|
26
|
+
function all(promiseArray as dynamic) as dynamic
|
|
27
27
|
end function
|
|
28
28
|
end namespace
|
|
29
|
-
|
|
29
|
+
namespace rooibos.promises
|
|
30
|
+
' Takes an array of promises as input and returns a single Promise.
|
|
30
31
|
' This returned promise fulfills when all of the input's promises settle (including when an empty array is passed),
|
|
31
32
|
' with an array of objects that describe the outcome of each promise.
|
|
32
|
-
|
|
33
|
-
function allSettled(promiseArray as dynamic) as dynamic
|
|
33
|
+
function allSettled(promiseArray as dynamic) as dynamic
|
|
34
34
|
end function
|
|
35
35
|
end namespace
|
|
36
|
-
|
|
36
|
+
namespace rooibos.promises
|
|
37
|
+
' Takes an array of promises as input and returns a single Promise.
|
|
37
38
|
' This returned promise fulfills when any of the input's promises fulfills, with this first fulfillment value.
|
|
38
39
|
' It rejects when all of the input's promises reject (including when an empty array is passed), with an AggregateError containing an array of rejection reasons.
|
|
39
|
-
|
|
40
|
-
function any(promiseArray as dynamic) as dynamic
|
|
40
|
+
function any(promiseArray as dynamic) as dynamic
|
|
41
41
|
end function
|
|
42
42
|
end namespace
|
|
43
|
-
' Takes an array of promises as input and returns a single Promise.
|
|
44
|
-
' This returned promise settles with the eventual state of the first promise that settles.
|
|
45
43
|
namespace rooibos.promises
|
|
46
|
-
|
|
44
|
+
' Takes an array of promises as input and returns a single Promise.
|
|
45
|
+
' This returned promise settles with the eventual state of the first promise that settles.
|
|
46
|
+
function race(promiseArray as dynamic) as dynamic
|
|
47
47
|
end function
|
|
48
48
|
end namespace
|
|
49
49
|
namespace rooibos.promises
|
|
@@ -58,29 +58,29 @@ end namespace
|
|
|
58
58
|
function isComplete(promise as object) as boolean
|
|
59
59
|
end function
|
|
60
60
|
end namespace
|
|
61
|
-
|
|
61
|
+
namespace rooibos.promises
|
|
62
|
+
' Determines if the given item is a promise.
|
|
62
63
|
'
|
|
63
64
|
' Will return true if at least one of the following conditions are true:
|
|
64
65
|
' - the SubType exactly equals "Promise"
|
|
65
66
|
' - the subtype ends with "_promise" case insensitive
|
|
66
67
|
' - the node has a field called "promiseState"
|
|
67
|
-
|
|
68
|
-
function isPromise(promise as dynamic) as boolean
|
|
68
|
+
function isPromise(promise as dynamic) as boolean
|
|
69
69
|
end function
|
|
70
70
|
end namespace
|
|
71
|
-
' Remove all promise storage from the current m
|
|
72
71
|
namespace rooibos.promises
|
|
73
|
-
|
|
72
|
+
' Remove all promise storage from the current m
|
|
73
|
+
sub clean()
|
|
74
74
|
end sub
|
|
75
75
|
end namespace
|
|
76
|
-
'Allows chaining multiple promise operations in a row in a clean syntax
|
|
77
76
|
namespace rooibos.promises
|
|
78
|
-
|
|
77
|
+
'Allows chaining multiple promise operations in a row in a clean syntax
|
|
78
|
+
function chain(initialPromise as object, context = "__INVALID__" as object) as object
|
|
79
79
|
end function
|
|
80
80
|
end namespace
|
|
81
|
-
' Makes sure the value supplied is a promise
|
|
82
81
|
namespace rooibos.promises
|
|
83
|
-
|
|
82
|
+
' Makes sure the value supplied is a promise
|
|
83
|
+
function ensurePromise(value as object) as object
|
|
84
84
|
end function
|
|
85
85
|
end namespace
|
|
86
86
|
namespace rooibos.promises
|
|
@@ -151,14 +151,14 @@ namespace rooibos.promises.internal
|
|
|
151
151
|
sub delay(callback as function, context as dynamic, duration = 0.0001 as float)
|
|
152
152
|
end sub
|
|
153
153
|
' Observes a node field using observeFieldScoped
|
|
154
|
-
' @
|
|
154
|
+
' @parrooibos.promises.internal.roSGNodeNode} node - The node to apply the observer
|
|
155
155
|
' @param {String} field - The name of the field to be monitored.
|
|
156
156
|
' @param {Dynamic} callback - The name or message port to be executed when the value of the field changes.
|
|
157
157
|
' @return true if field could be observed, false if not
|
|
158
158
|
function observeFieldScoped(node as object, field as string, callback as dynamic, infoFields = [] as object)
|
|
159
159
|
end function
|
|
160
160
|
' Unobserve a node field using unobserveFieldScoped
|
|
161
|
-
' @
|
|
161
|
+
' @parrooibos.promises.internal.roSGNodeNode} node - The node to remove the observer from
|
|
162
162
|
' @param {String} field - The name of the field to no longer be monitored.
|
|
163
163
|
' @return true if field could be unobserved, false if not
|
|
164
164
|
function unobserveFieldScoped(node as object, field as string)
|
|
@@ -72,12 +72,12 @@ namespace rooibos
|
|
|
72
72
|
m.printLine(0, " Passed: " + rooibos.common.AsString(m.allStats.passedCount))
|
|
73
73
|
m.printLine(0, " Crashed: " + rooibos.common.AsString(m.allStats.crashedCount))
|
|
74
74
|
m.printLine(0, " Failed: " + rooibos.common.AsString(m.allStats.failedCount))
|
|
75
|
-
m.printLine(0, " Ignored: " + rooibos.common.AsString(
|
|
75
|
+
m.printLine(0, " Ignored: " + rooibos.common.AsString(m.allStats.ignoredCount))
|
|
76
76
|
m.printLine(0, " Time: " + rooibos.common.AsString(m.allStats.time) + "ms")
|
|
77
77
|
m.printLine()
|
|
78
78
|
m.printLine()
|
|
79
79
|
|
|
80
|
-
if
|
|
80
|
+
if m.allStats.ignoredCount > 0 then
|
|
81
81
|
m.printLine(0, "IGNORED TESTS:")
|
|
82
82
|
for each ignoredItemName in ignoredInfo.items
|
|
83
83
|
m.printLine(1, ignoredItemName)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getAnnotationType = exports.RooibosAnnotation = exports.AnnotationParams = exports.AnnotationType = void 0;
|
|
4
4
|
const Diagnostics_1 = require("../utils/Diagnostics");
|
|
5
|
+
const Utils_1 = require("./Utils");
|
|
5
6
|
var AnnotationType;
|
|
6
7
|
(function (AnnotationType) {
|
|
7
8
|
AnnotationType["None"] = "none";
|
|
@@ -46,9 +47,12 @@ let annotationLookup = {
|
|
|
46
47
|
};
|
|
47
48
|
const defaultSlowDuration = 75;
|
|
48
49
|
class AnnotationParams {
|
|
49
|
-
constructor(annotation,
|
|
50
|
+
constructor(annotation, lineNumber,
|
|
51
|
+
/**
|
|
52
|
+
* The argument expressions of the annotation. These are cloned into the generated test suite data so they get transpiled like any other code
|
|
53
|
+
*/
|
|
54
|
+
params, isIgnore = false, isSolo = false, noCatch = false, noEarlyexit = false) {
|
|
50
55
|
this.annotation = annotation;
|
|
51
|
-
this.text = text;
|
|
52
56
|
this.lineNumber = lineNumber;
|
|
53
57
|
this.params = params;
|
|
54
58
|
this.isIgnore = isIgnore;
|
|
@@ -167,6 +171,7 @@ class RooibosAnnotation {
|
|
|
167
171
|
asyncTimeout = -1;
|
|
168
172
|
}
|
|
169
173
|
for (const annotation of getAnnotationsOfType(AnnotationType.Params, AnnotationType.SoloParams, AnnotationType.IgnoreParams)) {
|
|
174
|
+
(0, Utils_1.linkAnnotationToStatement)(annotation, statement);
|
|
170
175
|
if (testAnnotation) {
|
|
171
176
|
testAnnotation.parseParams(file, annotation, getAnnotationType(annotation.name), noCatch);
|
|
172
177
|
}
|
|
@@ -194,23 +199,13 @@ class RooibosAnnotation {
|
|
|
194
199
|
return { blockAnnotation: blockAnnotation, testAnnotation: testAnnotation };
|
|
195
200
|
}
|
|
196
201
|
parseParams(file, annotation, annotationType, noCatch) {
|
|
197
|
-
|
|
202
|
+
var _a, _b;
|
|
198
203
|
let isSolo = annotationType === AnnotationType.SoloParams;
|
|
199
204
|
let isIgnore = annotationType === AnnotationType.IgnoreParams;
|
|
200
205
|
if (isSolo) {
|
|
201
206
|
this.hasSoloParams = true;
|
|
202
207
|
}
|
|
203
|
-
|
|
204
|
-
if (rawParams) {
|
|
205
|
-
this.params.push(new AnnotationParams(annotation, rawParams, annotation.range.start.line, annotation.getArguments(), isIgnore, isSolo, noCatch));
|
|
206
|
-
}
|
|
207
|
-
else {
|
|
208
|
-
(0, Diagnostics_1.diagnosticIllegalParams)(file, annotation);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
catch (e) {
|
|
212
|
-
(0, Diagnostics_1.diagnosticIllegalParams)(file, annotation);
|
|
213
|
-
}
|
|
208
|
+
this.params.push(new AnnotationParams(annotation, annotation.range.start.line, (_b = (_a = annotation.call) === null || _a === void 0 ? void 0 : _a.args) !== null && _b !== void 0 ? _b : [], isIgnore, isSolo, noCatch));
|
|
214
209
|
}
|
|
215
210
|
}
|
|
216
211
|
exports.RooibosAnnotation = RooibosAnnotation;
|
|
@@ -121,7 +121,11 @@ class CodeCoverageProcessor {
|
|
|
121
121
|
},
|
|
122
122
|
ExpressionStatement: (ds, parent, owner, key) => {
|
|
123
123
|
this.addStatement(ds);
|
|
124
|
-
|
|
124
|
+
//bsc's class transpiler assumes a `super()` call sits at index 0 of the constructor body, and
|
|
125
|
+
//injects field initializers immediately after it. Inserting our coverage statement *before*
|
|
126
|
+
//`super()` would shift it off index 0, causing field initializers to be emitted before the
|
|
127
|
+
//`super()` call. So for `super()` we insert coverage *after* the call instead.
|
|
128
|
+
this.convertStatementToCoverageStatement(ds, CodeCoverageLineType.code, owner, key, this.isSuperCall(ds));
|
|
125
129
|
}
|
|
126
130
|
}), { walkMode: brighterscript_1.WalkMode.visitAllRecursive });
|
|
127
131
|
const coverageMapObject = {};
|
|
@@ -132,14 +136,27 @@ class CodeCoverageProcessor {
|
|
|
132
136
|
this.filePathMap[this.fileId] = file.pkgPath;
|
|
133
137
|
this.addBrsAPIText(file, astEditor);
|
|
134
138
|
}
|
|
135
|
-
|
|
139
|
+
/**
|
|
140
|
+
* Is this statement a call to `super()`? (i.e. the parent-constructor call in a derived class constructor)
|
|
141
|
+
*/
|
|
142
|
+
isSuperCall(statement) {
|
|
143
|
+
var _a, _b, _c;
|
|
144
|
+
return (0, brighterscript_1.isExpressionStatement)(statement) &&
|
|
145
|
+
(0, brighterscript_1.isCallExpression)(statement.expression) &&
|
|
146
|
+
((_c = (_b = (_a = brighterscript_1.util.findBeginningVariableExpression(statement.expression.callee)) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.text) === null || _c === void 0 ? void 0 : _c.toLowerCase()) === 'super';
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Insert a coverage-tracking statement adjacent to the given statement.
|
|
150
|
+
* When `insertAfter` is true, the coverage statement is inserted *after* the given statement rather than before it.
|
|
151
|
+
*/
|
|
152
|
+
convertStatementToCoverageStatement(statement, coverageType, owner, key, insertAfter = false) {
|
|
136
153
|
if (this.processedStatements.has(statement) || this.addedStatements.has(statement)) {
|
|
137
154
|
return;
|
|
138
155
|
}
|
|
139
156
|
const lineNumber = statement.range.start.line;
|
|
140
157
|
this.coverageMap.set(lineNumber, coverageType);
|
|
141
158
|
const parsed = brighterscript_1.Parser.parse(this.getFuncCallText(lineNumber, coverageType)).ast.statements[0];
|
|
142
|
-
this.astEditor.arraySplice(owner, key, 0, parsed);
|
|
159
|
+
this.astEditor.arraySplice(owner, insertAfter ? key + 1 : key, 0, parsed);
|
|
143
160
|
this.addedStatements.add(parsed);
|
|
144
161
|
// store the statement in a set to avoid handling again after inserting statement above
|
|
145
162
|
this.processedStatements.add(statement);
|
|
@@ -101,15 +101,35 @@ class MockUtil {
|
|
|
101
101
|
}
|
|
102
102
|
gatherGlobalMethodMocks(testSuite) {
|
|
103
103
|
// console.log('gathering global method mocks for testSuite', testSuite.name);
|
|
104
|
+
const processedFuncs = new Set();
|
|
104
105
|
for (let group of [...testSuite.testGroups.values()].filter((tg) => tg.isIncluded)) {
|
|
106
|
+
for (const hookName of [group.setupFunctionName, group.tearDownFunctionName, group.beforeEachFunctionName, group.afterEachFunctionName]) {
|
|
107
|
+
if (hookName) {
|
|
108
|
+
const key = hookName.toLowerCase();
|
|
109
|
+
if (!processedFuncs.has(key)) {
|
|
110
|
+
this.gatherMockedFunctionByName(testSuite, hookName);
|
|
111
|
+
processedFuncs.add(key);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
105
115
|
for (let testCase of [...group.testCases].filter((tc) => tc.isIncluded)) {
|
|
106
|
-
|
|
116
|
+
const key = testCase.funcName.toLowerCase();
|
|
117
|
+
if (!processedFuncs.has(key)) {
|
|
118
|
+
this.gatherMockedGlobalMethods(testSuite, testCase);
|
|
119
|
+
processedFuncs.add(key);
|
|
120
|
+
}
|
|
107
121
|
}
|
|
108
122
|
}
|
|
109
123
|
}
|
|
110
124
|
gatherMockedGlobalMethods(testSuite, testCase) {
|
|
125
|
+
this.gatherMockedFunctionByName(testSuite, testCase.funcName);
|
|
126
|
+
}
|
|
127
|
+
gatherMockedFunctionByName(testSuite, funcName) {
|
|
111
128
|
try {
|
|
112
|
-
let func = testSuite.classStatement.methods.find((m) => m.name.text.toLowerCase() ===
|
|
129
|
+
let func = testSuite.classStatement.methods.find((m) => m.name.text.toLowerCase() === funcName.toLowerCase());
|
|
130
|
+
if (!func) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
113
133
|
func.walk((0, brighterscript_1.createVisitor)({
|
|
114
134
|
ExpressionStatement: (expressionStatement, parent, owner) => {
|
|
115
135
|
let callExpression = expressionStatement.expression;
|
|
@@ -112,7 +112,7 @@ class RooibosSession {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
updateRunTimeConfigFunction(classStatement, editor) {
|
|
115
|
-
var _a, _b, _c;
|
|
115
|
+
var _a, _b, _c, _d;
|
|
116
116
|
let method = classStatement.methods.find((m) => m.name.text === 'getRuntimeConfig');
|
|
117
117
|
if (method) {
|
|
118
118
|
editor.addToArray(method.func.body.statements, method.func.body.statements.length, brighterscript_1.Parser.parse((0, undent_1.default) `
|
|
@@ -130,6 +130,7 @@ class RooibosSession {
|
|
|
130
130
|
"colorizeOutput": ${this.config.colorizeOutput ? 'true' : 'false'}
|
|
131
131
|
"throwOnFailedAssertion": ${this.config.throwOnFailedAssertion ? 'true' : 'false'}
|
|
132
132
|
"keepAppOpen": ${this.config.keepAppOpen === undefined || this.config.keepAppOpen ? 'true' : 'false'}
|
|
133
|
+
"shutdownDelay": ${(_d = this.config.shutdownDelay) !== null && _d !== void 0 ? _d : 400}
|
|
133
134
|
"isRecordingCodeCoverage": ${this.config.isRecordingCodeCoverage ? 'true' : 'false'}
|
|
134
135
|
}
|
|
135
136
|
`).ast.statements[0]);
|
|
@@ -21,7 +21,6 @@ class TestCase {
|
|
|
21
21
|
this.isParamTest = this.expectedNumberOfParams > 0;
|
|
22
22
|
}
|
|
23
23
|
asText() {
|
|
24
|
-
let rawParamsText = this.fixBadJson(this.rawParams).replace(/null/g, 'invalid');
|
|
25
24
|
return `
|
|
26
25
|
{
|
|
27
26
|
isSolo: ${this.isSolo}
|
|
@@ -36,28 +35,12 @@ class TestCase {
|
|
|
36
35
|
lineNumber: ${this.lineNumber + 1}
|
|
37
36
|
paramLineNumber: ${this.isParamTest ? this.paramLineNumber + 1 : 0}
|
|
38
37
|
assertIndex: ${this.assertIndex}
|
|
39
|
-
rawParams: ${
|
|
38
|
+
rawParams: ${this.rawParams ? '[]' /* filled with the actual param expressions by `addParamsToTestSuiteData` */ : 'invalid'}
|
|
40
39
|
paramTestIndex: ${this.paramTestIndex}
|
|
41
40
|
expectedNumberOfParams: ${this.expectedNumberOfParams}
|
|
42
41
|
isParamsValid: ${(this.rawParams || []).length === this.expectedNumberOfParams}
|
|
43
42
|
}`;
|
|
44
43
|
}
|
|
45
|
-
fixBadJson(o) {
|
|
46
|
-
// In case of an array we'll stringify all objects.
|
|
47
|
-
if (Array.isArray(o)) {
|
|
48
|
-
return `[${o.map(obj => `${this.fixBadJson(obj)}`).join(',')}]`;
|
|
49
|
-
}
|
|
50
|
-
// not an object, stringify using native function
|
|
51
|
-
if (typeof o !== 'object' || o === null) {
|
|
52
|
-
return JSON.stringify(o);
|
|
53
|
-
}
|
|
54
|
-
return `{${Object
|
|
55
|
-
.keys(o)
|
|
56
|
-
.map(key => {
|
|
57
|
-
return `"${key.replace(/"/g, '')}":${this.fixBadJson(o[key])}`;
|
|
58
|
-
})
|
|
59
|
-
.join(',')}}`;
|
|
60
|
-
}
|
|
61
44
|
}
|
|
62
45
|
exports.TestCase = TestCase;
|
|
63
46
|
//# sourceMappingURL=TestCase.js.map
|
|
@@ -23,15 +23,28 @@ class TestGroup extends TestSuite_1.TestBlock {
|
|
|
23
23
|
this.hasAsyncTests || (this.hasAsyncTests = testCase.isAsync);
|
|
24
24
|
}
|
|
25
25
|
modifyAssertions(testCase, noEarlyExit, editor, namespaceLookup, scope) {
|
|
26
|
+
let func = this.testSuite.classStatement.methods.find((m) => m.name.text.toLowerCase() === testCase.funcName.toLowerCase());
|
|
27
|
+
this.modifyAssertionsInFunction(func, noEarlyExit, editor, namespaceLookup, scope);
|
|
28
|
+
}
|
|
29
|
+
modifyAssertionsForHook(hookFuncName, noEarlyExit, editor, namespaceLookup, scope) {
|
|
30
|
+
if (!hookFuncName) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
let func = this.testSuite.classStatement.methods.find((m) => m.name.text.toLowerCase() === hookFuncName.toLowerCase());
|
|
34
|
+
if (!func) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.modifyAssertionsInFunction(func, noEarlyExit, editor, namespaceLookup, scope);
|
|
38
|
+
}
|
|
39
|
+
modifyAssertionsInFunction(func, noEarlyExit, editor, namespaceLookup, scope) {
|
|
26
40
|
//for each method
|
|
27
41
|
//if assertion
|
|
28
42
|
//wrap with if is not fail
|
|
29
43
|
//add line number as last param
|
|
30
44
|
try {
|
|
31
|
-
let func = this.testSuite.classStatement.methods.find((m) => m.name.text.toLowerCase() === testCase.funcName.toLowerCase());
|
|
32
45
|
func.walk((0, brighterscript_1.createVisitor)({
|
|
33
46
|
ExpressionStatement: (expressionStatement, parent, owner, key) => {
|
|
34
|
-
var _a, _b;
|
|
47
|
+
var _a, _b, _c;
|
|
35
48
|
let callExpression = expressionStatement.expression;
|
|
36
49
|
if ((0, brighterscript_1.isCallExpression)(callExpression) && (0, brighterscript_1.isDottedGetExpression)(callExpression.callee)) {
|
|
37
50
|
let dge = callExpression.callee;
|
|
@@ -44,6 +57,14 @@ class TestGroup extends TestSuite_1.TestBlock {
|
|
|
44
57
|
// `someMagicVar`.assert*(...)
|
|
45
58
|
const callPath = (_b = brighterscript_1.util.getAllDottedGetParts(callExpression.callee.obj)) === null || _b === void 0 ? void 0 : _b.map((part) => part.text).join('.');
|
|
46
59
|
if (callPath) {
|
|
60
|
+
// Skip if callPath starts with a namespace name — this is a namespace
|
|
61
|
+
// function call (e.g. some.space.assertEqual()), not a method call on
|
|
62
|
+
// an object like m. Injecting assertion tracking on a namespace prefix
|
|
63
|
+
// produces invalid output (e.g. some_space.currentAssertLineNumber).
|
|
64
|
+
const callPathFirstPart = callPath.split('.')[0].toLowerCase();
|
|
65
|
+
if (namespaceLookup.has(callPathFirstPart) || ((_c = scope === null || scope === void 0 ? void 0 : scope.namespaceLookup) === null || _c === void 0 ? void 0 : _c.has(callPathFirstPart))) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
47
68
|
if (dge.name.text === 'stubCall') {
|
|
48
69
|
this.modifyModernRooibosExpectCallExpression(callExpression, editor, namespaceLookup, scope);
|
|
49
70
|
return expressionStatement;
|
|
@@ -78,7 +78,17 @@ class TestSuite extends TestBlock {
|
|
|
78
78
|
}
|
|
79
79
|
addDataFunctions(editor) {
|
|
80
80
|
if (this.isIncluded) {
|
|
81
|
-
(0, Utils_1.addOverriddenMethod)(this.file, this.annotation.annotation, this.classStatement, 'getTestSuiteData', `return ${this.asText()}`, editor);
|
|
81
|
+
const method = (0, Utils_1.addOverriddenMethod)(this.file, this.annotation.annotation, this.classStatement, 'getTestSuiteData', `return ${this.asText()}`, editor);
|
|
82
|
+
if (method) {
|
|
83
|
+
//same order as the `rawParams` placeholders in `asText()`
|
|
84
|
+
const paramExpressionsList = [];
|
|
85
|
+
for (const testGroup of [...this.testGroups.values()].filter((tg) => tg.isIncluded)) {
|
|
86
|
+
for (const testCase of [...testGroup.testCases].filter((tc) => tc.isIncluded && tc.rawParams)) {
|
|
87
|
+
paramExpressionsList.push(testCase.rawParams);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
(0, Utils_1.addParamsToTestSuiteData)(this.file, method, paramExpressionsList, editor);
|
|
91
|
+
}
|
|
82
92
|
}
|
|
83
93
|
}
|
|
84
94
|
getTestGroups() {
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getScopeForSuite = exports.getPathValuePartAsString = exports.getStringPathFromDottedGet = exports.getRootObjectFromDottedGet = exports.getAllDottedGetParts = exports.functionRequiresReturnValue = exports.sanitizeBsJsonString = exports.addOverriddenMethod = void 0;
|
|
3
|
+
exports.getScopeForSuite = exports.addParamsToTestSuiteData = exports.linkAnnotationToStatement = exports.getPathValuePartAsString = exports.getStringPathFromDottedGet = exports.getRootObjectFromDottedGet = exports.getAllDottedGetParts = exports.functionRequiresReturnValue = exports.sanitizeBsJsonString = exports.addOverriddenMethod = void 0;
|
|
4
4
|
const brighterscript_1 = require("brighterscript");
|
|
5
5
|
const Diagnostics_1 = require("../utils/Diagnostics");
|
|
6
|
+
/**
|
|
7
|
+
* Add a generated method to the class.
|
|
8
|
+
* @returns the added method, or undefined if the source could not be parsed
|
|
9
|
+
*/
|
|
6
10
|
function addOverriddenMethod(file, annotation, target, name, source, editor) {
|
|
7
11
|
var _a, _b;
|
|
8
12
|
let { method, diagnostics, text } = createMethod(file, name, source);
|
|
@@ -11,11 +15,12 @@ function addOverriddenMethod(file, annotation, target, name, source, editor) {
|
|
|
11
15
|
//trigger that functionality BEFORE performing AstEditor operations. TODO remove this whenever bsc stops doing this.
|
|
12
16
|
(_b = (_a = target).ensureConstructorFunctionExists) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
13
17
|
editor.addToArray(target.body, target.body.length, method);
|
|
14
|
-
|
|
18
|
+
method.parent = target;
|
|
19
|
+
return method;
|
|
15
20
|
}
|
|
16
21
|
const error = (diagnostics === null || diagnostics === void 0 ? void 0 : diagnostics.length) > 0 ? diagnostics[0].message : 'unknown error';
|
|
17
22
|
(0, Diagnostics_1.diagnosticCorruptTestProduced)(file, annotation, error, text);
|
|
18
|
-
return
|
|
23
|
+
return undefined;
|
|
19
24
|
}
|
|
20
25
|
exports.addOverriddenMethod = addOverriddenMethod;
|
|
21
26
|
/**
|
|
@@ -130,6 +135,73 @@ function getPathValuePartAsString(expr) {
|
|
|
130
135
|
}
|
|
131
136
|
}
|
|
132
137
|
exports.getPathValuePartAsString = getPathValuePartAsString;
|
|
138
|
+
/**
|
|
139
|
+
* bsc does not link annotations into the AST, so the expressions in their arguments have no parent (and therefore no symbol table or namespace).
|
|
140
|
+
* That makes the bsc validator flag references like `@params(SomeEnum.value)` as unknown names. Link the annotation (and its arguments) to
|
|
141
|
+
* the statement it decorates so those references are validated and resolved like any other expression in that statement's scope.
|
|
142
|
+
*/
|
|
143
|
+
function linkAnnotationToStatement(annotation, statement) {
|
|
144
|
+
if (!(annotation === null || annotation === void 0 ? void 0 : annotation.call)) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
(0, brighterscript_1.walkArray)(annotation.call.args, () => { }, { walkMode: brighterscript_1.WalkMode.visitAllRecursive }, annotation.call);
|
|
148
|
+
annotation.call.parent = annotation;
|
|
149
|
+
annotation.parent = statement;
|
|
150
|
+
}
|
|
151
|
+
exports.linkAnnotationToStatement = linkAnnotationToStatement;
|
|
152
|
+
/**
|
|
153
|
+
* Fill the `rawParams: []` placeholders in a generated `getTestSuiteData` method with clones of each test case's actual `@params` argument expressions.
|
|
154
|
+
* The clones are registered in the file's references, so bsc's own pre-transpile processing (i.e. inlining enums and constants) applies to them
|
|
155
|
+
* exactly like it does for handwritten code. This must run before bsc's `beforeFileTranspile` (i.e. during `beforeProgramTranspile`).
|
|
156
|
+
* @param file the file containing the test suite
|
|
157
|
+
* @param method the generated `getTestSuiteData` method
|
|
158
|
+
* @param paramExpressionsList the `@params` argument expressions for each placeholder, in the order they appear in the method
|
|
159
|
+
* @param editor the editor used to make (and later undo) the changes
|
|
160
|
+
*/
|
|
161
|
+
function addParamsToTestSuiteData(file, method, paramExpressionsList, editor) {
|
|
162
|
+
const placeholders = [];
|
|
163
|
+
method.walk((node) => {
|
|
164
|
+
if ((0, brighterscript_1.isAAMemberExpression)(node) && node.keyToken.text === 'rawParams' && (0, brighterscript_1.isArrayLiteralExpression)(node.value)) {
|
|
165
|
+
placeholders.push(node.value);
|
|
166
|
+
}
|
|
167
|
+
}, { walkMode: brighterscript_1.WalkMode.visitExpressionsRecursive });
|
|
168
|
+
const references = new Set();
|
|
169
|
+
const addReferences = (expression) => {
|
|
170
|
+
references.add(expression);
|
|
171
|
+
if ((0, brighterscript_1.isArrayLiteralExpression)(expression)) {
|
|
172
|
+
for (const element of expression.elements) {
|
|
173
|
+
if (!(0, brighterscript_1.isCommentStatement)(element)) {
|
|
174
|
+
addReferences(element);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else if ((0, brighterscript_1.isAALiteralExpression)(expression)) {
|
|
179
|
+
for (const member of expression.elements) {
|
|
180
|
+
if ((0, brighterscript_1.isAAMemberExpression)(member)) {
|
|
181
|
+
addReferences(member.value);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
for (let i = 0; i < placeholders.length && i < paramExpressionsList.length; i++) {
|
|
187
|
+
const clones = paramExpressionsList[i].map(x => x.clone());
|
|
188
|
+
editor.arrayPush(placeholders[i].elements, ...clones);
|
|
189
|
+
//link the clones into the AST
|
|
190
|
+
(0, brighterscript_1.walkArray)(placeholders[i].elements, () => { }, { walkMode: brighterscript_1.WalkMode.visitAllRecursive }, placeholders[i]);
|
|
191
|
+
clones.forEach(addReferences);
|
|
192
|
+
}
|
|
193
|
+
const fileReferences = file.parser.references.expressions;
|
|
194
|
+
editor.edit(() => {
|
|
195
|
+
for (const expression of references) {
|
|
196
|
+
fileReferences.add(expression);
|
|
197
|
+
}
|
|
198
|
+
}, () => {
|
|
199
|
+
for (const expression of references) {
|
|
200
|
+
fileReferences.delete(expression);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
exports.addParamsToTestSuiteData = addParamsToTestSuiteData;
|
|
133
205
|
function getScopeForSuite(testSuite) {
|
|
134
206
|
if (testSuite.isNodeTest) {
|
|
135
207
|
return testSuite.file.program.getScopesForFile(testSuite.file).find((scope) => {
|
package/dist/plugin.js
CHANGED
|
@@ -130,22 +130,35 @@ class RooibosPlugin {
|
|
|
130
130
|
}
|
|
131
131
|
beforeProgramTranspile(program, entries, editor) {
|
|
132
132
|
this.session.prepareForTranspile(editor, program, this.mockUtil);
|
|
133
|
+
//this must happen before bsc's `beforeFileTranspile` (which runs before ours), so bsc will inline any enums/constants used in the `@params`
|
|
134
|
+
for (const testSuite of this.session.sessionInfo.testSuitesToRun) {
|
|
135
|
+
testSuite.addDataFunctions(editor);
|
|
136
|
+
}
|
|
133
137
|
}
|
|
134
138
|
afterProgramTranspile(program, entries, editor) {
|
|
135
139
|
this.session.addLaunchHookFileIfNotPresent();
|
|
136
140
|
this.codeCoverageProcessor.generateMetadata(this.config.isRecordingCodeCoverage, program);
|
|
137
141
|
}
|
|
138
142
|
beforeFileTranspile(event) {
|
|
139
|
-
|
|
140
|
-
|
|
143
|
+
const testSuites = this.session.sessionInfo.testSuitesToRun.filter((ts) => ts.file.pkgPath === event.file.pkgPath);
|
|
144
|
+
for (const testSuite of testSuites) {
|
|
141
145
|
const scope = (0, Utils_1.getScopeForSuite)(testSuite);
|
|
142
146
|
let noEarlyExit = testSuite.annotation.noEarlyExit;
|
|
143
147
|
if (noEarlyExit) {
|
|
144
148
|
console.warn(`WARNING: testSuite "${testSuite.name}" is marked as noEarlyExit`);
|
|
145
149
|
}
|
|
146
150
|
const modifiedTestCases = new Set();
|
|
147
|
-
|
|
151
|
+
const modifiedHookFunctions = new Set();
|
|
148
152
|
for (let group of [...testSuite.testGroups.values()].filter((tg) => tg.isIncluded)) {
|
|
153
|
+
for (const hookName of [group.setupFunctionName, group.tearDownFunctionName, group.beforeEachFunctionName, group.afterEachFunctionName]) {
|
|
154
|
+
if (hookName) {
|
|
155
|
+
const hookKey = group.testSuite.generatedNodeName + group.file.pkgPath + hookName.toLowerCase();
|
|
156
|
+
if (!modifiedHookFunctions.has(hookKey)) {
|
|
157
|
+
group.modifyAssertionsForHook(hookName, noEarlyExit, event.editor, this.session.namespaceLookup, scope);
|
|
158
|
+
modifiedHookFunctions.add(hookKey);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
149
162
|
for (let testCase of [...group.testCases].filter((tc) => tc.isIncluded)) {
|
|
150
163
|
let caseName = group.testSuite.generatedNodeName + group.file.pkgPath + testCase.funcName;
|
|
151
164
|
if (!modifiedTestCases.has(caseName)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rooibos-roku",
|
|
3
|
-
"version": "5.16.
|
|
3
|
+
"version": "5.16.6",
|
|
4
4
|
"description": "simple, flexible, fun brightscript test framework for roku scenegraph apps - roku brighterscript plugin",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"preversion": "npm run build && npm run lint && npm run test",
|
|
@@ -16,15 +16,16 @@
|
|
|
16
16
|
"test:nocover": "mocha",
|
|
17
17
|
"audit": "npm audit || audit-ci --config ./audit-ci.jsonc",
|
|
18
18
|
"cli": "ts-node src/cli.ts",
|
|
19
|
+
"cli:device": "ts-node src/cli.ts --project test-project/bsconfig.device.json",
|
|
19
20
|
"package": "npm run build && npm pack"
|
|
20
21
|
},
|
|
21
22
|
"dependencies": {
|
|
22
|
-
"brighterscript": "^0.
|
|
23
|
+
"brighterscript": "^0.73.5",
|
|
23
24
|
"fast-glob": "^3.2.12",
|
|
24
25
|
"fs-extra": "^10.1.0",
|
|
25
26
|
"minimatch": "^3.0.4",
|
|
26
|
-
"roku-debug": "^0.
|
|
27
|
-
"roku-deploy": "^
|
|
27
|
+
"roku-debug": "^0.24.6",
|
|
28
|
+
"roku-deploy": "^4.0.0-alpha.9",
|
|
28
29
|
"rooibos_promises": "npm:@rokucommunity/promises@^0.5.0",
|
|
29
30
|
"source-map": "^0.7.3",
|
|
30
31
|
"undent": "^1.0.1",
|
|
@@ -33,7 +34,7 @@
|
|
|
33
34
|
"yargs": "^16.2.0"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
|
-
"@rokucommunity/bslint": "^0.8.
|
|
37
|
+
"@rokucommunity/bslint": "^0.8.46",
|
|
37
38
|
"@types/chai": "^4.1.2",
|
|
38
39
|
"@types/events": "^3.0.0",
|
|
39
40
|
"@types/fs-extra": "^5.0.1",
|
|
@@ -55,13 +56,19 @@
|
|
|
55
56
|
"jsdoc": "^4.0.5",
|
|
56
57
|
"mocha": "^10.8.2",
|
|
57
58
|
"nyc": "^15.1.0",
|
|
58
|
-
"ropm": "^0.11.
|
|
59
|
+
"ropm": "^0.11.11",
|
|
59
60
|
"source-map-support": "^0.5.13",
|
|
60
61
|
"ts-node": "^10.7.0",
|
|
61
62
|
"typescript": "^4.7.2"
|
|
62
63
|
},
|
|
63
64
|
"overrides": {
|
|
64
|
-
"serialize-javascript": "^7
|
|
65
|
+
"serialize-javascript": "^7",
|
|
66
|
+
"js-yaml@^3": "^3.15.2",
|
|
67
|
+
"js-yaml@^4": "^4",
|
|
68
|
+
"browserslist": "^4.28.8",
|
|
69
|
+
"istanbul-lib-processinfo": "^3.0.1",
|
|
70
|
+
"uuid": "^11.1.1",
|
|
71
|
+
"@babel/core": "^7.29.7"
|
|
65
72
|
},
|
|
66
73
|
"main": "dist/plugin.js",
|
|
67
74
|
"bin": {
|
|
@@ -109,17 +116,6 @@
|
|
|
109
116
|
"functions": 5,
|
|
110
117
|
"branches": 5
|
|
111
118
|
},
|
|
112
|
-
"mocha": {
|
|
113
|
-
"spec": "src/**/*.spec.ts",
|
|
114
|
-
"fullTrace": true,
|
|
115
|
-
"require": [
|
|
116
|
-
"source-map-support/register",
|
|
117
|
-
"ts-node/register"
|
|
118
|
-
],
|
|
119
|
-
"watchExtensions": [
|
|
120
|
-
"ts"
|
|
121
|
-
]
|
|
122
|
-
},
|
|
123
119
|
"ropm": {
|
|
124
120
|
"rootDir": "./framework/src"
|
|
125
121
|
}
|