-
Notifications
You must be signed in to change notification settings - Fork 405
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
chore(integration-karma): migrate to webdriverio/vitest #4594
Conversation
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'll do a clean up before continuing the migration work, but here's some notes on what's going on.
packages/@lwc/integration-karma/test/api/freezeTemplate/index.spec.js
Outdated
Show resolved
Hide resolved
packages/@lwc/integration-karma/test/api/freezeTemplate/index.spec.js
Outdated
Show resolved
Hide resolved
packages/@lwc/integration-karma/test/polyfills/event-composed/index.spec.js
Outdated
Show resolved
Hide resolved
window.HydrateTest = (function (lwc, testUtils) { | ||
testUtils.setHooks({ | ||
sanitizeHtmlContent: (content) => content, | ||
}); |
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 haven't started migrating test-hydrate yet, although I'm keeping it in mind while rewriting the scripts and plugins.
'use strict'; | ||
|
||
import { resolve } from 'path'; | ||
|
||
import options from '../../shared/options'; | ||
const { ENABLE_SYNTHETIC_SHADOW_IN_HYDRATION, GREP, COVERAGE, COVERAGE_DIR_FOR_OPTIONS } = options; |
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 scripts are just copied, ported to typescript, and kept for reference to rewrite / refactor. They aren't really used as it's too karma-specific.
import path from 'node:path'; | ||
import chokidar, { FSWatcher } from 'chokidar'; | ||
|
||
export default class Watcher { | ||
_suiteDependencyLookup: { | ||
[x: string]: any; | ||
}; | ||
_watcher: FSWatcher; | ||
constructor( |
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 don't think this will be used as vitest handles it out of the box and has customization options.
packages/@lwc/integration-karma/vitest-scripts/karma-plugins/env.ts
Outdated
Show resolved
Hide resolved
createHCONFIG2JSPreprocessor.$inject = ['config', 'logger', 'emitter']; | ||
|
||
export default { | ||
'preprocessor:hydration-tests': ['factory', createHCONFIG2JSPreprocessor], | ||
}; |
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.
hydration-tests plugin not yet rewritten.
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 made some changes the @lwc/rollup-plugin to simplify this migration. They could be removed before merge, or kept if there's some perf benefit in addition to simplifying the vitest plugin.
let { | ||
rootDir, | ||
modules = [], // TODO [#3370]: remove experimental template expression flag | ||
experimentalComplexExpressions, | ||
apiVersion, | ||
} = pluginOptions; | ||
|
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.
Making some options configurable after the fact
api: { | ||
updateOptions(options: { | ||
rootDir: string; | ||
modules?: ModuleRecord[]; | ||
experimentalComplexExpressions?: boolean; | ||
apiVersion?: number; | ||
}) { | ||
rootDir = options.rootDir; | ||
|
||
modules = [ | ||
...(options.modules ?? []), | ||
...DEFAULT_MODULES, | ||
{ dir: options.rootDir }, | ||
]; | ||
|
||
if (options.experimentalComplexExpressions !== undefined) { | ||
experimentalComplexExpressions = options.experimentalComplexExpressions; | ||
} | ||
|
||
if (options.apiVersion !== undefined) { | ||
apiVersion = options.apiVersion; | ||
} | ||
}, | ||
}, |
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.
Providing an api to change some options to avoid recreating the plugin for tests and fixtures which require different settings.
I've since found a cleaner approach which I might use as reference: https://github.com/vitejs/vite-plugin-vue/blob/main/packages/plugin-vue/src/index.ts#L192-L200
beforeAll(function () { | ||
const getNormalizedFunctionAsString = (fn) => fn.toString().replace(/(\s|\n)/g, ''); | ||
|
||
jasmine.addMatchers({ | ||
toEqualWireSettings: function () { | ||
return { | ||
compare: function (actual, expected) { | ||
Object.keys(actual).forEach((currentKey) => { | ||
const normalizedActual = Object.assign({}, actual[currentKey], { | ||
config: getNormalizedFunctionAsString(actual[currentKey].config), | ||
}); | ||
|
||
const normalizedExpected = Object.assign({}, expected[currentKey], { | ||
config: getNormalizedFunctionAsString( | ||
expected[currentKey].config || function () {} | ||
), | ||
}); | ||
|
||
expect(normalizedActual).toEqual(normalizedExpected); | ||
}); | ||
|
||
return { | ||
pass: 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.
This beforeAll() was just adding a custom matcher. I moved it to the test scripts in karma and implemented the equivalent in the vitest scripts.
Thanks a lot for this PR! I haven't had a chance to review yet, but I have some quick thoughts:
Originally, I had planned on us migrating to something like Web Test Runner with Jasmine. That's not to say Vite isn't the right choice (we're already using it elsewhere), but that is what I had in mind. |
@nolanlawson thanks for looking into it! re 2: Vitest also runs in a single tab and the test speed hasn't changed much (although hydration tests runs 2x faster with a tweak I made). I kept the clean up routine the same and mostly ported the ad-hoc plugins without much behavioral change. re 3: we can definitely test different browser versions with playwright using providerOptions, but also we can use webdriverio and its own providerOptions. Admittedly, I haven't looked into any of this yet as my current focus is making all the different flags work (as well as the single failing test in chrome). re 4: I'm not sure that case is currently causing any issues, at least not with the current flags, but I get your point. There's a bunch of work I'm not sure how to handle yet, especially coverage and merging the results, because I want to first figure out all the flags and especially this failing test (only on chrome/webkit and maybe only on macOS. Firefox works fine.):
There's no rush on this PR (it can be left in draft and closed at some point), but I'd love your feedback especially regarding that failing test. My current plan is to make some smaller PRs based on my learnings that would help transition into this setup or another setup. |
I would much prefer this. WebDriver is the standard, we are already using webdriverio elsewhere, and I imagine this would play nicer with our current SauceLabs setup. The way that Playwright hacks around with CDP and a custom WebKit build makes me nervous.
This is interesting, I wasn't aware of this... I assumed Vitest was doing some kind of test isolation, i.e. with browser tabs. If the tests take the same-ish amount of time to run, then my concern goes away. The current lack of test isolation isn't a hard requirement either. Overall I really appreciate your work on this, but yeah this PR might end up being delayed as we work on other stuff. Right now it's kind of a crunch time for my team, so we may not be able to give this PR as much attention as it deserves. I really appreciate your help, though! Let me know if there's anything else I can answer to help unblock you. 🙂 |
@nolanlawson your insight about I'm closing this PR for now as I found severe regression in test performance using webdriverio with vitest browser mode. It's not a first-class citizen there compared to playwright, maybe in a few months. The performance impact is mostly due to the built-in test isolation, and the DOM clean up routines are not behaving the same way in order to run without isolation. Could they be improved to be more portable? Perhaps something similar to the hydration suite with a dedicated div per file/test? Playwright runs the tests just as fast with the isolation, but I totally get why it's not a good option here. I'll continue submitting improvements to the current karma tests. If you happen to have ideas, I'll be happy to take on any issues. #4600 is my current pet peeve, but it's so hard to reproduce. Edit: About Web Test Runner, I like it, but I'm not confident it's a better option compared to keeping karma or rolling something custom when thinking about maintenance. |
@cardoso I really appreciate all your work on this. Uplifting our entire Karma test suite is a huge task. But even the small fixes you've found along the way have really helped improve our test quality! ❤️ I too was kind of disappointed when I searched the testing landscape for a good alternative to Karma. There just aren't many tools that avoid test isolation. I see the benefits of test isolation, but I really dislike it for our tests because 1) we are already diligent about cleaning things up, and 2) it's so fast! Another option I (honestly) considered was to use raw WebDriverIO and just serve an HTML page with the Jasmine tests. We're mostly just using Rollup plugins, so this could even work in dev mode. But obviously we'd have to write a lot of glue code ourselves (e.g. for SauceLabs) which is not fun. For the time being, I would not stress out too much on this – Karma is deprecated, but it's not going to stop working anytime soon. And maybe a good alternative will emerge as more teams try to move off of it. |
Details
I'm pushing this PR as draft to better manage the diff and eventually clean it up for review.
It adds a
yarn test:browser
script to@lwc/integration-karma
which runs a vitest config in browser mode.The vitest config uses plugins and setup scripts that mimic the custom scripts and plugins used by karma, but are being written mostly from scratch.
The aim during migration is to ideally have minimal modification to tests, so the setup scripts polyfills jasmine and other karma globals. There's some exceptions: Some tests add custom matchers. I prefer to move those to the setup scripts, since polyfilling jasmine.addMatchers with expect.extend is more work than it's worth.
yarn test
(karma) runs unmodified.yarn test:browser
(playwright/vitest) currently passes almost all tests but rewriting the plugins, scripts, and polyfills is still ongoing.Once
yarn test:browser
is passing all tests, the plan is to remove karma completely, and transition this PR to ready for review. Most likely I'll leave the CI and coverage work for reviewers.Same for
yarn hydration:test
(karma) andyarn hydration:browser
(playwright/vitest)If this works out, future tests can be written using facilities from vitest browser mode and playwright.
Old tests can be modernized as needed, and eventually the jasmine/karma polyfills can be removed.
Closes #3589
Current status
test-hydration (all)
test (firefox)
test (chromium)
Does this pull request introduce a breaking change?
Does this pull request introduce an observable change?
GUS work item