mumuki-laboratory 5.0.12 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +339 -0
  3. data/app/assets/javascripts/application/bridge.js +36 -7
  4. data/app/assets/javascripts/application/kids.js +92 -7
  5. data/app/assets/javascripts/application/submission.js +2 -1
  6. data/app/assets/stylesheets/application/modules/_highlight.scss +8 -0
  7. data/app/assets/stylesheets/application/modules/_kids.scss +92 -27
  8. data/app/controllers/api/base_controller.rb +23 -0
  9. data/app/controllers/api/courses_controller.rb +26 -0
  10. data/app/controllers/api/organizations_controller.rb +28 -0
  11. data/app/controllers/api/roles_controller.rb +47 -0
  12. data/app/controllers/api/students_controller.rb +9 -0
  13. data/app/controllers/api/teachers_controller.rb +9 -0
  14. data/app/controllers/api/users_controller.rb +18 -0
  15. data/app/controllers/assets_controller.rb +2 -1
  16. data/app/controllers/concerns/on_base_organization_only.rb +11 -0
  17. data/app/controllers/concerns/organizations_controller_template.rb +34 -0
  18. data/app/controllers/concerns/users_controller_template.rb +28 -0
  19. data/app/controllers/concerns/with_api_errors.rb +37 -0
  20. data/app/controllers/concerns/with_authorization.rb +19 -0
  21. data/app/controllers/concerns/with_errors_filter.rb +32 -0
  22. data/app/helpers/reset_button_helper.rb +1 -1
  23. data/app/models/api_client.rb +27 -0
  24. data/app/models/api_client_spec.rb +6 -0
  25. data/app/models/concerns/with_assignments.rb +4 -1
  26. data/app/models/course.rb +4 -6
  27. data/app/models/exercise/challenge.rb +5 -6
  28. data/app/models/language.rb +1 -1
  29. data/app/models/organization.rb +4 -0
  30. data/app/models/user.rb +22 -1
  31. data/app/views/exercise_solutions/_kids_results_button.html.erb +11 -0
  32. data/app/views/exercise_solutions/_results.html.erb +1 -7
  33. data/app/views/exercise_solutions/_results_button.html.erb +7 -0
  34. data/app/views/layouts/_kids.html.erb +5 -2
  35. data/app/views/layouts/exercise_inputs/editors/_custom.html.erb +1 -0
  36. data/app/views/layouts/exercise_inputs/forms/_kids_form.html.erb +3 -0
  37. data/app/views/layouts/exercise_inputs/layouts/_input_kids.html.erb +3 -3
  38. data/app/views/layouts/modals/_kids_context.html.erb +0 -3
  39. data/app/views/layouts/modals/_kids_results.html.erb +2 -0
  40. data/config/routes.rb +23 -0
  41. data/db/migrate/20180129142749_add_api_client.rb +11 -0
  42. data/lib/mumuki/laboratory/controllers/results_rendering.rb +7 -1
  43. data/lib/mumuki/laboratory/extensions/string.rb +8 -0
  44. data/lib/mumuki/laboratory/locales/en.yml +4 -0
  45. data/lib/mumuki/laboratory/locales/es.yml +4 -0
  46. data/lib/mumuki/laboratory/locales/pt.yml +4 -0
  47. data/lib/mumuki/laboratory/mumukit/auth.rb +7 -0
  48. data/lib/mumuki/laboratory/version.rb +1 -1
  49. data/public/amarillo_exito.svg +11 -0
  50. data/public/amarillo_fracaso.svg +5 -0
  51. data/public/compass_rose.svg +1417 -0
  52. data/spec/controllers/api_clients_controller.rb +26 -0
  53. data/spec/controllers/confirmations_controller_spec.rb +1 -1
  54. data/spec/controllers/courses_api_controller_spec.rb +28 -0
  55. data/spec/controllers/exercise_solutions_controller_spec.rb +1 -1
  56. data/spec/controllers/messages_controller_spec.rb +1 -1
  57. data/spec/controllers/organizations_api_controller_spec.rb +235 -0
  58. data/spec/controllers/students_api_controller_spec.rb +101 -0
  59. data/spec/controllers/users_api_controller_spec.rb +56 -0
  60. data/spec/dummy/db/schema.rb +9 -0
  61. data/spec/factories/api_client_factory.rb +18 -0
  62. data/spec/factories/course_factory.rb +9 -0
  63. data/spec/features/chapter_spec.rb +1 -1
  64. data/spec/features/complements_flow_spec.rb +1 -1
  65. data/spec/features/exams_flow_spec.rb +1 -1
  66. data/spec/features/exercise_flow_spec.rb +1 -1
  67. data/spec/features/guide_reset_spec.rb +1 -1
  68. data/spec/features/guides_flow_spec.rb +1 -1
  69. data/spec/features/home_public_flow_spec.rb +1 -1
  70. data/spec/features/lessons_flow_spec.rb +1 -1
  71. data/spec/features/links_flow_spec.rb +1 -1
  72. data/spec/features/login_flow_spec.rb +1 -1
  73. data/spec/features/profile_flow_spec.rb +1 -1
  74. data/spec/features/standard_flow_spec.rb +1 -1
  75. data/spec/helpers/application_helper_spec.rb +1 -1
  76. data/spec/helpers/email_helper_spec.rb +1 -1
  77. data/spec/helpers/exercise_input_helper_spec.rb +1 -1
  78. data/spec/helpers/with_breadcrumbs_spec.rb +1 -1
  79. data/spec/helpers/with_navigation_spec.rb +1 -1
  80. data/spec/models/assignment_spec.rb +1 -1
  81. data/spec/models/book_import_spec.rb +1 -1
  82. data/spec/models/book_spec.rb +1 -1
  83. data/spec/models/course_spec.rb +1 -1
  84. data/spec/models/event_generation_spec.rb +1 -1
  85. data/spec/models/exam_spec.rb +1 -1
  86. data/spec/models/exercise_spec.rb +11 -3
  87. data/spec/models/guide_spec.rb +1 -1
  88. data/spec/models/interactive_spec.rb +1 -1
  89. data/spec/models/lesson_spec.rb +1 -1
  90. data/spec/models/message_spec.rb +1 -1
  91. data/spec/models/navigation_spec.rb +1 -1
  92. data/spec/models/organization_spec.rb +1 -1
  93. data/spec/models/problem_spec.rb +1 -1
  94. data/spec/models/question_spec.rb +1 -1
  95. data/spec/models/reading_spec.rb +1 -1
  96. data/spec/models/solution_spec.rb +1 -1
  97. data/spec/models/usage_spec.rb +1 -1
  98. data/spec/models/user_changed_spec.rb +1 -1
  99. data/spec/models/user_spec.rb +5 -5
  100. data/spec/spec_helper.rb +19 -3
  101. metadata +37 -2
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe ApiClientsController, type: :controller, organization_workspace: :base do
4
+ before { @request.env["HTTP_AUTHORIZATION"] = api_client.token }
5
+ let(:api_client) { create :api_client }
6
+ let(:api_client_json) do
7
+ {description: 'foo',
8
+ user_attributes: user_json
9
+ }
10
+ end
11
+ let(:user_json) do
12
+ {first_name: 'foo',
13
+ last_name: 'bar',
14
+ email: 'foo@bar.com',
15
+ permissions: {student: 'foo/*'}
16
+ }
17
+ end
18
+ context 'post' do
19
+ before { post :create, params: { api_client: api_client_json }}
20
+
21
+ it { expect(response.status).to eq 200 }
22
+ it { expect(ApiClient.count).to eq 1 }
23
+ it { expect(ApiClient.first.user.permissions).to eq('student' => 'foo/*') }
24
+ it { expect(Apiclient.first.user.email).to eq 'foo@bar.com' }
25
+ end
26
+ end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ExerciseConfirmationsController do
3
+ describe ExerciseConfirmationsController, organization_workspace: :test do
4
4
  let(:user) { create(:user) }
