-
Notifications
You must be signed in to change notification settings - Fork 1
Testing
We have evaluated several testing frameworks and have decided to use different testing framework for both FrontEnd and Backend. FrontEnd uses Vitest and Backend uses Jest. More information about our Architecture Decision will be displayed in Architectural Decision Log
FrontEnd uses Vitest as its testing framework due to it being a Vite-Native testing Framework. It is a testing framework that is based on Jest but it reuses Vite's Config and plugins.
- Vitest uses Vite's conig and plugins, making it consistent across the app.
- It is Jest Compatible
- It reruns the related changes that you did. For example, changes on a component only triggers the test that is coupled with.
- Out-of-box ESM, TypeScript and JSX support powered by esbuild.
Go to project directory
cd /path/of/directory
Install Vitest
npm install -D vitest
Add Vitest in your scripts
test: Vitest
Create a vitest.config.ts in the root directory of your application.
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: './src/tests/setupTests.js',
},
});
environment: 'jsdom' simulate a browser-like environment in Node.js using jsdom. This is particularly useful for testing web applications as it provides a DOM implementation. setupFiles: './src/tests/setupTests.js' points to a JavaScript file that contains setup code for your tests. Such as configuring global variables, setting up mock functions, or initializing libraries that are required for your test.
Testing Health Check Component if it displays NMP API is Healthy and Ready!
HealthCheck.ts
import { useEffect, useState } from 'react';
import axios from 'axios';
const HealthCheck = () => {
const [status, setStatus] = useState(null);
useEffect(() => {
const backEndUrl = import.meta.env.VITE_BACKEND_URL;
const url = `${backEndUrl}/health`;
axios
.get(url)
.then((response) => {
console.log('Health Check data:', response.data);
setStatus(response.data);
})
.catch((error) => {
console.error('Error fetching data:', error);
});
}, []);
return (
<div>
<h1>Health Check</h1>
<h2>{status}</h2>
</div>
);
};
export default HealthCheck;
HealthCheck.test.ts
import { vi, describe, expect, it } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import axios from 'axios';
import HealthCheck from '../components/HealthCheck';
vi.mock('axios');
describe('HealthCheck Component', () => {
it('fetches and displays HealthCheck Component response data', async () => {
// Mocked data returned by the Axios Get request
const response = 'NMP API is healthy and ready!';
// Setup the mock to return the mocked data
vi.mocked(axios.get).mockResolvedValueOnce({ data: response });
render(<HealthCheck />);
// Wait for the healthcheck data to be fetched and displayed
await waitFor(() => {
expect(screen.getByText('NMP API is healthy and ready!')).toBeInTheDocument();
});
});
});
The Backend uses Jest, which seemed like the most popular testing solution for js/ts testing, which means there is a ton of community articles in support of it's usage and implementation. Since this is new to us, this seemed like as good of a choice as we could make.
Jest will be used for testing all of our endpoints, reinsuring proper implementation. When relying only in manual testing, one might be focused on testing parts of the application while neglecting others. With automated testing, we can ensure every commit checks all the backend endpoints, in a granular level, avoiding pushing bugs. It does add extra work for development, but this is a learning experience and the more tools we learn the better. Also, it might save time from having to go back and find bugs that could be caught with tests. It will also improve overall quality.
Jest is one of the most popular testing suites for TypeScript and we it seemed to to what we needed in straightforward way.
If you want to know more about Jest, here's a link on how to get started:
https://jestjs.io/docs/getting-started
This is our simplest test, covering our /health
endpoint:
/backend/src/test/health.test.ts
import testRequest from './testRequest';
describe('Test the health path', () => {
test('returns status code 200 if healthy', async () => {
const res = await testRequest.get('/health');
expect(res.statusCode).toEqual(200);
expect(res.text).toBe('BetterBerries API is healthy and ready!');
});
});
Note the test should cover both the status and any data contained in the response. This ensures we're not giving false positives back to requests.
You can execute the test script, running all tests in the backend/src/test directory, with npm run test
.
We decided to implement Husky for testing, formatting and linting execution upon git hooks. Since it's a pretty thorough test and takes a minute, it's currently triggered by a push hook.
Our repo root is not a node project, so we had to install husky in either frontend or backend. We chose the backend. It switches between the backend and frontend folders to execute the required scripts.
cd frontend
npm run test
npm run format
npm run lint
cd ../backend
npm run test
npm run format
npm run lint
This is really cool because we can ensure our code is always formatted, linted and tested before we push it to our remote branches.
Husky Pre-push execution
Husky failed execution