mumuki-laboratory 8.4.0 → 9.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/mumuki_laboratory/application/upload.js +69 -14
  3. data/app/assets/stylesheets/mumuki_laboratory/application/_layout.scss +3 -0
  4. data/app/assets/stylesheets/mumuki_laboratory/application/_modules.scss +1 -0
  5. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_content_show.scss +15 -2
  6. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_discussion.scss +31 -8
  7. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_medal.scss +1 -1
  8. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_menu.scss +35 -0
  9. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_profile.scss +11 -0
  10. data/app/controllers/api/base_controller.rb +0 -1
  11. data/app/controllers/api/courses_controller.rb +1 -1
  12. data/app/controllers/api/organizations_controller.rb +5 -2
  13. data/app/controllers/api/roles_controller.rb +4 -0
  14. data/app/controllers/api/users_controller.rb +6 -1
  15. data/app/controllers/application_controller.rb +1 -1
  16. data/app/controllers/concerns/with_authorization.rb +1 -16
  17. data/app/controllers/concerns/with_user_params.rb +4 -0
  18. data/app/controllers/discussions_messages_controller.rb +0 -1
  19. data/app/controllers/exam_authorization_requests_controller.rb +26 -0
  20. data/app/controllers/exam_registrations_controller.rb +6 -0
  21. data/app/controllers/users_controller.rb +8 -5
  22. data/app/helpers/application_helper.rb +4 -0
  23. data/app/helpers/breadcrumbs_helper.rb +4 -0
  24. data/app/helpers/content_view_helper.rb +19 -0
  25. data/app/helpers/exercise_input_helper.rb +8 -17
  26. data/app/helpers/icons_helper.rb +3 -11
  27. data/app/helpers/links_helper.rb +3 -3
  28. data/app/helpers/menu_bar_helper.rb +3 -3
  29. data/app/helpers/progress_bar_helper.rb +2 -2
  30. data/app/helpers/user_menu_helper.rb +18 -0
  31. data/app/views/chapters/show.html.erb +17 -16
  32. data/app/views/complements/show.html.erb +1 -1
  33. data/app/views/discussions/_message.html.erb +7 -7
  34. data/app/views/exam_authorization_requests/show.html.erb +17 -0
  35. data/app/views/exam_registrations/show.html.erb +37 -0
  36. data/app/views/exams/show.html.erb +1 -1
  37. data/app/views/{layouts → exercises}/_exercise_skipped.html.erb +0 -0
  38. data/app/views/exercises/_exercise_title_icons.html.erb +4 -0
  39. data/app/views/exercises/show.html.erb +5 -8
  40. data/app/views/{layouts → guides}/_guide.html.erb +3 -3
  41. data/app/views/guides/_guide_container.html.erb +24 -0
  42. data/app/views/{layouts → guides}/_guide_title_icons.html.erb +1 -3
  43. data/app/views/layouts/_progress_bar.html.erb +9 -7
  44. data/app/views/layouts/_progress_listing.html.erb +5 -5
  45. data/app/views/layouts/_user_menu.html.erb +21 -0
  46. data/app/views/layouts/application.html.erb +1 -6
  47. data/app/views/layouts/exercise_inputs/editors/_upload.html.erb +11 -2
  48. data/app/views/lessons/show.html.erb +1 -1
  49. data/app/views/notifications/_discussion.html.erb +1 -0
  50. data/app/views/notifications/_dropdown.html.erb +13 -0
  51. data/app/views/notifications/_exam_authorization_request.html.erb +1 -0
  52. data/app/views/notifications/_exam_registration.html.erb +1 -0
  53. data/app/views/notifications/_message.html.erb +1 -0
  54. data/app/views/users/_user_form.html.erb +10 -8
  55. data/app/views/users/discussions.html.erb +28 -0
  56. data/app/views/users/edit.html.erb +1 -1
  57. data/app/views/users/messages.html.erb +27 -0
  58. data/app/views/users/show.html.erb +4 -51
  59. data/app/views/users/terms.html.erb +2 -2
  60. data/config/routes.rb +6 -0
  61. data/lib/mumuki/laboratory/controllers/notifications.rb +3 -22
  62. data/lib/mumuki/laboratory/locales/en.yml +34 -17
  63. data/lib/mumuki/laboratory/locales/es-CL.yml +25 -8
  64. data/lib/mumuki/laboratory/locales/es.yml +30 -14
  65. data/lib/mumuki/laboratory/locales/pt.yml +27 -10
  66. data/lib/mumuki/laboratory/version.rb +1 -1
  67. data/spec/controllers/exam_authorization_requests_controller_spec.rb +40 -0
  68. data/spec/controllers/exam_registrations_controller_spec.rb +19 -0
  69. data/spec/controllers/organizations_api_controller_spec.rb +16 -9
  70. data/spec/dummy/db/schema.rb +23 -0
  71. data/spec/features/exercise_flow_spec.rb +3 -3
  72. data/spec/features/login_flow_spec.rb +1 -1
  73. data/spec/features/menu_bar_spec.rb +24 -24
  74. data/spec/features/notifications_flow_spec.rb +46 -0
  75. data/spec/features/profile_flow_spec.rb +6 -9
  76. data/spec/features/terms_flow_spec.rb +30 -0
  77. data/spec/helpers/application_helper_spec.rb +10 -0
  78. data/spec/javascripts/bridge-spec.js +2 -2
  79. data/spec/javascripts/csrf-token-spec.js +2 -2
  80. data/spec/javascripts/editors-spec.js +7 -9
  81. data/spec/javascripts/elipsis-spec.js +4 -4
  82. data/spec/javascripts/events-spec.js +7 -7
  83. data/spec/javascripts/exercise-spec.js +7 -8
  84. data/spec/javascripts/global-spec.js +3 -3
  85. data/spec/javascripts/i18n-spec.js +23 -20
  86. data/spec/javascripts/kids-button-spec.js +6 -8
  87. data/spec/javascripts/results-renderers-spec.js +5 -5
  88. data/spec/javascripts/speech-bubble-renderer-spec.js +2 -3
  89. data/spec/javascripts/submissions-store-spec.js +14 -14
  90. data/spec/javascripts/sync-mode-spec.js +3 -3
  91. data/spec/javascripts/timeout-spec.js +2 -2
  92. data/spec/javascripts/timer-spec.js +2 -2
  93. data/spec/javascripts/upload-spec.js +80 -0
  94. metadata +132 -108
  95. data/app/views/layouts/_guide_container.html.erb +0 -28
