"mach puppteer-test" fails with "npm error error TS5055: Cannot write file 'toolkit/content/widgets/browser-custom-element.mjs' because it would overwrite input file."
Categories
(Remote Protocol :: Agent, defect, P2)
Tracking
(firefox153 fixed)
| Tracking | Status | |
|---|---|---|
| firefox153 | --- | fixed |
People
(Reporter: whimboo, Assigned: whimboo)
References
(Blocks 1 open bug)
Details
(Whiteboard: [webdriver:m20])
Attachments
(1 file)
I'm trying to run Puppeteer tests locally but it fails with:
Top level .git is not Puppeteer
npm error Lifecycle script `clean` failed with error:
npm error code 1
npm error path /Users/henrik/code/gecko/remote/test/puppeteer/tools/mocha-runner
npm error workspace @puppeteer/mocha-runner@0.1.0
npm error location /Users/henrik/code/gecko/remote/test/puppeteer/tools/mocha-runner
npm error command failed
npm error command sh -c ../clean.mjs
npm warn deprecated readdir-scoped-modules@1.1.0: This functionality has been moved to @npmcli/fs
npm warn deprecated debuglog@1.0.1: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
npm error code 1
npm error path /Users/henrik/code/gecko/remote/test/puppeteer/tools/eslint
npm error command failed
npm error command sh -c wireit
npm error error TS5055: Cannot write file '/Users/henrik/code/gecko/toolkit/content/widgets/browser-custom-element.mjs' because it would overwrite input file.
Running mach clobber doesn't help as well. Not sure why Puppeteer's installer is trying to write toolkit/content/widgets/browser-custom-element.mjs.
| Assignee | ||
Comment 1•3 months ago
|
||
This problem was actually caused by a node_modules folder in the root of the repository:
drwxr-xr-x 449 henrik staff 14368 Apr 28 18:06 node_modules
In case it happens again here the list of node modules installed:
✗ ls node_modules git:(geckodriver_http_upgrade↓1718↑4|…12
@babel escalade is-symbol read-installed-packages
@cacheable escape-string-regexp is-typed-array read-package-json
@csstools eslint is-unicode-supported readdirp
@dual-bundle eslint-compat-utils is-weakmap reflect.getprototypeof
@es-joy eslint-config-prettier is-weakref regexp.prototype.flags
@eslint eslint-import-resolver-node is-weakset require-directory
@eslint-community eslint-module-utils isarray require-from-string
@humanfs eslint-plugin-es-x isexe requizzle
@humanwhocodes eslint-plugin-eslint-plugin iterator.prototype reserved-identifiers
@isaacs eslint-plugin-html jackspeak resolve
@jridgewell eslint-plugin-import js-tokens resolve-from
@jsdoc eslint-plugin-jest js-yaml resolve-pkg-maps
@keyv eslint-plugin-jsdoc js2xmlparser ret
@lit eslint-plugin-jsx-a11y jsdoc reusify
@lit-labs eslint-plugin-lit jsdoc-type-pratt-parser run-parallel
@microsoft eslint-plugin-mozilla jsesc safe-array-concat
@nodelib eslint-plugin-n json-buffer safe-buffer
@npmcli eslint-plugin-no-unsanitized json-parse-even-better-errors safe-push-apply
@pkgjs eslint-plugin-promise json-schema-traverse safe-regex
@rtsao eslint-plugin-react json-stable-stringify-without-jsonify safe-regex-test
@sindresorhus eslint-plugin-react-hooks json5 semver
@stylistic eslint-plugin-security jsx-ast-utils serialize-javascript
@types eslint-plugin-spidermonkey-js keyv set-function-length
@typescript eslint-scope kind-of set-function-name
@typescript-eslint eslint-visitor-keys klaw set-proto
abbrev espree known-css-properties shebang-command
acorn esquery language-subtag-registry shebang-regex
acorn-jsx esrecurse language-tags side-channel
ajv estraverse levn side-channel-list
ansi-regex esutils license-checker-rseidelsohn side-channel-map
ansi-styles fast-deep-equal lines-and-columns side-channel-weakmap
are-docs-informative fast-glob linkify-it signal-exit
argparse fast-json-stable-stringify lit slash
aria-query fast-levenshtein lit-element slice-ansi
array-buffer-byte-length fast-uri lit-html slide
array-find-index fastest-levenshtein locate-path source-map-js
array-includes fastq lodash spdx-compare
array-union file-entry-cache lodash.clonedeep spdx-correct
array.prototype.findlast fill-range lodash.merge spdx-exceptions
array.prototype.findlastindex find-up lodash.truncate spdx-expression-parse
array.prototype.flat flat log-symbols spdx-license-ids
array.prototype.flatmap flat-cache loose-envify spdx-ranges
array.prototype.tosorted flatted lru-cache spdx-satisfies
arraybuffer.prototype.slice for-each markdown-it stop-iteration-iterator
ast-types-flow foreground-child markdown-it-anchor string-width
astral-regex function-bind marked string-width-cjs
async-function function.prototype.name math-intrinsics string.prototype.includes
available-typed-arrays functions-have-names mathml-tag-names string.prototype.matchall
axe-core generator-function mdn-data string.prototype.repeat
axobject-query gensync mdurl string.prototype.trim
balanced-match get-caller-file meow string.prototype.trimend
baseline-browser-mapping get-intrinsic merge2 string.prototype.trimstart
bluebird get-proto micromatch strip-ansi
brace-expansion get-symbol-description minimatch strip-ansi-cjs
braces get-tsconfig minimist strip-bom
browser-stdout glob minipass strip-json-comments
browserslist glob-parent mkdirp style-search
cacheable global-modules mocha stylelint
call-bind global-prefix ms stylelint-config-recommended
call-bind-apply-helpers globals nanoid stylelint-config-recommended-scss
call-bound globalthis natural-compare stylelint-config-standard
callsites globby node-exports-info stylelint-config-standard-scss
camelcase globjoin node-releases stylelint-scss
caniuse-lite gopd nopt stylelint-use-logical
catharsis graceful-fs normalize-package-data supports-color
chalk has-bigints normalize-path supports-hyperlinks
chokidar has-flag npm-normalize-package-bin supports-preserve-symlinks-flag
cliui has-property-descriptors object-assign svg-tags
color-convert has-proto object-deep-merge table
color-name has-symbols object-inspect tapable
colord has-tostringtag object-keys tinyglobby
comment-parser hashery object.assign to-regex-range
concat-map hasown object.entries to-valid-identifier
convert-source-map he object.fromentries toml-eslint-parser
cosmiconfig hermes-estree object.groupby treeify
cross-spawn hermes-parser object.values ts-api-utils
css-functions-list hookified optionator ts-patch
css-tree hosted-git-info own-keys tsconfig-paths
cssesc html-entities p-limit type-check
damerau-levenshtein html-tags p-locate typed-array-buffer
data-view-buffer htmlparser2 package-json-from-dist typed-array-byte-length
data-view-byte-length ignore parent-module typed-array-byte-offset
data-view-byte-offset import-fresh parse-imports-exports typed-array-length
debug imurmurhash parse-json typescript
decamelize ini parse-statements uc.micro
deep-is internal-slot parse5 unbox-primitive
define-data-property is-array-buffer parse5-htmlparser2-tree-adapter underscore
define-properties is-arrayish path-exists update-browserslist-db
diff is-async-function path-key uri-js
dir-glob is-bigint path-parse util-deprecate
doctrine is-boolean-object path-scurry validate-npm-package-license
dom-serializer is-callable path-type which
domelementtype is-core-module picocolors which-boxed-primitive
domhandler is-data-view picomatch which-builtin-type
domutils is-date-object possible-typed-array-names which-collection
dunder-proto is-extglob postcss which-typed-array
eastasianwidth is-finalizationregistry postcss-media-query-parser word-wrap
electron-to-chromium is-fullwidth-code-point postcss-resolve-nested-selector workerpool
emoji-regex is-generator-function postcss-safe-parser wrap-ansi
enhanced-resolve is-glob postcss-scss wrap-ansi-cjs
entities is-map postcss-selector-parser write-file-atomic
env-paths is-negative-zero postcss-value-parser xmlcreate
error-ex is-number prelude-ls y18n
es-abstract is-number-object prettier yallist
es-define-property is-path-inside prop-types yargs
es-errors is-plain-obj punycode yargs-parser
es-iterator-helpers is-plain-object punycode.js yargs-unparser
es-object-atoms is-regex qified yarn
es-set-tostringtag is-set queue-microtask yocto-queue
es-shim-unscopables is-shared-array-buffer randombytes zod
es-to-primitive is-string react-is zod-validation-error
| Assignee | ||
Comment 2•3 months ago
|
||
Oh, it's interesting it contains all the packages that we usually install when running mach lint. Trying to replicate the issue with letting mach lint re-create the node_modules wasn't successful. Also restoring the folder via time machine didn't reveal the issue.
Mark, maybe you have an idea what could have caused it? If not we probably need to close as incomplete for now.
Comment 3•3 months ago
|
||
Sorry, I've seen npm do strange things now and again, which may or may not be the same as this, but I've no idea what happened here.
| Assignee | ||
Comment 4•3 months ago
|
||
Thanks. Lets close for now. I'll reopen in case I stumble into this issue again.
| Assignee | ||
Comment 5•3 months ago
|
||
And it fails again:
error TS5055: Cannot write file '/Users/henrik/code/gecko/toolkit/content/widgets/browser-custom-element.mjs' because it would overwrite input file.
../../../../toolkit/content/widgets/browser-custom-element.mjs(93,14): error TS9006: Declaration emit for this file requires using private name 'MozElementBase' from module '"/Users/henrik/code/gecko/tools/@types/lib.gecko.augmentations"'. An explicit type annotation may unblock declaration emit.
Comment 6•3 months ago
|
||
That's coming from TypeScript. I suspect it was introduced because of bug 2033020 - the top-level of firefox-main is now using its own custom dom library rather than TypeScript's own.
I would guess it may be hitting this line, and because you're in build mode, it is trying to output that.
I wonder if the typeRoots directive might help here, though I don't know if that's the best way or not - I think ideally we'd probably have something along the lines of remote/test/puppeteer being the top-level directory, and don't look up the tree.
| Assignee | ||
Comment 7•3 months ago
|
||
What I did recently was to run mach lint --outgoing --warning --fix for the patches on bug 2033393, and because it took too long I canceled it via Cmd+C. Not sure if that might have left around some traces which could cause this problem.
| Assignee | ||
Updated•3 months ago
|
| Assignee | ||
Comment 8•3 months ago
|
||
As I was informed others have this problem as well. Maybe it's related to a new / clean repository where Puppeteer was not run before and then tried to run after ./mach lint was running. I'll check that tomorrow.
| Assignee | ||
Comment 9•3 months ago
|
||
As it looks like this makes it really reproducible:
- Have a clean repo or reset everything under
/remote/test/puppeteer(rm -rf remote/test/puppeteer && git reset --hard) - Run the linter jobs like
./mach lint --outgoing --warning - Run Puppeteer tests:
./mach puppeteer-test
This means everyone who didn't run Puppeteer tests before any invocation of ./mach lint is affected. Lets discuss if we should bump it as P2 and get it fixed sooner than later.
| Assignee | ||
Comment 10•3 months ago
|
||
The underlying problem here with mach puppeteer-test is probably:
- npm ci runs in remote/test/puppeteer and triggers the prepare lifecycle script for @puppeteer/eslint
- The prepare script runs wireit → tsc -b
- TypeScript auto-discovers @typescript/lib-dom by walking up node_modules directories until it reaches the root gecko/node_modules/@typescript/lib-dom
- That's a symlink to tools/@types, which contains path mappings to gecko source files (like browser-custom-element.mjs)
- With allowJs: true, TypeScript tries to process the .mjs file and fails with TS5055
| Assignee | ||
Updated•2 months ago
|
| Assignee | ||
Comment 11•2 months ago
|
||
I've taken another look at this bug and here is what's happening:
When mach lint runs, it executes npm ci at the gecko root, which installs all devDependencies from the root package.json — including "@typescript/lib-dom": "file:tools/@types". This creates a symlink at node_modules/@typescript/lib-dom pointing to tools/@types/, which contains gecko-specific type augmentations (e.g., lib.gecko.augmentations.d.ts imports toolkit/content/widgets/browser-custom-element.mjs).
When mach puppeteer-test subsequently runs, npm ci in remote/test/puppeteer/ triggers tsc -b via prepare lifecycle scripts. TypeScript's custom lib replacement mechanism (TS 4.5+) walks up node_modules directories looking for @typescript/lib-dom, finds the root one, and pulls in the gecko augmentations. With allowJs: true, TypeScript tries to process the .mjs source file and fails with TS5055.
Here potential options to fix it:
- Runtime shadow in
puppeteer_test(): Create a minimal@typescript/lib-dompackage atremote/test/node_modules/that shadows the root one. Node resolution finds it first and stops walking up. Survivesgit cleanimplicitly: cleaning removes both the shadow and the rootnode_modules/that causes the problem. - Check in the shadow package: Commit the shadow directly to git. Persistent, but tracking
node_modulesin git is unusual and confusing. - Move lint
node_modulesto a different directory: Prevent the root-level@typescript/lib-domfrom existing. High-risk infrastructure change affecting eslint, stylelint, node-licenses, tools/ts, and moztreedocs.
The optimal solution for me seems to be option 1, a shadow_root_lib_dom() helper in remote/mach_commands.py that:
- Checks if the root
node_modules/@typescript/lib-domexists — if not, no action needed. - Creates
remote/test/node_modules/@typescript/lib-dom/with:package.jsondeclaring itself as@typescript/lib-domwithtypes: "./index.d.ts"index.d.tscontaining a/// <reference path="..." />to Puppeteer's owntypescript/lib/lib.dom.d.ts, which bypasses the lib replacement mechanism (file-level resolution, not package resolution)
- Always validates file content and updates if stale.
This needs to be called before the if install: branch so that this code runs even with the --no-install argument specified.
| Assignee | ||
Comment 12•2 months ago
|
||
Updated•2 months ago
|
Updated•2 months ago
|
Comment 13•2 months ago
|
||
Comment 14•2 months ago
|
||
| bugherder | ||
Description
•