|  | 
|  | 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