Skip to content

Support assert_has value finder for select - #309

Merged
germsvel merged 6 commits into
germsvel:mainfrom
ftes:assert-has-select-value
Apr 23, 2026
Merged

Support assert_has value finder for select#309
germsvel merged 6 commits into
germsvel:mainfrom
ftes:assert-has-select-value

Conversation

@ftes

@ftes ftes commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Support assert_has/3 and refute_has/3 with value: for select elements by matching selected option text.

Implements #262.

Comment thread lib/phoenix_test/element/form.ex
Comment thread lib/phoenix_test/assertions.ex Outdated
case opts.label do
:no_label ->
&Query.find(&1, selector, Opts.to_list(opts))
&Query.find_by_value(&1, selector, value, Opts.to_list(opts))

@ftes ftes Apr 21, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Find by value implemented differently for select than input.

This makes we wonder: Should we make this explicit in the API: assert_has("select", label: "Race", selected_option_text: "Elf")?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using one of the following would be good for clarity:

assert_has("select", label: "Race", selected: "Elf")

assert_has("select", label: "Race", selected_value: "Elf")

assert_has("select", label: "Race", selected_option: "Elf")

What do you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

selected_value is my least favourite, because it might imply you're asserting on the selected option's value rather than the option's label.

How about selected. It's not precise (as in selected_option_label), but given PhoenixTest preference for operating on visible labels, I think this is consistent and concise.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm with you. I think selected is the best of the three.

Comment thread lib/phoenix_test/html.ex Outdated
Comment on lines +77 to +79
selected_options
|> Stream.concat(all(select, "option"))
|> Enum.take(1)

@ftes ftes Apr 21, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too cryptic?
"Take first selected option, otherwise fall back to first option (selected by default)"

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a bit cryptic. I didn't realize that's what it was doing. 😄

Can we add tests at this level that document that? I think I'd be okay with cryptic so long as the html_test.exs tests capture that clearly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made the code more explicit and added tests.

@ftes
ftes marked this pull request as ready for review April 21, 2026 12:14

@germsvel germsvel left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the work! 🙌

Thanks for doing this. I left a few comments. The biggest one (I think) is what should we call the option? Otherwise, this is looking great!

Comment thread lib/phoenix_test/assertions.ex Outdated
case opts.label do
:no_label ->
&Query.find(&1, selector, Opts.to_list(opts))
&Query.find_by_value(&1, selector, value, Opts.to_list(opts))

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using one of the following would be good for clarity:

assert_has("select", label: "Race", selected: "Elf")

assert_has("select", label: "Race", selected_value: "Elf")

assert_has("select", label: "Race", selected_option: "Elf")

What do you think?

Comment thread lib/phoenix_test/html.ex Outdated
Comment on lines +77 to +79
selected_options
|> Stream.concat(all(select, "option"))
|> Enum.take(1)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a bit cryptic. I didn't realize that's what it was doing. 😄

Can we add tests at this level that document that? I think I'd be okay with cryptic so long as the html_test.exs tests capture that clearly.

@ftes
ftes force-pushed the assert-has-select-value branch from 7e6c218 to 0871355 Compare April 23, 2026 18:00
@ftes
ftes force-pushed the assert-has-select-value branch from 8283fa5 to af39450 Compare April 23, 2026 18:46
when is_binary(label) do
&Query.find_by_label(&1, selector, label, Opts.to_list(opts))
end
case {content, opts, operation} do

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to make the conflicting content opts more explicit.

That led me to discover that text + label opts are unsupported (label silently ignored). I made that explicit by raising an error instead.

defp finder_fun(selector, %Opts{text: :no_text, value: value} = opts, _operation) do
value_finder_fun(ensure_binary(value), selector, opts)
end
{[], %Opts{label: label}, _} when is_binary(label) ->

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We keep repeating the is_binary(label) guard and ensure_binary(value) type coercions.

That could be hoisted into Opts.parse - since we don't support different Opts types elsewhere.

Didn't want to change too much here though.

@ftes
ftes force-pushed the assert-has-select-value branch from 1d57cc0 to eee4c7b Compare April 23, 2026 18:57

@germsvel germsvel left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lovely! Thanks @ftes!

@germsvel
germsvel merged commit e18894b into germsvel:main Apr 23, 2026
2 checks passed
germsvel pushed a commit that referenced this pull request Apr 23, 2026
Follow up for #309.

With the new approach (separate selected option), some changes to existing value finder path became unnecessary. This just cleans up some unnecessary functions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants