mumuki-laboratory 8.1.3 → 8.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -8
  3. data/app/assets/javascripts/mumuki_laboratory/application/bridge.js +2 -1
  4. data/app/assets/javascripts/mumuki_laboratory/application/button.js +2 -4
  5. data/app/assets/javascripts/mumuki_laboratory/application/codemirror-builder.js +1 -1
  6. data/app/assets/javascripts/mumuki_laboratory/application/codemirror.js +2 -2
  7. data/app/assets/javascripts/mumuki_laboratory/application/i18n.js +73 -0
  8. data/app/assets/javascripts/mumuki_laboratory/application/kids.js +22 -1
  9. data/app/assets/javascripts/mumuki_laboratory/application/kindergarten.js +6 -1
  10. data/app/assets/javascripts/mumuki_laboratory/application/primary.js +5 -3
  11. data/app/assets/javascripts/mumuki_laboratory/application/results-renderer.js +28 -1
  12. data/app/assets/javascripts/mumuki_laboratory/application/submission.js +72 -48
  13. data/app/assets/stylesheets/mumuki_laboratory/application.scss +1 -0
  14. data/app/assets/stylesheets/mumuki_laboratory/application/_codemirror-themes.scss +1 -0
  15. data/app/assets/stylesheets/mumuki_laboratory/application/codemirror-themes/_mu-light.scss +3 -0
  16. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_kids.scss +4 -0
  17. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_kids_results.scss +1 -0
  18. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_overlap.scss +0 -4
  19. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_terms.scss +4 -0
  20. data/app/controllers/chapters_controller.rb +9 -5
  21. data/app/controllers/guide_container_controller.rb +2 -7
  22. data/app/helpers/assignment_result_helper.rb +1 -1
  23. data/app/helpers/contextualization_result_helper.rb +0 -8
  24. data/app/helpers/discussions_helper.rb +12 -4
  25. data/app/helpers/editor_tabs_helper.rb +1 -1
  26. data/app/helpers/icons_helper.rb +1 -1
  27. data/app/helpers/links_helper.rb +1 -1
  28. data/app/helpers/menu_bar_helper.rb +9 -1
  29. data/app/helpers/overlapped_buttons_helper.rb +13 -5
  30. data/app/views/book/show.html.erb +1 -1
  31. data/app/views/book_discussions/index.html.erb +3 -1
  32. data/app/views/chapters/show.html.erb +21 -9
  33. data/app/views/complements/show.html.erb +1 -1
  34. data/app/views/discussions/_message.html.erb +2 -2
  35. data/app/views/discussions/index.html.erb +11 -4
  36. data/app/views/exams/show.html.erb +1 -1
  37. data/app/views/exercise_solutions/_kids_level_up.html.erb +1 -1
  38. data/app/views/exercises/_exercise_assignment.html.erb +1 -1
  39. data/app/views/exercises/_read_only.html.erb +1 -1
  40. data/app/views/exercises/show.html.erb +2 -2
  41. data/app/views/layouts/_discussions.html.erb +0 -4
  42. data/app/views/layouts/_guide.html.erb +9 -36
  43. data/app/views/layouts/_guide_container.html.erb +28 -0
  44. data/app/views/layouts/_guide_title_icons.html.erb +9 -0
  45. data/app/views/layouts/_kids.html.erb +4 -4
  46. data/app/views/layouts/_kindergarten.html.erb +5 -5
  47. data/app/views/layouts/_social_media.html.erb +4 -4
  48. data/app/views/layouts/_timer.html.erb +1 -1
  49. data/app/views/layouts/application.html.erb +7 -5
  50. data/app/views/layouts/exercise_inputs/editors/_code.html.erb +1 -6
  51. data/app/views/layouts/exercise_inputs/editors/_multiple_files.html.erb +4 -9
  52. data/app/views/layouts/exercise_inputs/forms/_problem_form.html.erb +1 -1
  53. data/app/views/layouts/exercise_inputs/layouts/_input_kindergarten.html.erb +1 -1
  54. data/app/views/layouts/modals/_guide_corollary.html.erb +13 -3
  55. data/app/views/layouts/modals/_kids_results.html.erb +2 -2
  56. data/app/views/layouts/modals/_kindergarten_context.html.erb +3 -3
  57. data/app/views/layouts/modals/_kindergarten_results.html.erb +3 -3
  58. data/app/views/layouts/modals/_kindergarten_results_aborted.html.erb +2 -2
  59. data/app/views/layouts/modals/_level_up.html.erb +1 -1
  60. data/app/views/lessons/show.html.erb +1 -1
  61. data/app/views/users/_edit_user_form.html.erb +1 -1
  62. data/app/views/users/_term.html.erb +1 -1
  63. data/app/views/users/_user_form.html.erb +1 -1
  64. data/lib/mumuki/laboratory/controllers/results_rendering.rb +2 -1
  65. data/lib/mumuki/laboratory/engine.rb +1 -1
  66. data/lib/mumuki/laboratory/locales/en.yml +6 -8
  67. data/lib/mumuki/laboratory/locales/es-CL.yml +6 -3
  68. data/lib/mumuki/laboratory/locales/es.yml +9 -10
  69. data/lib/mumuki/laboratory/locales/pt.yml +6 -8
  70. data/lib/mumuki/laboratory/version.rb +1 -1
  71. data/spec/controllers/exercise_solutions_controller_spec.rb +3 -2
  72. data/spec/dummy/db/schema.rb +50 -1
  73. data/spec/dummy/public/character/animations.json +1 -0
  74. data/{public → spec/dummy/public}/character/kibi/context.svg +0 -0
  75. data/{public → spec/dummy/public}/character/kibi/failure.svg +0 -0
  76. data/{public → spec/dummy/public}/character/kibi/jump.svg +0 -0
  77. data/spec/dummy/public/character/kibi/passed_with_warnings.svg +4 -0
  78. data/{public → spec/dummy/public}/character/kibi/success2_l.svg +0 -0
  79. data/{public → spec/dummy/public}/character/kibi/success_l.svg +0 -0
  80. data/{public → spec/dummy/public}/character/magnifying_glass/apparition.svg +0 -0
  81. data/{public → spec/dummy/public}/character/magnifying_glass/loop.svg +0 -0
  82. data/spec/features/chapters_flow_spec.rb +112 -0
  83. data/spec/features/login_flow_spec.rb +1 -1
  84. data/spec/features/terms_flow_spec.rb +2 -0
  85. data/spec/features/topic_flow_spec.rb +0 -1
  86. data/spec/helpers/icons_helper_spec.rb +3 -3
  87. data/spec/helpers/test_results_rendering_spec.rb +8 -8
  88. data/spec/helpers/with_navigation_spec.rb +14 -14
  89. data/spec/javascripts/bridge-spec.js +2 -2
  90. data/spec/javascripts/csrf-token-spec.js +2 -2
  91. data/spec/javascripts/editors-spec.js +7 -9
  92. data/spec/javascripts/elipsis-spec.js +4 -4
  93. data/spec/javascripts/events-spec.js +7 -7
  94. data/spec/javascripts/exercise-spec.js +7 -8
  95. data/spec/javascripts/gamification-spec.js +2 -2
  96. data/spec/javascripts/global-spec.js +3 -3
  97. data/spec/javascripts/i18n-spec.js +82 -0
  98. data/spec/javascripts/kids-button-spec.js +34 -0
  99. data/spec/javascripts/results-renderers-spec.js +5 -5
  100. data/spec/javascripts/speech-bubble-renderer-spec.js +2 -3
  101. data/spec/javascripts/submissions-store-spec.js +14 -14
  102. data/spec/javascripts/sync-mode-spec.js +3 -3
  103. data/spec/javascripts/timeout-spec.js +2 -2
  104. data/spec/javascripts/timer-spec.js +2 -2
  105. metadata +140 -117
  106. data/spec/dummy/config/database.travis.yml +0 -4
  107. data/spec/features/chapter_spec.rb +0 -70
