From d52aa4f20ebf79e93c647c46398e9b52f44608ec Mon Sep 17 00:00:00 2001 From: Joeli Pokkinen Date: Tue, 14 Apr 2026 15:02:10 +0300 Subject: [PATCH 01/11] Screen reader and keybord usable clear search button for vocab search --- resource/js/vocab-search.js | 10 +++++++++- tests/cypress/template/vocab-search-bar.cy.js | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/resource/js/vocab-search.js b/resource/js/vocab-search.js index ca3a15336..4a2ccfb9d 100644 --- a/resource/js/vocab-search.js +++ b/resource/js/vocab-search.js @@ -32,6 +32,9 @@ function startVocabSearchApp () { }, searchAriaMessage () { return $t('Search') + }, + clearSearchButtonAriaMessage () { + return $t('Clear search field') } }, mounted () { @@ -232,6 +235,10 @@ function startVocabSearchApp () { this.searchTerm = '' this.renderedResultsList = [] this.hideAutoComplete() + + this.$nextTick(() => { + this.$refs.searchInputField.focus() + }) }, /* * Show the existing autocomplete list if it was hidden by onClickOutside() @@ -271,6 +278,7 @@ function startVocabSearchApp () { - - diff --git a/resource/js/vocab-search.js b/resource/js/vocab-search.js index d7079841e..9c5ef7421 100644 --- a/resource/js/vocab-search.js +++ b/resource/js/vocab-search.js @@ -16,7 +16,7 @@ function startVocabSearchApp () { }, computed: { searchPlaceholder () { - return $t('Search...') + return $t('Search') }, anyLanguages () { return $t('Any language') @@ -27,13 +27,13 @@ function startVocabSearchApp () { selectSearchLanguageAriaMessage () { return $t('Select search language') }, - textInputWithDropdownButtonAriaMessage () { - return $t('Text input with dropdown button') + searchFieldAriaMessage () { + return $t('Search text field') }, - searchAriaMessage () { + searchButtonAriaMessage () { return $t('Search') }, - clearSearchButtonAriaMessage () { + clearSearchAriaMessage () { return $t('Clear search field') } }, @@ -283,7 +283,7 @@ function startVocabSearchApp () { id="search-field" autocomplete="off" data-bs-toggle="" - :aria-label="textInputWithDropdownButtonAriaMessage" + :aria-label="searchFieldAriaMessage" :placeholder="searchPlaceholder" v-click-outside="hideAutoComplete" v-model="searchTerm" @@ -375,16 +375,15 @@ function startVocabSearchApp () { - - diff --git a/tests/cypress/template/global-search-bar.cy.js b/tests/cypress/template/global-search-bar.cy.js index e4e717837..a5bf28b1b 100644 --- a/tests/cypress/template/global-search-bar.cy.js +++ b/tests/cypress/template/global-search-bar.cy.js @@ -8,8 +8,8 @@ describe('Global search bar', () => { cy.get('#vocab-list li').should('have.length', 14) }) - it('Dropdown menu header text is updated according to the selected vocabularies', () => { - cy.get('#vocab-selector .vocab-dropdown-btn').should('contain.text', '1. Valitse sanasto') + it('dropdown menu header text is updated according to the selected vocabularies', () => { + cy.get('#vocab-selector .vocab-dropdown-btn').should('contain.text', 'Valitse sanasto') // select "altlabel" cy.get('#vocab-list').contains('label', 'altlabel').find('input[type="checkbox"]').check({ force: true }) cy.get('#vocab-selector .vocab-dropdown-btn').should('contain.text', 'altlabel') @@ -26,13 +26,12 @@ describe('Global search bar', () => { it('Dropdown menu header text returns to original hint if no vocabularies are selected', () => { cy.get('#vocab-list li').eq(1).find('input[type="checkbox"]').check({ force: true }) cy.get('#vocab-list li').eq(1).find('input[type="checkbox"]').uncheck({ force: true }) - cy.get('#vocab-selector .vocab-dropdown-btn').should('contain.text', '1. Valitse sanasto') + cy.get('#vocab-selector .vocab-dropdown-btn').should('contain.text', 'Valitse sanasto') }) - it('Changing the search language changes the language selector dropdown header text', () => { - cy.get('#global-search-toggle').click() - cy.get('#language-selector .dropdown-toggle').should('contain.text', '2. Valitse kieli') - cy.get('#language-selector .dropdown-toggle').click() + it('changing the search language changes the language selector dropdown header text', () => { + + cy.get('#language-selector .dropdown-toggle').should('contain.text', 'Valitse kieli') cy.get('#language-list').should('be.visible') @@ -47,12 +46,8 @@ describe('Global search bar', () => { it('Selecting "all languages" does not change content language', () => { - cy.get('#global-search-toggle').click() - cy.get('#language-selector .dropdown-toggle').should('contain.text', '2. Valitse kieli') - cy.get('#language-selector .dropdown-toggle').click() - cy.get('#language-list').should('be.visible') - - cy.get('#language-list li').contains('label', 'englanti').click() + cy.get('#language-selector .dropdown-toggle').should('contain.text', 'Valitse kieli') + cy.get('#language-list li label').find('input[type="radio"][value="en"]').check({ force: true }) cy.url().should('include', 'clang=en') cy.get('#language-selector .dropdown-toggle').click() @@ -301,4 +296,69 @@ describe('Global search bar', () => { cy.get('#language-selector .dropdown-toggle').should('contain.text', 'englanti') }); }) + describe('Translations', () => { + it('Global search bar has correct translations', () => { + + cy.visit('/en/') + + cy.get('#global-search-toggle').click(); + cy.get('#search-wrapper').should('exist'); + + // Check that vocabulary selector has correct place holder text + cy.get('#vocab-selector button').should('have.text', 'Choose vocabulary') + // Check that vocabulary selector has correct Aria label + cy.get('#vocab-selector button').should('have.attr', 'aria-label', 'Select search vocabularies') + // Check that search language selector has correct place holder text + cy.get('#language-selector button').should('have.text', 'Choose language') + // Check that search language selector has correct Aria label + cy.get('#language-selector button').should('have.attr', 'aria-label', 'Select search language') + // Check that search field has correct Aria label + cy.get('#search-field').should('have.attr', 'aria-label', 'Search') + // Check that search field has correct placeholder + cy.get('#search-field').should('have.attr', 'placeholder', 'Enter search term') + // Check that search field has correct aria-label + cy.get('#search-button').should('have.attr', 'aria-label', 'Search') + // Check that search language list has correctly translated text for anylang selector + cy.get('#language-list li').contains('label', 'Any language') + // Check that search results have correct message when no results were found + cy.get('#search-field').type('Ei tuloksia') + cy.get('#search-autocomplete-results').within(() => { + cy.get('li').eq(0).invoke('text').should('contain', 'No results') + }) + // the clear search button should have an aria label + cy.get('#clear-button').should('have.attr', 'aria-label', 'Clear search field') + + + // go to YSO vocab front page in Finnish + cy.visit('/fi/') + + cy.get('#global-search-toggle').click(); + cy.get('#search-wrapper').should('exist'); + + // Check that vocabulary selector has correct place holder text + cy.get('#vocab-selector button').should('have.text', 'Valitse sanasto') + // Check that vocabulary selector has correct Aria label + cy.get('#vocab-selector button').should('have.attr', 'aria-label', 'Valitse haun kohdesanastot') + // Check that search language selector has correct place holder text + cy.get('#language-selector button').should('have.text', 'Valitse kieli') + // Check that search language selector has correct Aria label + cy.get('#language-selector button').should('have.attr', 'aria-label', 'Valitse hakukieli') + // Check that search field has correct Aria label + cy.get('#search-field').should('have.attr', 'aria-label', 'Hae') + // Check that search field has correct placeholder + cy.get('#search-field').should('have.attr', 'placeholder', 'Syötä haettava termi') + // Check that search field has correct aria-label + cy.get('#search-button').should('have.attr', 'aria-label', 'Hae') + // Check that search language list has correctly translated text for anylang selector + cy.get('#language-list li').contains('label', 'kaikilla kielillä') + // Check that search results have correct message when no results were found + cy.get('#search-field').type('Ei tuloksia') + cy.get('#search-autocomplete-results').within(() => { + cy.get('li').eq(0).invoke('text').should('contain', 'Ei tuloksia') + }) + // the clear search button should have an aria label + cy.get('#clear-button').should('have.attr', 'aria-label', 'Tyhjennä hakukenttä') + + }); + }) }) From 3667537eaa26d1e1a2e3e8d76181e928d4713aba Mon Sep 17 00:00:00 2001 From: Joeli Pokkinen Date: Thu, 16 Apr 2026 15:46:23 +0300 Subject: [PATCH 06/11] Update vocab search placeholder text --- resource/js/vocab-search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resource/js/vocab-search.js b/resource/js/vocab-search.js index 9c5ef7421..212150d4b 100644 --- a/resource/js/vocab-search.js +++ b/resource/js/vocab-search.js @@ -16,7 +16,7 @@ function startVocabSearchApp () { }, computed: { searchPlaceholder () { - return $t('Search') + return $t('Search in this vocabulary') }, anyLanguages () { return $t('Any language') From 445791c4a0e1ec5821f59b2fb9ca6f46696b9983 Mon Sep 17 00:00:00 2001 From: Joeli Pokkinen Date: Thu, 16 Apr 2026 15:46:56 +0300 Subject: [PATCH 07/11] Update translation messages --- resource/translations/messages.en.json | 93 ++++++++++++++------------ resource/translations/messages.fi.json | 2 +- 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/resource/translations/messages.en.json b/resource/translations/messages.en.json index a377cf6ec..28ce97e05 100644 --- a/resource/translations/messages.en.json +++ b/resource/translations/messages.en.json @@ -126,62 +126,69 @@ "wgs84:long": "Longitude", "wgs84:long_help": "Longitude in decimal degrees according to WGS 84 system.", "zxx-x-taxon": "Scientific name", - "Loading more items": "Loading more items", - "Go to the concept page": "Go to the concept page", - "Open": "Open", "1. Choose vocabulary": "1. Choose vocabulary", "2. Choose language": "2. Choose language", "3. Enter search term": "3. Enter search term", - "Any language": "Any language", - "No results": "No results", - "Select search language": "Select search language", - "Text input with dropdown button": "Text input with dropdown button", - "Search": "Search", + "404 Error: The page %requested_page% cannot be found.": "404 Error: The page %requested_page% cannot be found.", + "About": "About", + "Adding an empty twig file will remove this message.": "Adding an empty twig file will remove this message.", "All %d results displayed": "All %d results displayed", - "Resource counts by type": "Resource counts by type", - "Type": "Type", - "Count": "Count", - "Deprecated concept": "Deprecated concept", - "show all # values": "show all # values", - "Term counts by language": "Term counts by language", - "Preferred terms": "Preferred terms", "Alternate terms": "Alternate terms", - "Hidden terms": "Hidden terms", - "Search...": "Search...", - "About": "About", - "%search_count% results for '%term%'": "%search_count% results for '%term%'", - "This concept has been deprecated.": "This concept has been deprecated.", - "See": "See", + "Any language": "Any language", "Breadcrumbs": "Breadcrumbs", + "Browse concepts": "Browse concepts", + "Choose alphabetical listing letter": "Choose alphabetical listing letter", + "Choose language": "Choose language", + "Choose vocabulary": "Choose vocabulary", + "Clear search field": "Clear search field", + "Concepts loaded for letter %letter%": "Concepts loaded for letter %letter%" + "Concept %term% in vocabulary %vocab%": "Concept %term% in vocabulary %vocab%", + "Contact us!": "Contact us!", "Copy to clipboard": "Copy to clipboard", - "Truncated (too many items in list)": "Truncated (too many items in list)", + "Count": "Count", + "Deprecated concept": "Deprecated concept", "Download this concept": "Download this concept", + "E-mail": "E-mail", + "Enter search term": "Enter search term", + "Enter your e-mail address": "Enter your e-mail address", + "Enter your name": "Enter your name", "Error": "Error", - "404 Error: The page %requested_page% cannot be found.": "404 Error: The page %requested_page% cannot be found.", - "Sidebar listing: list and traverse vocabulary contents by a criterion": "Sidebar listing: list and traverse vocabulary contents by a criterion", - "More information about this term": "More information about this term", - "Concept %term% in vocabulary %vocab%": "Concept %term% in vocabulary %vocab%", - "To customize what is shown here, add one or more .twig template files under the %slotPath% directory.": "To customize what is shown here, add one or more .twig template files under the %slotPath% directory.", - "Adding an empty twig file will remove this message.": "Adding an empty twig file will remove this message.", - "Skosmos version %version%": "Skosmos version %version%", - "The search provided no results.": "The search provided no results.", "Feedback": "Feedback", "Feedback has been sent!": "Feedback has been sent!", - "Contact us!": "Contact us!", - "Vocabulary": "Vocabulary", - "Not to a specific vocabulary": "Not to a specific vocabulary", + "Go to the concept page": "Go to the concept page", + "Hidden terms": "Hidden terms", + "Hide concepts": "Hide concepts", + "Loading more items": "Loading more items", + "Message": "Message", + "More information about this term": "More information about this term", "Name": "Name", - "Enter your name": "Enter your name", - "E-mail": "E-mail", - "Enter your e-mail address": "Enter your e-mail address", + "No results": "No results", + "Not to a specific vocabulary": "Not to a specific vocabulary", + "Open": "Open", + "Preferred terms": "Preferred terms", + "Resource counts by type": "Resource counts by type", + "%search_count% results for '%term%'": "%search_count% results for '%term%'", + "Search in this vocabulary": "Search in this vocabulary", + "Search": "Search", + "Search...": "Search...", + "Search text field": "Search text field", + "See": "See", + "Select search language": "Select search language", + "Select search vocabularies": "Select search vocabularies", + "Send feedback": "Send feedback", + "show all # values": "show all # values", + "Sidebar listing: list and traverse vocabulary contents by a criterion": "Sidebar listing: list and traverse vocabulary contents by a criterion", + "Skosmos version %version%": "Skosmos version %version%", "Subject": "Subject", - "Write a subject": "Write a subject", - "Message": "Message", + "Term counts by language": "Term counts by language", + "Text input with dropdown button": "Text input with dropdown button", + "The search provided no results.": "The search provided no results.", + "This concept has been deprecated.": "This concept has been deprecated.", + "To customize what is shown here, add one or more .twig template files under the %slotPath% directory.": "To customize what is shown here, add one or more .twig template files under the %slotPath% directory.", + "Truncated (too many items in list)": "Truncated (too many items in list)", + "Type": "Type", "Value is required and can not be empty": "Value is required and can not be empty", - "Send feedback": "Send feedback", + "Vocabulary": "Vocabulary", "Warning!": "Warning!", - "Choose alphabetical listing letter": "Choose alphabetical listing letter", - "Browse concepts": "Browse concepts", - "Hide concepts": "Hide concepts", - "Concepts loaded for letter %letter%": "Concepts loaded for letter %letter%" + "Write a subject": "Write a subject" } diff --git a/resource/translations/messages.fi.json b/resource/translations/messages.fi.json index 7391ae5e3..0961c9ec2 100644 --- a/resource/translations/messages.fi.json +++ b/resource/translations/messages.fi.json @@ -236,4 +236,4 @@ "wgs84:long": "Pituusaste", "wgs84:long_help": "Pituusaste WGS 84 -j\u00e4rjestelm\u00e4n mukaan desimaaliasteina.", "zxx-x-taxon": "Tieteellinen nimi" -} \ No newline at end of file +} From b3243b4a005c440f09b75073d03a8b5af76066a3 Mon Sep 17 00:00:00 2001 From: Joeli Pokkinen Date: Thu, 16 Apr 2026 16:30:30 +0300 Subject: [PATCH 08/11] Fix global search cypress test indentation & get rid of semicolons --- .../cypress/template/global-search-bar.cy.js | 343 +++++++++--------- 1 file changed, 175 insertions(+), 168 deletions(-) diff --git a/tests/cypress/template/global-search-bar.cy.js b/tests/cypress/template/global-search-bar.cy.js index a5bf28b1b..3330a776d 100644 --- a/tests/cypress/template/global-search-bar.cy.js +++ b/tests/cypress/template/global-search-bar.cy.js @@ -2,6 +2,7 @@ describe('Global search bar', () => { beforeEach(() => { cy.visit('/fi/') cy.get('#search-wrapper').should('exist') + cy.get('#global-search-toggle').click() }) it('Vocab-list has 14 vocabularies', () => { @@ -32,7 +33,7 @@ describe('Global search bar', () => { it('changing the search language changes the language selector dropdown header text', () => { cy.get('#language-selector .dropdown-toggle').should('contain.text', 'Valitse kieli') - + cy.get('#language-selector .dropdown-toggle').click() cy.get('#language-list').should('be.visible') cy.get('#language-list li').contains('label', 'englanti').click() @@ -56,15 +57,14 @@ describe('Global search bar', () => { cy.url().should('include', 'clang=en') }) - it('Dropdown search results are displayed for the selected vocabulary and search language', () => { + it('Dropdown search results are displayed for the selected vocabulary and search language', () => { - cy.get('#global-search-toggle').click() cy.get('#vocab-list').contains('label', 'YSO').find('input[type="checkbox"]').check({ force: true }) cy.get('#language-selector .dropdown-toggle').click() cy.get('#language-list li').contains('label', 'suomi').click() - cy.get('#search-field').type('arkeolog'); // even if the search yields no results, there shoulde a single line in the result list - cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible').children().should('have.length.greaterThan', 0); + cy.get('#search-field').type('arkeolog') // even if the search yields no results, there shoulde a single line in the result list + cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible').children().should('have.length.greaterThan', 0) cy.get('#search-autocomplete-results').within(() => { cy.get('li').should('have.length', 5) }) @@ -77,232 +77,239 @@ describe('Global search bar', () => { cy.get('#language-selector .dropdown-toggle').click() cy.get('#language-list li').contains('label', 'ruotsi').click() - cy.get('#search-field').type('kissa'); // even if the search yields no results, there shoulde a single line in the result list - cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible').children().should('have.length.greaterThan', 0); + cy.get('#search-field').type('kissa') // even if the search yields no results, there shoulde a single line in the result list + cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible').children().should('have.length.greaterThan', 0) cy.get('#search-autocomplete-results').within(() => { cy.get('li').eq(0).invoke('text').should('contain', 'Ei tuloksia') // the single result should display a no results message }) }) - it('Clear button should hide the autocomplete list', () => { - // go to YSO vocab front page - cy.visit('/yso/en/') + it('Clear button should hide the autocomplete list', () => { + // go to landing page + cy.visit('/en/') - cy.get('#search-field').type('kas'); - cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible'); // the autocomplete should appear + // open search bar + cy.get('#global-search-toggle').click() - cy.get('#clear-button').should('have.attr', 'aria-label', 'Clear search field'); // the clear search button should have an aria label + cy.get('#search-field').type('kas') + cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible') // the autocomplete should appear - cy.get('#clear-button').click() - cy.get('#search-autocomplete-results').should('not.be.visible'); // the autocomplete should disappear + cy.get('#clear-button').should('have.attr', 'aria-label', 'Clear search field') // the clear search button should have an aria label - // check that the focus is moved to the search field - cy.get('#search-field').should('be.focused') - }) + cy.get('#clear-button').click() + cy.get('#search-autocomplete-results').should('not.be.visible') // the autocomplete should disappear - it('Emptying the text search field hides the autocomplete list', () => { + // check that the focus is moved to the search field + cy.get('#search-field').should('be.focused') + }) - cy.get('#global-search-toggle').click() - cy.get('#search-field').type('kissa'); - cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible'); // the autocomplete should appear + it('Emptying the text search field hides the autocomplete list', () => { - cy.get('#search-field').clear(); - cy.get('#search-autocomplete-results').should('not.be.visible'); // the autocomplete should disappear - }) + cy.get('#search-field').type('kissa') + cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible') // the autocomplete should appear - it('Clicking outside of the autocomplete list hides the autocomplete list', () => { + cy.get('#search-field').clear() + cy.get('#search-autocomplete-results').should('not.be.visible') // the autocomplete should disappear + }) - cy.get('#global-search-toggle').click() - cy.get('#search-field').type('kissa'); - cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible'); // the autocomplete should appear + it('Clicking outside of the autocomplete list hides the autocomplete list', () => { - cy.get('#main-container').click({ force: true }); // using force true to click on elements not considered actionable - cy.get('#search-autocomplete-results').should('not.be.visible'); // the autocomplete should disappear - }) - it('Autocomplete search result list contains concept types', () => { - // go to test vocab - cy.visit('/en/') + cy.get('#search-field').type('kissa') + cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible') // the autocomplete should appear - // open search bar - cy.get('#global-search-toggle').click() + cy.get('#main-container').click({ force: true }) // using force true to click on elements not considered actionable + cy.get('#search-autocomplete-results').should('not.be.visible') // the autocomplete should disappear + }) - // select a vocabulary - cy.contains('#vocab-list li label.vocab-select', 'test-notation-sort').parents('li').find('input[type="checkbox"]').check({ force: true }); + it('Autocomplete search result list contains concept types', () => { + // go to landing page + cy.visit('/en/') - // Choose English from the language dropdown - cy.get('#language-selector .dropdown-toggle').click(); - cy.get('#language-list .dropdown-item').contains('English').click(); + // open search bar + cy.get('#global-search-toggle').click() - // Enter a search term - cy.get('#search-field').type('Barra'); + // select a vocabulary + cy.contains('#vocab-list li label.vocab-select', 'test-notation-sort').parents('li').find('input[type="checkbox"]').check({ force: true }) - // Autocomplete should appear - cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible'); + // Choose English from the language dropdown + cy.get('#language-selector .dropdown-toggle').click() + cy.get('#language-list .dropdown-item').contains('English').click() - // Verify the dropdown should have the concept type literal - cy.get('#search-autocomplete-results').within(() => { - cy.get('li').first().should('contain', 'Test class') - }) + // Enter a search term + cy.get('#search-field').type('Barra') + + // Autocomplete should appear + cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible') + + // Verify the dropdown should have the concept type literal + cy.get('#search-autocomplete-results').within(() => { + cy.get('li').first().should('contain', 'Test class') }) - it('Autocomplete search result list concept types are translated', () => { - // go to landing page - cy.visit('/en/') + }) - // open search bar - cy.get('#global-search-toggle').click() + it('Autocomplete search result list concept types are translated', () => { + // go to landing page + cy.visit('/en/') - // select a vocabulary - cy.contains('#vocab-list li label.vocab-select', 'conceptPropertyLabels').parents('li').find('input[type="checkbox"]').check({ force: true }); + // open search bar + cy.get('#global-search-toggle').click() - // Choose English from the language dropdown - cy.get('#language-selector .dropdown-toggle').click(); - cy.get('#language-list .dropdown-item').contains('English').click(); + // select a vocabulary + cy.contains('#vocab-list li label.vocab-select', 'conceptPropertyLabels').parents('li').find('input[type="checkbox"]').check({ force: true }) - // Enter a search term - cy.get('#search-field').type('Fish'); + // Choose English from the language dropdown + cy.get('#language-selector .dropdown-toggle').click() + cy.get('#language-list .dropdown-item').contains('English').click() - // Autocomplete should appear - cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible'); + // Enter a search term + cy.get('#search-field').type('Fish') - // Verify the dropdown should have the concept type literal - cy.get('#search-autocomplete-results').within(() => { - cy.get('li').first().find('div.col-auto.align-self-end.pr-1').should('have.text', 'Concept') - }) + // Autocomplete should appear + cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible') + + // Verify the dropdown should have the concept type literal + cy.get('#search-autocomplete-results').within(() => { + cy.get('li').first().find('div.col-auto.align-self-end.pr-1').should('have.text', 'Concept') }) - it ('Autocomplete search result links point to concept pages', () => { - // go to test vocab - cy.visit('/en/') + }) - // open search bar - cy.get('#global-search-toggle').click() + it ('Autocomplete search result links point to concept pages', () => { + // go to test vocab + cy.visit('/en/') - // select a vocabulary - cy.contains('#vocab-list li label.vocab-select', 'test-notation-sort').parents('li').find('input[type="checkbox"]').check({ force: true }); + // open search bar + cy.get('#global-search-toggle').click() - // Choose English from the language dropdown - cy.get('#language-selector .dropdown-toggle').click(); - cy.get('#language-list .dropdown-item').contains('English').click(); + // select a vocabulary + cy.contains('#vocab-list li label.vocab-select', 'test-notation-sort').parents('li').find('input[type="checkbox"]').check({ force: true }) - // Enter a search term - cy.get('#search-field').type('Barra'); + // Choose English from the language dropdown + cy.get('#language-selector .dropdown-toggle').click() + cy.get('#language-list .dropdown-item').contains('English').click() - // Autocomplete should appear - cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible'); - cy.get('#search-autocomplete-results').within(() => { - cy.get('li').first().click() - }) + // Enter a search term + cy.get('#search-field').type('Barra') - // Verify the search took us to the concept page - cy.url().should('include', 'uri=http%3A%2F%2Fwww.skosmos.skos%2Ftest%2Fta0116'); + // Autocomplete should appear + cy.get('#search-autocomplete-results', { timeout: 20000 }).should('be.visible') + cy.get('#search-autocomplete-results').within(() => { + cy.get('li').first().click() + }) + // Verify the search took us to the concept page + cy.url().should('include', 'uri=http%3A%2F%2Fwww.skosmos.skos%2Ftest%2Fta0116') + + }) + + describe('Keyboard navigation', () => { + beforeEach(() => { + cy.visit('/fi/') + cy.get('#global-search-toggle').click() + cy.get('#search-wrapper').should('exist') }) - describe('Keyboard navigation', () => { - beforeEach(() => { - cy.visit('/fi/'); - cy.get('#global-search-toggle').click(); - cy.get('#search-wrapper').should('exist'); - }); - const getVocabButton = () => cy.get('#vocab-selector .dropdown-toggle').first(); - const getLangButton = () => cy.get('#language-selector .dropdown-toggle').first(); + const getVocabButton = () => cy.get('#vocab-selector .dropdown-toggle').first() + const getLangButton = () => cy.get('#language-selector .dropdown-toggle').first() - const press = (key) => cy.focused().type(`{${key}}`); + const press = (key) => cy.focused().type(`{${key}}`) - it('Left/Right: navigate between vocab selector and language selector', () => { - getVocabButton().focus().should('be.focused'); + it('Left/Right: navigate between vocab selector and language selector', () => { + getVocabButton().focus().should('be.focused') - press('rightarrow'); - getLangButton().should('be.focused'); + press('rightarrow') + getLangButton().should('be.focused') - press('leftarrow'); - getVocabButton().should('be.focused'); - }); + press('leftarrow') + getVocabButton().should('be.focused') + }) - it('Arrow down opens the vocabulary dropdown when vocab selector is focused', () => { - getVocabButton().focus().should('be.focused'); - press('downarrow'); + it('Arrow down opens the vocabulary dropdown when vocab selector is focused', () => { + getVocabButton().focus().should('be.focused') + press('downarrow') - cy.get('#vocab-selector .dropdown-menu').should('have.class', 'show'); - }); + cy.get('#vocab-selector .dropdown-menu').should('have.class', 'show') + }) - it('Escape closes the vocabulary dropdown', () => { - getVocabButton().focus(); - press('downarrow'); - cy.get('#vocab-selector .dropdown-menu').should('have.class', 'show'); + it('Escape closes the vocabulary dropdown', () => { + getVocabButton().focus() + press('downarrow') + cy.get('#vocab-selector .dropdown-menu').should('have.class', 'show') - cy.focused().type('{esc}'); - cy.get('#vocab-selector .dropdown-menu').should('not.have.class', 'show'); + cy.focused().type('{esc}') + cy.get('#vocab-selector .dropdown-menu').should('not.have.class', 'show') - }); + }) - it('Arrow up on top item closes the vocabulary dropdown', () => { - getVocabButton().focus(); - press('downarrow'); - cy.get('#vocab-selector .dropdown-menu').should('have.class', 'show'); + it('Arrow up on top item closes the vocabulary dropdown', () => { + getVocabButton().focus() + press('downarrow') + cy.get('#vocab-selector .dropdown-menu').should('have.class', 'show') - cy.focused().type('{uparrow}'); - cy.get('#vocab-selector .dropdown-menu').should('not.have.class', 'show'); - }); + cy.focused().type('{uparrow}') + cy.get('#vocab-selector .dropdown-menu').should('not.have.class', 'show') + }) - it('Arrow up / drrow down navigates within vocabulary list', () => { - getVocabButton().focus(); - press('downarrow'); - cy.get('#vocab-selector .dropdown-menu').should('have.class', 'show'); + it('Arrow up / drrow down navigates within vocabulary list', () => { + getVocabButton().focus() + press('downarrow') + cy.get('#vocab-selector .dropdown-menu').should('have.class', 'show') - cy.get('#vocab-list li').first().as('firstItem').get('input').should('be.focused'); + cy.get('#vocab-list li').first().as('firstItem').get('input').should('be.focused') - cy.focused().type('{downarrow}'); - cy.get('#vocab-list li').eq(1).get('input').should('be.focused'); + cy.focused().type('{downarrow}') + cy.get('#vocab-list li').eq(1).get('input').should('be.focused') - cy.focused().type('{downarrow}'); - cy.get('#vocab-list li').eq(2).get('input').should('be.focused'); + cy.focused().type('{downarrow}') + cy.get('#vocab-list li').eq(2).get('input').should('be.focused') - cy.focused().type('{uparrow}'); - cy.get('#vocab-list li').eq(1).get('input').should('be.focused'); - }); + cy.focused().type('{uparrow}') + cy.get('#vocab-list li').eq(1).get('input').should('be.focused') + }) - it('Enter toggles a vocabulary in the dropdown', () => { - getVocabButton().focus(); - press('downarrow'); - cy.get('#vocab-selector .dropdown-menu').should('have.class', 'show'); + it('Enter toggles a vocabulary in the dropdown', () => { + getVocabButton().focus() + press('downarrow') + cy.get('#vocab-selector .dropdown-menu').should('have.class', 'show') - cy.get('#vocab-list li').eq(1).focus().should('be.focused'); - cy.focused().type('{enter}'); + cy.get('#vocab-list li').eq(1).focus().should('be.focused') + cy.focused().type('{enter}') - cy.get('#vocab-list li').eq(1).get('input').should('be.checked'); - }); + cy.get('#vocab-list li').eq(1).get('input').should('be.checked') + }) - it('Arrow down opens the language dropdown when language selector is focused', () => { - getLangButton().focus().should('be.focused'); - cy.focused().type('{downarrow}'); - cy.get('#language-selector .dropdown-menu').should('have.class', 'show'); - }); + it('Arrow down opens the language dropdown when language selector is focused', () => { + getLangButton().focus().should('be.focused') + cy.focused().type('{downarrow}') + cy.get('#language-selector .dropdown-menu').should('have.class', 'show') + }) - it('Escape closes the language dropdown', () => { - getLangButton().click(); - cy.get('#language-selector .dropdown-menu').should('have.class', 'show'); + it('Escape closes the language dropdown', () => { + getLangButton().click() + cy.get('#language-selector .dropdown-menu').should('have.class', 'show') - cy.focused().type('{esc}'); - cy.get('#language-selector .dropdown-menu').should('not.have.class', 'show'); - }); + cy.focused().type('{esc}') + cy.get('#language-selector .dropdown-menu').should('not.have.class', 'show') + }) - it('Enter selects a language in the language dropdown', () => { - getLangButton().click(); - cy.get('#language-selector .dropdown-menu').should('have.class', 'show'); - cy.focused().type('{downarrow}'); + it('Enter selects a language in the language dropdown', () => { + getLangButton().click() + cy.get('#language-selector .dropdown-menu').should('have.class', 'show') + cy.focused().type('{downarrow}') - cy.focused().type('{enter}'); + cy.focused().type('{enter}') - cy.get('#language-selector .dropdown-toggle').should('contain.text', 'englanti') - }); + cy.get('#language-selector .dropdown-toggle').should('contain.text', 'englanti') }) - describe('Translations', () => { - it('Global search bar has correct translations', () => { + }) + + describe('Translations', () => { - cy.visit('/en/') + it('Global search bar has correct translations', () => { - cy.get('#global-search-toggle').click(); - cy.get('#search-wrapper').should('exist'); + cy.visit('/en/') + + cy.get('#global-search-toggle').click() + cy.get('#search-wrapper').should('exist') // Check that vocabulary selector has correct place holder text cy.get('#vocab-selector button').should('have.text', 'Choose vocabulary') @@ -332,8 +339,8 @@ describe('Global search bar', () => { // go to YSO vocab front page in Finnish cy.visit('/fi/') - cy.get('#global-search-toggle').click(); - cy.get('#search-wrapper').should('exist'); + cy.get('#global-search-toggle').click() + cy.get('#search-wrapper').should('exist') // Check that vocabulary selector has correct place holder text cy.get('#vocab-selector button').should('have.text', 'Valitse sanasto') @@ -359,6 +366,6 @@ describe('Global search bar', () => { // the clear search button should have an aria label cy.get('#clear-button').should('have.attr', 'aria-label', 'Tyhjennä hakukenttä') - }); + }) }) }) From adee1a6d4dc606d6d656fe0afd9369b665fd9d5e Mon Sep 17 00:00:00 2001 From: Joeli Pokkinen Date: Thu, 16 Apr 2026 17:19:52 +0300 Subject: [PATCH 09/11] Tweak vocabulary search messages --- resource/translations/messages.sv.json | 2 +- tests/cypress/template/vocab-search-bar.cy.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/resource/translations/messages.sv.json b/resource/translations/messages.sv.json index 4159fa8ec..fa5c70fbc 100644 --- a/resource/translations/messages.sv.json +++ b/resource/translations/messages.sv.json @@ -231,4 +231,4 @@ "wgs84:long": "Longitud", "wgs84:long_help": "Longitud som decimalgrader enligt WGS 84-systemet.", "zxx-x-taxon": "Vetenskapligt namn" -} \ No newline at end of file +} diff --git a/tests/cypress/template/vocab-search-bar.cy.js b/tests/cypress/template/vocab-search-bar.cy.js index cbcf02592..606975200 100644 --- a/tests/cypress/template/vocab-search-bar.cy.js +++ b/tests/cypress/template/vocab-search-bar.cy.js @@ -289,11 +289,11 @@ describe('Vocab search bar', () => { // Check that language selector has correct Aria label cy.get('#language-selector button').should('have.attr', 'aria-label', 'Select search language') // Check that search field has correct Aria label - cy.get('#search-field').should('have.attr', 'aria-label', 'Text input with dropdown button') + cy.get('#search-field').should('have.attr', 'aria-label', 'Search text field') // Check that search field has correct Aria label cy.get('#search-button').should('have.attr', 'aria-label', 'Search') // Check that search field has correct placeholder - cy.get('#search-field').should('have.attr', 'placeholder', 'Search...') + cy.get('#search-field').should('have.attr', 'placeholder', 'Search in this vocabulary') // Check that search results have correct message when no results were found cy.get('#search-field').type('No results') cy.get('#search-autocomplete-results').within(() => { @@ -305,11 +305,11 @@ describe('Vocab search bar', () => { // Check that language selector has correct Aria label cy.get('#language-selector button').should('have.attr', 'aria-label', 'Valitse hakukieli') // Check that search field has correct Aria label - cy.get('#search-field').should('have.attr', 'aria-label', 'Tekstinsyöttö pudotusvalikolla') + cy.get('#search-field').should('have.attr', 'aria-label', 'Hakutekstikenttä') // Check that search field has correct Aria label cy.get('#search-button').should('have.attr', 'aria-label', 'Hae') // Check that search field has correct placeholder - cy.get('#search-field').should('have.attr', 'placeholder', 'Hae...') + cy.get('#search-field').should('have.attr', 'placeholder', 'Hae tästä sanastosta') // Check that search results have correct message when no results were found cy.get('#search-field').type('No results') cy.get('#search-autocomplete-results').within(() => { @@ -321,11 +321,11 @@ describe('Vocab search bar', () => { // Check that language selector has correct Aria label cy.get('#language-selector button').should('have.attr', 'aria-label', 'Välj sökspråk') // Check that search field has correct Aria label - cy.get('#search-field').should('have.attr', 'aria-label', 'Textinmatning med rullgardinsmeny') + cy.get('#search-field').should('have.attr', 'aria-label', 'Sökfält') // Check that search field has correct Aria label cy.get('#search-button').should('have.attr', 'aria-label', 'Sök') // Check that search field has correct placeholder - cy.get('#search-field').should('have.attr', 'placeholder', 'Sök...') + cy.get('#search-field').should('have.attr', 'placeholder', 'Sök i denna vokabulär') // Check that search results have correct message when no results were found cy.get('#search-field').type('No results') cy.get('#search-autocomplete-results').within(() => { From daa4ff87d1a8ce509dd97d781d888c5228b2bb27 Mon Sep 17 00:00:00 2001 From: Joeli Pokkinen Date: Thu, 23 Apr 2026 08:57:42 +0300 Subject: [PATCH 10/11] Fixed malformed JSON from merge conflict --- resource/translations/messages.en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resource/translations/messages.en.json b/resource/translations/messages.en.json index 28ce97e05..6d9ff34c6 100644 --- a/resource/translations/messages.en.json +++ b/resource/translations/messages.en.json @@ -141,7 +141,7 @@ "Choose language": "Choose language", "Choose vocabulary": "Choose vocabulary", "Clear search field": "Clear search field", - "Concepts loaded for letter %letter%": "Concepts loaded for letter %letter%" + "Concepts loaded for letter %letter%": "Concepts loaded for letter %letter%", "Concept %term% in vocabulary %vocab%": "Concept %term% in vocabulary %vocab%", "Contact us!": "Contact us!", "Copy to clipboard": "Copy to clipboard", From 7b4806acd359b387c93477b87f5a2c2dc7636752 Mon Sep 17 00:00:00 2001 From: Joeli Pokkinen Date: Thu, 23 Apr 2026 09:28:57 +0300 Subject: [PATCH 11/11] Search field aria messages in line with search field placeholder texts --- resource/js/global-search.js | 2 +- resource/js/vocab-search.js | 2 +- tests/cypress/template/global-search-bar.cy.js | 4 ++-- tests/cypress/template/vocab-search-bar.cy.js | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/resource/js/global-search.js b/resource/js/global-search.js index 275811321..2496401df 100644 --- a/resource/js/global-search.js +++ b/resource/js/global-search.js @@ -40,7 +40,7 @@ function startGlobalSearchApp () { return $t('Select search language') }, searchFieldAriaMessage () { - return $t('Search') + return $t('Enter search term') }, searchButtonAriaMessage () { return $t('Search') diff --git a/resource/js/vocab-search.js b/resource/js/vocab-search.js index 212150d4b..fd943877c 100644 --- a/resource/js/vocab-search.js +++ b/resource/js/vocab-search.js @@ -28,7 +28,7 @@ function startVocabSearchApp () { return $t('Select search language') }, searchFieldAriaMessage () { - return $t('Search text field') + return $t('Search in this vocabulary') }, searchButtonAriaMessage () { return $t('Search') diff --git a/tests/cypress/template/global-search-bar.cy.js b/tests/cypress/template/global-search-bar.cy.js index 3330a776d..d89897f15 100644 --- a/tests/cypress/template/global-search-bar.cy.js +++ b/tests/cypress/template/global-search-bar.cy.js @@ -320,7 +320,7 @@ describe('Global search bar', () => { // Check that search language selector has correct Aria label cy.get('#language-selector button').should('have.attr', 'aria-label', 'Select search language') // Check that search field has correct Aria label - cy.get('#search-field').should('have.attr', 'aria-label', 'Search') + cy.get('#search-field').should('have.attr', 'aria-label', 'Enter search term') // Check that search field has correct placeholder cy.get('#search-field').should('have.attr', 'placeholder', 'Enter search term') // Check that search field has correct aria-label @@ -351,7 +351,7 @@ describe('Global search bar', () => { // Check that search language selector has correct Aria label cy.get('#language-selector button').should('have.attr', 'aria-label', 'Valitse hakukieli') // Check that search field has correct Aria label - cy.get('#search-field').should('have.attr', 'aria-label', 'Hae') + cy.get('#search-field').should('have.attr', 'aria-label', 'Syötä haettava termi') // Check that search field has correct placeholder cy.get('#search-field').should('have.attr', 'placeholder', 'Syötä haettava termi') // Check that search field has correct aria-label diff --git a/tests/cypress/template/vocab-search-bar.cy.js b/tests/cypress/template/vocab-search-bar.cy.js index 606975200..a3af4c07a 100644 --- a/tests/cypress/template/vocab-search-bar.cy.js +++ b/tests/cypress/template/vocab-search-bar.cy.js @@ -289,7 +289,7 @@ describe('Vocab search bar', () => { // Check that language selector has correct Aria label cy.get('#language-selector button').should('have.attr', 'aria-label', 'Select search language') // Check that search field has correct Aria label - cy.get('#search-field').should('have.attr', 'aria-label', 'Search text field') + cy.get('#search-field').should('have.attr', 'aria-label', 'Search in this vocabulary') // Check that search field has correct Aria label cy.get('#search-button').should('have.attr', 'aria-label', 'Search') // Check that search field has correct placeholder @@ -305,7 +305,7 @@ describe('Vocab search bar', () => { // Check that language selector has correct Aria label cy.get('#language-selector button').should('have.attr', 'aria-label', 'Valitse hakukieli') // Check that search field has correct Aria label - cy.get('#search-field').should('have.attr', 'aria-label', 'Hakutekstikenttä') + cy.get('#search-field').should('have.attr', 'aria-label', 'Hae tästä sanastosta') // Check that search field has correct Aria label cy.get('#search-button').should('have.attr', 'aria-label', 'Hae') // Check that search field has correct placeholder @@ -321,7 +321,7 @@ describe('Vocab search bar', () => { // Check that language selector has correct Aria label cy.get('#language-selector button').should('have.attr', 'aria-label', 'Välj sökspråk') // Check that search field has correct Aria label - cy.get('#search-field').should('have.attr', 'aria-label', 'Sökfält') + cy.get('#search-field').should('have.attr', 'aria-label', 'Sök i denna vokabulär') // Check that search field has correct Aria label cy.get('#search-button').should('have.attr', 'aria-label', 'Sök') // Check that search field has correct placeholder