mumuki-laboratory 7.6.2 → 7.8.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 +203 -2
- data/Rakefile +9 -0
- data/app/assets/javascripts/mumuki_laboratory/application.js +0 -1
- data/app/assets/javascripts/mumuki_laboratory/application/alias-modes.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/assets-loader.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/bridge.js +82 -47
- data/app/assets/javascripts/mumuki_laboratory/application/button.js +90 -1
- data/app/assets/javascripts/mumuki_laboratory/application/codemirror-builder.js +28 -25
- data/app/assets/javascripts/mumuki_laboratory/application/codemirror.js +8 -9
- data/app/assets/javascripts/mumuki_laboratory/application/confirmation.js +2 -2
- data/app/assets/javascripts/mumuki_laboratory/application/console.js +41 -43
- data/app/assets/javascripts/mumuki_laboratory/application/csrf-token.js +9 -12
- data/app/assets/javascripts/mumuki_laboratory/application/custom-editor.js +46 -8
- data/app/assets/javascripts/mumuki_laboratory/application/discussions.js +15 -16
- data/app/assets/javascripts/mumuki_laboratory/application/editors.js +104 -0
- data/app/assets/javascripts/mumuki_laboratory/application/elipsis.js +5 -4
- data/app/assets/javascripts/mumuki_laboratory/application/exercise.js +32 -0
- data/app/assets/javascripts/mumuki_laboratory/application/inputs.js +4 -2
- data/app/assets/javascripts/mumuki_laboratory/application/interval.js +2 -4
- data/app/assets/javascripts/mumuki_laboratory/application/kids.js +74 -37
- data/app/assets/javascripts/mumuki_laboratory/application/load-analytics.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/load-error-svg.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/messages.js +2 -2
- data/app/assets/javascripts/mumuki_laboratory/application/multiple-choice.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/multiple-scenarios.js +3 -6
- data/app/assets/javascripts/mumuki_laboratory/application/pin.js +3 -5
- data/app/assets/javascripts/mumuki_laboratory/application/progress.js +27 -6
- data/app/assets/javascripts/mumuki_laboratory/application/results-renderer.js +60 -0
- data/app/assets/javascripts/mumuki_laboratory/application/speech-bubble-renderer.js +12 -5
- data/app/assets/javascripts/mumuki_laboratory/application/submission.js +122 -55
- data/app/assets/javascripts/mumuki_laboratory/application/submissions-store.js +93 -0
- data/app/assets/javascripts/mumuki_laboratory/application/sync-mode.js +75 -0
- data/app/assets/javascripts/mumuki_laboratory/application/timer.js +5 -6
- data/app/assets/javascripts/mumuki_laboratory/application/tooltip.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/upload.js +1 -1
- data/app/assets/javascripts/mumuki_laboratory/application/user.js +1 -1
- data/app/assets/stylesheets/mumuki_laboratory/application/_modules.scss +1 -0
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_discussion.scss +43 -5
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_gs-board.scss +3 -0
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_kids.scss +3 -4
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_kindergarten.scss +55 -0
- data/app/controllers/application_controller.rb +1 -0
- data/app/controllers/assets_controller.rb +2 -0
- data/app/controllers/concerns/with_authorization.rb +4 -0
- data/app/controllers/concerns/with_user_discussion_validation.rb +14 -0
- data/app/controllers/discussions_controller.rb +6 -14
- data/app/controllers/discussions_messages_controller.rb +10 -1
- data/app/controllers/exercise_solutions_controller.rb +4 -2
- data/app/helpers/application_helper.rb +9 -5
- data/app/helpers/discussions_helper.rb +37 -23
- data/app/helpers/exercise_input_helper.rb +1 -1
- data/app/helpers/{locale_helper.rb → globals_helper.rb} +6 -2
- data/app/helpers/icons_helper.rb +3 -3
- data/app/mailers/user_mailer.rb +24 -11
- data/app/views/book/show.html.erb +1 -1
- data/app/views/book_discussions/index.html.erb +3 -3
- data/app/views/discussions/_message.html.erb +20 -8
- data/app/views/discussions/index.html.erb +0 -1
- data/app/views/discussions/new.html.erb +33 -0
- data/app/views/discussions/show.html.erb +18 -46
- data/app/views/exercise_solutions/_contextualization_results_container.html.erb +1 -1
- data/app/views/exercise_solutions/_results_title.html.erb +2 -2
- data/app/views/exercises/_read_only.html.erb +33 -6
- data/app/views/exercises/show.html.erb +2 -0
- data/app/views/layouts/_copyright.html.erb +1 -1
- data/app/views/layouts/_discussions.html.erb +21 -3
- data/app/views/layouts/_main.html.erb +1 -2
- data/app/views/layouts/_progress.html.erb +1 -1
- data/app/views/layouts/_progress_bar.html.erb +7 -1
- data/app/views/layouts/_test_results.html.erb +1 -1
- data/app/views/layouts/application.html.erb +1 -1
- data/app/views/layouts/exercise_inputs/editors/_custom.html.erb +1 -1
- data/app/views/layouts/exercise_inputs/forms/_kids_form.html.erb +1 -1
- data/app/views/layouts/exercise_inputs/forms/_problem_form.html.erb +1 -1
- data/app/views/layouts/exercise_inputs/layouts/_input_bottom.html.erb +1 -1
- data/app/views/layouts/exercise_inputs/layouts/_input_kindergarten.html.erb +40 -0
- data/app/views/layouts/exercise_inputs/layouts/{_input_kids.html.erb → _input_primary.html.erb} +1 -1
- data/app/views/layouts/exercise_inputs/layouts/_input_right.html.erb +1 -1
- data/app/views/layouts/modals/_kids_context.html.erb +1 -8
- data/app/views/user_mailer/1st_reminder.html.erb +1 -1
- data/app/views/user_mailer/1st_reminder.text.erb +1 -1
- data/app/views/user_mailer/2nd_reminder.html.erb +1 -1
- data/app/views/user_mailer/2nd_reminder.text.erb +1 -1
- data/app/views/user_mailer/3rd_reminder.html.erb +1 -1
- data/app/views/user_mailer/3rd_reminder.text.erb +1 -1
- data/app/views/user_mailer/no_submissions_reminder.html.erb +1 -1
- data/app/views/user_mailer/no_submissions_reminder.text.erb +1 -1
- data/config/routes.rb +2 -1
- data/lib/mumuki/laboratory/controllers.rb +1 -0
- data/lib/mumuki/laboratory/controllers/incognito_mode.rb +28 -0
- data/lib/mumuki/laboratory/controllers/results_rendering.rb +1 -2
- data/lib/mumuki/laboratory/locales/en.yml +14 -6
- data/lib/mumuki/laboratory/locales/es-CL.yml +292 -0
- data/lib/mumuki/laboratory/locales/es.yml +13 -5
- data/lib/mumuki/laboratory/locales/pt.yml +12 -6
- data/lib/mumuki/laboratory/version.rb +1 -1
- data/spec/controllers/confirmations_controller_spec.rb +1 -1
- data/spec/controllers/discussions_messages_controller_spec.rb +73 -0
- data/spec/controllers/exercise_solutions_controller_spec.rb +41 -6
- data/spec/dummy/db/schema.rb +13 -1
- data/spec/features/chapter_spec.rb +17 -0
- data/spec/features/discussion_flow_spec.rb +190 -0
- data/spec/features/exercise_flow_spec.rb +48 -3
- data/spec/features/home_public_flow_spec.rb +16 -0
- data/spec/features/menu_bar_spec.rb +88 -7
- data/spec/helpers/breadcrumbs_helper_spec.rb +1 -1
- data/spec/javascripts/bridge-spec.js +5 -0
- data/spec/javascripts/csrf-token-spec.js +7 -0
- data/spec/javascripts/editors-spec.js +54 -0
- data/spec/javascripts/elipsis-spec.js +25 -0
- data/spec/javascripts/exercise-spec.js +22 -0
- data/spec/javascripts/global-spec.js +6 -0
- data/spec/javascripts/results-renderers-spec.js +17 -0
- data/spec/javascripts/spec-helper.js +34 -0
- data/spec/javascripts/speech-bubble-renderer-spec.js +11 -0
- data/spec/javascripts/submissions-store-spec.js +44 -0
- data/spec/javascripts/sync-mode-spec.js +15 -0
- data/spec/javascripts/timeout-spec.js +5 -0
- data/spec/javascripts/timer-spec.js +5 -0
- data/spec/mailers/user_mailer_spec.rb +18 -3
- data/spec/teaspoon_env.rb +193 -0
- metadata +50 -11
- data/app/helpers/version_helper.rb +0 -5
- data/app/views/layouts/modals/_new_discussion.html.erb +0 -27
- data/vendor/assets/javascripts/hotjar.js +0 -8
@@ -91,4 +91,20 @@ feature 'public org', organization_workspace: :test do
|
|
91
91
|
expect(user.reload.last_organization).to eq current_organization
|
92
92
|
end
|
93
93
|
end
|
94
|
+
|
95
|
+
context 'incognito user' do
|
96
|
+
before { current_organization.update! incognito_mode_enabled: true }
|
97
|
+
scenario 'from inside' do
|
98
|
+
Capybara.current_session.driver.header 'Referer', 'http://google.com'
|
99
|
+
|
100
|
+
visit '/'
|
101
|
+
|
102
|
+
expect(page).to have_text('ム mumuki')
|
103
|
+
expect(page).to have_text('First Steps')
|
104
|
+
expect(page).to have_selector('.chapter', text: 'Functional Programming')
|
105
|
+
expect(page).to have_text(current_organization.book.name)
|
106
|
+
|
107
|
+
expect(page).to have_text('Sign in')
|
108
|
+
end
|
109
|
+
end
|
94
110
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
feature 'menu bar' do
|
4
|
-
let(:
|
4
|
+
let(:lesson) { create(:lesson, exercises: create_list(:exercise, 3))}
|
5
|
+
let(:chapter) { create(:chapter, lessons: [lesson]) }
|
5
6
|
let(:book) { create(:book, chapters: [chapter], name: 'private', slug: 'mumuki/mumuki-the-private-book') }
|
6
7
|
let(:private_organization) { create(:organization, name: 'private', book: book) }
|
7
8
|
|
@@ -32,6 +33,8 @@ feature 'menu bar' do
|
|
32
33
|
expect(page).not_to have_text('Profile')
|
33
34
|
expect(page).not_to have_text('Classroom')
|
34
35
|
expect(page).not_to have_text('Bibliotheca')
|
36
|
+
expect(page).not_to have_text('Solve other\'s doubts')
|
37
|
+
expect(page).not_to have_text('My doubts')
|
35
38
|
end
|
36
39
|
end
|
37
40
|
end
|
@@ -52,15 +55,91 @@ feature 'menu bar' do
|
|
52
55
|
expect(page).to have_text('Profile')
|
53
56
|
expect(page).not_to have_text('Classroom')
|
54
57
|
expect(page).not_to have_text('Bibliotheca')
|
58
|
+
expect(page).not_to have_text('Solve other\'s doubts')
|
59
|
+
expect(page).not_to have_text('My doubts')
|
55
60
|
end
|
56
61
|
|
57
|
-
|
58
|
-
|
62
|
+
context 'student with no discussions should' do
|
63
|
+
scenario 'only see profile if forum is not enabled' do
|
64
|
+
set_current_user! student
|
59
65
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
66
|
+
visit '/'
|
67
|
+
expect(page).to have_text('Profile')
|
68
|
+
expect(page).not_to have_text('Classroom')
|
69
|
+
expect(page).not_to have_text('Bibliotheca')
|
70
|
+
expect(page).not_to have_text('Solve other\'s doubts')
|
71
|
+
expect(page).not_to have_text('My doubts')
|
72
|
+
end
|
73
|
+
|
74
|
+
scenario 'see profile and solve_other_doubts links if forum is enabled' do
|
75
|
+
set_current_user! student
|
76
|
+
private_organization.update! forum_enabled: true
|
77
|
+
|
78
|
+
visit '/'
|
79
|
+
expect(page).to have_text('Profile')
|
80
|
+
expect(page).not_to have_text('Classroom')
|
81
|
+
expect(page).not_to have_text('Bibliotheca')
|
82
|
+
expect(page).to have_text('Solve other\'s doubts')
|
83
|
+
expect(page).not_to have_text('My doubts')
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'student with discussions should' do
|
88
|
+
let(:discussion) { create(:discussion, item: lesson.exercises.last, initiator: student)}
|
89
|
+
|
90
|
+
scenario 'only see profile if forum is not enabled' do
|
91
|
+
set_current_user! student
|
92
|
+
student.subscribe_to! discussion
|
93
|
+
|
94
|
+
visit '/'
|
95
|
+
expect(page).to have_text('Profile')
|
96
|
+
expect(page).not_to have_text('Classroom')
|
97
|
+
expect(page).not_to have_text('Bibliotheca')
|
98
|
+
expect(page).not_to have_text('Solve other\'s doubts')
|
99
|
+
expect(page).not_to have_text('My doubts')
|
100
|
+
end
|
101
|
+
|
102
|
+
scenario 'see all discussions links if forum is enabled' do
|
103
|
+
set_current_user! student
|
104
|
+
private_organization.update! forum_enabled: true
|
105
|
+
student.subscribe_to! discussion
|
106
|
+
|
107
|
+
visit '/'
|
108
|
+
expect(page).to have_text('Profile')
|
109
|
+
expect(page).not_to have_text('Classroom')
|
110
|
+
expect(page).not_to have_text('Bibliotheca')
|
111
|
+
expect(page).to have_text('Solve other\'s doubts')
|
112
|
+
expect(page).to have_text('My doubts')
|
113
|
+
end
|
114
|
+
|
115
|
+
scenario 'only see profile if forum is enabled in a forum_only_for_trusted organization' do
|
116
|
+
set_current_user! student
|
117
|
+
student.subscribe_to! discussion
|
118
|
+
private_organization.update! forum_enabled: true
|
119
|
+
private_organization.update! forum_only_for_trusted: true
|
120
|
+
|
121
|
+
visit '/'
|
122
|
+
expect(page).to have_text('Profile')
|
123
|
+
expect(page).not_to have_text('Classroom')
|
124
|
+
expect(page).not_to have_text('Bibliotheca')
|
125
|
+
expect(page).not_to have_text('Solve other\'s doubts')
|
126
|
+
expect(page).not_to have_text('My doubts')
|
127
|
+
end
|
128
|
+
|
129
|
+
scenario 'see all discussions links if forum is enabled in a forum_only_for_trusted organization but it is trusted' do
|
130
|
+
student.update! trusted_for_forum: true
|
131
|
+
set_current_user! student
|
132
|
+
student.subscribe_to! discussion
|
133
|
+
private_organization.update! forum_enabled: true
|
134
|
+
private_organization.update! forum_only_for_trusted: true
|
135
|
+
|
136
|
+
visit '/'
|
137
|
+
expect(page).to have_text('Profile')
|
138
|
+
expect(page).not_to have_text('Classroom')
|
139
|
+
expect(page).not_to have_text('Bibliotheca')
|
140
|
+
expect(page).to have_text('Solve other\'s doubts')
|
141
|
+
expect(page).to have_text('My doubts')
|
142
|
+
end
|
64
143
|
end
|
65
144
|
|
66
145
|
scenario 'teacher should see profile and classroom' do
|
@@ -71,6 +150,8 @@ feature 'menu bar' do
|
|
71
150
|
expect(page).to have_text('Profile')
|
72
151
|
expect(page).to have_text('Classroom')
|
73
152
|
expect(page).not_to have_text('Bibliotheca')
|
153
|
+
expect(page).not_to have_text('Solve other\'s doubts')
|
154
|
+
expect(page).not_to have_text('My doubts')
|
74
155
|
end
|
75
156
|
|
76
157
|
scenario 'writer should see profile and bibliotheca' do
|
@@ -91,7 +91,7 @@ describe BreadcrumbsHelper, organization_workspace: :test do
|
|
91
91
|
expect(breadcrumb).to include('my lesson')
|
92
92
|
expect(breadcrumb).to include('my exercise')
|
93
93
|
expect(breadcrumb).to include('discussions')
|
94
|
-
expect(breadcrumb).to include(discussion.
|
94
|
+
expect(breadcrumb).to include(discussion.item.navigable_name)
|
95
95
|
expect(breadcrumb).to be_html_safe
|
96
96
|
end
|
97
97
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
describe('editors', () => {
|
2
|
+
|
3
|
+
beforeEach(() => {
|
4
|
+
mumuki.CustomEditor.clearSources()
|
5
|
+
})
|
6
|
+
|
7
|
+
it('has initially no sources', () => {
|
8
|
+
expect(mumuki.CustomEditor.hasSources).toBe(false)
|
9
|
+
});
|
10
|
+
|
11
|
+
it('can add a custom source', () => {
|
12
|
+
mumuki.editors.addCustomSource({
|
13
|
+
getContent() {
|
14
|
+
return { name: "solution[content]", value: 'the value' } ;
|
15
|
+
}
|
16
|
+
});
|
17
|
+
|
18
|
+
expect(mumuki.CustomEditor.hasSources).toBe(true);
|
19
|
+
expect(mumuki.CustomEditor.getContents()[0].value).toEqual('the value');
|
20
|
+
expect(mumuki.CustomEditor.getContents()[0].name).toEqual('solution[content]');
|
21
|
+
});
|
22
|
+
|
23
|
+
it('reads the custom sources if present, ignoring the form', () => {
|
24
|
+
$('body').html(`
|
25
|
+
<form role="form" class="new_solution">
|
26
|
+
<div class="field form-group editor-code">
|
27
|
+
<textarea class="form-control editor" name="solution[content]" id="solution_content">the standard solution</textarea>
|
28
|
+
</div>
|
29
|
+
</form>`)
|
30
|
+
|
31
|
+
mumuki.editors.addCustomSource({
|
32
|
+
getContent() {
|
33
|
+
return { name: "solution[content]", value: 'the custom solution' } ;
|
34
|
+
}
|
35
|
+
});
|
36
|
+
|
37
|
+
expect(mumuki.editors.getSubmission()).toEqual({"solution[content]":"the custom solution"});
|
38
|
+
});
|
39
|
+
|
40
|
+
it('reads the form if no sources', () => {
|
41
|
+
$('body').html(`
|
42
|
+
<form role="form" class="new_solution">
|
43
|
+
<div class="field form-group editor-code">
|
44
|
+
<textarea class="form-control editor" name="solution[content]" id="solution_content">the solution</textarea>
|
45
|
+
</div>
|
46
|
+
</form>`)
|
47
|
+
expect(mumuki.editors.getSubmission()).toEqual({"solution[content]":"the solution"});
|
48
|
+
});
|
49
|
+
|
50
|
+
it('produces empty submission if no form nor sources', () => {
|
51
|
+
$('body').html(``);
|
52
|
+
expect(mumuki.editors.getSubmission()).toEqual({});
|
53
|
+
});
|
54
|
+
})
|
@@ -0,0 +1,25 @@
|
|
1
|
+
describe('elipsis', () => {
|
2
|
+
it('does nothing when no elipsis', () => {
|
3
|
+
expect(mumuki.elipsis('hello')).toEqual('hello');
|
4
|
+
})
|
5
|
+
|
6
|
+
it('replaces student elipsis', () => {
|
7
|
+
expect(mumuki.elipsis(`function longitud(unString) {
|
8
|
+
/*<elipsis-for-student@*/
|
9
|
+
return unString.length;
|
10
|
+
/*@elipsis-for-student>*/
|
11
|
+
}`)).toEqual(`function longitud(unString) {
|
12
|
+
/* ... */
|
13
|
+
}`)
|
14
|
+
});
|
15
|
+
|
16
|
+
it('replaces student hidden', () => {
|
17
|
+
expect(mumuki.elipsis(`function longitud(unString) {
|
18
|
+
/*<hidden-for-student@*/
|
19
|
+
return unString.length;
|
20
|
+
/*@hidden-for-student>*/
|
21
|
+
}`)).toEqual(`function longitud(unString) {
|
22
|
+
/**/
|
23
|
+
}`)
|
24
|
+
});
|
25
|
+
})
|
@@ -0,0 +1,22 @@
|
|
1
|
+
describe('exercise', () => {
|
2
|
+
it('current exercise information is available when present', () => {
|
3
|
+
$('body').html(`
|
4
|
+
<input type="hidden" name="mu-exercise-id" id="mu-exercise-id" value="3361" />
|
5
|
+
<input type="hidden" name="mu-exercise-layout" id="mu-exercise-layout" value="input_right" />`)
|
6
|
+
|
7
|
+
mumuki.exercise.load()
|
8
|
+
|
9
|
+
expect(mumuki.exercise.id).toBe(3361);
|
10
|
+
expect(mumuki.exercise.layout).toBe('input_right');
|
11
|
+
})
|
12
|
+
|
13
|
+
it('current exercise information is available when not present', () => {
|
14
|
+
$('body').html(``)
|
15
|
+
|
16
|
+
mumuki.exercise.load()
|
17
|
+
|
18
|
+
expect(mumuki.exercise.id).toBe(null);
|
19
|
+
expect(mumuki.exercise.layout).toBe(null);
|
20
|
+
})
|
21
|
+
|
22
|
+
})
|
@@ -0,0 +1,17 @@
|
|
1
|
+
describe('results renderers', () => {
|
2
|
+
it('can compute class for status', () => {
|
3
|
+
expect(mumuki.renderers.classForStatus('passed')).toEqual('success');
|
4
|
+
})
|
5
|
+
|
6
|
+
it('can compute icon for status', () => {
|
7
|
+
expect(mumuki.renderers.iconForStatus('pending')).toEqual('fa-circle');
|
8
|
+
})
|
9
|
+
|
10
|
+
it('can compute progress list item for status', () => {
|
11
|
+
expect(mumuki.renderers.progressListItemClassForStatus('passed_with_warnings')).toEqual('progress-list-item text-center warning ');
|
12
|
+
})
|
13
|
+
|
14
|
+
it('can compute progress list item for status when active', () => {
|
15
|
+
expect(mumuki.renderers.progressListItemClassForStatus('failed', true)).toEqual('progress-list-item text-center danger active');
|
16
|
+
})
|
17
|
+
})
|
@@ -0,0 +1,34 @@
|
|
1
|
+
// Teaspoon includes some support files, but you can use anything from your own support path too.
|
2
|
+
// require support/jasmine-jquery-1.7.0
|
3
|
+
// require support/jasmine-jquery-2.0.0
|
4
|
+
// require support/jasmine-jquery-2.1.0
|
5
|
+
// require support/sinon
|
6
|
+
//
|
7
|
+
// PhantomJS (Teaspoons default driver) doesn't have support for Function.prototype.bind, which has caused confusion.
|
8
|
+
// Use this polyfill to avoid the confusion.
|
9
|
+
//
|
10
|
+
// You can require your own javascript files here. By default this will include everything in application, however you
|
11
|
+
// may get better load performance if you require the specific files that are being used in the spec that tests them.
|
12
|
+
//=require mumuki_laboratory/application
|
13
|
+
//
|
14
|
+
// Deferring execution
|
15
|
+
// If you're using CommonJS, RequireJS or some other asynchronous library you can defer execution. Call
|
16
|
+
// Teaspoon.execute() after everything has been loaded. Simple example of a timeout:
|
17
|
+
//
|
18
|
+
// Teaspoon.defer = true
|
19
|
+
// setTimeout(Teaspoon.execute, 1000)
|
20
|
+
//
|
21
|
+
// Matching files
|
22
|
+
// By default Teaspoon will look for files that match _spec.{js,js.coffee,.coffee}. Add a filename_spec.js file in your
|
23
|
+
// spec path and it'll be included in the default suite automatically. If you want to customize suites, check out the
|
24
|
+
// configuration in teaspoon_env.rb
|
25
|
+
//
|
26
|
+
// Manifest
|
27
|
+
// If you'd rather require your spec files manually (to control order for instance) you can disable the suite matcher in
|
28
|
+
// the configuration and use this file as a manifest.
|
29
|
+
//
|
30
|
+
// For more information: http://github.com/modeset/teaspoon
|
31
|
+
|
32
|
+
window.addEventListener("error", (e) => {
|
33
|
+
window['__globalLoadingError__'] = e;
|
34
|
+
});
|
@@ -0,0 +1,11 @@
|
|
1
|
+
describe('results renderers', () => {
|
2
|
+
it('can render result item', () => {
|
3
|
+
expect(mumuki.renderers.renderSpeechBubbleResultItem('fix that')).toEqual(`
|
4
|
+
<div class="results-item">
|
5
|
+
<ul class="results-list">
|
6
|
+
<li>fix that</li>
|
7
|
+
</ul>
|
8
|
+
</div>`);
|
9
|
+
})
|
10
|
+
|
11
|
+
})
|
@@ -0,0 +1,44 @@
|
|
1
|
+
describe("SubmissionsStore", () => {
|
2
|
+
const emptyProgramSubmission = {"solution[content]": "program {}"};
|
3
|
+
/** @type {SubmissionResult} */
|
4
|
+
const passedSubmissionResult = {status: 'passed'};
|
5
|
+
/** @type {SubmissionAndResult} */
|
6
|
+
const passedEmptyProgramSubmissionAndResult = { submission: emptyProgramSubmission, result: passedSubmissionResult };
|
7
|
+
|
8
|
+
beforeEach(() => {
|
9
|
+
window.localStorage.clear()
|
10
|
+
});
|
11
|
+
|
12
|
+
describe('getLastSubmission', () => {
|
13
|
+
it("answers null if submission not present", () => {
|
14
|
+
expect(mumuki.SubmissionsStore.getLastSubmissionAndResult(1)).toBe(null)
|
15
|
+
})
|
16
|
+
|
17
|
+
it("answers the last submission result if already sent", () => {
|
18
|
+
mumuki.SubmissionsStore.setSubmissionResultFor(1, passedEmptyProgramSubmissionAndResult)
|
19
|
+
expect(mumuki.SubmissionsStore.getLastSubmissionAndResult(1)).toEqual(passedEmptyProgramSubmissionAndResult)
|
20
|
+
})
|
21
|
+
})
|
22
|
+
|
23
|
+
describe('getLastSubmissionStatus', () => {
|
24
|
+
it("answers pending if submission not present", () => {
|
25
|
+
expect(mumuki.SubmissionsStore.getLastSubmissionStatus(1)).toBe('pending')
|
26
|
+
})
|
27
|
+
|
28
|
+
it("answers the last submission status if previously sent", () => {
|
29
|
+
mumuki.SubmissionsStore.setSubmissionResultFor(1, passedEmptyProgramSubmissionAndResult)
|
30
|
+
expect(mumuki.SubmissionsStore.getLastSubmissionStatus(1)).toBe('passed')
|
31
|
+
})
|
32
|
+
});
|
33
|
+
|
34
|
+
describe('getCachedResultFor', () => {
|
35
|
+
it("answers null if submission not present", () => {
|
36
|
+
expect(mumuki.SubmissionsStore.getSubmissionResultFor(1, emptyProgramSubmission)).toBe(null)
|
37
|
+
})
|
38
|
+
|
39
|
+
it("answers the last submission if previously sent", () => {
|
40
|
+
mumuki.SubmissionsStore.setSubmissionResultFor(1, passedEmptyProgramSubmissionAndResult)
|
41
|
+
expect(mumuki.SubmissionsStore.getSubmissionResultFor(1, emptyProgramSubmission)).toEqual(passedSubmissionResult)
|
42
|
+
})
|
43
|
+
});
|
44
|
+
})
|
@@ -0,0 +1,15 @@
|
|
1
|
+
describe('sync mode', () => {
|
2
|
+
it('can choose server mode', () => {
|
3
|
+
mumuki.incognitoUser = false;
|
4
|
+
mumuki.syncMode._selectSyncMode();
|
5
|
+
|
6
|
+
expect(mumuki.syncMode._current instanceof mumuki.syncMode.ServerSyncMode).toBe(true);
|
7
|
+
})
|
8
|
+
|
9
|
+
it('can choose local mode', () => {
|
10
|
+
mumuki.incognitoUser = true;
|
11
|
+
mumuki.syncMode._selectSyncMode();
|
12
|
+
|
13
|
+
expect(mumuki.syncMode._current instanceof mumuki.syncMode.ClientSyncMode).toBe(true);
|
14
|
+
})
|
15
|
+
})
|
@@ -148,21 +148,21 @@ RSpec.describe UserMailer, type: :mailer do
|
|
148
148
|
|
149
149
|
context "registered 1 week ago" do
|
150
150
|
it { expect(user.should_remind?).to be true }
|
151
|
-
it { expect(reminder.body.encoded).to include(
|
151
|
+
it { expect(reminder.body.encoded).to include('you've never submitted solutions') }
|
152
152
|
end
|
153
153
|
|
154
154
|
context "last submission 2 weeks ago" do
|
155
155
|
let(:days_since_user_creation) { 16 }
|
156
156
|
|
157
157
|
it { expect(user.should_remind?).to be true }
|
158
|
-
it { expect(reminder.body.encoded).to include(
|
158
|
+
it { expect(reminder.body.encoded).to include('you've never submitted solutions') }
|
159
159
|
end
|
160
160
|
|
161
161
|
context "last submission 3 weeks ago" do
|
162
162
|
let(:days_since_user_creation) { 26 }
|
163
163
|
|
164
164
|
it { expect(user.should_remind?).to be true }
|
165
|
-
it { expect(reminder.body.encoded).to include(
|
165
|
+
it { expect(reminder.body.encoded).to include('you've never submitted solutions') }
|
166
166
|
end
|
167
167
|
|
168
168
|
context "last submission 4 weeks ago" do
|
@@ -178,4 +178,19 @@ RSpec.describe UserMailer, type: :mailer do
|
|
178
178
|
it { expect(user.should_remind?).to be false }
|
179
179
|
end
|
180
180
|
end
|
181
|
+
|
182
|
+
describe 'welcome email' do
|
183
|
+
let(:email) { UserMailer.welcome_email(user, organization) }
|
184
|
+
|
185
|
+
let(:non_custom_welcome_orga) { create :organization }
|
186
|
+
let(:custom_welcome_orga) { create :organization, welcome_email_template: 'hello <%= @user.first_name %>!' }
|
187
|
+
|
188
|
+
let(:user) { create :user, first_name: 'some name' }
|
189
|
+
|
190
|
+
context 'when organization does have a custom welcome template' do
|
191
|
+
let(:organization) { custom_welcome_orga }
|
192
|
+
|
193
|
+
it { expect(email.body.encoded).to eq 'hello some name!' }
|
194
|
+
end
|
195
|
+
end
|
181
196
|
end
|