diff --git a/CHANGELOG.md b/CHANGELOG.md index f8929aa180..bdb69519cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ * Add files for secondary navigation: ([PR #4229](https://github.com/alphagov/govuk_publishing_components/pull/4229)) * New class to collapse columns for print ([PR #4224](https://github.com/alphagov/govuk_publishing_components/pull/4224)) * Fix homepage super navigation buttons when text scale is increased ([PR #4232](https://github.com/alphagov/govuk_publishing_components/pull/4232)) +* Add experimental `search_with_autocomplete` component ([PR #4218](https://github.com/alphagov/govuk_publishing_components/pull/4218)) ## 43.1.1 diff --git a/app/assets/images/govuk_publishing_components/icon-autocomplete-search-suggestion.svg b/app/assets/images/govuk_publishing_components/icon-autocomplete-search-suggestion.svg new file mode 100644 index 0000000000..39d55088b3 --- /dev/null +++ b/app/assets/images/govuk_publishing_components/icon-autocomplete-search-suggestion.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/assets/javascripts/govuk_publishing_components/components/search-with-autocomplete.js b/app/assets/javascripts/govuk_publishing_components/components/search-with-autocomplete.js new file mode 100644 index 0000000000..0de69690b6 --- /dev/null +++ b/app/assets/javascripts/govuk_publishing_components/components/search-with-autocomplete.js @@ -0,0 +1,123 @@ +/* global accessibleAutocomplete, fetch */ +//= require accessible-autocomplete/dist/accessible-autocomplete.min.js + +window.GOVUK = window.GOVUK || {} +window.GOVUK.Modules = window.GOVUK.Modules || {}; + +(function (Modules) { + class GemSearchWithAutocomplete { + constructor ($module) { + this.$module = $module + + this.$originalInput = this.$module.querySelector('input') + this.$inputWrapper = this.$module.querySelector('.js-search-input-wrapper') + this.$form = this.$module.closest('form') + + this.sourceUrl = this.$module.getAttribute('data-source-url') + this.sourceKey = this.$module.getAttribute('data-source-key') + } + + init () { + const configOptions = { + element: this.$inputWrapper, + id: this.$originalInput.id, + name: this.$originalInput.name, + inputClasses: this.$originalInput.classList, + defaultValue: this.$originalInput.value, + cssNamespace: 'gem-c-search-with-autocomplete', + confirmOnBlur: false, + showNoOptionsFound: false, + source: this.getResults.bind(this), + onConfirm: this.submitContainingForm.bind(this), + templates: { + suggestion: this.constructSuggestionHTMLString.bind(this) + }, + tStatusNoResults: () => 'No search suggestions found', + tStatusQueryTooShort: (minQueryLength) => `Type in ${minQueryLength} or more characters for search suggestions`, + tStatusResults: (length, contentSelectedOption) => { + const words = { + result: (length === 1) ? 'search suggestion' : 'search suggestions', + is: (length === 1) ? 'is' : 'are' + } + + return `${length} ${words.result} ${words.is} available. ${contentSelectedOption}` + }, + tAssistiveHint: () => 'When search suggestions are available use up and down arrows to review and enter to select. Touch device users, explore by touch or with swipe gestures.' + } + accessibleAutocomplete(configOptions) + + // The accessible-autocomplete component is meant to generate a new input element rather than enhancing an existing one, so we need to do some cleanup here. + this.$autocompleteInput = this.$inputWrapper.querySelector( + '.gem-c-search-with-autocomplete__input' + ) + // Ensure the new input element generated by accessible-autocomplete has the correct type + this.$autocompleteInput.setAttribute('type', 'search') + // Remove the original input from the DOM + this.$originalInput.parentNode.removeChild(this.$originalInput) + } + + // Callback used by accessible-autocomplete to generate the HTML for each suggestion based on + // the values returned from the source + constructSuggestionHTMLString (result) { + const sanitizedResult = this.sanitizeResult(result) + const inputValue = this.$inputWrapper.querySelector('input').value.toLowerCase() + + const index = sanitizedResult.toLowerCase().indexOf(inputValue) + + let html = sanitizedResult + if (index !== -1) { + const before = sanitizedResult.slice(0, index) + const match = sanitizedResult.slice(index, index + inputValue.length) + const after = sanitizedResult.slice(index + inputValue.length) + + html = `${before}${match}${after}` + } + + return ` +
+ + ${html} +
+ ` + } + + // Callback used by accessible-autocomplete to fetch results from the source + getResults (query, populateResults) { + const url = new URL(this.sourceUrl) + url.searchParams.set('q', query) + fetch(url, { headers: { Accept: 'application/json' } }) + .then(response => response.json()) + .then((data) => { populateResults(data[this.sourceKey]) }) + .catch(() => { populateResults([]) }) + } + + // Callback used by accessible-autocomplete to submit the containing form when a suggestion is + // confirmed by the user (e.g. by pressing Enter or clicking on it) + submitContainingForm (value) { + if (this.$form) { + // The accessible-autocomplete component calls this callback _before_ it updates its + // internal state, so the value of the input field is not yet updated when this callback is + // called. We need to force the value to be updated before submitting the form, but the rest + // of the state can catch up later. + this.$autocompleteInput.value = value + + if (this.$form.requestSubmit) { + this.$form.requestSubmit() + } else { + // Fallback for certain Grade C browsers that don't support `requestSubmit` + this.$form.submit() + } + } + } + + // Sanitises a result coming back from the source to prevent XSS issues if the result happens to + // contain HTML. + sanitizeResult (value) { + const scratch = document.createElement('div') + scratch.textContent = value + return scratch.innerHTML + } + } + + Modules.GemSearchWithAutocomplete = GemSearchWithAutocomplete +})(window.GOVUK.Modules) diff --git a/app/assets/stylesheets/govuk_publishing_components/components/_search-with-autocomplete.scss b/app/assets/stylesheets/govuk_publishing_components/components/_search-with-autocomplete.scss new file mode 100644 index 0000000000..050c63afa9 --- /dev/null +++ b/app/assets/stylesheets/govuk_publishing_components/components/_search-with-autocomplete.scss @@ -0,0 +1,200 @@ +@import "govuk_publishing_components/individual_component_support"; + +// These styles are adapted from the original Accessible Autocomplete component stylesheet, mostly +// to remove superfluous styles that are already provided by the GOV.UK Design System, and to adapt +// the styling to match the new GOV.UK search box designs (e.g. to remove the zebra striping on +// rows, adjust whitespace, and manage the tweaked markup we use in the suggestion template). +// +// Note that most selectors targetted within this file are those constructed by the Accessible +// Autocomplete component, so they may not 100% match our own component conventions. +// +// see https://github.com/alphagov/accessible-autocomplete/blob/main/src/autocomplete.css + +// Helps to make the autocomplete menu as wide as the entire search box _including_ the submit +// button, not just the width of the input field. +@mixin enhance-autocomplete-menu-width($button-size) { + margin-right: -$button-size; +} + +$input-size: 40px; +$large-input-size: 50px; + +.gem-c-search-with-autocomplete__wrapper { + position: relative; +} + +.gem-c-search-with-autocomplete__menu { + margin: 0; + padding: 0; + overflow-x: hidden; + background-color: govuk-colour("white"); + border: 1px solid $govuk-border-colour; + border-top: 0; + + @include enhance-autocomplete-menu-width($input-size); +} + +.gem-c-search-with-autocomplete__menu--visible { + display: block; +} + +.gem-c-search-with-autocomplete__menu--hidden { + display: none; +} + +.gem-c-search-with-autocomplete__menu--inline { + position: relative; +} + +.gem-c-search-with-autocomplete__option { + display: block; + cursor: pointer; + + @include govuk-font(19); + + // Ensure only the option itself receives pointer events + & > * { + pointer-events: none; + } + + // Accessible Autocomplete's iOS screenreader inset has broken CSS which hasn't been fixed + // upstream, and means that its text is not just visible to screenreader users, but displayed + // for everyone. This span is added dynamically only on iOS and not given a class, so we need to + // target it in a roundabout way and make it invisible to non-screenreader users. + & > span { + clip: rect(0 0 0 0); + clip-path: inset(50%); + height: 1px; + overflow: hidden; + position: absolute; + white-space: nowrap; + width: 1px; + } +} + +// Common styling for _all_ focus states, including keyboard focus, mouse hover, and keyboard focus +// but mouse on another option. +.gem-c-search-with-autocomplete__option--focused, +.gem-c-search-with-autocomplete__option:hover, +.gem-c-search-with-autocomplete__option:focus-visible { + background-color: govuk-colour("light-grey"); + outline: none; + + @include govuk-link-decoration; + @include govuk-link-hover-decoration; + + .gem-c-search-with-autocomplete__suggestion-icon { + background-color: $govuk-text-colour; + } +} + +// Styling specifically _only_ for keyboard focus +.gem-c-search-with-autocomplete__option:focus-visible { + .gem-c-search-with-autocomplete__suggestion-text { + background-color: $govuk-focus-colour; + } +} + +.gem-c-search-with-autocomplete__option-wrapper { + display: flex; + align-items: center; + margin: 0 govuk-spacing(3); + padding: govuk-spacing(1) 0; + border-bottom: 1px solid govuk-colour("mid-grey"); +} + +.gem-c-search-with-autocomplete__option:last-child .gem-c-search-with-autocomplete__option-wrapper { + border-bottom: 0; +} + +.gem-c-search-with-autocomplete__suggestion-icon { + width: calc($input-size / 2); + height: $input-size; + margin-right: govuk-spacing(2); + flex: none; + mask-image: url("govuk_publishing_components/icon-autocomplete-search-suggestion.svg"); + -webkit-mask-image: url("govuk_publishing_components/icon-autocomplete-search-suggestion.svg"); + background-color: $govuk-secondary-text-colour; +} + +.gem-c-search-with-autocomplete__suggestion-text { + font-weight: bold; +} + +.gem-c-search-with-autocomplete__suggestion-highlight { + font-weight: normal; + background: none; +} + +// Tweak the look and feel for the autocomplete in large mode +.gem-c-search-with-autocomplete.gem-c-search-with-autocomplete--large { + .gem-c-search-with-autocomplete__menu { + @include enhance-autocomplete-menu-width($large-input-size); + } + + .gem-c-search-with-autocomplete__option { + min-height: $large-input-size; + } +} + +// Fix top border styling on "borderless" search input when rendered on a GOV.UK blue background +.gem-c-search-with-autocomplete.gem-c-search-with-autocomplete--on-govuk-blue { + .gem-c-search-with-autocomplete__menu { + border-top: 1px solid $govuk-border-colour; + } +} + +// High contrast mode adjustments +@media (forced-colors: active) { + .gem-c-search-with-autocomplete__menu { + border-color: FieldText; + } + + .gem-c-search-with-autocomplete__option { + forced-color-adjust: none; // opt out of all default forced-colors adjustments + background-color: Field; + color: FieldText; + } + + .gem-c-search-with-autocomplete__option--focused, + .gem-c-search-with-autocomplete__option:hover, + .gem-c-search-with-autocomplete__option:focus-visible { + background-color: Highlight; + color: HighlightText; + border-color: FieldText; + + .gem-c-search-with-autocomplete__suggestion-text { + background: none; + } + + .gem-c-search-with-autocomplete__suggestion-highlight { + color: HighlightText; + } + + .gem-c-search-with-autocomplete__suggestion-icon { + background-color: HighlightText; + } + } + + // Allow mouse hover styling to take precedence over keyboard focus styling + .gem-c-search-with-autocomplete__option:focus-visible:not(:hover) { + background-color: SelectedItem; + color: SelectedItemText; + + .gem-c-search-with-autocomplete__suggestion-highlight { + color: SelectedItemText; + } + + .gem-c-search-with-autocomplete__suggestion-icon { + background-color: SelectedItemText; + } + } + + .gem-c-search-with-autocomplete__suggestion-highlight { + color: FieldText; + } + + .gem-c-search-with-autocomplete__suggestion-icon { + background-color: FieldText; + } +} diff --git a/app/views/govuk_publishing_components/components/_search.html.erb b/app/views/govuk_publishing_components/components/_search.html.erb index fc5721c766..14f92e30c6 100644 --- a/app/views/govuk_publishing_components/components/_search.html.erb +++ b/app/views/govuk_publishing_components/components/_search.html.erb @@ -61,20 +61,22 @@ <%= tag_label %> <% end %>
- <%= tag.input( - aria: { - controls: aria_controls, - }, - enterkeyhint: "search", - class: "gem-c-search__item gem-c-search__input js-class-toggle", - id: id, - name: name, - title: t("components.search_box.input_title"), - type: "search", - value: value, - autocorrect: correction_value, - autocapitalize: correction_value, - ) %> +
+ <%= tag.input( + aria: { + controls: aria_controls, + }, + enterkeyhint: "search", + class: "gem-c-search__item gem-c-search__input js-class-toggle", + id: id, + name: name, + title: t("components.search_box.input_title"), + type: "search", + value: value, + autocorrect: correction_value, + autocapitalize: correction_value, + ) %> +
<%= tag.button class: "gem-c-search__submit", type: "submit", data: data_attributes, enterkeyhint: "search" do %> <%= button_text %> diff --git a/app/views/govuk_publishing_components/components/_search_with_autocomplete.html.erb b/app/views/govuk_publishing_components/components/_search_with_autocomplete.html.erb new file mode 100644 index 0000000000..69323a8d24 --- /dev/null +++ b/app/views/govuk_publishing_components/components/_search_with_autocomplete.html.erb @@ -0,0 +1,27 @@ +<% + add_gem_component_stylesheet("search-with-autocomplete") + + source_url = local_assigns[:source_url] + source_key = local_assigns[:source_key] + + if source_url.nil? || source_key.nil? + raise ArgumentError, "The search_with_autocomplete component requires source_url and source_key" + end + + search_component_options = local_assigns.except(:autocomplete, :source_url, :source_key).merge( + # The `search` component has an inline label by default, but this conflicts with the accessible- + # autocomplete component's markup and styling. Every potential use of this component is in + # situations where we want the label not to be inline anyway, so we override the default here. + inline_label: false + ) + + classes = %w[gem-c-search-with-autocomplete] + classes << "gem-c-search-with-autocomplete--large" if local_assigns[:size] == "large" + classes << "gem-c-search-with-autocomplete--on-govuk-blue" if local_assigns[:on_govuk_blue] +%> +<%= tag.div( + class: classes.join(" "), + data: { module: "gem-search-with-autocomplete", source_url:, source_key: } +) do %> + <%= render "govuk_publishing_components/components/search", search_component_options %> +<% end %> diff --git a/app/views/govuk_publishing_components/components/docs/search_with_autocomplete.yml b/app/views/govuk_publishing_components/components/docs/search_with_autocomplete.yml new file mode 100644 index 0000000000..1ea6aeec51 --- /dev/null +++ b/app/views/govuk_publishing_components/components/docs/search_with_autocomplete.yml @@ -0,0 +1,61 @@ +name: Search with autocomplete (experimental) +description: | + A version of the search component enhanced with the ability to fetch and display search + suggestions from a remote source as a user types. +body: | + This component uses [Accessible Autocomplete](https://github.com/alphagov/accessible-autocomplete) + to enhance the [`search` component's](/component-guide/search) input element. + If the user does not have JavaScript enabled, the search component will function as normal. + + The Accessible Autocomplete component generates its own input field (rather than working on the + existing one). We then remove the old input field from the DOM, and enhance the component to: + + * give it the correct attributes and classes from the original input field + * fetch suggestions from a remote URL as the user types + * highlight parts of suggestions where they match the user's input + * submit the form the component is contained in when a suggestion is selected + + The component will fetch results from the provided `source_url`, which should always return a JSON + response with a single object at the root, which has a property `source_key` containing an array + of strings. The component will then display these strings as suggestions to the user. + + Note that the inline label on the `search` component conflicts with the markup and styling + generated internally by Accessible Autocomplete. Our current designs do not foresee us using + autocomplete on a search box with an inline label, and this component will always force the + `inline_label` option on its nested `search` component to be `false`. + + Note that this component has undergone a DAC audit in September 2024, but should be considered + experimental until it has been AB tested on GOV.UK. +accessibility_criteria: | + This component should meet the accessibility acceptance criteria outlined in the [nested search + component](/component-guide/search#accessibility-acceptance-criteria), as well as those of the + external [Accessible Autocomplete + Component](https://github.com/alphagov/accessible-autocomplete/blob/master/accessibility-criteria.md) + project. +examples: + default: + data: + source_url: 'https://www.gov.uk/api/search.json?suggest=autocomplete' + source_key: suggested_autocomplete + set_input_value: + data: + source_url: 'https://www.gov.uk/api/search.json?suggest=autocomplete' + source_key: suggested_autocomplete + value: "driving licence" + homepage: + description: For use on the homepage. + data: + source_url: 'https://www.gov.uk/api/search.json?suggest=autocomplete' + source_key: suggested_autocomplete + label_text: "Search" + on_govuk_blue: true + label_size: "s" + homepage: true + size: "large" + context: + dark_background: true + complex_custom_label: + data: + source_url: 'https://www.gov.uk/api/search.json?suggest=autocomplete' + source_key: suggested_autocomplete + label_text:

Search GOV.UK

diff --git a/package.json b/package.json index feb120b3c8..c40d70ae13 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ } }, "dependencies": { + "accessible-autocomplete": "^3.0.0", "axe-core": "^4.10.0", "govuk-frontend": "5.5.0", "govuk-single-consent": "^3.0.9", diff --git a/spec/components/search_with_autocomplete_spec.rb b/spec/components/search_with_autocomplete_spec.rb new file mode 100644 index 0000000000..998185ec66 --- /dev/null +++ b/spec/components/search_with_autocomplete_spec.rb @@ -0,0 +1,52 @@ +require "rails_helper" + +describe "Search with autocomplete", type: :view do + def component_name + "search_with_autocomplete" + end + + it "requires source_url parameter to be set" do + expect { render_component({ source_key: "foo" }) }.to raise_error( + /requires source_url and source_key/, + ) + end + + it "requires source_key parameter to be set" do + expect { render_component({ source_url: "foo" }) }.to raise_error( + /requires source_url and source_key/, + ) + end + + it "renders the search component within itself" do + render_component({ + source_url: "http://example.org/api/autocomplete", + source_key: "suggestions", + }) + assert_select ".gem-c-search-with-autocomplete .gem-c-search" + end + + it "passes on options to the search component" do + render_component({ + source_url: "http://example.org/api/autocomplete", + source_key: "suggestions", + on_govuk_blue: true, + name: "custom_field_name", + button_text: "Some test text", + }) + + assert_select ".gem-c-search.gem-c-search--on-govuk-blue" + assert_select ".gem-c-search input[name='custom_field_name']" + assert_select ".gem-c-search button", text: "Some test text" + end + + it "can render in large and govuk-blue variants" do + render_component({ + source_url: "http://example.org/api/autocomplete", + source_key: "suggestions", + on_govuk_blue: true, + size: "large", + }) + + assert_select ".gem-c-search.gem-c-search--on-govuk-blue.gem-c-search--large" + end +end diff --git a/spec/javascripts/components/search-with-autocomplete-spec.js b/spec/javascripts/components/search-with-autocomplete-spec.js new file mode 100644 index 0000000000..0de155b9a6 --- /dev/null +++ b/spec/javascripts/components/search-with-autocomplete-spec.js @@ -0,0 +1,218 @@ +/* eslint-env jasmine */ +/* global GOVUK, Event, FormData */ + +describe('Search with autocomplete component', () => { + let autocomplete, fixture + + const loadAutocompleteComponent = (markup) => { + fixture = document.createElement('div') + document.body.appendChild(fixture) + fixture.innerHTML = markup + autocomplete = new GOVUK.Modules.GemSearchWithAutocomplete(fixture.querySelector('.gem-c-search-with-autocomplete')) + } + + const html = ` +
+
+ +
+
+ ` + const performInput = (input, value, onDone) => { + input.value = value + input.dispatchEvent(new Event('input')) + + // "Tick the clock" and yield compute time to the autocomplete component so it can do its work + // and potentially update the DOM. We could use a mutation observer for this, but that would + // only work if there are any results (as there would be no updates if there are no results). + setTimeout(onDone, 1) + } + + const expectMenuToBeShownWithOptions = (options) => { + const menu = fixture.querySelector('.gem-c-search-with-autocomplete__menu') + const results = [...menu.querySelectorAll('.gem-c-search-with-autocomplete__option')].map( + (r) => r.textContent.trim() + ) + expect(menu.classList).toContain('gem-c-search-with-autocomplete__menu--visible') + expect(results).toEqual(options) + } + + const expectMenuNotToBeShown = () => { + const menu = fixture.querySelector('.gem-c-search-with-autocomplete__menu') + expect(menu.classList).not.toContain('gem-c-search-with-autocomplete__menu--visible') + } + + const stubSuccessfulFetch = (suggestions) => { + spyOn(window, 'fetch').and.returnValue(Promise.resolve({ + json: () => Promise.resolve({ suggestions }) + })) + } + + const stubLocalErrorFetch = () => { + spyOn(window, 'fetch').and.returnValue(Promise.reject(new Error('Network error'))) + } + + const stubServerErrorFetch = () => { + spyOn(window, 'fetch').and.returnValue(Promise.resolve({ + ok: false, + status: 500, + json: () => Promise.resolve({ error: 'Internal server error' }) + })) + } + + beforeEach(() => { + loadAutocompleteComponent(html) + autocomplete.init() + }) + + afterEach(() => { + fixture.remove() + }) + + it('recreates the input exactly', () => { + const input = fixture.querySelector('input') + + expect(input.getAttribute('name')).toEqual('q') + expect(input.getAttribute('id')).toEqual('search-main-7b87262d') + expect(input.getAttribute('type')).toEqual('search') + expect(input.value).toEqual("i've been looking for freedom") + }) + + it('fetches data from the correct source', (done) => { + const input = fixture.querySelector('input') + stubSuccessfulFetch(['foo']) + + performInput(input, 'test query', (results) => { + const expectedUrl = new URL( + 'https://www.example.org/api/autocomplete.json?foo=bar&q=test+query' + ) + expect(window.fetch).toHaveBeenCalledWith( + expectedUrl, { headers: { Accept: 'application/json' } } + ) + + done() + }) + }) + + it('handles empty results coming back from source', (done) => { + const input = fixture.querySelector('input') + stubSuccessfulFetch([]) + + performInput(input, 'test query', () => { + expectMenuNotToBeShown() + + done() + }) + }) + + it('handles a local error during fetch', (done) => { + const input = fixture.querySelector('input') + stubLocalErrorFetch() + + performInput(input, 'test query', () => { + expectMenuNotToBeShown() + + done() + }) + }) + + it('handles a server error during fetch', (done) => { + const input = fixture.querySelector('input') + stubServerErrorFetch() + + performInput(input, 'test query', () => { + expectMenuNotToBeShown() + + done() + }) + }) + + it('populates the autocomplete with the expected options given the source response', (done) => { + const input = fixture.querySelector('input') + stubSuccessfulFetch(['foo', 'bar', 'baz']) + + performInput(input, 'test query', () => { + expectMenuToBeShownWithOptions(['foo', 'bar', 'baz']) + + done() + }) + }) + + it('highlights the matched part of the suggestion text', (done) => { + const input = fixture.querySelector('input') + stubSuccessfulFetch(['foo bar baz']) + + performInput(input, 'bar', () => { + const suggestionText = fixture.querySelector('.gem-c-search-with-autocomplete__suggestion-text').innerHTML + expect(suggestionText).toEqual('foo bar baz') + + done() + }) + }) + + it('sanitizes potential garbled results from the source', (done) => { + const input = fixture.querySelector('input') + stubSuccessfulFetch(['&']) + + performInput(input, '1999', () => { + const suggestionText = fixture.querySelector('.gem-c-search-with-autocomplete__suggestion-text').innerHTML + expect(suggestionText).toEqual('<blink>&</blink>') + + done() + }) + }) + + it('submits the containing form when a suggestion is confirmed', (done) => { + const form = fixture.querySelector('form') + const input = fixture.querySelector('input') + const submitSpy = spyOn(form, 'requestSubmit') + + stubSuccessfulFetch(['foo']) + performInput(input, 'test query', () => { + const firstOption = fixture.querySelector('.gem-c-search-with-autocomplete__option') + firstOption.click() + + expect(submitSpy).toHaveBeenCalled() + done() + }) + }) + + it('ensures that the form is submitted with the right value in the onConfirm callback', () => { + const form = fixture.querySelector('form') + const submitSpy = spyOn(form, 'requestSubmit') + + autocomplete.submitContainingForm('updated value') + + const formData = new FormData(form) + expect(formData.get('q')).toEqual('updated value') + expect(submitSpy).toHaveBeenCalled() + }) +}) diff --git a/spec/lib/govuk_publishing_components/app_helpers/asset_helper_spec.rb b/spec/lib/govuk_publishing_components/app_helpers/asset_helper_spec.rb index bd091548ee..3b5fd776bb 100644 --- a/spec/lib/govuk_publishing_components/app_helpers/asset_helper_spec.rb +++ b/spec/lib/govuk_publishing_components/app_helpers/asset_helper_spec.rb @@ -19,7 +19,7 @@ def request end it "detect the total number of stylesheet paths" do - expect(get_component_css_paths.count).to eql(78) + expect(get_component_css_paths.count).to eql(79) end it "initialize empty asset helper" do diff --git a/yarn.lock b/yarn.lock index f93b00d572..550a09f05f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -276,6 +276,11 @@ accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" +accessible-autocomplete@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/accessible-autocomplete/-/accessible-autocomplete-3.0.0.tgz#f66ed03fb22d78f721326d187ee491dddbadec75" + integrity sha512-Kpm6EX+jjD0AurWfzSP4EVLEKsLUWCazZwidjum+8FCRtSINeaPzVa3ElKVGWvSqVZN9zjeSBF8cirhYEZjW1A== + acorn-jsx@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b"