Trigger doesn't fire rspec have_broadcasted_to
Describe the bug Switched to anycable from straight up AC. Trying to convert tests and the old tests that used to pass, now fail with 0 broadcasts. The app itself works fine with updates to AnyCable.
rspec test looks like this
it 'does project socket broadcast' do
expect do
subject.process(message_hash) # this calls the trigger listed below in it's process
end.to have_broadcasted_to("graphql-event::liveProject:projectId:#{project.id}")
end
Trigger is called this way...
MainApiSchema.subscriptions.trigger('liveActivityFeed', { project_id: project.id }, { item: feed })
Versions ruby: 2.6.3 rails (or other framework): 6.0.3.2 graphql: 1.11 graphql-anycable: 0.4.0 anycable: 1.0.1
GraphQL schema
module Types
class ActivityFeedItemType < Types::BaseObject
description 'Events that are associated to a project.'
field :id, Integer, null: false
field :category, String, null: false
field :topic, String, null: false
field :reference, String, null: false, method: :reference_type
field :reference_id, Integer, null: false
field :metadata, Types::Scalars::Json, null: false
field :created_from_type, String, null: false
field :created_from_id, Integer, null: false
field :created_at, GraphQL::Types::ISO8601DateTime, null: false, method: :reference_created_at
def metadata
object.metadata['data']
end
end
end
class MainApiSchema < GraphQL::Schema
mutation(Types::MutationType)
query(Types::QueryType)
subscription(Types::SubscriptionType)
# enable batch loading
use BatchLoader::GraphQL
use GraphQL::Tracing::NewRelicTracing
use GraphQL::Subscriptions::AnyCableSubscriptions
use GraphQL::Execution::Interpreter
use GraphQL::Analysis::AST
use GraphQL::Execution::Errors
end
module Subscriptions
class ActivityFeedSubscription < Subscriptions::BaseSubscription
description 'An activity feed item was added to the project'
argument :project_id, ID, required: true
field :item,
Types::ActivityFeedItemType,
null: true,
description: 'New feed item added for a project'
end
end
GraphQL query
How do you subscribe to subscriptions?
subscription onActivityFeedCreated($projectId: ID!){
liveActivityFeed(projectId: $projectId) {
item {
...feedFragment
}
}
fragment feedFragment on ActivityFeedItem {
id
topic
category
reference
referenceId
metadata
createdAt
createdFromType
createdFromId
}
Steps to reproduce Create rspec test and call. You can skip the middleman with my subject.call method and just put trigger in there.
it 'does feed socket broadcast' do
expect do
MainApiSchema.subscriptions.trigger('liveActivityFeed', { project_id: project.id }, { item: feedItem })
end.to have_broadcasted_to("graphql-event::liveActivityFeed:projectId:#{project.id}")
end
Expected behavior have_broadcasted_to should return true
Actual behavior Error in rspec log:
ArtifactAssociatedConsumer#process_message when the artifact is present does socket broadcast
Failure/Error:
expect do
subject.process(message_hash)
end.to have_broadcasted_to("graphql-event::liveActivityFeed:projectId:#{project.id}")
expected to broadcast exactly 1 messages to graphql-event::liveActivityFeed:projectId:13, but broadcast 0
# ./spec/consumers/artifact_associated_consumer_spec.rb:77:in `block (4 levels) in <top (required)>'
Additional context Cable yml looks like this...
development:
adapter: <%= ENV.fetch("ACTION_CABLE_ADAPTER", "any_cable") %>
test:
adapter: test
production:
adapter: <%= ENV.fetch("ACTION_CABLE_ADAPTER", "any_cable") %>
and my other config settings are per AnyCable documentation
Thank you for pointing it out! @palkan, any thoughts?
I have no idea for now and it will require some time to investigate. I hope I will be able to dig into it next week maybe.
I believe this happens because we broadcast directly via AnyCable, not via ActionCable.server.pubsub: https://github.com/anycable/graphql-anycable/blob/a0b48167327170add168714055940b2c297b6dc9/lib/graphql/subscriptions/anycable_subscriptions.rb#L83
The workaround for this could be adding a Rails specific Subscriptions class, which inherits from AnyCableSubscriptions and overrides the #deliver method to use Action Cable.
Thx for feedback. Since this is in our testing, we changed our tests to make sure the trigger is getting called...
expect_any_instance_of(GraphQL::Subscriptions::AnyCableSubscriptions).to receive(:trigger).with('liveActivityFeed', { project_id: project.id }, { item: be_present })
We also stubbed out the trigger call so our external CI tools didn't require redis_url
we broadcast directly via AnyCable, not via ActionCable.server.pubsub:
This is because we want it to be also usable without Rails. Not sure how to fix it there at the moment.
Not sure how to fix it there at the moment.
This
The workaround for this could be adding a Rails specific Subscriptions class, which inherits from AnyCableSubscriptions