Skip to content
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

Using with vue component tests #80

Open
nirajfu3e opened this issue Feb 25, 2022 · 6 comments
Open

Using with vue component tests #80

nirajfu3e opened this issue Feb 25, 2022 · 6 comments

Comments

@nirajfu3e
Copy link

I am trying to use the package with a axion request on a vue component following the basic example but maybe I am not understanding the basics here, I can't get a then spy to have been called.

<!-- Component.vue -->
<input
  class="search-input form-control"
  id="field-text"
  type="text"
/>

<div class="search-results" v-if="searchResults">
    <div
        v-for="searchResult in searchResults"
        :key="searchResult.id"
        class="search-result"
    >
        {{ searchResult.country }}
    </div>
    <div
        v-if="searchResults.length === 0"
        class="no-results"
    >
        No result found
    </div>
</div>
<script>
onInput: _.debounce(function(event) {
    api.search(this.term).then(
        ({data}) => this.results = data
    )
}, 300)
</script>

Then the test which uses vue-testing-library is as follows

// Component.spec.js
it('renders properly', async (done) => {
    let catchFn = jest.fn(),
        thenFn = jest.fn();

    // using the component, which should make a server response
    let term = 'London';

    render(Component, {
            localVue,
            store: store,
        })
    }

   
    const input = screen.getByRole('textbox')
    await userEvent.type(input, term)
    await userEvent.click(document.body)

    // Set timeout is required since there is a debounce of 300ms on input field
    setTimeout((async () => {
        done()

        // since `post` method is a spy, we can check if the server request was correct
        // a) the correct method was used (post)
        // b) went to the correct web service URL ('/search')
        // c) if the payload was correct ('{term: term}')
        expect(mockAxios.post).toHaveBeenCalledWith('/search', {term: term });

        // simulating a server response
        let responseObj = {
            "data": [
                {
                    "id": 1,
                    "country": "Foo",
                },
                {
                    "id": 2,
                    "country": "Bar",
                },
            ]
        };
        mockAxios.mockResponse(responseObj);

        // checking the `then` spy has been called and if the
        expect(thenFn).toHaveBeenCalled();

        // catch should not have been called
        expect(catchFn).not.toHaveBeenCalled();

        // debug the output
        screen.debug();
    }), 400)
});

In the test the first assertion (expect(mockAxios.post).toHaveBeenCalledWith('/search', {term: term });) works as expected. It mocks the response as well but it fails on the expect(thenFn).toHaveBeenCalled(); showing there were 0 calls for thenFn.

I was also expecting the results on the this.results = data to be populated with the mocked response data and the template updated, just like when you get a response from an actual api endpoint would but it looks like that never happens. Am I missing something here?

@kingjan1999
Copy link
Collaborator

Hi,

it looks like your example is incomplete. You're initializing thenFn with jest.fn() but don't reference it somewhere else. Thus, it never get's called.

@nirajfu3e
Copy link
Author

nirajfu3e commented Feb 25, 2022

@kingjan1999 Thank you for the very quick response and you are indeed correct. I forgot to ask where would I call it as the example in the readme, it is used as follows:

UppercaseProxy(clientMessage)
  .then(thenFn)
  .catch(catchFn);

I tried doing this but it didn't work as expected since the render function doesn't return a promise.

render(Component, {
          localVue,
          store: store,
      })
  }).then(thenFn)
.catch(catchFn);

@kingjan1999
Copy link
Collaborator

@nirajfu3e In the readme example, UppercaseProxy returns a promise. Therefore, it is easy to chain another then or catch on the returned promise. In your example, the promise used in onInput can't be accessed from the test. Consequently, you can't just attach a spy function to verify the actual then callback is executed. You need to verify this based on the actions done there, e.g on what is set to this.results or actually rendered by Vue.

@nirajfu3e
Copy link
Author

@kingjan1999 That makes perfect sense and that is how I was planning to test it - by checking what was actually rendered by Vue. For some reason the mocked data set with responseObj doesn't seem to be applying on this.results and the vue template doesn't get updated to display the results.

Am I correct in assuming that when we simulate the server response, on Component.vue it should have used the mockedResponse created with mockAxios.mockResponse(responseObj) and update the template rendered by Vue just like it would outside of test environment?

Thanks.

@kingjan1999
Copy link
Collaborator

@nirajfu3e That's exactly what should happen, yes. Can you check whether the then callback is called at all (e.g. with some logging)? Or provide a minimal working example (repo), so that I can look further into this?

@nirajfu3e
Copy link
Author

@kingjan1999 I did console.log and when I mock the response object I can see the output of the data but strangely, I can't seem to use array destructing ({data}) => this.searchResults = data (returns undefined). If I simply do (data) => this.searchResults = data, then it shows the data when the response is mocked but still doesn't seem to update the rendered value.

I tried creating a CodeSandbox but for some reason the setup is not working on it but I have got the tests with an API mocked there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants