diff --git a/frontend/src/features/frame/components/topbar/Search.tsx b/frontend/src/features/frame/components/topbar/Search.tsx index f765e7c6be..9d6ed2bef2 100644 --- a/frontend/src/features/frame/components/topbar/Search.tsx +++ b/frontend/src/features/frame/components/topbar/Search.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; - +import { extractVideoId } from 'src/utils/video'; import makeStyles from '@mui/styles/makeStyles'; const useStyles = makeStyles(() => ({ @@ -50,12 +50,32 @@ const Search = () => { const searchParams = new URLSearchParams(paramsString); const [search, setSearch] = useState(searchParams.get('search') || ''); + /** + * Redirect to analysis page when `search` is a: + * - YouTube URL + * - Tournesol URL (analysis page) + * - Tournesol UID + * + * ...else redirect to the regular search results. + * + * It's not easy to distinguish a YT video id from a string of 11 + * characters, so both case are treated in the same way. + */ const onSubmit = (event: React.SyntheticEvent) => { event.preventDefault(); searchParams.delete('search'); searchParams.append('search', search); searchParams.delete('offset'); - history.push('/recommendations?' + searchParams.toString()); + + const videoId = extractVideoId(search); + + // TODO: we should pass an argument to `extractVideoId` so that raw YouTube + // ids are ignored. + if (videoId && search.length !== 11) { + history.push('/entities/yt:' + videoId.toString()); + } else { + history.push('/recommendations?' + searchParams.toString()); + } }; return ( diff --git a/tests/cypress/e2e/frontend/search.cy.ts b/tests/cypress/e2e/frontend/search.cy.ts new file mode 100644 index 0000000000..55a7956cd1 --- /dev/null +++ b/tests/cypress/e2e/frontend/search.cy.ts @@ -0,0 +1,32 @@ +describe('Search', () => { + describe('with a YouTube URL', () => { + it('redirect automatically to the analysis page', () => { + const videoURL = 'https://www.youtube.com/watch?v=b6vdKFxCvfU'; + const videoId = 'b6vdKFxCvfU'; + + // Intercept the request to the API + cy.intercept('GET', `/polls/videos/entities/yt:${videoId}/**`).as('videopoll'); + + cy.visit('/'); + cy.get('input[id="searchInput"]').click().type(`${videoURL}{enter}`); + + + cy.url().should('include', `/entities/yt:${videoId}`) + cy.wait(`@videopoll`).its('response.statusCode').should('eq', 200); + }); + }); + + describe('with a Tournesol video UID', () => { + it('redirect automatically to the analysis page', () => { + const videoId = 'WPPPFqsECz0'; + + // Intercept the request to the API + cy.intercept('GET', `/polls/videos/entities/yt:${videoId}/**`).as('videopoll'); + + cy.visit('/'); + cy.get('input[id="searchInput"]').click().type(`yt:${videoId}{enter}`); + + cy.wait(`@videopoll`).its('response.statusCode').should('eq', 200); + }); + }); +});