Unit testing
info
As microfrontends gain widespread adoption, testing tools will catch up and the testing story will improve.
Unit testing a single-spa application, parcel, or utility is very similar to unit testing in the framework you are using, with two notable exceptions:
- Importing microfrontends
System.import
In general we recommend following the principle of only testing the units that need to be tested and aren't covered by other tests. Testing library code like single-spa.registerApplication
is usually unnecessary because those are covered by the library's unit tests.
#
Importing microfrontendsIt is fairly common in microfrontends to have one microfrontend import and rely upon a component from another microfrontend. Reliance on another microfrontend can be challenging to test because unit tests generally run locally and you won't have access to other microfrontends. When this occurs we generally recommend mocking the other microfrontend for the unit test.
An example of this can be found in the Button
component exported by the styleguide
in react.microfrontends.app. Because that component is imported and used by the planets application you will need to make it available to the test environment by mocking the dependency. This is necessary because the test environment cannot dynamically import other microfrontends, like the browser can. Given the wide variety of unit testing tools you will need to follow the pattern established by the test environment you are using for mocking other microfrontends.
note
We suggest mocks over installing microfrontends for local tests (for example via NPM modules) because mocks are easier to maintain and avoid several potential incompatiblity issues such as version mismatch, module format incompatibility, environment differences, and more.
System.import
#
Occasionally you will choose to interop with another microfrontend asynchronously by explicitly calling System.import
. Testing in this scenairo may require mocking both SystemJS and the module you're importing. Additionally because System.import
returns a promise your tests in that area will need to be asynchronous and wait for promises to resolve.
An example of this can be found in people
and planets
applications from react.microfrontends.app
. The People application exports a function that resolves with a component. The Planets Application imports and uses that component asynchronously with React.lazy
. Testing this component would necessitate mocking both SystemJS
and People
.
#
Shared MocksIf each project mocks every other microfrontend it is possible that the mocks will eventually become out of sync with the actual deployed microfrontend. One way to prevent this is to share mocks so that keeping the mocks in sync only requires one change instead of updating mocks in many different repositories.
#
Testing examples#
JestIn the above examples I showed how People
imports a component from styleguide
. In order to unit test the component in people with Jest you will need to configure jest and mock the styleguide
MFE. In jest configuration is done via multiple areas.
#
Jest configJest is configured with a configuration file. Below is an example configuration using some of the options. See more options on Jest's official documentation site.
#
mocks directoryJest will detect folders named __mocks__
and if the naming convention is exact or the modules have been mapped using moduleNameMapper
then Jest will use those mocks in place of an import. This structure is essential for other microfrontends where you don't have the code locally. See more information on jest's official documentation
#
setup fileJest uses a setup file to create globals mocks that can be utilized by every test or otherwise configure the test environment. If you were mocking localStorage
or SystemJS
this is a good place to configure those mocks. See more use-cases for a set-up file on Jest's offical documentation