[labs/testing] testing package with SSR testing utilities#2957
[labs/testing] testing package with SSR testing utilities#2957
Conversation
🦋 Changeset detectedLatest commit: cd6144e The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
📊 Tachometer Benchmark ResultsSummary⏳ Benchmarks are currently running. Results below are out of date. nop-update
render
update
Results⏳ Benchmarks are currently running. Results below are out of date. ⏱ lit-element-list
render
update
update-reflect
⏱ lit-html-kitchen-sink
render
update
nop-update
⏱ lit-html-repeat
render
update
⏱ lit-html-template-heavy
render
update
⏱ reactive-element-list
render
update
update-reflect
|
It seems like we'll need to require the const el = await ssrFixture(html`<my-element></my-element>`, {
base: import.meta.url, // path to resolve relative modules against
modules: ['./my-element.js'], // path to component definition, relative to base (or cwd if not specified)
hydrate: false, // whether to hydrate the component after loading to document (default: true)
});On the client, it would just |
Yeah, doing this as an integration test seems like the most bang-for-buck. Seems like you'll want to test a variety of component scenarios, obv a happy case where it all passes, but also some cases where we expect the tests to fail e.g. to ensure we catch when users do SSR-incompatible things. I'd expect main focus to be on the latter, since the ^^ points out that we'll want to nicely pipe errors raised from (hmmm, now that I think about it)
Seems like we might just be able to switch all the |
c3cecdf to
5466d84
Compare
38c3813 to
cc44c30
Compare
aomarks
left a comment
There was a problem hiding this comment.
This is looking really great! Pretty minor comments.
aomarks
left a comment
There was a problem hiding this comment.
Looks great! Just some minor comments, LGTM otherwise.
| } | ||
| ); | ||
|
|
||
| // TODO(augustinekim) Clean up the container from the document |
There was a problem hiding this comment.
How will we know when to do the cleanup? I wonder if we should have a cleanupFixtures or something, which tracks all fixtures in a global, that users can put in their after callbacks?
There was a problem hiding this comment.
open-wc's implementation keeps the containers in a module scoped array https://github.com/open-wc/open-wc/blob/master/packages/testing-helpers/src/fixtureWrapper.js and the fixture import has a side effect of registering the cleanup on afterEach and teardown if mocha is registered globally. https://github.com/open-wc/open-wc/blob/master/packages/testing-helpers/src/fixture.js
We could also provide the cleanup function for users to call themselves if they care about cleaning up.
There was a problem hiding this comment.
+1 to a cleanupFixtures function, that makes sense.
We could also just have fixture keep a module-scoped lastContainer and remove it before creating another so we're not accumulating loads of containers during a long suite, if it's safe to assume people don't generally create multiple fixtures in tests (?, not sure about that).
There was a problem hiding this comment.
Added a cleanupFixtures for now.
I haven't seen cases of users creating multiple fixtures in a single test but don't want to discount that it might happen. I don't feel like trying to automatically clean up is important enough to potentially break that particular use case.
Co-authored-by: Alexander Marks <aomarks@google.com>
kevinpschaaf
left a comment
There was a problem hiding this comment.
Just a few minor suggestions and clarifications; feel free to consider/resolve, but I'm good merging this based on your judgement on those.
| } | ||
| ); | ||
|
|
||
| // TODO(augustinekim) Clean up the container from the document |
There was a problem hiding this comment.
+1 to a cleanupFixtures function, that makes sense.
We could also just have fixture keep a module-scoped lastContainer and remove it before creating another so we're not accumulating loads of containers during a long suite, if it's safe to assume people don't generally create multiple fixtures in tests (?, not sure about that).
| /http:\/\/localhost.+(?=\?wtr-session-id)/ | ||
| ); | ||
| if (!match) { | ||
| throw new Error('Could not find call site for csrFixture'); |
There was a problem hiding this comment.
In what cases do we expect this to fail? It's unclear in the readme if users are expected to pass import.meta.url or if they can reasonably expect this to work without having to pass that. Maybe clarify?
There was a problem hiding this comment.
I don't anticipate us to ever reach this unless how the stack is generated gets changed (or the regex somehow fails for some browser besides chrome, firefox, webkit) or if web test runner changes the query to something other than wtr-session-id.
I've updated the readme to expand more on the base option. Leaving it empty should have the same behavior as passing in import.meta.url.
| render(template, container); | ||
|
|
||
| // Awaiting for the next microtask to ensure contents are rendered. | ||
| await undefined; |
There was a problem hiding this comment.
Not sure what the open-wc fixture does, but it might be good to wait a requestAnimationFrame instead, to ensure the entire tree of components (if there are multiple levels) are done rendering...?
There was a problem hiding this comment.
https://github.com/open-wc/open-wc/blob/master/packages/testing-helpers/src/elementUpdated.js
open-wc looks for specific promises to await on and falls back to requestAnimationFrame if they don't exist. Perhaps we could do something similar and look for updateComplete and await that.
| (strings as {raw: TemplateStringsArray['raw']}).raw = strings; | ||
|
|
||
| let rendered = ''; | ||
| for (const str of render({...template, strings}, {deferHydration: true})) { |
There was a problem hiding this comment.
Not familiar with how workers work... since this is all executed in module scope, if it throws, then we'll get a worker.on('error') callback?
There was a problem hiding this comment.
Yes that's correct. Currently the wtr server command simply fails for those cases so the fixture function call will then throw. We see that happen in the bad-element test.
| export function litSsrPlugin(): TestRunnerPlugin<Payload> { | ||
| return { | ||
| name: 'lit-ssr-plugin', | ||
| async executeCommand({command, payload}) { |
There was a problem hiding this comment.
Not blocking for this PR, but would love to think about how this could be factored a little differently so that it could be called from e.g. a koa/express middleware as well, so we're not tied directly to web-test-runner. Should be straightforward, I think?
Resolves #2867
This PR adds a
@lit-labs/testingpackage.The
litSsrPluginplugin for Web Test Runner registers thelit-ssr-renderserver command that takes the template and module paths, and renders them within a worker thread in the same manner as eleventy-plugin-lit.The server command is utilized by
ssrFixtureto be called in the test file supplying lit-html template to render and component definition module path(s).The README has example usage.
Still to do are to add tests, and a fixture function with client side rendering with the same signature for ease of writing tests across the different rendering methods.
This is still an early draft and I'm looking for feedback on