-
Notifications
You must be signed in to change notification settings - Fork 339
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
Improvements to Jest project setup + test package updates #2850
Conversation
ed92373
to
9889dd9
Compare
9889dd9
to
bf2beda
Compare
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.
Thanks @colinrotherham!
I can generally understand the changes except for the last commit – I don't really understand what it's fixing or how the changes relate to each other. Would you mind adding a bit more detail to the commit message that explains what's going on, for future us?
jest.config.js
Outdated
cacheDirectory: '<rootDir>/.cache/jest/', | ||
testPathIgnorePatterns: [ | ||
'/node_modules/', | ||
'after-*' |
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 think this has broken the test:build:package
and test:build:dist
tasks:
govuk-frontend on upgrade-test-jest-percy [$!] via ⬢ v16.17.0 took 20s
➜ npm run test:build:package
> test:build:package
> jest tasks/gulp/__tests__/after-build-package.test.js
No tests found, exiting with code 1
Run with `--passWithNoTests` to exit with code 0
In /Users/oliver.byford/Code/govuk-frontend
1165 files checked across 4 projects. Run with `--verbose` for more details.
Pattern: tasks/gulp/__tests__/after-build-package.test.js - 0 matches
govuk-frontend on upgrade-test-jest-percy [$!] via ⬢ v16.17.0 took 3s
➜ npm run test:build:dist
> test:build:dist
> jest tasks/gulp/__tests__/after-build-dist.test.js
No tests found, exiting with code 1
Run with `--passWithNoTests` to exit with code 0
In /Users/oliver.byford/Code/govuk-frontend
1165 files checked across 4 projects. Run with `--verbose` for more details.
Pattern: tasks/gulp/__tests__/after-build-dist.test.js - 0 matches
The desired behaviour is that the tests in tasks/gulp/__tests__/
are excluded from running as part of npm test
but we can call them as part of the build:package
and build:dist
tasks to check that the package / dist are what we expect.
(I suspect there's a better way to do this! Maybe we can use the Jest projects config?)
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.
Don't worry, this is what code reviews are for 😊
I'll find a better way of grouping those excluded-but-not-excluded tests—probably Jest config yep!
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.
@36degrees I've pushed this up again
The GitHub tests are now split out so Percy only monitors what it needs to:
https://github.com/alphagov/govuk-frontend/blob/upgrade-test-jest-percy/.github/workflows/tests.yml#L47
|
||
beforeAll(() => { | ||
// Support fetch() detection, upload via WebSocket() | ||
global.window = { fetch, WebSocket } |
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.
@36degrees To answer the "Why do we need this?"
For context, Jest used to run with @jest-environment jsdom
by default
Performance improvements
https://jestjs.io/blog/2022/04/25/jest-28
https://jestjs.io/blog/2021/05/25/jest-27
Jest now runs all tests via a Node.js environment (no browser globals) but with the recent updates we can't have both @jest-environment jsdom
and @jest-environment puppeteer
working together
The problem? Percy code is required (by Jest) as a "browserified" bundle, so hits this code path:
https://github.com/percy/cli/blob/19f8be4903543544bdef197f2f7d5a6a648ed37d/packages/sdk-utils/src/logger.js#L74
So this restores both browser globals and fixes:
- Fetch API for Percy to see if it's CLI agent is running
- WebSocket for Percy to upload screenshots securely
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 have been wondering about splitting the Percy snapshotting out as it's not really part of the 'tests' and doesn't rely on anything else from Jest.
I suspect we might also need to do this if we wanted to conditionally run the visual regression tests only if certain files have changed.
Until then, to stop us having to go down that rabbit hole too far, would another way to solve this be to split the snapshotting out into its own Jest test case?
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.
@36degrees Yeah, appreciate this is a quick fix. Did you see the new projects list?
npx jest --selectProjects "JavaScript component tests"
Likewise we can run everything except a certain project:
npx jest --ignoreProjects "Snapshot tests"
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.
Does Percy inherently need both jsdom and puppeteer because we're running it in Jest? Or is this a symptom of the fact we have these tests inside a file with a lot of other ~unrelated tests and some of them need jsdom and some need puppeteer?
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 it just needs a browser window
object
It's because we use @percy/puppeteer
which crashes without window.fetch
and window.WebSocket
. For performance reasons, Jest CLI no longer defaults to a simulated browser (jsdom) environment
Here's an extract of their code (via browserify bundle) showing .call(window)
(function() {
/* Percy internals */
}).call(window);
if (typeof define === "function" && define.amd) {
define("@percy/sdk-utils", [], () => window.PercySDKUtils);
} else if (typeof module === "object" && module.exports) {
module.exports = window.PercySDKUtils;
}
I'm happy with this fix until we can investigate calling @percy/client
directly
This PR is primarily to get jest --watch
stable again (starting/stopping test site cleanly etc)
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.
To be honest, looks like a repeat of #2643 again
Jest v28
package.json
exports
support
…As a result, you might e.g. get browser code which assumes ESM, when Jest provides ['require', 'browser']. You can either report a bug to the library…
Jest now (correctly??) loads the default browser bundle for @percy/puppeteer on this line:
https://github.com/percy/cli/blob/master/packages/sdk-utils/package.json#L27
"exports": {
".": {
"node": "./dist/index.js",
"default": "./dist/bundle.js"
}
}
We'll have to stick with this fix and consider a PR with Percy to add import
and require
exports
bf2beda
to
d79e7bd
Compare
d79e7bd
to
332367c
Compare
332367c
to
0c82db1
Compare
0c82db1
to
1d91abd
Compare
1d91abd
to
70d7d34
Compare
70d7d34
to
d829a3d
Compare
To help review this one I've split out two of the noisier changes: #2857 Make |
d829a3d
to
9940cce
Compare
Rebasing with #2857 to pick up config path changes |
9940cce
to
f2fe40f
Compare
.github/workflows/tests.yml
Outdated
npx jest --color --selectProjects "JavaScript unit tests" | ||
npx jest --color --selectProjects "JavaScript behaviour tests" | ||
|
||
- name: Run visual regression |
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 also running the component tests as well, right? Also not sure if 'Run visual regression' is the right name as the actual regression testing is a separate status check – this just sends the screenshots over to Percy.
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.
- name: Run visual regression | |
- name: Send screenshots to Percy |
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.
Yeah Percy starts a little service on http://localhost:5338/percy/snapshot
then runs your command
Our tests call await percySnapshot()
which sends the screenshot if Percy started cleanly (with a token)
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.
Thanks @36degrees I've updated this to your suggestion 👍
jest.config.js
Outdated
] | ||
}, | ||
{ | ||
...config, | ||
displayName: 'Snapshot tests', |
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.
Appreciate this name is not new, but it's not what I'd naturally call these. Especially as Jest has its own meaning for 'snapshots'.
Maybe 'Nunjucks macro tests'?
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.
displayName: 'Snapshot tests', | |
displayName: 'Nunjucks macro tests', |
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.
Updated this one too 👍
|
||
beforeAll(() => { | ||
// Support fetch() detection, upload via WebSocket() | ||
global.window = { fetch, WebSocket } |
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.
Does Percy inherently need both jsdom and puppeteer because we're running it in Jest? Or is this a symptom of the fact we have these tests inside a file with a lot of other ~unrelated tests and some of them need jsdom and some need puppeteer?
package.json
Outdated
"test:build:dist": "jest tasks/gulp/__tests__/after-build-dist.test.js", | ||
"pretest": "npm run build:assets", | ||
"test": "jest --color --ignoreProjects \"Gulp tasks\" --maxWorkers=50%", | ||
"test:build:assets": "npx jest --selectProjects \"Gulp tasks\" --testMatch \"**/*components*\"", |
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.
Is this intended to run check-individual-components-compile.test.js
?
I had no idea that test file existed…
- I think it's running on the contents of the
src
directory, so don't think it makes sense to run it afterbuild:assets
as that sort of suggests it's running tests against the copied files in thepublic
directory. - I think the test basically duplicates tests we already have in
components/all.test.js
:
govuk-frontend/src/govuk/components/all.test.js
Lines 40 to 44 in a1a1944
it(`${component}.scss renders to CSS without errors`, () => { return renderSass({ file: `${configPaths.src}/components/${component}/_${component}.scss` }) })
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.
If both of those are correct, I think we should delete check-individual-components-compile.test.js
(because it's covered by the tests in src/govuk/components/all.test.js
) and remove the test:build:assets
script.
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.
Yep that was the intention, agreed. I'll remove 👍
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.
Removed it now, well spotted. Don't need to call renderSass()
on every component twice 😊
f2fe40f
to
97f9135
Compare
97f9135
to
dc76549
Compare
7cdecd0
to
f3146cd
Compare
docs/contributing/tasks.md
Outdated
@@ -28,6 +28,10 @@ NPM scripts are defined in `package.json`. These trigger a number of gulp tasks. | |||
- compiles CSS & JS | |||
- starts up Express | |||
|
|||
**`npm run build:assets` will do the following:** | |||
- compiles CSS & JS | |||
- runs `npm run test:build:assets` (which will test the output is correct) |
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 needs removing now that we've gotten rid of test:build:assets
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.
Fixed, thanks @36degrees
Test server (and puppeteer) now starts/stops automatically for only the tests that need it You can now reliably use the Jest CLI to run single tests, filters or target projects: ```js npx jest --selectProjects 'Gulp tasks' npx jest --selectProjects 'Snapshot tests' npx jest --selectProjects 'JavaScript unit tests' npx jest --selectProjects 'JavaScript behaviour tests' npx jest --selectProjects 'JavaScript component tests' ```
Due to missing `require` or `exports` main entry points in Percy SDK utils, Jest is (correctly) loading the browser bundle instead See https://github.com/percy/cli/blob/a9858d20a9b9708da0464c0617b32b2ee1c97433/packages/sdk-utils/package.json#L27
Test was sometimes failing under load, potentially related to emulation mode viewport width not revealing the mobile menu immediately
See ./src/govuk/components/all.test.js
f3146cd
to
5e550d8
Compare
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.
Fab work 👏🏻
Lots of little fixes in this PR
window.fetch()
(newer versions assume a browser or jsdom environment)Remove deprecatedReplace deprecatedrequest
packagerequest
package with Fetch API #2858You can now reliably use the Jest CLI to run single tests, filters or target projects:
☝️ The test site (and puppeteer) will now start/stop automatically when needed
Jest with
--watch
flagFor example, this PR resolves various Jest issues such as:
These can be shown by adding
--detectOpenHandles
as suggested: