mumuki-laboratory 7.10.3 → 7.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -7
- data/Rakefile +9 -2
- data/app/assets/javascripts/mumuki_laboratory/application/bridge.js +26 -5
- data/app/assets/javascripts/mumuki_laboratory/application/gamification.js +85 -0
- data/app/assets/javascripts/mumuki_laboratory/application/kindergarten.js +145 -0
- data/app/assets/javascripts/mumuki_laboratory/application/profile.js +31 -16
- data/app/assets/javascripts/mumuki_laboratory/application/submission.js +1 -0
- data/app/assets/javascripts/mumuki_laboratory/application/submissions-store.js +19 -2
- data/app/assets/stylesheets/mumuki_laboratory/application/_errors.scss +3 -4
- data/app/assets/stylesheets/mumuki_laboratory/application/_modules.scss +3 -1
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_avatar.scss +21 -0
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/{_chapter_show.scss → _content_show.scss} +0 -0
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_kindergarten.scss +401 -12
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_medal.scss +48 -0
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_terms.scss +44 -0
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_profile.scss +9 -0
- data/app/controllers/application_controller.rb +15 -8
- data/app/controllers/book_discussions_controller.rb +4 -0
- data/app/controllers/users_controller.rb +8 -2
- data/app/helpers/application_helper.rb +2 -2
- data/app/helpers/avatar_helper.rb +11 -3
- data/app/helpers/kindergarten_helper.rb +5 -0
- data/app/helpers/links_helper.rb +8 -0
- data/app/helpers/medal_helper.rb +36 -0
- data/app/helpers/open_graph_helper.rb +2 -2
- data/app/helpers/organization_list_helper.rb +1 -1
- data/app/helpers/overlapped_buttons_helper.rb +1 -1
- data/app/helpers/page_title_helper.rb +2 -2
- data/app/helpers/profile_helper.rb +9 -1
- data/app/views/book/_header.html.erb +17 -0
- data/app/views/book/show.html.erb +1 -18
- data/app/views/discussions/terms.html.erb +10 -0
- data/app/views/exercises/show.html.erb +1 -0
- data/app/views/invitations/_invitation_form.html.erb +1 -0
- data/app/views/layouts/_discussions.html.erb +5 -1
- data/app/views/layouts/_error.html.erb +3 -6
- data/app/views/layouts/_guide.html.erb +10 -3
- data/app/views/layouts/_kindergarten.html.erb +38 -0
- data/app/views/layouts/_main.html.erb +3 -1
- data/app/views/layouts/_organization_chooser.html.erb +0 -7
- data/app/views/layouts/_terms_acceptance_disclaimer.html.erb +6 -0
- data/app/views/layouts/application.html.erb +3 -2
- data/app/views/layouts/exercise_inputs/layouts/_input_kindergarten.html.erb +27 -27
- data/app/views/layouts/modals/_guide_corollary.html.erb +9 -0
- data/app/views/layouts/modals/_kindergarten_context.html.erb +30 -0
- data/app/views/layouts/modals/_kindergarten_results.html.erb +23 -0
- data/app/views/layouts/modals/_kindergarten_results_aborted.html.erb +24 -0
- data/app/views/users/_avatar_list.html.erb +6 -2
- data/app/views/users/_edit_user_form.html.erb +9 -4
- data/app/views/users/_term.html.erb +10 -0
- data/app/views/users/_user_form.html.erb +5 -1
- data/app/views/users/terms.html.erb +18 -0
- data/config/routes.rb +2 -0
- data/lib/mumuki/laboratory/controllers/current_organization.rb +1 -1
- data/lib/mumuki/laboratory/controllers/results_rendering.rb +3 -2
- data/lib/mumuki/laboratory/locales/en.yml +10 -5
- data/lib/mumuki/laboratory/locales/es-CL.yml +5 -4
- data/lib/mumuki/laboratory/locales/es.yml +12 -7
- data/lib/mumuki/laboratory/locales/pt.yml +12 -7
- data/lib/mumuki/laboratory/version.rb +1 -1
- data/spec/capybara_helper.rb +99 -0
- data/spec/controllers/exercise_solutions_controller_spec.rb +3 -4
- data/spec/dummy/db/schema.rb +37 -1
- data/spec/dummy/public/medal/outline.svg +1089 -0
- data/spec/features/choose_organization_spec.rb +12 -30
- data/spec/features/disable_user_flow_spec.rb +3 -5
- data/spec/features/disabled_organization_flow_spec.rb +9 -14
- data/spec/features/exercise_flow_spec.rb +2 -2
- data/spec/features/guide_reset_spec.rb +1 -1
- data/spec/features/guides_flow_spec.rb +1 -1
- data/spec/features/home_private_flow_spec.rb +1 -3
- data/spec/features/home_public_flow_spec.rb +6 -12
- data/spec/features/invitations_flow_spec.rb +2 -2
- data/spec/features/login_flow_spec.rb +2 -2
- data/spec/features/not_found_private_flow_spec.rb +4 -4
- data/spec/features/not_found_public_flow_spec.rb +1 -6
- data/spec/features/profile_flow_spec.rb +1 -1
- data/spec/helpers/page_title_helper_spec.rb +3 -3
- data/spec/javascripts/editors-spec.js +23 -0
- data/spec/javascripts/gamification-spec.js +58 -0
- data/spec/javascripts/submissions-store-spec.js +139 -6
- data/spec/spec_helper.rb +2 -0
- data/spec/teaspoon_env.rb +24 -6
- metadata +40 -7
@@ -8,7 +8,7 @@ feature 'Choose organization Flow' do
|
|
8
8
|
let(:user4) { create(:user, permissions: {student: 'immersive-orga/*'}) }
|
9
9
|
|
10
10
|
before do
|
11
|
-
%w(pdep central foo immersive-orga).each do |it|
|
11
|
+
%w(pdep central foo immersive-orga base).each do |it|
|
12
12
|
create(:organization,
|
13
13
|
name: it,
|
14
14
|
book: create(:book,
|
@@ -18,14 +18,15 @@ feature 'Choose organization Flow' do
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
before { Organization.
|
21
|
+
before { Organization.locate!('immersive-orga').update!(immersive: true) }
|
22
|
+
before { Organization.locate!('central').update!(immersible: true) }
|
22
23
|
before { set_current_user! user }
|
23
24
|
|
24
25
|
context 'when organization exists' do
|
25
26
|
before { Organization.central.switch! }
|
26
27
|
|
27
28
|
scenario 'when visiting with implicit subdomain and no permissions' do
|
28
|
-
|
29
|
+
set_subdomain_host! 'central'
|
29
30
|
|
30
31
|
visit '/'
|
31
32
|
|
@@ -33,19 +34,19 @@ feature 'Choose organization Flow' do
|
|
33
34
|
expect(page).not_to have_text('Do you want to go there?')
|
34
35
|
end
|
35
36
|
|
36
|
-
scenario 'when visiting
|
37
|
+
scenario 'when visiting immersible orga with permissions to only one non-immersive organization' do
|
37
38
|
set_current_user! user2
|
38
|
-
|
39
|
+
set_subdomain_host! 'central'
|
39
40
|
|
40
41
|
visit '/'
|
41
42
|
|
42
43
|
expect(page).to have_text('Sign Out')
|
43
|
-
expect(page).
|
44
|
+
expect(page).not_to have_text('Do you want to go there?')
|
44
45
|
end
|
45
46
|
|
46
|
-
scenario 'when visiting
|
47
|
+
scenario 'when visiting immersible orga with permissions to only one immersive organization', :navigation_error do
|
47
48
|
set_current_user! user4
|
48
|
-
|
49
|
+
set_subdomain_host! 'central'
|
49
50
|
|
50
51
|
visit '/'
|
51
52
|
|
@@ -54,37 +55,18 @@ feature 'Choose organization Flow' do
|
|
54
55
|
expect(page).to have_text('immersive-orga')
|
55
56
|
end
|
56
57
|
|
57
|
-
scenario 'when visiting
|
58
|
+
scenario 'when visiting immersible orga with permissions to many non-immersive organizations' do
|
58
59
|
set_current_user! user3
|
59
|
-
|
60
|
+
set_subdomain_host! 'central'
|
60
61
|
|
61
62
|
visit '/'
|
62
63
|
|
63
64
|
expect(page).to have_text('Sign Out')
|
64
|
-
expect(page).to have_text('Do you want to go there?')
|
65
|
-
end
|
66
|
-
|
67
|
-
scenario 'when visiting central explicitly' do
|
68
|
-
set_subdomain_host!('central')
|
69
|
-
|
70
|
-
visit '/'
|
71
|
-
|
72
|
-
expect(page).not_to have_text('Do you want to go there?')
|
73
|
-
expect(page).not_to have_text('pdep')
|
74
|
-
end
|
75
|
-
|
76
|
-
scenario 'when visit foo subdomain' do
|
77
|
-
set_current_user! user3
|
78
|
-
set_subdomain_host!('foo')
|
79
|
-
|
80
|
-
visit '/'
|
81
|
-
|
82
65
|
expect(page).not_to have_text('Do you want to go there?')
|
83
|
-
expect(page).to have_text('foo')
|
84
66
|
end
|
85
67
|
end
|
86
68
|
|
87
|
-
scenario 'when organization does not exist' do
|
69
|
+
scenario 'when organization does not exist', :http_response_headers do
|
88
70
|
visit '/'
|
89
71
|
|
90
72
|
expect(page).to have_http_status(404)
|
@@ -17,8 +17,7 @@ feature 'disable user flow', organization_workspace: :test do
|
|
17
17
|
scenario 'enabled visitor' do
|
18
18
|
visit '/'
|
19
19
|
|
20
|
-
expect(
|
21
|
-
expect(page).to have_text(current_organization.book.name)
|
20
|
+
expect(page_body).to have_text(current_organization.book.name)
|
22
21
|
expect(user.reload.last_organization).to eq current_organization
|
23
22
|
end
|
24
23
|
|
@@ -27,8 +26,7 @@ feature 'disable user flow', organization_workspace: :test do
|
|
27
26
|
|
28
27
|
visit '/'
|
29
28
|
|
30
|
-
expect(
|
31
|
-
expect(
|
32
|
-
expect(page).to have_text('You are trying to visit a permamently disabled or deleted resource')
|
29
|
+
expect(page_body).to_not have_text(current_organization.book.name)
|
30
|
+
expect(page_body).to have_text('You are trying to visit a permamently disabled or deleted resource')
|
33
31
|
end
|
34
32
|
end
|
@@ -17,8 +17,7 @@ feature 'disable user flow', organization_workspace: :test do
|
|
17
17
|
scenario 'enabled organization' do
|
18
18
|
visit '/'
|
19
19
|
|
20
|
-
expect(
|
21
|
-
expect(page).to have_text(current_organization.book.name)
|
20
|
+
expect(page_body).to have_text(current_organization.book.name)
|
22
21
|
expect(user.reload.last_organization).to eq current_organization
|
23
22
|
end
|
24
23
|
|
@@ -29,17 +28,15 @@ feature 'disable user flow', organization_workspace: :test do
|
|
29
28
|
scenario 'visit /' do
|
30
29
|
visit '/'
|
31
30
|
|
32
|
-
expect(
|
33
|
-
expect(
|
34
|
-
expect(page).to have_text(I18n.t(:unprepared_organization_explanation))
|
31
|
+
expect(page_body).to_not have_text(current_organization.book.name)
|
32
|
+
expect(page_body).to have_text(I18n.t(:unprepared_organization_explanation))
|
35
33
|
end
|
36
34
|
|
37
35
|
scenario 'visit /user' do
|
38
36
|
visit '/test/user'
|
39
37
|
|
40
|
-
expect(
|
41
|
-
expect(
|
42
|
-
expect(page).to have_text(I18n.t(:unprepared_organization_explanation))
|
38
|
+
expect(page_body).to_not have_text(current_organization.book.name)
|
39
|
+
expect(page_body).to have_text(I18n.t(:unprepared_organization_explanation))
|
43
40
|
end
|
44
41
|
|
45
42
|
end
|
@@ -51,17 +48,15 @@ feature 'disable user flow', organization_workspace: :test do
|
|
51
48
|
scenario 'visit /' do
|
52
49
|
visit '/'
|
53
50
|
|
54
|
-
expect(
|
55
|
-
expect(
|
56
|
-
expect(page).to have_text(I18n.t(:disabled_organization_explanation))
|
51
|
+
expect(page_body).to_not have_text(current_organization.book.name)
|
52
|
+
expect(page_body).to have_text(I18n.t(:disabled_organization_explanation))
|
57
53
|
end
|
58
54
|
|
59
55
|
scenario 'visit /user' do
|
60
56
|
visit '/test/user'
|
61
57
|
|
62
|
-
expect(
|
63
|
-
expect(
|
64
|
-
expect(page).to have_text(I18n.t(:disabled_organization_explanation))
|
58
|
+
expect(page_body).to_not have_text(current_organization.book.name)
|
59
|
+
expect(page_body).to have_text(I18n.t(:disabled_organization_explanation))
|
65
60
|
end
|
66
61
|
|
67
62
|
end
|
@@ -182,7 +182,7 @@ feature 'Exercise Flow', organization_workspace: :test do
|
|
182
182
|
expect(page.find("#mu-exercise-layout")['value']).to eq('input_right')
|
183
183
|
end
|
184
184
|
|
185
|
-
scenario 'visit exercise by id, upload layout, not queriable language' do
|
185
|
+
scenario 'visit exercise by id, upload layout, not queriable language', :invalid_selector_error do
|
186
186
|
visit "/exercises/#{problem_5.id}"
|
187
187
|
|
188
188
|
expect(page).to have_text('Succ5')
|
@@ -272,7 +272,7 @@ feature 'Exercise Flow', organization_workspace: :test do
|
|
272
272
|
expect(page).not_to have_xpath("//a[@title='Edit']")
|
273
273
|
end
|
274
274
|
|
275
|
-
scenario 'writer should see the edit exercise link' do
|
275
|
+
scenario 'writer should see the edit exercise link', :xpath_no_matches do
|
276
276
|
set_current_user! writer
|
277
277
|
|
278
278
|
visit "/exercises/#{problem_2.id}"
|
@@ -39,7 +39,7 @@ feature 'Guide Reset Flow', organization_workspace: :test do
|
|
39
39
|
expect(page).to_not have_xpath(restart_xpath)
|
40
40
|
end
|
41
41
|
|
42
|
-
scenario 'visit guide with solutions sent for it' do
|
42
|
+
scenario 'visit guide with solutions sent for it', :xpath_no_matches do
|
43
43
|
problem.submit_solution! user
|
44
44
|
|
45
45
|
visit "/lessons/#{lesson.id}"
|
@@ -115,7 +115,7 @@ feature 'Guides Flow', organization_workspace: :test do
|
|
115
115
|
expect(page).not_to have_xpath("//a[@title='Edit']")
|
116
116
|
end
|
117
117
|
|
118
|
-
scenario 'writer should see the edit guide link' do
|
118
|
+
scenario 'writer should see the edit guide link', :xpath_no_matches do
|
119
119
|
set_current_user! writer
|
120
120
|
|
121
121
|
visit "/guides/#{lesson.guide.id}"
|
@@ -45,7 +45,7 @@ feature 'private org' do
|
|
45
45
|
allow_any_instance_of(ApplicationController).to receive(:from_sessions?).and_return(false)
|
46
46
|
end
|
47
47
|
|
48
|
-
scenario 'visitor should raise forbidden error' do
|
48
|
+
scenario 'visitor should raise forbidden error', :organization_not_nil do
|
49
49
|
set_current_user! visitor
|
50
50
|
|
51
51
|
visit '/'
|
@@ -59,7 +59,6 @@ feature 'private org' do
|
|
59
59
|
visit '/'
|
60
60
|
|
61
61
|
expect(student.reload.last_organization).to eq current_organization
|
62
|
-
expect(page).to have_text('powered by mumuki')
|
63
62
|
expect(page).to have_text(current_organization.description)
|
64
63
|
expect(page).to have_text(current_organization.book.description)
|
65
64
|
end
|
@@ -70,7 +69,6 @@ feature 'private org' do
|
|
70
69
|
visit '/'
|
71
70
|
|
72
71
|
expect(teacher.reload.last_organization).to eq current_organization
|
73
|
-
expect(page).to have_text('powered by mumuki')
|
74
72
|
expect(page).to have_text(current_organization.description)
|
75
73
|
expect(page).to have_text(current_organization.book.description)
|
76
74
|
end
|
@@ -17,11 +17,10 @@ feature 'public org', organization_workspace: :test do
|
|
17
17
|
|
18
18
|
context 'anonymous visitor' do
|
19
19
|
scenario 'from outside' do
|
20
|
-
|
20
|
+
set_request_header! 'Referer', 'http://google.com'
|
21
21
|
|
22
22
|
visit '/'
|
23
23
|
|
24
|
-
expect(page).to have_text('ム mumuki')
|
25
24
|
expect(page).to have_text('First Steps')
|
26
25
|
expect(page).to have_selector('.chapter', text: 'Functional Programming')
|
27
26
|
expect(page).to have_text(current_organization.book.name)
|
@@ -29,11 +28,10 @@ feature 'public org', organization_workspace: :test do
|
|
29
28
|
end
|
30
29
|
|
31
30
|
scenario 'from inside' do
|
32
|
-
|
31
|
+
set_request_header! 'Referer', 'http://en.mumuki.io/exercises/1'
|
33
32
|
|
34
33
|
visit '/'
|
35
34
|
|
36
|
-
expect(page).to have_text('ム mumuki')
|
37
35
|
expect(page).to have_text('First Steps')
|
38
36
|
expect(page).to have_selector('.chapter', text: 'Functional Programming')
|
39
37
|
expect(page).to have_text(current_organization.book.name)
|
@@ -46,11 +44,10 @@ feature 'public org', organization_workspace: :test do
|
|
46
44
|
before { exam.authorize! user }
|
47
45
|
|
48
46
|
scenario 'from outside' do
|
49
|
-
|
47
|
+
set_request_header! 'Referer', 'http://google.com'
|
50
48
|
|
51
49
|
visit '/'
|
52
50
|
|
53
|
-
expect(page).to have_text('ム mumuki')
|
54
51
|
expect(page).to have_text('First Steps')
|
55
52
|
expect(page).to have_selector('.chapter', text: 'Functional Programming')
|
56
53
|
expect(page).to have_text(current_organization.book.name)
|
@@ -59,11 +56,10 @@ feature 'public org', organization_workspace: :test do
|
|
59
56
|
end
|
60
57
|
|
61
58
|
scenario 'from inside' do
|
62
|
-
|
59
|
+
set_request_header! 'Referer', 'http://en.mumuki.io/exercises/1'
|
63
60
|
|
64
61
|
visit '/'
|
65
62
|
|
66
|
-
expect(page).to have_text('ム mumuki')
|
67
63
|
expect(page).to have_text('First Steps')
|
68
64
|
expect(page).to have_selector('.chapter', text: 'Functional Programming')
|
69
65
|
expect(page).to_not have_selector('.chapter.mu-locked', text: 'Functional Programming')
|
@@ -80,11 +76,10 @@ feature 'public org', organization_workspace: :test do
|
|
80
76
|
before { exam.authorize! user }
|
81
77
|
|
82
78
|
scenario 'from inside' do
|
83
|
-
|
79
|
+
set_request_header! 'Referer', 'http://google.com'
|
84
80
|
|
85
81
|
visit '/'
|
86
82
|
|
87
|
-
expect(page).to have_text('ム mumuki')
|
88
83
|
expect(page).to have_text('First Steps')
|
89
84
|
expect(page).to have_selector('.chapter.mu-locked', text: 'Functional Programming')
|
90
85
|
expect(page).to have_text(current_organization.book.name)
|
@@ -95,11 +90,10 @@ feature 'public org', organization_workspace: :test do
|
|
95
90
|
context 'incognito user' do
|
96
91
|
before { current_organization.update! incognito_mode_enabled: true }
|
97
92
|
scenario 'from inside' do
|
98
|
-
|
93
|
+
set_request_header! 'Referer', 'http://google.com'
|
99
94
|
|
100
95
|
visit '/'
|
101
96
|
|
102
|
-
expect(page).to have_text('ム mumuki')
|
103
97
|
expect(page).to have_text('First Steps')
|
104
98
|
expect(page).to have_selector('.chapter', text: 'Functional Programming')
|
105
99
|
expect(page).to have_text(current_organization.book.name)
|
@@ -9,7 +9,7 @@ feature 'Invitations Flow', organization_workspace: :test do
|
|
9
9
|
create(:lesson, guide: guide)
|
10
10
|
]) }
|
11
11
|
let(:book) { organization.book }
|
12
|
-
|
12
|
+
|
13
13
|
before do
|
14
14
|
book.update! chapters: [chapter]
|
15
15
|
end
|
@@ -33,7 +33,7 @@ feature 'Invitations Flow', organization_workspace: :test do
|
|
33
33
|
context 'with existing memberships' do
|
34
34
|
let(:permissions) { { student: 'test/nodejs' } }
|
35
35
|
|
36
|
-
scenario 'visit invitation, already joined' do
|
36
|
+
scenario 'visit invitation, already joined', :navigation_error do
|
37
37
|
visit '/join/invitacionAlNodejs'
|
38
38
|
expect(page).to have_text('Start Practicing!')
|
39
39
|
end
|
@@ -24,7 +24,7 @@ feature 'Login Flow', organization_workspace: :test do
|
|
24
24
|
expect(page).to have_text('Sign Out')
|
25
25
|
end
|
26
26
|
|
27
|
-
scenario 'can login and keeps session' do
|
27
|
+
scenario 'can login and keeps session', :navigation_error do
|
28
28
|
visit '/'
|
29
29
|
|
30
30
|
click_on 'Sign in'
|
@@ -45,7 +45,7 @@ feature 'Login Flow', organization_workspace: :test do
|
|
45
45
|
expect(page).to have_text('awesomeRubyGuide')
|
46
46
|
end
|
47
47
|
|
48
|
-
scenario 'can logout' do
|
48
|
+
scenario 'can logout', :element_not_interactable_error do
|
49
49
|
visit '/'
|
50
50
|
|
51
51
|
click_on 'Sign in'
|
@@ -22,8 +22,8 @@ feature 'not found private on app', organization_workspace: :base do
|
|
22
22
|
expect(page).to have_text 'You may have mistyped the address or the page may have moved'
|
23
23
|
end
|
24
24
|
|
25
|
-
scenario 'api without authorization' do
|
26
|
-
|
25
|
+
scenario 'api without authorization', :json_eq_error do
|
26
|
+
set_request_header! 'Authorization', "Bearer #{student_api_client.token}"
|
27
27
|
|
28
28
|
visit '/api/nonexistentroute'
|
29
29
|
|
@@ -33,8 +33,8 @@ feature 'not found private on app', organization_workspace: :base do
|
|
33
33
|
' with permissions !student:central/*;teacher:;headmaster:;janitor:;admin:;owner:']
|
34
34
|
end
|
35
35
|
|
36
|
-
scenario 'api with authentication' do
|
37
|
-
|
36
|
+
scenario 'api with authentication', :json_eq_error do
|
37
|
+
set_request_header! 'Authorization', "Bearer #{admin_api_client.token}"
|
38
38
|
|
39
39
|
visit '/api/nonexistentroute'
|
40
40
|
|
@@ -2,17 +2,12 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
feature 'not found public on app' do
|
4
4
|
let!(:central) { create(:organization, name: 'central') }
|
5
|
+
let!(:base) { create(:organization, name: 'base') }
|
5
6
|
let!(:some_orga) { create(:public_organization, name: 'someorga', profile: profile) }
|
6
7
|
|
7
8
|
let(:profile) { Mumuki::Domain::Organization::Profile.parse json }
|
8
9
|
let(:json) { { contact_email: 'some@email.com', locale: 'en', errors_explanations: { 404 => 'Some explanation'} } }
|
9
10
|
|
10
|
-
scenario 'when routes does not exist in implicit central' do
|
11
|
-
visit '/foo'
|
12
|
-
|
13
|
-
expect(page).to have_text('You may have mistyped the address')
|
14
|
-
end
|
15
|
-
|
16
11
|
scenario 'when route does not exist in explicit central' do
|
17
12
|
set_subdomain_host! 'test'
|
18
13
|
|
@@ -49,7 +49,7 @@ feature 'Profile Flow', organization_workspace: :test do
|
|
49
49
|
expect(page).to have_text('Please complete your profile data to continue!')
|
50
50
|
end
|
51
51
|
|
52
|
-
scenario 'is able to log out' do
|
52
|
+
scenario 'is able to log out', :element_not_interactable_error do
|
53
53
|
click_on 'Sign in'
|
54
54
|
set_automatic_login! false
|
55
55
|
|
@@ -12,8 +12,8 @@ describe PageTitleHelper, organization_workspace: :test do
|
|
12
12
|
|
13
13
|
before { reindex_current_organization! }
|
14
14
|
|
15
|
-
it { expect(page_title nil).to eq '
|
16
|
-
it { expect(page_title Problem.new).to eq '
|
17
|
-
it { expect(page_title exercise).to eq 'C1: A Guide - An Exercise -
|
15
|
+
it { expect(page_title nil).to eq 'test' }
|
16
|
+
it { expect(page_title Problem.new).to eq 'test' }
|
17
|
+
it { expect(page_title exercise).to eq 'C1: A Guide - An Exercise - test' }
|
18
18
|
end
|
19
19
|
end
|
@@ -47,6 +47,29 @@ describe('editors', () => {
|
|
47
47
|
expect(mumuki.editors.getSubmission()).toEqual({"solution[content]":"the solution"});
|
48
48
|
});
|
49
49
|
|
50
|
+
|
51
|
+
it('reads the form if no sources and exercise is multifile', () => {
|
52
|
+
$('body').html(`
|
53
|
+
<form role="form" class="new_solution">
|
54
|
+
<div class="field form-group editor-code">
|
55
|
+
<textarea
|
56
|
+
class="form-control editor"
|
57
|
+
data-editor-language="html"
|
58
|
+
name="solution[content[index.html]]"
|
59
|
+
id="solution_content[index.html]">some html</textarea>
|
60
|
+
<textarea
|
61
|
+
class="form-control editor"
|
62
|
+
data-editor-language="css"
|
63
|
+
name="solution[content[receta.css]]"
|
64
|
+
id="solution_content[receta.css]">some css</textarea>
|
65
|
+
</div>
|
66
|
+
</form>`)
|
67
|
+
expect(mumuki.editors.getSubmission()).toEqual({
|
68
|
+
"solution[content[index.html]]": "some html",
|
69
|
+
"solution[content[receta.css]]": "some css"
|
70
|
+
});
|
71
|
+
});
|
72
|
+
|
50
73
|
it('produces empty submission if no form nor sources', () => {
|
51
74
|
$('body').html(``);
|
52
75
|
expect(mumuki.editors.getSubmission()).toEqual({});
|
@@ -0,0 +1,58 @@
|
|
1
|
+
describe('gamification', () => {
|
2
|
+
describe('formula', () => {
|
3
|
+
it('has positive coefficients', () => {
|
4
|
+
expect(mumuki.gamification.Formula.QUADRATIC_COEFFICIENT).toBeGreaterThan(0);
|
5
|
+
expect(mumuki.gamification.Formula.LINEAR_COEFFICIENT).toBeGreaterThan(0);
|
6
|
+
});
|
7
|
+
|
8
|
+
it('has negative constant term', () => {
|
9
|
+
expect(mumuki.gamification.Formula.CONSTANT_TERM).toBeLessThan(0);
|
10
|
+
});
|
11
|
+
});
|
12
|
+
|
13
|
+
describe('level progression', () => {
|
14
|
+
describe('exp to level up', () => {
|
15
|
+
it('takes 175 exp points to go from level 1 to 2', () => {
|
16
|
+
expect(new mumuki.gamification.LevelProgression(0).expToLevelUp()).toBe(175);
|
17
|
+
});
|
18
|
+
|
19
|
+
it('takes 225 points to go from level 2 to 3', () => {
|
20
|
+
expect(new mumuki.gamification.LevelProgression(175).expToLevelUp()).toBe(225);
|
21
|
+
});
|
22
|
+
});
|
23
|
+
|
24
|
+
describe('current level', () => {
|
25
|
+
it('is at level 1 when 0 exp points', () => {
|
26
|
+
expect(new mumuki.gamification.LevelProgression(0).currentLevel()).toBe(1);
|
27
|
+
});
|
28
|
+
|
29
|
+
it('is at level 5 when 1000 exp points', () => {
|
30
|
+
expect(new mumuki.gamification.LevelProgression(1000).currentLevel()).toBe(5);
|
31
|
+
});
|
32
|
+
});
|
33
|
+
|
34
|
+
describe('triggers level change', () => {
|
35
|
+
it('does not trigger when small exp difference', () => {
|
36
|
+
expect(new mumuki.gamification.LevelProgression(1000).triggersLevelChange(1050)).toBe(false);
|
37
|
+
});
|
38
|
+
|
39
|
+
it('does trigger when big exp difference', () => {
|
40
|
+
expect(new mumuki.gamification.LevelProgression(1000).triggersLevelChange(1500)).toBe(true);
|
41
|
+
});
|
42
|
+
});
|
43
|
+
|
44
|
+
describe('current level progress', () => {
|
45
|
+
it('is at 0% when just leveled up', () => {
|
46
|
+
expect(new mumuki.gamification.LevelProgression(675).currentLevelProgress()).toBe(0);
|
47
|
+
});
|
48
|
+
|
49
|
+
it('is at 50% when halfway through', () => {
|
50
|
+
expect(new mumuki.gamification.LevelProgression(837).currentLevelProgress()).toBeCloseTo(0.50, 0.01);
|
51
|
+
});
|
52
|
+
|
53
|
+
it('is at 99% when almost there', () => {
|
54
|
+
expect(new mumuki.gamification.LevelProgression(999).currentLevelProgress()).toBeCloseTo(0.99, 0.01);
|
55
|
+
});
|
56
|
+
});
|
57
|
+
});
|
58
|
+
});
|