graphql_devise 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +118 -0
  3. data/Appraisals +39 -5
  4. data/CHANGELOG.md +68 -6
  5. data/README.md +150 -51
  6. data/Rakefile +2 -1
  7. data/app/controllers/graphql_devise/concerns/additional_controller_methods.rb +72 -0
  8. data/app/controllers/graphql_devise/concerns/set_user_by_token.rb +5 -27
  9. data/app/controllers/graphql_devise/graphql_controller.rb +1 -1
  10. data/app/helpers/graphql_devise/mailer_helper.rb +2 -2
  11. data/app/models/graphql_devise/concerns/additional_model_methods.rb +21 -0
  12. data/app/models/graphql_devise/concerns/model.rb +6 -9
  13. data/docs/usage/reset_password_flow.md +90 -0
  14. data/graphql_devise.gemspec +2 -2
  15. data/lib/generators/graphql_devise/install_generator.rb +1 -1
  16. data/lib/graphql_devise.rb +20 -6
  17. data/lib/graphql_devise/concerns/controller_methods.rb +3 -3
  18. data/lib/graphql_devise/mount_method/operation_preparer.rb +6 -6
  19. data/lib/graphql_devise/mount_method/operation_preparers/custom_operation_preparer.rb +6 -4
  20. data/lib/graphql_devise/mount_method/operation_preparers/default_operation_preparer.rb +6 -4
  21. data/lib/graphql_devise/mount_method/operation_preparers/{resource_name_setter.rb → resource_klass_setter.rb} +4 -4
  22. data/lib/graphql_devise/resolvers/confirm_account.rb +1 -1
  23. data/lib/graphql_devise/resource_loader.rb +26 -11
  24. data/lib/graphql_devise/schema_plugin.rb +41 -18
  25. data/lib/graphql_devise/version.rb +1 -1
  26. data/spec/dummy/app/controllers/api/v1/graphql_controller.rb +13 -2
  27. data/spec/dummy/app/graphql/dummy_schema.rb +4 -3
  28. data/spec/dummy/app/graphql/types/query_type.rb +5 -0
  29. data/spec/dummy/config/routes.rb +2 -1
  30. data/spec/dummy/db/migrate/20200623003142_create_schema_users.rb +0 -1
  31. data/spec/dummy/db/migrate/20210516211417_add_vip_to_users.rb +5 -0
  32. data/spec/dummy/db/schema.rb +4 -4
  33. data/spec/generators/graphql_devise/install_generator_spec.rb +1 -1
  34. data/spec/graphql/user_queries_spec.rb +120 -0
  35. data/spec/requests/graphql_controller_spec.rb +12 -11
  36. data/spec/requests/queries/introspection_query_spec.rb +149 -0
  37. data/spec/requests/user_controller_spec.rb +93 -32
  38. data/spec/services/mount_method/operation_preparer_spec.rb +5 -5
  39. data/spec/services/mount_method/operation_preparers/custom_operation_preparer_spec.rb +5 -5
  40. data/spec/services/mount_method/operation_preparers/default_operation_preparer_spec.rb +5 -5
  41. data/spec/services/mount_method/operation_preparers/{resource_name_setter_spec.rb → resource_klass_setter_spec.rb} +6 -6
  42. data/spec/services/resource_loader_spec.rb +5 -5
  43. data/spec/support/contexts/graphql_request.rb +11 -3
  44. data/spec/support/contexts/schema_test.rb +14 -0
  45. metadata +25 -14
  46. data/.travis.yml +0 -79
@@ -4,23 +4,25 @@ module GraphqlDevise
4
4
  module MountMethod
5
5
  module OperationPreparers
6
6
  class DefaultOperationPreparer
7
- def initialize(selected_operations:, custom_keys:, mapping_name:, preparer:)
7
+ def initialize(selected_operations:, custom_keys:, model:, preparer:)
8
8
  @selected_operations = selected_operations
9
9
  @custom_keys = custom_keys
10
- @mapping_name = mapping_name
10
+ @model = model
11
11
  @preparer = preparer
12
12
  end
13
13
 
14
14
  def call
15
+ mapping_name = GraphqlDevise.to_mapping_name(@model)
16
+
15
17
  @selected_operations.except(*@custom_keys).each_with_object({}) do |(action, operation_info), result|