@@ -42,7 +42,7 @@ feature 'Login Flow', organization_workspace: :test do
42
42
 
43
43
  expect(page).to_not have_text('Sign in')
44
44
  expect(page).to have_text('Sign Out')
45
- expect(page).to have_text('awesomeRubyGuide')
45
+ expect(page).to have_text('C1')
46
46
  end
47
47
 
48
48
  scenario 'can logout', :element_not_interactable_error do
@@ -102,6 +102,7 @@ feature 'Terms Flow', organization_workspace: :test do
102
102
  visit '/discussions'
103
103
  expect(page).to have_text('Accept terms')
104
104
 
105
+ check :user_terms_of_service
105
106
  click_on 'Accept'
106
107
  expect(page).to have_text('Discussions')
107
108
  end
@@ -111,6 +112,7 @@ feature 'Terms Flow', organization_workspace: :test do
111
112
  visit '/'
112
113
  expect(page).to have_text('Accept terms')
113
114
 
115
+ check :user_terms_of_service
114
116
  click_on 'Accept'
115
117
  expect(page).to have_text(test_organization.book.name)
116
118
  end
@@ -15,7 +15,6 @@ feature 'Topic Flow', organization_workspace: :test do
15
15
  visit "/topics/#{topic_in_path.transparent_id}"
