From bd8da8b9ab18670524624c1fffc467ba0858d68a Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Sun, 16 Oct 2022 17:27:04 +0300 Subject: [PATCH] Add e2e test utils for new_header Rename the tests that use utils functions adding `-old` --- .../VHeaderMobile/VContentSettingsButton.vue | 14 +- .../VHeaderMobile/VContentSettingsModal.vue | 10 +- src/locales/en.json | 8 +- test/README.md | 2 +- .../{filters.spec.ts => filters-old.spec.ts} | 22 +-- ...e-menu.spec.ts => mobile-menu-old.spec.ts} | 14 +- test/playwright/e2e/recent-searches.spec.ts | 7 + ....spec.ts => search-navigation-old.spec.ts} | 2 +- ...pec.ts => search-query-client-old.spec.ts} | 4 +- ...pec.ts => search-query-server-old.spec.ts} | 8 +- ...types.spec.ts => search-types-old.spec.ts} | 2 +- test/playwright/utils/breakpoints.ts | 17 +- test/playwright/utils/navigation.ts | 180 ++++++++++++++---- .../components/audio-results-old.spec.ts | 43 +++++ .../audio-results-desktop-2xl-linux.png | Bin .../audio-results-desktop-lg-linux.png | Bin .../audio-results-desktop-md-linux.png | Bin .../audio-results-desktop-xl-linux.png | Bin ...ts-narrow-viewport-desktop-UA-sm-linux.png | Bin ...ts-narrow-viewport-desktop-UA-xs-linux.png | Bin ...lts-narrow-viewport-mobile-UA-sm-linux.png | Bin ...lts-narrow-viewport-mobile-UA-xs-linux.png | Bin .../components/audio-results.spec.ts | 37 ---- .../components/header-old.spec.ts | 8 +- .../components/header.spec.ts | 10 +- 25 files changed, 259 insertions(+), 129 deletions(-) rename test/playwright/e2e/{filters.spec.ts => filters-old.spec.ts} (92%) rename test/playwright/e2e/{mobile-menu.spec.ts => mobile-menu-old.spec.ts} (83%) rename test/playwright/e2e/{search-navigation.spec.ts => search-navigation-old.spec.ts} (99%) rename test/playwright/e2e/{search-query-client.spec.ts => search-query-client-old.spec.ts} (96%) rename test/playwright/e2e/{search-query-server.spec.ts => search-query-server-old.spec.ts} (94%) rename test/playwright/e2e/{search-types.spec.ts => search-types-old.spec.ts} (98%) create mode 100644 test/playwright/visual-regression/components/audio-results-old.spec.ts rename test/playwright/visual-regression/components/{audio-results.spec.ts-snapshots => audio-results-old.spec.ts-snapshots}/audio-results-desktop-2xl-linux.png (100%) rename test/playwright/visual-regression/components/{audio-results.spec.ts-snapshots => audio-results-old.spec.ts-snapshots}/audio-results-desktop-lg-linux.png (100%) rename test/playwright/visual-regression/components/{audio-results.spec.ts-snapshots => audio-results-old.spec.ts-snapshots}/audio-results-desktop-md-linux.png (100%) rename test/playwright/visual-regression/components/{audio-results.spec.ts-snapshots => audio-results-old.spec.ts-snapshots}/audio-results-desktop-xl-linux.png (100%) rename test/playwright/visual-regression/components/{audio-results.spec.ts-snapshots => audio-results-old.spec.ts-snapshots}/audio-results-narrow-viewport-desktop-UA-sm-linux.png (100%) rename test/playwright/visual-regression/components/{audio-results.spec.ts-snapshots => audio-results-old.spec.ts-snapshots}/audio-results-narrow-viewport-desktop-UA-xs-linux.png (100%) rename test/playwright/visual-regression/components/{audio-results.spec.ts-snapshots => audio-results-old.spec.ts-snapshots}/audio-results-narrow-viewport-mobile-UA-sm-linux.png (100%) rename test/playwright/visual-regression/components/{audio-results.spec.ts-snapshots => audio-results-old.spec.ts-snapshots}/audio-results-narrow-viewport-mobile-UA-xs-linux.png (100%) delete mode 100644 test/playwright/visual-regression/components/audio-results.spec.ts diff --git a/src/components/VHeader/VHeaderMobile/VContentSettingsButton.vue b/src/components/VHeader/VHeaderMobile/VContentSettingsButton.vue index c086bd4e03..f18bcd018a 100644 --- a/src/components/VHeader/VHeaderMobile/VContentSettingsButton.vue +++ b/src/components/VHeader/VHeaderMobile/VContentSettingsButton.vue @@ -2,9 +2,9 @@ @@ -32,9 +32,9 @@ export default { type: Boolean, default: false, }, - areFiltersSelected: { - type: Boolean, - default: false, + appliedFilterCount: { + type: Number, + default: 0, }, }, setup() { diff --git a/src/components/VHeader/VHeaderMobile/VContentSettingsModal.vue b/src/components/VHeader/VHeaderMobile/VContentSettingsModal.vue index e842ad11e7..3f3599a94e 100644 --- a/src/components/VHeader/VHeaderMobile/VContentSettingsModal.vue +++ b/src/components/VHeader/VHeaderMobile/VContentSettingsModal.vue @@ -9,7 +9,7 @@ @@ -32,7 +32,7 @@ class="self-center ms-auto" size="search-medium" :icon-props="{ iconPath: closeIcon }" - :aria-label="$t('browse-page.aria.close')" + :aria-label="$t('modal.aria-close')" @click="closeModal" /> @@ -120,11 +120,10 @@ export default defineComponent({ const isClearButtonDisabled = computed( () => !searchStore.isAnyFilterApplied ) + const appliedFilterCount = computed(() => searchStore.appliedFilterCount) const clearFiltersLabel = computed(() => searchStore.isAnyFilterApplied - ? i18n.t('filter-list.clear-numbered', { - number: searchStore.appliedFilterCount, - }) + ? i18n.tc('filter-list.clear-numbered', appliedFilterCount.value) : i18n.t('filter-list.clear') ) @@ -145,6 +144,7 @@ export default defineComponent({ changeSelectedTab, areFiltersSelected, + appliedFilterCount, showClearFiltersButton, isClearButtonDisabled, clearFiltersLabel, diff --git a/src/locales/en.json b/src/locales/en.json index b0000b224e..04d742fc6d 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -41,7 +41,6 @@ "aria": { "primary": "primary", "menu": "menu", - "menu-notification": "Some filters are applied", "search": "search", "sr-search": "search button" }, @@ -60,7 +59,11 @@ "with-count": "{count} Filter|{count} Filters" }, "see-results": "See results", - "back-button": "Go back" + "back-button": "Go back", + "content-settings-button": { + "simple": "Menu", + "with-count": "Menu. {count} filter applied|Menu. {count} filters applied" + } }, "navigation": { "about": "About", @@ -628,6 +631,7 @@ "interpunct": "•", "modal": { "close": "Close", + "aria-close": "Close the modal", "close-named": "Close {name}" }, "error-images": { diff --git a/test/README.md b/test/README.md index fc6356b72f..7c05c7624e 100644 --- a/test/README.md +++ b/test/README.md @@ -3,6 +3,6 @@ Normally when you build Openverse, you download the updated information about locales and translation files to `src/locales` folder. To prevent too many requests during CI, we save the locale files that are necessary to run the app during Playwright tests. 1. `scripts/valid-locales.json` contains a list of valid locales with properties including their translation status (the percentage of strings that are translated). -2. `es.json` is the `es` locale file used for search navigation tests (`../playwright/e2e/search-navigation.spec.ts`). +2. `es.json` is the `es` locale file used for search navigation tests (`../playwright/e2e/search-navigation-old.spec.ts`). 3. `ru.json` is the `ru` locale file used for testing the translation banner because the current translated percentage is ~40%, which is below the banner threshold of 90%. 4. `ar.json` is the machine-translated `ar` locale file used for RTL testing. diff --git a/test/playwright/e2e/filters.spec.ts b/test/playwright/e2e/filters-old.spec.ts similarity index 92% rename from test/playwright/e2e/filters.spec.ts rename to test/playwright/e2e/filters-old.spec.ts index 08ba98e96b..9bb9b049f8 100644 --- a/test/playwright/e2e/filters.spec.ts +++ b/test/playwright/e2e/filters-old.spec.ts @@ -48,7 +48,7 @@ for (const searchType of supportedSearchTypes) { }) => { await goToSearchTerm(page, 'cat', { searchType }) - await openFilters(page) + await openFilters(page, 'old') await assertCheckboxCount(page, 'total', FILTER_COUNTS[searchType]) }) @@ -58,7 +58,7 @@ test('initial filters are applied based on the url', async ({ page }) => { await page.goto( '/search/?q=cat&license_type=commercial&license=cc0&searchBy=creator' ) - await openFilters(page) + await openFilters(page, 'old') const expectedFilters = ['cc0', 'commercial', 'creator'] for (const checkbox of expectedFilters) { @@ -72,13 +72,13 @@ test('common filters are retained when media type changes from all media to sing await page.goto( '/search/?q=cat&license_type=commercial&license=cc0&searchBy=creator' ) - await openFilters(page) + await openFilters(page, 'old') const expectedFilters = ['cc0', 'commercial', 'creator'] for (const checkbox of expectedFilters) { await assertCheckboxStatus(page, checkbox) } - await changeContentType(page, 'Images') + await changeContentType(page, 'Images', 'old') await expect(page).toHaveURL( '/search/image?q=cat&license_type=commercial&license=cc0&searchBy=creator' @@ -94,13 +94,13 @@ test('common filters are retained when media type changes from single type to al await page.goto( '/search/image?q=cat&license_type=commercial&license=cc0&searchBy=creator' ) - await openFilters(page) + await openFilters(page, 'old') for (const checkbox of ['cc0', 'commercial', 'creator']) { await assertCheckboxStatus(page, checkbox) } - await changeContentType(page, 'All content') + await changeContentType(page, 'All content', 'old') for (const checkbox of ['cc0', 'commercial', 'creator']) { await assertCheckboxStatus(page, checkbox) @@ -114,7 +114,7 @@ test('selecting some filters can disable dependent filters', async ({ page, }) => { await page.goto('/search/audio?q=cat&license_type=commercial') - await openFilters(page) + await openFilters(page, 'old') // by-nc is special because we normally test for fuzzy match, and by-nc matches 3 labels. const byNc = page.locator('input[value="by-nc"]') @@ -144,12 +144,12 @@ test('selecting some filters can disable dependent filters', async ({ */ test('filters are updated when media type changes', async ({ page }) => { await page.goto('/search/image?q=cat&aspect_ratio=tall&license=cc0') - await openFilters(page) + await openFilters(page, 'old') await assertCheckboxStatus(page, 'tall') await assertCheckboxStatus(page, 'cc0') - await changeContentType(page, 'Audio') + await changeContentType(page, 'Audio', 'old') // Only CC0 checkbox is checked, and the filter button label is '1 Filter' await assertCheckboxStatus(page, 'cc0') @@ -164,7 +164,7 @@ test('new media request is sent when a filter is selected', async ({ page, }) => { await page.goto('/search/image?q=cat') - await openFilters(page) + await openFilters(page, 'old') await assertCheckboxStatus(page, 'cc0', '', 'unchecked') @@ -190,7 +190,7 @@ for (const [searchType, source] of [ await page.goto( `/search/${searchType}?q=birds&source=${source.toLowerCase()}` ) - await openFilters(page) + await openFilters(page, 'old') await assertCheckboxStatus(page, source, '', 'checked') }) diff --git a/test/playwright/e2e/mobile-menu.spec.ts b/test/playwright/e2e/mobile-menu-old.spec.ts similarity index 83% rename from test/playwright/e2e/mobile-menu.spec.ts rename to test/playwright/e2e/mobile-menu-old.spec.ts index 85ecc9ad5c..193c6a2002 100644 --- a/test/playwright/e2e/mobile-menu.spec.ts +++ b/test/playwright/e2e/mobile-menu-old.spec.ts @@ -3,8 +3,8 @@ import { test, expect } from '@playwright/test' import { closeMobileMenu, goToSearchTerm, + openContentTypes, openFilters, - openMobileMenu, } from '~~/test/playwright/utils/navigation' const mockUaString = @@ -20,16 +20,16 @@ test.describe.configure({ mode: 'parallel' }) test('Can open filters menu on mobile at least twice', async ({ page }) => { await page.goto('/search/?q=cat') - await openFilters(page) + await openFilters(page, 'old') await expect(page.locator(`input[type="checkbox"]`)).toHaveCount(11, { timeout: 100, }) - await closeMobileMenu(page) + await closeMobileMenu(page, 'old') await expect(page.locator(`input[type="checkbox"]`)).toHaveCount(0, { timeout: 100, }) - await openFilters(page) + await openFilters(page, 'old') await expect(page.locator(`input[type="checkbox"]`)).toHaveCount(11, { timeout: 100, }) @@ -37,10 +37,10 @@ test('Can open filters menu on mobile at least twice', async ({ page }) => { test('Can open mobile menu at least twice', async ({ page }) => { await goToSearchTerm(page, 'cat') - await openMobileMenu(page) + await openContentTypes(page, 'old') await expect(page.locator('button', { hasText: 'Close' })).toBeVisible() - await closeMobileMenu(page) + await closeMobileMenu(page, 'old') await expect(page.locator('button', { hasText: 'Close' })).not.toBeVisible() - await openMobileMenu(page) + await openContentTypes(page, 'old') await expect(page.locator('button', { hasText: 'Close' })).toBeVisible() }) diff --git a/test/playwright/e2e/recent-searches.spec.ts b/test/playwright/e2e/recent-searches.spec.ts index e95c396e4e..a2dd57a584 100644 --- a/test/playwright/e2e/recent-searches.spec.ts +++ b/test/playwright/e2e/recent-searches.spec.ts @@ -37,6 +37,8 @@ test('shows recent searches in reverse chronological order', async ({ test('clicking takes user to that search', async ({ page }) => { await executeSearches(page) expect(page.url()).toContain('?q=galah') + // Click on the input to open the Recent searches + await page.locator('input[type="search"]').click() await page .locator(`[aria-label="Recent searches"]`) .locator('[id="option-1"]') @@ -45,6 +47,9 @@ test('clicking takes user to that search', async ({ page }) => { }) test('recent searches shows message when blank', async ({ page }) => { + // Click on the input to open the Recent searches + await page.locator('input[type="search"]').click() + const recentSearchesText = await page .locator('[data-testid="recent-searches"]') .textContent() @@ -53,6 +58,8 @@ test('recent searches shows message when blank', async ({ page }) => { test('clicking Clear clears the recent searches', async ({ page }) => { await executeSearches(page) + // Click on the input to open the Recent searches + await page.locator('input[type="search"]').click() await page.locator('[aria-label="Clear recent searches"]').click() const recentSearchesText = await page .locator('[data-testid="recent-searches"]') diff --git a/test/playwright/e2e/search-navigation.spec.ts b/test/playwright/e2e/search-navigation-old.spec.ts similarity index 99% rename from test/playwright/e2e/search-navigation.spec.ts rename to test/playwright/e2e/search-navigation-old.spec.ts index 5a9132aed1..3d4857d7aa 100644 --- a/test/playwright/e2e/search-navigation.spec.ts +++ b/test/playwright/e2e/search-navigation-old.spec.ts @@ -18,7 +18,7 @@ test.describe('search history navigation', () => { }) => { await goToSearchTerm(page, 'galah') // Open filter sidebar - await openFilters(page) + await openFilters(page, 'old') // Apply a filter await page.click('#modification') diff --git a/test/playwright/e2e/search-query-client.spec.ts b/test/playwright/e2e/search-query-client-old.spec.ts similarity index 96% rename from test/playwright/e2e/search-query-client.spec.ts rename to test/playwright/e2e/search-query-client-old.spec.ts index 7a745092ba..327bc1d4d2 100644 --- a/test/playwright/e2e/search-query-client.spec.ts +++ b/test/playwright/e2e/search-query-client-old.spec.ts @@ -51,7 +51,7 @@ test('url filter parameters not used by current mediaType are discarded', async query: 'category=photograph', }) - await changeContentType(page, 'Audio') + await changeContentType(page, 'Audio', 'old') await expect(page).toHaveURL('/search/audio?q=cat') }) @@ -63,7 +63,7 @@ test('url filter types not used by current mediaType are discarded', async ({ query: 'aspect_ratio=tall', }) - await changeContentType(page, 'Audio') + await changeContentType(page, 'Audio', 'old') await expect(page).toHaveURL('/search/audio?q=cat') }) diff --git a/test/playwright/e2e/search-query-server.spec.ts b/test/playwright/e2e/search-query-server-old.spec.ts similarity index 94% rename from test/playwright/e2e/search-query-server.spec.ts rename to test/playwright/e2e/search-query-server-old.spec.ts index f041073b43..560cfe5f7f 100644 --- a/test/playwright/e2e/search-query-server.spec.ts +++ b/test/playwright/e2e/search-query-server-old.spec.ts @@ -44,7 +44,7 @@ test('url path /search/ is used to select `all` search tab', async ({ }) => { await page.goto('/search/?q=cat') - const contentType = await currentContentType(page) + const contentType = await currentContentType(page, 'old') expect(contentType?.trim()).toEqual('All content') }) @@ -53,7 +53,7 @@ test('url path /search/audio is used to select `audio` search tab', async ({ }) => { await goToSearchTerm(page, 'cat', { searchType: AUDIO }) - const contentType = await currentContentType(page) + const contentType = await currentContentType(page, 'old') expect(contentType?.trim()).toEqual('Audio') }) @@ -64,7 +64,7 @@ test('url query to filter, all tab, one parameter per filter type', async ({ query: 'license=cc0&license_type=commercial&searchBy=creator', }) - await openFilters(page) + await openFilters(page, 'old') for (const checkbox of ['cc0', 'commercial', 'creator']) { await assertCheckboxStatus(page, checkbox) } @@ -77,7 +77,7 @@ test('url query to filter, image tab, several filters for one filter type select searchType: IMAGE, query: 'searchBy=creator&extension=jpg,png,gif,svg', }) - await openFilters(page) + await openFilters(page, 'old') const checkboxes = ['jpeg', 'png', 'gif', 'svg'] for (const checkbox of checkboxes) { const forValue = checkbox === 'jpeg' ? 'jpg' : checkbox diff --git a/test/playwright/e2e/search-types.spec.ts b/test/playwright/e2e/search-types-old.spec.ts similarity index 98% rename from test/playwright/e2e/search-types.spec.ts rename to test/playwright/e2e/search-types-old.spec.ts index 08852e8c06..bd6251520d 100644 --- a/test/playwright/e2e/search-types.spec.ts +++ b/test/playwright/e2e/search-types-old.spec.ts @@ -115,7 +115,7 @@ for (const searchType of searchTypes) { // Audio is loading a lot of files, so we do not use it for the first SSR page const pageToOpen = searchType.id === 'all' ? searchTypes[1] : searchTypes[0] await page.goto(pageToOpen.url) - await changeContentType(page, searchType.name) + await changeContentType(page, searchType.name, 'old') await checkSearchResult(page, searchType) }) } diff --git a/test/playwright/utils/breakpoints.ts b/test/playwright/utils/breakpoints.ts index 3d58c7189e..8993bfd16e 100644 --- a/test/playwright/utils/breakpoints.ts +++ b/test/playwright/utils/breakpoints.ts @@ -24,6 +24,12 @@ type BreakpointBlock = (options: { const desktopBreakpoints = ['2xl', 'xl', 'lg', 'md'] as const const mobileBreakpoints = ['sm', 'xs'] as const +/** + * For e2e functionality testing, we need to test mobile and desktop screens. + */ +export const testScreens = ['sm', 'xl'] as const +export type TestScreen = typeof testScreens[number] + // For desktop UA use the default const desktopUa = undefined const mobileUa = @@ -138,18 +144,21 @@ const describeEachBreakpoint = const describeEvery = describeEachBreakpoint( Object.keys(VIEWPORTS) as Breakpoint[] ) -const describeEachDesktop = describeEachBreakpoint(desktopBreakpoints) -const describeEachDesktopExceptMd = describeEachBreakpoint( +const describeEachDesktopWithMd = describeEachBreakpoint(desktopBreakpoints) +const describeEachDesktop = describeEachBreakpoint( desktopBreakpoints.filter((b) => b !== 'md') ) const describeEachMobile = describeEachBreakpoint(mobileBreakpoints) +const describeEachMobileWithoutMd = describeEachBreakpoint(mobileBreakpoints) export default { ...breakpointTests, describeEachBreakpoint, describeEvery, - // TODO: replace with describeEachDesktopExceptMd when the new header is ready describeEachDesktop, - describeEachDesktopExceptMd, + // TODO: remove describeEachDesktopWithMd after the new_header is merged + describeEachDesktopWithMd, describeEachMobile, + // TODO: remove describeEachMobileWithoutMd after the new_header is merged + describeEachMobileWithoutMd, } diff --git a/test/playwright/utils/navigation.ts b/test/playwright/utils/navigation.ts index 89e0fe1238..64df12b175 100644 --- a/test/playwright/utils/navigation.ts +++ b/test/playwright/utils/navigation.ts @@ -67,9 +67,10 @@ export type LanguageDirection = 'ltr' | 'rtl' const smWidth = SCREEN_SIZES.get('sm') as number -const buttonSelectors = { - filter: '[aria-controls="filters"]', - contentSwitcher: '[aria-controls="content-switcher-modal"]', +export const buttonSelectors = { + filter: 'button[aria-controls="filters"]', + contentSwitcher: 'button[aria-controls="content-switcher-modal"]', + mobileContentSettings: `button[aria-controls="content-settings-modal"]`, } export function sleep(ms: number) { @@ -106,7 +107,7 @@ const isButtonPressed = async ( } const pageWidth = viewportSize.width if (pageWidth > 640) { - return (await page.getAttribute(buttonSelector, 'aria-pressed')) === 'true' + return await getPressed(page, buttonSelector) } else { return await page.locator('button', { hasText: 'Close' }).isVisible() } @@ -120,27 +121,105 @@ const openMenu = async (page: Page, button: 'filter' | 'contentSwitcher') => { } } -export const openFilters = async (page: Page) => { - await openMenu(page, 'filter') +export const openFilters = async ( + page: Page, + mode: 'new' | 'old' = 'new', + dir: LanguageDirection = 'ltr' +) => { + if (mode === 'old' || (mode === 'new' && isPageDesktop(page))) { + await openMenu(page, 'filter') + } else { + await openContentSettingsTab(page, 'filters', dir) + } +} + +export const openContentTypes = async ( + page: Page, + mode: 'new' | 'old' = 'new', + dir: LanguageDirection = 'ltr' +) => { + if (mode === 'old' || (mode === 'new' && isPageDesktop(page))) { + await openMenu(page, 'contentSwitcher') + } else { + await openContentSettingsTab(page, 'contentTypes', dir) + } } -export const closeFilters = async (page: Page) => { - const selector = buttonSelectors['filter'] +export const isPageDesktop = (page: Page, mode: 'new' | 'old' = 'new') => { + const pageWidth = page.viewportSize()?.width + if (!pageWidth) return false + const desktopMinWidth = mode === 'new' ? 1024 : 768 + return pageWidth >= desktopMinWidth +} +/** + * Returns `true` if the `selector`'s `aria-pressed` attribute is `true`. + */ +const getPressed = async (page: Page, selector: string) => { + return ( + (await page.getAttribute(selector, 'aria-pressed')) === 'true' || + (await page.getAttribute(selector, 'aria-expanded')) === 'true' + ) +} - if (await isButtonPressed(page, selector)) { +/** + * Clicks the `selector` button if it is not already pressed. + */ +const ensureButtonPressed = async (page: Page, selector: string) => { + if (!(await getPressed(page, selector))) { await page.click(selector) - expect(await isButtonPressed(page, selector)).toEqual(false) + expect(await getPressed(page, selector)).toEqual(true) } } +/** + * Open the Content types tab in the mobile content settings modal. + */ +export const openContentSettingsTab = async ( + page: Page, + tab: 'contentTypes' | 'filters' = 'contentTypes', + dir: LanguageDirection = 'ltr' +) => { + const selector = buttonSelectors.mobileContentSettings + + await ensureButtonPressed(page, selector) + + const tabLabel = t( + tab === 'contentTypes' ? 'search-type.heading' : 'filters.title', + dir + ) + await page.locator(`button[role="tab"]:has-text("${tabLabel}")`).click() +} + +export const closeFilters = async (page: Page, mode: 'old' | 'new' = 'new') => { + if (mode === 'old' || (mode === 'new' && isPageDesktop(page))) { + const selector = buttonSelectors['filter'] -export const openMobileMenu = async (page: Page) => { - await openMenu(page, 'contentSwitcher') + if (await isButtonPressed(page, selector)) { + await page.click(selector) + expect(await isButtonPressed(page, selector)).toEqual(false) + } + } else { + await closeMobileMenu(page, mode) + } } -export const closeMobileMenu = async (page: Page) => { - await page.click('text=Close') +/** + * Previous to the `new_header` milestone, the mobile menu had a text button, now it is an icon button. + */ +export const closeMobileMenu = async ( + page: Page, + mode: 'new' | 'old' = 'new', + dir: LanguageDirection = 'ltr' +) => { + if (mode === 'old') { + await page.click(`button:has-text('${t('modal.close', dir)}')`) + } else { + await page.click(`button[aria-label="${t('modal.aria-close', dir)}"]`) + } } +export const isMobileMenuOpen = async (page: Page) => + page.locator('[role="dialog"]').isVisible({ timeout: 100 }) + export const assertCheckboxStatus = async ( page: Page, label: string, @@ -171,27 +250,48 @@ export const assertCheckboxStatus = async ( export const changeContentType = async ( page: Page, - to: 'Audio' | 'Images' | 'All content' + to: 'Audio' | 'Images' | 'All content', + mode: 'old' | 'new' = 'new' ) => { - await page.click( - `button[aria-controls="content-switcher-popover"], button[aria-controls="content-switcher-modal"]` - ) - // Ensure that the asynchronous navigation is finished before next steps - await Promise.all([ - page.waitForNavigation(), - page.locator(`#content-switcher-popover a:has-text("${to}")`).click(), - ]) + if (mode === 'old' || isPageDesktop(page)) { + await page.click( + `button[aria-controls="content-switcher-popover"], button[aria-controls="content-switcher-modal"]` + ) + // Ensure that the asynchronous navigation is finished before next steps + await Promise.all([ + page.waitForNavigation(), + page.locator(`#content-switcher-popover a:has-text("${to}")`).click(), + ]) + } else { + await openContentTypes(page, mode) + await page.locator(`a[role="radio"]:has-text("${to}")`).click() + await closeMobileMenu(page, mode) + } } /** - * Finds a button with a popup to the left of the filters button which doesn't have a 'menu' label - * @param page - The current page + * For desktop, returns the content of the Content switcher button. + * For mobile, returns null. + * @param page - Playwright page object. + * @param mode - `new` if `new_header` flag is on, `old` otherwise. */ -export const currentContentType = async (page: Page) => { - const contentSwitcherButton = await page.locator( - `button[aria-controls="content-switcher-popover"], button[aria-controls="content-switcher-modal"]` - ) - return contentSwitcherButton.textContent() +export const currentContentType = async ( + page: Page, + mode: 'old' | 'new' = 'new' +) => { + if (isPageDesktop(page)) { + const contentSwitcherButton = await page.locator( + `button[aria-controls="content-switcher-popover"]` + ) + return (await contentSwitcherButton.textContent())?.trim() + } else { + await openContentTypes(page, mode) + const currentContentType = await page + .locator('a[aria-current="page"]') + .textContent() + await closeMobileMenu(page, mode) + return currentContentType + } } /** @@ -261,10 +361,6 @@ export const goToSearchTerm = async ( await page.waitForLoadState('load') } await scrollDownAndUp(page) - const pageWidth = page.viewportSize()?.width - if (pageWidth && pageWidth > smWidth && query !== '&ff_new_header=on') { - await page.waitForSelector(`[aria-label="${t('header.aria.menu', dir)}"]`) - } } /** @@ -272,11 +368,10 @@ export const goToSearchTerm = async ( * and waits for navigation. */ export const searchFromHeader = async (page: Page, term: string) => { + // Double click on the search bar to remove previous value + await page.dblclick('id=search-bar') await page.fill('id=search-bar', term) - await Promise.all([ - page.waitForNavigation(), - page.locator('button[type="submit"]').click(), - ]) + await Promise.all([page.waitForNavigation(), page.keyboard.press('Enter')]) } /** @@ -344,6 +439,15 @@ export const pathWithDir = (rawPath: string, dir: string) => { } export const enableNewHeader = async (page: Page) => { + // Add the new_header cookie + await page.context().addCookies([ + { + name: 'features', + value: '%7B%22new_header%22%3A%22on%22%7D', + domain: 'localhost', + path: '/', + }, + ]) await page.goto('/preferences') const newHeaderCheckboxLocator = 'input#new_header' diff --git a/test/playwright/visual-regression/components/audio-results-old.spec.ts b/test/playwright/visual-regression/components/audio-results-old.spec.ts new file mode 100644 index 0000000000..9806a5e20c --- /dev/null +++ b/test/playwright/visual-regression/components/audio-results-old.spec.ts @@ -0,0 +1,43 @@ +import { test } from '@playwright/test' + +import breakpoints from '~~/test/playwright/utils/breakpoints' +import { closeFilters } from '~~/test/playwright/utils/navigation' + +test.describe.configure({ mode: 'parallel' }) + +test.describe('audio results', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/search/audio?q=birds') + }) + + breakpoints.describeEachMobileWithoutMd( + { uaMocking: false }, + ({ expectSnapshot }) => { + test('should render small row layout desktop UA with narrow viewport', async ({ + page, + }) => { + await closeFilters(page, 'old') + await expectSnapshot('audio-results-narrow-viewport-desktop-UA', page) + }) + } + ) + + breakpoints.describeEachMobileWithoutMd( + { uaMocking: true }, + ({ expectSnapshot }) => { + test('should render small row layout mobile UA with narrow viewport', async ({ + page, + }) => { + await closeFilters(page, 'old') + await expectSnapshot('audio-results-narrow-viewport-mobile-UA', page) + }) + } + ) + + breakpoints.describeEachDesktopWithMd(({ expectSnapshot }) => { + test('desktop audio results', async ({ page }) => { + await closeFilters(page, 'old') + await expectSnapshot('audio-results-desktop', page) + }) + }) +}) diff --git a/test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-desktop-2xl-linux.png b/test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-desktop-2xl-linux.png similarity index 100% rename from test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-desktop-2xl-linux.png rename to test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-desktop-2xl-linux.png diff --git a/test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-desktop-lg-linux.png b/test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-desktop-lg-linux.png similarity index 100% rename from test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-desktop-lg-linux.png rename to test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-desktop-lg-linux.png diff --git a/test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-desktop-md-linux.png b/test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-desktop-md-linux.png similarity index 100% rename from test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-desktop-md-linux.png rename to test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-desktop-md-linux.png diff --git a/test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-desktop-xl-linux.png b/test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-desktop-xl-linux.png similarity index 100% rename from test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-desktop-xl-linux.png rename to test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-desktop-xl-linux.png diff --git a/test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-narrow-viewport-desktop-UA-sm-linux.png b/test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-narrow-viewport-desktop-UA-sm-linux.png similarity index 100% rename from test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-narrow-viewport-desktop-UA-sm-linux.png rename to test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-narrow-viewport-desktop-UA-sm-linux.png diff --git a/test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-narrow-viewport-desktop-UA-xs-linux.png b/test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-narrow-viewport-desktop-UA-xs-linux.png similarity index 100% rename from test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-narrow-viewport-desktop-UA-xs-linux.png rename to test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-narrow-viewport-desktop-UA-xs-linux.png diff --git a/test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-narrow-viewport-mobile-UA-sm-linux.png b/test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-narrow-viewport-mobile-UA-sm-linux.png similarity index 100% rename from test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-narrow-viewport-mobile-UA-sm-linux.png rename to test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-narrow-viewport-mobile-UA-sm-linux.png diff --git a/test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-narrow-viewport-mobile-UA-xs-linux.png b/test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-narrow-viewport-mobile-UA-xs-linux.png similarity index 100% rename from test/playwright/visual-regression/components/audio-results.spec.ts-snapshots/audio-results-narrow-viewport-mobile-UA-xs-linux.png rename to test/playwright/visual-regression/components/audio-results-old.spec.ts-snapshots/audio-results-narrow-viewport-mobile-UA-xs-linux.png diff --git a/test/playwright/visual-regression/components/audio-results.spec.ts b/test/playwright/visual-regression/components/audio-results.spec.ts deleted file mode 100644 index 5f9cefeb26..0000000000 --- a/test/playwright/visual-regression/components/audio-results.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { test } from '@playwright/test' - -import breakpoints from '~~/test/playwright/utils/breakpoints' -import { closeFilters } from '~~/test/playwright/utils/navigation' - -test.describe.configure({ mode: 'parallel' }) - -test.describe('audio results', () => { - test.beforeEach(async ({ page }) => { - await page.goto('/search/audio?q=birds') - }) - - breakpoints.describeEachMobile({ uaMocking: false }, ({ expectSnapshot }) => { - test('should render small row layout desktop UA with narrow viewport', async ({ - page, - }) => { - await closeFilters(page) - await expectSnapshot('audio-results-narrow-viewport-desktop-UA', page) - }) - }) - - breakpoints.describeEachMobile({ uaMocking: true }, ({ expectSnapshot }) => { - test('should render small row layout mobile UA with narrow viewport', async ({ - page, - }) => { - await closeFilters(page) - await expectSnapshot('audio-results-narrow-viewport-mobile-UA', page) - }) - }) - - breakpoints.describeEachDesktop(({ expectSnapshot }) => { - test('desktop audio results', async ({ page }) => { - await closeFilters(page) - await expectSnapshot('audio-results-desktop', page) - }) - }) -}) diff --git a/test/playwright/visual-regression/components/header-old.spec.ts b/test/playwright/visual-regression/components/header-old.spec.ts index cf8410e116..07218a2f99 100644 --- a/test/playwright/visual-regression/components/header-old.spec.ts +++ b/test/playwright/visual-regression/components/header-old.spec.ts @@ -22,7 +22,7 @@ test.describe('header-old snapshots', () => { }) test.describe('header-old', () => { - breakpoints.describeEachDesktop(({ expectSnapshot }) => { + breakpoints.describeEachDesktopWithMd(({ expectSnapshot }) => { test('filters open', async ({ page }) => { await page.mouse.move(0, 150) await expectSnapshot( @@ -35,14 +35,14 @@ test.describe('header-old snapshots', () => { breakpoints.describeEvery(({ expectSnapshot }) => { test('resting', async ({ page }) => { // By default, filters are open. We need to close them. - await closeFilters(page) + await closeFilters(page, 'old') // Make sure the header is not hovered on await page.mouse.move(0, 150) await expectSnapshot(`resting-${dir}`, page.locator(headerSelector)) }) test('scrolled', async ({ page }) => { - await closeFilters(page) + await closeFilters(page, 'old') await scrollToBottom(page) await page.mouse.move(0, 150) await sleep(200) @@ -53,7 +53,7 @@ test.describe('header-old snapshots', () => { }) test('searchbar hovered', async ({ page }) => { - await closeFilters(page) + await closeFilters(page, 'old') await page.hover('input') await hideInputCursors(page) await expectSnapshot( diff --git a/test/playwright/visual-regression/components/header.spec.ts b/test/playwright/visual-regression/components/header.spec.ts index 6dc194d31d..01f9fcb76d 100644 --- a/test/playwright/visual-regression/components/header.spec.ts +++ b/test/playwright/visual-regression/components/header.spec.ts @@ -25,7 +25,7 @@ test.describe('header snapshots', () => { }) test.describe('header', () => { - breakpoints.describeEachDesktopExceptMd(({ expectSnapshot }) => { + breakpoints.describeEachDesktop(({ expectSnapshot }) => { test('filters open', async ({ page }) => { await page.mouse.move(0, 150) await expectSnapshot( @@ -36,14 +36,14 @@ test.describe('header snapshots', () => { test('resting', async ({ page }) => { // By default, filters are open. We need to close them. - await closeFilters(page) + await closeFilters(page, 'old') // Make sure the header is not hovered on await page.mouse.move(0, 150) await expectSnapshot(`resting-${dir}`, page.locator(headerSelector)) }) test('scrolled', async ({ page }) => { - await closeFilters(page) + await closeFilters(page, 'old') await scrollToBottom(page) await page.mouse.move(0, 150) await sleep(200) @@ -54,7 +54,7 @@ test.describe('header snapshots', () => { }) test('searchbar hovered', async ({ page }) => { - await closeFilters(page) + await closeFilters(page, 'old') await page.hover('input') await hideInputCursors(page) await expectSnapshot( @@ -64,7 +64,7 @@ test.describe('header snapshots', () => { }) test('searchbar active', async ({ page }) => { - await closeFilters(page) + await closeFilters(page, 'old') await hideInputCursors(page) await page.click('input') await expectSnapshot(