16
- mapped_action = "#{@mapping_name}_#{action}"
18
+ mapped_action = "#{mapping_name}_#{action}"
17
19
  operation = operation_info[:klass]
18
20
  options = operation_info.except(:klass)
19
21
 
20
22
  result[mapped_action.to_sym] = [
21
23
  OperationPreparers::GqlNameSetter.new(mapped_action),
22
24
  @preparer,
23
- OperationPreparers::ResourceNameSetter.new(@mapping_name)
25
+ OperationPreparers::ResourceKlassSetter.new(@model)
24
26
  ].reduce(child_class(operation)) do |prepared_operation, preparer|
25
27
  preparer.call(prepared_operation, **options)
26
28
  end
@@ -3,13 +3,13 @@
3
3
  module GraphqlDevise
4
4
  module MountMethod
5
5
  module OperationPreparers
6
- class ResourceNameSetter
7
- def initialize(name)
8
- @name = name
6
+ class ResourceKlassSetter
7
+ def initialize(klass)
8
+ @klass = klass
9
9
  end
10
10
 
11
11
  def call(operation, **)
12
- operation.instance_variable_set(:@resource_name, @name)
12
+ operation.instance_variable_set(:@resource_klass, @klass)
13
13
 
14
14
  operation
15
15
  end
@@ -32,7 +32,7 @@ module GraphqlDevise
32
32
  end
33
33
 
34
34
  controller.redirect_to(redirect_to_link)
35
- { authenticatable: resource }
35
+ resource
36
36
  else
37
37
  raise_user_error(I18n.t('graphql_devise.confirmations.invalid_token'))
38
38
  end
@@ -10,12 +10,27 @@ module GraphqlDevise
10
10
  end
11
11
 
12
12
  def call(query, mutation)
13
- mapping_name = @resource.to_s.underscore.tr('/', '_').to_sym
14
-
15
13
  # clean_options responds to all keys defined in GraphqlDevise::MountMethod::SUPPORTED_OPTIONS
16
14
  clean_options = GraphqlDevise::MountMethod::OptionSanitizer.new(@options).call!
17
15
 
18
- return clean_options if GraphqlDevise.resource_mounted?(mapping_name) && @routing
16
+ model = if @resource.is_a?(String)
17
+ ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc, caller)
18
+ Providing a String as the model you want to mount is deprecated and will be removed in a future version of
19
+ this gem. Please use the actual model constant instead.
20
+
21
+ EXAMPLE
22
+
23
+ GraphqlDevise::ResourceLoader.new(User) # instead of GraphqlDevise::ResourceLoader.new('User')
24
+
25
+ mount_graphql_devise_for User # instead of mount_graphql_devise_for 'User'
26
+ DEPRECATION
27
+ @resource.constantize
28
+ else
29
+ @resource
30
+ end
31
+
32
+ # Necesary when mounting a resource via route file as Devise forces the reloading of routes
33
+ return clean_options if GraphqlDevise.resource_mounted?(model) && @routing
19
34
 
20
35
  validate_options!(clean_options)
21
36
 
@@ -23,7 +38,7 @@ module GraphqlDevise
23
38
  "Types::#{@resource}Type".safe_constantize ||
24
39
  GraphqlDevise::Types::AuthenticatableType
25
40
 
26
- prepared_mutations = prepare_mutations(mapping_name, clean_options, authenticatable_type)
41
+ prepared_mutations = prepare_mutations(model, clean_options, authenticatable_type)
27
42
 
28
43
  if prepared_mutations.any? && mutation.blank?
29
44
  raise GraphqlDevise::Error, 'You need to provide a mutation type unless all mutations are skipped'
@@ -33,7 +48,7 @@ module GraphqlDevise
33
48
  mutation.field(action, mutation: prepared_mutation, authenticate: false)
34
49
  end
35
50
 
36
- prepared_resolvers = prepare_resolvers(mapping_name, clean_options, authenticatable_type)
51
+ prepared_resolvers = prepare_resolvers(model, clean_options, authenticatable_type)
37
52
 
38
53
  if prepared_resolvers.any? && query.blank?
39
54
  raise GraphqlDevise::Error, 'You need to provide a query type unless all queries are skipped'
