Automated Testing: Enforce no-unresolved checks for test files#79718
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
| const subpath = path.join( '.', pathParts.join( '/' ) ); | ||
| const exportPath = manifest.exports?.[ subpath ]?.import; |
There was a problem hiding this comment.
I don't know that this was working at all before for anything other than the . entrypoint. With this previous logic, subpath would end up would end up like build-module/paragraph/index.mjs (for the @wordpress/block-library example in the changes above) because path.join only emits a leading dot if the given path segments are empty. But each exports key must have a leading dot:
All target paths in the
"exports"map (the values associated with export keys) must be relative URL strings starting with./.
https://nodejs.org/api/packages.html#targets-must-be-relative-urls
So trying to access manifest.exports?.[ 'build-module/paragraph/index.mjs' ] would never work (ignoring the fact the package defines the matching export with a wildcard).
|
I will test this for isolated mode tomorrow. |
|
Size Change: -37 B (0%) Total Size: 7.61 MB 📦 View Changed
|
| import * as paragraphBlock from '@wordpress/block-library/src/paragraph'; | ||
| import * as groupBlock from '@wordpress/block-library/src/group'; | ||
| import * as paragraphBlock from '@wordpress/block-library/build-module/paragraph/index.mjs'; | ||
| import * as groupBlock from '@wordpress/block-library/build-module/group/index.mjs'; |
There was a problem hiding this comment.
These changes break the unit tests, which similarly expect to be able to run without a preceding build. Which leaves us in a tricky spot because the point of the import rules is to ensure valid imports, and the previous code here is not valid: @wordpress/block-library doesn't export /src/ on its package API surface.
Not entirely sure yet what the best option here would be, but a couple ideas to explore:
- Making block implementations available on the root package exports (affects the public API in a way I'm not sure we're comfortable with)
- Mirroring the same kind of remapping resolver logic we're implementing here for ESLint but in Jest
There was a problem hiding this comment.
- Mirroring the same kind of remapping resolver logic we're implementing here for ESLint but in Jest
We already have something like this, but only supporting top-level package imports:
gutenberg/test/unit/jest.config.js
Lines 25 to 31 in 0fc4838
gutenberg/test/unit/jest.config.js
Lines 47 to 48 in 0fc4838
It looks like we already had to hack around this for some package subpath exports, like in @wordpress/theme:
gutenberg/test/unit/jest.config.js
Lines 49 to 50 in 0fc4838
Maybe that's the short-term option here: Add a remapping for these block imports to simulate support, and separately work to mirror the remapping behavior consistently between ESLint and Jest.
| }, | ||
| "./package.json": "./package.json", | ||
| "./build-style/": "./build-style/" | ||
| "./build-style/*": "./build-style/*" |
There was a problem hiding this comment.
The previous syntax here was technically valid for exposing an entire directory and isn't supported in the custom resolver changes introduced with this pull request. But this way of defining exports is deprecated and I think we should move away from it entirely.
|
It looks like there’s one more generated-artifact case to handle before the global CI is still failing on: This one seems separate from the discussion above. Here We can either add a well-documented lint exception, or somehow teach the resolver about this specific generated entrypoint? Probably better to avoid broadening the development-file exemption again, since that would undercut the main goal of this PR. |
|
Hm, yeah, that's an interesting one. Maybe it's reasonable to prebuild this specific artifact in the same way we already do for |
When analyzing the test files, it references built artifacts which must exist as otherwise they are unresolvable imports.
|
The |
ciampo
left a comment
There was a problem hiding this comment.
Agreed, a prelint build weakens the PR’s “lint without build artifacts” ideal, but it is consistent with existing icons/theme precedent and fast.
Also agree that the long-term solution is to make any artifacts statically available
What?
Updates ESLint configuration to enforce
import/no-unresolvedrules consistently, regardless of "development files" status. Includes fixes for existing issues.Builds upon #79703. The earlier pull request focused on
import/no-extraneous-dependencies, adding missing dependencies topackage.json. This one focuses onimport/no-unresolvedand improving the accuracy of our custom resolver intools/eslint/import-resolver.cjsto account for false negatives.Why?
As explained in #79703, there's no special reason for these files to be exempt from these rules that are meant to help us ensure that imports are valid. The reasons for disabling them are likely a combination of (a) temporarily ignoring failing files that were deemed "less critical" and (b) limitations of the default ESLint import resolver described in #72136 which have since been resolved.
How?
import/no-unresolvedoverride (exemption) from ESLint configurationWe use a custom import resolver to remap import requests to their source files, so that running ESLint doesn't require a full build to happen before it's run. Previously, this custom resolver was rather naive about handling
exportsentrypoints, but the naivety was largely unsurfaced because of the previous exemptions. Removing these exemptions revealed the shortcomings, which are addressed in the changes here.Notably, it now supports wildcard path matching (needed for e.g. block-library block exports), resolving exports which are mapped directly to a string (as opposed to an object of
import,default,types, etc.), and resolving more file extensions (.jsxand.cjs). Ideally, the exports resolution wouldn't be something we implement ourselves. Packages like the popularresolvehave options for providing apackageobject, but it still does filesystem operations that make it heavier than we need it to be. Its internalresolveExportshelper would be handy and is in many ways what we've implemented here, but it isn't exposed as part of the library's public API. I'd be open to considering another library which is expressly aimed at resolvingpackage.jsonexportsif one exists.Testing Instructions
npm run clean:packagesto delete any built artifacts to effectively exercise the expected resolver behavior that it doesn't rely on built package contents to lintnpm run lint:jsshould pass.Use of AI Tools
I used Cursor IDE + Composer model to do an assessed categorization of the issues reported after removing
import/no-unresolved. But the actual code changes were largely manual, with a bit of tab completion here and there.