16
16
 
17
17
  expect(page).to have_text('Functional Programming')
18
- expect(page).to have_text('Lessons')
19
18
  end
20
19
 
21
20
  scenario 'visit topic in path not transparently' do
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe IconsHelper, organization_workspace: :test do
4
4
  helper IconsHelper
5
- helper FontAwesome::Rails::IconHelper
5
+ helper FontAwesome5::Rails::IconHelper
6
6
 
7
7
  describe '#language_icon' do
8
8
  let(:haskell) { create(:language, name: 'Haskell') }
@@ -16,7 +16,7 @@ describe IconsHelper, organization_workspace: :test do
16
16
  }
17
17
  let(:failed_submission) { create(:assignment, status: :failed) }
18
18
 
19
- it { expect(status_icon(passed_submission)).to eq '<i class="fa fa-check-circle text-success status-icon"></i>' }
20
- it { expect(status_icon(failed_submission)).to eq '<i class="fa fa-times-circle text-danger status-icon"></i>' }
19
+ it { expect(status_icon(passed_submission)).to eq '<i class="fas fa-check-circle text-success status-icon"></i>' }
20
+ it { expect(status_icon(failed_submission)).to eq '<i class="fas fa-times-circle text-danger status-icon"></i>' }
21
21
  end
22
22
  end
@@ -3,7 +3,7 @@ require 'ostruct'
3
3
 
4
4
  describe ContextualizationResultHelper do
5
5
  helper IconsHelper
6
- helper FontAwesome::Rails::IconHelper
6
+ helper FontAwesome5::Rails::IconHelper
7
7
  helper ContextualizationResultHelper
8
8
 
9
9
 
@@ -13,13 +13,13 @@ describe ContextualizationResultHelper do
13
13
  context 'plain explanation' do
14
14
  let(:expectation_result) { {result: :failed, explanation: 'you must delegate'} }
15
15
 
16
- it { expect(html).to eq '<i class="fa fa-times-circle text-danger status-icon"></i> you must delegate' }
16
+ it { expect(html).to eq '<i class="fas fa-times-circle text-danger status-icon"></i> you must delegate' }
17
17
  end
18
18
 
19
19
  context 'html explanation' do
20
20
  let(:expectation_result) { {result: :failed, explanation: 'you must use <strong>if</strong>'} }
21
21
 
22
- it { expect(html).to eq '<i class="fa fa-times-circle text-danger status-icon"></i> you must use <strong>if</strong>' }
22
+ it { expect(html).to eq '<i class="fas fa-times-circle text-danger status-icon"></i> you must use <strong>if</strong>' }
23
23
  end
24
24
  end
25
25
 
@@ -35,7 +35,7 @@ describe ContextualizationResultHelper do
35
35
  test_results: [{title: '2 is 2', status: :passed, result: ''}]) }
36
36
 
37
37
  it { expect(html).to be_html_safe }
38
- it { expect(html).to include "<i class=\"fa fa-check-circle text-success status-icon\"></i>" }
38
+ it { expect(html).to include "<i class=\"fas fa-check-circle text-success status-icon\"></i>" }
39
39
  it { expect(html).to include "2 is 2" }
40
40
  end
41
41
 
@@ -47,7 +47,7 @@ describe ContextualizationResultHelper do
47
47
  exercise: problem,
48
48
  test_results: [{title: '2 is 2', status: :failed, result: 'something _went_ wrong'}]) }
49
49
 
50
- it { expect(html).to include "<i class=\"fa fa-times-circle text-danger status-icon\"></i>" }
50
+ it { expect(html).to include "<i class=\"fas fa-times-circle text-danger status-icon\"></i>" }
51
51
  it { expect(html).to include "2 is 2" }
52
52
  it { expect(html).to include "<pre>something _went_ wrong</pre>" }
53
53
  end
@@ -59,7 +59,7 @@ describe ContextualizationResultHelper do
59
59
  exercise: problem,
60
60
  test_results: [{title: '2 is 2', status: :failed, result: 'something went _really_ wrong'}]) }
61
61
 
62
- it { expect(html).to include "<i class=\"fa fa-times-circle text-danger status-icon\"></i>" }
62
+ it { expect(html).to include "<i class=\"fas fa-times-circle text-danger status-icon\"></i>" }
63
63
  it { expect(html).to include "2 is 2" }
64
64
  it { expect(html).to include "<p>something went <em>really</em> wrong</p>" }
65
65
  end