@@ -43,17 +58,17 @@ module GraphqlDevise
43
58
  query.field(action, resolver: resolver, authenticate: false)
44
59
  end
45
60
 
46
- GraphqlDevise.add_mapping(mapping_name, @resource)
47
- GraphqlDevise.mount_resource(mapping_name) if @routing
61
+ GraphqlDevise.add_mapping(GraphqlDevise.to_mapping_name(@resource).to_sym, @resource)
62
+ GraphqlDevise.mount_resource(model) if @routing
48
63
 
49
64
  clean_options
50
65
  end
51
66
 
52
67
  private
53
68
 
54
- def prepare_resolvers(mapping_name, clean_options, authenticatable_type)
69
+ def prepare_resolvers(model, clean_options, authenticatable_type)
55
70
  GraphqlDevise::MountMethod::OperationPreparer.new(
56
- mapping_name: mapping_name,
71
+ model: model,
57
72
  custom: clean_options.operations,
58
73
  additional_operations: clean_options.additional_queries,
59
74
  preparer: GraphqlDevise::MountMethod::OperationPreparers::ResolverTypeSetter.new(authenticatable_type),
@@ -63,9 +78,9 @@ module GraphqlDevise
63
78
  ).call
64
79
  end
65
80
 
66
- def prepare_mutations(mapping_name, clean_options, authenticatable_type)
81
+ def prepare_mutations(model, clean_options, authenticatable_type)
67
82
  GraphqlDevise::MountMethod::OperationPreparer.new(
68
- mapping_name: mapping_name,
83
+ model: model,
69
84
  custom: clean_options.operations,
70
85
  additional_operations: clean_options.additional_mutations,
71
86
  preparer: GraphqlDevise::MountMethod::OperationPreparers::MutationFieldSetter.new(authenticatable_type),
@@ -2,18 +2,20 @@
2
2
 
3
3
  module GraphqlDevise
4
4
  class SchemaPlugin
5
+ # NOTE: Based on GQL-Ruby docs https://graphql-ruby.org/schema/introspection.html
6
+ INTROSPECTION_FIELDS = ['__schema', '__type', '__typename']
5
7
  DEFAULT_NOT_AUTHENTICATED = ->(field) { raise GraphqlDevise::AuthenticationError, "#{field} field requires authentication" }
6
8
 
7
- def initialize(query: nil, mutation: nil, authenticate_default: true, resource_loaders: [], unauthenticated_proc: DEFAULT_NOT_AUTHENTICATED)
9
+ def initialize(query: nil, mutation: nil, authenticate_default: true, public_introspection: !Rails.env.production?, resource_loaders: [], unauthenticated_proc: DEFAULT_NOT_AUTHENTICATED)
8
10
  @query = query
9
11
  @mutation = mutation
10
12
  @resource_loaders = resource_loaders
11
13
  @authenticate_default = authenticate_default
14
+ @public_introspection = public_introspection
12
15
  @unauthenticated_proc = unauthenticated_proc
13
16
 
14
17
  # Must happen on initialize so operations are loaded before the types are added to the schema on GQL < 1.10
15
18
  load_fields
16
- reconfigure_warden!
17
19
  end
18
20
 
19
21
  def use(schema_definition)
@@ -24,14 +26,27 @@ module GraphqlDevise
24
26
  # Authenticate only root level queries
25
27
  return yield unless event == 'execute_field' && path(trace_data).count == 1
26
28
 
27
- field = traced_field(trace_data)
28
- provided_value = authenticate_option(field, trace_data)
29
- context = set_current_resource(context_from_data(trace_data))
29
+ field = traced_field(trace_data)
30
+ auth_required = authenticate_option(field, trace_data)
31
+ context = context_from_data(trace_data)
30
32
 
31
- if !provided_value.nil?
32
- raise_on_missing_resource(context, field) if provided_value
33
- elsif @authenticate_default
34
- raise_on_missing_resource(context, field)
33
+ if context.key?(:resource_name)
34
+ ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc, caller)
35
+ Providing `resource_name` as part of the GQL context, or doing so by using the `graphql_context(resource_name)`
36
+ method on your controller is deprecated and will be removed in a future version of this gem.
37
+ Please use `gql_devise_context` in you controller instead.
38
+
39
+ EXAMPLE
40
+ include GraphqlDevise::Concerns::SetUserByToken
41
+
42
+ DummySchema.execute(params[:query], context: gql_devise_context(User))
43
+ DummySchema.execute(params[:query], context: gql_devise_context(User, Admin))
44
+ DEPRECATION
45
+ end
46
+
47
+ if auth_required && !(public_introspection && introspection_field?(field))
48
+ context = set_current_resource(context)
49
+ raise_on_missing_resource(context, field, auth_required)
35
50
  end