5
5
  let(:reading) { create(:reading) }
6
6
 
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Api::CoursesController, type: :controller, organization_workspace: :base do
4
+ before { set_api_client! }
5
+ let(:api_client) { create :api_client }
6
+ let(:course_json) do
7
+ {slug: 'test/bar',
8
+ shifts: %w(morning),
9
+ code: 'k2003',
10
+ days: %w(monday wednesday),
11
+ period: '2016',
12
+ description: 'test course'}
13
+ end
14
+
15
+ let!(:organization) { create :organization, name: 'test' }
16
+
17
+ context 'post' do
18
+ before { post :create, params: { course: course_json }}
19
+
20
+ it { expect(response.status).to eq 200 }
21
+ it { expect(Course.count).to eq 1 }
22
+ it { expect(Course.first.slug).to eq 'test/bar' }
23
+ it { expect(Course.first.organization).to eq(organization) }
24
+ it { expect(Course.first.shifts).to eq(%w(morning)) }
25
+ it { expect(Course.first.days).to eq(%w(monday wednesday)) }
26
+ end
27
+
28
+ end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ExerciseSolutionsController do
3
+ describe ExerciseSolutionsController, organization_workspace: :test do
4
4
  let(:user) { create(:user) }
5
5
  let(:problem) { create(:problem) }