@@ -26,4 +26,14 @@ describe ApplicationHelper, organization_workspace: :test do
26
26
  it { expect(link_to_path_element(lesson)).to start_with '<a href="/lessons/1-foo">foo' }
27
27
  end
28
28
 
29
+ describe 'bibliotheca links' do
30
+ let(:current_user) { create(:user) }
31
+ let(:lesson) { create(:lesson, id: 1, name: 'foo') }
32
+ let(:guide) { lesson.guide }
33
+
34
+ before { current_user.make_editor_of! guide.slug }
35
+
36
+ it { expect(url_for_bibliotheca_guide(guide)).to start_with 'http://bibliotheca.localmumuki.io/#/guides/mumuki/mumuki-test-lesson' }
37
+ end
38
+
29
39
  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
+ });
@@ -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
+ });
@@ -1,29 +1,30 @@
1
1
  describe('I18n', () => {
2
-
3
2
  describe('t / translate', () => {
4
-
5
3
  it('accept english translations', () => {
6
4
  mumuki.locale = 'en';
7
5
  expect(mumuki.I18n.translate('passed')).toBe('Everything is in order! Your solution passed all our tests!');
8
- })
6
+ });
7
+
9
8
  it('accept spanish translations', () => {
10
9
  mumuki.locale = 'es';
11
10
  expect(mumuki.I18n.translate('passed_with_warnings')).toBe('Tu solución funcionó, pero hay cosas que mejorar');
12
- })
11
+ });
12
+
13
13
  it('accept chilean translations', () => {
14
14
  mumuki.locale = 'es-CL';
15
15
  expect(mumuki.I18n.translate('failed')).toBe('Tu solución no pasó las pruebas');
16
- })
16
+ });
17
+
17
18
  it('accept portuguese translations', () => {
18
19
  mumuki.locale = 'pt';
19
20
  expect(mumuki.I18n.translate('errored')).toBe('Opa! Sua solução não pode ser executada');
20
- })
21
+ });
22
+
21
23
  it('fails when translation missing', () => {
22
24
  mumuki.locale = 'en';
23
25
  expect(mumuki.I18n.translate('foo')).toBe('Translation missing: en, `foo`');
24
- })
25
-
26
- })
26
+ });
27
+ });
27
28
 