36
51
 
37
52
  yield
@@ -39,10 +54,13 @@ module GraphqlDevise
39
54
 
40
55
  private
41
56
 
57
+ attr_reader :public_introspection
58
+
42
59
  def set_current_resource(context)
43
- controller = context[:controller]
44
- resource_names = Array(context[:resource_name])
45
- context[:current_resource] = resource_names.find do |resource_name|
60
+ controller = context[:controller]
61
+ resource_names = Array(context[:resource_name])
62
+
63
+ context[:current_resource] ||= resource_names.find do |resource_name|
46
64
  unless Devise.mappings.key?(resource_name)
47
65
  raise(
48
66
  GraphqlDevise::Error,
@@ -57,8 +75,12 @@ module GraphqlDevise
57
75
  context
58
76
  end
59
77
 
60
- def raise_on_missing_resource(context, field)
78
+ def raise_on_missing_resource(context, field, auth_required)
61
79
  @unauthenticated_proc.call(field.name) if context[:current_resource].blank?
80
+
81
+ if auth_required.respond_to?(:call) && !auth_required.call(context[:current_resource])
82
+ @unauthenticated_proc.call(field.name)
83
+ end
62
84
  end
63
85
 
64
86
  def context_from_data(trace_data)
@@ -88,16 +110,13 @@ module GraphqlDevise
88
110
  end
89
111
 
90
112
  def authenticate_option(field, trace_data)
91
- if trace_data[:context]
113
+ auth_required = if trace_data[:context]
92
114
  field.metadata[:authenticate]
93
115
  else
94
116
  field.graphql_definition.metadata[:authenticate]
95
117
  end
96
- end
97
118
 
98
- def reconfigure_warden!
99
- Devise.class_variable_set(:@@warden_configured, nil)
100
- Devise.configure_warden!
119
+ auth_required.nil? ? @authenticate_default : auth_required
101
120
  end
102
121
 
103
122
  def load_fields
@@ -107,6 +126,10 @@ module GraphqlDevise
107
126
  resource_loader.call(@query, @mutation)
108
127
  end
109
128
  end
129
+
130
+ def introspection_field?(field)
131
+ INTROSPECTION_FIELDS.include?(field.name)
132
+ end
110
133
  end
111
134
  end
112
135
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GraphqlDevise
4
- VERSION = '0.14.0'.freeze
4
+ VERSION = '0.16.0'.freeze
5
5
  end
@@ -6,19 +6,30 @@ module Api
6
6
  include GraphqlDevise::Concerns::SetUserByToken
7
7
 
8
8
  def graphql
9
- result = DummySchema.execute(params[:query], execute_params(params))
9
+ result = DummySchema.execute(params[:query], **execute_params(params))
10
10
 
11
11
  render json: result unless performed?
12
12
  end
13
13
 
14
14
  def interpreter
15
- render json: InterpreterSchema.execute(params[:query], execute_params(params))
15
+ render json: InterpreterSchema.execute(params[:query], **execute_params(params))
16
16
  end
17
17
 
18
18
  def failing_resource_name
19
19
  render json: DummySchema.execute(params[:query], context: graphql_context([:user, :fail]))
20
20
  end
21
21
 
22
+ def controller_auth
23
+ result = DummySchema.execute(
24
+ params[:query],
25
+ operation_name: params[:operationName],
26
+ variables: ensure_hash(params[:variables]),
27
+ context: gql_devise_context(SchemaUser, User)
28
+ )
29
+
30
+ render json: result unless performed?
31
+ end
32
+
22
33
  private
23
34
 
24
35
  def execute_params(item)
@@ -2,9 +2,10 @@
2
2
 
3
3
  class DummySchema < GraphQL::Schema
4
4
  use GraphqlDevise::SchemaPlugin.new(
5
- query: Types::QueryType,
6
- mutation: Types::MutationType,
7
- resource_loaders: [
5
+ query: Types::QueryType,
6
+ mutation: Types::MutationType,
7
+ public_introspection: true,
8
+ resource_loaders: [
8
9
  GraphqlDevise::ResourceLoader.new(
9
10
  'User',
10
11
  only: [
@@ -5,6 +5,7 @@ module Types
5
5
  field :user, resolver: Resolvers::UserShow
6
6
  field :public_field, String, null: false, authenticate: false
7
7
  field :private_field, String, null: false, authenticate: true
8
+ field :vip_field, String, null: false, authenticate: ->(user) { user.is_a?(User) && user.vip? }
8
9
 
9
10
  def public_field
10
11
  'Field does not require authentication'
@@ -13,5 +14,9 @@ module Types
13
14
  def private_field
14
15
  'Field will always require authentication'
15
16
  end
17
+
18
+ def vip_field
19
+ 'Field available only for VIP Users'
20
+ end
16
21
  end
17
22
  end
@@ -11,7 +11,7 @@ Rails.application.routes.draw do
11
11
  }
12
12
 
13
13
  mount_graphql_devise_for(
14
- 'Admin',
14
+ Admin,
15
15
  authenticatable_type: Types::CustomAdminType,
16
16
  skip: [:sign_up, :check_password_token],
17
17
  operations: {
@@ -37,4 +37,5 @@ Rails.application.routes.draw do
37
37
  post '/api/v1/graphql', to: 'api/v1/graphql#graphql'
38
38
  post '/api/v1/interpreter', to: 'api/v1/graphql#interpreter'
39
39
  post '/api/v1/failing', to: 'api/v1/graphql#failing_resource_name'
40
+ post '/api/v1/controller_auth', to: 'api/v1/graphql#controller_auth'
40
41
  end
@@ -41,6 +41,5 @@ class CreateSchemaUsers < ActiveRecord::Migration[6.0]
41
41
  add_index :schema_users, [:uid, :provider], unique: true
42
42
  add_index :schema_users, :reset_password_token, unique: true
43
43
  add_index :schema_users, :confirmation_token, unique: true
44
- add_index :schema_users, :unlock_token, unique: true
45
44
  end
46
45
  end
@@ -0,0 +1,5 @@
1
+ class AddVipToUsers < ActiveRecord::Migration[6.1]
2
+ def change
3
+ add_column :users, :vip, :boolean, null: false, default: false
4
+ end
5
+ end
@@ -2,15 +2,15 @@
2
2
  # of editing this file, please use the migrations feature of Active Record to
3
3
  # incrementally modify your database, and then regenerate this schema definition.
4
4
  #
5
- # This file is the source Rails uses to define your schema when running `rails
6
- # db:schema:load`. When creating a new database, `rails db:schema:load` tends to
5
+ # This file is the source Rails uses to define your schema when running `bin/rails
6
+ # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
7
7
  # be faster and is potentially less error prone than running all of your
8
8
  # migrations from scratch. Old migrations may fail to apply correctly if those
9
9
  # migrations use external dependencies or application code.
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 2020_06_23_003142) do
13
+ ActiveRecord::Schema.define(version: 2021_05_16_211417) do
14
14
 
15
15
  create_table "admins", force: :cascade do |t|
16
16
  t.string "provider", default: "email", null: false
@@ -73,7 +73,6 @@ ActiveRecord::Schema.define(version: 2020_06_23_003142) do
73
73
  t.text "tokens"
74
74
  t.datetime "created_at", precision: 6, null: false
75
75
  t.datetime "updated_at", precision: 6, null: false
76
- t.index "\"unlock_token\"", name: "index_schema_users_on_unlock_token", unique: true
77
76
  t.index ["confirmation_token"], name: "index_schema_users_on_confirmation_token", unique: true
78
77
  t.index ["email"], name: "index_schema_users_on_email", unique: true
79
78
  t.index ["reset_password_token"], name: "index_schema_users_on_reset_password_token", unique: true
@@ -106,6 +105,7 @@ ActiveRecord::Schema.define(version: 2020_06_23_003142) do
106
105
  t.datetime "created_at", null: false
107
106
  t.datetime "updated_at", null: false
108
107
  t.boolean "auth_available", default: true, null: false
108
+ t.boolean "vip", default: false, null: false
109
109
  t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
110
110
  t.index ["email"], name: "index_users_on_email", unique: true
111
111
  t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
@@ -33,7 +33,7 @@ RSpec.describe GraphqlDevise::InstallGenerator, type: :generator do
33
33
 
34
34
  assert_file 'app/controllers/application_controller.rb', /^\s{2}include GraphqlDevise::Concerns::SetUserByToken/
35
35
 
36
- assert_file 'app/graphql/gqld_dummy_schema.rb', /\s+#{Regexp.escape("GraphqlDevise::ResourceLoader.new('Admin')")}/
36
+ assert_file 'app/graphql/gqld_dummy_schema.rb', /\s+#{Regexp.escape("GraphqlDevise::ResourceLoader.new(Admin)")}/
37
37
  end
38
38
  end
39
39
 
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe 'Users controller specs' do
6
+ include_context 'with graphql schema test'
7
+
8
+ let(:schema) { DummySchema }
9
+ let(:user) { create(:user, :confirmed) }
10
+ let(:field) { 'privateField' }
11
+ let(:public_message) { 'Field does not require authentication' }
12
+ let(:private_message) { 'Field will always require authentication' }
13
+ let(:private_error) do
14
+ {
15
+ message: "#{field} field requires authentication",
16
+ extensions: { code: 'AUTHENTICATION_ERROR' }
17
+ }
18
+ end
19
+
20
+ describe 'publicField' do
21
+ let(:query) do
22
+ <<-GRAPHQL
23
+ query {
24
+ publicField
25
+ }
26
+ GRAPHQL
27
+ end
28
+
29
+ context 'when using a regular schema' do
30
+ it 'does not require authentication' do
31
+ expect(response[:data][:publicField]).to eq(public_message)
32
+ end
33
+ end
34
+ end
35
+
36
+ describe 'privateField' do
37
+ let(:query) do
38
+ <<-GRAPHQL
39
+ query {
40
+ privateField
41
+ }
42
+ GRAPHQL
43
+ end
44
+
45
+ context 'when using a regular schema' do
46
+ context 'when user is authenticated' do
47
+ let(:resource) { user }
48
+
49
+ it 'allows to perform the query' do
50
+ expect(response[:data][:privateField]).to eq(private_message)
51
+ end
52
+
53
+ context 'when using a SchemaUser' do
54
+ let(:resource) { create(:schema_user, :confirmed) }
55
+
56
+ it 'allows to perform the query' do
57
+ expect(response[:data][:privateField]).to eq(private_message)
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ context 'when using an interpreter schema' do
64
+ let(:schema) { InterpreterSchema }
65
+
66
+ context 'when user is authenticated' do
67
+ let(:resource) { user }
68
+
69
+ it 'allows to perform the query' do
70
+ expect(response[:data][:privateField]).to eq(private_message)
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ describe 'user' do
77
+ let(:user_data) { { email: user.email, id: user.id } }
78
+ let(:query) do
79
+ <<-GRAPHQL
80
+ query {
81
+ user(
82
+ id: #{user.id}
83
+ ) {
84
+ id
85
+ email
86
+ }
87
+ }
88
+ GRAPHQL
89
+ end
90
+
91
+ context 'when using a regular schema' do
92
+ context 'when user is authenticated' do
93
+ let(:resource) { user }
94
+
95
+ it 'allows to perform the query' do
96
+ expect(response[:data][:user]).to match(**user_data)
97
+ end
98
+ end
99
+ end
100
+
101
+ context 'when using an interpreter schema' do
102
+ let(:schema) { InterpreterSchema }
103
+
104
+ context 'when user is authenticated' do
105
+ let(:resource) { user }
106
+
107
+ it 'allows to perform the query' do
108
+ expect(response[:data][:user]).to match(**user_data)
109
+ end
110
+ end
111
+
112
+ context 'when user is not authenticated' do
113
+ # Interpreter schema fields are public unless specified otherwise (plugin setting)
114
+ it 'allows to perform the query' do
115
+ expect(response[:data][:user]).to match(**user_data)
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end