Testing (live)views with translations and accents

Hello there :waving_hand:

I am facing an issue with a small phoenix app I am currently hacking.
As a frenchman, I am developing web apps for a French audience, and so I have to deal with all the diacritics (accents etc.) of the language.

Doing so, I faced some issues then testing my pages: there is probably a better way to handle them, but I could not figure it out :person_shrugging:

Issue 1: accents get escaped

For example, I cannot simply use the =~ operator to check the presence of some text in the HTML:

assert html =~ "S'inscrire" # 🛑 Not working
assert html =~ dgettext("auth", "Register") # 🛑 Neither

This is because the “apostrophe” is escaped as “'” in the final HTML.
I ended up adding a new function to my ConnCase

  import Phoenix.HTML

  # ...

  @doc """
  Call GetText *and escape* the result.
  """
  def translation(domain \\ nil, key, bindings \\ %{}) do
    if domain do
      Gettext.dgettext(MaGardeWeb.Gettext, domain, key, bindings)
    else
      Gettext.gettext(MaGardeWeb.Gettext, key, bindings)
    end
    |> html_escape()
    |> safe_to_string()
  end

This way I can use a call to translation(...) in my tests in place of the Gettext functions whenever I need it : not ideal but better that looking up the escaped strings every time.

Is there an easier / better way to do this ?

Issue 2 : even when I use HTML escaping, I cannot select elements in LiveView tests

Once again, when I try to select the “S’inscrire” button (means register in French), nothing seems to work:

lv |> element("main a", "S'inscrire") # 🛑 Not working
lv |> element("main a", "S'inscrire") # 🛑 Nope
lv |> element("main a", translation("auth", "Register")) # 🛑 Still not good...

And when I look into the error that raised, it literally prints the escaped text content while complaining it cannot be found :cry: :

** (ArgumentError) selector "main a" did not match text filter "S'inscrire", got: 

    <a href="/users/register" data-phx-link="redirect" data-phx-link-state="push" 
      class="font-semibold text-brand hover:underline">S&#39;inscrire</a>

What did I do wrong ? and what’s the right way to do this ?

Thanks a lot for any insight on these topics, since I’m quite stuck right now.
Regards,
Aurélien

Only tangential, but I very rarely (or never?) test against actual text on the webpage because that is just so brittle.

Instead, I would assert that a button exists or that some element has been added or removed after some action.

1 Like

I understand your point, and kinda agree when testing for page content, but for CTAs I like selecting elements using the actual label: “Click Sign In”, “Click Submit” etc.

And it works nicely in English, but for some obscure reason it does not in French (the app is “french-only”)…

1 Like

Even for things like this I would avoid using the text because 2 days later some designer comes along and feels that “Please click Sign In now” is much better and then you have to change your test.

You do you, but my experience has been to avoid using text to assert or as selectors.

2 Likes

Another workaround could be to use a different selector and then use your own function to verify the text contents:

lv |> element("[test-role=register-button]") |> assert_text("S'inscrire")

where assert_text handles translation or escaping and either raises or returns the original input.