Elixir 1.7.3 (compiled with Erlang/OTP 19)
~~~~
The trigger configuration within the schema should also cause subscription data to be published within tests.
At first a bit more context. I am currently following along the Craft GraphQL APIs in Elixir with Absinthe book. Also, instead of just running the example code, I am implementing the PlateSlate application following the books narrative by hand (only diverging a bit with regards to file placement, module naming and package versions).
While taking a stab at the exercises for chapter 8 I came across a rather strange problem that I don鈥檛 seem to find a solution for.
For reference, I have created an example repository.
To the point, employees can update the order and both can subscribe to updates on the orders (but customers may only receive updates for their own orders). So the exercises prompted me to limit the subscriptions on the updateOrder field.
Within the graphiql (advanced) interface this all seems to work well, but when it comes to the test cases for updating the order (update to ready and complete) it seems that the trigger configured within the updateOrder field is not executed and therefore no subscriptions data is being pushed.
(Please note that instead of blocking the subscription right away for customers on orders they don't own, I opted to try to allow those subscriptions to happen but to limit the publication's audience by topic)
While running the tests with mix test / mix test.watch, the following error is generated:
~~~~
Running tests...
Excluding tags: [:skip]
...................
1) test customers can't see completion updates to other customer's orders (PlateSlateWeb.GraphQL.Subscription.UpdateOrderTest)
test/plate_slate_web/graphql/subscription_update_order_test.exs:128
No message matching %Phoenix.Socket.Message{event: "subscription:data", payload: _} after 100ms.
The process mailbox is empty.
code: assert_push "subscription:data", _
stacktrace:
test/plate_slate_web/graphql/subscription_update_order_test.exs:166: (test)
....
Finished in 1.4 seconds
24 tests, 1 failure
~~~~
The field implementation:
~~~~
field :update_order, :order do
arg :id, non_null(:id)
config fn args, %{context: context} ->
case context[:current_user] do
%{role: "employee"} ->
{:ok, topic: "order:#{args.id}"}
%{role: "customer", id: id} ->
{:ok, topic: "of_customer:#{id}:#{args.id}"}
_ ->
{:error, "unauthorized"}
end
end
trigger :complete_order, topic: fn
%{order: order} ->
[
"order:#{order.id}",
"of_customer:#{order.customer_number}:#{order.id}",
]
_ -> []
end
resolve fn %{order: order}, _, _ ->
{:ok, order}
end
end
~~~~
The resolver:
~~~
def complete_order(_, %{id: id}, _) do
order = Ordering.get_order!(id)
with {:ok, order} <- Ordering.update_order(order, %{state: "complete"}) do
{:ok, %{order: order}}
end
end
~
The relevant test .. IMO a bit too long to paste here.
The test itself does create a customer, an employee as well as two orders (one for an imaginary customer with a non existent customer number and one for the created one). The socket is authenticated using the customer within the context. Then the customer subscribes to both created orders.
The first subscription (on the first order; from the other customer) does not receive any subscription data. The second, however, should but it also does not receive the data.
In order to check if manually pushing the data works, I left a bit of publication code commented over here. When I uncomment that piece of code, the tests will succeed.
Hey @rmoorman I hope you're liking the book. You're super close to getting it to work. This line here:
needs to specify the pubsub via: %{context: %{current_user: employee, pubsub: PlateSlateWeb.Endpoint}. Without that there's no mechanism to broadcast. I should probably have Absinthe emit a warning if a mutation has triggers configured but no pubsub is supplied.
When using Absinthe.Plug it can figure out the pubsub based on the endpoint. For manual Absinthe.run calls you need to supply that yourself.
@benwilson512, thank you for taking the time to look into this. I really like the book; especially the breadth of the topics covered; but then also with a lot of detail.
A warning or a little note in the docs somewhere around the documentation of the trigger macro function would have been helpful indeed :-). Shall I try to write up a note for the documentation?
Just ran into this as well and was able to find this issue and sort it out! Thanks for the explanation!
Most helpful comment
Hey @rmoorman I hope you're liking the book. You're super close to getting it to work. This line here:
https://github.com/rmoorman/absinthe-subscription-issues-20181030/blob/master/plate_slate/test/plate_slate_web/graphql/subscription_update_order_test.exs#L187
needs to specify the pubsub via:
%{context: %{current_user: employee, pubsub: PlateSlateWeb.Endpoint}. Without that there's no mechanism to broadcast. I should probably have Absinthe emit a warning if a mutation has triggers configured but no pubsub is supplied.When using Absinthe.Plug it can figure out the pubsub based on the endpoint. For manual
Absinthe.runcalls you need to supply that yourself.