In Svelte, I have a parent component which listens to a component event dispatched by a child component.
I know how to use component.$on
to check that the dispatched event does the right thing within the component which is dispatching, like so.
But I can't figure out how to check that the component which receives the dispatch does the right thing in response.
Here's a basic example:
Child.svelte
<script>
import { createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher()
function handleSubmit(event) {
dispatch('results', 'some results')
}
</script>
<form on:submit|preventDefault={ handleSubmit }>
<button type='submit'>Submit</button>
</form>
Parent.svelte
<script>
import Child from './Child.svelte'
let showResults = false
function handleResults(event) {
showResults = true
}
</script>
<Child on:results={ handleResults } />
{ #if showResults }
<p id='results'>Some results.</p>
{ /if }
The idea is to eventually write a test using @testing-library/svelte
like:
import { render } from '@testing-library/svelte'
import Parent from './Parent.svelte'
test('shows results when it receives them', () => {
const rendered = render(Parent)
// ***
// Simulate the `results` event from the child component?
// ***
// Check that the results appear.
})
If the parent were reacting to a DOM event, I would use fireEvent
.
But I don't know how I would get a hold of the <Child>
component in this case, and even if I could I'm guessing that Svelte is using a different mechanism for component events.
(Just to test it out, I used createEvent
to fire a custom results
event on one of the DOM elements rendered by <Child>
but it didn't seem to do anything.)
Anyone have any ideas? Thanks!
If you're already planning on using
@testing-library/svelte
, I think the easiest way is not to try to manually trigger theChild
component'sresults
event, but to use Testing Library to grab the form/submit elements and trigger the submit event (usingfireEvent
aSubmitEvent
on the<form>
or their@testing-library/user-event
library, or even a vanilladispatchEvent
). Svelte would then dispatch the customresults
event thatParent
is listening on.Something like:
Hope this is what you had in mind.
Edit: For mocking
Child.svelte
, something like this in a__mocks__/Child.svelte
should work:Which is the exact same implementation as the actual module (I gave the button a different label just to make it clear it's the mocked version when querying it), but the idea is that this would never need to change and is only used to dispatch a
results
event. Then you'd just need to tell Jest or whatever you're using that you're mocking it (jest.mock("./Child.svelte");
), change thegetByRole
query to match the new name (or just leave the mock with the original name), then it should just work.Whether you think that's worth it or not is up to you. I've generally had success testing the UI as a whole rather than mocking sub-components, but I guess it comes down to preference. Yes, you might have to change the test if the Child component changes, but only if you change the label of the button or change the user interaction mechanism.
You don't need to know about the details of the components, you don't even need to know that it's split into a separate Child component, all the test would care about is a general idea of the structure of the UIāthat there's a button called "Submit" and that clicking on it should show an additional
<p>
tag.