Add process-local endpoint configuration via PhoenixTest.Config#307
Add process-local endpoint configuration via PhoenixTest.Config#307nbernardes wants to merge 1 commit intogermsvel:mainfrom
PhoenixTest.Config#307Conversation
|
Hey @germsvel, is it possible to take a look at this? particularly useful for umbrellas with multiple endpoints |
germsvel
left a comment
There was a problem hiding this comment.
Thanks so much for opening this PR! 🙏
Sorry it took so long to review. I didn't even realize this was open (somehow). But I've also been very busy. So, thanks for the patience.
I'm not opposed to introducing this. I don't typically work in Umbrella apps, but I can see what you mean by needing it with phoenix test playwright and umbrella apps.
I left a few suggestions that I think would make it better. If something is unclear, let me know. Happy to chat more about it.
| test "raises when no endpoint configured" do | ||
| Process.delete(:phoenix_test_endpoint) | ||
| original = Application.get_env(:phoenix_test, :endpoint) | ||
| Application.delete_env(:phoenix_test, :endpoint) |
There was a problem hiding this comment.
I think this test makes it so we can't run this in async: true mode (since we're updating application config). Sadly, we may have to set async: false
| drivers can resolve the endpoint too. | ||
|
|
||
| 2. You can set it at compile time in `config/test.exs`: | ||
| 3. You can set a global fallback in `config/test.exs`: |
There was a problem hiding this comment.
I realize this was already set as #2 (and we're just changing it to #3), but now that we're adding another option, it makes this seem less preferred.
I still think the global config is the most common and simplest option. Since most apps aren't umbrella apps, I'd like to keep it as the "default" for people. So, I'd like to keep it as the first option. And only the people who can't use it like that can look at what other options to opt into.
So, could we set this as option 1? Then using the put_endpoint on the conn as second, and only mentioned the per-process Config one as third?
That makes sense in my head because it goes from basic to complex:
- Single Phoenix app - use global
- Umbrella app without JS - use
put_endpointfor conn - Umbrella app with JS and needs per-process stuff, use the new thing.
|
|
||
| @process_key :phoenix_test_endpoint | ||
|
|
||
| def put_endpoint(endpoint) when is_atom(endpoint) do |
There was a problem hiding this comment.
I think it'll be confusing that we have a PhoenixTest.put_endpoint and a PhoenixTest.Config.put_endpoint. Rather than do that, I wonder if we create a new function and call it PhoenixTest.put_process_endpoint. Perhaps it's a little to explicit, but it's (hopefully) clear.
What do you think?
| No endpoint configured for PhoenixTest. | ||
|
|
||
| Set it per-test-process in your test setup (recommended for umbrella apps): | ||
|
|
||
| setup do | ||
| PhoenixTest.Config.put_endpoint(MyAppWeb.Endpoint) | ||
| :ok | ||
| end | ||
|
|
||
| Or set it on the conn directly: | ||
|
|
||
| {:ok, conn: Phoenix.ConnTest.build_conn() |> PhoenixTest.put_endpoint(MyAppWeb.Endpoint)} | ||
|
|
||
| Or set it globally in config/test.exs: | ||
|
|
||
| config :phoenix_test, :endpoint, MyAppWeb.Endpoint | ||
| """ |
There was a problem hiding this comment.
Can we also invert the order in which we show these messages? (see my other comment).
I'd prefer it to be like this since it goes from simple & common case to more complex and less common (at least in my mind):
- global
- build_conn |> put_endpoint
- process put_endpoint
Problem
When using
phoenix_test, the endpoint needs to vary depending on which test suite is running. In umbrella apps or projects with multiple Phoenix endpoints,Application.get_env(:phoenix_test, :endpoint)is global, so it can't differ per test suite and isn't safe when running tests in parallel.put_endpoint/2solves this for standard PhoenixTest (it sets conn.private), but external drivers likephoenix_test_playwrightread the endpoint from Application config directly since they don't usePlug.Conn.Solution
Introduce
PhoenixTest.Config.put_endpoint/1which stores the endpoint in the process dictionary. Since eachExUnittest runs in its own process, different test suites can set different endpoints without interfering with each other.Endpoint resolution chain:
conn.private[:phoenix_endpoint](per-conn)Application.get_env(:phoenix_test, :endpoint)(global fallback)put_endpoint/2now also sets the process-level config, so both approaches stay in sync.Usage
Fully backward-compatible - existing config :phoenix_test, :endpoint setups continue to work unchanged.