Skip to content

Commit b21838f

Browse files
committed
test: Add system tests for exercise administration
The exercise administration form is a critical pass. The test will secure the functionality with the upcoming changes. Relates to #2922
1 parent 0579609 commit b21838f

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed

spec/support/wait_for_turbolinks.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# frozen_string_literal: true
2+
3+
module WaitForTurbolinks
4+
# Capybara waits ordinary page navigation. With Turbolinks
5+
# the page is checked immediate. This might be before the
6+
# Turbolinks navigation finished. This makes system tests brittle.
7+
# By checking the Turbolinks progress bar we can wait for the
8+
# Turbolinks request to finish.
9+
def wait_for_turbolinks
10+
has_css?('.turbolinks-progress-bar', visible: true)
11+
has_no_css?('.turbolinks-progress-bar')
12+
end
13+
end
14+
15+
RSpec.configure do |config|
16+
config.include WaitForTurbolinks, type: :system
17+
end

spec/system/exercises_system_spec.rb

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
5+
RSpec.describe 'Exercise creation', :js do
6+
let!(:ruby) { create(:ruby) }
7+
8+
before do
9+
visit(sign_in_path)
10+
fill_in('email', with: teacher.email)
11+
fill_in('password', with: attributes_for(:teacher)[:password])
12+
click_button(I18n.t('sessions.new.link'))
13+
wait_for_turbolinks
14+
end
15+
16+
context 'when an exercise created' do
17+
let(:teacher) { create(:teacher) }
18+
let(:submission_deadline) { 3.months.from_now.beginning_of_minute }
19+
let(:late_submission_deadline) { submission_deadline + 1.week }
20+
let(:title) { 'Ruby challenge' }
21+
let(:internal_title) { 'Project Ruby: Table flip' }
22+
23+
let(:code) do
24+
<<~RUBY
25+
def self.❨╯°□°❩╯︵┻━┻
26+
puts "Calm down, bro"
27+
end
28+
RUBY
29+
end
30+
31+
let(:description) do
32+
<<~TEXT
33+
Ruby challenge
34+
35+
Do something with Ruby.
36+
TEXT
37+
end
38+
39+
before do
40+
visit(exercises_path)
41+
click_on I18n.t('shared.new_model', model: Exercise.model_name.human)
42+
wait_for_turbolinks
43+
end
44+
45+
it 'creates an exercise with nested data' do
46+
fill_in Exercise.human_attribute_name(:title), with: title
47+
fill_in Exercise.human_attribute_name(:internal_title), with: internal_title
48+
49+
# description
50+
within('.markdown-editor__wrapper') do
51+
find('.ProseMirror').set(description)
52+
end
53+
54+
chosen_select(Exercise.human_attribute_name(:execution_environment), ruby.name)
55+
56+
chosen_date_time_select(Exercise.human_attribute_name(:submission_deadline), submission_deadline)
57+
58+
chosen_date_time_select(Exercise.human_attribute_name(:late_submission_deadline), late_submission_deadline)
59+
60+
check Exercise.human_attribute_name(:public)
61+
62+
click_on I18n.t('exercises.form.add_file')
63+
64+
within(find_by_id('files').all('li').last) do
65+
fill_in CodeOcean::File.human_attribute_name(:name), with: 'main'
66+
67+
chosen_select(CodeOcean::File.human_attribute_name(:file_type), ruby.file_type.name)
68+
chosen_select(CodeOcean::File.human_attribute_name(:role), I18n.t('code_ocean/files.roles.main_file'))
69+
70+
check(CodeOcean::File.human_attribute_name(:read_only))
71+
72+
find_by_id('editor-edit').click
73+
send_keys code.strip
74+
end
75+
76+
click_button I18n.t('shared.create', model: Exercise.model_name.human)
77+
78+
expect(page).to have_text 'Exercise has successfully been created.'
79+
80+
# Exercise is created with expected attributes
81+
expect(page).to have_text(title)
82+
expect(page).to have_text(internal_title)
83+
expect(page).to have_text(submission_deadline.to_s)
84+
expect(page).to have_text(late_submission_deadline.to_s)
85+
expect(page).to have_text(ruby.name)
86+
87+
description.lines.each do |line|
88+
expect(page).to have_text(line.delete("\n"))
89+
end
90+
91+
# Exercise includes the code
92+
find('span', text: 'main.rb').click
93+
94+
code.lines.each do |code_line|
95+
expect(page).to have_text(code_line.delete("\n"))
96+
end
97+
end
98+
end
99+
100+
context 'when an exercise is updated' do
101+
let!(:exercise) { create(:fibonacci) }
102+
let(:teacher) { exercise.user }
103+
let(:deleted_file_name) { 'reference.rb' }
104+
let(:updated_file_name) { 'exercise.rb' }
105+
106+
before do
107+
visit(exercises_path)
108+
end
109+
110+
it 'updates an exercise with nested data' do
111+
click_on exercise.title
112+
click_on 'Edit'
113+
click_on I18n.t('shared.edit')
114+
115+
fill_in Exercise.human_attribute_name(:difficulty), with: 5
116+
117+
find('span', text: updated_file_name).click
118+
119+
within('.card', text: updated_file_name) do
120+
fill_in CodeOcean::File.human_attribute_name(:name), with: 'main_exercise'
121+
end
122+
123+
find('span', text: deleted_file_name).click
124+
125+
within('.card', text: deleted_file_name) do
126+
accept_confirm do
127+
find('div.btn', text: I18n.t('shared.destroy')).click
128+
end
129+
end
130+
131+
click_button I18n.t('shared.update', model: Exercise.model_name.human)
132+
133+
expect(page).to have_text("#{Exercise.human_attribute_name(:difficulty)}\n5")
134+
expect(page).to have_text('main_exercise.rb')
135+
expect(page).to have_no_text(deleted_file_name)
136+
end
137+
end
138+
139+
def chosen_select(name, value)
140+
id = first('label', text: name)[:for]
141+
142+
set_value_for_chosen_element(id, value)
143+
end
144+
145+
def chosen_date_time_select(name, date)
146+
id = first('label', text: name)[:for]
147+
148+
set_value_for_chosen_element("#{id}_1i", date.year.to_s)
149+
set_value_for_chosen_element("#{id}_2i", date.strftime('%B'))
150+
set_value_for_chosen_element("#{id}_3i", date.day.to_s)
151+
set_value_for_chosen_element("#{id}_4i", date.hour.to_s)
152+
set_value_for_chosen_element("#{id}_5i", date.min.to_s)
153+
end
154+
155+
def set_value_for_chosen_element(id, value)
156+
element = find_by_id("#{id}_chosen")
157+
element.click
158+
159+
within(element) do
160+
first('.chosen-results li', text: value).click
161+
end
162+
end
163+
end

0 commit comments

Comments
 (0)