describe('TodoItem snapshot test', () => { it('first render', () => { const wrapper = shallowMount(TodoItem, { propsData: { item: { finished: true, content: 'test TodoItem' } } }) expect(wrapper.html()).toMatchSnapshot() }) it('toggle checked', () => { const renderer = createRenderer(); const wrapper = shallowMount(TodoItem, { propsData: { item: { finished: true, content: 'test TodoItem' } } }) const checkbox = wrapper.find('input'); checkbox.trigger('click'); renderer.renderToString(wrapper.vm, (err, str) => { expect(str).toMatchSnapshot() }) }) it('mouseover', () => { const renderer = createRenderer(); const wrapper = shallowMount(TodoItem, { propsData: { item: { finished: false, content: 'test TodoItem' } } }) wrapper.trigger('mouseover'); renderer.renderToString(wrapper.vm, (err, str) => { expect(str).toMatchSnapshot() }) }) })
这里有三个测试。第二个测试模拟checkbox点击,将Todo项从已完成切换到未完成,期待类todo-finished会被移除。第三个测试在未完成Todo项上模拟鼠标悬浮,触发mouseover事件,期待删除按钮会展示。
这里使用toMatchSnapshot()来进行匹配快照。这里生成快照文件所需的HTML字符串有wrapper.html()和Renderer.renderToString这两种方式,区别在于前者是同步获取,后者是异步获取。
测试模拟事件时,最好以异步方式获取HTML字符串。同步方式获取的字符串并不一定是UI更新后的视图。
尽管VTU文档中说所有的更新都是同步,但实际上在第二个快照测试中,如果使用expect(wrapper.html()).toMatchSnapshot(),生成的快照文件中Todo项仍有类todo-finished,期待的结果应该是没有类todo-finished,结果并非更新后的视图。而在第三个快照测试中,使用expect(wrapper.html()).toMatchSnapshot()生成的快照,按钮如期望展示,是UI更新后的视图。所以才不建议在DOM更新的情况下使用wrapper.html()获取HTML字符串。
下面是两种对比的结果,1是使用wrapper.html()生成的快照,2是使用Renderer.renderToString生成的。
exports[`TodoItem snapshot test mouseover 1`] = `<li><input type="checkbox"> <span>test TodoItem</span> <button>delete</button></li>`; exports[`TodoItem snapshot test mouseover 2`] = `<li><input type="checkbox"> <span>test TodoItem</span> <button>delete</button></li>`; exports[`TodoItem snapshot test toggle checked 1`] = `<li><input type="checkbox"> <span>test TodoItem</span> <button>delete</button></li>`; exports[`TodoItem snapshot test toggle checked 2`] = `<li><input type="checkbox"> <span>test TodoItem</span> <button>delete</button></li>`;
这里使用vue-server-renderer提供的createRenderer来生成一个Renderer实例,实例方法renderToString来获取HTML字符串。这种是典型的回调风格,断言语句在回调中执行即可。
// ... wrapper.trigger('mouseover'); renderer.renderToString(wrapper.vm, (err, str) => { expect(str).toMatchSnapshot() })
如果不想使用这个库,也可以使用VTU中提供的。由于wrapper.html()是同步获取,所以获取操作及断言语句需要在Vue.nextTick()返回的Promise中执行。
// ... wrapper.trigger('mouseover'); Vue.nextTick().then(()=>{ expect(wrapper.html()).toMatchSnapshot() })
观察测试结果
执行npm run test:unit或yarn test:unit运行测试。
初次执行,终端输出会有Snapshots: 3 written, 3 total这一行,表示新增三个快照测试,并生成初始快照文件。
› 3 snapshots written. Snapshot Summary › 3 snapshots written from 1 test suite. Test Suites: 1 passed, 1 total Tests: 7 passed, 7 total Snapshots: 3 written, 3 total Time: 2.012s Ran all test suites. Done in 3.13s.
快照文件如下示:
// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`TodoItem snapshot test first render 1`] = `<li><input type="checkbox"> <span>test TodoItem</span> <button>delete</button></li>`; exports[`TodoItem snapshot test mouseover 1`] = `<li><input type="checkbox"> <span>test TodoItem</span> <button>delete</button></li>`; exports[`TodoItem snapshot test toggle checked 1`] = `<li><input type="checkbox"> <span>test TodoItem</span> <button>delete</button></li>`;
第二次执行测试后,输出中有Snapshots: 3 passed, 3 total,表示有三个快照测试成功通过,总共有三个快照测试。
Test Suites: 1 passed, 1 total Tests: 7 passed, 7 total Snapshots: 3 passed, 3 total Time: 2s Ran all test suites. Done in 3.11s.