svelte-component-double
v2.1.0
Published
A test double for Svelte 3 components
Downloads
2,127
Readme
svelte-component-double
An test double for Svelte components. It works with Vitest, Jest and Jasmine.
Installation
First install the package:
npm install --save-dev svelte-component-double
Vitest setup & usage
Create a file in your Vite project, named test/registerSvelteComponentDouble.js
, with the followig content:
import { expect } from 'vitest';
import * as matchers from 'svelte-component-double/vitest';
expect.extend(matchers);
import { componentDouble } from 'svelte-component-double';
globalThis.componentDouble = componentDouble;
Then update your vi.config.js
file to include this as a setup file for Vitest:
const config = {
...,
test: {
...,
setupFiles: [
...,
'./test/registerSvelteComponentDouble.js'
]
}
}
Then you can begin to write mocked tests like this:
import {
describe,
it,
expect,
beforeEach,
vi
} from 'vitest';
import {
render,
screen
} from '@testing-library/svelte';
import Child from './Child.svelte';
import Parent from './Parent.svelte';
vi.mock('./Child.svelte', async () => ({
default: componentDouble('Child')
}));
describe('Parent component', () => {
beforeEach(Child.reset);
it('renders a Child with the right props', () => {
render(Parent);
expect(Child).toBeRenderedWithProps({
foo: "bar"
});
});
});
Since mocks are active for the entire module, you may wish to place mocked tests in a separate test file e.g. parent.mocks.test.js
, keeping parent.test.js
free for non-mocked tests.
Jasmine setup & usage
Add the following helper in spec/support/jasmine.json
.
"helpers": [
"../node_modules/svelte-component-double/lib/matchers/jasmine.js"
]
You'll need to use a mocking tool like babel-plugin-rewire-exports.
In the example below, Parent
is the component under test, and Child
is being spied on.
import Child, { rewire as rewire$Child, restore } from '../src/Child.svelte';
import Parent from '../src/Parent.svelte';
import { componentDouble } from 'svelte-component-double';
describe('Parent component', () => {
it('renders a Child', () => {
// ensure JSDOM is set up and ready to go
rewire$Child(componentDouble(Child));
const el = document.createElement('div');
new Parent({ target: el });
expect(Child).toHaveBeenCalled();
expect(el.querySelector(spySelector(Child))).not.toBeNull();
});
});
Matchers
The expect(component)
function has the following matchers available.
| Matcher | Description |
| -------- | ----------- |
| toBeRendered()
| Passes if there was at least one instance of the component instantiated in the current document. |
| toBeRenderedIn(container)
| Same but with a specific DOM container instead of | document.body
. |
| toBeRenderedWithProps(props)
| Passes if there was at least one instance of the component instantiated with these exact props. |
| toBeRenderedWithPropsIn(props, container)
| Same as above but with a specic DOM container instead of document.body
. |
Identifying stubbed DOM elements
A spied/stubbed component will be rendered into the DOM like this:
<div class="spy-ComponentName" id="spy-ComponentName-instanceNumber" />
You can use the selector
function to return a selector that will match all instances of a rendered double. So for the example above, calling spySelector(Child)
will return "div[class=spy-Child]"
.
You can use the instanceSelector(n)
to return a selector that matches a specific instance of the component.
Triggering two-way bindings
If your stubbed component uses a two-way binding you can trigger that binding to update using the updateBoundValue
function.
For example, say you have the component TagList
which can be used like this:
<TagList bind:tags={tags} />
Then you can test how your component responds to updates to tags
like this:
rewire$TagList(componentDouble(TagList));
mount(<your component that uses TagList>);
TagList.firstInstance().updateBoundValue(
component, "tags", ["a", "b", "c"]);
Warning: updateBoundValue
has been tested with Svelte version 3.16. It is incompatible with 3.15 and below.
Component property reference
All of these functions are available on your component double type.
| Property/function | Type | Description |
| ----------------- | ---- | ----------- |
| instances
| Array of instances | Each instance of the component that has been rendered. |
| reset()
| Function | Resets a mocked component between tests. Call this in your beforeEach
block. |
| selector()
| Function | Selector for all instances of this double. |
| instanceSelector(n)
| Function | Selector for a single instances of this double. |
| findMatching(matchFn)
| Function | Find the call whose props match the matchFn
predicate |
| firstInstance()
| Function | Returns the first instance of a component, which you an then manipulate using functions such as updateBoundValue
(see note above). |
| lastInstance()
| Function | Returns the last instance of a component. |
| getInstanceFromElement(domElement)
| Function | Returns the component instance that rendered the given DOM element. |
| mountedInstances()
| Function | Returns only the instances that are currently rendered in the DOM. |
| propsOfAllInstances()
| Function | Returns an array for props for each of the rendered instance of this component.|
| dispatch(event)
| Function | Dispatches an event to the last rendered component. You can also call dispatch
on individual instances. |
Contributing
All contributions are welcome. Please feel free to create issues or raise PRs.