28
29
  describe('register', () => {
29
30
  beforeEach(() => {
@@ -33,21 +34,23 @@ describe('I18n', () => {
33
34
  greet: (data) => `Hi ${data.name}`,
34
35
  errored: "D'Oh!"
35
36
  }
36
- })
37
- })
37
+ });
38
+ });
39
+
38
40
  it('overrides existing translation key', () => {
39
41
  expect(mumuki.I18n.translate('errored')).toBe("D'Oh!");
40
- })
42
+ });
43
+
41
44
  it('add missing translation key', () => {
42
45
  expect(mumuki.I18n.translate('greet', {name: 'Jane'})).toBe('Hi Jane');
43
- })
46
+ });
47
+
44
48
  it('keep non overriding translation key', () => {
45
49
  expect(mumuki.I18n.translate('passed')).toBe('Everything is in order! Your solution passed all our tests!');
46
- })
47
- })
50
+ });
51
+ });
48
52
 
49
53
  describe('with some prefix', () => {
50
-
51
54
  fixture.set(`
52
55
  <div class="mu-kindergarten" data-i18n-prefix="testing">
53
56
  <button class="mu-kids-button">Click me<button>
@@ -61,19 +64,19 @@ describe('I18n', () => {
61
64
  en: {
62
65
  testing_failed: 'Ops! Execution failed',
63
66
  }
64
- })
67
+ });
65
68
  });
66
69
 
67
70
  it('Using prefix with existing translation key', () => {
68
71
  expect(mumuki.I18n.t('passed')).toBe('Everything is in order! Your solution passed all our tests!');
69
72
  });
73
+
70
74
  it('Use prefix with none existing translation key but default key exists', () => {
71
75
  expect(mumuki.I18n.t('failed')).toBe('Ops! Execution failed');
72
76
  });
77
+
73
78
  it('No key found', () => {
74
79
  expect(mumuki.I18n.t('foo')).toBe('Translation missing: en, `foo`');
75
- })
76
-
80
+ });
77
81
  });
78
-
79
82
  });
@@ -1,5 +1,4 @@
1
1
  describe('KidsButton', () => {
2
-
3
2
  let button;
4
3
 
5
4
  fixture.set(`
@@ -12,25 +11,24 @@ describe('KidsButton', () => {
12
11
  beforeEach(() => {
13
12
  mumuki.kids = new mumuki.Kids();
14
13
  button = new mumuki.submission.KidsSubmitButton($('.mu-kids-button'));
15
- })
14
+ });
16
15
 
17
16
  it('can create button', () => {
18
17
  expect(button).not.toBe(null);
19
- })
18
+ });
20
19
 
21
20
  it('overlay is hidden by default', () => {
22
21
  expect(mumuki.kids.$overlay.css('display')).toBe('none');
23
- })
22
+ });
24
23
 
25
24
  it('call showOverlay on wait', () => {
26
25
  button.wait();
27
26
  expect(mumuki.kids.$overlay.css('display')).toBe('block');
28
- })
27
+ });
29
28
 
30
29
  it('call hideOverlay on continue', () => {
31
30
  button.wait();
32
31
  button.continue();
33
32
  expect(mumuki.kids.$overlay.css('display')).toBe('none');
34
- })
35
-
36
- })
33
+ });
34
+ });
@@ -1,17 +1,17 @@
1
1
  describe('results renderers', () => {
2
2
  it('can compute class for status', () => {
3
3
  expect(mumuki.renderers.classForStatus('passed')).toEqual('success');
4
- })
4
+ });
5
5
 
6
6
  it('can compute icon for status', () => {
7
7
  expect(mumuki.renderers.iconForStatus('pending')).toEqual('fa-circle');
8
- })
8
+ });
9
9
 
10
10
  it('can compute progress list item for status', () => {
11
11
  expect(mumuki.renderers.progressListItemClassForStatus('passed_with_warnings')).toEqual('progress-list-item text-center warning ');
12
- })
12
+ });
13
13
 
