test: move mockWarn into setup files

This commit is contained in:
Evan You 2020-07-27 22:58:37 -04:00
parent d4527230e4
commit 5c74243211
35 changed files with 103 additions and 199 deletions

View File

@ -1,5 +1,6 @@
module.exports = { module.exports = {
preset: 'ts-jest', preset: 'ts-jest',
setupFilesAfterEnv: ['./scripts/setupJestEnv.ts'],
globals: { globals: {
__DEV__: true, __DEV__: true,
__TEST__: true, __TEST__: true,

View File

@ -7,12 +7,9 @@ import {
compileStyleAsync, compileStyleAsync,
SFCStyleCompileOptions SFCStyleCompileOptions
} from '../src/compileStyle' } from '../src/compileStyle'
import { mockWarn } from '@vue/shared'
import path from 'path' import path from 'path'
describe('SFC scoped CSS', () => { describe('SFC scoped CSS', () => {
mockWarn()
function compileScoped( function compileScoped(
source: string, source: string,
options?: Partial<SFCStyleCompileOptions> options?: Partial<SFCStyleCompileOptions>

View File

@ -13,3 +13,12 @@ declare var __VERSION__: string
declare var __FEATURE_OPTIONS_API__: boolean declare var __FEATURE_OPTIONS_API__: boolean
declare var __FEATURE_PROD_DEVTOOLS__: boolean declare var __FEATURE_PROD_DEVTOOLS__: boolean
declare var __FEATURE_SUSPENSE__: boolean declare var __FEATURE_SUSPENSE__: boolean
// for tests
declare namespace jest {
interface Matchers<R, T> {
toHaveBeenWarned(): R
toHaveBeenWarnedLast(): R
toHaveBeenWarnedTimes(n: number): R
}
}

View File

@ -1,10 +1,7 @@
import { reactive, effect, toRaw, isReactive } from '../../src' import { reactive, effect, toRaw, isReactive } from '../../src'
import { mockWarn } from '@vue/shared'
describe('reactivity/collections', () => { describe('reactivity/collections', () => {
describe('Map', () => { describe('Map', () => {
mockWarn()
test('instanceof', () => { test('instanceof', () => {
const original = new Map() const original = new Map()
const observed = reactive(original) const observed = reactive(original)

View File

@ -1,10 +1,7 @@
import { reactive, effect, isReactive, toRaw } from '../../src' import { reactive, effect, isReactive, toRaw } from '../../src'
import { mockWarn } from '@vue/shared'
describe('reactivity/collections', () => { describe('reactivity/collections', () => {
describe('Set', () => { describe('Set', () => {
mockWarn()
it('instanceof', () => { it('instanceof', () => {
const original = new Set() const original = new Set()
const observed = reactive(original) const observed = reactive(original)

View File

@ -7,11 +7,8 @@ import {
WritableComputedRef, WritableComputedRef,
isReadonly isReadonly
} from '../src' } from '../src'
import { mockWarn } from '@vue/shared'
describe('reactivity/computed', () => { describe('reactivity/computed', () => {
mockWarn()
it('should return updated value', () => { it('should return updated value', () => {
const value = reactive<{ foo?: number }>({}) const value = reactive<{ foo?: number }>({})
const cValue = computed(() => value.foo) const cValue = computed(() => value.foo)

View File

@ -1,11 +1,8 @@
import { ref, isRef } from '../src/ref' import { ref, isRef } from '../src/ref'
import { reactive, isReactive, toRaw, markRaw } from '../src/reactive' import { reactive, isReactive, toRaw, markRaw } from '../src/reactive'
import { mockWarn } from '@vue/shared'
import { computed } from '../src/computed' import { computed } from '../src/computed'
describe('reactivity/reactive', () => { describe('reactivity/reactive', () => {
mockWarn()
test('Object', () => { test('Object', () => {
const original = { foo: 1 } const original = { foo: 1 }
const observed = reactive(original) const observed = reactive(original)

View File

@ -10,7 +10,6 @@ import {
shallowReadonly, shallowReadonly,
isProxy isProxy
} from '../src' } from '../src'
import { mockWarn } from '@vue/shared'
/** /**
* @see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html * @see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html
@ -18,8 +17,6 @@ import { mockWarn } from '@vue/shared'
type Writable<T> = { -readonly [P in keyof T]: T[P] } type Writable<T> = { -readonly [P in keyof T]: T[P] }
describe('reactivity/readonly', () => { describe('reactivity/readonly', () => {
mockWarn()
describe('Object', () => { describe('Object', () => {
it('should make nested values readonly', () => { it('should make nested values readonly', () => {
const original = { foo: 1, bar: { baz: 2 } } const original = { foo: 1, bar: { baz: 2 } }

View File

@ -13,11 +13,8 @@ import {
getCurrentInstance, getCurrentInstance,
defineComponent defineComponent
} from '@vue/runtime-test' } from '@vue/runtime-test'
import { mockWarn } from '@vue/shared'
describe('api: createApp', () => { describe('api: createApp', () => {
mockWarn()
test('mount', () => { test('mount', () => {
const Comp = defineComponent({ const Comp = defineComponent({
props: { props: {

View File

@ -10,13 +10,9 @@ import {
reactive reactive
} from '../src/index' } from '../src/index'
import { render, nodeOps, serialize } from '@vue/runtime-test' import { render, nodeOps, serialize } from '@vue/runtime-test'
import { mockWarn } from '@vue/shared'
// reference: https://vue-composition-api-rfc.netlify.com/api.html#provide-inject // reference: https://vue-composition-api-rfc.netlify.com/api.html#provide-inject
describe('api: provide/inject', () => { describe('api: provide/inject', () => {
mockWarn()
it('string keys', () => { it('string keys', () => {
const Provider = { const Provider = {
setup() { setup() {

View File

@ -10,7 +10,6 @@ import {
ref, ref,
defineComponent defineComponent
} from '@vue/runtime-test' } from '@vue/runtime-test'
import { mockWarn } from '@vue/shared'
describe('api: options', () => { describe('api: options', () => {
test('data', async () => { test('data', async () => {
@ -705,8 +704,6 @@ describe('api: options', () => {
}) })
describe('warnings', () => { describe('warnings', () => {
mockWarn()
test('Expected a function as watch handler', () => { test('Expected a function as watch handler', () => {
const Comp = { const Comp = {
watch: { watch: {

View File

@ -14,13 +14,10 @@ import {
TrackOpTypes, TrackOpTypes,
TriggerOpTypes TriggerOpTypes
} from '@vue/reactivity' } from '@vue/reactivity'
import { mockWarn } from '@vue/shared'
// reference: https://vue-composition-api-rfc.netlify.com/api.html#watch // reference: https://vue-composition-api-rfc.netlify.com/api.html#watch
describe('api: watch', () => { describe('api: watch', () => {
mockWarn()
it('effect', async () => { it('effect', async () => {
const state = reactive({ count: 0 }) const state = reactive({ count: 0 })
let dummy let dummy

View File

@ -1,13 +1,10 @@
// Note: emits and listener fallthrough is tested in // Note: emits and listener fallthrough is tested in
// ./rendererAttrsFallthrough.spec.ts. // ./rendererAttrsFallthrough.spec.ts.
import { mockWarn } from '@vue/shared'
import { render, defineComponent, h, nodeOps } from '@vue/runtime-test' import { render, defineComponent, h, nodeOps } from '@vue/runtime-test'
import { isEmitListener } from '../src/componentEmits' import { isEmitListener } from '../src/componentEmits'
describe('component: emit', () => { describe('component: emit', () => {
mockWarn()
test('trigger handlers', () => { test('trigger handlers', () => {
const Foo = defineComponent({ const Foo = defineComponent({
render() {}, render() {},

View File

@ -10,11 +10,8 @@ import {
serializeInner serializeInner
} from '@vue/runtime-test' } from '@vue/runtime-test'
import { render as domRender, nextTick } from 'vue' import { render as domRender, nextTick } from 'vue'
import { mockWarn } from '@vue/shared'
describe('component props', () => { describe('component props', () => {
mockWarn()
test('stateful', () => { test('stateful', () => {
let props: any let props: any
let attrs: any let attrs: any

View File

@ -6,12 +6,9 @@ import {
createApp, createApp,
shallowReadonly shallowReadonly
} from '@vue/runtime-test' } from '@vue/runtime-test'
import { mockWarn } from '@vue/shared'
import { ComponentInternalInstance } from '../src/component' import { ComponentInternalInstance } from '../src/component'
describe('component: proxy', () => { describe('component: proxy', () => {
mockWarn()
test('data', () => { test('data', () => {
let instance: ComponentInternalInstance let instance: ComponentInternalInstance
let instanceProxy: any let instanceProxy: any

View File

@ -11,11 +11,8 @@ import {
watchEffect watchEffect
} from '@vue/runtime-test' } from '@vue/runtime-test'
import { setErrorRecovery } from '../src/errorHandling' import { setErrorRecovery } from '../src/errorHandling'
import { mockWarn } from '@vue/shared'
describe('error handling', () => { describe('error handling', () => {
mockWarn()
beforeEach(() => { beforeEach(() => {
setErrorRecovery(true) setErrorRecovery(true)
}) })

View File

@ -1,9 +1,7 @@
import { renderSlot } from '../../src/helpers/renderSlot' import { renderSlot } from '../../src/helpers/renderSlot'
import { h } from '../../src/h' import { h } from '../../src/h'
import { mockWarn } from '@vue/shared'
describe('renderSlot', () => { describe('renderSlot', () => {
mockWarn()
it('should render slot', () => { it('should render slot', () => {
let child let child
const vnode = renderSlot( const vnode = renderSlot(

View File

@ -12,11 +12,8 @@ import {
Comment, Comment,
VNode VNode
} from '@vue/runtime-test' } from '@vue/runtime-test'
import { mockWarn } from '@vue/shared'
describe('resolveAssets', () => { describe('resolveAssets', () => {
mockWarn()
test('should work', () => { test('should work', () => {
const FooBar = () => null const FooBar = () => null
const BarBaz = { mounted: () => null } const BarBaz = { mounted: () => null }

View File

@ -1,9 +1,6 @@
import { toHandlers } from '../../src/helpers/toHandlers' import { toHandlers } from '../../src/helpers/toHandlers'
import { mockWarn } from '@vue/shared'
describe('toHandlers', () => { describe('toHandlers', () => {
mockWarn()
it('should not accept non-objects', () => { it('should not accept non-objects', () => {
toHandlers(null as any) toHandlers(null as any)
toHandlers(undefined as any) toHandlers(undefined as any)

View File

@ -12,7 +12,6 @@ import {
defineComponent defineComponent
} from '@vue/runtime-dom' } from '@vue/runtime-dom'
import { renderToString, SSRContext } from '@vue/server-renderer' import { renderToString, SSRContext } from '@vue/server-renderer'
import { mockWarn } from '@vue/shared'
function mountWithHydration(html: string, render: () => any) { function mountWithHydration(html: string, render: () => any) {
const container = document.createElement('div') const container = document.createElement('div')
@ -34,8 +33,6 @@ const triggerEvent = (type: string, el: Element) => {
} }
describe('SSR hydration', () => { describe('SSR hydration', () => {
mockWarn()
beforeEach(() => { beforeEach(() => {
document.body.innerHTML = '' document.body.innerHTML = ''
}) })

View File

@ -13,11 +13,8 @@ import {
createCommentVNode, createCommentVNode,
Fragment Fragment
} from '@vue/runtime-dom' } from '@vue/runtime-dom'
import { mockWarn } from '@vue/shared'
describe('attribute fallthrough', () => { describe('attribute fallthrough', () => {
mockWarn()
it('should allow attrs to fallthrough', async () => { it('should allow attrs to fallthrough', async () => {
const click = jest.fn() const click = jest.fn()
const childUpdated = jest.fn() const childUpdated = jest.fn()

View File

@ -8,10 +8,6 @@ import {
serialize, serialize,
serializeInner serializeInner
} from '@vue/runtime-test' } from '@vue/runtime-test'
import { mockWarn } from '@vue/shared'
mockWarn()
function toSpan(content: any) { function toSpan(content: any) {
if (typeof content === 'string') { if (typeof content === 'string') {
return h('span', content.toString()) return h('span', content.toString())

View File

@ -11,14 +11,12 @@ import {
transformVNodeArgs transformVNodeArgs
} from '../src/vnode' } from '../src/vnode'
import { Data } from '../src/component' import { Data } from '../src/component'
import { ShapeFlags, PatchFlags, mockWarn } from '@vue/shared' import { ShapeFlags, PatchFlags } from '@vue/shared'
import { h, reactive, isReactive } from '../src' import { h, reactive, isReactive } from '../src'
import { createApp, nodeOps, serializeInner } from '@vue/runtime-test' import { createApp, nodeOps, serializeInner } from '@vue/runtime-test'
import { setCurrentRenderingInstance } from '../src/componentRenderUtils' import { setCurrentRenderingInstance } from '../src/componentRenderUtils'
describe('vnode', () => { describe('vnode', () => {
mockWarn()
test('create with just tag', () => { test('create with just tag', () => {
const vnode = createVNode('p') const vnode = createVNode('p')
expect(vnode.type).toBe('p') expect(vnode.type).toBe('p')

View File

@ -1,10 +1,7 @@
import { render, h, nodeOps } from '@vue/runtime-test' import { render, h, nodeOps } from '@vue/runtime-test'
import { useCssModule } from '../../src/helpers/useCssModule' import { useCssModule } from '../../src/helpers/useCssModule'
import { mockWarn } from '@vue/shared'
describe('useCssModule', () => { describe('useCssModule', () => {
mockWarn()
function mountWithModule(modules: any, name?: string) { function mountWithModule(modules: any, name?: string) {
let res let res
render( render(

View File

@ -1,10 +1,7 @@
import { patchProp } from '../src/patchProp' import { patchProp } from '../src/patchProp'
import { render, h } from '../src' import { render, h } from '../src'
import { mockWarn } from '@vue/shared'
describe('runtime-dom: props patching', () => { describe('runtime-dom: props patching', () => {
mockWarn()
test('basic', () => { test('basic', () => {
const el = document.createElement('div') const el = document.createElement('div')
patchProp(el, 'id', null, 'foo') patchProp(el, 'id', null, 'foo')

View File

@ -14,11 +14,8 @@ import {
serialize, serialize,
triggerEvent triggerEvent
} from '../src' } from '../src'
import { mockWarn } from '@vue/shared'
describe('test renderer', () => { describe('test renderer', () => {
mockWarn()
it('should work', () => { it('should work', () => {
const root = nodeOps.createElement('div') const root = nodeOps.createElement('div')
render( render(

View File

@ -10,14 +10,11 @@ import {
createTextVNode, createTextVNode,
createStaticVNode createStaticVNode
} from 'vue' } from 'vue'
import { escapeHtml, mockWarn } from '@vue/shared' import { escapeHtml } from '@vue/shared'
import { renderToStream as _renderToStream } from '../src/renderToStream' import { renderToStream as _renderToStream } from '../src/renderToStream'
import { Readable } from 'stream' import { Readable } from 'stream'
import { ssrRenderSlot } from '../src/helpers/ssrRenderSlot' import { ssrRenderSlot } from '../src/helpers/ssrRenderSlot'
import { ssrRenderComponent } from '../src/helpers/ssrRenderComponent' import { ssrRenderComponent } from '../src/helpers/ssrRenderComponent'
mockWarn()
const promisifyStream = (stream: Readable) => { const promisifyStream = (stream: Readable) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let result = '' let result = ''

View File

@ -10,13 +10,10 @@ import {
createTextVNode, createTextVNode,
createStaticVNode createStaticVNode
} from 'vue' } from 'vue'
import { escapeHtml, mockWarn } from '@vue/shared' import { escapeHtml } from '@vue/shared'
import { renderToString } from '../src/renderToString' import { renderToString } from '../src/renderToString'
import { ssrRenderSlot, SSRSlot } from '../src/helpers/ssrRenderSlot' import { ssrRenderSlot, SSRSlot } from '../src/helpers/ssrRenderSlot'
import { ssrRenderComponent } from '../src/helpers/ssrRenderComponent' import { ssrRenderComponent } from '../src/helpers/ssrRenderComponent'
mockWarn()
describe('ssr: renderToString', () => { describe('ssr: renderToString', () => {
test('should apply app context', async () => { test('should apply app context', async () => {
const app = createApp({ const app = createApp({

View File

@ -1,10 +1,7 @@
import { createApp, h, Suspense } from 'vue' import { createApp, h, Suspense } from 'vue'
import { renderToString } from '../src/renderToString' import { renderToString } from '../src/renderToString'
import { mockWarn } from '@vue/shared'
describe('SSR Suspense', () => { describe('SSR Suspense', () => {
mockWarn()
const ResolvingAsync = { const ResolvingAsync = {
async setup() { async setup() {
return () => h('div', 'async') return () => h('div', 'async')

View File

@ -6,7 +6,6 @@ export * from './shapeFlags'
export * from './slotFlags' export * from './slotFlags'
export * from './globalsWhitelist' export * from './globalsWhitelist'
export * from './codeframe' export * from './codeframe'
export * from './mockWarn'
export * from './normalizeProp' export * from './normalizeProp'
export * from './domTagConfig' export * from './domTagConfig'
export * from './domAttrConfig' export * from './domAttrConfig'

View File

@ -1,105 +0,0 @@
declare global {
namespace jest {
interface Matchers<R, T> {
toHaveBeenWarned(): R
toHaveBeenWarnedLast(): R
toHaveBeenWarnedTimes(n: number): R
}
}
}
export const mockError = () => mockWarn(true)
export function mockWarn(asError = false) {
expect.extend({
toHaveBeenWarned(received: string) {
asserted.add(received)
const passed = warn.mock.calls.some(
args => args[0].indexOf(received) > -1
)
if (passed) {
return {
pass: true,
message: () => `expected "${received}" not to have been warned.`
}
} else {
const msgs = warn.mock.calls.map(args => args[0]).join('\n - ')
return {
pass: false,
message: () =>
`expected "${received}" to have been warned.\n\nActual messages:\n\n - ${msgs}`
}
}
},
toHaveBeenWarnedLast(received: string) {
asserted.add(received)
const passed =
warn.mock.calls[warn.mock.calls.length - 1][0].indexOf(received) > -1
if (passed) {
return {
pass: true,
message: () => `expected "${received}" not to have been warned last.`
}
} else {
const msgs = warn.mock.calls.map(args => args[0]).join('\n - ')
return {
pass: false,
message: () =>
`expected "${received}" to have been warned last.\n\nActual messages:\n\n - ${msgs}`
}
}
},
toHaveBeenWarnedTimes(received: string, n: number) {
asserted.add(received)
let found = 0
warn.mock.calls.forEach(args => {
if (args[0].indexOf(received) > -1) {
found++
}
})
if (found === n) {
return {
pass: true,
message: () =>
`expected "${received}" to have been warned ${n} times.`
}
} else {
return {
pass: false,
message: () =>
`expected "${received}" to have been warned ${n} times but got ${found}.`
}
}
}
})
let warn: jest.SpyInstance
const asserted: Set<string> = new Set()
beforeEach(() => {
asserted.clear()
warn = jest.spyOn(console, asError ? 'error' : 'warn')
warn.mockImplementation(() => {})
})
afterEach(() => {
const assertedArray = Array.from(asserted)
const nonAssertedWarnings = warn.mock.calls
.map(args => args[0])
.filter(received => {
return !assertedArray.some(assertedMsg => {
return received.indexOf(assertedMsg) > -1
})
})
warn.mockRestore()
if (nonAssertedWarnings.length) {
nonAssertedWarnings.forEach(warning => {
console.warn(warning)
})
throw new Error(`test case threw unexpected warnings.`)
}
})
}

View File

@ -1,10 +1,8 @@
import { E2E_TIMEOUT, setupPuppeteer } from './e2eUtils' import { E2E_TIMEOUT, setupPuppeteer } from './e2eUtils'
import path from 'path' import path from 'path'
import { mockWarn } from '@vue/shared'
import { h, createApp, Transition } from 'vue' import { h, createApp, Transition } from 'vue'
describe('e2e: Transition', () => { describe('e2e: Transition', () => {
mockWarn()
const { const {
page, page,
html, html,

View File

@ -1,10 +1,8 @@
import { E2E_TIMEOUT, setupPuppeteer } from './e2eUtils' import { E2E_TIMEOUT, setupPuppeteer } from './e2eUtils'
import path from 'path' import path from 'path'
import { mockWarn } from '@vue/shared'
import { createApp, ref } from 'vue' import { createApp, ref } from 'vue'
describe('e2e: TransitionGroup', () => { describe('e2e: TransitionGroup', () => {
mockWarn()
const { page, html, nextFrame, timeout } = setupPuppeteer() const { page, html, nextFrame, timeout } = setupPuppeteer()
const baseUrl = `file://${path.resolve(__dirname, './transition.html')}` const baseUrl = `file://${path.resolve(__dirname, './transition.html')}`

View File

@ -1,9 +1,6 @@
import { createApp, ref, nextTick } from '../src' import { createApp, ref, nextTick } from '../src'
import { mockWarn } from '@vue/shared'
describe('compiler + runtime integration', () => { describe('compiler + runtime integration', () => {
mockWarn()
it('should support runtime template compilation', () => { it('should support runtime template compilation', () => {
const container = document.createElement('div') const container = document.createElement('div')
const App = { const App = {
@ -55,7 +52,7 @@ describe('compiler + runtime integration', () => {
expect(one.deactivated).toHaveBeenCalledTimes(0) expect(one.deactivated).toHaveBeenCalledTimes(0)
expect(one.destroyed).toHaveBeenCalledTimes(0) expect(one.destroyed).toHaveBeenCalledTimes(0)
toggle.value = false; toggle.value = false
await nextTick() await nextTick()
expect(container.innerHTML).toBe(`<!--v-if-->`) expect(container.innerHTML).toBe(`<!--v-if-->`)
expect(one.created).toHaveBeenCalledTimes(1) expect(one.created).toHaveBeenCalledTimes(1)
@ -64,7 +61,7 @@ describe('compiler + runtime integration', () => {
expect(one.deactivated).toHaveBeenCalledTimes(1) expect(one.deactivated).toHaveBeenCalledTimes(1)
expect(one.destroyed).toHaveBeenCalledTimes(0) expect(one.destroyed).toHaveBeenCalledTimes(0)
toggle.value = true; toggle.value = true
await nextTick() await nextTick()
expect(container.innerHTML).toBe(`one`) expect(container.innerHTML).toBe(`one`)
expect(one.created).toHaveBeenCalledTimes(1) expect(one.created).toHaveBeenCalledTimes(1)

88
scripts/setupJestEnv.ts Normal file
View File

@ -0,0 +1,88 @@
expect.extend({
toHaveBeenWarned(received: string) {
asserted.add(received)
const passed = warn.mock.calls.some(args => args[0].indexOf(received) > -1)
if (passed) {
return {
pass: true,
message: () => `expected "${received}" not to have been warned.`
}
} else {
const msgs = warn.mock.calls.map(args => args[0]).join('\n - ')
return {
pass: false,
message: () =>
`expected "${received}" to have been warned.\n\nActual messages:\n\n - ${msgs}`
}
}
},
toHaveBeenWarnedLast(received: string) {
asserted.add(received)
const passed =
warn.mock.calls[warn.mock.calls.length - 1][0].indexOf(received) > -1
if (passed) {
return {
pass: true,
message: () => `expected "${received}" not to have been warned last.`
}
} else {
const msgs = warn.mock.calls.map(args => args[0]).join('\n - ')
return {
pass: false,
message: () =>
`expected "${received}" to have been warned last.\n\nActual messages:\n\n - ${msgs}`
}
}
},
toHaveBeenWarnedTimes(received: string, n: number) {
asserted.add(received)
let found = 0
warn.mock.calls.forEach(args => {
if (args[0].indexOf(received) > -1) {
found++
}
})
if (found === n) {
return {
pass: true,
message: () => `expected "${received}" to have been warned ${n} times.`
}
} else {
return {
pass: false,
message: () =>
`expected "${received}" to have been warned ${n} times but got ${found}.`
}
}
}
})
let warn: jest.SpyInstance
const asserted: Set<string> = new Set()
beforeEach(() => {
asserted.clear()
warn = jest.spyOn(console, 'warn')
warn.mockImplementation(() => {})
})
afterEach(() => {
const assertedArray = Array.from(asserted)
const nonAssertedWarnings = warn.mock.calls
.map(args => args[0])
.filter(received => {
return !assertedArray.some(assertedMsg => {
return received.indexOf(assertedMsg) > -1
})
})
warn.mockRestore()
if (nonAssertedWarnings.length) {
nonAssertedWarnings.forEach(warning => {
console.warn(warning)
})
throw new Error(`test case threw unexpected warnings.`)
}
})