7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Web UIテストでカスタムデータ属性の用いてDOM要素を指定

Last updated at Posted at 2021-04-24

最近、Web UIのテストでカスタムデータ属性DOM要素を指定するやり方が気に入ってます。それについてまとめてみようと思います。

この手法はWebのテストのみならず、JavaScriptのスクリプトでも適用できるのですが、今はPhoenix LiveViewのテストの勉強中なのでWeb UIテストの文脈で書いてます。

TL;DR

今書いている時点で、一般的によく使われるID セレクターより、個人的にデータ属性を使用してDOM要素を取得するのが好みです。特にdata-roleというカスタム属性を使うことにより、アプリ全体で一貫した規約的なものができ、かつ柔軟にその要素の役割を明示することにもなると考えています。

仮にこういうHTML文書があったとします。

defmodule MnishiguchiWeb.AlchemistsLive do
  use MnishiguchiWeb, :live_view

  alias Mnishiguchi.Alchemists

  @impl Phoenix.LiveView
  def mount(_params, _session, socket) do
    {:ok, assign(socket, alchemists: Alchemists.list_alchemists())}
  end

  @impl Phoenix.LiveView
  def render(assigns) do
    ~L"""
    <div class="row">
      <%= for alchemist <- @alchemists do %>
        <div class="card mb-3" data-role="alchemist-card" data-id="<%= alchemist.id %>">
          <div class="card-body">
            <h5 class="card-title"><%= alchemist.name %></h5>
          </div>
        <div>
      <% end %>
    </div>
    """
  end
end

テストコードではdata-roleカスタム属性を用いてDOM要素を見つけられます。

defmodule MnishiguchiWeb.AlchemistsLiveTest do
  use MnishiguchiWeb.ConnCase, async: true

  import Phoenix.LiveViewTest

  @path "/alchemists"

  test "displays alchemists", %{conn: conn} do
    _alchemist1 = create_alchemist(name: "Taro Yamada")

    {:ok, view, _disconnected_html} = live(conn, @path)

    assert has_alchemist_card?(view, "Taro Yamada")
    refute has_alchemist_card?(view, "Jiro Yamada")
  end

  defp has_alchemist_card?(view, name) do
    has_element?(view, "[data-role=alchemist-card]", name)
  end
end

IDで特定したいのであれば、data-roledata-idとの2つのカスタム属性を用いてDOM要素を使用する手もあります。

  defp has_alchemist_card?(view, id, name) do
    has_element?(view, "[data-role=alchemist-card][data-id=#{id}]", name)
  end

DOM要素のテキストにこだわらないのであれば、こういうので良い場合があるかもしれません。

  defp has_alchemist_card?(view) do
    has_element?(view, "[data-role=alchemist-card]")
  end

Phoenix.LiveViewTestは、すばらしくawesomeです。

has_element?/3等の便利な関数を用いて、ヘッドレスブラウザーなしで動的コンテンツをテストできます。

open_browser/2でブラウザーを開いて今どんな状態なのかを確認することもできます。

最高に快適です。

その他のアプローチ

もちろん、世の中には他にもいろんなDOM要素を指定するCSS セレクターがあります。

よく使われるものの中にはこれらがあります。

data-test-iddata-roleに似ているのですが、明示的にテスト用属性なので少し意味合いが違います。テスト用途に限定せずにその要素のアプリでの振る舞いについて示す方が良いのではと考えています。

ARIAロールが使えるところはARIAロールを積極的に使うべきなのでしょう。Phoenixのデフォルトのフラッシュメッセージにはrole="alert"が付与されています。

<main role="main" class="container my-4">
  <p class="alert alert-info" role="alert"
    phx-click="lv:clear-flash"
    phx-value-key="info"><%= live_flash(@flash, :info) %></p>

  <p class="alert alert-danger" role="alert"
    phx-click="lv:clear-flash"
    phx-value-key="error"><%= live_flash(@flash, :error) %></p>

  <%= @inner_content %>
</main>

ですので、テストコードでそれが利用できます。

assert has_element?(view, "[role=alert]", ~s[No item matching "-1"])

しかしながら、ARIAロールは正式な仕様のようなので自由に好きなようにかけるものではありませんし、現時点ではまだ多くのロールの仕様がきまってない?ようです。それが難点です。

カスタムデータ属性を使用するメリット

  • UIのスタイリング目的でHTMLタグ、CSSクラスやIDをイジっているときにテストが壊れるリスクの軽減
  • DOM要素の役割を柔軟に表現できる
  • 実は、属性セレクターには、いくつか便利なパターンマッチング構文があります

カスタムデータ属性を使用するデメリット

  • 若干コードが冗長
  • 一般的にはID セレクターの方がよく使われている

以上!

https://developer.mozilla.org/ja/docs/Web/HTML/Global_attributes/data-*

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?