Type of tests
We have a few type of tests:
- static code analysis (eslint)
- type tests (TypeScript)
- unit/integration (Jest & @testing-library/vue)
- e2e (Cypress)
- manual testing
Getting started with Unit testing
Approach
- Test application from a user perspective and hide implementation details in tests.
- Focus on
theme
package testing - Write data-driven tests
- Use
describe
block to group tests - Use
it
function to write test cases
Toolset
Tools that we use for unit testing:
- Vue testing library (opens new window)
- Jest (opens new window)
- jest-dom (opens new window)
- user-event (opens new window)
- TestingPlayground (opens new window)
Before start
We recommend reading these articles before starting writing unit tests:
- Testing implementation details (opens new window)
- Avoid nesting during testing (opens new window)
- AHA programming (opens new window)
Custom render method
We have custom render
method built on top of testing library render (opens new window) method.
function render(Component, options, callbackFunction) {
return {
...DOMTestingLibraryQueries,
container,
baseElement,
debug,
unmount,
isUnmounted,
html,
emitted,
updateProps,
}
}
Parameters
Take a look at the description of parameters that render
function has:
Component
The valid Vue Component to be tested.
Options
An object containing additional information to be passed to @vue/test-utils mount (opens new window).
Read more about options here (opens new window).
callbackFunction
function callbackFunction(vueInstance, vuexStore, router) {}
A callback function that receives the Vue instance as a parameter. Its return value is merged with options, allowing 3rd party plugins to be installed prior to mount. To see how this works, see the example using vue-i18n (opens new window).
Example of use
import { render } from '~/test-utils';
import ComponmentToTest from '../ComponentToTest';
test('Should display Hello world', () => {
const { getByText } = render(ComponmentToTest);
expect(getByText('Hello world')).toBeInTheDocument();
});
Passing props
const { getByText } = render(Component, {
props: {
myProps: true,
},
});
Passing mocks
const $mock = jesyt.fn();
const { getByText } = render(Component, {
mocks: {
$mock
},
});
How to add test
Let's imagine that you want to test packages/theme/components/CartSidebar.vue
component.
- Add
CartSidebar.spec.js
file topackages/theme/components/__tests__
directory - If
__tests__
directory does not exist, please create a new one - Add
describe
block and tests inside it.
Rules:
- Each test file should have
*.spec.js
prefix - Each test file should be placed inside
__tests__
directory
Mocking
Our approach assuming mock composable in unit tests.
To do so you can use existing mocks that are exported from ~/test-utils
.
You can find them in packages/theme/test-utils/mocks
directory
In case when you can find existing mock, please create a new one:
- Add file with mock in
packages/theme/test-utils/mocks
directory - Re-export the mock in
packages/theme/test-utils/mocks/index.js
file
Example of use mock in test
import { useGuestUser, useUser } from '@vue-storefront/magento';
import { render, useUserMock, useGuestUserMock } from '~/test-utils';
import UserAccount from '../UserAccount'; // component to test
jest.mock('@vue-storefront/magento', () => ({
useGuestUser: jest.fn(),
useUser: jest.fn(),
}));
test('Email should be validated', async () => {
useUser.mockReturnValue(useUserMock());
useGuestUser.mockReturnValue(useGuestUserMock());
// (...)
});
Extending default mock
You can extend default mock by passing an object with props that you want to extend as a argument to mock function:
const attachToCartMock = jest.fn();
useGuestUser.mockReturnValue(useGuestUserMock({
attachToCart: attachToCartMock,
}));
Mocking other modules
Sometimes you need to extend some external composables, or extend only one composable returned by whole package. Here is the recipe:
jest.mock('@nuxtjs/composition-api', () => {
// Require the original module to not be mocked...
const originalModule = jest.requireActual('@nuxtjs/composition-api');
return {
...originalModule,
useRouter: jest.fn(),
};
});
Setup
In case when something should be set-up before test running, you should use packages/theme/jest-setup.js
file.
Take a look at the current implementation:
import '@testing-library/jest-dom';
import Vue from 'vue';
Vue.directive('e2e', {});
Sample test files
Please take a look at these test files to see the aproach:
packages/theme/pages/Checkout/__tests__/UserAccount.spec.js
packages/theme/components/__tests__/AddtoWishlist.spec.js