Skip to content

Commit

Permalink
WIP switch back to JS unit tests
Browse files Browse the repository at this point in the history
This allows us to get away from testing this custom JavaScript behaviour
in multiple integration tests. We might want to test that everything
works without the add/add and finish buttons being present (it does)
  • Loading branch information
yndajas committed Sep 18, 2024
1 parent 4cb1dae commit 4e90458
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 459 deletions.
24 changes: 12 additions & 12 deletions app/assets/javascripts/modules/accessible-autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
window.GOVUK = window.GOVUK || {}
window.GOVUK.Modules = window.GOVUK.Modules || {}

;(function (Modules) {
; (function (Modules) {
'use strict'

function AccessibleAutocomplete ($module) {
Expand All @@ -23,28 +23,28 @@ window.GOVUK.Modules = window.GOVUK.Modules || {}
new window.accessibleAutocomplete.enhanceSelectElement(configOptions) // eslint-disable-line no-new, new-cap

const autocompleteElement = selectElement.parentNode.querySelector('.autocomplete__input')
enableArrow(autocompleteElement)
enableAddButton()
enableArrow(this.$module, autocompleteElement)
enableAddButton(this.$module)
resetSelectWhenDesynced(selectElement, autocompleteElement)
enableClearButton(selectElement, autocompleteElement)
enableClearButton(this.$module, selectElement, autocompleteElement)
}

Modules.AccessibleAutocomplete = AccessibleAutocomplete
})(window.GOVUK.Modules)

function enableArrow (autocompleteElement) {
const arrowElement = autocompleteElement.parentNode.querySelector('.autocomplete__dropdown-arrow-down')
function enableArrow (module, autocompleteElement) {
const arrowElement = module.querySelector('.autocomplete__dropdown-arrow-down')

arrowElement.addEventListener('click', function () {
autocompleteElement.click()
autocompleteElement.focus()
})
}

function enableAddButton () {
const addButton = document.querySelector('.js-autocomplete__add-button')
const addAndFinishButton = document.querySelector('.js-autocomplete__add-and-finish-button')
const addMoreInput = document.querySelector('input[name="application[add_more]"]')
function enableAddButton (module) {
const addButton = module.querySelector('.js-autocomplete__add-button')
const addAndFinishButton = module.querySelector('.js-autocomplete__add-and-finish-button')
const addMoreInput = module.querySelector('input[name="application[add_more]"]')

if (addButton) {
addAndFinishButton.type = 'button'
Expand Down Expand Up @@ -84,8 +84,8 @@ function resetSelectWhenDesynced (selectElement, autocompleteElement) {
})
}

function enableClearButton (selectElement, autocompleteElement) {
const clearButton = document.querySelector('.js-autocomplete__clear-button')
function enableClearButton (module, selectElement, autocompleteElement) {
const clearButton = module.querySelector('.js-autocomplete__clear-button')

if (clearButton) {
clearButton.addEventListener('click', function () {
Expand Down
53 changes: 27 additions & 26 deletions app/views/shared/_add_permissions_with_autocomplete_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<%= form_tag action, method: :patch do |f| %>
<div data-module="accessible-autocomplete">
<div data-module="accessible-autocomplete">
<%= form_tag action, method: :patch do |f| %>
<%= render "govuk_publishing_components/components/select", {
id: "new_permission_id",
heading_size: "m",
Expand All @@ -8,32 +8,33 @@
name: "application[new_permission_id]",
options: unassigned_permission_options.unshift({ text: '', value: nil })
} %>
</div>

<% assigned_permissions.map(&:id).each do |id| %>
<%= hidden_field_tag "application[current_permission_ids][]", id %>
<% end %>
<div class="govuk-button-group">
<%= render "govuk_publishing_components/components/button", {
text: "Add",
aria_label: "Add permission",
classes: "js-autocomplete__add-button"
} %>
<%= hidden_field_tag "application[add_more]", "false" %>
<%= render "govuk_publishing_components/components/button", {
text: "Add and finish",
aria_label: "Add permission and finish",
classes: "js-autocomplete__add-and-finish-button"
} %>
<div class="govuk-button-group">
<%= render "govuk_publishing_components/components/button", {
text: "Add",
aria_label: "Add permission",
classes: "js-autocomplete__add-button"
} %>
<%= render "govuk_publishing_components/components/button", {
text: "Clear selection",
type: "button",
classes: "js-autocomplete__clear-button",
secondary_solid: true
} %>
</div>

<%= render "govuk_publishing_components/components/button", {
text: "Add and finish",
aria_label: "Add permission and finish",
classes: "js-autocomplete__add-and-finish-button"
} %>

<%= render "govuk_publishing_components/components/button", {
text: "Clear selection",
type: "button",
classes: "js-autocomplete__clear-button",
secondary_solid: true
} %>
</div>
<% end %>
<% assigned_permissions.map(&:id).each do |id| %>
<%= hidden_field_tag "application[current_permission_ids][]", id %>
<% end %>
<%= hidden_field_tag "application[add_more]", "false" %>
<% end %>
</div>
46 changes: 0 additions & 46 deletions spec/javascripts/modules/accessible-autocomplete-dropdown-spec.js

This file was deleted.

93 changes: 93 additions & 0 deletions spec/javascripts/modules/accessible-autocomplete-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
describe('GOVUK.Modules.AccessibleAutocomplete', function () {
let component, module, autocompleteInput, selectInput

beforeEach(async function () {
component = document.createElement('div')
component.setAttribute('data-module', 'accessible-autocomplete')
component.innerHTML = `
<div class="govuk-form-group gem-c-select">
<label class="govuk-label govuk-label--m" for="new_permission_id">Add a permission</label>
<div id="hint-1234" class="gem-c-hint govuk-hint">
Search for the permission you want to add.
</div>
<select name="application[new_permission_id]" id="new_permission_id" class="govuk-select" aria-describedby="hint-1234">
<option value=""></option>
<option value="1">permission-1</option>
<option value="2">permission-2</option>
<option value="3">permission-3</option>
</select>
</div>
<div class="govuk-button-group">
<button class="gem-c-button govuk-button js-autocomplete__add-button" type="submit" aria-label="Add permission">Add</button>
<button class="gem-c-button govuk-button js-autocomplete__add-and-finish-button" type="submit" aria-label="Add permission and finish">Add and finish</button>
<button class="gem-c-button govuk-button govuk-button--secondary js-autocomplete__clear-button" type="button">Clear selection</button>
</div>
<input type="hidden" name="application[add_more]" id="application_add_more" value="false" autocomplete="off">
`

module = new GOVUK.Modules.AccessibleAutocomplete(component)
module.init()

autocompleteInput = component.querySelector('.autocomplete__input')
selectInput = component.querySelector('select')

autocompleteInput.value = 'per'
await wait()

expect(selectInput.value).toBe('')
const firstAutocompleteListItem = component.querySelector('#new_permission_id__option--0')
firstAutocompleteListItem.click()
expect(autocompleteInput.value).toBe('permission-1')
expect(selectInput.value).toBe('1')
})

it('opens the menu when clicking the arrow', async function () {
const menuElement = component.querySelector('.autocomplete__menu')
const menuElementClassesBefore = Array.from(menuElement.classList)
expect(menuElementClassesBefore.includes('autocomplete__menu--visible')).toBe(false)
expect(menuElementClassesBefore.includes('autocomplete__menu--hidden')).toBe(true)

const arrowElement = component.querySelector('.autocomplete__dropdown-arrow-down')
arrowElement.dispatchEvent(new Event('click'))

await wait()

const menuElementClassesAfter = Array.from(menuElement.classList)
expect(menuElementClassesAfter.includes('autocomplete__menu--visible')).toBe(true)
expect(menuElementClassesAfter.includes('autocomplete__menu--hidden')).toBe(false)
})

it("resets the value of the select element when it no longer matches what's shown in the autocomplete input", async function () {
autocompleteInput.value = 'permission-'
autocompleteInput.dispatchEvent(new KeyboardEvent('keyup'))
await wait()

expect(selectInput.value).toBe('')
})

it('clears the value of the select and autocomplete elements when clicking the clear button', async function () {
const clearButton = component.querySelector('.js-autocomplete__clear-button')
clearButton.click()
await wait()

expect(component.querySelector('select').value).toBe('')
})

it('clears the value of the select and autocomplete elements when hitting space on the clear button', async function () {
const clearButton = component.querySelector('.js-autocomplete__clear-button')
clearButton.dispatchEvent(new KeyboardEvent('keydown', { key: ' ' }))
await wait()

expect(selectInput.value).toBe('')
})

it('clears the value of the select and autocomplete elements when hitting enter on the clear button', async function () {
const clearButton = component.querySelector('.js-autocomplete__clear-button')
clearButton.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }))
await wait()

expect(selectInput.value).toBe('')
})
})

const wait = async () => await new Promise(resolve => setTimeout(resolve, 1000))
128 changes: 0 additions & 128 deletions test/integration/inviting_users_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -384,132 +384,4 @@ class InvitingUsersTest < ActionDispatch::IntegrationTest
end
end
end

context "with JavaScript enabled" do
setup do
use_javascript_driver

create(:organisation, name: "ABCDEF")
create(:organisation, name: "GHIJKL")
@organisation = create(:organisation, name: "MNOPQR")
create(:organisation, name: "STUVWX")
create(:organisation, name: "YZ1234")

superadmin = create(:superadmin_user)
visit root_path
signin_with(superadmin)

visit new_user_invitation_path
fill_in "Name", with: "H from Steps"
fill_in "Email", with: "h@from.steps"
select "Superadmin", from: "Role"

@autocomplete_input_element = find(".autocomplete__input")
@select_element = find("#user_organisation_id-select", visible: false)
end

should "be able to invite a user" do
assert_select_with_autocomplete(
autocomplete_input_element: @autocomplete_input_element,
select_element: @select_element,
option_text: @organisation.name,
option_value: @organisation.id.to_s,
unique_partial_string: "MNO",
)

click_button "Create user and send email"

new_user = User.find_by(email: "h@from.steps", role: Roles::Superadmin.name)
assert_not_nil new_user
assert_equal new_user.organisation, @organisation
end

should("not show an 'Add' button") { assert_no_selector "button", text: "Add" }

should "reset the value of the select element when it no longer matches what's shown in the autocomplete input" do
assert_select_with_autocomplete(
autocomplete_input_element: @autocomplete_input_element,
select_element: @select_element,
option_text: @organisation.name,
option_value: @organisation.id.to_s,
unique_partial_string: "MNO",
)

assert_resets_select_when_desynced_with_autocomplete(
autocomplete_input_element: @autocomplete_input_element,
select_element: @select_element,
option_text: @organisation.name,
unique_partial_string: "MNOP",
)

click_button "Create user and send email"

new_user = User.find_by(email: "h@from.steps", role: Roles::Superadmin.name)
assert_not_nil new_user
assert_nil new_user.organisation
end

should "clear the value of the select and autocomplete elements when clicking the clear button" do
assert_select_with_autocomplete(
autocomplete_input_element: @autocomplete_input_element,
select_element: @select_element,
option_text: @organisation.name,
option_value: @organisation.id.to_s,
unique_partial_string: "MNO",
)

assert_clear_autocomplete_selection_by_click(
autocomplete_input_element: @autocomplete_input_element,
select_element: @select_element,
)

click_button "Create user and send email"

new_user = User.find_by(email: "h@from.steps", role: Roles::Superadmin.name)
assert_not_nil new_user
assert_nil new_user.organisation
end

should "clear the value of the select and autocomplete elements when hitting space on the clear button" do
assert_select_with_autocomplete(
autocomplete_input_element: @autocomplete_input_element,
select_element: @select_element,
option_text: @organisation.name,
option_value: @organisation.id.to_s,
unique_partial_string: "MNO",
)

assert_clear_autocomplete_selection_by_space(
autocomplete_input_element: @autocomplete_input_element,
select_element: @select_element,
)

click_button "Create user and send email"

new_user = User.find_by(email: "h@from.steps", role: Roles::Superadmin.name)
assert_not_nil new_user
assert_nil new_user.organisation
end

should "clear the value of the select and autocomplete elements when hitting enter on the clear button" do
assert_select_with_autocomplete(
autocomplete_input_element: @autocomplete_input_element,
select_element: @select_element,
option_text: @organisation.name,
option_value: @organisation.id.to_s,
unique_partial_string: "MNO",
)

assert_clear_autocomplete_selection_by_enter(
autocomplete_input_element: @autocomplete_input_element,
select_element: @select_element,
)

click_button "Create user and send email"

new_user = User.find_by(email: "h@from.steps", role: Roles::Superadmin.name)
assert_not_nil new_user
assert_nil new_user.organisation
end
end
end
Loading

0 comments on commit 4e90458

Please sign in to comment.