diff --git a/bsc-plugin/package-lock.json b/bsc-plugin/package-lock.json
index 7825e735..8d455fd8 100644
--- a/bsc-plugin/package-lock.json
+++ b/bsc-plugin/package-lock.json
@@ -7,10 +7,12 @@
"": {
"name": "rooibos-roku",
"version": "5.14.0",
+ "hasInstallScript": true,
"license": "ISC",
"dependencies": {
"roku-debug": "^0.21.10",
"roku-deploy": "^3.12.1",
+ "rooibos_promises": "npm:@rokucommunity/promises@^0.5.0",
"source-map": "^0.7.3",
"undent": "^0.1.0",
"vscode-languageserver": "~6.1.1",
@@ -42,6 +44,7 @@
"mocha": "^9.1.3",
"nyc": "^15.1.0",
"release-it": "^17.6.0",
+ "ropm": "^0.10.30",
"source-map-support": "^0.5.13",
"trim-whitespace": "^1.3.3",
"ts-node": "^9.0.0",
@@ -1784,6 +1787,26 @@
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
"dev": true
},
+ "node_modules/@xml-tools/ast": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/@xml-tools/ast/-/ast-5.0.5.tgz",
+ "integrity": "sha512-avvzTOvGplCx9JSKdsTe3vK+ACvsHy2HxVfkcfIqPzu+kF5CT4rw5aUVzs0tJF4cnDyMRVkSyVxR07X0Px8gPA==",
+ "dev": true,
+ "dependencies": {
+ "@xml-tools/common": "^0.1.6",
+ "@xml-tools/parser": "^1.0.11",
+ "lodash": "4.17.21"
+ }
+ },
+ "node_modules/@xml-tools/common": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/@xml-tools/common/-/common-0.1.6.tgz",
+ "integrity": "sha512-7aVZeEYccs1KI/Asd6KKnrB4dTAWXTkjRMjG40ApGEUp5NpfQIvWLEBvMv85Koj2lbSpagcAERwDy9qMsfWGdA==",
+ "dev": true,
+ "dependencies": {
+ "lodash": "4.17.21"
+ }
+ },
"node_modules/@xml-tools/parser": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.11.tgz",
@@ -3288,6 +3311,43 @@
"node": ">= 14"
}
},
+ "node_modules/del": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz",
+ "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==",
+ "dev": true,
+ "dependencies": {
+ "globby": "^11.0.1",
+ "graceful-fs": "^4.2.4",
+ "is-glob": "^4.0.1",
+ "is-path-cwd": "^2.2.0",
+ "is-path-inside": "^3.0.2",
+ "p-map": "^4.0.0",
+ "rimraf": "^3.0.2",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/del/node_modules/p-map": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+ "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "dev": true,
+ "dependencies": {
+ "aggregate-error": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -4430,6 +4490,197 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/glob-all": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/glob-all/-/glob-all-3.2.1.tgz",
+ "integrity": "sha512-x877rVkzB3ipid577QOp+eQCR6M5ZyiwrtaYgrX/z3EThaSPFtLDwBXFHc3sH1cG0R0vFYI5SRYeWMMSEyXkUw==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.2",
+ "yargs": "^15.3.1"
+ },
+ "bin": {
+ "glob-all": "bin/glob-all"
+ }
+ },
+ "node_modules/glob-all/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/glob-all/node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/glob-all/node_modules/cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ }
+ },
+ "node_modules/glob-all/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/glob-all/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/glob-all/node_modules/decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/glob-all/node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/glob-all/node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/glob-all/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/glob-all/node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/glob-all/node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/glob-all/node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/glob-all/node_modules/y18n": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+ "dev": true
+ },
+ "node_modules/glob-all/node_modules/yargs": {
+ "version": "15.4.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+ "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^6.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^4.1.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^4.2.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^18.1.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/glob-all/node_modules/yargs-parser": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
@@ -4815,6 +5066,15 @@
"node": ">= 4"
}
},
+ "node_modules/ignore-walk": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz",
+ "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==",
+ "dev": true,
+ "dependencies": {
+ "minimatch": "^3.0.4"
+ }
+ },
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
@@ -5195,6 +5455,15 @@
"node": ">=8"
}
},
+ "node_modules/is-path-cwd": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
+ "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/is-path-inside": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
@@ -5621,6 +5890,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/latinize": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/latinize/-/latinize-0.5.0.tgz",
+ "integrity": "sha512-SHzxgdcFP/64lUEfX3183QALY2KdSQxad3gmhCc/b03QN1mbx0AnJWvsQjqoJLbucY9pJuK+NMbnasUIocDmnQ==",
+ "dev": true
+ },
"node_modules/lcov-parse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz",
@@ -6382,6 +6657,39 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/npm-bundled": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz",
+ "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==",
+ "dev": true,
+ "dependencies": {
+ "npm-normalize-package-bin": "^1.0.1"
+ }
+ },
+ "node_modules/npm-normalize-package-bin": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
+ "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==",
+ "dev": true
+ },
+ "node_modules/npm-packlist": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.1.4.tgz",
+ "integrity": "sha512-Qzg2pvXC9U4I4fLnUrBmcIT4x0woLtUgxUi9eC+Zrcv1Xx5eamytGAfbDWQ67j7xOcQ2VW1I3su9smVTIdu7Hw==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.6",
+ "ignore-walk": "^3.0.3",
+ "npm-bundled": "^1.1.1",
+ "npm-normalize-package-bin": "^1.0.1"
+ },
+ "bin": {
+ "npm-packlist": "bin/index.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/npm-run-path": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
@@ -8594,21 +8902,206 @@
"node": ">=6 <7 || >=8"
}
},
- "node_modules/run-applescript": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz",
- "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==",
+ "node_modules/rooibos_promises": {
+ "name": "@rokucommunity/promises",
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@rokucommunity/promises/-/promises-0.5.0.tgz",
+ "integrity": "sha512-Xl/8z4+WMeSHCG418Y9O49r/PQphwJ7efVmqlLoOvEg3EQ3ET//VHDQJa0YucuuTQurHfrLjXDj4foluhdHRSg=="
+ },
+ "node_modules/ropm": {
+ "version": "0.10.30",
+ "resolved": "https://registry.npmjs.org/ropm/-/ropm-0.10.30.tgz",
+ "integrity": "sha512-i8OXfo2J1jrxsoMxiKn5OQeeg7pJPn2R/FDj/mKgq3llc/rojblRk+MJsoXXDDxB4T6GeocthOrVkF6PaFzHYA==",
"dev": true,
- "engines": {
- "node": ">=18"
+ "dependencies": {
+ "@xml-tools/ast": "^5.0.5",
+ "@xml-tools/parser": "1.0.10",
+ "brighterscript": "^0.68.3",
+ "del": "6.0.0",
+ "fs-extra": "9.1.0",
+ "glob-all": "3.2.1",
+ "latinize": "0.5.0",
+ "npm-packlist": "2.1.4",
+ "roku-deploy": "^3.12.3",
+ "semver": "^7.6.3",
+ "yargs": "16.2.0"
},
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "bin": {
+ "ropm": "dist/cli.js"
+ },
+ "engines": {
+ "node": ">=8.1.10"
}
},
- "node_modules/run-async": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+ "node_modules/ropm/node_modules/@xml-tools/parser": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.10.tgz",
+ "integrity": "sha512-9oRb68wEKT+MRB7e2GwTiKicRKVXKzquBDGgH6YcGafvnSYXorWi2oaTVtbv2109RlGiQSnoXaQFUXCnHwFS7Q==",
+ "dev": true,
+ "dependencies": {
+ "chevrotain": "7.1.1"
+ }
+ },
+ "node_modules/ropm/node_modules/brighterscript": {
+ "version": "0.68.3",
+ "resolved": "https://registry.npmjs.org/brighterscript/-/brighterscript-0.68.3.tgz",
+ "integrity": "sha512-Fy9/QRsGdqZayWuho4oW8cknP3ZnOHL2l7uWn/AEJfiikwlhgz5jZu1oQV1iyjBQBLpgqIsqk9fHWqRybs3/8A==",
+ "dev": true,
+ "dependencies": {
+ "@rokucommunity/bslib": "^0.1.1",
+ "@rokucommunity/logger": "^0.3.9",
+ "@xml-tools/parser": "^1.0.7",
+ "array-flat-polyfill": "^1.0.1",
+ "chalk": "^2.4.2",
+ "chevrotain": "^7.0.1",
+ "chokidar": "^3.5.1",
+ "clear": "^0.1.0",
+ "cross-platform-clear-console": "^2.3.0",
+ "debounce-promise": "^3.1.0",
+ "eventemitter3": "^4.0.0",
+ "fast-glob": "^3.2.12",
+ "file-url": "^3.0.0",
+ "fs-extra": "^8.1.0",
+ "jsonc-parser": "^2.3.0",
+ "long": "^3.2.0",
+ "luxon": "^2.5.2",
+ "minimatch": "^3.0.4",
+ "moment": "^2.23.0",
+ "p-settle": "^2.1.0",
+ "parse-ms": "^2.1.0",
+ "readline": "^1.3.0",
+ "require-relative": "^0.8.7",
+ "roku-deploy": "^3.12.3",
+ "serialize-error": "^7.0.1",
+ "source-map": "^0.7.4",
+ "vscode-languageserver": "^9.0.1",
+ "vscode-languageserver-protocol": "^3.17.5",
+ "vscode-languageserver-textdocument": "^1.0.11",
+ "vscode-languageserver-types": "^3.17.5",
+ "vscode-uri": "^3.0.8",
+ "xml2js": "^0.5.0",
+ "yargs": "^16.2.0"
+ },
+ "bin": {
+ "bsc": "dist/cli.js"
+ }
+ },
+ "node_modules/ropm/node_modules/brighterscript/node_modules/fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=6 <7 || >=8"
+ }
+ },
+ "node_modules/ropm/node_modules/brighterscript/node_modules/jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+ "dev": true,
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/ropm/node_modules/brighterscript/node_modules/universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/ropm/node_modules/chevrotain": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-7.1.1.tgz",
+ "integrity": "sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==",
+ "dev": true,
+ "dependencies": {
+ "regexp-to-ast": "0.5.0"
+ }
+ },
+ "node_modules/ropm/node_modules/fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "dev": true,
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ropm/node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/ropm/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ropm/node_modules/universalify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/ropm/node_modules/vscode-languageserver": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz",
+ "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==",
+ "dev": true,
+ "dependencies": {
+ "vscode-languageserver-protocol": "3.17.5"
+ },
+ "bin": {
+ "installServerIntoExtension": "bin/installServerIntoExtension"
+ }
+ },
+ "node_modules/run-applescript": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz",
+ "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/run-async": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
"integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
"dev": true,
"engines": {
@@ -11191,6 +11684,26 @@
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
"dev": true
},
+ "@xml-tools/ast": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/@xml-tools/ast/-/ast-5.0.5.tgz",
+ "integrity": "sha512-avvzTOvGplCx9JSKdsTe3vK+ACvsHy2HxVfkcfIqPzu+kF5CT4rw5aUVzs0tJF4cnDyMRVkSyVxR07X0Px8gPA==",
+ "dev": true,
+ "requires": {
+ "@xml-tools/common": "^0.1.6",
+ "@xml-tools/parser": "^1.0.11",
+ "lodash": "4.17.21"
+ }
+ },
+ "@xml-tools/common": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/@xml-tools/common/-/common-0.1.6.tgz",
+ "integrity": "sha512-7aVZeEYccs1KI/Asd6KKnrB4dTAWXTkjRMjG40ApGEUp5NpfQIvWLEBvMv85Koj2lbSpagcAERwDy9qMsfWGdA==",
+ "dev": true,
+ "requires": {
+ "lodash": "4.17.21"
+ }
+ },
"@xml-tools/parser": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.11.tgz",
@@ -12283,6 +12796,33 @@
"esprima": "^4.0.1"
}
},
+ "del": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz",
+ "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==",
+ "dev": true,
+ "requires": {
+ "globby": "^11.0.1",
+ "graceful-fs": "^4.2.4",
+ "is-glob": "^4.0.1",
+ "is-path-cwd": "^2.2.0",
+ "is-path-inside": "^3.0.2",
+ "p-map": "^4.0.0",
+ "rimraf": "^3.0.2",
+ "slash": "^3.0.0"
+ },
+ "dependencies": {
+ "p-map": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+ "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "dev": true,
+ "requires": {
+ "aggregate-error": "^3.0.0"
+ }
+ }
+ }
+ },
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -13118,6 +13658,154 @@
"path-is-absolute": "^1.0.0"
}
},
+ "glob-all": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/glob-all/-/glob-all-3.2.1.tgz",
+ "integrity": "sha512-x877rVkzB3ipid577QOp+eQCR6M5ZyiwrtaYgrX/z3EThaSPFtLDwBXFHc3sH1cG0R0vFYI5SRYeWMMSEyXkUw==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.2",
+ "yargs": "^15.3.1"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ },
+ "cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "dev": true
+ },
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
+ "wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "y18n": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+ "dev": true
+ },
+ "yargs": {
+ "version": "15.4.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+ "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+ "dev": true,
+ "requires": {
+ "cliui": "^6.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^4.1.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^4.2.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^18.1.2"
+ }
+ },
+ "yargs-parser": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ }
+ }
+ },
"glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
@@ -13396,6 +14084,15 @@
"integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
"dev": true
},
+ "ignore-walk": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz",
+ "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==",
+ "dev": true,
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
"immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
@@ -13665,6 +14362,12 @@
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
"dev": true
},
+ "is-path-cwd": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
+ "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==",
+ "dev": true
+ },
"is-path-inside": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
@@ -13999,6 +14702,12 @@
"package-json": "^10.0.0"
}
},
+ "latinize": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/latinize/-/latinize-0.5.0.tgz",
+ "integrity": "sha512-SHzxgdcFP/64lUEfX3183QALY2KdSQxad3gmhCc/b03QN1mbx0AnJWvsQjqoJLbucY9pJuK+NMbnasUIocDmnQ==",
+ "dev": true
+ },
"lcov-parse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz",
@@ -14553,6 +15262,33 @@
"integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==",
"dev": true
},
+ "npm-bundled": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz",
+ "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==",
+ "dev": true,
+ "requires": {
+ "npm-normalize-package-bin": "^1.0.1"
+ }
+ },
+ "npm-normalize-package-bin": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
+ "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==",
+ "dev": true
+ },
+ "npm-packlist": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.1.4.tgz",
+ "integrity": "sha512-Qzg2pvXC9U4I4fLnUrBmcIT4x0woLtUgxUi9eC+Zrcv1Xx5eamytGAfbDWQ67j7xOcQ2VW1I3su9smVTIdu7Hw==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.6",
+ "ignore-walk": "^3.0.3",
+ "npm-bundled": "^1.1.1",
+ "npm-normalize-package-bin": "^1.0.1"
+ }
+ },
"npm-run-path": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
@@ -16183,6 +16919,162 @@
}
}
},
+ "rooibos_promises": {
+ "version": "npm:@rokucommunity/promises@0.5.0",
+ "resolved": "https://registry.npmjs.org/@rokucommunity/promises/-/promises-0.5.0.tgz",
+ "integrity": "sha512-Xl/8z4+WMeSHCG418Y9O49r/PQphwJ7efVmqlLoOvEg3EQ3ET//VHDQJa0YucuuTQurHfrLjXDj4foluhdHRSg=="
+ },
+ "ropm": {
+ "version": "0.10.30",
+ "resolved": "https://registry.npmjs.org/ropm/-/ropm-0.10.30.tgz",
+ "integrity": "sha512-i8OXfo2J1jrxsoMxiKn5OQeeg7pJPn2R/FDj/mKgq3llc/rojblRk+MJsoXXDDxB4T6GeocthOrVkF6PaFzHYA==",
+ "dev": true,
+ "requires": {
+ "@xml-tools/ast": "^5.0.5",
+ "@xml-tools/parser": "1.0.10",
+ "brighterscript": "^0.68.3",
+ "del": "6.0.0",
+ "fs-extra": "9.1.0",
+ "glob-all": "3.2.1",
+ "latinize": "0.5.0",
+ "npm-packlist": "2.1.4",
+ "roku-deploy": "^3.12.3",
+ "semver": "^7.6.3",
+ "yargs": "16.2.0"
+ },
+ "dependencies": {
+ "@xml-tools/parser": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.10.tgz",
+ "integrity": "sha512-9oRb68wEKT+MRB7e2GwTiKicRKVXKzquBDGgH6YcGafvnSYXorWi2oaTVtbv2109RlGiQSnoXaQFUXCnHwFS7Q==",
+ "dev": true,
+ "requires": {
+ "chevrotain": "7.1.1"
+ }
+ },
+ "brighterscript": {
+ "version": "0.68.3",
+ "resolved": "https://registry.npmjs.org/brighterscript/-/brighterscript-0.68.3.tgz",
+ "integrity": "sha512-Fy9/QRsGdqZayWuho4oW8cknP3ZnOHL2l7uWn/AEJfiikwlhgz5jZu1oQV1iyjBQBLpgqIsqk9fHWqRybs3/8A==",
+ "dev": true,
+ "requires": {
+ "@rokucommunity/bslib": "^0.1.1",
+ "@rokucommunity/logger": "^0.3.9",
+ "@xml-tools/parser": "^1.0.7",
+ "array-flat-polyfill": "^1.0.1",
+ "chalk": "^2.4.2",
+ "chevrotain": "^7.0.1",
+ "chokidar": "^3.5.1",
+ "clear": "^0.1.0",
+ "cross-platform-clear-console": "^2.3.0",
+ "debounce-promise": "^3.1.0",
+ "eventemitter3": "^4.0.0",
+ "fast-glob": "^3.2.12",
+ "file-url": "^3.0.0",
+ "fs-extra": "^8.1.0",
+ "jsonc-parser": "^2.3.0",
+ "long": "^3.2.0",
+ "luxon": "^2.5.2",
+ "minimatch": "^3.0.4",
+ "moment": "^2.23.0",
+ "p-settle": "^2.1.0",
+ "parse-ms": "^2.1.0",
+ "readline": "^1.3.0",
+ "require-relative": "^0.8.7",
+ "roku-deploy": "^3.12.3",
+ "serialize-error": "^7.0.1",
+ "source-map": "^0.7.4",
+ "vscode-languageserver": "^9.0.1",
+ "vscode-languageserver-protocol": "^3.17.5",
+ "vscode-languageserver-textdocument": "^1.0.11",
+ "vscode-languageserver-types": "^3.17.5",
+ "vscode-uri": "^3.0.8",
+ "xml2js": "^0.5.0",
+ "yargs": "^16.2.0"
+ },
+ "dependencies": {
+ "fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ },
+ "jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true
+ }
+ }
+ },
+ "chevrotain": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-7.1.1.tgz",
+ "integrity": "sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==",
+ "dev": true,
+ "requires": {
+ "regexp-to-ast": "0.5.0"
+ }
+ },
+ "fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "dev": true,
+ "requires": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ }
+ },
+ "jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6",
+ "universalify": "^2.0.0"
+ }
+ },
+ "semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true
+ },
+ "universalify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+ "dev": true
+ },
+ "vscode-languageserver": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz",
+ "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==",
+ "dev": true,
+ "requires": {
+ "vscode-languageserver-protocol": "3.17.5"
+ }
+ }
+ }
+ },
"run-applescript": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz",
diff --git a/bsc-plugin/package.json b/bsc-plugin/package.json
index 64d0e2a0..f0284717 100644
--- a/bsc-plugin/package.json
+++ b/bsc-plugin/package.json
@@ -16,7 +16,10 @@
"publish-npm:beta": "npm run test && npm publish --tag=beta",
"local": "ts-node scripts/install-local.js",
"remote": "ts-node scripts/install-npm.js",
- "cli": "ts-node src/cli.ts"
+ "cli": "ts-node src/cli.ts",
+ "prepack": "node scripts/pack.js --pre",
+ "postpack": "node scripts/pack.js --post",
+ "postinstall": "ropm copy"
},
"repository": {
"type": "git",
@@ -35,6 +38,7 @@
"dependencies": {
"roku-debug": "^0.21.10",
"roku-deploy": "^3.12.1",
+ "rooibos_promises": "npm:@rokucommunity/promises@^0.5.0",
"source-map": "^0.7.3",
"undent": "^0.1.0",
"vscode-languageserver": "~6.1.1",
@@ -63,6 +67,7 @@
"mocha": "^9.1.3",
"nyc": "^15.1.0",
"release-it": "^17.6.0",
+ "ropm": "^0.10.30",
"source-map-support": "^0.5.13",
"trim-whitespace": "^1.3.3",
"ts-node": "^9.0.0",
@@ -121,6 +126,9 @@
"ts"
]
},
+ "ropm": {
+ "rootDir": "../framework/src"
+ },
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
diff --git a/bsc-plugin/scripts/pack.js b/bsc-plugin/scripts/pack.js
new file mode 100644
index 00000000..ade1383d
--- /dev/null
+++ b/bsc-plugin/scripts/pack.js
@@ -0,0 +1,20 @@
+var fsExtra = require('fs-extra');
+var path = require('path');
+
+var cachePath = path.join(__dirname, 'pack-cache.txt');
+var packageJsonPath = path.join(__dirname, '../package.json');
+
+var packageJson = fsExtra.readJsonSync(packageJsonPath);
+
+//store the script and remove it from package.json
+if (process.argv.includes('--pre')) {
+ fsExtra.outputFileSync(cachePath, packageJson.scripts.postinstall);
+ delete packageJson.scripts.postinstall;
+
+ //restore the script
+} else if (process.argv.includes('--post')) {
+ packageJson.scripts.postinstall = fsExtra.readFileSync(cachePath, packageJson.scripts.postinstall).toString();
+ fsExtra.removeSync(cachePath);
+}
+
+fsExtra.outputJsonSync(packageJsonPath, packageJson, { spaces: 4 });
diff --git a/bsc-plugin/src/lib/rooibos/Annotation.ts b/bsc-plugin/src/lib/rooibos/Annotation.ts
index 5d2cffbe..991b7ff6 100644
--- a/bsc-plugin/src/lib/rooibos/Annotation.ts
+++ b/bsc-plugin/src/lib/rooibos/Annotation.ts
@@ -141,13 +141,18 @@ export class RooibosAnnotation {
isSolo = getAnnotationsOfType(AnnotationType.Solo).length > 0;
isIgnore = getAnnotationsOfType(AnnotationType.Ignore).length > 0;
+ for (const annotation of getAnnotationsOfType(AnnotationType.NodeTest)) {
+ nodeName = annotation.getArguments()[0] as string;
+ }
+
for (const annotation of getAnnotationsOfType(AnnotationType.Async)) {
async = true;
asyncTimeout = annotation.getArguments().length === 1 ? parseInt(annotation.getArguments()[0] as any) : -1;
- }
-
- for (const annotation of getAnnotationsOfType(AnnotationType.NodeTest)) {
- nodeName = annotation.getArguments()[0] as string;
+ if (nodeName === null) {
+ // If the test is async, it must be a node test
+ // Default to `Node` if no node is specified
+ nodeName = 'Node';
+ }
}
for (const annotation of getAnnotationsOfType(AnnotationType.Tags)) {
diff --git a/bsc-plugin/src/lib/rooibos/FileFactory.ts b/bsc-plugin/src/lib/rooibos/FileFactory.ts
index 71ddeaec..cd98282f 100644
--- a/bsc-plugin/src/lib/rooibos/FileFactory.ts
+++ b/bsc-plugin/src/lib/rooibos/FileFactory.ts
@@ -24,7 +24,7 @@ export class FileFactory {
this.coverageComponentBrsTemplate = fs.readFileSync(path.join(this.frameworkSourcePath, '/source/rooibos/CodeCoverage.brs'), 'utf8');
}
- public addedSourceFrameworkFilePaths: string[] = [];
+ public sourceFilesToAutoImport: string[] = [];
public addedFrameworkFiles: BscFile[] = [];
public addFrameworkFiles(program: Program) {
@@ -43,10 +43,10 @@ export class FileFactory {
});
for (let filePath of globedFiles) {
- if (/^source[/\\]rooibos[/\\]/g.test(filePath)) {
+ if (this.shouldAddFileToImportList(filePath)) {
// Save a list of all source files added to the program
// to be imported by node test components
- this.addedSourceFrameworkFilePaths.push(filePath);
+ this.sourceFilesToAutoImport.push(filePath);
}
let sourcePath = path.resolve(this.frameworkSourcePath, filePath);
let fileContents = fs.readFileSync(sourcePath, 'utf8').toString();
@@ -67,7 +67,7 @@ export class FileFactory {
public createTestXML(name: string, baseName: string, suite?: TestSuite): string {
let scriptImports = [];
- for (let filePath of this.addedSourceFrameworkFilePaths) {
+ for (let filePath of this.sourceFilesToAutoImport) {
scriptImports.push(``);
}
@@ -117,6 +117,16 @@ export class FileFactory {
return result !== undefined;
}
+ private shouldAddFileToImportList(destFilePath): boolean {
+ const pathDetails = path.parse(destFilePath);
+ if (pathDetails.dir === 'source' || pathDetails.dir.startsWith('source\\') || pathDetails.dir.startsWith('source/')) {
+ if (pathDetails.ext === '.brs' || (pathDetails.ext === '.bs' && !pathDetails.name.endsWith('.d'))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public addFile(program, projectPath: string, contents: string) {
try {
const file = program.setFile({
diff --git a/bsc-plugin/src/lib/rooibos/RooibosSession.ts b/bsc-plugin/src/lib/rooibos/RooibosSession.ts
index fa2422ba..a78931f6 100644
--- a/bsc-plugin/src/lib/rooibos/RooibosSession.ts
+++ b/bsc-plugin/src/lib/rooibos/RooibosSession.ts
@@ -219,6 +219,12 @@ export class RooibosSession {
}
let brsFile = this.fileFactory.addFile(program, suite.bsPkgPath, undent`
function init()
+ m.top.addField("rooibosRunSuite", "boolean", false)
+ m.top.observeFieldScoped("rooibosRunSuite", "rooibosRunSuite")
+ end function
+
+ function rooibosRunSuite()
+ m.top.unobserveFieldScoped("rooibosRunSuite")
nodeRunner = Rooibos_TestRunner(m.top.getScene(), m)
m.top.rooibosTestResult = nodeRunner.runInNodeMode("${suite.name}")
end function
diff --git a/bsc-plugin/src/lib/rooibos/TestGroup.ts b/bsc-plugin/src/lib/rooibos/TestGroup.ts
index ee4e9ce2..6775d635 100644
--- a/bsc-plugin/src/lib/rooibos/TestGroup.ts
+++ b/bsc-plugin/src/lib/rooibos/TestGroup.ts
@@ -220,6 +220,7 @@ export class TestGroup extends TestBlock {
name: ${sanitizeBsJsonString(this.name)}
isSolo: ${this.isSolo}
isIgnored: ${this.isIgnored}
+ isAsync: ${this.isAsync}
filename: "${this.pkgPath}"
lineNumber: "${this.annotation.annotation.range.start.line + 1}"
setupFunctionName: "${this.setupFunctionName || ''}"
diff --git a/bsc-plugin/src/lib/rooibos/TestSuite.ts b/bsc-plugin/src/lib/rooibos/TestSuite.ts
index befc6e32..528d9709 100644
--- a/bsc-plugin/src/lib/rooibos/TestSuite.ts
+++ b/bsc-plugin/src/lib/rooibos/TestSuite.ts
@@ -1,5 +1,6 @@
import * as path from 'path';
import type { AstEditor, BrsFile, ClassStatement } from 'brighterscript';
+import { nodes } from 'brighterscript/dist/roku-types';
import { diagnosticNodeTestIllegalNode, diagnosticNodeTestRequiresNode } from '../utils/Diagnostics';
@@ -9,6 +10,8 @@ import type { TestGroup } from './TestGroup';
import { addOverriddenMethod, sanitizeBsJsonString } from './Utils';
import type { RooibosSession } from './RooibosSession';
+const nativeNodeNames = Object.keys(nodes);
+
/**
* base of test suites and blocks..
*/
@@ -124,7 +127,7 @@ export class TestSuite extends TestBlock {
if (this.isNodeTest) {
if (!this.nodeName) {
diagnosticNodeTestRequiresNode(this.file, this.annotation.annotation);
- } else if (!this.file.program.getComponent(this.nodeName)) {
+ } else if (!this.file.program.getComponent(this.nodeName) && !nativeNodeNames.includes(this.nodeName.toLowerCase())) {
diagnosticNodeTestIllegalNode(this.file, this.annotation.annotation, this.nodeName);
}
}
@@ -138,6 +141,7 @@ export class TestSuite extends TestBlock {
isSolo: ${this.isSolo}
noCatch: ${this.annotation.noCatch}
isIgnored: ${this.isIgnored}
+ isAsync: ${this.isAsync}
pkgPath: "${this.pkgPath}"
filePath: "${this.filePath}"
lineNumber: ${this.classStatement.range.start.line + 1}
diff --git a/bsc-plugin/src/lib/rooibos/TestSuiteBuilder.ts b/bsc-plugin/src/lib/rooibos/TestSuiteBuilder.ts
index e7dfac3b..846ffee2 100644
--- a/bsc-plugin/src/lib/rooibos/TestSuiteBuilder.ts
+++ b/bsc-plugin/src/lib/rooibos/TestSuiteBuilder.ts
@@ -186,6 +186,9 @@ export class TestSuiteBuilder {
}
private sanitizeFunctionName(name: string) {
+ if (/^\d/.test(name)) {
+ name = '_' + name;
+ }
return name.replace(/[^0-9_a-z]/ig, '_');
}
public createTestCases(statement: ClassMethodStatement, annotation: RooibosAnnotation): boolean {
diff --git a/bsc-plugin/src/plugin.spec.ts b/bsc-plugin/src/plugin.spec.ts
index 2da0898b..4d8dd924 100644
--- a/bsc-plugin/src/plugin.spec.ts
+++ b/bsc-plugin/src/plugin.spec.ts
@@ -488,6 +488,7 @@ describe('RooibosPlugin', () => {
isSolo: false
noCatch: false
isIgnored: false
+ isAsync: false
pkgPath: "${s`source/test.spec.bs`}"
filePath: "${s`${tmpPath}/rootDir/source/test.spec.bs`}"
lineNumber: 3
@@ -510,6 +511,7 @@ describe('RooibosPlugin', () => {
name: "groupA"
isSolo: false
isIgnored: false
+ isAsync: false
filename: "${s`source/test.spec.bs`}"
lineNumber: "4"
setupFunctionName: ""
@@ -556,6 +558,124 @@ describe('RooibosPlugin', () => {
})).not.to.exist;
});
+ it('handles groups that start with numbers', async () => {
+ plugin.afterProgramCreate(program);
+ // program.validate();
+ const file = program.setFile('source/test.spec.bs', `
+ @suite
+ class ATest extends rooibos.BaseTestSuite
+ @describe("1groupA")
+ @it("is test1")
+ @slow(1000)
+ function Test_3()
+ end function
+ end class
+ `);
+ program.validate();
+ await builder.transpile();
+ console.log(builder.getDiagnostics());
+ expect(builder.getDiagnostics()).to.have.length(1);
+ expect(builder.getDiagnostics()[0].severity).to.equal(DiagnosticSeverity.Warning);
+ expect(plugin.session.sessionInfo.testSuitesToRun).to.not.be.empty;
+ expect(plugin.session.sessionInfo.suitesCount).to.equal(1);
+ expect(plugin.session.sessionInfo.groupsCount).to.equal(1);
+ expect(plugin.session.sessionInfo.testsCount).to.equal(1);
+
+ expect(
+ getContents('rooibosMain.brs')
+ ).to.eql(undent`
+ function main()
+ Rooibos_init("RooibosScene")
+ end function
+ `);
+ expect(
+ getContents('test.spec.brs')
+ ).to.eql(undent`
+ function __ATest_builder()
+ instance = __rooibos_BaseTestSuite_builder()
+ instance.super0_new = instance.new
+ instance.new = sub()
+ m.super0_new()
+ end sub
+ instance._1groupA_is_test1 = function()
+ end function
+ instance.super0_getTestSuiteData = instance.getTestSuiteData
+ instance.getTestSuiteData = function()
+ return {
+ name: "ATest"
+ isSolo: false
+ noCatch: false
+ isIgnored: false
+ isAsync: false
+ pkgPath: "${s`source/test.spec.bs`}"
+ filePath: "${s`${tmpPath}/rootDir/source/test.spec.bs`}"
+ lineNumber: 3
+ valid: true
+ hasFailures: false
+ hasSoloTests: false
+ hasIgnoredTests: false
+ hasSoloGroups: false
+ setupFunctionName: ""
+ tearDownFunctionName: ""
+ beforeEachFunctionName: ""
+ afterEachFunctionName: ""
+ isNodeTest: false
+ isAsync: false
+ asyncTimeout: 60000
+ nodeName: ""
+ generatedNodeName: "ATest"
+ testGroups: [
+ {
+ name: "1groupA"
+ isSolo: false
+ isIgnored: false
+ isAsync: false
+ filename: "${s`source/test.spec.bs`}"
+ lineNumber: "4"
+ setupFunctionName: ""
+ tearDownFunctionName: ""
+ beforeEachFunctionName: ""
+ afterEachFunctionName: ""
+ testCases: [
+ {
+ isSolo: false
+ noCatch: false
+ funcName: "_1groupA_is_test1"
+ isIgnored: false
+ isAsync: false
+ asyncTimeout: 2000
+ slow: 1000
+ isParamTest: false
+ name: "is test1"
+ lineNumber: 7
+ paramLineNumber: 0
+ assertIndex: 0
+ rawParams: invalid
+ paramTestIndex: 0
+ expectedNumberOfParams: 0
+ isParamsValid: true
+ }
+ ]
+ }
+ ]
+ }
+ end function
+ return instance
+ end function
+ function ATest()
+ instance = __ATest_builder()
+ instance.new()
+ return instance
+ end function
+ `);
+
+ //verify the AST was restored after transpile
+ const cls = file.ast.statements[0] as ClassStatement;
+ expect(cls.body.find((x: ClassMethodStatement) => {
+ return x.name?.text.toLowerCase() === 'getTestSuiteData'.toLowerCase();
+ })).not.to.exist;
+ });
+
it('test full transpile with complex params', async () => {
plugin.afterProgramCreate(program);
// program.validate();
@@ -2174,7 +2294,8 @@ describe('RooibosPlugin', () => {
[['mocha'], 'rooibos_MochaTestReporter'],
[['JUnit', 'MyCustomReporter'], `rooibos_JUnitTestReporter${sep}MyCustomReporter`]
];
- it('adds custom test reporters', async () => {
+ it('adds custom test reporters', async function test() {
+ this.timeout(10_000);
for (const [reporters, expected] of params) {
setupProgram({
rootDir: _rootDir,
diff --git a/docs/index.md b/docs/index.md
index 2c8dbb50..665f5020 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1064,7 +1064,7 @@ The behavior of your unit tests is identical to unit testing any other class, wi
### Async testing
To indicate a test suite will run in async mode you will mark the test suite with the @async annotation or mark one ore more tests with @async. This will cause rooibos to run the tests in async mode. If all tests in the suite do not complete within the timeout, then the suite will fail. The default time out is 60 seconds.
-When you mark any test in a suite with the @async annotation this will keep the test running in the background, waiting for a call to m.done(). If the call is not made within the timeout, then the test fails. Again, the default timeout for each test is 2 seconds.
+When you mark any test in a suite with the @async annotation this will keep the test running in the background, waiting for a call to `m.done()`. If the call is not made within the timeout, then the test fails. Again, the default timeout for each test is 2 seconds.
Note: you are not required to add @async to your testSuite, it is implied when you add it one more more tests. However, you may wish to add tge async annotation to your suite, to override the default of 60 seconds (e.g. with the annotation `async(12000)` we are instructing rooibos to wait up to 2 minutes for the _whole_ suite).
@@ -1142,7 +1142,26 @@ function OnTimer()
m.testSuite.done()
end function
```
+#### Working with Promises
+Alternately, instead of using the `done()` callback, you may return a `Promise` from your test. The test will automaticly complete when the promise is completed. If the returned promise rejects the test will be considered failed.
+
+This is useful if the APIs you are testing return promises:
+
+```
+ @it('respond with matching records')
+ function _()
+ return rooibos.promises.chain(db.find({type: 'User'})).then(sub(result)
+ m.testSuite.assertEqual(result.count(), 3)
+ end sub).catch(sub(error)
+ m.testSuite.fail("should not reject")
+ end sub).toPromises()
+ end function
+```
+
+Rooibos implements the [rokucomunity/promises](https://github.com/rokucommunity/promises) library to enable this support. Please visit that project for more details and examples of promises.
+
+Note: `Promises` are only supported in Node tests and returning a promise from a non-Node test will automaticly fail the test.
## Advanced setup
diff --git a/framework/src/source/rooibos/BaseTestSuite.bs b/framework/src/source/rooibos/BaseTestSuite.bs
index 6db66780..92f1b20c 100644
--- a/framework/src/source/rooibos/BaseTestSuite.bs
+++ b/framework/src/source/rooibos/BaseTestSuite.bs
@@ -32,6 +32,9 @@ namespace rooibos
protected __stubId = -1
protected __mockId = -1
protected __mockTargetId = -1
+ protected currentExecutionTime = 0
+ protected timedOut = false
+ public deferred = invalid
'special values
protected invalidValue = "#ROIBOS#INVALID_VALUE" ' special value used in mock arguments
@@ -80,6 +83,11 @@ namespace rooibos
m.nodeName = data.nodeName
m.generatedNodeName = data.generatedNodeName
m.isFailingFast = false
+
+ if m.isNodeTest
+ m.deferred = rooibos.promises.create()
+ end if
+
m.stats = new rooibos.Stats()
end if
end function
@@ -112,7 +120,7 @@ namespace rooibos
m.notifyReportersOnSuiteBegin()
rooibos.common.logTrace(">>>>>>>>>>>>")
rooibos.common.logTrace("RUNNING TEST SUITE")
- if m.isAsync = true
+ if m.isNodeTest = true
rooibos.common.logTrace("THIS GROUP IS ASYNC")
m.runAsync()
else
@@ -140,15 +148,6 @@ namespace rooibos
end if
end for
-
- if m.isNodeTest and m.testRunner.top <> invalid
- m.testRunner.top.addFields({ asyncRooibosTestResult: {
- stats: m.stats
- tests: m.tests
- groups: m.groups
- }
- })
- end if
m.notifyReportersOnSuiteComplete()
end function
@@ -172,24 +171,17 @@ namespace rooibos
m.currentGroupIndex++
m.currentGroup = m.groups[m.currentGroupIndex]
if m.currentGroup = invalid
- m.setTestTimer(0)
rooibos.common.logTrace("All groups are finished")
'finished
- m.finishAsyncGroups()
+ m.testSuiteDone()
else
group = m.currentGroup
- m.testRunner.top.rooibosGroupFinished = false
-
- m.testRunner.top.observeFieldScoped("rooibosGroupFinished", "rooibos_onGroupComplete")
-
- completed = group.run()
-
- if group.stats.hasFailures
- rooibos.common.logDebug("Group failed before any async code could be executed")
- m.testRunner.top.unobserveFieldScoped("rooibosGroupFinished")
- ' m.testGroupDone()
- m.onAsyncGroupComplete(group)
- else if m.testRunner.top.rooibosGroupFinished
+ group.run()
+ if rooibos.promises.isPromise(group.deferred)
+ rooibos.promises.onFinally(group.deferred, sub(context)
+ context.self.onAsyncGroupComplete(context.group)
+ end sub, { group: group, self: m })
+ else
m.onAsyncGroupComplete(group)
end if
end if
@@ -197,7 +189,6 @@ namespace rooibos
private function onAsyncGroupComplete(group = invalid) as void
rooibos.common.logTrace("++ CURRENT GROUP COMPLETED")
- m.testRunner.top.unobserveFieldScoped("rooibosGroupFinished")
group = group = invalid ? m.currentGroup : group
if group = invalid
@@ -210,41 +201,19 @@ namespace rooibos
if m.stats.hasFailures and m.isFailingFast
rooibos.common.logTrace("Terminating group due to failed test")
m.isTestFailedDueToEarlyExit = true
- m.finishAsyncGroups()
+ m.testSuiteDone()
else
m.runNextAsync()
end if
-
- end function
-
- private function finishAsyncGroups()
- m.testRunner.top.unobserveFieldScoped("rooibosGroupFinished")
-
- m.testRunner.top.addFields({ asyncRooibosTestResult: {
- stats: m.stats
- tests: m.tests
- groups: m.groups
- }
- })
- rooibos.common.logTrace("Indicating test suite is done")
- m.testSuiteDone()
end function
- private function setTestTimer(duration)
- rooibos.common.logTrace(`SETTING TIMER FOR ${duration}`)
- if m.testTimer = invalid
- m.testTimer = createObject("roSGNode", "Timer")
- end if
- if duration = 0
- m.testTimer.unobserveFieldScoped("fire")
- m.testTimer.control = "stop"
- else
- m.currentTimeout = duration
- m.testTimer.observeFieldScoped("fire", "rooibos_onTestTimer")
-
- m.testTimer.duration = duration / 1000.0
- m.testTimer.control = "start"
+ ' calculate if the suite has timed out. Will return true if the suite flipped the timedOut flag
+ function isSuiteTimedOut()
+ if m.isNodeTest and m.asyncTimeout > 0 and m.currentExecutionTime >= m.asyncTimeout
+ m.timedOut = true
+ return true
end if
+ return false
end function
function runTest(test as rooibos.Test)
@@ -253,11 +222,19 @@ namespace rooibos
m.currentResult.skip("Test is ignored")
return invalid
end if
+
+ ' Fail the test if the suite has timed out.
+ ' Currently, this will only happen if the suite is a node test.
+ if m.isNodeTest and m.timedOut
+ m.currentResult.fail("Suite test execution exceeded " + m.asyncTimeout.toStr() + "ms")
+ return invalid
+ end if
+
m.currentResult.throwOnFailedAssertion = m.throwOnFailedAssertion
if m.catchCrashes and not test.noCatch and not m.noCatch
try
test.run()
- if m.isAutoAssertingMocks = true and not test.isAsync
+ if m.isAutoAssertingMocks = true and test.deferred = invalid
m.AssertMocks()
m.CleanMocks()
m.CleanStubs()
@@ -268,12 +245,14 @@ namespace rooibos
end try
else
test.run()
- if m.isAutoAssertingMocks = true and not test.isAsync
+ if m.isAutoAssertingMocks = true and test.deferred = invalid
m.AssertMocks()
m.CleanMocks()
m.CleanStubs()
end if
end if
+
+ return test.deferred
end function
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -3079,30 +3058,27 @@ namespace rooibos
wait(delay, port)
end function
- function setAsync(isAsync as boolean)
- rooibos.common.logTrace(`Setting current test to async ${isAsync}`)
- m.top.rooibosTestIsAsync = isAsync
- end function
-
function done()
rooibos.common.logTrace("Async test is complete")
if m.isDoneCalled = false
m.isDoneCalled = true
- m.top.rooibosTestFinished = true
+ deferred = m.currentGroup?.currentTest?.deferred
+ if rooibos.promises.isPromise(deferred)
+ rooibos.promises.resolve(true, deferred)
+ end if
else
rooibos.common.logWarning("extra done call after test is done! Did you properly clean up your observers?")
end if
end function
function testSuiteDone()
- rooibos.common.logTrace("Async suite is complete")
+ rooibos.common.logTrace("Indicating test suite is done")
m.notifyReportersOnSuiteComplete()
- m.top.rooibosSuiteFinished = true
- end function
-
- function testGroupDone()
- rooibos.common.logTrace("Async group is complete")
- m.top.rooibosGroupFinished = true
+ m.testRunner.top.rooibosTestResult = {
+ stats: m.stats
+ tests: m.tests
+ groups: m.groups
+ }
end function
function assertAsyncField(target, fieldName, delay = 500, maxAttempts = 10)
@@ -3165,20 +3141,9 @@ namespace rooibos
end if
end for
end sub
-
end class
- function onGroupComplete()
- rooibos.common.logTrace("++++++++ THE GROUP COMPLETED")
- m.testRunner.currentTestSuite.onAsyncGroupComplete()
- end function
-
- function onTestTimer()
- rooibos.common.logTrace("++++++++ TEST TIMED OUT")
- m.testRunner.currentTestSuite.failBecauseOfTimeOut()
- end function
-
function getMocksByFunctionName()
if m._rMocksByFunctionName = invalid
m._rMocksByFunctionName = {}
@@ -3197,4 +3162,4 @@ namespace rooibos
function isFunctionMocked(functionName as string)
return rooibos.getMockForFunction(functionName) <> invalid
end function
-end namespace
\ No newline at end of file
+end namespace
diff --git a/framework/src/source/rooibos/Test.bs b/framework/src/source/rooibos/Test.bs
index 8faf88bf..47137cf3 100644
--- a/framework/src/source/rooibos/Test.bs
+++ b/framework/src/source/rooibos/Test.bs
@@ -10,6 +10,7 @@ namespace rooibos
public paramLineNumber
public testSuite = invalid
public testGroup = invalid
+ public deferred = invalid
public rawParams
public paramTestIndex
@@ -19,9 +20,13 @@ namespace rooibos
public result = invalid
- function new(testGroup, data)
+ function new(testGroup, data, testSuite = invalid)
m.testGroup = testGroup
- m.testSuite = testGroup.testSuite
+ if testSuite <> invalid
+ m.testSuite = testSuite
+ else
+ m.testSuite = testGroup.testSuite
+ end if
m.isSolo = data.isSolo
m.noCatch = data.noCatch
m.funcName = data.funcName
@@ -37,6 +42,10 @@ namespace rooibos
m.isParamTest = data.isParamTest
m.expectedNumberOfParams = data.expectedNumberOfParams
+ if m.testSuite.isNodeTest
+ m.deferred = rooibos.promises.create()
+ end if
+
if m.isParamTest
m.name = m.name + stri(m.paramTestIndex)
end if
@@ -45,47 +54,120 @@ namespace rooibos
end function
function run()
- rooibosTimer = createObject("roTimespan")
- rooibosTimer.mark()
+ m.rooibosTimer = createObject("roTimespan")
if m.isParamTest
- m.runParamsTest()
+ m.rooibosTimer.mark()
+ promise = m.runParamsTest()
else
- m.testSuite[m.funcName]()
+ promise = m.testSuite[m.funcName]()
+ end if
+
+ if rooibos.promises.isPromise(promise)
+ if m.testSuite.isNodeTest
+ m.markDoneWhenTestCompletes(promise)
+ else
+ throw "Can not return a promise from a non-node test"
+ end if
+ else if m.testSuite.isNodeTest and not m.isAsync
+ ' The test is a node test and not async so we need to resolve the deferred
+ ' immediately
+ m.recordExecutionTime()
+ rooibos.promises.resolve(invalid, m.deferred)
end if
- m.result.time = rooibosTimer.totalMilliseconds()
+ if m.deferred <> invalid
+ m.recordExecutionTimeWhenDone()
+ m.registerTimeout()
+ else
+ m.recordExecutionTime()
+ end if
+ return m.differed
+ end function
+
+ ' Sets up a promise chain to link the deferred to the test promise results
+ ' and resolves or rejects the deferred based on the result of the test promise.
+ ' Also records the execution time of the test if not already recorded.
+ function markDoneWhenTestCompletes(testPromise)
+ rooibos.promises.chain(testPromise, m).then(sub(result, m)
+ m.recordExecutionTime()
+ rooibos.common.logDebug("Test promise resolved")
+ rooibos.promises.resolve(result, m.deferred)
+ end sub).catch(sub(error, m)
+ m.recordExecutionTime()
+ rooibos.common.logDebug("Test promise rejected")
+ rooibos.promises.reject(error, m.deferred)
+ end sub)
+ end function
+
+ function registerTimeout()
+ rooibos.promises.internal.delay(sub(m)
+ if not rooibos.promises.isComplete(m.deferred)
+ m.recordExecutionTime(m.asyncTimeout)
+ m.testSuite.fail(`Test execution exceeded ${m.asyncTimeout}ms`)
+ rooibos.promises.resolve(invalid, m.deferred)
+ end if
+ end sub, m, m.asyncTimeout / 1000)
+ end function
+
+ function recordExecutionTimeWhenDone()
+ rooibos.promises.chain(m.deferred, m).then(sub(result, m)
+ m.recordExecutionTime()
+ rooibos.promises.resolve(result, m.deferred)
+ end sub).catch(sub(error, m)
+ m.recordExecutionTime()
+ rooibos.promises.reject(error, m.deferred)
+ end sub)
+ end function
+
+ function recordExecutionTime(time = m.rooibosTimer.totalMilliseconds())
+ if m.result.time = -1
+ m.result.time = time
+ end if
end function
function runParamsTest()
testParams = m.getTestParams()
if m.expectedNumberOfParams = 1
- m.testSuite[m.funcName](testParams[0])
+ m.rooibosTimer.mark()
+ return m.testSuite[m.funcName](testParams[0])
else if m.expectedNumberOfParams = 2
- m.testSuite[m.funcName](testParams[0], testParams[1])
+ m.rooibosTimer.mark()
+ return m.testSuite[m.funcName](testParams[0], testParams[1])
else if m.expectedNumberOfParams = 3
- m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2])
+ m.rooibosTimer.mark()
+ return m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2])
else if m.expectedNumberOfParams = 4
- m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3])
+ m.rooibosTimer.mark()
+ return m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3])
else if m.expectedNumberOfParams = 5
- m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4])
+ m.rooibosTimer.mark()
+ return m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4])
else if m.expectedNumberOfParams = 6
- m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5])
+ m.rooibosTimer.mark()
+ return m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5])
else if m.expectedNumberOfParams = 7
- m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5], testParams[6])
+ m.rooibosTimer.mark()
+ return m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5], testParams[6])
else if m.expectedNumberOfParams = 8
- m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5], testParams[6], testParams[7])
+ m.rooibosTimer.mark()
+ return m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5], testParams[6], testParams[7])
else if m.expectedNumberOfParams = 9
- m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5], testParams[6], testParams[7], testParams[8])
+ m.rooibosTimer.mark()
+ return m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5], testParams[6], testParams[7], testParams[8])
else if m.expectedNumberOfParams = 10
- m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5], testParams[6], testParams[7], testParams[8], testParams[9])
+ m.rooibosTimer.mark()
+ return m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5], testParams[6], testParams[7], testParams[8], testParams[9])
else if m.expectedNumberOfParams = 11
- m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5], testParams[6], testParams[7], testParams[8], testParams[9], testParams[10])
+ m.rooibosTimer.mark()
+ return m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5], testParams[6], testParams[7], testParams[8], testParams[9], testParams[10])
else if m.expectedNumberOfParams = 12
- m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5], testParams[6], testParams[7], testParams[8], testParams[9], testParams[10], testParams[11])
+ m.rooibosTimer.mark()
+ return m.testSuite[m.funcName](testParams[0], testParams[1], testParams[2], testParams[3], testParams[4], testParams[5], testParams[6], testParams[7], testParams[8], testParams[9], testParams[10], testParams[11])
else if m.expectedNumberOfParams > 12
+ m.rooibosTimer.mark()
m.testSuite.fail("Test case had more than 12 params. Max of 12 params is supported")
end if
end function
@@ -108,4 +190,4 @@ namespace rooibos
end function
end class
-end namespace
\ No newline at end of file
+end namespace
diff --git a/framework/src/source/rooibos/TestGroup.bs b/framework/src/source/rooibos/TestGroup.bs
index eacf6e40..2c8c6a9c 100644
--- a/framework/src/source/rooibos/TestGroup.bs
+++ b/framework/src/source/rooibos/TestGroup.bs
@@ -26,6 +26,7 @@ namespace rooibos
nodeName = invalid
testsData = invalid
tests = []
+ public deferred = invalid
function new(testSuite, data)
m.testSuite = testSuite
@@ -37,7 +38,7 @@ namespace rooibos
m.isAsync = data.isAsync
m.asyncTimeout = data.asyncTimeout
m.testsData = data.testCases
- m.isNodeTest = false
+ m.isNodeTest = testSuite.isNodeTest
m.nodeName = invalid
m.setupFunctionName = data.setupFunctionName
m.tearDownFunctionName = data.tearDownFunctionName
@@ -45,6 +46,10 @@ namespace rooibos
m.afterEachFunctionName = data.afterEachFunctionName
m.lineNumber = data.lineNumber
+ if m.isNodeTest
+ m.deferred = rooibos.promises.create()
+ end if
+
'bs:disable-next-line
m.global = testSuite.global
m.top = testSuite.top
@@ -63,11 +68,10 @@ namespace rooibos
rooibos.common.logTrace("RUNNING TEST GROUP")
m.testRunner = m.testSuite.testRunner
m.notifyReportersOnTestGroupBegin()
- m.testSuite.setTestTimer(0)
- if m.testSuite.isAsync = true
+ if m.testSuite.isNodeTest = true
rooibos.common.logTrace("THIS GROUP IS ASYNC")
m.runAsync()
- return false
+ return m.deferred
else
rooibos.common.logTrace("THIS GROUP IS SYNC")
m.runSync()
@@ -145,40 +149,36 @@ namespace rooibos
m.finishAsyncTests()
else
test = m.currentTest
- if test.isIgnored
+ ' Check to see if the test is ignored or if the suite is timed out
+ ' and skip the before and after hooks
+ if test.isIgnored or m.testSuite.isSuiteTimedOut()
m.notifyReportersOnTestBegin(test)
m.testSuite.runTest(test)
- m.testRunner.top.rooibosTestFinished = true
m.onAsyncTestComplete()
return invalid
end if
- m.testRunner.top.rooibosTestFinished = false
isOk = m.runSuiteFunction(m.beforeEachFunctionName, "beforeEach", m.currentTest)
if isOk
- 'TODO - set a timeout here
- if test.isAsync <> true
- rooibos.common.logDebug("Executing test synchronously")
- m.notifyReportersOnTestBegin(test)
- m.testSuite.runTest(test)
- m.testRunner.top.rooibosTestFinished = true
- m.onAsyncTestComplete()
- else
- m.testRunner.top.observeFieldScoped("rooibosTestFinished", "rooibos_onTestComplete")
- if test.isAsync = true
- m.testSuite.setTestTimer(test.asyncTimeout)
- end if
- m.notifyReportersOnTestBegin(test)
- m.testSuite.runTest(test)
+ m.notifyReportersOnTestBegin(test)
- if test.result.isFail
- rooibos.common.logTrace("Test failed before any async code could be executed")
- m.testRunner.top.unobserveFieldScoped("rooibosTestFinished")
- m.testRunner.top.rooibosTestFinished = true
- m.onAsyncTestComplete()
+ m.testSuite.runTest(test)
+ rooibos.common.logDebug("Waiting on deferred test results")
+
+ rooibos.promises.chain(test.deferred, { self: m, test: test }).then(function(_, context)
+ rooibos.common.logDebug("Promise resolved")
+ context.self.testSuite.done()
+ end function).catch(function(error, context)
+ rooibos.common.logDebug("Promise rejected")
+ if rooibos.common.isAssociativeArray(error) and not error.isEmpty() and rooibos.common.isArray(error.backtrace) and not error.backtrace.isEmpty() and rooibos.common.isBoolean(error.rethrown)
+ context.self.testSuite.failCrash(error)
+ else
+ context.self.testSuite.fail("Test failed due to promise rejection")
end if
- end if
-
+ context.self.testSuite.done()
+ end function).finally(function(context)
+ context.self.onAsyncTestComplete()
+ end function)
else
rooibos.common.logTrace("Error running test before each function")
m.isTestFailedDueToEarlyExit = true
@@ -191,10 +191,6 @@ namespace rooibos
rooibos.common.logTrace("++ CURRENT TEST COMPLETED")
m.notifyReportersOnTestComplete(m.currentTest)
m.runSuiteFunction(m.afterEachFunctionName, "afterEach", m.currentTest)
-
- m.testRunner.top.unobserveFieldScoped("rooibosTestFinished")
-
- m.currentTest.result.time = m.testTimer.totalMilliseconds()
m.stats.appendTestResult(m.currentTest.result)
if m.stats.hasFailures and m.testSuite.isFailingFast
@@ -208,17 +204,10 @@ namespace rooibos
end function
private function finishAsyncTests()
- m.testRunner.top.unobserveFieldScoped("rooibosTestFinished")
- m.testSuite.setTestTimer(0)
m.runSuiteFunction(m.tearDownFunctionName, "tearDown")
rooibos.common.logTrace("Indicating test suite is done")
- ' m.testRunner.top.addFields({ asyncRooibosTestResult: {
- ' stats: m.stats
- ' tests: m.tests
- ' }
- ' })
m.notifyReportersOnTestGroupComplete()
- m.testSuite.testGroupDone()
+ rooibos.promises.resolve(true, m.deferred)
end function
private function runSuiteFunction(methodName, defaultMethodName, test = invalid)
@@ -227,17 +216,23 @@ namespace rooibos
methodName = defaultMethodName
end if
if m.testSuite.catchCrashes and not m.testSuite.noCatch and not (test <> invalid and test.noCatch)
+ ' Add the users suite functions execution time to the suites current execution time
+ timespan = createObject("roTimespan")
try
m.testSuite[methodName]()
+ m.testSuite.currentExecutionTime += timespan.totalMilliseconds()
return true
catch error
if test <> invalid
'bs:disable-next-line
test.result.crash("function " + methodName + "crashed!", error)
+ m.testSuite.currentExecutionTime += timespan.totalMilliseconds()
end if
end try
else
+ timespan = createObject("roTimespan")
m.testSuite[methodName]()
+ m.testSuite.currentExecutionTime += timespan.totalMilliseconds()
return true
end if
@@ -262,6 +257,11 @@ namespace rooibos
end sub
private sub notifyReportersOnTestComplete(test as rooibos.Test)
+ if test.result.time > 0
+ ' Add the test execution time to the suites current execution time
+ m.testSuite.currentExecutionTime += test.result.time
+ end if
+
for each reporter in m.testSuite.testReporters
if rooibos.common.isFunction(reporter.onTestComplete)
reporter.onTestComplete({ test: test })
@@ -277,9 +277,4 @@ namespace rooibos
end for
end sub
end class
-
- function onTestComplete()
- rooibos.common.logTrace("++++++++ THE TEST COMPLETED")
- m.testRunner.currentGroup.onAsyncTestComplete()
- end function
-end namespace
\ No newline at end of file
+end namespace
diff --git a/framework/src/source/rooibos/TestResult.bs b/framework/src/source/rooibos/TestResult.bs
index 7fae892c..5b8cb4ef 100644
--- a/framework/src/source/rooibos/TestResult.bs
+++ b/framework/src/source/rooibos/TestResult.bs
@@ -9,7 +9,7 @@ namespace rooibos
public message = ""
public lineNumber = -1
public test = invalid
- public time = 0
+ public time = -1
public error = invalid
public throwOnFailedAssertion = false
@@ -31,7 +31,7 @@ namespace rooibos
function reset() as void
m.isFail = false
m.isCrash = false
- m.time = 0
+ m.time = -1
m.message = ""
m.lineNumber = -1
end function
diff --git a/framework/src/source/rooibos/TestRunner.bs b/framework/src/source/rooibos/TestRunner.bs
index fc52e2ba..b47e8283 100644
--- a/framework/src/source/rooibos/TestRunner.bs
+++ b/framework/src/source/rooibos/TestRunner.bs
@@ -157,29 +157,14 @@ namespace rooibos
m.nodeContext.testSuite = testSuite
m.nodeTestName = nodeTestName
m.nodeContext.testRunner = m
- m.nodeContext.top.addFields({
- "rooibosSuiteFinished": false
- "rooibosTestFinished": false
- "rooibosTestIsAsync": false
- "rooibosGroupFinished": false
- })
-
end if
if testSuite <> invalid
m.currentTestSuite = testSuite
testSuite.testRunner = m
- if testSuite.isAsync = true
- rooibos.common.logDebug("Running suite asynchronously!")
- m.nodeContext.top.observeFieldScoped("rooibosSuiteFinished", "Rooibos_onTestSuiteComplete")
- testSuite.run()
- return invalid
- else
- rooibos.common.logDebug("Running suite synchronously!")
- testSuite.run()
- return m.onTestSuiteComplete()
- end if
-
+ rooibos.common.logDebug("Running suite as a Node test!")
+ testSuite.run()
+ return invalid
else
rooibos.common.logError(`Could not create test suite ${nodeTestName}`)
end if
@@ -215,7 +200,6 @@ namespace rooibos
testSuite.run()
end if
m.stats.merge(testSuite.stats)
-
end if
end function
@@ -249,9 +233,17 @@ namespace rooibos
rooibos.common.logDebug(`+++++RUNNING NODE TEST${chr(10)}node type is ${testSuite.generatedNodeName}`)
node = m.testScene.createChild(testSuite.generatedNodeName)
- 'wait on the field
+ port = CreateObject("roMessagePort")
+ node.observeField("rooibosTestResult", port)
+ ' Trigger test via observer so that thread ownership
+ ' can be transferred to the render thread
+ node.rooibosRunSuite = true
+ 'wait on the field
if type(node) = "roSGNode"
+ event = wait(0, port)
+ nodeResults = event.getData()
+
m.groups = []
for each groupData in testSuite.groupsData
'bs:disable-next-line
@@ -259,21 +251,6 @@ namespace rooibos
testSuite.groups.push(group)
end for
- if testSuite.isAsync = true
- if node.rooibosSuiteFinished = false
- timeout = testSuite.asyncTimeout = invalid ? 60000 : testSuite.asyncTimeout
-
- rooibos.common.logDebug(`Waiting max ${timeout}ms for the test suite to finish`)
- t = createObject("roTimespan")
- while node.rooibosSuiteFinished = false
- m.wait(10)
- if t.totalMilliseconds() >= timeout
- exit while
- end if
- end while
- end if
- end if
- nodeResults = node.asyncRooibosTestResult
if nodeResults <> invalid
testSuite.stats.merge(nodeResults.stats)
m.mergeGroups(testSuite, nodeResults.groups)
@@ -304,8 +281,7 @@ namespace rooibos
realGroup.tests = []
for testDataIndex = 0 to group.testsData.count() - 1
testData = group.testsData[testDataIndex]
- realTest = new rooibos.Test(m, testData)
- realTest.testSuite = testSuite
+ realTest = new rooibos.Test(m, testData, testSuite)
realGroup.tests.push(realTest)
test = group.tests[testDataIndex]
realTest.result.merge(test.result)
diff --git a/tests/src/components/TaskExample.bs b/tests/src/components/TaskExample.bs
new file mode 100644
index 00000000..8874f700
--- /dev/null
+++ b/tests/src/components/TaskExample.bs
@@ -0,0 +1,8 @@
+sub init()
+ m.top.functionName = "runTaskThread"
+end sub
+
+sub runTaskThread()
+ sleep(m.top.sleepTime)
+ m.top.result = "done"
+end sub
diff --git a/tests/src/components/TaskExample.xml b/tests/src/components/TaskExample.xml
new file mode 100644
index 00000000..d51e76d2
--- /dev/null
+++ b/tests/src/components/TaskExample.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/tests/src/source/Basic.spec.bs b/tests/src/source/Basic.spec.bs
index 140f858b..e01688a2 100644
--- a/tests/src/source/Basic.spec.bs
+++ b/tests/src/source/Basic.spec.bs
@@ -57,15 +57,29 @@ namespace tests
@it("times out")
@slow(150)
function _()
- item = { "id": "item" }
+ task = createObject("roSgNode", "TaskExample")
+ task.sleepTime = 2000
+ task.control = "run"
- m.assertAsyncField(item, "id", 10)
+ m.assertAsyncField(task, "result", 10)
isFail = m.currentResult.isFail
m.currentResult.Reset()
m.assertTrue(isFail)
end function
+ @it("does not timeout")
+ @slow(150)
+ function _()
+ task = createObject("roSgNode", "TaskExample")
+ task.sleepTime = 50
+ task.control = "run"
+
+ m.assertAsyncField(task, "result", 10)
+ isFail = m.currentResult.isFail
+ m.assertFalse(isFail)
+ end function
+
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@describe("assertClass")
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -223,4 +237,4 @@ namespace tests
end function
end class
-end namespace
\ No newline at end of file
+end namespace
diff --git a/tests/src/source/FailedAssertion.spec.bs b/tests/src/source/FailedAssertion.spec.bs
index 14b6d481..29402f5f 100644
--- a/tests/src/source/FailedAssertion.spec.bs
+++ b/tests/src/source/FailedAssertion.spec.bs
@@ -7,14 +7,23 @@ namespace tests
class FailedAssertionTests extends rooibos.BaseTestSuite
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @describe("tests fail on crash")
+ @describe("automatically failing tests")
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- @it("reports error")
+ @it("fails on crash in the test function")
function _()
+ ' Make sure a passed assertion is superseded by a crash
+ m.assertTrue(true)
throw "some error"
end function
+ @it("fails if returned a promise from a non-node test")
+ function _()
+ ' Make sure a passed assertion is superseded by fact a promise was returned
+ m.assertTrue(true)
+ return rooibos.promises.resolve(true)
+ end function
+
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@describe("tests AssertTrue fail")
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/tests/src/source/NodeExample.spec.bs b/tests/src/source/NodeExample.spec.bs
index 2cfcb19b..ffbe6599 100644
--- a/tests/src/source/NodeExample.spec.bs
+++ b/tests/src/source/NodeExample.spec.bs
@@ -40,7 +40,7 @@ namespace tests
text = HelloFromNode(name, age)
m.AssertEqual(text, "HELLO " + name + " age:" + stri(age))
m.timer = createObject("roSGNode", "Timer")
- m.timer.duration = 0.5
+ m.timer.duration = 0.01
m.timer.observeFieldScoped("fire", "OnTimer")
m.timer.control = "start"
end function
@@ -63,7 +63,7 @@ namespace tests
callback = callback.toStr().tokenize(" ").peek()
m.timer = createObject("roSGNode", "Timer")
- m.timer.duration = 0.1
+ m.timer.duration = 0.01
m.timer.observeFieldScoped("fire", callback)
m.timer.control = "start"
end function
diff --git a/tests/src/source/Promises.spec.bs b/tests/src/source/Promises.spec.bs
new file mode 100644
index 00000000..402d6e1d
--- /dev/null
+++ b/tests/src/source/Promises.spec.bs
@@ -0,0 +1,84 @@
+namespace tests
+ @suite
+ @async
+ class PromisesTests extends rooibos.BaseTestSuite
+
+ '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ @describe("tests that should as fail")
+ '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+ @it("fail the test as the returned to the test promise that will reject")
+ function _()
+ return toPromiseWithDelay(0.001, false, false)
+ end function
+
+ '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ @describe("tests that should pass)")
+ '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+ @it("pass the test as the returned to the test promise that will resolve")
+ function _()
+ return toPromiseWithDelay(0.001, true, true)
+ end function
+
+ @it("example using rooibos.promise.chain")
+ function _()
+ context = {
+ thenCount: 0
+ catchCount: 0
+ finallyCount: 0
+ }
+
+ return rooibos.promises.chain(rooibos.promises.resolve(1), context).then(sub(result, context)
+ context.thenCount++
+ m.testSuite.assertEqual(result, 1)
+ end sub).catch(sub(error, context)
+ context.catchCount++
+ m.testSuite.fail("should not get here")
+ end sub).finally(sub(context)
+ context.finallyCount++
+ m.testSuite.assertEqual(context, {
+ thenCount: 1
+ catchCount: 0
+ finallyCount: 1
+ })
+ end sub).toPromise()
+ end function
+
+ '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ @describe("tests that should as fail as crashes")
+ '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+ @async(100)
+ @it("async test that times out")
+ sub _()
+ end sub
+
+ @async(100)
+ @it("async test that times out due to promise not resolving")
+ function _()
+ return rooibos.promises.create()
+ end function
+
+ @it("fail the test as the returned to the test promise that will reject with a exception object")
+ function _()
+ try
+ v = 1 / 0
+ catch error
+ return toPromiseWithDelay(0.001, error, false)
+ end try
+ end function
+ end class
+end namespace
+
+function toPromiseWithDelay(duration = 0.0001 as float, value = true as dynamic, resolve = true as boolean) as dynamic
+ deferred = rooibos.promises.create()
+ rooibos.promises.internal.delay(sub(context as dynamic)
+ if context.resolve then
+ rooibos.promises.resolve(context.value, context.deferred)
+ else
+ rooibos.promises.reject(context.value, context.deferred)
+ end if
+ end sub, { deferred: deferred, value: value, resolve: resolve }, duration)
+ return deferred
+end function
\ No newline at end of file
diff --git a/tests/src/source/SuiteTimeouts.spec.bs b/tests/src/source/SuiteTimeouts.spec.bs
new file mode 100644
index 00000000..31ccc5c2
--- /dev/null
+++ b/tests/src/source/SuiteTimeouts.spec.bs
@@ -0,0 +1,111 @@
+namespace tests
+ @suite
+ @async(1000)
+ class SuiteTimeoutTests extends rooibos.BaseTestSuite
+
+ '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ @describe("100 ms tests")
+ '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+ @it("test one")
+ @async(100)
+ function _()
+ end function
+
+ @it("test two")
+ @async(100)
+ function _()
+ end function
+
+ @it("test three")
+ @async(100)
+ function _()
+ end function
+
+ @it("test four")
+ @async(100)
+ function _()
+ end function
+
+ @it("test five")
+ @async(100)
+ function _()
+ end function
+
+ @it("test six")
+ @async(100)
+ function _()
+ end function
+
+ @it("test seven")
+ @async(100)
+ function _()
+ end function
+
+ @it("test eight")
+ @async(100)
+ function _()
+ end function
+
+ @it("test nine")
+ @async(100)
+ function _()
+ end function
+
+ @it("test ten")
+ @async(100)
+ function _()
+ end function
+
+ @it("test eleven")
+ @async(100)
+ function _()
+ end function
+
+ @it("test twelve")
+ @async(100)
+ function _()
+ end function
+
+ @it("test thirteen")
+ @async(100)
+ function _()
+ end function
+
+ @it("test fourteen")
+ @async(100)
+ function _()
+ end function
+
+ @it("test fifteen")
+ @async(100)
+ function _()
+ end function
+
+ @it("test sixteen")
+ @async(100)
+ function _()
+ end function
+
+ @it("test seventeen")
+ @async(100)
+ function _()
+ end function
+
+ @it("test eighteen")
+ @async(100)
+ function _()
+ end function
+
+ @it("test nineteen")
+ @async(100)
+ function _()
+ end function
+
+ @it("test twenty")
+ @async(100)
+ function _()
+ end function
+
+ end class
+end namespace