diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 43505523..a9b6c2fa 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -19,4 +19,4 @@ jobs: - run: npm ci - run: npm run lint - run: npm run build - - run: npm run tap + - run: npm run test:node diff --git a/.nvmrc b/.nvmrc index 6f7f377b..a45fd52c 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v16 +24 diff --git a/package-lock.json b/package-lock.json index afda7ac2..350d3310 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,7 +56,6 @@ "scratch-storage": "2.3.1", "script-loader": "0.7.2", "stats.js": "0.17.0", - "tap": "16.2.0", "tiny-worker": "2.3.0", "uglifyjs-webpack-plugin": "1.2.7", "webpack": "4.47.0", @@ -1876,136 +1875,6 @@ "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/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/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -2522,19 +2391,6 @@ "node": ">=0.3.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2621,7 +2477,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "devOptional": true, + "optional": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -2630,18 +2486,6 @@ "node": ">= 8" } }, - "node_modules/append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "dependencies": { - "default-require-extensions": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -2668,12 +2512,6 @@ "node": ">=4" } }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2943,15 +2781,6 @@ } ] }, - "node_modules/async-hook-domain": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/async-hook-domain/-/async-hook-domain-2.0.4.tgz", - "integrity": "sha512-14LjCmlK1PK8eDtTezR6WX8TMaYNIzBIsd2D1sGoGjgx0BuNMMoSdk7i/drlbtamy0AWv9yv2tkB+ASdmeqFIw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", @@ -3308,20 +3137,11 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "devOptional": true, + "optional": true, "engines": { "node": ">=8" } }, - "node_modules/bind-obj-methods": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bind-obj-methods/-/bind-obj-methods-3.0.0.tgz", - "integrity": "sha512-nLEaaz3/sEzNSyPWRsN9HNsqwk1AUyECtGj+XwGdIi3xABnEqecvXtIJ0wehQXuuER5uZ/5fTs2usONgYjG+iw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -3482,8 +3302,8 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -3848,21 +3668,6 @@ "node": ">=0.10.0" } }, - "node_modules/caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", - "dev": true, - "dependencies": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/call-bind": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", @@ -4020,13 +3825,13 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "devOptional": true, "funding": [ { "type": "individual", "url": "https://paulmillr.com/funding/" } ], + "optional": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -4047,7 +3852,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "devOptional": true, + "optional": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -4121,15 +3926,6 @@ "node": ">= 0.4" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -4148,17 +3944,6 @@ "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", "dev": true }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, "node_modules/clone-response": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", @@ -4214,15 +3999,6 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "bin": { - "color-support": "bin.js" - } - }, "node_modules/colors": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", @@ -4959,21 +4735,6 @@ "node": ">=6" } }, - "node_modules/default-require-extensions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", - "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", - "dev": true, - "dependencies": { - "strip-bom": "^4.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/define-data-property": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", @@ -5121,15 +4882,6 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/diff-match-patch": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.4.tgz", @@ -5480,12 +5232,6 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "node_modules/emojis-list": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", @@ -5752,12 +5498,6 @@ "node": ">=0.10" } }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, "node_modules/es6-iterator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", @@ -6445,12 +6185,6 @@ "node": ">=0.8.x" } }, - "node_modules/events-to-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz", - "integrity": "sha512-inRWzRY7nG+aXZxBzEqYKB3HPgwflZRopAjDCHv0whhRx+MTUr1ei0ICZUypdyE0HRm4L2d5VEcIqLD6yl+BFA==", - "dev": true - }, "node_modules/eventsource": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", @@ -7062,8 +6796,8 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -7140,12 +6874,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/findit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz", - "integrity": "sha512-ENZS237/Hr8bjczn5eKuBohLgaD0JyUd0arxretR1f9RO46vZHA1b2y0VorgGV3WaOT3c+78P8h7v4JGJ1i/rg==", - "dev": true - }, "node_modules/findup": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz", @@ -7286,19 +7014,6 @@ "node": ">=0.10.0" } }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -7990,38 +7705,12 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true }, - "node_modules/fs-exists-cached": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz", - "integrity": "sha512-kSxoARUDn4F2RPXX48UXnaFKwVU7Ivd/6qpzZL29MCDmr9sTvybv4gFCp+qaI4fM9m0z9fgz/yJvi56GAz+BZg==", - "dev": true - }, "node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -8111,12 +7800,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/function-loop": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/function-loop/-/function-loop-2.0.1.tgz", - "integrity": "sha512-ktIR+O6i/4h+j/ZhZJNdzeI4i9lEPeEK6UPR2EVyTVBqOwcU3Za9xYKLH64ZR9HmcROyRrOkizNyjjtWJzDDkQ==", - "dev": true - }, "node_modules/function.prototype.name": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", @@ -8205,15 +7888,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", @@ -8693,34 +8367,6 @@ "minimalistic-assert": "^1.0.1" } }, - "node_modules/hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", - "dev": true, - "dependencies": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hasha/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -8812,12 +8458,6 @@ "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==", "dev": true }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, "node_modules/htmlparser2": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.0.tgz", @@ -9118,15 +8758,6 @@ "not-in-publish": "not-in-publish.js" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", @@ -9409,7 +9040,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "devOptional": true, + "optional": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -9535,15 +9166,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-generator-function": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", @@ -9624,8 +9246,8 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.12.0" } @@ -9919,193 +9541,6 @@ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "dependencies": { - "append-transform": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-processinfo": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", - "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", - "dev": true, - "dependencies": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.3", - "istanbul-lib-coverage": "^3.2.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-processinfo/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/istanbul-lib-report/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/isurl": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", @@ -10133,18 +9568,6 @@ "set-function-name": "^2.0.1" } }, - "node_modules/jackspeak": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-1.4.2.tgz", - "integrity": "sha512-GHeGTmnuaHnvS+ZctRB01bfxARuu9wW83ENbuiweu07SFcVlZrJpcshSre/keGT7YGBhLHg/+rXCNSrsEHKU4Q==", - "dev": true, - "dependencies": { - "cliui": "^7.0.4" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/js-md5": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.7.3.tgz", @@ -10441,33 +9864,6 @@ "node": ">= 0.8.0" } }, - "node_modules/libtap": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/libtap/-/libtap-1.4.1.tgz", - "integrity": "sha512-S9v19shLTigoMn3c02V7LZ4t09zxmVP3r3RbEAwuHFYeKgF+ESFJxoQ0PMFKW4XdgQhcjVBEwDoopG6WROq/gw==", - "dev": true, - "dependencies": { - "async-hook-domain": "^2.0.4", - "bind-obj-methods": "^3.0.0", - "diff": "^4.0.2", - "function-loop": "^2.0.1", - "minipass": "^3.1.5", - "own-or": "^1.0.0", - "own-or-env": "^1.0.2", - "signal-exit": "^3.0.4", - "stack-utils": "^2.0.4", - "tap-parser": "^11.0.0", - "tap-yaml": "^1.0.0", - "tcompare": "^5.0.6", - "trivial-deferred": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/lie": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", @@ -10570,12 +9966,6 @@ "integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==", "dev": true }, - "node_modules/lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", - "dev": true - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -11132,24 +10522,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/mississippi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", @@ -11530,18 +10902,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "dependencies": { - "process-on-spawn": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", @@ -11628,132 +10988,6 @@ "node": ">=0.10.0" } }, - "node_modules/nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", - "dev": true, - "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "bin": { - "nyc": "bin/nyc.js" - }, - "engines": { - "node": ">=8.9" - } - }, - "node_modules/nyc/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/nyc/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/nyc/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/nyc/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/nyc/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/nyc/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -12007,15 +11241,6 @@ "node": ">=4" } }, - "node_modules/opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "dev": true, - "bin": { - "opener": "bin/opener-bin.js" - } - }, "node_modules/opn": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", @@ -12082,21 +11307,6 @@ "node": ">=0.10.0" } }, - "node_modules/own-or": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/own-or/-/own-or-1.0.0.tgz", - "integrity": "sha512-NfZr5+Tdf6MB8UI9GLvKRs4cXY8/yB0w3xtt84xFdWy8hkGjn+JFc60VhzS/hFRfbyxFcGYMTjnF4Me+RbbqrA==", - "dev": true - }, - "node_modules/own-or-env": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/own-or-env/-/own-or-env-1.0.2.tgz", - "integrity": "sha512-NQ7v0fliWtK7Lkb+WdFqe6ky9XAzYmlkXthQrBbzlYbmFKoAYbDDcwmOm6q8kOuwSRXW8bdL5ORksploUJmWgw==", - "dev": true, - "dependencies": { - "own-or": "^1.0.0" - } - }, "node_modules/p-cancelable": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", @@ -12187,18 +11397,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/p-retry": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", @@ -12232,21 +11430,6 @@ "node": ">=4" } }, - "node_modules/package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -12440,7 +11623,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "devOptional": true, + "optional": true, "engines": { "node": ">=8.6" }, @@ -12628,18 +11811,6 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "node_modules/process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "dependencies": { - "fromentries": "^1.2.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/progress": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", @@ -12906,7 +12077,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "devOptional": true, + "optional": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -13076,18 +12247,6 @@ "jsesc": "bin/jsesc" } }, - "node_modules/release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", - "dev": true, - "dependencies": { - "es6-error": "^4.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -14494,38 +13653,6 @@ "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", "deprecated": "See https://github.com/lydell/source-map-url#deprecated" }, - "node_modules/spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "dependencies": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/spawn-wrap/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -14639,27 +13766,6 @@ "safe-buffer": "^5.1.1" } }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/startaudiocontext": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/startaudiocontext/-/startaudiocontext-1.2.1.tgz", @@ -14950,20 +14056,6 @@ "safe-buffer": "~5.2.0" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/string.prototype.matchall": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", @@ -15045,15 +14137,6 @@ "node": ">=8" } }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-dirs": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", @@ -15257,2011 +14340,6 @@ "integrity": "sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==", "dev": true }, - "node_modules/tap": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/tap/-/tap-16.2.0.tgz", - "integrity": "sha512-ikfNLy701p2+sH3R0pAXQ/Aen6ZByaguUY7UsoTLL4AXa2c9gYQL+pI21p13lq54R7/CEoLaViC1sexcWG32ig==", - "bundleDependencies": [ - "ink", - "treport", - "@types/react", - "@isaacs/import-jsx", - "react" - ], - "dev": true, - "dependencies": { - "@isaacs/import-jsx": "^4.0.1", - "@types/react": "^17", - "chokidar": "^3.3.0", - "findit": "^2.0.0", - "foreground-child": "^2.0.0", - "fs-exists-cached": "^1.0.0", - "glob": "^7.1.6", - "ink": "^3.2.0", - "isexe": "^2.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "jackspeak": "^1.4.1", - "libtap": "^1.4.0", - "minipass": "^3.1.1", - "mkdirp": "^1.0.4", - "nyc": "^15.1.0", - "opener": "^1.5.1", - "react": "^17.0.2", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.6", - "source-map-support": "^0.5.16", - "tap-mocha-reporter": "^5.0.3", - "tap-parser": "^11.0.1", - "tap-yaml": "^1.0.0", - "tcompare": "^5.0.7", - "treport": "^3.0.3", - "which": "^2.0.2" - }, - "bin": { - "tap": "bin/run.js" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "peerDependencies": { - "coveralls": "^3.1.1", - "flow-remove-types": ">=2.112.0", - "ts-node": ">=8.5.2", - "typescript": ">=3.7.2" - }, - "peerDependenciesMeta": { - "coveralls": { - "optional": true - }, - "flow-remove-types": { - "optional": true - }, - "ts-node": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/tap-mocha-reporter": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/tap-mocha-reporter/-/tap-mocha-reporter-5.0.4.tgz", - "integrity": "sha512-J+YMO8B7lq1O6Zxd/jeuG27vJ+Y4tLiRMKPSb7KR6FVh86k3Rq1TwYc2GKPyIjCbzzdMdReh3Vfz9L5cg1Z2Bw==", - "dev": true, - "dependencies": { - "color-support": "^1.1.0", - "debug": "^4.1.1", - "diff": "^4.0.1", - "escape-string-regexp": "^2.0.0", - "glob": "^7.0.5", - "tap-parser": "^11.0.0", - "tap-yaml": "^1.0.0", - "unicode-length": "^2.0.2" - }, - "bin": { - "tap-mocha-reporter": "index.js" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tap-mocha-reporter/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap-parser": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-11.0.2.tgz", - "integrity": "sha512-6qGlC956rcORw+fg7Fv1iCRAY8/bU9UabUAhs3mXRH6eRmVZcNPLheSXCYaVaYeSwx5xa/1HXZb1537YSvwDZg==", - "dev": true, - "dependencies": { - "events-to-array": "^1.0.1", - "minipass": "^3.1.6", - "tap-yaml": "^1.0.0" - }, - "bin": { - "tap-parser": "bin/cmd.js" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tap-yaml": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.2.tgz", - "integrity": "sha512-GegASpuqBnRNdT1U+yuUPZ8rEU64pL35WPBpCISWwff4dErS2/438barz7WFJl4Nzh3Y05tfPidZnH+GaV1wMg==", - "dev": true, - "dependencies": { - "yaml": "^1.10.2" - } - }, - "node_modules/tap/node_modules/@ampproject/remapping": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/tap/node_modules/@babel/code-frame": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/compat-data": { - "version": "7.17.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/core": { - "version": "7.17.8", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.7", - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-module-transforms": "^7.17.7", - "@babel/helpers": "^7.17.8", - "@babel/parser": "^7.17.8", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/tap/node_modules/@babel/generator": { - "version": "7.17.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-compilation-targets": { - "version": "7.17.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-environment-visitor": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-function-name": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-get-function-arity": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-hoist-variables": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-module-imports": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-module-transforms": { - "version": "7.17.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.17.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-plugin-utils": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-simple-access": { - "version": "7.17.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-validator-option": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/helpers": { - "version": "7.17.8", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/highlight": { - "version": "7.16.10", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/parser": { - "version": "7.17.8", - "dev": true, - "inBundle": true, - "license": "MIT", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/tap/node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/tap/node_modules/@babel/plugin-syntax-jsx": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/tap/node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/tap/node_modules/@babel/plugin-transform-destructuring": { - "version": "7.17.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/tap/node_modules/@babel/plugin-transform-parameters": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/tap/node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.17.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-jsx": "^7.16.7", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/tap/node_modules/@babel/template": { - "version": "7.16.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/traverse": { - "version": "7.17.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@babel/types": { - "version": "7.17.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/@isaacs/import-jsx": { - "version": "4.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.5.5", - "@babel/plugin-proposal-object-rest-spread": "^7.5.5", - "@babel/plugin-transform-destructuring": "^7.5.0", - "@babel/plugin-transform-react-jsx": "^7.3.0", - "caller-path": "^3.0.1", - "find-cache-dir": "^3.2.0", - "make-dir": "^3.0.2", - "resolve-from": "^3.0.0", - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tap/node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/tap/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/tap/node_modules/@types/prop-types": { - "version": "15.7.4", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/@types/react": { - "version": "17.0.41", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/tap/node_modules/@types/scheduler": { - "version": "0.16.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/@types/yoga-layout": { - "version": "1.9.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/ansi-escapes": { - "version": "4.3.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "dev": true, - "inBundle": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/ansi-styles": { - "version": "3.2.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/ansicolors": { - "version": "0.3.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/astral-regex": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/auto-bind": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/tap/node_modules/browserslist": { - "version": "4.20.2", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "inBundle": true, - "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001317", - "electron-to-chromium": "^1.4.84", - "escalade": "^3.1.1", - "node-releases": "^2.0.2", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/tap/node_modules/caller-callsite": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/caller-path": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "caller-callsite": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/callsites": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/caniuse-lite": { - "version": "1.0.30001319", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ], - "inBundle": true, - "license": "CC-BY-4.0" - }, - "node_modules/tap/node_modules/cardinal": { - "version": "2.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansicolors": "~0.3.2", - "redeyed": "~2.1.0" - }, - "bin": { - "cdl": "bin/cdl.js" - } - }, - "node_modules/tap/node_modules/chalk": { - "version": "2.4.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/ci-info": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/cli-boxes": { - "version": "2.2.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/cli-cursor": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/cli-truncate": { - "version": "2.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/code-excerpt": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "convert-to-spaces": "^1.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tap/node_modules/color-convert": { - "version": "1.9.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/tap/node_modules/color-name": { - "version": "1.1.3", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/commondir": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/convert-source-map": { - "version": "1.8.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/tap/node_modules/convert-to-spaces": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/tap/node_modules/csstype": { - "version": "3.0.11", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/debug": { - "version": "4.3.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/tap/node_modules/electron-to-chromium": { - "version": "1.4.89", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/escalade": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/tap/node_modules/esprima": { - "version": "4.0.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/events-to-array": { - "version": "1.1.2", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/find-cache-dir": { - "version": "3.3.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/tap/node_modules/find-up": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/gensync": { - "version": "1.0.0-beta.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/glob": { - "version": "7.2.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/tap/node_modules/globals": { - "version": "11.12.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/has-flag": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/indent-string": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/inflight": { - "version": "1.0.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/tap/node_modules/inherits": { - "version": "2.0.4", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/ink": { - "version": "3.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^4.2.1", - "auto-bind": "4.0.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.0", - "cli-cursor": "^3.1.0", - "cli-truncate": "^2.1.0", - "code-excerpt": "^3.0.0", - "indent-string": "^4.0.0", - "is-ci": "^2.0.0", - "lodash": "^4.17.20", - "patch-console": "^1.0.0", - "react-devtools-core": "^4.19.1", - "react-reconciler": "^0.26.2", - "scheduler": "^0.20.2", - "signal-exit": "^3.0.2", - "slice-ansi": "^3.0.0", - "stack-utils": "^2.0.2", - "string-width": "^4.2.2", - "type-fest": "^0.12.0", - "widest-line": "^3.1.0", - "wrap-ansi": "^6.2.0", - "ws": "^7.5.5", - "yoga-layout-prebuilt": "^1.9.6" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": ">=16.8.0", - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/tap/node_modules/ink/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/tap/node_modules/ink/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/tap/node_modules/ink/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/tap/node_modules/ink/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/ink/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/ink/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/is-ci": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ci-info": "^2.0.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/tap/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/js-tokens": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/jsesc": { - "version": "2.5.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/json5": { - "version": "2.2.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/locate-path": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/lodash": { - "version": "4.17.21", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/loose-envify": { - "version": "1.4.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/tap/node_modules/make-dir": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/mimic-fn": { - "version": "2.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tap/node_modules/minipass": { - "version": "3.1.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tap/node_modules/ms": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/node-releases": { - "version": "2.0.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/object-assign": { - "version": "4.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tap/node_modules/once": { - "version": "1.4.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/tap/node_modules/onetime": { - "version": "5.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/p-limit": { - "version": "2.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/p-locate": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/p-try": { - "version": "2.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/patch-console": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/tap/node_modules/path-exists": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tap/node_modules/picocolors": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/pkg-dir": { - "version": "4.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/punycode": { - "version": "2.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/react": { - "version": "17.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tap/node_modules/react-devtools-core": { - "version": "4.24.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "shell-quote": "^1.6.1", - "ws": "^7" - } - }, - "node_modules/tap/node_modules/react-reconciler": { - "version": "0.26.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "react": "^17.0.2" - } - }, - "node_modules/tap/node_modules/redeyed": { - "version": "2.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "esprima": "~4.0.0" - } - }, - "node_modules/tap/node_modules/resolve-from": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/restore-cursor": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/tap/node_modules/safe-buffer": { - "version": "5.1.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/scheduler": { - "version": "0.20.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/tap/node_modules/semver": { - "version": "6.3.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/tap/node_modules/shell-quote": { - "version": "1.7.3", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/signal-exit": { - "version": "3.0.7", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/slice-ansi": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/tap/node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/tap/node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/source-map": { - "version": "0.5.7", - "dev": true, - "inBundle": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tap/node_modules/stack-utils": { - "version": "2.0.5", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tap/node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/supports-color": { - "version": "5.5.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/tap-parser": { - "version": "11.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "events-to-array": "^1.0.1", - "minipass": "^3.1.6", - "tap-yaml": "^1.0.0" - }, - "bin": { - "tap-parser": "bin/cmd.js" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tap/node_modules/tap-yaml": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "yaml": "^1.5.0" - } - }, - "node_modules/tap/node_modules/to-fast-properties": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/treport": { - "version": "3.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@isaacs/import-jsx": "^4.0.1", - "cardinal": "^2.1.1", - "chalk": "^3.0.0", - "ink": "^3.2.0", - "ms": "^2.1.2", - "tap-parser": "^11.0.0", - "unicode-length": "^2.0.2" - }, - "peerDependencies": { - "react": "^17.0.2" - } - }, - "node_modules/tap/node_modules/treport/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/tap/node_modules/treport/node_modules/chalk": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/treport/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/tap/node_modules/treport/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/treport/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/treport/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/type-fest": { - "version": "0.12.0", - "dev": true, - "inBundle": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/unicode-length": { - "version": "2.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.0.0", - "strip-ansi": "^3.0.1" - } - }, - "node_modules/tap/node_modules/unicode-length/node_modules/ansi-regex": { - "version": "2.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tap/node_modules/unicode-length/node_modules/strip-ansi": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tap/node_modules/widest-line": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/wrap-ansi": { - "version": "6.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/tap/node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/tap/node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/wrappy": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/ws": { - "version": "7.5.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/tap/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/yaml": { - "version": "1.10.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, - "node_modules/tap/node_modules/yoga-layout-prebuilt": { - "version": "1.10.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@types/yoga-layout": "1.9.2" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -17324,18 +14402,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/tcompare": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-5.0.7.tgz", - "integrity": "sha512-d9iddt6YYGgyxJw5bjsN7UJUO1kGOtjSlNy/4PoGYAjQS5pAT/hzIoLf1bZCw+uUxRmZJh7Yy1aA7xKVRT9B4w==", - "dev": true, - "dependencies": { - "diff": "^4.0.2" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/terser": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", @@ -17587,20 +14653,6 @@ "node": ">=0.10.0" } }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/text-encoding": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz", @@ -17773,8 +14825,8 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "is-number": "^7.0.0" }, @@ -17848,15 +14900,6 @@ "node": ">=0.10.0" } }, - "node_modules/trivial-deferred": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-1.1.2.tgz", - "integrity": "sha512-vDPiDBC3hyP6O4JrJYMImW3nl3c03Tsj9fEXc7Qc/XKa1O7gf5ZtFfIR/E0dun9SnDHdwjna1Z2rSzYgqpxh/g==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -17910,15 +14953,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -18007,15 +15041,6 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, "node_modules/uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -18229,15 +15254,6 @@ "node": ">=4" } }, - "node_modules/unicode-length": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-length/-/unicode-length-2.1.0.tgz", - "integrity": "sha512-4bV582zTV9Q02RXBxSUMiuN/KHo5w4aTojuKTNT96DIKps/SIawFp7cS5Mu25VuY1AioGXrmYyzKZUzh8OqoUw==", - "dev": true, - "dependencies": { - "punycode": "^2.0.0" - } - }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", @@ -20155,56 +17171,6 @@ "node": ">= 4" } }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/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/wrap-ansi/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/wrap-ansi/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/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -20222,18 +17188,6 @@ "node": ">=0.10.0" } }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, "node_modules/ws": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", @@ -20268,169 +17222,6 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "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/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/yargs/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/yargs/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/yargs/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/yargs/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/yargs/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/yargs/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/yargs/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/yargs/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/yargs/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/yargs/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/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/package.json b/package.json index 3155445d..5c93e5d5 100644 --- a/package.json +++ b/package.json @@ -13,26 +13,19 @@ "browser": "./src/index.js", "scripts": { "build": "webpack --progress --colors --bail", - "coverage": "tap ./test/{unit,integration}/*.js --coverage --coverage-report=lcov", "docs": "jsdoc -c .jsdoc.json", "i18n:src": "mkdirp translations/core && format-message extract --out-file translations/core/en.json src/extensions/**/index.js", "i18n:push": "tx-push-src scratch-editor extensions translations/core/en.json", "lint": "eslint .", "prepublish": "in-publish && npm run build || not-in-publish", "start": "webpack-dev-server", - "tap": "tap ./test/{unit,integration}/*.js", - "tap:unit": "tap ./test/unit/*.js", - "tap:integration": "tap ./test/integration/*.js", - "test": "npm run lint && npm run tap", + "test": "npm run lint && npm run test:node", + "test:node": "node --test --test-force-exit --test-timeout=30000 test/unit/*.js test/integration/*.js", + "test:unit": "node --test --test-force-exit --test-timeout=30000 test/unit/*.js", + "test:integration": "node --test --test-force-exit --test-timeout=30000 test/integration/*.js", "watch": "webpack --progress --colors --watch", "version": "json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\"" }, - "tap": { - "branches": 60, - "functions": 70, - "lines": 70, - "statements": 70 - }, "dependencies": { "@turbowarp/json": "^0.1.2", "@turbowarp/jszip": "^3.11.0", @@ -84,7 +77,6 @@ "scratch-storage": "2.3.1", "script-loader": "0.7.2", "stats.js": "0.17.0", - "tap": "16.2.0", "tiny-worker": "2.3.0", "uglifyjs-webpack-plugin": "1.2.7", "webpack": "4.47.0", diff --git a/test/fixtures/test-compare.js b/test/fixtures/test-compare.js index 4aa625ea..23ae020f 100644 --- a/test/fixtures/test-compare.js +++ b/test/fixtures/test-compare.js @@ -1,14 +1,15 @@ -const testCompare = (t, lhs, op, rhs, message) => { - const details = `Expected: ${lhs} ${op} ${rhs}`; - const extra = {details}; +const assert = require('node:assert'); + +const testCompare = (lhs, op, rhs, message) => { + const details = `${message}. Expected: ${lhs} ${op} ${rhs}`; switch (op) { - case '<': return t.ok(lhs < rhs, message, extra); - case '<=': return t.ok(lhs <= rhs, message, extra); - case '===': return t.ok(lhs === rhs, message, extra); - case '!==': return t.ok(lhs !== rhs, message, extra); - case '>=': return t.ok(lhs >= rhs, message, extra); - case '>': return t.ok(lhs > rhs, message, extra); - default: return t.fail(`Unrecognized op: ${op}`); + case '<': return assert.ok(lhs < rhs, details); + case '<=': return assert.ok(lhs <= rhs, details); + case '===': return assert.ok(lhs === rhs, details); + case '!==': return assert.ok(lhs !== rhs, details); + case '>=': return assert.ok(lhs >= rhs, details); + case '>': return assert.ok(lhs > rhs, details); + default: return assert.fail(`Unrecognized op: ${op}`); } }; diff --git a/test/integration/addSprite.js b/test/integration/addSprite.js index 75024156..aa8eb628 100644 --- a/test/integration/addSprite.js +++ b/test/integration/addSprite.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; @@ -11,12 +12,11 @@ const project = readFileToBuffer(projectUri); const vm = new VirtualMachine(); -test('spec', t => { - t.type(vm.addSprite, 'function'); - t.end(); +test('spec', () => { + assert.strictEqual(typeof vm.addSprite, 'function'); }); -test('default cat', t => { +test('default cat', (t, done) => { // Get default cat from .sprite2 const uri = path.resolve(__dirname, '../fixtures/example_sprite.sprite2'); const sprite = readFileToBuffer(uri); @@ -26,50 +26,50 @@ test('default cat', t => { // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length === 0); + assert.ok(threads.length === 0); vm.quit(); - t.end(); + done(); }); vm.start(); vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.loadProject(project).then(() => { - t.equal(vm.runtime.targets.length, 2); // stage and default sprite + assert.strictEqual(vm.runtime.targets.length, 2); // stage and default sprite // Add another sprite vm.addSprite(sprite).then(() => { const targets = vm.runtime.targets; // Test - t.type(targets, 'object'); - t.equal(targets.length, 3); + assert.strictEqual(typeof targets, 'object'); + assert.strictEqual(targets.length, 3); const newTarget = targets[2]; - t.ok(newTarget instanceof RenderedTarget); - t.type(newTarget.id, 'string'); - t.type(newTarget.blocks, 'object'); - t.type(newTarget.variables, 'object'); + assert.ok(newTarget instanceof RenderedTarget); + assert.strictEqual(typeof newTarget.id, 'string'); + assert.strictEqual(typeof newTarget.blocks, 'object'); + assert.strictEqual(typeof newTarget.variables, 'object'); const varIds = Object.keys(newTarget.variables); - t.type(varIds.length, 1); + assert.strictEqual(varIds.length, 1); const variable = newTarget.variables[varIds[0]]; - t.equal(variable.name, 'foo'); - t.equal(variable.value, 0); + assert.strictEqual(variable.name, 'foo'); + assert.strictEqual(variable.value, 0); - t.equal(newTarget.isOriginal, true); - t.equal(newTarget.currentCostume, 0); - t.equal(newTarget.isOriginal, true); - t.equal(newTarget.isStage, false); - t.equal(newTarget.sprite.name, 'Apple'); + assert.strictEqual(newTarget.isOriginal, true); + assert.strictEqual(newTarget.currentCostume, 0); + assert.strictEqual(newTarget.isOriginal, true); + assert.strictEqual(newTarget.isStage, false); + assert.strictEqual(newTarget.sprite.name, 'Apple'); vm.greenFlag(); setTimeout(() => { - t.equal(variable.value, 10); + assert.strictEqual(variable.value, 10); vm.getPlaygroundData(); vm.stopAll(); }, 1000); diff --git a/test/integration/block_to_workspace_comment_import.js b/test/integration/block_to_workspace_comment_import.js index daea35a5..366ba6c4 100644 --- a/test/integration/block_to_workspace_comment_import.js +++ b/test/integration/block_to_workspace_comment_import.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,38 +8,38 @@ const VirtualMachine = require('../../src/index'); const projectUri = path.resolve(__dirname, '../fixtures/block-to-workspace-comments.sb2'); const project = readFileToBuffer(projectUri); -test('importing sb2 project where block comment is converted to workspace comment and block is deleted', t => { +test('importing sb2 project where block comment is converted to workspace comment and block is deleted', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.equal(threads.length, 0); + assert.strictEqual(threads.length, 0); const target = vm.runtime.targets[1]; // Sprite 1 has 3 Comments, 1 block comment and 2 workspace comments (which were // originally created via a block comment to workspace comment conversion in Scratch 2.0). const targetComments = Object.values(target.comments); - t.equal(targetComments.length, 3); + assert.strictEqual(targetComments.length, 3); const spriteWorkspaceComments = targetComments.filter(comment => comment.blockId === null); - t.equal(spriteWorkspaceComments.length, 2); + assert.strictEqual(spriteWorkspaceComments.length, 2); // Test the sprite block comments const blockComments = targetComments.filter(comment => !!comment.blockId); - t.equal(blockComments.length, 1); + assert.strictEqual(blockComments.length, 1); // There should not be any comments where blockId is a number const invalidComments = targetComments.filter(comment => typeof comment.blockId === 'number'); - t.equal(invalidComments.length, 0); + assert.strictEqual(invalidComments.length, 0); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/block_to_workspace_comment_import_no_scripts.js b/test/integration/block_to_workspace_comment_import_no_scripts.js index f3dec670..fb8f1266 100644 --- a/test/integration/block_to_workspace_comment_import_no_scripts.js +++ b/test/integration/block_to_workspace_comment_import_no_scripts.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -8,14 +9,14 @@ const projectUri = path.resolve(__dirname, '../fixtures/block-to-workspace-comme const project = readFileToBuffer(projectUri); /* eslint-disable-next-line max-len */ -test('importing sb2 project where block comment is converted to workspace comment and block is deleted, and there are no scripts on the workspace', t => { +test('importing sb2 project where block comment is converted to workspace comment and block is deleted, and there are no scripts on the workspace', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.equal(threads.length, 0); + assert.strictEqual(threads.length, 0); const target = vm.runtime.targets[1]; @@ -23,27 +24,27 @@ test('importing sb2 project where block comment is converted to workspace commen // originally created via a block comment to workspace comment conversion in Scratch 2.0. // What differentiates this test from above is that there are no scripts in this project. const targetComments = Object.values(target.comments); - t.equal(targetComments.length, 1); + assert.strictEqual(targetComments.length, 1); const spriteWorkspaceComments = targetComments.filter(comment => comment.blockId === null); - t.equal(spriteWorkspaceComments.length, 1); + assert.strictEqual(spriteWorkspaceComments.length, 1); // Test the sprite block comments const blockComments = targetComments.filter(comment => !!comment.blockId); - t.equal(blockComments.length, 0); + assert.strictEqual(blockComments.length, 0); // There should not be any comments where blockId is a number const invalidComments = targetComments.filter(comment => typeof comment.blockId === 'number'); - t.equal(invalidComments.length, 0); + assert.strictEqual(invalidComments.length, 0); const targetBlocks = Object.values(target.blocks._blocks); - t.equal(targetBlocks.length, 0); + assert.strictEqual(targetBlocks.length, 0); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/broadcast_special_chars_sb2.js b/test/integration/broadcast_special_chars_sb2.js index 24988f40..eeb605cc 100644 --- a/test/integration/broadcast_special_chars_sb2.js +++ b/test/integration/broadcast_special_chars_sb2.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -10,16 +11,16 @@ const VariableUtil = require('../../src/util/variable-util'); const projectUri = path.resolve(__dirname, '../fixtures/broadcast_special_chars.sb2'); const project = readFileToBuffer(projectUri); -test('importing sb2 project with special chars in message names', t => { +test('importing sb2 project with special chars in message names', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.equal(threads.length, 0); + assert.strictEqual(threads.length, 0); - t.equal(vm.runtime.targets.length, 2); + assert.strictEqual(vm.runtime.targets.length, 2); const stage = vm.runtime.targets[0]; const cat = vm.runtime.targets[1]; @@ -31,13 +32,13 @@ test('importing sb2 project with special chars in message names', t => { // Check for unsafe characters, replaceUnsafeChars should just result in the original string // (e.g. there was nothing to replace) // Check that the message ID does not have any unsafe characters - t.equal(StringUtil.replaceUnsafeChars(abMessageId), abMessageId); + assert.strictEqual(StringUtil.replaceUnsafeChars(abMessageId), abMessageId); // Check that the message still has the correct info - t.equal(StringUtil.replaceUnsafeChars(abMessage.id), abMessage.id); - t.equal(abMessage.id, abMessageId); - t.equal(abMessage.type, Variable.BROADCAST_MESSAGE_TYPE); - t.equal(abMessage.value, 'a&b'); + assert.strictEqual(StringUtil.replaceUnsafeChars(abMessage.id), abMessage.id); + assert.strictEqual(abMessage.id, abMessageId); + assert.strictEqual(abMessage.type, Variable.BROADCAST_MESSAGE_TYPE); + assert.strictEqual(abMessage.value, 'a&b'); const ltPerfectMessageId = Object.keys(stage.variables).filter(k => stage.variables[k].name === '< perfect')[0]; @@ -45,31 +46,31 @@ test('importing sb2 project with special chars in message names', t => { // Check for unsafe characters, replaceUnsafeChars should just result in the original string // (e.g. there was nothing to replace) // Check that the message ID does not have any unsafe characters - t.equal(StringUtil.replaceUnsafeChars(ltPerfectMessageId), ltPerfectMessageId); + assert.strictEqual(StringUtil.replaceUnsafeChars(ltPerfectMessageId), ltPerfectMessageId); // Check that the message still has the correct info - t.equal(StringUtil.replaceUnsafeChars(ltPerfectMessage.id), ltPerfectMessage.id); - t.equal(ltPerfectMessage.id, ltPerfectMessageId); - t.equal(ltPerfectMessage.type, Variable.BROADCAST_MESSAGE_TYPE); - t.equal(ltPerfectMessage.value, '< perfect'); + assert.strictEqual(StringUtil.replaceUnsafeChars(ltPerfectMessage.id), ltPerfectMessage.id); + assert.strictEqual(ltPerfectMessage.id, ltPerfectMessageId); + assert.strictEqual(ltPerfectMessage.type, Variable.BROADCAST_MESSAGE_TYPE); + assert.strictEqual(ltPerfectMessage.value, '< perfect'); // Find all the references for these messages, and verify they have the correct ID - t.equal(allBroadcastFields[ltPerfectMessageId].length, 1); - t.equal(allBroadcastFields[abMessageId].length, 1); + assert.strictEqual(allBroadcastFields[ltPerfectMessageId].length, 1); + assert.strictEqual(allBroadcastFields[abMessageId].length, 1); const catBlocks = Object.keys(cat.blocks._blocks).map(blockId => cat.blocks._blocks[blockId]); const catMessageBlocks = catBlocks.filter( block => Object.prototype.hasOwnProperty.call(block.fields, 'BROADCAST_OPTION') ); - t.equal(catMessageBlocks.length, 2); - t.equal(catMessageBlocks[0].fields.BROADCAST_OPTION.id, ltPerfectMessageId); - t.equal(catMessageBlocks[1].fields.BROADCAST_OPTION.id, abMessageId); + assert.strictEqual(catMessageBlocks.length, 2); + assert.strictEqual(catMessageBlocks[0].fields.BROADCAST_OPTION.id, ltPerfectMessageId); + assert.strictEqual(catMessageBlocks[1].fields.BROADCAST_OPTION.id, abMessageId); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/broadcast_special_chars_sb3.js b/test/integration/broadcast_special_chars_sb3.js index 91050e59..a08d535f 100644 --- a/test/integration/broadcast_special_chars_sb3.js +++ b/test/integration/broadcast_special_chars_sb3.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -10,16 +11,16 @@ const VariableUtil = require('../../src/util/variable-util'); const projectUri = path.resolve(__dirname, '../fixtures/broadcast_special_chars.sb3'); const project = readFileToBuffer(projectUri); -test('importing sb3 project with special chars in message names', t => { +test('importing sb3 project with special chars in message names', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.equal(threads.length, 0); + assert.strictEqual(threads.length, 0); - t.equal(vm.runtime.targets.length, 2); + assert.strictEqual(vm.runtime.targets.length, 2); const stage = vm.runtime.targets[0]; const cat = vm.runtime.targets[1]; @@ -31,13 +32,13 @@ test('importing sb3 project with special chars in message names', t => { // Check for unsafe characters, replaceUnsafeChars should just result in the original string // (e.g. there was nothing to replace) // Check that the message ID does not have any unsafe characters - t.equal(StringUtil.replaceUnsafeChars(abMessageId), abMessageId); + assert.strictEqual(StringUtil.replaceUnsafeChars(abMessageId), abMessageId); // Check that the message still has the correct info - t.equal(StringUtil.replaceUnsafeChars(abMessage.id), abMessage.id); - t.equal(abMessage.id, abMessageId); - t.equal(abMessage.type, Variable.BROADCAST_MESSAGE_TYPE); - t.equal(abMessage.value, 'a&b'); + assert.strictEqual(StringUtil.replaceUnsafeChars(abMessage.id), abMessage.id); + assert.strictEqual(abMessage.id, abMessageId); + assert.strictEqual(abMessage.type, Variable.BROADCAST_MESSAGE_TYPE); + assert.strictEqual(abMessage.value, 'a&b'); const ltPerfectMessageId = Object.keys(stage.variables).filter(k => stage.variables[k].name === '< perfect')[0]; @@ -45,31 +46,31 @@ test('importing sb3 project with special chars in message names', t => { // Check for unsafe characters, replaceUnsafeChars should just result in the original string // (e.g. there was nothing to replace) // Check that the message ID does not have any unsafe characters - t.equal(StringUtil.replaceUnsafeChars(ltPerfectMessageId), ltPerfectMessageId); + assert.strictEqual(StringUtil.replaceUnsafeChars(ltPerfectMessageId), ltPerfectMessageId); // Check that the message still has the correct info - t.equal(StringUtil.replaceUnsafeChars(ltPerfectMessage.id), ltPerfectMessage.id); - t.equal(ltPerfectMessage.id, ltPerfectMessageId); - t.equal(ltPerfectMessage.type, Variable.BROADCAST_MESSAGE_TYPE); - t.equal(ltPerfectMessage.value, '< perfect'); + assert.strictEqual(StringUtil.replaceUnsafeChars(ltPerfectMessage.id), ltPerfectMessage.id); + assert.strictEqual(ltPerfectMessage.id, ltPerfectMessageId); + assert.strictEqual(ltPerfectMessage.type, Variable.BROADCAST_MESSAGE_TYPE); + assert.strictEqual(ltPerfectMessage.value, '< perfect'); // Find all the references for these messages, and verify they have the correct ID - t.equal(allBroadcastFields[ltPerfectMessageId].length, 1); - t.equal(allBroadcastFields[abMessageId].length, 1); + assert.strictEqual(allBroadcastFields[ltPerfectMessageId].length, 1); + assert.strictEqual(allBroadcastFields[abMessageId].length, 1); const catBlocks = Object.keys(cat.blocks._blocks).map(blockId => cat.blocks._blocks[blockId]); const catMessageBlocks = catBlocks.filter( block => Object.prototype.hasOwnProperty.call(block.fields, 'BROADCAST_OPTION') ); - t.equal(catMessageBlocks.length, 2); - t.equal(catMessageBlocks[0].fields.BROADCAST_OPTION.id, ltPerfectMessageId); - t.equal(catMessageBlocks[1].fields.BROADCAST_OPTION.id, abMessageId); + assert.strictEqual(catMessageBlocks.length, 2); + assert.strictEqual(catMessageBlocks[0].fields.BROADCAST_OPTION.id, ltPerfectMessageId); + assert.strictEqual(catMessageBlocks[1].fields.BROADCAST_OPTION.id, abMessageId); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/clone-cleanup.js b/test/integration/clone-cleanup.js index af6707ec..100c524d 100644 --- a/test/integration/clone-cleanup.js +++ b/test/integration/clone-cleanup.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,7 +8,7 @@ const VirtualMachine = require('../../src/index'); const projectUri = path.resolve(__dirname, '../fixtures/clone-cleanup.sb2'); const project = readFileToBuffer(projectUri); -test('clone-cleanup', t => { +test('clone-cleanup', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -19,19 +20,19 @@ test('clone-cleanup', t => { const verifyCounts = (expectedClones, extraThreads) => { // stage plus one sprite, plus clones - t.strictEqual(vm.runtime.targets.length, 2 + expectedClones, + assert.strictEqual(vm.runtime.targets.length, 2 + expectedClones, `target count at step ${testStep}`); // the stage should never have any clones - t.strictEqual(vm.runtime.targets[0].sprite.clones.length, 1, + assert.strictEqual(vm.runtime.targets[0].sprite.clones.length, 1, `stage clone count at step ${testStep}`); // check sprite clone count (+1 for original) - t.strictEqual(vm.runtime.targets[1].sprite.clones.length, 1 + expectedClones, + assert.strictEqual(vm.runtime.targets[1].sprite.clones.length, 1 + expectedClones, `sprite clone count at step ${testStep}`); // thread count isn't directly tied to clone count since threads can end - t.strictEqual(vm.runtime.threads.length, extraThreads + (2 * expectedClones), + assert.strictEqual(vm.runtime.threads.length, extraThreads + (2 * expectedClones), `thread count at step ${testStep}`); }; @@ -66,13 +67,13 @@ test('clone-cleanup', t => { verifyCounts(0, 0); vm.quit(); - t.end(); + done(); break; } }; // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/cloud_variables_sb2.js b/test/integration/cloud_variables_sb2.js index 0b2e0a3a..16643cd7 100644 --- a/test/integration/cloud_variables_sb2.js +++ b/test/integration/cloud_variables_sb2.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -14,7 +15,7 @@ const cloudVarLimit = readFileToBuffer(cloudVarLimitUri); const cloudVarExceededLimit = readFileToBuffer(cloudVarExceededLimitUri); const cloudVarLocal = readFileToBuffer(cloudVarLocalUri); -test('importing an sb2 project with cloud variables', t => { +test('importing an sb2 project with cloud variables', async () => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -23,26 +24,24 @@ test('importing an sb2 project with cloud variables', t => { vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(cloudVarSimple).then(() => { - t.equal(vm.runtime.hasCloudData(), true); + await vm.loadProject(cloudVarSimple); + assert.strictEqual(vm.runtime.hasCloudData(), true); - const stage = vm.runtime.targets[0]; - const stageVars = Object.values(stage.variables); - t.equal(stageVars.length, 1); + const stage = vm.runtime.targets[0]; + const stageVars = Object.values(stage.variables); + assert.strictEqual(stageVars.length, 1); - const variable = stageVars[0]; - t.equal(variable.name, '☁ firstCloud'); - t.equal(Number(variable.value), 100); // Though scratch 2 requires - // cloud variables to be numbers, this is something that happens - // when the message is being sent to the server rather than on the client - t.equal(variable.isCloud, true); + const variable = stageVars[0]; + assert.strictEqual(variable.name, '☁ firstCloud'); + assert.strictEqual(Number(variable.value), 100); // Though scratch 2 requires + // cloud variables to be numbers, this is something that happens + // when the message is being sent to the server rather than on the client + assert.strictEqual(variable.isCloud, true); - vm.quit(); - t.end(); - }); + vm.quit(); }); -test('importing an sb2 project with cloud variables at the limit for a project', t => { +test('importing an sb2 project with cloud variables at the limit for a project', async () => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -51,22 +50,20 @@ test('importing an sb2 project with cloud variables at the limit for a project', vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(cloudVarLimit).then(() => { - t.equal(vm.runtime.hasCloudData(), true); + await vm.loadProject(cloudVarLimit); + assert.strictEqual(vm.runtime.hasCloudData(), true); - const stage = vm.runtime.targets[0]; - const stageVars = Object.values(stage.variables); + const stage = vm.runtime.targets[0]; + const stageVars = Object.values(stage.variables); - t.equal(stageVars.length, 10); - // All of the 8 stage variables should be cloud variables - t.equal(stageVars.filter(v => v.isCloud).length, 10); + assert.strictEqual(stageVars.length, 10); + // All of the 8 stage variables should be cloud variables + assert.strictEqual(stageVars.filter(v => v.isCloud).length, 10); - vm.quit(); - t.end(); - }); + vm.quit(); }); -test('importing an sb2 project with cloud variables exceeding the limit for a project', t => { +test('importing an sb2 project with cloud variables exceeding the limit for a project', async () => { // This tests a hacked project where additional cloud variables exceeding // the project limit have been added. const vm = new VirtualMachine(); @@ -77,22 +74,20 @@ test('importing an sb2 project with cloud variables exceeding the limit for a pr vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(cloudVarExceededLimit).then(() => { - t.equal(vm.runtime.hasCloudData(), true); + await vm.loadProject(cloudVarExceededLimit); + assert.strictEqual(vm.runtime.hasCloudData(), true); - const stage = vm.runtime.targets[0]; - const stageVars = Object.values(stage.variables); + const stage = vm.runtime.targets[0]; + const stageVars = Object.values(stage.variables); - t.equal(stageVars.length, 15); - // Only 8 of the variables should have the isCloud flag set to true - t.equal(stageVars.filter(v => v.isCloud).length, 10); + assert.strictEqual(stageVars.length, 15); + // Only 8 of the variables should have the isCloud flag set to true + assert.strictEqual(stageVars.filter(v => v.isCloud).length, 10); - vm.quit(); - t.end(); - }); + vm.quit(); }); -test('importing one project after the other resets cloud variable limit', t => { +test('importing one project after the other resets cloud variable limit', async () => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -101,30 +96,27 @@ test('importing one project after the other resets cloud variable limit', t => { vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(cloudVarExceededLimit).then(() => { - t.equal(vm.runtime.canAddCloudVariable(), false); + await vm.loadProject(cloudVarExceededLimit); + assert.strictEqual(vm.runtime.canAddCloudVariable(), false); - vm.loadProject(cloudVarSimple).then(() => { - const stage = vm.runtime.targets[0]; - const stageVars = Object.values(stage.variables); - t.equal(stageVars.length, 1); + await vm.loadProject(cloudVarSimple); + const stage = vm.runtime.targets[0]; + const stageVars = Object.values(stage.variables); + assert.strictEqual(stageVars.length, 1); - const variable = stageVars[0]; - t.equal(variable.name, '☁ firstCloud'); - t.equal(Number(variable.value), 100); // Though scratch 2 requires - // cloud variables to be numbers, this is something that happens - // when the message is being sent to the server rather than on the client - t.equal(variable.isCloud, true); + const variable = stageVars[0]; + assert.strictEqual(variable.name, '☁ firstCloud'); + assert.strictEqual(Number(variable.value), 100); // Though scratch 2 requires + // cloud variables to be numbers, this is something that happens + // when the message is being sent to the server rather than on the client + assert.strictEqual(variable.isCloud, true); - t.equal(vm.runtime.canAddCloudVariable(), true); + assert.strictEqual(vm.runtime.canAddCloudVariable(), true); - vm.quit(); - t.end(); - }); - }); + vm.quit(); }); -test('local cloud variables get imported as regular variables', t => { +test('local cloud variables get imported as regular variables', async () => { // This tests a hacked project where a sprite-local variable is // has the cloud variable flag set. const vm = new VirtualMachine(); @@ -135,21 +127,19 @@ test('local cloud variables get imported as regular variables', t => { vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(cloudVarLocal).then(() => { - t.equal(vm.runtime.hasCloudData(), false); + await vm.loadProject(cloudVarLocal); + assert.strictEqual(vm.runtime.hasCloudData(), false); - const stage = vm.runtime.targets[0]; - const stageVars = Object.values(stage.variables); + const stage = vm.runtime.targets[0]; + const stageVars = Object.values(stage.variables); - t.equal(stageVars.length, 0); + assert.strictEqual(stageVars.length, 0); - const sprite = vm.runtime.targets[1]; - const spriteVars = Object.values(sprite.variables); + const sprite = vm.runtime.targets[1]; + const spriteVars = Object.values(sprite.variables); - t.equal(spriteVars.length, 1); - t.equal(spriteVars[0].isCloud, false); + assert.strictEqual(spriteVars.length, 1); + assert.strictEqual(spriteVars[0].isCloud, false); - vm.quit(); - t.end(); - }); + vm.quit(); }); diff --git a/test/integration/cloud_variables_sb3.js b/test/integration/cloud_variables_sb3.js index 7caab31e..a7d5630c 100644 --- a/test/integration/cloud_variables_sb3.js +++ b/test/integration/cloud_variables_sb3.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -14,7 +15,7 @@ const cloudVarLimit = readFileToBuffer(cloudVarLimitUri); const cloudVarExceededLimit = readFileToBuffer(cloudVarExceededLimitUri); const cloudVarLocal = readFileToBuffer(cloudVarLocalUri); -test('importing an sb3 project with cloud variables', t => { +test('importing an sb3 project with cloud variables', async () => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -23,24 +24,22 @@ test('importing an sb3 project with cloud variables', t => { vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(cloudVarSimple).then(() => { - t.equal(vm.runtime.hasCloudData(), true); + await vm.loadProject(cloudVarSimple); + assert.strictEqual(vm.runtime.hasCloudData(), true); - const stage = vm.runtime.targets[0]; - const stageVars = Object.values(stage.variables); - t.equal(stageVars.length, 1); + const stage = vm.runtime.targets[0]; + const stageVars = Object.values(stage.variables); + assert.strictEqual(stageVars.length, 1); - const variable = stageVars[0]; - t.equal(variable.name, '☁ firstCloud'); - t.equal(Number(variable.value), 100); - t.equal(variable.isCloud, true); + const variable = stageVars[0]; + assert.strictEqual(variable.name, '☁ firstCloud'); + assert.strictEqual(Number(variable.value), 100); + assert.strictEqual(variable.isCloud, true); - vm.quit(); - t.end(); - }); + vm.quit(); }); -test('importing an sb3 project with cloud variables at the limit for a project', t => { +test('importing an sb3 project with cloud variables at the limit for a project', async () => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -49,22 +48,20 @@ test('importing an sb3 project with cloud variables at the limit for a project', vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(cloudVarLimit).then(() => { - t.equal(vm.runtime.hasCloudData(), true); + await vm.loadProject(cloudVarLimit); + assert.strictEqual(vm.runtime.hasCloudData(), true); - const stage = vm.runtime.targets[0]; - const stageVars = Object.values(stage.variables); + const stage = vm.runtime.targets[0]; + const stageVars = Object.values(stage.variables); - t.equal(stageVars.length, 10); - // All of the 10 stage variables should be cloud variables - t.equal(stageVars.filter(v => v.isCloud).length, 10); + assert.strictEqual(stageVars.length, 10); + // All of the 10 stage variables should be cloud variables + assert.strictEqual(stageVars.filter(v => v.isCloud).length, 10); - vm.quit(); - t.end(); - }); + vm.quit(); }); -test('importing an sb3 project with cloud variables exceeding the limit for a project', t => { +test('importing an sb3 project with cloud variables exceeding the limit for a project', async () => { // This tests a hacked project where additional cloud variables exceeding // the project limit have been added. const vm = new VirtualMachine(); @@ -75,22 +72,20 @@ test('importing an sb3 project with cloud variables exceeding the limit for a pr vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(cloudVarExceededLimit).then(() => { - t.equal(vm.runtime.hasCloudData(), true); + await vm.loadProject(cloudVarExceededLimit); + assert.strictEqual(vm.runtime.hasCloudData(), true); - const stage = vm.runtime.targets[0]; - const stageVars = Object.values(stage.variables); + const stage = vm.runtime.targets[0]; + const stageVars = Object.values(stage.variables); - t.equal(stageVars.length, 15); - // Only 8 of the variables should have the isCloud flag set to true - t.equal(stageVars.filter(v => v.isCloud).length, 10); + assert.strictEqual(stageVars.length, 15); + // Only 8 of the variables should have the isCloud flag set to true + assert.strictEqual(stageVars.filter(v => v.isCloud).length, 10); - vm.quit(); - t.end(); - }); + vm.quit(); }); -test('importing one project after the other resets cloud variable limit', t => { +test('importing one project after the other resets cloud variable limit', async () => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -99,28 +94,25 @@ test('importing one project after the other resets cloud variable limit', t => { vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(cloudVarExceededLimit).then(() => { - t.equal(vm.runtime.canAddCloudVariable(), false); + await vm.loadProject(cloudVarExceededLimit); + assert.strictEqual(vm.runtime.canAddCloudVariable(), false); - vm.loadProject(cloudVarSimple).then(() => { - const stage = vm.runtime.targets[0]; - const stageVars = Object.values(stage.variables); - t.equal(stageVars.length, 1); + await vm.loadProject(cloudVarSimple); + const stage = vm.runtime.targets[0]; + const stageVars = Object.values(stage.variables); + assert.strictEqual(stageVars.length, 1); - const variable = stageVars[0]; - t.equal(variable.name, '☁ firstCloud'); - t.equal(Number(variable.value), 100); - t.equal(variable.isCloud, true); + const variable = stageVars[0]; + assert.strictEqual(variable.name, '☁ firstCloud'); + assert.strictEqual(Number(variable.value), 100); + assert.strictEqual(variable.isCloud, true); - t.equal(vm.runtime.canAddCloudVariable(), true); + assert.strictEqual(vm.runtime.canAddCloudVariable(), true); - vm.quit(); - t.end(); - }); - }); + vm.quit(); }); -test('local cloud variables get imported as regular variables', t => { +test('local cloud variables get imported as regular variables', async () => { // This tests a hacked project where a sprite-local variable is // has the cloud variable flag set. const vm = new VirtualMachine(); @@ -131,21 +123,19 @@ test('local cloud variables get imported as regular variables', t => { vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(cloudVarLocal).then(() => { - t.equal(vm.runtime.hasCloudData(), false); + await vm.loadProject(cloudVarLocal); + assert.strictEqual(vm.runtime.hasCloudData(), false); - const stage = vm.runtime.targets[0]; - const stageVars = Object.values(stage.variables); + const stage = vm.runtime.targets[0]; + const stageVars = Object.values(stage.variables); - t.equal(stageVars.length, 0); + assert.strictEqual(stageVars.length, 0); - const sprite = vm.runtime.targets[1]; - const spriteVars = Object.values(sprite.variables); + const sprite = vm.runtime.targets[1]; + const spriteVars = Object.values(sprite.variables); - t.equal(spriteVars.length, 1); - t.equal(spriteVars[0].isCloud, false); + assert.strictEqual(spriteVars.length, 1); + assert.strictEqual(spriteVars[0].isCloud, false); - vm.quit(); - t.end(); - }); + vm.quit(); }); diff --git a/test/integration/comments.js b/test/integration/comments.js index 14304ab8..a1b0656c 100644 --- a/test/integration/comments.js +++ b/test/integration/comments.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,14 +8,14 @@ const VirtualMachine = require('../../src/index'); const projectUri = path.resolve(__dirname, '../fixtures/comments.sb2'); const project = readFileToBuffer(projectUri); -test('importing sb2 project with comments', t => { +test('importing sb2 project with comments', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.equal(threads.length, 0); + assert.strictEqual(threads.length, 0); const stage = vm.runtime.targets[0]; const target = vm.runtime.targets[1]; @@ -22,60 +23,60 @@ test('importing sb2 project with comments', t => { const stageComments = Object.values(stage.comments); // Stage has 1 comment, and it is minimized. - t.equal(stageComments.length, 1); - t.equal(stageComments[0].minimized, true); - t.equal(stageComments[0].text, 'A minimized stage comment.'); + assert.strictEqual(stageComments.length, 1); + assert.strictEqual(stageComments[0].minimized, true); + assert.strictEqual(stageComments[0].text, 'A minimized stage comment.'); // The stage comment is a workspace comment - t.equal(stageComments[0].blockId, null); + assert.strictEqual(stageComments[0].blockId, null); // Sprite 1 has 6 Comments, 1 workspace comment, and 5 block comments const targetComments = Object.values(target.comments); - t.equal(targetComments.length, 6); + assert.strictEqual(targetComments.length, 6); const spriteWorkspaceComments = targetComments.filter(comment => comment.blockId === null); - t.equal(spriteWorkspaceComments.length, 1); - t.equal(spriteWorkspaceComments[0].minimized, false); - t.equal(spriteWorkspaceComments[0].text, 'This is a workspace comment.'); + assert.strictEqual(spriteWorkspaceComments.length, 1); + assert.strictEqual(spriteWorkspaceComments[0].minimized, false); + assert.strictEqual(spriteWorkspaceComments[0].text, 'This is a workspace comment.'); // Test the sprite block comments const blockComments = targetComments.filter(comment => !!comment.blockId); - t.equal(blockComments.length, 5); + assert.strictEqual(blockComments.length, 5); - t.equal(blockComments[0].minimized, true); - t.equal(blockComments[0].text, '1. Green Flag Comment.'); + assert.strictEqual(blockComments[0].minimized, true); + assert.strictEqual(blockComments[0].text, '1. Green Flag Comment.'); const greenFlagBlock = target.blocks.getBlock(blockComments[0].blockId); - t.equal(greenFlagBlock.comment, blockComments[0].id); - t.equal(greenFlagBlock.opcode, 'event_whenflagclicked'); + assert.strictEqual(greenFlagBlock.comment, blockComments[0].id); + assert.strictEqual(greenFlagBlock.opcode, 'event_whenflagclicked'); - t.equal(blockComments[1].minimized, true); - t.equal(blockComments[1].text, '2. Turn 15 Degrees Comment.'); + assert.strictEqual(blockComments[1].minimized, true); + assert.strictEqual(blockComments[1].text, '2. Turn 15 Degrees Comment.'); const turnRightBlock = target.blocks.getBlock(blockComments[1].blockId); - t.equal(turnRightBlock.comment, blockComments[1].id); - t.equal(turnRightBlock.opcode, 'motion_turnright'); + assert.strictEqual(turnRightBlock.comment, blockComments[1].id); + assert.strictEqual(turnRightBlock.opcode, 'motion_turnright'); - t.equal(blockComments[2].minimized, false); - t.equal(blockComments[2].text, '3. Comment for a loop.'); + assert.strictEqual(blockComments[2].minimized, false); + assert.strictEqual(blockComments[2].text, '3. Comment for a loop.'); const repeatBlock = target.blocks.getBlock(blockComments[2].blockId); - t.equal(repeatBlock.comment, blockComments[2].id); - t.equal(repeatBlock.opcode, 'control_repeat'); + assert.strictEqual(repeatBlock.comment, blockComments[2].id); + assert.strictEqual(repeatBlock.opcode, 'control_repeat'); - t.equal(blockComments[3].minimized, false); - t.equal(blockComments[3].text, '4. Comment for a block nested in a loop.'); + assert.strictEqual(blockComments[3].minimized, false); + assert.strictEqual(blockComments[3].text, '4. Comment for a block nested in a loop.'); const changeColorBlock = target.blocks.getBlock(blockComments[3].blockId); - t.equal(changeColorBlock.comment, blockComments[3].id); - t.equal(changeColorBlock.opcode, 'looks_changeeffectby'); + assert.strictEqual(changeColorBlock.comment, blockComments[3].id); + assert.strictEqual(changeColorBlock.opcode, 'looks_changeeffectby'); - t.equal(blockComments[4].minimized, false); - t.equal(blockComments[4].text, '5. Comment for a block outside of a loop.'); + assert.strictEqual(blockComments[4].minimized, false); + assert.strictEqual(blockComments[4].text, '5. Comment for a block outside of a loop.'); const stopAllBlock = target.blocks.getBlock(blockComments[4].blockId); - t.equal(stopAllBlock.comment, blockComments[4].id); - t.equal(stopAllBlock.opcode, 'control_stop'); + assert.strictEqual(stopAllBlock.comment, blockComments[4].id); + assert.strictEqual(stopAllBlock.opcode, 'control_stop'); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/comments_sb3.js b/test/integration/comments_sb3.js index ceebfb2c..7350439c 100644 --- a/test/integration/comments_sb3.js +++ b/test/integration/comments_sb3.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,14 +8,14 @@ const VirtualMachine = require('../../src/index'); const projectUri = path.resolve(__dirname, '../fixtures/comments.sb3'); const project = readFileToBuffer(projectUri); -test('load an sb3 project with comments', t => { +test('load an sb3 project with comments', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.equal(threads.length, 0); + assert.strictEqual(threads.length, 0); const stage = vm.runtime.targets[0]; const target = vm.runtime.targets[1]; @@ -22,60 +23,60 @@ test('load an sb3 project with comments', t => { const stageComments = Object.values(stage.comments); // Stage has 1 comment, and it is minimized. - t.equal(stageComments.length, 1); - t.equal(stageComments[0].minimized, true); - t.equal(stageComments[0].text, 'A minimized stage comment.'); + assert.strictEqual(stageComments.length, 1); + assert.strictEqual(stageComments[0].minimized, true); + assert.strictEqual(stageComments[0].text, 'A minimized stage comment.'); // The stage comment is a workspace comment - t.equal(stageComments[0].blockId, null); + assert.strictEqual(stageComments[0].blockId, null); // Sprite 1 has 6 Comments, 1 workspace comment, and 5 block comments const targetComments = Object.values(target.comments); - t.equal(targetComments.length, 6); + assert.strictEqual(targetComments.length, 6); const spriteWorkspaceComments = targetComments.filter(comment => comment.blockId === null); - t.equal(spriteWorkspaceComments.length, 1); - t.equal(spriteWorkspaceComments[0].minimized, false); - t.equal(spriteWorkspaceComments[0].text, 'This is a workspace comment.'); + assert.strictEqual(spriteWorkspaceComments.length, 1); + assert.strictEqual(spriteWorkspaceComments[0].minimized, false); + assert.strictEqual(spriteWorkspaceComments[0].text, 'This is a workspace comment.'); // Test the sprite block comments const blockComments = targetComments.filter(comment => !!comment.blockId); - t.equal(blockComments.length, 5); + assert.strictEqual(blockComments.length, 5); - t.equal(blockComments[0].minimized, true); - t.equal(blockComments[0].text, '1. Green Flag Comment.'); + assert.strictEqual(blockComments[0].minimized, true); + assert.strictEqual(blockComments[0].text, '1. Green Flag Comment.'); const greenFlagBlock = target.blocks.getBlock(blockComments[0].blockId); - t.equal(greenFlagBlock.comment, blockComments[0].id); - t.equal(greenFlagBlock.opcode, 'event_whenflagclicked'); + assert.strictEqual(greenFlagBlock.comment, blockComments[0].id); + assert.strictEqual(greenFlagBlock.opcode, 'event_whenflagclicked'); - t.equal(blockComments[1].minimized, true); - t.equal(blockComments[1].text, '2. Turn 15 Degrees Comment.'); + assert.strictEqual(blockComments[1].minimized, true); + assert.strictEqual(blockComments[1].text, '2. Turn 15 Degrees Comment.'); const turnRightBlock = target.blocks.getBlock(blockComments[1].blockId); - t.equal(turnRightBlock.comment, blockComments[1].id); - t.equal(turnRightBlock.opcode, 'motion_turnright'); + assert.strictEqual(turnRightBlock.comment, blockComments[1].id); + assert.strictEqual(turnRightBlock.opcode, 'motion_turnright'); - t.equal(blockComments[2].minimized, false); - t.equal(blockComments[2].text, '3. Comment for a loop.'); + assert.strictEqual(blockComments[2].minimized, false); + assert.strictEqual(blockComments[2].text, '3. Comment for a loop.'); const repeatBlock = target.blocks.getBlock(blockComments[2].blockId); - t.equal(repeatBlock.comment, blockComments[2].id); - t.equal(repeatBlock.opcode, 'control_repeat'); + assert.strictEqual(repeatBlock.comment, blockComments[2].id); + assert.strictEqual(repeatBlock.opcode, 'control_repeat'); - t.equal(blockComments[3].minimized, false); - t.equal(blockComments[3].text, '4. Comment for a block nested in a loop.'); + assert.strictEqual(blockComments[3].minimized, false); + assert.strictEqual(blockComments[3].text, '4. Comment for a block nested in a loop.'); const changeColorBlock = target.blocks.getBlock(blockComments[3].blockId); - t.equal(changeColorBlock.comment, blockComments[3].id); - t.equal(changeColorBlock.opcode, 'looks_changeeffectby'); + assert.strictEqual(changeColorBlock.comment, blockComments[3].id); + assert.strictEqual(changeColorBlock.opcode, 'looks_changeeffectby'); - t.equal(blockComments[4].minimized, false); - t.equal(blockComments[4].text, '5. Comment for a block outside of a loop.'); + assert.strictEqual(blockComments[4].minimized, false); + assert.strictEqual(blockComments[4].text, '5. Comment for a block outside of a loop.'); const stopAllBlock = target.blocks.getBlock(blockComments[4].blockId); - t.equal(stopAllBlock.comment, blockComments[4].id); - t.equal(stopAllBlock.opcode, 'control_stop'); + assert.strictEqual(stopAllBlock.comment, blockComments[4].id); + assert.strictEqual(stopAllBlock.opcode, 'control_stop'); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/complex.js b/test/integration/complex.js index de22faef..cb5e2623 100644 --- a/test/integration/complex.js +++ b/test/integration/complex.js @@ -1,6 +1,7 @@ const fs = require('fs'); const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -11,16 +12,16 @@ const project = readFileToBuffer(projectUri); const spriteUri = path.resolve(__dirname, '../fixtures/sprite.json'); const sprite = fs.readFileSync(spriteUri, 'utf8'); -test('complex', t => { +test('complex', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length === 0); + assert.ok(threads.length === 0); vm.quit(); - t.end(); + done(); }); // Manipulate each target @@ -55,7 +56,7 @@ test('complex', t => { }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/control.js b/test/integration/control.js index 3a3ad7d0..16c6998a 100644 --- a/test/integration/control.js +++ b/test/integration/control.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,20 +8,20 @@ const VirtualMachine = require('../../src/index'); const uri = path.resolve(__dirname, '../fixtures/control.sb2'); const project = readFileToBuffer(uri); -test('control', t => { +test('control', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length > 0); + assert.ok(threads.length > 0); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/data.js b/test/integration/data.js index 65e50c4a..7f021da7 100644 --- a/test/integration/data.js +++ b/test/integration/data.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,7 +8,7 @@ const VirtualMachine = require('../../src/index'); const uri = path.resolve(__dirname, '../fixtures/data.sb2'); const project = readFileToBuffer(uri); -test('data', t => { +test('data', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -15,11 +16,11 @@ test('data', t => { vm.on('playgroundData', () => { // @todo Additional tests vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/delete-and-restore-sprite.js b/test/integration/delete-and-restore-sprite.js index 80352cd0..1cc19cf4 100644 --- a/test/integration/delete-and-restore-sprite.js +++ b/test/integration/delete-and-restore-sprite.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; @@ -11,12 +12,11 @@ const project = readFileToBuffer(projectUri); const vm = new VirtualMachine(); -test('spec', t => { - t.type(vm.deleteSprite, 'function'); - t.end(); +test('spec', () => { + assert.strictEqual(typeof vm.deleteSprite, 'function'); }); -test('default cat', t => { +test('default cat', (t, done) => { // Get default cat from .sprite2 // const uri = path.resolve(__dirname, '../fixtures/example_sprite.sprite2'); // const sprite = readFileToBuffer(uri); @@ -26,32 +26,32 @@ test('default cat', t => { // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length === 0); + assert.ok(threads.length === 0); vm.quit(); - t.end(); + done(); }); vm.start(); vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.loadProject(project).then(() => { - t.equal(vm.runtime.targets.length, 2); // stage and default sprite + assert.strictEqual(vm.runtime.targets.length, 2); // stage and default sprite const defaultSprite = vm.runtime.targets[1]; // Delete the sprite const addSpriteBack = vm.deleteSprite(vm.runtime.targets[1].id); - t.equal(vm.runtime.targets.length, 1); + assert.strictEqual(vm.runtime.targets.length, 1); - t.type(addSpriteBack, 'function'); + assert.strictEqual(typeof addSpriteBack, 'function'); addSpriteBack().then(() => { - t.equal(vm.runtime.targets.length, 2); - t.equal(vm.runtime.targets[1].getName(), defaultSprite.getName()); + assert.strictEqual(vm.runtime.targets.length, 2); + assert.strictEqual(vm.runtime.targets[1].getName(), defaultSprite.getName()); vm.greenFlag(); diff --git a/test/integration/event.js b/test/integration/event.js index 886bca2e..6eced037 100644 --- a/test/integration/event.js +++ b/test/integration/event.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,20 +8,20 @@ const VirtualMachine = require('../../src/index'); const uri = path.resolve(__dirname, '../fixtures/event.sb2'); const project = readFileToBuffer(uri); -test('event', t => { +test('event', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length > 0); + assert.ok(threads.length > 0); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/execute.js b/test/integration/execute.js index 88d9e7d4..ee9cea48 100644 --- a/test/integration/execute.js +++ b/test/integration/execute.js @@ -1,7 +1,7 @@ const fs = require('fs'); const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; @@ -14,15 +14,15 @@ const VirtualMachine = require('../../src/index'); * or did "fail". Four keywords can be set at the beginning of a SAY messaage * to indicate a test primitive. * - * - "pass MESSAGE" will t.pass(MESSAGE). - * - "fail MESSAGE" will t.fail(MESSAGE). + * - "pass MESSAGE" will pass an assertion with MESSAGE. + * - "fail MESSAGE" will fail the test with MESSAGE once the project finishes. * - "plan NUMBER_OF_TESTS" will t.plan(Number(NUMBER_OF_TESTS)). - * - "end" will t.end(). + * - "end" marks the test as having reached its end. * * A good strategy to follow is to SAY "plan NUMBER_OF_TESTS" first. Then * "pass" and "fail" depending on expected scratch results in conditions, event * scripts, or what is best for testing the target block or group of blocks. - * When its done you must SAY "end" so the test and tap know that the end has + * When its done you must SAY "end" so the test knows that the end has * been reached. */ @@ -43,16 +43,15 @@ const whenThreadsComplete = (t, vm, uri, timeLimit = 5000) => }, 50); const timeoutId = setTimeout(() => { - t.fail(`Timeout waiting for threads to complete: ${uri}`); - reject(new Error('time limit reached')); - // Attempt to stop the lingering VM from interfering with other tests. vm.quit(); + + reject(new Error(`Timeout waiting for threads to complete: ${uri}`)); }, timeLimit); // Clear the interval to allow the process to exit // naturally. - t.tearDown(() => { + t.after(() => { clearInterval(intervalId); clearTimeout(timeoutId); }); @@ -66,22 +65,25 @@ const fileFilter = /\.sb[23]?$/i; fs.readdirSync(executeDir) .filter(uri => fileFilter.test(uri)) .forEach(uri => { - const run = (t, enableCompiler) => { + const run = async (t, enableCompiler) => { const vm = new VirtualMachine(); + // Stop a VM left running by a failed test from leaking into later tests. + t.after(() => vm.quit()); - // Map string messages to tap reporting methods. This will be used + // Map string messages to test reporting methods. This will be used // with events from scratch's runtime emitted on block instructions. let didPlan; let didEnd; + const failures = []; const reporters = { comment (message) { - t.comment(message); + t.diagnostic(message); }, pass (reason) { - t.pass(reason); + t.assert.ok(true, reason); }, fail (reason) { - t.fail(reason); + failures.push(reason); }, plan (count) { didPlan = true; @@ -90,7 +92,6 @@ fs.readdirSync(executeDir) end () { didEnd = true; vm.quit(); - t.end(); } }; const reportVmResult = text => { @@ -128,25 +129,26 @@ fs.readdirSync(executeDir) // Load the project and once all threads are complete ensure that // the scratch project sent us a "end" message. - return vm.loadProject(project) - .then(() => vm.greenFlag()) - .then(() => whenThreadsComplete(t, vm, uri)) - .then(() => { - // Setting a plan is not required but is a good idea. - if (!didPlan) { - t.comment('did not say "plan NUMBER_OF_TESTS"'); - } + await vm.loadProject(project); + await vm.greenFlag(); + await whenThreadsComplete(t, vm, uri); + // Setting a plan is not required but is a good idea. + if (!didPlan) { + t.diagnostic('did not say "plan NUMBER_OF_TESTS"'); + } - // End must be called so that tap knows the test is done. If - // the test has an SAY "end" block but that block did not - // execute, this explicit failure will raise that issue so - // it can be resolved. - if (!didEnd) { - t.fail('did not say "end"'); - vm.quit(); - t.end(); - } - }); + // If the test has an SAY "end" block but that block did not + // execute, this explicit failure will raise that issue so + // it can be resolved. + if (!didEnd) { + vm.quit(); + failures.push('did not say "end"'); + } + + // Not an assertion, as it would count towards the project's plan. + if (failures.length) { + throw new Error(failures.join('\n')); + } }; test(`${uri} (interpreted)`, t => run(t, false)); test(`${uri} (compiled)`, t => run(t, true)); diff --git a/test/integration/hat-execution-order.js b/test/integration/hat-execution-order.js index 89788d8c..bbe9b636 100644 --- a/test/integration/hat-execution-order.js +++ b/test/integration/hat-execution-order.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -8,19 +9,15 @@ const projectUri = path.resolve(__dirname, '../fixtures/hat-execution-order.sb2' const project = readFileToBuffer(projectUri); const compilerAndInterpreter = (name, callback) => { - test(`${name} - interpreted`, t => { - callback(t, { - enabled: false - }); - }); - test(`${name} - compiled`, t => { - callback(t, { - enabled: true - }); - }); + test(`${name} - interpreted`, (t, done) => callback(done, { + enabled: false + })); + test(`${name} - compiled`, (t, done) => callback(done, { + enabled: true + })); }; -compilerAndInterpreter('complex', (t, co) => { +compilerAndInterpreter('complex', (done, co) => { const vm = new VirtualMachine(); vm.setCompilerOptions(co); vm.attachStorage(makeTestStorage()); @@ -28,18 +25,18 @@ compilerAndInterpreter('complex', (t, co) => { // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length === 0); + assert.ok(threads.length === 0); const resultKey = Object.keys(vm.runtime.targets[0].variables)[0]; const results = vm.runtime.targets[0].variables[resultKey].value; - t.deepEqual(results, ['3', '2', '1', 'stage']); + assert.deepEqual(results, ['3', '2', '1', 'stage']); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/hat-threads-run-every-frame.js b/test/integration/hat-threads-run-every-frame.js index 9772ea5a..b328075f 100644 --- a/test/integration/hat-threads-run-every-frame.js +++ b/test/integration/hat-threads-run-every-frame.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -8,32 +9,28 @@ const Runtime = require('../../src/engine/runtime'); const execute = require('../../src/engine/execute.js'); const compilerAndInterpreter = (name, callback) => { - test(`${name} - interpreted`, t => { - callback(t, { - enabled: false - }); - }); - test(`${name} - compiled`, t => { - callback(t, { - enabled: true - }); - }); + test(`${name} - interpreted`, (t, done) => callback(done, { + enabled: false + })); + test(`${name} - compiled`, (t, done) => callback(done, { + enabled: true + })); }; const projectUri = path.resolve(__dirname, '../fixtures/timer-greater-than-hat.sb2'); const project = readFileToBuffer(projectUri); -const checkIsHatThread = (t, vm, hatThread) => { - t.equal(hatThread.stackClick, false); - t.equal(hatThread.updateMonitor, false); +const checkIsHatThread = (vm, hatThread) => { + assert.strictEqual(hatThread.stackClick, false); + assert.strictEqual(hatThread.updateMonitor, false); const blockContainer = hatThread.target.blocks; const opcode = blockContainer.getOpcode(blockContainer.getBlock(hatThread.topBlock)); - t.assert(vm.runtime.getIsEdgeActivatedHat(opcode)); + assert.ok(vm.runtime.getIsEdgeActivatedHat(opcode)); }; -const checkIsStackClickThread = (t, vm, stackClickThread) => { - t.equal(stackClickThread.stackClick, true); - t.equal(stackClickThread.updateMonitor, false); +const checkIsStackClickThread = (vm, stackClickThread) => { + assert.strictEqual(stackClickThread.stackClick, true); + assert.strictEqual(stackClickThread.updateMonitor, false); }; /** @@ -43,13 +40,13 @@ const checkIsStackClickThread = (t, vm, stackClickThread) => { * The intention is to make sure that the hat block condition is evaluated * on each frame. */ -compilerAndInterpreter('edge activated hat thread runs once every frame', (t, co) => { +compilerAndInterpreter('edge activated hat thread runs once every frame', (done, co) => { const vm = new VirtualMachine(); vm.setCompilerOptions(co); vm.attachStorage(makeTestStorage()); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { // Note: don't run vm.start(), we handle calling _step() manually in this test vm.runtime.currentStepTime = Runtime.THREAD_STEP_INTERVAL; vm.clear(); @@ -57,23 +54,23 @@ compilerAndInterpreter('edge activated hat thread runs once every frame', (t, co vm.setTurboMode(false); vm.loadProject(project).then(() => { - t.equal(vm.runtime.threads.length, 0); + assert.strictEqual(vm.runtime.threads.length, 0); vm.runtime._step(); let threads = vm.runtime._lastStepDoneThreads; - t.equal(vm.runtime.threads.length, 0); - t.equal(threads.length, 1); - checkIsHatThread(t, vm, threads[0]); - t.assert(threads[0].status === Thread.STATUS_DONE); + assert.strictEqual(vm.runtime.threads.length, 0); + assert.strictEqual(threads.length, 1); + checkIsHatThread(vm, threads[0]); + assert.ok(threads[0].status === Thread.STATUS_DONE); // Check that the hat thread is added again when another step is taken vm.runtime._step(); threads = vm.runtime._lastStepDoneThreads; - t.equal(vm.runtime.threads.length, 0); - t.equal(threads.length, 1); - checkIsHatThread(t, vm, threads[0]); - t.assert(threads[0].status === Thread.STATUS_DONE); - t.end(); + assert.strictEqual(vm.runtime.threads.length, 0); + assert.strictEqual(threads.length, 1); + checkIsHatThread(vm, threads[0]); + assert.ok(threads[0].status === Thread.STATUS_DONE); + done(); }); }); }); @@ -83,13 +80,13 @@ compilerAndInterpreter('edge activated hat thread runs once every frame', (t, co * caching should be reset. */ // eslint-disable-next-line max-len -compilerAndInterpreter('edge activated hat thread runs after being added to previously executed target', (t, co) => { +compilerAndInterpreter('edge activated hat thread runs after being added to previously executed target', (done, co) => { const vm = new VirtualMachine(); vm.setCompilerOptions(co); vm.attachStorage(makeTestStorage()); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { // Note: don't run vm.start(), we handle calling _step() manually in this test vm.runtime.currentStepTime = Runtime.THREAD_STEP_INTERVAL; vm.clear(); @@ -97,14 +94,14 @@ compilerAndInterpreter('edge activated hat thread runs after being added to prev vm.setTurboMode(false); vm.loadProject(project).then(() => { - t.equal(vm.runtime.threads.length, 0); + assert.strictEqual(vm.runtime.threads.length, 0); vm.runtime._step(); let threads = vm.runtime._lastStepDoneThreads; - t.equal(vm.runtime.threads.length, 0); - t.equal(threads.length, 1); - checkIsHatThread(t, vm, threads[0]); - t.assert(threads[0].status === Thread.STATUS_DONE); + assert.strictEqual(vm.runtime.threads.length, 0); + assert.strictEqual(threads.length, 1); + checkIsHatThread(vm, threads[0]); + assert.ok(threads[0].status === Thread.STATUS_DONE); // Add a second hat that should create a second thread const hatBlock = threads[0].target.blocks.getBlock(threads[0].topBlock); @@ -115,13 +112,13 @@ compilerAndInterpreter('edge activated hat thread runs after being added to prev // Check that the hat thread is added again when another step is taken vm.runtime._step(); threads = vm.runtime._lastStepDoneThreads; - t.equal(vm.runtime.threads.length, 0); - t.equal(threads.length, 2); - checkIsHatThread(t, vm, threads[0]); - checkIsHatThread(t, vm, threads[1]); - t.assert(threads[0].status === Thread.STATUS_DONE); - t.assert(threads[1].status === Thread.STATUS_DONE); - t.end(); + assert.strictEqual(vm.runtime.threads.length, 0); + assert.strictEqual(threads.length, 2); + checkIsHatThread(vm, threads[0]); + checkIsHatThread(vm, threads[1]); + assert.ok(threads[0].status === Thread.STATUS_DONE); + assert.ok(threads[1].status === Thread.STATUS_DONE); + done(); }); }); }); @@ -130,13 +127,13 @@ compilerAndInterpreter('edge activated hat thread runs after being added to prev * If the hat doesn't finish evaluating within one frame, it shouldn't be added again * on the next frame. (We skip execution by setting the step time to 0) */ -compilerAndInterpreter('edge activated hat thread not added twice', (t, co) => { +compilerAndInterpreter('edge activated hat thread not added twice', (done, co) => { const vm = new VirtualMachine(); vm.setCompilerOptions(co); vm.attachStorage(makeTestStorage()); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { // Note: don't run vm.start(), we handle calling _step() manually in this test vm.runtime.currentStepTime = 0; vm.clear(); @@ -144,25 +141,25 @@ compilerAndInterpreter('edge activated hat thread not added twice', (t, co) => { vm.setTurboMode(false); vm.loadProject(project).then(() => { - t.equal(vm.runtime.threads.length, 0); + assert.strictEqual(vm.runtime.threads.length, 0); vm.runtime._step(); let doneThreads = vm.runtime._lastStepDoneThreads; - t.equal(vm.runtime.threads.length, 1); - t.equal(doneThreads.length, 0); + assert.strictEqual(vm.runtime.threads.length, 1); + assert.strictEqual(doneThreads.length, 0); const prevThread = vm.runtime.threads[0]; - checkIsHatThread(t, vm, vm.runtime.threads[0]); - t.assert(vm.runtime.threads[0].status === Thread.STATUS_RUNNING); + checkIsHatThread(vm, vm.runtime.threads[0]); + assert.ok(vm.runtime.threads[0].status === Thread.STATUS_RUNNING); // Check that no new threads are added when another step is taken vm.runtime._step(); doneThreads = vm.runtime._lastStepDoneThreads; // There should now be one done hat thread and one new hat thread to run - t.equal(vm.runtime.threads.length, 1); - t.equal(doneThreads.length, 0); - checkIsHatThread(t, vm, vm.runtime.threads[0]); - t.assert(vm.runtime.threads[0] === prevThread); - t.end(); + assert.strictEqual(vm.runtime.threads.length, 1); + assert.strictEqual(doneThreads.length, 0); + checkIsHatThread(vm, vm.runtime.threads[0]); + assert.ok(vm.runtime.threads[0] === prevThread); + done(); }); }); }); @@ -172,7 +169,7 @@ compilerAndInterpreter('edge activated hat thread not added twice', (t, co) => { * Duplicating a sprite should also track duplicated edge activated hat in * runtime's _edgeActivatedHatValues map. */ -compilerAndInterpreter('edge activated hat should trigger for both sprites when sprite is duplicated', (t, co) => { +compilerAndInterpreter('edge activated hat should trigger for both sprites when sprite is duplicated', (done, co) => { // Project that is similar to timer-greater-than-hat.sb2, but has code on the sprite so that // the sprite can be duplicated @@ -184,7 +181,7 @@ compilerAndInterpreter('edge activated hat should trigger for both sprites when vm.attachStorage(makeTestStorage()); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { // Note: don't run vm.start(), we handle calling _step() manually in this test vm.runtime.currentStepTime = 0; vm.clear(); @@ -192,15 +189,15 @@ compilerAndInterpreter('edge activated hat should trigger for both sprites when vm.setTurboMode(false); vm.loadProject(projectWithSprite).then(() => { - t.equal(vm.runtime.threads.length, 0); + assert.strictEqual(vm.runtime.threads.length, 0); vm.runtime._step(); - t.equal(vm.runtime.threads.length, 1); - checkIsHatThread(t, vm, vm.runtime.threads[0]); - t.assert(vm.runtime.threads[0].status === Thread.STATUS_RUNNING); + assert.strictEqual(vm.runtime.threads.length, 1); + checkIsHatThread(vm, vm.runtime.threads[0]); + assert.ok(vm.runtime.threads[0].status === Thread.STATUS_RUNNING); let numTargetEdgeHats = vm.runtime.targets.reduce((val, target) => val + Object.keys(target._edgeActivatedHatValues).length, 0); - t.equal(numTargetEdgeHats, 1); + assert.strictEqual(numTargetEdgeHats, 1); vm.duplicateSprite(vm.runtime.targets[1].id).then(() => { vm.runtime._step(); @@ -208,8 +205,8 @@ compilerAndInterpreter('edge activated hat should trigger for both sprites when // after execute is run on each thread numTargetEdgeHats = vm.runtime.targets.reduce((val, target) => val + Object.keys(target._edgeActivatedHatValues).length, 0); - t.equal(numTargetEdgeHats, 2); - t.end(); + assert.strictEqual(numTargetEdgeHats, 2); + done(); }); }); @@ -220,7 +217,7 @@ compilerAndInterpreter('edge activated hat should trigger for both sprites when * Cloning a sprite should also track cloned edge activated hat separately * runtime's _edgeActivatedHatValues map. */ -compilerAndInterpreter('edge activated hat should trigger for both sprites when sprite is cloned', (t, co) => { +compilerAndInterpreter('edge activated hat should trigger for both sprites when sprite is cloned', (done, co) => { // Project that is similar to loudness-hat-block.sb2, but has code on the sprite so that // the sprite can be duplicated @@ -232,7 +229,7 @@ compilerAndInterpreter('edge activated hat should trigger for both sprites when vm.attachStorage(makeTestStorage()); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { // Note: don't run vm.start(), we handle calling _step() manually in this test vm.runtime.currentStepTime = 0; vm.clear(); @@ -240,18 +237,18 @@ compilerAndInterpreter('edge activated hat should trigger for both sprites when vm.setTurboMode(false); vm.loadProject(projectWithSprite).then(() => { - t.equal(vm.runtime.threads.length, 0); + assert.strictEqual(vm.runtime.threads.length, 0); vm.runtime._step(); - t.equal(vm.runtime.threads.length, 1); - checkIsHatThread(t, vm, vm.runtime.threads[0]); - t.assert(vm.runtime.threads[0].status === Thread.STATUS_RUNNING); + assert.strictEqual(vm.runtime.threads.length, 1); + checkIsHatThread(vm, vm.runtime.threads[0]); + assert.ok(vm.runtime.threads[0].status === Thread.STATUS_RUNNING); // Run execute on the thread to populate the runtime's // _edgeActivatedHatValues object execute(vm.runtime.sequencer, vm.runtime.threads[0]); let numTargetEdgeHats = vm.runtime.targets.reduce((val, target) => val + Object.keys(target._edgeActivatedHatValues).length, 0); - t.equal(numTargetEdgeHats, 1); + assert.strictEqual(numTargetEdgeHats, 1); const cloneTarget = vm.runtime.targets[1].makeClone(); vm.runtime.addTarget(cloneTarget); @@ -262,8 +259,8 @@ compilerAndInterpreter('edge activated hat should trigger for both sprites when vm.runtime.threads.forEach(thread => execute(vm.runtime.sequencer, thread)); numTargetEdgeHats = vm.runtime.targets.reduce((val, target) => val + Object.keys(target._edgeActivatedHatValues).length, 0); - t.equal(numTargetEdgeHats, 2); - t.end(); + assert.strictEqual(numTargetEdgeHats, 2); + done(); }); }); }); @@ -272,13 +269,13 @@ compilerAndInterpreter('edge activated hat should trigger for both sprites when * When adding a stack click thread first, make sure that the edge activated hat thread and * the stack click thread are both pushed and run (despite having the same top block) */ -compilerAndInterpreter('edge activated hat thread does not interrupt stack click thread', (t, co) => { +compilerAndInterpreter('edge activated hat thread does not interrupt stack click thread', (done, co) => { const vm = new VirtualMachine(); vm.setCompilerOptions(co); vm.attachStorage(makeTestStorage()); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { // Note: don't run vm.start(), we handle calling _step() manually in this test vm.runtime.currentStepTime = Runtime.THREAD_STEP_INTERVAL; vm.clear(); @@ -286,14 +283,14 @@ compilerAndInterpreter('edge activated hat thread does not interrupt stack click vm.setTurboMode(false); vm.loadProject(project).then(() => { - t.equal(vm.runtime.threads.length, 0); + assert.strictEqual(vm.runtime.threads.length, 0); vm.runtime._step(); let doneThreads = vm.runtime._lastStepDoneThreads; - t.equal(vm.runtime.threads.length, 0); - t.equal(doneThreads.length, 1); - checkIsHatThread(t, vm, doneThreads[0]); - t.assert(doneThreads[0].status === Thread.STATUS_DONE); + assert.strictEqual(vm.runtime.threads.length, 0); + assert.strictEqual(doneThreads.length, 1); + checkIsHatThread(vm, doneThreads[0]); + assert.ok(doneThreads[0].status === Thread.STATUS_DONE); // Add stack click thread on this hat vm.runtime.toggleScript(doneThreads[0].topBlock, {stackClick: true}); @@ -301,8 +298,8 @@ compilerAndInterpreter('edge activated hat thread does not interrupt stack click // Check that the hat thread is added again when another step is taken vm.runtime._step(); doneThreads = vm.runtime._lastStepDoneThreads; - t.equal(vm.runtime.threads.length, 0); - t.equal(doneThreads.length, 2); + assert.strictEqual(vm.runtime.threads.length, 0); + assert.strictEqual(doneThreads.length, 2); let hatThread; let stackClickThread; if (doneThreads[0].stackClick) { @@ -312,11 +309,11 @@ compilerAndInterpreter('edge activated hat thread does not interrupt stack click stackClickThread = doneThreads[1]; hatThread = doneThreads[0]; } - checkIsHatThread(t, vm, hatThread); - checkIsStackClickThread(t, vm, stackClickThread); - t.assert(doneThreads[0].status === Thread.STATUS_DONE); - t.assert(doneThreads[1].status === Thread.STATUS_DONE); - t.end(); + checkIsHatThread(vm, hatThread); + checkIsStackClickThread(vm, stackClickThread); + assert.ok(doneThreads[0].status === Thread.STATUS_DONE); + assert.ok(doneThreads[1].status === Thread.STATUS_DONE); + done(); }); }); }); @@ -325,13 +322,13 @@ compilerAndInterpreter('edge activated hat thread does not interrupt stack click * When adding the hat thread first, make sure that the edge activated hat thread and * the stack click thread are both pushed and run (despite having the same top block) */ -compilerAndInterpreter('edge activated hat thread does not interrupt stack click thread', (t, co) => { +compilerAndInterpreter('edge activated hat thread does not interrupt stack click thread', (done, co) => { const vm = new VirtualMachine(); vm.setCompilerOptions(co); vm.attachStorage(makeTestStorage()); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { // Note: don't run vm.start(), we handle calling _step() manually in this test vm.runtime.currentStepTime = 0; vm.clear(); @@ -339,14 +336,14 @@ compilerAndInterpreter('edge activated hat thread does not interrupt stack click vm.setTurboMode(false); vm.loadProject(project).then(() => { - t.equal(vm.runtime.threads.length, 0); + assert.strictEqual(vm.runtime.threads.length, 0); vm.runtime._step(); let doneThreads = vm.runtime._lastStepDoneThreads; - t.equal(vm.runtime.threads.length, 1); - t.equal(doneThreads.length, 0); - checkIsHatThread(t, vm, vm.runtime.threads[0]); - t.assert(vm.runtime.threads[0].status === Thread.STATUS_RUNNING); + assert.strictEqual(vm.runtime.threads.length, 1); + assert.strictEqual(doneThreads.length, 0); + checkIsHatThread(vm, vm.runtime.threads[0]); + assert.ok(vm.runtime.threads[0].status === Thread.STATUS_RUNNING); vm.runtime.currentStepTime = Runtime.THREAD_STEP_INTERVAL; @@ -356,8 +353,8 @@ compilerAndInterpreter('edge activated hat thread does not interrupt stack click // Check that the hat thread is added again when another step is taken vm.runtime._step(); doneThreads = vm.runtime._lastStepDoneThreads; - t.equal(vm.runtime.threads.length, 0); - t.equal(doneThreads.length, 2); + assert.strictEqual(vm.runtime.threads.length, 0); + assert.strictEqual(doneThreads.length, 2); let hatThread; let stackClickThread; if (doneThreads[0].stackClick) { @@ -367,11 +364,11 @@ compilerAndInterpreter('edge activated hat thread does not interrupt stack click stackClickThread = doneThreads[1]; hatThread = doneThreads[0]; } - checkIsHatThread(t, vm, hatThread); - checkIsStackClickThread(t, vm, stackClickThread); - t.assert(doneThreads[0].status === Thread.STATUS_DONE); - t.assert(doneThreads[1].status === Thread.STATUS_DONE); - t.end(); + checkIsHatThread(vm, hatThread); + checkIsStackClickThread(vm, stackClickThread); + assert.ok(doneThreads[0].status === Thread.STATUS_DONE); + assert.ok(doneThreads[1].status === Thread.STATUS_DONE); + done(); }); }); }); diff --git a/test/integration/import-sb.js b/test/integration/import-sb.js index b58afa06..05983340 100644 --- a/test/integration/import-sb.js +++ b/test/integration/import-sb.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,20 +8,20 @@ const VirtualMachine = require('../../src/index'); const uri = path.resolve(__dirname, '../fixtures/single_sound.sb'); const project = readFileToBuffer(uri); -test('default', t => { +test('default', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length === 0); + assert.ok(threads.length === 0); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); @@ -33,7 +34,7 @@ test('default', t => { // Check that the sound has the correct md5 // This md5 was obtained from the asset server - t.equal(firstSound.md5, 'edb9713dedbe9a2e05c09e0540182ef1.wav'); + assert.strictEqual(firstSound.md5, 'edb9713dedbe9a2e05c09e0540182ef1.wav'); // After two seconds, get playground data and stop setTimeout(() => { diff --git a/test/integration/import-sb2-from-object.js b/test/integration/import-sb2-from-object.js index 63b7ae9b..e3414b8f 100644 --- a/test/integration/import-sb2-from-object.js +++ b/test/integration/import-sb2-from-object.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const extractProjectJson = require('../fixtures/readProjectFile').extractProjectJson; const VirtualMachine = require('../../src/index'); @@ -7,20 +8,20 @@ const VirtualMachine = require('../../src/index'); const uri = path.resolve(__dirname, '../fixtures/default.sb2'); const project = extractProjectJson(uri); -test('default', t => { +test('default', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length === 0); + assert.ok(threads.length === 0); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/import_nested_sb2.js b/test/integration/import_nested_sb2.js index 38104669..df6f258a 100644 --- a/test/integration/import_nested_sb2.js +++ b/test/integration/import_nested_sb2.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const extractProjectJson = require('../fixtures/readProjectFile').extractProjectJson; @@ -7,12 +8,11 @@ const renderedTarget = require('../../src/sprites/rendered-target'); const runtime = require('../../src/engine/runtime'); const sb2 = require('../../src/serialization/sb2'); -test('spec', t => { - t.type(sb2.deserialize, 'function'); - t.end(); +test('spec', () => { + assert.strictEqual(typeof sb2.deserialize, 'function'); }); -test('nested default/*', t => { +test('nested default/*', async () => { // Get SB2 JSON (string) const uri = path.resolve(__dirname, '../fixtures/default_nested.sb2'); const json = extractProjectJson(uri, 'default'); @@ -20,33 +20,31 @@ test('nested default/*', t => { // Create runtime instance & load SB2 into it const rt = new runtime(); rt.attachStorage(makeTestStorage()); - sb2.deserialize(json, rt).then(({targets}) => { - // Test - t.type(json, 'object'); - t.type(rt, 'object'); - t.type(targets, 'object'); + const {targets} = await sb2.deserialize(json, rt); + // Test + assert.strictEqual(typeof json, 'object'); + assert.strictEqual(typeof rt, 'object'); + assert.strictEqual(typeof targets, 'object'); - t.ok(targets[0] instanceof renderedTarget); - t.type(targets[0].id, 'string'); - t.type(targets[0].blocks, 'object'); - t.type(targets[0].variables, 'object'); - t.type(targets[0].comments, 'object'); + assert.ok(targets[0] instanceof renderedTarget); + assert.strictEqual(typeof targets[0].id, 'string'); + assert.strictEqual(typeof targets[0].blocks, 'object'); + assert.strictEqual(typeof targets[0].variables, 'object'); + assert.strictEqual(typeof targets[0].comments, 'object'); - t.equal(targets[0].isOriginal, true); - t.equal(targets[0].currentCostume, 0); - t.equal(targets[0].isOriginal, true); - t.equal(targets[0].isStage, true); + assert.strictEqual(targets[0].isOriginal, true); + assert.strictEqual(targets[0].currentCostume, 0); + assert.strictEqual(targets[0].isOriginal, true); + assert.strictEqual(targets[0].isStage, true); - t.ok(targets[1] instanceof renderedTarget); - t.type(targets[1].id, 'string'); - t.type(targets[1].blocks, 'object'); - t.type(targets[1].variables, 'object'); - t.type(targets[1].comments, 'object'); + assert.ok(targets[1] instanceof renderedTarget); + assert.strictEqual(typeof targets[1].id, 'string'); + assert.strictEqual(typeof targets[1].blocks, 'object'); + assert.strictEqual(typeof targets[1].variables, 'object'); + assert.strictEqual(typeof targets[1].comments, 'object'); - t.equal(targets[1].isOriginal, true); - t.equal(targets[1].currentCostume, 0); - t.equal(targets[1].isOriginal, true); - t.equal(targets[1].isStage, false); - t.end(); - }); + assert.strictEqual(targets[1].isOriginal, true); + assert.strictEqual(targets[1].currentCostume, 0); + assert.strictEqual(targets[1].isOriginal, true); + assert.strictEqual(targets[1].isStage, false); }); diff --git a/test/integration/import_sb2.js b/test/integration/import_sb2.js index fb6fe850..2c6ff823 100644 --- a/test/integration/import_sb2.js +++ b/test/integration/import_sb2.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const extractProjectJson = require('../fixtures/readProjectFile').extractProjectJson; @@ -7,12 +8,11 @@ const renderedTarget = require('../../src/sprites/rendered-target'); const runtime = require('../../src/engine/runtime'); const sb2 = require('../../src/serialization/sb2'); -test('spec', t => { - t.type(sb2.deserialize, 'function'); - t.end(); +test('spec', () => { + assert.strictEqual(typeof sb2.deserialize, 'function'); }); -test('default', t => { +test('default', async () => { // Get SB2 JSON (string) const uri = path.resolve(__dirname, '../fixtures/default.sb2'); const json = extractProjectJson(uri); @@ -20,33 +20,31 @@ test('default', t => { // Create runtime instance & load SB2 into it const rt = new runtime(); rt.attachStorage(makeTestStorage()); - sb2.deserialize(json, rt).then(({targets}) => { - // Test - t.type(json, 'object'); - t.type(rt, 'object'); - t.type(targets, 'object'); + const {targets} = await sb2.deserialize(json, rt); + // Test + assert.strictEqual(typeof json, 'object'); + assert.strictEqual(typeof rt, 'object'); + assert.strictEqual(typeof targets, 'object'); - t.ok(targets[0] instanceof renderedTarget); - t.type(targets[0].id, 'string'); - t.type(targets[0].blocks, 'object'); - t.type(targets[0].variables, 'object'); - t.type(targets[0].comments, 'object'); + assert.ok(targets[0] instanceof renderedTarget); + assert.strictEqual(typeof targets[0].id, 'string'); + assert.strictEqual(typeof targets[0].blocks, 'object'); + assert.strictEqual(typeof targets[0].variables, 'object'); + assert.strictEqual(typeof targets[0].comments, 'object'); - t.equal(targets[0].isOriginal, true); - t.equal(targets[0].currentCostume, 0); - t.equal(targets[0].isOriginal, true); - t.equal(targets[0].isStage, true); + assert.strictEqual(targets[0].isOriginal, true); + assert.strictEqual(targets[0].currentCostume, 0); + assert.strictEqual(targets[0].isOriginal, true); + assert.strictEqual(targets[0].isStage, true); - t.ok(targets[1] instanceof renderedTarget); - t.type(targets[1].id, 'string'); - t.type(targets[1].blocks, 'object'); - t.type(targets[1].variables, 'object'); - t.type(targets[1].comments, 'object'); + assert.ok(targets[1] instanceof renderedTarget); + assert.strictEqual(typeof targets[1].id, 'string'); + assert.strictEqual(typeof targets[1].blocks, 'object'); + assert.strictEqual(typeof targets[1].variables, 'object'); + assert.strictEqual(typeof targets[1].comments, 'object'); - t.equal(targets[1].isOriginal, true); - t.equal(targets[1].currentCostume, 0); - t.equal(targets[1].isOriginal, true); - t.equal(targets[1].isStage, false); - t.end(); - }); + assert.strictEqual(targets[1].isOriginal, true); + assert.strictEqual(targets[1].currentCostume, 0); + assert.strictEqual(targets[1].isOriginal, true); + assert.strictEqual(targets[1].isStage, false); }); diff --git a/test/integration/internal-extension.js b/test/integration/internal-extension.js index 51540e18..1460282e 100644 --- a/test/integration/internal-extension.js +++ b/test/integration/internal-extension.js @@ -1,4 +1,5 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const Worker = require('tiny-worker'); const BlockType = require('../../src/extension-support/block-type'); @@ -51,22 +52,22 @@ class TestInternalExtension { } } -test('internal extension', t => { +test('internal extension', () => { const vm = new VirtualMachine(); const extension = new TestInternalExtension(); - t.ok(extension.status.constructorCalled); + assert.ok(extension.status.constructorCalled); - t.notOk(extension.status.getInfoCalled); + assert.ok(!extension.status.getInfoCalled); vm.extensionManager._registerInternalExtension(extension); - t.ok(extension.status.getInfoCalled); + assert.ok(extension.status.getInfoCalled); const func = vm.runtime.getOpcodeFunction('testInternalExtension_go'); - t.type(func, 'function'); + assert.strictEqual(typeof func, 'function'); - t.notOk(extension.status.goCalled); + assert.ok(!extension.status.goCalled); const goBlockInfo = func(); - t.ok(extension.status.goCalled); + assert.ok(extension.status.goCalled); // The 'go' block returns its own blockInfo. Make sure it matches the expected info. // Note that the extension parser fills in missing fields so there are more fields here than in `getInfo`. @@ -79,41 +80,38 @@ test('internal extension', t => { terminal: false, text: 'go' }; - t.deepEqual(goBlockInfo, expectedBlockInfo); + assert.deepEqual(goBlockInfo, expectedBlockInfo); // There should be 2 menus - one is an array, one is the function to call. - t.equal(vm.runtime._blockInfo[0].menus.length, 2); + assert.strictEqual(vm.runtime._blockInfo[0].menus.length, 2); // First menu has 3 items. - t.equal( + assert.strictEqual( vm.runtime._blockInfo[0].menus[0].json.args0[0].options.length, 3); // Second menu is a dynamic menu and therefore should be a function. - t.type( - vm.runtime._blockInfo[0].menus[1].json.args0[0].options, 'function'); - - t.end(); + assert.strictEqual(typeof vm.runtime._blockInfo[0].menus[1].json.args0[0].options, 'function'); }); -test('load sync', t => { +test('load sync', () => { const vm = new VirtualMachine(); vm.extensionManager.loadExtensionIdSync('coreExample'); - t.ok(vm.extensionManager.isExtensionLoaded('coreExample')); + assert.ok(vm.extensionManager.isExtensionLoaded('coreExample')); - t.equal(vm.runtime._blockInfo.length, 1); + assert.strictEqual(vm.runtime._blockInfo.length, 1); // blocks should be an array of two items: a button pseudo-block and a reporter block. - t.equal(vm.runtime._blockInfo[0].blocks.length, 3); - t.type(vm.runtime._blockInfo[0].blocks[0].info, 'object'); - t.type(vm.runtime._blockInfo[0].blocks[0].info.func, 'MAKE_A_VARIABLE'); - t.equal(vm.runtime._blockInfo[0].blocks[0].info.blockType, 'button'); - t.type(vm.runtime._blockInfo[0].blocks[1].info, 'object'); - t.equal(vm.runtime._blockInfo[0].blocks[1].info.opcode, 'exampleOpcode'); - t.equal(vm.runtime._blockInfo[0].blocks[1].info.blockType, 'reporter'); - t.type(vm.runtime._blockInfo[0].blocks[2].info, 'object'); - t.equal(vm.runtime._blockInfo[0].blocks[2].info.opcode, 'exampleWithInlineImage'); - t.equal(vm.runtime._blockInfo[0].blocks[2].info.blockType, 'command'); + assert.strictEqual(vm.runtime._blockInfo[0].blocks.length, 3); + assert.strictEqual(typeof vm.runtime._blockInfo[0].blocks[0].info, 'object'); + assert.strictEqual(vm.runtime._blockInfo[0].blocks[0].info.func, 'MAKE_A_VARIABLE'); + assert.strictEqual(vm.runtime._blockInfo[0].blocks[0].info.blockType, 'button'); + assert.strictEqual(typeof vm.runtime._blockInfo[0].blocks[1].info, 'object'); + assert.strictEqual(vm.runtime._blockInfo[0].blocks[1].info.opcode, 'exampleOpcode'); + assert.strictEqual(vm.runtime._blockInfo[0].blocks[1].info.blockType, 'reporter'); + assert.strictEqual(typeof vm.runtime._blockInfo[0].blocks[2].info, 'object'); + assert.strictEqual(vm.runtime._blockInfo[0].blocks[2].info.opcode, 'exampleWithInlineImage'); + assert.strictEqual(vm.runtime._blockInfo[0].blocks[2].info.blockType, 'command'); // Test the opcode function - t.equal(vm.runtime._blockInfo[0].blocks[1].info.func(), 'no stage yet'); + assert.strictEqual(vm.runtime._blockInfo[0].blocks[1].info.func(), 'no stage yet'); const sprite = new Sprite(null, vm.runtime); sprite.name = 'Stage'; @@ -121,7 +119,5 @@ test('load sync', t => { stage.isStage = true; vm.runtime.targets = [stage]; - t.equal(vm.runtime._blockInfo[0].blocks[1].info.func(), 'Stage'); - - t.end(); + assert.strictEqual(vm.runtime._blockInfo[0].blocks[1].info.func(), 'Stage'); }); diff --git a/test/integration/list-monitor-rename.js b/test/integration/list-monitor-rename.js index 286f861a..97e9f514 100644 --- a/test/integration/list-monitor-rename.js +++ b/test/integration/list-monitor-rename.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,7 +8,7 @@ const VirtualMachine = require('../../src/index'); const projectUri = path.resolve(__dirname, '../fixtures/list-monitor-rename.sb3'); const project = readFileToBuffer(projectUri); -test('importing sb3 project with incorrect list monitor name', t => { +test('importing sb3 project with incorrect list monitor name', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -24,19 +25,19 @@ test('importing sb3 project with incorrect list monitor name', t => { const monitorRecord = vm.runtime._monitorState.get(listId); const monitorBlock = vm.runtime.monitorBlocks.getBlock(listId); - t.equal(monitorRecord.opcode, 'data_listcontents'); + assert.strictEqual(monitorRecord.opcode, 'data_listcontents'); // The list name should be properly renamed - t.equal(monitorRecord.params.LIST, renamedListName); - t.equal(monitorBlock.fields.LIST.value, renamedListName); + assert.strictEqual(monitorRecord.params.LIST, renamedListName); + assert.strictEqual(monitorBlock.fields.LIST.value, renamedListName); } vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/load-extensions.js b/test/integration/load-extensions.js index dfddb8de..ad52a2fc 100644 --- a/test/integration/load-extensions.js +++ b/test/integration/load-extensions.js @@ -1,6 +1,6 @@ const path = require('path'); -const tap = require('tap'); -const {test} = tap; +const {test} = require('node:test'); +const assert = require('node:assert'); const fs = require('fs'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const dispatch = require('../../src/dispatch/central-dispatch'); @@ -27,21 +27,17 @@ test('Load external extensions', async t => { const uri = path.resolve(__dirname, `../fixtures/load-extensions/confirm-load/${file}`); const project = readFileToBuffer(uri); - await t.test('Confirm expected extension is installed in example sb2 and sb3 projects', extTest => { - vm.loadProject(project) - .then(() => { - extTest.ok(vm.extensionManager.isExtensionLoaded(ext)); - extTest.end(); - }); + await t.test('Confirm expected extension is installed in example sb2 and sb3 projects', async () => { + await vm.loadProject(project); + assert.ok(vm.extensionManager.isExtensionLoaded(ext)); }); } stopVideoLoop(vm); vm.quit(); - t.end(); }); -test('Load video sensing extension and video properties', async t => { +test('Load video sensing extension and video properties', async () => { const vm = new VirtualMachine(); // An array of test projects and their expected video state values const testProjects = [ @@ -66,18 +62,17 @@ test('Load video sensing extension and video properties', async t => { const stage = vm.runtime.getTargetForStage(); - t.ok(vm.extensionManager.isExtensionLoaded('videoSensing')); + assert.ok(vm.extensionManager.isExtensionLoaded('videoSensing')); // Check that the stage target has the video state values we expect // based on the test project files, then check that the video io device // has the expected state as well - t.equal(stage.videoState, project.videoState); - t.equal(vm.runtime.ioDevices.video.mirror, project.mirror); - t.equal(stage.videoTransparency, project.videoTransparency); - t.equal(vm.runtime.ioDevices.video._ghost, project.videoTransparency); + assert.strictEqual(stage.videoState, project.videoState); + assert.strictEqual(vm.runtime.ioDevices.video.mirror, project.mirror); + assert.strictEqual(stage.videoTransparency, project.videoTransparency); + assert.strictEqual(vm.runtime.ioDevices.video._ghost, project.videoTransparency); } stopVideoLoop(vm); vm.quit(); - t.end(); }); diff --git a/test/integration/load-sb2-originally-sb1-without-backdrop-image.js b/test/integration/load-sb2-originally-sb1-without-backdrop-image.js index d1211e24..bd467800 100644 --- a/test/integration/load-sb2-originally-sb1-without-backdrop-image.js +++ b/test/integration/load-sb2-originally-sb1-without-backdrop-image.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; @@ -10,25 +11,25 @@ const project = readFileToBuffer(projectUri); const vm = new VirtualMachine(); -test('sb2 project (originally from Scratch 1.4) with missing backdrop image should load', t => { +test('sb2 project (originally from Scratch 1.4) with missing backdrop image should load', (t, done) => { vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length === 0); + assert.ok(threads.length === 0); vm.quit(); - t.end(); + done(); }); vm.start(); vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.loadProject(project).then(() => { - t.equal(vm.runtime.targets.length, 2); // stage and default sprite + assert.strictEqual(vm.runtime.targets.length, 2); // stage and default sprite vm.greenFlag(); diff --git a/test/integration/looks.js b/test/integration/looks.js index 869c7fb0..38e5eae3 100644 --- a/test/integration/looks.js +++ b/test/integration/looks.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,20 +8,20 @@ const VirtualMachine = require('../../src/index'); const uri = path.resolve(__dirname, '../fixtures/looks.sb2'); const project = readFileToBuffer(uri); -test('looks', t => { +test('looks', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length === 0); + assert.ok(threads.length === 0); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/monitor-threads-run-every-frame.js b/test/integration/monitor-threads-run-every-frame.js index 089beafd..de60ae4f 100644 --- a/test/integration/monitor-threads-run-every-frame.js +++ b/test/integration/monitor-threads-run-every-frame.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -9,23 +10,23 @@ const Runtime = require('../../src/engine/runtime'); const projectUri = path.resolve(__dirname, '../fixtures/timer-monitor.sb3'); const project = readFileToBuffer(projectUri); -const checkMonitorThreadPresent = (t, threads) => { - t.equal(threads.length, 1); +const checkMonitorThreadPresent = threads => { + assert.strictEqual(threads.length, 1); const monitorThread = threads[0]; - t.equal(monitorThread.stackClick, false); - t.equal(monitorThread.updateMonitor, true); - t.equal(monitorThread.topBlock.toString(), 'timer'); + assert.strictEqual(monitorThread.stackClick, false); + assert.strictEqual(monitorThread.updateMonitor, true); + assert.strictEqual(monitorThread.topBlock.toString(), 'timer'); }; /** * Creates a monitor and then checks if it gets run every frame. */ -test('monitor thread runs every frame', t => { +test('monitor thread runs every frame', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { // Note: don't run vm.start(), we handle calling _step() manually in this test vm.runtime.currentStepTime = Runtime.THREAD_STEP_INTERVAL; vm.clear(); @@ -33,23 +34,23 @@ test('monitor thread runs every frame', t => { vm.setTurboMode(false); vm.loadProject(project).then(() => { - t.equal(vm.runtime.threads.length, 0); + assert.strictEqual(vm.runtime.threads.length, 0); vm.runtime._step(); let doneThreads = vm.runtime._lastStepDoneThreads; - t.equal(vm.runtime.threads.length, 0); - t.equal(doneThreads.length, 1); - checkMonitorThreadPresent(t, doneThreads); - t.assert(doneThreads[0].status === Thread.STATUS_DONE); + assert.strictEqual(vm.runtime.threads.length, 0); + assert.strictEqual(doneThreads.length, 1); + checkMonitorThreadPresent(doneThreads); + assert.ok(doneThreads[0].status === Thread.STATUS_DONE); // Check that both are added again when another step is taken vm.runtime._step(); doneThreads = vm.runtime._lastStepDoneThreads; - t.equal(vm.runtime.threads.length, 0); - t.equal(doneThreads.length, 1); - checkMonitorThreadPresent(t, doneThreads); - t.assert(doneThreads[0].status === Thread.STATUS_DONE); - t.end(); + assert.strictEqual(vm.runtime.threads.length, 0); + assert.strictEqual(doneThreads.length, 1); + checkMonitorThreadPresent(doneThreads); + assert.ok(doneThreads[0].status === Thread.STATUS_DONE); + done(); }); }); }); @@ -58,12 +59,12 @@ test('monitor thread runs every frame', t => { * If the monitor doesn't finish evaluating within one frame, it shouldn't be added again * on the next frame. (We skip execution by setting the step time to 0) */ -test('monitor thread not added twice', t => { +test('monitor thread not added twice', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { // Note: don't run vm.start(), we handle calling _step() manually in this test vm.runtime.currentStepTime = 0; @@ -72,24 +73,24 @@ test('monitor thread not added twice', t => { vm.setTurboMode(false); vm.loadProject(project).then(() => { - t.equal(vm.runtime.threads.length, 0); + assert.strictEqual(vm.runtime.threads.length, 0); vm.runtime._step(); let doneThreads = vm.runtime._lastStepDoneThreads; - t.equal(vm.runtime.threads.length, 1); - t.equal(doneThreads.length, 0); - checkMonitorThreadPresent(t, vm.runtime.threads); - t.assert(vm.runtime.threads[0].status === Thread.STATUS_RUNNING); + assert.strictEqual(vm.runtime.threads.length, 1); + assert.strictEqual(doneThreads.length, 0); + checkMonitorThreadPresent(vm.runtime.threads); + assert.ok(vm.runtime.threads[0].status === Thread.STATUS_RUNNING); const prevThread = vm.runtime.threads[0]; // Check that both are added again when another step is taken vm.runtime._step(); doneThreads = vm.runtime._lastStepDoneThreads; - t.equal(vm.runtime.threads.length, 1); - t.equal(doneThreads.length, 0); - checkMonitorThreadPresent(t, vm.runtime.threads); - t.equal(vm.runtime.threads[0], prevThread); - t.end(); + assert.strictEqual(vm.runtime.threads.length, 1); + assert.strictEqual(doneThreads.length, 0); + checkMonitorThreadPresent(vm.runtime.threads); + assert.strictEqual(vm.runtime.threads[0], prevThread); + done(); }); }); }); diff --git a/test/integration/monitors_sb2.js b/test/integration/monitors_sb2.js index e98ac40f..de2f9998 100644 --- a/test/integration/monitors_sb2.js +++ b/test/integration/monitors_sb2.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,7 +8,7 @@ const VirtualMachine = require('../../src/index'); const projectUri = path.resolve(__dirname, '../fixtures/monitors.sb2'); const project = readFileToBuffer(projectUri); -test('importing sb2 project with monitors', t => { +test('importing sb2 project with monitors', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -16,16 +17,16 @@ test('importing sb2 project with monitors', t => { const threads = JSON.parse(e.threads); // All monitors should create threads that finish during the step and // are revoved from runtime.threads. - t.equal(threads.length, 0); + assert.strictEqual(threads.length, 0); // we care that the last step updated the right number of monitors // we don't care whether the last step ran other threads or not const lastStepUpdatedMonitorThreads = vm.runtime._lastStepDoneThreads.filter(thread => thread.updateMonitor); - t.equal(lastStepUpdatedMonitorThreads.length, 8); + assert.strictEqual(lastStepUpdatedMonitorThreads.length, 8); // There should be one additional hidden monitor that is in the monitorState but // does not start a thread. - t.equal(vm.runtime._monitorState.size, 9); + assert.strictEqual(vm.runtime._monitorState.size, 9); const stage = vm.runtime.targets[0]; const target = vm.runtime.targets[1]; @@ -33,55 +34,55 @@ test('importing sb2 project with monitors', t => { // Global variable named "global" is a slider let variableId = Object.keys(stage.variables).filter(k => stage.variables[k].name === 'global')[0]; let monitorRecord = vm.runtime._monitorState.get(variableId); - t.equal(monitorRecord.opcode, 'data_variable'); - t.equal(monitorRecord.mode, 'slider'); - t.equal(monitorRecord.sliderMin, -200); // Make sure these are imported for sliders. - t.equal(monitorRecord.sliderMax, 30); - t.equal(monitorRecord.isDiscrete, false); - t.equal(monitorRecord.x, 5); // These are imported for all monitors, just check once. - t.equal(monitorRecord.y, 59); - t.equal(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.opcode, 'data_variable'); + assert.strictEqual(monitorRecord.mode, 'slider'); + assert.strictEqual(monitorRecord.sliderMin, -200); // Make sure these are imported for sliders. + assert.strictEqual(monitorRecord.sliderMax, 30); + assert.strictEqual(monitorRecord.isDiscrete, false); + assert.strictEqual(monitorRecord.x, 5); // These are imported for all monitors, just check once. + assert.strictEqual(monitorRecord.y, 59); + assert.strictEqual(monitorRecord.visible, true); // Global variable named "global list" is a list variableId = Object.keys(stage.variables).filter(k => stage.variables[k].name === 'global list')[0]; monitorRecord = vm.runtime._monitorState.get(variableId); - t.equal(monitorRecord.opcode, 'data_listcontents'); - t.equal(monitorRecord.mode, 'list'); - t.equal(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.opcode, 'data_listcontents'); + assert.strictEqual(monitorRecord.mode, 'list'); + assert.strictEqual(monitorRecord.visible, true); // Local variable named "local" is hidden variableId = Object.keys(target.variables).filter(k => target.variables[k].name === 'local')[0]; monitorRecord = vm.runtime._monitorState.get(variableId); - t.equal(monitorRecord.opcode, 'data_variable'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, false); + assert.strictEqual(monitorRecord.opcode, 'data_variable'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, false); // Local list named "local list" is visible variableId = Object.keys(target.variables).filter(k => target.variables[k].name === 'local list')[0]; monitorRecord = vm.runtime._monitorState.get(variableId); - t.equal(monitorRecord.opcode, 'data_listcontents'); - t.equal(monitorRecord.mode, 'list'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.width, 106); // Make sure these are imported from lists. - t.equal(monitorRecord.height, 206); + assert.strictEqual(monitorRecord.opcode, 'data_listcontents'); + assert.strictEqual(monitorRecord.mode, 'list'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.width, 106); // Make sure these are imported from lists. + assert.strictEqual(monitorRecord.height, 206); // Backdrop name monitor is visible, not sprite specific // should get imported with id that references the name parameter // via '_name' at the end since the 3.0 block has a dropdown. monitorRecord = vm.runtime._monitorState.get('backdropnumbername_name'); - t.equal(monitorRecord.opcode, 'looks_backdropnumbername'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); + assert.strictEqual(monitorRecord.opcode, 'looks_backdropnumbername'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); // x position monitor is in large mode, specific to sprite 1 monitorRecord = vm.runtime._monitorState.get(`${target.id}_xposition`); - t.equal(monitorRecord.opcode, 'motion_xposition'); - t.equal(monitorRecord.mode, 'large'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, 'Sprite1'); - t.equal(monitorRecord.targetId, target.id); + assert.strictEqual(monitorRecord.opcode, 'motion_xposition'); + assert.strictEqual(monitorRecord.mode, 'large'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, 'Sprite1'); + assert.strictEqual(monitorRecord.targetId, target.id); let monitorId; @@ -94,40 +95,40 @@ test('importing sb2 project with monitors', t => { monitorId = 'current_date'; monitorRecord = vm.runtime._monitorState.get(monitorId); - t.equal(monitorRecord.opcode, 'sensing_current'); + assert.strictEqual(monitorRecord.opcode, 'sensing_current'); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorBlock.fields.CURRENTMENU.value, 'DATE'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); + assert.strictEqual(monitorBlock.fields.CURRENTMENU.value, 'DATE'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); monitorId = 'current_minute'; monitorRecord = vm.runtime._monitorState.get(monitorId); - t.equal(monitorRecord.opcode, 'sensing_current'); + assert.strictEqual(monitorRecord.opcode, 'sensing_current'); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorBlock.fields.CURRENTMENU.value, 'MINUTE'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); + assert.strictEqual(monitorBlock.fields.CURRENTMENU.value, 'MINUTE'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); monitorId = 'current_dayofweek'; monitorRecord = vm.runtime._monitorState.get(monitorId); - t.equal(monitorRecord.opcode, 'sensing_current'); + assert.strictEqual(monitorRecord.opcode, 'sensing_current'); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorBlock.fields.CURRENTMENU.value, 'DAYOFWEEK'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); + assert.strictEqual(monitorBlock.fields.CURRENTMENU.value, 'DAYOFWEEK'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/monitors_sb2_to_sb3.js b/test/integration/monitors_sb2_to_sb3.js index 77b67bce..1d016c49 100644 --- a/test/integration/monitors_sb2_to_sb3.js +++ b/test/integration/monitors_sb2_to_sb3.js @@ -1,12 +1,13 @@ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); let vm; -tap.beforeEach(() => { +beforeEach(() => { const projectUri = path.resolve(__dirname, '../fixtures/monitors.sb2'); const project = readFileToBuffer(projectUri); @@ -21,9 +22,8 @@ tap.beforeEach(() => { return vm.loadProject(project); }); -const test = tap.test; -test('saving and loading sb2 project with monitors preserves sliderMin and sliderMax', t => { +test('saving and loading sb2 project with monitors preserves sliderMin and sliderMax', (t, done) => { vm.on('playgroundData', e /* eslint-disable-line no-unused-vars */ => { // TODO related to above TODO, comment these back in when we figure out @@ -41,7 +41,7 @@ test('saving and loading sb2 project with monitors preserves sliderMin and slide // There should be one additional hidden monitor that is in the monitorState but // does not start a thread. - t.equal(vm.runtime._monitorState.size, 9); + assert.strictEqual(vm.runtime._monitorState.size, 9); const stage = vm.runtime.targets[0]; const target = vm.runtime.targets[1]; @@ -50,55 +50,55 @@ test('saving and loading sb2 project with monitors preserves sliderMin and slide let variableId = Object.keys(stage.variables).filter(k => stage.variables[k].name === 'global')[0]; // Used later when checking save and load of slider min/max let monitorRecord = vm.runtime._monitorState.get(variableId); - t.equal(monitorRecord.opcode, 'data_variable'); - t.equal(monitorRecord.mode, 'slider'); - t.equal(monitorRecord.sliderMin, -200); // Make sure these are imported for sliders. - t.equal(monitorRecord.sliderMax, 30); - t.equal(monitorRecord.isDiscrete, false); - t.equal(monitorRecord.x, 5); // These are imported for all monitors, just check once. - t.equal(monitorRecord.y, 59); - t.equal(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.opcode, 'data_variable'); + assert.strictEqual(monitorRecord.mode, 'slider'); + assert.strictEqual(monitorRecord.sliderMin, -200); // Make sure these are imported for sliders. + assert.strictEqual(monitorRecord.sliderMax, 30); + assert.strictEqual(monitorRecord.isDiscrete, false); + assert.strictEqual(monitorRecord.x, 5); // These are imported for all monitors, just check once. + assert.strictEqual(monitorRecord.y, 59); + assert.strictEqual(monitorRecord.visible, true); // Global variable named "global list" is a list variableId = Object.keys(stage.variables).filter(k => stage.variables[k].name === 'global list')[0]; monitorRecord = vm.runtime._monitorState.get(variableId); - t.equal(monitorRecord.opcode, 'data_listcontents'); - t.equal(monitorRecord.mode, 'list'); - t.equal(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.opcode, 'data_listcontents'); + assert.strictEqual(monitorRecord.mode, 'list'); + assert.strictEqual(monitorRecord.visible, true); // Local variable named "local" is hidden variableId = Object.keys(target.variables).filter(k => target.variables[k].name === 'local')[0]; monitorRecord = vm.runtime._monitorState.get(variableId); - t.equal(monitorRecord.opcode, 'data_variable'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, false); + assert.strictEqual(monitorRecord.opcode, 'data_variable'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, false); // Local list named "local list" is visible variableId = Object.keys(target.variables).filter(k => target.variables[k].name === 'local list')[0]; monitorRecord = vm.runtime._monitorState.get(variableId); - t.equal(monitorRecord.opcode, 'data_listcontents'); - t.equal(monitorRecord.mode, 'list'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.width, 106); // Make sure these are imported from lists. - t.equal(monitorRecord.height, 206); + assert.strictEqual(monitorRecord.opcode, 'data_listcontents'); + assert.strictEqual(monitorRecord.mode, 'list'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.width, 106); // Make sure these are imported from lists. + assert.strictEqual(monitorRecord.height, 206); // Backdrop name monitor is visible, not sprite specific // should get imported with id that references the name parameter // via '_name' at the end since the 3.0 block has a dropdown. monitorRecord = vm.runtime._monitorState.get('backdropnumbername_name'); - t.equal(monitorRecord.opcode, 'looks_backdropnumbername'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); + assert.strictEqual(monitorRecord.opcode, 'looks_backdropnumbername'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); // x position monitor is in large mode, specific to sprite 1 monitorRecord = vm.runtime._monitorState.get(`${target.id}_xposition`); - t.equal(monitorRecord.opcode, 'motion_xposition'); - t.equal(monitorRecord.mode, 'large'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, 'Sprite1'); - t.equal(monitorRecord.targetId, target.id); + assert.strictEqual(monitorRecord.opcode, 'motion_xposition'); + assert.strictEqual(monitorRecord.mode, 'large'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, 'Sprite1'); + assert.strictEqual(monitorRecord.targetId, target.id); let monitorId; @@ -111,45 +111,44 @@ test('saving and loading sb2 project with monitors preserves sliderMin and slide monitorId = 'current_date'; monitorRecord = vm.runtime._monitorState.get(monitorId); - t.equal(monitorRecord.opcode, 'sensing_current'); + assert.strictEqual(monitorRecord.opcode, 'sensing_current'); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorBlock.fields.CURRENTMENU.value, 'DATE'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); + assert.strictEqual(monitorBlock.fields.CURRENTMENU.value, 'DATE'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); monitorId = 'current_minute'; monitorRecord = vm.runtime._monitorState.get(monitorId); - t.equal(monitorRecord.opcode, 'sensing_current'); + assert.strictEqual(monitorRecord.opcode, 'sensing_current'); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorBlock.fields.CURRENTMENU.value, 'MINUTE'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); + assert.strictEqual(monitorBlock.fields.CURRENTMENU.value, 'MINUTE'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); monitorId = 'current_dayofweek'; monitorRecord = vm.runtime._monitorState.get(monitorId); - t.equal(monitorRecord.opcode, 'sensing_current'); + assert.strictEqual(monitorRecord.opcode, 'sensing_current'); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorBlock.fields.CURRENTMENU.value, 'DAYOFWEEK'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); + assert.strictEqual(monitorBlock.fields.CURRENTMENU.value, 'DAYOFWEEK'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(async () => { const sb3ProjectJson = vm.toJSON(); - return vm.loadProject(sb3ProjectJson).then(() => { - setTimeout(() => { - vm.getPlaygroundData(); - vm.stopAll(); - }, 100); - }); + await vm.loadProject(sb3ProjectJson); + setTimeout(() => { + vm.getPlaygroundData(); + vm.stopAll(); + }, 100); }); }); diff --git a/test/integration/monitors_sb3.js b/test/integration/monitors_sb3.js index f688d79c..f899f3e4 100644 --- a/test/integration/monitors_sb3.js +++ b/test/integration/monitors_sb3.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -8,7 +9,7 @@ const Variable = require('../../src/engine/variable'); const projectUri = path.resolve(__dirname, '../fixtures/monitors.sb3'); const project = readFileToBuffer(projectUri); -test('importing sb3 project with monitors', t => { +test('importing sb3 project with monitors', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -17,16 +18,16 @@ test('importing sb3 project with monitors', t => { const threads = JSON.parse(e.threads); // All monitors should create threads that finish during the step and // are revoved from runtime.threads. - t.equal(threads.length, 0); + assert.strictEqual(threads.length, 0); // we care that the last step updated the right number of monitors // we don't care whether the last step ran other threads or not const lastStepUpdatedMonitorThreads = vm.runtime._lastStepDoneThreads.filter(thread => thread.updateMonitor); - t.equal(lastStepUpdatedMonitorThreads.length, 17); + assert.strictEqual(lastStepUpdatedMonitorThreads.length, 17); // There should be one additional hidden monitor that is in the monitorState but // does not start a thread. - t.equal(vm.runtime._monitorState.size, 18); + assert.strictEqual(vm.runtime._monitorState.size, 18); const stage = vm.runtime.targets[0]; const shirtSprite = vm.runtime.targets[1]; @@ -36,94 +37,96 @@ test('importing sb3 project with monitors', t => { let variableId = Object.keys(stage.variables).filter(k => stage.variables[k].name === 'my variable')[0]; let monitorRecord = vm.runtime._monitorState.get(variableId); let monitorBlock = vm.runtime.monitorBlocks.getBlock(variableId); - t.equal(monitorRecord.opcode, 'data_variable'); - t.equal(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.opcode, 'data_variable'); + assert.strictEqual(monitorRecord.mode, 'default'); // The following few properties are imported for all monitors, just check once. - t.equal(monitorRecord.sliderMin, 0); - t.equal(monitorRecord.sliderMax, 100); - t.equal(monitorRecord.isDiscrete, true); // The default if not present - t.equal(monitorRecord.x, 10); - t.equal(monitorRecord.y, 62); + assert.strictEqual(monitorRecord.sliderMin, 0); + assert.strictEqual(monitorRecord.sliderMax, 100); + assert.strictEqual(monitorRecord.isDiscrete, true); // The default if not present + assert.strictEqual(monitorRecord.x, 10); + assert.strictEqual(monitorRecord.y, 62); // Height and width are only used for list monitors and should default to 0 // for all other monitors - t.equal(monitorRecord.width, 0); - t.equal(monitorRecord.height, 0); - t.equal(monitorRecord.visible, true); - t.type(monitorRecord.params, 'object'); + assert.strictEqual(monitorRecord.width, 0); + assert.strictEqual(monitorRecord.height, 0); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(typeof monitorRecord.params, 'object'); // The variable name should be stored in the monitor params - t.equal(monitorRecord.params.VARIABLE, 'my variable'); + assert.strictEqual(monitorRecord.params.VARIABLE, 'my variable'); // Test that the monitor block and its fields were constructed correctly - t.equal(monitorBlock.fields.VARIABLE.value, 'my variable'); - t.equal(monitorBlock.fields.VARIABLE.name, 'VARIABLE'); - t.equal(monitorBlock.fields.VARIABLE.id, variableId); - t.equal(monitorBlock.fields.VARIABLE.variableType, Variable.SCALAR_TYPE); + assert.strictEqual(monitorBlock.fields.VARIABLE.value, 'my variable'); + assert.strictEqual(monitorBlock.fields.VARIABLE.name, 'VARIABLE'); + assert.strictEqual(monitorBlock.fields.VARIABLE.id, variableId); + assert.strictEqual(monitorBlock.fields.VARIABLE.variableType, Variable.SCALAR_TYPE); // There is a global variable named 'secret_slide' which has a hidden monitor variableId = Object.keys(stage.variables).filter(k => stage.variables[k].name === 'secret_slide')[0]; monitorRecord = vm.runtime._monitorState.get(variableId); monitorBlock = vm.runtime.monitorBlocks.getBlock(variableId); - t.equal(monitorRecord.opcode, 'data_variable'); - t.equal(monitorRecord.mode, 'slider'); - t.equal(monitorRecord.visible, false); - t.equal(monitorRecord.sliderMin, 0); - t.equal(monitorRecord.sliderMax, 100); - t.type(monitorRecord.params, 'object'); - t.equal(monitorRecord.params.VARIABLE, 'secret_slide'); + assert.strictEqual(monitorRecord.opcode, 'data_variable'); + assert.strictEqual(monitorRecord.mode, 'slider'); + assert.strictEqual(monitorRecord.visible, false); + assert.strictEqual(monitorRecord.sliderMin, 0); + assert.strictEqual(monitorRecord.sliderMax, 100); + assert.strictEqual(typeof monitorRecord.params, 'object'); + assert.strictEqual(monitorRecord.params.VARIABLE, 'secret_slide'); // Test that the monitor block and its fields were constructed correctly - t.equal(monitorBlock.fields.VARIABLE.value, 'secret_slide'); - t.equal(monitorBlock.fields.VARIABLE.name, 'VARIABLE'); - t.equal(monitorBlock.fields.VARIABLE.id, variableId); - t.equal(monitorBlock.fields.VARIABLE.variableType, Variable.SCALAR_TYPE); + assert.strictEqual(monitorBlock.fields.VARIABLE.value, 'secret_slide'); + assert.strictEqual(monitorBlock.fields.VARIABLE.name, 'VARIABLE'); + assert.strictEqual(monitorBlock.fields.VARIABLE.id, variableId); + assert.strictEqual(monitorBlock.fields.VARIABLE.variableType, Variable.SCALAR_TYPE); // Shirt sprite has a local list named "fashion" variableId = Object.keys(shirtSprite.variables).filter(k => shirtSprite.variables[k].name === 'fashion')[0]; monitorRecord = vm.runtime._monitorState.get(variableId); monitorBlock = vm.runtime.monitorBlocks.getBlock(variableId); - t.equal(monitorRecord.opcode, 'data_listcontents'); - t.equal(monitorRecord.mode, 'list'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.height, 122); - t.equal(monitorRecord.width, 104); - t.type(monitorRecord.params, 'object'); - t.equal(monitorRecord.params.LIST, 'fashion'); // The list name should be stored in the monitor params + assert.strictEqual(monitorRecord.opcode, 'data_listcontents'); + assert.strictEqual(monitorRecord.mode, 'list'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.height, 122); + assert.strictEqual(monitorRecord.width, 104); + assert.strictEqual(typeof monitorRecord.params, 'object'); + // The list name should be stored in the monitor params + assert.strictEqual(monitorRecord.params.LIST, 'fashion'); // Test that the monitor block and its fields were constructed correctly - t.equal(monitorBlock.fields.LIST.value, 'fashion'); - t.equal(monitorBlock.fields.LIST.name, 'LIST'); - t.equal(monitorBlock.fields.LIST.id, variableId); - t.equal(monitorBlock.fields.LIST.variableType, Variable.LIST_TYPE); + assert.strictEqual(monitorBlock.fields.LIST.value, 'fashion'); + assert.strictEqual(monitorBlock.fields.LIST.name, 'LIST'); + assert.strictEqual(monitorBlock.fields.LIST.id, variableId); + assert.strictEqual(monitorBlock.fields.LIST.variableType, Variable.LIST_TYPE); // Shirt sprite has a local variable named "tee" variableId = Object.keys(shirtSprite.variables).filter(k => shirtSprite.variables[k].name === 'tee')[0]; monitorRecord = vm.runtime._monitorState.get(variableId); monitorBlock = vm.runtime.monitorBlocks.getBlock(variableId); - t.equal(monitorRecord.opcode, 'data_variable'); - t.equal(monitorRecord.mode, 'slider'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.sliderMin, 0); - t.equal(monitorRecord.sliderMax, 100); - t.type(monitorRecord.params, 'object'); - t.equal(monitorRecord.params.VARIABLE, 'tee'); + assert.strictEqual(monitorRecord.opcode, 'data_variable'); + assert.strictEqual(monitorRecord.mode, 'slider'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.sliderMin, 0); + assert.strictEqual(monitorRecord.sliderMax, 100); + assert.strictEqual(typeof monitorRecord.params, 'object'); + assert.strictEqual(monitorRecord.params.VARIABLE, 'tee'); // Test that the monitor block and its fields were constructed correctly - t.equal(monitorBlock.fields.VARIABLE.value, 'tee'); - t.equal(monitorBlock.fields.VARIABLE.name, 'VARIABLE'); - t.equal(monitorBlock.fields.VARIABLE.id, variableId); - t.equal(monitorBlock.fields.VARIABLE.variableType, Variable.SCALAR_TYPE); + assert.strictEqual(monitorBlock.fields.VARIABLE.value, 'tee'); + assert.strictEqual(monitorBlock.fields.VARIABLE.name, 'VARIABLE'); + assert.strictEqual(monitorBlock.fields.VARIABLE.id, variableId); + assert.strictEqual(monitorBlock.fields.VARIABLE.variableType, Variable.SCALAR_TYPE); // Heart sprite has a local list named "hearty" variableId = Object.keys(heartSprite.variables).filter(k => heartSprite.variables[k].name === 'hearty')[0]; monitorRecord = vm.runtime._monitorState.get(variableId); monitorBlock = vm.runtime.monitorBlocks.getBlock(variableId); - t.equal(monitorRecord.opcode, 'data_variable'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.type(monitorRecord.params, 'object'); - t.equal(monitorRecord.params.VARIABLE, 'hearty'); // The variable name should be stored in the monitor params + assert.strictEqual(monitorRecord.opcode, 'data_variable'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(typeof monitorRecord.params, 'object'); + // The variable name should be stored in the monitor params + assert.strictEqual(monitorRecord.params.VARIABLE, 'hearty'); // Test that the monitor block and its fields were constructed correctly - t.equal(monitorBlock.fields.VARIABLE.value, 'hearty'); - t.equal(monitorBlock.fields.VARIABLE.name, 'VARIABLE'); - t.equal(monitorBlock.fields.VARIABLE.id, variableId); - t.equal(monitorBlock.fields.VARIABLE.variableType, Variable.SCALAR_TYPE); + assert.strictEqual(monitorBlock.fields.VARIABLE.value, 'hearty'); + assert.strictEqual(monitorBlock.fields.VARIABLE.name, 'VARIABLE'); + assert.strictEqual(monitorBlock.fields.VARIABLE.id, variableId); + assert.strictEqual(monitorBlock.fields.VARIABLE.variableType, Variable.SCALAR_TYPE); // Backdrop name monitor is visible, not sprite specific // should get imported with id that references the name parameter @@ -131,13 +134,13 @@ test('importing sb3 project with monitors', t => { let monitorId = 'backdropnumbername_name'; monitorRecord = vm.runtime._monitorState.get(monitorId); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorRecord.opcode, 'looks_backdropnumbername'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); + assert.strictEqual(monitorRecord.opcode, 'looks_backdropnumbername'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); // Test that the monitor block and its fields were constructed correctly - t.equal(monitorBlock.fields.NUMBER_NAME.value, 'name'); + assert.strictEqual(monitorBlock.fields.NUMBER_NAME.value, 'name'); // Backdrop name monitor is visible, not sprite specific // should get imported with id that references the name parameter @@ -145,52 +148,52 @@ test('importing sb3 project with monitors', t => { monitorId = 'backdropnumbername_number'; monitorRecord = vm.runtime._monitorState.get(monitorId); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorRecord.opcode, 'looks_backdropnumbername'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); + assert.strictEqual(monitorRecord.opcode, 'looks_backdropnumbername'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); // Test that the monitor block and its fields were constructed correctly - t.equal(monitorBlock.fields.NUMBER_NAME.value, 'number'); + assert.strictEqual(monitorBlock.fields.NUMBER_NAME.value, 'number'); // x position monitor is in large mode, specific to shirt sprite monitorId = `${shirtSprite.id}_xposition`; monitorRecord = vm.runtime._monitorState.get(monitorId); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorRecord.opcode, 'motion_xposition'); - t.equal(monitorRecord.mode, 'large'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, 'Shirt-T'); - t.equal(monitorRecord.targetId, shirtSprite.id); + assert.strictEqual(monitorRecord.opcode, 'motion_xposition'); + assert.strictEqual(monitorRecord.mode, 'large'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, 'Shirt-T'); + assert.strictEqual(monitorRecord.targetId, shirtSprite.id); // y position monitor is in large mode, specific to shirt sprite monitorId = `${shirtSprite.id}_yposition`; monitorRecord = vm.runtime._monitorState.get(monitorId); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorRecord.opcode, 'motion_yposition'); - t.equal(monitorRecord.mode, 'large'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, 'Shirt-T'); - t.equal(monitorRecord.targetId, shirtSprite.id); + assert.strictEqual(monitorRecord.opcode, 'motion_yposition'); + assert.strictEqual(monitorRecord.mode, 'large'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, 'Shirt-T'); + assert.strictEqual(monitorRecord.targetId, shirtSprite.id); // direction monitor is in large mode, specific to shirt sprite monitorId = `${shirtSprite.id}_direction`; monitorRecord = vm.runtime._monitorState.get(monitorId); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorRecord.opcode, 'motion_direction'); - t.equal(monitorRecord.mode, 'large'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, 'Shirt-T'); - t.equal(monitorRecord.targetId, shirtSprite.id); + assert.strictEqual(monitorRecord.opcode, 'motion_direction'); + assert.strictEqual(monitorRecord.mode, 'large'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, 'Shirt-T'); + assert.strictEqual(monitorRecord.targetId, shirtSprite.id); monitorId = `${shirtSprite.id}_size`; monitorRecord = vm.runtime._monitorState.get(monitorId); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorRecord.opcode, 'looks_size'); - t.equal(monitorRecord.mode, 'large'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, 'Shirt-T'); - t.equal(monitorRecord.targetId, shirtSprite.id); + assert.strictEqual(monitorRecord.opcode, 'looks_size'); + assert.strictEqual(monitorRecord.mode, 'large'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, 'Shirt-T'); + assert.strictEqual(monitorRecord.targetId, shirtSprite.id); // The monitor IDs for the sensing_current block should be unique // to the parameter that is selected on the block being monitored. @@ -198,61 +201,61 @@ test('importing sb3 project with monitors', t => { // though the field value on the block is uppercase. monitorId = 'current_date'; monitorRecord = vm.runtime._monitorState.get(monitorId); - t.equal(monitorRecord.opcode, 'sensing_current'); + assert.strictEqual(monitorRecord.opcode, 'sensing_current'); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorBlock.fields.CURRENTMENU.value, 'DATE'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); + assert.strictEqual(monitorBlock.fields.CURRENTMENU.value, 'DATE'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); monitorId = 'current_year'; monitorRecord = vm.runtime._monitorState.get(monitorId); - t.equal(monitorRecord.opcode, 'sensing_current'); + assert.strictEqual(monitorRecord.opcode, 'sensing_current'); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorBlock.fields.CURRENTMENU.value, 'YEAR'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); + assert.strictEqual(monitorBlock.fields.CURRENTMENU.value, 'YEAR'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); monitorId = 'current_month'; monitorRecord = vm.runtime._monitorState.get(monitorId); - t.equal(monitorRecord.opcode, 'sensing_current'); + assert.strictEqual(monitorRecord.opcode, 'sensing_current'); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorBlock.fields.CURRENTMENU.value, 'MONTH'); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); + assert.strictEqual(monitorBlock.fields.CURRENTMENU.value, 'MONTH'); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); // Extension Monitors monitorId = 'music_getTempo'; monitorRecord = vm.runtime._monitorState.get(monitorId); - t.equal(monitorRecord.opcode, 'music_getTempo'); + assert.strictEqual(monitorRecord.opcode, 'music_getTempo'); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); - t.equal(vm.extensionManager.isExtensionLoaded('music'), true); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); + assert.strictEqual(vm.extensionManager.isExtensionLoaded('music'), true); monitorId = 'ev3_getDistance'; monitorRecord = vm.runtime._monitorState.get(monitorId); - t.equal(monitorRecord.opcode, 'ev3_getDistance'); + assert.strictEqual(monitorRecord.opcode, 'ev3_getDistance'); monitorBlock = vm.runtime.monitorBlocks.getBlock(monitorId); - t.equal(monitorRecord.mode, 'default'); - t.equal(monitorRecord.visible, true); - t.equal(monitorRecord.spriteName, null); - t.equal(monitorRecord.targetId, null); - t.equal(vm.extensionManager.isExtensionLoaded('ev3'), true); + assert.strictEqual(monitorRecord.mode, 'default'); + assert.strictEqual(monitorRecord.visible, true); + assert.strictEqual(monitorRecord.spriteName, null); + assert.strictEqual(monitorRecord.targetId, null); + assert.strictEqual(vm.extensionManager.isExtensionLoaded('ev3'), true); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/motion.js b/test/integration/motion.js index 6d69bb9b..b3820a49 100644 --- a/test/integration/motion.js +++ b/test/integration/motion.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,20 +8,20 @@ const VirtualMachine = require('../../src/index'); const uri = path.resolve(__dirname, '../fixtures/motion.sb2'); const project = readFileToBuffer(uri); -test('motion', t => { +test('motion', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length > 0); + assert.ok(threads.length > 0); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/offline-custom-assets.js b/test/integration/offline-custom-assets.js index 50bd9c00..4ee5be83 100644 --- a/test/integration/offline-custom-assets.js +++ b/test/integration/offline-custom-assets.js @@ -6,7 +6,8 @@ */ const path = require('path'); const fs = require('fs'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const AdmZip = require('adm-zip'); const ScratchStorage = require('scratch-storage'); const VirtualMachine = require('../../src/index'); @@ -23,7 +24,7 @@ const costumeData = new Uint8Array(costume); const sound = projectZip.readFile('0.wav'); const soundData = new Uint8Array(sound); -test('offline-custom-assets', t => { +test('offline-custom-assets', (t, done) => { const vm = new VirtualMachine(); // Use a test storage here that does not have any web sources added to it. const testStorage = new ScratchStorage(); @@ -32,13 +33,13 @@ test('offline-custom-assets', t => { // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length === 0); + assert.ok(threads.length === 0); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); @@ -46,23 +47,23 @@ test('offline-custom-assets', t => { vm.loadProject(project).then(() => { // Verify initial state - t.equals(vm.runtime.targets.length, 2); + assert.strictEqual(vm.runtime.targets.length, 2); const costumes = vm.runtime.targets[1].getCostumes(); - t.equals(costumes.length, 1); + assert.strictEqual(costumes.length, 1); const customCostume = costumes[0]; - t.equals(customCostume.name, 'A_Test_Costume'); + assert.strictEqual(customCostume.name, 'A_Test_Costume'); const storedCostume = customCostume.asset; - t.type(storedCostume, 'object'); - t.deepEquals(storedCostume.data, costumeData); + assert.strictEqual(typeof storedCostume, 'object'); + assert.deepEqual(storedCostume.data, costumeData); const sounds = vm.runtime.targets[1].sprite.sounds; - t.equals(sounds.length, 1); + assert.strictEqual(sounds.length, 1); const customSound = sounds[0]; - t.equals(customSound.name, 'A_Test_Recording'); + assert.strictEqual(customSound.name, 'A_Test_Recording'); const storedSound = customSound.asset; - t.type(storedSound, 'object'); - t.deepEquals(storedSound.data, soundData); + assert.strictEqual(typeof storedSound, 'object'); + assert.deepEqual(storedSound.data, soundData); vm.greenFlag(); diff --git a/test/integration/pen.js b/test/integration/pen.js index e2821e24..574da26b 100644 --- a/test/integration/pen.js +++ b/test/integration/pen.js @@ -1,6 +1,7 @@ const Worker = require('tiny-worker'); const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const Scratch3PenBlocks = require('../../src/extensions/scratch3_pen/index.js'); const VirtualMachine = require('../../src/index'); @@ -15,7 +16,7 @@ const project = readFileToBuffer(uri); // By default Central Dispatch works with the Worker class built into the browser. Tell it to use TinyWorker instead. dispatch.workerClass = Worker; -test('pen', t => { +test('pen', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -25,7 +26,7 @@ test('pen', t => { const catSprite = vm.runtime.targets[1].sprite; const [originalCat, cloneCat] = catSprite.clones; - t.notStrictEqual(originalCat, cloneCat); + assert.notStrictEqual(originalCat, cloneCat); /** @type {PenState} */ const originalPenState = originalCat.getCustomState(Scratch3PenBlocks.STATE_KEY); @@ -33,16 +34,16 @@ test('pen', t => { /** @type {PenState} */ const clonePenState = cloneCat.getCustomState(Scratch3PenBlocks.STATE_KEY); - t.notStrictEqual(originalPenState, clonePenState); - t.equal(originalPenState.penAttributes.diameter, 51); - t.equal(clonePenState.penAttributes.diameter, 42); + assert.notStrictEqual(originalPenState, clonePenState); + assert.strictEqual(originalPenState.penAttributes.diameter, 51); + assert.strictEqual(clonePenState.penAttributes.diameter, 42); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/procedure.js b/test/integration/procedure.js index a3264fae..fc293a3e 100644 --- a/test/integration/procedure.js +++ b/test/integration/procedure.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,20 +8,20 @@ const VirtualMachine = require('../../src/index'); const uri = path.resolve(__dirname, '../fixtures/procedure.sb2'); const project = readFileToBuffer(uri); -test('procedure', t => { +test('procedure', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length === 0); + assert.ok(threads.length === 0); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/runId.js b/test/integration/runId.js index cdc006b2..06b1505b 100644 --- a/test/integration/runId.js +++ b/test/integration/runId.js @@ -1,6 +1,7 @@ const Worker = require('tiny-worker'); const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const VirtualMachine = require('../../src/index'); const dispatch = require('../../src/dispatch/central-dispatch'); @@ -15,7 +16,7 @@ const project = readFileToBuffer(uri); // By default Central Dispatch works with the Worker class built into the browser. Tell it to use TinyWorker instead. dispatch.workerClass = Worker; -test('runId', async t => { +test('runId', async () => { const guidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; const isGuid = data => guidRegex.test(data); @@ -25,7 +26,7 @@ test('runId', async t => { const runIdLog = []; const pushRunId = () => { const runId = storage.scratchFetch.getMetadata(storage.scratchFetch.RequestMetadata.RunId); - t.ok(isGuid(runId), 'Run IDs should always be a properly-formatted GUID', {runId}); + assert.ok(isGuid(runId), 'Run IDs should always be a properly-formatted GUID', {runId}); runIdLog.push(runId); }; @@ -64,10 +65,9 @@ test('runId', async t => { for (let i = 0; i < runIdLog.length - 1; ++i) { for (let j = i + 1; j < runIdLog.length; ++j) { - t.notSame(runIdLog[i], runIdLog[j], 'Run IDs should always be unique', {runIdLog}); + assert.notDeepEqual(runIdLog[i], runIdLog[j], 'Run IDs should always be unique'); } } vm.quit(); - t.end(); }); diff --git a/test/integration/running_project_changed_state.js b/test/integration/running_project_changed_state.js index ea18f878..2c9eb182 100644 --- a/test/integration/running_project_changed_state.js +++ b/test/integration/running_project_changed_state.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,7 +8,7 @@ const VirtualMachine = require('../../src/index'); const uri = path.resolve(__dirname, '../fixtures/looks.sb2'); const project = readFileToBuffer(uri); -test('Running project should not emit project changed event', t => { +test('Running project should not emit project changed event', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -18,13 +19,13 @@ test('Running project should not emit project changed event', t => { // Evaluate playground data and exit vm.on('playgroundData', () => { - t.equal(projectChanged, false); + assert.strictEqual(projectChanged, false); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/saythink-and-wait.js b/test/integration/saythink-and-wait.js index e902d3a9..65a28083 100644 --- a/test/integration/saythink-and-wait.js +++ b/test/integration/saythink-and-wait.js @@ -1,6 +1,7 @@ const Worker = require('tiny-worker'); const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -12,12 +13,12 @@ const project = readFileToBuffer(uri); // By default Central Dispatch works with the Worker class built into the browser. Tell it to use TinyWorker instead. dispatch.workerClass = Worker; -test('say/think and wait', t => { +test('say/think and wait', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); @@ -30,7 +31,7 @@ test('say/think and wait', t => { setTimeout(() => { vm.stopAll(); vm.quit(); - t.end(); + done(); }, 2000); }); }); diff --git a/test/integration/sb2-import-extension-monitors.js b/test/integration/sb2-import-extension-monitors.js index 75dad344..9099eae8 100644 --- a/test/integration/sb2-import-extension-monitors.js +++ b/test/integration/sb2-import-extension-monitors.js @@ -1,6 +1,6 @@ const path = require('path'); -const tap = require('tap'); -const test = tap.test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const {readFileToBuffer, extractProjectJson} = require('../fixtures/readProjectFile'); const VirtualMachine = require('../../src/index'); @@ -25,7 +25,7 @@ const visibleTempoMonitorProjectUri = path.resolve( __dirname, '../fixtures/visible-tempo-monitor-no-other-music-blocks.sb2'); const visibleTempoMonitorProject = readFileToBuffer(visibleTempoMonitorProjectUri); -test('loading sb2 project with invisible video monitor should not load monitor or extension', t => { +test('loading sb2 project with invisible video monitor should not load monitor or extension', async () => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -34,15 +34,13 @@ test('loading sb2 project with invisible video monitor should not load monitor o vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(invisibleVideoMonitorProject).then(() => { - t.equal(vm.extensionManager.isExtensionLoaded('videoSensing'), false); - t.equal(vm.runtime._monitorState.size, 0); - vm.quit(); - t.end(); - }); + await vm.loadProject(invisibleVideoMonitorProject); + assert.strictEqual(vm.extensionManager.isExtensionLoaded('videoSensing'), false); + assert.strictEqual(vm.runtime._monitorState.size, 0); + vm.quit(); }); -test('loading sb2 project with visible video monitor should not load extension', t => { +test('loading sb2 project with visible video monitor should not load extension', async () => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -51,30 +49,26 @@ test('loading sb2 project with visible video monitor should not load extension', vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(visibleVideoMonitorProject).then(() => { - t.equal(vm.extensionManager.isExtensionLoaded('videoSensing'), false); - t.equal(vm.runtime._monitorState.size, 0); - vm.quit(); - t.end(); - }); + await vm.loadProject(visibleVideoMonitorProject); + assert.strictEqual(vm.extensionManager.isExtensionLoaded('videoSensing'), false); + assert.strictEqual(vm.runtime._monitorState.size, 0); + vm.quit(); }); // This test looks a little different than the rest because loading a project with // the video sensing block requires a mock renderer and other setup, so instead // we are just using deserialize to test what we need instead -test('sb2 project with video sensing blocks and monitor should load extension but not monitor', t => { +test('sb2 project with video sensing blocks and monitor should load extension but not monitor', async () => { const vm = new VirtualMachine(); - sb2.deserialize(visibleVideoMonitorAndBlocksProject, vm.runtime).then(project => { - // Extension loads but monitor does not - project.extensions.extensionIDs.has('videoSensing'); - // Non-core extension monitors haven't been added to the runtime - t.equal(vm.runtime._monitorState.size, 0); - t.end(); - }); + const project = await sb2.deserialize(visibleVideoMonitorAndBlocksProject, vm.runtime); + // Extension loads but monitor does not + assert.ok(project.extensions.extensionIDs.has('videoSensing')); + // Non-core extension monitors haven't been added to the runtime + assert.strictEqual(vm.runtime._monitorState.size, 0); }); -test('sb2 project with invisible music monitor should not load monitor or extension', t => { +test('sb2 project with invisible music monitor should not load monitor or extension', async () => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -83,15 +77,13 @@ test('sb2 project with invisible music monitor should not load monitor or extens vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(invisibleTempoMonitorProject).then(() => { - t.equal(vm.extensionManager.isExtensionLoaded('music'), false); - t.equal(vm.runtime._monitorState.size, 0); - vm.quit(); - t.end(); - }); + await vm.loadProject(invisibleTempoMonitorProject); + assert.strictEqual(vm.extensionManager.isExtensionLoaded('music'), false); + assert.strictEqual(vm.runtime._monitorState.size, 0); + vm.quit(); }); -test('sb2 project with visible music monitor should load monitor and extension', t => { +test('sb2 project with visible music monitor should load monitor and extension', async () => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -100,12 +92,10 @@ test('sb2 project with visible music monitor should load monitor and extension', vm.clear(); vm.setCompatibilityMode(false); vm.setTurboMode(false); - vm.loadProject(visibleTempoMonitorProject).then(() => { - t.equal(vm.extensionManager.isExtensionLoaded('music'), true); - t.equal(vm.runtime._monitorState.size, 1); - t.equal(vm.runtime._monitorState.has('music_getTempo'), true); - t.equal(vm.runtime._monitorState.get('music_getTempo').visible, true); - vm.quit(); - t.end(); - }); + await vm.loadProject(visibleTempoMonitorProject); + assert.strictEqual(vm.extensionManager.isExtensionLoaded('music'), true); + assert.strictEqual(vm.runtime._monitorState.size, 1); + assert.strictEqual(vm.runtime._monitorState.has('music_getTempo'), true); + assert.strictEqual(vm.runtime._monitorState.get('music_getTempo').visible, true); + vm.quit(); }); diff --git a/test/integration/sb2_corrupted_png.js b/test/integration/sb2_corrupted_png.js index 17c1d695..5bfccd66 100644 --- a/test/integration/sb2_corrupted_png.js +++ b/test/integration/sb2_corrupted_png.js @@ -7,7 +7,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const md5 = require('js-md5'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); @@ -54,9 +55,8 @@ global.document = { let vm; let defaultBitmapAssetId; -tap.setTimeout(30000); -tap.beforeEach(() => { +beforeEach(() => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -69,59 +69,52 @@ tap.beforeEach(() => { return vm.loadProject(project); }); -const test = tap.test; - -test('load sb2 project with corrupted bitmap costume file', t => { - t.equal(vm.runtime.targets.length, 2); +test('load sb2 project with corrupted bitmap costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 2); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const greenGuySprite = vm.runtime.targets[1]; - t.equal(greenGuySprite.getName(), 'GreenGuy'); - t.equal(greenGuySprite.getCostumes().length, 1); + assert.strictEqual(greenGuySprite.getName(), 'GreenGuy'); + assert.strictEqual(greenGuySprite.getCostumes().length, 1); const corruptedCostume = greenGuySprite.getCostumes()[0]; - t.equal(corruptedCostume.name, 'GreenGuy'); - t.equal(corruptedCostume.assetId, defaultBitmapAssetId); - t.equal(corruptedCostume.dataFormat, 'png'); + assert.strictEqual(corruptedCostume.name, 'GreenGuy'); + assert.strictEqual(corruptedCostume.assetId, defaultBitmapAssetId); + assert.strictEqual(corruptedCostume.dataFormat, 'png'); // Runtime should have info about broken asset - t.ok(corruptedCostume.broken); - t.equal(corruptedCostume.broken.assetId, brokenCostumeMd5); + assert.ok(corruptedCostume.broken); + assert.strictEqual(corruptedCostume.broken.assetId, brokenCostumeMd5); // Verify that we saved the original asset data - t.equal(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); - - t.end(); + assert.strictEqual(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); }); -test('load and then save project with corrupted bitmap costume file', t => { +test('load and then save project with corrupted bitmap costume file', () => { const resavedProject = JSON.parse(vm.toJSON()); - t.equal(resavedProject.targets.length, 2); + assert.strictEqual(resavedProject.targets.length, 2); const stage = resavedProject.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const greenGuySprite = resavedProject.targets[1]; - t.equal(greenGuySprite.name, 'GreenGuy'); - t.equal(greenGuySprite.costumes.length, 1); + assert.strictEqual(greenGuySprite.name, 'GreenGuy'); + assert.strictEqual(greenGuySprite.costumes.length, 1); const corruptedCostume = greenGuySprite.costumes[0]; - t.equal(corruptedCostume.name, 'GreenGuy'); + assert.strictEqual(corruptedCostume.name, 'GreenGuy'); // Resaved project costume should have the metadata that corresponds to the original broken costume - t.equal(corruptedCostume.assetId, brokenCostumeMd5); - t.equal(corruptedCostume.dataFormat, 'png'); + assert.strictEqual(corruptedCostume.assetId, brokenCostumeMd5); + assert.strictEqual(corruptedCostume.dataFormat, 'png'); // Test that we didn't save any data about the costume being broken - t.notOk(corruptedCostume.broken); - - t.end(); + assert.ok(!corruptedCostume.broken); }); -test('serializeCostume saves orignal broken costume', t => { +test('serializeCostume saves orignal broken costume', () => { const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[1].id); - t.equal(costumeDescs.length, 1); + assert.strictEqual(costumeDescs.length, 1); const costume = costumeDescs[0]; - t.equal(costume.fileName, `${brokenCostumeMd5}.png`); - t.equal(md5(costume.fileContent), brokenCostumeMd5); - t.end(); + assert.strictEqual(costume.fileName, `${brokenCostumeMd5}.png`); + assert.strictEqual(md5(costume.fileContent), brokenCostumeMd5); }); diff --git a/test/integration/sb2_corrupted_svg.js b/test/integration/sb2_corrupted_svg.js index 5ad71fa1..072d57fb 100644 --- a/test/integration/sb2_corrupted_svg.js +++ b/test/integration/sb2_corrupted_svg.js @@ -7,7 +7,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const md5 = require('js-md5'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); @@ -47,7 +48,7 @@ global.document = { let vm; let defaultVectorAssetId; -tap.beforeEach(() => { +beforeEach(() => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -69,59 +70,52 @@ tap.beforeEach(() => { return vm.loadProject(project); }); -const test = tap.test; - -test('load sb2 project with corrupted vector costume file', t => { - t.equal(vm.runtime.targets.length, 2); +test('load sb2 project with corrupted vector costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 2); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const blueGuySprite = vm.runtime.targets[1]; - t.equal(blueGuySprite.getName(), 'Blue Guy'); - t.equal(blueGuySprite.getCostumes().length, 1); + assert.strictEqual(blueGuySprite.getName(), 'Blue Guy'); + assert.strictEqual(blueGuySprite.getCostumes().length, 1); const corruptedCostume = blueGuySprite.getCostumes()[0]; - t.equal(corruptedCostume.name, 'Blue Guy 2'); - t.equal(corruptedCostume.assetId, defaultVectorAssetId); - t.equal(corruptedCostume.dataFormat, 'svg'); + assert.strictEqual(corruptedCostume.name, 'Blue Guy 2'); + assert.strictEqual(corruptedCostume.assetId, defaultVectorAssetId); + assert.strictEqual(corruptedCostume.dataFormat, 'svg'); // Runtime should have info about broken asset - t.ok(corruptedCostume.broken); - t.equal(corruptedCostume.broken.assetId, brokenCostumeMd5); + assert.ok(corruptedCostume.broken); + assert.strictEqual(corruptedCostume.broken.assetId, brokenCostumeMd5); // Verify that we saved the original asset data - t.equal(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); - - t.end(); + assert.strictEqual(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); }); -test('load and then save project with corrupted vector costume file', t => { +test('load and then save project with corrupted vector costume file', () => { const resavedProject = JSON.parse(vm.toJSON()); - t.equal(resavedProject.targets.length, 2); + assert.strictEqual(resavedProject.targets.length, 2); const stage = resavedProject.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const blueGuySprite = resavedProject.targets[1]; - t.equal(blueGuySprite.name, 'Blue Guy'); - t.equal(blueGuySprite.costumes.length, 1); + assert.strictEqual(blueGuySprite.name, 'Blue Guy'); + assert.strictEqual(blueGuySprite.costumes.length, 1); const corruptedCostume = blueGuySprite.costumes[0]; - t.equal(corruptedCostume.name, 'Blue Guy 2'); + assert.strictEqual(corruptedCostume.name, 'Blue Guy 2'); // Resaved project costume should have the metadata that corresponds to the original broken costume - t.equal(corruptedCostume.assetId, brokenCostumeMd5); - t.equal(corruptedCostume.dataFormat, 'svg'); + assert.strictEqual(corruptedCostume.assetId, brokenCostumeMd5); + assert.strictEqual(corruptedCostume.dataFormat, 'svg'); // Test that we didn't save any data about the costume being broken - t.notOk(corruptedCostume.broken); - - t.end(); + assert.ok(!corruptedCostume.broken); }); -test('serializeCostume saves orignal broken costume', t => { +test('serializeCostume saves orignal broken costume', () => { const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[1].id); - t.equal(costumeDescs.length, 1); + assert.strictEqual(costumeDescs.length, 1); const costume = costumeDescs[0]; - t.equal(costume.fileName, `${brokenCostumeMd5}.svg`); - t.equal(md5(costume.fileContent), brokenCostumeMd5); - t.end(); + assert.strictEqual(costume.fileName, `${brokenCostumeMd5}.svg`); + assert.strictEqual(md5(costume.fileContent), brokenCostumeMd5); }); diff --git a/test/integration/sb2_missing_png.js b/test/integration/sb2_missing_png.js index 8c1870d8..5bbede59 100644 --- a/test/integration/sb2_missing_png.js +++ b/test/integration/sb2_missing_png.js @@ -7,7 +7,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); const FakeBitmapAdapter = require('../fixtures/fake-bitmap-adapter'); @@ -41,9 +42,7 @@ global.document = { let vm; -tap.setTimeout(30000); - -tap.beforeEach(() => { +beforeEach(() => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -54,59 +53,51 @@ tap.beforeEach(() => { return vm.loadProject(project); }); -const test = tap.test; - -test('loading sb2 project with missing bitmap costume file', t => { - t.equal(vm.runtime.targets.length, 2); +test('loading sb2 project with missing bitmap costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 2); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const greenGuySprite = vm.runtime.targets[1]; - t.equal(greenGuySprite.getName(), 'GreenGuy'); - t.equal(greenGuySprite.getCostumes().length, 1); + assert.strictEqual(greenGuySprite.getName(), 'GreenGuy'); + assert.strictEqual(greenGuySprite.getCostumes().length, 1); const missingCostume = greenGuySprite.getCostumes()[0]; - t.equal(missingCostume.name, 'GreenGuy'); + assert.strictEqual(missingCostume.name, 'GreenGuy'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data const defaultVectorAssetId = vm.runtime.storage.defaultAssetId.ImageBitmap; - t.equal(missingCostume.assetId, defaultVectorAssetId); - t.equal(missingCostume.dataFormat, 'png'); + assert.strictEqual(missingCostume.assetId, defaultVectorAssetId); + assert.strictEqual(missingCostume.dataFormat, 'png'); // Runtime should have info about broken asset - t.ok(missingCostume.broken); - t.equal(missingCostume.broken.assetId, missingCostumeAssetId); - - t.end(); + assert.ok(missingCostume.broken); + assert.strictEqual(missingCostume.broken.assetId, missingCostumeAssetId); }); -test('load and then save sb2 project with missing costume file', t => { +test('load and then save sb2 project with missing costume file', () => { const resavedProject = JSON.parse(vm.toJSON()); - t.equal(resavedProject.targets.length, 2); + assert.strictEqual(resavedProject.targets.length, 2); const stage = resavedProject.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const greenGuySprite = resavedProject.targets[1]; - t.equal(greenGuySprite.name, 'GreenGuy'); - t.equal(greenGuySprite.costumes.length, 1); + assert.strictEqual(greenGuySprite.name, 'GreenGuy'); + assert.strictEqual(greenGuySprite.costumes.length, 1); const missingCostume = greenGuySprite.costumes[0]; - t.equal(missingCostume.name, 'GreenGuy'); + assert.strictEqual(missingCostume.name, 'GreenGuy'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data - t.equal(missingCostume.assetId, missingCostumeAssetId); - t.equal(missingCostume.dataFormat, 'png'); + assert.strictEqual(missingCostume.assetId, missingCostumeAssetId); + assert.strictEqual(missingCostume.dataFormat, 'png'); // Test that we didn't save any data about the costume being broken - t.notOk(missingCostume.broken); - - t.end(); + assert.ok(!missingCostume.broken); }); -test('serializeCostume does not save data for missing costume', t => { +test('serializeCostume does not save data for missing costume', () => { const costumeDescs = serializeCostumes(vm.runtime); - t.equal(costumeDescs.length, 1); // Should only have one costume, the backdrop - t.not(costumeDescs[0].fileName, `${missingCostumeAssetId}.png`); - - t.end(); + assert.strictEqual(costumeDescs.length, 1); // Should only have one costume, the backdrop + assert.notStrictEqual(costumeDescs[0].fileName, `${missingCostumeAssetId}.png`); }); diff --git a/test/integration/sb2_missing_svg.js b/test/integration/sb2_missing_svg.js index 1c5bb5fb..4a7f88b2 100644 --- a/test/integration/sb2_missing_svg.js +++ b/test/integration/sb2_missing_svg.js @@ -7,7 +7,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); const FakeBitmapAdapter = require('../fixtures/fake-bitmap-adapter'); @@ -40,7 +41,7 @@ global.document = { let vm; -tap.beforeEach(() => { +beforeEach(() => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -51,59 +52,51 @@ tap.beforeEach(() => { return vm.loadProject(project); }); -const test = tap.test; - -test('loading sb2 project with missing vector costume file', t => { - t.equal(vm.runtime.targets.length, 2); +test('loading sb2 project with missing vector costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 2); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const blueGuySprite = vm.runtime.targets[1]; - t.equal(blueGuySprite.getName(), 'Blue Guy'); - t.equal(blueGuySprite.getCostumes().length, 1); + assert.strictEqual(blueGuySprite.getName(), 'Blue Guy'); + assert.strictEqual(blueGuySprite.getCostumes().length, 1); const missingCostume = blueGuySprite.getCostumes()[0]; - t.equal(missingCostume.name, 'Blue Guy 2'); + assert.strictEqual(missingCostume.name, 'Blue Guy 2'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data const defaultVectorAssetId = vm.runtime.storage.defaultAssetId.ImageVector; - t.equal(missingCostume.assetId, defaultVectorAssetId); - t.equal(missingCostume.dataFormat, 'svg'); + assert.strictEqual(missingCostume.assetId, defaultVectorAssetId); + assert.strictEqual(missingCostume.dataFormat, 'svg'); // Runtime should have info about broken asset - t.ok(missingCostume.broken); - t.equal(missingCostume.broken.assetId, missingCostumeAssetId); - - t.end(); + assert.ok(missingCostume.broken); + assert.strictEqual(missingCostume.broken.assetId, missingCostumeAssetId); }); -test('load and then save sb2 project with missing costume file', t => { +test('load and then save sb2 project with missing costume file', () => { const resavedProject = JSON.parse(vm.toJSON()); - t.equal(resavedProject.targets.length, 2); + assert.strictEqual(resavedProject.targets.length, 2); const stage = resavedProject.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const blueGuySprite = resavedProject.targets[1]; - t.equal(blueGuySprite.name, 'Blue Guy'); - t.equal(blueGuySprite.costumes.length, 1); + assert.strictEqual(blueGuySprite.name, 'Blue Guy'); + assert.strictEqual(blueGuySprite.costumes.length, 1); const missingCostume = blueGuySprite.costumes[0]; - t.equal(missingCostume.name, 'Blue Guy 2'); + assert.strictEqual(missingCostume.name, 'Blue Guy 2'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data - t.equal(missingCostume.assetId, missingCostumeAssetId); - t.equal(missingCostume.dataFormat, 'svg'); + assert.strictEqual(missingCostume.assetId, missingCostumeAssetId); + assert.strictEqual(missingCostume.dataFormat, 'svg'); // Test that we didn't save any data about the costume being broken - t.notOk(missingCostume.broken); - - t.end(); + assert.ok(!missingCostume.broken); }); -test('serializeCostume does not save data for missing costume', t => { +test('serializeCostume does not save data for missing costume', () => { const costumeDescs = serializeCostumes(vm.runtime); - t.equal(costumeDescs.length, 1); // Should only have one costume, the backdrop - t.not(costumeDescs[0].fileName, `${missingCostumeAssetId}.svg`); - - t.end(); + assert.strictEqual(costumeDescs.length, 1); // Should only have one costume, the backdrop + assert.notStrictEqual(costumeDescs[0].fileName, `${missingCostumeAssetId}.svg`); }); diff --git a/test/integration/sb3-roundtrip.js b/test/integration/sb3-roundtrip.js index 9dbc339d..5b2c3490 100644 --- a/test/integration/sb3-roundtrip.js +++ b/test/integration/sb3-roundtrip.js @@ -1,4 +1,5 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const Blocks = require('../../src/engine/blocks'); const Clone = require('../../src/util/clone'); @@ -18,7 +19,7 @@ const defaultCostumeInfo = { const defaultSoundInfo = { }; -test('sb3-roundtrip', t => { +test('sb3-roundtrip', async () => { const runtime1 = new Runtime(); runtime1.attachStorage(makeTestStorage()); @@ -26,85 +27,76 @@ test('sb3-roundtrip', t => { runtime2.attachStorage(makeTestStorage()); const testRuntimeState = (label, runtime) => { - t.strictEqual(runtime.targets.length, 2, `${label}: target count`); + assert.strictEqual(runtime.targets.length, 2, `${label}: target count`); const [stageClone, spriteClone] = runtime.targets; - t.strictEqual(stageClone.isOriginal, true); - t.strictEqual(stageClone.isStage, true); + assert.strictEqual(stageClone.isOriginal, true); + assert.strictEqual(stageClone.isStage, true); const stage = stageClone.sprite; - t.strictEqual(stage.name, 'Stage'); - t.strictEqual(stage.clones.length, 1); - t.strictEqual(stage.clones[0], stageClone); + assert.strictEqual(stage.name, 'Stage'); + assert.strictEqual(stage.clones.length, 1); + assert.strictEqual(stage.clones[0], stageClone); - t.strictEqual(stage.costumes.length, 1); + assert.strictEqual(stage.costumes.length, 1); const [building] = stage.costumes; - t.strictEqual(building.assetId, 'fe5e3566965f9de793beeffce377d054'); - t.strictEqual(building.dataFormat, 'jpg'); + assert.strictEqual(building.assetId, 'fe5e3566965f9de793beeffce377d054'); + assert.strictEqual(building.dataFormat, 'jpg'); - t.strictEqual(stage.sounds.length, 0); + assert.strictEqual(stage.sounds.length, 0); - t.strictEqual(spriteClone.isOriginal, true); - t.strictEqual(spriteClone.isStage, false); + assert.strictEqual(spriteClone.isOriginal, true); + assert.strictEqual(spriteClone.isStage, false); const sprite = spriteClone.sprite; - t.strictEqual(sprite.name, 'Sprite'); - t.strictEqual(sprite.clones.length, 1); - t.strictEqual(sprite.clones[0], spriteClone); + assert.strictEqual(sprite.name, 'Sprite'); + assert.strictEqual(sprite.clones.length, 1); + assert.strictEqual(sprite.clones[0], spriteClone); - t.strictEqual(sprite.costumes.length, 2); + assert.strictEqual(sprite.costumes.length, 2); const [cat, squirrel] = sprite.costumes; - t.strictEqual(cat.assetId, 'f88bf1935daea28f8ca098462a31dbb0'); - t.strictEqual(cat.dataFormat, 'svg'); - t.strictEqual(squirrel.assetId, '7e24c99c1b853e52f8e7f9004416fa34'); - t.strictEqual(squirrel.dataFormat, 'png'); + assert.strictEqual(cat.assetId, 'f88bf1935daea28f8ca098462a31dbb0'); + assert.strictEqual(cat.dataFormat, 'svg'); + assert.strictEqual(squirrel.assetId, '7e24c99c1b853e52f8e7f9004416fa34'); + assert.strictEqual(squirrel.dataFormat, 'png'); - t.strictEqual(sprite.sounds.length, 1); + assert.strictEqual(sprite.sounds.length, 1); const [meow] = sprite.sounds; - t.strictEqual(meow.md5, '83c36d806dc92327b9e7049a565c6bff.wav'); + assert.strictEqual(meow.md5, '83c36d806dc92327b9e7049a565c6bff.wav'); }; - const loadThings = Promise.all([ + const [building, cat, squirrel, meow] = await Promise.all([ loadCostume('fe5e3566965f9de793beeffce377d054.jpg', Clone.simple(defaultCostumeInfo), runtime1), loadCostume('f88bf1935daea28f8ca098462a31dbb0.svg', Clone.simple(defaultCostumeInfo), runtime1), loadCostume('7e24c99c1b853e52f8e7f9004416fa34.png', Clone.simple(defaultCostumeInfo), runtime1), loadSound(Object.assign({md5: '83c36d806dc92327b9e7049a565c6bff.wav'}, defaultSoundInfo), runtime1) ]); - const installThings = loadThings.then(results => { - const [building, cat, squirrel, meow] = results; + const stageBlocks = new Blocks(runtime1); + const stage = new Sprite(stageBlocks, runtime1); + stage.name = 'Stage'; + stage.costumes = [building]; + stage.sounds = []; + const stageClone = stage.createClone(); + stageClone.isStage = true; - const stageBlocks = new Blocks(runtime1); - const stage = new Sprite(stageBlocks, runtime1); - stage.name = 'Stage'; - stage.costumes = [building]; - stage.sounds = []; - const stageClone = stage.createClone(); - stageClone.isStage = true; + const spriteBlocks = new Blocks(runtime1); + const sprite = new Sprite(spriteBlocks, runtime1); + sprite.name = 'Sprite'; + sprite.costumes = [cat, squirrel]; + sprite.sounds = [meow]; + const spriteClone = sprite.createClone(); - const spriteBlocks = new Blocks(runtime1); - const sprite = new Sprite(spriteBlocks, runtime1); - sprite.name = 'Sprite'; - sprite.costumes = [cat, squirrel]; - sprite.sounds = [meow]; - const spriteClone = sprite.createClone(); + runtime1.targets = [stageClone, spriteClone]; - runtime1.targets = [stageClone, spriteClone]; + testRuntimeState('original', runtime1); - testRuntimeState('original', runtime1); - }); - - const serializeAndDeserialize = installThings.then(() => { - // Doing a JSON `stringify` and `parse` here more accurately simulate a save/load cycle. In particular: - // 1. it ensures that any non-serializable data is thrown away, and - // 2. `sb3.deserialize` and its helpers do some `hasOwnProperty` checks which fail on the object returned by - // `sb3.serialize` but succeed if that object is "flattened" in this way. - const serializedState = JSON.parse(JSON.stringify(sb3.serialize(runtime1))); - return sb3.deserialize(serializedState, runtime2); - }); - - return serializeAndDeserialize.then(({targets}) => { - runtime2.targets = targets; - testRuntimeState('copy', runtime2); - }); + // Doing a JSON `stringify` and `parse` here more accurately simulate a save/load cycle. In particular: + // 1. it ensures that any non-serializable data is thrown away, and + // 2. `sb3.deserialize` and its helpers do some `hasOwnProperty` checks which fail on the object returned by + // `sb3.serialize` but succeed if that object is "flattened" in this way. + const serializedState = JSON.parse(JSON.stringify(sb3.serialize(runtime1))); + const {targets} = await sb3.deserialize(serializedState, runtime2); + runtime2.targets = targets; + testRuntimeState('copy', runtime2); }); diff --git a/test/integration/sb3_corrupted_png.js b/test/integration/sb3_corrupted_png.js index 46f75ba1..8ee2c095 100644 --- a/test/integration/sb3_corrupted_png.js +++ b/test/integration/sb3_corrupted_png.js @@ -7,7 +7,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const md5 = require('js-md5'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); @@ -54,9 +55,8 @@ global.document = { let vm; let defaultBitmapAssetId; -tap.setTimeout(30000); -tap.beforeEach(() => { +beforeEach(() => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -69,59 +69,52 @@ tap.beforeEach(() => { return vm.loadProject(project); }); -const test = tap.test; - -test('load sb3 project with corrupted bitmap costume file', t => { - t.equal(vm.runtime.targets.length, 2); +test('load sb3 project with corrupted bitmap costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 2); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const greenGuySprite = vm.runtime.targets[1]; - t.equal(greenGuySprite.getName(), 'Green Guy'); - t.equal(greenGuySprite.getCostumes().length, 1); + assert.strictEqual(greenGuySprite.getName(), 'Green Guy'); + assert.strictEqual(greenGuySprite.getCostumes().length, 1); const corruptedCostume = greenGuySprite.getCostumes()[0]; - t.equal(corruptedCostume.name, 'Green Guy'); - t.equal(corruptedCostume.assetId, defaultBitmapAssetId); - t.equal(corruptedCostume.dataFormat, 'png'); + assert.strictEqual(corruptedCostume.name, 'Green Guy'); + assert.strictEqual(corruptedCostume.assetId, defaultBitmapAssetId); + assert.strictEqual(corruptedCostume.dataFormat, 'png'); // Runtime should have info about broken asset - t.ok(corruptedCostume.broken); - t.equal(corruptedCostume.broken.assetId, brokenCostumeMd5); + assert.ok(corruptedCostume.broken); + assert.strictEqual(corruptedCostume.broken.assetId, brokenCostumeMd5); // Verify that we saved the original asset data - t.equal(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); - - t.end(); + assert.strictEqual(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); }); -test('load and then save project with corrupted bitmap costume file', t => { +test('load and then save project with corrupted bitmap costume file', () => { const resavedProject = JSON.parse(vm.toJSON()); - t.equal(resavedProject.targets.length, 2); + assert.strictEqual(resavedProject.targets.length, 2); const stage = resavedProject.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const greenGuySprite = resavedProject.targets[1]; - t.equal(greenGuySprite.name, 'Green Guy'); - t.equal(greenGuySprite.costumes.length, 1); + assert.strictEqual(greenGuySprite.name, 'Green Guy'); + assert.strictEqual(greenGuySprite.costumes.length, 1); const corruptedCostume = greenGuySprite.costumes[0]; - t.equal(corruptedCostume.name, 'Green Guy'); + assert.strictEqual(corruptedCostume.name, 'Green Guy'); // Resaved project costume should have the metadata that corresponds to the original broken costume - t.equal(corruptedCostume.assetId, brokenCostumeMd5); - t.equal(corruptedCostume.dataFormat, 'png'); + assert.strictEqual(corruptedCostume.assetId, brokenCostumeMd5); + assert.strictEqual(corruptedCostume.dataFormat, 'png'); // Test that we didn't save any data about the costume being broken - t.notOk(corruptedCostume.broken); - - t.end(); + assert.ok(!corruptedCostume.broken); }); -test('serializeCostume saves orignal broken costume', t => { +test('serializeCostume saves orignal broken costume', () => { const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[1].id); - t.equal(costumeDescs.length, 1); + assert.strictEqual(costumeDescs.length, 1); const costume = costumeDescs[0]; - t.equal(costume.fileName, `${brokenCostumeMd5}.png`); - t.equal(md5(costume.fileContent), brokenCostumeMd5); - t.end(); + assert.strictEqual(costume.fileName, `${brokenCostumeMd5}.png`); + assert.strictEqual(md5(costume.fileContent), brokenCostumeMd5); }); diff --git a/test/integration/sb3_corrupted_sound.js b/test/integration/sb3_corrupted_sound.js index 6afeda71..673159cc 100644 --- a/test/integration/sb3_corrupted_sound.js +++ b/test/integration/sb3_corrupted_sound.js @@ -7,7 +7,8 @@ * to load the sound if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const md5 = require('js-md5'); const makeTestStorage = require('../fixtures/make-test-storage'); const {extractAsset, readFileToBuffer} = require('../fixtures/readProjectFile'); @@ -49,7 +50,7 @@ const FakeAudioEngine = function () { let vm; let defaultSoundAssetId; -tap.beforeEach(() => { +beforeEach(() => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -61,59 +62,52 @@ tap.beforeEach(() => { return vm.loadProject(project); }); -const test = tap.test; - -test('load sb3 project with corrupted sound file', t => { - t.equal(vm.runtime.targets.length, 2); +test('load sb3 project with corrupted sound file', () => { + assert.strictEqual(vm.runtime.targets.length, 2); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const catSprite = vm.runtime.targets[1]; - t.equal(catSprite.getName(), 'Sprite1'); - t.equal(catSprite.getSounds().length, 1); + assert.strictEqual(catSprite.getName(), 'Sprite1'); + assert.strictEqual(catSprite.getSounds().length, 1); const corruptedSound = catSprite.getSounds()[0]; - t.equal(corruptedSound.name, 'Boop Sound Recording'); - t.equal(corruptedSound.assetId, defaultSoundAssetId); - t.equal(corruptedSound.dataFormat, 'wav'); + assert.strictEqual(corruptedSound.name, 'Boop Sound Recording'); + assert.strictEqual(corruptedSound.assetId, defaultSoundAssetId); + assert.strictEqual(corruptedSound.dataFormat, 'wav'); // Runtime should have info about broken asset - t.ok(corruptedSound.broken); - t.equal(corruptedSound.broken.assetId, brokenSoundMd5); + assert.ok(corruptedSound.broken); + assert.strictEqual(corruptedSound.broken.assetId, brokenSoundMd5); // Verify that we saved the original asset data - t.equal(md5(corruptedSound.broken.asset.data), brokenSoundMd5); - - t.end(); + assert.strictEqual(md5(corruptedSound.broken.asset.data), brokenSoundMd5); }); -test('load and then save project with corrupted sound file', t => { +test('load and then save project with corrupted sound file', () => { const resavedProject = JSON.parse(vm.toJSON()); - t.equal(resavedProject.targets.length, 2); + assert.strictEqual(resavedProject.targets.length, 2); const stage = resavedProject.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const catSprite = resavedProject.targets[1]; - t.equal(catSprite.name, 'Sprite1'); - t.equal(catSprite.sounds.length, 1); + assert.strictEqual(catSprite.name, 'Sprite1'); + assert.strictEqual(catSprite.sounds.length, 1); const corruptedSound = catSprite.sounds[0]; - t.equal(corruptedSound.name, 'Boop Sound Recording'); + assert.strictEqual(corruptedSound.name, 'Boop Sound Recording'); // Resaved project costume should have the metadata that corresponds to the original broken costume - t.equal(corruptedSound.assetId, brokenSoundMd5); - t.equal(corruptedSound.dataFormat, 'wav'); + assert.strictEqual(corruptedSound.assetId, brokenSoundMd5); + assert.strictEqual(corruptedSound.dataFormat, 'wav'); // Test that we didn't save any data about the costume being broken - t.notOk(corruptedSound.broken); - - t.end(); + assert.ok(!corruptedSound.broken); }); -test('serializeSounds saves orignal broken sound', t => { +test('serializeSounds saves orignal broken sound', () => { const soundDescs = serializeSounds(vm.runtime, vm.runtime.targets[1].id); - t.equal(soundDescs.length, 1); + assert.strictEqual(soundDescs.length, 1); const sound = soundDescs[0]; - t.equal(sound.fileName, `${brokenSoundMd5}.wav`); - t.equal(md5(sound.fileContent), brokenSoundMd5); - t.end(); + assert.strictEqual(sound.fileName, `${brokenSoundMd5}.wav`); + assert.strictEqual(md5(sound.fileContent), brokenSoundMd5); }); diff --git a/test/integration/sb3_corrupted_svg.js b/test/integration/sb3_corrupted_svg.js index d4efe365..69d4305b 100644 --- a/test/integration/sb3_corrupted_svg.js +++ b/test/integration/sb3_corrupted_svg.js @@ -7,7 +7,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const md5 = require('js-md5'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); @@ -27,7 +28,7 @@ const brokenCostumeMd5 = md5(originalCostume); let vm; let defaultVectorAssetId; -tap.beforeEach(() => { +beforeEach(() => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -48,59 +49,52 @@ tap.beforeEach(() => { return vm.loadProject(project); }); -const test = tap.test; - -test('load sb3 project with corrupted vector costume file', t => { - t.equal(vm.runtime.targets.length, 2); +test('load sb3 project with corrupted vector costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 2); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const blueGuySprite = vm.runtime.targets[1]; - t.equal(blueGuySprite.getName(), 'Blue Square Guy'); - t.equal(blueGuySprite.getCostumes().length, 1); + assert.strictEqual(blueGuySprite.getName(), 'Blue Square Guy'); + assert.strictEqual(blueGuySprite.getCostumes().length, 1); const corruptedCostume = blueGuySprite.getCostumes()[0]; - t.equal(corruptedCostume.name, 'costume1'); - t.equal(corruptedCostume.assetId, defaultVectorAssetId); - t.equal(corruptedCostume.dataFormat, 'svg'); + assert.strictEqual(corruptedCostume.name, 'costume1'); + assert.strictEqual(corruptedCostume.assetId, defaultVectorAssetId); + assert.strictEqual(corruptedCostume.dataFormat, 'svg'); // Runtime should have info about broken asset - t.ok(corruptedCostume.broken); - t.equal(corruptedCostume.broken.assetId, brokenCostumeMd5); + assert.ok(corruptedCostume.broken); + assert.strictEqual(corruptedCostume.broken.assetId, brokenCostumeMd5); // Verify that we saved the original asset data - t.equal(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); - - t.end(); + assert.strictEqual(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); }); -test('load and then save project with corrupted vector costume file', t => { +test('load and then save project with corrupted vector costume file', () => { const resavedProject = JSON.parse(vm.toJSON()); - t.equal(resavedProject.targets.length, 2); + assert.strictEqual(resavedProject.targets.length, 2); const stage = resavedProject.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const blueGuySprite = resavedProject.targets[1]; - t.equal(blueGuySprite.name, 'Blue Square Guy'); - t.equal(blueGuySprite.costumes.length, 1); + assert.strictEqual(blueGuySprite.name, 'Blue Square Guy'); + assert.strictEqual(blueGuySprite.costumes.length, 1); const corruptedCostume = blueGuySprite.costumes[0]; - t.equal(corruptedCostume.name, 'costume1'); + assert.strictEqual(corruptedCostume.name, 'costume1'); // Resaved project costume should have the metadata that corresponds to the original broken costume - t.equal(corruptedCostume.assetId, brokenCostumeMd5); - t.equal(corruptedCostume.dataFormat, 'svg'); + assert.strictEqual(corruptedCostume.assetId, brokenCostumeMd5); + assert.strictEqual(corruptedCostume.dataFormat, 'svg'); // Test that we didn't save any data about the costume being broken - t.notOk(corruptedCostume.broken); - - t.end(); + assert.ok(!corruptedCostume.broken); }); -test('serializeCostume saves orignal broken costume', t => { +test('serializeCostume saves orignal broken costume', () => { const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[1].id); - t.equal(costumeDescs.length, 1); + assert.strictEqual(costumeDescs.length, 1); const costume = costumeDescs[0]; - t.equal(costume.fileName, `${brokenCostumeMd5}.svg`); - t.equal(md5(costume.fileContent), brokenCostumeMd5); - t.end(); + assert.strictEqual(costume.fileName, `${brokenCostumeMd5}.svg`); + assert.strictEqual(md5(costume.fileContent), brokenCostumeMd5); }); diff --git a/test/integration/sb3_missing_png.js b/test/integration/sb3_missing_png.js index 27924c00..97205602 100644 --- a/test/integration/sb3_missing_png.js +++ b/test/integration/sb3_missing_png.js @@ -7,7 +7,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); const FakeBitmapAdapter = require('../fixtures/fake-bitmap-adapter'); @@ -41,9 +42,7 @@ global.document = { let vm; -tap.setTimeout(30000); - -tap.beforeEach(() => { +beforeEach(() => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -54,59 +53,51 @@ tap.beforeEach(() => { return vm.loadProject(project); }); -const test = tap.test; - -test('loading sb3 project with missing bitmap costume file', t => { - t.equal(vm.runtime.targets.length, 2); +test('loading sb3 project with missing bitmap costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 2); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const greenGuySprite = vm.runtime.targets[1]; - t.equal(greenGuySprite.getName(), 'Green Guy'); - t.equal(greenGuySprite.getCostumes().length, 1); + assert.strictEqual(greenGuySprite.getName(), 'Green Guy'); + assert.strictEqual(greenGuySprite.getCostumes().length, 1); const missingCostume = greenGuySprite.getCostumes()[0]; - t.equal(missingCostume.name, 'Green Guy'); + assert.strictEqual(missingCostume.name, 'Green Guy'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data const defaultVectorAssetId = vm.runtime.storage.defaultAssetId.ImageBitmap; - t.equal(missingCostume.assetId, defaultVectorAssetId); - t.equal(missingCostume.dataFormat, 'png'); + assert.strictEqual(missingCostume.assetId, defaultVectorAssetId); + assert.strictEqual(missingCostume.dataFormat, 'png'); // Runtime should have info about broken asset - t.ok(missingCostume.broken); - t.equal(missingCostume.broken.assetId, missingCostumeAssetId); - - t.end(); + assert.ok(missingCostume.broken); + assert.strictEqual(missingCostume.broken.assetId, missingCostumeAssetId); }); -test('load and then save sb3 project with missing costume file', t => { +test('load and then save sb3 project with missing costume file', () => { const resavedProject = JSON.parse(vm.toJSON()); - t.equal(resavedProject.targets.length, 2); + assert.strictEqual(resavedProject.targets.length, 2); const stage = resavedProject.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const greenGuySprite = resavedProject.targets[1]; - t.equal(greenGuySprite.name, 'Green Guy'); - t.equal(greenGuySprite.costumes.length, 1); + assert.strictEqual(greenGuySprite.name, 'Green Guy'); + assert.strictEqual(greenGuySprite.costumes.length, 1); const missingCostume = greenGuySprite.costumes[0]; - t.equal(missingCostume.name, 'Green Guy'); + assert.strictEqual(missingCostume.name, 'Green Guy'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data - t.equal(missingCostume.assetId, missingCostumeAssetId); - t.equal(missingCostume.dataFormat, 'png'); + assert.strictEqual(missingCostume.assetId, missingCostumeAssetId); + assert.strictEqual(missingCostume.dataFormat, 'png'); // Test that we didn't save any data about the costume being broken - t.notOk(missingCostume.broken); - - t.end(); + assert.ok(!missingCostume.broken); }); -test('serializeCostume does not save data for missing costume', t => { +test('serializeCostume does not save data for missing costume', () => { const costumeDescs = serializeCostumes(vm.runtime); - t.equal(costumeDescs.length, 1); // Should only have one costume, the backdrop - t.not(costumeDescs[0].fileName, `${missingCostumeAssetId}.png`); - - t.end(); + assert.strictEqual(costumeDescs.length, 1); // Should only have one costume, the backdrop + assert.notStrictEqual(costumeDescs[0].fileName, `${missingCostumeAssetId}.png`); }); diff --git a/test/integration/sb3_missing_sound.js b/test/integration/sb3_missing_sound.js index b3c6980c..3e0860f1 100644 --- a/test/integration/sb3_missing_sound.js +++ b/test/integration/sb3_missing_sound.js @@ -6,7 +6,8 @@ * so that user data does not get overwritten / lost. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -19,7 +20,7 @@ const missingSoundAssetId = '78618aadd225b1db7bf837fa17dc0568'; let vm; -tap.beforeEach(() => { +beforeEach(() => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -28,59 +29,51 @@ tap.beforeEach(() => { return vm.loadProject(project); }); -const test = tap.test; - -test('loading sb3 project with missing sound file', t => { - t.equal(vm.runtime.targets.length, 2); +test('loading sb3 project with missing sound file', () => { + assert.strictEqual(vm.runtime.targets.length, 2); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const catSprite = vm.runtime.targets[1]; - t.equal(catSprite.getSounds().length, 1); + assert.strictEqual(catSprite.getSounds().length, 1); const missingSound = catSprite.getSounds()[0]; - t.equal(missingSound.name, 'Boop Sound Recording'); + assert.strictEqual(missingSound.name, 'Boop Sound Recording'); // Sound should have original data but no asset const defaultSoundAssetId = vm.runtime.storage.defaultAssetId.Sound; - t.equal(missingSound.assetId, defaultSoundAssetId); - t.equal(missingSound.dataFormat, 'wav'); + assert.strictEqual(missingSound.assetId, defaultSoundAssetId); + assert.strictEqual(missingSound.dataFormat, 'wav'); // Runtime should have info about broken asset - t.ok(missingSound.broken); - t.equal(missingSound.broken.assetId, missingSoundAssetId); - - t.end(); + assert.ok(missingSound.broken); + assert.strictEqual(missingSound.broken.assetId, missingSoundAssetId); }); -test('load and then save sb3 project with missing sound file', t => { +test('load and then save sb3 project with missing sound file', () => { const resavedProject = JSON.parse(vm.toJSON()); - t.equal(resavedProject.targets.length, 2); + assert.strictEqual(resavedProject.targets.length, 2); const stage = resavedProject.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const catSprite = resavedProject.targets[1]; - t.equal(catSprite.name, 'Sprite1'); - t.equal(catSprite.sounds.length, 1); + assert.strictEqual(catSprite.name, 'Sprite1'); + assert.strictEqual(catSprite.sounds.length, 1); const missingSound = catSprite.sounds[0]; - t.equal(missingSound.name, 'Boop Sound Recording'); + assert.strictEqual(missingSound.name, 'Boop Sound Recording'); // Costume should have both default sound data (e.g. "Gray Question Sound" ^_^) and original data - t.equal(missingSound.assetId, missingSoundAssetId); - t.equal(missingSound.dataFormat, 'wav'); + assert.strictEqual(missingSound.assetId, missingSoundAssetId); + assert.strictEqual(missingSound.dataFormat, 'wav'); // Test that we didn't save any data about the costume being broken - t.notOk(missingSound.broken); - - t.end(); + assert.ok(!missingSound.broken); }); -test('serializeCostume does not save data for missing costume', t => { +test('serializeCostume does not save data for missing costume', () => { const soundDescs = serializeSounds(vm.runtime); - t.equal(soundDescs.length, 1); // Should only have one sound, the pop sound for the stage - t.not(soundDescs[0].fileName, `${missingSoundAssetId}.wav`); - - t.end(); + assert.strictEqual(soundDescs.length, 1); // Should only have one sound, the pop sound for the stage + assert.notStrictEqual(soundDescs[0].fileName, `${missingSoundAssetId}.wav`); }); diff --git a/test/integration/sb3_missing_svg.js b/test/integration/sb3_missing_svg.js index f0adf82d..8084f76d 100644 --- a/test/integration/sb3_missing_svg.js +++ b/test/integration/sb3_missing_svg.js @@ -7,7 +7,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; @@ -21,7 +22,7 @@ const missingCostumeAssetId = 'a267f8b97ee9cf8aa9832aa0b4cfd9eb'; let vm; -tap.beforeEach(() => { +beforeEach(() => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -31,59 +32,51 @@ tap.beforeEach(() => { return vm.loadProject(project); }); -const test = tap.test; - -test('loading sb3 project with missing vector costume file', t => { - t.equal(vm.runtime.targets.length, 2); +test('loading sb3 project with missing vector costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 2); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const blueGuySprite = vm.runtime.targets[1]; - t.equal(blueGuySprite.getName(), 'Blue Square Guy'); - t.equal(blueGuySprite.getCostumes().length, 1); + assert.strictEqual(blueGuySprite.getName(), 'Blue Square Guy'); + assert.strictEqual(blueGuySprite.getCostumes().length, 1); const missingCostume = blueGuySprite.getCostumes()[0]; - t.equal(missingCostume.name, 'costume1'); + assert.strictEqual(missingCostume.name, 'costume1'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data const defaultVectorAssetId = vm.runtime.storage.defaultAssetId.ImageVector; - t.equal(missingCostume.assetId, defaultVectorAssetId); - t.equal(missingCostume.dataFormat, 'svg'); + assert.strictEqual(missingCostume.assetId, defaultVectorAssetId); + assert.strictEqual(missingCostume.dataFormat, 'svg'); // Runtime should have info about broken asset - t.ok(missingCostume.broken); - t.equal(missingCostume.broken.assetId, missingCostumeAssetId); - - t.end(); + assert.ok(missingCostume.broken); + assert.strictEqual(missingCostume.broken.assetId, missingCostumeAssetId); }); -test('load and then save sb3 project with missing costume file', t => { +test('load and then save sb3 project with missing costume file', () => { const resavedProject = JSON.parse(vm.toJSON()); - t.equal(resavedProject.targets.length, 2); + assert.strictEqual(resavedProject.targets.length, 2); const stage = resavedProject.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const blueGuySprite = resavedProject.targets[1]; - t.equal(blueGuySprite.name, 'Blue Square Guy'); - t.equal(blueGuySprite.costumes.length, 1); + assert.strictEqual(blueGuySprite.name, 'Blue Square Guy'); + assert.strictEqual(blueGuySprite.costumes.length, 1); const missingCostume = blueGuySprite.costumes[0]; - t.equal(missingCostume.name, 'costume1'); + assert.strictEqual(missingCostume.name, 'costume1'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data - t.equal(missingCostume.assetId, missingCostumeAssetId); - t.equal(missingCostume.dataFormat, 'svg'); + assert.strictEqual(missingCostume.assetId, missingCostumeAssetId); + assert.strictEqual(missingCostume.dataFormat, 'svg'); // Test that we didn't save any data about the costume being broken - t.notOk(missingCostume.broken); - - t.end(); + assert.ok(!missingCostume.broken); }); -test('serializeCostume does not save data for missing costume', t => { +test('serializeCostume does not save data for missing costume', () => { const costumeDescs = serializeCostumes(vm.runtime); - t.equal(costumeDescs.length, 1); // Should only have one costume, the backdrop - t.not(costumeDescs[0].fileName, `${missingCostumeAssetId}.svg`); - - t.end(); + assert.strictEqual(costumeDescs.length, 1); // Should only have one costume, the backdrop + assert.notStrictEqual(costumeDescs[0].fileName, `${missingCostumeAssetId}.svg`); }); diff --git a/test/integration/sensing.js b/test/integration/sensing.js index dbe0df94..f4dd4fd3 100644 --- a/test/integration/sensing.js +++ b/test/integration/sensing.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -7,20 +8,20 @@ const VirtualMachine = require('../../src/index'); const uri = path.resolve(__dirname, '../fixtures/sensing.sb2'); const project = readFileToBuffer(uri); -test('sensing', t => { +test('sensing', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length > 0); + assert.ok(threads.length > 0); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/sound.js b/test/integration/sound.js index 6d27cb51..90efee8e 100644 --- a/test/integration/sound.js +++ b/test/integration/sound.js @@ -1,6 +1,7 @@ const Worker = require('tiny-worker'); const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -12,20 +13,20 @@ const project = readFileToBuffer(uri); // By default Central Dispatch works with the Worker class built into the browser. Tell it to use TinyWorker instead. dispatch.workerClass = Worker; -test('sound', t => { +test('sound', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', e => { const threads = JSON.parse(e.threads); - t.ok(threads.length > 0); + assert.ok(threads.length > 0); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); diff --git a/test/integration/sprite2_corrupted_png.js b/test/integration/sprite2_corrupted_png.js index 0740eb6b..e5471844 100644 --- a/test/integration/sprite2_corrupted_png.js +++ b/test/integration/sprite2_corrupted_png.js @@ -8,7 +8,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const md5 = require('js-md5'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); @@ -59,9 +60,8 @@ global.document = { let vm; let defaultBitmapAssetId; -tap.setTimeout(30000); -tap.beforeEach(() => { +beforeEach(async () => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -71,56 +71,50 @@ tap.beforeEach(() => { vm.attachRenderer(new FakeRenderer()); vm.attachV2BitmapAdapter(new FakeBitmapAdapter()); - return vm.loadProject(project).then(() => vm.addSprite(sprite)); + await vm.loadProject(project); + return vm.addSprite(sprite); }); -const test = tap.test; - -test('load sprite2 with corrupted bitmap costume file', t => { - t.equal(vm.runtime.targets.length, 3); +test('load sprite2 with corrupted bitmap costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 3); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const greenGuySprite = vm.runtime.targets[2]; - t.equal(greenGuySprite.getName(), 'GreenGuy'); - t.equal(greenGuySprite.getCostumes().length, 1); + assert.strictEqual(greenGuySprite.getName(), 'GreenGuy'); + assert.strictEqual(greenGuySprite.getCostumes().length, 1); const corruptedCostume = greenGuySprite.getCostumes()[0]; - t.equal(corruptedCostume.name, 'GreenGuy'); - t.equal(corruptedCostume.assetId, defaultBitmapAssetId); - t.equal(corruptedCostume.dataFormat, 'png'); + assert.strictEqual(corruptedCostume.name, 'GreenGuy'); + assert.strictEqual(corruptedCostume.assetId, defaultBitmapAssetId); + assert.strictEqual(corruptedCostume.dataFormat, 'png'); // Runtime should have info about broken asset - t.ok(corruptedCostume.broken); - t.equal(corruptedCostume.broken.assetId, brokenCostumeMd5); + assert.ok(corruptedCostume.broken); + assert.strictEqual(corruptedCostume.broken.assetId, brokenCostumeMd5); // Verify that we saved the original asset data - t.equal(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); - - t.end(); + assert.strictEqual(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); }); -test('load and then save sprite with corrupted costume file', t => { +test('load and then save sprite with corrupted costume file', () => { const resavedSprite = JSON.parse(vm.toJSON(vm.runtime.targets[2].id)); - t.equal(resavedSprite.name, 'GreenGuy'); - t.equal(resavedSprite.costumes.length, 1); + assert.strictEqual(resavedSprite.name, 'GreenGuy'); + assert.strictEqual(resavedSprite.costumes.length, 1); const corruptedCostume = resavedSprite.costumes[0]; - t.equal(corruptedCostume.name, 'GreenGuy'); + assert.strictEqual(corruptedCostume.name, 'GreenGuy'); // Resaved project costume should have the metadata that corresponds to the original broken costume - t.equal(corruptedCostume.assetId, brokenCostumeMd5); - t.equal(corruptedCostume.dataFormat, 'png'); + assert.strictEqual(corruptedCostume.assetId, brokenCostumeMd5); + assert.strictEqual(corruptedCostume.dataFormat, 'png'); // Test that we didn't save any data about the costume being broken - t.notOk(corruptedCostume.broken); - - t.end(); + assert.ok(!corruptedCostume.broken); }); -test('serializeCostume saves orignal broken costume', t => { +test('serializeCostume saves orignal broken costume', () => { const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[2].id); - t.equal(costumeDescs.length, 1); + assert.strictEqual(costumeDescs.length, 1); const costume = costumeDescs[0]; - t.equal(costume.fileName, `${brokenCostumeMd5}.png`); - t.equal(md5(costume.fileContent), brokenCostumeMd5); - t.end(); + assert.strictEqual(costume.fileName, `${brokenCostumeMd5}.png`); + assert.strictEqual(md5(costume.fileContent), brokenCostumeMd5); }); diff --git a/test/integration/sprite2_corrupted_svg.js b/test/integration/sprite2_corrupted_svg.js index 866448d7..af7c8cbc 100644 --- a/test/integration/sprite2_corrupted_svg.js +++ b/test/integration/sprite2_corrupted_svg.js @@ -8,7 +8,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const md5 = require('js-md5'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); @@ -51,7 +52,7 @@ global.document = { let vm; let defaultVectorAssetId; -tap.beforeEach(() => { +beforeEach(async () => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -70,56 +71,50 @@ tap.beforeEach(() => { vm.attachRenderer(new FakeRenderer()); vm.attachV2BitmapAdapter(new FakeBitmapAdapter()); - return vm.loadProject(project).then(() => vm.addSprite(sprite)); + await vm.loadProject(project); + return vm.addSprite(sprite); }); -const test = tap.test; - -test('load sprite2 with corrupted vector costume file', t => { - t.equal(vm.runtime.targets.length, 3); +test('load sprite2 with corrupted vector costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 3); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const blueGuySprite = vm.runtime.targets[2]; - t.equal(blueGuySprite.getName(), 'Blue Guy'); - t.equal(blueGuySprite.getCostumes().length, 1); + assert.strictEqual(blueGuySprite.getName(), 'Blue Guy'); + assert.strictEqual(blueGuySprite.getCostumes().length, 1); const corruptedCostume = blueGuySprite.getCostumes()[0]; - t.equal(corruptedCostume.name, 'Blue Guy 2'); - t.equal(corruptedCostume.assetId, defaultVectorAssetId); - t.equal(corruptedCostume.dataFormat, 'svg'); + assert.strictEqual(corruptedCostume.name, 'Blue Guy 2'); + assert.strictEqual(corruptedCostume.assetId, defaultVectorAssetId); + assert.strictEqual(corruptedCostume.dataFormat, 'svg'); // Runtime should have info about broken asset - t.ok(corruptedCostume.broken); - t.equal(corruptedCostume.broken.assetId, brokenCostumeMd5); + assert.ok(corruptedCostume.broken); + assert.strictEqual(corruptedCostume.broken.assetId, brokenCostumeMd5); // Verify that we saved the original asset data - t.equal(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); - - t.end(); + assert.strictEqual(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); }); -test('load and then save sprite with corrupted costume file', t => { +test('load and then save sprite with corrupted costume file', () => { const resavedSprite = JSON.parse(vm.toJSON(vm.runtime.targets[2].id)); - t.equal(resavedSprite.name, 'Blue Guy'); - t.equal(resavedSprite.costumes.length, 1); + assert.strictEqual(resavedSprite.name, 'Blue Guy'); + assert.strictEqual(resavedSprite.costumes.length, 1); const corruptedCostume = resavedSprite.costumes[0]; - t.equal(corruptedCostume.name, 'Blue Guy 2'); + assert.strictEqual(corruptedCostume.name, 'Blue Guy 2'); // Resaved project costume should have the metadata that corresponds to the original broken costume - t.equal(corruptedCostume.assetId, brokenCostumeMd5); - t.equal(corruptedCostume.dataFormat, 'svg'); + assert.strictEqual(corruptedCostume.assetId, brokenCostumeMd5); + assert.strictEqual(corruptedCostume.dataFormat, 'svg'); // Test that we didn't save any data about the costume being broken - t.notOk(corruptedCostume.broken); - - t.end(); + assert.ok(!corruptedCostume.broken); }); -test('serializeCostume saves orignal broken costume', t => { +test('serializeCostume saves orignal broken costume', () => { const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[2].id); - t.equal(costumeDescs.length, 1); + assert.strictEqual(costumeDescs.length, 1); const costume = costumeDescs[0]; - t.equal(costume.fileName, `${brokenCostumeMd5}.svg`); - t.equal(md5(costume.fileContent), brokenCostumeMd5); - t.end(); + assert.strictEqual(costume.fileName, `${brokenCostumeMd5}.svg`); + assert.strictEqual(md5(costume.fileContent), brokenCostumeMd5); }); diff --git a/test/integration/sprite2_missing_png.js b/test/integration/sprite2_missing_png.js index 07453cd1..2c9fa67e 100644 --- a/test/integration/sprite2_missing_png.js +++ b/test/integration/sprite2_missing_png.js @@ -7,7 +7,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); const FakeBitmapAdapter = require('../fixtures/fake-bitmap-adapter'); @@ -44,9 +45,7 @@ global.document = { let vm; -tap.setTimeout(30000); - -tap.beforeEach(() => { +beforeEach(async () => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -54,55 +53,48 @@ tap.beforeEach(() => { vm.attachRenderer(new FakeRenderer()); vm.attachV2BitmapAdapter(new FakeBitmapAdapter()); - return vm.loadProject(project).then(() => vm.addSprite(sprite)); + await vm.loadProject(project); + return vm.addSprite(sprite); }); -const test = tap.test; - -test('loading sprite2 with missing bitmap costume file', t => { - t.equal(vm.runtime.targets.length, 3); +test('loading sprite2 with missing bitmap costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 3); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const greenGuySprite = vm.runtime.targets[2]; - t.equal(greenGuySprite.getName(), 'GreenGuy'); - t.equal(greenGuySprite.getCostumes().length, 1); + assert.strictEqual(greenGuySprite.getName(), 'GreenGuy'); + assert.strictEqual(greenGuySprite.getCostumes().length, 1); const missingCostume = greenGuySprite.getCostumes()[0]; - t.equal(missingCostume.name, 'GreenGuy'); + assert.strictEqual(missingCostume.name, 'GreenGuy'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data const defaultBitmapAssetId = vm.runtime.storage.defaultAssetId.ImageBitmap; - t.equal(missingCostume.assetId, defaultBitmapAssetId); - t.equal(missingCostume.dataFormat, 'png'); + assert.strictEqual(missingCostume.assetId, defaultBitmapAssetId); + assert.strictEqual(missingCostume.dataFormat, 'png'); // Runtime should have info about broken asset - t.ok(missingCostume.broken); - t.equal(missingCostume.broken.assetId, missingCostumeAssetId); - - t.end(); + assert.ok(missingCostume.broken); + assert.strictEqual(missingCostume.broken.assetId, missingCostumeAssetId); }); -test('load and then save sprite2 with missing bitmap costume file', t => { +test('load and then save sprite2 with missing bitmap costume file', () => { const resavedSprite = JSON.parse(vm.toJSON(vm.runtime.targets[2].id)); - t.equal(resavedSprite.name, 'GreenGuy'); - t.equal(resavedSprite.costumes.length, 1); + assert.strictEqual(resavedSprite.name, 'GreenGuy'); + assert.strictEqual(resavedSprite.costumes.length, 1); const missingCostume = resavedSprite.costumes[0]; - t.equal(missingCostume.name, 'GreenGuy'); + assert.strictEqual(missingCostume.name, 'GreenGuy'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data - t.equal(missingCostume.assetId, missingCostumeAssetId); - t.equal(missingCostume.dataFormat, 'png'); + assert.strictEqual(missingCostume.assetId, missingCostumeAssetId); + assert.strictEqual(missingCostume.dataFormat, 'png'); // Test that we didn't save any data about the costume being broken - t.notOk(missingCostume.broken); - - t.end(); + assert.ok(!missingCostume.broken); }); -test('serializeCostume does not save data for missing costume', t => { +test('serializeCostume does not save data for missing costume', () => { const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[2].id); - t.equal(costumeDescs.length, 0); - - t.end(); + assert.strictEqual(costumeDescs.length, 0); }); diff --git a/test/integration/sprite2_missing_svg.js b/test/integration/sprite2_missing_svg.js index bcd9b12f..ba595f39 100644 --- a/test/integration/sprite2_missing_svg.js +++ b/test/integration/sprite2_missing_svg.js @@ -7,7 +7,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); const FakeBitmapAdapter = require('../fixtures/fake-bitmap-adapter'); @@ -44,7 +45,7 @@ global.document = { let vm; -tap.beforeEach(() => { +beforeEach(async () => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -52,55 +53,48 @@ tap.beforeEach(() => { vm.attachRenderer(new FakeRenderer()); vm.attachV2BitmapAdapter(new FakeBitmapAdapter()); - return vm.loadProject(project).then(() => vm.addSprite(sprite)); + await vm.loadProject(project); + return vm.addSprite(sprite); }); -const test = tap.test; - -test('loading sprite2 with missing vector costume file', t => { - t.equal(vm.runtime.targets.length, 3); +test('loading sprite2 with missing vector costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 3); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const blueGuySprite = vm.runtime.targets[2]; - t.equal(blueGuySprite.getName(), 'Blue Guy'); - t.equal(blueGuySprite.getCostumes().length, 1); + assert.strictEqual(blueGuySprite.getName(), 'Blue Guy'); + assert.strictEqual(blueGuySprite.getCostumes().length, 1); const missingCostume = blueGuySprite.getCostumes()[0]; - t.equal(missingCostume.name, 'Blue Guy 2'); + assert.strictEqual(missingCostume.name, 'Blue Guy 2'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data const defaultVectorAssetId = vm.runtime.storage.defaultAssetId.ImageVector; - t.equal(missingCostume.assetId, defaultVectorAssetId); - t.equal(missingCostume.dataFormat, 'svg'); + assert.strictEqual(missingCostume.assetId, defaultVectorAssetId); + assert.strictEqual(missingCostume.dataFormat, 'svg'); // Runtime should have info about broken asset - t.ok(missingCostume.broken); - t.equal(missingCostume.broken.assetId, missingCostumeAssetId); - - t.end(); + assert.ok(missingCostume.broken); + assert.strictEqual(missingCostume.broken.assetId, missingCostumeAssetId); }); -test('load and then save sprite2 with missing vector costume file', t => { +test('load and then save sprite2 with missing vector costume file', () => { const resavedSprite = JSON.parse(vm.toJSON(vm.runtime.targets[2].id)); - t.equal(resavedSprite.name, 'Blue Guy'); - t.equal(resavedSprite.costumes.length, 1); + assert.strictEqual(resavedSprite.name, 'Blue Guy'); + assert.strictEqual(resavedSprite.costumes.length, 1); const missingCostume = resavedSprite.costumes[0]; - t.equal(missingCostume.name, 'Blue Guy 2'); + assert.strictEqual(missingCostume.name, 'Blue Guy 2'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data - t.equal(missingCostume.assetId, missingCostumeAssetId); - t.equal(missingCostume.dataFormat, 'svg'); + assert.strictEqual(missingCostume.assetId, missingCostumeAssetId); + assert.strictEqual(missingCostume.dataFormat, 'svg'); // Test that we didn't save any data about the costume being broken - t.notOk(missingCostume.broken); - - t.end(); + assert.ok(!missingCostume.broken); }); -test('serializeCostume does not save data for missing costume', t => { +test('serializeCostume does not save data for missing costume', () => { const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[2].id); - t.equal(costumeDescs.length, 0); - - t.end(); + assert.strictEqual(costumeDescs.length, 0); }); diff --git a/test/integration/sprite3_corrupted_png.js b/test/integration/sprite3_corrupted_png.js index 98a75687..a581b942 100644 --- a/test/integration/sprite3_corrupted_png.js +++ b/test/integration/sprite3_corrupted_png.js @@ -8,7 +8,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const md5 = require('js-md5'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); @@ -59,9 +60,8 @@ global.document = { let vm; let defaultBitmapAssetId; -tap.setTimeout(30000); -tap.beforeEach(() => { +beforeEach(async () => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -71,56 +71,50 @@ tap.beforeEach(() => { vm.attachRenderer(new FakeRenderer()); vm.attachV2BitmapAdapter(new FakeBitmapAdapter()); - return vm.loadProject(project).then(() => vm.addSprite(sprite)); + await vm.loadProject(project); + return vm.addSprite(sprite); }); -const test = tap.test; - -test('load sprite3 with corrupted bitmap costume file', t => { - t.equal(vm.runtime.targets.length, 3); +test('load sprite3 with corrupted bitmap costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 3); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const greenGuySprite = vm.runtime.targets[2]; - t.equal(greenGuySprite.getName(), 'Green Guy'); - t.equal(greenGuySprite.getCostumes().length, 1); + assert.strictEqual(greenGuySprite.getName(), 'Green Guy'); + assert.strictEqual(greenGuySprite.getCostumes().length, 1); const corruptedCostume = greenGuySprite.getCostumes()[0]; - t.equal(corruptedCostume.name, 'Green Guy'); - t.equal(corruptedCostume.assetId, defaultBitmapAssetId); - t.equal(corruptedCostume.dataFormat, 'png'); + assert.strictEqual(corruptedCostume.name, 'Green Guy'); + assert.strictEqual(corruptedCostume.assetId, defaultBitmapAssetId); + assert.strictEqual(corruptedCostume.dataFormat, 'png'); // Runtime should have info about broken asset - t.ok(corruptedCostume.broken); - t.equal(corruptedCostume.broken.assetId, brokenCostumeMd5); + assert.ok(corruptedCostume.broken); + assert.strictEqual(corruptedCostume.broken.assetId, brokenCostumeMd5); // Verify that we saved the original asset data - t.equal(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); - - t.end(); + assert.strictEqual(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); }); -test('load and then save sprite with corrupted costume file', t => { +test('load and then save sprite with corrupted costume file', () => { const resavedSprite = JSON.parse(vm.toJSON(vm.runtime.targets[2].id)); - t.equal(resavedSprite.name, 'Green Guy'); - t.equal(resavedSprite.costumes.length, 1); + assert.strictEqual(resavedSprite.name, 'Green Guy'); + assert.strictEqual(resavedSprite.costumes.length, 1); const corruptedCostume = resavedSprite.costumes[0]; - t.equal(corruptedCostume.name, 'Green Guy'); + assert.strictEqual(corruptedCostume.name, 'Green Guy'); // Resaved project costume should have the metadata that corresponds to the original broken costume - t.equal(corruptedCostume.assetId, brokenCostumeMd5); - t.equal(corruptedCostume.dataFormat, 'png'); + assert.strictEqual(corruptedCostume.assetId, brokenCostumeMd5); + assert.strictEqual(corruptedCostume.dataFormat, 'png'); // Test that we didn't save any data about the costume being broken - t.notOk(corruptedCostume.broken); - - t.end(); + assert.ok(!corruptedCostume.broken); }); -test('serializeCostume saves orignal broken costume', t => { +test('serializeCostume saves orignal broken costume', () => { const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[2].id); - t.equal(costumeDescs.length, 1); + assert.strictEqual(costumeDescs.length, 1); const costume = costumeDescs[0]; - t.equal(costume.fileName, `${brokenCostumeMd5}.png`); - t.equal(md5(costume.fileContent), brokenCostumeMd5); - t.end(); + assert.strictEqual(costume.fileName, `${brokenCostumeMd5}.png`); + assert.strictEqual(md5(costume.fileContent), brokenCostumeMd5); }); diff --git a/test/integration/sprite3_corrupted_svg.js b/test/integration/sprite3_corrupted_svg.js index f78f468a..11debd86 100644 --- a/test/integration/sprite3_corrupted_svg.js +++ b/test/integration/sprite3_corrupted_svg.js @@ -8,7 +8,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const md5 = require('js-md5'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); @@ -32,7 +33,7 @@ const brokenCostumeMd5 = md5(originalCostume); let vm; let defaultVectorAssetId; -tap.beforeEach(() => { +beforeEach(async () => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -50,56 +51,50 @@ tap.beforeEach(() => { vm.attachRenderer(new FakeRenderer()); - return vm.loadProject(project).then(() => vm.addSprite(sprite)); + await vm.loadProject(project); + return vm.addSprite(sprite); }); -const test = tap.test; - -test('load sprite3 with corrupted vector costume file', t => { - t.equal(vm.runtime.targets.length, 3); +test('load sprite3 with corrupted vector costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 3); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const blueGuySprite = vm.runtime.targets[2]; - t.equal(blueGuySprite.getName(), 'Blue Square Guy'); - t.equal(blueGuySprite.getCostumes().length, 1); + assert.strictEqual(blueGuySprite.getName(), 'Blue Square Guy'); + assert.strictEqual(blueGuySprite.getCostumes().length, 1); const corruptedCostume = blueGuySprite.getCostumes()[0]; - t.equal(corruptedCostume.name, 'costume1'); - t.equal(corruptedCostume.assetId, defaultVectorAssetId); - t.equal(corruptedCostume.dataFormat, 'svg'); + assert.strictEqual(corruptedCostume.name, 'costume1'); + assert.strictEqual(corruptedCostume.assetId, defaultVectorAssetId); + assert.strictEqual(corruptedCostume.dataFormat, 'svg'); // Runtime should have info about broken asset - t.ok(corruptedCostume.broken); - t.equal(corruptedCostume.broken.assetId, brokenCostumeMd5); + assert.ok(corruptedCostume.broken); + assert.strictEqual(corruptedCostume.broken.assetId, brokenCostumeMd5); // Verify that we saved the original asset data - t.equal(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); - - t.end(); + assert.strictEqual(md5(corruptedCostume.broken.asset.data), brokenCostumeMd5); }); -test('load and then save sprite with corrupted costume file', t => { +test('load and then save sprite with corrupted costume file', () => { const resavedSprite = JSON.parse(vm.toJSON(vm.runtime.targets[2].id)); - t.equal(resavedSprite.name, 'Blue Square Guy'); - t.equal(resavedSprite.costumes.length, 1); + assert.strictEqual(resavedSprite.name, 'Blue Square Guy'); + assert.strictEqual(resavedSprite.costumes.length, 1); const corruptedCostume = resavedSprite.costumes[0]; - t.equal(corruptedCostume.name, 'costume1'); + assert.strictEqual(corruptedCostume.name, 'costume1'); // Resaved project costume should have the metadata that corresponds to the original broken costume - t.equal(corruptedCostume.assetId, brokenCostumeMd5); - t.equal(corruptedCostume.dataFormat, 'svg'); + assert.strictEqual(corruptedCostume.assetId, brokenCostumeMd5); + assert.strictEqual(corruptedCostume.dataFormat, 'svg'); // Test that we didn't save any data about the costume being broken - t.notOk(corruptedCostume.broken); - - t.end(); + assert.ok(!corruptedCostume.broken); }); -test('serializeCostume saves orignal broken costume', t => { +test('serializeCostume saves orignal broken costume', () => { const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[2].id); - t.equal(costumeDescs.length, 1); + assert.strictEqual(costumeDescs.length, 1); const costume = costumeDescs[0]; - t.equal(costume.fileName, `${brokenCostumeMd5}.svg`); - t.equal(md5(costume.fileContent), brokenCostumeMd5); - t.end(); + assert.strictEqual(costume.fileName, `${brokenCostumeMd5}.svg`); + assert.strictEqual(md5(costume.fileContent), brokenCostumeMd5); }); diff --git a/test/integration/sprite3_missing_png.js b/test/integration/sprite3_missing_png.js index b35bdbbb..eeafb372 100644 --- a/test/integration/sprite3_missing_png.js +++ b/test/integration/sprite3_missing_png.js @@ -7,7 +7,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); const FakeBitmapAdapter = require('../fixtures/fake-bitmap-adapter'); @@ -44,9 +45,7 @@ global.document = { let vm; -tap.setTimeout(30000); - -tap.beforeEach(() => { +beforeEach(async () => { const storage = makeTestStorage(); vm = new VirtualMachine(); @@ -54,55 +53,48 @@ tap.beforeEach(() => { vm.attachRenderer(new FakeRenderer()); vm.attachV2BitmapAdapter(new FakeBitmapAdapter()); - return vm.loadProject(project).then(() => vm.addSprite(sprite)); + await vm.loadProject(project); + return vm.addSprite(sprite); }); -const test = tap.test; - -test('loading sprite3 with missing bitmap costume file', t => { - t.equal(vm.runtime.targets.length, 3); +test('loading sprite3 with missing bitmap costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 3); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const greenGuySprite = vm.runtime.targets[2]; - t.equal(greenGuySprite.getName(), 'Green Guy'); - t.equal(greenGuySprite.getCostumes().length, 1); + assert.strictEqual(greenGuySprite.getName(), 'Green Guy'); + assert.strictEqual(greenGuySprite.getCostumes().length, 1); const missingCostume = greenGuySprite.getCostumes()[0]; - t.equal(missingCostume.name, 'Green Guy'); + assert.strictEqual(missingCostume.name, 'Green Guy'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data const defaultBitmapAssetId = vm.runtime.storage.defaultAssetId.ImageBitmap; - t.equal(missingCostume.assetId, defaultBitmapAssetId); - t.equal(missingCostume.dataFormat, 'png'); + assert.strictEqual(missingCostume.assetId, defaultBitmapAssetId); + assert.strictEqual(missingCostume.dataFormat, 'png'); // Runtime should have info about broken asset - t.ok(missingCostume.broken); - t.equal(missingCostume.broken.assetId, missingCostumeAssetId); - - t.end(); + assert.ok(missingCostume.broken); + assert.strictEqual(missingCostume.broken.assetId, missingCostumeAssetId); }); -test('load and then save sprite3 with missing bitmap costume file', t => { +test('load and then save sprite3 with missing bitmap costume file', () => { const resavedSprite = JSON.parse(vm.toJSON(vm.runtime.targets[2].id)); - t.equal(resavedSprite.name, 'Green Guy'); - t.equal(resavedSprite.costumes.length, 1); + assert.strictEqual(resavedSprite.name, 'Green Guy'); + assert.strictEqual(resavedSprite.costumes.length, 1); const missingCostume = resavedSprite.costumes[0]; - t.equal(missingCostume.name, 'Green Guy'); + assert.strictEqual(missingCostume.name, 'Green Guy'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data - t.equal(missingCostume.assetId, missingCostumeAssetId); - t.equal(missingCostume.dataFormat, 'png'); + assert.strictEqual(missingCostume.assetId, missingCostumeAssetId); + assert.strictEqual(missingCostume.dataFormat, 'png'); // Test that we didn't save any data about the costume being broken - t.notOk(missingCostume.broken); - - t.end(); + assert.ok(!missingCostume.broken); }); -test('serializeCostume does not save data for missing costume', t => { +test('serializeCostume does not save data for missing costume', () => { const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[2].id); - t.equal(costumeDescs.length, 0); - - t.end(); + assert.strictEqual(costumeDescs.length, 0); }); diff --git a/test/integration/sprite3_missing_svg.js b/test/integration/sprite3_missing_svg.js index 1fdbb458..18ba8846 100644 --- a/test/integration/sprite3_missing_svg.js +++ b/test/integration/sprite3_missing_svg.js @@ -7,7 +7,8 @@ * to load the costume if the saved project is re-loaded. */ const path = require('path'); -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const FakeRenderer = require('../fixtures/fake-renderer'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; @@ -25,62 +26,55 @@ const missingCostumeAssetId = 'a267f8b97ee9cf8aa9832aa0b4cfd9eb'; let vm; -tap.beforeEach(() => { +beforeEach(async () => { const storage = makeTestStorage(); vm = new VirtualMachine(); vm.attachStorage(storage); vm.attachRenderer(new FakeRenderer()); - return vm.loadProject(project).then(() => vm.addSprite(sprite)); + await vm.loadProject(project); + return vm.addSprite(sprite); }); -const test = tap.test; - -test('loading sprite3 with missing vector costume file', t => { - t.equal(vm.runtime.targets.length, 3); +test('loading sprite3 with missing vector costume file', () => { + assert.strictEqual(vm.runtime.targets.length, 3); const stage = vm.runtime.targets[0]; - t.ok(stage.isStage); + assert.ok(stage.isStage); const blueGuySprite = vm.runtime.targets[2]; - t.equal(blueGuySprite.getName(), 'Blue Square Guy'); - t.equal(blueGuySprite.getCostumes().length, 1); + assert.strictEqual(blueGuySprite.getName(), 'Blue Square Guy'); + assert.strictEqual(blueGuySprite.getCostumes().length, 1); const missingCostume = blueGuySprite.getCostumes()[0]; - t.equal(missingCostume.name, 'costume1'); + assert.strictEqual(missingCostume.name, 'costume1'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data const defaultVectorAssetId = vm.runtime.storage.defaultAssetId.ImageVector; - t.equal(missingCostume.assetId, defaultVectorAssetId); - t.equal(missingCostume.dataFormat, 'svg'); + assert.strictEqual(missingCostume.assetId, defaultVectorAssetId); + assert.strictEqual(missingCostume.dataFormat, 'svg'); // Runtime should have info about broken asset - t.ok(missingCostume.broken); - t.equal(missingCostume.broken.assetId, missingCostumeAssetId); - - t.end(); + assert.ok(missingCostume.broken); + assert.strictEqual(missingCostume.broken.assetId, missingCostumeAssetId); }); -test('load and then save sprite3 with missing vector costume file', t => { +test('load and then save sprite3 with missing vector costume file', () => { const resavedSprite = JSON.parse(vm.toJSON(vm.runtime.targets[2].id)); - t.equal(resavedSprite.name, 'Blue Square Guy'); - t.equal(resavedSprite.costumes.length, 1); + assert.strictEqual(resavedSprite.name, 'Blue Square Guy'); + assert.strictEqual(resavedSprite.costumes.length, 1); const missingCostume = resavedSprite.costumes[0]; - t.equal(missingCostume.name, 'costume1'); + assert.strictEqual(missingCostume.name, 'costume1'); // Costume should have both default cosutme (e.g. Gray Question Mark) data and original data - t.equal(missingCostume.assetId, missingCostumeAssetId); - t.equal(missingCostume.dataFormat, 'svg'); + assert.strictEqual(missingCostume.assetId, missingCostumeAssetId); + assert.strictEqual(missingCostume.dataFormat, 'svg'); // Test that we didn't save any data about the costume being broken - t.notOk(missingCostume.broken); - - t.end(); + assert.ok(!missingCostume.broken); }); -test('serializeCostume does not save data for missing costume', t => { +test('serializeCostume does not save data for missing costume', () => { const costumeDescs = serializeCostumes(vm.runtime, vm.runtime.targets[2].id); - t.equal(costumeDescs.length, 0); - - t.end(); + assert.strictEqual(costumeDescs.length, 0); }); diff --git a/test/integration/stack-click.js b/test/integration/stack-click.js index a6911064..928b3431 100644 --- a/test/integration/stack-click.js +++ b/test/integration/stack-click.js @@ -1,5 +1,6 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); @@ -14,20 +15,20 @@ const project = readFileToBuffer(projectUri); * The intention is to make sure that the stack can be activated by a stack click * even when the hat predicate is false. */ -test('stack click activates the stack', t => { +test('stack click activates the stack', (t, done) => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); // Evaluate playground data and exit vm.on('playgroundData', () => { // The sprite should have moved 100 to the right - t.equal(vm.editingTarget.x, 100); + assert.strictEqual(vm.editingTarget.x, 100); vm.quit(); - t.end(); + done(); }); // Start VM, load project, and run - t.doesNotThrow(() => { + assert.doesNotThrow(() => { vm.start(); vm.clear(); vm.setCompatibilityMode(false); @@ -37,7 +38,7 @@ test('stack click activates the stack', t => { const allBlocks = blockContainer._blocks; // Confirm the editing target is initially at 0 - t.equal(vm.editingTarget.x, 0); + assert.strictEqual(vm.editingTarget.x, 0); // Find hat for greater than and click it for (const blockId in allBlocks) { diff --git a/test/integration/tw-block-stop-thread.js b/test/integration/tw-block-stop-thread.js index b3a7c3cd..f06ad600 100644 --- a/test/integration/tw-block-stop-thread.js +++ b/test/integration/tw-block-stop-thread.js @@ -1,4 +1,5 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const fs = require('fs'); const path = require('path'); const VM = require('../../src/virtual-machine'); @@ -16,9 +17,8 @@ const stopBySetStatus = thread => { thread.status = Thread.STATUS_DONE; }; -test('constants', t => { - t.equal(Thread.STATUS_DONE, 4); - t.end(); +test('constants', () => { + assert.strictEqual(Thread.STATUS_DONE, 4); }); for (const [enableCompiler, stopFunction] of [ @@ -29,10 +29,10 @@ for (const [enableCompiler, stopFunction] of [ ]) { const subtestName = `${enableCompiler ? 'compiler' : 'interpreter'} - ${stopFunction.name}`; - test(`${subtestName} - stop in command block`, t => { + test(`${subtestName} - stop in command block`, async () => { const vm = new VM(); vm.setCompilerOptions({enabled: enableCompiler}); - t.equal(vm.runtime.compilerOptions.enabled, enableCompiler); + assert.strictEqual(vm.runtime.compilerOptions.enabled, enableCompiler); const callOrder = []; vm.addAddonBlock({ @@ -58,21 +58,19 @@ for (const [enableCompiler, stopFunction] of [ } }); - vm.loadProject(fixtureData).then(() => { - vm.greenFlag(); - vm.runtime._step(); - t.same(callOrder, [ - ['input block', {}], - ['first block', {'number or text': 1}] - ]); - t.end(); - }); + await vm.loadProject(fixtureData); + vm.greenFlag(); + vm.runtime._step(); + assert.deepEqual(callOrder, [ + ['input block', {}], + ['first block', {'number or text': 1}] + ]); }); - test(`${subtestName} - stop in command block after yielding once`, t => { + test(`${subtestName} - stop in command block after yielding once`, async () => { const vm = new VM(); vm.setCompilerOptions({enabled: enableCompiler}); - t.equal(vm.runtime.compilerOptions.enabled, enableCompiler); + assert.strictEqual(vm.runtime.compilerOptions.enabled, enableCompiler); const callOrder = []; vm.addAddonBlock({ @@ -100,21 +98,19 @@ for (const [enableCompiler, stopFunction] of [ } }); - vm.loadProject(fixtureData).then(() => { - vm.greenFlag(); - vm.runtime._step(); - t.same(callOrder, [ - ['first block', {'number or text': 5}], - ['first block', {'number or text': 5}] - ]); - t.end(); - }); + await vm.loadProject(fixtureData); + vm.greenFlag(); + vm.runtime._step(); + assert.deepEqual(callOrder, [ + ['first block', {'number or text': 5}], + ['first block', {'number or text': 5}] + ]); }); - test(`${subtestName} - stop in reporter block`, t => { + test(`${subtestName} - stop in reporter block`, async () => { const vm = new VM(); vm.setCompilerOptions({enabled: enableCompiler}); - t.equal(vm.runtime.compilerOptions.enabled, enableCompiler); + assert.strictEqual(vm.runtime.compilerOptions.enabled, enableCompiler); const callOrder = []; vm.addAddonBlock({ @@ -140,20 +136,18 @@ for (const [enableCompiler, stopFunction] of [ } }); - vm.loadProject(fixtureData).then(() => { - vm.greenFlag(); - vm.runtime._step(); - t.same(callOrder, [ - ['input block', {}] - ]); - t.end(); - }); + await vm.loadProject(fixtureData); + vm.greenFlag(); + vm.runtime._step(); + assert.deepEqual(callOrder, [ + ['input block', {}] + ]); }); - test(`${subtestName} - stop in reporter block after yielding once`, t => { + test(`${subtestName} - stop in reporter block after yielding once`, async () => { const vm = new VM(); vm.setCompilerOptions({enabled: enableCompiler}); - t.equal(vm.runtime.compilerOptions.enabled, enableCompiler); + assert.strictEqual(vm.runtime.compilerOptions.enabled, enableCompiler); const callOrder = []; vm.addAddonBlock({ @@ -185,14 +179,12 @@ for (const [enableCompiler, stopFunction] of [ } }); - vm.loadProject(fixtureData).then(() => { - vm.greenFlag(); - vm.runtime._step(); - t.same(callOrder, [ - ['input block', {}], - ['input block', {}] - ]); - t.end(); - }); + await vm.loadProject(fixtureData); + vm.greenFlag(); + vm.runtime._step(); + assert.deepEqual(callOrder, [ + ['input block', {}], + ['input block', {}] + ]); }); } diff --git a/test/integration/tw-snapshots.js b/test/integration/tw-snapshots.js index 4f4edc96..5148ef5f 100644 --- a/test/integration/tw-snapshots.js +++ b/test/integration/tw-snapshots.js @@ -1,23 +1,21 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const Snapshots = require('../snapshot/lib'); for (const testCase of Snapshots.tests) { // eslint-disable-next-line no-loop-func - test(testCase.id, async t => { + test(testCase.id, async () => { const expected = Snapshots.getExpectedSnapshot(testCase); const actual = await Snapshots.generateActualSnapshot(testCase); const result = Snapshots.compareSnapshots(expected, actual); - if (result === 'VALID') { - t.pass('matches'); - } else if (result === 'INPUT_MODIFIED') { - t.fail('input project changed; run: node test/snapshot --update'); + if (result === 'INPUT_MODIFIED') { + assert.fail('input project changed; run: node test/snapshot --update'); } else if (result === 'MISSING_SNAPSHOT') { - t.fail('snapshot is missing; run: node test/snapshot --update'); - } else { - // This assertion will always fail, but tap will print out the snapshots + assert.fail('snapshot is missing; run: node test/snapshot --update'); + } else if (result !== 'VALID') { + // This assertion will always fail, but it will print out the snapshots // for easier comparison. - t.equal(expected, actual, 'did not match; you may have to run: node test/snapshot --update'); + assert.strictEqual(expected, actual, 'did not match; you may have to run: node test/snapshot --update'); } - t.end(); }); } diff --git a/test/integration/tw_add_builtin_extension.js b/test/integration/tw_add_builtin_extension.js index 9992b295..297c1343 100644 --- a/test/integration/tw_add_builtin_extension.js +++ b/test/integration/tw_add_builtin_extension.js @@ -1,6 +1,7 @@ const fs = require('fs'); const path = require('path'); -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const VM = require('../../src/virtual-machine'); const Scratch = require('../../src/extension-support/tw-extension-api-common'); @@ -23,23 +24,27 @@ class TestBuiltinExtension { } } -test('addBuiltingExtension', t => { +test('addBuiltingExtension', (t, done) => { const vm = new VM(); - t.equal(vm.extensionManager.isBuiltinExtension('testbuiltin'), false, 'extension is not known'); - t.equal(vm.extensionManager.isExtensionLoaded('testbuiltin'), false, 'extension is not loaded'); + assert.strictEqual(vm.extensionManager.isBuiltinExtension('testbuiltin'), false, 'extension is not known'); + assert.strictEqual(vm.extensionManager.isExtensionLoaded('testbuiltin'), false, 'extension is not loaded'); vm.extensionManager.addBuiltinExtension('testbuiltin', TestBuiltinExtension); - t.equal(vm.extensionManager.isBuiltinExtension('testbuiltin'), true, 'extension is now known'); - t.equal(vm.extensionManager.isExtensionLoaded('testbuiltin'), false, 'extension is still not loaded'); + assert.strictEqual(vm.extensionManager.isBuiltinExtension('testbuiltin'), true, 'extension is now known'); + assert.strictEqual(vm.extensionManager.isExtensionLoaded('testbuiltin'), false, 'extension is still not loaded'); const fixture = fs.readFileSync(path.join(__dirname, '..', 'fixtures', 'tw-add-builtin-extension.sb3')); vm.loadProject(fixture).then(() => { - t.equal(vm.extensionManager.isExtensionLoaded('testbuiltin'), true, 'extension was loaded automatically'); + assert.strictEqual( + vm.extensionManager.isExtensionLoaded('testbuiltin'), + true, + 'extension was loaded automatically' + ); vm.runtime.on('SAY', (target, type, text) => { - t.equal(text, 'It works! 123', 'said value from extension'); - t.end(); + assert.strictEqual(text, 'It works! 123', 'said value from extension'); + done(); }); vm.greenFlag(); @@ -47,14 +52,12 @@ test('addBuiltingExtension', t => { }); }); -test('each runtime has own set of extensions', t => { +test('each runtime has own set of extensions', () => { const vm1 = new VM(); const vm2 = new VM(); vm1.extensionManager.addBuiltinExtension('testbuiltin', TestBuiltinExtension); - t.ok(vm1.extensionManager.isBuiltinExtension('testbuiltin')); - t.notOk(vm2.extensionManager.isBuiltinExtension('testbuiltin')); - - t.end(); + assert.ok(vm1.extensionManager.isBuiltinExtension('testbuiltin')); + assert.ok(!vm2.extensionManager.isBuiltinExtension('testbuiltin')); }); diff --git a/test/integration/tw_addon_blocks.js b/test/integration/tw_addon_blocks.js index c83f9567..59d86303 100644 --- a/test/integration/tw_addon_blocks.js +++ b/test/integration/tw_addon_blocks.js @@ -1,4 +1,5 @@ -const tap = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const fs = require('fs'); const path = require('path'); const VirtualMachine = require('../../src/virtual-machine'); @@ -6,14 +7,14 @@ const Thread = require('../../src/engine/thread'); const fixtureData = fs.readFileSync(path.join(__dirname, '..', 'fixtures', 'tw-addon-blocks.sb3')); -const runExecutionTests = compilerEnabled => test => { +const runExecutionTests = compilerEnabled => async parent => { const load = async () => { const vm = new VirtualMachine(); vm.setCompilerOptions({ enabled: compilerEnabled }); vm.on('COMPILE_ERROR', (target, error) => { - test.fail(`Compile error in ${target.getName()}: ${error}`); + assert.fail(`Compile error in ${target.getName()}: ${error}`); }); await vm.loadProject(fixtureData); return vm; @@ -24,192 +25,172 @@ const runExecutionTests = compilerEnabled => test => { return variable.value; }; - test.test('baseline - no addon blocks', t => { - load().then(vm => { - t.equal(getVar(vm, 'block 1'), 'initial'); - t.equal(getVar(vm, 'block 2'), 'initial'); - t.equal(getVar(vm, 'block 3'), 'initial'); - t.equal(getVar(vm, 'block 4'), 'initial'); - t.equal(getVar(vm, 'block 4 output'), 'initial'); + await parent.test('baseline - no addon blocks', async () => { + const vm = await load(); + assert.strictEqual(getVar(vm, 'block 1'), 'initial'); + assert.strictEqual(getVar(vm, 'block 2'), 'initial'); + assert.strictEqual(getVar(vm, 'block 3'), 'initial'); + assert.strictEqual(getVar(vm, 'block 4'), 'initial'); + assert.strictEqual(getVar(vm, 'block 4 output'), 'initial'); - vm.greenFlag(); - vm.runtime._step(); + vm.greenFlag(); + vm.runtime._step(); - t.equal(getVar(vm, 'block 1'), 'block 1 ran'); - t.equal(getVar(vm, 'block 2'), 'block 2: banana'); - t.equal(getVar(vm, 'block 3'), 'block 3 ran'); - t.equal(getVar(vm, 'block 4'), 'block 4 ran'); - t.equal(getVar(vm, 'block 4 output'), 'block 4: apple'); - - t.end(); - }); + assert.strictEqual(getVar(vm, 'block 1'), 'block 1 ran'); + assert.strictEqual(getVar(vm, 'block 2'), 'block 2: banana'); + assert.strictEqual(getVar(vm, 'block 3'), 'block 3 ran'); + assert.strictEqual(getVar(vm, 'block 4'), 'block 4 ran'); + assert.strictEqual(getVar(vm, 'block 4 output'), 'block 4: apple'); }); - test.test('simple statement blocks', t => { - load().then(vm => { - t.plan(9); + await parent.test('simple statement blocks', async t => { + const vm = await load(); + t.plan(9); - let calledBlock1 = false; - let calledBlock2 = false; + let calledBlock1 = false; + let calledBlock2 = false; - vm.addAddonBlock({ - procedureCode: 'block 1', - callback: (args, util) => { - calledBlock1 = true; - t.same(args, {}); - t.ok(util.thread instanceof Thread); - // may have to update when project changes - t.equal(util.thread.peekStack(), 'd'); - } - }); - - vm.addAddonBlock({ - procedureCode: 'block 2 %s', - arguments: ['number or text'], - callback: (args, util) => { - calledBlock2 = true; - t.same(args, { - 'number or text': 'banana' - }); - // may have to update when project changes - t.equal(util.thread.peekStack(), 'c'); - } - }); - - vm.greenFlag(); - vm.runtime._step(); - - t.ok(calledBlock1); - t.ok(calledBlock2); - - // Overridden blocks should not run - t.equal(getVar(vm, 'block 1'), 'false'); - t.equal(getVar(vm, 'block 2'), 'false'); - - t.end(); - }); - }); - - test.test('yield with thread.status = STATUS_PROMISE_WAIT', t => { - load().then(vm => { - t.plan(7); - - let threadToResume; - let ranBlock3 = false; - vm.addAddonBlock({ - procedureCode: 'block 3', - callback: (args, util) => { - ranBlock3 = true; - util.thread.status = Thread.STATUS_PROMISE_WAIT; - threadToResume = util.thread; - }, - arguments: [] - }); - - vm.greenFlag(); - vm.runtime._step(); - - // Make sure we paused it - t.ok(ranBlock3); - t.equal(threadToResume.status, Thread.STATUS_PROMISE_WAIT); - - // Should've stopped after block 2 - t.equal(getVar(vm, 'block 2'), 'block 2: banana'); - t.equal(getVar(vm, 'block 3'), 'false'); - t.equal(getVar(vm, 'block 4'), 'false'); - - threadToResume.status = Thread.STATUS_RUNNING; - vm.runtime._step(); - - // Should've finished running - t.equal(getVar(vm, 'block 3'), 'false'); // overridden, should not run - t.equal(getVar(vm, 'block 4'), 'block 4 ran'); - - t.end(); - }); - }); - - test.test('yield with util.yield()', t => { - load().then(vm => { - t.plan(10); - - let shouldYield = true; - let calledBlock1 = 0; - - vm.addAddonBlock({ - procedureCode: 'block 1', - callback: (args, util) => { - calledBlock1++; - - if (shouldYield) { - util.runtime.requestRedraw(); - util.yield(); - } - }, - arguments: [] - }); - - vm.greenFlag(); - for (let i = 0; i < 10; i++) { - vm.runtime._step(); + vm.addAddonBlock({ + procedureCode: 'block 1', + callback: (args, util) => { + calledBlock1 = true; + t.assert.deepEqual(args, {}); + t.assert.ok(util.thread instanceof Thread); + // may have to update when project changes + t.assert.strictEqual(util.thread.peekStack(), 'd'); } - - t.equal(calledBlock1, 10); - t.equal(getVar(vm, 'block 1'), 'false'); - t.equal(getVar(vm, 'block 2'), 'false'); - t.equal(getVar(vm, 'block 3'), 'false'); - t.equal(getVar(vm, 'block 4'), 'false'); - - shouldYield = false; - vm.runtime._step(); - - t.equal(calledBlock1, 11); - t.equal(getVar(vm, 'block 1'), 'false'); // overrridden, should not run - t.equal(getVar(vm, 'block 2'), 'block 2: banana'); - t.equal(getVar(vm, 'block 3'), 'block 3 ran'); - t.equal(getVar(vm, 'block 4'), 'block 4 ran'); - - t.end(); }); + + vm.addAddonBlock({ + procedureCode: 'block 2 %s', + arguments: ['number or text'], + callback: (args, util) => { + calledBlock2 = true; + t.assert.deepEqual(args, { + 'number or text': 'banana' + }); + // may have to update when project changes + t.assert.strictEqual(util.thread.peekStack(), 'c'); + } + }); + + vm.greenFlag(); + vm.runtime._step(); + + t.assert.ok(calledBlock1); + t.assert.ok(calledBlock2); + + // Overridden blocks should not run + t.assert.strictEqual(getVar(vm, 'block 1'), 'false'); + t.assert.strictEqual(getVar(vm, 'block 2'), 'false'); }); - test.test('yield with resolved Promise', t => { - load().then(vm => { - let resolveCallback; - vm.addAddonBlock({ - procedureCode: 'block 2 %s', - arguments: ['number or text'], - callback: () => new Promise(resolve => { - resolveCallback = resolve; - }) - }); - - vm.greenFlag(); - for (let i = 0; i < 5; i++) { - vm.runtime._step(); - } - - t.type(resolveCallback, 'function'); - t.equal(getVar(vm, 'block 1'), 'block 1 ran'); - t.equal(getVar(vm, 'block 2'), 'false'); - t.equal(getVar(vm, 'block 3'), 'false'); - t.equal(getVar(vm, 'block 4'), 'false'); - - resolveCallback(); - Promise.resolve().then(() => { - vm.runtime._step(); - t.equal(getVar(vm, 'block 2'), 'false'); // overridden, should not run - t.equal(getVar(vm, 'block 3'), 'block 3 ran'); - t.equal(getVar(vm, 'block 4'), 'block 4 ran'); - - t.end(); - }); + await parent.test('yield with thread.status = STATUS_PROMISE_WAIT', async () => { + const vm = await load(); + let threadToResume; + let ranBlock3 = false; + vm.addAddonBlock({ + procedureCode: 'block 3', + callback: (args, util) => { + ranBlock3 = true; + util.thread.status = Thread.STATUS_PROMISE_WAIT; + threadToResume = util.thread; + }, + arguments: [] }); + + vm.greenFlag(); + vm.runtime._step(); + + // Make sure we paused it + assert.ok(ranBlock3); + assert.strictEqual(threadToResume.status, Thread.STATUS_PROMISE_WAIT); + + // Should've stopped after block 2 + assert.strictEqual(getVar(vm, 'block 2'), 'block 2: banana'); + assert.strictEqual(getVar(vm, 'block 3'), 'false'); + assert.strictEqual(getVar(vm, 'block 4'), 'false'); + + threadToResume.status = Thread.STATUS_RUNNING; + vm.runtime._step(); + + // Should've finished running + assert.strictEqual(getVar(vm, 'block 3'), 'false'); // overridden, should not run + assert.strictEqual(getVar(vm, 'block 4'), 'block 4 ran'); + }); + + await parent.test('yield with util.yield()', async () => { + const vm = await load(); + let shouldYield = true; + let calledBlock1 = 0; + + vm.addAddonBlock({ + procedureCode: 'block 1', + callback: (args, util) => { + calledBlock1++; + + if (shouldYield) { + util.runtime.requestRedraw(); + util.yield(); + } + }, + arguments: [] + }); + + vm.greenFlag(); + for (let i = 0; i < 10; i++) { + vm.runtime._step(); + } + + assert.strictEqual(calledBlock1, 10); + assert.strictEqual(getVar(vm, 'block 1'), 'false'); + assert.strictEqual(getVar(vm, 'block 2'), 'false'); + assert.strictEqual(getVar(vm, 'block 3'), 'false'); + assert.strictEqual(getVar(vm, 'block 4'), 'false'); + + shouldYield = false; + vm.runtime._step(); + + assert.strictEqual(calledBlock1, 11); + assert.strictEqual(getVar(vm, 'block 1'), 'false'); // overrridden, should not run + assert.strictEqual(getVar(vm, 'block 2'), 'block 2: banana'); + assert.strictEqual(getVar(vm, 'block 3'), 'block 3 ran'); + assert.strictEqual(getVar(vm, 'block 4'), 'block 4 ran'); + }); + + await parent.test('yield with resolved Promise', async () => { + const vm = await load(); + let resolveCallback; + vm.addAddonBlock({ + procedureCode: 'block 2 %s', + arguments: ['number or text'], + callback: () => new Promise(resolve => { + resolveCallback = resolve; + }) + }); + + vm.greenFlag(); + for (let i = 0; i < 5; i++) { + vm.runtime._step(); + } + + assert.strictEqual(typeof resolveCallback, 'function'); + assert.strictEqual(getVar(vm, 'block 1'), 'block 1 ran'); + assert.strictEqual(getVar(vm, 'block 2'), 'false'); + assert.strictEqual(getVar(vm, 'block 3'), 'false'); + assert.strictEqual(getVar(vm, 'block 4'), 'false'); + + resolveCallback(); + await Promise.resolve(); + vm.runtime._step(); + assert.strictEqual(getVar(vm, 'block 2'), 'false'); // overridden, should not run + assert.strictEqual(getVar(vm, 'block 3'), 'block 3 ran'); + assert.strictEqual(getVar(vm, 'block 4'), 'block 4 ran'); }); /* // Doesn't work right now -- not clear whether it should or not - test.skip('yield with rejected Promise', t => { + parent.test.skip('yield with rejected Promise', t => { load().then(vm => { let rejectCallback; vm.addAddonBlock({ @@ -244,39 +225,34 @@ const runExecutionTests = compilerEnabled => test => { }); */ - test.test('returning values', t => { - load().then(vm => { - vm.addAddonBlock({ - procedureCode: 'block 4 %s', - callback: args => { - t.same(args, { - 'number or text': 'apple' - }); - return `value from addon block: ${args['number or text']}`; - }, - arguments: ['number or text'] - }); - - vm.greenFlag(); - vm.runtime._step(); - - t.equal(getVar(vm, 'block 1'), 'block 1 ran'); - t.equal(getVar(vm, 'block 2'), 'block 2: banana'); - t.equal(getVar(vm, 'block 3'), 'block 3 ran'); - t.equal(getVar(vm, 'block 4'), 'false'); // block 4 itself should not have run, we overrode it - t.equal(getVar(vm, 'block 4 output'), 'value from addon block: apple'); - - t.end(); + await parent.test('returning values', async () => { + const vm = await load(); + vm.addAddonBlock({ + procedureCode: 'block 4 %s', + callback: args => { + assert.deepEqual(args, { + 'number or text': 'apple' + }); + return `value from addon block: ${args['number or text']}`; + }, + arguments: ['number or text'] }); - }); - test.end(); + vm.greenFlag(); + vm.runtime._step(); + + assert.strictEqual(getVar(vm, 'block 1'), 'block 1 ran'); + assert.strictEqual(getVar(vm, 'block 2'), 'block 2: banana'); + assert.strictEqual(getVar(vm, 'block 3'), 'block 3 ran'); + assert.strictEqual(getVar(vm, 'block 4'), 'false'); // block 4 itself should not have run, we overrode it + assert.strictEqual(getVar(vm, 'block 4 output'), 'value from addon block: apple'); + }); }; -tap.test('with compiler disabled', runExecutionTests(false)); -tap.test('with compiler enabled', runExecutionTests(true)); +test('with compiler disabled', runExecutionTests(false)); +test('with compiler enabled', runExecutionTests(true)); -tap.test('block info', t => { +test('block info', () => { const vm = new VirtualMachine(); const BLOCK_INFO_ID = 'a-b'; @@ -289,7 +265,7 @@ tap.test('block info', t => { }); let blockInfo = vm.runtime._blockInfo.find(i => i.id === BLOCK_INFO_ID); - t.equal(blockInfo, undefined); + assert.strictEqual(blockInfo, undefined); vm.addAddonBlock({ procedureCode: 'statement %s', @@ -304,12 +280,12 @@ tap.test('block info', t => { }); blockInfo = vm.runtime._blockInfo.find(i => i.id === BLOCK_INFO_ID); - t.type(blockInfo.id, 'string'); - t.type(blockInfo.name, 'string'); - t.type(blockInfo.color1, 'string'); - t.type(blockInfo.color2, 'string'); - t.type(blockInfo.color3, 'string'); - t.same(blockInfo.blocks, [ + assert.strictEqual(typeof blockInfo.id, 'string'); + assert.strictEqual(typeof blockInfo.name, 'string'); + assert.strictEqual(typeof blockInfo.color1, 'string'); + assert.strictEqual(typeof blockInfo.color2, 'string'); + assert.strictEqual(typeof blockInfo.color3, 'string'); + assert.deepEqual(blockInfo.blocks, [ { info: {}, // eslint-disable-next-line max-len @@ -321,6 +297,4 @@ tap.test('block info', t => { xml: '' } ]); - - t.end(); }); diff --git a/test/integration/tw_allow_drop_anywhere.js b/test/integration/tw_allow_drop_anywhere.js index 0bc19fbc..8053e6cb 100644 --- a/test/integration/tw_allow_drop_anywhere.js +++ b/test/integration/tw_allow_drop_anywhere.js @@ -1,16 +1,16 @@ -const {test} = require('tap'); +const {test} = require('node:test'); const Runtime = require('../../src/engine/runtime'); const BlockType = require('../../src/extension-support/block-type'); -test('allowDropAnywhere', t => { +test('allowDropAnywhere', (t, done) => { t.plan(2); const rt = new Runtime(); rt.on('EXTENSION_ADDED', json => { - t.equal(json.blocks[0].json.output, 'String'); - t.equal(json.blocks[1].json.output, null); - t.end(); + t.assert.strictEqual(json.blocks[0].json.output, 'String'); + t.assert.strictEqual(json.blocks[1].json.output, null); + done(); }); rt._registerExtensionPrimitives({ diff --git a/test/integration/tw_asset_progress.js b/test/integration/tw_asset_progress.js index 4eccf9d3..782431c1 100644 --- a/test/integration/tw_asset_progress.js +++ b/test/integration/tw_asset_progress.js @@ -1,4 +1,5 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const fs = require('fs'); const path = require('path'); const Runtime = require('../../src/engine/runtime'); @@ -6,19 +7,19 @@ const VirtualMachine = require('../../src/virtual-machine'); const makeTestStorage = require('../fixtures/make-test-storage'); const AssetUtil = require('../../src/util/tw-asset-util'); -test('emitAssetProgress', t => { +test('emitAssetProgress', () => { const vm = new VirtualMachine(); let runtimeOK = false; let vmOK = false; vm.runtime.on('ASSET_PROGRESS', (finished, total) => { - t.equal(finished, 1, 'runtime finished'); - t.equal(total, 2, 'runtime total'); + assert.strictEqual(finished, 1, 'runtime finished'); + assert.strictEqual(total, 2, 'runtime total'); runtimeOK = true; }); vm.on('ASSET_PROGRESS', (finished, total) => { - t.equal(finished, 1, 'vm finished'); - t.equal(total, 2, 'vm total'); + assert.strictEqual(finished, 1, 'vm finished'); + assert.strictEqual(total, 2, 'vm total'); vmOK = true; }); @@ -26,9 +27,8 @@ test('emitAssetProgress', t => { vm.runtime.finishedAssetRequests = 1; vm.runtime.emitAssetProgress(); - t.ok(runtimeOK, 'runtime'); - t.ok(vmOK, 'vm'); - t.end(); + assert.ok(runtimeOK, 'runtime'); + assert.ok(vmOK, 'vm'); }); test('resetProgress', t => { @@ -39,28 +39,26 @@ test('resetProgress', t => { runtime.totalAssetRequests = 10; runtime.on('ASSET_PROGRESS', (finished, total) => { - t.equal(finished, 0, 'event finished'); - t.equal(total, 0, 'event total'); + t.assert.strictEqual(finished, 0, 'event finished'); + t.assert.strictEqual(total, 0, 'event total'); }); runtime.resetProgress(); - t.equal(runtime.finishedAssetRequests, 0, 'property finishedAssetRequests'); - t.equal(runtime.totalAssetRequests, 0, 'property totalAssetRequests'); - t.end(); + t.assert.strictEqual(runtime.finishedAssetRequests, 0, 'property finishedAssetRequests'); + t.assert.strictEqual(runtime.totalAssetRequests, 0, 'property totalAssetRequests'); }); test('dispose', t => { t.plan(1); const runtime = new Runtime(); runtime.resetProgress = () => { - t.pass(); + t.assert.ok(true); }; runtime.dispose(); - t.end(); }); -test('wrapAssetRequest', t => { +test('wrapAssetRequest', (t, done) => { const runtime = new Runtime(); const log = []; @@ -72,12 +70,12 @@ test('wrapAssetRequest', t => { runtime.wrapAssetRequest(() => Promise.resolve(1)), runtime.wrapAssetRequest(() => Promise.resolve(2)) ]).then(results => { - t.same(results, [1, 2]); + assert.deepEqual(results, [1, 2]); // eslint-disable-next-line prefer-promise-reject-errors runtime.wrapAssetRequest(() => Promise.reject(3)).catch(error => { - t.equal(error, 3); - t.same(log, [ + assert.strictEqual(error, 3); + assert.deepEqual(log, [ [0, 1], [0, 2], [1, 2], @@ -85,12 +83,12 @@ test('wrapAssetRequest', t => { [2, 3], [3, 3] ]); - t.end(); + done(); }); }); }); -test('asset util emits progress', t => { +test('asset util emits progress', async () => { const runtime = new Runtime(); const storage = makeTestStorage(); @@ -104,19 +102,17 @@ test('asset util emits progress', t => { log.push([finished, total]); }); - AssetUtil.getByMd5ext(runtime, null, runtime.storage.AssetType.SVG, 'abcdef.svg').then(() => { - t.same(log, [ - [0, 1], - [1, 1] - ]); - t.end(); - }); + await AssetUtil.getByMd5ext(runtime, null, runtime.storage.AssetType.SVG, 'abcdef.svg'); + assert.deepEqual(log, [ + [0, 1], + [1, 1] + ]); }); // For the next tests, we have some fixtures that contain 2 assets: 1 sound + 1 costume // We'll just load them and make sure that each deserializer emits reasonable progress events for (const format of ['sb', 'sb2', 'sb3']) { - test(format, t => { + test(format, async () => { const fixture = fs.readFileSync(path.join(__dirname, `../fixtures/tw-asset-progress.${format}`)); const vm = new VirtualMachine(); @@ -125,16 +121,13 @@ for (const format of ['sb', 'sb2', 'sb3']) { log.push([finished, total]); }); - vm.loadProject(fixture) - .then(() => { - t.same(log, [ - [0, 0], // loadProject() implies dispose() - [0, 1], - [0, 2], - [1, 2], - [2, 2] - ]); - t.end(); - }); + await vm.loadProject(fixture); + assert.deepEqual(log, [ + [0, 0], // loadProject() implies dispose() + [0, 1], + [0, 2], + [1, 2], + [2, 2] + ]); }); } diff --git a/test/integration/tw_automatic_variable_creation.js b/test/integration/tw_automatic_variable_creation.js index e77d575a..c83e1e13 100644 --- a/test/integration/tw_automatic_variable_creation.js +++ b/test/integration/tw_automatic_variable_creation.js @@ -1,16 +1,17 @@ const fs = require('fs'); const path = require('path'); -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const VM = require('../../src/virtual-machine'); for (const compilerEnabled of [false, true]) { const prefix = compilerEnabled ? 'compiler' : 'interpreter'; - test(`${prefix} - quirks when block field has literal null for variable ID`, t => { + test(`${prefix} - quirks when block field has literal null for variable ID`, async () => { const vm = new VM(); vm.setCompilerOptions({ enabled: compilerEnabled }); - t.equal(vm.runtime.compilerOptions.enabled, compilerEnabled, 'compiler options sanity check'); + assert.strictEqual(vm.runtime.compilerOptions.enabled, compilerEnabled, 'compiler options sanity check'); // The execute tests ensure that this fixture compiles and runs fine and the snapshot test ensures // it compiles correctly. This additional test will ensure that the internal variable objects are @@ -20,24 +21,21 @@ for (const compilerEnabled of [false, true]) { '../fixtures/execute/tw-automatic-variable-creation-literal-null-id.sb3' ); - vm.loadProject(fs.readFileSync(fixturePath)).then(() => { - vm.greenFlag(); - vm.runtime._step(); + await vm.loadProject(fs.readFileSync(fixturePath)); + vm.greenFlag(); + vm.runtime._step(); - // Variable does not exist, should get made as local variable in sprite - const variables = vm.runtime.targets[1].variables; - t.equal(Object.keys(variables).length, 1, 'created 1 new variable'); + // Variable does not exist, should get made as local variable in sprite + const variables = vm.runtime.targets[1].variables; + assert.strictEqual(Object.keys(variables).length, 1, 'created 1 new variable'); - // Scratch quirk - the entry in .variables should have key "null" - const newVariableKey = Object.keys(variables)[0]; - t.equal(newVariableKey, 'null', 'key is "null"'); + // Scratch quirk - the entry in .variables should have key "null" + const newVariableKey = Object.keys(variables)[0]; + assert.strictEqual(newVariableKey, 'null', 'key is "null"'); - // Scratch quirk - the actual variable.id should be the random string - const newVariable = Object.values(variables)[0]; - t.notEqual(newVariable.id, 'null', 'variable.id is not "null"'); - t.type(newVariable.id, 'string', 'variable.id is a string'); - - t.end(); - }); + // Scratch quirk - the actual variable.id should be the random string + const newVariable = Object.values(variables)[0]; + assert.notStrictEqual(newVariable.id, 'null', 'variable.id is not "null"'); + assert.strictEqual(typeof newVariable.id, 'string', 'variable.id is a string'); }); } diff --git a/test/integration/tw_block_returning_promise_like.js b/test/integration/tw_block_returning_promise_like.js index e212ef42..a0a94d1a 100644 --- a/test/integration/tw_block_returning_promise_like.js +++ b/test/integration/tw_block_returning_promise_like.js @@ -1,4 +1,5 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const fs = require('fs'); const path = require('path'); const VirtualMachine = require('../../src/virtual-machine'); @@ -36,34 +37,33 @@ class TestExtension { const fixture = fs.readFileSync(path.join(__dirname, '../fixtures/tw-block-returning-promise-like.sb3')); for (const compilerEnabled of [false, true]) { - test(`handles blocks that return a promise-like object - ${compilerEnabled ? 'compiled' : 'interpreted'}`, t => { + // eslint-disable-next-line max-len + test(`handles blocks that return a promise-like object - ${compilerEnabled ? 'compiled' : 'interpreted'}`, async () => { const vm = new VirtualMachine(); vm.extensionManager.addBuiltinExtension('testextension', TestExtension); vm.setCompilerOptions({ enabled: compilerEnabled }); - t.equal(vm.runtime.compilerOptions.enabled, compilerEnabled, 'sanity check'); + assert.strictEqual(vm.runtime.compilerOptions.enabled, compilerEnabled, 'sanity check'); vm.runtime.on('COMPILE_ERROR', () => { - t.fail('Compile error'); + assert.fail('Compile error'); }); - vm.loadProject(fixture).then(() => { - let ended = 0; - vm.runtime.on('SAY', (target, type, text) => { - if (text === 'end') { - ended++; - } else { - t.fail('said something unknown'); - } - }); - - vm.greenFlag(); - vm.runtime._step(); - - t.equal(ended, 1, 'script ran once immediately'); - t.end(); + await vm.loadProject(fixture); + let ended = 0; + vm.runtime.on('SAY', (target, type, text) => { + if (text === 'end') { + ended++; + } else { + assert.fail('said something unknown'); + } }); + + vm.greenFlag(); + vm.runtime._step(); + + assert.strictEqual(ended, 1, 'script ran once immediately'); }); } diff --git a/test/integration/tw_compat_block_utility_stackframe_exposed.js b/test/integration/tw_compat_block_utility_stackframe_exposed.js index a49aac67..efa5404b 100644 --- a/test/integration/tw_compat_block_utility_stackframe_exposed.js +++ b/test/integration/tw_compat_block_utility_stackframe_exposed.js @@ -1,15 +1,14 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const fs = require('fs'); const path = require('path'); const VM = require('../../src/virtual-machine'); const Timer = require('../../src/util/timer'); -test('compatibility stack frame is exposed on thread', t => { +test('compatibility stack frame is exposed on thread', async () => { const vm = new VM(); - vm.loadProject(fs.readFileSync(path.join(__dirname, '../fixtures/tw-glide.sb3'))).then(() => { - vm.greenFlag(); - vm.runtime._step(); - t.ok(vm.runtime.threads[0].compatibilityStackFrame.timer instanceof Timer); - t.end(); - }); + await vm.loadProject(fs.readFileSync(path.join(__dirname, '../fixtures/tw-glide.sb3'))); + vm.greenFlag(); + vm.runtime._step(); + assert.ok(vm.runtime.threads[0].compatibilityStackFrame.timer instanceof Timer); }); diff --git a/test/integration/tw_compression_per_file_type.js b/test/integration/tw_compression_per_file_type.js index 35f02a68..28b6efdf 100644 --- a/test/integration/tw_compression_per_file_type.js +++ b/test/integration/tw_compression_per_file_type.js @@ -1,31 +1,28 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const fs = require('fs'); const path = require('path'); const VM = require('../../src/virtual-machine'); const makeTestStorage = require('../fixtures/make-test-storage'); const JSZip = require('@turbowarp/jszip'); -test('saveProjectSb3() per-file compression', t => { +test('saveProjectSb3() per-file compression', async () => { const vm = new VM(); vm.attachStorage(makeTestStorage()); const fixture = fs.readFileSync(path.join(__dirname, '../fixtures/tw-mixed-file-formats.sb3')); - vm.loadProject(fixture) - .then(() => vm.saveProjectSb3('arraybuffer')) - .then(buffer => JSZip.loadAsync(buffer)) - .then(zip => { - const isCompressed = pathInZip => { - // note: uses JSZip private APIs, not very stable, but it should be okay... - const file = zip.files[pathInZip]; - return file._data.compression.magic === '\x08\x00'; - }; + await vm.loadProject(fixture); + const buffer = await vm.saveProjectSb3('arraybuffer'); + const zip = await JSZip.loadAsync(buffer); + const isCompressed = pathInZip => { + // note: uses JSZip private APIs, not very stable, but it should be okay... + const file = zip.files[pathInZip]; + return file._data.compression.magic === '\x08\x00'; + }; - t.ok(isCompressed('project.json')); - t.ok(isCompressed('5cb46ddd903fc2c9976ff881df9273c9.wav')); - t.ok(isCompressed('cd21514d0531fdffb22204e0ec5ed84a.svg')); + assert.ok(isCompressed('project.json')); + assert.ok(isCompressed('5cb46ddd903fc2c9976ff881df9273c9.wav')); + assert.ok(isCompressed('cd21514d0531fdffb22204e0ec5ed84a.svg')); - t.notOk(isCompressed('0b2e50ca4107ce57416e2ceb840a6347.jpg')); - t.notOk(isCompressed('5c8826d846c06dddeb77590e8792fb7d.png')); - - t.end(); - }); + assert.ok(!isCompressed('0b2e50ca4107ce57416e2ceb840a6347.jpg')); + assert.ok(!isCompressed('5c8826d846c06dddeb77590e8792fb7d.png')); }); diff --git a/test/integration/tw_conditional_and_loop.js b/test/integration/tw_conditional_and_loop.js index 05efbde4..69bb7432 100644 --- a/test/integration/tw_conditional_and_loop.js +++ b/test/integration/tw_conditional_and_loop.js @@ -1,6 +1,6 @@ const fs = require('fs'); const path = require('path'); -const {test} = require('tap'); +const {test} = require('node:test'); const VirtualMachine = require('../../src/virtual-machine'); const Scratch = require('../../src/extension-support/tw-extension-api-common'); @@ -139,7 +139,7 @@ class TestExtensionUsingStartBranch { for (const Extension of [TestExtensionUsingReturn, TestExtensionUsingStartBranch]) { for (const compilerEnabled of [false, true]) { - test(`CONDITIONAL - ${Extension.name} - ${compilerEnabled ? 'compiled' : 'interpreted'}`, t => { + test(`CONDITIONAL - ${Extension.name} - ${compilerEnabled ? 'compiled' : 'interpreted'}`, (t, done) => { t.plan(1); const vm = new VirtualMachine(); @@ -148,7 +148,7 @@ for (const Extension of [TestExtensionUsingReturn, TestExtensionUsingStartBranch }); vm.extensionManager.addBuiltinExtension('loopsAndThings', Extension); vm.runtime.on('COMPILE_ERROR', () => { - t.fail('Compile error'); + t.assert.fail('Compile error'); }); vm.loadProject(fs.readFileSync(path.join(__dirname, '../fixtures/tw-conditional.sb3'))).then(() => { @@ -158,10 +158,10 @@ for (const Extension of [TestExtensionUsingReturn, TestExtensionUsingStartBranch okayCount++; } else if (text === 'end') { vm.quit(); - t.equal(okayCount, 5); - t.end(); + t.assert.strictEqual(okayCount, 5); + done(); } else { - t.fail(`Unexpected text: ${text}`); + t.assert.fail(`Unexpected text: ${text}`); } }); @@ -170,7 +170,7 @@ for (const Extension of [TestExtensionUsingReturn, TestExtensionUsingStartBranch }); }); - test(`LOOP - ${Extension.name} - ${compilerEnabled ? 'compiled' : 'interpreted'}`, t => { + test(`LOOP - ${Extension.name} - ${compilerEnabled ? 'compiled' : 'interpreted'}`, (t, done) => { t.plan(1); const vm = new VirtualMachine(); @@ -179,14 +179,14 @@ for (const Extension of [TestExtensionUsingReturn, TestExtensionUsingStartBranch }); vm.extensionManager.addBuiltinExtension('loopsAndThings', Extension); vm.runtime.on('COMPILE_ERROR', () => { - t.fail('Compile error'); + t.assert.fail('Compile error'); }); vm.loadProject(fs.readFileSync(path.join(__dirname, '../fixtures/tw-loop.sb3'))).then(() => { vm.runtime.on('SAY', (target, type, text) => { vm.quit(); - t.equal(text, 'a 3 b 12 c 48 frames 64'); - t.end(); + t.assert.strictEqual(text, 'a 3 b 12 c 48 frames 64'); + done(); }); vm.greenFlag(); @@ -194,7 +194,7 @@ for (const Extension of [TestExtensionUsingReturn, TestExtensionUsingStartBranch }); }); - test(`beyond branchCount - ${Extension.name} - ${compilerEnabled ? 'compiled' : 'interpreted'}`, t => { + test(`beyond branchCount - ${Extension.name} - ${compilerEnabled ? 'compiled' : 'interpreted'}`, (t, done) => { t.plan(1); const vm = new VirtualMachine(); @@ -203,16 +203,16 @@ for (const Extension of [TestExtensionUsingReturn, TestExtensionUsingStartBranch }); vm.extensionManager.addBuiltinExtension('loopsAndThings', Extension); vm.runtime.on('COMPILE_ERROR', () => { - t.fail('Compile error'); + t.assert.fail('Compile error'); }); vm.loadProject(fs.readFileSync(path.join(__dirname, '../fixtures/tw-beyond-branchCount.sb3'))).then(() => { vm.runtime.on('SAY', (target, type, text) => { if (text === 'BeyondBranchCount') { - t.pass('BeyondBranchCount'); + t.assert.ok(true, 'BeyondBranchCount'); } else if (text === 'end') { vm.quit(); - t.end(); + done(); } }); diff --git a/test/integration/tw_default_extension_url.js b/test/integration/tw_default_extension_url.js index 2dd6573b..ca7b034d 100644 --- a/test/integration/tw_default_extension_url.js +++ b/test/integration/tw_default_extension_url.js @@ -1,9 +1,8 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const VirtualMachine = require('../../src/virtual-machine'); -test('Loading project uses default extension URLs', t => { - t.plan(1); - +test('Loading project uses default extension URLs', async () => { const vm = new VirtualMachine(); const events = []; vm.securityManager.canLoadExtensionFromProject = url => { @@ -15,7 +14,7 @@ test('Loading project uses default extension URLs', t => { return Promise.resolve(); }; - vm.loadProject({ + await vm.loadProject({ targets: [ { isStage: true, @@ -91,14 +90,11 @@ test('Loading project uses default extension URLs', t => { vm: '0.2.0', agent: '' } - }).then(() => { - t.same(events, [ - 'canLoadExtensionFromProject https://extensions.turbowarp.org/lab/text.js', - 'loadExtensionURL https://extensions.turbowarp.org/lab/text.js', - 'canLoadExtensionFromProject https://example.com/box2d.js', - 'loadExtensionURL https://example.com/box2d.js' - ]); - - t.end(); }); + assert.deepEqual(events, [ + 'canLoadExtensionFromProject https://extensions.turbowarp.org/lab/text.js', + 'loadExtensionURL https://extensions.turbowarp.org/lab/text.js', + 'canLoadExtensionFromProject https://example.com/box2d.js', + 'loadExtensionURL https://example.com/box2d.js' + ]); }); diff --git a/test/integration/tw_deterministic_sb3.js b/test/integration/tw_deterministic_sb3.js index 1e903eb0..c65076eb 100644 --- a/test/integration/tw_deterministic_sb3.js +++ b/test/integration/tw_deterministic_sb3.js @@ -1,14 +1,13 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const VM = require('../../src/virtual-machine'); -test('saveProjectSb3 is deterministic over time', t => { +test('saveProjectSb3 is deterministic over time', async () => { const vm = new VM(); - Promise.all([ + const [a, b] = await Promise.all([ vm.saveProjectSb3('nodebuffer'), // Zip modification time is only accurate to the second new Promise(resolve => setTimeout(resolve, 1000)).then(() => vm.saveProjectSb3('nodebuffer')) - ]).then(([a, b]) => { - t.same(a, b); - t.end(); - }); + ]); + assert.deepEqual(a, b); }); diff --git a/test/integration/tw_edge_activated_hat_returns_promise.js b/test/integration/tw_edge_activated_hat_returns_promise.js index c24386e8..b8e0e553 100644 --- a/test/integration/tw_edge_activated_hat_returns_promise.js +++ b/test/integration/tw_edge_activated_hat_returns_promise.js @@ -1,22 +1,19 @@ const VM = require('../../src/virtual-machine'); -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const fs = require('fs'); const path = require('path'); const compilerAndInterpreter = (name, callback) => { - test(`${name} - interpreted`, t => { - callback(t, { - enabled: false - }); - }); - test(`${name} - compiled`, t => { - callback(t, { - enabled: true - }); - }); + test(`${name} - interpreted`, () => callback({ + enabled: false + })); + test(`${name} - compiled`, () => callback({ + enabled: true + })); }; -compilerAndInterpreter('edge activated hats returning promises work properly', async (t, co) => { +compilerAndInterpreter('edge activated hats returning promises work properly', async co => { const vm = new VM(); vm.setCompilerOptions(co); @@ -44,28 +41,26 @@ compilerAndInterpreter('edge activated hats returning promises work properly', a hatValue = false; await step(10); - t.equal(sayCounter, 0); + assert.strictEqual(sayCounter, 0); hatValue = true; await step(); // promise can't resolve in this tick, so block shouldn't run yet - t.equal(sayCounter, 0); + assert.strictEqual(sayCounter, 0); await step(); - t.equal(sayCounter, 1); + assert.strictEqual(sayCounter, 1); await step(10); - t.equal(sayCounter, 1); + assert.strictEqual(sayCounter, 1); hatValue = false; await step(10); - t.equal(sayCounter, 1); + assert.strictEqual(sayCounter, 1); hatValue = true; await step(); - t.equal(sayCounter, 1); + assert.strictEqual(sayCounter, 1); await step(); - t.equal(sayCounter, 2); + assert.strictEqual(sayCounter, 2); await step(10); - t.equal(sayCounter, 2); - - t.end(); + assert.strictEqual(sayCounter, 2); }); diff --git a/test/integration/tw_extension_and_block_xml.js b/test/integration/tw_extension_and_block_xml.js index 673fe339..8df1c49f 100644 --- a/test/integration/tw_extension_and_block_xml.js +++ b/test/integration/tw_extension_and_block_xml.js @@ -1,7 +1,8 @@ const fs = require('fs'); const pathUtil = require('path'); const htmlparser = require('htmlparser2'); -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const VirtualMachine = require('../../src/virtual-machine'); const Runtime = require('../../src/engine/runtime'); const ArgumentType = require('../../src/extension-support/argument-type'); @@ -66,7 +67,7 @@ const baseExtensionInfo = { } }; -test('XML escaped in Runtime.getBlocksXML()', t => { +test('XML escaped in Runtime.getBlocksXML()', () => { // While these changes will make the extension unusable in a real editor environment, we still // want to make sure that these fields are actually being escaped. const mangledExtension = JSON.parse(JSON.stringify(baseExtensionInfo)); @@ -80,14 +81,14 @@ test('XML escaped in Runtime.getBlocksXML()', t => { }); const xmlList = vm.runtime.getBlocksXML(); - t.type(xmlList, Array, 'getBlocksXML returns array'); - t.equal(xmlList.length, 1, 'array has 1 item'); + assert.ok(xmlList instanceof Array, 'getBlocksXML returns array'); + assert.strictEqual(xmlList.length, 1, 'array has 1 item'); const xmlEntry = xmlList[0]; - t.equal(xmlEntry.id, `xmltest`, 'id worked'); + assert.strictEqual(xmlEntry.id, `xmltest`, 'id worked'); const parsedXml = htmlparser.parseDOM(xmlEntry.xml); - t.equal(parsedXml.length, 1, 'xml has 1 root node'); + assert.strictEqual(parsedXml.length, 1, 'xml has 1 root node'); /* Expected XML structure: @@ -112,52 +113,64 @@ test('XML escaped in Runtime.getBlocksXML()', t => { */ const category = parsedXml[0]; - t.equal(category.name, 'category', 'has '); - t.equal(category.attribs.name, '<>"'&& Name', 'escaped category name'); - t.equal(category.attribs.id, 'xmltest', 'category id'); - t.equal(category.attribs.colour, '<"'&amp;amp;color1>', 'escaped category color'); - t.equal(category.attribs.secondarycolour, '<"'&amp;amp;color2>', 'escaped category color 2'); - t.equal(category.attribs.iconuri, 'data:<>&"' category icon', 'escaped category icon'); - t.equal(category.children.length, 3, 'category has 3 children'); + assert.strictEqual(category.name, 'category', 'has '); + assert.strictEqual(category.attribs.name, '<>"'&& Name', 'escaped category name'); + assert.strictEqual(category.attribs.id, 'xmltest', 'category id'); + assert.strictEqual(category.attribs.colour, '<"'&amp;amp;color1>', 'escaped category color'); + assert.strictEqual( + category.attribs.secondarycolour, + '<"'&amp;amp;color2>', + 'escaped category color 2' + ); + assert.strictEqual( + category.attribs.iconuri, + 'data:<>&"' category icon', + 'escaped category icon' + ); + assert.strictEqual(category.children.length, 3, 'category has 3 children'); // Check docsURI const docsButton = category.children[0]; - t.equal(docsButton.name, 'button', 'has docs '); +const testButton = function (button) { + assert.deepEqual(button.json, null); // should be null or undefined + assert.strictEqual(button.xml, ''); }; -const testReporter = function (t, reporter) { - t.equal(reporter.json.type, 'test_reporter'); - testCategoryInfo(t, reporter); - t.equal(reporter.json.checkboxInFlyout, true); - t.equal(reporter.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_ROUND); - t.equal(reporter.json.output, 'String'); - t.notOk(Object.prototype.hasOwnProperty.call(reporter.json, 'previousStatement')); - t.notOk(Object.prototype.hasOwnProperty.call(reporter.json, 'nextStatement')); - t.same(reporter.json.extensions, ['from_extension', 'scratch_extension']); - t.equal(reporter.json.message0, '%1 %2simple text'); // "%1 %2" from the block icon - t.notOk(Object.prototype.hasOwnProperty.call(reporter.json, 'message1')); - t.same(reporter.json.args0, [ +const testReporter = function (reporter) { + assert.strictEqual(reporter.json.type, 'test_reporter'); + testCategoryInfo(reporter); + assert.strictEqual(reporter.json.checkboxInFlyout, true); + assert.strictEqual(reporter.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_ROUND); + assert.strictEqual(reporter.json.output, 'String'); + assert.ok(!Object.prototype.hasOwnProperty.call(reporter.json, 'previousStatement')); + assert.ok(!Object.prototype.hasOwnProperty.call(reporter.json, 'nextStatement')); + assert.deepEqual(reporter.json.extensions, ['from_extension', 'scratch_extension']); + assert.strictEqual(reporter.json.message0, '%1 %2simple text'); // "%1 %2" from the block icon + assert.ok(!Object.prototype.hasOwnProperty.call(reporter.json, 'message1')); + assert.deepEqual(reporter.json.args0, [ // %1 in message0: the block icon { type: 'field_image', @@ -160,22 +161,22 @@ const testReporter = function (t, reporter) { type: 'field_vertical_separator' } ]); - t.notOk(Object.prototype.hasOwnProperty.call(reporter.json, 'args1')); - t.equal(reporter.xml, ''); + assert.ok(!Object.prototype.hasOwnProperty.call(reporter.json, 'args1')); + assert.strictEqual(reporter.xml, ''); }; -const testInlineImage = function (t, inlineImage) { - t.equal(inlineImage.json.type, 'test_inlineImage'); - testCategoryInfo(t, inlineImage); - t.equal(inlineImage.json.checkboxInFlyout, true); - t.equal(inlineImage.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_ROUND); - t.equal(inlineImage.json.output, 'String'); - t.notOk(Object.prototype.hasOwnProperty.call(inlineImage.json, 'previousStatement')); - t.notOk(Object.prototype.hasOwnProperty.call(inlineImage.json, 'nextStatement')); - t.same(inlineImage.json.extensions, ['from_extension']); - t.equal(inlineImage.json.message0, 'text and %1'); // block text followed by inline image - t.notOk(Object.prototype.hasOwnProperty.call(inlineImage.json, 'message1')); - t.same(inlineImage.json.args0, [ +const testInlineImage = function (inlineImage) { + assert.strictEqual(inlineImage.json.type, 'test_inlineImage'); + testCategoryInfo(inlineImage); + assert.strictEqual(inlineImage.json.checkboxInFlyout, true); + assert.strictEqual(inlineImage.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_ROUND); + assert.strictEqual(inlineImage.json.output, 'String'); + assert.ok(!Object.prototype.hasOwnProperty.call(inlineImage.json, 'previousStatement')); + assert.ok(!Object.prototype.hasOwnProperty.call(inlineImage.json, 'nextStatement')); + assert.deepEqual(inlineImage.json.extensions, ['from_extension']); + assert.strictEqual(inlineImage.json.message0, 'text and %1'); // block text followed by inline image + assert.ok(!Object.prototype.hasOwnProperty.call(inlineImage.json, 'message1')); + assert.deepEqual(inlineImage.json.args0, [ // %1 in message0: the block icon { type: 'field_image', @@ -185,122 +186,122 @@ const testInlineImage = function (t, inlineImage) { flip_rtl: false // False by default } ]); - t.notOk(Object.prototype.hasOwnProperty.call(inlineImage.json, 'args1')); - t.equal(inlineImage.xml, ''); + assert.ok(!Object.prototype.hasOwnProperty.call(inlineImage.json, 'args1')); + assert.strictEqual(inlineImage.xml, ''); }; -const testSeparator = function (t, separator) { - t.same(separator.json, null); // should be null or undefined - t.equal(separator.xml, ''); +const testSeparator = function (separator) { + assert.deepEqual(separator.json, null); // should be null or undefined + assert.strictEqual(separator.xml, ''); }; -const testCommand = function (t, command) { - t.equal(command.json.type, 'test_command'); - testCategoryInfo(t, command); - t.equal(command.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE); - t.assert(Object.prototype.hasOwnProperty.call(command.json, 'previousStatement')); - t.assert(Object.prototype.hasOwnProperty.call(command.json, 'nextStatement')); - t.same(command.json.extensions, ['from_extension']); - t.equal(command.json.message0, 'text with %1 %2'); - t.notOk(Object.prototype.hasOwnProperty.call(command.json, 'message1')); - t.strictSame(command.json.args0[0], { +const testCommand = function (command) { + assert.strictEqual(command.json.type, 'test_command'); + testCategoryInfo(command); + assert.strictEqual(command.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE); + assert.ok(Object.prototype.hasOwnProperty.call(command.json, 'previousStatement')); + assert.ok(Object.prototype.hasOwnProperty.call(command.json, 'nextStatement')); + assert.deepEqual(command.json.extensions, ['from_extension']); + assert.strictEqual(command.json.message0, 'text with %1 %2'); + assert.ok(!Object.prototype.hasOwnProperty.call(command.json, 'message1')); + assert.deepStrictEqual(command.json.args0[0], { type: 'input_value', name: 'ARG' }); - t.notOk(Object.prototype.hasOwnProperty.call(command.json, 'args1')); - t.equal(command.xml, + assert.ok(!Object.prototype.hasOwnProperty.call(command.json, 'args1')); + assert.strictEqual(command.xml, '' + '' + 'default text'); }; -const testConditional = function (t, conditional) { - t.equal(conditional.json.type, 'test_ifElse'); - testCategoryInfo(t, conditional); - t.equal(conditional.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE); - t.ok(Object.prototype.hasOwnProperty.call(conditional.json, 'previousStatement')); - t.ok(Object.prototype.hasOwnProperty.call(conditional.json, 'nextStatement')); - t.same(conditional.json.extensions, ['from_extension']); - t.equal(conditional.json.message0, 'test if %1 is spiffy and if so then'); - t.equal(conditional.json.message1, '%1'); // placeholder for substack #1 - t.equal(conditional.json.message2, 'or elsewise'); - t.equal(conditional.json.message3, '%1'); // placeholder for substack #2 - t.notOk(Object.prototype.hasOwnProperty.call(conditional.json, 'message4')); - t.strictSame(conditional.json.args0[0], { +const testConditional = function (conditional) { + assert.strictEqual(conditional.json.type, 'test_ifElse'); + testCategoryInfo(conditional); + assert.strictEqual(conditional.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE); + assert.ok(Object.prototype.hasOwnProperty.call(conditional.json, 'previousStatement')); + assert.ok(Object.prototype.hasOwnProperty.call(conditional.json, 'nextStatement')); + assert.deepEqual(conditional.json.extensions, ['from_extension']); + assert.strictEqual(conditional.json.message0, 'test if %1 is spiffy and if so then'); + assert.strictEqual(conditional.json.message1, '%1'); // placeholder for substack #1 + assert.strictEqual(conditional.json.message2, 'or elsewise'); + assert.strictEqual(conditional.json.message3, '%1'); // placeholder for substack #2 + assert.ok(!Object.prototype.hasOwnProperty.call(conditional.json, 'message4')); + assert.deepStrictEqual(conditional.json.args0[0], { type: 'input_value', name: 'THING', check: 'Boolean' }); - t.strictSame(conditional.json.args1[0], { + assert.deepStrictEqual(conditional.json.args1[0], { type: 'input_statement', name: 'SUBSTACK' }); - t.notOk(Object.prototype.hasOwnProperty.call(conditional.json, conditional.json.args2)); - t.strictSame(conditional.json.args3[0], { + assert.ok(!Object.prototype.hasOwnProperty.call(conditional.json, conditional.json.args2)); + assert.deepStrictEqual(conditional.json.args3[0], { type: 'input_statement', name: 'SUBSTACK2' }); - t.notOk(Object.prototype.hasOwnProperty.call(conditional.json, 'args4')); - t.equal(conditional.xml, ''); + assert.ok(!Object.prototype.hasOwnProperty.call(conditional.json, 'args4')); + assert.strictEqual(conditional.xml, ''); }; -const testLoop = function (t, loop) { - t.equal(loop.json.type, 'test_loop'); - testCategoryInfo(t, loop); - t.equal(loop.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE); - t.ok(Object.prototype.hasOwnProperty.call(loop.json, 'previousStatement')); - t.notOk(Object.prototype.hasOwnProperty.call(loop.json, 'nextStatement')); // isTerminal is set on this block - t.same(loop.json.extensions, ['from_extension']); - t.equal(loop.json.message0, 'loopty %1 loops'); - t.equal(loop.json.message1, '%1'); // placeholder for substack - t.equal(loop.json.message2, '%1'); // placeholder for loop arrow - t.notOk(Object.prototype.hasOwnProperty.call(loop.json, 'message3')); - t.strictSame(loop.json.args0[0], { +const testLoop = function (loop) { + assert.strictEqual(loop.json.type, 'test_loop'); + testCategoryInfo(loop); + assert.strictEqual(loop.json.outputShape, ScratchBlocksConstants.OUTPUT_SHAPE_SQUARE); + assert.ok(Object.prototype.hasOwnProperty.call(loop.json, 'previousStatement')); + assert.ok(!Object.prototype.hasOwnProperty.call(loop.json, 'nextStatement')); // isTerminal is set on this block + assert.deepEqual(loop.json.extensions, ['from_extension']); + assert.strictEqual(loop.json.message0, 'loopty %1 loops'); + assert.strictEqual(loop.json.message1, '%1'); // placeholder for substack + assert.strictEqual(loop.json.message2, '%1'); // placeholder for loop arrow + assert.ok(!Object.prototype.hasOwnProperty.call(loop.json, 'message3')); + assert.deepStrictEqual(loop.json.args0[0], { type: 'input_value', name: 'MANY' }); - t.strictSame(loop.json.args1[0], { + assert.deepStrictEqual(loop.json.args1[0], { type: 'input_statement', name: 'SUBSTACK' }); - t.equal(loop.json.lastDummyAlign2, 'RIGHT'); // move loop arrow to right side - t.equal(loop.json.args2[0].type, 'field_image'); - t.equal(loop.json.args2[0].flip_rtl, true); - t.notOk(Object.prototype.hasOwnProperty.call(loop.json, 'args3')); - t.equal(loop.xml, + assert.strictEqual(loop.json.lastDummyAlign2, 'RIGHT'); // move loop arrow to right side + assert.strictEqual(loop.json.args2[0].type, 'field_image'); + assert.strictEqual(loop.json.args2[0].flip_rtl, true); + assert.ok(!Object.prototype.hasOwnProperty.call(loop.json, 'args3')); + assert.strictEqual(loop.xml, ''); }; -test('registerExtensionPrimitives', t => { +test('registerExtensionPrimitives', (t, done) => { const runtime = new Runtime(); runtime.on(Runtime.EXTENSION_ADDED, categoryInfo => { const blocksInfo = categoryInfo.blocks; - t.equal(blocksInfo.length, testExtensionInfo.blocks.length); + assert.strictEqual(blocksInfo.length, testExtensionInfo.blocks.length); blocksInfo.forEach(blockInfo => { // `true` here means "either an object or a non-empty string but definitely not null or undefined" - t.true(blockInfo.info, 'Every block and pseudo-block must have a non-empty "info" field'); + assert.ok(blockInfo.info, 'Every block and pseudo-block must have a non-empty "info" field'); }); // Note that this also implicitly tests that block order is preserved const [button, reporter, inlineImage, separator, command, conditional, loop] = blocksInfo; - testButton(t, button); - testReporter(t, reporter); - testInlineImage(t, inlineImage); - testSeparator(t, separator); - testCommand(t, command); - testConditional(t, conditional); - testLoop(t, loop); + testButton(button); + testReporter(reporter); + testInlineImage(inlineImage); + testSeparator(separator); + testCommand(command); + testConditional(conditional); + testLoop(loop); - t.end(); + done(); }); runtime._registerExtensionPrimitives(testExtensionInfo); }); -test('custom field types should be added to block and EXTENSION_FIELD_ADDED callback triggered', t => { +test('custom field types should be added to block and EXTENSION_FIELD_ADDED callback triggered', () => { const runtime = new Runtime(); runtime.on(Runtime.EXTENSION_ADDED, categoryInfo => { @@ -309,7 +310,7 @@ test('custom field types should be added to block and EXTENSION_FIELD_ADDED call // We expect that for each argument there's a corresponding -tag in the block XML Object.values(blockInfo.info.arguments).forEach(argument => { const regex = new RegExp(``); - t.true(regex.test(blockInfo.xml)); + assert.ok(regex.test(blockInfo.xml)); }); }); @@ -322,6 +323,5 @@ test('custom field types should be added to block and EXTENSION_FIELD_ADDED call runtime._registerExtensionPrimitives(extensionInfoWithCustomFieldTypes); // Extension includes two custom field types - t.equal(fieldAddedCallbacks, 2); - t.end(); + assert.strictEqual(fieldAddedCallbacks, 2); }); diff --git a/test/unit/extension_microbit.js b/test/unit/extension_microbit.js index 4c68eb3f..c5162d1c 100644 --- a/test/unit/extension_microbit.js +++ b/test/unit/extension_microbit.js @@ -1,12 +1,8 @@ -const test = require('tap').test; +const {test} = require('node:test'); // const MicroBit = require('../../src/extensions/scratch3_microbit/index.js'); -test('displayText', t => { - t.end(); -}); +test('displayText', () => {}); -test('displayMatrix', t => { - t.end(); -}); +test('displayMatrix', () => {}); // etc... diff --git a/test/unit/extension_music.js b/test/unit/extension_music.js index d17069d4..8f3bffac 100644 --- a/test/unit/extension_music.js +++ b/test/unit/extension_music.js @@ -1,4 +1,5 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const Music = require('../../src/extensions/scratch3_music/index.js'); const fakeRuntime = { @@ -16,34 +17,30 @@ const util = { yield: () => null }; -test('playDrum uses 1-indexing and wrap clamps', t => { +test('playDrum uses 1-indexing and wrap clamps', () => { // Stub playDrumNum let playedDrum; blocks._playDrumNum = (_util, drum) => (playedDrum = drum); let args = {DRUM: 1}; blocks.playDrumForBeats(args, util); - t.strictEqual(playedDrum, 0); + assert.strictEqual(playedDrum, 0); args = {DRUM: blocks.DRUM_INFO.length + 1}; blocks.playDrumForBeats(args, util); - t.strictEqual(playedDrum, 0); - - t.end(); + assert.strictEqual(playedDrum, 0); }); -test('setInstrument uses 1-indexing and wrap clamps', t => { +test('setInstrument uses 1-indexing and wrap clamps', () => { // Stub getMusicState const state = {currentInstrument: 0}; blocks._getMusicState = () => state; let args = {INSTRUMENT: 1}; blocks.setInstrument(args, util); - t.strictEqual(state.currentInstrument, 0); + assert.strictEqual(state.currentInstrument, 0); args = {INSTRUMENT: blocks.INSTRUMENT_INFO.length + 1}; blocks.setInstrument(args, util); - t.strictEqual(state.currentInstrument, 0); - - t.end(); + assert.strictEqual(state.currentInstrument, 0); }); diff --git a/test/unit/extension_text_to_speech.js b/test/unit/extension_text_to_speech.js index 83c06549..f8763b38 100644 --- a/test/unit/extension_text_to_speech.js +++ b/test/unit/extension_text_to_speech.js @@ -1,4 +1,5 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const TextToSpeech = require('../../src/extensions/scratch3_text2speech/index.js'); const fakeStage = { @@ -12,33 +13,29 @@ const fakeRuntime = { const ext = new TextToSpeech(fakeRuntime); -test('if no language is saved in the project, use default', t => { - t.strictEqual(ext.getCurrentLanguage(), 'en'); - t.end(); +test('if no language is saved in the project, use default', () => { + assert.strictEqual(ext.getCurrentLanguage(), 'en'); }); -test('if an unsupported language is dropped onto the set language block, use default', t => { +test('if an unsupported language is dropped onto the set language block, use default', () => { ext.setLanguage({LANGUAGE: 'nope'}); - t.strictEqual(ext.getCurrentLanguage(), 'en'); - t.end(); + assert.strictEqual(ext.getCurrentLanguage(), 'en'); }); -test('if a supported language name is dropped onto the set language block, use it', t => { +test('if a supported language name is dropped onto the set language block, use it', () => { ext.setLanguage({LANGUAGE: 'español'}); - t.strictEqual(ext.getCurrentLanguage(), 'es'); - t.end(); + assert.strictEqual(ext.getCurrentLanguage(), 'es'); }); -test('get the extension locale for a supported locale that differs', t => { +test('get the extension locale for a supported locale that differs', () => { ext.setLanguage({LANGUAGE: 'ja-hira'}); - t.strictEqual(ext.getCurrentLanguage(), 'ja'); - t.end(); + assert.strictEqual(ext.getCurrentLanguage(), 'ja'); }); -test('use localized spoken language name in place of localized written language name', t => { +test('use localized spoken language name in place of localized written language name', () => { ext.getEditorLanguage = () => 'es'; const languageMenu = ext.getLanguageMenu(); const localizedNameForChineseInSpanish = languageMenu.find(el => el.value === 'zh-cn').text; - t.strictEqual(localizedNameForChineseInSpanish, 'Chino (mandarín)'); // i.e. should not be 'Chino (simplificado)' - t.end(); + // i.e. should not be 'Chino (simplificado)' + assert.strictEqual(localizedNameForChineseInSpanish, 'Chino (mandarín)'); }); diff --git a/test/unit/extension_video_sensing.js b/test/unit/extension_video_sensing.js index 22c2adae..2b8105a5 100644 --- a/test/unit/extension_video_sensing.js +++ b/test/unit/extension_video_sensing.js @@ -2,7 +2,8 @@ const {createReadStream} = require('fs'); const {join} = require('path'); const {PNG} = require('pngjs'); -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const {wrapClamp} = require('../../src/util/math-util'); @@ -140,272 +141,233 @@ const fakeBlockUtility = { target: fakeTarget }; -test('detect motionAmount between frames', t => { - t.plan(6); +test('detect motionAmount between frames', async () => { + const frames = await readFrames(); + const detect = new VideoMotion(); - return readFrames() - .then(frames => { - const detect = new VideoMotion(); + // Each of these pairs should have enough motion for the detector. + const framePairs = [ + [frames.center, frames.left], + [frames.center, frames.left2], + [frames.left, frames.left2], + [frames.left, frames.center], + [frames.center, frames.down], + [frames.down, frames.center] + ]; - // Each of these pairs should have enough motion for the detector. - const framePairs = [ - [frames.center, frames.left], - [frames.center, frames.left2], - [frames.left, frames.left2], - [frames.left, frames.center], - [frames.center, frames.down], - [frames.down, frames.center] - ]; + // Add both frames of a pair and test for motion. + let index = 0; + for (const [frame1, frame2] of framePairs) { + detect.addFrame(frame1); + detect.addFrame(frame2); - // Add both frames of a pair and test for motion. - let index = 0; - for (const [frame1, frame2] of framePairs) { - detect.addFrame(frame1); - detect.addFrame(frame2); - - detect.analyzeFrame(); - t.ok( - detect.motionAmount > 10, - `frame pair ${index + 1} has motion ${detect.motionAmount} over threshold (10)` - ); - index += 1; - } - - t.end(); - }); + detect.analyzeFrame(); + assert.ok( + detect.motionAmount > 10, + `frame pair ${index + 1} has motion ${detect.motionAmount} over threshold (10)` + ); + index += 1; + } }); -test('detect local motionAmount between frames', t => { - t.plan(6); +test('detect local motionAmount between frames', async () => { + const frames = await readFrames(); + const detect = new VideoMotion(); - return readFrames() - .then(frames => { - const detect = new VideoMotion(); + // Each of these pairs should have enough motion for the detector. + const framePairs = [ + [frames.center, frames.left], + [frames.center, frames.left2], + [frames.left, frames.left2], + [frames.left, frames.center], + [frames.center, frames.down], + [frames.down, frames.center] + ]; - // Each of these pairs should have enough motion for the detector. - const framePairs = [ - [frames.center, frames.left], - [frames.center, frames.left2], - [frames.left, frames.left2], - [frames.left, frames.center], - [frames.center, frames.down], - [frames.down, frames.center] - ]; + // Add both frames of a pair and test for local motion. + let index = 0; + for (const [frame1, frame2] of framePairs) { + detect.addFrame(frame1); + detect.addFrame(frame2); - // Add both frames of a pair and test for local motion. - let index = 0; - for (const [frame1, frame2] of framePairs) { - detect.addFrame(frame1); - detect.addFrame(frame2); - - detect.analyzeFrame(); - detect.getLocalMotion(fakeDrawable, fakeMotionState); - t.ok( - fakeMotionState.motionAmount > 10, - `frame pair ${index + 1} has motion ${fakeMotionState.motionAmount} over threshold (10)` - ); - index += 1; - } - - t.end(); - }); + detect.analyzeFrame(); + detect.getLocalMotion(fakeDrawable, fakeMotionState); + assert.ok( + fakeMotionState.motionAmount > 10, + `frame pair ${index + 1} has motion ${fakeMotionState.motionAmount} over threshold (10)` + ); + index += 1; + } }); -test('detect motionDirection between frames', t => { - t.plan(6); +test('detect motionDirection between frames', async () => { + const frames = await readFrames(); + const detect = new VideoMotion(); - return readFrames() - .then(frames => { - const detect = new VideoMotion(); + // Each of these pairs is moving in the given direction. Does the detector + // guess a value to that? + const directionMargin = 10; + const framePairs = [ + { + frames: [frames.center, frames.left], + direction: -90 + }, + { + frames: [frames.center, frames.left2], + direction: -90 + }, + { + frames: [frames.left, frames.left2], + direction: -90 + }, + { + frames: [frames.left, frames.center], + direction: 90 + }, + { + frames: [frames.center, frames.down], + direction: 180 + }, + { + frames: [frames.down, frames.center], + direction: 0 + } + ]; - // Each of these pairs is moving in the given direction. Does the detector - // guess a value to that? - const directionMargin = 10; - const framePairs = [ - { - frames: [frames.center, frames.left], - direction: -90 - }, - { - frames: [frames.center, frames.left2], - direction: -90 - }, - { - frames: [frames.left, frames.left2], - direction: -90 - }, - { - frames: [frames.left, frames.center], - direction: 90 - }, - { - frames: [frames.center, frames.down], - direction: 180 - }, - { - frames: [frames.down, frames.center], - direction: 0 - } - ]; + // Add both frames of a pair and check if the motionDirection is near the + // expected angle. + let index = 0; + for (const {frames: [frame1, frame2], direction} of framePairs) { + detect.addFrame(frame1); + detect.addFrame(frame2); - // Add both frames of a pair and check if the motionDirection is near the - // expected angle. - let index = 0; - for (const {frames: [frame1, frame2], direction} of framePairs) { - detect.addFrame(frame1); - detect.addFrame(frame2); - - detect.analyzeFrame(); - t.ok( - isNearAngle(detect.motionDirection, direction, directionMargin), - `frame pair ${index + 1} is ${detect.motionDirection.toFixed(0)} ` + - `degrees and close to ${direction} degrees` - ); - index += 1; - } - - t.end(); - }); + detect.analyzeFrame(); + assert.ok( + isNearAngle(detect.motionDirection, direction, directionMargin), + `frame pair ${index + 1} is ${detect.motionDirection.toFixed(0)} ` + + `degrees and close to ${direction} degrees` + ); + index += 1; + } }); -test('detect local motionDirection between frames', t => { - t.plan(6); +test('detect local motionDirection between frames', async () => { + const frames = await readFrames(); + const detect = new VideoMotion(); - return readFrames() - .then(frames => { - const detect = new VideoMotion(); + // Each of these pairs is moving in the given direction. Does the detector + // guess a value to that? + const directionMargin = 10; + const framePairs = [ + { + frames: [frames.center, frames.left], + direction: -90 + }, + { + frames: [frames.center, frames.left2], + direction: -90 + }, + { + frames: [frames.left, frames.left2], + direction: -90 + }, + { + frames: [frames.left, frames.center], + direction: 90 + }, + { + frames: [frames.center, frames.down], + direction: 180 + }, + { + frames: [frames.down, frames.center], + direction: 0 + } + ]; - // Each of these pairs is moving in the given direction. Does the detector - // guess a value to that? - const directionMargin = 10; - const framePairs = [ - { - frames: [frames.center, frames.left], - direction: -90 - }, - { - frames: [frames.center, frames.left2], - direction: -90 - }, - { - frames: [frames.left, frames.left2], - direction: -90 - }, - { - frames: [frames.left, frames.center], - direction: 90 - }, - { - frames: [frames.center, frames.down], - direction: 180 - }, - { - frames: [frames.down, frames.center], - direction: 0 - } - ]; + // Add both frames of a pair and check if the local motionDirection is near + // the expected angle. + let index = 0; + for (const {frames: [frame1, frame2], direction} of framePairs) { + detect.addFrame(frame1); + detect.addFrame(frame2); - // Add both frames of a pair and check if the local motionDirection is near - // the expected angle. - let index = 0; - for (const {frames: [frame1, frame2], direction} of framePairs) { - detect.addFrame(frame1); - detect.addFrame(frame2); - - detect.analyzeFrame(); - detect.getLocalMotion(fakeDrawable, fakeMotionState); - const motionDirection = fakeMotionState.motionDirection; - t.ok( - isNearAngle(motionDirection, direction, directionMargin), - `frame pair ${index + 1} is ${motionDirection.toFixed(0)} degrees and close to ${direction} degrees` - ); - index += 1; - } - - t.end(); - }); + detect.analyzeFrame(); + detect.getLocalMotion(fakeDrawable, fakeMotionState); + const motionDirection = fakeMotionState.motionDirection; + assert.ok( + isNearAngle(motionDirection, direction, directionMargin), + `frame pair ${index + 1} is ${motionDirection.toFixed(0)} degrees and close to ${direction} degrees` + ); + index += 1; + } }); -test('videoOn returns value dependent on arguments', t => { - t.plan(4); +test('videoOn returns value dependent on arguments', async () => { + const frames = await readFrames(); + const sensing = new VideoSensing(fakeRuntime); - return readFrames() - .then(frames => { - const sensing = new VideoSensing(fakeRuntime); + // With these two frame test if we get expected values depending on the + // arguments to videoOn. + sensing.detect.addFrame(frames.center); + sensing.detect.addFrame(frames.left); - // With these two frame test if we get expected values depending on the - // arguments to videoOn. - sensing.detect.addFrame(frames.center); - sensing.detect.addFrame(frames.left); + const motionAmount = sensing.videoOn({ + ATTRIBUTE: VideoSensing.SensingAttribute.MOTION, + SUBJECT: VideoSensing.SensingSubject.STAGE + }, fakeBlockUtility); + assert.ok( + motionAmount > 10, + `stage motionAmount ${motionAmount} is over the threshold (10)` + ); - const motionAmount = sensing.videoOn({ - ATTRIBUTE: VideoSensing.SensingAttribute.MOTION, - SUBJECT: VideoSensing.SensingSubject.STAGE - }, fakeBlockUtility); - t.ok( - motionAmount > 10, - `stage motionAmount ${motionAmount} is over the threshold (10)` - ); + const localMotionAmount = sensing.videoOn({ + ATTRIBUTE: VideoSensing.SensingAttribute.MOTION, + SUBJECT: VideoSensing.SensingSubject.SPRITE + }, fakeBlockUtility); + assert.ok( + localMotionAmount > 10, + `sprite motionAmount ${localMotionAmount} is over the threshold (10)` + ); - const localMotionAmount = sensing.videoOn({ - ATTRIBUTE: VideoSensing.SensingAttribute.MOTION, - SUBJECT: VideoSensing.SensingSubject.SPRITE - }, fakeBlockUtility); - t.ok( - localMotionAmount > 10, - `sprite motionAmount ${localMotionAmount} is over the threshold (10)` - ); + const motionDirection = sensing.videoOn({ + ATTRIBUTE: VideoSensing.SensingAttribute.DIRECTION, + SUBJECT: VideoSensing.SensingSubject.STAGE + }, fakeBlockUtility); + assert.ok( + isNearAngle(motionDirection, -90), + `stage motionDirection ${motionDirection.toFixed(0)} degrees is close to ${90} degrees` + ); - const motionDirection = sensing.videoOn({ - ATTRIBUTE: VideoSensing.SensingAttribute.DIRECTION, - SUBJECT: VideoSensing.SensingSubject.STAGE - }, fakeBlockUtility); - t.ok( - isNearAngle(motionDirection, -90), - `stage motionDirection ${motionDirection.toFixed(0)} degrees is close to ${90} degrees` - ); - - const localMotionDirection = sensing.videoOn({ - ATTRIBUTE: VideoSensing.SensingAttribute.DIRECTION, - SUBJECT: VideoSensing.SensingSubject.SPRITE - }, fakeBlockUtility); - t.ok( - isNearAngle(localMotionDirection, -90), - `sprite motionDirection ${localMotionDirection.toFixed(0)} degrees is close to ${90} degrees` - ); - - t.end(); - }); + const localMotionDirection = sensing.videoOn({ + ATTRIBUTE: VideoSensing.SensingAttribute.DIRECTION, + SUBJECT: VideoSensing.SensingSubject.SPRITE + }, fakeBlockUtility); + assert.ok( + isNearAngle(localMotionDirection, -90), + `sprite motionDirection ${localMotionDirection.toFixed(0)} degrees is close to ${90} degrees` + ); }); -test('whenMotionGreaterThan returns true if local motion meets target', t => { - t.plan(2); +test('whenMotionGreaterThan returns true if local motion meets target', async () => { + const frames = await readFrames(); + const sensing = new VideoSensing(fakeRuntime); - return readFrames() - .then(frames => { - const sensing = new VideoSensing(fakeRuntime); + // With these two frame test if we get expected values depending on the + // arguments to whenMotionGreaterThan. + sensing.detect.addFrame(frames.center); + sensing.detect.addFrame(frames.left); - // With these two frame test if we get expected values depending on the - // arguments to whenMotionGreaterThan. - sensing.detect.addFrame(frames.center); - sensing.detect.addFrame(frames.left); + const over20 = sensing.whenMotionGreaterThan({ + REFERENCE: 20 + }, fakeBlockUtility); + assert.ok( + over20, + `enough motion in drawable bounds to reach reference of 20` + ); - const over20 = sensing.whenMotionGreaterThan({ - REFERENCE: 20 - }, fakeBlockUtility); - t.ok( - over20, - `enough motion in drawable bounds to reach reference of 20` - ); - - const over80 = sensing.whenMotionGreaterThan({ - REFERENCE: 80 - }, fakeBlockUtility); - t.notOk( - over80, - `not enough motion in drawable bounds to reach reference of 80` - ); - - t.end(); - }); + const over80 = sensing.whenMotionGreaterThan({ + REFERENCE: 80 + }, fakeBlockUtility); + assert.ok(!over80, `not enough motion in drawable bounds to reach reference of 80`); }); diff --git a/test/unit/io_clock.js b/test/unit/io_clock.js index 03ee48fb..81a2815a 100644 --- a/test/unit/io_clock.js +++ b/test/unit/io_clock.js @@ -1,37 +1,36 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const Clock = require('../../src/io/clock'); const Runtime = require('../../src/engine/runtime'); -test('spec', t => { +test('spec', () => { const rt = new Runtime(); const c = new Clock(rt); - t.type(Clock, 'function'); - t.type(c, 'object'); - t.type(c.projectTimer, 'function'); - t.type(c.pause, 'function'); - t.type(c.resume, 'function'); - t.type(c.resetProjectTimer, 'function'); - t.end(); + assert.strictEqual(typeof Clock, 'function'); + assert.strictEqual(typeof c, 'object'); + assert.strictEqual(typeof c.projectTimer, 'function'); + assert.strictEqual(typeof c.pause, 'function'); + assert.strictEqual(typeof c.resume, 'function'); + assert.strictEqual(typeof c.resetProjectTimer, 'function'); }); test('cycle', t => { + t.mock.timers.enable({apis: ['Date']}); const rt = new Runtime(); const c = new Clock(rt); - t.ok(c.projectTimer() <= 0.1); - setTimeout(() => { - c.resetProjectTimer(); - setTimeout(() => { - // The timer shouldn't advance until all threads have been stepped - t.ok(c.projectTimer() === 0); - c.pause(); - t.ok(c.projectTimer() === 0); - c.resume(); - t.ok(c.projectTimer() === 0); - t.end(); - }, 100); - }, 100); + assert.strictEqual(c.projectTimer(), 0); + t.mock.timers.tick(100); rt._step(); - t.ok(c.projectTimer() > 0); + assert.strictEqual(c.projectTimer(), 0.1); + + c.resetProjectTimer(); + t.mock.timers.tick(100); + // The timer shouldn't advance until all threads have been stepped + assert.strictEqual(c.projectTimer(), 0); + c.pause(); + assert.strictEqual(c.projectTimer(), 0); + c.resume(); + assert.strictEqual(c.projectTimer(), 0); }); diff --git a/test/unit/io_cloud.js b/test/unit/io_cloud.js index ea572afb..c156f8c4 100644 --- a/test/unit/io_cloud.js +++ b/test/unit/io_cloud.js @@ -1,36 +1,35 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const Cloud = require('../../src/io/cloud'); const Target = require('../../src/engine/target'); const Variable = require('../../src/engine/variable'); const Runtime = require('../../src/engine/runtime'); -test('spec', t => { +test('spec', () => { const runtime = new Runtime(); const cloud = new Cloud(runtime); - t.type(cloud, 'object'); - t.type(cloud.postData, 'function'); - t.type(cloud.requestCreateVariable, 'function'); - t.type(cloud.requestUpdateVariable, 'function'); - t.type(cloud.requestRenameVariable, 'function'); - t.type(cloud.requestDeleteVariable, 'function'); - t.type(cloud.updateCloudVariable, 'function'); - t.type(cloud.setProvider, 'function'); - t.type(cloud.setStage, 'function'); - t.type(cloud.clear, 'function'); - t.end(); + assert.strictEqual(typeof cloud, 'object'); + assert.strictEqual(typeof cloud.postData, 'function'); + assert.strictEqual(typeof cloud.requestCreateVariable, 'function'); + assert.strictEqual(typeof cloud.requestUpdateVariable, 'function'); + assert.strictEqual(typeof cloud.requestRenameVariable, 'function'); + assert.strictEqual(typeof cloud.requestDeleteVariable, 'function'); + assert.strictEqual(typeof cloud.updateCloudVariable, 'function'); + assert.strictEqual(typeof cloud.setProvider, 'function'); + assert.strictEqual(typeof cloud.setStage, 'function'); + assert.strictEqual(typeof cloud.clear, 'function'); }); -test('stage and provider are null initially', t => { +test('stage and provider are null initially', () => { const runtime = new Runtime(); const cloud = new Cloud(runtime); - t.strictEquals(cloud.provider, null); - t.strictEquals(cloud.stage, null); - t.end(); + assert.strictEqual(cloud.provider, null); + assert.strictEqual(cloud.stage, null); }); -test('setProvider sets the provider', t => { +test('setProvider sets the provider', () => { const runtime = new Runtime(); const cloud = new Cloud(runtime); @@ -39,12 +38,10 @@ test('setProvider sets the provider', t => { }; cloud.setProvider(provider); - t.strictEquals(cloud.provider, provider); - - t.end(); + assert.strictEqual(cloud.provider, provider); }); -test('postData update message updates the variable', t => { +test('postData update message updates the variable', () => { const runtime = new Runtime(); const stage = new Target(runtime); const fooVar = Variable.create( @@ -55,7 +52,7 @@ test('postData update message updates the variable', t => { ); stage.variables[fooVar.id] = fooVar; - t.strictEquals(fooVar.value, 0); + assert.strictEqual(fooVar.value, 0); const cloud = new Cloud(runtime); cloud.setStage(stage); @@ -63,11 +60,10 @@ test('postData update message updates the variable', t => { name: 'foo', value: 3 }}); - t.strictEquals(fooVar.value, 3); - t.end(); + assert.strictEqual(fooVar.value, 3); }); -test('requestUpdateVariable calls provider\'s updateVariable function', t => { +test('requestUpdateVariable calls provider\'s updateVariable function', () => { let updateVariableCalled = false; let mockVarName = ''; let mockVarValue = ''; @@ -86,13 +82,12 @@ test('requestUpdateVariable calls provider\'s updateVariable function', t => { const cloud = new Cloud(runtime); cloud.setProvider(provider); cloud.requestUpdateVariable('foo', 3); - t.equals(updateVariableCalled, true); - t.strictEquals(mockVarName, 'foo'); - t.strictEquals(mockVarValue, 3); - t.end(); + assert.strictEqual(updateVariableCalled, true); + assert.strictEqual(mockVarName, 'foo'); + assert.strictEqual(mockVarValue, 3); }); -test('requestCreateVariable calls provider\'s createVariable function', t => { +test('requestCreateVariable calls provider\'s createVariable function', () => { let createVariableCalled = false; const mockVariable = Variable.create('a var id', 'my var', Variable.SCALAR_TYPE, false); let mockVarName; @@ -112,15 +107,14 @@ test('requestCreateVariable calls provider\'s createVariable function', t => { const cloud = new Cloud(runtime); cloud.setProvider(provider); cloud.requestCreateVariable(mockVariable); - t.equals(createVariableCalled, true); - t.strictEquals(mockVarName, 'my var'); - t.strictEquals(mockVarValue, 0); + assert.strictEqual(createVariableCalled, true); + assert.strictEqual(mockVarName, 'my var'); + assert.strictEqual(mockVarValue, 0); // Calling requestCreateVariable does not set isCloud flag on variable - t.strictEquals(mockVariable.isCloud, false); - t.end(); + assert.strictEqual(mockVariable.isCloud, false); }); -test('requestRenameVariable calls provider\'s renameVariable function', t => { +test('requestRenameVariable calls provider\'s renameVariable function', () => { let renameVariableCalled = false; let mockVarOldName; let mockVarNewName; @@ -139,13 +133,12 @@ test('requestRenameVariable calls provider\'s renameVariable function', t => { const cloud = new Cloud(runtime); cloud.setProvider(provider); cloud.requestRenameVariable('my var', 'new var name'); - t.equals(renameVariableCalled, true); - t.strictEquals(mockVarOldName, 'my var'); - t.strictEquals(mockVarNewName, 'new var name'); - t.end(); + assert.strictEqual(renameVariableCalled, true); + assert.strictEqual(mockVarOldName, 'my var'); + assert.strictEqual(mockVarNewName, 'new var name'); }); -test('requestDeleteVariable calls provider\'s deleteVariable function', t => { +test('requestDeleteVariable calls provider\'s deleteVariable function', () => { let deleteVariableCalled = false; let mockVarName; const mockDeleteVariable = name => { @@ -162,7 +155,6 @@ test('requestDeleteVariable calls provider\'s deleteVariable function', t => { const cloud = new Cloud(runtime); cloud.setProvider(provider); cloud.requestDeleteVariable('my var'); - t.equals(deleteVariableCalled, true); - t.strictEquals(mockVarName, 'my var'); - t.end(); + assert.strictEqual(deleteVariableCalled, true); + assert.strictEqual(mockVarName, 'my var'); }); diff --git a/test/unit/io_keyboard.js b/test/unit/io_keyboard.js index 441cc232..6ae0580d 100644 --- a/test/unit/io_keyboard.js +++ b/test/unit/io_keyboard.js @@ -1,18 +1,18 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const Keyboard = require('../../src/io/keyboard'); const Runtime = require('../../src/engine/runtime'); -test('spec', t => { +test('spec', () => { const rt = new Runtime(); const k = new Keyboard(rt); - t.type(k, 'object'); - t.type(k.postData, 'function'); - t.type(k.getKeyIsDown, 'function'); - t.end(); + assert.strictEqual(typeof k, 'object'); + assert.strictEqual(typeof k.postData, 'function'); + assert.strictEqual(typeof k.getKeyIsDown, 'function'); }); -test('space key', t => { +test('space key', () => { const rt = new Runtime(); const k = new Keyboard(rt); @@ -20,13 +20,12 @@ test('space key', t => { key: ' ', isDown: true }); - t.strictDeepEquals(k._keysPressed, ['space']); - t.strictEquals(k.getKeyIsDown('space'), true); - t.strictEquals(k.getKeyIsDown('any'), true); - t.end(); + assert.deepStrictEqual(k._keysPressed, ['space']); + assert.strictEqual(k.getKeyIsDown('space'), true); + assert.strictEqual(k.getKeyIsDown('any'), true); }); -test('letter key', t => { +test('letter key', () => { const rt = new Runtime(); const k = new Keyboard(rt); @@ -34,15 +33,14 @@ test('letter key', t => { key: 'a', isDown: true }); - t.strictDeepEquals(k._keysPressed, ['A']); - t.strictEquals(k.getKeyIsDown(65), true); - t.strictEquals(k.getKeyIsDown('a'), true); - t.strictEquals(k.getKeyIsDown('A'), true); - t.strictEquals(k.getKeyIsDown('any'), true); - t.end(); + assert.deepStrictEqual(k._keysPressed, ['A']); + assert.strictEqual(k.getKeyIsDown(65), true); + assert.strictEqual(k.getKeyIsDown('a'), true); + assert.strictEqual(k.getKeyIsDown('A'), true); + assert.strictEqual(k.getKeyIsDown('any'), true); }); -test('number key', t => { +test('number key', () => { const rt = new Runtime(); const k = new Keyboard(rt); @@ -50,14 +48,13 @@ test('number key', t => { key: '1', isDown: true }); - t.strictDeepEquals(k._keysPressed, ['1']); - t.strictEquals(k.getKeyIsDown(49), true); - t.strictEquals(k.getKeyIsDown('1'), true); - t.strictEquals(k.getKeyIsDown('any'), true); - t.end(); + assert.deepStrictEqual(k._keysPressed, ['1']); + assert.strictEqual(k.getKeyIsDown(49), true); + assert.strictEqual(k.getKeyIsDown('1'), true); + assert.strictEqual(k.getKeyIsDown('any'), true); }); -test('non-english key', t => { +test('non-english key', () => { const rt = new Runtime(); const k = new Keyboard(rt); @@ -65,10 +62,9 @@ test('non-english key', t => { key: '日', isDown: true }); - t.strictDeepEquals(k._keysPressed, ['日']); - t.strictEquals(k.getKeyIsDown('日'), true); - t.strictEquals(k.getKeyIsDown('any'), true); - t.end(); + assert.deepStrictEqual(k._keysPressed, ['日']); + assert.strictEqual(k.getKeyIsDown('日'), true); + assert.strictEqual(k.getKeyIsDown('any'), true); }); /* TW: This test is disabled because we intentionally add support for modifier keys. @@ -86,7 +82,7 @@ test('ignore modifier key', t => { }); */ -test('keyup', t => { +test('keyup', () => { const rt = new Runtime(); const k = new Keyboard(rt); @@ -98,8 +94,7 @@ test('keyup', t => { key: 'ArrowLeft', isDown: false }); - t.strictDeepEquals(k._keysPressed, []); - t.strictEquals(k.getKeyIsDown('left arrow'), false); - t.strictEquals(k.getKeyIsDown('any'), false); - t.end(); + assert.deepStrictEqual(k._keysPressed, []); + assert.strictEqual(k.getKeyIsDown('left arrow'), false); + assert.strictEqual(k.getKeyIsDown('any'), false); }); diff --git a/test/unit/io_keyboard_tw.js b/test/unit/io_keyboard_tw.js index 4e76e3e9..026ed877 100644 --- a/test/unit/io_keyboard_tw.js +++ b/test/unit/io_keyboard_tw.js @@ -1,16 +1,16 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const Keyboard = require('../../src/io/keyboard'); const Runtime = require('../../src/engine/runtime'); -test('extended spec', t => { +test('extended spec', () => { const rt = new Runtime(); const k = new Keyboard(rt); - t.type(k.getLastKeyPressed, 'function'); - t.end(); + assert.strictEqual(typeof k.getLastKeyPressed, 'function'); }); -test('extended key support', t => { +test('extended key support', () => { const rt = new Runtime(); const k = new Keyboard(rt); @@ -18,30 +18,28 @@ test('extended key support', t => { key: 'Backspace', isDown: true }); - t.strictDeepEquals(k._keysPressed, ['backspace']); - t.strictEqual(k.getKeyIsDown('backspace'), true); - t.end(); + assert.deepStrictEqual(k._keysPressed, ['backspace']); + assert.strictEqual(k.getKeyIsDown('backspace'), true); }); -test('last key pressed', t => { +test('last key pressed', () => { const rt = new Runtime(); const k = new Keyboard(rt); - t.strictEqual(k.getLastKeyPressed(), ''); + assert.strictEqual(k.getLastKeyPressed(), ''); k.postData({ key: 'a', isDown: true }); - t.strictEqual(k.getLastKeyPressed(), 'a'); + assert.strictEqual(k.getLastKeyPressed(), 'a'); k.postData({ key: 'b', isDown: true }); - t.strictEqual(k.getLastKeyPressed(), 'b'); - t.end(); + assert.strictEqual(k.getLastKeyPressed(), 'b'); }); -test('holding shift and key, releasing shift, then releasing key', t => { +test('holding shift and key, releasing shift, then releasing key', () => { const rt = new Runtime(); const k = new Keyboard(rt); @@ -51,9 +49,9 @@ test('holding shift and key, releasing shift, then releasing key', t => { isDown: true, keyCode: 50 }); - t.equal(k.getKeyIsDown('2'), false); - t.equal(k.getKeyIsDown('@'), true); - t.equal(k.getKeyIsDown('any'), true); + assert.strictEqual(k.getKeyIsDown('2'), false); + assert.strictEqual(k.getKeyIsDown('@'), true); + assert.strictEqual(k.getKeyIsDown('any'), true); // Release shift, then release 2 k.postData({ key: 'Shift', @@ -65,14 +63,12 @@ test('holding shift and key, releasing shift, then releasing key', t => { isDown: false, keyCode: 50 }); - t.equal(k.getKeyIsDown('@'), false); - t.equal(k.getKeyIsDown('2'), false); - t.equal(k.getKeyIsDown('any'), false); - - t.end(); + assert.strictEqual(k.getKeyIsDown('@'), false); + assert.strictEqual(k.getKeyIsDown('2'), false); + assert.strictEqual(k.getKeyIsDown('any'), false); }); -test('holding shift and key, releasing shift, waiting, then releasing key', t => { +test('holding shift and key, releasing shift, waiting, then releasing key', () => { const rt = new Runtime(); const k = new Keyboard(rt); @@ -81,9 +77,9 @@ test('holding shift and key, releasing shift, waiting, then releasing key', t => isDown: true, keyCode: 50 }); - t.equal(k.getKeyIsDown('2'), false); - t.equal(k.getKeyIsDown('@'), true); - t.equal(k.getKeyIsDown('any'), true); + assert.strictEqual(k.getKeyIsDown('2'), false); + assert.strictEqual(k.getKeyIsDown('@'), true); + assert.strictEqual(k.getKeyIsDown('any'), true); k.postData({ key: 'Shift', isDown: false, @@ -95,36 +91,32 @@ test('holding shift and key, releasing shift, waiting, then releasing key', t => isDown: true, keyCode: 50 }); - t.equal(k.getKeyIsDown('@'), false); - t.equal(k.getKeyIsDown('2'), true); - t.equal(k.getKeyIsDown('any'), true); + assert.strictEqual(k.getKeyIsDown('@'), false); + assert.strictEqual(k.getKeyIsDown('2'), true); + assert.strictEqual(k.getKeyIsDown('any'), true); // And now we release 2 k.postData({ key: '2', isDown: false, keyCode: 50 }); - t.equal(k.getKeyIsDown('@'), false); - t.equal(k.getKeyIsDown('2'), false); - t.equal(k.getKeyIsDown('any'), false); - - t.end(); + assert.strictEqual(k.getKeyIsDown('@'), false); + assert.strictEqual(k.getKeyIsDown('2'), false); + assert.strictEqual(k.getKeyIsDown('any'), false); }); -test('hasUsedKey', t => { +test('hasUsedKey', () => { const rt = new Runtime(); const k = new Keyboard(rt); - t.equal(k.hasUsedKey('backspace'), false); - t.equal(k.hasUsedKey('delete'), false); + assert.strictEqual(k.hasUsedKey('backspace'), false); + assert.strictEqual(k.hasUsedKey('delete'), false); k.getKeyIsDown('backspace'); - t.equal(k.hasUsedKey('backspace'), true); - t.equal(k.hasUsedKey('delete'), false); + assert.strictEqual(k.hasUsedKey('backspace'), true); + assert.strictEqual(k.hasUsedKey('delete'), false); k.getKeyIsDown('delete'); - t.equal(k.hasUsedKey('backspace'), true); - t.equal(k.hasUsedKey('delete'), true); - - t.end(); + assert.strictEqual(k.hasUsedKey('backspace'), true); + assert.strictEqual(k.hasUsedKey('delete'), true); }); diff --git a/test/unit/io_mouse.js b/test/unit/io_mouse.js index c1fa2193..27da4cb5 100644 --- a/test/unit/io_mouse.js +++ b/test/unit/io_mouse.js @@ -1,22 +1,22 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const Mouse = require('../../src/io/mouse'); const Runtime = require('../../src/engine/runtime'); -test('spec', t => { +test('spec', () => { const rt = new Runtime(); const m = new Mouse(rt); - t.type(m, 'object'); - t.type(m.postData, 'function'); - t.type(m.getClientX, 'function'); - t.type(m.getClientY, 'function'); - t.type(m.getScratchX, 'function'); - t.type(m.getScratchY, 'function'); - t.type(m.getIsDown, 'function'); - t.end(); + assert.strictEqual(typeof m, 'object'); + assert.strictEqual(typeof m.postData, 'function'); + assert.strictEqual(typeof m.getClientX, 'function'); + assert.strictEqual(typeof m.getClientY, 'function'); + assert.strictEqual(typeof m.getScratchX, 'function'); + assert.strictEqual(typeof m.getScratchY, 'function'); + assert.strictEqual(typeof m.getIsDown, 'function'); }); -test('mouseUp', t => { +test('mouseUp', () => { const rt = new Runtime(); const m = new Mouse(rt); @@ -27,15 +27,14 @@ test('mouseUp', t => { canvasWidth: 480, canvasHeight: 360 }); - t.strictEquals(m.getClientX(), -20); - t.strictEquals(m.getClientY(), 10); - t.strictEquals(m.getScratchX(), -240); - t.strictEquals(m.getScratchY(), 170); - t.strictEquals(m.getIsDown(), false); - t.end(); + assert.strictEqual(m.getClientX(), -20); + assert.strictEqual(m.getClientY(), 10); + assert.strictEqual(m.getScratchX(), -240); + assert.strictEqual(m.getScratchY(), 170); + assert.strictEqual(m.getIsDown(), false); }); -test('mouseDown', t => { +test('mouseDown', () => { const rt = new Runtime(); const m = new Mouse(rt); @@ -46,15 +45,14 @@ test('mouseDown', t => { canvasWidth: 480, canvasHeight: 360 }); - t.strictEquals(m.getClientX(), 9.9); - t.strictEquals(m.getClientY(), 400.1); - t.strictEquals(m.getScratchX(), -230); - t.strictEquals(m.getScratchY(), -180); - t.strictEquals(m.getIsDown(), true); - t.end(); + assert.strictEqual(m.getClientX(), 9.9); + assert.strictEqual(m.getClientY(), 400.1); + assert.strictEqual(m.getScratchX(), -230); + assert.strictEqual(m.getScratchY(), -180); + assert.strictEqual(m.getIsDown(), true); }); -test('at zoomed scale', t => { +test('at zoomed scale', () => { const rt = new Runtime(); const m = new Mouse(rt); @@ -64,14 +62,13 @@ test('at zoomed scale', t => { canvasWidth: 960, canvasHeight: 720 }); - t.strictEquals(m.getClientX(), 240); - t.strictEquals(m.getClientY(), 540); - t.strictEquals(m.getScratchX(), -120); - t.strictEquals(m.getScratchY(), -90); - t.end(); + assert.strictEqual(m.getClientX(), 240); + assert.strictEqual(m.getClientY(), 540); + assert.strictEqual(m.getScratchX(), -120); + assert.strictEqual(m.getScratchY(), -90); }); -test('mousedown activating click hats', t => { +test('mousedown activating click hats', () => { const rt = new Runtime(); const m = new Mouse(rt); @@ -103,23 +100,23 @@ test('mousedown activating click hats', t => { // Mouse move without mousedown m.postData(mouseMoveEvent); - t.strictEquals(ranClickHats, false); + assert.strictEqual(ranClickHats, false); // Mouse down event triggers the hats if target is not draggable dummyTarget.draggable = false; m.postData(mouseDownEvent); - t.strictEquals(ranClickHats, true); + assert.strictEqual(ranClickHats, true); // But another mouse move while down doesn't trigger ranClickHats = false; m.postData(mouseDownEvent); - t.strictEquals(ranClickHats, false); + assert.strictEqual(ranClickHats, false); // And it does trigger on mouse up if target is draggable ranClickHats = false; dummyTarget.draggable = true; m.postData(mouseUpEvent); - t.strictEquals(ranClickHats, true); + assert.strictEqual(ranClickHats, true); // And hats don't trigger if mouse down is outside canvas ranClickHats = false; @@ -127,7 +124,5 @@ test('mousedown activating click hats', t => { x: 50000, y: 50 })); - t.strictEquals(ranClickHats, false); - - t.end(); + assert.strictEqual(ranClickHats, false); }); diff --git a/test/unit/io_mouse_tw.js b/test/unit/io_mouse_tw.js index 9252caab..386c0933 100644 --- a/test/unit/io_mouse_tw.js +++ b/test/unit/io_mouse_tw.js @@ -1,8 +1,9 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const Mouse = require('../../src/io/mouse'); const Runtime = require('../../src/engine/runtime'); -test('position clamping', t => { +test('position clamping', () => { const rt = new Runtime(); const m = new Mouse(rt); @@ -13,94 +14,89 @@ test('position clamping', t => { canvasWidth: 480, canvasHeight: 360 }); - t.strictEquals(m.getClientX(), BIG); - t.strictEquals(m.getClientY(), BIG); - t.strictEquals(m.getScratchX(), 240); - t.strictEquals(m.getScratchY(), -180); - t.end(); + assert.strictEqual(m.getClientX(), BIG); + assert.strictEqual(m.getClientY(), BIG); + assert.strictEqual(m.getScratchX(), 240); + assert.strictEqual(m.getScratchY(), -180); }); -test('mouseButtonDown', t => { +test('mouseButtonDown', () => { const rt = new Runtime(); const m = new Mouse(rt); - t.strictEquals(m.getButtonIsDown(0), false); - t.strictEquals(m.getButtonIsDown(1), false); - t.strictEquals(m.getButtonIsDown(2), false); + assert.strictEqual(m.getButtonIsDown(0), false); + assert.strictEqual(m.getButtonIsDown(1), false); + assert.strictEqual(m.getButtonIsDown(2), false); m.postData({ isDown: true, button: 0 }); - t.strictEquals(m.getButtonIsDown(0), true); - t.strictEquals(m.getButtonIsDown(1), false); - t.strictEquals(m.getButtonIsDown(2), false); + assert.strictEqual(m.getButtonIsDown(0), true); + assert.strictEqual(m.getButtonIsDown(1), false); + assert.strictEqual(m.getButtonIsDown(2), false); m.postData({ isDown: true, button: 2 }); - t.strictEquals(m.getButtonIsDown(0), true); - t.strictEquals(m.getButtonIsDown(1), false); - t.strictEquals(m.getButtonIsDown(2), true); + assert.strictEqual(m.getButtonIsDown(0), true); + assert.strictEqual(m.getButtonIsDown(1), false); + assert.strictEqual(m.getButtonIsDown(2), true); m.postData({ isDown: false, button: 2 }); - t.strictEquals(m.getButtonIsDown(0), true); - t.strictEquals(m.getButtonIsDown(1), false); - t.strictEquals(m.getButtonIsDown(2), false); - t.end(); + assert.strictEqual(m.getButtonIsDown(0), true); + assert.strictEqual(m.getButtonIsDown(1), false); + assert.strictEqual(m.getButtonIsDown(2), false); }); -test('mouseDown with buttons', t => { +test('mouseDown with buttons', () => { const rt = new Runtime(); const m = new Mouse(rt); - t.strictEquals(m.getIsDown(), false); + assert.strictEqual(m.getIsDown(), false); m.postData({ isDown: true, button: 0 }); - t.strictEquals(m.getIsDown(), true); + assert.strictEqual(m.getIsDown(), true); m.postData({ isDown: true, button: 2 }); - t.strictEquals(m.getIsDown(), true); + assert.strictEqual(m.getIsDown(), true); m.postData({ isDown: false, button: 2 }); - t.strictEquals(m.getIsDown(), false); - t.end(); + assert.strictEqual(m.getIsDown(), false); }); -test('missing button is treated as left', t => { +test('missing button is treated as left', () => { const rt = new Runtime(); const m = new Mouse(rt); - t.strictEquals(m.getButtonIsDown(0), false); + assert.strictEqual(m.getButtonIsDown(0), false); m.postData({ isDown: true }); - t.strictEquals(m.getButtonIsDown(0), true); + assert.strictEqual(m.getButtonIsDown(0), true); m.postData({ isDown: false }); - t.strictEquals(m.getButtonIsDown(0), false); - t.end(); + assert.strictEqual(m.getButtonIsDown(0), false); }); -test('usesRightClickDown', t => { +test('usesRightClickDown', () => { const rt = new Runtime(); const m = new Mouse(rt); - t.strictEquals(m.usesRightClickDown, false); - t.strictEquals(m.getButtonIsDown(2), false); - t.strictEquals(m.usesRightClickDown, true); - t.end(); + assert.strictEqual(m.usesRightClickDown, false); + assert.strictEqual(m.getButtonIsDown(2), false); + assert.strictEqual(m.usesRightClickDown, true); }); -test('no rounding when misc limits disabled', t => { +test('no rounding when misc limits disabled', () => { const rt = new Runtime(); const m = new Mouse(rt); @@ -110,19 +106,17 @@ test('no rounding when misc limits disabled', t => { canvasWidth: 960, canvasHeight: 720 }); - t.equal(m.getScratchX(), -119); - t.equal(m.getScratchY(), -90); + assert.strictEqual(m.getScratchX(), -119); + assert.strictEqual(m.getScratchY(), -90); rt.setRuntimeOptions({ miscLimits: false }); - t.equal(m.getScratchX(), -119.5); - t.equal(m.getScratchY(), -90.5); - - t.end(); + assert.strictEqual(m.getScratchX(), -119.5); + assert.strictEqual(m.getScratchY(), -90.5); }); -test('accepts 0 as x and y position', t => { +test('accepts 0 as x and y position', () => { const rt = new Runtime(); const m = new Mouse(rt); @@ -132,8 +126,8 @@ test('accepts 0 as x and y position', t => { canvasWidth: 480, canvasHeight: 360 }); - t.equal(m.getClientX(), 1); - t.equal(m.getClientY(), 2); + assert.strictEqual(m.getClientX(), 1); + assert.strictEqual(m.getClientY(), 2); m.postData({ x: 0, @@ -141,8 +135,6 @@ test('accepts 0 as x and y position', t => { canvasWidth: 480, canvasHeight: 360 }); - t.equal(m.getClientX(), 0); - t.equal(m.getClientY(), 0); - - t.end(); + assert.strictEqual(m.getClientX(), 0); + assert.strictEqual(m.getClientY(), 0); }); diff --git a/test/unit/io_mousewheel.js b/test/unit/io_mousewheel.js index f54d47cc..7e948a4a 100644 --- a/test/unit/io_mousewheel.js +++ b/test/unit/io_mousewheel.js @@ -1,17 +1,17 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const MouseWheel = require('../../src/io/mouseWheel'); const Runtime = require('../../src/engine/runtime'); -test('spec', t => { +test('spec', () => { const rt = new Runtime(); const mw = new MouseWheel(rt); - t.type(mw, 'object'); - t.type(mw.postData, 'function'); - t.end(); + assert.strictEqual(typeof mw, 'object'); + assert.strictEqual(typeof mw.postData, 'function'); }); -test('blocks activated by scrolling', t => { +test('blocks activated by scrolling', () => { let _startHatsArgs; const rt = { startHats: (...args) => { @@ -24,21 +24,19 @@ test('blocks activated by scrolling', t => { mw.postData({ deltaY: -1 }); - t.strictEquals(_startHatsArgs[0], 'event_whenkeypressed'); - t.strictEquals(_startHatsArgs[1].KEY_OPTION, 'up arrow'); + assert.strictEqual(_startHatsArgs[0], 'event_whenkeypressed'); + assert.strictEqual(_startHatsArgs[1].KEY_OPTION, 'up arrow'); _startHatsArgs = null; mw.postData({ deltaY: +1 }); - t.strictEquals(_startHatsArgs[0], 'event_whenkeypressed'); - t.strictEquals(_startHatsArgs[1].KEY_OPTION, 'down arrow'); + assert.strictEqual(_startHatsArgs[0], 'event_whenkeypressed'); + assert.strictEqual(_startHatsArgs[1].KEY_OPTION, 'down arrow'); _startHatsArgs = null; mw.postData({ deltaY: 0 }); - t.strictEquals(_startHatsArgs, null); - - t.end(); + assert.strictEqual(_startHatsArgs, null); }); diff --git a/test/unit/io_scratchBLE.js b/test/unit/io_scratchBLE.js index 8da2b3d0..d12d5879 100644 --- a/test/unit/io_scratchBLE.js +++ b/test/unit/io_scratchBLE.js @@ -1,26 +1,14 @@ -const test = require('tap').test; +const {test} = require('node:test'); // const ScratchBLE = require('../../src/io/scratchBLE'); -test('constructor', t => { - t.end(); -}); +test('constructor', () => {}); -test('waitForSocket', t => { - t.end(); -}); +test('waitForSocket', () => {}); -test('requestPeripheral', t => { - t.end(); -}); +test('requestPeripheral', () => {}); -test('didReceiveCall', t => { - t.end(); -}); +test('didReceiveCall', () => {}); -test('read', t => { - t.end(); -}); +test('read', () => {}); -test('write', t => { - t.end(); -}); +test('write', () => {}); diff --git a/test/unit/io_scratchBT.js b/test/unit/io_scratchBT.js index 843526ab..2a362941 100644 --- a/test/unit/io_scratchBT.js +++ b/test/unit/io_scratchBT.js @@ -1,22 +1,12 @@ -const test = require('tap').test; +const {test} = require('node:test'); // const ScratchBT = require('../../src/io/scratchBT'); -test('constructor', t => { - t.end(); -}); +test('constructor', () => {}); -test('requestPeripheral', t => { - t.end(); -}); +test('requestPeripheral', () => {}); -test('connectPeripheral', t => { - t.end(); -}); +test('connectPeripheral', () => {}); -test('sendMessage', t => { - t.end(); -}); +test('sendMessage', () => {}); -test('didReceiveCall', t => { - t.end(); -}); +test('didReceiveCall', () => {}); diff --git a/test/unit/io_userData.js b/test/unit/io_userData.js index 49dee9f9..d851d8e5 100644 --- a/test/unit/io_userData.js +++ b/test/unit/io_userData.js @@ -1,25 +1,23 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const UserData = require('../../src/io/userData'); -test('spec', t => { +test('spec', () => { const userData = new UserData(); - t.type(userData, 'object'); - t.type(userData.postData, 'function'); - t.type(userData.getUsername, 'function'); - t.end(); + assert.strictEqual(typeof userData, 'object'); + assert.strictEqual(typeof userData.postData, 'function'); + assert.strictEqual(typeof userData.getUsername, 'function'); }); -test('getUsername returns empty string initially', t => { +test('getUsername returns empty string initially', () => { const userData = new UserData(); - t.strictEquals(userData.getUsername(), ''); - t.end(); + assert.strictEqual(userData.getUsername(), ''); }); -test('postData sets the username', t => { +test('postData sets the username', () => { const userData = new UserData(); userData.postData({username: 'TEST'}); - t.strictEquals(userData.getUsername(), 'TEST'); - t.end(); + assert.strictEqual(userData.getUsername(), 'TEST'); }); diff --git a/test/unit/maybe_format_message.js b/test/unit/maybe_format_message.js index 969e25a2..12f28f6c 100644 --- a/test/unit/maybe_format_message.js +++ b/test/unit/maybe_format_message.js @@ -1,4 +1,5 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const maybeFormatMessage = require('../../src/util/maybe-format-message'); const nonMessages = [ @@ -45,33 +46,27 @@ const complexMessage = { const quickExpectedResult = 'The quick brown fox jumped over the lazy dog.'; const otherExpectedResult = 'Too slow, Gobo!'; -test('preserve non-messages', t => { - t.plan(nonMessages.length); - +test('preserve non-messages', () => { for (const x of nonMessages) { const result = maybeFormatMessage(x); - t.strictSame(x, result); + assert.deepStrictEqual(x, result); } - - t.end(); }); -test('format messages', t => { +test('format messages', () => { const quickResult1 = maybeFormatMessage(simpleMessage); - t.strictNotSame(quickResult1, simpleMessage); - t.same(quickResult1, quickExpectedResult); + assert.notDeepStrictEqual(quickResult1, simpleMessage); + assert.deepEqual(quickResult1, quickExpectedResult); const quickResult2 = maybeFormatMessage(complexMessage, argsQuick); - t.strictNotSame(quickResult2, complexMessage); - t.same(quickResult2, quickExpectedResult); + assert.notDeepStrictEqual(quickResult2, complexMessage); + assert.deepEqual(quickResult2, quickExpectedResult); const otherResult1 = maybeFormatMessage(complexMessage, argsOther); - t.strictNotSame(otherResult1, complexMessage); - t.same(otherResult1, otherExpectedResult); + assert.notDeepStrictEqual(otherResult1, complexMessage); + assert.deepEqual(otherResult1, otherExpectedResult); const otherResult2 = maybeFormatMessage(complexMessage, argsEmpty); - t.strictNotSame(otherResult2, complexMessage); - t.same(otherResult2, otherExpectedResult); - - t.end(); + assert.notDeepStrictEqual(otherResult2, complexMessage); + assert.deepEqual(otherResult2, otherExpectedResult); }); diff --git a/test/unit/mock-timer.js b/test/unit/mock-timer.js index db587894..5cd4eddd 100644 --- a/test/unit/mock-timer.js +++ b/test/unit/mock-timer.js @@ -1,29 +1,28 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const MockTimer = require('../fixtures/mock-timer'); -test('spec', t => { +test('spec', () => { const timer = new MockTimer(); - t.type(MockTimer, 'function'); - t.type(timer, 'object'); + assert.strictEqual(typeof MockTimer, 'function'); + assert.strictEqual(typeof timer, 'object'); // Most members of MockTimer mimic members of Timer. - t.type(timer.startTime, 'number'); - t.type(timer.time, 'function'); - t.type(timer.start, 'function'); - t.type(timer.timeElapsed, 'function'); - t.type(timer.setTimeout, 'function'); - t.type(timer.clearTimeout, 'function'); + assert.strictEqual(typeof timer.startTime, 'number'); + assert.strictEqual(typeof timer.time, 'function'); + assert.strictEqual(typeof timer.start, 'function'); + assert.strictEqual(typeof timer.timeElapsed, 'function'); + assert.strictEqual(typeof timer.setTimeout, 'function'); + assert.strictEqual(typeof timer.clearTimeout, 'function'); // A few members of MockTimer have no Timer equivalent and should only be used in tests. - t.type(timer.advanceMockTime, 'function'); - t.type(timer.advanceMockTimeAsync, 'function'); - t.type(timer.hasTimeouts, 'function'); - - t.end(); + assert.strictEqual(typeof timer.advanceMockTime, 'function'); + assert.strictEqual(typeof timer.advanceMockTimeAsync, 'function'); + assert.strictEqual(typeof timer.hasTimeouts, 'function'); }); -test('time', t => { +test('time', () => { const timer = new MockTimer(); const delta = 1; @@ -32,12 +31,11 @@ test('time', t => { timer.advanceMockTime(delta); const time3 = timer.time(); - t.equal(time1, time2); - t.equal(time2 + delta, time3); - t.end(); + assert.strictEqual(time1, time2); + assert.strictEqual(time2 + delta, time3); }); -test('start / timeElapsed', t => new Promise(resolve => { +test('start / timeElapsed', () => new Promise(resolve => { const timer = new MockTimer(); const halfDelay = 1; const fullDelay = halfDelay + halfDelay; @@ -48,12 +46,11 @@ test('start / timeElapsed', t => new Promise(resolve => { // Wait and measure timer timer.setTimeout(() => { - t.equal(timeoutCalled, 0); + assert.strictEqual(timeoutCalled, 0); ++timeoutCalled; const timeElapsed = timer.timeElapsed(); - t.equal(timeElapsed, fullDelay); - t.end(); + assert.strictEqual(timeElapsed, fullDelay); resolve(); }, fullDelay); @@ -64,14 +61,14 @@ test('start / timeElapsed', t => new Promise(resolve => { // give the mock timer a chance to run tasks global.setTimeout(() => { // we've only mock-waited for half the delay so it should not have run yet - t.equal(timeoutCalled, 0); + assert.strictEqual(timeoutCalled, 0); // this should trigger the callback timer.advanceMockTime(halfDelay); }, 0); })); -test('clearTimeout / hasTimeouts', t => new Promise((resolve, reject) => { +test('clearTimeout / hasTimeouts', () => new Promise((resolve, reject) => { const timer = new MockTimer(); const timeoutId = timer.setTimeout(() => { @@ -80,7 +77,6 @@ test('clearTimeout / hasTimeouts', t => new Promise((resolve, reject) => { timer.setTimeout(() => { resolve('Non-canceled task ran'); - t.end(); }, 2); timer.clearTimeout(timeoutId); diff --git a/test/unit/project_changed_state.js b/test/unit/project_changed_state.js index 85e362cb..14cce37c 100644 --- a/test/unit/project_changed_state.js +++ b/test/unit/project_changed_state.js @@ -1,4 +1,5 @@ -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const path = require('path'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const makeTestStorage = require('../fixtures/make-test-storage'); @@ -7,7 +8,7 @@ const VirtualMachine = require('../../src/virtual-machine'); let vm; let projectChanged; -tap.beforeEach(() => { +beforeEach(async () => { const projectUri = path.resolve(__dirname, '../fixtures/default.sb2'); const project = readFileToBuffer(projectUri); @@ -18,38 +19,31 @@ tap.beforeEach(() => { }); vm.attachStorage(makeTestStorage()); - return vm.loadProject(project).then(() => { - // The test in project_load_changed_state.js tests - // that loading a project does not emit a project changed - // event. This setup tries to be agnostic of whether that - // test is passing or failing. - projectChanged = false; - }); + await vm.loadProject(project); + // The test in project_load_changed_state.js tests + // that loading a project does not emit a project changed + // event. This setup tries to be agnostic of whether that + // test is passing or failing. + projectChanged = false; }); -const test = tap.test; - -test('Adding a sprite (from sprite2) should emit a project changed event', t => { +test('Adding a sprite (from sprite2) should emit a project changed event', async () => { const sprite2Uri = path.resolve(__dirname, '../fixtures/cat.sprite2'); const sprite2 = readFileToBuffer(sprite2Uri); - vm.addSprite(sprite2).then(() => { - t.equal(projectChanged, true); - t.end(); - }); + await vm.addSprite(sprite2); + assert.strictEqual(projectChanged, true); }); -test('Adding a sprite (from sprite3) should emit a project changed event', t => { +test('Adding a sprite (from sprite3) should emit a project changed event', async () => { const sprite3Uri = path.resolve(__dirname, '../fixtures/cat.sprite3'); const sprite3 = readFileToBuffer(sprite3Uri); - vm.addSprite(sprite3).then(() => { - t.equal(projectChanged, true); - t.end(); - }); + await vm.addSprite(sprite3); + assert.strictEqual(projectChanged, true); }); -test('Adding a costume should emit a project changed event', t => { +test('Adding a costume should emit a project changed event', async () => { const newCostume = { name: 'costume1', baseLayerID: 0, @@ -59,13 +53,11 @@ test('Adding a costume should emit a project changed event', t => { rotationCenterY: 55 }; - vm.addCostume('f9a1c175dbe2e5dee472858dd30d16bb.svg', newCostume).then(() => { - t.equal(projectChanged, true); - t.end(); - }); + await vm.addCostume('f9a1c175dbe2e5dee472858dd30d16bb.svg', newCostume); + assert.strictEqual(projectChanged, true); }); -test('Adding a costume from library should emit a project changed event', t => { +test('Adding a costume from library should emit a project changed event', async () => { const newCostume = { name: 'costume1', baseLayerID: 0, @@ -75,13 +67,11 @@ test('Adding a costume from library should emit a project changed event', t => { rotationCenterY: 55 }; - vm.addCostumeFromLibrary('f9a1c175dbe2e5dee472858dd30d16bb.svg', newCostume).then(() => { - t.equal(projectChanged, true); - t.end(); - }); + await vm.addCostumeFromLibrary('f9a1c175dbe2e5dee472858dd30d16bb.svg', newCostume); + assert.strictEqual(projectChanged, true); }); -test('Adding a backdrop should emit a project changed event', t => { +test('Adding a backdrop should emit a project changed event', async () => { const newCostume = { name: 'costume1', baseLayerID: 0, @@ -91,13 +81,11 @@ test('Adding a backdrop should emit a project changed event', t => { rotationCenterY: 55 }; - vm.addBackdrop('f9a1c175dbe2e5dee472858dd30d16bb.svg', newCostume).then(() => { - t.equal(projectChanged, true); - t.end(); - }); + await vm.addBackdrop('f9a1c175dbe2e5dee472858dd30d16bb.svg', newCostume); + assert.strictEqual(projectChanged, true); }); -test('Adding a sound should emit a project changed event', t => { +test('Adding a sound should emit a project changed event', async () => { const newSound = { soundName: 'meow', soundID: 0, @@ -106,59 +94,51 @@ test('Adding a sound should emit a project changed event', t => { rate: 22050 }; - vm.addSound(newSound).then(() => { - t.equal(projectChanged, true); - t.end(); - }); + await vm.addSound(newSound); + assert.strictEqual(projectChanged, true); }); -test('Deleting a sprite should emit a project changed event', t => { +test('Deleting a sprite should emit a project changed event', () => { const spriteId = vm.editingTarget.id; vm.deleteSprite(spriteId); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Deleting a costume should emit a project changed event', t => { +test('Deleting a costume should emit a project changed event', () => { vm.deleteCostume(0); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Deleting a sound should emit a project changed event', t => { +test('Deleting a sound should emit a project changed event', () => { vm.deleteSound(0); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Reordering a sprite should emit a project changed event', t => { +test('Reordering a sprite should emit a project changed event', async () => { const sprite3Uri = path.resolve(__dirname, '../fixtures/cat.sprite3'); const sprite3 = readFileToBuffer(sprite3Uri); // Add a new sprite so we have 2 to reorder - vm.addSprite(sprite3).then(() => { - // Reset the project changed flag to ignore change from adding new sprite - projectChanged = false; - t.equal(vm.runtime.targets.filter(target => !target.isStage).length, 2); - vm.reorderTarget(2, 1); - t.equal(projectChanged, true); - t.end(); - }); + await vm.addSprite(sprite3); + // Reset the project changed flag to ignore change from adding new sprite + projectChanged = false; + assert.strictEqual(vm.runtime.targets.filter(target => !target.isStage).length, 2); + vm.reorderTarget(2, 1); + assert.strictEqual(projectChanged, true); }); -test('Reordering a costume should emit a project changed event', t => { - t.equal(vm.editingTarget.sprite.costumes.length, 2); +test('Reordering a costume should emit a project changed event', () => { + assert.strictEqual(vm.editingTarget.sprite.costumes.length, 2); const spriteId = vm.editingTarget.id; const reordered = vm.reorderCostume(spriteId, 1, 0); - t.equal(reordered, true); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(reordered, true); + assert.strictEqual(projectChanged, true); }); -test('Reordering a sound should emit a project changed event', t => { +test('Reordering a sound should emit a project changed event', async () => { const spriteId = vm.editingTarget.id; const newSound = { soundName: 'meow', @@ -167,45 +147,40 @@ test('Reordering a sound should emit a project changed event', t => { sampleCount: 18688, rate: 22050 }; - vm.addSound(newSound).then(() => { - // Reset the project changed flag to ignore change from adding new sound - projectChanged = false; - t.equal(vm.editingTarget.sprite.sounds.length, 2); - const reordered = vm.reorderSound(spriteId, 1, 0); - t.equal(reordered, true); - t.equal(projectChanged, true); - t.end(); - }); + await vm.addSound(newSound); + // Reset the project changed flag to ignore change from adding new sound + projectChanged = false; + assert.strictEqual(vm.editingTarget.sprite.sounds.length, 2); + const reordered = vm.reorderSound(spriteId, 1, 0); + assert.strictEqual(reordered, true); + assert.strictEqual(projectChanged, true); }); -test('Renaming a sprite should emit a project changed event', t => { +test('Renaming a sprite should emit a project changed event', () => { const spriteId = vm.editingTarget.id; vm.renameSprite(spriteId, 'My Sprite'); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Renaming a costume should emit a project changed event', t => { +test('Renaming a costume should emit a project changed event', () => { vm.renameCostume(0, 'My Costume'); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Renaming a sound should emit a project changed event', t => { +test('Renaming a sound should emit a project changed event', () => { vm.renameSound(0, 'My Sound'); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Changing sprite info should emit a project changed event', t => { +test('Changing sprite info should emit a project changed event', () => { const newSpritePosition = { x: 10, y: 100 }; vm.postSpriteInfo(newSpritePosition); - t.equal(projectChanged, true); + assert.strictEqual(projectChanged, true); projectChanged = false; const newSpriteDirection = { @@ -213,28 +188,24 @@ test('Changing sprite info should emit a project changed event', t => { }; vm.postSpriteInfo(newSpriteDirection); - t.equal(projectChanged, true); + assert.strictEqual(projectChanged, true); projectChanged = false; - t.end(); - }); -test('Editing a vector costume should emit a project changed event', t => { +test('Editing a vector costume should emit a project changed event', () => { const mockSvg = 'svg'; const mockRotationX = -13; const mockRotationY = 25; vm.updateSvg(0, mockSvg, mockRotationX, mockRotationY); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Editing a sound should emit a project changed event', t => { +test('Editing a sound should emit a project changed event', () => { const mockSoundBuffer = []; const mockSoundEncoding = []; vm.updateSoundBuffer(0, mockSoundBuffer, mockSoundEncoding); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); diff --git a/test/unit/project_changed_state_blocks.js b/test/unit/project_changed_state_blocks.js index 9685cdd2..58b7c14b 100644 --- a/test/unit/project_changed_state_blocks.js +++ b/test/unit/project_changed_state_blocks.js @@ -1,4 +1,5 @@ -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const path = require('path'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const makeTestStorage = require('../fixtures/make-test-storage'); @@ -8,7 +9,7 @@ let vm; let projectChanged; let blockContainer; -tap.beforeEach(() => { +beforeEach(async () => { const projectUri = path.resolve(__dirname, '../fixtures/default.sb2'); const project = readFileToBuffer(projectUri); @@ -19,61 +20,56 @@ tap.beforeEach(() => { }); vm.attachStorage(makeTestStorage()); - return vm.loadProject(project).then(() => { - blockContainer = vm.editingTarget.blocks; - - // Add mock blocks to use for tests - blockContainer.createBlock({ - id: 'a parent block', - opcode: 'my_testParentBlock', - fields: {}, - inputs: {} - }); - - - blockContainer.createBlock({ - id: 'a new block', - opcode: 'my_testBlock', - topLevel: true, - x: -10, - y: 35, - fields: { - A_FIELD: { - name: 'A_FIELD', - value: 10 - } - }, - inputs: {}, - parent: 'a block' - }); - - // Reset project changes from new blocks - projectChanged = false; + await vm.loadProject(project); + blockContainer = vm.editingTarget.blocks; + // Add mock blocks to use for tests + blockContainer.createBlock({ + id: 'a parent block', + opcode: 'my_testParentBlock', + fields: {}, + inputs: {} }); + + + blockContainer.createBlock({ + id: 'a new block', + opcode: 'my_testBlock', + topLevel: true, + x: -10, + y: 35, + fields: { + A_FIELD: { + name: 'A_FIELD', + value: 10 + } + }, + inputs: {}, + parent: 'a block' + }); + + // Reset project changes from new blocks + projectChanged = false; + }); -const test = tap.test; - -test('Creating a block should emit a project changed event', t => { +test('Creating a block should emit a project changed event', () => { blockContainer.createBlock({ id: 'another block', opcode: 'my_testBlock', topLevel: true }); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Deleting a block should emit a project changed event', t => { +test('Deleting a block should emit a project changed event', () => { blockContainer.deleteBlock('a new block'); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Changing a block should emit a project changed event', t => { +test('Changing a block should emit a project changed event', () => { blockContainer.changeBlock({ element: 'field', id: 'a new block', @@ -81,7 +77,7 @@ test('Changing a block should emit a project changed event', t => { value: 300 }); - t.equal(projectChanged, true); + assert.strictEqual(projectChanged, true); projectChanged = false; blockContainer.changeBlock({ @@ -90,7 +86,7 @@ test('Changing a block should emit a project changed event', t => { value: true }); - t.equal(projectChanged, true); + assert.strictEqual(projectChanged, true); projectChanged = false; blockContainer.changeBlock({ @@ -99,12 +95,10 @@ test('Changing a block should emit a project changed event', t => { value: '' }); - t.equal(projectChanged, true); - - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Moving a block to a new position should emit a project changed event', t => { +test('Moving a block to a new position should emit a project changed event', () => { blockContainer.moveBlock({ id: 'a new block', newCoordinate: { @@ -113,11 +107,10 @@ test('Moving a block to a new position should emit a project changed event', t = } }); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Connecting a block to a new parent should emit a project changed event', t => { +test('Connecting a block to a new parent should emit a project changed event', () => { blockContainer.createBlock({ id: 'another block', opcode: 'my_testBlock' @@ -130,21 +123,19 @@ test('Connecting a block to a new parent should emit a project changed event', t newParent: 'another block' }); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Disconnecting a block from another should emit a project changed event', t => { +test('Disconnecting a block from another should emit a project changed event', () => { blockContainer.moveBlock({ id: 'a new block', oldParent: 'a parent block' }); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Creating a local variable should emit a project changed event', t => { +test('Creating a local variable should emit a project changed event', () => { blockContainer.blocklyListen({ type: 'var_create', varId: 'a new variable', @@ -154,7 +145,7 @@ test('Creating a local variable should emit a project changed event', t => { isCloud: false }); - t.equal(projectChanged, true); + assert.strictEqual(projectChanged, true); projectChanged = false; @@ -168,12 +159,10 @@ test('Creating a local variable should emit a project changed event', t => { isCloud: false }); - t.equal(projectChanged, false); - - t.end(); + assert.strictEqual(projectChanged, false); }); -test('Creating a global variable should emit a project changed event', t => { +test('Creating a global variable should emit a project changed event', () => { blockContainer.blocklyListen({ type: 'var_create', varId: 'a new variable', @@ -183,7 +172,7 @@ test('Creating a global variable should emit a project changed event', t => { isCloud: false }); - t.equal(projectChanged, true); + assert.strictEqual(projectChanged, true); projectChanged = false; @@ -197,12 +186,10 @@ test('Creating a global variable should emit a project changed event', t => { isCloud: false }); - t.equal(projectChanged, false); - - t.end(); + assert.strictEqual(projectChanged, false); }); -test('Renaming a variable should emit a project changed event', t => { +test('Renaming a variable should emit a project changed event', () => { blockContainer.blocklyListen({ type: 'var_create', varId: 'a new variable', @@ -221,11 +208,10 @@ test('Renaming a variable should emit a project changed event', t => { newName: 'bar' }); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Deleting a variable should emit a project changed event', t => { +test('Deleting a variable should emit a project changed event', () => { blockContainer.blocklyListen({ type: 'var_create', varId: 'a new variable', @@ -246,11 +232,10 @@ test('Deleting a variable should emit a project changed event', t => { isCloud: false }); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Creating a block comment should emit a project changed event', t => { +test('Creating a block comment should emit a project changed event', () => { blockContainer.blocklyListen({ type: 'comment_create', blockId: 'a new block', @@ -265,11 +250,10 @@ test('Creating a block comment should emit a project changed event', t => { text: 'comment' }); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Creating a workspace comment should emit a project changed event', t => { +test('Creating a workspace comment should emit a project changed event', () => { blockContainer.blocklyListen({ type: 'comment_create', blockId: null, @@ -284,11 +268,10 @@ test('Creating a workspace comment should emit a project changed event', t => { text: 'comment' }); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Changing a comment should emit a project changed event', t => { +test('Changing a comment should emit a project changed event', () => { blockContainer.blocklyListen({ type: 'comment_create', blockId: null, @@ -317,11 +300,10 @@ test('Changing a comment should emit a project changed event', t => { } }); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Attempting to change a comment that does not exist should not emit a project changed event', t => { +test('Attempting to change a comment that does not exist should not emit a project changed event', () => { blockContainer.blocklyListen({ type: 'comment_change', blockId: null, @@ -334,11 +316,10 @@ test('Attempting to change a comment that does not exist should not emit a proje } }); - t.equal(projectChanged, false); - t.end(); + assert.strictEqual(projectChanged, false); }); -test('Deleting a block comment should emit a project changed event', t => { +test('Deleting a block comment should emit a project changed event', () => { blockContainer.blocklyListen({ type: 'comment_create', blockId: 'a new block', @@ -369,11 +350,10 @@ test('Deleting a block comment should emit a project changed event', t => { text: 'comment' }); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Deleting a workspace comment should emit a project changed event', t => { +test('Deleting a workspace comment should emit a project changed event', () => { blockContainer.blocklyListen({ type: 'comment_create', blockId: null, @@ -404,11 +384,10 @@ test('Deleting a workspace comment should emit a project changed event', t => { text: 'comment' }); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); -test('Deleting a comment that does not exist should not emit a project changed event', t => { +test('Deleting a comment that does not exist should not emit a project changed event', () => { blockContainer.blocklyListen({ type: 'comment_delete', blockId: null, @@ -423,11 +402,10 @@ test('Deleting a comment that does not exist should not emit a project changed e text: 'comment' }); - t.equal(projectChanged, false); - t.end(); + assert.strictEqual(projectChanged, false); }); -test('Moving a comment should emit a project changed event', t => { +test('Moving a comment should emit a project changed event', () => { blockContainer.blocklyListen({ type: 'comment_create', blockId: null, @@ -458,6 +436,5 @@ test('Moving a comment should emit a project changed event', t => { } }); - t.equal(projectChanged, true); - t.end(); + assert.strictEqual(projectChanged, true); }); diff --git a/test/unit/project_load_changed_state.js b/test/unit/project_load_changed_state.js index 85354148..e01974e8 100644 --- a/test/unit/project_load_changed_state.js +++ b/test/unit/project_load_changed_state.js @@ -1,15 +1,14 @@ -const tap = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const path = require('path'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const makeTestStorage = require('../fixtures/make-test-storage'); const VirtualMachine = require('../../src/virtual-machine'); -const test = tap.test; - // Test that loading a project does not emit a project change // This is in its own file so that it does not affect the test setup // and results of the other project changed state tests -test('Loading a project should not emit a project changed event', t => { +test('Loading a project should not emit a project changed event', async () => { const projectUri = path.resolve(__dirname, '../fixtures/default.sb2'); const project = readFileToBuffer(projectUri); @@ -21,8 +20,6 @@ test('Loading a project should not emit a project changed event', t => { }); vm.attachStorage(makeTestStorage()); - return vm.loadProject(project).then(() => { - t.equal(projectChanged, false); - t.end(); - }); + await vm.loadProject(project); + assert.strictEqual(projectChanged, false); }); diff --git a/test/unit/serialization_sb2.js b/test/unit/serialization_sb2.js index 9b01dcb4..ea882695 100644 --- a/test/unit/serialization_sb2.js +++ b/test/unit/serialization_sb2.js @@ -1,104 +1,95 @@ const path = require('path'); -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const extractProjectJson = require('../fixtures/readProjectFile').extractProjectJson; const RenderedTarget = require('../../src/sprites/rendered-target'); const Runtime = require('../../src/engine/runtime'); const sb2 = require('../../src/serialization/sb2'); -test('spec', t => { - t.type(sb2, 'object'); - t.type(sb2.deserialize, 'function'); - t.end(); +test('spec', () => { + assert.strictEqual(typeof sb2, 'object'); + assert.strictEqual(typeof sb2.deserialize, 'function'); }); -test('default', t => { +test('default', async () => { // Get SB2 JSON (string) const uri = path.resolve(__dirname, '../fixtures/default.sb2'); const json = extractProjectJson(uri); // Create runtime instance & load SB2 into it const rt = new Runtime(); - sb2.deserialize(json, rt).then(({targets}) => { - // Test - t.type(json, 'object'); - t.type(rt, 'object'); - t.type(targets, 'object'); + const {targets} = await sb2.deserialize(json, rt); + // Test + assert.strictEqual(typeof json, 'object'); + assert.strictEqual(typeof rt, 'object'); + assert.strictEqual(typeof targets, 'object'); - t.ok(targets[0] instanceof RenderedTarget); - t.type(targets[0].id, 'string'); - t.type(targets[0].blocks, 'object'); - t.type(targets[0].variables, 'object'); - t.type(targets[0].comments, 'object'); + assert.ok(targets[0] instanceof RenderedTarget); + assert.strictEqual(typeof targets[0].id, 'string'); + assert.strictEqual(typeof targets[0].blocks, 'object'); + assert.strictEqual(typeof targets[0].variables, 'object'); + assert.strictEqual(typeof targets[0].comments, 'object'); - t.equal(targets[0].isOriginal, true); - t.equal(targets[0].currentCostume, 0); - t.equal(targets[0].isOriginal, true); - t.equal(targets[0].isStage, true); + assert.strictEqual(targets[0].isOriginal, true); + assert.strictEqual(targets[0].currentCostume, 0); + assert.strictEqual(targets[0].isOriginal, true); + assert.strictEqual(targets[0].isStage, true); - t.ok(targets[1] instanceof RenderedTarget); - t.type(targets[1].id, 'string'); - t.type(targets[1].blocks, 'object'); - t.type(targets[1].variables, 'object'); - t.type(targets[1].comments, 'object'); + assert.ok(targets[1] instanceof RenderedTarget); + assert.strictEqual(typeof targets[1].id, 'string'); + assert.strictEqual(typeof targets[1].blocks, 'object'); + assert.strictEqual(typeof targets[1].variables, 'object'); + assert.strictEqual(typeof targets[1].comments, 'object'); - t.equal(targets[1].isOriginal, true); - t.equal(targets[1].currentCostume, 0); - t.equal(targets[1].isOriginal, true); - t.equal(targets[1].isStage, false); - t.end(); - }); + assert.strictEqual(targets[1].isOriginal, true); + assert.strictEqual(targets[1].currentCostume, 0); + assert.strictEqual(targets[1].isOriginal, true); + assert.strictEqual(targets[1].isStage, false); }); -test('data scoping', t => { +test('data scoping', async () => { // Get SB2 JSON (string) const uri = path.resolve(__dirname, '../fixtures/data.sb2'); const json = extractProjectJson(uri); // Create runtime instance & load SB2 into it const rt = new Runtime(); - sb2.deserialize(json, rt).then(({targets}) => { - const globalVariableIds = Object.keys(targets[0].variables); - const localVariableIds = Object.keys(targets[1].variables); - t.equal(targets[0].variables[globalVariableIds[0]].name, 'foo'); - t.equal(targets[1].variables[localVariableIds[0]].name, 'local'); - t.end(); - }); + const {targets} = await sb2.deserialize(json, rt); + const globalVariableIds = Object.keys(targets[0].variables); + const localVariableIds = Object.keys(targets[1].variables); + assert.strictEqual(targets[0].variables[globalVariableIds[0]].name, 'foo'); + assert.strictEqual(targets[1].variables[localVariableIds[0]].name, 'local'); }); -test('whenclicked blocks imported separately', t => { +test('whenclicked blocks imported separately', async () => { // This sb2 fixture has a single "whenClicked" block on both sprite and stage const uri = path.resolve(__dirname, '../fixtures/when-clicked.sb2'); const json = extractProjectJson(uri); // Create runtime instance & load SB2 into it const rt = new Runtime(); - sb2.deserialize(json, rt).then(({targets}) => { - const stage = targets[0]; - t.equal(stage.isStage, true); // Make sure we have the correct target - const stageOpcode = stage.blocks.getBlock(stage.blocks.getScripts()[0]).opcode; - t.equal(stageOpcode, 'event_whenstageclicked'); + const {targets} = await sb2.deserialize(json, rt); + const stage = targets[0]; + assert.strictEqual(stage.isStage, true); // Make sure we have the correct target + const stageOpcode = stage.blocks.getBlock(stage.blocks.getScripts()[0]).opcode; + assert.strictEqual(stageOpcode, 'event_whenstageclicked'); - const sprite = targets[1]; - t.equal(sprite.isStage, false); // Make sure we have the correct target - const spriteOpcode = sprite.blocks.getBlock(sprite.blocks.getScripts()[0]).opcode; - t.equal(spriteOpcode, 'event_whenthisspriteclicked'); - - t.end(); - }); + const sprite = targets[1]; + assert.strictEqual(sprite.isStage, false); // Make sure we have the correct target + const spriteOpcode = sprite.blocks.getBlock(sprite.blocks.getScripts()[0]).opcode; + assert.strictEqual(spriteOpcode, 'event_whenthisspriteclicked'); }); -test('Ordering', t => { +test('Ordering', async () => { // This SB2 has 3 sprites that have been reordered in scratch 2 // so the order in the file is not the order specified by the indexInLibrary property. const uri = path.resolve(__dirname, '../fixtures/ordering.sb2'); const json = extractProjectJson(uri); const rt = new Runtime(); - sb2.deserialize(json, rt).then(({targets}) => { - // Would fail with any other ordering. - t.equal(targets[1].sprite.name, 'First'); - t.equal(targets[2].sprite.name, 'Second'); - t.equal(targets[3].sprite.name, 'Third'); - t.end(); - }); + const {targets} = await sb2.deserialize(json, rt); + // Would fail with any other ordering. + assert.strictEqual(targets[1].sprite.name, 'First'); + assert.strictEqual(targets[2].sprite.name, 'Second'); + assert.strictEqual(targets[3].sprite.name, 'Third'); }); diff --git a/test/unit/serialization_sb3.js b/test/unit/serialization_sb3.js index 20897b1f..fdc8246d 100644 --- a/test/unit/serialization_sb3.js +++ b/test/unit/serialization_sb3.js @@ -1,4 +1,5 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const path = require('path'); const VirtualMachine = require('../../src/index'); const Runtime = require('../../src/engine/runtime'); @@ -15,346 +16,290 @@ const originSB3ProjectPath = path.resolve(__dirname, '../fixtures/origin.sb3'); const originAbsentSB3ProjectPath = path.resolve(__dirname, '../fixtures/origin-absent.sb3'); const FakeRenderer = require('../fixtures/fake-renderer'); -test('serialize', t => { +test('serialize', async () => { const vm = new VirtualMachine(); - vm.loadProject(readFileToBuffer(exampleProjectPath)) - .then(() => { - const result = sb3.serialize(vm.runtime); - // @todo Analyze - t.type(JSON.stringify(result), 'string'); - t.end(); - }); + await vm.loadProject(readFileToBuffer(exampleProjectPath)); + const result = sb3.serialize(vm.runtime); + // @todo Analyze + assert.strictEqual(typeof JSON.stringify(result), 'string'); }); -test('deserialize', t => { +test('deserialize', async () => { const vm = new VirtualMachine(); - sb3.deserialize('', vm.runtime).then(({targets}) => { - // @todo Analyze - t.type(targets, 'object'); - t.end(); + const {targets} = await sb3.deserialize('', vm.runtime); + // @todo Analyze + assert.strictEqual(typeof targets, 'object'); +}); + + +test('serialize sb2 project with comments as sb3', async () => { + const vm = new VirtualMachine(); + await vm.loadProject(readFileToBuffer(commentsSB2ProjectPath)); + const result = sb3.serialize(vm.runtime); + + assert.strictEqual(typeof JSON.stringify(result), 'string'); + assert.strictEqual(typeof result.targets, 'object'); + assert.strictEqual(Array.isArray(result.targets), true); + assert.strictEqual(result.targets.length, 2); + + const stage = result.targets[0]; + assert.strictEqual(stage.isStage, true); + // The stage has 0 blocks, and 1 workspace comment + assert.strictEqual(typeof stage.blocks, 'object'); + assert.strictEqual(Object.keys(stage.blocks).length, 0); + assert.strictEqual(typeof stage.comments, 'object'); + assert.strictEqual(Object.keys(stage.comments).length, 1); + const stageBlockComments = Object.values(stage.comments).filter(comment => !!comment.blockId); + const stageWorkspaceComments = Object.values(stage.comments).filter(comment => comment.blockId === null); + assert.strictEqual(stageBlockComments.length, 0); + assert.strictEqual(stageWorkspaceComments.length, 1); + + const sprite = result.targets[1]; + assert.strictEqual(sprite.isStage, false); + assert.strictEqual(typeof sprite.blocks, 'object'); + // Sprite 1 has 6 blocks, 5 block comments, and 1 workspace comment + assert.strictEqual(Object.keys(sprite.blocks).length, 6); + assert.strictEqual(typeof sprite.comments, 'object'); + assert.strictEqual(Object.keys(sprite.comments).length, 6); + + const spriteBlockComments = Object.values(sprite.comments).filter(comment => !!comment.blockId); + const spriteWorkspaceComments = Object.values(sprite.comments).filter(comment => comment.blockId === null); + assert.strictEqual(spriteBlockComments.length, 5); + assert.strictEqual(spriteWorkspaceComments.length, 1); +}); + +test('deserialize sb3 project with comments', async () => { + const vm = new VirtualMachine(); + await vm.loadProject(readFileToBuffer(commentsSB3ProjectPath)); + const runtime = vm.runtime; + + assert.strictEqual(typeof runtime.targets, 'object'); + assert.strictEqual(Array.isArray(runtime.targets), true); + assert.strictEqual(runtime.targets.length, 2); + + const stage = runtime.targets[0]; + assert.strictEqual(stage.isStage, true); + // The stage has 0 blocks, and 1 workspace comment + assert.strictEqual(typeof stage.blocks, 'object'); + assert.strictEqual(Object.keys(stage.blocks._blocks).length, 0); + assert.strictEqual(typeof stage.comments, 'object'); + assert.strictEqual(Object.keys(stage.comments).length, 1); + const stageBlockComments = Object.values(stage.comments).filter(comment => !!comment.blockId); + const stageWorkspaceComments = Object.values(stage.comments).filter(comment => comment.blockId === null); + assert.strictEqual(stageBlockComments.length, 0); + assert.strictEqual(stageWorkspaceComments.length, 1); + + const sprite = runtime.targets[1]; + assert.strictEqual(sprite.isStage, false); + assert.strictEqual(typeof sprite.blocks, 'object'); + // Sprite 1 has 6 blocks, 5 block comments, and 1 workspace comment + assert.strictEqual(Object.values(sprite.blocks._blocks).filter(block => !block.shadow).length, 6); + assert.strictEqual(typeof sprite.comments, 'object'); + assert.strictEqual(Object.keys(sprite.comments).length, 6); + + const spriteBlockComments = Object.values(sprite.comments).filter(comment => !!comment.blockId); + const spriteWorkspaceComments = Object.values(sprite.comments).filter(comment => comment.blockId === null); + assert.strictEqual(spriteBlockComments.length, 5); + assert.strictEqual(spriteWorkspaceComments.length, 1); +}); + +test('deserialize sb3 project with comments - no duplicate id serialization', async () => { + const vm = new VirtualMachine(); + await vm.loadProject(readFileToBuffer(commentsSB3NoDupeIds)); + const runtime = vm.runtime; + + assert.strictEqual(typeof runtime.targets, 'object'); + assert.strictEqual(Array.isArray(runtime.targets), true); + assert.strictEqual(runtime.targets.length, 2); + + const stage = runtime.targets[0]; + assert.strictEqual(stage.isStage, true); + // The stage has 0 blocks, and 0 workspace comment + assert.strictEqual(typeof stage.blocks, 'object'); + assert.strictEqual(Object.keys(stage.blocks._blocks).length, 0); + assert.strictEqual(typeof stage.comments, 'object'); + assert.strictEqual(Object.keys(stage.comments).length, 0); + + const sprite = runtime.targets[1]; + assert.strictEqual(sprite.isStage, false); + assert.strictEqual(typeof sprite.blocks, 'object'); + // Sprite1 has 1 blocks, 1 block comment, and 1 workspace comment + assert.strictEqual(Object.values(sprite.blocks._blocks).filter(block => !block.shadow).length, 1); + assert.strictEqual(typeof sprite.comments, 'object'); + assert.strictEqual(Object.keys(sprite.comments).length, 2); + + const spriteBlockComments = Object.values(sprite.comments).filter(comment => !!comment.blockId); + const spriteWorkspaceComments = Object.values(sprite.comments).filter(comment => comment.blockId === null); + assert.strictEqual(spriteBlockComments.length, 1); + assert.strictEqual(spriteWorkspaceComments.length, 1); +}); + +test('serializing and deserializing sb3 preserves sprite layer order', async () => { + const vm = new VirtualMachine(); + vm.attachRenderer(new FakeRenderer()); + await vm.loadProject(readFileToBuffer(path.resolve(__dirname, '../fixtures/ordering.sb2'))); + // Target get layer order needs a renderer, + // fake the numbers we would get back from the + // renderer in order to test that they are serialized + // correctly + vm.runtime.targets[0].getLayerOrder = () => 0; + vm.runtime.targets[1].getLayerOrder = () => 20; + vm.runtime.targets[2].getLayerOrder = () => 10; + vm.runtime.targets[3].getLayerOrder = () => 30; + + const result = sb3.serialize(vm.runtime); + + assert.strictEqual(typeof JSON.stringify(result), 'string'); + assert.strictEqual(typeof result.targets, 'object'); + assert.strictEqual(Array.isArray(result.targets), true); + assert.strictEqual(result.targets.length, 4); + + // First check that the sprites are ordered correctly (as they would + // appear in the target pane) + assert.strictEqual(result.targets[0].name, 'Stage'); + assert.strictEqual(result.targets[1].name, 'First'); + assert.strictEqual(result.targets[2].name, 'Second'); + assert.strictEqual(result.targets[3].name, 'Third'); + + // Check that they are in the correct layer order (as they would render + // back to front on the stage) + assert.strictEqual(result.targets[0].layerOrder, 0); + assert.strictEqual(result.targets[1].layerOrder, 2); + assert.strictEqual(result.targets[2].layerOrder, 1); + assert.strictEqual(result.targets[3].layerOrder, 3); + + const serializedObject = await result; + const {targets, layerOrder} = await sb3.deserialize( + JSON.parse(JSON.stringify(serializedObject)), new Runtime(), null, false); + // First check that the sprites are ordered correctly (as they would + // appear in the target pane) + assert.strictEqual(targets[0].sprite.name, 'Stage'); + assert.strictEqual(targets[1].sprite.name, 'First'); + assert.strictEqual(targets[2].sprite.name, 'Second'); + assert.strictEqual(targets[3].sprite.name, 'Third'); + + // Check that they are in the correct layer order (as they would render + // back to front on the stage) + assert.deepEqual(layerOrder, [0, 2, 1, 3]); +}); + +test('serializeBlocks', async () => { + const vm = new VirtualMachine(); + await vm.loadProject(readFileToBuffer(commentsSB3ProjectPath)); + const blocks = vm.runtime.targets[1].blocks._blocks; + const result = sb3.serializeBlocks(blocks); + // @todo Analyze + assert.strictEqual(typeof result[0], 'object'); + assert.ok(Object.keys(result[0]).length < Object.keys(blocks).length, 'less blocks in serialized format'); + assert.ok(Array.isArray(result[1])); +}); + +test('serializeBlocks serializes x and y for topLevel blocks with x,y of 0,0', async () => { + const vm = new VirtualMachine(); + await vm.loadProject(readFileToBuffer(topLevelReportersProjectPath)); + // Verify that there are 2 blocks and they are both top level + const blocks = vm.runtime.targets[1].blocks._blocks; + const blockIds = Object.keys(blocks); + assert.strictEqual(blockIds.length, 2); + const blocksArray = blockIds.map(key => blocks[key]); + assert.strictEqual(blocksArray.every(b => b.topLevel), true); + // Simulate cleaning up the blocks by resetting x and y positions to 0 + blockIds.forEach(blockId => { + blocks[blockId].x = 0; + blocks[blockId].y = 0; + }); + const result = sb3.serializeBlocks(blocks); + const serializedBlocks = result[0]; + + assert.strictEqual(typeof serializedBlocks, 'object'); + const serializedBlockIds = Object.keys(serializedBlocks); + assert.strictEqual(serializedBlockIds.length, 2); + const firstBlock = serializedBlocks[serializedBlockIds[0]]; + const secondBlock = serializedBlocks[serializedBlockIds[1]]; + assert.strictEqual(firstBlock.x, 0); + assert.strictEqual(firstBlock.y, 0); + assert.strictEqual(secondBlock.x, 0); + assert.strictEqual(secondBlock.y, 0); +}); + +test('deserializeBlocks', async () => { + const vm = new VirtualMachine(); + await vm.loadProject(readFileToBuffer(commentsSB3ProjectPath)); + const blocks = vm.runtime.targets[1].blocks._blocks; + const serialized = sb3.serializeBlocks(blocks)[0]; + const deserialized = sb3.deserializeBlocks(serialized); + assert.strictEqual(Object.keys(deserialized).length, Object.keys(blocks).length, 'same number of blocks'); +}); + +test('deserializeBlocks on already deserialized input', async () => { + const vm = new VirtualMachine(); + await vm.loadProject(readFileToBuffer(commentsSB3ProjectPath)); + const blocks = vm.runtime.targets[1].blocks._blocks; + const serialized = sb3.serializeBlocks(blocks)[0]; + const deserialized = sb3.deserializeBlocks(serialized); + const deserializedAgain = sb3.deserializeBlocks(deserialized); + assert.deepEqual(deserialized, deserializedAgain, 'no change from second pass of deserialize'); +}); + +test('getExtensionIdForOpcode', () => { + assert.strictEqual(sb3.getExtensionIdForOpcode('wedo_loopy'), 'wedo'); + + // does not consider CORE to be extensions + assert.ok(!sb3.getExtensionIdForOpcode('control_loopy')); + + // only considers things before the first underscore + assert.strictEqual(sb3.getExtensionIdForOpcode('hello_there_loopy'), 'hello'); + + // does not return anything for opcodes with no extension + assert.ok(!sb3.getExtensionIdForOpcode('hello')); + + // forbidden characters must be replaced with '-' + assert.strictEqual(sb3.getExtensionIdForOpcode('hi:there/happy_people'), 'hi-there-happy'); +}); + +test('(#1608) serializeBlocks maintains top level variable reporters', async () => { + const vm = new VirtualMachine(); + await vm.loadProject(readFileToBuffer(variableReporterSB2ProjectPath)); + const blocks = vm.runtime.targets[0].blocks._blocks; + const result = sb3.serialize(vm.runtime); + // Project should have 1 block, a top-level variable reporter + assert.strictEqual(Object.keys(blocks).length, 1); + assert.strictEqual(Object.keys(result.targets[0].blocks).length, 1); + + // Make sure deserializing these blocks works + assert.doesNotThrow(() => { + sb3.deserialize(JSON.parse(JSON.stringify(result)), vm.runtime); }); }); - -test('serialize sb2 project with comments as sb3', t => { +test('(#1850) sprite draggability state read when loading SB3 file', async () => { const vm = new VirtualMachine(); - vm.loadProject(readFileToBuffer(commentsSB2ProjectPath)) - .then(() => { - const result = sb3.serialize(vm.runtime); - - t.type(JSON.stringify(result), 'string'); - t.type(result.targets, 'object'); - t.equal(Array.isArray(result.targets), true); - t.equal(result.targets.length, 2); - - const stage = result.targets[0]; - t.equal(stage.isStage, true); - // The stage has 0 blocks, and 1 workspace comment - t.type(stage.blocks, 'object'); - t.equal(Object.keys(stage.blocks).length, 0); - t.type(stage.comments, 'object'); - t.equal(Object.keys(stage.comments).length, 1); - const stageBlockComments = Object.values(stage.comments).filter(comment => !!comment.blockId); - const stageWorkspaceComments = Object.values(stage.comments).filter(comment => comment.blockId === null); - t.equal(stageBlockComments.length, 0); - t.equal(stageWorkspaceComments.length, 1); - - const sprite = result.targets[1]; - t.equal(sprite.isStage, false); - t.type(sprite.blocks, 'object'); - // Sprite 1 has 6 blocks, 5 block comments, and 1 workspace comment - t.equal(Object.keys(sprite.blocks).length, 6); - t.type(sprite.comments, 'object'); - t.equal(Object.keys(sprite.comments).length, 6); - - const spriteBlockComments = Object.values(sprite.comments).filter(comment => !!comment.blockId); - const spriteWorkspaceComments = Object.values(sprite.comments).filter(comment => comment.blockId === null); - t.equal(spriteBlockComments.length, 5); - t.equal(spriteWorkspaceComments.length, 1); - - t.end(); - }); + await vm.loadProject(readFileToBuffer(draggableSB3ProjectPath)); + const sprite1Obj = vm.runtime.targets.find(target => target.sprite.name === 'Sprite1'); + // Sprite1 in project should have draggable set to true + assert.strictEqual(sprite1Obj.draggable, true); }); -test('deserialize sb3 project with comments', t => { +test('load origin value from SB3 file json metadata', async () => { const vm = new VirtualMachine(); - vm.loadProject(readFileToBuffer(commentsSB3ProjectPath)) - .then(() => { - const runtime = vm.runtime; - - t.type(runtime.targets, 'object'); - t.equal(Array.isArray(runtime.targets), true); - t.equal(runtime.targets.length, 2); - - const stage = runtime.targets[0]; - t.equal(stage.isStage, true); - // The stage has 0 blocks, and 1 workspace comment - t.type(stage.blocks, 'object'); - t.equal(Object.keys(stage.blocks._blocks).length, 0); - t.type(stage.comments, 'object'); - t.equal(Object.keys(stage.comments).length, 1); - const stageBlockComments = Object.values(stage.comments).filter(comment => !!comment.blockId); - const stageWorkspaceComments = Object.values(stage.comments).filter(comment => comment.blockId === null); - t.equal(stageBlockComments.length, 0); - t.equal(stageWorkspaceComments.length, 1); - - const sprite = runtime.targets[1]; - t.equal(sprite.isStage, false); - t.type(sprite.blocks, 'object'); - // Sprite 1 has 6 blocks, 5 block comments, and 1 workspace comment - t.equal(Object.values(sprite.blocks._blocks).filter(block => !block.shadow).length, 6); - t.type(sprite.comments, 'object'); - t.equal(Object.keys(sprite.comments).length, 6); - - const spriteBlockComments = Object.values(sprite.comments).filter(comment => !!comment.blockId); - const spriteWorkspaceComments = Object.values(sprite.comments).filter(comment => comment.blockId === null); - t.equal(spriteBlockComments.length, 5); - t.equal(spriteWorkspaceComments.length, 1); - - t.end(); - }); + await vm.loadProject(readFileToBuffer(originSB3ProjectPath)); + assert.strictEqual(typeof vm.runtime.origin, 'string'); + await vm.loadProject(readFileToBuffer(originAbsentSB3ProjectPath)); + // After loading a project with an origin, then loading one without an origin, + // origin value should no longer be set. + assert.strictEqual(vm.runtime.origin, null); }); -test('deserialize sb3 project with comments - no duplicate id serialization', t => { +test('serialize origin value if it is present', async () => { const vm = new VirtualMachine(); - vm.loadProject(readFileToBuffer(commentsSB3NoDupeIds)) - .then(() => { - const runtime = vm.runtime; - - t.type(runtime.targets, 'object'); - t.equal(Array.isArray(runtime.targets), true); - t.equal(runtime.targets.length, 2); - - const stage = runtime.targets[0]; - t.equal(stage.isStage, true); - // The stage has 0 blocks, and 0 workspace comment - t.type(stage.blocks, 'object'); - t.equal(Object.keys(stage.blocks._blocks).length, 0); - t.type(stage.comments, 'object'); - t.equal(Object.keys(stage.comments).length, 0); - - const sprite = runtime.targets[1]; - t.equal(sprite.isStage, false); - t.type(sprite.blocks, 'object'); - // Sprite1 has 1 blocks, 1 block comment, and 1 workspace comment - t.equal(Object.values(sprite.blocks._blocks).filter(block => !block.shadow).length, 1); - t.type(sprite.comments, 'object'); - t.equal(Object.keys(sprite.comments).length, 2); - - const spriteBlockComments = Object.values(sprite.comments).filter(comment => !!comment.blockId); - const spriteWorkspaceComments = Object.values(sprite.comments).filter(comment => comment.blockId === null); - t.equal(spriteBlockComments.length, 1); - t.equal(spriteWorkspaceComments.length, 1); - - t.end(); - }); + await vm.loadProject(readFileToBuffer(originSB3ProjectPath)); + const result = sb3.serialize(vm.runtime); + assert.strictEqual(typeof result.meta.origin, 'string'); }); -test('serializing and deserializing sb3 preserves sprite layer order', t => { +test('do not serialize origin value if it is not present', async () => { const vm = new VirtualMachine(); - vm.attachRenderer(new FakeRenderer()); - return vm.loadProject(readFileToBuffer(path.resolve(__dirname, '../fixtures/ordering.sb2'))) - .then(() => { - // Target get layer order needs a renderer, - // fake the numbers we would get back from the - // renderer in order to test that they are serialized - // correctly - vm.runtime.targets[0].getLayerOrder = () => 0; - vm.runtime.targets[1].getLayerOrder = () => 20; - vm.runtime.targets[2].getLayerOrder = () => 10; - vm.runtime.targets[3].getLayerOrder = () => 30; - - const result = sb3.serialize(vm.runtime); - - t.type(JSON.stringify(result), 'string'); - t.type(result.targets, 'object'); - t.equal(Array.isArray(result.targets), true); - t.equal(result.targets.length, 4); - - // First check that the sprites are ordered correctly (as they would - // appear in the target pane) - t.equal(result.targets[0].name, 'Stage'); - t.equal(result.targets[1].name, 'First'); - t.equal(result.targets[2].name, 'Second'); - t.equal(result.targets[3].name, 'Third'); - - // Check that they are in the correct layer order (as they would render - // back to front on the stage) - t.equal(result.targets[0].layerOrder, 0); - t.equal(result.targets[1].layerOrder, 2); - t.equal(result.targets[2].layerOrder, 1); - t.equal(result.targets[3].layerOrder, 3); - - return result; - }) - .then(serializedObject => - sb3.deserialize( - JSON.parse(JSON.stringify(serializedObject)), new Runtime(), null, false) - .then(({targets, layerOrder}) => { - // First check that the sprites are ordered correctly (as they would - // appear in the target pane) - t.equal(targets[0].sprite.name, 'Stage'); - t.equal(targets[1].sprite.name, 'First'); - t.equal(targets[2].sprite.name, 'Second'); - t.equal(targets[3].sprite.name, 'Third'); - - // Check that they are in the correct layer order (as they would render - // back to front on the stage) - t.same(layerOrder, [0, 2, 1, 3]); - - t.end(); - })); -}); - -test('serializeBlocks', t => { - const vm = new VirtualMachine(); - vm.loadProject(readFileToBuffer(commentsSB3ProjectPath)) - .then(() => { - const blocks = vm.runtime.targets[1].blocks._blocks; - const result = sb3.serializeBlocks(blocks); - // @todo Analyze - t.type(result[0], 'object'); - t.ok(Object.keys(result[0]).length < Object.keys(blocks).length, 'less blocks in serialized format'); - t.ok(Array.isArray(result[1])); - t.end(); - }); -}); - -test('serializeBlocks serializes x and y for topLevel blocks with x,y of 0,0', t => { - const vm = new VirtualMachine(); - vm.loadProject(readFileToBuffer(topLevelReportersProjectPath)) - .then(() => { - // Verify that there are 2 blocks and they are both top level - const blocks = vm.runtime.targets[1].blocks._blocks; - const blockIds = Object.keys(blocks); - t.equal(blockIds.length, 2); - const blocksArray = blockIds.map(key => blocks[key]); - t.equal(blocksArray.every(b => b.topLevel), true); - // Simulate cleaning up the blocks by resetting x and y positions to 0 - blockIds.forEach(blockId => { - blocks[blockId].x = 0; - blocks[blockId].y = 0; - }); - const result = sb3.serializeBlocks(blocks); - const serializedBlocks = result[0]; - - t.type(serializedBlocks, 'object'); - const serializedBlockIds = Object.keys(serializedBlocks); - t.equal(serializedBlockIds.length, 2); - const firstBlock = serializedBlocks[serializedBlockIds[0]]; - const secondBlock = serializedBlocks[serializedBlockIds[1]]; - t.equal(firstBlock.x, 0); - t.equal(firstBlock.y, 0); - t.equal(secondBlock.x, 0); - t.equal(secondBlock.y, 0); - - t.end(); - }); -}); - -test('deserializeBlocks', t => { - const vm = new VirtualMachine(); - vm.loadProject(readFileToBuffer(commentsSB3ProjectPath)) - .then(() => { - const blocks = vm.runtime.targets[1].blocks._blocks; - const serialized = sb3.serializeBlocks(blocks)[0]; - const deserialized = sb3.deserializeBlocks(serialized); - t.equal(Object.keys(deserialized).length, Object.keys(blocks).length, 'same number of blocks'); - t.end(); - }); -}); - -test('deserializeBlocks on already deserialized input', t => { - const vm = new VirtualMachine(); - vm.loadProject(readFileToBuffer(commentsSB3ProjectPath)) - .then(() => { - const blocks = vm.runtime.targets[1].blocks._blocks; - const serialized = sb3.serializeBlocks(blocks)[0]; - const deserialized = sb3.deserializeBlocks(serialized); - const deserializedAgain = sb3.deserializeBlocks(deserialized); - t.deepEqual(deserialized, deserializedAgain, 'no change from second pass of deserialize'); - t.end(); - }); -}); - -test('getExtensionIdForOpcode', t => { - t.equal(sb3.getExtensionIdForOpcode('wedo_loopy'), 'wedo'); - - // does not consider CORE to be extensions - t.false(sb3.getExtensionIdForOpcode('control_loopy')); - - // only considers things before the first underscore - t.equal(sb3.getExtensionIdForOpcode('hello_there_loopy'), 'hello'); - - // does not return anything for opcodes with no extension - t.false(sb3.getExtensionIdForOpcode('hello')); - - // forbidden characters must be replaced with '-' - t.equal(sb3.getExtensionIdForOpcode('hi:there/happy_people'), 'hi-there-happy'); - - t.end(); -}); - -test('(#1608) serializeBlocks maintains top level variable reporters', t => { - const vm = new VirtualMachine(); - vm.loadProject(readFileToBuffer(variableReporterSB2ProjectPath)) - .then(() => { - const blocks = vm.runtime.targets[0].blocks._blocks; - const result = sb3.serialize(vm.runtime); - // Project should have 1 block, a top-level variable reporter - t.equal(Object.keys(blocks).length, 1); - t.equal(Object.keys(result.targets[0].blocks).length, 1); - - // Make sure deserializing these blocks works - t.doesNotThrow(() => { - sb3.deserialize(JSON.parse(JSON.stringify(result)), vm.runtime); - }); - t.end(); - }); -}); - -test('(#1850) sprite draggability state read when loading SB3 file', t => { - const vm = new VirtualMachine(); - vm.loadProject(readFileToBuffer(draggableSB3ProjectPath)) - .then(() => { - const sprite1Obj = vm.runtime.targets.find(target => target.sprite.name === 'Sprite1'); - // Sprite1 in project should have draggable set to true - t.equal(sprite1Obj.draggable, true); - t.end(); - }); -}); - -test('load origin value from SB3 file json metadata', t => { - const vm = new VirtualMachine(); - vm.loadProject(readFileToBuffer(originSB3ProjectPath)) - .then(() => { - t.type(vm.runtime.origin, 'string'); - }) - .then(() => vm.loadProject(readFileToBuffer(originAbsentSB3ProjectPath))) - .then(() => { - // After loading a project with an origin, then loading one without an origin, - // origin value should no longer be set. - t.equal(vm.runtime.origin, null); - t.end(); - }); -}); - -test('serialize origin value if it is present', t => { - const vm = new VirtualMachine(); - vm.loadProject(readFileToBuffer(originSB3ProjectPath)) - .then(() => { - const result = sb3.serialize(vm.runtime); - t.type(result.meta.origin, 'string'); - t.end(); - }); -}); - -test('do not serialize origin value if it is not present', t => { - const vm = new VirtualMachine(); - vm.loadProject(readFileToBuffer(originAbsentSB3ProjectPath)) - .then(() => { - const result = sb3.serialize(vm.runtime); - t.equal(result.meta.origin, undefined); - t.end(); - }); + await vm.loadProject(readFileToBuffer(originAbsentSB3ProjectPath)); + const result = sb3.serialize(vm.runtime); + assert.strictEqual(result.meta.origin, undefined); }); diff --git a/test/unit/spec.js b/test/unit/spec.js index 88bad158..0ef5b196 100644 --- a/test/unit/spec.js +++ b/test/unit/spec.js @@ -1,36 +1,36 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const VirtualMachine = require('../../src/index'); -test('interface', t => { +test('interface', () => { const vm = new VirtualMachine(); - t.type(vm, 'object'); - t.type(vm.start, 'function'); - t.type(vm.greenFlag, 'function'); - t.type(vm.setTurboMode, 'function'); - t.type(vm.setCompatibilityMode, 'function'); - t.type(vm.stopAll, 'function'); - t.type(vm.clear, 'function'); + assert.strictEqual(typeof vm, 'object'); + assert.strictEqual(typeof vm.start, 'function'); + assert.strictEqual(typeof vm.greenFlag, 'function'); + assert.strictEqual(typeof vm.setTurboMode, 'function'); + assert.strictEqual(typeof vm.setCompatibilityMode, 'function'); + assert.strictEqual(typeof vm.stopAll, 'function'); + assert.strictEqual(typeof vm.clear, 'function'); - t.type(vm.getPlaygroundData, 'function'); - t.type(vm.postIOData, 'function'); + assert.strictEqual(typeof vm.getPlaygroundData, 'function'); + assert.strictEqual(typeof vm.postIOData, 'function'); - t.type(vm.loadProject, 'function'); - t.type(vm.addSprite, 'function'); - t.type(vm.addCostume, 'function'); - t.type(vm.addBackdrop, 'function'); - t.type(vm.addSound, 'function'); - t.type(vm.deleteCostume, 'function'); - t.type(vm.deleteSound, 'function'); - t.type(vm.renameSprite, 'function'); - t.type(vm.deleteSprite, 'function'); + assert.strictEqual(typeof vm.loadProject, 'function'); + assert.strictEqual(typeof vm.addSprite, 'function'); + assert.strictEqual(typeof vm.addCostume, 'function'); + assert.strictEqual(typeof vm.addBackdrop, 'function'); + assert.strictEqual(typeof vm.addSound, 'function'); + assert.strictEqual(typeof vm.deleteCostume, 'function'); + assert.strictEqual(typeof vm.deleteSound, 'function'); + assert.strictEqual(typeof vm.renameSprite, 'function'); + assert.strictEqual(typeof vm.deleteSprite, 'function'); - t.type(vm.attachRenderer, 'function'); - t.type(vm.blockListener, 'function'); - t.type(vm.flyoutBlockListener, 'function'); - t.type(vm.setEditingTarget, 'function'); + assert.strictEqual(typeof vm.attachRenderer, 'function'); + assert.strictEqual(typeof vm.blockListener, 'function'); + assert.strictEqual(typeof vm.flyoutBlockListener, 'function'); + assert.strictEqual(typeof vm.setEditingTarget, 'function'); - t.type(vm.emitTargetsUpdate, 'function'); - t.type(vm.emitWorkspaceUpdate, 'function'); - t.type(vm.postSpriteInfo, 'function'); - t.end(); + assert.strictEqual(typeof vm.emitTargetsUpdate, 'function'); + assert.strictEqual(typeof vm.emitWorkspaceUpdate, 'function'); + assert.strictEqual(typeof vm.postSpriteInfo, 'function'); }); diff --git a/test/unit/sprites_rendered-target.js b/test/unit/sprites_rendered-target.js index f2bff6f9..c6a5f4f9 100644 --- a/test/unit/sprites_rendered-target.js +++ b/test/unit/sprites_rendered-target.js @@ -1,43 +1,42 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const RenderedTarget = require('../../src/sprites/rendered-target'); const Sprite = require('../../src/sprites/sprite'); const Runtime = require('../../src/engine/runtime'); const FakeRenderer = require('../fixtures/fake-renderer'); -test('clone effects', t => { +test('clone effects', () => { // Create two clones and ensure they have different graphic effect objects. // Regression test for Github issue #224 const r = new Runtime(); const spr = new Sprite(null, r); const a = new RenderedTarget(spr, r); const b = new RenderedTarget(spr, r); - t.ok(a.effects !== b.effects); - t.end(); + assert.ok(a.effects !== b.effects); }); -test('setxy', t => { +test('setxy', () => { const r = new Runtime(); const s = new Sprite(null, r); const a = new RenderedTarget(s, r); const renderer = new FakeRenderer(); a.renderer = renderer; a.setXY(123, 321, true); - t.equals(a.x, 123); - t.equals(a.y, 321); + assert.strictEqual(a.x, 123); + assert.strictEqual(a.y, 321); renderer.getFencedPositionOfDrawable = () => [50, 50]; a.setXY(100, 100, true); - t.equals(a.x, 50); - t.equals(a.y, 50); + assert.strictEqual(a.x, 50); + assert.strictEqual(a.y, 50); r.setRuntimeOptions({ fencing: false }); a.setXY(100, 100, true); - t.equals(a.x, 100); - t.equals(a.y, 100); - t.end(); + assert.strictEqual(a.x, 100); + assert.strictEqual(a.y, 100); }); -test('blocks get new id on duplicate', t => { +test('blocks get new id on duplicate', async () => { const r = new Runtime(); const s = new Sprite(null, r); const rt = new RenderedTarget(s, r); @@ -49,53 +48,48 @@ test('blocks get new id on duplicate', t => { rt.blocks.createBlock(block); - return rt.duplicate().then(duplicate => { - t.notOk(Object.prototype.hasOwnProperty.call(duplicate.blocks._blocks, block.id)); - t.end(); - }); + const duplicate = await rt.duplicate(); + assert.ok(!Object.prototype.hasOwnProperty.call(duplicate.blocks._blocks, block.id)); }); -test('direction', t => { +test('direction', () => { const r = new Runtime(); const s = new Sprite(null, r); const a = new RenderedTarget(s, r); const renderer = new FakeRenderer(); a.renderer = renderer; a.setDirection(123); - t.equals(a._getRenderedDirectionAndScale().direction, 123); - t.end(); + assert.strictEqual(a._getRenderedDirectionAndScale().direction, 123); }); -test('setVisible', t => { +test('setVisible', () => { const r = new Runtime(); const s = new Sprite(null, r); const a = new RenderedTarget(s, r); const renderer = new FakeRenderer(); a.renderer = renderer; a.setVisible(true); - t.end(); }); -test('setSize', t => { +test('setSize', () => { const r = new Runtime(); const s = new Sprite(null, r); const a = new RenderedTarget(s, r); const renderer = new FakeRenderer(); a.renderer = renderer; a.setSize(123); - t.equals(a._getRenderedDirectionAndScale().scale[0], 123); + assert.strictEqual(a._getRenderedDirectionAndScale().scale[0], 123); renderer.getCurrentSkinSize = () => [100, 100]; a.setSize(99999); - t.equals(a._getRenderedDirectionAndScale().scale[0], 540); + assert.strictEqual(a._getRenderedDirectionAndScale().scale[0], 540); r.setRuntimeOptions({ fencing: false }); a.setSize(99999); - t.equals(a._getRenderedDirectionAndScale().scale[0], 99999); - t.end(); + assert.strictEqual(a._getRenderedDirectionAndScale().scale[0], 99999); }); -test('set and clear effects', t => { +test('set and clear effects', () => { const r = new Runtime(); const s = new Sprite(null, r); const a = new RenderedTarget(s, r); @@ -103,16 +97,15 @@ test('set and clear effects', t => { a.renderer = renderer; for (const effect in a.effects) { a.setEffect(effect, 1); - t.equals(a.effects[effect], 1); + assert.strictEqual(a.effects[effect], 1); } a.clearEffects(); for (const effect in a.effects) { - t.equals(a.effects[effect], 0); + assert.strictEqual(a.effects[effect], 0); } - t.end(); }); -test('setCostume', t => { +test('setCostume', () => { const o = new Object(); const r = new Runtime(); const s = new Sprite(null, r); @@ -121,10 +114,9 @@ test('setCostume', t => { const renderer = new FakeRenderer(); a.renderer = renderer; a.setCostume(0); - t.end(); }); -test('deleteCostume', t => { +test('deleteCostume', () => { const o1 = {id: 1}; const o2 = {id: 2}; const o3 = {id: 3}; @@ -144,11 +136,11 @@ test('deleteCostume', t => { // Costume 3 a.setCostume(0); const deletedCostume = a.deleteCostume(0); - t.equals(a.sprite.costumes.length, 2); - t.equals(a.sprite.costumes[0].id, 2); - t.equals(a.sprite.costumes[1].id, 3); - t.equals(a.currentCostume, 0); - t.deepEqual(deletedCostume, o1); + assert.strictEqual(a.sprite.costumes.length, 2); + assert.strictEqual(a.sprite.costumes[0].id, 2); + assert.strictEqual(a.sprite.costumes[1].id, 3); + assert.strictEqual(a.currentCostume, 0); + assert.deepEqual(deletedCostume, o1); // Costume 1 Costume 1 // x* Costume 2 => * Costume 3 @@ -156,11 +148,11 @@ test('deleteCostume', t => { a.sprite.costumes = [o1, o2, o3]; a.setCostume(1); const deletedCostume2 = a.deleteCostume(1); - t.equals(a.sprite.costumes.length, 2); - t.equals(a.sprite.costumes[0].id, 1); - t.equals(a.sprite.costumes[1].id, 3); - t.equals(a.currentCostume, 1); - t.deepEqual(deletedCostume2, o2); + assert.strictEqual(a.sprite.costumes.length, 2); + assert.strictEqual(a.sprite.costumes[0].id, 1); + assert.strictEqual(a.sprite.costumes[1].id, 3); + assert.strictEqual(a.currentCostume, 1); + assert.deepEqual(deletedCostume2, o2); // Costume 1 Costume 1 // Costume 2 => * Costume 2 @@ -168,20 +160,20 @@ test('deleteCostume', t => { a.sprite.costumes = [o1, o2, o3]; a.setCostume(2); const deletedCostume3 = a.deleteCostume(2); - t.equals(a.sprite.costumes.length, 2); - t.equals(a.sprite.costumes[0].id, 1); - t.equals(a.sprite.costumes[1].id, 2); - t.equals(a.currentCostume, 1); - t.deepEqual(deletedCostume3, o3); + assert.strictEqual(a.sprite.costumes.length, 2); + assert.strictEqual(a.sprite.costumes[0].id, 1); + assert.strictEqual(a.sprite.costumes[1].id, 2); + assert.strictEqual(a.currentCostume, 1); + assert.deepEqual(deletedCostume3, o3); // Refuses to delete only costume a.sprite.costumes = [o1]; a.setCostume(0); const noDeletedCostume = a.deleteCostume(0); - t.equals(a.sprite.costumes.length, 1); - t.equals(a.sprite.costumes[0].id, 1); - t.equals(a.currentCostume, 0); - t.equal(noDeletedCostume, null); + assert.strictEqual(a.sprite.costumes.length, 1); + assert.strictEqual(a.sprite.costumes[0].id, 1); + assert.strictEqual(a.currentCostume, 0); + assert.strictEqual(noDeletedCostume, null); // Costume 1 Costume 1 // x Costume 2 Costume 3 @@ -191,12 +183,12 @@ test('deleteCostume', t => { a.sprite.costumes = [o1, o2, o3, o4, o5]; a.setCostume(3); a.deleteCostume(1); - t.equals(a.sprite.costumes.length, 4); - t.equals(a.sprite.costumes[0].id, 1); - t.equals(a.sprite.costumes[1].id, 3); - t.equals(a.sprite.costumes[2].id, 4); - t.equals(a.sprite.costumes[3].id, 5); - t.equals(a.currentCostume, 2); + assert.strictEqual(a.sprite.costumes.length, 4); + assert.strictEqual(a.sprite.costumes[0].id, 1); + assert.strictEqual(a.sprite.costumes[1].id, 3); + assert.strictEqual(a.sprite.costumes[2].id, 4); + assert.strictEqual(a.sprite.costumes[3].id, 5); + assert.strictEqual(a.currentCostume, 2); // Costume 1 Costume 1 // * Costume 2 * Costume 2 @@ -206,12 +198,12 @@ test('deleteCostume', t => { a.sprite.costumes = [o1, o2, o3, o4, o5]; a.setCostume(1); a.deleteCostume(3); - t.equals(a.sprite.costumes.length, 4); - t.equals(a.sprite.costumes[0].id, 1); - t.equals(a.sprite.costumes[1].id, 2); - t.equals(a.sprite.costumes[2].id, 3); - t.equals(a.sprite.costumes[3].id, 5); - t.equals(a.currentCostume, 1); + assert.strictEqual(a.sprite.costumes.length, 4); + assert.strictEqual(a.sprite.costumes[0].id, 1); + assert.strictEqual(a.sprite.costumes[1].id, 2); + assert.strictEqual(a.sprite.costumes[2].id, 3); + assert.strictEqual(a.sprite.costumes[3].id, 5); + assert.strictEqual(a.currentCostume, 1); // Costume 1 Costume 1 // * Costume 2 * Costume 2 @@ -221,16 +213,15 @@ test('deleteCostume', t => { a.sprite.costumes = [o1, o2, o3, o4, o5]; a.setCostume(1); a.deleteCostume(4); - t.equals(a.sprite.costumes.length, 4); - t.equals(a.sprite.costumes[0].id, 1); - t.equals(a.sprite.costumes[1].id, 2); - t.equals(a.sprite.costumes[2].id, 3); - t.equals(a.sprite.costumes[3].id, 4); - t.equals(a.currentCostume, 1); - t.end(); + assert.strictEqual(a.sprite.costumes.length, 4); + assert.strictEqual(a.sprite.costumes[0].id, 1); + assert.strictEqual(a.sprite.costumes[1].id, 2); + assert.strictEqual(a.sprite.costumes[2].id, 3); + assert.strictEqual(a.sprite.costumes[3].id, 4); + assert.strictEqual(a.currentCostume, 1); }); -test('deleteSound', t => { +test('deleteSound', () => { const o1 = {id: 1}; const o2 = {id: 2}; const o3 = {id: 3}; @@ -243,98 +234,89 @@ test('deleteSound', t => { a.renderer = renderer; const firstDeleted = a.deleteSound(0); - t.deepEqual(a.sprite.sounds, [o2, o3]); - t.deepEqual(firstDeleted, o1); + assert.deepEqual(a.sprite.sounds, [o2, o3]); + assert.deepEqual(firstDeleted, o1); // Allows deleting the only sound a.sprite.sounds = [o1]; a.deleteSound(0); - t.deepEqual(a.sprite.sounds, []); - - t.end(); + assert.deepEqual(a.sprite.sounds, []); }); -test('setRotationStyle', t => { +test('setRotationStyle', () => { const r = new Runtime(); const s = new Sprite(null, r); const a = new RenderedTarget(s, r); const renderer = new FakeRenderer(); a.renderer = renderer; a.setRotationStyle(RenderedTarget.ROTATION_STYLE_NONE); - t.end(); }); -test('getBounds', t => { +test('getBounds', () => { const r = new Runtime(); const s = new Sprite(null, r); const renderer = new FakeRenderer(); r.attachRenderer(renderer); const a = new RenderedTarget(s, r); a.renderer = renderer; - t.equals(a.getBounds().top, 0); + assert.strictEqual(a.getBounds().top, 0); a.setXY(241, 241); - t.equals(a.getBounds().top, 241); - t.end(); + assert.strictEqual(a.getBounds().top, 241); }); -test('isTouchingPoint', t => { +test('isTouchingPoint', () => { const r = new Runtime(); const s = new Sprite(null, r); const renderer = new FakeRenderer(); r.attachRenderer(renderer); const a = new RenderedTarget(s, r); a.renderer = renderer; - t.equals(a.isTouchingPoint(), true); - t.end(); + assert.strictEqual(a.isTouchingPoint(), true); }); -test('isTouchingEdge', t => { +test('isTouchingEdge', () => { const r = new Runtime(); const s = new Sprite(null, r); const renderer = new FakeRenderer(); r.attachRenderer(renderer); const a = new RenderedTarget(s, r); a.renderer = renderer; - t.equals(a.isTouchingEdge(), false); + assert.strictEqual(a.isTouchingEdge(), false); a.setXY(1000, 1000); - t.equals(a.isTouchingEdge(), true); - t.end(); + assert.strictEqual(a.isTouchingEdge(), true); }); -test('isTouchingSprite', t => { +test('isTouchingSprite', () => { const r = new Runtime(); const s = new Sprite(null, r); const renderer = new FakeRenderer(); r.attachRenderer(renderer); const a = new RenderedTarget(s, r); a.renderer = renderer; - t.equals(a.isTouchingSprite('fake'), false); - t.end(); + assert.strictEqual(a.isTouchingSprite('fake'), false); }); -test('isTouchingColor', t => { +test('isTouchingColor', () => { const r = new Runtime(); const s = new Sprite(null, r); const renderer = new FakeRenderer(); r.attachRenderer(renderer); const a = new RenderedTarget(s, r); a.renderer = renderer; - t.equals(a.isTouchingColor(), false); - t.end(); + assert.strictEqual(a.isTouchingColor(), false); }); -test('colorIsTouchingColor', t => { +test('colorIsTouchingColor', () => { const r = new Runtime(); const s = new Sprite(null, r); const renderer = new FakeRenderer(); r.attachRenderer(renderer); const a = new RenderedTarget(s, r); a.renderer = renderer; - t.equals(a.colorIsTouchingColor(), false); - t.end(); + assert.strictEqual(a.colorIsTouchingColor(), false); }); -test('layers', t => { // TODO this tests fake functionality. Move layering tests into Render. +test('layers', () => { // TODO this tests fake functionality. Move layering tests into Render. const r = new Runtime(); const s = new Sprite(null, r); const renderer = new FakeRenderer(); @@ -343,148 +325,136 @@ test('layers', t => { // TODO this tests fake functionality. Move layering tests const a = new RenderedTarget(s, r); a.renderer = renderer; a.goToFront(); - t.equals(a.renderer.order, 5); + assert.strictEqual(a.renderer.order, 5); a.goBackwardLayers(2); - t.equals(a.renderer.order, 3); + assert.strictEqual(a.renderer.order, 3); a.goToBack(); // Note, there are only sprites in this test, no stage, and the addition // of layer groups, goToBack no longer specifies a minimum order number - t.equals(a.renderer.order, 0); + assert.strictEqual(a.renderer.order, 0); a.goForwardLayers(1); - t.equals(a.renderer.order, 1); + assert.strictEqual(a.renderer.order, 1); o.drawableID = 999; a.goBehindOther(o); - t.equals(a.renderer.order, 1); - t.end(); + assert.strictEqual(a.renderer.order, 1); }); -test('getLayerOrder returns result of renderer getDrawableOrder or null if renderer is not attached', t => { +test('getLayerOrder returns result of renderer getDrawableOrder or null if renderer is not attached', () => { const r = new Runtime(); const s = new Sprite(null, r); const a = new RenderedTarget(s, r); // getLayerOrder should return null if there is no renderer attached to the runtime - t.equal(a.getLayerOrder(), null); + assert.strictEqual(a.getLayerOrder(), null); const renderer = new FakeRenderer(); r.attachRenderer(renderer); const b = new RenderedTarget(s, r); - t.equal(b.getLayerOrder(), 'stub'); - - t.end(); + assert.strictEqual(b.getLayerOrder(), 'stub'); }); -test('keepInFence', t => { +test('keepInFence', () => { const r = new Runtime(); const s = new Sprite(null, r); const renderer = new FakeRenderer(); r.attachRenderer(renderer); const a = new RenderedTarget(s, r); a.renderer = renderer; - t.equals(a.keepInFence(1000, 1000)[0], 240); - t.equals(a.keepInFence(-1000, 1000)[0], -240); - t.equals(a.keepInFence(1000, 1000)[1], 180); - t.equals(a.keepInFence(1000, -1000)[1], -180); - t.end(); + assert.strictEqual(a.keepInFence(1000, 1000)[0], 240); + assert.strictEqual(a.keepInFence(-1000, 1000)[0], -240); + assert.strictEqual(a.keepInFence(1000, 1000)[1], 180); + assert.strictEqual(a.keepInFence(1000, -1000)[1], -180); }); -test('#stopAll clears graphics effects', t => { +test('#stopAll clears graphics effects', () => { const r = new Runtime(); const s = new Sprite(null, r); const a = new RenderedTarget(s, r); const effectName = 'brightness'; a.setEffect(effectName, 100); a.onStopAll(); - t.equals(a.effects[effectName], 0); - t.end(); + assert.strictEqual(a.effects[effectName], 0); }); -test('#getCostumes returns the costumes', t => { +test('#getCostumes returns the costumes', () => { const r = new Runtime(); const spr = new Sprite(null, r); const a = new RenderedTarget(spr, r); a.sprite.costumes = [{id: 1}, {id: 2}, {id: 3}]; - t.equals(a.getCostumes().length, 3); - t.equals(a.getCostumes()[0].id, 1); - t.equals(a.getCostumes()[1].id, 2); - t.equals(a.getCostumes()[2].id, 3); - t.end(); + assert.strictEqual(a.getCostumes().length, 3); + assert.strictEqual(a.getCostumes()[0].id, 1); + assert.strictEqual(a.getCostumes()[1].id, 2); + assert.strictEqual(a.getCostumes()[2].id, 3); }); -test('#getSounds returns the sounds', t => { +test('#getSounds returns the sounds', () => { const r = new Runtime(); const spr = new Sprite(null, r); const a = new RenderedTarget(spr, r); const sounds = [1, 2, 3]; a.sprite.sounds = sounds; - t.equals(a.getSounds(), sounds); - t.end(); + assert.strictEqual(a.getSounds(), sounds); }); -test('#toJSON returns the sounds and costumes', t => { +test('#toJSON returns the sounds and costumes', () => { const r = new Runtime(); const spr = new Sprite(null, r); const a = new RenderedTarget(spr, r); const sounds = [1, 2, 3]; a.sprite.sounds = sounds; a.sprite.costumes = [{id: 1}, {id: 2}, {id: 3}]; - t.same(a.toJSON().sounds, sounds); - t.same(a.toJSON().costumes, a.sprite.costumes); - t.end(); + assert.deepEqual(a.toJSON().sounds, sounds); + assert.deepEqual(a.toJSON().costumes, a.sprite.costumes); }); -test('#addSound does not duplicate names', t => { +test('#addSound does not duplicate names', () => { const r = new Runtime(); const spr = new Sprite(null, r); const a = new RenderedTarget(spr, r); a.sprite.sounds = [{name: 'first'}]; a.addSound({name: 'first'}); - t.deepEqual(a.sprite.sounds, [{name: 'first'}, {name: 'first2'}]); - t.end(); + assert.deepEqual(a.sprite.sounds, [{name: 'first'}, {name: 'first2'}]); }); -test('#addCostume does not duplicate names', t => { +test('#addCostume does not duplicate names', () => { const r = new Runtime(); const spr = new Sprite(null, r); const a = new RenderedTarget(spr, r); a.addCostume({name: 'first'}); a.addCostume({name: 'first'}); - t.equal(a.sprite.costumes.length, 2); - t.equal(a.sprite.costumes[0].name, 'first'); - t.equal(a.sprite.costumes[1].name, 'first2'); - t.end(); + assert.strictEqual(a.sprite.costumes.length, 2); + assert.strictEqual(a.sprite.costumes[0].name, 'first'); + assert.strictEqual(a.sprite.costumes[1].name, 'first2'); }); -test('#renameSound does not duplicate names', t => { +test('#renameSound does not duplicate names', () => { const r = new Runtime(); const spr = new Sprite(null, r); const a = new RenderedTarget(spr, r); a.sprite.sounds = [{name: 'first'}, {name: 'second'}]; a.renameSound(0, 'first'); // Shouldn't increment the name, noop - t.deepEqual(a.sprite.sounds, [{name: 'first'}, {name: 'second'}]); + assert.deepEqual(a.sprite.sounds, [{name: 'first'}, {name: 'second'}]); a.renameSound(1, 'first'); - t.deepEqual(a.sprite.sounds, [{name: 'first'}, {name: 'first2'}]); - t.end(); + assert.deepEqual(a.sprite.sounds, [{name: 'first'}, {name: 'first2'}]); }); -test('#renameCostume does not duplicate names', t => { +test('#renameCostume does not duplicate names', () => { const r = new Runtime(); const spr = new Sprite(null, r); const a = new RenderedTarget(spr, r); a.sprite.costumes = [{name: 'first'}, {name: 'second'}]; a.renameCostume(0, 'first'); // Shouldn't increment the name, noop - t.equal(a.sprite.costumes.length, 2); - t.equal(a.sprite.costumes[0].name, 'first'); - t.equal(a.sprite.costumes[1].name, 'second'); + assert.strictEqual(a.sprite.costumes.length, 2); + assert.strictEqual(a.sprite.costumes[0].name, 'first'); + assert.strictEqual(a.sprite.costumes[1].name, 'second'); a.renameCostume(1, 'first'); - t.equal(a.sprite.costumes.length, 2); - t.equal(a.sprite.costumes[0].name, 'first'); - t.equal(a.sprite.costumes[1].name, 'first2'); - t.end(); + assert.strictEqual(a.sprite.costumes.length, 2); + assert.strictEqual(a.sprite.costumes[0].name, 'first'); + assert.strictEqual(a.sprite.costumes[1].name, 'first2'); }); -test('#reorderCostume', t => { +test('#reorderCostume', () => { const o1 = {id: 0}; const o2 = {id: 1}; const o3 = {id: 2}; @@ -504,41 +474,39 @@ test('#reorderCostume', t => { const costumeIds = () => a.sprite.costumes.map(c => c.id); resetCostumes(); - t.deepEquals(costumeIds(), [0, 1, 2, 3, 4]); - t.equals(a.currentCostume, 0); + assert.deepEqual(costumeIds(), [0, 1, 2, 3, 4]); + assert.strictEqual(a.currentCostume, 0); // Returns false if the costumes are the same and no change occurred - t.equal(a.reorderCostume(3, 3), false); - t.equal(a.reorderCostume(999, 5000), false); // Clamped to the same values. - t.equal(a.reorderCostume(-999, -5000), false); + assert.strictEqual(a.reorderCostume(3, 3), false); + assert.strictEqual(a.reorderCostume(999, 5000), false); // Clamped to the same values. + assert.strictEqual(a.reorderCostume(-999, -5000), false); // Make sure reordering up and down works and current costume follows resetCostumes(); - t.equal(a.reorderCostume(0, 3), true); - t.deepEquals(costumeIds(), [1, 2, 3, 0, 4]); - t.equals(a.currentCostume, 3); // Index of id=0 + assert.strictEqual(a.reorderCostume(0, 3), true); + assert.deepEqual(costumeIds(), [1, 2, 3, 0, 4]); + assert.strictEqual(a.currentCostume, 3); // Index of id=0 resetCostumes(); a.setCostume(1); - t.equal(a.reorderCostume(3, 1), true); - t.deepEquals(costumeIds(), [0, 3, 1, 2, 4]); - t.equals(a.currentCostume, 2); // Index of id=1 + assert.strictEqual(a.reorderCostume(3, 1), true); + assert.deepEqual(costumeIds(), [0, 3, 1, 2, 4]); + assert.strictEqual(a.currentCostume, 2); // Index of id=1 // Out of bounds indices get clamped resetCostumes(); - t.equal(a.reorderCostume(10, 0), true); - t.deepEquals(costumeIds(), [4, 0, 1, 2, 3]); - t.equals(a.currentCostume, 1); // Index of id=0 + assert.strictEqual(a.reorderCostume(10, 0), true); + assert.deepEqual(costumeIds(), [4, 0, 1, 2, 3]); + assert.strictEqual(a.currentCostume, 1); // Index of id=0 resetCostumes(); - t.equal(a.reorderCostume(2, -1000), true); - t.deepEquals(costumeIds(), [2, 0, 1, 3, 4]); - t.equals(a.currentCostume, 1); // Index of id=0 - - t.end(); + assert.strictEqual(a.reorderCostume(2, -1000), true); + assert.deepEqual(costumeIds(), [2, 0, 1, 3, 4]); + assert.strictEqual(a.currentCostume, 1); // Index of id=0 }); -test('#reorderSound', t => { +test('#reorderSound', () => { const o1 = {id: 0, name: 'name0'}; const o2 = {id: 1, name: 'name1'}; const o3 = {id: 2, name: 'name2'}; @@ -557,30 +525,28 @@ test('#reorderSound', t => { const soundIds = () => a.sprite.sounds.map(c => c.id); resetSounds(); - t.deepEquals(soundIds(), [0, 1, 2, 3, 4]); + assert.deepEqual(soundIds(), [0, 1, 2, 3, 4]); // Return false if indices are the same and no change occurred. - t.equal(a.reorderSound(3, 3), false); - t.equal(a.reorderSound(100000, 99999), false); // Clamped to the same values - t.equal(a.reorderSound(-100000, -99999), false); + assert.strictEqual(a.reorderSound(3, 3), false); + assert.strictEqual(a.reorderSound(100000, 99999), false); // Clamped to the same values + assert.strictEqual(a.reorderSound(-100000, -99999), false); // Make sure reordering up and down works and current sound follows resetSounds(); - t.equal(a.reorderSound(0, 3), true); - t.deepEquals(soundIds(), [1, 2, 3, 0, 4]); + assert.strictEqual(a.reorderSound(0, 3), true); + assert.deepEqual(soundIds(), [1, 2, 3, 0, 4]); resetSounds(); - t.equal(a.reorderSound(3, 1), true); - t.deepEquals(soundIds(), [0, 3, 1, 2, 4]); + assert.strictEqual(a.reorderSound(3, 1), true); + assert.deepEqual(soundIds(), [0, 3, 1, 2, 4]); // Out of bounds indices get clamped resetSounds(); - t.equal(a.reorderSound(10, 0), true); - t.deepEquals(soundIds(), [4, 0, 1, 2, 3]); + assert.strictEqual(a.reorderSound(10, 0), true); + assert.deepEqual(soundIds(), [4, 0, 1, 2, 3]); resetSounds(); - t.equal(a.reorderSound(2, -1000), true); - t.deepEquals(soundIds(), [2, 0, 1, 3, 4]); - - t.end(); + assert.strictEqual(a.reorderSound(2, -1000), true); + assert.deepEqual(soundIds(), [2, 0, 1, 3, 4]); }); diff --git a/test/unit/tw_asset_util.js b/test/unit/tw_asset_util.js index a3449570..26ab2a66 100644 --- a/test/unit/tw_asset_util.js +++ b/test/unit/tw_asset_util.js @@ -1,57 +1,55 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const JSZip = require('@turbowarp/jszip'); const makeTestStorage = require('../fixtures/make-test-storage'); const AssetUtil = require('../../src/util/tw-asset-util'); const Runtime = require('../../src/engine/runtime'); -test('getByMd5ext from zip root', t => { +test('getByMd5ext from zip root', async () => { const rt = new Runtime(); rt.attachStorage(makeTestStorage()); - rt.storage.load = () => t.fail('should not call storage.load()'); + rt.storage.load = () => assert.fail('should not call storage.load()'); const zip = new JSZip(); zip.file('00000000000000000000000000000000.svg', new Uint8Array([1, 2, 3])); - AssetUtil.getByMd5ext(rt, zip, rt.storage.AssetType.SVG, '00000000000000000000000000000000.svg') - .then(asset => { - t.same(asset.data, new Uint8Array([1, 2, 3])); - t.end(); - }); + const asset = await AssetUtil.getByMd5ext( + rt, zip, rt.storage.AssetType.SVG, '00000000000000000000000000000000.svg' + ); + assert.deepEqual(asset.data, new Uint8Array([1, 2, 3])); }); -test('getByMd5ext from zip subdirectory', t => { +test('getByMd5ext from zip subdirectory', async () => { const rt = new Runtime(); rt.attachStorage(makeTestStorage()); - rt.storage.load = () => t.fail('should not call storage.load()'); + rt.storage.load = () => assert.fail('should not call storage.load()'); const zip = new JSZip(); zip.file('folder/00000000000000000000000000000000.svg', new Uint8Array([25, 26, 27])); - AssetUtil.getByMd5ext(rt, zip, rt.storage.AssetType.SVG, '00000000000000000000000000000000.svg') - .then(asset => { - t.same(asset.data, new Uint8Array([25, 26, 27])); - t.end(); - }); + const asset = await AssetUtil.getByMd5ext( + rt, zip, rt.storage.AssetType.SVG, '00000000000000000000000000000000.svg' + ); + assert.deepEqual(asset.data, new Uint8Array([25, 26, 27])); }); -test('getByMd5ext from storage with null zip', t => { +test('getByMd5ext from storage with null zip', async t => { t.plan(4); const rt = new Runtime(); rt.attachStorage(makeTestStorage()); rt.storage.load = (assetType, md5, ext) => { - t.equal(assetType, rt.storage.AssetType.SVG); - t.equal(md5, '00000000000000000000000000000000'); - t.equal(ext, 'svg'); + t.assert.strictEqual(assetType, rt.storage.AssetType.SVG); + t.assert.strictEqual(md5, '00000000000000000000000000000000'); + t.assert.strictEqual(ext, 'svg'); return Promise.resolve({ fromStorage: true }); }; - AssetUtil.getByMd5ext(rt, null, rt.storage.AssetType.SVG, '00000000000000000000000000000000.svg') - .then(asset => { - t.ok(asset.fromStorage); - t.end(); - }); + const asset = await AssetUtil.getByMd5ext( + rt, null, rt.storage.AssetType.SVG, '00000000000000000000000000000000.svg' + ); + t.assert.ok(asset.fromStorage); }); diff --git a/test/unit/tw_block_colors.js b/test/unit/tw_block_colors.js index 79085c8e..ecf4591d 100644 --- a/test/unit/tw_block_colors.js +++ b/test/unit/tw_block_colors.js @@ -1,8 +1,9 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const VirtualMachine = require('../../src/virtual-machine'); const BlockType = require('../../src/extension-support/block-type'); -test('with explicit category colors', t => { +test('with explicit category colors', () => { const vm = new VirtualMachine(); vm.extensionManager._registerInternalExtension({ getInfo: () => ({ @@ -44,30 +45,28 @@ test('with explicit category colors', t => { const blocks = vm.runtime.getBlocksJSON(); - t.equal(blocks[0].colour, '#ff0000'); - t.equal(blocks[0].colourSecondary, '#00ff00'); - t.equal(blocks[0].colourTertiary, '#0000ff'); + assert.strictEqual(blocks[0].colour, '#ff0000'); + assert.strictEqual(blocks[0].colourSecondary, '#00ff00'); + assert.strictEqual(blocks[0].colourTertiary, '#0000ff'); - t.equal(blocks[1].colour, '#ffff00'); - t.equal(blocks[1].colourSecondary, '#00ff00'); - t.equal(blocks[1].colourTertiary, '#0000ff'); + assert.strictEqual(blocks[1].colour, '#ffff00'); + assert.strictEqual(blocks[1].colourSecondary, '#00ff00'); + assert.strictEqual(blocks[1].colourTertiary, '#0000ff'); - t.equal(blocks[2].colour, '#ff0000'); - t.equal(blocks[2].colourSecondary, '#ff00ff'); - t.equal(blocks[2].colourTertiary, '#0000ff'); + assert.strictEqual(blocks[2].colour, '#ff0000'); + assert.strictEqual(blocks[2].colourSecondary, '#ff00ff'); + assert.strictEqual(blocks[2].colourTertiary, '#0000ff'); - t.equal(blocks[3].colour, '#ff0000'); - t.equal(blocks[3].colourSecondary, '#00ff00'); - t.equal(blocks[3].colourTertiary, '#00ffff'); + assert.strictEqual(blocks[3].colour, '#ff0000'); + assert.strictEqual(blocks[3].colourSecondary, '#00ff00'); + assert.strictEqual(blocks[3].colourTertiary, '#00ffff'); - t.equal(blocks[4].colour, '#7fff00'); - t.equal(blocks[4].colourSecondary, '#ff007f'); - t.equal(blocks[4].colourTertiary, '#007fff'); - - t.end(); + assert.strictEqual(blocks[4].colour, '#7fff00'); + assert.strictEqual(blocks[4].colourSecondary, '#ff007f'); + assert.strictEqual(blocks[4].colourTertiary, '#007fff'); }); -test('with the default colors', t => { +test('with the default colors', () => { const vm = new VirtualMachine(); vm.extensionManager._registerInternalExtension({ getInfo: () => ({ @@ -106,25 +105,23 @@ test('with the default colors', t => { const blocks = vm.runtime.getBlocksJSON(); - t.equal(blocks[0].colour, '#0FBD8C'); - t.equal(blocks[0].colourSecondary, '#0DA57A'); - t.equal(blocks[0].colourTertiary, '#0B8E69'); + assert.strictEqual(blocks[0].colour, '#0FBD8C'); + assert.strictEqual(blocks[0].colourSecondary, '#0DA57A'); + assert.strictEqual(blocks[0].colourTertiary, '#0B8E69'); - t.equal(blocks[1].colour, '#ffff00'); - t.equal(blocks[1].colourSecondary, '#0DA57A'); - t.equal(blocks[1].colourTertiary, '#0B8E69'); + assert.strictEqual(blocks[1].colour, '#ffff00'); + assert.strictEqual(blocks[1].colourSecondary, '#0DA57A'); + assert.strictEqual(blocks[1].colourTertiary, '#0B8E69'); - t.equal(blocks[2].colour, '#0FBD8C'); - t.equal(blocks[2].colourSecondary, '#ff00ff'); - t.equal(blocks[2].colourTertiary, '#0B8E69'); + assert.strictEqual(blocks[2].colour, '#0FBD8C'); + assert.strictEqual(blocks[2].colourSecondary, '#ff00ff'); + assert.strictEqual(blocks[2].colourTertiary, '#0B8E69'); - t.equal(blocks[3].colour, '#0FBD8C'); - t.equal(blocks[3].colourSecondary, '#0DA57A'); - t.equal(blocks[3].colourTertiary, '#00ffff'); + assert.strictEqual(blocks[3].colour, '#0FBD8C'); + assert.strictEqual(blocks[3].colourSecondary, '#0DA57A'); + assert.strictEqual(blocks[3].colourTertiary, '#00ffff'); - t.equal(blocks[4].colour, '#7fff00'); - t.equal(blocks[4].colourSecondary, '#ff007f'); - t.equal(blocks[4].colourTertiary, '#007fff'); - - t.end(); + assert.strictEqual(blocks[4].colour, '#7fff00'); + assert.strictEqual(blocks[4].colourSecondary, '#ff007f'); + assert.strictEqual(blocks[4].colourTertiary, '#007fff'); }); diff --git a/test/unit/tw_block_extensions.js b/test/unit/tw_block_extensions.js index eed5c3a8..e35633cb 100644 --- a/test/unit/tw_block_extensions.js +++ b/test/unit/tw_block_extensions.js @@ -1,8 +1,9 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const VirtualMachine = require('../../src/virtual-machine'); const BlockType = require('../../src/extension-support/block-type'); -test('does not duplicate', t => { +test('does not duplicate', () => { const vm = new VirtualMachine(); vm.extensionManager._registerInternalExtension({ getInfo: () => ({ @@ -25,14 +26,13 @@ test('does not duplicate', t => { }); const blocks = vm.runtime.getBlocksJSON(); - t.same( + assert.deepEqual( blocks[0].extensions, ['from_extension', 'default_extension_colors', 'scratch_extension', 'something_invalid'] ); - t.end(); }); -test('block icon', t => { +test('block icon', () => { const vm = new VirtualMachine(); vm.extensionManager._registerInternalExtension({ getInfo: () => ({ @@ -70,19 +70,17 @@ test('block icon', t => { }); const blocks = vm.runtime.getBlocksJSON(); - t.same(blocks[0].extensions, ['from_extension', 'default_extension_colors']); - t.same(blocks[1].extensions, ['from_extension', 'default_extension_colors']); - t.same(blocks[2].extensions, ['from_extension', 'default_extension_colors', 'scratch_extension']); - t.same(blocks[3].extensions, ['from_extension', 'default_extension_colors', 'scratch_extension']); - t.same( + assert.deepEqual(blocks[0].extensions, ['from_extension', 'default_extension_colors']); + assert.deepEqual(blocks[1].extensions, ['from_extension', 'default_extension_colors']); + assert.deepEqual(blocks[2].extensions, ['from_extension', 'default_extension_colors', 'scratch_extension']); + assert.deepEqual(blocks[3].extensions, ['from_extension', 'default_extension_colors', 'scratch_extension']); + assert.deepEqual( blocks[4].extensions, ['from_extension', 'default_extension_colors', 'scratch_extension', 'colours_sensing'] ); - - t.end(); }); -test('category icon', t => { +test('category icon', () => { const vm = new VirtualMachine(); vm.extensionManager._registerInternalExtension({ getInfo: () => ({ @@ -99,11 +97,10 @@ test('category icon', t => { }); const blocks = vm.runtime.getBlocksJSON(); - t.same(blocks[0].extensions, ['from_extension', 'default_extension_colors', 'scratch_extension']); - t.end(); + assert.deepEqual(blocks[0].extensions, ['from_extension', 'default_extension_colors', 'scratch_extension']); }); -test('category color', t => { +test('category color', () => { const vm = new VirtualMachine(); vm.extensionManager._registerInternalExtension({ getInfo: () => ({ @@ -121,11 +118,10 @@ test('category color', t => { }); const blocks = vm.runtime.getBlocksJSON(); - t.same(blocks[0].extensions, ['from_extension', 'scratch_extension']); - t.end(); + assert.deepEqual(blocks[0].extensions, ['from_extension', 'scratch_extension']); }); -test('category color', t => { +test('category color', () => { const vm = new VirtualMachine(); vm.extensionManager._registerInternalExtension({ getInfo: () => ({ @@ -146,7 +142,6 @@ test('category color', t => { }); const blocks = vm.runtime.getBlocksJSON(); - t.same(blocks[0].extensions, ['from_extension', 'default_extension_colors']); - t.same(blocks[1].extensions, ['from_extension']); - t.end(); + assert.deepEqual(blocks[0].extensions, ['from_extension', 'default_extension_colors']); + assert.deepEqual(blocks[1].extensions, ['from_extension']); }); diff --git a/test/unit/tw_block_sensing.js b/test/unit/tw_block_sensing.js index 779c8a14..d35b907b 100644 --- a/test/unit/tw_block_sensing.js +++ b/test/unit/tw_block_sensing.js @@ -1,8 +1,9 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const Scratch3SensingBlocks = require('../../src/blocks/scratch3_sensing'); const Runtime = require('../../src/engine/runtime'); -test('isOnline', t => { +test('isOnline', () => { const rt = new Runtime(); const sensing = new Scratch3SensingBlocks(rt); @@ -15,14 +16,12 @@ test('isOnline', t => { configurable: true, enumerable: true }); - t.equal(sensing.isOnline(), false); + assert.strictEqual(sensing.isOnline(), false); Object.defineProperty(global.navigator, 'onLine', { get: () => true, configurable: true, enumerable: true }); - t.equal(sensing.isOnline(), true); - - t.end(); + assert.strictEqual(sensing.isOnline(), true); }); diff --git a/test/unit/tw_block_shape.js b/test/unit/tw_block_shape.js index a5ef5028..1facc499 100644 --- a/test/unit/tw_block_shape.js +++ b/test/unit/tw_block_shape.js @@ -1,8 +1,9 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const Runtime = require('../../src/engine/runtime'); const Scratch = require('../../src/extension-support/tw-extension-api-common'); -test('blockShape', t => { +test('blockShape', () => { const rt = new Runtime(); rt._registerExtensionPrimitives({ id: 'shapetest', @@ -30,9 +31,8 @@ test('blockShape', t => { }); const json = rt.getBlocksJSON(); - t.equal(json.length, 3); - t.equal(json[0].outputShape, 1); - t.equal(json[1].outputShape, 2); - t.equal(json[2].outputShape, 3); - t.end(); + assert.strictEqual(json.length, 3); + assert.strictEqual(json[0].outputShape, 1); + assert.strictEqual(json[1].outputShape, 2); + assert.strictEqual(json[2].outputShape, 3); }); diff --git a/test/unit/tw_branch_icon_uri.js b/test/unit/tw_branch_icon_uri.js index f001039e..9f344f6f 100644 --- a/test/unit/tw_branch_icon_uri.js +++ b/test/unit/tw_branch_icon_uri.js @@ -1,8 +1,9 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const VirtualMachine = require('../../src/virtual-machine'); const BlockType = require('../../src/extension-support/block-type'); -test('branchIconURI', t => { +test('branchIconURI', () => { const vm = new VirtualMachine(); vm.extensionManager._registerInternalExtension({ getInfo: () => ({ @@ -37,10 +38,8 @@ test('branchIconURI', t => { }); const blocks = vm.runtime.getBlocksJSON(); - t.equal(blocks[0].args2[0].src, 'media://repeat.svg', 'default custom icon'); - t.equal(blocks[1].args2[0].src, 'data:whatever1', 'LOOP with custom icon'); - t.equal(blocks[2].args2[0].src, 'data:whatever2', 'CONDITIONAL with custom icon'); - t.same(blocks[3].args2, null, 'LOOP with no icon'); - - t.end(); + assert.strictEqual(blocks[0].args2[0].src, 'media://repeat.svg', 'default custom icon'); + assert.strictEqual(blocks[1].args2[0].src, 'data:whatever1', 'LOOP with custom icon'); + assert.strictEqual(blocks[2].args2[0].src, 'data:whatever2', 'CONDITIONAL with custom icon'); + assert.deepEqual(blocks[3].args2, null, 'LOOP with no icon'); }); diff --git a/test/unit/tw_cast.js b/test/unit/tw_cast.js index 92763371..6c2e764f 100644 --- a/test/unit/tw_cast.js +++ b/test/unit/tw_cast.js @@ -1,83 +1,82 @@ const Cast = require('../../src/util/cast'); -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); -test('Cast.compare with assorted whitespace characters', t => { - t.equal(Cast.compare('', ''), 0); +test('Cast.compare with assorted whitespace characters', () => { + assert.strictEqual(Cast.compare('', ''), 0); - t.equal(Cast.compare(' ', ''), 1); - t.equal(Cast.compare('', ' '), -1); + assert.strictEqual(Cast.compare(' ', ''), 1); + assert.strictEqual(Cast.compare('', ' '), -1); - t.equal(Cast.compare(' ', ' '), -1); - t.equal(Cast.compare(' ', ' '), 1); + assert.strictEqual(Cast.compare(' ', ' '), -1); + assert.strictEqual(Cast.compare(' ', ' '), 1); - t.equal(Cast.compare(' \u00a0 ', '\r\n'), 1); - t.equal(Cast.compare('\r\n', ' \u00a0 '), -1); + assert.strictEqual(Cast.compare(' \u00a0 ', '\r\n'), 1); + assert.strictEqual(Cast.compare('\r\n', ' \u00a0 '), -1); - t.equal(Cast.compare(' 0', 0), 0); - t.equal(Cast.compare(0, ' 0'), 0); + assert.strictEqual(Cast.compare(' 0', 0), 0); + assert.strictEqual(Cast.compare(0, ' 0'), 0); - t.equal(Cast.compare(' 0 ', ' \r\n\u00a0 0 \n\n\n\n'), 0); - t.equal(Cast.compare(' \r\n\u00a0 0 \n\n\n\n', ' 0 '), 0); + assert.strictEqual(Cast.compare(' 0 ', ' \r\n\u00a0 0 \n\n\n\n'), 0); + assert.strictEqual(Cast.compare(' \r\n\u00a0 0 \n\n\n\n', ' 0 '), 0); - t.equal(Cast.compare(' 0 ', ' \r\n\u00a0 0 \n\n\n\b'), 1); - t.equal(Cast.compare(' \r\n\u00a0 0 \n\n\n\b', ' 0 '), -1); + assert.strictEqual(Cast.compare(' 0 ', ' \r\n\u00a0 0 \n\n\n\b'), 1); + assert.strictEqual(Cast.compare(' \r\n\u00a0 0 \n\n\n\b', ' 0 '), -1); - t.equal(Cast.compare(' 0', '0'), 0); - t.equal(Cast.compare('0', ' 0'), 0); + assert.strictEqual(Cast.compare(' 0', '0'), 0); + assert.strictEqual(Cast.compare('0', ' 0'), 0); - t.equal(Cast.compare('', 0), -1); - t.equal(Cast.compare(0, ''), 1); + assert.strictEqual(Cast.compare('', 0), -1); + assert.strictEqual(Cast.compare(0, ''), 1); - t.equal(Cast.compare(' ', 0), -1); - t.equal(Cast.compare(0, ' '), 1); + assert.strictEqual(Cast.compare(' ', 0), -1); + assert.strictEqual(Cast.compare(0, ' '), 1); - t.equal(Cast.compare('0', ' '), 1); - t.equal(Cast.compare(' ', '0'), -1); + assert.strictEqual(Cast.compare('0', ' '), 1); + assert.strictEqual(Cast.compare(' ', '0'), -1); - t.equal(Cast.compare('\n0', '\n-1'), 1); - t.equal(Cast.compare('\n-1', '\n0'), -1); + assert.strictEqual(Cast.compare('\n0', '\n-1'), 1); + assert.strictEqual(Cast.compare('\n-1', '\n0'), -1); - t.equal(Cast.compare('', 'false'), -1); - t.equal(Cast.compare('false', ''), 1); + assert.strictEqual(Cast.compare('', 'false'), -1); + assert.strictEqual(Cast.compare('false', ''), 1); - t.equal(Cast.compare('', ' false'), -1); - t.equal(Cast.compare(' false', ''), 1); + assert.strictEqual(Cast.compare('', ' false'), -1); + assert.strictEqual(Cast.compare(' false', ''), 1); - t.equal(Cast.compare('\n', ' false'), -1); - t.equal(Cast.compare('false', '\n'), 1); + assert.strictEqual(Cast.compare('\n', ' false'), -1); + assert.strictEqual(Cast.compare('false', '\n'), 1); - t.equal(Cast.compare(false, ''), 1); - t.equal(Cast.compare('', false), -1); + assert.strictEqual(Cast.compare(false, ''), 1); + assert.strictEqual(Cast.compare('', false), -1); - t.equal(Cast.compare(false, ' '), 1); - t.equal(Cast.compare(' ', false), -1); + assert.strictEqual(Cast.compare(false, ' '), 1); + assert.strictEqual(Cast.compare(' ', false), -1); - t.equal(Cast.compare('\t', '0'), 0); - t.equal(Cast.compare('0', '\t'), 0); + assert.strictEqual(Cast.compare('\t', '0'), 0); + assert.strictEqual(Cast.compare('0', '\t'), 0); - t.equal(Cast.compare('\t', 0), 0); - t.equal(Cast.compare(0, '\t'), 0); + assert.strictEqual(Cast.compare('\t', 0), 0); + assert.strictEqual(Cast.compare(0, '\t'), 0); - t.equal(Cast.compare('\t', ''), 1); - t.equal(Cast.compare('', '\t'), -1); + assert.strictEqual(Cast.compare('\t', ''), 1); + assert.strictEqual(Cast.compare('', '\t'), -1); - t.equal(Cast.compare(' \t ', '0'), 0); - t.equal(Cast.compare('0', ' \t '), 0); + assert.strictEqual(Cast.compare(' \t ', '0'), 0); + assert.strictEqual(Cast.compare('0', ' \t '), 0); - t.equal(Cast.compare('\r\n \t\u00a0', 0), 0); - t.equal(Cast.compare(0, '\r\n \t\u00a0'), 0); + assert.strictEqual(Cast.compare('\r\n \t\u00a0', 0), 0); + assert.strictEqual(Cast.compare(0, '\r\n \t\u00a0'), 0); - t.equal(Cast.compare('\t', false), 0); - t.equal(Cast.compare(false, '\t'), 0); + assert.strictEqual(Cast.compare('\t', false), 0); + assert.strictEqual(Cast.compare(false, '\t'), 0); - t.equal(Cast.compare('\t', 'false'), -1); - t.equal(Cast.compare('false', '\t'), 1); + assert.strictEqual(Cast.compare('\t', 'false'), -1); + assert.strictEqual(Cast.compare('false', '\t'), 1); - t.equal(Cast.compare('\t', '1'), -1); - t.equal(Cast.compare('1', '\t'), 1); + assert.strictEqual(Cast.compare('\t', '1'), -1); + assert.strictEqual(Cast.compare('1', '\t'), 1); - t.equal(Cast.compare('\t', 1), -1); - t.equal(Cast.compare(1, '\t'), 1); - - t.end(); + assert.strictEqual(Cast.compare('\t', 1), -1); + assert.strictEqual(Cast.compare(1, '\t'), 1); }); diff --git a/test/unit/tw_clones.js b/test/unit/tw_clones.js index b4a02119..d2a0b05b 100644 --- a/test/unit/tw_clones.js +++ b/test/unit/tw_clones.js @@ -1,18 +1,18 @@ const Runtime = require('../../src/engine/runtime'); const Sprite = require('../../src/sprites/sprite'); -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); -test('clone counter', t => { +test('clone counter', () => { const rt = new Runtime(); const sprite = new Sprite(null, rt); const original = sprite.createClone(); - t.equal(rt._cloneCounter, 0); + assert.strictEqual(rt._cloneCounter, 0); const clone = original.makeClone(); - t.equal(rt._cloneCounter, 1); + assert.strictEqual(rt._cloneCounter, 1); clone.dispose(); - t.equal(rt._cloneCounter, 0); + assert.strictEqual(rt._cloneCounter, 0); original.dispose(); - t.equal(rt._cloneCounter, 0); - t.end(); + assert.strictEqual(rt._cloneCounter, 0); }); diff --git a/test/unit/tw_compress.js b/test/unit/tw_compress.js index fb5f5676..24c6ee90 100644 --- a/test/unit/tw_compress.js +++ b/test/unit/tw_compress.js @@ -1,8 +1,9 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const compress = require('../../src/serialization/tw-compress-sb3'); const uid = require('../../src/util/uid'); -test('handles type INPUT_DIFF_BLOCK_SHADOW (3) compressed inputs', t => { +test('handles type INPUT_DIFF_BLOCK_SHADOW (3) compressed inputs', () => { const data = { targets: [ { @@ -76,24 +77,22 @@ test('handles type INPUT_DIFF_BLOCK_SHADOW (3) compressed inputs', t => { compress(data); const blocks = Object.entries(data.targets[0].blocks); - t.equal(blocks.length, 3); + assert.strictEqual(blocks.length, 3); const [parentId, parentBlock] = blocks.find(i => i[1].opcode === 'looks_switchbackdropto'); const [inputId, inputBlock] = blocks.find(i => i[1].opcode === 'operator_not'); const [shadowId, shadowBlock] = blocks.find(i => i[1].opcode === 'looks_backdrops'); - t.equal(parentBlock.inputs.BACKDROP.length, 3); - t.equal(parentBlock.inputs.BACKDROP[0], 3); - t.equal(parentBlock.inputs.BACKDROP[1], inputId); - t.equal(parentBlock.inputs.BACKDROP[2], shadowId); + assert.strictEqual(parentBlock.inputs.BACKDROP.length, 3); + assert.strictEqual(parentBlock.inputs.BACKDROP[0], 3); + assert.strictEqual(parentBlock.inputs.BACKDROP[1], inputId); + assert.strictEqual(parentBlock.inputs.BACKDROP[2], shadowId); - t.equal(inputBlock.parent, parentId); - t.equal(shadowBlock.parent, parentId); - - t.end(); + assert.strictEqual(inputBlock.parent, parentId); + assert.strictEqual(shadowBlock.parent, parentId); }); -test('Compressed IDs will not collide with uncompressed IDs', t => { +test('Compressed IDs will not collide with uncompressed IDs', () => { const soup = 'abcdefghjijklmnopqstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789'; const items = [ [soup, '', ''], @@ -217,14 +216,12 @@ test('Compressed IDs will not collide with uncompressed IDs', t => { ...Object.keys(data.targets[0].comments) ]; for (const compressedID of compressedIDs) { - t.notOk(uncompressedIDs.includes(compressedID), `${compressedID} does not collide`); + assert.ok(!uncompressedIDs.includes(compressedID), `${compressedID} does not collide`); } } - - t.end(); }); -test('Script execution order is preserved', t => { +test('Script execution order is preserved', () => { const originalBlocks = {}; const blockIds = []; @@ -292,17 +289,17 @@ test('Script execution order is preserved', t => { // Sanity check: Make sure the new object is actually different const newBlocks = data.targets[0].blocks; - t.not(originalBlocks, newBlocks); - t.notSame(Object.keys(originalBlocks), Object.keys(newBlocks)); + assert.notStrictEqual(originalBlocks, newBlocks); + assert.notDeepEqual(Object.keys(originalBlocks), Object.keys(newBlocks)); // Check that the order has not changed const newBlockValues = Object.values(newBlocks); - t.same(Object.values(originalBlocks), newBlockValues); - t.equal(newBlockValues[0].fields.BROADCAST_OPTION[0], 'broadcast-name-45'); - t.equal(newBlockValues[1].fields.BROADCAST_OPTION[0], 'broadcast-name-555'); - t.equal(newBlockValues[339 + 2].fields.BROADCAST_OPTION[0], 'broadcast-name-muffin'); - t.equal(newBlockValues[newBlockValues.length - 2].fields.BROADCAST_OPTION[0], 'broadcast-name-apple'); - t.equal(newBlockValues[newBlockValues.length - 1].fields.BROADCAST_OPTION[0], 'broadcast-name--1'); + assert.deepEqual(Object.values(originalBlocks), newBlockValues); + assert.strictEqual(newBlockValues[0].fields.BROADCAST_OPTION[0], 'broadcast-name-45'); + assert.strictEqual(newBlockValues[1].fields.BROADCAST_OPTION[0], 'broadcast-name-555'); + assert.strictEqual(newBlockValues[339 + 2].fields.BROADCAST_OPTION[0], 'broadcast-name-muffin'); + assert.strictEqual(newBlockValues[newBlockValues.length - 2].fields.BROADCAST_OPTION[0], 'broadcast-name-apple'); + assert.strictEqual(newBlockValues[newBlockValues.length - 1].fields.BROADCAST_OPTION[0], 'broadcast-name--1'); // Check that the new IDs do not look like array indexes as their enumeration // order could cause unexpected behavior in other places. @@ -310,9 +307,7 @@ test('Script execution order is preserved', t => { // The actual definition of an array index is: https://tc39.es/ecma262/#array-index // This approximation is currently good enough if (!Number.isNaN(+newBlockId)) { - t.fail(`${newBlockId} might be treated as an array index`); + assert.fail(`${newBlockId} might be treated as an array index`); } } - - t.end(); }); diff --git a/test/unit/tw_costume_and_sound_inputs.js b/test/unit/tw_costume_and_sound_inputs.js index 4294f5ee..2c165cc1 100644 --- a/test/unit/tw_costume_and_sound_inputs.js +++ b/test/unit/tw_costume_and_sound_inputs.js @@ -1,4 +1,5 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const Runtime = require('../../src/engine/runtime'); const BlockType = require('../../src/extension-support/block-type'); const ArgumentType = require('../../src/extension-support/argument-type'); @@ -38,20 +39,20 @@ const extension = { ] }; -test('COSTUME and SOUND inputs generate correct scratch-blocks XML', t => { +test('COSTUME and SOUND inputs generate correct scratch-blocks XML', (t, done) => { const rt = new Runtime(); rt.on('EXTENSION_ADDED', info => { /* eslint-disable max-len */ - t.equal( + assert.strictEqual( info.blocks[0].xml, 'default costume' ); - t.equal( + assert.strictEqual( info.blocks[1].xml, 'default sound' ); /* eslint-enable max-len */ - t.end(); + done(); }); rt._registerExtensionPrimitives(extension); }); diff --git a/test/unit/tw_costume_import_export.js b/test/unit/tw_costume_import_export.js index 7958b08c..2f1ca9bd 100644 --- a/test/unit/tw_costume_import_export.js +++ b/test/unit/tw_costume_import_export.js @@ -2,59 +2,58 @@ const { parseVectorMetadata, exportCostume } = require('../../src/serialization/tw-costume-import-export'); -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); -test('parseVectorMetadata', t => { +test('parseVectorMetadata', () => { /* eslint-disable max-len */ - t.same( + assert.deepEqual( parseVectorMetadata(''), [0, 0] ); - t.same( + assert.deepEqual( parseVectorMetadata(''), [0, 0] ); - t.same( + assert.deepEqual( parseVectorMetadata(''), [-1, 3] ); - t.same( + assert.deepEqual( parseVectorMetadata(''), [106.62300344745225, -11.822572945859918] ); - t.same( + assert.deepEqual( parseVectorMetadata(''), null ); - t.same( + assert.deepEqual( parseVectorMetadata(''), null ); - t.same( + assert.deepEqual( parseVectorMetadata(''), null ); /* eslint-enable max-len */ - - t.end(); }); -test('exportCostume', t => { +test('exportCostume', () => { // PNG and JPG costumes are exported as-is - t.same(exportCostume({ + assert.deepEqual(exportCostume({ dataFormat: 'png', asset: { data: new Uint8Array([10, 20, 30]) } }), new Uint8Array([10, 20, 30])); - t.same(exportCostume({ + assert.deepEqual(exportCostume({ dataFormat: 'jpg', asset: { data: new Uint8Array([40, 50, 60]) } }), new Uint8Array([40, 50, 60])); - t.same(exportCostume({ + assert.deepEqual(exportCostume({ dataFormat: 'svg', asset: { data: new TextEncoder().encode('') @@ -63,7 +62,7 @@ test('exportCostume', t => { rotationCenterY: -3.7373 }), new TextEncoder().encode('')); - t.same(exportCostume({ + assert.deepEqual(exportCostume({ dataFormat: 'svg', asset: { data: new TextEncoder().encode('') @@ -71,6 +70,4 @@ test('exportCostume', t => { rotationCenterX: 89.339393, rotationCenterY: -3.7373 }), new TextEncoder().encode('')); - - t.end(); }); diff --git a/test/unit/tw_delete_resources.js b/test/unit/tw_delete_resources.js index b64f98c5..a3345b81 100644 --- a/test/unit/tw_delete_resources.js +++ b/test/unit/tw_delete_resources.js @@ -1,5 +1,6 @@ const crypto = require('crypto'); -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const JSZip = require('@turbowarp/jszip'); const VirtualMachine = require('../../src/virtual-machine'); const FakeRenderer = require('../fixtures/fake-renderer'); @@ -139,7 +140,7 @@ const makeVM = async () => { return vm; }; -test('deleting a costume destroys its skin; restoring re-creates it', async t => { +test('deleting a costume destroys its skin; restoring re-creates it', async () => { const vm = await makeVM(); const target = vm.runtime.getSpriteTargetByName('Sprite1'); const sprite = target.sprite; @@ -151,21 +152,19 @@ test('deleting a costume destroys its skin; restoring re-creates it', async t => const costume = sprite.costumes[1]; const skinId = costume.skinId; - t.type(skinId, 'number', 'costume has a skin'); + assert.strictEqual(typeof skinId, 'number', 'costume has a skin'); const restore = vm.deleteCostume(1); - t.same(sprite.costumes.map(c => c.name), ['costume1'], 'costume removed'); - t.ok(vm.runtime.renderer.destroyedSkins.includes(skinId), 'skin destroyed'); - t.equal(clone.currentCostume, 0, 'clone switched costume'); + assert.deepEqual(sprite.costumes.map(c => c.name), ['costume1'], 'costume removed'); + assert.ok(vm.runtime.renderer.destroyedSkins.includes(skinId), 'skin destroyed'); + assert.strictEqual(clone.currentCostume, 0, 'clone switched costume'); await restore(); - t.same(sprite.costumes.map(c => c.name), ['costume1', 'costume2'], 'costume restored'); - t.type(sprite.costumes[1].skinId, 'number', 'restored costume has a new skin'); - - t.end(); + assert.deepEqual(sprite.costumes.map(c => c.name), ['costume1', 'costume2'], 'costume restored'); + assert.strictEqual(typeof sprite.costumes[1].skinId, 'number', 'restored costume has a new skin'); }); -test('deleting a sound disposes its player; restoring re-decodes it', async t => { +test('deleting a sound disposes its player; restoring re-decodes it', async () => { const vm = await makeVM(); const target = vm.runtime.getSpriteTargetByName('Sprite1'); const sprite = target.sprite; @@ -173,56 +172,50 @@ test('deleting a sound disposes its player; restoring re-decodes it', async t => const sound = sprite.sounds[0]; const soundId = sound.soundId; - t.type(soundId, 'string', 'sound has a player'); + assert.strictEqual(typeof soundId, 'string', 'sound has a player'); const restore = vm.deleteSound(0); - t.same(sprite.sounds.map(s => s.name), ['sound2'], 'sound removed'); - t.same(sprite.soundBank.removedSounds, [soundId], 'player removed from the bank'); + assert.deepEqual(sprite.sounds.map(s => s.name), ['sound2'], 'sound removed'); + assert.deepEqual(sprite.soundBank.removedSounds, [soundId], 'player removed from the bank'); await restore(); - t.same(sprite.sounds.map(s => s.name), ['sound2', 'sound1'], 'sound restored'); + assert.deepEqual(sprite.sounds.map(s => s.name), ['sound2', 'sound1'], 'sound restored'); const restored = sprite.sounds[1]; - t.type(restored.soundId, 'string', 'restored sound has a player'); - t.ok(sprite.soundBank.soundPlayers[restored.soundId], 'player is in the bank'); - - t.end(); + assert.strictEqual(typeof restored.soundId, 'string', 'restored sound has a player'); + assert.ok(sprite.soundBank.soundPlayers[restored.soundId], 'player is in the bank'); }); -test('reordering sounds does not dispose their players', async t => { +test('reordering sounds does not dispose their players', async () => { const vm = await makeVM(); const target = vm.runtime.getSpriteTargetByName('Sprite1'); const sprite = target.sprite; target.reorderSound(0, 1); - t.same(sprite.sounds.map(s => s.name), ['sound2', 'sound1'], 'sounds reordered'); - t.same(sprite.soundBank.removedSounds, [], 'no players disposed'); - - t.end(); + assert.deepEqual(sprite.sounds.map(s => s.name), ['sound2', 'sound1'], 'sounds reordered'); + assert.deepEqual(sprite.soundBank.removedSounds, [], 'no players disposed'); }); -test('deleting a sprite frees all of its resources, including with clones', async t => { +test('deleting a sprite frees all of its resources, including with clones', async () => { const vm = await makeVM(); const target = vm.runtime.getSpriteTargetByName('Sprite1'); const sprite = target.sprite; vm.runtime.addTarget(target.makeClone()); vm.runtime.addTarget(target.makeClone()); - t.equal(sprite.clones.length, 3, 'sprite has clones'); + assert.strictEqual(sprite.clones.length, 3, 'sprite has clones'); const skinIds = sprite.costumes.map(c => c.skinId); const soundBank = sprite.soundBank; vm.deleteSprite(target.id); - t.ok(vm.runtime.targets.every(t2 => t2.sprite !== sprite), 'all clones are disposed'); + assert.ok(vm.runtime.targets.every(t2 => t2.sprite !== sprite), 'all clones are disposed'); for (const skinId of skinIds) { - t.ok(vm.runtime.renderer.destroyedSkins.includes(skinId), `skin ${skinId} destroyed`); + assert.ok(vm.runtime.renderer.destroyedSkins.includes(skinId), `skin ${skinId} destroyed`); } - t.ok(soundBank.disposed, 'sound bank disposed'); - - t.end(); + assert.ok(soundBank.disposed, 'sound bank disposed'); }); -test('loading a new project frees the resources of the previous one', async t => { +test('loading a new project frees the resources of the previous one', async () => { const vm = await makeVM(); const skinIds = []; for (const target of vm.runtime.targets) { @@ -231,18 +224,16 @@ test('loading a new project frees the resources of the previous one', async t => } } const soundBank = vm.runtime.getSpriteTargetByName('Sprite1').sprite.soundBank; - t.ok(skinIds.length >= 3, 'previous project had skins'); + assert.ok(skinIds.length >= 3, 'previous project had skins'); await vm.loadProject(await makeProjectZip()); for (const skinId of skinIds) { - t.ok(vm.runtime.renderer.destroyedSkins.includes(skinId), `skin ${skinId} destroyed`); + assert.ok(vm.runtime.renderer.destroyedSkins.includes(skinId), `skin ${skinId} destroyed`); } - t.ok(soundBank.disposed, 'sound bank disposed'); - - t.end(); + assert.ok(soundBank.disposed, 'sound bank disposed'); }); -test('restoring a costume that has no md5', async t => { +test('restoring a costume that has no md5', async () => { const vm = await makeVM(); const target = vm.runtime.getSpriteTargetByName('Sprite1'); const sprite = target.sprite; @@ -255,16 +246,14 @@ test('restoring a costume that has no md5', async t => { rotationCenterX: 5, rotationCenterY: 5 }); - t.notOk(sprite.costumes[2].md5, 'costume has no md5'); + assert.ok(!sprite.costumes[2].md5, 'costume has no md5'); const restore = vm.deleteCostume(2); await restore(); - t.same(sprite.costumes.map(c => c.name), ['costume1', 'costume2', 'library'], 'costume restored'); - - t.end(); + assert.deepEqual(sprite.costumes.map(c => c.name), ['costume1', 'costume2', 'library'], 'costume restored'); }); -test('restoring after the sprite is deleted does not leak', async t => { +test('restoring after the sprite is deleted does not leak', async () => { const vm = await makeVM(); const target = vm.runtime.getSpriteTargetByName('Sprite1'); const sprite = target.sprite; @@ -282,16 +271,14 @@ test('restoring after the sprite is deleted does not leak', async t => { await costumePromise; await soundPromise; - t.same(sprite.costumes, [], 'costume not added to deleted sprite'); - t.same(sprite.sounds, [], 'sound not added to deleted sprite'); - t.not(deletedCostume.skinId, oldSkinId, 'restore created a new skin'); - t.ok(vm.runtime.renderer.destroyedSkins.includes(deletedCostume.skinId), 'new skin destroyed'); - t.ok(soundBank.removedSounds.includes(deletedSound.soundId), 'restored player removed from bank'); - - t.end(); + assert.deepEqual(sprite.costumes, [], 'costume not added to deleted sprite'); + assert.deepEqual(sprite.sounds, [], 'sound not added to deleted sprite'); + assert.notStrictEqual(deletedCostume.skinId, oldSkinId, 'restore created a new skin'); + assert.ok(vm.runtime.renderer.destroyedSkins.includes(deletedCostume.skinId), 'new skin destroyed'); + assert.ok(soundBank.removedSounds.includes(deletedSound.soundId), 'restored player removed from bank'); }); -test('deleting the editing sprite while it has clones', async t => { +test('deleting the editing sprite while it has clones', async () => { const vm = await makeVM(); const stage = vm.runtime.getTargetForStage(); const target = vm.runtime.getSpriteTargetByName('Sprite1'); @@ -299,20 +286,16 @@ test('deleting the editing sprite while it has clones', async t => { vm.runtime.addTarget(target.makeClone()); vm.deleteSprite(target.id); - t.equal(vm.editingTarget, stage, 'editing target moved to the stage'); - - t.end(); + assert.strictEqual(vm.editingTarget, stage, 'editing target moved to the stage'); }); -test('deleting a sprite does not modify previously returned costume or sound lists', async t => { +test('deleting a sprite does not modify previously returned costume or sound lists', async () => { const vm = await makeVM(); const target = vm.runtime.getSpriteTargetByName('Sprite1'); const costumes = target.getCostumes(); const sounds = target.getSounds(); vm.deleteSprite(target.id); - t.equal(costumes.length, 2); - t.equal(sounds.length, 2); - - t.end(); + assert.strictEqual(costumes.length, 2); + assert.strictEqual(sounds.length, 2); }); diff --git a/test/unit/tw_extension_api_common.js b/test/unit/tw_extension_api_common.js index cbb1d6bb..1129ce02 100644 --- a/test/unit/tw_extension_api_common.js +++ b/test/unit/tw_extension_api_common.js @@ -1,44 +1,38 @@ const ScratchCommon = require('../../src/extension-support/tw-extension-api-common'); -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); -test('ArgumentType', t => { - t.equal(ScratchCommon.ArgumentType.ANGLE, 'angle'); - t.end(); +test('ArgumentType', () => { + assert.strictEqual(ScratchCommon.ArgumentType.ANGLE, 'angle'); }); -test('BlockType', t => { - t.equal(ScratchCommon.BlockType.BOOLEAN, 'Boolean'); - t.end(); +test('BlockType', () => { + assert.strictEqual(ScratchCommon.BlockType.BOOLEAN, 'Boolean'); }); -test('TargetType', t => { - t.equal(ScratchCommon.TargetType.SPRITE, 'sprite'); - t.end(); +test('TargetType', () => { + assert.strictEqual(ScratchCommon.TargetType.SPRITE, 'sprite'); }); -test('Cast', t => { +test('Cast', () => { // Cast is thoroughly tested elsewhere. We just want to make sure that the public methods // don't get deleted unexpectedly. - t.equal(ScratchCommon.Cast.toNumber('5'), 5); - t.equal(ScratchCommon.Cast.toBoolean('true'), true); - t.equal(ScratchCommon.Cast.toString('something'), 'something'); - t.same(ScratchCommon.Cast.toRgbColorList('#abcdef'), [0xab, 0xcd, 0xef]); - t.same(ScratchCommon.Cast.toRgbColorObject('#abcdef'), {r: 0xab, g: 0xcd, b: 0xef}); - t.equal(ScratchCommon.Cast.isWhiteSpace(''), true); - t.equal(ScratchCommon.Cast.compare(1, 2), -1); - t.equal(ScratchCommon.Cast.isInt(5.5), false); - t.type(ScratchCommon.Cast.LIST_INVALID, 'string'); - t.type(ScratchCommon.Cast.LIST_ALL, 'string'); - t.equal(ScratchCommon.Cast.toListIndex('1.5', 10, false), 1); - t.end(); + assert.strictEqual(ScratchCommon.Cast.toNumber('5'), 5); + assert.strictEqual(ScratchCommon.Cast.toBoolean('true'), true); + assert.strictEqual(ScratchCommon.Cast.toString('something'), 'something'); + assert.deepEqual(ScratchCommon.Cast.toRgbColorList('#abcdef'), [0xab, 0xcd, 0xef]); + assert.deepEqual(ScratchCommon.Cast.toRgbColorObject('#abcdef'), {r: 0xab, g: 0xcd, b: 0xef}); + assert.strictEqual(ScratchCommon.Cast.isWhiteSpace(''), true); + assert.strictEqual(ScratchCommon.Cast.compare(1, 2), -1); + assert.strictEqual(ScratchCommon.Cast.isInt(5.5), false); + assert.strictEqual(typeof ScratchCommon.Cast.LIST_INVALID, 'string'); + assert.strictEqual(typeof ScratchCommon.Cast.LIST_ALL, 'string'); + assert.strictEqual(ScratchCommon.Cast.toListIndex('1.5', 10, false), 1); }); -test('external', t => { +test('external', async () => { // has more tests in separate file, mostly just making sure that external exists at all - ScratchCommon.external.fetch('data:text/plain;,test').then(r => { - r.text().then(text => { - t.equal(text, 'test'); - t.end(); - }); - }); + const r = await ScratchCommon.external.fetch('data:text/plain;,test'); + const text = await r.text(); + assert.strictEqual(text, 'test'); }); diff --git a/test/unit/tw_extension_manager.js b/test/unit/tw_extension_manager.js index c7b18def..3f7b70f5 100644 --- a/test/unit/tw_extension_manager.js +++ b/test/unit/tw_extension_manager.js @@ -1,30 +1,29 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const ExtensionManager = require('../../src/extension-support/extension-manager'); const VM = require('../../src/virtual-machine'); -test('isBuiltinExtension', t => { +test('isBuiltinExtension', () => { const fakeRuntime = {}; const manager = new ExtensionManager(fakeRuntime); - t.equal(manager.isBuiltinExtension('pen'), true); - t.equal(manager.isBuiltinExtension('lksdfjlskdf'), false); - t.end(); + assert.strictEqual(manager.isBuiltinExtension('pen'), true); + assert.strictEqual(manager.isBuiltinExtension('lksdfjlskdf'), false); }); -test('_isValidExtensionURL', t => { +test('_isValidExtensionURL', () => { const fakeRuntime = {}; const manager = new ExtensionManager(fakeRuntime); - t.equal(manager._isValidExtensionURL('fetch'), false); - t.equal(manager._isValidExtensionURL(''), false); - t.equal(manager._isValidExtensionURL('extensions.turbowarp.org/fetch.js'), false); - t.equal(manager._isValidExtensionURL('https://extensions.turbowarp.org/fetch.js'), true); - t.equal(manager._isValidExtensionURL('http://extensions.turbowarp.org/fetch.js'), true); - t.equal(manager._isValidExtensionURL('http://localhost:8000'), true); - t.equal(manager._isValidExtensionURL('data:application/javascript;base64,YWxlcnQoMSk='), true); - t.equal(manager._isValidExtensionURL('file:///home/test/extension.js'), true); - t.end(); + assert.strictEqual(manager._isValidExtensionURL('fetch'), false); + assert.strictEqual(manager._isValidExtensionURL(''), false); + assert.strictEqual(manager._isValidExtensionURL('extensions.turbowarp.org/fetch.js'), false); + assert.strictEqual(manager._isValidExtensionURL('https://extensions.turbowarp.org/fetch.js'), true); + assert.strictEqual(manager._isValidExtensionURL('http://extensions.turbowarp.org/fetch.js'), true); + assert.strictEqual(manager._isValidExtensionURL('http://localhost:8000'), true); + assert.strictEqual(manager._isValidExtensionURL('data:application/javascript;base64,YWxlcnQoMSk='), true); + assert.strictEqual(manager._isValidExtensionURL('file:///home/test/extension.js'), true); }); -test('loadExtensionURL, getExtensionURLs, deduplication', async t => { +test('loadExtensionURL, getExtensionURLs, deduplication', async () => { const vm = new VM(); let loadedExtensions = 0; @@ -48,33 +47,31 @@ test('loadExtensionURL, getExtensionURLs, deduplication', async t => { }; const url1 = 'https://turbowarp.org/1.js'; - t.equal(vm.extensionManager.isExtensionURLLoaded(url1), false); - t.same(vm.extensionManager.getExtensionURLs(), {}); + assert.strictEqual(vm.extensionManager.isExtensionURLLoaded(url1), false); + assert.deepEqual(vm.extensionManager.getExtensionURLs(), {}); await vm.extensionManager.loadExtensionURL(url1); - t.equal(vm.extensionManager.isExtensionURLLoaded(url1), true); - t.equal(loadedExtensions, 1); - t.same(vm.extensionManager.getExtensionURLs(), { + assert.strictEqual(vm.extensionManager.isExtensionURLLoaded(url1), true); + assert.strictEqual(loadedExtensions, 1); + assert.deepEqual(vm.extensionManager.getExtensionURLs(), { extension1: url1 }); // Loading the extension again should do nothing. await vm.extensionManager.loadExtensionURL(url1); - t.equal(vm.extensionManager.isExtensionURLLoaded(url1), true); - t.equal(loadedExtensions, 1); - t.same(vm.extensionManager.getExtensionURLs(), { + assert.strictEqual(vm.extensionManager.isExtensionURLLoaded(url1), true); + assert.strictEqual(loadedExtensions, 1); + assert.deepEqual(vm.extensionManager.getExtensionURLs(), { extension1: url1 }); // Loading another extension should work const url2 = 'https://turbowarp.org/2.js'; - t.equal(vm.extensionManager.isExtensionURLLoaded(url2), false); + assert.strictEqual(vm.extensionManager.isExtensionURLLoaded(url2), false); await vm.extensionManager.loadExtensionURL(url2); - t.equal(vm.extensionManager.isExtensionURLLoaded(url2), true); - t.equal(loadedExtensions, 2); - t.same(vm.extensionManager.getExtensionURLs(), { + assert.strictEqual(vm.extensionManager.isExtensionURLLoaded(url2), true); + assert.strictEqual(loadedExtensions, 2); + assert.deepEqual(vm.extensionManager.getExtensionURLs(), { extension1: url1, extension2: url2 }); - - t.end(); }); diff --git a/test/unit/tw_extension_monitors.js b/test/unit/tw_extension_monitors.js index 577305a0..0173b3e3 100644 --- a/test/unit/tw_extension_monitors.js +++ b/test/unit/tw_extension_monitors.js @@ -1,9 +1,10 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const Runtime = require('../../src/engine/runtime'); const BlockType = require('../../src/extension-support/block-type'); const ArgumentType = require('../../src/extension-support/argument-type'); -test('Boolean blocks can be monitors', t => { +test('Boolean blocks can be monitors', () => { const rt = new Runtime(); rt._registerExtensionPrimitives({ id: 'testextension', @@ -52,12 +53,11 @@ test('Boolean blocks can be monitors', t => { }); const json = rt.getBlocksJSON(); - t.equal(json.length, 6); - t.equal(json[0].checkboxInFlyout, true); - t.equal(json[1].checkboxInFlyout, undefined); - t.equal(json[2].checkboxInFlyout, undefined); - t.equal(json[3].checkboxInFlyout, true); - t.equal(json[4].checkboxInFlyout, undefined); - t.equal(json[5].checkboxInFlyout, undefined); - t.end(); + assert.strictEqual(json.length, 6); + assert.strictEqual(json[0].checkboxInFlyout, true); + assert.strictEqual(json[1].checkboxInFlyout, undefined); + assert.strictEqual(json[2].checkboxInFlyout, undefined); + assert.strictEqual(json[3].checkboxInFlyout, true); + assert.strictEqual(json[4].checkboxInFlyout, undefined); + assert.strictEqual(json[5].checkboxInFlyout, undefined); }); diff --git a/test/unit/tw_extension_music.js b/test/unit/tw_extension_music.js index 2d5e1fae..0d41d326 100644 --- a/test/unit/tw_extension_music.js +++ b/test/unit/tw_extension_music.js @@ -1,27 +1,26 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const Music = require('../../src/extensions/scratch3_music/index.js'); const Runtime = require('../../src/engine/runtime.js'); -test('_isConcurrencyLimited', t => { +test('_isConcurrencyLimited', () => { const rt = new Runtime(); // sanity check so that the setRuntimeOptions() call below actually does something - t.equal(rt.runtimeOptions.miscLimits, true, 'misc limits enabled by default'); + assert.strictEqual(rt.runtimeOptions.miscLimits, true, 'misc limits enabled by default'); const blocks = new Music(rt); - t.equal(blocks._isConcurrencyLimited(), false, 'not limited initially'); + assert.strictEqual(blocks._isConcurrencyLimited(), false, 'not limited initially'); // logic here is slightly weird but this matches Scratch blocks._concurrencyCounter = Music.CONCURRENCY_LIMIT; - t.equal(blocks._isConcurrencyLimited(), false, 'not limited at limit'); + assert.strictEqual(blocks._isConcurrencyLimited(), false, 'not limited at limit'); blocks._concurrencyCounter = Music.CONCURRENCY_LIMIT + 1; - t.equal(blocks._isConcurrencyLimited(), true, 'limited above limit'); + assert.strictEqual(blocks._isConcurrencyLimited(), true, 'limited above limit'); rt.setRuntimeOptions({ miscLimits: false }); - t.equal(blocks._isConcurrencyLimited(), false, 'not limited when miscLimits: false'); - - t.end(); + assert.strictEqual(blocks._isConcurrencyLimited(), false, 'not limited when miscLimits: false'); }); diff --git a/test/unit/tw_external.js b/test/unit/tw_external.js index 2110412d..70154b09 100644 --- a/test/unit/tw_external.js +++ b/test/unit/tw_external.js @@ -1,23 +1,19 @@ const external = require('../../src/extension-support/tw-external'); -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); -test('importModule', t => { - external.importModule('data:text/javascript;,export%20default%201').then(mod => { - t.equal(mod.default, 1); - t.end(); - }); +test('importModule', async () => { + const mod = await external.importModule('data:text/javascript;,export%20default%201'); + assert.strictEqual(mod.default, 1); }); -test('fetch', t => { - external.fetch('data:text/plain;,test').then(res => { - res.text().then(text => { - t.equal(text, 'test'); - t.end(); - }); - }); +test('fetch', async () => { + const res = await external.fetch('data:text/plain;,test'); + const text = await res.text(); + assert.strictEqual(text, 'test'); }); -test('dataURL', t => { +test('dataURL', async () => { global.FileReader = class { readAsDataURL (blob) { blob.arrayBuffer().then(arrayBuffer => { @@ -28,38 +24,29 @@ test('dataURL', t => { } }; - external.dataURL('data:text/plain;,doesthiswork').then(dataURL => { - t.equal(dataURL, `data:text/plain;base64,${btoa('doesthiswork')}`); - t.end(); - }); + const dataURL = await external.dataURL('data:text/plain;,doesthiswork'); + assert.strictEqual(dataURL, `data:text/plain;base64,${btoa('doesthiswork')}`); }); -test('blob', t => { - external.blob('data:text/plain;,test').then(blob => { - blob.text().then(blobText => { - t.equal(blobText, 'test'); - t.end(); - }); - }); +test('blob', async () => { + const blob = await external.blob('data:text/plain;,test'); + const blobText = await blob.text(); + assert.strictEqual(blobText, 'test'); }); -test('evalAndReturn', t => { - external.evalAndReturn('data:text/plain;,var%20x=20', 'x').then(result => { - t.equal(result, 20); - t.end(); - }); +test('evalAndReturn', async () => { + const result = await external.evalAndReturn('data:text/plain;,var%20x=20', 'x'); + assert.strictEqual(result, 20); }); -test('evalAndReturn with a trailing comment without newline', t => { - external.evalAndReturn('data:text/plain;,var%20x=20 // whatever', 'x').then(result => { - t.equal(result, 20); - t.end(); - }); +test('evalAndReturn with a trailing comment without newline', async () => { + const result = await external.evalAndReturn('data:text/plain;,var%20x=20 // whatever', 'x'); + assert.strictEqual(result, 20); }); -test('relative URL throws', t => { +test('relative URL throws', (t, done) => { external.fetch('./test.js').catch(err => { - t.equal(err.message, `Unsupported URL: ./test.js`); - t.end(); + assert.strictEqual(err.message, `Unsupported URL: ./test.js`); + done(); }); }); diff --git a/test/unit/tw_jsexecute.js b/test/unit/tw_jsexecute.js index 4eaf9c06..0a4b9b1c 100644 --- a/test/unit/tw_jsexecute.js +++ b/test/unit/tw_jsexecute.js @@ -1,22 +1,21 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const jsexecute = require('../../src/compiler/jsexecute'); const Cast = require('../../src/util/cast'); const {stringify} = require('@turbowarp/json'); const evaluateRuntimeFunction = functionName => jsexecute.scopedEval(functionName); -test('runtimeFunctions are valid', t => { +test('runtimeFunctions are valid', () => { for (const functionName of Object.keys(jsexecute.runtimeFunctions)) { const fn = evaluateRuntimeFunction(functionName); - t.type(fn, 'function', `${functionName} is function`); + assert.strictEqual(typeof fn, 'function', `${functionName} is function`); } - t.end(); }); -test('all runtimeFunctions can be used together', t => { +test('all runtimeFunctions can be used together', () => { const script = Object.keys(jsexecute.runtimeFunctions).join(';'); jsexecute.scopedEval(script); - t.end(); }); const VALUES = [ @@ -55,30 +54,29 @@ const VALUES = [ 'äpfel' ]; -test('comparison functions are equivalent to Cast.compare', t => { +test('comparison functions are equivalent to Cast.compare', () => { const compareEqual = evaluateRuntimeFunction('compareEqual'); const compareGreaterThan = evaluateRuntimeFunction('compareGreaterThan'); const compareLessThan = evaluateRuntimeFunction('compareLessThan'); for (const a of VALUES) { for (const b of VALUES) { - // Because there are so many tests, calling t.ok() each time is actually quite slow, - // so only call into tap when something failed. + // Because there are so many tests, asserting each comparison is actually quite slow, + // so only call into assert when something failed. const cast = Cast.compare(a, b); if (compareEqual(a, b) !== (cast === 0)) { - t.fail(`${stringify(a)} should be === ${stringify(b)}`); + assert.fail(`${stringify(a)} should be === ${stringify(b)}`); } if (compareGreaterThan(a, b) !== (cast > 0)) { - t.fail(`${stringify(a)} should be > ${stringify(b)}`); + assert.fail(`${stringify(a)} should be > ${stringify(b)}`); } if (compareLessThan(a, b) !== (cast < 0)) { - t.fail(`${stringify(a)} should be < ${stringify(b)}`); + assert.fail(`${stringify(a)} should be < ${stringify(b)}`); } } } - t.end(); }); -test('list search functions are equivalent to Cast.compare', t => { +test('list search functions are equivalent to Cast.compare', () => { const listFind = evaluateRuntimeFunction('listFind'); const listContains = evaluateRuntimeFunction('listContains'); for (const item of VALUES) { @@ -93,17 +91,18 @@ test('list search functions are equivalent to Cast.compare', t => { const expected = list.findIndex(v => Cast.compare(v, item) === 0) + 1; const actualIndex = listFind(list, item) + 1; if (actualIndex !== expected) { - t.fail(`index of ${stringify(item)} in ${stringify(list)} should be ${expected}, got ${actualIndex}`); + assert.fail( + `index of ${stringify(item)} in ${stringify(list)} should be ${expected}, got ${actualIndex}` + ); } if (listContains({value: list}, item) !== (expected !== 0)) { - t.fail(`${stringify(list)} should ${expected ? '' : 'not '}contain ${stringify(item)}`); + assert.fail(`${stringify(list)} should ${expected ? '' : 'not '}contain ${stringify(item)}`); } } } - t.end(); }); -test('listGet is equivalent to listIndexSlow', t => { +test('listGet is equivalent to listIndexSlow', () => { const listGet = evaluateRuntimeFunction('listGet'); const listIndexSlow = evaluateRuntimeFunction('listIndexSlow'); const list = ['a', 'b', 'c', 4, 5]; @@ -113,13 +112,12 @@ test('listGet is equivalent to listIndexSlow', t => { const expected = expectedIndex === -1 ? '' : list[expectedIndex]; const actual = listGet(list, index); if (actual !== expected) { - t.fail(`item ${stringify(index)} should be ${stringify(expected)}, got ${stringify(actual)}`); + assert.fail(`item ${stringify(index)} should be ${stringify(expected)}, got ${stringify(actual)}`); } } - t.end(); }); -test('listReplace is equivalent to listIndexSlow', t => { +test('listReplace is equivalent to listIndexSlow', () => { const listReplace = evaluateRuntimeFunction('listReplace'); const listIndexSlow = evaluateRuntimeFunction('listIndexSlow'); const INDEXES = [...VALUES, 1, 2, 3.7, 5, 6, -1, -0.5, 2 ** 31, (2 ** 32) + 1, -(2 ** 32) + 2, 'last', '3', ' 2 ']; @@ -132,11 +130,12 @@ test('listReplace is equivalent to listIndexSlow', t => { } listReplace(list, index, 'new'); if (stringify(list.value) !== stringify(expected)) { - t.fail(`replacing ${stringify(index)} should give ${stringify(expected)}, got ${stringify(list.value)}`); + assert.fail( + `replacing ${stringify(index)} should give ${stringify(expected)}, got ${stringify(list.value)}` + ); } if (list._monitorUpToDate !== (expectedIndex === -1)) { - t.fail(`replacing ${stringify(index)} should ${expectedIndex === -1 ? 'not ' : ''}update monitor`); + assert.fail(`replacing ${stringify(index)} should ${expectedIndex === -1 ? 'not ' : ''}update monitor`); } } - t.end(); }); diff --git a/test/unit/tw_monitor_record.js b/test/unit/tw_monitor_record.js index 614d16c8..4ac337b2 100644 --- a/test/unit/tw_monitor_record.js +++ b/test/unit/tw_monitor_record.js @@ -1,60 +1,55 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const MonitorRecord = require('../../src/engine/monitor-record'); -test('new and get', t => { +test('new and get', () => { const record = new MonitorRecord({ id: 'a', x: 10, y: 20 }); - t.equal(record.id, 'a'); - t.equal(record.x, 10); - t.equal(record.y, 20); + assert.strictEqual(record.id, 'a'); + assert.strictEqual(record.x, 10); + assert.strictEqual(record.y, 20); - t.equal(record.get('id'), 'a'); - t.equal(record.get('x'), 10); - t.equal(record.get('y'), 20); - - t.end(); + assert.strictEqual(record.get('id'), 'a'); + assert.strictEqual(record.get('x'), 10); + assert.strictEqual(record.get('y'), 20); }); -test('merge', t => { +test('merge', () => { const record = new MonitorRecord({ id: 'a', x: 10, y: 20 }); - t.equal(record.merge({ + assert.strictEqual(record.merge({ x: 40, y: null }), true); - t.equal(record.x, 40); - t.equal(record.y, 20); + assert.strictEqual(record.x, 40); + assert.strictEqual(record.y, 20); - t.equal(record.merge({ + assert.strictEqual(record.merge({ x: 40, y: undefined }), false); - t.equal(record.x, 40); - t.equal(record.y, 20); - - t.end(); + assert.strictEqual(record.x, 40); + assert.strictEqual(record.y, 20); }); -test('externalDeltaToJS', t => { - t.same(MonitorRecord.externalDeltaToJS({ +test('externalDeltaToJS', () => { + assert.deepEqual(MonitorRecord.externalDeltaToJS({ whatever: 'a' }), {whatever: 'a'}); - t.same(MonitorRecord.externalDeltaToJS({ + assert.deepEqual(MonitorRecord.externalDeltaToJS({ toJS: () => ({whatever: 'a'}) }), {whatever: 'a'}); - t.same(MonitorRecord.externalDeltaToJS( + assert.deepEqual(MonitorRecord.externalDeltaToJS( new Map([['whatever', 'a']]) ), {whatever: 'a'}); - - t.end(); }); diff --git a/test/unit/tw_monitor_state.js b/test/unit/tw_monitor_state.js index 780edb6b..86ffa164 100644 --- a/test/unit/tw_monitor_state.js +++ b/test/unit/tw_monitor_state.js @@ -1,57 +1,56 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const MonitorState = require('../../src/engine/tw-monitor-state'); const MonitorRecord = require('../../src/engine/monitor-record'); -test('basic operation', t => { +test('basic operation', () => { const state = new MonitorState(); - t.equal(state.dirty, false); - t.equal(state.has('id'), false); - t.equal(state.size, 0); - t.equal(state.empty(), true); + assert.strictEqual(state.dirty, false); + assert.strictEqual(state.has('id'), false); + assert.strictEqual(state.size, 0); + assert.strictEqual(state.empty(), true); state.set('id', new MonitorRecord({ id: 'id', value: 0 })); - t.equal(state.has('id'), true); - t.equal(state.get('id').id, 'id'); - t.equal(state.get('id').value, 0); - t.equal(state.size, 1); - t.equal(state.empty(), false); - t.equal(state.dirty, true); + assert.strictEqual(state.has('id'), true); + assert.strictEqual(state.get('id').id, 'id'); + assert.strictEqual(state.get('id').value, 0); + assert.strictEqual(state.size, 1); + assert.strictEqual(state.empty(), false); + assert.strictEqual(state.dirty, true); state.dirty = false; state.set('id', new MonitorRecord({ id: 'id', value: -0 })); - t.equal(state.get('id').value, -0); - t.equal(state.dirty, true); + assert.strictEqual(state.get('id').value, -0); + assert.strictEqual(state.dirty, true); state.dirty = false; state.set('id', new MonitorRecord({ id: 'id', value: -0 })); - t.equal(state.dirty, false); + assert.strictEqual(state.dirty, false); state.dirty = false; state.delete('id'); - t.equal(state.has('id'), false); - t.equal(state.get('id'), undefined); - t.equal(state.size, 0); - t.equal(state.empty(), true); - t.equal(state.dirty, true); + assert.strictEqual(state.has('id'), false); + assert.strictEqual(state.get('id'), undefined); + assert.strictEqual(state.size, 0); + assert.strictEqual(state.empty(), true); + assert.strictEqual(state.dirty, true); state.dirty = false; state.delete('id'); - t.equal(state.dirty, false); - - t.end(); + assert.strictEqual(state.dirty, false); }); -test('filter', t => { +test('filter', () => { const state = new MonitorState(); state.set('id1', new MonitorRecord({ @@ -69,19 +68,17 @@ test('filter', t => { state.dirty = false; state.filter(record => record.value !== 10); - t.equal(state.dirty, true); - t.equal(state.has('id1'), true); - t.equal(state.has('id2'), false); - t.equal(state.has('id3'), true); + assert.strictEqual(state.dirty, true); + assert.strictEqual(state.has('id1'), true); + assert.strictEqual(state.has('id2'), false); + assert.strictEqual(state.has('id3'), true); state.dirty = false; state.filter(record => record.value !== 10); - t.equal(state.dirty, false); - - t.end(); + assert.strictEqual(state.dirty, false); }); -test('value', t => { +test('value', () => { const state = new MonitorState(); const a = new MonitorRecord({ @@ -93,13 +90,11 @@ test('value', t => { state.set('a', a); state.set('b', b); - t.same(state.values(), [a, b]); - t.same(state.valueSeq(), [a, b]); - - t.end(); + assert.deepEqual(state.values(), [a, b]); + assert.deepEqual(state.valueSeq(), [a, b]); }); -test('shallowClone', t => { +test('shallowClone', () => { const state = new MonitorState(); state.set('id', new MonitorRecord({ @@ -107,9 +102,7 @@ test('shallowClone', t => { })); const clone = state.shallowClone(); - t.not(state, clone); - t.equal(state.map, clone.map); - t.equal(clone.dirty, false); - - t.end(); + assert.notStrictEqual(state, clone); + assert.strictEqual(state.map, clone.map); + assert.strictEqual(clone.dirty, false); }); diff --git a/test/unit/tw_mouse.js b/test/unit/tw_mouse.js index 17aeb200..a9ceaaad 100644 --- a/test/unit/tw_mouse.js +++ b/test/unit/tw_mouse.js @@ -1,7 +1,7 @@ -const {test} = require('tap'); +const {test} = require('node:test'); const Runtime = require('../../src/engine/runtime'); -test('isDown does not error before project loads', t => { +test('isDown does not error before project loads', () => { const rt = new Runtime(); rt.ioDevices.mouse.postData({ isDown: true, @@ -10,5 +10,4 @@ test('isDown does not error before project loads', t => { canvasWidth: 100, canvasHeight: 100 }); - t.end(); }); diff --git a/test/unit/tw_number_argument.js b/test/unit/tw_number_argument.js index d8acebd8..f72e559a 100644 --- a/test/unit/tw_number_argument.js +++ b/test/unit/tw_number_argument.js @@ -1,30 +1,31 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const Runtime = require('../../src/engine/runtime'); const BlockType = require('../../src/extension-support/block-type'); const ArgumentType = require('../../src/extension-support/argument-type'); -test('NUMBER argument defaultValue', t => { +test('NUMBER argument defaultValue', (t, done) => { const runtime = new Runtime(); runtime.on(Runtime.EXTENSION_ADDED, categoryInfo => { /* eslint-disable max-len */ - t.equal( + assert.strictEqual( categoryInfo.blocks[0].xml, '' ); - t.equal( + assert.strictEqual( categoryInfo.blocks[1].xml, '' ); - t.equal( + assert.strictEqual( categoryInfo.blocks[2].xml, '0' ); - t.equal( + assert.strictEqual( categoryInfo.blocks[3].xml, '0' ); /* eslint-enable max-len */ - t.end(); + done(); }); runtime._registerExtensionPrimitives({ id: 'testextension', diff --git a/test/unit/tw_performance_measure_error.js b/test/unit/tw_performance_measure_error.js index 5995e8c0..61ab8f6a 100644 --- a/test/unit/tw_performance_measure_error.js +++ b/test/unit/tw_performance_measure_error.js @@ -1,4 +1,4 @@ -const test = require('tap').test; +const {test} = require('node:test'); const fs = require('fs'); const path = require('path'); const VirtualMachine = require('../../src/virtual-machine'); @@ -12,8 +12,7 @@ global.performance = { } }; -test('performance.measure() error in loadProject is ignored', async t => { +test('performance.measure() error in loadProject is ignored', async () => { const vm = new VirtualMachine(); await vm.loadProject(fs.readFileSync(path.join(__dirname, '..', 'fixtures', 'tw-empty-project.sb3'))); - t.end(); }); diff --git a/test/unit/tw_safe_stringify.js b/test/unit/tw_safe_stringify.js index 8307d6ea..a47a740b 100644 --- a/test/unit/tw_safe_stringify.js +++ b/test/unit/tw_safe_stringify.js @@ -1,32 +1,31 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const safeStringify = require('../../src/util/tw-safe-stringify'); -test('safeStringify', t => { - t.equal(safeStringify(''), ''); - t.equal(safeStringify('a'), 'a'); +test('safeStringify', () => { + assert.strictEqual(safeStringify(''), ''); + assert.strictEqual(safeStringify('a'), 'a'); - t.equal(safeStringify(true), 'true'); - t.equal(safeStringify(false), 'false'); + assert.strictEqual(safeStringify(true), 'true'); + assert.strictEqual(safeStringify(false), 'false'); - t.equal(safeStringify(0), '0'); - t.equal(safeStringify(-0), '-0'); - t.equal(safeStringify(1), '1'); - t.equal(safeStringify(Infinity), 'Infinity'); - t.equal(safeStringify(-Infinity), '-Infinity'); - t.equal(safeStringify(NaN), 'NaN'); + assert.strictEqual(safeStringify(0), '0'); + assert.strictEqual(safeStringify(-0), '-0'); + assert.strictEqual(safeStringify(1), '1'); + assert.strictEqual(safeStringify(Infinity), 'Infinity'); + assert.strictEqual(safeStringify(-Infinity), '-Infinity'); + assert.strictEqual(safeStringify(NaN), 'NaN'); - t.equal(safeStringify(null), 'null'); - t.equal(safeStringify(undefined), 'undefined'); + assert.strictEqual(safeStringify(null), 'null'); + assert.strictEqual(safeStringify(undefined), 'undefined'); - t.equal(safeStringify({}), '{}'); - t.equal(safeStringify({a: 'b'}), '{"a":"b"}'); + assert.strictEqual(safeStringify({}), '{}'); + assert.strictEqual(safeStringify({a: 'b'}), '{"a":"b"}'); - t.equal(safeStringify([]), '[]'); - t.equal(safeStringify([1, 2, 3]), '[1,2,3]'); + assert.strictEqual(safeStringify([]), '[]'); + assert.strictEqual(safeStringify([1, 2, 3]), '[1,2,3]'); const circular = {}; circular.circular = circular; - t.equal(safeStringify(circular), '{"circular":"{...}"}'); - - t.end(); + assert.strictEqual(safeStringify(circular), '{"circular":"{...}"}'); }); diff --git a/test/unit/tw_sandboxed_extensions.js b/test/unit/tw_sandboxed_extensions.js index 86630ec3..439a2e5c 100644 --- a/test/unit/tw_sandboxed_extensions.js +++ b/test/unit/tw_sandboxed_extensions.js @@ -1,4 +1,5 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); global.Request = class { constructor (url) { @@ -18,60 +19,58 @@ global.self = {}; // This will install extension worker APIs onto `global` require('../../src/extension-support/extension-worker'); -test('basic API', t => { - t.type(global.Scratch.extensions.register, 'function'); - t.equal(global.Scratch.ArgumentType.BOOLEAN, 'Boolean'); - t.equal(global.Scratch.BlockType.REPORTER, 'reporter'); - t.end(); +test('basic API', () => { + assert.strictEqual(typeof global.Scratch.extensions.register, 'function'); + assert.strictEqual(global.Scratch.ArgumentType.BOOLEAN, 'Boolean'); + assert.strictEqual(global.Scratch.BlockType.REPORTER, 'reporter'); }); -test('not unsandboxed', t => { - t.not(global.Scratch.extensions.unsandboxed, true); - t.end(); +test('not unsandboxed', () => { + assert.notStrictEqual(global.Scratch.extensions.unsandboxed, true); }); -test('Cast', t => { +test('Cast', () => { // Cast is thoroughly tested elsewhere - t.equal(global.Scratch.Cast.toString(5), '5'); - t.equal(global.Scratch.Cast.toNumber(' 5'), 5); - t.equal(global.Scratch.Cast.toBoolean('true'), true); - t.end(); + assert.strictEqual(global.Scratch.Cast.toString(5), '5'); + assert.strictEqual(global.Scratch.Cast.toNumber(' 5'), 5); + assert.strictEqual(global.Scratch.Cast.toBoolean('true'), true); }); -test('fetch', async t => { - t.equal(await global.Scratch.canFetch('https://untrusted.example/'), true); - t.equal(await global.Scratch.fetch('https://untrusted.example/'), '[Response https://untrusted.example/ options={}]'); - t.equal(await global.Scratch.fetch('https://untrusted.example/', { +test('fetch', async () => { + assert.strictEqual(await global.Scratch.canFetch('https://untrusted.example/'), true); + assert.strictEqual(await global.Scratch.fetch('https://untrusted.example/'), '[Response https://untrusted.example/ options={}]'); + assert.strictEqual(await global.Scratch.fetch('https://untrusted.example/', { method: 'POST' }), `[Response https://untrusted.example/ options={"method":"POST"}]`); - t.end(); }); -test('openWindow', async t => { - t.equal(await global.Scratch.canOpenWindow('https://example.com/'), false); - await t.rejects(global.Scratch.openWindow('https://example.com/'), /^Scratch\.openWindow not supported in sandboxed extensions$/); - t.end(); +test('openWindow', async () => { + assert.strictEqual(await global.Scratch.canOpenWindow('https://example.com/'), false); + await assert.rejects(global.Scratch.openWindow('https://example.com/'), { + message: /^Scratch\.openWindow not supported in sandboxed extensions$/ + }); }); -test('redirect', async t => { - t.equal(await global.Scratch.canRedirect('https://example.com/'), false); - await t.rejects(global.Scratch.redirect('https://example.com/'), /^Scratch\.redirect not supported in sandboxed extensions$/); - t.end(); +test('redirect', async () => { + assert.strictEqual(await global.Scratch.canRedirect('https://example.com/'), false); + await assert.rejects(global.Scratch.redirect('https://example.com/'), { + message: /^Scratch\.redirect not supported in sandboxed extensions$/ + }); }); -test('translate', t => { - t.equal(global.Scratch.translate({ +test('translate', () => { + assert.strictEqual(global.Scratch.translate({ id: 'test1', default: 'Message 1: {var}', description: 'Description' }, { var: 'test' }), 'Message 1: test'); - t.equal(global.Scratch.translate('test1'), 'test1'); - t.equal(global.Scratch.translate('test1 {VAR}', { + assert.strictEqual(global.Scratch.translate('test1'), 'test1'); + assert.strictEqual(global.Scratch.translate('test1 {VAR}', { VAR: '3' }), 'test1 3'); - t.equal(global.Scratch.translate.language, 'en'); + assert.strictEqual(global.Scratch.translate.language, 'en'); const messages = { en: { @@ -84,14 +83,14 @@ test('translate', t => { // Should default to English when no navigator object global.Scratch.translate.setup(messages); - t.equal(global.Scratch.translate({ + assert.strictEqual(global.Scratch.translate({ id: 'test1', default: 'Message 1', description: 'Description' }, { var: 'ok' }), 'EN Message 1: ok'); - t.equal(global.Scratch.translate.language, 'en'); + assert.strictEqual(global.Scratch.translate.language, 'en'); // But if there is a navigator object, it should use its language. global.navigator = { @@ -100,54 +99,44 @@ test('translate', t => { // Note that real extensions will only generally call setup() once, but we need to do this // again so that it realizes the language changed. global.Scratch.translate.setup(messages); - t.equal(global.Scratch.translate({ + assert.strictEqual(global.Scratch.translate({ id: 'test1', default: 'Message 1', description: 'Description' }, { var: 'ok' }), 'ES Message 1: ok'); - t.equal(global.Scratch.translate.language, 'es'); - - t.end(); + assert.strictEqual(global.Scratch.translate.language, 'es'); }); -test('canRecordAudio', async t => { - t.equal(await global.Scratch.canRecordAudio(), false); - t.end(); +test('canRecordAudio', async () => { + assert.strictEqual(await global.Scratch.canRecordAudio(), false); }); -test('canRecordVideo', async t => { - t.equal(await global.Scratch.canRecordVideo(), false); - t.end(); +test('canRecordVideo', async () => { + assert.strictEqual(await global.Scratch.canRecordVideo(), false); }); -test('canReadClipboard', async t => { - t.equal(await global.Scratch.canReadClipboard(), false); - t.end(); +test('canReadClipboard', async () => { + assert.strictEqual(await global.Scratch.canReadClipboard(), false); }); -test('canNotify', async t => { - t.equal(await global.Scratch.canNotify(), false); - t.end(); +test('canNotify', async () => { + assert.strictEqual(await global.Scratch.canNotify(), false); }); -test('canGeolocate', async t => { - t.equal(await global.Scratch.canGeolocate(), false); - t.end(); +test('canGeolocate', async () => { + assert.strictEqual(await global.Scratch.canGeolocate(), false); }); -test('canEmbed', async t => { - t.equal(await global.Scratch.canEmbed('https://example.com/'), false); - t.end(); +test('canEmbed', async () => { + assert.strictEqual(await global.Scratch.canEmbed('https://example.com/'), false); }); -test('canDownload', async t => { - t.equal(await global.Scratch.canDownload('https://example.com/test.sb3', 'test.sb3'), false); - t.end(); +test('canDownload', async () => { + assert.strictEqual(await global.Scratch.canDownload('https://example.com/test.sb3', 'test.sb3'), false); }); -test('download', async t => { - await t.rejects(global.Scratch.download('https://turbowarp.org/', 'index.html'), /not supported in sandboxed extension/); - t.end(); +test('download', async () => { + await assert.rejects(global.Scratch.download('https://turbowarp.org/', 'index.html'), /not supported in sandboxed extension/); }); diff --git a/test/unit/tw_scratchx.js b/test/unit/tw_scratchx.js index 9619919b..7dc81923 100644 --- a/test/unit/tw_scratchx.js +++ b/test/unit/tw_scratchx.js @@ -1,22 +1,21 @@ const ScratchXUtilities = require('../../src/extension-support/tw-scratchx-utilities'); const createScratchX = require('../../src/extension-support/tw-scratchx-compatibility-layer'); -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); -test('argument index to id', t => { - t.equal(ScratchXUtilities.argumentIndexToId(0), '0'); - t.equal(ScratchXUtilities.argumentIndexToId(1), '1'); - t.equal(ScratchXUtilities.argumentIndexToId(2), '2'); - t.equal(ScratchXUtilities.argumentIndexToId(3), '3'); - t.equal(ScratchXUtilities.argumentIndexToId(39), '39'); - t.equal(ScratchXUtilities.argumentIndexToId(1000000000), '1000000000'); - t.end(); +test('argument index to id', () => { + assert.strictEqual(ScratchXUtilities.argumentIndexToId(0), '0'); + assert.strictEqual(ScratchXUtilities.argumentIndexToId(1), '1'); + assert.strictEqual(ScratchXUtilities.argumentIndexToId(2), '2'); + assert.strictEqual(ScratchXUtilities.argumentIndexToId(3), '3'); + assert.strictEqual(ScratchXUtilities.argumentIndexToId(39), '39'); + assert.strictEqual(ScratchXUtilities.argumentIndexToId(1000000000), '1000000000'); }); -test('generate extension id', t => { - t.equal(ScratchXUtilities.generateExtensionId('Spotify'), 'sbxspotify'); - t.equal(ScratchXUtilities.generateExtensionId('Spo _t ify'), 'sbxspotify'); - t.equal(ScratchXUtilities.generateExtensionId('Spo _t $#@! 3ify😮'), 'sbxspot3ify'); - t.end(); +test('generate extension id', () => { + assert.strictEqual(ScratchXUtilities.generateExtensionId('Spotify'), 'sbxspotify'); + assert.strictEqual(ScratchXUtilities.generateExtensionId('Spo _t ify'), 'sbxspotify'); + assert.strictEqual(ScratchXUtilities.generateExtensionId('Spo _t $#@! 3ify😮'), 'sbxspot3ify'); }); const mockScratchExtensions = () => { @@ -45,13 +44,12 @@ const convert = (...args) => { return registered; }; -test('register', t => { +test('register', () => { const ScratchExtensions = mockScratchExtensions(); - t.type(ScratchExtensions.register, 'function'); - t.end(); + assert.strictEqual(typeof ScratchExtensions.register, 'function'); }); -test('complex extension', async t => { +test('complex extension', async () => { let stepsMoved = 0; const moveSteps = n => { stepsMoved += n; @@ -107,10 +105,10 @@ test('complex extension', async t => { ); const info = converted.getInfo(); - t.equal(info.id, 'sbxmyextension'); - t.equal(info.docsURI, 'https://turbowarp.org/myextensiondocs.html'); + assert.strictEqual(info.id, 'sbxmyextension'); + assert.strictEqual(info.docsURI, 'https://turbowarp.org/myextensiondocs.html'); - t.same(info.blocks, [ + assert.deepEqual(info.blocks, [ { opcode: 'moveSteps', text: 'move [0] steps', @@ -192,7 +190,7 @@ test('complex extension', async t => { } ]); - t.same(info.menus, { + assert.deepEqual(info.menus, { myMenu: { items: ['abc', 'def', 123, true, false] }, @@ -202,55 +200,53 @@ test('complex extension', async t => { }); // Now let's make sure that the converter has properly wrapped our functions. - t.equal(stepsMoved, 0); - t.equal(converted.moveSteps({ + assert.strictEqual(stepsMoved, 0); + assert.strictEqual(converted.moveSteps({ 0: 30 }), undefined); - t.equal(stepsMoved, 30); + assert.strictEqual(stepsMoved, 30); - t.equal(doNothingCalled, false); - t.equal(converted.doNothing({}), undefined); - t.equal(doNothingCalled, true); + assert.strictEqual(doNothingCalled, false); + assert.strictEqual(converted.doNothing({}), undefined); + assert.strictEqual(doNothingCalled, true); - t.type(converted.fetch({ + assert.strictEqual(typeof converted.fetch({ 0: 'https://example.com/' }).then, 'function'); - t.equal(await converted.fetch({ + assert.strictEqual(await converted.fetch({ 0: 'https://example.com/' }), 'Fetched: https://example.com/'); - t.equal(converted.multiplyAndAppend({ + assert.strictEqual(converted.multiplyAndAppend({ 0: 31, 1: 7, 2: 'Cat' }), '217Cat'); - t.type(converted.repeat({ + assert.strictEqual(typeof converted.repeat({ 0: '', 1: 0 }).then, 'function'); - t.equal(await converted.repeat({ + assert.strictEqual(await converted.repeat({ 0: 'scratchx', 1: 3 }), 'scratchxscratchxscratchx'); - t.equal(converted.touching({ + assert.strictEqual(converted.touching({ 0: 'Sprite1', 1: true }), false); - t.equal(converted.touching({ + assert.strictEqual(converted.touching({ 0: 'Sprite9', 1: true }), true); - t.equal(converted.touching({ + assert.strictEqual(converted.touching({ 0: 'Sprite9', 1: false }), false); - - t.end(); }); -test('display name', t => { +test('display name', () => { const converted = convert( 'Internal Name', { @@ -261,11 +257,10 @@ test('display name', t => { } ); - t.equal(converted.getInfo().name, 'Display Name'); - t.end(); + assert.strictEqual(converted.getInfo().name, 'Display Name'); }); -test('_getStatus', t => { +test('_getStatus', () => { const _getStatus = () => ({ status: 2, msg: 'Ready' @@ -280,7 +275,6 @@ test('_getStatus', t => { unusedProperty: 10 } ); - t.equal(converted._getStatus, _getStatus); - t.equal('unusedProperty' in converted, false); - t.end(); + assert.strictEqual(converted._getStatus, _getStatus); + assert.strictEqual('unusedProperty' in converted, false); }); diff --git a/test/unit/tw_static_fetch.js b/test/unit/tw_static_fetch.js index 51df28c4..70783c2d 100644 --- a/test/unit/tw_static_fetch.js +++ b/test/unit/tw_static_fetch.js @@ -1,38 +1,34 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const staticFetch = require('../../src/util/tw-static-fetch'); -test('fetch simple base64', t => { +test('fetch simple base64', async () => { const res = staticFetch('data:text/plain;base64,VGVzdGluZyB0ZXN0aW5nIDEyMw=='); - res.text().then(text => { - t.equal(text, 'Testing testing 123'); - t.equal(res.status, 200); - t.equal(res.ok, true); - t.equal(res.headers.get('content-type'), 'text/plain'); - t.equal(res.headers.get('content-length'), '19'); - t.end(); - }); + const text = await res.text(); + assert.strictEqual(text, 'Testing testing 123'); + assert.strictEqual(res.status, 200); + assert.strictEqual(res.ok, true); + assert.strictEqual(res.headers.get('content-type'), 'text/plain'); + assert.strictEqual(res.headers.get('content-length'), '19'); }); -test('fetch base64 with all possible bytes', t => { +test('fetch base64 with all possible bytes', async () => { // eslint-disable-next-line max-len const res = staticFetch('Data:Application/Octet-Stream;BASE64,AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w=='); - res.arrayBuffer().then(buffer => { - t.same(Array.from(new Uint8Array(buffer)), Array(256) - .fill() - .map((_, index) => index) - ); - t.equal(res.headers.get('content-type'), 'application/octet-stream'); - t.equal(res.headers.get('content-length'), '256'); - t.end(); - }); + const buffer = await res.arrayBuffer(); + assert.deepEqual(Array.from(new Uint8Array(buffer)), Array(256) + .fill() + .map((_, index) => index) + ); + assert.strictEqual(res.headers.get('content-type'), 'application/octet-stream'); + assert.strictEqual(res.headers.get('content-length'), '256'); }); -test('fetch not data:', t => { - t.equal(staticFetch('blob:https://turbowarp.org/54346944-16cf-4ce9-aed4-e1df8ad0d779'), null); - t.equal(staticFetch('https://example.com/'), null); - t.equal(staticFetch('http://example.com/'), null); - t.equal(staticFetch('file:///etc/hosts'), null); - t.equal(staticFetch('oegirjdf'), null); - t.equal(staticFetch(''), null); - t.end(); +test('fetch not data:', () => { + assert.strictEqual(staticFetch('blob:https://turbowarp.org/54346944-16cf-4ce9-aed4-e1df8ad0d779'), null); + assert.strictEqual(staticFetch('https://example.com/'), null); + assert.strictEqual(staticFetch('http://example.com/'), null); + assert.strictEqual(staticFetch('file:///etc/hosts'), null); + assert.strictEqual(staticFetch('oegirjdf'), null); + assert.strictEqual(staticFetch(''), null); }); diff --git a/test/unit/tw_stop_this_script.js b/test/unit/tw_stop_this_script.js index 1f00096d..45e04404 100644 --- a/test/unit/tw_stop_this_script.js +++ b/test/unit/tw_stop_this_script.js @@ -1,9 +1,10 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const Thread = require('../../src/engine/thread'); const Runtime = require('../../src/engine/runtime'); const Target = require('../../src/engine/target'); -test('stopThisScript procedures_call reporter form', t => { +test('stopThisScript procedures_call reporter form', () => { const rt = new Runtime(); const target = new Target(rt, null); @@ -44,9 +45,7 @@ test('stopThisScript procedures_call reporter form', t => { // stopping or returning should always return to reporterCall, not the block after thread.stopThisScript(); - t.same(thread.stack, [ + assert.deepEqual(thread.stack, [ 'reporterCall' ]); - - t.end(); }); diff --git a/test/unit/tw_stored_settings.js b/test/unit/tw_stored_settings.js index 7b88bf53..0df6dd14 100644 --- a/test/unit/tw_stored_settings.js +++ b/test/unit/tw_stored_settings.js @@ -1,11 +1,10 @@ -const tap = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const path = require('path'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const makeTestStorage = require('../fixtures/make-test-storage'); const VirtualMachine = require('../../src/virtual-machine'); -const test = tap.test; - const makeVM = () => { const vm = new VirtualMachine(); vm.attachStorage(makeTestStorage()); @@ -13,79 +12,66 @@ const makeVM = () => { }; for (const file of ['empty-comment.sb3', 'no-comment.sb3']) { - test(`serializes and deserializes settings (${file})`, t => { + test(`serializes and deserializes settings (${file})`, async () => { const project = readFileToBuffer(path.resolve(__dirname, `../fixtures/tw-stored-settings/${file}`)); const vm = makeVM(); - vm.loadProject(project).then(() => { - vm.setFramerate(45); - vm.setTurboMode(true); - vm.setInterpolation(true); - vm.setRuntimeOptions({ - maxClones: Infinity, - miscLimits: false, - fencing: false - }); - vm.setStageSize(100, 101); - vm.storeProjectOptions(); - - const newVM = makeVM(); - newVM.loadProject(vm.toJSON()) - .then(() => { - t.equal(newVM.runtime.framerate, vm.runtime.framerate); - t.equal(newVM.runtime.turboMode, vm.runtime.turboMode); - t.same(newVM.runtime.runtimeOptions, vm.runtime.runtimeOptions); - t.equal(newVM.runtime.interpolationEnabled, vm.runtime.interpolationEnabled); - t.equal(newVM.runtime.stageWidth, vm.runtime.stageWidth); - t.equal(newVM.runtime.stageHeight, vm.runtime.stageHeight); - t.end(); - }); + await vm.loadProject(project); + vm.setFramerate(45); + vm.setTurboMode(true); + vm.setInterpolation(true); + vm.setRuntimeOptions({ + maxClones: Infinity, + miscLimits: false, + fencing: false }); + vm.setStageSize(100, 101); + vm.storeProjectOptions(); + + const newVM = makeVM(); + await newVM.loadProject(vm.toJSON()); + assert.strictEqual(newVM.runtime.framerate, vm.runtime.framerate); + assert.strictEqual(newVM.runtime.turboMode, vm.runtime.turboMode); + assert.deepEqual(newVM.runtime.runtimeOptions, vm.runtime.runtimeOptions); + assert.strictEqual(newVM.runtime.interpolationEnabled, vm.runtime.interpolationEnabled); + assert.strictEqual(newVM.runtime.stageWidth, vm.runtime.stageWidth); + assert.strictEqual(newVM.runtime.stageHeight, vm.runtime.stageHeight); }); } -test('Reuses comment if it already exists', t => { +test('Reuses comment if it already exists', async () => { const project = readFileToBuffer(path.resolve(__dirname, `../fixtures/tw-stored-settings/empty-comment.sb3`)); const vm = makeVM(); - vm.loadProject(project) - .then(() => { - t.equal(Object.keys(vm.runtime.getTargetForStage().comments).length, 1); - vm.setFramerate(99); - vm.storeProjectOptions(); - t.equal(Object.keys(vm.runtime.getTargetForStage().comments).length, 1); - t.end(); - }); + await vm.loadProject(project); + assert.strictEqual(Object.keys(vm.runtime.getTargetForStage().comments).length, 1); + vm.setFramerate(99); + vm.storeProjectOptions(); + assert.strictEqual(Object.keys(vm.runtime.getTargetForStage().comments).length, 1); }); -test('Storing settings emits workspace update only when stage open', t => { +test('Storing settings emits workspace update only when stage open', async () => { const project = readFileToBuffer(path.resolve(__dirname, `../fixtures/tw-stored-settings/sprite.sb3`)); const vm = makeVM(); - vm.loadProject(project) - .then(() => { - let didFireUpdate = false; - vm.on('workspaceUpdate', () => { - didFireUpdate = true; - }); - vm.storeProjectOptions(); - t.equal(didFireUpdate, false); - vm.setEditingTarget(vm.runtime.getTargetForStage().id); - vm.storeProjectOptions(); - t.equal(didFireUpdate, true); - t.end(); - }); + await vm.loadProject(project); + let didFireUpdate = false; + vm.on('workspaceUpdate', () => { + didFireUpdate = true; + }); + vm.storeProjectOptions(); + assert.strictEqual(didFireUpdate, false); + vm.setEditingTarget(vm.runtime.getTargetForStage().id); + vm.storeProjectOptions(); + assert.strictEqual(didFireUpdate, true); }); -test('Storing settings emits project changed', t => { +test('Storing settings emits project changed', async t => { const project = readFileToBuffer(path.resolve(__dirname, `../fixtures/tw-stored-settings/sprite.sb3`)); const vm = makeVM(); - vm.loadProject(project) - .then(() => { - t.plan(1); - vm.on('PROJECT_CHANGED', () => { - t.pass(); - }); - vm.storeProjectOptions(); - t.end(); - }); + await vm.loadProject(project); + t.plan(1); + vm.on('PROJECT_CHANGED', () => { + t.assert.ok(true); + }); + vm.storeProjectOptions(); }); test('Stored turbo mode emits event on VM', async t => { @@ -93,8 +79,7 @@ test('Stored turbo mode emits event on VM', async t => { const project = readFileToBuffer(path.resolve(__dirname, '../fixtures/tw-stored-settings/turbo-mode.sb3')); t.plan(1); vm.on('TURBO_MODE_ON', () => { - t.pass('emitted TURBO_MODE_ON'); + t.assert.ok(true, 'emitted TURBO_MODE_ON'); }); await vm.loadProject(project); - t.end(); }); diff --git a/test/unit/tw_translate.js b/test/unit/tw_translate.js index 3e9c9ccf..69cc73c5 100644 --- a/test/unit/tw_translate.js +++ b/test/unit/tw_translate.js @@ -1,4 +1,5 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); // Simulate the network being down or filtered // Run this before fetch-with-timeout.js is gets loaded. @@ -16,13 +17,8 @@ Object.defineProperty(global, 'navigator', { // Translate tries to access AbortController from window, but does not require it to exist. global.window = {}; -test('translate returns original string on network error', t => { - t.plan(1); - +test('translate returns original string on network error', async () => { const extension = new Scratch3TranslateBlocks(); - extension.getTranslate({WORDS: 'My message 123123', LANGUAGE: 'es'}) - .then(message => { - t.equal(message, 'My message 123123'); - t.end(); - }); + const message = await extension.getTranslate({WORDS: 'My message 123123', LANGUAGE: 'es'}); + assert.strictEqual(message, 'My message 123123'); }); diff --git a/test/unit/tw_unsandboxed_extensions.js b/test/unit/tw_unsandboxed_extensions.js index af899672..0b17ffee 100644 --- a/test/unit/tw_unsandboxed_extensions.js +++ b/test/unit/tw_unsandboxed_extensions.js @@ -1,4 +1,5 @@ -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const UnsandboxedExtensionRunner = require('../../src/extension-support/tw-unsandboxed-extension-runner'); const VirtualMachine = require('../../src/virtual-machine'); @@ -55,39 +56,36 @@ global.window = { // Remove navigator object from Node 21 and later delete global.navigator; -tap.beforeEach(() => { +beforeEach(() => { scriptCallbacks.clear(); global.location = { href: 'https://example.com/' }; }); -const {test} = tap; - test('basic API', async t => { t.plan(9); const vm = new VirtualMachine(); class MyExtension {} setScript('https://turbowarp.org/1.js', () => { - t.equal(global.Scratch.vm, vm); - t.equal(global.Scratch.renderer, vm.runtime.renderer); - t.equal(global.Scratch.extensions.unsandboxed, true); + t.assert.strictEqual(global.Scratch.vm, vm); + t.assert.strictEqual(global.Scratch.renderer, vm.runtime.renderer); + t.assert.strictEqual(global.Scratch.extensions.unsandboxed, true); // These APIs are tested elsewhere, just make sure they're getting exported - t.equal(global.Scratch.ArgumentType.NUMBER, 'number'); - t.equal(global.Scratch.BlockType.REPORTER, 'reporter'); - t.equal(global.Scratch.TargetType.SPRITE, 'sprite'); - t.equal(global.Scratch.Cast.toNumber('3.14'), 3.14); + t.assert.strictEqual(global.Scratch.ArgumentType.NUMBER, 'number'); + t.assert.strictEqual(global.Scratch.BlockType.REPORTER, 'reporter'); + t.assert.strictEqual(global.Scratch.TargetType.SPRITE, 'sprite'); + t.assert.strictEqual(global.Scratch.Cast.toNumber('3.14'), 3.14); global.Scratch.extensions.register(new MyExtension()); }); const extensions = await UnsandboxedExtensionRunner.load('https://turbowarp.org/1.js', vm); - t.equal(extensions.length, 1); - t.ok(extensions[0] instanceof MyExtension); - t.end(); + t.assert.strictEqual(extensions.length, 1); + t.assert.ok(extensions[0] instanceof MyExtension); }); -test('multiple VMs loading extensions', async t => { +test('multiple VMs loading extensions', async () => { const vm1 = new VirtualMachine(); const vm2 = new VirtualMachine(); @@ -117,22 +115,20 @@ test('multiple VMs loading extensions', async t => { UnsandboxedExtensionRunner.load('https://turbowarp.org/2.js', vm2) ]); - t.not(api1, api2); - t.type(api1.extensions.register, 'function'); - t.type(api2.extensions.register, 'function'); - t.equal(api1.vm, vm1); - t.equal(api2.vm, vm2); + assert.notStrictEqual(api1, api2); + assert.strictEqual(typeof api1.extensions.register, 'function'); + assert.strictEqual(typeof api2.extensions.register, 'function'); + assert.strictEqual(api1.vm, vm1); + assert.strictEqual(api2.vm, vm2); - t.equal(extensions.length, 2); - t.equal(extensions[0].length, 1); - t.equal(extensions[1].length, 1); - t.ok(extensions[0][0] instanceof Extension1); - t.ok(extensions[1][0] instanceof Extension2); - - t.end(); + assert.strictEqual(extensions.length, 2); + assert.strictEqual(extensions[0].length, 1); + assert.strictEqual(extensions[1].length, 1); + assert.ok(extensions[0][0] instanceof Extension1); + assert.ok(extensions[1][0] instanceof Extension2); }); -test('register multiple extensions in one script', async t => { +test('register multiple extensions in one script', async () => { const vm = new VirtualMachine(); class Extension1 {} class Extension2 {} @@ -141,25 +137,18 @@ test('register multiple extensions in one script', async t => { global.Scratch.extensions.register(new Extension2()); }); const extensions = await UnsandboxedExtensionRunner.load('https://turbowarp.org/multiple.js', vm); - t.equal(extensions.length, 2); - t.ok(extensions[0] instanceof Extension1); - t.ok(extensions[1] instanceof Extension2); - t.end(); + assert.strictEqual(extensions.length, 2); + assert.ok(extensions[0] instanceof Extension1); + assert.ok(extensions[1] instanceof Extension2); }); -test('extension error results in rejection', async t => { +test('extension error results in rejection', async () => { const vm = new VirtualMachine(); - try { - await UnsandboxedExtensionRunner.load('https://turbowarp.org/404.js', vm); - // Above should throw an error as the script will not load successfully - t.fail(); - } catch (e) { - t.pass(); - } - t.end(); + // The script will not load successfully + await assert.rejects(UnsandboxedExtensionRunner.load('https://turbowarp.org/404.js', vm)); }); -test('ScratchX', async t => { +test('ScratchX', async () => { const vm = new VirtualMachine(); setScript('https://turbowarp.org/scratchx.js', () => { const ext = { @@ -173,93 +162,86 @@ test('ScratchX', async t => { global.ScratchExtensions.register('Test', descriptor, ext); }); const extensions = await UnsandboxedExtensionRunner.load('https://turbowarp.org/scratchx.js', vm); - t.equal(extensions.length, 1); - t.equal(extensions[0].test(), 2); - t.end(); + assert.strictEqual(extensions.length, 1); + assert.strictEqual(extensions[0].test(), 2); }); -test('canFetch', async t => { +test('canFetch', async () => { // see tw_security_manager.js const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); const result = global.Scratch.canFetch('https://example.com/'); - t.type(result, Promise); - t.equal(await result, true); - t.end(); + assert.ok(result instanceof Promise); + assert.strictEqual(await result, true); }); -test('fetch', async t => { +test('fetch', async () => { const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); global.Scratch.canFetch = url => url === 'https://example.com/2'; - await t.rejects(global.Scratch.fetch('https://example.com/1'), /Permission to fetch https:\/\/example.com\/1 rejected/); - await t.rejects(global.Scratch.fetch(new Request('https://example.com/1')), /Permission to fetch https:\/\/example.com\/1 rejected/); - t.equal(await global.Scratch.fetch('https://example.com/2'), '[Response https://example.com/2 options={}]'); - t.equal(await global.Scratch.fetch(new Request('https://example.com/2')), '[Response https://example.com/2 options={}]'); - t.equal(await global.Scratch.fetch('https://example.com/2', { + await assert.rejects(global.Scratch.fetch('https://example.com/1'), /Permission to fetch https:\/\/example.com\/1 rejected/); + await assert.rejects(global.Scratch.fetch(new Request('https://example.com/1')), /Permission to fetch https:\/\/example.com\/1 rejected/); + assert.strictEqual(await global.Scratch.fetch('https://example.com/2'), '[Response https://example.com/2 options={}]'); + assert.strictEqual(await global.Scratch.fetch(new Request('https://example.com/2')), '[Response https://example.com/2 options={}]'); + assert.strictEqual(await global.Scratch.fetch('https://example.com/2', { redirect: 'follow', method: 'POST', body: 'abc' }), '[Response https://example.com/2 options={"redirect":"follow","method":"POST","body":"abc"}]'); - t.end(); }); -test('canOpenWindow', async t => { +test('canOpenWindow', async () => { // see tw_security_manager.js const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); const result = global.Scratch.canOpenWindow('https://example.com/'); - t.type(result, Promise); - t.equal(await result, true); - t.end(); + assert.ok(result instanceof Promise); + assert.strictEqual(await result, true); }); -test('openWindow', async t => { +test('openWindow', async () => { const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); global.Scratch.canOpenWindow = url => url === 'https://example.com/2'; - await t.rejects(global.Scratch.openWindow('https://example.com/1'), /Permission to open tab https:\/\/example.com\/1 rejected/); - t.equal(await global.Scratch.openWindow('https://example.com/2'), '[Window https://example.com/2 target=_blank features=noreferrer]'); - t.equal(await global.Scratch.openWindow('https://example.com/2', 'popup=1'), '[Window https://example.com/2 target=_blank features=noreferrer,popup=1]'); - t.end(); + await assert.rejects(global.Scratch.openWindow('https://example.com/1'), /Permission to open tab https:\/\/example.com\/1 rejected/); + assert.strictEqual(await global.Scratch.openWindow('https://example.com/2'), '[Window https://example.com/2 target=_blank features=noreferrer]'); + assert.strictEqual(await global.Scratch.openWindow('https://example.com/2', 'popup=1'), '[Window https://example.com/2 target=_blank features=noreferrer,popup=1]'); }); -test('canRedirect', async t => { +test('canRedirect', async () => { // see tw_security_manager.js const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); const result = global.Scratch.canRedirect('https://example.com/'); - t.type(result, Promise); - t.equal(await result, true); - t.end(); + assert.ok(result instanceof Promise); + assert.strictEqual(await result, true); }); -test('redirect', async t => { +test('redirect', async () => { const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); global.Scratch.canRedirect = url => url === 'https://example.com/2'; - await t.rejects(global.Scratch.redirect('https://example.com/1'), /Permission to redirect to https:\/\/example.com\/1 rejected/); - t.equal(global.location.href, 'https://example.com/'); + await assert.rejects(global.Scratch.redirect('https://example.com/1'), /Permission to redirect to https:\/\/example.com\/1 rejected/); + assert.strictEqual(global.location.href, 'https://example.com/'); await global.Scratch.redirect('https://example.com/2'); - t.equal(global.location.href, 'https://example.com/2'); - t.end(); + assert.strictEqual(global.location.href, 'https://example.com/2'); }); -test('translate', async t => { +test('translate', async () => { const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); - t.equal(global.Scratch.translate({ + assert.strictEqual(global.Scratch.translate({ id: 'test1', default: 'Message 1: {var}', description: 'Description' }, { var: 'test' }), 'Message 1: test'); - t.equal(global.Scratch.translate('test1 {var}', { + assert.strictEqual(global.Scratch.translate('test1 {var}', { var: 'ok' }), 'test1 ok'); - t.equal(global.Scratch.translate.language, 'en'); + assert.strictEqual(global.Scratch.translate.language, 'en'); global.Scratch.translate.setup({ en: { @@ -269,99 +251,92 @@ test('translate', async t => { test1: 'ES Message 1: {var}' } }); - t.equal(global.Scratch.translate({ + assert.strictEqual(global.Scratch.translate({ id: 'test1', default: 'Message 1: {var}', description: 'Description' }, { var: 'test' }), 'EN Message 1: test'); - t.equal(global.Scratch.translate('test1 {var}', { + assert.strictEqual(global.Scratch.translate('test1 {var}', { var: 'ok' }), 'test1 ok'); - t.equal(global.Scratch.translate.language, 'en'); + assert.strictEqual(global.Scratch.translate.language, 'en'); await vm.setLocale('es'); // do not call setup() again; real extensions will not do that. // need to make sure that the translatiosn are saved after calling setLocale. - t.equal(global.Scratch.translate({ + assert.strictEqual(global.Scratch.translate({ id: 'test1', default: 'Message 1: {var}', description: 'Description' }, { var: 'test' }), 'ES Message 1: test'); - t.equal(global.Scratch.translate.language, 'es'); - - t.end(); + assert.strictEqual(global.Scratch.translate.language, 'es'); }); -test('canRecordAudio', async t => { +test('canRecordAudio', async () => { const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); vm.securityManager.canRecordAudio = () => false; - t.equal(await global.Scratch.canRecordAudio(), false); + assert.strictEqual(await global.Scratch.canRecordAudio(), false); vm.securityManager.canRecordAudio = () => true; - t.equal(await global.Scratch.canRecordAudio(), true); + assert.strictEqual(await global.Scratch.canRecordAudio(), true); - t.end(); }); -test('canRecordVideo', async t => { +test('canRecordVideo', async () => { const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); vm.securityManager.canRecordVideo = () => false; - t.equal(await global.Scratch.canRecordVideo(), false); + assert.strictEqual(await global.Scratch.canRecordVideo(), false); vm.securityManager.canRecordVideo = () => true; - t.equal(await global.Scratch.canRecordVideo(), true); + assert.strictEqual(await global.Scratch.canRecordVideo(), true); - t.end(); }); -test('canReadClipboard', async t => { +test('canReadClipboard', async () => { const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); vm.securityManager.canReadClipboard = () => false; - t.equal(await global.Scratch.canReadClipboard(), false); + assert.strictEqual(await global.Scratch.canReadClipboard(), false); vm.securityManager.canReadClipboard = () => true; - t.equal(await global.Scratch.canReadClipboard(), true); + assert.strictEqual(await global.Scratch.canReadClipboard(), true); - t.end(); }); -test('canNotify', async t => { +test('canNotify', async () => { const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); vm.securityManager.canNotify = () => false; - t.equal(await global.Scratch.canNotify(), false); + assert.strictEqual(await global.Scratch.canNotify(), false); vm.securityManager.canNotify = () => true; - t.equal(await global.Scratch.canNotify(), true); + assert.strictEqual(await global.Scratch.canNotify(), true); - t.end(); }); -test('canGeolocate', async t => { +test('canGeolocate', async () => { const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); vm.securityManager.canGeolocate = () => false; - t.equal(await global.Scratch.canGeolocate(), false); + assert.strictEqual(await global.Scratch.canGeolocate(), false); vm.securityManager.canGeolocate = () => true; - t.equal(await global.Scratch.canGeolocate(), true); + assert.strictEqual(await global.Scratch.canGeolocate(), true); - t.end(); }); -test('rewriteExtensionURL', async t => { +test('rewriteExtensionURL', async () => { const vm = new VirtualMachine(); let createdRewrittenExtension = false; @@ -380,7 +355,7 @@ test('rewriteExtensionURL', async t => { class OriginalExtension { getInfo () { - t.fail('Should not create original extension'); + assert.fail('Should not create original extension'); return { id: 'extensionid', blocks: [] @@ -401,24 +376,22 @@ test('rewriteExtensionURL', async t => { await vm.extensionManager.loadExtensionURL('https://turbowarp.org/original.js'); - t.ok(createdRewrittenExtension, 'used rewritten extension'); - t.ok(vm.extensionManager.isExtensionURLLoaded('https://turbowarp.org/original.js'), 'marks original URL as loaded'); - t.notOk(vm.extensionManager.isExtensionURLLoaded('https://turbowarp.org/rewritten.js'), 'does not mark new URL as loaded'); - t.end(); + assert.ok(createdRewrittenExtension, 'used rewritten extension'); + assert.ok(vm.extensionManager.isExtensionURLLoaded('https://turbowarp.org/original.js'), 'marks original URL as loaded'); + assert.ok(!vm.extensionManager.isExtensionURLLoaded('https://turbowarp.org/rewritten.js'), 'does not mark new URL as loaded'); }); -test('canEmbed', async t => { +test('canEmbed', async () => { const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); vm.securityManager.canEmbed = url => url === 'https://example.com/safe'; - t.ok(await global.Scratch.canEmbed('https://example.com/safe')); - t.notOk(await global.Scratch.canEmbed('https://example.com/unsafe')); + assert.ok(await global.Scratch.canEmbed('https://example.com/safe')); + assert.ok(!(await global.Scratch.canEmbed('https://example.com/unsafe'))); - t.end(); }); -test('canDownload', async t => { +test('canDownload', async () => { const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); @@ -428,16 +401,16 @@ test('canDownload', async t => { return url === 'https://example.com/safe.txt' && name === 'safe.txt'; }; - t.ok(await global.Scratch.canDownload('https://example.com/safe.txt', 'safe.txt')); - t.notOk(await global.Scratch.canDownload('https://example.com/unsafe.txt', 'safe.txt')); - t.notOk(await global.Scratch.canDownload('https://example.com/safe.txt', 'unsafe.txt')); - t.notOk(await global.Scratch.canDownload('https://example.com/unsafe.txt', 'unsafe.txt')); + assert.ok(await global.Scratch.canDownload('https://example.com/safe.txt', 'safe.txt')); + assert.ok(!(await global.Scratch.canDownload('https://example.com/unsafe.txt', 'safe.txt'))); + assert.ok(!(await global.Scratch.canDownload('https://example.com/safe.txt', 'unsafe.txt'))); + assert.ok(!(await global.Scratch.canDownload('https://example.com/unsafe.txt', 'unsafe.txt'))); // Should be rejected without even calling user-provided canDownload. // eslint-disable-next-line no-script-url - t.notOk(await global.Scratch.canDownload('javascript:alert(1)', 'index.html')); + assert.ok(!(await global.Scratch.canDownload('javascript:alert(1)', 'index.html'))); - t.same(canDownloadChecks, [ + assert.deepEqual(canDownloadChecks, [ [ 'https://example.com/safe.txt', 'safe.txt' @@ -455,11 +428,9 @@ test('canDownload', async t => { 'unsafe.txt' ] ]); - - t.end(); }); -test('download', async t => { +test('download', async () => { const vm = new VirtualMachine(); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); @@ -487,20 +458,20 @@ test('download', async t => { }; await global.Scratch.download('https://example.com/safe.txt', 'safe.txt'); - await t.rejects(global.Scratch.download('https://example.com/unsafe.txt', 'safe.txt'), /Permission to download/); - await t.rejects(global.Scratch.download('https://example.com/safe.txt', 'unsafe.txt'), /Permission to download/); - await t.rejects(global.Scratch.download('https://example.com/unsafe.txt', 'unsafe.txt'), /Permission to download/); + await assert.rejects(global.Scratch.download('https://example.com/unsafe.txt', 'safe.txt'), /Permission to download/); + await assert.rejects(global.Scratch.download('https://example.com/safe.txt', 'unsafe.txt'), /Permission to download/); + await assert.rejects(global.Scratch.download('https://example.com/unsafe.txt', 'unsafe.txt'), /Permission to download/); // eslint-disable-next-line no-script-url - await t.rejects(global.Scratch.download('javascript:alert(1)', 'safe.txt'), /Permission to download/); + await assert.rejects(global.Scratch.download('javascript:alert(1)', 'safe.txt'), /Permission to download/); - t.same(actualDownloadAttempts, [ + assert.deepEqual(actualDownloadAttempts, [ [ 'https://example.com/safe.txt', 'safe.txt' ] ]); - t.same(canDownloadChecks, [ + assert.deepEqual(canDownloadChecks, [ [ 'https://example.com/safe.txt', 'safe.txt' @@ -518,16 +489,13 @@ test('download', async t => { 'unsafe.txt' ] ]); - - t.end(); }); -test('CREATE_UNSANDBOXED_EXTENSION_API', t => { +test('CREATE_UNSANDBOXED_EXTENSION_API', () => { const vm = new VirtualMachine(); vm.on('CREATE_UNSANDBOXED_EXTENSION_API', api => { api.extraStuff = 'aaaa'; }); UnsandboxedExtensionRunner.setupUnsandboxedExtensionAPI(vm); - t.equal(global.Scratch.extraStuff, 'aaaa'); - t.end(); + assert.strictEqual(global.Scratch.extraStuff, 'aaaa'); }); diff --git a/test/unit/tw_util_async_limiter.js b/test/unit/tw_util_async_limiter.js index db909934..ad80bc4e 100644 --- a/test/unit/tw_util_async_limiter.js +++ b/test/unit/tw_util_async_limiter.js @@ -1,13 +1,14 @@ const AsyncLimiter = require('../../src/util/async-limiter'); -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); -test('Runs callback', async t => { +test('Runs callback', async () => { /* eslint-disable-next-line require-await */ const callback = async (a, b) => a + b; const limiter = new AsyncLimiter(callback, 2); - t.same(await Promise.all([ + assert.deepEqual(await Promise.all([ limiter.do(1, 2), limiter.do(3, 4), limiter.do(5, 6), @@ -20,23 +21,16 @@ test('Runs callback', async t => { 15, 19 ]); - t.end(); }); -test('Errors', async t => { - t.plan(1); +test('Errors', async () => { const errorObject = new Error('Testing testing 123'); // want to get the same *exact* object back const callback = () => Promise.reject(errorObject); const limiter = new AsyncLimiter(callback, 10); - try { - await limiter.do(); - } catch (e) { - t.equal(e, errorObject); - } - t.end(); + await assert.rejects(limiter.do(), e => e === errorObject); }); -test('Limit and queue', async t => { +test('Limit and queue', async () => { const calls = []; const callback = () => new Promise(resolve => { calls.push({ @@ -50,15 +44,13 @@ test('Limit and queue', async t => { limiter.do(); } - t.equal(calls.length, 5); + assert.strictEqual(calls.length, 5); calls.forEach(i => i.resolve()); await Promise.resolve(); - t.equal(calls.length, 10); + assert.strictEqual(calls.length, 10); calls.forEach(i => i.resolve()); await Promise.resolve(); - t.equal(calls.length, 12); - - t.end(); + assert.strictEqual(calls.length, 12); }); diff --git a/test/unit/tw_util_string.js b/test/unit/tw_util_string.js index c316aead..d22fe86b 100644 --- a/test/unit/tw_util_string.js +++ b/test/unit/tw_util_string.js @@ -1,10 +1,10 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const StringUtil = require('../../src/util/string-util'); -test('caseInsensitiveUnusedName', t => { - t.equal(StringUtil.caseInsensitiveUnusedName('test', []), 'test'); - t.equal(StringUtil.caseInsensitiveUnusedName('test', ['Test']), 'test2'); - t.equal(StringUtil.caseInsensitiveUnusedName('TEST3', ['test3']), 'TEST2'); - t.equal(StringUtil.caseInsensitiveUnusedName('TEST', ['test', 'TESt1', 'teST2']), 'TEST3'); - t.end(); +test('caseInsensitiveUnusedName', () => { + assert.strictEqual(StringUtil.caseInsensitiveUnusedName('test', []), 'test'); + assert.strictEqual(StringUtil.caseInsensitiveUnusedName('test', ['Test']), 'test2'); + assert.strictEqual(StringUtil.caseInsensitiveUnusedName('TEST3', ['test3']), 'TEST2'); + assert.strictEqual(StringUtil.caseInsensitiveUnusedName('TEST', ['test', 'TESt1', 'teST2']), 'TEST3'); }); diff --git a/test/unit/tw_vm_exports.js b/test/unit/tw_vm_exports.js index 040d183a..8c439d52 100644 --- a/test/unit/tw_vm_exports.js +++ b/test/unit/tw_vm_exports.js @@ -1,16 +1,15 @@ -const {test} = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const VM = require('../../src/virtual-machine'); -test('exports exist', t => { +test('exports exist', () => { const vm = new VM(); - t.type(vm.exports.Sprite, 'function'); - t.type(vm.exports.RenderedTarget, 'function'); - t.end(); + assert.strictEqual(typeof vm.exports.Sprite, 'function'); + assert.strictEqual(typeof vm.exports.RenderedTarget, 'function'); }); -test('JSZip', t => { +test('JSZip', () => { const JSZip = new VM().exports.JSZip; const zip = new JSZip(); - t.type(zip.file, 'function'); - t.end(); + assert.strictEqual(typeof zip.file, 'function'); }); diff --git a/test/unit/util_base64.js b/test/unit/util_base64.js index f43aa148..22aa5a2e 100644 --- a/test/unit/util_base64.js +++ b/test/unit/util_base64.js @@ -1,23 +1,21 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const Base64Util = require('../../src/util/base64-util'); -test('uint8ArrayToBase64', t => { - t.equal(Base64Util.uint8ArrayToBase64(new Uint8Array([0, 50, 80, 200])), 'ADJQyA=='); - t.equal(Base64Util.uint8ArrayToBase64([0, 50, 80, 200]), 'ADJQyA=='); - t.end(); +test('uint8ArrayToBase64', () => { + assert.strictEqual(Base64Util.uint8ArrayToBase64(new Uint8Array([0, 50, 80, 200])), 'ADJQyA=='); + assert.strictEqual(Base64Util.uint8ArrayToBase64([0, 50, 80, 200]), 'ADJQyA=='); }); -test('arrayBufferToBase64', t => { - t.equal(Base64Util.arrayBufferToBase64(new Uint8Array([0, 50, 80, 200]).buffer), 'ADJQyA=='); - t.end(); +test('arrayBufferToBase64', () => { + assert.strictEqual(Base64Util.arrayBufferToBase64(new Uint8Array([0, 50, 80, 200]).buffer), 'ADJQyA=='); }); -test('base64ToUint8Array', t => { - t.same(Base64Util.base64ToUint8Array('ADJQyA=='), new Uint8Array([0, 50, 80, 200])); - t.end(); +test('base64ToUint8Array', () => { + assert.deepEqual(Base64Util.base64ToUint8Array('ADJQyA=='), new Uint8Array([0, 50, 80, 200])); }); -test('round trips', t => { +test('round trips', () => { const data = [ new Uint8Array(new Array(255) .fill() @@ -32,10 +30,9 @@ test('round trips', t => { const uint8ToBase64 = Base64Util.uint8ArrayToBase64(uint8array); const arrayToBase64 = Base64Util.uint8ArrayToBase64(Array.from(uint8array)); const bufferToBase64 = Base64Util.arrayBufferToBase64(uint8array.buffer); - t.equal(uint8ToBase64, arrayToBase64); - t.equal(uint8ToBase64, bufferToBase64); + assert.strictEqual(uint8ToBase64, arrayToBase64); + assert.strictEqual(uint8ToBase64, bufferToBase64); const decoded = Base64Util.base64ToUint8Array(uint8ToBase64); - t.same(uint8array, decoded); + assert.deepEqual(uint8array, decoded); } - t.end(); }); diff --git a/test/unit/util_cast.js b/test/unit/util_cast.js index bf2bbdff..2aa8a0e6 100644 --- a/test/unit/util_cast.js +++ b/test/unit/util_cast.js @@ -1,201 +1,194 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const cast = require('../../src/util/cast'); -test('toNumber', t => { +test('toNumber', () => { // Numeric - t.strictEqual(cast.toNumber(0), 0); - t.strictEqual(cast.toNumber(1), 1); - t.strictEqual(cast.toNumber(3.14), 3.14); + assert.strictEqual(cast.toNumber(0), 0); + assert.strictEqual(cast.toNumber(1), 1); + assert.strictEqual(cast.toNumber(3.14), 3.14); // String - t.strictEqual(cast.toNumber('0'), 0); - t.strictEqual(cast.toNumber('1'), 1); - t.strictEqual(cast.toNumber('3.14'), 3.14); - t.strictEqual(cast.toNumber('0.1e10'), 1000000000); - t.strictEqual(cast.toNumber('foobar'), 0); + assert.strictEqual(cast.toNumber('0'), 0); + assert.strictEqual(cast.toNumber('1'), 1); + assert.strictEqual(cast.toNumber('3.14'), 3.14); + assert.strictEqual(cast.toNumber('0.1e10'), 1000000000); + assert.strictEqual(cast.toNumber('foobar'), 0); // Boolean - t.strictEqual(cast.toNumber(true), 1); - t.strictEqual(cast.toNumber(false), 0); - t.strictEqual(cast.toNumber('true'), 0); - t.strictEqual(cast.toNumber('false'), 0); + assert.strictEqual(cast.toNumber(true), 1); + assert.strictEqual(cast.toNumber(false), 0); + assert.strictEqual(cast.toNumber('true'), 0); + assert.strictEqual(cast.toNumber('false'), 0); // Undefined & object - t.strictEqual(cast.toNumber(undefined), 0); - t.strictEqual(cast.toNumber({}), 0); - t.strictEqual(cast.toNumber(NaN), 0); - t.end(); + assert.strictEqual(cast.toNumber(undefined), 0); + assert.strictEqual(cast.toNumber({}), 0); + assert.strictEqual(cast.toNumber(NaN), 0); }); -test('toBoolean', t => { +test('toBoolean', () => { // Numeric - t.strictEqual(cast.toBoolean(0), false); - t.strictEqual(cast.toBoolean(1), true); - t.strictEqual(cast.toBoolean(3.14), true); + assert.strictEqual(cast.toBoolean(0), false); + assert.strictEqual(cast.toBoolean(1), true); + assert.strictEqual(cast.toBoolean(3.14), true); // String - t.strictEqual(cast.toBoolean('0'), false); - t.strictEqual(cast.toBoolean('1'), true); - t.strictEqual(cast.toBoolean('3.14'), true); - t.strictEqual(cast.toBoolean('0.1e10'), true); - t.strictEqual(cast.toBoolean('foobar'), true); + assert.strictEqual(cast.toBoolean('0'), false); + assert.strictEqual(cast.toBoolean('1'), true); + assert.strictEqual(cast.toBoolean('3.14'), true); + assert.strictEqual(cast.toBoolean('0.1e10'), true); + assert.strictEqual(cast.toBoolean('foobar'), true); // Boolean - t.strictEqual(cast.toBoolean(true), true); - t.strictEqual(cast.toBoolean(false), false); + assert.strictEqual(cast.toBoolean(true), true); + assert.strictEqual(cast.toBoolean(false), false); // Undefined & object - t.strictEqual(cast.toBoolean(undefined), false); - t.strictEqual(cast.toBoolean({}), true); - t.end(); + assert.strictEqual(cast.toBoolean(undefined), false); + assert.strictEqual(cast.toBoolean({}), true); }); -test('toString', t => { +test('toString', () => { // Numeric - t.strictEqual(cast.toString(0), '0'); - t.strictEqual(cast.toString(1), '1'); - t.strictEqual(cast.toString(3.14), '3.14'); + assert.strictEqual(cast.toString(0), '0'); + assert.strictEqual(cast.toString(1), '1'); + assert.strictEqual(cast.toString(3.14), '3.14'); // String - t.strictEqual(cast.toString('0'), '0'); - t.strictEqual(cast.toString('1'), '1'); - t.strictEqual(cast.toString('3.14'), '3.14'); - t.strictEqual(cast.toString('0.1e10'), '0.1e10'); - t.strictEqual(cast.toString('foobar'), 'foobar'); + assert.strictEqual(cast.toString('0'), '0'); + assert.strictEqual(cast.toString('1'), '1'); + assert.strictEqual(cast.toString('3.14'), '3.14'); + assert.strictEqual(cast.toString('0.1e10'), '0.1e10'); + assert.strictEqual(cast.toString('foobar'), 'foobar'); // Boolean - t.strictEqual(cast.toString(true), 'true'); - t.strictEqual(cast.toString(false), 'false'); + assert.strictEqual(cast.toString(true), 'true'); + assert.strictEqual(cast.toString(false), 'false'); // Undefined & object - t.strictEqual(cast.toString(undefined), 'undefined'); - t.strictEqual(cast.toString({}), '[object Object]'); - t.end(); + assert.strictEqual(cast.toString(undefined), 'undefined'); + assert.strictEqual(cast.toString({}), '[object Object]'); }); -test('toRgbColorList', t => { +test('toRgbColorList', () => { // Hex (minimal, see "color" util tests) - t.deepEqual(cast.toRgbColorList('#000'), [0, 0, 0]); - t.deepEqual(cast.toRgbColorList('#000000'), [0, 0, 0]); - t.deepEqual(cast.toRgbColorList('#fff'), [255, 255, 255]); - t.deepEqual(cast.toRgbColorList('#ffffff'), [255, 255, 255]); + assert.deepEqual(cast.toRgbColorList('#000'), [0, 0, 0]); + assert.deepEqual(cast.toRgbColorList('#000000'), [0, 0, 0]); + assert.deepEqual(cast.toRgbColorList('#fff'), [255, 255, 255]); + assert.deepEqual(cast.toRgbColorList('#ffffff'), [255, 255, 255]); // Decimal (minimal, see "color" util tests) - t.deepEqual(cast.toRgbColorList(0), [0, 0, 0]); - t.deepEqual(cast.toRgbColorList(1), [0, 0, 1]); - t.deepEqual(cast.toRgbColorList(16777215), [255, 255, 255]); + assert.deepEqual(cast.toRgbColorList(0), [0, 0, 0]); + assert.deepEqual(cast.toRgbColorList(1), [0, 0, 1]); + assert.deepEqual(cast.toRgbColorList(16777215), [255, 255, 255]); // Malformed - t.deepEqual(cast.toRgbColorList('ffffff'), [0, 0, 0]); - t.deepEqual(cast.toRgbColorList('foobar'), [0, 0, 0]); - t.deepEqual(cast.toRgbColorList('#nothex'), [0, 0, 0]); - t.end(); + assert.deepEqual(cast.toRgbColorList('ffffff'), [0, 0, 0]); + assert.deepEqual(cast.toRgbColorList('foobar'), [0, 0, 0]); + assert.deepEqual(cast.toRgbColorList('#nothex'), [0, 0, 0]); }); -test('toRgbColorObject', t => { +test('toRgbColorObject', () => { // Hex (minimal, see "color" util tests) - t.deepEqual(cast.toRgbColorObject('#000'), {r: 0, g: 0, b: 0}); - t.deepEqual(cast.toRgbColorObject('#000000'), {r: 0, g: 0, b: 0}); - t.deepEqual(cast.toRgbColorObject('#fff'), {r: 255, g: 255, b: 255}); - t.deepEqual(cast.toRgbColorObject('#ffffff'), {r: 255, g: 255, b: 255}); + assert.deepEqual(cast.toRgbColorObject('#000'), {r: 0, g: 0, b: 0}); + assert.deepEqual(cast.toRgbColorObject('#000000'), {r: 0, g: 0, b: 0}); + assert.deepEqual(cast.toRgbColorObject('#fff'), {r: 255, g: 255, b: 255}); + assert.deepEqual(cast.toRgbColorObject('#ffffff'), {r: 255, g: 255, b: 255}); // Decimal (minimal, see "color" util tests) - t.deepEqual(cast.toRgbColorObject(0), {a: 255, r: 0, g: 0, b: 0}); - t.deepEqual(cast.toRgbColorObject(1), {a: 255, r: 0, g: 0, b: 1}); - t.deepEqual(cast.toRgbColorObject(16777215), {a: 255, r: 255, g: 255, b: 255}); - t.deepEqual(cast.toRgbColorObject('0x80010203'), {a: 128, r: 1, g: 2, b: 3}); + assert.deepEqual(cast.toRgbColorObject(0), {a: 255, r: 0, g: 0, b: 0}); + assert.deepEqual(cast.toRgbColorObject(1), {a: 255, r: 0, g: 0, b: 1}); + assert.deepEqual(cast.toRgbColorObject(16777215), {a: 255, r: 255, g: 255, b: 255}); + assert.deepEqual(cast.toRgbColorObject('0x80010203'), {a: 128, r: 1, g: 2, b: 3}); // Malformed - t.deepEqual(cast.toRgbColorObject('ffffff'), {a: 255, r: 0, g: 0, b: 0}); - t.deepEqual(cast.toRgbColorObject('foobar'), {a: 255, r: 0, g: 0, b: 0}); - t.deepEqual(cast.toRgbColorObject('#nothex'), {a: 255, r: 0, g: 0, b: 0}); - t.end(); + assert.deepEqual(cast.toRgbColorObject('ffffff'), {a: 255, r: 0, g: 0, b: 0}); + assert.deepEqual(cast.toRgbColorObject('foobar'), {a: 255, r: 0, g: 0, b: 0}); + assert.deepEqual(cast.toRgbColorObject('#nothex'), {a: 255, r: 0, g: 0, b: 0}); }); -test('compare', t => { +test('compare', () => { // Numeric - t.strictEqual(cast.compare(0, 0), 0); - t.strictEqual(cast.compare(1, 0), 1); - t.strictEqual(cast.compare(0, 1), -1); - t.strictEqual(cast.compare(1, 1), 0); + assert.strictEqual(cast.compare(0, 0), 0); + assert.strictEqual(cast.compare(1, 0), 1); + assert.strictEqual(cast.compare(0, 1), -1); + assert.strictEqual(cast.compare(1, 1), 0); // String - t.strictEqual(cast.compare('0', '0'), 0); - t.strictEqual(cast.compare('0.1e10', '1000000000'), 0); - t.strictEqual(cast.compare('foobar', 'FOOBAR'), 0); - t.ok(cast.compare('dog', 'cat') > 0); + assert.strictEqual(cast.compare('0', '0'), 0); + assert.strictEqual(cast.compare('0.1e10', '1000000000'), 0); + assert.strictEqual(cast.compare('foobar', 'FOOBAR'), 0); + assert.ok(cast.compare('dog', 'cat') > 0); // Boolean - t.strictEqual(cast.compare(true, true), 0); - t.strictEqual(cast.compare(true, false), 1); - t.strictEqual(cast.compare(false, true), -1); - t.strictEqual(cast.compare(true, true), 0); + assert.strictEqual(cast.compare(true, true), 0); + assert.strictEqual(cast.compare(true, false), 1); + assert.strictEqual(cast.compare(false, true), -1); + assert.strictEqual(cast.compare(true, true), 0); // Undefined & object - t.strictEqual(cast.compare(undefined, undefined), 0); - t.strictEqual(cast.compare(undefined, 'undefined'), 0); - t.strictEqual(cast.compare({}, {}), 0); - t.strictEqual(cast.compare({}, '[object Object]'), 0); - t.end(); + assert.strictEqual(cast.compare(undefined, undefined), 0); + assert.strictEqual(cast.compare(undefined, 'undefined'), 0); + assert.strictEqual(cast.compare({}, {}), 0); + assert.strictEqual(cast.compare({}, '[object Object]'), 0); }); -test('isInt', t => { +test('isInt', () => { // Numeric - t.strictEqual(cast.isInt(0), true); - t.strictEqual(cast.isInt(1), true); - t.strictEqual(cast.isInt(0.0), true); - t.strictEqual(cast.isInt(3.14), false); - t.strictEqual(cast.isInt(NaN), true); + assert.strictEqual(cast.isInt(0), true); + assert.strictEqual(cast.isInt(1), true); + assert.strictEqual(cast.isInt(0.0), true); + assert.strictEqual(cast.isInt(3.14), false); + assert.strictEqual(cast.isInt(NaN), true); // String - t.strictEqual(cast.isInt('0'), true); - t.strictEqual(cast.isInt('1'), true); - t.strictEqual(cast.isInt('0.0'), false); - t.strictEqual(cast.isInt('0.1e10'), false); - t.strictEqual(cast.isInt('3.14'), false); + assert.strictEqual(cast.isInt('0'), true); + assert.strictEqual(cast.isInt('1'), true); + assert.strictEqual(cast.isInt('0.0'), false); + assert.strictEqual(cast.isInt('0.1e10'), false); + assert.strictEqual(cast.isInt('3.14'), false); // Boolean - t.strictEqual(cast.isInt(true), true); - t.strictEqual(cast.isInt(false), true); + assert.strictEqual(cast.isInt(true), true); + assert.strictEqual(cast.isInt(false), true); // Undefined & object - t.strictEqual(cast.isInt(undefined), false); - t.strictEqual(cast.isInt({}), false); - t.end(); + assert.strictEqual(cast.isInt(undefined), false); + assert.strictEqual(cast.isInt({}), false); }); -test('toListIndex', t => { +test('toListIndex', () => { const list = [0, 1, 2, 3, 4, 5]; const empty = []; // Valid - t.strictEqual(cast.toListIndex(1, list.length, false), 1); - t.strictEqual(cast.toListIndex(6, list.length, false), 6); + assert.strictEqual(cast.toListIndex(1, list.length, false), 1); + assert.strictEqual(cast.toListIndex(6, list.length, false), 6); // Invalid - t.strictEqual(cast.toListIndex(-1, list.length, false), cast.LIST_INVALID); - t.strictEqual(cast.toListIndex(0.1, list.length, false), cast.LIST_INVALID); - t.strictEqual(cast.toListIndex(0, list.length, false), cast.LIST_INVALID); - t.strictEqual(cast.toListIndex(7, list.length, false), cast.LIST_INVALID); + assert.strictEqual(cast.toListIndex(-1, list.length, false), cast.LIST_INVALID); + assert.strictEqual(cast.toListIndex(0.1, list.length, false), cast.LIST_INVALID); + assert.strictEqual(cast.toListIndex(0, list.length, false), cast.LIST_INVALID); + assert.strictEqual(cast.toListIndex(7, list.length, false), cast.LIST_INVALID); // "all" - t.strictEqual(cast.toListIndex('all', list.length, true), cast.LIST_ALL); - t.strictEqual(cast.toListIndex('all', list.length, false), cast.LIST_INVALID); + assert.strictEqual(cast.toListIndex('all', list.length, true), cast.LIST_ALL); + assert.strictEqual(cast.toListIndex('all', list.length, false), cast.LIST_INVALID); // "last" - t.strictEqual(cast.toListIndex('last', list.length, false), list.length); - t.strictEqual(cast.toListIndex('last', empty.length, false), cast.LIST_INVALID); + assert.strictEqual(cast.toListIndex('last', list.length, false), list.length); + assert.strictEqual(cast.toListIndex('last', empty.length, false), cast.LIST_INVALID); // "random" const random = cast.toListIndex('random', list.length, false); - t.ok(random <= list.length); - t.ok(random > 0); - t.strictEqual(cast.toListIndex('random', empty.length, false), cast.LIST_INVALID); + assert.ok(random <= list.length); + assert.ok(random > 0); + assert.strictEqual(cast.toListIndex('random', empty.length, false), cast.LIST_INVALID); // "any" (alias for "random") const any = cast.toListIndex('any', list.length, false); - t.ok(any <= list.length); - t.ok(any > 0); - t.strictEqual(cast.toListIndex('any', empty.length, false), cast.LIST_INVALID); - t.end(); + assert.ok(any <= list.length); + assert.ok(any > 0); + assert.strictEqual(cast.toListIndex('any', empty.length, false), cast.LIST_INVALID); }); diff --git a/test/unit/util_color.js b/test/unit/util_color.js index 299a4e9f..407f9adf 100644 --- a/test/unit/util_color.js +++ b/test/unit/util_color.js @@ -1,135 +1,118 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const color = require('../../src/util/color'); /** * Assert that two HSV colors are similar to each other, within a tolerance. - * @param {Test} t - the Tap test object. * @param {HSVObject} actual - the first HSV color to compare. * @param {HSVObject} expected - the other HSV color to compare. */ -const hsvSimilar = function (t, actual, expected) { +const hsvSimilar = function (actual, expected) { if ((Math.abs(actual.h - expected.h) >= 1) || (Math.abs(actual.s - expected.s) >= 0.01) || (Math.abs(actual.v - expected.v) >= 0.01) ) { - t.fail('HSV colors not similar enough', { - actual: actual, - expected: expected - }); + assert.fail(`HSV colors not similar enough: ${JSON.stringify(actual)} vs ${JSON.stringify(expected)}`); } }; /** * Assert that two RGB colors are similar to each other, within a tolerance. - * @param {Test} t - the Tap test object. * @param {RGBObject} actual - the first RGB color to compare. * @param {RGBObject} expected - the other RGB color to compare. */ -const rgbSimilar = function (t, actual, expected) { +const rgbSimilar = function (actual, expected) { if ((Math.abs(actual.r - expected.r) >= 1) || (Math.abs(actual.g - expected.g) >= 1) || (Math.abs(actual.b - expected.b) >= 1) ) { - t.fail('RGB colors not similar enough', { - actual: actual, - expected: expected - }); + assert.fail(`RGB colors not similar enough: ${JSON.stringify(actual)} vs ${JSON.stringify(expected)}`); } }; -test('decimalToHex', t => { - t.strictEqual(color.decimalToHex(0), '#000000'); - t.strictEqual(color.decimalToHex(1), '#000001'); - t.strictEqual(color.decimalToHex(16777215), '#ffffff'); - t.strictEqual(color.decimalToHex(-16777215), '#000001'); - t.strictEqual(color.decimalToHex(99999999), '#5f5e0ff'); - t.end(); +test('decimalToHex', () => { + assert.strictEqual(color.decimalToHex(0), '#000000'); + assert.strictEqual(color.decimalToHex(1), '#000001'); + assert.strictEqual(color.decimalToHex(16777215), '#ffffff'); + assert.strictEqual(color.decimalToHex(-16777215), '#000001'); + assert.strictEqual(color.decimalToHex(99999999), '#5f5e0ff'); }); -test('decimalToRgb', t => { - t.deepEqual(color.decimalToRgb(0), {a: 255, r: 0, g: 0, b: 0}); - t.deepEqual(color.decimalToRgb(1), {a: 255, r: 0, g: 0, b: 1}); - t.deepEqual(color.decimalToRgb(16777215), {a: 255, r: 255, g: 255, b: 255}); - t.deepEqual(color.decimalToRgb(-16777215), {a: 255, r: 0, g: 0, b: 1}); - t.deepEqual(color.decimalToRgb(99999999), {a: 5, r: 245, g: 224, b: 255}); - t.end(); +test('decimalToRgb', () => { + assert.deepEqual(color.decimalToRgb(0), {a: 255, r: 0, g: 0, b: 0}); + assert.deepEqual(color.decimalToRgb(1), {a: 255, r: 0, g: 0, b: 1}); + assert.deepEqual(color.decimalToRgb(16777215), {a: 255, r: 255, g: 255, b: 255}); + assert.deepEqual(color.decimalToRgb(-16777215), {a: 255, r: 0, g: 0, b: 1}); + assert.deepEqual(color.decimalToRgb(99999999), {a: 5, r: 245, g: 224, b: 255}); }); -test('hexToRgb', t => { - t.deepEqual(color.hexToRgb('#000'), {r: 0, g: 0, b: 0}); - t.deepEqual(color.hexToRgb('#000000'), {r: 0, g: 0, b: 0}); - t.deepEqual(color.hexToRgb('#fff'), {r: 255, g: 255, b: 255}); - t.deepEqual(color.hexToRgb('#ffffff'), {r: 255, g: 255, b: 255}); - t.deepEqual(color.hexToRgb('#0fa'), {r: 0, g: 255, b: 170}); - t.deepEqual(color.hexToRgb('#00ffaa'), {r: 0, g: 255, b: 170}); - t.deepEqual(color.hexToRgb('#00FFaA'), {r: 0, g: 255, b: 170}); +test('hexToRgb', () => { + assert.deepEqual(color.hexToRgb('#000'), {r: 0, g: 0, b: 0}); + assert.deepEqual(color.hexToRgb('#000000'), {r: 0, g: 0, b: 0}); + assert.deepEqual(color.hexToRgb('#fff'), {r: 255, g: 255, b: 255}); + assert.deepEqual(color.hexToRgb('#ffffff'), {r: 255, g: 255, b: 255}); + assert.deepEqual(color.hexToRgb('#0fa'), {r: 0, g: 255, b: 170}); + assert.deepEqual(color.hexToRgb('#00ffaa'), {r: 0, g: 255, b: 170}); + assert.deepEqual(color.hexToRgb('#00FFaA'), {r: 0, g: 255, b: 170}); - t.deepEqual(color.hexToRgb('000'), {r: 0, g: 0, b: 0}); - t.deepEqual(color.hexToRgb('fff'), {r: 255, g: 255, b: 255}); - t.deepEqual(color.hexToRgb('aBc'), {r: 0xaa, g: 0xbb, b: 0xcc}); - t.deepEqual(color.hexToRgb('00ffaa'), {r: 0, g: 255, b: 170}); + assert.deepEqual(color.hexToRgb('000'), {r: 0, g: 0, b: 0}); + assert.deepEqual(color.hexToRgb('fff'), {r: 255, g: 255, b: 255}); + assert.deepEqual(color.hexToRgb('aBc'), {r: 0xaa, g: 0xbb, b: 0xcc}); + assert.deepEqual(color.hexToRgb('00ffaa'), {r: 0, g: 255, b: 170}); - t.deepEqual(color.hexToRgb('0'), null); - t.deepEqual(color.hexToRgb('hello world'), null); - t.deepEqual(color.hexToRgb('red'), null); - - t.end(); + assert.deepEqual(color.hexToRgb('0'), null); + assert.deepEqual(color.hexToRgb('hello world'), null); + assert.deepEqual(color.hexToRgb('red'), null); }); -test('rgbToHex', t => { - t.strictEqual(color.rgbToHex({r: 0, g: 0, b: 0}), '#000000'); - t.strictEqual(color.rgbToHex({r: 255, g: 255, b: 255}), '#ffffff'); - t.strictEqual(color.rgbToHex({r: 0, g: 255, b: 170}), '#00ffaa'); - t.end(); +test('rgbToHex', () => { + assert.strictEqual(color.rgbToHex({r: 0, g: 0, b: 0}), '#000000'); + assert.strictEqual(color.rgbToHex({r: 255, g: 255, b: 255}), '#ffffff'); + assert.strictEqual(color.rgbToHex({r: 0, g: 255, b: 170}), '#00ffaa'); }); -test('rgbToDecimal', t => { - t.strictEqual(color.rgbToDecimal({r: 0, g: 0, b: 0}), 0); - t.strictEqual(color.rgbToDecimal({r: 255, g: 255, b: 255}), 16777215); - t.strictEqual(color.rgbToDecimal({r: 0, g: 255, b: 170}), 65450); - t.end(); +test('rgbToDecimal', () => { + assert.strictEqual(color.rgbToDecimal({r: 0, g: 0, b: 0}), 0); + assert.strictEqual(color.rgbToDecimal({r: 255, g: 255, b: 255}), 16777215); + assert.strictEqual(color.rgbToDecimal({r: 0, g: 255, b: 170}), 65450); }); -test('hexToDecimal', t => { - t.strictEqual(color.hexToDecimal('#000'), 0); - t.strictEqual(color.hexToDecimal('#000000'), 0); - t.strictEqual(color.hexToDecimal('#fff'), 16777215); - t.strictEqual(color.hexToDecimal('#ffffff'), 16777215); - t.strictEqual(color.hexToDecimal('#0fa'), 65450); - t.strictEqual(color.hexToDecimal('#00ffaa'), 65450); - t.end(); +test('hexToDecimal', () => { + assert.strictEqual(color.hexToDecimal('#000'), 0); + assert.strictEqual(color.hexToDecimal('#000000'), 0); + assert.strictEqual(color.hexToDecimal('#fff'), 16777215); + assert.strictEqual(color.hexToDecimal('#ffffff'), 16777215); + assert.strictEqual(color.hexToDecimal('#0fa'), 65450); + assert.strictEqual(color.hexToDecimal('#00ffaa'), 65450); }); -test('hsvToRgb', t => { - rgbSimilar(t, color.hsvToRgb({h: 0, s: 0, v: 0}), {r: 0, g: 0, b: 0}); - rgbSimilar(t, color.hsvToRgb({h: 123, s: 0.1234, v: 0}), {r: 0, g: 0, b: 0}); - rgbSimilar(t, color.hsvToRgb({h: 0, s: 0, v: 1}), {r: 255, g: 255, b: 255}); - rgbSimilar(t, color.hsvToRgb({h: 321, s: 0, v: 1}), {r: 255, g: 255, b: 255}); - rgbSimilar(t, color.hsvToRgb({h: 0, s: 1, v: 1}), {r: 255, g: 0, b: 0}); - rgbSimilar(t, color.hsvToRgb({h: 120, s: 1, v: 1}), {r: 0, g: 255, b: 0}); - rgbSimilar(t, color.hsvToRgb({h: 240, s: 1, v: 1}), {r: 0, g: 0, b: 255}); - t.end(); +test('hsvToRgb', () => { + rgbSimilar(color.hsvToRgb({h: 0, s: 0, v: 0}), {r: 0, g: 0, b: 0}); + rgbSimilar(color.hsvToRgb({h: 123, s: 0.1234, v: 0}), {r: 0, g: 0, b: 0}); + rgbSimilar(color.hsvToRgb({h: 0, s: 0, v: 1}), {r: 255, g: 255, b: 255}); + rgbSimilar(color.hsvToRgb({h: 321, s: 0, v: 1}), {r: 255, g: 255, b: 255}); + rgbSimilar(color.hsvToRgb({h: 0, s: 1, v: 1}), {r: 255, g: 0, b: 0}); + rgbSimilar(color.hsvToRgb({h: 120, s: 1, v: 1}), {r: 0, g: 255, b: 0}); + rgbSimilar(color.hsvToRgb({h: 240, s: 1, v: 1}), {r: 0, g: 0, b: 255}); }); -test('rgbToHsv', t => { - hsvSimilar(t, color.rgbToHsv({r: 0, g: 0, b: 0}), {h: 0, s: 0, v: 0}); - hsvSimilar(t, color.rgbToHsv({r: 64, g: 64, b: 64}), {h: 0, s: 0, v: 0.25}); - hsvSimilar(t, color.rgbToHsv({r: 128, g: 128, b: 128}), {h: 0, s: 0, v: 0.5}); - hsvSimilar(t, color.rgbToHsv({r: 192, g: 192, b: 192}), {h: 0, s: 0, v: 0.75}); - hsvSimilar(t, color.rgbToHsv({r: 255, g: 255, b: 255}), {h: 0, s: 0, v: 1}); - hsvSimilar(t, color.rgbToHsv({r: 255, g: 0, b: 0}), {h: 0, s: 1, v: 1}); - hsvSimilar(t, color.rgbToHsv({r: 0, g: 255, b: 0}), {h: 120, s: 1, v: 1}); - hsvSimilar(t, color.rgbToHsv({r: 0, g: 0, b: 255}), {h: 240, s: 1, v: 1}); - t.end(); +test('rgbToHsv', () => { + hsvSimilar(color.rgbToHsv({r: 0, g: 0, b: 0}), {h: 0, s: 0, v: 0}); + hsvSimilar(color.rgbToHsv({r: 64, g: 64, b: 64}), {h: 0, s: 0, v: 0.25}); + hsvSimilar(color.rgbToHsv({r: 128, g: 128, b: 128}), {h: 0, s: 0, v: 0.5}); + hsvSimilar(color.rgbToHsv({r: 192, g: 192, b: 192}), {h: 0, s: 0, v: 0.75}); + hsvSimilar(color.rgbToHsv({r: 255, g: 255, b: 255}), {h: 0, s: 0, v: 1}); + hsvSimilar(color.rgbToHsv({r: 255, g: 0, b: 0}), {h: 0, s: 1, v: 1}); + hsvSimilar(color.rgbToHsv({r: 0, g: 255, b: 0}), {h: 120, s: 1, v: 1}); + hsvSimilar(color.rgbToHsv({r: 0, g: 0, b: 255}), {h: 240, s: 1, v: 1}); }); -test('mixRgb', t => { - rgbSimilar(t, color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, -1), {r: 10, g: 20, b: 30}); - rgbSimilar(t, color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, 0), {r: 10, g: 20, b: 30}); - rgbSimilar(t, color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, 0.25), {r: 15, g: 25, b: 35}); - rgbSimilar(t, color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, 0.5), {r: 20, g: 30, b: 40}); - rgbSimilar(t, color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, 0.75), {r: 25, g: 35, b: 45}); - rgbSimilar(t, color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, 1), {r: 30, g: 40, b: 50}); - rgbSimilar(t, color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, 2), {r: 30, g: 40, b: 50}); - t.end(); +test('mixRgb', () => { + rgbSimilar(color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, -1), {r: 10, g: 20, b: 30}); + rgbSimilar(color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, 0), {r: 10, g: 20, b: 30}); + rgbSimilar(color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, 0.25), {r: 15, g: 25, b: 35}); + rgbSimilar(color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, 0.5), {r: 20, g: 30, b: 40}); + rgbSimilar(color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, 0.75), {r: 25, g: 35, b: 45}); + rgbSimilar(color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, 1), {r: 30, g: 40, b: 50}); + rgbSimilar(color.mixRgb({r: 10, g: 20, b: 30}, {r: 30, g: 40, b: 50}, 2), {r: 30, g: 40, b: 50}); }); diff --git a/test/unit/util_jsonrpc-web-socket.js b/test/unit/util_jsonrpc-web-socket.js index ba03e83a..4df17712 100644 --- a/test/unit/util_jsonrpc-web-socket.js +++ b/test/unit/util_jsonrpc-web-socket.js @@ -1,10 +1,6 @@ -const test = require('tap').test; +const {test} = require('node:test'); // const JSONRPCWebSocket = require('../../src/util/jsonrpc-web-socket'); -test('constructor', t => { - t.end(); -}); +test('constructor', () => {}); -test('dispose', t => { - t.end(); -}); +test('dispose', () => {}); diff --git a/test/unit/util_jsonrpc.js b/test/unit/util_jsonrpc.js index 33c103b8..de33b950 100644 --- a/test/unit/util_jsonrpc.js +++ b/test/unit/util_jsonrpc.js @@ -1,18 +1,10 @@ -const test = require('tap').test; +const {test} = require('node:test'); // const JSONRPC = require('../../src/util/jsonrpc'); -test('constructor', t => { - t.end(); -}); +test('constructor', () => {}); -test('sendRemoteRequest', t => { - t.end(); -}); +test('sendRemoteRequest', () => {}); -test('sendRemoteNotification', t => { - t.end(); -}); +test('sendRemoteNotification', () => {}); -test('didReceiveCall', t => { - t.end(); -}); +test('didReceiveCall', () => {}); diff --git a/test/unit/util_math.js b/test/unit/util_math.js index c93f17fa..493dad39 100644 --- a/test/unit/util_math.js +++ b/test/unit/util_math.js @@ -1,55 +1,50 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const math = require('../../src/util/math-util'); -test('degToRad', t => { - t.strictEqual(math.degToRad(0), 0); - t.strictEqual(math.degToRad(1), 0.017453292519943295); - t.strictEqual(math.degToRad(180), Math.PI); - t.strictEqual(math.degToRad(360), 2 * Math.PI); - t.strictEqual(math.degToRad(720), 4 * Math.PI); - t.end(); +test('degToRad', () => { + assert.strictEqual(math.degToRad(0), 0); + assert.strictEqual(math.degToRad(1), 0.017453292519943295); + assert.strictEqual(math.degToRad(180), Math.PI); + assert.strictEqual(math.degToRad(360), 2 * Math.PI); + assert.strictEqual(math.degToRad(720), 4 * Math.PI); }); -test('radToDeg', t => { - t.strictEqual(math.radToDeg(0), 0); - t.strictEqual(math.radToDeg(1), 57.29577951308232); - t.strictEqual(math.radToDeg(180), 10313.240312354817); - t.strictEqual(math.radToDeg(360), 20626.480624709635); - t.strictEqual(math.radToDeg(720), 41252.96124941927); - t.end(); +test('radToDeg', () => { + assert.strictEqual(math.radToDeg(0), 0); + assert.strictEqual(math.radToDeg(1), 57.29577951308232); + assert.strictEqual(math.radToDeg(180), 10313.240312354817); + assert.strictEqual(math.radToDeg(360), 20626.480624709635); + assert.strictEqual(math.radToDeg(720), 41252.96124941927); }); -test('clamp', t => { - t.strictEqual(math.clamp(0, 0, 10), 0); - t.strictEqual(math.clamp(1, 0, 10), 1); - t.strictEqual(math.clamp(-10, 0, 10), 0); - t.strictEqual(math.clamp(100, 0, 10), 10); - t.end(); +test('clamp', () => { + assert.strictEqual(math.clamp(0, 0, 10), 0); + assert.strictEqual(math.clamp(1, 0, 10), 1); + assert.strictEqual(math.clamp(-10, 0, 10), 0); + assert.strictEqual(math.clamp(100, 0, 10), 10); }); -test('wrapClamp', t => { - t.strictEqual(math.wrapClamp(0, 0, 10), 0); - t.strictEqual(math.wrapClamp(1, 0, 10), 1); - t.strictEqual(math.wrapClamp(-10, 0, 10), 1); - t.strictEqual(math.wrapClamp(100, 0, 10), 1); - t.end(); +test('wrapClamp', () => { + assert.strictEqual(math.wrapClamp(0, 0, 10), 0); + assert.strictEqual(math.wrapClamp(1, 0, 10), 1); + assert.strictEqual(math.wrapClamp(-10, 0, 10), 1); + assert.strictEqual(math.wrapClamp(100, 0, 10), 1); }); -test('tan', t => { - t.strictEqual(math.tan(90), Infinity); - t.strictEqual(math.tan(180), 0); - t.strictEqual(math.tan(-90), -Infinity); - t.strictEqual(math.tan(33), 0.6494075932); - t.end(); +test('tan', () => { + assert.strictEqual(math.tan(90), Infinity); + assert.strictEqual(math.tan(180), -0); + assert.strictEqual(math.tan(-90), -Infinity); + assert.strictEqual(math.tan(33), 0.6494075932); }); -test('reducedSortOrdering', t => { - t.deepEqual(math.reducedSortOrdering([5, 18, 6, 3]), [1, 3, 2, 0]); - t.deepEqual(math.reducedSortOrdering([5, 1, 56, 19]), [1, 0, 3, 2]); - t.end(); +test('reducedSortOrdering', () => { + assert.deepEqual(math.reducedSortOrdering([5, 18, 6, 3]), [1, 3, 2, 0]); + assert.deepEqual(math.reducedSortOrdering([5, 1, 56, 19]), [1, 0, 3, 2]); }); -test('inclusiveRandIntWithout', t => { +test('inclusiveRandIntWithout', () => { const withRandomValue = function (randValue, ...args) { const oldMathRandom = Math.random; Object.assign(global.Math, {random: () => randValue}); @@ -58,13 +53,11 @@ test('inclusiveRandIntWithout', t => { return result; }; - t.strictEqual(withRandomValue(3 / 6, 0, 6, 2), 4); - t.strictEqual(withRandomValue(2 / 6, 0, 6, 2), 3); - t.strictEqual(withRandomValue(1 / 6, 0, 6, 2), 1); - t.strictEqual(withRandomValue(1.9 / 6, 0, 6, 2), 1); + assert.strictEqual(withRandomValue(3 / 6, 0, 6, 2), 4); + assert.strictEqual(withRandomValue(2 / 6, 0, 6, 2), 3); + assert.strictEqual(withRandomValue(1 / 6, 0, 6, 2), 1); + assert.strictEqual(withRandomValue(1.9 / 6, 0, 6, 2), 1); - t.strictEqual(withRandomValue(3 / 4, 10, 14, 10), 14); - t.strictEqual(withRandomValue(0 / 4, 10, 14, 10), 11); - - t.end(); + assert.strictEqual(withRandomValue(3 / 4, 10, 14, 10), 14); + assert.strictEqual(withRandomValue(0 / 4, 10, 14, 10), 11); }); diff --git a/test/unit/util_new-block-ids.js b/test/unit/util_new-block-ids.js index 58a4b8ff..2ce5a2b5 100644 --- a/test/unit/util_new-block-ids.js +++ b/test/unit/util_new-block-ids.js @@ -1,12 +1,12 @@ const newBlockIds = require('../../src/util/new-block-ids'); const simpleStack = require('../fixtures/simple-stack'); -const tap = require('tap'); -const test = tap.test; +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); let originals; let newBlocks; -tap.beforeEach(() => { +beforeEach(() => { originals = simpleStack; // Will be mutated so make a copy first newBlocks = JSON.parse(JSON.stringify(simpleStack)); @@ -25,39 +25,32 @@ tap.beforeEach(() => { * Inspect fixtures/simple-stack for the full object. */ -test('top-level block IDs have all changed', t => { +test('top-level block IDs have all changed', () => { newBlocks.forEach((block, i) => { - t.notEqual(block.id, originals[i].id); + assert.notStrictEqual(block.id, originals[i].id); }); - t.end(); }); -test('input reference is maintained on parent for attached block', t => { - t.equal(newBlocks[0].inputs.TO.block, newBlocks[1].id); - t.end(); +test('input reference is maintained on parent for attached block', () => { + assert.strictEqual(newBlocks[0].inputs.TO.block, newBlocks[1].id); }); -test('input reference is maintained on parent for obscured shadow', t => { - t.equal(newBlocks[0].inputs.TO.shadow, newBlocks[2].id); - t.end(); +test('input reference is maintained on parent for obscured shadow', () => { + assert.strictEqual(newBlocks[0].inputs.TO.shadow, newBlocks[2].id); }); -test('parent reference is maintained for attached input', t => { - t.equal(newBlocks[1].parent, newBlocks[0].id); - t.end(); +test('parent reference is maintained for attached input', () => { + assert.strictEqual(newBlocks[1].parent, newBlocks[0].id); }); -test('parent reference is maintained for obscured shadow', t => { - t.equal(newBlocks[2].parent, newBlocks[0].id); - t.end(); +test('parent reference is maintained for obscured shadow', () => { + assert.strictEqual(newBlocks[2].parent, newBlocks[0].id); }); -test('parent reference is maintained for next block', t => { - t.equal(newBlocks[3].parent, newBlocks[0].id); - t.end(); +test('parent reference is maintained for next block', () => { + assert.strictEqual(newBlocks[3].parent, newBlocks[0].id); }); -test('next reference is maintained for previous block', t => { - t.equal(newBlocks[0].next, newBlocks[3].id); - t.end(); +test('next reference is maintained for previous block', () => { + assert.strictEqual(newBlocks[0].next, newBlocks[3].id); }); diff --git a/test/unit/util_rateLimiter.js b/test/unit/util_rateLimiter.js index 1e34d910..fa907b47 100644 --- a/test/unit/util_rateLimiter.js +++ b/test/unit/util_rateLimiter.js @@ -1,7 +1,8 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const RateLimiter = require('../../src/util/rateLimiter.js'); -test('rate limiter', t => { +test('rate limiter', () => { // Create a rate limiter with maximum of 20 sends per second const rate = 20; const limiter = new RateLimiter(rate); @@ -11,22 +12,20 @@ test('rate limiter', t => { limiter._timer = {timeElapsed: () => simulatedTime}; // The rate limiter starts with a number of tokens equal to the max rate - t.equal(limiter._count, rate); + assert.strictEqual(limiter._count, rate); // Running okayToSend a number of times equal to the max rate // uses up all of the tokens for (let i = 0; i < rate; i++) { - t.true(limiter.okayToSend()); + assert.ok(limiter.okayToSend()); // Tokens are counting down - t.equal(limiter._count, rate - (i + 1)); + assert.strictEqual(limiter._count, rate - (i + 1)); } - t.false(limiter.okayToSend()); + assert.ok(!limiter.okayToSend()); // Advance the timer enough so we get exactly one more token // One extra millisecond is required to get over the threshold simulatedTime += (1000 / rate) + 1; - t.true(limiter.okayToSend()); - t.false(limiter.okayToSend()); - - t.end(); + assert.ok(limiter.okayToSend()); + assert.ok(!limiter.okayToSend()); }); diff --git a/test/unit/util_string.js b/test/unit/util_string.js index 199fa27c..01fbd341 100644 --- a/test/unit/util_string.js +++ b/test/unit/util_string.js @@ -1,70 +1,68 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const StringUtil = require('../../src/util/string-util'); -test('splitFirst', t => { - t.deepEqual(StringUtil.splitFirst('asdf.1234', '.'), ['asdf', '1234']); - t.deepEqual(StringUtil.splitFirst('asdf.', '.'), ['asdf', '']); - t.deepEqual(StringUtil.splitFirst('.1234', '.'), ['', '1234']); - t.deepEqual(StringUtil.splitFirst('foo', '.'), ['foo', null]); - t.end(); +test('splitFirst', () => { + assert.deepEqual(StringUtil.splitFirst('asdf.1234', '.'), ['asdf', '1234']); + assert.deepEqual(StringUtil.splitFirst('asdf.', '.'), ['asdf', '']); + assert.deepEqual(StringUtil.splitFirst('.1234', '.'), ['', '1234']); + assert.deepEqual(StringUtil.splitFirst('foo', '.'), ['foo', null]); }); -test('withoutTrailingDigits', t => { - t.strictEqual(StringUtil.withoutTrailingDigits('boeing747'), 'boeing'); - t.strictEqual(StringUtil.withoutTrailingDigits('boeing747 '), 'boeing747 '); - t.strictEqual(StringUtil.withoutTrailingDigits('boeing𝟨'), 'boeing𝟨'); - t.strictEqual(StringUtil.withoutTrailingDigits('boeing 747'), 'boeing '); - t.strictEqual(StringUtil.withoutTrailingDigits('747'), ''); - t.end(); +test('withoutTrailingDigits', () => { + assert.strictEqual(StringUtil.withoutTrailingDigits('boeing747'), 'boeing'); + assert.strictEqual(StringUtil.withoutTrailingDigits('boeing747 '), 'boeing747 '); + assert.strictEqual(StringUtil.withoutTrailingDigits('boeing𝟨'), 'boeing𝟨'); + assert.strictEqual(StringUtil.withoutTrailingDigits('boeing 747'), 'boeing '); + assert.strictEqual(StringUtil.withoutTrailingDigits('747'), ''); }); -test('unusedName', t => { - t.strictEqual( +test('unusedName', () => { + assert.strictEqual( StringUtil.unusedName( 'name', ['not the same name'] ), 'name' ); - t.strictEqual( + assert.strictEqual( StringUtil.unusedName( 'name', ['name'] ), 'name2' ); - t.strictEqual( + assert.strictEqual( StringUtil.unusedName( 'name', ['name30'] ), 'name' ); - t.strictEqual( + assert.strictEqual( StringUtil.unusedName( 'name', ['name', 'name2'] ), 'name3' ); - t.strictEqual( + assert.strictEqual( StringUtil.unusedName( 'name', ['name', 'name3'] ), 'name2' ); - t.strictEqual( + assert.strictEqual( StringUtil.unusedName( 'boeing747', ['boeing747'] ), 'boeing2' // Yup, this matches scratch-flash... ); - t.end(); }); -test('stringify', t => { +test('stringify', () => { const obj = { a: Infinity, b: NaN, @@ -76,54 +74,49 @@ test('stringify', t => { } }; const parsed = JSON.parse(StringUtil.stringify(obj)); - t.equal(parsed.a, 0); - t.equal(parsed.b, 0); - t.equal(parsed.c, 0); - t.equal(parsed.d, 23); - t.equal(parsed.e, 'str'); - t.equal(parsed.f.nested, 0); - t.end(); + assert.strictEqual(parsed.a, 0); + assert.strictEqual(parsed.b, 0); + assert.strictEqual(parsed.c, 0); + assert.strictEqual(parsed.d, 23); + assert.strictEqual(parsed.e, 'str'); + assert.strictEqual(parsed.f.nested, 0); }); -test('replaceUnsafeChars', t => { +test('replaceUnsafeChars', () => { const empty = ''; - t.equal(StringUtil.replaceUnsafeChars(empty), empty); + assert.strictEqual(StringUtil.replaceUnsafeChars(empty), empty); const safe = 'hello'; - t.equal(StringUtil.replaceUnsafeChars(safe), safe); + assert.strictEqual(StringUtil.replaceUnsafeChars(safe), safe); const unsafe = '< > & \' "'; - t.equal(StringUtil.replaceUnsafeChars(unsafe), 'lt gt amp apos quot'); + assert.strictEqual(StringUtil.replaceUnsafeChars(unsafe), 'lt gt amp apos quot'); const single = '&'; - t.equal(StringUtil.replaceUnsafeChars(single), 'amp'); + assert.strictEqual(StringUtil.replaceUnsafeChars(single), 'amp'); const mix = 'b& c\'def_-"'; - t.equal(StringUtil.replaceUnsafeChars(mix), 'ltagtbamp caposdef_-quot'); + assert.strictEqual(StringUtil.replaceUnsafeChars(mix), 'ltagtbamp caposdef_-quot'); const dupes = '<<&_"_"_&>>'; - t.equal(StringUtil.replaceUnsafeChars(dupes), 'ltltamp_quot_quot_ampgtgt'); + assert.strictEqual(StringUtil.replaceUnsafeChars(dupes), 'ltltamp_quot_quot_ampgtgt'); const emoji = '(>^_^)>'; - t.equal(StringUtil.replaceUnsafeChars(emoji), '(gt^_^)gt'); - - t.end(); + assert.strictEqual(StringUtil.replaceUnsafeChars(emoji), '(gt^_^)gt'); }); -test('replaceUnsafeChars should handle non strings', t => { +test('replaceUnsafeChars should handle non strings', () => { const array = ['hello', 'world']; - t.equal(StringUtil.replaceUnsafeChars(array), String(array)); + assert.strictEqual(StringUtil.replaceUnsafeChars(array), String(array)); const arrayWithSpecialChar = ['hello', '']; - t.equal(StringUtil.replaceUnsafeChars(arrayWithSpecialChar), 'hello,ltworldgt'); + assert.strictEqual(StringUtil.replaceUnsafeChars(arrayWithSpecialChar), 'hello,ltworldgt'); const arrayWithNumbers = [1, 2, 3]; - t.equal(StringUtil.replaceUnsafeChars(arrayWithNumbers), '1,2,3'); + assert.strictEqual(StringUtil.replaceUnsafeChars(arrayWithNumbers), '1,2,3'); // Objects shouldn't get provided to replaceUnsafeChars, but in the event // they do, it should just return the object (and log an error) const object = {hello: 'world'}; - t.equal(StringUtil.replaceUnsafeChars(object), object); - - t.end(); + assert.strictEqual(StringUtil.replaceUnsafeChars(object), object); }); diff --git a/test/unit/util_task-queue.js b/test/unit/util_task-queue.js index 6e484a7a..73494ac2 100644 --- a/test/unit/util_task-queue.js +++ b/test/unit/util_task-queue.js @@ -1,4 +1,5 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const TaskQueue = require('../../src/util/task-queue'); @@ -22,30 +23,27 @@ const makeTestQueue = () => { return bukkit; }; -test('spec', t => { - t.type(TaskQueue, 'function'); +test('spec', () => { + assert.strictEqual(typeof TaskQueue, 'function'); const bukkit = makeTestQueue(); - t.type(bukkit, 'object'); + assert.strictEqual(typeof bukkit, 'object'); - t.type(bukkit.length, 'number'); - t.type(bukkit.do, 'function'); - t.type(bukkit.cancel, 'function'); - t.type(bukkit.cancelAll, 'function'); - - t.end(); + assert.strictEqual(typeof bukkit.length, 'number'); + assert.strictEqual(typeof bukkit.do, 'function'); + assert.strictEqual(typeof bukkit.cancel, 'function'); + assert.strictEqual(typeof bukkit.cancelAll, 'function'); }); -test('constructor', t => { - t.ok(new TaskQueue(1, 1)); - t.ok(new TaskQueue(1, 1, {})); - t.ok(new TaskQueue(1, 1, {startingTokens: 0})); - t.ok(new TaskQueue(1, 1, {maxTotalCost: 999})); - t.ok(new TaskQueue(1, 1, {startingTokens: 0, maxTotalCost: 999})); - t.end(); +test('constructor', () => { + assert.ok(new TaskQueue(1, 1)); + assert.ok(new TaskQueue(1, 1, {})); + assert.ok(new TaskQueue(1, 1, {startingTokens: 0})); + assert.ok(new TaskQueue(1, 1, {maxTotalCost: 999})); + assert.ok(new TaskQueue(1, 1, {startingTokens: 0, maxTotalCost: 999})); }); -test('run tasks', async t => { +test('run tasks', async () => { const bukkit = makeTestQueue(); const taskResults = []; @@ -53,15 +51,15 @@ test('run tasks', async t => { const promises = [ bukkit.do(() => { taskResults.push('a'); - testCompare(t, bukkit._timer.timeElapsed(), '>=', 50, 'Costly task must wait'); + testCompare(bukkit._timer.timeElapsed(), '>=', 50, 'Costly task must wait'); }, 50), bukkit.do(() => { taskResults.push('b'); - testCompare(t, bukkit._timer.timeElapsed(), '>=', 60, 'Tasks must run in serial'); + testCompare(bukkit._timer.timeElapsed(), '>=', 60, 'Tasks must run in serial'); }, 10), bukkit.do(() => { taskResults.push('c'); - testCompare(t, bukkit._timer.timeElapsed(), '<=', 70, 'Cheap task should run soon'); + testCompare(bukkit._timer.timeElapsed(), '<=', 70, 'Cheap task should run soon'); }, 1) ]; @@ -70,13 +68,11 @@ test('run tasks', async t => { await bukkit._timer.advanceMockTimeAsync(10); } - return Promise.all(promises).then(() => { - t.deepEqual(taskResults, ['a', 'b', 'c'], 'All tasks must run in correct order'); - t.end(); - }); + await Promise.all(promises); + assert.deepEqual(taskResults, ['a', 'b', 'c'], 'All tasks must run in correct order'); }); -test('cancel', async t => { +test('cancel', async () => { const bukkit = makeTestQueue(); const taskResults = []; @@ -88,7 +84,7 @@ test('cancel', async t => { }, 999); const cancelCheckPromise = cancelTaskPromise.then( () => { - t.fail('Task should have been canceled'); + assert.fail('Task should have been canceled'); }, () => { taskResults.push(goodCancelMessage); @@ -97,28 +93,26 @@ test('cancel', async t => { const keepTaskPromise = bukkit.do( () => { taskResults.push(afterCancelMessage); - testCompare(t, bukkit._timer.timeElapsed(), '<', 10, 'Canceled task must not delay other tasks'); + testCompare(bukkit._timer.timeElapsed(), '<', 10, 'Canceled task must not delay other tasks'); }, 5); // give the bucket a chance to make a mistake await bukkit._timer.advanceMockTimeAsync(1); - t.equal(bukkit.length, 2); + assert.strictEqual(bukkit.length, 2); const taskWasCanceled = bukkit.cancel(cancelTaskPromise); - t.ok(taskWasCanceled); - t.equal(bukkit.length, 1); + assert.ok(taskWasCanceled); + assert.strictEqual(bukkit.length, 1); while (bukkit.length > 0) { await bukkit._timer.advanceMockTimeAsync(1); } - return Promise.all([cancelCheckPromise, keepTaskPromise]).then(() => { - t.deepEqual(taskResults, [goodCancelMessage, afterCancelMessage]); - t.end(); - }); + await Promise.all([cancelCheckPromise, keepTaskPromise]); + assert.deepEqual(taskResults, [goodCancelMessage, afterCancelMessage]); }); -test('cancelAll', async t => { +test('cancelAll', async () => { const bukkit = makeTestQueue(); const taskResults = []; @@ -128,7 +122,7 @@ test('cancelAll', async t => { const promises = [ bukkit.do(() => taskResults.push('nope'), 999).then( () => { - t.fail('Task1 should have been canceled'); + assert.fail('Task1 should have been canceled'); }, () => { taskResults.push(goodCancelMessage1); @@ -136,7 +130,7 @@ test('cancelAll', async t => { ), bukkit.do(() => taskResults.push('nah'), 999).then( () => { - t.fail('Task2 should have been canceled'); + assert.fail('Task2 should have been canceled'); }, () => { taskResults.push(goodCancelMessage2); @@ -152,13 +146,11 @@ test('cancelAll', async t => { // advance enough that both tasks would run if they hadn't been canceled await bukkit._timer.advanceMockTimeAsync(10000); - return Promise.all(promises).then(() => { - t.deepEqual(taskResults, [goodCancelMessage1, goodCancelMessage2], 'Tasks should cancel in order'); - t.end(); - }); + await Promise.all(promises); + assert.deepEqual(taskResults, [goodCancelMessage1, goodCancelMessage2], 'Tasks should cancel in order'); }); -test('max total cost', async t => { +test('max total cost', async () => { const bukkit = makeTestQueue(); let numTasks = 0; @@ -171,22 +163,14 @@ test('max total cost', async t => { } // This one should be rejected because the queue is full - bukkit - .do(task, 1000) - .then( - () => { - t.fail('Full queue did not reject task'); - }, - () => { - t.pass(); - } - ); + const rejection = assert.rejects(bukkit.do(task, 1000)); while (bukkit.length > 0) { await bukkit._timer.advanceMockTimeAsync(1000); } + await rejection; + // this should be 10 if the last task is rejected or 11 if it runs - t.equal(numTasks, 10); - t.end(); + assert.strictEqual(numTasks, 10); }); diff --git a/test/unit/util_timer.js b/test/unit/util_timer.js index 5235f543..5000654e 100644 --- a/test/unit/util_timer.js +++ b/test/unit/util_timer.js @@ -1,4 +1,5 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const Timer = require('../../src/util/timer'); // Stubbed current time @@ -11,31 +12,28 @@ const testNow = { } }; -test('spec', t => { +test('spec', () => { const timer = new Timer(testNow); - t.type(Timer, 'function'); - t.type(timer, 'object'); + assert.strictEqual(typeof Timer, 'function'); + assert.strictEqual(typeof timer, 'object'); - t.type(timer.startTime, 'number'); - t.type(timer.time, 'function'); - t.type(timer.start, 'function'); - t.type(timer.timeElapsed, 'function'); - t.type(timer.setTimeout, 'function'); - t.type(timer.clearTimeout, 'function'); - - t.end(); + assert.strictEqual(typeof timer.startTime, 'number'); + assert.strictEqual(typeof timer.time, 'function'); + assert.strictEqual(typeof timer.start, 'function'); + assert.strictEqual(typeof timer.timeElapsed, 'function'); + assert.strictEqual(typeof timer.setTimeout, 'function'); + assert.strictEqual(typeof timer.clearTimeout, 'function'); }); -test('time', t => { +test('time', () => { const timer = new Timer(testNow); const time = timer.time(); - t.ok(testNow.now() >= time); - t.end(); + assert.ok(testNow.now() >= time); }); -test('start / timeElapsed', t => { +test('start / timeElapsed', () => { const timer = new Timer(testNow); const delay = 100; const threshold = 1000 / 60; // 60 hz @@ -45,20 +43,18 @@ test('start / timeElapsed', t => { // Measure timer const timeElapsed = timer.timeElapsed(); - t.ok(timeElapsed >= 0); - t.ok(timeElapsed >= (delay - threshold) && + assert.ok(timeElapsed >= 0); + assert.ok(timeElapsed >= (delay - threshold) && timeElapsed <= (delay + threshold)); - t.end(); }); -test('setTimeout / clearTimeout', t => new Promise((resolve, reject) => { +test('setTimeout / clearTimeout', () => new Promise((resolve, reject) => { const timer = new Timer(testNow); const cancelId = timer.setTimeout(() => { reject(new Error('Canceled task ran')); }, 1); timer.setTimeout(() => { resolve('Non-canceled task ran'); - t.end(); }, 2); timer.clearTimeout(cancelId); })); diff --git a/test/unit/util_variable.js b/test/unit/util_variable.js index 18b0e768..297b0d19 100644 --- a/test/unit/util_variable.js +++ b/test/unit/util_variable.js @@ -1,4 +1,5 @@ -const tap = require('tap'); +const {test, beforeEach} = require('node:test'); +const assert = require('node:assert'); const Target = require('../../src/engine/target'); const Runtime = require('../../src/engine/runtime'); const VariableUtil = require('../../src/util/variable-util'); @@ -6,7 +7,7 @@ const VariableUtil = require('../../src/util/variable-util'); let target1; let target2; -tap.beforeEach(() => { +beforeEach(() => { const runtime = new Runtime(); target1 = new Target(runtime); target1.blocks.createBlock({ @@ -50,34 +51,26 @@ tap.beforeEach(() => { return Promise.resolve(null); }); -const test = tap.test; - -test('get all var refs', t => { +test('get all var refs', () => { const allVarRefs = VariableUtil.getAllVarRefsForTargets([target1, target2]); - t.equal(Object.keys(allVarRefs).length, 2); - t.equal(allVarRefs.id1.length, 2); - t.equal(allVarRefs.id2.length, 1); - t.equal(allVarRefs['not a variable'], undefined); - - t.end(); + assert.strictEqual(Object.keys(allVarRefs).length, 2); + assert.strictEqual(allVarRefs.id1.length, 2); + assert.strictEqual(allVarRefs.id2.length, 1); + assert.strictEqual(allVarRefs['not a variable'], undefined); }); -test('merge variable ids', t => { +test('merge variable ids', () => { // Redo the id for the variable with 'id1' VariableUtil.updateVariableIdentifiers(target1.blocks.getAllVariableAndListReferences().id1, 'renamed id'); const varField = target1.blocks.getBlock('a block').fields.VARIABLE; - t.equals(varField.id, 'renamed id'); - t.equals(varField.value, 'foo'); - - t.end(); + assert.strictEqual(varField.id, 'renamed id'); + assert.strictEqual(varField.value, 'foo'); }); -test('merge variable ids but with new name too', t => { +test('merge variable ids but with new name too', () => { // Redo the id for the variable with 'id1' VariableUtil.updateVariableIdentifiers(target1.blocks.getAllVariableAndListReferences().id1, 'renamed id', 'baz'); const varField = target1.blocks.getBlock('a block').fields.VARIABLE; - t.equals(varField.id, 'renamed id'); - t.equals(varField.value, 'baz'); - - t.end(); + assert.strictEqual(varField.id, 'renamed id'); + assert.strictEqual(varField.value, 'baz'); }); diff --git a/test/unit/util_xml.js b/test/unit/util_xml.js index bb7607a6..3fee711b 100644 --- a/test/unit/util_xml.js +++ b/test/unit/util_xml.js @@ -1,52 +1,48 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const xml = require('../../src/util/xml-escape'); -test('escape', t => { +test('escape', () => { const input = ''; const output = '<foo bar="he & llo '"></foo>'; - t.strictEqual(xml(input), output); - t.end(); + assert.strictEqual(xml(input), output); }); -test('xmlEscape (more)', t => { +test('xmlEscape (more)', () => { const empty = ''; - t.equal(xml(empty), empty); + assert.strictEqual(xml(empty), empty); const safe = 'hello'; - t.equal(xml(safe), safe); + assert.strictEqual(xml(safe), safe); const unsafe = '< > & \' "'; - t.equal(xml(unsafe), '< > & ' "'); + assert.strictEqual(xml(unsafe), '< > & ' "'); const single = '&'; - t.equal(xml(single), '&'); + assert.strictEqual(xml(single), '&'); const mix = 'b& c\'def_-"'; - t.equal(xml(mix), '<a>b& c'def_-"'); + assert.strictEqual(xml(mix), '<a>b& c'def_-"'); const dupes = '<<&_"_"_&>>'; - t.equal(xml(dupes), '<<&_"_"_&>>'); + assert.strictEqual(xml(dupes), '<<&_"_"_&>>'); const emoji = '(>^_^)>'; - t.equal(xml(emoji), '(>^_^)>'); - - t.end(); + assert.strictEqual(xml(emoji), '(>^_^)>'); }); -test('xmlEscape should handle non strings', t => { +test('xmlEscape should handle non strings', () => { const array = ['hello', 'world']; - t.equal(xml(array), String(array)); + assert.strictEqual(xml(array), String(array)); const arrayWithSpecialChar = ['hello', '']; - t.equal(xml(arrayWithSpecialChar), 'hello,<world>'); + assert.strictEqual(xml(arrayWithSpecialChar), 'hello,<world>'); const arrayWithNumbers = [1, 2, 3]; - t.equal(xml(arrayWithNumbers), '1,2,3'); + assert.strictEqual(xml(arrayWithNumbers), '1,2,3'); // Objects shouldn't get provided to replaceUnsafeChars, but in the event // they do, it should just return the object (and log an error) const object = {hello: 'world'}; - t.equal(xml(object), object); - - t.end(); + assert.strictEqual(xml(object), object); }); diff --git a/test/unit/virtual-machine.js b/test/unit/virtual-machine.js index 36284708..64d8dfc1 100644 --- a/test/unit/virtual-machine.js +++ b/test/unit/virtual-machine.js @@ -1,4 +1,5 @@ -const tap = require('tap'); +const {test} = require('node:test'); +const assert = require('node:assert'); const VirtualMachine = require('../../src/virtual-machine'); const Sprite = require('../../src/sprites/sprite'); const Variable = require('../../src/engine/variable'); @@ -8,9 +9,7 @@ const Renderer = require('../fixtures/fake-renderer'); const Runtime = require('../../src/engine/runtime'); const RenderedTarget = require('../../src/sprites/rendered-target'); -const test = tap.test; - -test('deleteSound returns function after deleting or null if nothing was deleted', t => { +test('deleteSound returns function after deleting or null if nothing was deleted', () => { const vm = new VirtualMachine(); const rt = new Runtime(); const sprite = new Sprite(null, rt); @@ -19,21 +18,19 @@ test('deleteSound returns function after deleting or null if nothing was deleted vm.editingTarget = target; const addFun = vm.deleteSound(1); - t.equal(sprite.sounds.length, 2); - t.equal(sprite.sounds[0].id, 1); - t.equal(sprite.sounds[1].id, 3); - t.type(addFun, 'function'); + assert.strictEqual(sprite.sounds.length, 2); + assert.strictEqual(sprite.sounds[0].id, 1); + assert.strictEqual(sprite.sounds[1].id, 3); + assert.strictEqual(typeof addFun, 'function'); const noAddFun = vm.deleteSound(2); - t.equal(sprite.sounds.length, 2); - t.equal(sprite.sounds[0].id, 1); - t.equal(sprite.sounds[1].id, 3); - t.equal(noAddFun, null); - - t.end(); + assert.strictEqual(sprite.sounds.length, 2); + assert.strictEqual(sprite.sounds[0].id, 1); + assert.strictEqual(sprite.sounds[1].id, 3); + assert.strictEqual(noAddFun, null); }); -test('deleteCostume returns function after deleting or null if nothing was deleted', t => { +test('deleteCostume returns function after deleting or null if nothing was deleted', () => { const vm = new VirtualMachine(); const rt = new Runtime(); const sprite = new Sprite(null, rt); @@ -43,68 +40,63 @@ test('deleteCostume returns function after deleting or null if nothing was delet vm.editingTarget = target; const addFun = vm.deleteCostume(1); - t.equal(sprite.costumes.length, 2); - t.equal(sprite.costumes[0].id, 1); - t.equal(sprite.costumes[1].id, 3); - t.type(addFun, 'function'); + assert.strictEqual(sprite.costumes.length, 2); + assert.strictEqual(sprite.costumes[0].id, 1); + assert.strictEqual(sprite.costumes[1].id, 3); + assert.strictEqual(typeof addFun, 'function'); const noAddFun = vm.deleteCostume(2); - t.equal(sprite.costumes.length, 2); - t.equal(sprite.costumes[0].id, 1); - t.equal(sprite.costumes[1].id, 3); - t.equal(noAddFun, null); - - t.end(); + assert.strictEqual(sprite.costumes.length, 2); + assert.strictEqual(sprite.costumes[0].id, 1); + assert.strictEqual(sprite.costumes[1].id, 3); + assert.strictEqual(noAddFun, null); }); -test('addSprite throws on invalid string', t => { +test('addSprite throws on invalid string', (t, done) => { const vm = new VirtualMachine(); vm.addSprite('this is not a sprite') .catch(e => { - t.equal(e.startsWith('Sprite Upload Error:'), true); - t.end(); + assert.strictEqual(e.startsWith('Sprite Upload Error:'), true); + done(); }); }); -test('renameSprite throws when there is no sprite with that id', t => { +test('renameSprite throws when there is no sprite with that id', () => { const vm = new VirtualMachine(); vm.runtime.getTargetById = () => null; - t.throws( + assert.throws( (() => vm.renameSprite('id', 'name')), new Error('No target with the provided id.') ); - t.end(); }); -test('renameSprite throws when used on a non-sprite target', t => { +test('renameSprite throws when used on a non-sprite target', () => { const vm = new VirtualMachine(); const fakeTarget = { isSprite: () => false }; vm.runtime.getTargetById = () => (fakeTarget); - t.throws( + assert.throws( (() => vm.renameSprite('id', 'name')), new Error('Cannot rename non-sprite targets.') ); - t.end(); }); -test('renameSprite throws when there is no sprite for given target', t => { +test('renameSprite throws when there is no sprite for given target', () => { const vm = new VirtualMachine(); const fakeTarget = { sprite: null, isSprite: () => true }; vm.runtime.getTargetById = () => (fakeTarget); - t.throws( + assert.throws( (() => vm.renameSprite('id', 'name')), new Error('No sprite associated with this target.') ); - t.end(); }); -test('renameSprite sets the sprite name', t => { +test('renameSprite sets the sprite name', () => { const vm = new VirtualMachine(); const fakeTarget = { sprite: {name: 'original'}, @@ -112,11 +104,10 @@ test('renameSprite sets the sprite name', t => { }; vm.runtime.getTargetById = () => (fakeTarget); vm.renameSprite('id', 'not-original'); - t.equal(fakeTarget.sprite.name, 'not-original'); - t.end(); + assert.strictEqual(fakeTarget.sprite.name, 'not-original'); }); -test('renameSprite does not set sprite names to an empty string', t => { +test('renameSprite does not set sprite names to an empty string', () => { const vm = new VirtualMachine(); const fakeTarget = { sprite: {name: 'original'}, @@ -124,11 +115,10 @@ test('renameSprite does not set sprite names to an empty string', t => { }; vm.runtime.getTargetById = () => (fakeTarget); vm.renameSprite('id', ''); - t.equal(fakeTarget.sprite.name, 'original'); - t.end(); + assert.strictEqual(fakeTarget.sprite.name, 'original'); }); -test('renameSprite does not set sprite names to reserved names', t => { +test('renameSprite does not set sprite names to reserved names', () => { const vm = new VirtualMachine(); const fakeTarget = { sprite: {name: 'original'}, @@ -136,11 +126,10 @@ test('renameSprite does not set sprite names to reserved names', t => { }; vm.runtime.getTargetById = () => (fakeTarget); vm.renameSprite('id', '_mouse_'); - t.equal(fakeTarget.sprite.name, 'original'); - t.end(); + assert.strictEqual(fakeTarget.sprite.name, 'original'); }); -test('renameSprite increments from existing sprite names', t => { +test('renameSprite increments from existing sprite names', () => { const vm = new VirtualMachine(); vm.emitTargetsUpdate = () => {}; @@ -151,13 +140,12 @@ test('renameSprite increments from existing sprite names', t => { vm.runtime.targets = [target1, target2]; vm.renameSprite(target1.id, 'foo'); - t.equal(vm.runtime.targets[0].sprite.name, 'foo'); + assert.strictEqual(vm.runtime.targets[0].sprite.name, 'foo'); vm.renameSprite(target2.id, 'foo'); - t.equal(vm.runtime.targets[1].sprite.name, 'foo2'); - t.end(); + assert.strictEqual(vm.runtime.targets[1].sprite.name, 'foo2'); }); -test('renameSprite does not increment when renaming to the same name', t => { +test('renameSprite does not increment when renaming to the same name', () => { const vm = new VirtualMachine(); vm.emitTargetsUpdate = () => {}; @@ -167,41 +155,37 @@ test('renameSprite does not increment when renaming to the same name', t => { vm.runtime.targets = [target]; - t.equal(vm.runtime.targets[0].sprite.name, 'foo'); + assert.strictEqual(vm.runtime.targets[0].sprite.name, 'foo'); vm.renameSprite(target.id, 'foo'); - t.equal(vm.runtime.targets[0].sprite.name, 'foo'); - - t.end(); + assert.strictEqual(vm.runtime.targets[0].sprite.name, 'foo'); }); -test('deleteSprite throws when used on a non-sprite target', t => { +test('deleteSprite throws when used on a non-sprite target', () => { const vm = new VirtualMachine(); vm.runtime.targets = [{ id: 'id', isSprite: () => false }]; - t.throws( + assert.throws( (() => vm.deleteSprite('id')), new Error('Cannot delete non-sprite targets.') ); - t.end(); }); -test('deleteSprite throws when there is no sprite for the given target', t => { +test('deleteSprite throws when there is no sprite for the given target', () => { const vm = new VirtualMachine(); vm.runtime.targets = [{ id: 'id', isSprite: () => true, sprite: null }]; - t.throws( + assert.throws( (() => vm.deleteSprite('id')), new Error('No sprite associated with this target.') ); - t.end(); }); -test('deleteSprite throws when there is no target with given id', t => { +test('deleteSprite throws when there is no target with given id', () => { const vm = new VirtualMachine(); vm.runtime.targets = [{ id: 'id', @@ -210,28 +194,26 @@ test('deleteSprite throws when there is no target with given id', t => { name: 'this name' } }]; - t.throws( + assert.throws( (() => vm.deleteSprite('id1')), new Error('No target with the provided id.') ); - t.end(); }); -test('deleteSprite deletes a sprite when given id is associated with a known sprite', t => { +test('deleteSprite deletes a sprite when given id is associated with a known sprite', () => { const vm = new VirtualMachine(); const spr = new Sprite(null, vm.runtime); const currTarget = spr.createClone(); vm.runtime.targets = [currTarget]; - t.equal(currTarget.sprite.clones.length, 1); + assert.strictEqual(currTarget.sprite.clones.length, 1); vm.deleteSprite(currTarget.id); - t.equal(currTarget.sprite.clones.length, 0); - t.end(); + assert.strictEqual(currTarget.sprite.clones.length, 0); }); // eslint-disable-next-line max-len -test('deleteSprite sets editing target as null when given sprite is current editing target, and the only target in the runtime', t => { +test('deleteSprite sets editing target as null when given sprite is current editing target, and the only target in the runtime', () => { const vm = new VirtualMachine(); const spr = new Sprite(null, vm.runtime); const currTarget = spr.createClone(); @@ -241,13 +223,12 @@ test('deleteSprite sets editing target as null when given sprite is current edit vm.deleteSprite(currTarget.id); - t.equal(vm.runtime.targets.length, 0); - t.equal(vm.editingTarget, null); - t.end(); + assert.strictEqual(vm.runtime.targets.length, 0); + assert.strictEqual(vm.editingTarget, null); }); // eslint-disable-next-line max-len -test('deleteSprite updates editingTarget when sprite being deleted is current editing target, and there is another target in the runtime', t => { +test('deleteSprite updates editingTarget when sprite being deleted is current editing target, and there is another target in the runtime', () => { const vm = new VirtualMachine(); const spr1 = new Sprite(null, vm.runtime); const spr2 = new Sprite(null, vm.runtime); @@ -259,10 +240,10 @@ test('deleteSprite updates editingTarget when sprite being deleted is current ed vm.runtime.targets = [currTarget, otherTarget]; vm.editingTarget = currTarget; - t.equal(vm.runtime.targets.length, 2); + assert.strictEqual(vm.runtime.targets.length, 2); vm.deleteSprite(currTarget.id); - t.equal(vm.runtime.targets.length, 1); - t.equal(vm.editingTarget.id, otherTarget.id); + assert.strictEqual(vm.runtime.targets.length, 1); + assert.strictEqual(vm.editingTarget.id, otherTarget.id); // now let's try them in the other order in the runtime.targets list @@ -273,15 +254,13 @@ test('deleteSprite updates editingTarget when sprite being deleted is current ed vm.runtime.targets = [otherTarget2, currTarget2]; vm.editingTarget = currTarget2; - t.equal(vm.runtime.targets.length, 2); + assert.strictEqual(vm.runtime.targets.length, 2); vm.deleteSprite(currTarget2.id); - t.equal(vm.editingTarget.id, otherTarget2.id); - t.equal(vm.runtime.targets.length, 1); - - t.end(); + assert.strictEqual(vm.editingTarget.id, otherTarget2.id); + assert.strictEqual(vm.runtime.targets.length, 1); }); -test('duplicateSprite throws when there is no target with given id', t => { +test('duplicateSprite throws when there is no target with given id', () => { const vm = new VirtualMachine(); vm.runtime.targets = [{ id: 'id', @@ -290,41 +269,38 @@ test('duplicateSprite throws when there is no target with given id', t => { name: 'this name' } }]; - t.throws( + assert.throws( (() => vm.duplicateSprite('id1')), - new Error('No target with the provided id') + new Error('No target with the provided id.') ); - t.end(); }); -test('duplicateSprite throws when used on a non-sprite target', t => { +test('duplicateSprite throws when used on a non-sprite target', () => { const vm = new VirtualMachine(); vm.runtime.targets = [{ id: 'id', isSprite: () => false }]; - t.throws( + assert.throws( (() => vm.duplicateSprite('id')), new Error('Cannot duplicate non-sprite targets.') ); - t.end(); }); -test('duplicateSprite throws when there is no sprite for the given target', t => { +test('duplicateSprite throws when there is no sprite for the given target', () => { const vm = new VirtualMachine(); vm.runtime.targets = [{ id: 'id', isSprite: () => true, sprite: null }]; - t.throws( + assert.throws( (() => vm.duplicateSprite('id')), new Error('No sprite associated with this target.') ); - t.end(); }); -test('duplicateSprite duplicates a sprite when given id is associated with known sprite', t => { +test('duplicateSprite duplicates a sprite when given id is associated with known sprite', async () => { const vm = new VirtualMachine(); const spr = new Sprite(null, vm.runtime); const currTarget = spr.createClone(); @@ -333,15 +309,13 @@ test('duplicateSprite duplicates a sprite when given id is associated with known vm.emitWorkspaceUpdate = () => null; vm.runtime.targets = [currTarget]; - t.equal(vm.runtime.targets.length, 1); - vm.duplicateSprite(currTarget.id).then(() => { - t.equal(vm.runtime.targets.length, 2); - t.end(); - }); + assert.strictEqual(vm.runtime.targets.length, 1); + await vm.duplicateSprite(currTarget.id); + assert.strictEqual(vm.runtime.targets.length, 2); }); -test('duplicateSprite assigns duplicated sprite a fresh name', t => { +test('duplicateSprite assigns duplicated sprite a fresh name', async () => { const vm = new VirtualMachine(); const spr = new Sprite(null, vm.runtime); spr.name = 'sprite1'; @@ -351,17 +325,15 @@ test('duplicateSprite assigns duplicated sprite a fresh name', t => { vm.emitWorkspaceUpdate = () => null; vm.runtime.targets = [currTarget]; - t.equal(vm.runtime.targets.length, 1); - vm.duplicateSprite(currTarget.id).then(() => { - t.equal(vm.runtime.targets.length, 2); - t.equal(vm.runtime.targets[0].sprite.name, 'sprite1'); - t.equal(vm.runtime.targets[1].sprite.name, 'sprite2'); - t.end(); - }); + assert.strictEqual(vm.runtime.targets.length, 1); + await vm.duplicateSprite(currTarget.id); + assert.strictEqual(vm.runtime.targets.length, 2); + assert.strictEqual(vm.runtime.targets[0].sprite.name, 'sprite1'); + assert.strictEqual(vm.runtime.targets[1].sprite.name, 'sprite2'); }); -test('reorderCostume', t => { +test('reorderCostume', () => { const vm = new VirtualMachine(); vm.emitTargetsUpdate = () => {}; @@ -381,18 +353,16 @@ test('reorderCostume', t => { vm.runtime.targets = [target]; - t.equal(vm.reorderCostume('not-a-target', 0, 3), false); - t.equal(costumeIndex, null); - t.equal(newIndex, null); + assert.strictEqual(vm.reorderCostume('not-a-target', 0, 3), false); + assert.strictEqual(costumeIndex, null); + assert.strictEqual(newIndex, null); - t.equal(vm.reorderCostume(target.id, 0, 3), true); - t.equal(costumeIndex, 0); - t.equal(newIndex, 3); - - t.end(); + assert.strictEqual(vm.reorderCostume(target.id, 0, 3), true); + assert.strictEqual(costumeIndex, 0); + assert.strictEqual(newIndex, 3); }); -test('reorderSound', t => { +test('reorderSound', () => { const vm = new VirtualMachine(); vm.emitTargetsUpdate = () => {}; @@ -412,18 +382,16 @@ test('reorderSound', t => { vm.runtime.targets = [target]; - t.equal(vm.reorderSound('not-a-target', 0, 3), false); - t.equal(soundIndex, null); // Make sure reorder function was not called somehow. - t.equal(newIndex, null); + assert.strictEqual(vm.reorderSound('not-a-target', 0, 3), false); + assert.strictEqual(soundIndex, null); // Make sure reorder function was not called somehow. + assert.strictEqual(newIndex, null); - t.equal(vm.reorderSound(target.id, 0, 3), true); - t.equal(soundIndex, 0); // Make sure reorder function was called correctly. - t.equal(newIndex, 3); - - t.end(); + assert.strictEqual(vm.reorderSound(target.id, 0, 3), true); + assert.strictEqual(soundIndex, 0); // Make sure reorder function was called correctly. + assert.strictEqual(newIndex, 3); }); -test('shareCostumeToTarget', t => { +test('shareCostumeToTarget', async () => { const vm = new VirtualMachine(); const spr1 = new Sprite(null, vm.runtime); spr1.name = 'foo'; @@ -441,14 +409,12 @@ test('shareCostumeToTarget', t => { vm.editingTarget = vm.runtime.targets[0]; vm.emitWorkspaceUpdate = () => null; - vm.shareCostumeToTarget(0, target2.id).then(() => { - t.equal(target2.currentCostume, 1); - t.equal(target2.getCostumes()[1].name, 'costume1'); - t.end(); - }); + await vm.shareCostumeToTarget(0, target2.id); + assert.strictEqual(target2.currentCostume, 1); + assert.strictEqual(target2.getCostumes()[1].name, 'costume1'); }); -test('shareSoundToTarget', t => { +test('shareSoundToTarget', async () => { const vm = new VirtualMachine(); const spr1 = new Sprite(null, vm.runtime); spr1.name = 'foo'; @@ -466,37 +432,33 @@ test('shareSoundToTarget', t => { vm.editingTarget = vm.runtime.targets[0]; vm.emitWorkspaceUpdate = () => null; - vm.shareSoundToTarget(0, target2.id).then(() => { - t.equal(target2.getSounds()[1].name, 'sound1'); - t.end(); - }); + await vm.shareSoundToTarget(0, target2.id); + assert.strictEqual(target2.getSounds()[1].name, 'sound1'); }); -test('reorderTarget', t => { +test('reorderTarget', () => { const vm = new VirtualMachine(); vm.emitTargetsUpdate = () => {}; vm.runtime.targets = ['a', 'b', 'c', 'd']; - t.equal(vm.reorderTarget(2, 2), false); - t.deepEqual(vm.runtime.targets, ['a', 'b', 'c', 'd']); + assert.strictEqual(vm.reorderTarget(2, 2), false); + assert.deepEqual(vm.runtime.targets, ['a', 'b', 'c', 'd']); // Make sure clamping works - t.equal(vm.reorderTarget(-100, -5), false); - t.deepEqual(vm.runtime.targets, ['a', 'b', 'c', 'd']); + assert.strictEqual(vm.reorderTarget(-100, -5), false); + assert.deepEqual(vm.runtime.targets, ['a', 'b', 'c', 'd']); // Reorder upwards - t.equal(vm.reorderTarget(0, 2), true); - t.deepEqual(vm.runtime.targets, ['b', 'c', 'a', 'd']); + assert.strictEqual(vm.reorderTarget(0, 2), true); + assert.deepEqual(vm.runtime.targets, ['b', 'c', 'a', 'd']); // Reorder downwards - t.equal(vm.reorderTarget(3, 1), true); - t.deepEqual(vm.runtime.targets, ['b', 'd', 'c', 'a']); - - t.end(); + assert.strictEqual(vm.reorderTarget(3, 1), true); + assert.deepEqual(vm.runtime.targets, ['b', 'd', 'c', 'a']); }); -test('emitWorkspaceUpdate', t => { +test('emitWorkspaceUpdate', () => { const vm = new VirtualMachine(); const blocksToXML = comments => { let blockString = 'blocks\n'; @@ -567,18 +529,17 @@ test('emitWorkspaceUpdate', t => { let xml = null; vm.emit = (event, data) => (xml = data.xml); vm.emitWorkspaceUpdate(); - t.notEqual(xml.indexOf('global'), -1); - t.notEqual(xml.indexOf('local'), -1); - t.equal(xml.indexOf('unused'), -1); - t.notEqual(xml.indexOf('blocks'), -1); - t.equal(xml.indexOf('aStageComment'), -1); - t.equal(xml.indexOf('someBlockComment'), -1); - t.notEqual(xml.indexOf('someOtherComment'), -1); - t.notEqual(xml.indexOf('A Block Comment: aBlockComment'), -1); - t.end(); + assert.notStrictEqual(xml.indexOf('global'), -1); + assert.notStrictEqual(xml.indexOf('local'), -1); + assert.strictEqual(xml.indexOf('unused'), -1); + assert.notStrictEqual(xml.indexOf('blocks'), -1); + assert.strictEqual(xml.indexOf('aStageComment'), -1); + assert.strictEqual(xml.indexOf('someBlockComment'), -1); + assert.notStrictEqual(xml.indexOf('someOtherComment'), -1); + assert.notStrictEqual(xml.indexOf('A Block Comment: aBlockComment'), -1); }); -test('drag IO redirect', t => { +test('drag IO redirect', () => { const vm = new VirtualMachine(); const sprite1Info = []; const sprite2Info = []; @@ -600,24 +561,23 @@ test('drag IO redirect', t => { // postSpriteInfo should go to the editing target by default`` vm.postSpriteInfo('sprite1 info'); - t.equal(sprite1Info[0], 'sprite1 info'); + assert.strictEqual(sprite1Info[0], 'sprite1 info'); // postSprite info goes to the drag target if it exists vm.startDrag('sprite2'); vm.postSpriteInfo('sprite2 info'); - t.equal(sprite2Info[0], 'sprite2 info'); + assert.strictEqual(sprite2Info[0], 'sprite2 info'); // stop drag should set the editing target vm.stopDrag('sprite2'); - t.equal(vm.editingTarget.id, 'sprite2'); + assert.strictEqual(vm.editingTarget.id, 'sprite2'); // Then postSpriteInfo should continue posting to the new editing target vm.postSpriteInfo('sprite2 info 2'); - t.equal(sprite2Info[1], 'sprite2 info 2'); - t.end(); + assert.strictEqual(sprite2Info[1], 'sprite2 info 2'); }); -test('select original after dragging clone', t => { +test('select original after dragging clone', () => { const vm = new VirtualMachine(); let newEditingTargetId = null; vm.setEditingTarget = id => { @@ -636,15 +596,14 @@ test('select original after dragging clone', t => { // Stop drag on a bare target selects that target vm.stopDrag('sprite2'); - t.equal(newEditingTargetId, 'sprite2'); + assert.strictEqual(newEditingTargetId, 'sprite2'); // Stop drag on target with parent sprite selects the 0th clone of that sprite vm.stopDrag('sprite1_clone'); - t.equal(newEditingTargetId, 'sprite1_original'); - t.end(); + assert.strictEqual(newEditingTargetId, 'sprite1_original'); }); -test('setVariableValue', t => { +test('setVariableValue', () => { const vm = new VirtualMachine(); const spr = new Sprite(null, vm.runtime); const target = spr.createClone(); @@ -653,19 +612,17 @@ test('setVariableValue', t => { vm.runtime.targets = [target]; // Returns false if there is no variable to set - t.equal(vm.setVariableValue(target.id, 'not-a-variable', 100), false); + assert.strictEqual(vm.setVariableValue(target.id, 'not-a-variable', 100), false); // Returns false if there is no target with that id - t.equal(vm.setVariableValue('not-a-target', 'a-variable', 100), false); + assert.strictEqual(vm.setVariableValue('not-a-target', 'a-variable', 100), false); // Returns true and updates the value if variable is present - t.equal(vm.setVariableValue(target.id, 'a-variable', 100), true); - t.equal(target.lookupVariableById('a-variable').value, 100); - - t.end(); + assert.strictEqual(vm.setVariableValue(target.id, 'a-variable', 100), true); + assert.strictEqual(target.lookupVariableById('a-variable').value, 100); }); -test('setVariableValue requests update for cloud variable', t => { +test('setVariableValue requests update for cloud variable', () => { const vm = new VirtualMachine(); const spr = new Sprite(null, vm.runtime); const target = spr.createClone(); @@ -685,17 +642,15 @@ test('setVariableValue requests update for cloud variable', t => { }; vm.setVariableValue(target.id, 'not-a-variable', 100); - t.equal(requestUpdateVarWasCalled, false); + assert.strictEqual(requestUpdateVarWasCalled, false); vm.setVariableValue(target.id, 'a-variable', 100); - t.equal(requestUpdateVarWasCalled, true); - t.equal(varName, 'a-name'); - t.equal(varValue, 100); - - t.end(); + assert.strictEqual(requestUpdateVarWasCalled, true); + assert.strictEqual(varName, 'a-name'); + assert.strictEqual(varValue, 100); }); -test('getVariableValue', t => { +test('getVariableValue', () => { const vm = new VirtualMachine(); const spr = new Sprite(null, vm.runtime); const target = spr.createClone(); @@ -704,21 +659,19 @@ test('getVariableValue', t => { vm.runtime.targets = [target]; // Returns null if there is no variable with that id - t.equal(vm.getVariableValue(target.id, 'not-a-variable'), null); + assert.strictEqual(vm.getVariableValue(target.id, 'not-a-variable'), null); // Returns null if there is no target with that id - t.equal(vm.getVariableValue('not-a-target', 'a-variable'), null); + assert.strictEqual(vm.getVariableValue('not-a-target', 'a-variable'), null); // Returns true and updates the value if variable is present - t.equal(vm.getVariableValue(target.id, 'a-variable'), 0); + assert.strictEqual(vm.getVariableValue(target.id, 'a-variable'), 0); vm.setVariableValue(target.id, 'a-variable', 'string'); - t.equal(vm.getVariableValue(target.id, 'a-variable'), 'string'); - - t.end(); + assert.strictEqual(vm.getVariableValue(target.id, 'a-variable'), 'string'); }); // Block Listener tests for comment -test('comment_create event updates comment with null position', t => { +test('comment_create event updates comment with null position', () => { const vm = new VirtualMachine(); const spr = new Sprite(null, vm.runtime); const target = spr.createClone(); @@ -730,18 +683,16 @@ test('comment_create event updates comment with null position', t => { vm.runtime.setEditingTarget(target); const comment = target.comments['a comment']; - t.equal(comment.x, null); - t.equal(comment.y, null); + assert.strictEqual(comment.x, null); + assert.strictEqual(comment.y, null); vm.blockListener(events.createcommentUpdatePosition); - t.equal(comment.x, 10); - t.equal(comment.y, 20); - - t.end(); + assert.strictEqual(comment.x, 10); + assert.strictEqual(comment.y, 20); }); -test('shareBlocksToTarget shares global variables without any name changes', t => { +test('shareBlocksToTarget shares global variables without any name changes', async () => { const vm = new VirtualMachine(); const runtime = vm.runtime; const spr1 = new Sprite(null, runtime); @@ -756,56 +707,54 @@ test('shareBlocksToTarget shares global variables without any name changes', t = vm.runtime.setEditingTarget(target); stage.createVariable('mock var id', 'a mock variable', Variable.SCALAR_TYPE); - t.equal(Object.keys(target.variables).length, 0); - t.equal(Object.keys(stage.variables).length, 1); - t.equal(stage.variables['mock var id'].name, 'a mock variable'); + assert.strictEqual(Object.keys(target.variables).length, 0); + assert.strictEqual(Object.keys(stage.variables).length, 1); + assert.strictEqual(stage.variables['mock var id'].name, 'a mock variable'); vm.setVariableValue(stage.id, 'mock var id', 10); - t.equal(vm.getVariableValue(stage.id, 'mock var id'), 10); + assert.strictEqual(vm.getVariableValue(stage.id, 'mock var id'), 10); target.blocks.createBlock(adapter(events.mockVariableBlock)[0]); // Verify the block exists on the target, and that it references the global variable - t.type(target.blocks.getBlock('a block'), 'object'); - t.type(target.blocks.getBlock('a block').fields, 'object'); - t.type(target.blocks.getBlock('a block').fields.VARIABLE, 'object'); - t.equal(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id'); + assert.strictEqual(typeof target.blocks.getBlock('a block'), 'object'); + assert.strictEqual(typeof target.blocks.getBlock('a block').fields, 'object'); + assert.strictEqual(typeof target.blocks.getBlock('a block').fields.VARIABLE, 'object'); + assert.strictEqual(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id'); // Verify that the block does not exist on the stage - t.type(stage.blocks.getBlock('a block'), 'undefined'); + assert.strictEqual(typeof stage.blocks.getBlock('a block'), 'undefined'); // Share the block to the stage - vm.shareBlocksToTarget([target.blocks.getBlock('a block')], stage.id, target.id).then(() => { + await vm.shareBlocksToTarget([target.blocks.getBlock('a block')], stage.id, target.id); - // Verify that the block now exists on the target as well as the stage - t.type(target.blocks.getBlock('a block'), 'object'); - t.type(target.blocks.getBlock('a block').fields, 'object'); - t.type(target.blocks.getBlock('a block').fields.VARIABLE, 'object'); - t.equal(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id'); + // Verify that the block now exists on the target as well as the stage + assert.strictEqual(typeof target.blocks.getBlock('a block'), 'object'); + assert.strictEqual(typeof target.blocks.getBlock('a block').fields, 'object'); + assert.strictEqual(typeof target.blocks.getBlock('a block').fields.VARIABLE, 'object'); + assert.strictEqual(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id'); - const newBlockId = Object.keys(stage.blocks._blocks)[0]; - t.type(stage.blocks.getBlock(newBlockId), 'object'); - t.type(stage.blocks.getBlock(newBlockId).fields, 'object'); - t.type(stage.blocks.getBlock(newBlockId).fields.VARIABLE, 'object'); - t.equal(stage.blocks.getBlock(newBlockId).fields.VARIABLE.id, 'mock var id'); + const newBlockId = Object.keys(stage.blocks._blocks)[0]; + assert.strictEqual(typeof stage.blocks.getBlock(newBlockId), 'object'); + assert.strictEqual(typeof stage.blocks.getBlock(newBlockId).fields, 'object'); + assert.strictEqual(typeof stage.blocks.getBlock(newBlockId).fields.VARIABLE, 'object'); + assert.strictEqual(stage.blocks.getBlock(newBlockId).fields.VARIABLE.id, 'mock var id'); - // Verify the shared block id is different - t.notEqual(newBlockId, 'a block'); + // Verify the shared block id is different + assert.notStrictEqual(newBlockId, 'a block'); - // Verify that the variables haven't changed, the variable still exists on the - // stage, it should still have the same name and value, and there should be - // no variables on the target. - t.equal(Object.keys(target.variables).length, 0); - t.equal(Object.keys(stage.variables).length, 1); - t.equal(stage.variables['mock var id'].name, 'a mock variable'); - t.equal(vm.getVariableValue(stage.id, 'mock var id'), 10); - - t.end(); - }); + // Verify that the variables haven't changed, the variable still exists on the + // stage, it should still have the same name and value, and there should be + // no variables on the target. + assert.strictEqual(Object.keys(target.variables).length, 0); + assert.strictEqual(Object.keys(stage.variables).length, 1); + assert.strictEqual(stage.variables['mock var id'].name, 'a mock variable'); + assert.strictEqual(vm.getVariableValue(stage.id, 'mock var id'), 10); }); -test('shareBlocksToTarget shares a local variable to the stage, creating a global variable with a new name', t => { +// eslint-disable-next-line max-len +test('shareBlocksToTarget shares a local variable to the stage, creating a global variable with a new name', async () => { const vm = new VirtualMachine(); const runtime = vm.runtime; const spr1 = new Sprite(null, runtime); @@ -820,60 +769,58 @@ test('shareBlocksToTarget shares a local variable to the stage, creating a globa vm.runtime.setEditingTarget(target); target.createVariable('mock var id', 'a mock variable', Variable.SCALAR_TYPE); - t.equal(Object.keys(stage.variables).length, 0); - t.equal(Object.keys(target.variables).length, 1); - t.equal(target.variables['mock var id'].name, 'a mock variable'); + assert.strictEqual(Object.keys(stage.variables).length, 0); + assert.strictEqual(Object.keys(target.variables).length, 1); + assert.strictEqual(target.variables['mock var id'].name, 'a mock variable'); vm.setVariableValue(target.id, 'mock var id', 10); - t.equal(vm.getVariableValue(target.id, 'mock var id'), 10); + assert.strictEqual(vm.getVariableValue(target.id, 'mock var id'), 10); target.blocks.createBlock(adapter(events.mockVariableBlock)[0]); // Verify the block exists on the target, and that it references the global variable - t.type(target.blocks.getBlock('a block'), 'object'); - t.type(target.blocks.getBlock('a block').fields, 'object'); - t.type(target.blocks.getBlock('a block').fields.VARIABLE, 'object'); - t.equal(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id'); + assert.strictEqual(typeof target.blocks.getBlock('a block'), 'object'); + assert.strictEqual(typeof target.blocks.getBlock('a block').fields, 'object'); + assert.strictEqual(typeof target.blocks.getBlock('a block').fields.VARIABLE, 'object'); + assert.strictEqual(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id'); // Verify that the block does not exist on the stage - t.type(stage.blocks.getBlock('a block'), 'undefined'); + assert.strictEqual(typeof stage.blocks.getBlock('a block'), 'undefined'); // Share the block to the stage - vm.shareBlocksToTarget([target.blocks.getBlock('a block')], stage.id, target.id).then(() => { - // Verify that the block still exists on the target and remains unchanged - t.type(target.blocks.getBlock('a block'), 'object'); - t.type(target.blocks.getBlock('a block').fields, 'object'); - t.type(target.blocks.getBlock('a block').fields.VARIABLE, 'object'); - t.equal(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id'); + await vm.shareBlocksToTarget([target.blocks.getBlock('a block')], stage.id, target.id); + // Verify that the block still exists on the target and remains unchanged + assert.strictEqual(typeof target.blocks.getBlock('a block'), 'object'); + assert.strictEqual(typeof target.blocks.getBlock('a block').fields, 'object'); + assert.strictEqual(typeof target.blocks.getBlock('a block').fields.VARIABLE, 'object'); + assert.strictEqual(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id'); - const newBlockId = Object.keys(stage.blocks._blocks)[0]; - t.type(stage.blocks.getBlock(newBlockId), 'object'); - t.type(stage.blocks.getBlock(newBlockId).fields, 'object'); - t.type(stage.blocks.getBlock(newBlockId).fields.VARIABLE, 'object'); - t.equal(stage.blocks.getBlock(newBlockId).fields.VARIABLE.id, 'StageVarFromLocal_mock var id'); + const newBlockId = Object.keys(stage.blocks._blocks)[0]; + assert.strictEqual(typeof stage.blocks.getBlock(newBlockId), 'object'); + assert.strictEqual(typeof stage.blocks.getBlock(newBlockId).fields, 'object'); + assert.strictEqual(typeof stage.blocks.getBlock(newBlockId).fields.VARIABLE, 'object'); + assert.strictEqual(stage.blocks.getBlock(newBlockId).fields.VARIABLE.id, 'StageVarFromLocal_mock var id'); - // Verify that a new global variable was created, the old one still exists on - // the target and still has the same name and value, and the new one has - // a new name and value 0. - t.equal(Object.keys(target.variables).length, 1); - t.equal(target.variables['mock var id'].name, 'a mock variable'); - t.equal(vm.getVariableValue(target.id, 'mock var id'), 10); + // Verify that a new global variable was created, the old one still exists on + // the target and still has the same name and value, and the new one has + // a new name and value 0. + assert.strictEqual(Object.keys(target.variables).length, 1); + assert.strictEqual(target.variables['mock var id'].name, 'a mock variable'); + assert.strictEqual(vm.getVariableValue(target.id, 'mock var id'), 10); - // Verify that a new variable was created on the stage, with a new name and new id - t.equal(Object.keys(stage.variables).length, 1); - t.type(stage.variables['mock var id'], 'undefined'); - const newGlobalVar = Object.values(stage.variables)[0]; - t.equal(newGlobalVar.name, 'Stage: a mock variable'); - const newId = newGlobalVar.id; - t.notEqual(newId, 'mock var id'); - t.equals(vm.getVariableValue(stage.id, newId), 0); - - t.end(); - }); + // Verify that a new variable was created on the stage, with a new name and new id + assert.strictEqual(Object.keys(stage.variables).length, 1); + assert.strictEqual(typeof stage.variables['mock var id'], 'undefined'); + const newGlobalVar = Object.values(stage.variables)[0]; + assert.strictEqual(newGlobalVar.name, 'Stage: a mock variable'); + const newId = newGlobalVar.id; + assert.notStrictEqual(newId, 'mock var id'); + assert.strictEqual(vm.getVariableValue(stage.id, newId), 0); }); -test('shareBlocksToTarget chooses a fresh name for a new global variable checking for conflicts on all sprites', t => { +// eslint-disable-next-line max-len +test('shareBlocksToTarget chooses a fresh name for a new global variable checking for conflicts on all sprites', async () => { const vm = new VirtualMachine(); const runtime = vm.runtime; const spr1 = new Sprite(null, runtime); @@ -891,64 +838,61 @@ test('shareBlocksToTarget chooses a fresh name for a new global variable checkin vm.runtime.setEditingTarget(target); target.createVariable('mock var id', 'a mock variable', Variable.SCALAR_TYPE); - t.equal(Object.keys(stage.variables).length, 0); - t.equal(Object.keys(target.variables).length, 1); - t.equal(target.variables['mock var id'].name, 'a mock variable'); + assert.strictEqual(Object.keys(stage.variables).length, 0); + assert.strictEqual(Object.keys(target.variables).length, 1); + assert.strictEqual(target.variables['mock var id'].name, 'a mock variable'); vm.setVariableValue(target.id, 'mock var id', 10); - t.equal(vm.getVariableValue(target.id, 'mock var id'), 10); + assert.strictEqual(vm.getVariableValue(target.id, 'mock var id'), 10); target.blocks.createBlock(adapter(events.mockVariableBlock)[0]); // Verify the block exists on the target, and that it references the global variable - t.type(target.blocks.getBlock('a block'), 'object'); - t.type(target.blocks.getBlock('a block').fields, 'object'); - t.type(target.blocks.getBlock('a block').fields.VARIABLE, 'object'); - t.equal(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id'); + assert.strictEqual(typeof target.blocks.getBlock('a block'), 'object'); + assert.strictEqual(typeof target.blocks.getBlock('a block').fields, 'object'); + assert.strictEqual(typeof target.blocks.getBlock('a block').fields.VARIABLE, 'object'); + assert.strictEqual(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id'); // Verify that the block does not exist on the stage - t.type(stage.blocks.getBlock('a block'), 'undefined'); + assert.strictEqual(typeof stage.blocks.getBlock('a block'), 'undefined'); // Create a variable that conflicts with what will be the new name for the // new global variable to ensure a fresh name is chosen otherTarget.createVariable('a different var', 'Stage: a mock variable', Variable.SCALAR_TYPE); // Share the block to the stage - vm.shareBlocksToTarget([target.blocks.getBlock('a block')], stage.id, target.id).then(() => { - // Verify that the block still exists on the target and remains unchanged - t.type(target.blocks.getBlock('a block'), 'object'); - t.type(target.blocks.getBlock('a block').fields, 'object'); - t.type(target.blocks.getBlock('a block').fields.VARIABLE, 'object'); - t.equal(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id'); + await vm.shareBlocksToTarget([target.blocks.getBlock('a block')], stage.id, target.id); + // Verify that the block still exists on the target and remains unchanged + assert.strictEqual(typeof target.blocks.getBlock('a block'), 'object'); + assert.strictEqual(typeof target.blocks.getBlock('a block').fields, 'object'); + assert.strictEqual(typeof target.blocks.getBlock('a block').fields.VARIABLE, 'object'); + assert.strictEqual(target.blocks.getBlock('a block').fields.VARIABLE.id, 'mock var id'); - const newBlockId = Object.keys(stage.blocks._blocks)[0]; - t.type(stage.blocks.getBlock(newBlockId), 'object'); - t.type(stage.blocks.getBlock(newBlockId).fields, 'object'); - t.type(stage.blocks.getBlock(newBlockId).fields.VARIABLE, 'object'); - t.equal(stage.blocks.getBlock(newBlockId).fields.VARIABLE.id, 'StageVarFromLocal_mock var id'); + const newBlockId = Object.keys(stage.blocks._blocks)[0]; + assert.strictEqual(typeof stage.blocks.getBlock(newBlockId), 'object'); + assert.strictEqual(typeof stage.blocks.getBlock(newBlockId).fields, 'object'); + assert.strictEqual(typeof stage.blocks.getBlock(newBlockId).fields.VARIABLE, 'object'); + assert.strictEqual(stage.blocks.getBlock(newBlockId).fields.VARIABLE.id, 'StageVarFromLocal_mock var id'); - // Verify that a new global variable was created, the old one still exists on - // the target and still has the same name and value, and the new one has - // a new name and value 0. - t.equal(Object.keys(target.variables).length, 1); - t.equal(target.variables['mock var id'].name, 'a mock variable'); - t.equal(vm.getVariableValue(target.id, 'mock var id'), 10); + // Verify that a new global variable was created, the old one still exists on + // the target and still has the same name and value, and the new one has + // a new name and value 0. + assert.strictEqual(Object.keys(target.variables).length, 1); + assert.strictEqual(target.variables['mock var id'].name, 'a mock variable'); + assert.strictEqual(vm.getVariableValue(target.id, 'mock var id'), 10); - // Verify that a new variable was created on the stage, with a new name and new id - t.equal(Object.keys(stage.variables).length, 1); - t.type(stage.variables['mock var id'], 'undefined'); - const newGlobalVar = Object.values(stage.variables)[0]; - t.equal(newGlobalVar.name, 'Stage: a mock variable2'); - const newId = newGlobalVar.id; - t.notEqual(newId, 'mock var id'); - t.equals(vm.getVariableValue(stage.id, newId), 0); - - t.end(); - }); + // Verify that a new variable was created on the stage, with a new name and new id + assert.strictEqual(Object.keys(stage.variables).length, 1); + assert.strictEqual(typeof stage.variables['mock var id'], 'undefined'); + const newGlobalVar = Object.values(stage.variables)[0]; + assert.strictEqual(newGlobalVar.name, 'Stage: a mock variable2'); + const newId = newGlobalVar.id; + assert.notStrictEqual(newId, 'mock var id'); + assert.strictEqual(vm.getVariableValue(stage.id, newId), 0); }); -test('shareBlocksToTarget loads extensions that have not yet been loaded', t => { +test('shareBlocksToTarget loads extensions that have not yet been loaded', async () => { const vm = new VirtualMachine(); const runtime = vm.runtime; const spr1 = new Sprite(null, runtime); @@ -972,14 +916,12 @@ test('shareBlocksToTarget loads extensions that have not yet been loaded', t => }) }; - vm.shareBlocksToTarget(fakeBlocks, stage.id).then(() => { - // Verify that only the not-loaded extension gets loaded - t.deepEqual(loadedIds, ['translate']); - t.end(); - }); + await vm.shareBlocksToTarget(fakeBlocks, stage.id); + // Verify that only the not-loaded extension gets loaded + assert.deepEqual(loadedIds, ['translate']); }); -test('Setting turbo mode emits events', t => { +test('Setting turbo mode emits events', () => { let turboMode = null; const vm = new VirtualMachine(); @@ -992,46 +934,41 @@ test('Setting turbo mode emits events', t => { }); vm.setTurboMode(true); - t.equal(turboMode, true); + assert.strictEqual(turboMode, true); vm.setTurboMode(false); - t.equal(turboMode, false); - - t.end(); + assert.strictEqual(turboMode, false); }); -test('Getting the renderer returns the renderer', t => { +test('Getting the renderer returns the renderer', () => { const renderer = new Renderer(); const vm = new VirtualMachine(); vm.attachRenderer(renderer); - t.equal(vm.renderer, renderer); - t.end(); + assert.strictEqual(vm.renderer, renderer); }); -test('Starting the VM emits an event', t => { +test('Starting the VM emits an event', () => { let started = false; const vm = new VirtualMachine(); vm.addListener('RUNTIME_STARTED', () => { started = true; }); vm.start(); - t.equal(started, true); + assert.strictEqual(started, true); vm.quit(); - t.end(); }); -test('vm.greenFlag() emits a PROJECT_START event', t => { +test('vm.greenFlag() emits a PROJECT_START event', () => { let greenFlagged = false; const vm = new VirtualMachine(); vm.addListener('PROJECT_START', () => { greenFlagged = true; }); vm.greenFlag(); - t.equal(greenFlagged, true); - t.end(); + assert.strictEqual(greenFlagged, true); }); -test('toJSON encodes Infinity/NaN as 0, not null', t => { +test('toJSON encodes Infinity/NaN as 0, not null', () => { const vm = new VirtualMachine(); const runtime = vm.runtime; const spr1 = new Sprite(null, runtime); @@ -1049,24 +986,20 @@ test('toJSON encodes Infinity/NaN as 0, not null', t => { runtime.targets = [stage]; const json = JSON.parse(vm.toJSON()); - t.equal(json.targets[0].volume, 0); - t.equal(json.targets[0].tempo, 0); - t.equal(json.targets[0].variables.id1[1], 0); - t.equal(json.targets[0].variables.id2[1], 0); - t.equal(json.targets[0].variables.id3[1], 0); - - t.end(); + assert.strictEqual(json.targets[0].volume, 0); + assert.strictEqual(json.targets[0].tempo, 0); + assert.strictEqual(json.targets[0].variables.id1[1], 0); + assert.strictEqual(json.targets[0].variables.id2[1], 0); + assert.strictEqual(json.targets[0].variables.id3[1], 0); }); -test('clearFlyoutBlocks removes all of the flyout blocks', t => { +test('clearFlyoutBlocks removes all of the flyout blocks', () => { const vm = new VirtualMachine(); const flyoutBlocks = vm.runtime.flyoutBlocks; flyoutBlocks.createBlock(adapter(events.mockVariableBlock)[0]); - t.equal(Object.keys(flyoutBlocks._blocks).length, 1); + assert.strictEqual(Object.keys(flyoutBlocks._blocks).length, 1); vm.clearFlyoutBlocks(); - t.equal(Object.keys(flyoutBlocks._blocks).length, 0); - - t.end(); + assert.strictEqual(Object.keys(flyoutBlocks._blocks).length, 0); }); diff --git a/test/unit/virtual-machine_tw.js b/test/unit/virtual-machine_tw.js index aa806096..39bc1477 100644 --- a/test/unit/virtual-machine_tw.js +++ b/test/unit/virtual-machine_tw.js @@ -1,10 +1,11 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const VirtualMachine = require('../../src/virtual-machine'); const RenderedTarget = require('../../src/sprites/rendered-target'); const Sprite = require('../../src/sprites/sprite'); const Variable = require('../../src/engine/variable'); -test('emitTargetsUpdate targetList is lazy', t => { +test('emitTargetsUpdate targetList is lazy', () => { const vm = new VirtualMachine(); let calledToJSON = false; vm.runtime.targets = [{ @@ -18,13 +19,12 @@ test('emitTargetsUpdate targetList is lazy', t => { targetsUpdateEvent = e; }); vm.emitTargetsUpdate(); - t.equal(calledToJSON, false); + assert.strictEqual(calledToJSON, false); void targetsUpdateEvent.targetList; // should trigger lazy compute - t.equal(calledToJSON, true); - t.end(); + assert.strictEqual(calledToJSON, true); }); -test('values in lists and variables are serialized as-is', t => { +test('values in lists and variables are serialized as-is', () => { const vm = new VirtualMachine(); const sprite = new Sprite(); const target = new RenderedTarget(sprite, vm.runtime); @@ -54,45 +54,36 @@ test('values in lists and variables are serialized as-is', t => { const json = JSON.parse(vm.toJSON()); - t.deepEqual(json.targets[0].variables.var1[1], null); - t.deepEqual(json.targets[0].variables.var2[1], null); // undefined becomes null due to JSON limitations - t.deepEqual(json.targets[0].variables.var3[1], {}); - t.deepEqual(json.targets[0].variables.var4[1], 1); - t.deepEqual(json.targets[0].variables.var5[1], 'abc'); - t.deepEqual(json.targets[0].variables.var6[1], false); + assert.deepEqual(json.targets[0].variables.var1[1], null); + assert.deepEqual(json.targets[0].variables.var2[1], null); // undefined becomes null due to JSON limitations + assert.deepEqual(json.targets[0].variables.var3[1], {}); + assert.deepEqual(json.targets[0].variables.var4[1], 1); + assert.deepEqual(json.targets[0].variables.var5[1], 'abc'); + assert.deepEqual(json.targets[0].variables.var6[1], false); - t.deepEqual(json.targets[0].lists.list[1], ['abc', false, 1, null, null, {}]); - - t.end(); + assert.deepEqual(json.targets[0].lists.list[1], ['abc', false, 1, null, null, {}]); }); -test('addSound error handling when sprite does not exist', async t => { - t.plan(1); +test('addSound error handling when sprite does not exist', async () => { const vm = new VirtualMachine(); const id = 'Inva1id5pri731D$!'; - try { - await vm.addSound({ - thisObjectDoesNotMatter: true - }, id); - } catch (e) { - if (e && e.message === `No target with ID: ${id}`) { - t.pass(); - } - } - t.end(); + await assert.rejects(vm.addSound({ + thisObjectDoesNotMatter: true + }, id), { + message: `No target with ID: ${id}` + }); }); test('convertToPackagedRuntime forwards to runtime', t => { t.plan(1); const vm = new VirtualMachine(); vm.runtime.convertToPackagedRuntime = () => { - t.pass(); + t.assert.ok(true); }; vm.convertToPackagedRuntime(); - t.end(); }); -test('deleteSprite does not skip half of the clones', t => { +test('deleteSprite does not skip half of the clones', () => { const vm = new VirtualMachine(); const sprite = new Sprite(null, vm.runtime); const original = sprite.createClone(); @@ -104,8 +95,6 @@ test('deleteSprite does not skip half of the clones', t => { vm.deleteSprite(original.id); - t.equal(sprite.clones.length, 0, 'all clones removed from the sprite'); - t.equal(vm.runtime.targets.length, 0, 'all clones removed from the runtime'); - - t.end(); + assert.strictEqual(sprite.clones.length, 0, 'all clones removed from the sprite'); + assert.strictEqual(vm.runtime.targets.length, 0, 'all clones removed from the runtime'); }); diff --git a/test/unit/vm_collectAssets.js b/test/unit/vm_collectAssets.js index 8c356a8f..0d2e46f6 100644 --- a/test/unit/vm_collectAssets.js +++ b/test/unit/vm_collectAssets.js @@ -1,10 +1,11 @@ -const test = require('tap').test; +const {test} = require('node:test'); +const assert = require('node:assert'); const RenderedTarget = require('../../src/sprites/rendered-target'); const Sprite = require('../../src/sprites/sprite'); const VirtualMachine = require('../../src/virtual-machine'); -test('collectAssets', t => { +test('collectAssets', () => { const vm = new VirtualMachine(); const sprite = new Sprite(null, vm.runtime); const target = new RenderedTarget(sprite, vm.runtime); @@ -17,8 +18,7 @@ test('collectAssets', t => { sprite.sounds = [{id: 1, asset: soundAsset1}, {id: 2, asset: soundAsset2}]; sprite.costumes = [{id: 1, asset: costumeAsset1}]; const assets = vm.assets; - t.type(assets.length, 'number'); - t.equal(assets.length, 3); - t.deepEqual(assets, [soundAsset1, soundAsset2, costumeAsset1]); - t.end(); + assert.strictEqual(typeof assets.length, 'number'); + assert.strictEqual(assets.length, 3); + assert.deepEqual(assets, [soundAsset1, soundAsset2, costumeAsset1]); });