Jest testing, Node modules and Reflect

Tom Berwick
John Lewis Partnership Software Engineering
3 min readFeb 14, 2022
Photo by Ferenc Almasi on Unsplash

I first worked on johnlewis.com back in 2007. Back then the website was mainly written in VB.net, only one developer could “checkout” a file for editing at a time (which made merging a nightmare!) and test coverage was pretty much non-existent.

Having recently come back into IT from some stints in Innovation and JLP Ventures (great experiences which allowed me to look to the future and explore “startups” within the John Lewis Partnership), it’s great to see the levels of testing we now have in place for the website and the apps we produce.

On standard-pdp (product detail page - responsible for some product pages on johnlewis.com), like a lot of teams, we currently use Jest for our unit tests. One of the powerful capabilities of Jest is the ability to mock node modules. When testing components, this can be great for mocking the behaviour of external services which should have their own tests for their behaviour and/or they require network requests which you don’t want to be making in your tests. An example of this is shown below, where we might mock calls to analytics:

jest.mock(“../../utils/analytics/analytics”, () => {
return {
useAnalytics: jest.fn(),
dispatchAnalyticsEvent: jest.fn(),
updateAnalyticsObject: jest.fn(),
};
});

Most of the time this works great, and thanks to Javascript’s dynamic behaviour, we can override functions and properties when we want to test various scenarios during different unit tests.

However, due to the nature of node modules being cached upon `require` and their export structure, this isn’t always possible. One example that has cropped up a lot for us has been the ability to mock the publicRuntimeConfig supplied by NextJS via next/config. We might use this for feature flags, but unfortunately it’s not always straightforward to test these as we can’t change the values of publicRuntimeConfig. Speaking to other teams within front-end dev, one of the accepted solutions has been to just include the runtime config on a “per function” basis when needed. This can then be overridden on each individual test.

Whilst trying to think of a solution to this problem I wondered if there was anything else we could do to achieve this. Though I’ve never used it myself, a lot of languages make use of “Reflection” to achieve some dynamism and I wondered if we could do something similar here. Javascript has achieved similar features via mechanisms such as `Object.getOwnPropertyDescriptor` but since ES6 we can make use of Reflect.

From what I understand (and I could be wrong) — Reflect allows use to create “Proxies” of objects (There is a Proxy method as well that allows you to do all kinds of intercepts on getters and setters). This allows us to override one of the publicRuntimeConfig values for a specific test and then set it back again. A more complete example can be seen below

jest.mock(‘next/config’, () => () => ({
publicRuntimeConfig: {
host: ‘www.example.com',
useComponent: false,
},
}));
it(‘contains and renders component placeholder if USE_COMPONENT flag is true’, () => { Reflect.set(publicRuntimeConfig, ‘useComponent’, true); render(<ProductPage />);
expect(queryByTestId(‘product:someComponent’))
.toBeInTheDocument();
Reflect.set(publicRuntimeConfig, ‘useComponent’, false);});

This is an example where a broader knowledge of other languages and what’s possible (in this case Reflection) comes in handy. I’ll talk about that more in a future post I’ll write about side projects.

I hope someone has found this post interesting. I could obviously be totally misunderstanding the nature of Reflect within Javascript, so whilst it worked in the example above please comment if you have used it and have deeper knowledge of the inner workings!

At the John Lewis Partnership we value bringing the creativity of expert software engineers to bear on the challenges of discovering innovative solutions. We craft the future of two of Britain’s best loved brands (John Lewis & Waitrose) in an environment which respects diversity, values personal development and empowers individuals. We are currently recruiting across a range of software engineering specialisms. If you like what you have read and want to learn how to join us, take the first steps here.

--

--

Tom Berwick
John Lewis Partnership Software Engineering

Mobile App, game and full stack developer. Constantly trying to learn new things and dabble in growth hacking