rooibos-roku 5.16.3 → 5.16.5
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/CHANGELOG.md +39 -0
- package/README.md +14 -0
- package/audit-ci.jsonc +15 -0
- 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/Rooibos.bs +1 -1
- 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/TestGroup.js +23 -2
- package/dist/lib/utils/Diagnostics.js +1 -0
- package/dist/plugin.js +10 -0
- package/package.json +13 -8
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
## [5.16.5](https://github.com/rokucommunity/rooibos/compare/5.16.4...v5.16.5) - 2026-09-09
|
|
10
|
+
### Changed
|
|
11
|
+
- 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))
|
|
12
|
+
- Make before-exit sleep duration configurable ([#418](https://github.com/rokucommunity/rooibos/pull/418))
|
|
13
|
+
- Run stubCall/expectCalled/expectNotCalled rewrites in setUp/tearDown/beforeEach/afterEach hooks ([#403](https://github.com/rokucommunity/rooibos/pull/403))
|
|
14
|
+
- 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:
|
|
15
|
+
- 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))
|
|
16
|
+
- 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:
|
|
17
|
+
- 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))
|
|
18
|
+
- 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:
|
|
19
|
+
- Security enhancements ([#293](https://github.com/rokucommunity/roku-deploy/pull/293), [#345](https://github.com/rokucommunity/roku-deploy/pull/345))
|
|
20
|
+
- 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:
|
|
21
|
+
- 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))
|
|
22
|
+
- 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:
|
|
23
|
+
- 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))
|
|
24
|
+
### Fixed
|
|
25
|
+
- Fix coverage instrumentation changing constructor execution order ([#355](https://github.com/rokucommunity/rooibos/pull/355))
|
|
26
|
+
- fix: skip assertion tracking injection for namespace function calls ([#385](https://github.com/rokucommunity/rooibos/pull/385))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## [5.16.4](https://github.com/rokucommunity/rooibos/compare/5.16.3...v5.16.4) - 2026-06-10
|
|
31
|
+
### Changed
|
|
32
|
+
- Make tests less brittle - removes full transpile string checks ([#396](https://github.com/rokucommunity/rooibos/pull/396))
|
|
33
|
+
- Security enhancements
|
|
34
|
+
- upgrade to [brighterscript@0.72.5](https://github.com/rokucommunity/brighterscript/blob/master/CHANGELOG.md#0725---2026-06-10). Notable changes since 0.72.2:
|
|
35
|
+
- Security enhancements
|
|
36
|
+
- upgrade to [roku-debug@0.23.11](https://github.com/rokucommunity/roku-debug/blob/master/CHANGELOG.md#02311---2026-06-04). Notable changes since 0.23.8:
|
|
37
|
+
- Fix pressHomeButton crash in disconnectRequest ([#358](https://github.com/rokucommunity/roku-debug/pull/358))
|
|
38
|
+
- Security enhancements
|
|
39
|
+
- upgrade to [roku-deploy@3.17.6](https://github.com/rokucommunity/roku-deploy/blob/master/CHANGELOG.md#3176---2026-06-04). Notable changes since 3.17.4:
|
|
40
|
+
- Fix case-insensitive matching for absolute `files.src` glob patterns on case-insensitive file systems ([#279](https://github.com/rokucommunity/roku-deploy/pull/279))
|
|
41
|
+
- Preserve `!` glob-negation prefix in standardizePath ([#277](https://github.com/rokucommunity/roku-deploy/pull/277))
|
|
42
|
+
- Security enhancements
|
|
43
|
+
- upgrade to [ropm@0.11.8](https://github.com/rokucommunity/ropm/blob/master/CHANGELOG.md#0118---2026-05-30). Notable changes since 0.11.7:
|
|
44
|
+
- Security enhancements
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
9
48
|
## [5.16.3](https://github.com/rokucommunity/rooibos/compare/5.16.2...v5.16.3) - 2026-05-20
|
|
10
49
|
### Changed
|
|
11
50
|
- Update ropm to 0.11.7 and remove lodash override ([#391](https://github.com/rokucommunity/rooibos/pull/391))
|
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
|
|
@@ -47,3 +57,7 @@ Yes, it's been used in production by quite a few respectable companies. There ar
|
|
|
47
57
|
### Is Rooibos actively maintained?
|
|
48
58
|
|
|
49
59
|
We at RokuCommunity love rooibos, and regularly keep it up to date.
|
|
60
|
+
|
|
61
|
+
## Accepted security advisories
|
|
62
|
+
|
|
63
|
+
Dependencies flagged by `npm audit` that we have reviewed and chosen not to upgrade are tracked in [audit-ci.jsonc](https://github.com/RokuCommunity/rooibos/blob/master/audit-ci.jsonc). Each entry includes the advisory ID, the date it was added, and the reason it does not apply to this project.
|
package/audit-ci.jsonc
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Fail on high severity and above. See README "Accepted security advisories" for
|
|
3
|
+
// why each allowlisted entry is safe to defer.
|
|
4
|
+
"$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json",
|
|
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
|
+
]
|
|
15
|
+
}
|
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)
|
|
@@ -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]);
|
|
@@ -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;
|
|
@@ -14,6 +14,7 @@ function addDiagnosticForStatement(file, code, message, statement, severity = br
|
|
|
14
14
|
function addDiagnosticForAnnotation(file, code, message, annotation, severity = brighterscript_1.DiagnosticSeverity.Error, endChar) {
|
|
15
15
|
let line = annotation.range.start.line;
|
|
16
16
|
let col = annotation.range.start.character;
|
|
17
|
+
// TODO: Fix the end character to be the end of the annotation, not the start + 9999
|
|
17
18
|
file.addDiagnostics([createDiagnostic(file, code, message, line, col, annotation.range.end.line, annotation.range.end.character + 9999, severity)]);
|
|
18
19
|
}
|
|
19
20
|
function createDiagnostic(bscFile, code, message, startLine = 0, startCol = 99999, endLine = 0, endCol = 99999, severity = brighterscript_1.DiagnosticSeverity.Error) {
|
package/dist/plugin.js
CHANGED
|
@@ -144,8 +144,18 @@ class RooibosPlugin {
|
|
|
144
144
|
console.warn(`WARNING: testSuite "${testSuite.name}" is marked as noEarlyExit`);
|
|
145
145
|
}
|
|
146
146
|
const modifiedTestCases = new Set();
|
|
147
|
+
const modifiedHookFunctions = new Set();
|
|
147
148
|
testSuite.addDataFunctions(event.editor);
|
|
148
149
|
for (let group of [...testSuite.testGroups.values()].filter((tg) => tg.isIncluded)) {
|
|
150
|
+
for (const hookName of [group.setupFunctionName, group.tearDownFunctionName, group.beforeEachFunctionName, group.afterEachFunctionName]) {
|
|
151
|
+
if (hookName) {
|
|
152
|
+
const hookKey = group.testSuite.generatedNodeName + group.file.pkgPath + hookName.toLowerCase();
|
|
153
|
+
if (!modifiedHookFunctions.has(hookKey)) {
|
|
154
|
+
group.modifyAssertionsForHook(hookName, noEarlyExit, event.editor, this.session.namespaceLookup, scope);
|
|
155
|
+
modifiedHookFunctions.add(hookKey);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
149
159
|
for (let testCase of [...group.testCases].filter((tc) => tc.isIncluded)) {
|
|
150
160
|
let caseName = group.testSuite.generatedNodeName + group.file.pkgPath + testCase.funcName;
|
|
151
161
|
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.5",
|
|
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",
|
|
@@ -14,17 +14,18 @@
|
|
|
14
14
|
"docs": "jsdoc -c jsdoc.json -d .tmp/docs --verbose",
|
|
15
15
|
"test": "nyc mocha",
|
|
16
16
|
"test:nocover": "mocha",
|
|
17
|
-
"audit": "npm audit",
|
|
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.3",
|
|
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.3",
|
|
28
|
+
"roku-deploy": "^4.0.0-alpha.5",
|
|
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",
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"@types/yargs": "^15.0.5",
|
|
44
45
|
"@typescript-eslint/eslint-plugin": "^5.27.0",
|
|
45
46
|
"@typescript-eslint/parser": "^5.27.0",
|
|
47
|
+
"audit-ci": "^7.1.0",
|
|
46
48
|
"brighterscript-jsdocs-plugin": "^0.7.3",
|
|
47
49
|
"chai": "^4.2.0",
|
|
48
50
|
"docdash": "^2.0.2",
|
|
@@ -54,13 +56,16 @@
|
|
|
54
56
|
"jsdoc": "^4.0.5",
|
|
55
57
|
"mocha": "^10.8.2",
|
|
56
58
|
"nyc": "^15.1.0",
|
|
57
|
-
"ropm": "^0.11.
|
|
59
|
+
"ropm": "^0.11.11",
|
|
58
60
|
"source-map-support": "^0.5.13",
|
|
59
61
|
"ts-node": "^10.7.0",
|
|
60
62
|
"typescript": "^4.7.2"
|
|
61
63
|
},
|
|
62
64
|
"overrides": {
|
|
63
|
-
"serialize-javascript": "^7.0.5"
|
|
65
|
+
"serialize-javascript": "^7.0.5",
|
|
66
|
+
"js-yaml@^3": "^3.15.2",
|
|
67
|
+
"js-yaml@^4": "^4.3.2",
|
|
68
|
+
"browserslist": "^4.28.8"
|
|
64
69
|
},
|
|
65
70
|
"main": "dist/plugin.js",
|
|
66
71
|
"bin": {
|