14
14
  it('can compute progress list item for status when active', () => {
15
15
  expect(mumuki.renderers.progressListItemClassForStatus('failed', true)).toEqual('progress-list-item text-center danger active');
16
- })
17
- })
16
+ });
17
+ });
@@ -6,6 +6,5 @@ describe('results renderers', () => {
6
6
  <li>fix that</li>
7
7
  </ul>
8
8
  </div>`);
9
- })
10
-
11
- })
9
+ });
10
+ });
@@ -6,39 +6,39 @@ describe("SubmissionsStore", () => {
6
6
  const passedEmptyProgramSubmissionAndResult = { submission: emptyProgramSubmission, result: passedSubmissionResult };
7
7
 
8
8
  beforeEach(() => {
9
- window.localStorage.clear()
9
+ window.localStorage.clear();
10
10
  });
11
11
 
12
12
  describe('getLastSubmission', () => {
13
13
  it("answers null if submission not present", () => {
14
- expect(mumuki.SubmissionsStore.getLastSubmissionAndResult(1)).toBe(null)
14
+ expect(mumuki.SubmissionsStore.getLastSubmissionAndResult(1)).toBe(null);
15
15
  });
16
16
 
17
17
  it("answers the last submission result if already sent", () => {
18
- mumuki.SubmissionsStore.setSubmissionResultFor(1, passedEmptyProgramSubmissionAndResult)
19
- expect(mumuki.SubmissionsStore.getLastSubmissionAndResult(1)).toEqual(passedEmptyProgramSubmissionAndResult)
18
+ mumuki.SubmissionsStore.setSubmissionResultFor(1, passedEmptyProgramSubmissionAndResult);
19
+ expect(mumuki.SubmissionsStore.getLastSubmissionAndResult(1)).toEqual(passedEmptyProgramSubmissionAndResult);
20
20
  });
21
21
  });
22
22
 
23
23
  describe('getLastSubmissionStatus', () => {
24
24
  it("answers pending if submission not present", () => {
25
- expect(mumuki.SubmissionsStore.getLastSubmissionStatus(1)).toBe('pending')
25
+ expect(mumuki.SubmissionsStore.getLastSubmissionStatus(1)).toBe('pending');
26
26
  });
27
27
 
28
28
  it("answers the last submission status if previously sent", () => {
29
- mumuki.SubmissionsStore.setSubmissionResultFor(1, passedEmptyProgramSubmissionAndResult)
30
- expect(mumuki.SubmissionsStore.getLastSubmissionStatus(1)).toBe('passed')
29
+ mumuki.SubmissionsStore.setSubmissionResultFor(1, passedEmptyProgramSubmissionAndResult);
30
+ expect(mumuki.SubmissionsStore.getLastSubmissionStatus(1)).toBe('passed');
31
31
  });
32
32
  });
33
33
 
34
34
  describe('getCachedResultFor', () => {
35
35
  it("answers null if submission not present", () => {
36
- expect(mumuki.SubmissionsStore.getSubmissionResultFor(1, emptyProgramSubmission)).toBe(null)
36
+ expect(mumuki.SubmissionsStore.getSubmissionResultFor(1, emptyProgramSubmission)).toBe(null);
37
37
  });
38
38
 
39
39
  it("answers the last submission if previously sent", () => {
40
- mumuki.SubmissionsStore.setSubmissionResultFor(1, passedEmptyProgramSubmissionAndResult)
41
- expect(mumuki.SubmissionsStore.getSubmissionResultFor(1, emptyProgramSubmission)).toEqual(passedSubmissionResult)
40
+ mumuki.SubmissionsStore.setSubmissionResultFor(1, passedEmptyProgramSubmissionAndResult);
41
+ expect(mumuki.SubmissionsStore.getSubmissionResultFor(1, emptyProgramSubmission)).toEqual(passedSubmissionResult);
42
42
  });
43
43
  });
44
44
 
@@ -90,7 +90,7 @@ describe("SubmissionsStore", () => {
90
90
  {solution: {content: ''}},
91
91
  {solution: {content: 'bar'}})).toBe(false);
92
92
  });
93
- })
93
+ });
94
94
 
95
95
  describe('classic submissons', () => {
96
96
  it("answers true when they are equal", () => {
@@ -122,7 +122,7 @@ describe("SubmissionsStore", () => {
122
122
  {'solution[content]': ''},
123
123
  {'solution[content]': 'bar'})).toBe(false);
124
124
  });
125
- })
125
+ });
126
126
 
127
127
  describe('multifile submissions', () => {
128
128
  it("answers true when they are equal", () => {
@@ -172,6 +172,6 @@ describe("SubmissionsStore", () => {
172
172
  'solution[content[index.html]]': 'html foo'
173
173
  })).toBe(false);
174
174
  });
175
- })
175
+ });
176
176
  });
177
- })
177
+ });