Stefan R.
Stefan R.

Reputation: 181

How to mock/simulate a child component event for jest tests in svelte?

I want to run an isolate test on my svelte parent component (e.g. OrderSearch). Therefore the behavior of the child component (e.g. SearchForm) should be "simulated". The child component throws a search event that is bound in the parent component to initiateSearch.

SearchForm.svelte (Child component - NOT subject of testing - triggering of "submit" should be simulated)

<script>
  const dispatchEvent = createEventDispatcher()
  
  const submit = () => {
    dispatchEvent('search', {firstName: '42'})
  }
</script>

<div on:click="submit">Submit</div>

OrderSearch.svelte (Parent Component - Subject of testing)

<script>
  let results = []

  const initiateSearch = (e) => {
    console.log('initiate search with', e)

    // search is started and returns results
    results = [{orderId: 'bar'}]
  }
</script>  
 
<SearchForm on:search="initiateSearch"></SearchForm>

{#each results as order}
  <div data-testid="order">{order.id}</div>     
{/each}
  

My not working approach so far when testing the OrderSearch.svelte in an isolated way:

OrderSearchTest.js

const {getAllByTestId, component} = render(Component)

expect(getAllByTestId('order')).toHaveLength(0)

await component.getSubComponent('SearchForm').dispatchEvent('search', {detail: {orderId: 'jonine'}}

expect(getAllByTestId('order')).toHaveLength(1)

Upvotes: 5

Views: 1301

Answers (1)

drrkmcfrrk
drrkmcfrrk

Reputation: 378

Don't mock the child's event. You don't need to test that the on:<event> directive works, I would assume that Svelte has corresponding tests to ensure that it does. You need to test only that your component responds in the way that it should when the code that is executed on a particular event occurs. So trigger the event using fireEvent and mock or spy on a function, or function(s) called in the event handler.

Here's an example with appropriate changes made to your component:

OrderSearch.svelte

<script>
  import http from "path/to/some/http/util"
  let results = []

  const initiateSearch = async (e) => {
    // search is started and returns results
    results = await http.fetchSearchResults(e.detail)
  }
</script>  
 
<SearchForm on:search="initiateSearch"></SearchForm>

{#each results as order}
  <div data-testid="order">{order.id}</div>     
{/each}

Then the corresponding test could look like:

import mockHttp from "path/to/some/http/util"

jest.mock("path/to/some/http/util")

...

it("calls search endpoint and renders results after fetch resolves", async () => {
   mockHttp.fetchSearchResults.mockResolvedValue([{orderId: 'bar'}])
   const { queryByText, getAllByTestId } = render(Component)
   const submit = queryByText("Submit")

   expect(getAllByTestId('order')).toHaveLength(0)

   await fireEvent.click(submit)

   expect(getAllByTestId('order')).toHaveLength(1)
})

Upvotes: 1

Related Questions