2.0.0 • Published 1 year ago

svelte-component-double v2.0.0

Weekly downloads
96
License
MIT
Repository
github
Last release
1 year ago

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.

MatcherDescription
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 ofdocument.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/functionTypeDescription
instancesArray of instancesEach instance of the component that has been rendered.
reset()FunctionResets a mocked component between tests. Call this in your beforeEach block.
selector()FunctionSelector for all instances of this double.
instanceSelector(n)FunctionSelector for a single instances of this double.
findMatching(matchFn)FunctionFind the call whose props match the matchFn predicate
firstInstance()FunctionReturns the first instance of a component, which you an then manipulate using functions such as updateBoundValue (see note above).
lastInstance()FunctionReturns the last instance of a component.
getInstanceFromElement(domElement)FunctionReturns the component instance that rendered the given DOM element.
mountedInstances()FunctionReturns only the instances that are currently rendered in the DOM.
propsOfAllInstances()FunctionReturns an array for props for each of the rendered instance of this component.
dispatch(event)FunctionDispatches 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.

2.0.0

1 year ago

0.8.0

3 years ago

0.7.5

4 years ago

0.7.4

4 years ago

0.7.3

4 years ago

0.7.1

4 years ago

0.7.0

4 years ago

0.6.2

4 years ago

0.6.1

4 years ago

0.6.0

4 years ago

0.5.0

4 years ago

0.5.1

4 years ago

0.4.0

4 years ago

0.3.0

4 years ago

0.2.0

4 years ago

0.1.0

4 years ago