メインコンテンツへスキップ

API

Marko Testing Library は、DOM Testing Library のすべての機能に加えて、以下のメソッドを提供します。


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 Testing Librarydiv を作成し、その divdocument.body に追加します。ここにコンポーネントがレンダリングされます。このオプションを介して独自の HTMLElement container を提供する場合は、document.body に自動的に追加されません。

例:tablebody 要素の単体テストを行う場合、div の子要素にすることはできません。この場合、レンダリングcontainerとしてtableを指定できます。

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'))

これは、DOM Testing Library からも公開されている prettyDOM をラップしたシンプルなラッパーです。

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コンポーネントは、イベントを通して親コンポーネントと通信します。コンポーネントが適切なタイミングで適切なイベントをemitしていることもテストすることをお勧めします。

emittedヘルパーはそのように機能します。このヘルパーを呼び出すと、ヘルパーの最後の呼び出し以降にemitされたすべてのイベントが返されます。結果をフィルタリングするためにイベントタイプを渡すこともできます。

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にレンダリングされます。各テストの後でコンポーネントが適切に削除および破棄されるように、サポートされているテストフレームワークでafterEachにフックすることで、cleanupメソッドが自動的に呼び出されます。また、いつでも手動で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"]を含めることができます。