Skip to content

Commit 096fc72

Browse files
committed
chore: resolve conflicts
2 parents b4409b6 + 6dc4c64 commit 096fc72

File tree

4 files changed

+126
-1
lines changed

4 files changed

+126
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ text | ✅ |
8787
trigger | ✅ | returns `nextTick`. You can do `await wrapper.find('button').trigger('click')`
8888
setProps | ✅ |
8989
props | ✅
90-
setData | ❌ | has PR
90+
setData | ✅ |
9191
destroy | ✅ | renamed to `unmount` to match Vue 3 lifecycle hook name.
9292
props | ✅
9393
contains | ⚰️| use `find`

src/utils.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,31 @@ export function mergeGlobalProperties(
3636
directives: { ...configGlobal.directives, ...mountGlobal.directives }
3737
}
3838
}
39+
40+
// https://stackoverflow.com/a/48218209
41+
export const mergeDeep = (
42+
target: Record<string, any>,
43+
source: Record<string, any>
44+
) => {
45+
const isObject = (obj: unknown): obj is Object =>
46+
obj && typeof obj === 'object'
47+
48+
if (!isObject(target) || !isObject(source)) {
49+
return source
50+
}
51+
52+
Object.keys(source).forEach((key) => {
53+
const targetValue = target[key]
54+
const sourceValue = source[key]
55+
56+
if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
57+
target[key] = targetValue.concat(sourceValue)
58+
} else if (isObject(targetValue) && isObject(sourceValue)) {
59+
target[key] = mergeDeep(Object.assign({}, targetValue), sourceValue)
60+
} else {
61+
target[key] = sourceValue
62+
}
63+
})
64+
65+
return target
66+
}

src/vueWrapper.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { FindAllComponentsSelector, FindComponentSelector } from './types'
77
import { createWrapperError } from './errorWrapper'
88
import { TriggerOptions } from './createDomEvent'
99
import { find, matches } from './utils/find'
10+
import { mergeDeep } from './utils'
1011

1112
export class VueWrapper<T extends ComponentPublicInstance> {
1213
private componentVM: T
@@ -205,6 +206,11 @@ export class VueWrapper<T extends ComponentPublicInstance> {
205206
return Array.from(results).map((element) => new DOMWrapper(element))
206207
}
207208

209+
setData(data: Record<string, any>): Promise<void> {
210+
mergeDeep(this.componentVM.$data, data)
211+
return nextTick()
212+
}
213+
208214
setProps(props: Record<string, any>): Promise<void> {
209215
// if this VM's parent is not the root or if setProps does not exist, error out
210216
if (this.vm.$parent !== this.rootVM || !this.__setProps) {

tests/setData.spec.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { defineComponent, ref } from 'vue'
2+
3+
import { mount } from '../src'
4+
5+
describe('setData', () => {
6+
it('sets component data', async () => {
7+
const Component = {
8+
template: '<div>{{ foo }}</div>',
9+
data: () => ({ foo: 'bar' })
10+
}
11+
12+
const wrapper = mount(Component)
13+
expect(wrapper.html()).toContain('bar')
14+
15+
await wrapper.setData({ foo: 'qux' })
16+
expect(wrapper.html()).toContain('qux')
17+
})
18+
19+
it('causes nested nodes to re-render', async () => {
20+
const Component = {
21+
template: `<div><div v-if="show" id="show">Show</div></div>`,
22+
data: () => ({ show: false })
23+
}
24+
25+
const wrapper = mount(Component)
26+
27+
expect(wrapper.find('#show').exists()).toBe(false)
28+
29+
await wrapper.setData({ show: true })
30+
31+
expect(wrapper.find('#show').exists()).toBe(true)
32+
})
33+
34+
it('updates a single property of a complex object', async () => {
35+
const Component = {
36+
template: `<div>{{ complexObject.string }}. bar: {{ complexObject.foo.bar }}</div>`,
37+
data: () => ({
38+
complexObject: {
39+
string: 'will not change',
40+
foo: {
41+
bar: 'old val'
42+
}
43+
}
44+
})
45+
}
46+
47+
const wrapper = mount(Component)
48+
49+
expect(wrapper.html()).toContain('will not change. bar: old val')
50+
51+
await wrapper.setData({
52+
complexObject: {
53+
foo: {
54+
bar: 'new val'
55+
}
56+
}
57+
})
58+
59+
expect(wrapper.html()).toContain('will not change. bar: new val')
60+
})
61+
62+
it('does not set new properties', async () => {
63+
jest.spyOn(console, 'warn').mockImplementationOnce(() => {})
64+
65+
const Component = {
66+
template: `<div>{{ foo || 'fallback' }}</div>`
67+
}
68+
69+
const wrapper = mount(Component)
70+
71+
expect(wrapper.html()).toContain('fallback')
72+
73+
expect(() => wrapper.setData({ foo: 'bar' })).toThrowError(
74+
'Cannot add property foo'
75+
)
76+
})
77+
78+
it('does not modify composition API setup data', async () => {
79+
const Component = defineComponent({
80+
template: `<div>Count is: {{ count }}</div>`,
81+
setup: () => ({ count: ref(1) })
82+
})
83+
const wrapper = mount(Component)
84+
85+
expect(wrapper.html()).toContain('Count is: 1')
86+
87+
expect(() => wrapper.setData({ count: 2 })).toThrowError(
88+
'Cannot add property count'
89+
)
90+
})
91+
})

0 commit comments

Comments
 (0)