I'm building a single page web application (SPA) with server side rendering (SSR).
We have a node backend API which is called both from the node server during SSR and from the browser after initial rendering.
I want to write e2e tests that configures API responses (like with nock
) and work both with browser calls and SSR server calls. some pseudo-code :
it('loads some page (SSR mode)', () => {
mockAPI.response('/some-path', {text: "some text"}); // here i configure the mock server response
browser.load('/some-other-page'); // hit server for SSR response
expect(myPage).toContain('some text');
})
it('loads some other page (SPA mode)', () => {
mockAPI.response('/some-path', {text: "some other text"}); // here i configure another response for the same call
browser.click('#some-link'); // loads another page client side only : no SSR here
expect(myPage).toContain('some other text');
})
Currently Cypress allows me to mock fetch on the browser but not on the server.
Is there anything to achieve that ? Preferably with node libs.
MockTTP can do that. Excerpt from the doc :
const superagent = require("superagent");
const mockServer = require("mockttp").getLocal();
describe("Mockttp", () => {
// Start your server
beforeEach(() => mockServer.start(8080));
afterEach(() => mockServer.stop());
it("lets you mock requests, and assert on the results", () =>
// Mock your endpoints
mockServer.get("/mocked-path").thenReply(200, "A mocked response")
.then(() => {
// Make a request
return superagent.get("http://localhost:8080/mocked-path");
}).then(() => {
// Assert on the results
expect(response.text).to.equal("A mocked response");
});
);
});
We used a particularly ugly solution, that breaks the speed of cypress, but we needed that in order to mock/fake socket calls.
You can make a real simple express server that starts before running your tests. This 'real fake server' will be able to respond what you need. Here are the specs of our:
/
with method
, path
and {data}
in body params in order to setup a route/path
responds {data}
/
clear all the routesLet's consider your 'real fake server' run on 0.0.0.0:3000; you'll do:
beforeEach() {
cy.request('DELETE', 'http://0.0.0.0:3000/');
}
it('loads some page (SSR mode)', () => {
cy.request('POST', 'http://0.0.0.0:3000/', {
method: 'GET',
path: '/some-path',
data: {text: "some other text"}
}) // here i tell my 'real fake server' to
// respond {text: "some other text"} when it receives GET request on /some-path
browser.load('/some-other-page'); // hit server for SSR response
expect(myPage).toContain('some text');
})
it('loads some other page (SPA mode)', () => {
cy.request('POST', 'http://0.0.0.0:3000/', {
method: 'GET',
path: '/some-path',
data: {text: "some other text"}
}); // here i configure another response for the same call
browser.click('#some-link'); // loads another page client side only : no SSR here
expect(myPage).toContain('some other text');
})
Important : the resquests need to be in localhost. You won't be able to stub something external. (Hence, make an env var in order to request localhost:xxxx instead of google.com when you test your app)
You won't be able to control the 'real fake server' otherwise than this cy.request because your tests scripts run in the browser (correct me if I'm wrong) and the browser can't run an express server.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With