From 06b28344e3491de37238dec6a9e7113fc9c575fa Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 20 Aug 2026 13:25:52 -0700 Subject: [PATCH 1/9] test: Remove in-browser Mocha test dependency on webdriver and gulp --- package-lock.json | 485 ++++++++++++++++++ packages/blockly/gulpfile.mjs | 7 +- packages/blockly/package.json | 7 +- .../blockly/scripts/gulpfiles/test_tasks.mjs | 39 +- .../blockly/scripts/prepare_mocha_bundle.mjs | 50 ++ packages/blockly/tests/mocha/.mocharc.js | 6 - packages/blockly/tests/mocha/browser-setup.js | 39 ++ packages/blockly/tests/mocha/index.html | 246 +-------- packages/blockly/tests/mocha/tsconfig.json | 8 + packages/blockly/tests/mocha/webdriver.js | 268 ---------- 10 files changed, 596 insertions(+), 559 deletions(-) create mode 100644 packages/blockly/scripts/prepare_mocha_bundle.mjs delete mode 100644 packages/blockly/tests/mocha/.mocharc.js create mode 100644 packages/blockly/tests/mocha/browser-setup.js create mode 100644 packages/blockly/tests/mocha/tsconfig.json delete mode 100644 packages/blockly/tests/mocha/webdriver.js diff --git a/package-lock.json b/package-lock.json index aa8e3a55155..cb1d7e26bab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6841,6 +6841,448 @@ "node": ">=10" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", @@ -18505,6 +18947,48 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -39802,6 +40286,7 @@ "async-done": "^2.0.0", "chai": "^6.2.2", "concurrently": "^10.0.4", + "esbuild": "^0.28.2", "glob": "^13.0.6", "globals": "^17.7.0", "google-closure-compiler": "^20260803.0.0", diff --git a/packages/blockly/gulpfile.mjs b/packages/blockly/gulpfile.mjs index b84c7caa042..e240eec1483 100644 --- a/packages/blockly/gulpfile.mjs +++ b/packages/blockly/gulpfile.mjs @@ -38,11 +38,7 @@ import { pack, typings, } from './scripts/gulpfiles/package_tasks.mjs'; -import { - generators, - interactiveMocha, - test, -} from './scripts/gulpfiles/test_tasks.mjs'; +import {generators, test} from './scripts/gulpfiles/test_tasks.mjs'; const clean = parallel(cleanBuildDir, cleanReleaseDir); @@ -75,7 +71,6 @@ export { clean, test, generators as testGenerators, - interactiveMocha, buildAdvancedCompilationTest, docs, typings, diff --git a/packages/blockly/package.json b/packages/blockly/package.json index 98ebc5a1c25..0c6da5cbdf2 100644 --- a/packages/blockly/package.json +++ b/packages/blockly/package.json @@ -21,6 +21,7 @@ }, "imports": { "#core/*": "./build/src/core/*", + "#blocks/*": "./build/src/blocks/*", "#generators/*": "./build/src/generators/*" }, "publishConfig": { @@ -42,7 +43,7 @@ "projects": "@blockly/dev-tools", "target": "build" } - ] + ] }, "docs": { "dependsOn": ["package", "^build"] @@ -72,8 +73,9 @@ "test": "gulp test", "test:browser": "npx mocha --config tests/browser/.mocharc.js", "test:mocha:node": "npx mocha --config tests/mocha/.mocharc.node.cjs \"tests/mocha/**/*_test.js\"", + "test:mocha:bundle": "node scripts/prepare_mocha_bundle.mjs && esbuild build/tests/bundle-entry.js --bundle --sourcemap --outfile=build/tests/mocha-bundle.js", "test:generators": "gulp testGenerators", - "test:mocha:interactive": "npm run build && concurrently -n tsc,server \"tsc --watch --preserveWatchOutput --outDir \"build/src\" --declarationDir \"build/declarations\"\" \"gulp interactiveMocha\"", + "test:mocha:interactive": "npm run build && npm run test:mocha:bundle && concurrently -n tsc,esbuild,server \"tsc --watch --preserveWatchOutput --outDir \"build/src\" --declarationDir \"build/declarations\"\" \"esbuild build/tests/bundle-entry.js --bundle --sourcemap --outfile=build/tests/mocha-bundle.js --watch=forever\" \"http-server ./ -s -o /tests/mocha/index.html -c-1\"", "test:compile:advanced": "gulp buildAdvancedCompilationTest --debug", "updateGithubPages": "npm ci && gulp updateGithubPages --upstream", "updateGithubPages:staging": "npm ci && gulp updateGithubPages --use-local" @@ -138,6 +140,7 @@ "async-done": "^2.0.0", "chai": "^6.2.2", "concurrently": "^10.0.4", + "esbuild": "^0.28.2", "glob": "^13.0.6", "globals": "^17.7.0", "google-closure-compiler": "^20260803.0.0", diff --git a/packages/blockly/scripts/gulpfiles/test_tasks.mjs b/packages/blockly/scripts/gulpfiles/test_tasks.mjs index 53af411477a..155f2a690d9 100644 --- a/packages/blockly/scripts/gulpfiles/test_tasks.mjs +++ b/packages/blockly/scripts/gulpfiles/test_tasks.mjs @@ -12,7 +12,6 @@ import asyncDone from 'async-done'; import {spawnSync} from 'child_process'; import * as fs from 'fs'; -import {globSync} from 'glob'; import * as gulp from 'gulp'; import gzip from 'gulp-gzip'; import * as path from 'path'; @@ -20,8 +19,6 @@ import {rimraf} from 'rimraf'; import {RELEASE_DIR, TEST_TSC_OUTPUT_DIR} from './config.mjs'; -import {runMochaTestsInBrowser} from '../../tests/mocha/webdriver.js'; - const OUTPUT_DIR = 'build/generators'; const GOLDEN_DIR = 'tests/generators/golden'; @@ -265,48 +262,17 @@ async function metadata() { } /** - * Generates tests/mocha/test-modules.generated.mjs, - * the list of tests imported by the browser harness (tests/mocha/index.html). - * Keeping it generated from a glob means new *_test.js files are picked up - * automatically and the browser and Node runners stay in sync. - * @return {Promise} Asynchronous result. - */ -function generateMochaIndex() { - return runTestTask('generateMochaIndex', async () => { - const files = globSync('**/*_test.js', {cwd: 'tests/mocha'}).sort(); - - const body = files.map((f) => `import './${f}';`).join('\n') + '\n'; - fs.writeFileSync('tests/mocha/test-modules.generated.mjs', body); - }); -} - -/** - * Run Mocha tests inside a browser. + * Run Mocha tests under Node. * @return {Promise} Asynchronous result. */ function mocha() { - // Run in a subprocess so webdriverio is not loaded inside gulp's asyncDone - // domain (which has been observed to exit the process on CI after ~2s). - return runTestCommand('mocha', 'node tests/mocha/webdriver.js'); + return runTestCommand('mocha', 'npm run test:mocha:node'); } /** * Run Mocha tests inside a browser and keep the browser open upon completion. * @return {Promise} Asynchronous result. */ -export const interactiveMocha = gulp.series( - generateMochaIndex, - function interactiveMochaRun() { - return runTestTask('interactiveMocha', () => { - return runMochaTestsInBrowser(false).then((result) => { - if (result) { - throw new Error('Mocha tests failed'); - } - console.log('Mocha tests passed'); - }); - }); - }, -); /** * Helper method for comparison file. @@ -429,7 +395,6 @@ const tasks = [ // Build must run before the remaining tasks build, renamings, - generateMochaIndex, mocha, generators, typeDefinitions, diff --git a/packages/blockly/scripts/prepare_mocha_bundle.mjs b/packages/blockly/scripts/prepare_mocha_bundle.mjs new file mode 100644 index 00000000000..c7bc7120d0f --- /dev/null +++ b/packages/blockly/scripts/prepare_mocha_bundle.mjs @@ -0,0 +1,50 @@ +/** + * @license + * Copyright 2026 Raspberry Pi Foundation + * SPDX-License-Identifier: Apache-2.0 + */ + +import {globSync} from 'glob'; +import * as fs from 'node:fs/promises'; +import {createRequire} from 'node:module'; +import * as path from 'node:path'; + +const require = createRequire(import.meta.url); + +const TEST_DIR = 'tests/mocha'; +const OUT_DIR = 'build/tests'; +const ENTRY_POINT = path.posix.join(OUT_DIR, 'bundle-entry.js'); + +/** + * Writes out a file that loads the in-browser Mocha test bootstrap code and + * the tests themselves, and acts as an entrypoint for esbuild to enumerate and + * bundle the various scripts that make up the test suite. + */ +async function writeEntryPoint() { + const tests = globSync('**/*_test.{js,ts}', {cwd: TEST_DIR}).sort(); + const dir = path.posix.relative(path.posix.dirname(ENTRY_POINT), TEST_DIR); + + await fs.writeFile( + ENTRY_POINT, + [ + `import '${dir}/browser-setup.js';`, + ...tests.map((file) => `import '${dir}/${file}';`), + ].join('\n'), + ); +} + +await fs.mkdir(OUT_DIR, {recursive: true}); +await writeEntryPoint(); + +// Copy files loaded directly by index.html into the build/test directory, +// resolving their paths in the process. +const VENDORED_SCRIPTS = [ + // Prebuilt browser bundle. + {from: 'mocha/mocha.js', to: 'mocha.js'}, + // Loaded directly to avoid the two-Blockly problem. + {from: '@blockly/block-test/dist/index.js', to: 'block-test.js'}, +]; + +for (const {from, to} of VENDORED_SCRIPTS) { + await fs.copyFile(require.resolve(from), path.join(OUT_DIR, to)); +} diff --git a/packages/blockly/tests/mocha/.mocharc.js b/packages/blockly/tests/mocha/.mocharc.js deleted file mode 100644 index 42378c7fa9d..00000000000 --- a/packages/blockly/tests/mocha/.mocharc.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -module.exports = { - ui: 'tdd', - reporter: 'landing', -}; diff --git a/packages/blockly/tests/mocha/browser-setup.js b/packages/blockly/tests/mocha/browser-setup.js new file mode 100644 index 00000000000..286165e5632 --- /dev/null +++ b/packages/blockly/tests/mocha/browser-setup.js @@ -0,0 +1,39 @@ +/** + * @license + * Copyright 2026 Raspberry Pi Foundation + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Browser harness for the Blockly unit suite. + * + * This is the browser counterpart to node-setup.mjs: it loads Blockly, exposes + * the globals the tests expect, installs the shared DOM fixtures and configures + * Mocha. It is bundled, along with every test module, into + * build/tests/mocha-bundle.js, which is loaded by the test page. + */ + +// Prevent Prettier from reordering imports to load blocks before Blockly. +// organize-imports-ignore +import * as Blockly from '#core/blockly.js'; +import '#blocks/blocks.js'; +import {javascriptGenerator} from '#generators/javascript.js'; +import {config as chaiConfig} from 'chai'; +import sinon from 'sinon'; +import 'mocha/mocha.css'; +import {installFixtures} from './test_helpers/dom_fixtures.js'; + +chaiConfig.showDiff = false; + +globalThis.Blockly = Blockly; +globalThis.javascriptGenerator = javascriptGenerator; +globalThis.sinon = sinon; + +// The focusable trees, toolbox definitions and #blocklyDiv the tests expect. +// Shared with the Node harness so both run against identical markup. +installFixtures(); + +mocha.setup({ + ui: 'tdd', + failZero: true, +}); diff --git a/packages/blockly/tests/mocha/index.html b/packages/blockly/tests/mocha/index.html index bc77544301c..365d51d27e8 100644 --- a/packages/blockly/tests/mocha/index.html +++ b/packages/blockly/tests/mocha/index.html @@ -3,23 +3,7 @@ Mocha Tests for Blockly - - - +
- - - + + + + - - diff --git a/packages/blockly/tests/mocha/tsconfig.json b/packages/blockly/tests/mocha/tsconfig.json new file mode 100644 index 00000000000..a85bf44f30d --- /dev/null +++ b/packages/blockly/tests/mocha/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["**/*", "../../build/declarations/core/any_aliases.d.ts"], + "compilerOptions": { + "checkJs": false, + "noEmit": true + } +} diff --git a/packages/blockly/tests/mocha/webdriver.js b/packages/blockly/tests/mocha/webdriver.js deleted file mode 100644 index 99d3271ca75..00000000000 --- a/packages/blockly/tests/mocha/webdriver.js +++ /dev/null @@ -1,268 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @fileoverview Node.js script to run Mocha tests in Chrome, via webdriver. - */ -const webdriverio = require('webdriverio'); -const fs = require('fs'); -const path = require('path'); -const {posixPath} = require('../../scripts/helpers'); -const { - getWebdriverOptions, - runBrowserTestMain, -} = require('../scripts/webdriver_helpers.js'); - -/** @const {number} Max time to wait for the browser test page to finish. */ -const PAGE_TIMEOUT_MS = 120000; - -/** @const {number} Max time to wait for browser.deleteSession(). */ -const DELETE_SESSION_TIMEOUT_MS = 15000; - -/** - * Ensure browser test imports that use ../../node_modules/* continue to work - * when npm hoists dependencies to the repository root node_modules dir - */ -function ensureWorkspaceNodeModulesLinks() { - const workspaceNodeModules = path.resolve(__dirname, '../../node_modules'); - const rootNodeModules = path.resolve(__dirname, '../../../../node_modules'); - const packages = ['mocha', 'sinon', 'chai', '@blockly/dev-tools']; - - for (const pkg of packages) { - const workspacePkgPath = path.join(workspaceNodeModules, pkg); - const rootPkgPath = path.join(rootNodeModules, pkg); - - if (fs.existsSync(workspacePkgPath) || !fs.existsSync(rootPkgPath)) { - continue; - } - - fs.mkdirSync(path.dirname(workspacePkgPath), {recursive: true}); - fs.symlinkSync(rootPkgPath, workspacePkgPath, 'dir'); - } -} - -/** - * Run a promise with a timeout. - * @param {!Promise} promise The promise to run. - * @param {number} timeoutMs Timeout in milliseconds. - * @param {string} label Description for timeout errors. - * @return {!Promise} - */ -function withTimeout(promise, timeoutMs, label) { - return Promise.race([ - promise, - new Promise((_, reject) => { - setTimeout(() => { - reject(new Error(label + ' timed out after ' + timeoutMs + 'ms')); - }, timeoutMs); - }), - ]); -} - -/** - * Close the browser session, with a timeout so CI cannot hang forever. - * @param {?Object} browser The webdriverio browser instance. - */ -async function closeBrowserSession(browser) { - if (!browser) { - return; - } - try { - await withTimeout( - browser.deleteSession(), - DELETE_SESSION_TIMEOUT_MS, - 'browser.deleteSession()', - ); - } catch (e) { - console.warn('Failed to close browser session:', e.message); - } -} - -/** - * Enable focus emulation via CDP. Wrapped in a timeout because this call - * has been observed to hang intermittently on CI. - * @param {!Object} browser The webdriverio browser instance. - */ -async function enableFocusEmulation(browser) { - const timeoutMs = 10000; - try { - await withTimeout( - (async () => { - const puppeteer = await browser.getPuppeteer(); - await browser.call(async () => { - const page = (await puppeteer.pages())[0]; - const session = await page.createCDPSession(); - await session.send('Emulation.setFocusEmulationEnabled', { - enabled: true, - }); - }); - })(), - timeoutMs, - 'Focus emulation setup', - ); - } catch (e) { - console.warn('Focus emulation setup failed (continuing anyway):', - e.message); - } -} - -/** - * Print browser-side load diagnostics when tests fail to start or finish. - * @param {!Object} browser The webdriverio browser instance. - */ -async function printBrowserLoadDiagnostics(browser) { - if (!browser) { - return; - } - try { - await withTimeout((async () => { - console.log('============Blockly Mocha Load Diagnostics================'); - const loadStatus = await browser.$('#loadStatus') - .getAttribute('data-status'); - console.log('Load status:', loadStatus ?? 'unknown'); - const loadErrors = await browser.execute(() => { - return window.__blocklyTestLoadState?.errors ?? []; - }); - if (loadErrors.length) { - console.log('Captured load errors:'); - for (const error of loadErrors) { - console.log(' ' + error); - } - } - const failureMessagesEls = await browser.$$('#failureMessages p'); - for (const el of failureMessagesEls) { - const messageHtml = await el.getHTML(); - console.log(messageHtml.replace(/<\/?p>/g, '')); - } - if (loadStatus === 'pending' || loadStatus === 'imports-complete') { - console.log( - 'Blockly or test modules may not have loaded completely.'); - } - console.log('=========================================================='); - })(), 10000, 'Load diagnostics'); - } catch (diagErr) { - console.warn('Could not collect browser diagnostics:', diagErr.message); - } -} - -/** - * Wait until Mocha reports results or the page reports a load failure. - * @param {!Object} browser The webdriverio browser instance. - */ -async function waitForTestCompletion(browser) { - await browser.waitUntil(async() => { - const failureCount = await browser.$('#failureCount') - .getAttribute('tests_failed'); - if (failureCount !== 'unset') { - return true; - } - const loadStatus = await browser.$('#loadStatus') - .getAttribute('data-status'); - return loadStatus === 'failed'; - }, { - timeout: PAGE_TIMEOUT_MS, - timeoutMsg: 'Timed out waiting for Mocha tests to finish. Blockly may ' + - 'have failed to load; see load diagnostics below.', - }); -} - -/** - * Runs the Mocha tests in this directory in Chrome. It uses webdriverio to - * launch Chrome and load index.html. Outputs a summary of the test results - * to the console. - * - * @param {boolean} exitOnCompletetion True if the browser should automatically - * quit after tests have finished running. - * @return {number} 0 on success, 1 on failure. - */ -async function runMochaTestsInBrowser(exitOnCompletion = true) { - // Gulp may pass a done callback as the first argument. - if (typeof exitOnCompletion === 'function') { - exitOnCompletion = true; - } - return runMochaTestsInBrowserImpl(exitOnCompletion); -} - -/** - * @param {boolean} exitOnCompletion True if the browser should quit after tests. - * @return {number} 0 on success, 1 on failure. - */ -async function runMochaTestsInBrowserImpl(exitOnCompletion) { - ensureWorkspaceNodeModulesLinks(); - - const options = getWebdriverOptions(); - - const url = 'file://' + posixPath(__dirname) + '/index.html'; - console.log('Starting webdriverio...'); - let browser; - let numOfFailure = '1'; - let pageLoaded = false; - let testsCompleted = false; - try { - browser = await webdriverio.remote(options); - console.log('Loading URL: ' + url); - await browser.url(url); - pageLoaded = true; - - // Focus emulation via CDP has hung on CI; skip there. - if (!process.env.CI) { - await enableFocusEmulation(browser); - } - - await waitForTestCompletion(browser); - testsCompleted = true; - - const elem = await browser.$('#failureCount'); - numOfFailure = await elem.getAttribute('tests_failed'); - - if (numOfFailure > 0) { - console.log('============Blockly Mocha Test Failures================'); - const failureMessagesEls = await browser.$$('#failureMessages p'); - if (!failureMessagesEls.length) { - console.log('There is at least one test failure, but no messages ' + - 'reported. Mocha may be failing because no tests are being run.'); - } - for (const el of failureMessagesEls) { - const messageHtml = await el.getHTML(); - console.log(messageHtml.replace(/<\/?p>/g, '')); - } - } - } catch (e) { - await printBrowserLoadDiagnostics(browser); - throw e; - } finally { - if (exitOnCompletion) { - await closeBrowserSession(browser); - } - } - - if (!pageLoaded) { - throw new Error( - 'Mocha browser tests did not start: Chrome failed to load the test ' + - 'page. Check chromedriver and Chrome setup.', - ); - } - if (!testsCompleted) { - throw new Error( - 'Mocha browser tests did not finish: the test page never reported ' + - 'results.', - ); - } - - console.log('============Blockly Mocha Test Summary================='); - console.log(numOfFailure + ' tests failed'); - console.log('============Blockly Mocha Test Summary================='); - if (parseInt(numOfFailure) !== 0) { - return 1; - } - return 0; -} - -if (require.main === module) { - runBrowserTestMain(() => runMochaTestsInBrowser()); -} - -module.exports = {runMochaTestsInBrowser}; From fb2dad05b41a33acaa218c034adef55dd5f1dfd0 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 20 Aug 2026 13:28:37 -0700 Subject: [PATCH 2/9] chore: Remove dead code that supported the old metadata size check test --- .../blockly/scripts/gulpfiles/test_tasks.mjs | 97 ------------------- 1 file changed, 97 deletions(-) diff --git a/packages/blockly/scripts/gulpfiles/test_tasks.mjs b/packages/blockly/scripts/gulpfiles/test_tasks.mjs index 155f2a690d9..8c322a05e7e 100644 --- a/packages/blockly/scripts/gulpfiles/test_tasks.mjs +++ b/packages/blockly/scripts/gulpfiles/test_tasks.mjs @@ -164,103 +164,6 @@ function renamings() { return runTestCommand('renamings', 'tests/migration/validate-renamings.mjs'); } -/** - * Helper method for gzipping file. - * @param {string} file Target file. - * @return {Promise} Asynchronous result. - */ -function gzipFile(file) { - return new Promise((resolve) => { - const name = path.posix.join(RELEASE_DIR, file); - - const stream = gulp.src(name) - .pipe(gzip()) - .pipe(gulp.dest(RELEASE_DIR)); - - stream.on('end', () => { - resolve(); - }); - }); -} - -/** - * Helper method for comparing file size. - * @param {string} file Target file. - * @param {number} expected Expected size. - * @return {number} 0: success / 1: failed. - */ -function compareSize(file, expected) { - const name = path.posix.join(RELEASE_DIR, file); - const compare = Math.floor(expected * 1.1); - const stat = fs.statSync(name); - const size = stat.size; - - if (!compare) { - const message = `Failed: Previous size of ${name} is undefined.`; - console.log(`${BOLD_RED}${message}${ANSI_RESET}`); - return 1; - } - - if (size > compare) { - const message = `Failed: ` + - `Size of ${name} has grown more than 10%. ${size} vs ${expected}`; - console.log(`${BOLD_RED}${message}${ANSI_RESET}`); - return 1; - } - - const message = - `Size of ${name} at ${size} compared to previous ${expected}`; - console.log(`${BOLD_GREEN}${message}${ANSI_RESET}`); - return 0; -} - -/** - * Helper method for zipping the compressed files. - * @return {Promise} Asynchronous result. - */ -function zippingFiles() { - // GZip them for additional size comparisons (keep originals, force - // overwite previously-gzipped copies). - console.log('Zipping the compressed files'); - const gzip1 = gzipFile('blockly_compressed.js'); - const gzip2 = gzipFile('blocks_compressed.js'); - return Promise.all([gzip1, gzip2]); -} - -/** - * Check the sizes of built files for unexpected growth. - * @return {Promise} Asynchronous result. - */ -async function metadata() { - return runTestTask('metadata', async () => { - // Zipping the compressed files. - await zippingFiles(); - // Read expected size from script. - const contents = fs.readFileSync('tests/scripts/check_metadata.sh') - .toString(); - const pattern = /^readonly (?[A-Z_]+)=(?\d+)$/gm; - const matches = contents.matchAll(pattern); - const expected = {}; - for (const match of matches) { - expected[match.groups.key] = match.groups.value; - } - - // Check the sizes of the files. - let failed = 0; - failed += compareSize('blockly_compressed.js', - expected.BLOCKLY_SIZE_EXPECTED); - failed += compareSize('blocks_compressed.js', - expected.BLOCKS_SIZE_EXPECTED); - failed += compareSize('blockly_compressed.js.gz', - expected.BLOCKLY_GZ_SIZE_EXPECTED); - failed += compareSize('blocks_compressed.js.gz', - expected.BLOCKS_GZ_SIZE_EXPECTED); - if (failed > 0) { - throw new Error('Unexpected growth was detected.'); - } - }); -} - /** * Run Mocha tests under Node. * @return {Promise} Asynchronous result. From d453ee4906f6cfc7566c2ad8f09649c7b446fdfc Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 20 Aug 2026 13:57:38 -0700 Subject: [PATCH 3/9] chore: Remove dead comment --- packages/blockly/scripts/gulpfiles/test_tasks.mjs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/blockly/scripts/gulpfiles/test_tasks.mjs b/packages/blockly/scripts/gulpfiles/test_tasks.mjs index 8c322a05e7e..4013f658f0d 100644 --- a/packages/blockly/scripts/gulpfiles/test_tasks.mjs +++ b/packages/blockly/scripts/gulpfiles/test_tasks.mjs @@ -172,11 +172,6 @@ function mocha() { return runTestCommand('mocha', 'npm run test:mocha:node'); } -/** - * Run Mocha tests inside a browser and keep the browser open upon completion. - * @return {Promise} Asynchronous result. - */ - /** * Helper method for comparison file. * @param {string} file1 First target file. From 22300c2dc1b3e9345eb021e92aab70e13f9242d3 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 20 Aug 2026 14:01:07 -0700 Subject: [PATCH 4/9] test: Make browser-specific test browser-agnostic --- packages/blockly/tests/mocha/dropdowndiv_test.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/blockly/tests/mocha/dropdowndiv_test.js b/packages/blockly/tests/mocha/dropdowndiv_test.js index 0dd2f8af83f..cb6e119bc4d 100644 --- a/packages/blockly/tests/mocha/dropdowndiv_test.js +++ b/packages/blockly/tests/mocha/dropdowndiv_test.js @@ -177,10 +177,8 @@ suite('DropDownDiv', function () { const block = this.setUpBlockWithField(); const field = Array.from(block.getFields())[0]; - const errorMsgRegex = /Cannot read properties of null.+?/; - assert.throws( - () => Blockly.DropDownDiv.show(field, false, 50, 60, 70, 80, false), - errorMsgRegex, + assert.throws(() => + Blockly.DropDownDiv.show(field, false, 50, 60, 70, 80, false), ); }); From 9f4e48d325c8ecc94335545a04fcf206afd6c7e3 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Thu, 20 Aug 2026 14:33:16 -0700 Subject: [PATCH 5/9] test: Don't output the details of every testcase when run under node --- .../blockly/tests/mocha/.mocharc.node.cjs | 2 +- .../blockly/tests/mocha/quiet_reporter.cjs | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 packages/blockly/tests/mocha/quiet_reporter.cjs diff --git a/packages/blockly/tests/mocha/.mocharc.node.cjs b/packages/blockly/tests/mocha/.mocharc.node.cjs index ee49831778b..aa9860d5c83 100644 --- a/packages/blockly/tests/mocha/.mocharc.node.cjs +++ b/packages/blockly/tests/mocha/.mocharc.node.cjs @@ -14,7 +14,7 @@ module.exports = { ui: 'tdd', - reporter: 'spec', + reporter: './tests/mocha/quiet_reporter.cjs', parallel: true, require: ['./tests/mocha/node-setup.mjs'], timeout: 10000, diff --git a/packages/blockly/tests/mocha/quiet_reporter.cjs b/packages/blockly/tests/mocha/quiet_reporter.cjs new file mode 100644 index 00000000000..39650065da5 --- /dev/null +++ b/packages/blockly/tests/mocha/quiet_reporter.cjs @@ -0,0 +1,21 @@ +/** + * @license + * Copyright 2026 Raspberry Pi Foundation + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict'; + +const {reporters, Runner} = require('mocha'); +/** + * Mocha reporter that prints only the run totals, plus the details of any + * failures. + */ +class Quiet extends reporters.Base { + constructor(runner, options) { + super(runner, options); + runner.once(Runner.constants.EVENT_RUN_END, () => this.epilogue()); + } +} + +module.exports = Quiet; From 510fc504759774b4e6fc9a5c9a76fb51685d8cd5 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 21 Aug 2026 09:14:04 -0700 Subject: [PATCH 6/9] test: Enable hot reloading of Mocha tests --- packages/blockly/package.json | 2 +- packages/blockly/tests/mocha/index.html | 10 +++++++++- packages/blockly/tsconfig.json | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/blockly/package.json b/packages/blockly/package.json index 0c6da5cbdf2..0cd164a3cf2 100644 --- a/packages/blockly/package.json +++ b/packages/blockly/package.json @@ -75,7 +75,7 @@ "test:mocha:node": "npx mocha --config tests/mocha/.mocharc.node.cjs \"tests/mocha/**/*_test.js\"", "test:mocha:bundle": "node scripts/prepare_mocha_bundle.mjs && esbuild build/tests/bundle-entry.js --bundle --sourcemap --outfile=build/tests/mocha-bundle.js", "test:generators": "gulp testGenerators", - "test:mocha:interactive": "npm run build && npm run test:mocha:bundle && concurrently -n tsc,esbuild,server \"tsc --watch --preserveWatchOutput --outDir \"build/src\" --declarationDir \"build/declarations\"\" \"esbuild build/tests/bundle-entry.js --bundle --sourcemap --outfile=build/tests/mocha-bundle.js --watch=forever\" \"http-server ./ -s -o /tests/mocha/index.html -c-1\"", + "test:mocha:interactive": "npm run build && npm run test:mocha:bundle && concurrently -n tsc,esbuild,python3 \"tsc --watch --preserveWatchOutput --outDir \"build/src\" --declarationDir \"build/declarations\"\" \"esbuild build/tests/bundle-entry.js --bundle --sourcemap --outfile=build/tests/mocha-bundle.js --servedir=. --serve=127.0.0.1:8080 --watch=forever --log-level=warning\" \"python3 -m webbrowser 'http://localhost:8080/tests/mocha/index.html'\"", "test:compile:advanced": "gulp buildAdvancedCompilationTest --debug", "updateGithubPages": "npm ci && gulp updateGithubPages --upstream", "updateGithubPages:staging": "npm ci && gulp updateGithubPages --use-local" diff --git a/packages/blockly/tests/mocha/index.html b/packages/blockly/tests/mocha/index.html index 365d51d27e8..dba73856101 100644 --- a/packages/blockly/tests/mocha/index.html +++ b/packages/blockly/tests/mocha/index.html @@ -20,7 +20,15 @@ diff --git a/packages/blockly/tsconfig.json b/packages/blockly/tsconfig.json index 840d73a82c6..659c02029cd 100644 --- a/packages/blockly/tsconfig.json +++ b/packages/blockly/tsconfig.json @@ -5,6 +5,8 @@ // normally they are ignored as source files "allowJs": true, + "incremental": true, + // Generate d.ts files and sourcemaps. "declaration": true, // Generate declaration maps used for api-extractor From 701b307271c01622da7ce69d9b59ffdd34da41d9 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Fri, 21 Aug 2026 09:14:45 -0700 Subject: [PATCH 7/9] test: Log Mocha failures to console to provide sourcemapped stacktraces --- packages/blockly/tests/mocha/.mocharc.node.cjs | 1 + packages/blockly/tests/mocha/index.html | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/packages/blockly/tests/mocha/.mocharc.node.cjs b/packages/blockly/tests/mocha/.mocharc.node.cjs index aa9860d5c83..decf5d7dbee 100644 --- a/packages/blockly/tests/mocha/.mocharc.node.cjs +++ b/packages/blockly/tests/mocha/.mocharc.node.cjs @@ -14,6 +14,7 @@ module.exports = { ui: 'tdd', + 'node-option': ['enable-source-maps'], reporter: './tests/mocha/quiet_reporter.cjs', parallel: true, require: ['./tests/mocha/node-setup.mjs'], diff --git a/packages/blockly/tests/mocha/index.html b/packages/blockly/tests/mocha/index.html index dba73856101..02c3f9a9428 100644 --- a/packages/blockly/tests/mocha/index.html +++ b/packages/blockly/tests/mocha/index.html @@ -19,6 +19,14 @@ + -