Skip to content

Conversation

Janpot
Copy link
Member

@Janpot Janpot commented Aug 21, 2025

Trying to make #44325 more maintainable by moving all the test updates and fixes to its own PR

  • some changes to accomodate both for vitest and mocha
  • remove global screen, this breaks test isolation in vitest
  • improve karma reporting
  • remove regex from navigator check
  • make chai usage forward compatible
  • correct some missing dev dependencies
  • flatten packages/mui-codemod/src/v5.0.0/ tests, vitest equivalent of require.context doesn't deal well with multiple nesting levels
  • replace global with globalThis
  • fix karma keychain warning in local
  • ...

@Janpot Janpot added test scope: code-infra Changes related to the core-infra product. labels Aug 21, 2025
@mui-bot
Copy link

mui-bot commented Aug 21, 2025

Netlify deploy preview

https://deploy-preview-46795--material-ui.netlify.app/

Bundle size report

Bundle Parsed size Gzip size
@mui/material 🔺+7B(0.00%) 0B(0.00%)
@mui/lab 0B(0.00%) 0B(0.00%)
@mui/system 🔺+14B(+0.02%) 🔺+3B(+0.01%)
@mui/utils 🔺+1B(+0.01%) ▼-5B(-0.10%)

Details of bundle changes

Generated by 🚫 dangerJS against 6737e28

@Janpot Janpot marked this pull request as ready for review August 21, 2025 11:42
@Janpot Janpot requested a review from a team August 21, 2025 11:43
@oliviertassinari oliviertassinari changed the title [code-infra] Bring batch of changes rom vitest PR [code-infra] Bring batch of changes from vitest PR Aug 23, 2025
Comment on lines 312 to 318
await renderSpeedDial();
const screen = await renderSpeedDial();
Copy link
Member

@oliviertassinari oliviertassinari Aug 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to go backward. Tests are supposed to use the screen from the global import (not all of them do this yes, but we are trending toward it).

Suggested change
await renderSpeedDial();
const screen = await renderSpeedDial();
await renderSpeedDial();

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we should reverse that trend. Using global screen breaks the test isolation. I believe react testing library makes the assumption document and window globals never get reassigned as illustrated by testing-library/user-event#1295. There doesn't seem to be much motivation on their end to fix this, so I think it would be easiest to just avoid the global screen altogether.

Copy link
Member

@oliviertassinari oliviertassinari Aug 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using global screen breaks the test isolation.

I wouldn't expect this to be the case though. Is this about a bug?

I believe react testing library makes the assumption document and window globals never get reassigned as illustrated

Their docs uses the global API: https://testing-library.com/docs/react-testing-library/example-intro#quickstart. Are we supposed to reassign document and window? This sounds slower than it needs to be. We used to share the same document/window between all the tests:

createDOM();

We would only unmount the component with https://testing-library.com/docs/react-testing-library/api/#cleanup. If there was a leak, this would break other tests, which was great as it would force us to fix the component (it would leak equally in our users, unless the leak is in a pourly written test, but then I guess we can assert that the DOM is clean and have a flew other checks). I imagine that since the tests also run in the browser, we can't even afford to reset document and window in that context, so we have to work with them being the same.

testing-library/user-event#1295

Them having this issue could suggest that our setup is not standard.

Copy link
Member Author

@Janpot Janpot Aug 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Them having this issue could suggest that our setup is not standard.

Correct, our setup is non-standard vitest. Standard vitest is one suite, one process. This turned out about twice as slow as mocha. Mocha runs in a single process and creates the dom only once for all suites. It's possible to run vitest in a single process --no-isolate --no-file-parallelism, but it'll still recreates the dom for each suite. You may find this counterintuitive, but I don't expect this to be a very heavy operation. As is proven here, the vitest setup in this mode runs at a similar speeds to mocha.

This sounds slower than it needs to be.

Maybe a bit, keep in mind that loading the jsdom library is magnitudes slower than instantiating it:

console.time('load-jsdom');
const { JSDOM } = require('jsdom');
console.timeEnd('load-jsdom');
console.time('instantiate-jsdom');
const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`);
console.timeEnd('instantiate-jsdom');

gives the following on StackBlitz

load-jsdom: 265.355ms
instantiate-jsdom: 19.59ms

so when running isolate processes for our 500 suites, that is (265ms + 20ms) * 500 = 142.5s spent on jsdom, for running in a single process and recreating dom for each suite is 265ms + (500 * 20ms) = 10.3s, so technically it's a bit slower than it needs to be (vs mocha's 520ms), but it's 14 times more efficient than vitest in standard mode.

Loading libraries is an often overlooked aspect of performance, but for us, with 500+ suites it can be significant. e.g. I'm replacing lodash with lodash.kebabcase. Which is about 50ms to load vs 3ms. This becomes seriously significant when running vitest in parallel mode, it's essentially spending 25s on loading lodash, just for a single function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, just did another test:

console.time('load-jsdom');
const { JSDOM } = require('jsdom');
console.timeEnd('load-jsdom');
console.time('instantiate-jsdom');
const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`);
console.timeEnd('instantiate-jsdom');
console.time('instantiate-jsdom-2');
const dom2 = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`);
console.timeEnd('instantiate-jsdom-2');

Gives:

load-jsdom: 262.32ms
instantiate-jsdom: 20.845ms
instantiate-jsdom-2: 3.81ms

Turns out that instantiating when it's warm drops the time by another magnitude. instantiating jsdom becomes super cheap. So my 265ms + (500 * 20ms) = 10.3s is wrong. It should be 265ms + 20ms + 499*3ms = 1.7s. Negligible in our setup

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label Aug 24, 2025
@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged. label Sep 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
scope: code-infra Changes related to the core-infra product. test
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants