diff --git a/src/__tests__/rerender.js b/src/__tests__/rerender.js new file mode 100644 index 00000000..5951870c --- /dev/null +++ b/src/__tests__/rerender.js @@ -0,0 +1,53 @@ +import '@testing-library/jest-dom' +import {defineComponent, h, computed} from 'vue' +import {render} from '@testing-library/vue' +import NumberDisplay from './components/NumberDisplay' + +// It'd probably be better if you test the component that's doing the rerendering +// to ensure that the rerendered component is being updated correctly. +// That said, if you'd prefer to, for example, update the props of a rendered +// component, this function can be used to do so. +test('calling rerender remounts the component and updates the props', () => { + const {rerender, getByTestId} = render(NumberDisplay, { + props: {number: 1}, + }) + + expect(getByTestId('number-display')).toHaveTextContent('1') + + rerender({props: {number: 3}}) + expect(getByTestId('number-display')).toHaveTextContent('3') + + rerender({props: {number: 5}}) + expect(getByTestId('number-display')).toHaveTextContent('5') + + // Assert that, after rerendering and updating props, the component has been remounted, + // meaning we are testing a different component instance than we rendered initially. + expect(getByTestId('instance-id')).toHaveTextContent('3') +}) + +test('rerender works with composition API', () => { + const Component = defineComponent({ + props: { + foo: {type: String, default: 'foo'}, + }, + setup(props) { + const foobar = computed(() => `${props.foo}-bar`) + return () => + h( + 'div', + {'data-testid': 'node'}, + `Foo is: ${props.foo}. Foobar is: ${foobar.value}`, + ) + }, + }) + + const {rerender, getByTestId} = render(Component) + + const originalNode = getByTestId('node') + expect(originalNode).toHaveTextContent('Foo is: foo. Foobar is: foo-bar') + + rerender({props: {foo: 'qux'}}) + + const newNode = getByTestId('node') + expect(newNode).toHaveTextContent('Foo is: qux. Foobar is: qux-bar') +}) diff --git a/src/__tests__/set-props.js b/src/__tests__/set-props.js deleted file mode 100644 index 48fe37fc..00000000 --- a/src/__tests__/set-props.js +++ /dev/null @@ -1,51 +0,0 @@ -import '@testing-library/jest-dom' -import {defineComponent, h, computed} from 'vue' -import {render} from '@testing-library/vue' -import NumberDisplay from './components/NumberDisplay' - -// It'd probably be better if you test the component that's doing the prop -// updating to ensure that the props are being updated correctly. -// That said, if you'd prefer to update the props of a rendered component, this -// function can be used to update props of the rendered component. -test('calling render with the same component but different props does not remount', async () => { - const {getByTestId, setProps} = render(NumberDisplay, { - props: {number: 1}, - }) - - expect(getByTestId('number-display')).toHaveTextContent('1') - - await setProps({number: 2}) - - expect(getByTestId('number-display')).toHaveTextContent('2') - - // Assert that, even after updating props, the component hasn't remounted, - // meaning we are testing the same component instance we rendered initially. - expect(getByTestId('instance-id')).toHaveTextContent('1') -}) - -test('works with composition API', async () => { - const Component = defineComponent({ - props: { - foo: {type: String, default: 'foo'}, - }, - setup(props) { - const foobar = computed(() => `${props.foo}-bar`) - return () => - h( - 'div', - {'data-testid': 'node'}, - `Foo is: ${props.foo}. Foobar is: ${foobar.value}`, - ) - }, - }) - - const {setProps, getByTestId} = render(Component) - - const node = getByTestId('node') - - expect(node).toHaveTextContent('Foo is: foo. Foobar is: foo-bar') - - await setProps({foo: 'qux'}) - - expect(node).toHaveTextContent('Foo is: qux. Foobar is: qux-bar') -}) diff --git a/src/vue-testing-library.js b/src/vue-testing-library.js index b46e92c2..36e86ac9 100644 --- a/src/vue-testing-library.js +++ b/src/vue-testing-library.js @@ -47,23 +47,29 @@ function render( // additionalOptions = configurationCb(router) // } - const wrapper = mount( - TestComponent, - merge({ - attachTo: container, - global: { - plugins, - }, - ...mountOptions, - // ...additionalOptions, - }), - ) - - // this removes the additional "data-v-app" div node from VTU: - // https://github.com/vuejs/vue-test-utils-next/blob/master/src/mount.ts#L196-L213 - unwrapNode(wrapper.parentElement) - - mountedWrappers.add(wrapper) + const mountComponent = (Component, newProps) => { + const wrapper = mount( + Component, + merge({ + attachTo: container, + global: { + plugins, + }, + ...mountOptions, + props: newProps || mountOptions.props, + // ...additionalOptions, + }), + ) + + // this removes the additional "data-v-app" div node from VTU: + // https://github.com/vuejs/vue-test-utils-next/blob/master/src/mount.ts#L196-L213 + unwrapNode(wrapper.parentElement) + + mountedWrappers.add(wrapper) + return wrapper + } + + let wrapper = mountComponent(TestComponent) return { container, @@ -73,7 +79,12 @@ function render( unmount: () => wrapper.unmount(), html: () => wrapper.html(), emitted: () => wrapper.emitted(), - setProps: props => wrapper.setProps(props), + rerender: ({props}) => { + wrapper.unmount() + mountedWrappers.delete(wrapper) + + wrapper = mountComponent(TestComponent, props) + }, ...getQueriesForElement(baseElement), } }