mumuki-laboratory 7.12.1 → 8.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/mumuki_laboratory/application/bridge.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/button.js +2 -2
- data/app/assets/javascripts/mumuki_laboratory/application/codemirror-builder.js +2 -2
- data/app/assets/javascripts/mumuki_laboratory/application/codemirror.js +5 -5
- data/app/assets/javascripts/mumuki_laboratory/application/console.js +2 -2
- data/app/assets/javascripts/mumuki_laboratory/application/discussions.js +7 -7
- data/app/assets/javascripts/mumuki_laboratory/application/editors.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/elipsis.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/events.js +2 -2
- data/app/assets/javascripts/mumuki_laboratory/application/exercise.js +2 -2
- data/app/assets/javascripts/mumuki_laboratory/application/gamification.js +99 -11
- data/app/assets/javascripts/mumuki_laboratory/application/inputs.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/kids.js +20 -8
- data/app/assets/javascripts/mumuki_laboratory/application/kindergarten.js +16 -57
- data/app/assets/javascripts/mumuki_laboratory/application/messages.js +6 -6
- data/app/assets/javascripts/mumuki_laboratory/application/mu-modal-carrousel.js +63 -0
- data/app/assets/javascripts/mumuki_laboratory/application/multiple-choice.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/multiple-files.js +3 -3
- data/app/assets/javascripts/mumuki_laboratory/application/multiple-scenarios.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/number-counter.js +18 -0
- data/app/assets/javascripts/mumuki_laboratory/application/pin.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/primary.js +3 -2
- data/app/assets/javascripts/mumuki_laboratory/application/progress.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/results-renderer.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/speech-bubble-renderer.js +4 -4
- data/app/assets/javascripts/mumuki_laboratory/application/submission.js +3 -3
- data/app/assets/javascripts/mumuki_laboratory/application/submissions-store.js +3 -3
- data/app/assets/javascripts/mumuki_laboratory/application/sync-mode.js +2 -2
- data/app/assets/javascripts/mumuki_laboratory/application/timer.js +1 -1
- data/app/assets/stylesheets/mumuki_laboratory/application/_layout.scss +7 -7
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_kids_results.scss +117 -0
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_kindergarten.scss +45 -131
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_terms.scss +9 -12
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_profile.scss +31 -3
- data/app/controllers/api/courses_controller.rb +1 -2
- data/app/controllers/api/organizations_controller.rb +2 -3
- data/app/controllers/api/users_controller.rb +2 -4
- data/app/controllers/application_controller.rb +41 -8
- data/app/controllers/assets_controller.rb +1 -0
- data/app/controllers/book_discussions_controller.rb +1 -1
- data/app/controllers/chapters_controller.rb +1 -0
- data/app/controllers/concerns/with_user_discussion_validation.rb +6 -0
- data/app/controllers/discussions_controller.rb +4 -6
- data/app/controllers/exercises_controller.rb +1 -0
- data/app/controllers/guides_controller.rb +2 -0
- data/app/controllers/invitations_controller.rb +2 -2
- data/app/controllers/lessons_controller.rb +1 -0
- data/app/controllers/login_controller.rb +1 -0
- data/app/controllers/users_controller.rb +9 -1
- data/app/helpers/assistance_box_helper.rb +7 -5
- data/app/helpers/gamification_helper.rb +5 -0
- data/app/helpers/links_helper.rb +2 -2
- data/app/views/exercise_solutions/_assistant_rules_box.html.erb +13 -0
- data/app/views/exercise_solutions/_contextualization_results_container.html.erb +9 -0
- data/app/views/exercise_solutions/_kids_level_up.html.erb +11 -0
- data/app/views/exercise_solutions/_results.html.erb +19 -19
- data/app/views/exercise_solutions/_results_title.html.erb +5 -0
- data/app/views/exercises/show.html.erb +4 -1
- data/app/views/layouts/_copyright.html.erb +1 -1
- data/app/views/layouts/_kindergarten.html.erb +1 -1
- data/app/views/layouts/_organizations_listing.html.erb +8 -12
- data/app/views/layouts/application.html.erb +23 -15
- data/app/views/layouts/embedded.html.erb +14 -11
- data/app/views/layouts/modals/_guide_corollary.html.erb +1 -1
- data/app/views/layouts/modals/_kids_context.html.erb +1 -1
- data/app/views/layouts/modals/_kids_results.html.erb +16 -6
- data/app/views/layouts/modals/_kindergarten_context.html.erb +15 -15
- data/app/views/layouts/modals/_kindergarten_results.html.erb +20 -7
- data/app/views/layouts/modals/_kindergarten_results_aborted.html.erb +4 -4
- data/app/views/layouts/modals/_level_up.html.erb +27 -0
- data/app/views/users/_edit_user_form.html.erb +1 -1
- data/app/views/users/_user_form.html.erb +12 -2
- data/app/views/users/terms.html.erb +12 -0
- data/config/routes.rb +8 -8
- data/lib/mumuki/laboratory.rb +18 -5
- data/lib/mumuki/laboratory/controllers.rb +2 -0
- data/lib/mumuki/laboratory/controllers/action_redirector.rb +21 -0
- data/lib/mumuki/laboratory/controllers/immersive_navigation.rb +7 -0
- data/lib/mumuki/laboratory/controllers/results_rendering.rb +1 -0
- data/lib/mumuki/laboratory/events/events.rb +0 -33
- data/lib/mumuki/laboratory/locales/en.yml +5 -0
- data/lib/mumuki/laboratory/locales/es-CL.yml +6 -1
- data/lib/mumuki/laboratory/locales/es.yml +7 -2
- data/lib/mumuki/laboratory/locales/pt.yml +6 -1
- data/lib/mumuki/laboratory/version.rb +1 -1
- data/spec/capybara_helper.rb +5 -1
- data/spec/controllers/discussions_controller_spec.rb +19 -0
- data/spec/controllers/exercise_solutions_controller_spec.rb +1 -1
- data/spec/dummy/db/schema.rb +2 -1
- data/spec/features/immersive_redirection_spec.rb +181 -0
- data/spec/features/profile_flow_spec.rb +35 -3
- data/spec/features/terms_flow_spec.rb +155 -0
- metadata +110 -101
- data/app/helpers/organization_list_helper.rb +0 -5
- data/spec/features/choose_organization_spec.rb +0 -74
@@ -101,6 +101,7 @@ es:
|
|
101
101
|
exercise_success_rate: Tasa de éxito en ejercicios
|
102
102
|
exercises: Ejercicios
|
103
103
|
exit: Salir
|
104
|
+
exp_points: puntos de experiencia.
|
104
105
|
expectations: Objetivos
|
105
106
|
expected_state: Tablero esperado
|
106
107
|
explain_redirect: Notamos que te registraste en otra organización.
|
@@ -111,8 +112,8 @@ es:
|
|
111
112
|
first_name: Nombre
|
112
113
|
forbidden_explanation: ¿Puede que hayas ingresado con una cuenta incorrecta?
|
113
114
|
format: Dar formato
|
114
|
-
forum_terms: Reglas del
|
115
|
-
forum_terms_link: Si tenés alguna duda,
|
115
|
+
forum_terms: Reglas del espacio de consultas
|
116
|
+
forum_terms_link: Si tenés alguna duda, accedé a las %{terms_link}
|
116
117
|
fullscreen: "Pantalla completa"
|
117
118
|
gender: Género
|
118
119
|
get_messages: "Ver mensajes"
|
@@ -155,6 +156,8 @@ es:
|
|
155
156
|
lessons: Lecciones
|
156
157
|
lesson_number: Lección %{number}
|
157
158
|
let_us_know: ¡Por favor avisanos!
|
159
|
+
level: Nivel
|
160
|
+
level_up: ¡Subiste de nivel!
|
158
161
|
loading: Cargando
|
159
162
|
load_solution_into_console: Cargar la solución en la consola
|
160
163
|
locked_content: 'Este contenido se desbloqueará cuando termines los capítulos anteriores'
|
@@ -255,6 +258,7 @@ es:
|
|
255
258
|
other: '%{count} resueltas'
|
256
259
|
solved_exercises: Ejercicios Resueltos
|
257
260
|
solve_doubts: Resolvé consultas
|
261
|
+
solve_more_exercises_to_level_up: Resolvé <span>number</span> ejercicios más para pasar al siguiente nivel.
|
258
262
|
solve_your_doubts: Consultá tus dudas
|
259
263
|
solve_your_doubts_teaser: ¿Tenés alguna consulta?
|
260
264
|
something_went_wrong: ¡Ups!, algo no anduvo bien...
|
@@ -317,6 +321,7 @@ es:
|
|
317
321
|
working: "Procesando"
|
318
322
|
wrong_answer: La respuesta no es correcta
|
319
323
|
years: años
|
324
|
+
you_earned: Ganaste
|
320
325
|
you_must_sign_in_before_submitting: Tenés que iniciar sesión antes de empezar a enviar tus soluciones
|
321
326
|
you_never_submitted_solutions: Parece que nunca enviaste soluciones desde que creaste tu cuenta.
|
322
327
|
your_new_organization: tu nueva organización
|
@@ -97,6 +97,7 @@ pt:
|
|
97
97
|
exercise_success_rate: Taxa de sucesso em exercícios
|
98
98
|
exercises: Exercícios
|
99
99
|
exit: Sair
|
100
|
+
exp_points: pontos de experiência.
|
100
101
|
expectations: Objetivos
|
101
102
|
expected_state: Tabuleiro esperado
|
102
103
|
explain_redirect: Percebemos que você se registrou em outra organização.
|
@@ -107,7 +108,7 @@ pt:
|
|
107
108
|
first_name: Nome
|
108
109
|
forbidden_explanation: Você poderia ter entrado com uma conta incorreta?
|
109
110
|
format: Formato
|
110
|
-
forum_terms: Regras do
|
111
|
+
forum_terms: Regras do espaço de consulta
|
111
112
|
forum_terms_link: Se você tiver alguma dúvida, consulte as %{terms_link}
|
112
113
|
fullscreen: Tela completa
|
113
114
|
gender: Gênero
|
@@ -149,6 +150,8 @@ pt:
|
|
149
150
|
lessons: Lições
|
150
151
|
lesson_number: Lição %{number}
|
151
152
|
let_us_know: Por favor, avise-nos!
|
153
|
+
level: Nível
|
154
|
+
level_up: Você sobe de nível!
|
152
155
|
loading: Carregando
|
153
156
|
load_solution_into_console: Carregue a solução no console
|
154
157
|
locked_content: 'Este conteúdo será desbloqueado quando você terminar os capítulos anteriores'
|
@@ -242,6 +245,7 @@ pt:
|
|
242
245
|
solved_count: '%{count} resolvido'
|
243
246
|
solved_exercises: Exercícios resolvidos
|
244
247
|
solve_doubts: Resolvi dúvidas
|
248
|
+
solve_more_exercises_to_level_up: Resolva mais <span>number</span> exercícios para avançar para o próximo nível.
|
245
249
|
solve_your_doubts: Consulte suas dúvidas
|
246
250
|
solve_your_doubts_teaser: Você tem alguma dúvida?
|
247
251
|
something_went_wrong: Oops!, Algo não estava certo ...
|
@@ -292,5 +296,6 @@ pt:
|
|
292
296
|
working: Processamento
|
293
297
|
wrong_answer: A resposta não é correta
|
294
298
|
years: anos
|
299
|
+
you_earned: Você ganhou
|
295
300
|
you_must_sign_in_before_submitting: Você deve fazer o login antes de começar a enviar suas soluções
|
296
301
|
your_new_organization: sua nova organização
|
data/spec/capybara_helper.rb
CHANGED
@@ -87,7 +87,11 @@ def exclude_selenium_failing_tests!
|
|
87
87
|
:json_eq_error,
|
88
88
|
:navigation_error,
|
89
89
|
:organization_not_nil,
|
90
|
-
:xpath_no_matches
|
90
|
+
:xpath_no_matches,
|
91
|
+
|
92
|
+
# Fails because Rails redirection doesn't include Capybara port.
|
93
|
+
# It can be fixed by using path mapping instead of subdomain.
|
94
|
+
:subdomain_redirection_without_port
|
91
95
|
)
|
92
96
|
end
|
93
97
|
end
|
@@ -26,6 +26,25 @@ describe DiscussionsController, organization_workspace: :test do
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
describe 'index' do
|
30
|
+
context 'when user is banned from forum' do
|
31
|
+
before { user.update! banned_from_forum: true }
|
32
|
+
before { get :index, params: exercise_params }
|
33
|
+
|
34
|
+
it { expect(response.status).to eq 404 }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when user has exam in progress' do
|
38
|
+
let!(:exam) { create(:exam) }
|
39
|
+
before { exam.authorize! user }
|
40
|
+
before { exam.start! user }
|
41
|
+
|
42
|
+
before { get :index, params: exercise_params }
|
43
|
+
|
44
|
+
it { expect(response.status).to eq 403 }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
29
48
|
describe 'post' do
|
30
49
|
before { allow_any_instance_of(DiscussionsController).to receive(:discussion_params).and_return title: 'A title' }
|
31
50
|
before { post :create, params: exercise_params }
|
@@ -89,7 +89,7 @@ describe ExerciseSolutionsController, organization_workspace: :test do
|
|
89
89
|
|
90
90
|
it { expect(response.body).to json_eq({ status: :failed, guide_finished_by_solution: false },
|
91
91
|
except: [:html, :remaining_attempts_html, :title_html, :button_html,
|
92
|
-
:expectations, :test_results, :tips, :current_exp]) }
|
92
|
+
:expectations, :test_results, :tips, :current_exp, :level_up_html]) }
|
93
93
|
|
94
94
|
it 'includes kids specific renders' do
|
95
95
|
body = JSON.parse(response.body)
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -10,7 +10,7 @@
|
|
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:
|
13
|
+
ActiveRecord::Schema.define(version: 20201130163114) do
|
14
14
|
|
15
15
|
# These are extensions that must be enabled in order to support this database
|
16
16
|
enable_extension "plpgsql"
|
@@ -433,6 +433,7 @@ ActiveRecord::Schema.define(version: 20201027152806) do
|
|
433
433
|
t.datetime "privacy_terms_accepted_at"
|
434
434
|
t.datetime "legal_terms_accepted_at"
|
435
435
|
t.datetime "forum_terms_accepted_at"
|
436
|
+
t.boolean "banned_from_forum"
|
436
437
|
t.index ["avatar_type", "avatar_id"], name: "index_users_on_avatar_type_and_avatar_id"
|
437
438
|
t.index ["disabled_at"], name: "index_users_on_disabled_at"
|
438
439
|
t.index ["last_organization_id"], name: "index_users_on_last_organization_id"
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
feature 'Immersive redirection Flow', organization_workspace: :test, subdomain_redirection_without_port: true do
|
4
|
+
def create_guide(name)
|
5
|
+
create(:guide, name: name)
|
6
|
+
end
|
7
|
+
|
8
|
+
def create_immersive_organization(name, guides)
|
9
|
+
create(:organization,
|
10
|
+
name: name,
|
11
|
+
immersive: true,
|
12
|
+
book:
|
13
|
+
create(:book,
|
14
|
+
chapters: [
|
15
|
+
create(:chapter, lessons: guides.map { |it| create(:lesson, guide: it) })
|
16
|
+
]))
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:organization) { Organization.current }
|
20
|
+
let(:book) { organization.book }
|
21
|
+
|
22
|
+
let(:guide_one) { create_guide 'guide one' }
|
23
|
+
let(:guide_two) { create_guide 'guide two' }
|
24
|
+
let(:guide_three) { create_guide 'guide three' }
|
25
|
+
|
26
|
+
let(:lesson_one) { create(:lesson, guide: guide_one) }
|
27
|
+
let(:lesson_two) { create(:lesson, guide: guide_two) }
|
28
|
+
let(:lesson_three) { create(:lesson, guide: guide_three) }
|
29
|
+
|
30
|
+
before { book.update! chapters: [create(:chapter, lessons: [lesson_one, lesson_two, lesson_three])] }
|
31
|
+
before { set_current_user! user }
|
32
|
+
|
33
|
+
shared_examples 'immersive redirection' do |organization_name|
|
34
|
+
scenario 'should redirect to immersive organization' do
|
35
|
+
expect(page).to have_text organization_name
|
36
|
+
expect(page).not_to have_text "Go to #{organization_name}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
shared_examples 'navigate to content' do |guide_name|
|
41
|
+
scenario 'should navigate to content' do
|
42
|
+
expect(page).to have_text guide_name
|
43
|
+
expect(page).to have_text 'Exercises'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
shared_examples 'navigate to main page' do
|
48
|
+
scenario 'should navigate to main page' do
|
49
|
+
expect(page).to have_text 'Start Practicing!'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
shared_examples 'navigate to discussions main page' do
|
54
|
+
scenario 'should navigate to discussions main page' do
|
55
|
+
expect(page).to have_text 'Discussions'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
shared_examples 'navigate to user profile' do
|
60
|
+
scenario 'should navigate to user profile' do
|
61
|
+
expect(page).to have_text user.full_name
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with one immersive organization' do
|
66
|
+
let(:user) { create(:user, permissions: {student: 'immersive-orga/*'}) }
|
67
|
+
let!(:immersive_orga) { create_immersive_organization('immersive-orga', [guide_one]) }
|
68
|
+
|
69
|
+
feature 'when navigating to an available content' do
|
70
|
+
before { visit lesson_path(lesson_one) }
|
71
|
+
it_behaves_like 'immersive redirection', 'immersive-orga'
|
72
|
+
it_behaves_like 'navigate to content', 'guide one'
|
73
|
+
end
|
74
|
+
|
75
|
+
feature 'when navigating to an unavailable content' do
|
76
|
+
before { visit lesson_path(lesson_two) }
|
77
|
+
it_behaves_like 'immersive redirection', 'immersive-orga'
|
78
|
+
it_behaves_like 'navigate to main page'
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when navigating to a discussion' do
|
82
|
+
feature 'and forum enabled' do
|
83
|
+
before { immersive_orga.update(forum_enabled: true) }
|
84
|
+
before { visit discussions_path }
|
85
|
+
it_behaves_like 'immersive redirection', 'immersive-orga'
|
86
|
+
it_behaves_like 'navigate to discussions main page'
|
87
|
+
end
|
88
|
+
|
89
|
+
feature 'and forum not enabled' do
|
90
|
+
before { visit discussions_path }
|
91
|
+
it_behaves_like 'immersive redirection', 'immersive-orga'
|
92
|
+
it_behaves_like 'navigate to main page'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
feature 'when navigating to another route' do
|
97
|
+
before { visit user_path }
|
98
|
+
it_behaves_like 'immersive redirection', 'immersive-orga'
|
99
|
+
it_behaves_like 'navigate to user profile'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'with many immersive organizations' do
|
104
|
+
let(:user) { create(:user, permissions: {student: 'immersive-orga/*:private/*'}) }
|
105
|
+
|
106
|
+
let!(:private_orga) { create_immersive_organization('private', [guide_one, guide_two]) }
|
107
|
+
let!(:immersive_orga) { create_immersive_organization('immersive-orga', [guide_one]) }
|
108
|
+
|
109
|
+
shared_examples 'organization chooser' do
|
110
|
+
scenario 'should display organization chooser' do
|
111
|
+
expect(page).to have_text 'You have registered in another organization'
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def choose_organization(name)
|
116
|
+
within '.modal' do
|
117
|
+
click_on "Go to #{name}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
feature 'when content is present in one of them' do
|
122
|
+
before { visit lesson_path(lesson_two) }
|
123
|
+
it_behaves_like 'immersive redirection', 'private'
|
124
|
+
it_behaves_like 'navigate to content', 'guide two'
|
125
|
+
end
|
126
|
+
|
127
|
+
feature 'when content is present in two of them' do
|
128
|
+
before { visit lesson_path(lesson_one) }
|
129
|
+
it_behaves_like 'organization chooser'
|
130
|
+
|
131
|
+
context 'after choosing an organization' do
|
132
|
+
before { choose_organization 'private' }
|
133
|
+
it_behaves_like 'immersive redirection', 'private'
|
134
|
+
it_behaves_like 'navigate to content', 'guide one'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe 'when content is not present on any of them' do
|
139
|
+
before { visit lesson_path(lesson_three) }
|
140
|
+
it_behaves_like 'organization chooser'
|
141
|
+
|
142
|
+
context 'after choosing an organization' do
|
143
|
+
before { choose_organization 'immersive-orga' }
|
144
|
+
it_behaves_like 'immersive redirection', 'immersive-orga'
|
145
|
+
it_behaves_like 'navigate to main page'
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
feature 'when navigating to another route' do
|
150
|
+
before { visit user_path }
|
151
|
+
it_behaves_like 'organization chooser'
|
152
|
+
|
153
|
+
context 'after choosing an organization' do
|
154
|
+
before { choose_organization 'immersive-orga' }
|
155
|
+
it_behaves_like 'immersive redirection', 'immersive-orga'
|
156
|
+
it_behaves_like 'navigate to user profile'
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context 'when navigating to a discussion' do
|
161
|
+
before { immersive_orga.update(forum_enabled: true) }
|
162
|
+
before { visit discussions_path }
|
163
|
+
|
164
|
+
it_behaves_like 'organization chooser'
|
165
|
+
|
166
|
+
feature 'and forum enabled' do
|
167
|
+
before { choose_organization 'immersive-orga' }
|
168
|
+
|
169
|
+
it_behaves_like 'immersive redirection', 'immersive-orga'
|
170
|
+
it_behaves_like 'navigate to discussions main page'
|
171
|
+
end
|
172
|
+
|
173
|
+
feature 'and forum not enabled' do
|
174
|
+
before { choose_organization 'private' }
|
175
|
+
|
176
|
+
it_behaves_like 'immersive redirection', 'private'
|
177
|
+
it_behaves_like 'navigate to main page'
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -5,10 +5,9 @@ feature 'Profile Flow', organization_workspace: :test do
|
|
5
5
|
let(:haskell) { create(:haskell) }
|
6
6
|
let!(:chapter) {
|
7
7
|
create(:chapter, name: 'Functional Programming', lessons: [
|
8
|
-
build(:lesson, name: 'Values and Functions', language: haskell, description: 'Values are everywhere...', exercises: [
|
9
|
-
build(:exercise, name: 'The Basic Values', description: "Let's say we want to declare a variable...")
|
10
|
-
])
|
8
|
+
build(:lesson, name: 'Values and Functions', language: haskell, description: 'Values are everywhere...', exercises: [exercise])
|
11
9
|
]) }
|
10
|
+
let(:exercise) { build(:exercise, name: 'The Basic Values', description: "Let's say we want to declare a variable...") }
|
12
11
|
let(:problem) { create :problem}
|
13
12
|
let(:message) {
|
14
13
|
{'exercise_id' => problem.id,
|
@@ -71,6 +70,39 @@ feature 'Profile Flow', organization_workspace: :test do
|
|
71
70
|
context 'logged in user' do
|
72
71
|
before { set_current_user! user }
|
73
72
|
|
73
|
+
context 'user with uncompleted profile after saving' do
|
74
|
+
before { user.update! last_name: 'last_name', birthdate: Time.now - 20.years, gender: 'female' }
|
75
|
+
|
76
|
+
let(:button_options) do
|
77
|
+
# Match :first is used because there are two buttons: mobile and desktop.
|
78
|
+
{ class: 'mu-edit-profile-btn', match: :first }.tap do |options|
|
79
|
+
options.merge!(disabled: true) unless run_with_selenium?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when visiting an exercise' do
|
84
|
+
scenario 'is redirected to previous path' do
|
85
|
+
visit "/exercises/#{exercise.transparent_id}"
|
86
|
+
fill_in('user_first_name', with: 'first_name')
|
87
|
+
|
88
|
+
click_on(button_options)
|
89
|
+
expect(page).to have_text(exercise.description)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'when visiting profile edition' do
|
94
|
+
scenario 'is redirected to read only profile' do
|
95
|
+
visit "/user/edit"
|
96
|
+
fill_in('user_first_name', with: 'first_name')
|
97
|
+
|
98
|
+
# Match :first is used because there are two buttons: mobile and desktop.
|
99
|
+
click_on(button_options)
|
100
|
+
expect(page).to have_text('Your data was updated successfuly')
|
101
|
+
expect(page).to have_text('Profile')
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
74
106
|
context 'with no messages' do
|
75
107
|
|
76
108
|
scenario 'visit messages tab' do
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
feature 'Terms Flow', organization_workspace: :test do
|
4
|
+
let(:forum_terms_scopes) { Term::FORUM_RELATED }
|
5
|
+
let(:general_terms_scopes) { Term::GENERAL }
|
6
|
+
let(:role_terms_scopes) { Term::ROLE_SPECIFIC }
|
7
|
+
|
8
|
+
let(:all_terms_scopes) { forum_terms_scopes + general_terms_scopes + role_terms_scopes }
|
9
|
+
let!(:terms) { all_terms_scopes.map { |it| create(:term, scope: it, locale: Organization.current.locale) } }
|
10
|
+
|
11
|
+
let(:test_organization) { Organization.locate!("test") }
|
12
|
+
|
13
|
+
let!(:exercise) { create(:indexed_exercise) }
|
14
|
+
let(:expected_terms) { [] }
|
15
|
+
let(:unexpected_terms) { all_terms_scopes - expected_terms }
|
16
|
+
|
17
|
+
let(:student) { create(:user, uid: 'user.student@mumuki.org', permissions: {student: 'test/*'}) }
|
18
|
+
|
19
|
+
let(:janitor) { create(:user, uid: 'user.janitor@mumuki.org', permissions: {student: 'test/*', janitor: 'other/*'}) }
|
20
|
+
|
21
|
+
before { reindex_current_organization! }
|
22
|
+
|
23
|
+
shared_context 'has expected terms' do
|
24
|
+
scenario 'with expected terms' do
|
25
|
+
visit terms_path
|
26
|
+
|
27
|
+
expected_terms.each do |it|
|
28
|
+
expect(page).to have_text(Term.find_by(scope: it).content)
|
29
|
+
end
|
30
|
+
|
31
|
+
unexpected_terms.each do |it|
|
32
|
+
expect(page).not_to have_text(Term.find_by(scope: it).content)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with student logged in' do
|
38
|
+
before { set_current_user! student }
|
39
|
+
|
40
|
+
describe 'visit user terms path' do
|
41
|
+
let(:terms_path) { '/user/terms' }
|
42
|
+
let(:expected_terms) { general_terms_scopes }
|
43
|
+
|
44
|
+
it_behaves_like 'has expected terms'
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'visit forum' do
|
48
|
+
let(:terms_path) { '/discussions/terms' }
|
49
|
+
|
50
|
+
context 'with disabled forum' do
|
51
|
+
|
52
|
+
it_behaves_like 'has expected terms'
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'with enabled forum' do
|
56
|
+
let(:expected_terms) { forum_terms_scopes }
|
57
|
+
before { test_organization.update! forum_enabled: true }
|
58
|
+
|
59
|
+
it_behaves_like 'has expected terms'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'with janitor logged in' do
|
65
|
+
before { set_current_user! janitor }
|
66
|
+
|
67
|
+
describe 'visit user terms path' do
|
68
|
+
let(:terms_path) { '/user/terms' }
|
69
|
+
let(:expected_terms) { general_terms_scopes + %w(janitor) }
|
70
|
+
|
71
|
+
it_behaves_like 'has expected terms'
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'with accepted general terms' do
|
75
|
+
before { janitor.accept_profile_terms! }
|
76
|
+
|
77
|
+
context 'visit forum' do
|
78
|
+
let(:terms_path) { '/discussions/terms' }
|
79
|
+
|
80
|
+
context 'with enabled forum' do
|
81
|
+
let(:expected_terms) { forum_terms_scopes }
|
82
|
+
before { test_organization.update! forum_enabled: true }
|
83
|
+
|
84
|
+
it_behaves_like 'has expected terms'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
scenario 'visit any other path' do
|
89
|
+
visit '/'
|
90
|
+
|
91
|
+
expect(page).to have_text('Start Practicing')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'with unaccepted role terms' do
|
96
|
+
|
97
|
+
context 'visit forum' do
|
98
|
+
let(:terms_path) { '/discussions/terms' }
|
99
|
+
before { test_organization.update! forum_enabled: true }
|
100
|
+
|
101
|
+
scenario 'with enabled forum' do
|
102
|
+
visit '/discussions'
|
103
|
+
expect(page).to have_text('Accept terms')
|
104
|
+
|
105
|
+
click_on 'Accept'
|
106
|
+
expect(page).to have_text('Discussions')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
scenario 'visit any other path' do
|
111
|
+
visit '/'
|
112
|
+
expect(page).to have_text('Accept terms')
|
113
|
+
|
114
|
+
click_on 'Accept'
|
115
|
+
expect(page).to have_text(test_organization.book.name)
|
116
|
+
end
|
117
|
+
|
118
|
+
scenario 'visit user path' do
|
119
|
+
visit '/user'
|
120
|
+
|
121
|
+
expect(page).to have_text(janitor.first_name)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'without user logged in' do
|
127
|
+
describe 'visit user terms path' do
|
128
|
+
let(:terms_path) { '/user/terms' }
|
129
|
+
let(:expected_terms) { general_terms_scopes }
|
130
|
+
|
131
|
+
it_behaves_like 'has expected terms'
|
132
|
+
end
|
133
|
+
|
134
|
+
scenario 'visit any other path' do
|
135
|
+
visit '/'
|
136
|
+
|
137
|
+
expect(page).to have_text('Start Practicing')
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'visit forum' do
|
141
|
+
let(:terms_path) { '/discussions/terms' }
|
142
|
+
|
143
|
+
context 'with enabled forum' do
|
144
|
+
before { test_organization.update! forum_enabled: true }
|
145
|
+
|
146
|
+
scenario 'visit forum' do
|
147
|
+
visit '/discussions/terms'
|
148
|
+
expect(page).to have_text('You may have mistyped the address or the page may have moved')
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|