diff --git a/app/assets/javascripts/add_remove_authors.js b/app/assets/javascripts/add_remove_authors.js index 79312272..1dfdb9ca 100644 --- a/app/assets/javascripts/add_remove_authors.js +++ b/app/assets/javascripts/add_remove_authors.js @@ -1,25 +1,134 @@ -function addAuthor(type, count) { - var count = count || 1; - var newAuthor = document.createElement("div"); - var firstI = document.createElement("div"); - var lastI = document.createElement("div"); - var deleteB = document.createElement("div"); - newAuthor.setAttribute("class", "form-row"); - firstI.setAttribute("class", "col-md-5"); - lastI.setAttribute("class", "col-md-5"); - deleteB.setAttribute("class", "col-md-2"); - firstI.innerHTML = ``; - lastI.innerHTML = ``; - deleteB.innerHTML = ``; - newAuthor.setAttribute("id", "added_" + count); - newAuthor.appendChild(firstI); - newAuthor.appendChild(lastI); - newAuthor.appendChild(deleteB); - document.getElementById("author_group").appendChild(newAuthor); - count++; - document.getElementById("add_author_btn").setAttribute("onClick", `addAuthor('${type}', ${count})`); -} - -function removeAuthor(idToDelete) { - document.getElementById(idToDelete).outerHTML = ''; + +// Add an event listener to the author group element that will allow the "Remove Author" button to work +// even if the author group element is dynamically added to the page. +document.addEventListener("turbolinks:load", function() { + const authorGroupElement = document.getElementById('author_group'); + + if (authorGroupElement) { + authorGroupElement.addEventListener('click', function(event) { + if (event.target && + event.target.matches("button[type='button']") && + ['Remove Author', 'Remove Artist'].includes(event.target.textContent) + ) { + // Navigate up two levels to get the grandparent element, which is the author element. + const authorElement = event.target.parentNode.parentNode; + const authorElements = Array.from(authorGroupElement.children); + const authorIndex = authorElements.indexOf(authorElement); + + if (authorIndex !== -1) { + removeAuthor(authorIndex); + updateAuthorIds() + } + } + }); + } +}); + +function getRoleFromButton() { + const button = document.getElementById('add_author_btn'); + if (!button) return null; // Return null if the button doesn't exist + + return button.textContent.includes('Artist') ? 'Artist' : 'Author'; +} + +function removeAuthor(authorIndex) { + const authorGroupElement = document.getElementById('author_group'); + if (authorGroupElement && authorGroupElement.children[authorIndex]) { + authorGroupElement.children[authorIndex].remove(); + updateAuthorIds(); + } +} + + +function addAuthor(type) { + const authorGroup = document.getElementById("author_group"); + if (!authorGroup) return; + + const newAuthor = createAuthorElement(type); + authorGroup.appendChild(newAuthor); + updateAuthorIds(); +} + +function createAuthorElement(type) { + const newDataIndex = document.querySelectorAll(`[data-type='${type}']`).length; + const newAuthor = createElementWithAttributes("div", { class: "form-row", 'data-type': type, 'data-index': newDataIndex }); + newAuthor.appendChild(createInput(type, "author_first_name")); + newAuthor.appendChild(createInput(type, "author_last_name")); + newAuthor.appendChild(createDeleteButton()); + return newAuthor; +} + +function createElementWithAttributes(tag, attributes) { + const element = document.createElement(tag); + Object.entries(attributes).forEach(([key, value]) => element.setAttribute(key, value)); + return element; +} + +function createInput(type, name) { + // The "for" attribute of the label will be updated with the updateAuthorIds function. + + const role = getRoleFromButton(); + if (!role) return; + + const wrapper = createElementWithAttributes("div", { + class: "col-md-5", + "data-type": type + }); + + const label = createElementWithAttributes("label", { + class: "required", + "data-type": type + }); + + label.textContent = name.includes('first_name') ? role + ' First Name' : role + ' Last Name'; + + const input = createElementWithAttributes("input", { + type: "text", + name: `${type}[${name}][]`, + required: "required", + class: "form-control form-group", + "data-type": type + }); + + wrapper.appendChild(label); + wrapper.appendChild(input); + + return wrapper; } + +function createDeleteButton() { + const role = getRoleFromButton(); + if (!role) return; + + const wrapper = createElementWithAttributes("div", { class: "col-md-2" }); + const button = createElementWithAttributes("button", { + type: "button", + class: "form-control form-group bg-danger text-white" + }); + button.textContent = "Remove " + role; + wrapper.appendChild(button); + return wrapper; +} + +function updateAuthorIds() { + const authorGroups = document.querySelectorAll('#author_group .form-row'); + authorGroups.forEach((group, index) => { + group.id = `author_${index}`; + updateFieldAndLabel(group, 'first_name', index); + updateFieldAndLabel(group, 'last_name', index); + }); +} + +function updateFieldAndLabel(group, fieldName, index) { + const type = group.getAttribute('data-type'); + if (!type) return; + + const input = group.querySelector(`[name='${type}[author_${fieldName}][]']`); + if (!input) return; + + input.id = `author_${fieldName}_${index}`; + const label = input.previousElementSibling; + if (label && label.tagName === 'LABEL') { + label.setAttribute('for', input.id); + } +} \ No newline at end of file diff --git a/app/views/partials/_author.html.erb b/app/views/partials/_author.html.erb index 0f79ba0e..47cd2f8a 100644 --- a/app/views/partials/_author.html.erb +++ b/app/views/partials/_author.html.erb @@ -1,26 +1,27 @@
- <% if publication.author_first_name.empty? && publication.author_last_name.empty? %> + <% if publication.author_first_name.empty? && publication.author_last_name.empty? %> <% publication.author_first_name << '' %> <% publication.author_last_name << '' %> - <% end %> + <% end %> - <% publication.author_first_name.each_with_index do |_, index| %> -
-
- <%= label_tag(:author_first_name, author_or_artist_label + ' First Name', class: "required") %> - <%= text_field_tag "#{name}[author_first_name][]", publication.author_first_name[index], required: true, class: "form-control form-group" %> -
-
- <%= label_tag "#{name}_author_last_name_#{index}", "Author Last Name", class: "required" %> - <%= text_field_tag "#{name}[author_last_name][]", publication.author_last_name[index], required: true, class: "form-control form-group" %> -
- <% if index > 0 %> + <% publication.author_first_name.zip(publication.author_last_name).each_with_index do |(first_name, last_name), index| %> +
id="author_<%= index %>"> +
+ <%= label_tag("author_first_name_#{index}", "#{author_or_artist_label} First Name", class: "required") %> + <%= text_field_tag "#{name}[author_first_name][]", first_name, "data-publication-type": name, id: "author_first_name_#{index}", required: true, class: "form-control form-group" %> +
+
+ <%= label_tag "author_last_name_#{index}", "#{author_or_artist_label} Last Name", class: "required" %> + <%= text_field_tag "#{name}[author_last_name][]", last_name, "data-publication-type": name, id: "author_last_name_#{index}", required: true, class: "form-control form-group" %> +
+ <% if index > 0 %>
- <%= button_tag "Remove Author", type: "button", onclick: "removeAuthor('author_#{index}')", class: "form-control form-group bg-danger text-white" %> + <%= button_tag "Remove " + author_or_artist_label, type: "button", class: "form-control form-group bg-danger text-white" %>
- <% end %> + <% end %>
- <% end %> + <% end %>
-<%= button_tag "Add Author", type: "button", id: "add_author_btn", onclick: "addAuthor('#{name}')", class: "btn btn-primary" %> + +<%= button_tag "Add " + author_or_artist_label, type: "button", id: "add_author_btn", onclick: "addAuthor('#{name}')", class: "btn btn-primary" %> diff --git a/app/views/partials/_publications_colleges.html.erb b/app/views/partials/_publications_colleges.html.erb index 7aee9b7c..9d6a9442 100644 --- a/app/views/partials/_publications_colleges.html.erb +++ b/app/views/partials/_publications_colleges.html.erb @@ -1,13 +1,16 @@
- <%= form.label(:college_ids, author_or_artist_label + " College(s)") %>
- <%= form.collection_check_boxes :college_ids, College.all, :id, :name do |c| %> -
- <%= c.check_box class: "form-check-input" %> - <%= c.label class: "form-check-label" %> -
- <% end %> +
+ <%= author_or_artist_label %> College(s)
+ <%= form.collection_check_boxes :college_ids, College.all, :id, :name do |b| %> +
+ <%= b.check_box class: "form-check-input" %> + <%= b.label class: "form-check-label" %> +
+ <% end %> +
+
<%= form.label :other_college, 'Other College' %> diff --git a/spec/features/author_management/adding_authors_spec.rb b/spec/features/author_management/adding_authors_spec.rb new file mode 100644 index 00000000..e89a4993 --- /dev/null +++ b/spec/features/author_management/adding_authors_spec.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Adding Authors', :feature, js: true do + let(:submitter) { FactoryBot.create(:submitter) } + + before do + create_submitter(submitter) + end + + it 'adds authors to a new publication' do + visit new_other_publication_path + expect(page).to have_current_path(Rails.application.routes.url_helpers.new_other_publication_path) + + # Verify blank input fields for author's first name and last name + # to be present on page load + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 1) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 1) + check_field_values_by_index(0, '', '') + + # Fill out the fields with the first author's name + first_name_fields.last.set('First0') + last_name_fields.last.set('Last0') + + # Click "Add Author" and verify new and old fields + click_on 'Add Author' + + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 2) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 2) + + check_field_values_by_index(0, 'First0', 'Last0') + check_field_values_by_index(1, '', '') + + # Fill in second author's name + first_name_fields.last.set('First1') + last_name_fields.last.set('Last1') + + # Click "Add Author" again + click_on 'Add Author' + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 3) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 3) + check_field_values_by_index(0, 'First0', 'Last0') + check_field_values_by_index(1, 'First1', 'Last1') + check_field_values_by_index(2, '', '') + + # Fill in third author's name + first_name_fields.last.set('First2') + last_name_fields.last.set('Last2') + + # Click "Add Author" again + click_on 'Add Author' + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 4) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 4) + check_field_values_by_index(0, 'First0', 'Last0') + check_field_values_by_index(1, 'First1', 'Last1') + check_field_values_by_index(2, 'First2', 'Last2') + check_field_values_by_index(3, '', '') + + # Fill in fourth author's name + first_name_fields.last.set('First3') + last_name_fields.last.set('Last3') + + # Fill in the rest of the fields + fill_in 'other_publication[work_title]', with: 'Title' + fill_in 'other_publication[other_title]', with: 'Subtitle' + fill_in 'other_publication[uc_department]', with: 'Department' + fill_in 'other_publication[publication_date]', with: 'Date' + fill_in 'other_publication[url]', with: 'URL' + fill_in 'other_publication[doi]', with: 'DOI' + + # Click "Submit" and verify that we are redirected to the index page + # and that a success message is displayed + click_on 'Submit' + expect(page).to have_current_path(Rails.application.routes.url_helpers.publications_path) + expect(page).to have_text 'Other Publication was successfully created.' + + # Click on the hyperlink on the id of the newly created publication + # and verify that the author names are correct + click_on OtherPublication.last.work_title.to_s + expect(page).to have_current_path(Rails.application.routes.url_helpers.other_publication_path(OtherPublication.last.id)) + expect(page).to have_text 'First0 Last0' + expect(page).to have_text 'First1 Last1' + expect(page).to have_text 'First2 Last2' + expect(page).to have_text 'First3 Last3' + end + + it 'adds authors to an existing publication' do + # Create a new publication. Adding author functionality for a new publication + # is tested in the previous test. + create_other_publication # Defined in spec/support/helpers/feature_spec_helpers/author_management.rb + + # Click on the hyperlink on the id of the newly created publication + # and verify that the author names are correct + click_on OtherPublication.last.work_title.to_s + expect(page).to have_current_path(Rails.application.routes.url_helpers.other_publication_path(OtherPublication.last.id)) + expect(page).to have_selector('td', text: 'First0 Last0') # Information is in table format on the show page + + # Click on "Edit" and verify that we are redirected to the edit page + # and that the author names are correct + click_on 'Edit' + expect(page).to have_current_path(Rails.application.routes.url_helpers.edit_other_publication_path(OtherPublication.last.id)) + check_field_values_by_index(0, 'First0', 'Last0') + + # Add another author and verify that the author names are correct + click_on 'Add Author' + first_name_fields.last.set('First1') + last_name_fields.last.set('Last1') + check_field_values_by_index(0, 'First0', 'Last0') + check_field_values_by_index(1, 'First1', 'Last1') + + # Add a third author and verify that the author names are correct + click_on 'Add Author' + first_name_fields.last.set('First2') + last_name_fields.last.set('Last2') + check_field_values_by_index(0, 'First0', 'Last0') + check_field_values_by_index(1, 'First1', 'Last1') + check_field_values_by_index(2, 'First2', 'Last2') + + # Save the changes and verify that we are redirected to the show page + # and that the author names are correct + click_on 'Submit' + expect(page).to have_current_path(Rails.application.routes.url_helpers.other_publication_path(OtherPublication.last.id)) + expect(page).to have_text 'Other Publication was successfully updated.' + expect(page).to have_selector('td', text: 'First0 Last0, First1 Last1, First2 Last2') # Information is in table format on the show page + end +end diff --git a/spec/features/author_management/author_vs_artist_labels_spec.rb b/spec/features/author_management/author_vs_artist_labels_spec.rb new file mode 100644 index 00000000..e341c50e --- /dev/null +++ b/spec/features/author_management/author_vs_artist_labels_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require 'rails_helper' + +# When adding an author or artist for a publication, the page should +# correctly display the title of the author or artist as "Author" or "Artist". +# This is a feature test that checks the behavior of the page when adding +# and deleting authors and artists. +describe 'Author and Artist labels', :feature, js: true do + let(:submitter) { FactoryBot.create(:submitter) } + + before do + create_submitter(submitter) + end + + it 'uses the title of Author for new books' do + visit new_book_path + expect(page).to have_content('Add Author') + expect(page).not_to have_content('Add Artist') + first_name_fields.last.set('First0') + last_name_fields.last.set('Last0') + click_on 'Add Author' + first_name_fields.last.set('First1') + last_name_fields.last.set('Last1') + click_on 'Add Author' + expect(page).to have_selector('button', text: 'Remove Author', count: 2) + expect(page).not_to have_selector('button', text: 'Remove Artist') + first('button', text: 'Remove Author').click + expect(page).to have_selector('button', text: 'Remove Author', count: 1) + expect(page).not_to have_content('Artist') + end + + it 'has the title of Artist for new artworks' do + visit new_artwork_path + expect(page).to have_content('Add Artist') + expect(page).not_to have_content('Add Author') + first_name_fields.last.set('First0') + last_name_fields.last.set('Last0') + click_on 'Add Artist' + first_name_fields.last.set('First1') + last_name_fields.last.set('Last1') + click_on 'Add Artist' + expect(page).to have_selector('button', text: 'Remove Artist', count: 2) + expect(page).not_to have_selector('button', text: 'Remove Author') + first('button', text: 'Remove Artist').click + expect(page).to have_selector('button', text: 'Remove Artist', count: 1) + expect(page).not_to have_content('Author') + end +end diff --git a/spec/features/author_management/removing_authors_spec.rb b/spec/features/author_management/removing_authors_spec.rb new file mode 100644 index 00000000..de4ec0de --- /dev/null +++ b/spec/features/author_management/removing_authors_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Removing Authors', :feature, js: true do + let(:submitter) { FactoryBot.create(:submitter) } + + before do + create_submitter(submitter) + create_other_publication + add_three_more_authors_to_publication(OtherPublication.last) + visit edit_other_publication_path(OtherPublication.last) + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 4) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 4) + end + + it 'removes the second author from the publication' do + # Remove the second author + remove_author_at_index(1) + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 3) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 3) + check_field_values_by_index(0, 'First0', 'Last0') + check_field_values_by_index(1, 'First2', 'Last2') + check_field_values_by_index(2, 'First3', 'Last3') + + # Remove the second author again (should be "First2") + remove_author_at_index(1) + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 2) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 2) + check_field_values_by_index(0, 'First0', 'Last0') + check_field_values_by_index(1, 'First3', 'Last3') + + # Remove the second author again (should be "First3") + remove_author_at_index(1) + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 1) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 1) + check_field_values_by_index(0, 'First0', 'Last0') + end + + it 'removes the last author from the publication' do + remove_author_at_index(3) + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 3) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 3) + check_field_values_by_index(0, 'First0', 'Last0') + check_field_values_by_index(1, 'First1', 'Last1') + check_field_values_by_index(2, 'First2', 'Last2') + + remove_author_at_index(2) + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 2) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 2) + check_field_values_by_index(0, 'First0', 'Last0') + check_field_values_by_index(1, 'First1', 'Last1') + + remove_author_at_index(1) + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 1) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 1) + check_field_values_by_index(0, 'First0', 'Last0') + end + + it 'does not have a Remove Author button for the first author' do + expect(first_author_element).not_to have_selector('button', text: 'Remove Author') + end +end diff --git a/spec/features/author_management/updating_authors_spec.rb b/spec/features/author_management/updating_authors_spec.rb new file mode 100644 index 00000000..7037e7d2 --- /dev/null +++ b/spec/features/author_management/updating_authors_spec.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Adding Authors', :feature, js: true do + let(:submitter) { FactoryBot.create(:submitter) } + + before do + create_submitter(submitter) + end + + it "allows the user to update the first author's information" do + create_other_publication + add_three_more_authors_to_publication(OtherPublication.last) + visit edit_other_publication_path(OtherPublication.last) + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 4) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 4) + check_field_values_by_index(0, 'First0', 'Last0') + check_field_values_by_index(1, 'First1', 'Last1') + check_field_values_by_index(2, 'First2', 'Last2') + check_field_values_by_index(3, 'First3', 'Last3') + + # Update the first author's name + first_name_fields.first.set('First0modified') + last_name_fields.first.set('Last0modified') + click_on 'Submit' + + expect(page).to have_current_path(other_publication_path(OtherPublication.last)) + expect(page).to have_content('First0modified') + expect(page).to have_content('Last0modified') + expect(page).to have_content('First1') + expect(page).to have_content('Last1') + expect(page).to have_content('First2') + expect(page).to have_content('Last2') + expect(page).to have_content('First3') + expect(page).to have_content('Last3') + end + + it "allows the user to update the second author's information" do + create_other_publication + add_three_more_authors_to_publication(OtherPublication.last) + visit edit_other_publication_path(OtherPublication.last) + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 4) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 4) + check_field_values_by_index(0, 'First0', 'Last0') + check_field_values_by_index(1, 'First1', 'Last1') + check_field_values_by_index(2, 'First2', 'Last2') + check_field_values_by_index(3, 'First3', 'Last3') + + # Update the second author's name + first_name_fields[1].set('First1modified') + last_name_fields[1].set('Last1modified') + click_on 'Submit' + + expect(page).to have_current_path(other_publication_path(OtherPublication.last)) + expect(page).to have_content('First0') + expect(page).to have_content('Last0') + expect(page).to have_content('First1modified') + expect(page).to have_content('Last1modified') + expect(page).to have_content('First2') + expect(page).to have_content('Last2') + expect(page).to have_content('First3') + expect(page).to have_content('Last3') + end + + it "allows the user to update the last author's information" do + create_other_publication + add_three_more_authors_to_publication(OtherPublication.last) + visit edit_other_publication_path(OtherPublication.last) + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 4) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 4) + check_field_values_by_index(0, 'First0', 'Last0') + check_field_values_by_index(1, 'First1', 'Last1') + check_field_values_by_index(2, 'First2', 'Last2') + check_field_values_by_index(3, 'First3', 'Last3') + + # Update the last author's name + first_name_fields.last.set('First3modified') + last_name_fields.last.set('Last3modified') + click_on 'Submit' + + expect(page).to have_current_path(other_publication_path(OtherPublication.last)) + expect(page).to have_content('First0') + expect(page).to have_content('Last0') + expect(page).to have_content('First1') + expect(page).to have_content('Last1') + expect(page).to have_content('First2') + expect(page).to have_content('Last2') + expect(page).to have_content('First3modified') + expect(page).to have_content('Last3modified') + end + + it 'persists the changes when refreshing the page' do + create_other_publication + add_three_more_authors_to_publication(OtherPublication.last) + visit edit_other_publication_path(OtherPublication.last) + expect(page).to have_selector("input[name='other_publication[author_first_name][]']", count: 4) + expect(page).to have_selector("input[name='other_publication[author_last_name][]']", count: 4) + check_field_values_by_index(0, 'First0', 'Last0') + check_field_values_by_index(1, 'First1', 'Last1') + check_field_values_by_index(2, 'First2', 'Last2') + check_field_values_by_index(3, 'First3', 'Last3') + + # Update the first author's name + first_name_fields.first.set('First0modified') + last_name_fields.first.set('Last0modified') + first_name_fields[1].set('First1modified') + last_name_fields[1].set('Last1modified') + first_name_fields[2].set('First2modified') + last_name_fields[2].set('Last2modified') + first_name_fields.last.set('First3modified') + last_name_fields.last.set('Last3modified') + click_on 'Submit' + + page.driver.browser.navigate.refresh + expect(page).to have_text('First0modified Last0modified, First1modified Last1modified, First2modified Last2modified, First3modified Last3modified') + end +end diff --git a/spec/features/create_artwork_spec.rb b/spec/features/create_artwork_spec.rb index bee8bc5b..82b9dd0f 100644 --- a/spec/features/create_artwork_spec.rb +++ b/spec/features/create_artwork_spec.rb @@ -14,7 +14,7 @@ # New artwork Page expect(page).to have_current_path(Rails.application.routes.url_helpers.new_artwork_path) (0..artwork.author_first_name.count - 1).each do |i| - click_on('Add Author') if i != 0 + click_on('Add Artist') if i != 0 all(:xpath, "//input[@name='artwork[author_first_name][]']").last.set(artwork.author_first_name[i]) all(:xpath, "//input[@name='artwork[author_last_name][]']").last.set(artwork.author_last_name[i]) end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 84ff5fd6..418d45ae 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -72,6 +72,9 @@ config.filter_rails_from_backtrace! # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") + + # Include helpers for feature tests + config.include FeatureSpecHelpers::AuthorManagement, type: :feature end def create_submitter(submitter) diff --git a/spec/support/helpers/feature_spec_helpers/author_management.rb b/spec/support/helpers/feature_spec_helpers/author_management.rb new file mode 100644 index 00000000..e802e5d1 --- /dev/null +++ b/spec/support/helpers/feature_spec_helpers/author_management.rb @@ -0,0 +1,115 @@ +# frozen_string_literal: true + +module FeatureSpecHelpers + # AuthorManagement provides helper methods for managing author fields in feature tests. + # It includes functionality to add, remove, and verify authors in a publication context, + # specifically catering to dynamic web page interactions with Capybara. + # Methods within this module handle tasks like removing authors at a specific index, + # checking field values, and finding parent elements in the DOM structure. + module AuthorManagement + def remove_author_at_index(index) + return if index.zero? # The first author cannot be removed + return unless valid_index?(index) + + # Find the element at the given index + # (index + 1) is used because nth-child is 1-indexed + author_to_remove = find("#author_group > :nth-child(#{index + 1})") + return unless author_to_remove + + # Find the remove button in the author_to_remove element and click it + remove_button = author_to_remove.find('button', text: 'Remove Author', match: :first) + remove_button.click + rescue Capybara::ElementNotFound => e + raise "Remove Author button could not be found: #{e.message}" + end + + def check_field_values_by_index(index, expected_first_name, expected_last_name) + return unless valid_index?(index) + + verify_field_value( + fields: first_name_fields, + index:, + expected_value: expected_first_name, + field_name: 'First name' + ) + + verify_field_value( + fields: last_name_fields, + index:, + expected_value: expected_last_name, + field_name: 'Last name' + ) + end + + # Assuming authors are direct children of #author_group + # This method finds the first author element + def first_author_element + find('#author_group > :first-child') + end + + private + + # Returns the collection of author first name fields. + # @return [Array] The collection of author first name fields. + def first_name_fields + all("input[name$='[author_first_name][]']", wait: Capybara.default_max_wait_time) + end + + # Returns the collection of author last name fields. + # @return [Array] The collection of author last name fields. + def last_name_fields + all("input[name$='[author_last_name][]']", wait: Capybara.default_max_wait_time) + end + + # Validates if the provided index is within the range of existing author fields. + # @param [Integer] index - The index to validate. + # @return [Boolean] True if the index is valid, false otherwise. + def valid_index?(index) + index.between?(0, [first_name_fields.size, last_name_fields.size].min - 1) + end + + # Verifies the value of a field against the expected value. + # @param fields: [Array] The collection of fields to verify. + # @param index: [Integer] The index of the field to check. + # @param expected_value: [String] The expected value of the field. + # @param field_name: [String] The name of the field (for error messages). + def verify_field_value(fields:, index:, expected_value:, field_name:) + field = fields[index] + actual_value = field.value + error_message = "#{field_name} at index #{index} does not match" + expect(actual_value).to eq(expected_value), error_message + end + + # navigates to the new other publication page and fills out the form. + def create_other_publication + visit new_other_publication_path + + # Fill out the fields with the first author's name + first_name_fields.last.set('First0') + last_name_fields.last.set('Last0') + + # Fill in the rest of the fields + fill_in 'other_publication[work_title]', with: 'Title' + fill_in 'other_publication[other_title]', with: 'Subtitle' + fill_in 'other_publication[uc_department]', with: 'Department' + fill_in 'other_publication[publication_date]', with: 'Date' + fill_in 'other_publication[url]', with: 'URL' + fill_in 'other_publication[doi]', with: 'DOI' + + click_on 'Submit' + end + + # Adds three more authors to a publication. Valid only within + # the context of a feature test with an already created publication. + def add_three_more_authors_to_publication(publication) + visit edit_other_publication_path(publication) + 3.times do + current_count = first_name_fields.size + click_on 'Add Author' + first_name_fields.last.set("First#{current_count}") + last_name_fields.last.set("Last#{current_count}") + end + click_on 'Submit' + end + end +end