From 30d1518a165f1e9806a96bd7cab8d9b3e5fcd670 Mon Sep 17 00:00:00 2001 From: Mike van Veenhuijzen Date: Mon, 8 Apr 2024 16:41:23 +0200 Subject: [PATCH 1/4] fix(a11y): read title while searching --- .../src/components/ErrorPage/ErrorPage.tsx | 4 +- packages/ui-react/src/pages/Search/Search.tsx | 39 +++++++++++++------ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/packages/ui-react/src/components/ErrorPage/ErrorPage.tsx b/packages/ui-react/src/components/ErrorPage/ErrorPage.tsx index 94911cbb3..d0971b3f4 100644 --- a/packages/ui-react/src/components/ErrorPage/ErrorPage.tsx +++ b/packages/ui-react/src/components/ErrorPage/ErrorPage.tsx @@ -38,7 +38,9 @@ export const ErrorPageWithoutTranslation = ({ title, children, message, learnMor
{alt} -

{title || 'An error occurred'}

+

+ {title || 'An error occurred'} +

{message || 'Try refreshing this page or come back later.'}

{children} diff --git a/packages/ui-react/src/pages/Search/Search.tsx b/packages/ui-react/src/pages/Search/Search.tsx index c43896d41..5c9faca67 100644 --- a/packages/ui-react/src/pages/Search/Search.tsx +++ b/packages/ui-react/src/pages/Search/Search.tsx @@ -56,6 +56,14 @@ const Search = () => { }; }, []); + const title = isFetching + ? t('heading') + : !query + ? t('start_typing') + : playlist?.playlist.length + ? t('title', { count: playlist.playlist.length, query }) + : t('no_results_heading', { query }); + if ((error || !playlist) && !isFetching) { return ( @@ -66,19 +74,26 @@ const Search = () => { } if (!query) { - return ; + return ; } if (!playlist?.playlist.length) { return ( - -

{t('suggestions')}

-
    -
  • {t('tip_one')}
  • -
  • {t('tip_two')}
  • -
  • {t('tip_three')}
  • -
-
+ <> + + + {title} - {siteName} + + + +

{t('suggestions')}

+
    +
  • {t('tip_one')}
  • +
  • {t('tip_two')}
  • +
  • {t('tip_three')}
  • +
+
+ ); } @@ -86,11 +101,13 @@ const Search = () => {
- {t('title', { count: playlist.playlist.length, query })} - {siteName} + {title} - {siteName}
-

{t('heading')}

+

+ {title} +

Date: Mon, 8 Apr 2024 17:27:45 +0200 Subject: [PATCH 2/4] chore: update snapshot --- .../components/ErrorPage/__snapshots__/ErrorPage.test.tsx.snap | 1 + .../__snapshots__/DemoConfigDialog.test.tsx.snap | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/ui-react/src/components/ErrorPage/__snapshots__/ErrorPage.test.tsx.snap b/packages/ui-react/src/components/ErrorPage/__snapshots__/ErrorPage.test.tsx.snap index 7dea1eabe..018946364 100644 --- a/packages/ui-react/src/components/ErrorPage/__snapshots__/ErrorPage.test.tsx.snap +++ b/packages/ui-react/src/components/ErrorPage/__snapshots__/ErrorPage.test.tsx.snap @@ -14,6 +14,7 @@ exports[` > renders and matches snapshot 1`] = ` src="/images/logo.png" />

This is the title diff --git a/platforms/web/src/components/DemoConfigDialog/__snapshots__/DemoConfigDialog.test.tsx.snap b/platforms/web/src/components/DemoConfigDialog/__snapshots__/DemoConfigDialog.test.tsx.snap index 01b11132f..11f0d35e4 100644 --- a/platforms/web/src/components/DemoConfigDialog/__snapshots__/DemoConfigDialog.test.tsx.snap +++ b/platforms/web/src/components/DemoConfigDialog/__snapshots__/DemoConfigDialog.test.tsx.snap @@ -37,6 +37,7 @@ exports[` > renders and matches snapshot error dialog 1`] = ` src="/images/logo.png" />

app_config_not_found From 8d69123eb85c56c50f0f423e53aad71e5a9fb9f0 Mon Sep 17 00:00:00 2001 From: Mike van Veenhuijzen Date: Tue, 9 Apr 2024 16:26:08 +0200 Subject: [PATCH 3/4] fix(e2e): search results based on typeahead changes --- platforms/web/test-e2e/tests/search_test.ts | 27 ++++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/platforms/web/test-e2e/tests/search_test.ts b/platforms/web/test-e2e/tests/search_test.ts index 50c1439df..1f45d1c62 100644 --- a/platforms/web/test-e2e/tests/search_test.ts +++ b/platforms/web/test-e2e/tests/search_test.ts @@ -54,33 +54,36 @@ Scenario('Closing search return to original page (@mobile-only)', async ({ I }) }); Scenario('I can type a search phrase in the search bar', async ({ I }) => { + const searchTerm = 'Caminandes'; await openSearch(I); - I.fillField(searchBarLocator, 'Caminandes'); + I.fillField(searchBarLocator, searchTerm); I.seeElement(clearSearchLocator); - checkSearchResults(I, ['Caminandes 1', 'Caminandes 2', 'Caminandes 3']); + checkSearchResults(I, searchTerm, 3, ['Caminandes 1', 'Caminandes 2', 'Caminandes 3']); I.click(clearSearchLocator); assert.strictEqual('', await I.grabValueFrom(searchBarLocator)); - checkSearchResults(I, []); + I.dontSee('Search results'); I.see(emptySearchPrompt); }); Scenario('I can search by partial match', async ({ I }) => { + const searchTerm = 'ani'; await openSearch(I); - I.fillField(searchBarLocator, 'ani'); + I.fillField(searchBarLocator, searchTerm); I.seeElement(clearSearchLocator); - checkSearchResults(I, ['Minecraft Animation Workshop', 'Animating the Throw', 'Primitive Animals']); + checkSearchResults(I, searchTerm, 5, ['Minecraft Animation Workshop', 'Animating the Throw', 'Primitive Animals']); }); Scenario('I get empty search results when no videos match', async ({ I }) => { + const searchTerm = 'Axdfsdfgfgfd'; await openSearch(I); - I.fillField(searchBarLocator, 'Axdfsdfgfgfd'); + I.fillField(searchBarLocator, searchTerm); I.seeElement(clearSearchLocator); - checkSearchResults(I, []); + checkSearchResults(I, searchTerm, 0, []); I.see('No results found for "Axdfsdfgfgfd"'); I.see('Suggestions:'); @@ -124,17 +127,17 @@ Scenario('I can clear the search phrase manually', async ({ I }) => { I.dontSee('Suggestions:'); }); -function checkSearchResults(I: CodeceptJS.I, expectedResults: string[]) { +function checkSearchResults(I: CodeceptJS.I, searchTerm: string, expectedResults: number, searchMatches: string[]) { I.dontSee('Blender Channel'); I.dontSee('All Films'); - if (expectedResults.length > 0) { - I.see('Search results'); + if (expectedResults > 0) { + I.see(`${expectedResults} results for "${searchTerm}"`, 'h2'); I.dontSee(emptySearchPrompt); I.dontSee('No results found'); - expectedResults.forEach((result) => I.see(result)); + searchMatches.forEach((result) => I.see(result)); } else { - I.dontSee('Search results'); + I.see(`No results found for "${searchTerm}"`, 'h1'); I.dontSeeElement('div[class*="cell"]'); I.dontSeeElement('div[class*="card"]'); I.dontSeeElement('div[class*="poster"]'); From 03523ef22e0a4d8d301ece61ca7bcbf63d79a862 Mon Sep 17 00:00:00 2001 From: Christiaan Scheermeijer Date: Thu, 18 Apr 2024 11:45:08 +0200 Subject: [PATCH 4/4] refactor: use memo for title --- packages/ui-react/src/pages/Search/Search.tsx | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/ui-react/src/pages/Search/Search.tsx b/packages/ui-react/src/pages/Search/Search.tsx index 5c9faca67..30004fac1 100644 --- a/packages/ui-react/src/pages/Search/Search.tsx +++ b/packages/ui-react/src/pages/Search/Search.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useMemo } from 'react'; import { useParams } from 'react-router'; import { Helmet } from 'react-helmet'; import { useTranslation } from 'react-i18next'; @@ -34,7 +34,19 @@ const Search = () => { // User const { user, subscription } = useAccountStore(({ user, subscription }) => ({ user, subscription }), shallow); - const getURL = (playlistItem: PlaylistItem) => mediaURL({ media: playlistItem, playlistId: features?.searchPlaylist }); + const getURL = (playlistItem: PlaylistItem) => + mediaURL({ + media: playlistItem, + playlistId: features?.searchPlaylist, + }); + + const title = useMemo(() => { + if (isFetching) return t('heading'); + if (!query) return t('start_typing'); + if (!playlist?.playlist.length) return t('no_results_heading', { query }); + + return t('title', { count: playlist.playlist.length, query }); + }, [isFetching, playlist?.playlist.length, query, t]); // Update the search bar query to match the route param on mount useEffect(() => { @@ -56,14 +68,6 @@ const Search = () => { }; }, []); - const title = isFetching - ? t('heading') - : !query - ? t('start_typing') - : playlist?.playlist.length - ? t('title', { count: playlist.playlist.length, query }) - : t('no_results_heading', { query }); - if ((error || !playlist) && !isFetching) { return (