API
Marko 测试库
重新导出 DOM 测试库
中的所有内容,以及以下方法
render
function render(
template, // A Marko template to render
input, // Input for the above template
options // You won't often use this, expand below for docs on options
)
渲染到附加到 document.body
的容器中。
import {render} from '@marko/testing-library'
import MyTemplate from './my-template.marko'
render(MyTemplate)
import {render, screen} from '@marko/testing-library'
import Greeting from './greeting.marko'
test('renders a message', async () => {
const {container} = await render(Greeting, {name: 'Marko'})
expect(screen.getByText(/Marko/)).toBeInTheDocument()
expect(container.firstChild).toMatchInlineSnapshot(`
<h1>Hello, Marko!</h1>
`)
})
render
选项
你通常不需要指定选项,但如果你需要,以下是你可以作为 render
的第三个参数提供的可用选项。
container
对于客户端测试,Marko 测试库
默认情况下会创建一个 div
并将其附加到 document.body
,你的组件将在此处渲染。如果你通过此选项提供自己的 HTMLElement container
,它不会自动附加到 document.body
。
例如:如果你正在对 tablebody
元素进行单元测试,它不能是 div
的子元素。在这种情况下,你可以将 table
指定为渲染 container
。
const table = document.createElement('table')
const {container} = await render(MyTableBody, null, {
container: document.body.appendChild(table),
})
render
结果
render
方法返回一个 promise,它解析为包含几个属性的对象
...queries
render
的最重要的功能是,来自 核心 API 的查询会自动返回,其第一个参数绑定到渲染组件的结果。
查看 查询 以获取完整的列表。
示例
const {getByLabelText, queryAllByTestId} = await render(MyTemplate)
或者,你可以使用 顶级 screen
方法 查询 document.body
中当前渲染的所有组件,例如
import { render, screen } from "@marko/testing-library"
await render(MyTemplate)
const el = screen.getByText(...)
debug
此方法是为 container
内的所有子元素记录 prettyDOM
的快捷方式。
import {render} from '@marko/testing-library'
import Greeting from './greeting.marko'
const {debug} = await render(Greeting, {name: 'World'})
debug()
// <h1>Hello World</h1>
// you can also pass an element: debug(getByTestId('messages'))
这是一个简单的包装器,它围绕着也暴露的 prettyDOM
,它来自 DOM 测试库
。
rerender
Marko 组件的 input
可以随时从父组件更改。虽然通常情况下,此输入是通过你的组件声明性地传递的,但有时需要确保你的组件对新数据做出适当的反应。你可以通过将新数据传递给 rerender
帮助器来模拟你的组件接收新 input
。
import {render} from '@marko/testing-library'
import Greeting from './greeting.marko'
const {rerender, debug} = await render(Greeting, {name: 'World'})
// re-render the same component with different props
await rerender({name: 'Marko'})
debug()
// <h1>Hello Marko</h1>
emitted
Marko 组件还通过事件与它们的父组件进行通信。建议你还要测试你的组件是否在正确的时间发出了正确的事件。
emitted
帮助器就是这样做的。调用帮助器将返回自上次调用帮助器以来的所有已发出的事件。你也可以传递一个事件类型来过滤结果。
import {render, fireEvent} from '@marko/testing-library'
import Counter from './counter.marko'
const {getByText, emitted} = await render(Counter)
const button = getByText('Increment')
await fireEvent.click(button)
await fireEvent.click(button)
// Assuming the `Counter` component forwards these button clicks as `increment` events
expect(emitted('increment')).toHaveProperty('length', 2)
await fireEvent.click(button)
// Note: the tracked events are cleared every time you read them.
// Below we are snapshoting the events after our last assertion,
// the return value will include an array with all of the arguments for each increment event.
expect(emitted('increment')).toMatchInlineSnapshot(`
Array [
Array [
Object {
"count": 3,
},
],
]
`)
// Without an event type will give you all events with their type and arguments.
expect(emitted()).toMatchInlineSnapshot(`
Array [
Object {
"args": Array [
Object {
"count": 0,
},
],
"type": "increment",
},
Object {
"args": Array [
Object {
"count": 1,
},
],
"type": "increment",
},
Object {
"args": Array [
Object {
"count": 3,
},
],
"type": "increment",
}
]
`)
cleanup
与 顶级 cleanup 方法 一样,这允许你在测试完成之前删除和销毁当前渲染的组件。
这可以用来验证组件在被销毁后是否正确清理了所有 DOM 突变。
import {render, screen, getRoles} from '@marko/testing-library'
import Main from './main.marko'
import Dialog from './dialog.marko'
await render(Main)
const main = screen.getByRole('main')
expect(main).not.toHaveAttribute('aria-hidden')
const {cleanup} = await render(Dialog)
expect(main).toHaveAttribute('aria-hidden') // assert added attribute
cleanup() // destroy the dialog
expect(main).not.toHaveAttribute('aria-hidden') // assert attribute removed
container
已渲染的 Marko 组件的包含 DOM 节点。对于服务器端测试,这是一个 JSDOM.fragment,对于客户端测试,这将是作为 container
渲染选项传递的任何内容。
提示:要获取已渲染元素的根元素,请使用
container.firstChild
。
🚨 如果你发现自己正在使用
container
来查询渲染的元素,那么你应该重新考虑!其他查询旨在对将要对正在测试的组件进行的更改更具弹性。避免使用container
来查询元素!
fireEvent
因为 Marko 会批处理 DOM 更新以避免不必要的重新渲染,所以 fireEvent 帮助器被重新导出为 async
函数。等待它可以确保 DOM 已针对测试中触发的事件正确更新。
await fireEvent.click(getByText('Click me'))
cleanup
对于客户端测试,你的组件被渲染到一个占位符 HTMLElement 中。为了确保你的组件在每个测试后都被正确删除和销毁,cleanup
方法会通过钩入支持的测试框架中的 afterEach
自动为你调用。你也可以随时手动调用 cleanup
,它将删除所有附加的组件。
import {render, cleanup, screen} from '@marko/testing-library'
import Greeting from './greeting.marko'
await render(Greeting, {name: 'Marko'})
expect(screen.getByText(/Marko/)).toBeInTheDocument()
// manually cleanup the component before the test is finished
cleanup()
expect(screen.queryByText(/Marko/)).toBeNull()
你可以通过导入以下模块来关闭自动测试清理
import '@marko/testing-library/dont-cleanup-after-each'
使用 mocha 时,你可以使用 mocha --require @marko/testing-library/dont-cleanup-after-each
作为简写。
如果你正在使用 Jest,你可以在你的 Jest 配置中包含 setupFilesAfterEnv: ["@marko/testing-library/dont-cleanup-after-each"]
以避免在每个文件中执行此操作。