Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support phx-trigger-action #135

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

ftes
Copy link
Contributor

@ftes ftes commented Oct 5, 2024

Closes #47

Copy link
Owner

@germsvel germsvel left a comment

Choose a reason for hiding this comment

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

Thanks for taking a stab at this. I'm not sold on the implementation. I think it would work, but I'd like to see if we can find a better design so that it's not intertwined with the maybe_redirect logic.

What do you think? Could you explore that?

@@ -330,7 +330,22 @@ defmodule PhoenixTest.Live do
end

defp maybe_redirect(html, session) when is_binary(html) do
maybe_put_patch_path(session)
case Form.find(html, "form[phx-trigger-action]") do
Copy link
Owner

Choose a reason for hiding this comment

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

I find it a little strange that we'd be looking for a form inside maybe_redirect.

I imagine it'd be more duplication to do this in the places where we're submitting forms, but I wonder if we could find a better design for this?

I'd image there are places where we're dealing with a form (probably through a phx-change) where we already have the form data structure. Maybe we could check for a Form.phx_trigger_action? there? (similar to how we do it with other attributes like that)

Copy link
Contributor Author

@ftes ftes Oct 7, 2024

Choose a reason for hiding this comment

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

Actually, I think the phx-trigger-action is a bit like a client side redirect.

Two things to consider:

  • phx-trigger-action can be set on any re-render, not just when clicking a submit button for a form
  • phx-trigger-action can be set on any form, not necessarily the one the user is interacting with

I agree that the common use case is:

  1. User submits form
  2. handle_event("save" assigns trigger_submit: true
  3. Browser performs HTTP POST

But I think we should limit the implementation to that common use case.

I think its best to mimmick LiveView JS to support all kinds of uses cases:
Whenever something changed, check the HTML for forms with phx-trigger-action.
If present, then submit that form.

That's what I tried to to in this PR.

We could separate maybe_redirect and maybe_trigger_action.
Do you think that would help?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Commit e2dd5b4

I separated them into two separate post processing steps.
I tried to keep both functions completely separate by introducing a token flow.

Feels over-engineered. Maybe just renaming maybe_redirect to maybe_trigger_form_action_or_redirect would be good enough?

Copy link
Owner

Choose a reason for hiding this comment

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

Feels over-engineered. Maybe just renaming maybe_redirect to maybe_trigger_form_action_or_redirect would be good enough?

Yeah, I agree. I appreciate you taking the time to try a different approach to see if we landed at something better. But it does seem to introduce more confusion. I think your original maybe_redirect implementation was best -- especially since you explained how trigger_action works. I thought it was more limited.

I think its best to mimmick LiveView JS to support all kinds of uses cases:

I think that's a good north star for sure. As we evaluate what to include and not include, I think there are two levels that I like to keep in mind:

  1. PhoenixTest not lie to users -- so, tests shouldn't pass if production is going to break.
  2. It's less bad for tests to break when production would pass (e.g. maybe we don't have a complete implementation). Ideally, we can match production, but I think this should always be secondary to (1).

All that being said, any chance to revert the last commit, and I think we might be good to go? Do you think it'd be helpful to write test cases for the scenarios you mentioned? (when a different event happens and the trigger-action still happens?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted and added tests.

Also stumbled over #143.

Copy link
Owner

@germsvel germsvel left a comment

Choose a reason for hiding this comment

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

Thanks again for doing this!

I have a few comments and questions that I hope are helpful. Let me know if anything is unclear. I can also try to help out with implementation more, but it seems like you're more up to speed with how phx-trigger-action works in LiveView.

lib/phoenix_test/live.ex Outdated Show resolved Hide resolved

session.conn
|> PhoenixTest.Static.build()
|> PhoenixTest.Static.submit_form(form.selector, form_data)
Copy link
Owner

Choose a reason for hiding this comment

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

I have a question here. Do you know what happens in a normal LiveView if a form has something like a phx-change that redirects you somewhere and it has a phx-trigger-action? Which redirect "wins out"?

In this case, we're giving "priority" to the phx-trigger-action, which I imagine is the right call since most times I'd expect phx-change not to be doing the redirecting. But I'm curious if we know what happens in those scenarios (and if we should even concern ourselves with them, or if it's just an edge case that we shouldn't cover).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think you maybe have misread the code. Or I'm wrong. Either way, I'm adding a test to clarify.

My understanding:
This implementation already prioritizes redirects or patches.
phx-trigger-action is only followed if no patch or redirect happened.
I'm pretty sure this is also what LiveView does.

These two clauses match first:

defp maybe_redirect({:error, {:redirect, %{to: path}}}, session) do
defp maybe_redirect({:error, {:live_redirect, %{to: path}}} = result, session) do

So, given

<form phx-trigger-action={@trigger_submit} phx-change="redirect">
handle_event("redirect", _, socket) do
  socket
  |> push_navigate(to: "/elsewhere")
  |> assign(:trigger_submit: true)
end

a change to the form will cause a redirect to /elsewhere. And ignore the phx-trigger-action.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Double checked the actual behaviour:

  • redirect: wins over phx-trigger-action (✅ this PR is ok)
  • navigate: wins over phx-trigger-action (✅ this PR is ok)
  • patch: is executed before phx-trigger-action, both are applied (✅ this PR is ok)

So I think we're fine.

You're right in that phx-trigger-action is given priority over maybe_put_patch_path.
But if there's a phx-trigger-action, there's no point in updating the session.current_path, because we're about to POST to another path anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Once again, running the same test against an actual browser as well as the Live driver would give peace of mind here :).

Comment on lines +351 to +353
session.conn
|> PhoenixTest.Static.build()
|> PhoenixTest.Static.submit_form(form.selector, form_data)
Copy link
Owner

Choose a reason for hiding this comment

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

I would imagine our implementation here is good. But I haven't done stuff with phx-trigger-action, so want to ask. Do you know if we should be using LiveViewTest's follow_trigger_action function to get the method and data to send?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looking at the follow_trigger_action, we should be fine.
It does the same things we're doing (ensure phx-trigger-action attr present, then use method and action to HTTP submit the form).

Should we use follow_trigger_action anyway?

Maybe.

In future the implementations might drift apart (theoretically, not saying it's likely).
Using follow_trigger_action under the hood would prevent that.

No, rather be consistent with how we submit static forms from LiveViews

We have a precedent in PhoenixTest: static form submits from a LiveView (without phx-trigger-action).

Form.has_action?(form) ->
session.conn
|> PhoenixTest.Static.build()
|> PhoenixTest.Static.submit_form(selector, form_data)

For that we could use LiveViewTest.submit_form. Which uses the same helper function as LiveViewTest.follow_trigger_action.

For the sake of simplicity (my interpretation) we don't do that and rather just call the Static driver directly.

|> fill_in("Trigger action", with: "engage")
|> submit()
|> assert_has("#form-data", text: "hidden: included")
|> assert_has("#form-data", text: "trigger_action: engage")
Copy link
Owner

Choose a reason for hiding this comment

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

🎉

test/support/index_live.ex Outdated Show resolved Hide resolved
<label>Trigger action <input type="text" name="trigger_action" /></label>
</form>

<button phx-click="trigger-form">Trigger from elsewhere</button>
Copy link
Owner

Choose a reason for hiding this comment

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

👍

@ftes ftes force-pushed the feature/phx-trigger-action branch from 7b1d975 to d62c264 Compare October 28, 2024 11:10
@ftes ftes requested a review from germsvel October 28, 2024 12:00
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.

Support phx-trigger-action
2 participants