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