Reputation: 1277
I have Stencil component which uses axios.get to get some data from a server (e.g. localhost:3000 during development). Now I have an e2e.ts test which tests this component in conjunction with several other components. I would like to mock the axios.get function to isolate my tests from the server. In a spec.ts test I would mock axios using jest with the following code:
import axios from 'axios';
import {myComponent} from './my-component';
const mock = jest.spyOn(axios, 'get');
test('get data', async () => {
...
mock.mockResolvedValue('hello');
...
});
But this does not work in e2e tests. I have tried installing jest-puppeteer but I cannot find any examples of how you would mock a function with jest mocking API with jest-puppeteer.
Any example code would be greatly appreciated.
P.S. Note: if I use Puppeteer to intercept a request and respond to it I get a "Request is already handled" error. Here's example code:
const page = await newE2EPage();
await page.setRequestInterception(true);
page.on('request', req => {
if(req.url() === 'http://localhost:3000/') {
request.respond({
contentType: 'text/plain',
headers: {'Access-Control-Allow-Origin': '*'},
body: 'hello'
})
}
else {
request.continue({});
}
});
await page.setContent('<my-component></my-component>');
Upvotes: 1
Views: 3117
Reputation: 4978
I'm not 100% sure how well this answer translates to axios
, but this is possible with fetch
, which I encourage you to use because it's widely supported by browsers now, and Stencil automatically poly-fills it if needed.
For our app's e2e tests I wrote the following script that you can add to your e2e page after initalizing it:
await page.addScriptTag({
content: `
window.originalFetch = window.fetch;
window.requestsToIntercept = [];
window.fetch = (...args) => (async(args) => {
const result = await this.originalFetch(...args);
for (const request of requestsToIntercept) {
if (args[0].includes(request.url)) {
result.json = async () => JSON.parse(request.response);
result.text = async () => request.response;
}
}
return result;
})(args);`,
});
It overwrites the fetch
implementation and uses the global requestsToIntercept
array to stub responses. You can add a helper function to your code like
const interceptRequests = async (requests: { url: string; response: string }[]) =>
page.addScriptTag({
content: `window.requestsToIntercept.push(...${JSON.stringify(requests)});`
});
and then use it like
interceptRequests([{ url: '/foo', response: { foo: 'bar' } }])
This will intercept all requests that include /foo
and respond with the given response instead.
I'll leave it up to you to refactor this into helpers the way you want. Personally I decided to create a function that creates a newE2EPage
for me and adds interceptRequests
as a method to the page object.
BTW the reason that you can't enable request interception in Puppeteer is that Stencil already uses it internally, and therefore the request will already have been handled before your "on request" listener kicks in (as the error message states). There's a request to change this on Github: https://github.com/ionic-team/stencil/issues/2326.
Upvotes: 3