diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index bf0b8c9c177..1ee520db67c 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -101,6 +101,11 @@ runs: sudo apt install libnss3-tools brew install mkcert + - name: 'Setup DBus for Chrome' + shell: bash + run: | + echo "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus" >> $GITHUB_ENV + - name: Configure Parallel Builds if: ${{ inputs.parallel-build == 'true' }} shell: bash diff --git a/.github/workflows/compat-tests.yml b/.github/workflows/compat-tests.yml index 19620590cd8..3ace12ed41f 100644 --- a/.github/workflows/compat-tests.yml +++ b/.github/workflows/compat-tests.yml @@ -54,18 +54,24 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Run Tests run: pnpm test:vite - floating-dependencies: - timeout-minutes: 9 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - - uses: ./.github/actions/setup - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - name: Install dependencies w/o lockfile - run: pnpm install --no-lockfile - - name: Basic Tests - run: pnpm test + ### + # This Test No Longer Works Because pnpm install --no-lockfile + # returns exit code 1 whenever there is a lockfile present and + # changes are made to node_modules. This is probably a bug in pnpm. + ### + # + # floating-dependencies: + # timeout-minutes: 9 + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + # - uses: ./.github/actions/setup + # with: + # repo-token: ${{ secrets.GITHUB_TOKEN }} + # - name: Install dependencies w/o lockfile + # run: pnpm install --no-lockfile + # - name: Basic Tests + # run: pnpm test node-version-test: name: Use Node.js ${{ matrix.node-version }} timeout-minutes: 10 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8a66fd1cdca..41e1233d404 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -174,7 +174,11 @@ jobs: timeout-minutes: 12 env: CI: true - run: pnpm test:try-one ${{ matrix.scenario }} -- ember test --test-port=0 + run: | + cd tests/main; + pnpm exec ember try:one ${{ matrix.scenario }} --skip-cleanup; + pnpm build:tests; + pnpm run test; releases: timeout-minutes: 12 @@ -201,4 +205,8 @@ jobs: - name: Basic tests with ${{ matrix.release }} env: CI: true - run: pnpm test:try-one ${{ matrix.release }} -- ember test --test-port=0 + run: | + cd tests/main; + pnpm exec ember try:one ${{ matrix.release }} --skip-cleanup; + pnpm build:tests; + pnpm run test; diff --git a/.npmrc b/.npmrc index 85ad2a610f3..801200cc7af 100644 --- a/.npmrc +++ b/.npmrc @@ -1,31 +1,156 @@ -# package-import-method=hardlink -# module-exists will report false answers for the test apps -# unless we avoid hoisting -# while this is "true" this actually sets hoisting to "false" -# because we have a hoist-pattern. This basically just lets us -# use the very narrowly scoped hoist-pattern. -hoist=true -# Fastboot Doesnt respect node_modules resolution for whitelisted deps -# https://github.com/ember-fastboot/ember-cli-fastboot/issues/901 -hoist-pattern[]=*node-fetch* - -# we want true but cannot use true until the below issue is fixed -# https://github.com/pnpm/pnpm/issues/5340 -strict-peer-dependencies=true -auto-install-peers=false # probably apps should set this to true, but we need to test with it false to be sure we aren't the bad citizen -dedupe-peer-dependents=false # this currently introduces more bugs than it fixes -resolve-peers-from-workspace-root=false # if its not declared we don't want it resolved: ensure tests are truly isolated +## Woo! A Config File! +## +## This file is used to configure the behavior of pnpm. +## If adjusting settings, please document the "why" in comments. +## +## It may also be good to understand that we intentionally are +## not using `hoisting` and using `injected` workspace packages +## to ensure properly isolated dep trees for test apps. +# +## things like `moduleExists` from @embroider/macros will report false answers +## for the test apps unless we avoid hoisting. +## +## Note, if we ever need to hoist something, we can use hoist-pattern[]="" +## For instance: hoist-pattern[]=*node-fetch* +## to hoist the specific thing we need and set this to `true`. When true +## and a hoist-pattern is present only the hoist-pattern will be hoisted. +# +hoist=false + +## We should consider removing these +## But historically this was the default for pnpm +## and there is cleanup to do to make things work +## without these +## Its also just useful to have these tools top-level +# +public-hoist-pattern[]=*eslint* +public-hoist-pattern[]=*prettier* + +## Ideally this would be dynamic as in CI we only have 4 CPUs +## While locally we have 10-16 CPUs. The more CPUs we use during +## install, generally the faster the install will be. +## +child-concurrency=10 + +## This is the default but its good to be explicit +## This helps us to ensure we are using the workspace +## version of a package. +## save-workspace-protocol=rolling + +## The current default is "highest" but we want to be explicit +## Since we also just want to ensure we are always using the +## latest versions of things we can. +## resolution-mode=highest -dedupe-direct-deps=true -child-concurrency=10 -ignore-dep-scripts=true -dedupe-injected-deps=false -link-workspace-packages=deep -hoist-workspace-packages=false + +## This is documented in a slightly different place in the pnpm +## docs. If this setting is true (the default) then pnpm will +## run the pre* and post* versions of a script when running other +## scripts. For instance running "build" would also run "prebuild" +## and "postbuild". This is not the behavior we want. +## enable-pre-post-scripts=false + +## We use volta to manage our node and pnpm versions, so we do not +## want pnpm to manage these for us. +## manage-package-manager-versions=false + +## This is now the default but we want to be explicit +## This prevents security exploits from packages running +## arbitrary code during install. It also speeds up install times. +## Our own packages will still run their installation scripts +## +ignore-dep-scripts=true + +## Make sure we don't troll ourselves when updating deps +## +verify-deps-before-run=true + +## We do not want to auto-install peers because +## We want to ensure we understand what is actually required +## So that if a consuming app uses strict mode things will work +## +## This said, Apps should probably set this to true +## +auto-install-peers=false + +## We want to error if we did not setup required peers correctly +## However, this pnpm bug prevents us using this as it will +## error when using `--no-lockfile` without reporting any errors +## https://github.com/pnpm/pnpm/issues/8382 +## +strict-peer-dependencies=false + +## We use so many similarly grouped peers, we want to make the +## peer-groups easier to distinguish. +## This forces a shorter sha for all groups (vs the default of 1000) +## +peers-suffix-max-length=40 +virtual-store-dir-max-length=40 + +## If a dependency is not declared, we do not want to accidentally +## resolve it from the workspace root. This is a common source of +## bugs in monorepos. +## +resolve-peers-from-workspace-root=false + +## Our Workspace Packages are "injected" so prevent +## devDependencies from being exposed and to allow +## for us to test optional peerDependencies. +## inject-workspace-packages=true -public-hoist-pattern[]=*eslint* -public-hoist-pattern[]=*prettier* +## This also means we do not want to hoist them to the root +## As this would both expose them to all other packages AND +## results in them using symlinks instead of hardlinks +## +hoist-workspace-packages=false + +## We use the `workspace:*` protocol for all workspace +## packages. +## In theory it would be nice to use `deep` here just in case +## we missed something so that we could tell pnpm to use the +## workspace version of a package if it exists. At any depth. +## +## However, it seems that deep/true result in workspace packages +## that are dependencies being symlinked instead of hardlinked +## more often, even at the top-level of a package, which is not +## what we want. +## +link-workspace-packages=false # deep + +## Update injected dependencies when needed +## This will rerun after various "build" scripts +## In our published packages. +## +## Unfortunately, this does not run after scripts in +## the monorepo root, so we have added a special "sync" +## script to handle this. +## +sync-injected-deps-after-scripts[]=build:pkg +sync-injected-deps-after-scripts[]=build:infra +sync-injected-deps-after-scripts[]=build:glint +sync-injected-deps-after-scripts[]=sync + +## In keeping with our "no hoisting" and "no auto-peers" and +## "isolated dep trees", we also want to avoid other things +## that lead to reliance on hoisting. +## In general, deduping leads to hoisting. This particular +## setting causes direct-dependencies to resolve from the +## workspace root if already in root. We don't want this. +## +dedupe-direct-deps=false + +## We do not want to dedupe peer dependencies as this +## results in hoisting and violates optional peer isolation. +## +dedupe-peer-dependents=false + +## We do not want to dedupe injected dependencies as this +## results in hoisting and violates optional peer isolation. +## +dedupe-injected-deps=false + +## Fin diff --git a/package.json b/package.json index af96bbf2991..7ae1b4b56af 100644 --- a/package.json +++ b/package.json @@ -9,24 +9,23 @@ }, "scripts": { "takeoff": "FORCE_COLOR=2 pnpm install --prefer-offline --reporter=append-only", - "prepare": "turbo run build:infra; pnpm --filter './packages/*' run --parallel --if-present sync-hardlinks; turbo run build:pkg; pnpm run prepare:types; pnpm run _task:sync-hardlinks;", - "prepare:types": "tsc --build --force; turbo run build:glint;", + "prepare": "export TURBO_FORCE=true; turbo run build:pkg; pnpm run prepare:types;", + "prepare:types": "export TURBO_FORCE=true; tsc --build --force; turbo run build:glint;", "release": "./release/index.ts", "build": "turbo _build --log-order=stream --filter=./packages/* --concurrency=10;", - "_task:sync-hardlinks": "pnpm run -r --parallel --if-present sync-hardlinks;", + "sync": "pnpm --filter './packages/*' run --parallel --if-present sync", "build:docs": "mkdir -p packages/-ember-data/dist && cd ./docs-generator && node ./compile-docs.js", "lint:tests": "turbo --log-order=stream lint --filter=./tests/* --continue --concurrency=10", "lint:pkg": "turbo --log-order=stream lint --filter=./packages/* --continue --concurrency=10", - "lint": "pnpm run _task:sync-hardlinks; turbo --log-order=stream lint --continue --concurrency=10", - "lint:fix": "pnpm run _task:sync-hardlinks; turbo --log-order=stream lint --continue --concurrency=10 -- --fix", + "lint": "turbo --log-order=stream lint --continue --concurrency=10", + "lint:fix": "turbo --log-order=stream lint --continue --concurrency=10 -- --fix", "lint:prettier": "prettier --check --cache --cache-location=.prettier-cache --log-level=warn .", "lint:prettier:fix": "prettier --write --cache --cache-location=.prettier-cache --log-level=warn .", "preinstall": "npx only-allow pnpm", "check:test-types": "turbo --log-order=stream check:types --filter=./{tests,config}/* --continue --concurrency=10", - "check:types": "pnpm run _task:sync-hardlinks; bun run check:test-types", - "test": "pnpm run _task:sync-hardlinks; pnpm turbo test --concurrency=1", - "test:production": "pnpm run _task:sync-hardlinks; pnpm turbo test:production --concurrency=1", - "test:try-one": "pnpm --filter main-test-app run test:try-one", + "check:types": "bun run check:test-types", + "test": "pnpm turbo test --concurrency=1", + "test:production": "pnpm turbo test:production --concurrency=1", "test:docs": "FORCE_COLOR=2 pnpm build:docs && pnpm run -r --workspace-concurrency=-1 --if-present --reporter=append-only --reporter-hide-prefix test:docs", "test:blueprints": "pnpm run -r --workspace-concurrency=-1 --if-present test:blueprints", "test:fastboot": "pnpm run -r --workspace-concurrency=-1 --if-present test:fastboot", @@ -135,6 +134,13 @@ "@glimmer/component": "*" } }, + "ember-exam": { + "peerDependencies": { + "ember-cli": "*", + "ember-qunit": "*", + "qunit": "*" + } + }, "@ember/test-helpers": { "dependencies": { "webpack": "*" @@ -174,8 +180,7 @@ "testem@3.11.0": "patches/testem@3.11.0.patch", "@ember/test-helpers@3.3.0": "patches/@ember__test-helpers@3.3.0.patch", "@ember/test-helpers@4.0.4": "patches/@ember__test-helpers@4.0.4.patch", - "@ember/test-helpers@5.1.0": "patches/@ember__test-helpers@5.1.0.patch", - "pnpm-sync-dependencies-meta-injected": "patches/pnpm-sync-dependencies-meta-injected.patch" + "@ember/test-helpers@5.1.0": "patches/@ember__test-helpers@5.1.0.patch" } } } diff --git a/packages/-ember-data/package.json b/packages/-ember-data/package.json index 1b92d1d449c..ab6c2d8bc9c 100644 --- a/packages/-ember-data/package.json +++ b/packages/-ember-data/package.json @@ -17,8 +17,7 @@ "scripts": { "lint": "eslint . --quiet --cache --cache-strategy=content", "build:pkg": "vite build;", - "prepack": "bun run build:pkg", - "sync-hardlinks": "bun run sync-dependencies-meta-injected" + "prepack": "pnpm run build:pkg" }, "ember-addon": { "main": "addon-main.cjs", @@ -113,7 +112,6 @@ "@warp-drive/internal-config": "workspace:*", "ember-source": "~5.12.0", "eslint": "^9.12.0", - "pnpm-sync-dependencies-meta-injected": "0.0.14", "vite": "^5.2.11", "typescript": "^5.7.2", "qunit": "^2.18.0" diff --git a/packages/-warp-drive/package.json b/packages/-warp-drive/package.json index 902c3a5e204..33d644c69ab 100644 --- a/packages/-warp-drive/package.json +++ b/packages/-warp-drive/package.json @@ -26,8 +26,8 @@ "author": "Chris Thoburn ", "scripts": { "build:pkg": "vite build;", - "prepack": "bun run build:pkg", - "sync-hardlinks": "bun run sync-dependencies-meta-injected" + "prepack": "pnpm run build:pkg", + "sync": "echo \"syncing\"" }, "bin": { "warp-drive": "./dist/warp-drive.js", @@ -59,7 +59,6 @@ "@babel/plugin-transform-typescript": "^7.24.5", "@babel/preset-typescript": "^7.24.1", "@warp-drive/internal-config": "workspace:*", - "pnpm-sync-dependencies-meta-injected": "0.0.14", "typescript": "^5.7.2", "vite": "^5.2.11" }, diff --git a/packages/active-record/package.json b/packages/active-record/package.json index a3ee30a32bf..b7191bf07f2 100644 --- a/packages/active-record/package.json +++ b/packages/active-record/package.json @@ -36,8 +36,8 @@ "scripts": { "lint": "eslint . --quiet --cache --cache-strategy=content", "build:pkg": "vite build;", - "prepack": "bun run build:pkg", - "sync-hardlinks": "bun run sync-dependencies-meta-injected" + "prepack": "pnpm run build:pkg", + "sync": "echo \"syncing\"" }, "ember-addon": { "main": "addon-main.cjs", @@ -65,7 +65,6 @@ "@warp-drive/core-types": "workspace:*", "@warp-drive/internal-config": "workspace:*", "ember-source": "~5.12.0", - "pnpm-sync-dependencies-meta-injected": "0.0.14", "vite": "^5.2.11", "typescript": "^5.7.2" }, diff --git a/packages/adapter/package.json b/packages/adapter/package.json index 41865733199..16c2bf5ac27 100644 --- a/packages/adapter/package.json +++ b/packages/adapter/package.json @@ -16,8 +16,7 @@ "scripts": { "lint": "eslint . --quiet --cache --cache-strategy=content", "build:pkg": "vite build;", - "prepack": "bun run build:pkg", - "sync-hardlinks": "bun run sync-dependencies-meta-injected" + "prepack": "pnpm run build:pkg" }, "ember-addon": { "main": "addon-main.cjs", @@ -80,7 +79,6 @@ "@warp-drive/core-types": "workspace:*", "@warp-drive/internal-config": "workspace:*", "ember-source": "~5.12.0", - "pnpm-sync-dependencies-meta-injected": "0.0.14", "typescript": "^5.7.2", "vite": "^5.2.11" }, diff --git a/packages/build-config/package.json b/packages/build-config/package.json index f2347d2099b..fa00ab6919c 100644 --- a/packages/build-config/package.json +++ b/packages/build-config/package.json @@ -15,7 +15,8 @@ "author": "Chris Thoburn ", "scripts": { "build:infra": "vite build; vite build -c ./vite.config-cjs.mjs;", - "prepack": "bun run build:infra" + "prepack": "pnpm run build:infra", + "sync": "echo \"syncing\"" }, "type": "module", "files": [ @@ -54,7 +55,6 @@ "@babel/plugin-transform-typescript": "^7.24.5", "@babel/preset-typescript": "^7.24.1", "@babel/core": "^7.24.5", - "pnpm-sync-dependencies-meta-injected": "0.0.14", "typescript": "^5.7.2", "bun-types": "^1.2.2", "vite": "^5.2.11" diff --git a/packages/codemods/package.json b/packages/codemods/package.json index 27c400f3f8a..3ce3eae96dc 100644 --- a/packages/codemods/package.json +++ b/packages/codemods/package.json @@ -44,7 +44,6 @@ "@types/jscodeshift": "0.11.11", "@warp-drive/internal-config": "workspace:*", "eslint": "^9.12.0", - "pnpm-sync-dependencies-meta-injected": "0.0.14", "qunit": "^2.20.1" }, "engines": { diff --git a/packages/core-types/package.json b/packages/core-types/package.json index aac600f3e56..a657bedf9b3 100644 --- a/packages/core-types/package.json +++ b/packages/core-types/package.json @@ -15,8 +15,8 @@ "scripts": { "lint": "eslint . --quiet --cache --cache-strategy=content", "build:pkg": "vite build;", - "prepack": "bun run build:pkg", - "sync-hardlinks": "bun run sync-dependencies-meta-injected" + "prepack": "pnpm run build:pkg", + "sync": "echo \"syncing\"" }, "files": [ "dist", @@ -46,7 +46,6 @@ "@babel/plugin-transform-typescript": "^7.24.5", "@babel/preset-typescript": "^7.24.1", "@warp-drive/internal-config": "workspace:*", - "pnpm-sync-dependencies-meta-injected": "0.0.14", "typescript": "^5.7.2", "vite": "^5.2.11" }, diff --git a/packages/core-types/src/-private.ts b/packages/core-types/src/-private.ts index a08ec018525..4528646d9cc 100644 --- a/packages/core-types/src/-private.ts +++ b/packages/core-types/src/-private.ts @@ -67,6 +67,8 @@ type GlobalKey = // @ember-data/request | 'IS_FROZEN' | 'IS_CACHE_HANDLER' + // @ember-data/request-utils + | 'CONFIG' // @ember-data/store IdentityCache | 'DEBUG_MAP' | 'IDENTIFIERS' diff --git a/packages/debug/package.json b/packages/debug/package.json index 3f7f10b8716..6755e161dbb 100644 --- a/packages/debug/package.json +++ b/packages/debug/package.json @@ -16,8 +16,7 @@ "scripts": { "lint": "eslint . --quiet --cache --cache-strategy=content", "build:pkg": "vite build;", - "prepack": "bun run build:pkg", - "sync-hardlinks": "bun run sync-dependencies-meta-injected" + "prepack": "pnpm run build:pkg" }, "files": [ "unstable-preview-types", @@ -68,7 +67,6 @@ "@warp-drive/internal-config": "workspace:*", "ember-source": "~5.12.0", "decorator-transforms": "^2.3.0", - "pnpm-sync-dependencies-meta-injected": "0.0.14", "typescript": "^5.7.2", "vite": "^5.2.11" }, diff --git a/packages/diagnostic/package.json b/packages/diagnostic/package.json index 725daefdfe9..09c6a10f166 100644 --- a/packages/diagnostic/package.json +++ b/packages/diagnostic/package.json @@ -69,8 +69,8 @@ "lint": "eslint . --quiet --cache --cache-strategy=content", "build:tests": "rm -rf dist-test && cp -R test dist-test && mkdir -p dist-test/@warp-drive && cp -R dist dist-test/@warp-drive/diagnostic", "build:pkg": "vite build;", - "prepack": "bun run build:pkg", - "sync-hardlinks": "bun run sync-dependencies-meta-injected" + "prepack": "pnpm run build:pkg", + "sync": "echo \"syncing\"" }, "peerDependencies": { "ember-source": "3.28.12 || ^4.0.4 || ^5.0.0 || ^6.0.0", @@ -106,7 +106,6 @@ "ember-source": "~5.12.0", "@glimmer/component": "^1.1.2", "ember-cli-test-loader": "^3.1.0", - "pnpm-sync-dependencies-meta-injected": "0.0.14", "typescript": "^5.7.2", "vite": "^5.2.11" }, @@ -120,8 +119,7 @@ "ember-addon": { "main": "addon-main.cjs", "type": "addon", - "version": 2, - "preventDownleveling": true + "version": 2 }, "ember": { "edition": "octane" diff --git a/packages/diagnostic/server/NCC-1701-a-gold_100.svg b/packages/diagnostic/server/NCC-1701-a-gold_100.svg new file mode 100644 index 00000000000..024f6d7f905 --- /dev/null +++ b/packages/diagnostic/server/NCC-1701-a-gold_100.svg @@ -0,0 +1 @@ + diff --git a/packages/diagnostic/server/browsers/index.js b/packages/diagnostic/server/browsers/index.js index 83a34b7442f..05672e8a3e5 100644 --- a/packages/diagnostic/server/browsers/index.js +++ b/packages/diagnostic/server/browsers/index.js @@ -184,6 +184,7 @@ export function recommendedArgs(browser, options = {}) { '--no-sandbox', // these prevent user account // and extensions from mucking with things + '--disable-extensions', '--incognito', '--bwsi', '--enable-automation', diff --git a/packages/diagnostic/server/bun/fetch.js b/packages/diagnostic/server/bun/fetch.js index c8421eb4dd7..be4bdc288cd 100644 --- a/packages/diagnostic/server/bun/fetch.js +++ b/packages/diagnostic/server/bun/fetch.js @@ -31,17 +31,19 @@ export function handleBunFetch(config, state, req, server) { if (INDEX_PATHS.includes(url.pathname)) { if (bId && wId) { // serve test index.html - if (config.entry.indexOf('?')) { - config._realEntry = config.entry.substr(0, config.entry.indexOf('?')); + if (!config._realEntry && config.entry.indexOf('?')) { + config._realEntry = path.join(process.cwd(), config.entry.substr(0, config.entry.indexOf('?'))); } debug(`Serving entry ${config._realEntry} for browser ${bId} window ${wId}`); - return new Response(Bun.file(config._realEntry)); + + const asset = Bun.file(config._realEntry); + return new Response(asset); } const _bId = bId ?? state.lastBowserId ?? state.browserId; const _wId = wId ?? state.lastWindowId ?? state.windowId; debug(`Redirecting to ${config.entry} for browser ${_bId} window ${_wId}`); // redirect to index.html - return Response.redirect(`${protocol}://${state.hostname}:${state.port}?b=${_bId}&w=${_wId}`, { status: 302 }); + return Response.redirect(`/?b=${_bId}&w=${_wId}`, { status: 302 }); } else { const pathParts = url.pathname.split('/'); @@ -55,8 +57,11 @@ export function handleBunFetch(config, state, req, server) { } const route = pathParts.join('/'); - if (route === 'favicon.ico') { - return new Response('Not Found', { status: 404 }); + if (route === 'favicon.ico' || route === 'NCC-1701-a-gold_100.svg') { + const dir = import.meta.dir; + const asset = path.join(dir, '../NCC-1701-a-gold_100.svg'); + + return new Response(Bun.file(asset)); } // serve test assets diff --git a/packages/diagnostic/server/bun/socket-handler.js b/packages/diagnostic/server/bun/socket-handler.js index 4f57799b95c..ced50801b98 100644 --- a/packages/diagnostic/server/bun/socket-handler.js +++ b/packages/diagnostic/server/bun/socket-handler.js @@ -7,7 +7,7 @@ import { watchAssets } from './watch.js'; export function buildHandler(config, state) { const Connections = new Set(); if (config.serve && !config.noWatch) { - watchAssets(config.assets, () => { + watchAssets(state, config.assets, () => { Connections.forEach((ws) => { ws.send(JSON.stringify({ name: 'reload' })); }); @@ -18,7 +18,8 @@ export function buildHandler(config, state) { perMessageDeflate: true, async message(ws, message) { const msg = JSON.parse(message); - msg.launcher = state.browsers.get(msg.browserId).launcher; + msg.launcher = state.browsers.get(msg.browserId)?.launcher ?? ''; + info(`${chalk.green('āž”')} [${chalk.cyan(msg.browserId)}/${chalk.cyan(msg.windowId)}] ${chalk.green(msg.name)}`); switch (msg.name) { @@ -53,16 +54,7 @@ export function buildHandler(config, state) { debug(`${chalk.green('āœ… [All Complete]')} ${chalk.yellow('@' + sinceStart())}`); if (!config.serve) { - state.browsers.forEach((browser) => { - browser.proc.kill(); - browser.proc.unref(); - }); - state.server.stop(); - if (config.cleanup) { - debug(`Running configured cleanup hook`); - await config.cleanup(); - debug(`Configured cleanup hook completed`); - } + await state.safeCleanup(); debug(`\n\nExiting with code ${exitCode}`); // 1. We expect all cleanup to have happened after // config.cleanup(), so exiting here should be safe. @@ -70,6 +62,8 @@ export function buildHandler(config, state) { // case. // eslint-disable-next-line n/no-process-exit process.exit(exitCode); + } else { + state.completed = 0; } } else { console.log(`Waiting for ${state.expected - state.completed} more browsers to finish`); diff --git a/packages/diagnostic/server/bun/watch.js b/packages/diagnostic/server/bun/watch.js index e6be7cc4cc0..6bb61a623e3 100644 --- a/packages/diagnostic/server/bun/watch.js +++ b/packages/diagnostic/server/bun/watch.js @@ -1,6 +1,10 @@ import { watch } from 'fs'; -export function addCloseHandler(cb) { +export function addCloseHandler(state, cb) { + state.closeHandlers.push(createCloseHandler(cb)); +} + +function createCloseHandler(cb) { let executed = false; process.on('SIGINT', () => { @@ -26,14 +30,20 @@ export function addCloseHandler(cb) { executed = true; cb(); }); + + return () => { + if (executed) return; + executed = true; + cb(); + }; } -export function watchAssets(directory, onAssetChange) { +export function watchAssets(state, directory, onAssetChange) { const watcher = watch(directory, { recursive: true }, (event, filename) => { onAssetChange(event, filename); }); - addCloseHandler(() => { + addCloseHandler(state, () => { watcher.close(); }); } diff --git a/packages/diagnostic/server/default-setup.js b/packages/diagnostic/server/default-setup.js index e0ac49ce1f6..589be7b8266 100644 --- a/packages/diagnostic/server/default-setup.js +++ b/packages/diagnostic/server/default-setup.js @@ -3,7 +3,7 @@ import fs from 'fs'; import path from 'path'; import { getBrowser, recommendedArgs } from './browsers/index.js'; -import launch from './index.js'; +import { launch } from './index.js'; import DefaultReporter from './reporters/default.js'; import { getFlags } from './utils/get-flags.js'; @@ -79,6 +79,11 @@ export default async function launchDefault(overrides = {}) { debug: overrides.debug ?? false, headless: overrides.headless ?? false, useExisting: overrides.useExisting ?? false, + protocol: overrides.protocol ?? 'http', + key: overrides.key ?? null, + cert: overrides.cert ?? null, + hostname: overrides.hostname ?? 'localhost', + port: overrides.port ?? null, entry: overrides.entry ?? `./dist-test/tests/index.html?${TEST_PAGE_FLAGS.join('&')}`, assets: overrides.assets ?? './dist-test', diff --git a/packages/diagnostic/server/index.js b/packages/diagnostic/server/index.js index b75e3bcd5a4..e12c5bb6e7e 100644 --- a/packages/diagnostic/server/index.js +++ b/packages/diagnostic/server/index.js @@ -5,11 +5,12 @@ import { launchBrowsers } from './bun/launch-browser.js'; import { buildHandler } from './bun/socket-handler.js'; import { debug, error, print } from './utils/debug.js'; import { getPort } from './utils/port.js'; +import { addCloseHandler } from './bun/watch.js'; /** @type {import('bun-types')} */ const isBun = typeof Bun !== 'undefined'; -export default async function launch(config) { +export async function launch(config) { if (isBun) { debug(`Bun detected, using Bun.serve()`); @@ -34,6 +35,23 @@ export default async function launch(config) { browsers: new Map(), completed: 0, expected: config.parallel ?? 1, + closeHandlers: [], + }; + async function runCloseHandler(handler) { + try { + await handler(); + } catch (e) { + error(`Error in close handler: ${e?.message ?? e}`); + } + } + state.safeCleanup = async () => { + debug(`Running close handlers`); + const promises = []; + for (const handler of state.closeHandlers) { + promises.push(runCloseHandler(handler)); + } + await Promise.allSettled(promises); + debug(`All close handlers completed`); }; if (protocol === 'https') { @@ -56,6 +74,16 @@ export default async function launch(config) { }, websocket: buildHandler(config, state), }); + + addCloseHandler(state, () => { + state.browsers?.forEach((browser) => { + browser.proc.kill(); + // browser.proc.unref(); + }); + state.server.stop(); + // state.server.unref(); + }); + print(chalk.magenta(`šŸš€ Serving on ${chalk.white(protocol + '://' + hostname + ':')}${chalk.magenta(port)}`)); config.reporter.serverConfig = { port, @@ -66,6 +94,7 @@ export default async function launch(config) { if (config.setup) { debug(`Running configured setup hook`); + await config.setup({ port, hostname, @@ -73,15 +102,20 @@ export default async function launch(config) { }); debug(`Configured setup hook completed`); } + if (config.cleanup) { + addCloseHandler(state, async () => { + debug(`Running configured cleanup hook`); + await config.cleanup(); + debug(`Configured cleanup hook completed`); + }); + } - await launchBrowsers(config, state); + if (!config.noLaunch) { + await launchBrowsers(config, state); + } } catch (e) { error(`Error: ${e?.message ?? e}`); - if (config.cleanup) { - debug(`Running configured cleanup hook`); - await config.cleanup(); - debug(`Configured cleanup hook completed`); - } + await state.safeCleanup(); throw e; } } else { diff --git a/packages/diagnostic/server/launcher.html b/packages/diagnostic/server/launcher.html index cea14159dba..363e7f05bc9 100644 --- a/packages/diagnostic/server/launcher.html +++ b/packages/diagnostic/server/launcher.html @@ -2,6 +2,7 @@ @warp-drive/diagnostic Parallel Test Launcher +