@@ -72,7 +72,7 @@ describe ContextualizationResultHelper do
72
72
  test_results: [{title: 'foo is 2', status: :failed, result: 'foo is undefined', summary: {type: 'undefined_variable', message: 'you are using things that are _not defined_'}}]) }
73
73
 
74
74
  it { expect(html).to include 'foo is 2: you are using things that are <em>not defined</em>' }
75
- it { expect(html).to include "<i class=\"fa fa-times-circle text-danger status-icon\"></i>" }
75
+ it { expect(html).to include "<i class=\"fas fa-times-circle text-danger status-icon\"></i>" }
76
76
  it { expect(html).to include '<p>foo is undefined</p>' }
77
77
  end
78
78
 
@@ -84,7 +84,7 @@ describe ContextualizationResultHelper do
84
84
  test_results: [{title: '', status: :failed, result: 'foo is undefined', summary: {type: 'undefined_variable', message: 'you are using things that are _not defined_'}}]) }
85
85
 
86
86
  it { expect(html).to include 'you are using things that are <em>not defined</em>' }
87
- it { expect(html).to include "<i class=\"fa fa-times-circle text-danger status-icon\"></i>" }
87
+ it { expect(html).to include "<i class=\"fas fa-times-circle text-danger status-icon\"></i>" }
88
88
  it { expect(html).to include '<p>foo is undefined</p>' }
89
89
  end
90
90
  end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe WithStudentPathNavigation, organization_workspace: :test do
4
4
  helper WithStudentPathNavigation
5
- helper FontAwesome::Rails::IconHelper
5
+ helper FontAwesome5::Rails::IconHelper
6
6
 
7
7
  describe '#next_button' do
8
8
  let(:current_user) { create(:user) }
@@ -14,9 +14,9 @@ describe WithStudentPathNavigation, organization_workspace: :test do
14
14
  let!(:exercise_3) { create(:exercise, id: 13, name: 'exercise 3', guide: guide) }
15
15
 
16
16
  context 'when user did not submit any solution' do
17
- it { expect(next_button(exercise_1)).to eq "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/exercises/#{exercise_2.friendly_name}\">Next: exercise 2 <i class=\"fa fa-chevron-right\"></i></a>" }
18
- it { expect(next_button(exercise_2)).to eq "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/exercises/#{exercise_3.friendly_name}\">Next: exercise 3 <i class=\"fa fa-chevron-right\"></i></a>" }
19
- it { expect(next_button(exercise_3)).to eq "<a class=\"btn btn-warning btn-block\" role=\"button\" href=\"/exercises/#{exercise_1.friendly_name}\">Next pending: exercise 1 <i class=\"fa fa-chevron-right\"></i></a>" }
17
+ it { expect(next_button(exercise_1)).to eq "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/exercises/#{exercise_2.friendly_name}\"><span class=\"fa5-text-r\">Next: exercise 2</span><i class=\"fas fa-chevron-right\"></i></a>" }
18
+ it { expect(next_button(exercise_2)).to eq "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/exercises/#{exercise_3.friendly_name}\"><span class=\"fa5-text-r\">Next: exercise 3</span><i class=\"fas fa-chevron-right\"></i></a>" }
19
+ it { expect(next_button(exercise_3)).to eq "<a class=\"btn btn-warning btn-block\" role=\"button\" href=\"/exercises/#{exercise_1.friendly_name}\"><span class=\"fa5-text-r\">Next pending: exercise 1</span><i class=\"fas fa-chevron-right\"></i></a>" }
20
20
  end
21
21
 
22
22
  context 'when on last unresolved exercise' do
@@ -25,9 +25,9 @@ describe WithStudentPathNavigation, organization_workspace: :test do
25
25
  exercise_3.submit_solution!(current_user).passed!
26
26
  end
27
27
 
28
- it { expect(next_button(exercise_1)).to eq "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/exercises/#{exercise_2.friendly_name}\">Next: exercise 2 <i class=\"fa fa-chevron-right\"></i></a>" }
28
+ it { expect(next_button(exercise_1)).to eq "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/exercises/#{exercise_2.friendly_name}\"><span class=\"fa5-text-r\">Next: exercise 2</span><i class=\"fas fa-chevron-right\"></i></a>" }
29
29
  it { expect(next_button(exercise_2)).to be nil }
30
- it { expect(next_button(exercise_3)).to eq "<a class=\"btn btn-warning btn-block\" role=\"button\" href=\"/exercises/#{exercise_2.friendly_name}\">Next pending: exercise 2 <i class=\"fa fa-chevron-right\"></i></a>" }
30
+ it { expect(next_button(exercise_3)).to eq "<a class=\"btn btn-warning btn-block\" role=\"button\" href=\"/exercises/#{exercise_2.friendly_name}\"><span class=\"fa5-text-r\">Next pending: exercise 2</span><i class=\"fas fa-chevron-right\"></i></a>" }
31
31
  end
