jest-shallow-serializer
v1.2.0
Published
A flexible jest serializer for shallow rendering React components. Unlike full shallow renderers, this tool focuses on serializing only the components you pick, making snapshots cleaner and more focused. Perfect for targeted testing with minimal noise
Maintainers
Readme
jest-shallow-serializer
A flexible jest serializer for shallow rendering React components. Unlike full shallow renderers, this tool focuses on serializing only the components you pick, making snapshots cleaner and more focused. Perfect for targeted testing with minimal noise! 🚀
Features
- Selective shallow rendering - Choose which components to shallow render
- Babel macro support - Compile-time transformation for cleaner test files
- Nested component support - Mock context providers and nested exports
- No external dependencies - Works with Jest's built-in mocking
Motivation
I created this package because existing solutions for shallow rendering are no longer maintained, and the testing ecosystem seems to be shifting toward other approaches. However, I still believe shallow rendering is a valuable technique for isolating and testing components effectively, and this serializer aims to fill that gap.
Installation
- Install package
npm install jest-shallow-serializer --save-dev- Add
jest-shallow-serializertocompilerOptionstypes (intsconfig.json):
"types": ["jest-shallow-serializer"]- Add
jest-shallow-serializerto snapshot serializers (injest.configfile):
"snapshotSerializers": ["jest-shallow-serializer/serializer"]- Extend
globalscope (injest.configfile):
"setupFilesAfterEnv": ["<rootDir>/jest.setup.js"]jest.setup.js
import { doShallow, shallowWrapper, shallowed } from "jest-shallow-serializer";
Object.assign(global, {
doShallow,
shallowWrapper,
shallowed,
});- (Optional) You might need to add
doShallow,shallowWrapperandshallowedas globals (ineslint.config):
"globals": {
"doShallow": "readonly",
"shallowWrapper": "readonly",
"shallowed": "readonly"
},Usage
Unlike enzyme#shallow or react-test-renderer/shallow, this library performs selective shallow rendering. Developers choose specific components to shallow render by mocking them.
1. Babel Macro (Recommended)
The Babel macro provides a cleaner syntax by transforming your code at compile time.
Installation
- Install
babel-plugin-macros:
npm install babel-plugin-macros --save-dev- Add
macrosplugin to your Babel config:
babel.config.js
module.exports = {
plugins: ["macros"],
};Usage
import { shallowMock } from "jest-shallow-serializer/macro";
shallowMock("@/components/component-name", "ComponentName");The macro transforms this at compile time into:
jest.mock(
"@/components/component-name",
shallowWrapper("@/components/component-name", "ComponentName")
);Note: The first argument must be a string literal (the module path).
2. shallowWrapper + shallowed + jest.mock
import * as componentModule from "@/app/module/Component";
import { App } from "@/app/module/App";
jest.mock(
"@/app/module/Component",
shallowWrapper("@/app/module/Component", "ComponentName")
);
const shallowedComponentModule = shallowed(componentModule);3. doShallow + require
doShallow use jest.doMock, which is not hoisted, that's why we need to require shallowed module afterwards.
import { App } from "@/app/module/App";
const shallowedComponentModule = doShallow(
"@/app/module/Component",
"ComponentName"
);
const { ComponentName } = require("@/app/module/Component");After obtaining shallowedComponentModule, we can use it to mock / unmock a component:
describe("Component", () => {
afterEach(() => {
shallowedComponentModule.unmock("ComponentName");
});
it("matches snapshot", () => {
shallowedComponentModule.mock("ComponentName");
const { asFragment } = render(<App />);
expect(asFragment()).toMatchSnapshot();
});
it("next test", () => {
render(<App />); // here `ComponentName` won't be shallowed
});
});Next.js
If you're using Next.js, add the macros plugin to your Babel config:
// babel.config.js
module.exports = {
presets: ["next/babel"],
plugins: ["macros"],
};This works with both the App Router and Pages Router.
Nested exports / Context
You can also use dot notation in component names to shallow mock nested components. For example, if you want to mock context provider, simply use Context.Provider as the component name.
src
├── context.ts
├── Component.tsx
├── Component.spec.tsxcontext.ts
export const Context = createContext<string | undefined>(undefined);Component.tsx
import { Context } from "./context";
export const Component = ({ children }: TestComponentContextProps) => {
return <Context.Provider value="lorem ipsum">{children}</Context.Provider>;
};Component.spec.tsx
import { Component } from "./Component";
import { Context } from "./context";
jest.mock("./context", shallowWrapper("./context", "Context.Provider"));
const shallowedProvider = shallowed(Context);
describe("Component", () => {
afterEach(() => {
shallowedProvider.unmock("Context.Provider");
});
it("matches snapshot", () => {
shallowedProvider.mock("Context.Provider");
const { asFragment } = render(<Component />);
expect(asFragment()).toMatchSnapshot();
});
});