-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
[code-infra] vitest
browser & jsdom modes
#14508
base: master
Are you sure you want to change the base?
Conversation
Deploy preview: https://deploy-preview-14508--material-ui-x.netlify.app/ |
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
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.
With these last changes, ALL
X packages are running in vitest.
There are some details I commented below.
Main takes:
x-license
andx-internals
are only running in jsdom mode.x-date-pickers
Hijiri adapter is only running in jsdom mode.
I can isolate the this.skip
changes if necessary.
Tomorrow I'll check if I can make circle-ci work with vitest (I didn't try yet). So we can have proper comparisons
"@types/node": "^20.16.10", | ||
"@playwright/test": "1.44.1", | ||
"playwright": "1.44.1", | ||
"@mui/internal-test-utils": "https://pkg.csb.dev/mui/material-ui/commit/92c23999/@mui/internal-test-utils" |
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 to be changed when mui/material-ui#43625 is merged.
I would still leave it as a resolution
so all packages use the same.
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.
Personally, I would avoid all resolutions if we can, it tends to be misunderstood and overused and could result into setups that break on the user end but not on our end. (probably not for this dependency though)
If the version ranges are equal, there should be no duplication. And it shouldn't break in the first place if there was duplication.
it('should provide the right context as second argument', function test(t = {}) { | ||
if (isJSDOM) { | ||
// can't do Pointer event with JSDom https://github.com/jsdom/jsdom/issues/2527 | ||
this.skip(); | ||
// @ts-expect-error to support mocha and vitest | ||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions | ||
this?.skip?.() || t?.skip(); |
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.
You will see this pattern across multiple files, t = {}
tells mocha to treat this as an "empty" parameter, thus not triggering the logic to provide the done()
callback to it.
Without this mocha will fail because it waits for the done()
to be called.
This can then be migrated to just a .skip, but vitest offers many ways of skipping test.
function test(t) {
if (isJSDOM) {
t.skip();
}
}
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 added a shim in ./setupVitest
that we cold use while the tests run in both vitest and mocha. That prevents us in core from having to update all of these right now:
https://github.com/mui/material-ui/pull/43625/files#diff-21f1d3337bd5d6e3869ad10c93fa99770a34761876017b90bc1ed1ceaa7c93a9R45-R55
Want to move this to it.skipIf
eventually
The same couldn't be done for describe.skipIf
that only exists in vitest
, I added a shim for that in test utils:
Don't necessarily have to use it, but it can keep the amount of code changes in tests down.
beforeEach(() => { | ||
if (window?.document?.body?.style) { | ||
window.document.body.style.margin = '0'; | ||
} | ||
}); | ||
|
||
afterEach(() => { | ||
if (window?.document?.body?.style) { | ||
window.document.body.style.margin = '8px'; | ||
} | ||
}); |
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.
Some charts tests are reliant screen position, and margins are different for karma and vitest, so we force one. 🙃
// fireEvent.mouseDown(getCell(2, 0), { ctrlKey: true }); | ||
// fireEvent.mouseOver(getCell(3, 0), { ctrlKey: true }); | ||
const isMac = window.navigator.platform.toUpperCase().indexOf('MAC') >= 0; | ||
|
||
await user.keyboard(isMac ? '{Meta>}' : '{Control>}'); | ||
await user.pointer([ | ||
// touch the screen at element1 | ||
{ keys: '[MouseLeft>]', target: getCell(2, 0) }, | ||
// move the touch pointer to element2 | ||
{ target: getCell(3, 0) }, | ||
// release the touch pointer at the last position (element2) | ||
{ keys: '[/MouseLeft]' }, | ||
]); | ||
await user.keyboard(isMac ? '{/Meta}' : '{/Control}'); |
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.
Only the userEvents
worked here. Gotta change from meta/control based on OS.
// These test are flaky in JSDOM | ||
return; |
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.
Early returns, we should eventually remove these into native skip describes to make tests more reliable.
I didn't find an api that worked for both mocha and vitest except for returning.
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.
Added a describeSkipIf
to test utils that shims vitest
API of describe.skipIf
act(() => { | ||
screen.getByLabelText(/choose date/i).click(); | ||
}); |
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.
Wrap in act, .click()
so it doesn't scroll into view.
}); | ||
|
||
expect(onErrorMock.callCount).to.equal(2); | ||
expect(onErrorMock.lastCall.args[0]).to.deep.equal(['disablePast', 'disablePast']); | ||
testInvalidStatus([true, true], isSingleInput); | ||
|
||
act(() => { | ||
setValue(adapterToUse.date(now)); | ||
setValue(adapterToUse.addHours(now, 1)); |
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.
Had to add one hour to "now" for it to work here. I guess previously the timer didn't run?
// Ideally we move the configuration to each package. | ||
// Currently it doesn't work because vitest doesn't detect two different configurations in the same package. | ||
// We could bypass this limitation by having a folder per configuration. Eg: `packages/x-charts/browser` & `packages/x-charts/jsdom`. |
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.
// comment
vitest.workspace.ts
Outdated
// TODO: Decide on | ||
// Manually changing the process.env in browser tests doesn't work. | ||
// And alternative is to use `const {NODE_ENV} = process.env` in the code instead. | ||
// x-license relies on `process.env.NODE_ENV` to determine the environment. | ||
{ | ||
extends: './vitest.config.mts', | ||
plugins: [react()], | ||
test: { | ||
include: [`packages/x-license/src/**/*.test.?(c|m)[jt]s?(x)`], | ||
exclude: [`packages/x-license/src/**/*.browser.test.?(c|m)[jt]s?(x)`], | ||
name: `jsdom/x-license`, | ||
environment: 'jsdom', | ||
env: { | ||
MUI_JSDOM: 'true', | ||
}, | ||
}, | ||
}, |
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.
x-license
required to be run on jsdom only due to the process.env requirement.
vitest.workspace.ts
Outdated
// TODO: Decide on | ||
// Manually changing the process.env in browser tests doesn't work. | ||
// And alternative is to use `const {NODE_ENV} = process.env` in the code instead. | ||
// x-license relies on `process.env.NODE_ENV` to determine the environment. | ||
// x-internals has a weird chai import issue I couldn't fix | ||
...jsdomOnlyPackages.map((name) => ({ | ||
extends: './vitest.config.mts', | ||
plugins: [react()], | ||
test: { | ||
include: [`packages/${name}}/src/**/*.test.?(c|m)[jt]s?(x)`], | ||
exclude: [`packages/${name}}/src/**/*.browser.test.?(c|m)[jt]s?(x)`], | ||
name: `jsdom/${name}}`, | ||
environment: 'jsdom', | ||
env: { | ||
MUI_JSDOM: 'true', | ||
}, | ||
}, | ||
})), |
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.
Running these on jsdom only as x-license
requires process.env.NODE_ENV
and x-internals
has a weird chai error I couldn't fix.
test_unit_vitest: | ||
<<: *default-job | ||
steps: | ||
- checkout | ||
- install_js | ||
- run: | ||
name: Tests fake browser (vitest) | ||
command: pnpm vitest --project "jsdom/*" --coverage | ||
- run: | ||
name: Check coverage generated | ||
command: | | ||
if ! [[ -s coverage/lcov.info ]] | ||
then | ||
exit 1 | ||
fi |
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.
@Janpot is it possible to test circleci steps without merging? 🤔
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 be yes, when you add it to the workflow:
Line 332 in 98013ae
jobs: |
@@ -7,6 +8,8 @@ module.exports = { | |||
// Mocha seems to ignore .next anyway (maybe because dotfiles?). | |||
// We're leaving this to make sure. | |||
'docs/.next/**', | |||
'packages/**/*.browser.test.{js,ts,tsx,jsx}', |
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 a new file extension we're introducing? Can't find any such file.
@@ -106,17 +106,17 @@ module.exports = function getBabelConfig(api) { | |||
plugins.push([ |
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.
Let's add a TODO here to remove these plugins once fully migrated to vitest
?
// And alternative is to use `const {NODE_ENV} = process.env` in the code instead. | ||
// x-license relies on `process.env.NODE_ENV` to determine the environment. | ||
// x-internals has a weird chai import issue I couldn't fix | ||
...(jsdomOnlyPackages.includes(name) |
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.
It feels suboptimial to me to have to define this on the workspace level and not on the individual package level.
Would it be possible to give each vitest project their own config file which extends from one or more base files?
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.
For instance we could just define workspaces as
// ./vitest.workspace.ts
export default [
'./packages/*/vitest.config.{browser|jsdom}.ts'
]
and in the projects:
// ./packages/x-data-grid/vitest.config.browser.ts
import { mergeConfig } from 'vitest/config'
import browserDefault from '@mui/test-utils/browserDefault'
export default mergeConfig(browserDefault, {
// ...
})
// ./packages/x-data-grid/vitest.config.jsdom.ts
import jsdomDefault from '@mui/test-utils/jsdomDefault'
export default jsdomDefault
and omit the browser file for projects that are jsdom only
Not sure whether that works the way I expect it to be
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
@@ -244,7 +244,7 @@ module.exports = { | |||
}, | |||
}, | |||
{ | |||
files: ['packages/*/src/**/*{.ts,.tsx,.js}'], | |||
files: ['packages/*/src/**/*.?(c|m)[jt]s?(x)'], | |||
excludedFiles: ['*.d.ts', '*.spec.ts', '*.spec.tsx'], |
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 propose as a pattern we use ?(c|m)[jt]s?(x)
to select files, but use wildcard to exclude.
excludedFiles: ['*.d.ts', '*.spec.ts', '*.spec.tsx'], | |
excludedFiles: ['*.d.ts', '*.spec.*'], |
@@ -58,7 +58,7 @@ const RESTRICTED_TOP_LEVEL_IMPORTS = [ | |||
// It needs to know about the parent "no-restricted-imports" to not override them. | |||
const buildPackageRestrictedImports = (packageName, root, allowRootImports = true) => [ | |||
{ | |||
files: [`packages/${root}/src/**/*{.ts,.tsx,.js}`], | |||
files: [`packages/${root}/src/**/*.?(c|m)[jt]s?(x)`], | |||
excludedFiles: ['*.d.ts', '*.spec.ts', '*.spec.tsx', '**.test.tx', '**.test.tsx'], |
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.
"test.tx" 🙂
excludedFiles: ['*.d.ts', '*.spec.ts', '*.spec.tsx', '**.test.tx', '**.test.tsx'], | |
excludedFiles: ['*.d.ts', '*.spec.*', '*.test.*'], |
Related mui/material-ui#43625
Minimal changes to have
charts
tests working in browser modeCharts are the smallest test suit though
Help toward mui/mui-public#170.
Currently ignoring
DateFnsV3
adapter tests in the browser due to vitest-dev/vitest#6483 they work normally in jsdom though.Running tests