32
32
 
33
33
  context 'when user did submit a solution' do
@@ -35,9 +35,9 @@ describe WithStudentPathNavigation, organization_workspace: :test do
35
35
  exercise_1.submit_solution!(current_user).passed!
36
36
  end
37
37
 
38
- it { expect(next_button(exercise_1)).to eq "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/exercises/#{exercise_2.friendly_name}\">Next: exercise 2 <i class=\"fa fa-chevron-right\"></i></a>" }
39
- it { expect(next_button(exercise_2)).to eq "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/exercises/#{exercise_3.friendly_name}\">Next: exercise 3 <i class=\"fa fa-chevron-right\"></i></a>" }
40
- it { expect(next_button(exercise_3)).to eq "<a class=\"btn btn-warning btn-block\" role=\"button\" href=\"/exercises/#{exercise_2.friendly_name}\">Next pending: exercise 2 <i class=\"fa fa-chevron-right\"></i></a>" }
38
+ it { expect(next_button(exercise_1)).to eq "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/exercises/#{exercise_2.friendly_name}\"><span class=\"fa5-text-r\">Next: exercise 2</span><i class=\"fas fa-chevron-right\"></i></a>" }
39
+ it { expect(next_button(exercise_2)).to eq "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/exercises/#{exercise_3.friendly_name}\"><span class=\"fa5-text-r\">Next: exercise 3</span><i class=\"fas fa-chevron-right\"></i></a>" }
40
+ it { expect(next_button(exercise_3)).to eq "<a class=\"btn btn-warning btn-block\" role=\"button\" href=\"/exercises/#{exercise_2.friendly_name}\"><span class=\"fa5-text-r\">Next pending: exercise 2</span><i class=\"fas fa-chevron-right\"></i></a>" }
41
41
  end
42
42
  end
43
43
 
@@ -46,8 +46,8 @@ describe WithStudentPathNavigation, organization_workspace: :test do
46
46
  let!(:exercise) { create(:exercise, id: 12, name: 'exercise 2', guide: guide) }
47
47
 
48
48
  context 'when user did not submit any exercise' do
49
- it { expect(next_button(reading)).to eq "<a class=\"btn-confirmation btn btn-success btn-block\" data-confirmation-url=\"/exercises/#{reading.friendly_name}/confirmations\" role=\"button\" href=\"/exercises/#{exercise.friendly_name}\">Next: exercise 2 <i class=\"fa fa-chevron-right\"></i></a>" }
50
- it { expect(next_button(exercise)).to eq "<a class=\"btn btn-warning btn-block\" role=\"button\" href=\"/exercises/#{reading.friendly_name}\">Next pending: exercise 1 <i class=\"fa fa-chevron-right\"></i></a>" }
49
+ it { expect(next_button(reading)).to eq "<a class=\"btn-confirmation btn btn-success btn-block\" data-confirmation-url=\"/exercises/#{reading.friendly_name}/confirmations\" role=\"button\" href=\"/exercises/#{exercise.friendly_name}\"><span class=\"fa5-text-r\">Next: exercise 2</span><i class=\"fas fa-chevron-right\"></i></a>" }
50
+ it { expect(next_button(exercise)).to eq "<a class=\"btn btn-warning btn-block\" role=\"button\" href=\"/exercises/#{reading.friendly_name}\"><span class=\"fa5-text-r\">Next pending: exercise 1</span><i class=\"fas fa-chevron-right\"></i></a>" }
51
51
  end
52
52
 
53
53
  context 'when user finished just reading' do
@@ -55,7 +55,7 @@ describe WithStudentPathNavigation, organization_workspace: :test do
55
55
  reading.submit_confirmation!(current_user)
56
56
  end
57
57
 
58
- it { expect(next_button(reading)).to eq "<a class=\"btn-confirmation btn btn-success btn-block\" data-confirmation-url=\"/exercises/#{reading.friendly_name}/confirmations\" role=\"button\" href=\"/exercises/#{exercise.friendly_name}\">Next: exercise 2 <i class=\"fa fa-chevron-right\"></i></a>" }
58
+ it { expect(next_button(reading)).to eq "<a class=\"btn-confirmation btn btn-success btn-block\" data-confirmation-url=\"/exercises/#{reading.friendly_name}/confirmations\" role=\"button\" href=\"/exercises/#{exercise.friendly_name}\"><span class=\"fa5-text-r\">Next: exercise 2</span><i class=\"fas fa-chevron-right\"></i></a>" }
59
59
  it { expect(next_button(exercise)).to eq nil }
