Skip to content

Commit

Permalink
fix(rerender): Do not mount component again on rerender (#199)
Browse files Browse the repository at this point in the history
* Do not mount component again on rerender

* Remove leftover
  • Loading branch information
afontcu committed Jan 8, 2021
1 parent 94f57f8 commit ca5f32c
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 37 deletions.
23 changes: 11 additions & 12 deletions src/__tests__/rerender.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,24 @@ import NumberDisplay from './components/NumberDisplay'
// 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', () => {
test('rerender re-renders the element', async () => {
const {rerender, getByTestId} = render(NumberDisplay, {
props: {number: 1},
})

expect(getByTestId('number-display')).toHaveTextContent('1')

rerender({props: {number: 3}})
await rerender({number: 3})
expect(getByTestId('number-display')).toHaveTextContent('3')

rerender({props: {number: 5}})
await rerender({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')
// Notice we don't remount a different instance
expect(getByTestId('instance-id')).toHaveTextContent('1')
})

test('rerender works with composition API', () => {
test('rerender works with composition API', async () => {
const Component = defineComponent({
props: {
foo: {type: String, default: 'foo'},
Expand All @@ -43,11 +42,11 @@ test('rerender works with composition API', () => {

const {rerender, getByTestId} = render(Component)

const originalNode = getByTestId('node')
expect(originalNode).toHaveTextContent('Foo is: foo. Foobar is: foo-bar')
const getContent = () => getByTestId('node')

rerender({props: {foo: 'qux'}})
expect(getContent()).toHaveTextContent('Foo is: foo. Foobar is: foo-bar')

const newNode = getByTestId('node')
expect(newNode).toHaveTextContent('Foo is: qux. Foobar is: qux-bar')
await rerender({foo: 'qux'})

expect(getContent()).toHaveTextContent('Foo is: qux. Foobar is: qux-bar')
})
39 changes: 14 additions & 25 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
const mountedWrappers = new Set()

function render(
TestComponent,
Component,
{
store = null,
routes = null,
Expand Down Expand Up @@ -41,26 +41,20 @@ function render(
plugins.push(routerPlugin)
}

const mountComponent = (Component, newProps) => {
const wrapper = mount(
Component,
merge({
attachTo: container,
global: {plugins},
...mountOptions,
props: newProps || mountOptions.props,
}),
)

// 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)
const wrapper = mount(
Component,
merge({
attachTo: container,
global: {plugins},
...mountOptions,
}),
)

mountedWrappers.add(wrapper)
return wrapper
}
// 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)

let wrapper = mountComponent(TestComponent)
mountedWrappers.add(wrapper)

return {
container,
Expand All @@ -72,12 +66,7 @@ function render(
unmount: () => wrapper.unmount(),
html: () => wrapper.html(),
emitted: () => wrapper.emitted(),
rerender: ({props}) => {
wrapper.unmount()
mountedWrappers.delete(wrapper)

wrapper = mountComponent(TestComponent, props)
},
rerender: props => wrapper.setProps(props),
...getQueriesForElement(baseElement),
}
}
Expand Down

0 comments on commit ca5f32c

Please sign in to comment.