Automated tests are a great way to ensure the quality of your software and provide a good user experience. At Woovi, we have thousands of landing pages, and occasionally, the first contact a user will have with us will be through these pages that showcase the products we offer. Therefore, we need to ensure that each one of them is functioning correctly. Each user who visits our pages represents a new opportunity to gain a customer.
The Challenge of Testing Landing Pages
Woovi's landing pages only present static content, such as text, images, and buttons that redirect to other pages. Due to this simplicity, there is no need to create a specific test for each new page, as they do not have advanced business rules that require more complex tests. With each new page, different content is displayed, so we need to simplify the testing process. Manually testing each one is unfeasible. Don’t do it!
The Solution: Render Testing
We use render testing (render test from the Testing Library) in conjunction with the glob library to ensure that all pages are tested efficiently.
- Render Testing: This is used to check if a component or a page renders correctly without errors. It also ensures that the expected elements are present in the user interface after rendering.
- GlobSync: This is used to search for files and directories that match a specific pattern, in our case .tsx, synchronously. This means that the function executes the search and returns the result immediately, blocking execution until the operation is complete.
Organize your project as follows:
src/
│
├── __tests__/
│ └── renderScreens.spec.tsx # Render test file for pages
│
├── pages/ # Directory containing the pages to be tested
│ ├── Home.tsx # Example page: Home
│ ├── About.tsx # Example page: About
│ ├── Contact.tsx # Example page: Contact
│ └── ... # Other project pages
Source:
import { globSync } from 'glob';
import { render } from '@testing-library/react';
import path from 'path';
const screensPath = path.resolve(__dirname, '../pages');
const screensPattern = `${screensPath}/**/*.tsx`;
const screensIgnorePattern = '**/_*.tsx';
const getScreens = () => {
try {
const screenFiles = globSync(screensPattern, {
ignore: [screensIgnorePattern],
});
return screenFiles.map((filePath) => {
const relativePath = path.relative(screensPath, filePath);
const component = require(filePath).default;
return {
name: relativePath,
component,
};
});
} catch (e) {
console.log('Error fetching files:', e);
return [];
}
};
const screens = getScreens();
test.each(screens.map(({ name, component: Screen }) => [name, Screen]))(
'Render screen: %s',
(_, Screen) => {
render(<Screen />);
},
);
Output:
Code Explanation
- getScreens(): This function uses globSync to synchronously search for all .tsx files in the /pages directory and its subdirectories. It returns a list of objects, each containing the file name and the corresponding component.
- screens: A constant that stores the result of the getScreens function, containing all the pages that will be tested.
- test.each(): A method that runs the render test for each page. It passes the page name and component to the test function, ensuring that all pages render correctly.
Final Considerations
This automated testing method ensures that all your landing pages are rendered correctly, without the need to create individual tests for each page. This saves time and resources, while also ensuring that users have a consistent experience when visiting your pages.
Use this article as a base to adapt the tests to your project's needs, and always carefully test the implementation.
Top comments (11)
I'm not sure how much I like this. I think a lot but maybe a little. Perhaps my one issue is that a render test is the least amount of testing. Snapshot tests for each screen would add an acceptable level of coverage.
And that’s exactly the problem we want to avoid—creating a test for each page when the content is static and completely different from each other is impractical. How would you test over 1000 pages like this?
Assuming you're using Jest, adding "snapshot testing" is trivial, but will provide much better coverage. Something like:
This will take a "snapshot" of the the render output, and ensure it doesn't unexpectedly change.
But wouldn't this mean you'd have a huge snapshot, namely the whole DOM for a page? Every time you change something, you'd need to look into the test and then update it.
You're right about that. You can configure Jest to generate separate snapshot files by creating what Jest calls a "snapshot resolver."
Then you tell Jest to use your snapshot resolver in your Jest config file (
jest.config.js
):And updating all of those snapshots is as easy as running
jest -u
.This looks useful!!!
Great post!
Snapshots shouldn't be used to test. These only tell you that something rendered without a probable problem, but it doesn't convey any information about something. For example, it wouldn't tell you if a hero image is rendered on the top or in the middle, which I think you would like to test.
You probably read that somewhere or heard it from a more senior dev, but it's wrong. Snapshots should absolutely be used to test. They just shouldn't be your only test, as they test at one of the highest possible scopes for a component, but it is the best way to test
render
, which is a unit that needs to be tested. Regardless, snapshot testing will at least provide better coverage than him simply checking if the component renders without error since he can't feasibly do specific unit tests.How did you get so many likes and saves on your first post? 😂
Ok interesting, have to check it out!