60
60
  end
61
61
  end
@@ -83,12 +83,12 @@ describe WithStudentPathNavigation, organization_workspace: :test do
83
83
  let(:lessons) { [lesson_1, lesson_2, lesson_3] }
84
84
 
85
85
  context 'one suggestion' do
86
- it { expect(next_button(lesson_2)).to include "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/lessons/#{lesson_3.friendly_name}\">Next: #{lesson_3.name} <i class=\"fa fa-chevron-right\"></i></a>" }
86
+ it { expect(next_button(lesson_2)).to include "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/lessons/#{lesson_3.friendly_name}\"><span class=\"fa5-text-r\">Next: #{lesson_3.name}</span><i class=\"fas fa-chevron-right\"></i></a>" }
87
87
  it { expect(next_button(lesson_1)).to be_html_safe }
88
88
  end
89
89
 
90
90
  context 'many suggestions' do
91
- it { expect(next_button(lesson_1)).to include "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/lessons/#{lesson_2.friendly_name}\">Next: #{lesson_2.name} <i class=\"fa fa-chevron-right\"></i></a>" }
91
+ it { expect(next_button(lesson_1)).to include "<a class=\"btn btn-success btn-block\" role=\"button\" href=\"/lessons/#{lesson_2.friendly_name}\"><span class=\"fa5-text-r\">Next: #{lesson_2.name}</span><i class=\"fas fa-chevron-right\"></i></a>" }
92
92
  it { expect(next_button(lesson_1)).to be_html_safe }
93
93
  end
94
94
  end
@@ -1,5 +1,5 @@
1
1
  describe('bridge', () => {
2
2
  it('can create bridge', () => {
3
3
  expect(new mumuki.bridge.Laboratory()).not.toBe(null);
4
- })
5
- })
4
+ });
5
+ });
@@ -1,7 +1,7 @@
1
1
  describe('csrf token', () => {
2
2
  it('can create token', () => {
3
3
  expect(new mumuki.CsrfToken()).not.toBe(null);
4
- })
5
- })
4
+ });
5
+ });
6
6
 
7
7
 
@@ -1,11 +1,10 @@
1
1
  describe('editors', () => {
2
-
3
2
  beforeEach(() => {
4
- mumuki.CustomEditor.clearSources()
5
- })
3
+ mumuki.CustomEditor.clearSources();
4
+ });
6
5
 
7
6
  it('has initially no sources', () => {
8
- expect(mumuki.CustomEditor.hasSources).toBe(false)
7
+ expect(mumuki.CustomEditor.hasSources).toBe(false);
9
8
  });
10
9
 
11
10
  it('can add a custom source', () => {
@@ -26,7 +25,7 @@ describe('editors', () => {
26
25
  <div class="field form-group editor-code">
27
26
  <textarea class="form-control editor" name="solution[content]" id="solution_content">the standard solution</textarea>
28
27
  </div>
29
- </form>`)
28
+ </form>`);
30
29
 
31
30
  mumuki.editors.addCustomSource({
32
31
  getContent() {
@@ -43,11 +42,10 @@ describe('editors', () => {
43
42
  <div class="field form-group editor-code">
44
43
  <textarea class="form-control editor" name="solution[content]" id="solution_content">the solution</textarea>
45
44
  </div>
46
- </form>`)
45
+ </form>`);
47
46
  expect(mumuki.editors.getSubmission()).toEqual({"solution[content]":"the solution"});
48
47
  });
49
48
 
50
-
51
49
  it('reads the form if no sources and exercise is multifile', () => {
52
50
  $('body').html(`
53
51
  <form role="form" class="new_solution">
@@ -63,7 +61,7 @@ describe('editors', () => {
63
61
  name="solution[content[receta.css]]"
64
62
  id="solution_content[receta.css]">some css</textarea>
65
63
  </div>
66
- </form>`)
64
+ </form>`);
67
65
  expect(mumuki.editors.getSubmission()).toEqual({
68
66
  "solution[content[index.html]]": "some html",
69
67
  "solution[content[receta.css]]": "some css"
@@ -74,4 +72,4 @@ describe('editors', () => {
74
72
  $('body').html(``);
75
73
  expect(mumuki.editors.getSubmission()).toEqual({});
76
74
  });
77
- })
75
+ });
@@ -1,7 +1,7 @@
1
1
  describe('elipsis', () => {
2
2
  it('does nothing when no elipsis', () => {
3
3
  expect(mumuki.elipsis('hello')).toEqual('hello');
4
- })
4
+ });
5
5
 
6
6
  it('replaces student elipsis', () => {
7
7
  expect(mumuki.elipsis(`function longitud(unString) {
@@ -10,7 +10,7 @@ describe('elipsis', () => {
10
10
  /*@elipsis-for-student&gt;*/
11
11
  }`)).toEqual(`function longitud(unString) {
12
12
  /* ... */
13
- }`)
13
+ }`);
14
14
  });
15
15
 
16
16
  it('replaces student hidden', () => {
@@ -20,6 +20,6 @@ describe('elipsis', () => {
20
20
  /*@hidden-for-student&gt;*/
21
21
  }`)).toEqual(`function longitud(unString) {
22
22
  /**/
23
- }`)
23
+ }`);
24
24
  });
25
- })
25
+ });
@@ -6,18 +6,18 @@ describe('events', () => {
6
6
  it('is not called when it is not fired', () => {
7
7
  mumuki.events.on('foo', (e) => {
8
8
  fail(`should not be called, but got ${JSON.stringify(e)}`);
9
- })
10
- })
9
+ });
10
+ });
11
11
 
