Mocking Capacitor Plugins
When creating unit tests within your application, it is a best practice to create mocks for any external dependency to the unit that is under test. This includes Capacitor plugins that your component or service is using.
Most mocking libraries create mocks by taking an object and wrapping it in a JavaScript proxy so calls to the methods on that object can be examined and the return values of the methods can be controlled. Capacitor plugins, however, are implemented within the JavaScript layer as proxies. Creating a proxy of a proxy is not supported and fails. Manual mocks can be used to circumvent this issue.
Manual Mocks
Manual mocks allow the user to easily stub the functionality of an entire JavaScript module. As a result, when the tests do an import { Storage } from '@capacitor/storage', instead of loading the real Storage JavaScript proxy object, the tests would load something like this:
export const Storage = {
async get(data: { key: string }): Promise<{ value: string | undefined }> {
return { value: undefined };
},
async set(data: { key: string; value: string }): Promise<void> {},
async clear(): Promise<void> {},
};
Since this is a plain JavaScript object and not a proxy object, it is very easy to spy on. Also, since it is a mock it does not try to make any native calls. This makes the use of manual mocks an ideal choice to use when testing code that uses Capacitor plugins.
Jest
The Jest testing framework has manual mocks built in to it. Create a __mocks__/@capacitor folder at the root of your project, and Jest will automatically load files from there rather than from node_modules.
For example, let's say you have the following directory structure:
.
|
+- __mocks__
| |
| +- @capacitor
| |
| +- storage.ts
| +- toast.ts
...
+- src
Your tests will use the stubs defined in storage.ts and toast.ts rather than the real @capacitor/storage and @capacitor/toast plugins from node_modules.