'Compositions' (a.ka. 'component previews') are a the rendering of a component, in different variations.
It often happens that your compositions require a common context, such as a theme provider, a router, or an auth provider. In such cases, you can wrap every composition individually, or add it as a constant wrapper for all compositions, using the same env.
However, it often happens that your unit tests require the same context your compositions use. This blog post will show you how to create a common render context for both your compositions and unit tests.
You can find the complete code example as shown below;
Run the following command to create a React Context component:
In our example, the implementation of the render context is as follows:
/* @filename: my-render-context.tsx */
export function MyRenderContext({ children }: MyRenderContextProps) {
return (
<ThemeProvider theme={theme}>
<Box sx={{ p: 5 }}>
<Box sx={{ display: "flex", justifyContent: "flex-end" }}/>
{children}
</Box>
</ThemeProvider>
);
}
Create a React env (if you don't have one already) and add the render context component as a wrapper for all your component previews.
/* @filename: my-env/mounter.tsx */
import { MyRenderContext } from '@learnbit-react/common-render-context.render.my-render-context';
export default createMounter(MyRenderContext) as any;
See our demo env here. Learn more about changing your React components preview in the Component previews docs.
To use the same render context for your unit tests, pass the render context component as a wrapper to the react-testing-library render function.
/* @filename: demo/button.spec.tsx */
import { render } from "@testing-library/react";
import { SampleButton } from "./button.composition";
it('renders with the correct text', () => {
const { getByText } = render(<MyRenderContext><SampleButton /></MyRenderContext>);
const rendered = getByText('Click Me!');
expect(rendered).toBeTruthy();
});
it('should render with the theme color', () => {
const { getByText } = render(<MyRenderContext><SampleButton /></MyRenderContext>);
const rendered = getByText('Click Me!');
const styles = window.getComputedStyle(rendered);
const primaryColor = 'rgb(44, 0, 195)';
expect(styles.backgroundColor).toBe(primaryColor);
});
Though, this approach is simpler to implement and easy to understand. However, we need to repeatedly add the wrapper for all our test cases. Let's look at a way to avoid this repetition.
Run the following to create a component that extends the react-testing-library function, and customizes it to use the render context component as a wrapper.
The following is the implementation of the test renderer in our example:
import React from "react";
import { RenderResult, render as _render } from "@testing-library/react";
import { MyRenderContext } from "@learnbit-react/common-render-context.render.my-render-context";
export function render(children: React.JSX.Element): RenderResult {
return _render(<MyRenderContext>{children}</MyRenderContext>);
}
In each test case you can use the render
function as follows:
/* @filename: demo/button.spec.tsx */
import { render } from "@learnbit-react/common-render-context.my-testing-library";
import { SampleButton } from "./button.composition";
it("should render with the correct text", () => {
const { getByText } = render(<SampleButton />);
const rendered = getByText("Click Me!");
expect(rendered).toBeTruthy();
});
it("should render with the theme color", () => {
const { getByText } = render(<SampleButton />);
const rendered = getByText("Click Me!");
const styles = window.getComputedStyle(rendered);
const primaryColor = "rgb(44, 0, 195)";
expect(styles.backgroundColor).toBe(primaryColor);
});
You can use the custom testing library for all your unit tests. Add it to your component templates to avoid repetition.