-
Notifications
You must be signed in to change notification settings - Fork 9.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
misc: convert lighthouse-core/test to ES modules #13295
Conversation
@@ -1,6 +0,0 @@ | |||
printWidth: 100 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👀
import PageDependencyGraph from '../../../computed/page-dependency-graph.js'; | ||
import LoadSimulator from '../../../computed/load-simulator.js'; | ||
import trace from '../../fixtures/traces/progressive-app-m60.json'; | ||
import devtoolsLog from '../../fixtures/traces/progressive-app-m60.devtools.log.json'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was surprised to see json imports working here. I guess Jest makes some allowances for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was surprised to see json imports working here. I guess Jest makes some allowances for it.
how is this working? We have the jest transforms turned off and node should only do the import with --experimental-json-modules
turned on (and even then only as import devtoolsLog from '../../fixtures/traces/progressive-app-m60.devtools.log.json' assert { type: 'json' };
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No idea! I was converting these to readJson, but once I noticed they still worked I stopped doing that midway and just allowed these to stay as json imports. I should probably finish the job...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wdyt: should all these become readJson or should we stick to importing them since that (somehow) works?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wdyt: should all these become readJson or should we stick to importing them since that (somehow) works?
Since the import is so simple I'm good with relying on whatever overly-magical thing jest is doing behind the scenes, with the hopes that by the time we need to do something different, import assertions will be stable in whatever minimum Node version we're using
emulationMock.clearThrottling = jest.fn(); | ||
emulationMock.emulate = jest.fn(); | ||
networkMock.fetchResponseBodyFromCache = jest.fn().mockResolvedValue(''); | ||
navigationMock.gotoURL = fnAny().mockResolvedValue({finalUrl: 'https://example.com', warnings: [], timedOut: false}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the jest
here is now using types privided from jest directly via @jest/globals
, whereas before it was from @types/jest
(which is pinned to an older set of types). In the newer version, jest uses unknown
where we relied on any
for our types to work.
It's pretty awkward to use jsdoc to apply the correct template arguments, so I introduced a fnAny
helper.
'assertNoSameOriginServiceWorkerClients'), | ||
}; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the most complex example of the dynamic import workaround required for mocks to work.
@@ -238,41 +177,49 @@ async function flushAllTimersAndMicrotasks(ms = 1000) { | |||
* shouldn't concern themselves about. | |||
*/ | |||
function makeMocksForGatherRunner() { | |||
jest.mock('../gather/driver/environment.js', () => ({ | |||
jest.mock(require.resolve('../gather/driver/environment.js'), () => ({ | |||
getBenchmarkIndex: () => Promise.resolve(150), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even though this module is calling jest.mock
, it seems that in esmodule test files the file is mocked relative to the test file instead. Using require.resolve
to obtain an absolute path fixes that.
7daa80e
to
eb48cfc
Compare
5cd40eb
to
5272656
Compare
@adamraine @brendankenny want to look at this again? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I'm like 80% through by file count, now only 80% of the complexity left :) Flushing comments...
const Audit = require('../../../audits/accessibility/aria-allowed-attr.js'); | ||
const assert = require('assert').strict; | ||
import Audit from '../../../audits/accessibility/aria-allowed-attr.js'; | ||
import {strict as assert} from 'assert'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: do we want to start doing import assert from 'assert/strict';
? Seems way better to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use this current form in other places to, so let's handle it everywhere after this PR lands. tracking #13883
import PageDependencyGraph from '../../../computed/page-dependency-graph.js'; | ||
import LoadSimulator from '../../../computed/load-simulator.js'; | ||
import trace from '../../fixtures/traces/progressive-app-m60.json'; | ||
import devtoolsLog from '../../fixtures/traces/progressive-app-m60.devtools.log.json'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wdyt: should all these become readJson or should we stick to importing them since that (somehow) works?
Since the import is so simple I'm good with relying on whatever overly-magical thing jest is doing behind the scenes, with the hopes that by the time we need to do something different, import assertions will be stable in whatever minimum Node version we're using
const manifestWithoutMaskableSrc = | ||
JSON.stringify(require('../fixtures/manifest-no-maskable-icon.json')); | ||
JSON.stringify(readJson('lighthouse-core/test/fixtures/manifest-no-maskable-icon.json')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should these change to the bare json imports too?
import manifest from 'lighthouse-core/test/fixtures/manifest.json';
import manifestWithoutMaskable = 'lighthouse-core/test/fixtures/manifest-no-maskable-icon.json';
const manifestSrc = JSON.stringify(manifest);
const manifestWithoutMaskableSrc = JSON.stringify(manifestWithoutMaskable);
const BaseGatherer = require('../../../fraggle-rock/gather/base-gatherer.js'); | ||
const {initializeConfig} = require('../../../fraggle-rock/config/config.js'); | ||
const {LH_ROOT} = require('../../../../root.js'); | ||
import {jest} from '@jest/globals'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this isn't injected but describe
, it
, etc is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
correct.
lighthouse-core/test/gather/gatherers/main-document-content-test.js
Outdated
Show resolved
Hide resolved
lighthouse-core/test/gather/gatherers/network-user-agent-test.js
Outdated
Show resolved
Hide resolved
@@ -0,0 +1,4 @@ | |||
{ | |||
"type": "commonjs", | |||
"//": "jest only supports commonjs for setup modules" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙍
@brendankenny did you have more review to share? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I was the blocker on this. Changes look good to me, but I only looked at a high level at the mocking changes and I'm hoping @adamraine looked closer than I did :)
Yay big progress on esm!
/** | ||
* @param {ImportMeta} importMeta | ||
*/ | ||
function createCommonjsRefs(importMeta) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see the benefit of reducing churn in this change by providing this, but it does seem like we should be looking to the future, too. e.g. new files that need a _dirname + '/path/to/something'
, should really be doing new URL('/path/to/something', import.meta.url)
rather than encouraging further use of __filename
and _dirname
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed-#13953
ref #12689
I suggest reviewing this PR one commit at a time. I converted entire folders at a time, ensuring that
yarn jest
continued to work throughout.Jest currently does not support the hoisting behavior of mocks in esmodules, meaning that test files using mocks must dynamically import some of their dependencies (just the ones that use files being mocked). I hope this is just a temporary workaround, so I left the regular imports as uncommented. If Jest ever supports this we'll be able to revert back to regular imports simply.
I didn't add a linter yet, can do so in later PR to reduce churn in this one.