跳至主要內容

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 並將該 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,該 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"],以避免在每個檔案中執行此操作。