12
12
  it('is not called when it is fired but not enabled', () => {
13
13
  let fired = false;
14
14
  mumuki.events.on('foo', (e) => {
15
15
  fail(`should not be called, but got ${JSON.stringify(e)}`);
16
16
  fired = true;
17
- })
17
+ });
18
18
  mumuki.events.fire('foo', 42);
19
19
  expect(fired).toBe(false);
20
- })
20
+ });
21
21
 
22
22
  it('is called when it is fired and enabled', () => {
23
23
  let fired = false;
@@ -25,9 +25,9 @@ describe('events', () => {
25
25
  mumuki.events.on('foo', (event) => {
26
26
  expect(event).toEqual(42);
27
27
  fired = true;
28
- })
28
+ });
29
29
 
30
30
  mumuki.events.fire('foo', 42);
31
31
  expect(fired).toBe(true);
32
- })
33
- })
32
+ });
33
+ });
@@ -1,10 +1,9 @@
1
1
  describe('exercise', () => {
2
-
3
2
  it('current exercise information is available when present', () => {
4
3
  $('body').html(`
5
4
  <input type="hidden" name="mu-exercise-id" id="mu-exercise-id" value="3361" />
6
5
  <input type="hidden" name="mu-exercise-layout" id="mu-exercise-layout" value="input_right" />
7
- <input type="hidden" name="mu-exercise-settings" id="mu-exercise-settings" value="{}" />`)
6
+ <input type="hidden" name="mu-exercise-settings" id="mu-exercise-settings" value="{}" />`);
8
7
 
9
8
  mumuki.exercise.load();
10
9
 
@@ -12,13 +11,13 @@ describe('exercise', () => {
12
11
  expect(mumuki.exercise.layout).toBe('input_right');
13
12
  expect(mumuki.exercise.settings).toEqual({});
14
13
  expect(mumuki.exercise.current).not.toBe(null);
15
- })
14
+ });
16
15
 
17
16
  it('current exercise information is available when present and settings are not empty', () => {
18
17
  $('body').html(`
19
18
  <input type="hidden" name="mu-exercise-id" id="mu-exercise-id" value="3361" />
20
19
  <input type="hidden" name="mu-exercise-layout" id="mu-exercise-layout" value="input_right" />
21
- <input type="hidden" name="mu-exercise-settings" id="mu-exercise-settings" value="{&quot;game_framework&quot;:true}" />`)
20
+ <input type="hidden" name="mu-exercise-settings" id="mu-exercise-settings" value="{&quot;game_framework&quot;:true}" />`);
22
21
 
23
22
  mumuki.exercise.load();
24
23
 
@@ -26,10 +25,10 @@ describe('exercise', () => {
26
25
  expect(mumuki.exercise.layout).toBe('input_right');
27
26
  expect(mumuki.exercise.settings.game_framework).toBe(true);
28
27
  expect(mumuki.exercise.current).not.toBe(null);
29
- })
28
+ });
30
29
 
31
30
  it('current exercise information is available when not present', () => {
32
- $('body').html(``)
31
+ $('body').html(``);
33
32
 
34
33
  mumuki.exercise.load();
35
34
 
@@ -37,5 +36,5 @@ describe('exercise', () => {
37
36
  expect(mumuki.exercise.layout).toBe(null);
38
37
  expect(mumuki.exercise.settings).toBe(null);
39
38
  expect(mumuki.exercise.current).toBe(null);
40
- })
41
- })
39
+ });
40
+ });
@@ -33,11 +33,11 @@ describe('gamification', () => {
33
33
 
34
34
  describe('triggers level change', () => {
35
35
  it('does not trigger when small exp difference', () => {
36
- expect(new mumuki.gamification.LevelProgression(1000).triggersLevelChange(1050)).toBe(false);
36
+ expect(new mumuki.gamification.LevelProgression(1000).triggersLevelChange(50)).toBe(false);
37
37
  });
38
38
 
39
39
  it('does trigger when big exp difference', () => {
40
- expect(new mumuki.gamification.LevelProgression(1000).triggersLevelChange(1500)).toBe(true);
40
+ expect(new mumuki.gamification.LevelProgression(1000).triggersLevelChange(500)).toBe(true);
41
41
  });
42
42
  });
43
43
 
@@ -1,6 +1,6 @@
1
1
  describe("global loading", () => {
2
2
  it("produces no global loading errors", () => {
3
3
  const error = window['__globalLoadingError__'];
4
- expect(!error).toBe(true, `Expected no global loading errors but got ${error && error.message}`)
5
- })
6
- })
4
+ expect(!error).toBe(true, `Expected no global loading errors but got ${error && error.message}`);
5
+ });
6
+ });
@@ -0,0 +1,82 @@
1
+ describe('I18n', () => {
2
+ describe('t / translate', () => {
3
+ it('accept english translations', () => {
4
+ mumuki.locale = 'en';
5
+ expect(mumuki.I18n.translate('passed')).toBe('Everything is in order! Your solution passed all our tests!');
6
+ });
7
+
8
+ it('accept spanish translations', () => {
9
+ mumuki.locale = 'es';
10
+ expect(mumuki.I18n.translate('passed_with_warnings')).toBe('Tu solución funcionó, pero hay cosas que mejorar');
11
+ });
12
+
13
+ it('accept chilean translations', () => {
14
+ mumuki.locale = 'es-CL';
15
+ expect(mumuki.I18n.translate('failed')).toBe('Tu solución no pasó las pruebas');
16
+ });
17
+
18
+ it('accept portuguese translations', () => {
19
+ mumuki.locale = 'pt';
20
+ expect(mumuki.I18n.translate('errored')).toBe('Opa! Sua solução não pode ser executada');
21
+ });
22
+
23
+ it('fails when translation missing', () => {
24
+ mumuki.locale = 'en';
25
+ expect(mumuki.I18n.translate('foo')).toBe('Translation missing: en, `foo`');
26
+ });
27
+ });
28
+
29
+ describe('register', () => {
30
+ beforeEach(() => {
31
+ mumuki.locale = 'en';
32
+ mumuki.I18n.register({
33
+ en: {
34
+ greet: (data) => `Hi ${data.name}`,
35
+ errored: "D'Oh!"
36
+ }
37
+ });
38
+ });
39
+
40
+ it('overrides existing translation key', () => {
41
+ expect(mumuki.I18n.translate('errored')).toBe("D'Oh!");
42
+ });
43
+
44
+ it('add missing translation key', () => {
45
+ expect(mumuki.I18n.translate('greet', {name: 'Jane'})).toBe('Hi Jane');
46
+ });
47
+
48
+ it('keep non overriding translation key', () => {
49
+ expect(mumuki.I18n.translate('passed')).toBe('Everything is in order! Your solution passed all our tests!');
50
+ });
51
+ });
52
+
53
+ describe('with some prefix', () => {
54
+ fixture.set(`
55
+ <div class="mu-kindergarten" data-i18n-prefix="testing">
56
+ <button class="mu-kids-button">Click me<button>
57
+ <div class="mu-kids-overlay" style="display: none"></div>
58
+ </div>
59
+ `);
60
+
61
+ beforeEach(() => {
62
+ mumuki.locale = 'en';
63
+ mumuki.I18n.register({
64
+ en: {
65
+ testing_failed: 'Ops! Execution failed',
66
+ }
67
+ });
68
+ });
69
+
70
+ it('Using prefix with existing translation key', () => {
71
+ expect(mumuki.I18n.t('passed')).toBe('Everything is in order! Your solution passed all our tests!');
72
+ });
73
+
74
+ it('Use prefix with none existing translation key but default key exists', () => {
75
+ expect(mumuki.I18n.t('failed')).toBe('Ops! Execution failed');
76
+ });
77
+
78
+ it('No key found', () => {
79
+ expect(mumuki.I18n.t('foo')).toBe('Translation missing: en, `foo`');
80
+ });
81
+ });
82
+ });