6
6
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe MessagesController do
3
+ describe MessagesController, organization_workspace: :test do
4
4
  let(:user) { create(:user) }
5
5
  let(:exercise) { create(:exercise) }
6
6
  before { set_current_user! user }
@@ -0,0 +1,235 @@
1
+ require 'spec_helper'
2
+
3
+ describe Api::OrganizationsController, type: :controller, organization_workspace: :base do
4
+ def check_status!(status)
5
+ expect(response.status).to eq status
6
+ end
7
+
8
+ describe 'unauthenticated request' do
9
+ it { expect { get :index }.to raise_error 'missing authorization header' }
10
+ end
11
+
12
+ describe 'unauthenticated request' do
13
+ before { @request.env["HTTP_AUTHORIZATION"] = 'foo' }
14
+ it { expect { get :index }.to raise_error 'No Api Client found for Token' }
15
+ end
16
+
17
+ describe 'authenticated request' do
18
+ let(:book) { create :book }
19
+
20
+ before { set_api_client! }
21
+
22
+ describe 'GET' do
23
+ let!(:public_organization) { create :organization, name: 'public' }
24
+ let!(:dot_organization) { create :organization, name: 'dot.org' }
25
+ let!(:private_organization) { create :organization, name: 'private', public: false }
26
+ let!(:another_private_organization) { create :organization, name: 'another_private', public: false }
27
+
28
+ context 'GET /organizations' do
29
+ context 'with wildcard permissions' do
30
+ before { get :index }
31
+ let(:api_client) { create :api_client, role: :janitor, grant: '*' }
32
+ let!(:body) { response.body.parse_json }
33
+
34
+ it { check_status! 200 }
35
+
36
+ it { expect(body[:organizations].map { |it| it[:name] }).to eq %w(base public dot.org private another_private) }
37
+ end
38
+ context 'with non-wildcard permissions' do
39
+ before { get :index }
40
+ let(:api_client) { create :api_client, role: :janitor, grant: 'public/*:private/*' }
41
+ let!(:body) { response.body.parse_json }
42
+
43
+ it { check_status! 200 }
44
+
45
+ it { expect(body[:organizations].map { |it| it[:name] }).to eq %w(public private) }
46
+ end
47
+ end
48
+
49
+ context 'GET /organizations/:id' do
50
+ context 'with a public organization' do
51
+ before { get :show, params: {id: 'public'} }
52
+
53
+ context 'with a user without janitor permissions' do
54
+ let(:api_client) { create :api_client, role: :editor, grant: 'another_organization/*' }
55
+
56
+ it { check_status! 403 }
57
+ end
58
+
59
+ context 'with a user with janitor' do
60
+ let(:api_client) { create :api_client, role: :janitor, grant: 'public/*' }
61
+
62
+ it { check_status! 200 }
63
+ end
64
+ end
65
+
66
+ context 'with an organization that has a dot in its name' do
67
+ before { get :show, params: {id: 'dot.org'} }
68
+
69
+ let(:api_client) { create :api_client, role: :janitor, grant: 'dot.org/*' }
70
+ it { check_status! 200 }
71
+ end
72
+
73
+ context 'with a private organization' do
74
+ before { get :show, params: {id: 'private'} }
75
+
76
+ context 'with a user without permissions' do
77
+ let(:api_client) { create :api_client, role: :editor, grant: 'another_organization/*' }
78
+
79
+ it { check_status! 403 }
80
+ end
81
+
82
+ context 'with a user with permissions' do
83
+ let(:api_client) { create :api_client, role: :janitor, grant: 'private/*' }
84
+
85
+ it { check_status! 200 }
86
+ it { expect(response.body.parse_json).to json_like(private_organization.as_platform_json) }
87
+ end
88
+ end
89
+
90
+ context 'with a non-existing organization' do
91
+ before { get :show, params: {id: 'non-existing'} }
92
+ let(:api_client) { create :api_client, role: :editor, grant: 'bleh/*' }
93
+
94
+ it { check_status! 404 }
95
+ end
96
+ end
97
+ end
98
+
99
+ describe 'POST /organizations' do
100
+ before { post :create, params: {organization: organization_json} }
101
+ let(:organization_json) do
102
+ {contact_email: 'an_email@gmail.com',
103
+ name: 'a-name',
104
+ public: false,
105
+ book: book.slug,
106
+ locale: 'es'}
107
+ end
108
+
109
+ context 'with the owner permissions' do
110
+ let(:api_client) { create :api_client, role: :owner, grant: '*' }
111
+ let(:organization) { Organization.find_by name: 'a-name' }
112
+
113
+ it { check_status! 200 }
114
+ it { expect(response.body.parse_json).to json_like(organization.as_platform_json) }
115
+ it { expect(Organization.count).to eq 2 }
116
+ it { expect(organization.name).to eq 'a-name' }
117
+ it { expect(organization.contact_email).to eq 'an_email@gmail.com' }
118
+ it { expect(organization.book).to eq book }
119
+ it { expect(organization.locale).to eq 'es' }
120
+
121
+ context 'with only mandatory values' do
122
+ it { expect(organization.public?).to eq false }
123
+ it { expect(organization.login_methods).to eq %w(user_pass) }
124
+ it { expect(organization.logo_url).to eq 'https://mumuki.io/logo-alt-large.png' }
125
+ it { expect(organization.theme_stylesheet).to eq '.defaultCssFromBase { css: red }' }
126
+ it { expect(organization.extension_javascript).to eq 'function jsFromBase() {}' }
127
+ it { expect(organization.terms_of_service).to eq nil }
128
+ end
129
+
130
+ context 'with optional values' do
131
+ let(:organization_json) do
132
+ {contact_email: 'an_email@gmail.com',
133
+ name: 'a-name',
134
+ description: 'A description',
135
+ book: book.slug,
136
+ locale: 'es',
137
+ public: false,
138
+ login_methods: %w(facebook github),
139
+ logo_url: 'http://a-logo-url.com',
140
+ theme_stylesheet: '.theme { color: red }',
141
+ extension_javascript: 'window.a = function() { }',
142
+ terms_of_service: 'A TOS'}
143
+ end
144
+
145
+ it { expect(organization.public?).to eq false }
146
+ it { expect(organization.description).to eq 'A description' }
147
+ it { expect(organization.login_methods).to eq %w(facebook github) }
148
+ it { expect(organization.logo_url).to eq 'http://a-logo-url.com' }
149
+ it { expect(organization.theme_stylesheet).to eq ".theme { color: red }" }
150
+ it { expect(organization.extension_javascript).to eq "window.a = function() { }" }
151
+ it { expect(organization.terms_of_service).to eq 'A TOS' }
152
+ end
153
+
154
+ context 'with missing values' do
155
+ let(:organization_json) do
156
+ {contact_email: 'an_email@gmail.com',
157
+ locale: 'blabla'}
158
+ end
159
+ let(:expected_errors) do
160
+ {
161
+ errors: {
162
+ name: ["can't be blank"],
163
+ locale: ['is not included in the list']
164
+ }
165
+ }
166
+ end
167
+
168
+ it { check_status! 400 }
169
+ it { expect(response.body.parse_json).to eq expected_errors }
170
+ end
171
+ end
172
+
173
+ context 'with owner permissions' do
174
+ let(:api_client) { create :api_client, role: :owner, grant: '*' }
175
+
176
+ it { check_status! 200 }
177
+ end
178
+
179
+
180
+ context 'with not-janitor permissions' do
181
+ let(:api_client) { create :api_client, role: :editor, grant: '*' }
182
+
183
+ it { check_status! 403 }
184
+ end
185
+ end
186
+
187
+ describe 'PUT /organizations/:id' do
188
+ let!(:organization) {
189
+ create :organization,
190
+ name: 'existing-organization',
191
+ contact_email: 'first_email@gmail.com',
192
+ terms_of_service: 'A TOS',
193
+ public: false,
194
+ login_methods: ['facebook', 'user_pass'],
195
+ book: book }
196
+ let(:updated_organizaton) { organization.reload }
197
+ let(:update_json) { {contact_email: 'second_email@gmail.com', immersive: true, locale: 'en'} }
198
+
199
+ context 'with the owner permissions' do
200
+ let(:api_client) { create :api_client, role: :owner, grant: 'existing-organization/*' }
201
+ before { put :update, params: {id: organization.name, organization: update_json} }
202
+
203
+ it { check_status! 200 }
204
+ it { expect(response.body.parse_json).to json_like(
205
+ book: book.slug,
206
+ name: "existing-organization",
207
+ profile: {
208
+ description: "a great org",
209
+ locale: 'en',
210
+ contact_email: "second_email@gmail.com",
211
+ terms_of_service: 'A TOS'
212
+ },
213
+ settings: {
214
+ login_methods: ["facebook", "user_pass"],
215
+ public: false,
216
+ immersive: true
217
+ },
218
+ theme: {
219
+ extension_javascript: 'function jsFromBase() {}',
220
+ theme_stylesheet: '.defaultCssFromBase { css: red }'
221
+ }) }
222
+
223
+ it { expect(updated_organizaton.name).to eq 'existing-organization' }
224
+ it { expect(updated_organizaton.contact_email).to eq 'second_email@gmail.com' }
225
+ end
226
+
227
+ context 'with not-janitor permissions' do
228
+ let(:api_client) { create :api_client, role: :teacher, grant: 'existing-organization/*' }
229
+ before { put :update, params: {id: 'existing-organization', organization: update_json} }
230
+
231
+ it { check_status! 403 }
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ [:student, :teacher].each do |role|
4
+
5
+ describe "Api::#{role.capitalize}sController".constantize, type: :controller, organization_workspace: :base do
6
+ before { set_api_client! }
7
+ let(:api_client) { create :api_client, grant: 'anorganization/*' }
8
+ let(:json) { {
9
+ first_name: 'Agustin',
10
+ last_name: 'Pina',
11
+ email: 'agus@mumuki.org',
12
+ uid: 'agus@mumuki.org'
13
+ } }
14
+
15
+ let!(:organization) { create :organization, name: 'anorganization' }
16
+ let!(:course) { create :course, slug: 'anorganization/acode' }
17
+
18
+ context 'post' do
19
+ let(:params) { {role => json, organization: 'anorganization', course: 'acode'} }
20
+
21
+ context 'when user does not exist' do
22
+
23
+ before { post :create, params: params }
24
+
25
+ it { expect(response.status).to eq 200 }
26
+ it { expect(User.count).to eq 2 }
27
+ it { expect(User.last.last_name).to eq 'Pina' }
28
+ it { expect(User.last.first_name).to eq 'Agustin' }
29
+ it { expect(User.last.uid).to eq 'agus@mumuki.org' }
30
+ it { expect(User.last.email).to eq 'agus@mumuki.org' }
31
+ it { expect(User.last.permissions.has_permission? role, 'anorganization/acode').to be true }
32
+
33
+ end
34
+ context 'when user exist' do
35
+ context 'and have no permissions' do
36
+ before { create :user, json }
37
+ before { post :create, params: params }
38
+ it { expect(response.status).to eq 200 }
39
+ it { expect(User.count).to eq 2 }
40
+ it { expect(User.last.permissions.has_permission? role, 'anorganization/acode').to be true }
41
+ end
42
+ context 'and have permissions' do
43
+ before { create :user, json.merge(:permissions => {role => 'foo/bar'}) }
44
+ before { post :create, params: params }
45
+ it { expect(response.status).to eq 200 }
46
+ it { expect(User.count).to eq 2 }
47
+ it { expect(User.last.permissions.has_permission? role, 'anorganization/acode').to be true }
48
+ it { expect(User.last.permissions.has_permission? role, 'foo/bar').to be true }
49
+ end
50
+
51
+
52
+ end
53
+ end
54
+
55
+ context 'attach' do
56
+ let(:params) { {uid: json[:uid], organization: 'anorganization', course: 'acode'} }
57
+
58
+ context 'when user does not exist' do
59
+ before { post :attach, params: params }
60
+ it { expect(response.status).to eq 404 }
61
+ end
62
+
63
+ context 'when user exist' do
64
+ context 'and have no permissions' do
65
+ before { create :user, json }
66
+ before { post :attach, params: params }
67
+ it { expect(response.status).to eq 200 }
68
+ it { expect(User.last.permissions.has_permission? role, 'anorganization/acode').to be true }
69
+ end
70
+ context 'and have permissions' do
71
+ before { create :user, json.merge(:permissions => {role => 'foo/bar'}) }
72
+ before { post :attach, params: params }
73
+ it { expect(response.status).to eq 200 }
74
+ it { expect(User.last.permissions.has_permission? role, 'anorganization/acode').to be true }
75
+ it { expect(User.last.permissions.has_permission? role, 'foo/bar').to be true }
76
+ end
77
+ end
78
+
79
+ end
80
+
81
+ context 'detach' do
82
+ let(:params) { {uid: json[:uid], organization: 'anorganization', course: 'acode'} }
83
+
84
+ context 'when user does not exist' do
85
+ before { post :detach, params: params }
86
+ it { expect(response.status).to eq 404 }
87
+ end
88
+
89
+ context 'when user exist' do
90
+ context 'and have permissions' do
91
+ before { create :user, json.merge(:permissions => {role => 'anorganization/acode'}) }
92
+ before { post :detach, params: params }
93
+ it { expect(response.status).to eq 200 }
94
+ it { expect(User.last.permissions.has_permission? role, 'anorganization/acode').to be false }
95
+ end
96
+ end
97
+
98
+ end
99
+ end
100
+
101
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe Api::UsersController, type: :controller, organization_workspace: :base do
4
+ before { set_api_client! }
5
+ let(:api_client) { create :api_client }
6
+ let(:user_json) do
7
+ {
8
+ first_name: 'foo',
9
+ last_name: 'bar',
10
+ email: 'foo@bar.com',
11
+ permissions: {student: 'test/bar'},
12
+ }
13
+ end
14
+
15
+ let(:owner_json) do
16
+ {
17
+ first_name: 'foo',
18
+ last_name: 'bar',
19
+ email: 'foo@bar.com',
20
+ permissions: {owner: '*'}
21
+ }
22
+ end
23
+
24
+ context 'post' do
25
+ before { post :create, params: {user: user_json} }
26
+
27
+ it { expect(response.status).to eq 200 }
28
+ it { expect(response.body.parse_json).to json_like({uid: 'foo@bar.com',
29
+ first_name: 'foo',
30
+ last_name: 'bar',
31
+ email: 'foo@bar.com',
32
+ permissions: {'student' => 'test/bar'},
33
+ image_url: 'user_shape.png'},
34
+ except: [:id, :created_at, :updated_at]) }
35
+ it { expect(User.count).to eq 2 }
36
+ it { expect(User.last.student? 'test/_').to be true }
37
+ it { expect(User.last.uid).to eq 'foo@bar.com' }
38
+ end
39
+
40
+
41
+ context 'post without permissions' do
42
+ before { post :create, params: {user: owner_json} }
43
+
44
+ it { expect(response.status).to eq 403 }
45
+ end
46
+
47
+ context 'put' do
48
+ before { User.create! user_json }
49
+ before { put :update, params: {id: 'foo@bar.com', user: {first_name: 'Fede'}} }
50
+
51
+ it { expect(response.status).to eq 200 }
52
+ it { expect(User.last.first_name).to eq('Fede') }
53
+ it { expect(User.last.uid).to eq 'foo@bar.com' }
54
+ end
55
+
56
+ end