graphql.rb 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. # Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
  2. require 'graphql/gql/shared_examples/fails_if_unauthenticated'
  3. module ZammadSpecSupportGraphql
  4. #
  5. # Taken from github.com/rmosolgo/graphql-ruby/blob/master/spec/graphql/subscriptions/action_cable_subscriptions_spec.rb
  6. #
  7. # A stub implementation of ActionCable.
  8. # Any methods to support the mock backend have `mock` in the name.
  9. class MockActionCable
  10. class MockChannel
  11. def initialize
  12. @mock_broadcasted_messages = []
  13. end
  14. attr_reader :mock_broadcasted_messages
  15. def stream_from(stream_name, coder: nil, &block)
  16. # Rails uses `coder`, we don't
  17. block ||= ->(msg) { @mock_broadcasted_messages << msg }
  18. MockActionCable.mock_stream_for(stream_name).add_mock_channel(self, block)
  19. end
  20. end
  21. class MockStream
  22. def initialize
  23. @mock_channels = {}
  24. end
  25. def add_mock_channel(channel, handler)
  26. @mock_channels[channel] = handler
  27. end
  28. def mock_broadcast(message)
  29. @mock_channels.each do |_channel, handler|
  30. handler&.call(message)
  31. end
  32. end
  33. end
  34. class << self
  35. def clear_mocks
  36. @mock_streams = {}
  37. end
  38. def server
  39. self
  40. end
  41. def broadcast(stream_name, message)
  42. stream = @mock_streams[stream_name]
  43. stream&.mock_broadcast(message)
  44. end
  45. def mock_stream_for(stream_name)
  46. @mock_streams[stream_name] ||= MockStream.new
  47. end
  48. def build_mock_channel
  49. MockChannel.new
  50. end
  51. def mock_stream_names
  52. @mock_streams.keys
  53. end
  54. end
  55. end
  56. def graphql_current_user=(user)
  57. @graphql_current_user = user
  58. end
  59. #
  60. # Run a graphql query.
  61. #
  62. def graphql_execute(query, variables: {}, context: {})
  63. context[:current_user] ||= @graphql_current_user
  64. if @graphql_current_user
  65. # TODO: we only fake a SID for now, create a real session?
  66. context[:sid] = SecureRandom.hex(16)
  67. end
  68. @graphql_result = Gql::ZammadSchema.execute(query, variables: variables, context: context)
  69. end
  70. #
  71. # Response of the previous graphql_execute call.
  72. #
  73. def graphql_response
  74. @graphql_result
  75. end
  76. #
  77. # Create a mock channel that can be passed to graphql_execute like this:
  78. #
  79. # let(:mock_channel) { build_mock_channel }
  80. #
  81. # graphql_execute(query, context: { channel: mock_channel })
  82. #
  83. delegate :build_mock_channel, to: MockActionCable
  84. #
  85. # Read a graphql query definition file from app/frontend/*.
  86. #
  87. def read_graphql_file(filename)
  88. File.read(Rails.root.join("app/frontend/#{filename}"))
  89. end
  90. end
  91. RSpec.configure do |config|
  92. config.include ZammadSpecSupportGraphql, type: :graphql
  93. config.prepend_before(:each, type: :graphql) do
  94. ZammadSpecSupportGraphql::MockActionCable.clear_mocks
  95. Gql::ZammadSchema.subscriptions = GraphQL::Subscriptions::ActionCableSubscriptions.new(
  96. action_cable: ZammadSpecSupportGraphql::MockActionCable, action_cable_coder: JSON, schema: Gql::ZammadSchema
  97. )
  98. end
  99. config.append_after(:each, type: :graphql) do
  100. Gql::ZammadSchema.subscriptions = GraphQL::Subscriptions::ActionCableSubscriptions.new(schema: Gql::ZammadSchema)
  101. end
  102. # This helper allows you to authenticate as a given user in request specs
  103. # via the example metadata, rather than directly:
  104. #
  105. # it 'does something', authenticated_as: :user
  106. #
  107. # In order for this to work, you must define the user in a `let` block first:
  108. #
  109. # let(:user) { create(:customer) }
  110. #
  111. config.before(:each, :authenticated_as, type: :graphql) do |example|
  112. self.graphql_current_user = authenticated_as_get_user example.metadata[:authenticated_as], return_type: :user
  113. end
  114. # Temporary Hack: skip tests if ENABLE_EXPERIMENTAL_MOBILE_FRONTEND is not set.
  115. # TODO: Remove when this switch is not needed any more.
  116. config.around(:each, type: :graphql) do |example|
  117. example.run if ENV['ENABLE_EXPERIMENTAL_MOBILE_FRONTEND'] == 'true'
  118. end
  119. end