View Source Upgrade Guides

Upgrading to 0.2.13

Version 0.2.13 deprecates fill_form/3 and submit_form/3.

🥺 I know it's a pain. I'm sorry about that.

I don't take changing APIs lightly (even pre 1.0)... but I think you'll like these changes.

New form helpers

Let me introduce you to our new form helpers:

  • fill_in/3
  • select/3
  • choose/3
  • check/3
  • uncheck/3

These new form helpers target elements by labels! 🥳

Instead of relying on the underlying data structures generated by Phoenix forms and changesets, you can now specify which label you're targeting.

Change this: 👇

|> fill_form("form", user: %{
  name: "Aragorn",
  admin: true,
  country: "Arnor"

To this: 👇

|> fill_in("Name", with: "Aragorn")
|> check("Admin")
|> select("Arnor", from: "Countries")

The new format:

  • encourages us (me included!) to use labels in forms,
  • decouples the testing of our forms from the underlying shape of a changeset or Phoenix form -- something that's a mere implementation detail, and
  • allows us to express our tests closer to the language a user would use when seeing a page.

But what if I don't want the label to show?

It's a good idea to have labels for accessibility -- even if they're not visible on the page. In those cases, you should hide them with CSS.

For example, if you use Tailwind, you can add a sr-only class to your label. That will mark it as "screen-reader only" and hide it.

Targeting a form to fill out

Since fill_form/3 used to allow targeting a form by CSS selector, you may want to target a form via CSS selector with the new format. To do that, you can scope all of the form helpers using within/3:

|> within("#user-form", fn session ->
  |> fill_in("Name", with: "Aragorn")
  |> check("Admin")
  |> select("Arnor", from: "Countries")

NOTE: you may no longer need to target your form via CSS selector. The new helpers are a lot smarter since they're looking for the labels and their associated inputs or options.

But if you have multiple forms with the same labels (even when those labels point to different inputs), then you might have to scope your form-filling. And that's where within/3 can be handy.

Submitting forms without clicking a button

Once we've filled out a form, we typically click a button with click_button/2 to submit the form. But sometimes you want to emulate what would happen by just pressing <Enter> (or do what submit_form/3 used to do).

For that case, you can use submit/1 to submit the form you just filled out.

|> fill_in("Name", with: "Aragorn")
|> check("Admin")
|> select("Arnor", from: "Countries")
|> submit()