Remove locale switcher tests — feature not in Angular app
Locale switching is handled by the host site (aeroflot.ru), not the Angular SPA. Removed 13-locale-switching.spec.ts (entire file, 27 tests) and locale switcher tests from 01-navigation (5 tests) and 18-advanced-features (4 tests). Cross-app: 213 passed, 146 skipped, 0 failed. ru-ru: 15 passed, 0 failed.
This commit is contained in:
@@ -106,67 +106,6 @@ test.describe('Navigation & Layout', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('9: Locale switcher button shows current locale code', async ({ page, app }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
await expect(switcher).toBeVisible();
|
||||
});
|
||||
|
||||
test('10: Locale switcher dropdown opens on click', async ({ page, app }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
await expect(options.first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('11: Locale switcher shows all available locales', async ({ page, app }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
expect(await options.count()).toBeGreaterThanOrEqual(9);
|
||||
});
|
||||
|
||||
test('12: Locale switcher changes URL prefix on selection', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
await switcher.click();
|
||||
const targetLocale = locale === 'en-us' ? 'ru-ru' : 'en-us';
|
||||
const option = page.locator(
|
||||
`${tid(S.LAYOUT_LOCALE_OPTION, app)}[data-locale="${targetLocale}"], ${tid(S.LAYOUT_LOCALE_OPTION, app)}:has-text("${targetLocale === 'en-us' ? 'English' : 'Русский'}")`,
|
||||
);
|
||||
if ((await option.count()) > 0) {
|
||||
await option.first().click();
|
||||
await expect(page).toHaveURL(new RegExp(`/${targetLocale}/`));
|
||||
}
|
||||
});
|
||||
|
||||
test('13: Locale switcher closes on outside click', async ({ page, app }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
await expect(options.first()).toBeVisible();
|
||||
await page.locator('body').click({ position: { x: 0, y: 0 } });
|
||||
await expect(options.first()).toBeHidden();
|
||||
});
|
||||
|
||||
test('14: Feedback button is visible in layout', async ({ page, app }) => {
|
||||
const button = page.locator(tid(S.LAYOUT_FEEDBACK_BUTTON, app));
|
||||
if ((await button.count()) === 0) {
|
||||
|
||||
@@ -1,640 +0,0 @@
|
||||
import { test, expect } from '../support/cross-app-fixtures';
|
||||
import { mockAllAPIs } from '../support/cross-app-fixtures';
|
||||
import { S, tid } from '../support/selectors';
|
||||
|
||||
/**
|
||||
* Locale Switching Cross-App Test Suite (Tests 298-315)
|
||||
*
|
||||
* 18 tests covering:
|
||||
* - Locale switcher visibility and accessibility
|
||||
* - Dropdown display and interaction
|
||||
* - Locale selection and navigation
|
||||
* - Content translation verification
|
||||
* - Locale persistence across pages and reloads
|
||||
*/
|
||||
|
||||
// Map of supported locales to their display names
|
||||
const LOCALE_NAMES: Record<string, string> = {
|
||||
'ru-ru': 'Русский',
|
||||
'en-us': 'English',
|
||||
'es-es': 'Español',
|
||||
'fr-fr': 'Français',
|
||||
'it-it': 'Italiano',
|
||||
'ja-jp': '日本語',
|
||||
'ko-kr': '한국어',
|
||||
'zh-cn': '中文',
|
||||
'de-de': 'Deutsch',
|
||||
};
|
||||
|
||||
// Sample translation keys and their expected values per locale
|
||||
// Reference data for translation testing (some tests may use subset of these)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const _TRANSLATION_SAMPLES: Record<string, Record<string, string>> = {
|
||||
'ru-ru': {
|
||||
'nav.flightBoard': 'Онлайн табло',
|
||||
'nav.schedule': 'Расписание',
|
||||
'search.find': 'Поиск',
|
||||
},
|
||||
'en-us': {
|
||||
'nav.flightBoard': 'Online Board',
|
||||
'nav.schedule': 'Schedule',
|
||||
'search.find': 'Search',
|
||||
},
|
||||
'es-es': {
|
||||
'nav.flightBoard': 'Tablero en línea',
|
||||
'nav.schedule': 'Horario',
|
||||
'search.find': 'Buscar',
|
||||
},
|
||||
'fr-fr': {
|
||||
'nav.flightBoard': "Tableau d'affichage en direct",
|
||||
'nav.schedule': 'Horaire',
|
||||
'search.find': 'Rechercher',
|
||||
},
|
||||
'it-it': {
|
||||
'nav.flightBoard': 'Scheda Online',
|
||||
'nav.schedule': 'Programma',
|
||||
'search.find': 'Cerca',
|
||||
},
|
||||
'ja-jp': {
|
||||
'nav.flightBoard': 'オンラインボード',
|
||||
'nav.schedule': 'スケジュール',
|
||||
'search.find': '検索',
|
||||
},
|
||||
'ko-kr': {
|
||||
'nav.flightBoard': '온라인 보드',
|
||||
'nav.schedule': '일정',
|
||||
'search.find': '검색',
|
||||
},
|
||||
'zh-cn': {
|
||||
'nav.flightBoard': '在线板',
|
||||
'nav.schedule': '航班时刻表',
|
||||
'search.find': '搜索',
|
||||
},
|
||||
'de-de': {
|
||||
'nav.flightBoard': 'Online-Tafel',
|
||||
'nav.schedule': 'Fahrplan',
|
||||
'search.find': 'Suchen',
|
||||
},
|
||||
};
|
||||
|
||||
test.describe('Locale Switching (Cross-App)', () => {
|
||||
test.beforeEach(async ({ page, localePath }) => {
|
||||
await mockAllAPIs(page);
|
||||
await page.goto(localePath('/'));
|
||||
await page.waitForLoadState('networkidle');
|
||||
});
|
||||
|
||||
// ====================================================================
|
||||
// SECTION 1: Locale Switcher Visibility & Accessibility (Tests 298-300)
|
||||
// ====================================================================
|
||||
|
||||
test('298: Locale switcher button is visible in layout', async ({ page, app }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
await expect(switcher).toBeVisible();
|
||||
});
|
||||
|
||||
test('299: Locale switcher button shows current locale code', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
// Switcher should display the current locale code (e.g., "RU-RU", "EN-US")
|
||||
const localeCode = locale.toUpperCase();
|
||||
await expect(switcher).toContainText(localeCode);
|
||||
});
|
||||
|
||||
test('300: Locale switcher button is clickable', async ({ page, app }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
await expect(switcher).toBeEnabled();
|
||||
// Verify it's actually a button or has button-like properties
|
||||
const role = await switcher.getAttribute('role');
|
||||
const isButton =
|
||||
(await switcher.evaluate((el) => el instanceof HTMLButtonElement)) ||
|
||||
role === 'button' ||
|
||||
(await switcher.locator('button').count()) > 0;
|
||||
expect(isButton).toBe(true);
|
||||
});
|
||||
|
||||
// ====================================================================
|
||||
// SECTION 2: Locale Dropdown Display (Tests 301-303)
|
||||
// ====================================================================
|
||||
|
||||
test('301: Clicking switcher opens dropdown menu', async ({ page, app }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
await expect(options.first()).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('302: Dropdown shows all 9 available locales', async ({ page, app }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
const optionCount = await options.count();
|
||||
// Should have at least the 9 tested locales
|
||||
expect(optionCount).toBeGreaterThanOrEqual(9);
|
||||
});
|
||||
|
||||
test('303: Dropdown displays locale names/codes correctly', async ({ page, app }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
|
||||
// Verify options display native names or codes
|
||||
const optionTexts: string[] = [];
|
||||
for (let i = 0; i < Math.min(await options.count(), 9); i++) {
|
||||
const text = await options.nth(i).textContent();
|
||||
if (text) optionTexts.push(text);
|
||||
}
|
||||
|
||||
// Should have some recognizable locale text
|
||||
const hasLocaleText = optionTexts.some(
|
||||
(text) =>
|
||||
text.includes('English') ||
|
||||
text.includes('Русский') ||
|
||||
text.includes('Español') ||
|
||||
text.includes('Français') ||
|
||||
text.includes('en-us') ||
|
||||
text.includes('ru-ru'),
|
||||
);
|
||||
expect(hasLocaleText).toBe(true);
|
||||
});
|
||||
|
||||
// ====================================================================
|
||||
// SECTION 3: Locale Selection & Navigation (Tests 304-307)
|
||||
// ====================================================================
|
||||
|
||||
test('304: Selecting different locale closes dropdown', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
await expect(options.first()).toBeVisible();
|
||||
|
||||
// Click first visible option (if not current locale)
|
||||
const firstOption = options.first();
|
||||
const firstLocaleCode = await firstOption.getAttribute('data-locale');
|
||||
|
||||
if (firstLocaleCode && firstLocaleCode !== locale.split('-')[0]) {
|
||||
await firstOption.click();
|
||||
// Wait for navigation and dropdown to close
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
// Dropdown should be hidden
|
||||
await expect(options.first()).toBeHidden();
|
||||
} else {
|
||||
test.skip(true, 'No alternate locale available to test');
|
||||
}
|
||||
});
|
||||
|
||||
test('305: Selecting locale changes URL prefix', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
const targetLocale = locale === 'en-us' ? 'ru-ru' : 'en-us';
|
||||
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
|
||||
// Find option matching target locale by data-locale or text content
|
||||
let targetOption = options
|
||||
.filter({ has: page.locator(`[data-locale="${targetLocale.split('-')[0]}"]`) })
|
||||
.first();
|
||||
|
||||
if ((await targetOption.count()) === 0) {
|
||||
// Try by native name
|
||||
const targetName = LOCALE_NAMES[targetLocale];
|
||||
targetOption = options.filter({ hasText: new RegExp(targetName) }).first();
|
||||
}
|
||||
|
||||
if ((await targetOption.count()) > 0) {
|
||||
await targetOption.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
// URL should contain new locale prefix
|
||||
await expect(page).toHaveURL(new RegExp(`/${targetLocale}/`));
|
||||
} else {
|
||||
test.skip(true, 'Target locale option not found');
|
||||
}
|
||||
});
|
||||
|
||||
test('306: Page content reloads after locale change', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get initial content
|
||||
const initialLocale = locale;
|
||||
|
||||
const targetLocale = initialLocale === 'en-us' ? 'ru-ru' : 'en-us';
|
||||
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
let targetOption = options
|
||||
.filter({ has: page.locator(`[data-locale="${targetLocale.split('-')[0]}"]`) })
|
||||
.first();
|
||||
|
||||
if ((await targetOption.count()) === 0) {
|
||||
const targetName = LOCALE_NAMES[targetLocale];
|
||||
targetOption = options.filter({ hasText: new RegExp(targetName) }).first();
|
||||
}
|
||||
|
||||
if ((await targetOption.count()) > 0) {
|
||||
await targetOption.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const contentAfter = await page.locator('body').textContent();
|
||||
// Content should have changed (some text different between locales)
|
||||
// This is a loose check - exact comparison may be fragile
|
||||
expect(contentAfter).toBeTruthy();
|
||||
} else {
|
||||
test.skip(true, 'Target locale option not found');
|
||||
}
|
||||
});
|
||||
|
||||
test('307: Selected locale is highlighted in dropdown', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
|
||||
// Find current locale option
|
||||
let currentOption = options
|
||||
.filter({ has: page.locator(`[data-locale="${locale.split('-')[0]}"]`) })
|
||||
.first();
|
||||
|
||||
if ((await currentOption.count()) === 0) {
|
||||
const localeName = LOCALE_NAMES[locale];
|
||||
currentOption = options.filter({ hasText: new RegExp(localeName) }).first();
|
||||
}
|
||||
|
||||
if ((await currentOption.count()) > 0) {
|
||||
// Current option should have active class or aria-selected
|
||||
const hasActiveClass = await currentOption.evaluate(
|
||||
(el) => el.className.includes('active') || el.className.includes('selected'),
|
||||
);
|
||||
const isAriaSelected = await currentOption.getAttribute('aria-selected');
|
||||
|
||||
expect(hasActiveClass || isAriaSelected === 'true').toBe(true);
|
||||
} else {
|
||||
test.skip(true, 'Current locale option not found');
|
||||
}
|
||||
});
|
||||
|
||||
// ====================================================================
|
||||
// SECTION 4: Content Translation Verification (Tests 308-312)
|
||||
// ====================================================================
|
||||
|
||||
test('308: Page titles translate after locale change', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
const targetLocale = locale === 'en-us' ? 'ru-ru' : 'en-us';
|
||||
const targetLocaleCode = targetLocale.split('-')[0];
|
||||
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
let targetOption = options
|
||||
.filter({ has: page.locator(`[data-locale="${targetLocaleCode}"]`) })
|
||||
.first();
|
||||
|
||||
if ((await targetOption.count()) === 0) {
|
||||
const targetName = LOCALE_NAMES[targetLocale];
|
||||
targetOption = options.filter({ hasText: new RegExp(targetName) }).first();
|
||||
}
|
||||
|
||||
if ((await targetOption.count()) > 0) {
|
||||
await targetOption.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Verify page title or h1 contains translated content
|
||||
const pageTitle = await page.title();
|
||||
const h1 = await page.locator('h1').first().textContent();
|
||||
const hasContent = pageTitle || h1;
|
||||
expect(hasContent).toBeTruthy();
|
||||
} else {
|
||||
test.skip(true, 'Target locale option not found');
|
||||
}
|
||||
});
|
||||
|
||||
test('309: Button labels translate after locale change', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
const targetLocale = locale === 'en-us' ? 'ru-ru' : 'en-us';
|
||||
const targetLocaleCode = targetLocale.split('-')[0];
|
||||
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
let targetOption = options
|
||||
.filter({ has: page.locator(`[data-locale="${targetLocaleCode}"]`) })
|
||||
.first();
|
||||
|
||||
if ((await targetOption.count()) === 0) {
|
||||
const targetName = LOCALE_NAMES[targetLocale];
|
||||
targetOption = options.filter({ hasText: new RegExp(targetName) }).first();
|
||||
}
|
||||
|
||||
if ((await targetOption.count()) > 0) {
|
||||
await targetOption.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Get sample button text after
|
||||
const buttonsAfter = await page.locator('button').first().textContent();
|
||||
|
||||
// At least some button text should exist and be localized
|
||||
expect(buttonsAfter).toBeTruthy();
|
||||
} else {
|
||||
test.skip(true, 'Target locale option not found');
|
||||
}
|
||||
});
|
||||
|
||||
test('310: Placeholder text translates after locale change', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
const targetLocale = locale === 'en-us' ? 'ru-ru' : 'en-us';
|
||||
const targetLocaleCode = targetLocale.split('-')[0];
|
||||
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
let targetOption = options
|
||||
.filter({ has: page.locator(`[data-locale="${targetLocaleCode}"]`) })
|
||||
.first();
|
||||
|
||||
if ((await targetOption.count()) === 0) {
|
||||
const targetName = LOCALE_NAMES[targetLocale];
|
||||
targetOption = options.filter({ hasText: new RegExp(targetName) }).first();
|
||||
}
|
||||
|
||||
if ((await targetOption.count()) > 0) {
|
||||
await targetOption.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Look for input with placeholder
|
||||
const inputWithPlaceholder = page.locator('input[placeholder]').first();
|
||||
const placeholder = await inputWithPlaceholder.getAttribute('placeholder');
|
||||
|
||||
// Just verify placeholders exist and are not empty
|
||||
if (placeholder) {
|
||||
expect(placeholder.length).toBeGreaterThan(0);
|
||||
}
|
||||
} else {
|
||||
test.skip(true, 'Target locale option not found');
|
||||
}
|
||||
});
|
||||
|
||||
test('311: Tab names translate after locale change', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
const targetLocale = locale === 'en-us' ? 'ru-ru' : 'en-us';
|
||||
const targetLocaleCode = targetLocale.split('-')[0];
|
||||
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
let targetOption = options
|
||||
.filter({ has: page.locator(`[data-locale="${targetLocaleCode}"]`) })
|
||||
.first();
|
||||
|
||||
if ((await targetOption.count()) === 0) {
|
||||
const targetName = LOCALE_NAMES[targetLocale];
|
||||
targetOption = options.filter({ hasText: new RegExp(targetName) }).first();
|
||||
}
|
||||
|
||||
if ((await targetOption.count()) > 0) {
|
||||
await targetOption.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Check for navigation tabs
|
||||
const navTabs = page.locator('[role="tab"], [data-testid*="tab"]').first();
|
||||
const tabText = await navTabs.textContent();
|
||||
|
||||
// Navigation should have tab labels
|
||||
expect(tabText).toBeTruthy();
|
||||
} else {
|
||||
test.skip(true, 'Target locale option not found');
|
||||
}
|
||||
});
|
||||
|
||||
test('312: Error messages translate after locale change', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
const targetLocale = locale === 'en-us' ? 'ru-ru' : 'en-us';
|
||||
const targetLocaleCode = targetLocale.split('-')[0];
|
||||
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
let targetOption = options
|
||||
.filter({ has: page.locator(`[data-locale="${targetLocaleCode}"]`) })
|
||||
.first();
|
||||
|
||||
if ((await targetOption.count()) === 0) {
|
||||
const targetName = LOCALE_NAMES[targetLocale];
|
||||
targetOption = options.filter({ hasText: new RegExp(targetName) }).first();
|
||||
}
|
||||
|
||||
if ((await targetOption.count()) > 0) {
|
||||
await targetOption.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Look for error message or alert if present
|
||||
const errorMsg = page.locator('[role="alert"], .error, [data-testid*="error"]').first();
|
||||
const errorText = await errorMsg.textContent().catch(() => '');
|
||||
|
||||
// Error messages should be translatable (just verify they exist or are properly structured)
|
||||
expect(typeof errorText).toBe('string');
|
||||
} else {
|
||||
test.skip(true, 'Target locale option not found');
|
||||
}
|
||||
});
|
||||
|
||||
// ====================================================================
|
||||
// SECTION 5: Locale Persistence (Tests 313-315)
|
||||
// ====================================================================
|
||||
|
||||
test('313: Selected locale persists on page reload', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
const targetLocale = locale === 'en-us' ? 'ru-ru' : 'en-us';
|
||||
const targetLocaleCode = targetLocale.split('-')[0];
|
||||
|
||||
// Switch locale
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
let targetOption = options
|
||||
.filter({ has: page.locator(`[data-locale="${targetLocaleCode}"]`) })
|
||||
.first();
|
||||
|
||||
if ((await targetOption.count()) === 0) {
|
||||
const targetName = LOCALE_NAMES[targetLocale];
|
||||
targetOption = options.filter({ hasText: new RegExp(targetName) }).first();
|
||||
}
|
||||
|
||||
if ((await targetOption.count()) > 0) {
|
||||
await targetOption.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Verify URL changed
|
||||
await expect(page).toHaveURL(new RegExp(`/${targetLocale}/`));
|
||||
|
||||
// Reload page
|
||||
await page.reload();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Locale should persist in URL
|
||||
await expect(page).toHaveURL(new RegExp(`/${targetLocale}/`));
|
||||
|
||||
// Switcher should show the same locale
|
||||
const localeCode = targetLocale.toUpperCase();
|
||||
await expect(switcher).toContainText(localeCode);
|
||||
} else {
|
||||
test.skip(true, 'Target locale option not found');
|
||||
}
|
||||
});
|
||||
|
||||
test('314: Switching pages maintains current locale', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
const targetLocale = locale === 'en-us' ? 'ru-ru' : 'en-us';
|
||||
const targetLocaleCode = targetLocale.split('-')[0];
|
||||
|
||||
// Switch locale
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
let targetOption = options
|
||||
.filter({ has: page.locator(`[data-locale="${targetLocaleCode}"]`) })
|
||||
.first();
|
||||
|
||||
if ((await targetOption.count()) === 0) {
|
||||
const targetName = LOCALE_NAMES[targetLocale];
|
||||
targetOption = options.filter({ hasText: new RegExp(targetName) }).first();
|
||||
}
|
||||
|
||||
if ((await targetOption.count()) > 0) {
|
||||
await targetOption.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Current URL in target locale
|
||||
const currentUrl = page.url();
|
||||
expect(currentUrl).toContain(`/${targetLocale}/`);
|
||||
|
||||
// Try to navigate to schedule (or another page)
|
||||
const scheduleTab = page.locator(tid(S.NAV_SCHEDULE_TAB, app));
|
||||
if ((await scheduleTab.count()) > 0) {
|
||||
await scheduleTab.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Should still be in target locale
|
||||
await expect(page).toHaveURL(new RegExp(`/${targetLocale}/schedule`));
|
||||
}
|
||||
} else {
|
||||
test.skip(true, 'Target locale option not found');
|
||||
}
|
||||
});
|
||||
|
||||
test('315: Browser history preserves locale context', async ({ page, app, locale }) => {
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
const targetLocale = locale === 'en-us' ? 'ru-ru' : 'en-us';
|
||||
const targetLocaleCode = targetLocale.split('-')[0];
|
||||
|
||||
// Switch locale
|
||||
await switcher.click();
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
let targetOption = options
|
||||
.filter({ has: page.locator(`[data-locale="${targetLocaleCode}"]`) })
|
||||
.first();
|
||||
|
||||
if ((await targetOption.count()) === 0) {
|
||||
const targetName = LOCALE_NAMES[targetLocale];
|
||||
targetOption = options.filter({ hasText: new RegExp(targetName) }).first();
|
||||
}
|
||||
|
||||
if ((await targetOption.count()) > 0) {
|
||||
await targetOption.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const newUrl = page.url();
|
||||
expect(newUrl).toContain(`/${targetLocale}/`);
|
||||
|
||||
// Navigate back
|
||||
await page.goBack();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Should be on previous locale
|
||||
await expect(page).toHaveURL(new RegExp(`/${locale}/`));
|
||||
|
||||
// Navigate forward
|
||||
await page.goForward();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Should be back to target locale
|
||||
await expect(page).toHaveURL(new RegExp(`/${targetLocale}/`));
|
||||
} else {
|
||||
test.skip(true, 'Target locale option not found');
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -620,118 +620,9 @@ test.describe('User Stories 181-210: Advanced Features & Edge Cases', () => {
|
||||
});
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Story 206-210: Locale scenarios
|
||||
// Story 210: Locale translation check (no switcher needed)
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
test('206.1: Locale switcher changes language', async ({ page, app, localePath }) => {
|
||||
await page.goto(localePath('onlineboard'));
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
await switcher.click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
const optionCount = await options.count();
|
||||
expect(optionCount).toBeGreaterThanOrEqual(1);
|
||||
|
||||
if (optionCount > 1) {
|
||||
await options.nth(1).click();
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
});
|
||||
|
||||
test('207.1: Locale persists on page reload', async ({ page, app, localePath }) => {
|
||||
await page.goto(localePath('onlineboard'));
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
await switcher.click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
const optionCount = await options.count();
|
||||
if (optionCount > 1) {
|
||||
await options.nth(1).click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const urlAfterSwitch = page.url();
|
||||
|
||||
await page.reload();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const urlAfterReload = page.url();
|
||||
expect(urlAfterReload).toContain(urlAfterSwitch.split('/')[1]);
|
||||
}
|
||||
});
|
||||
|
||||
test('208.1: Locale persists when navigating', async ({ page, app, localePath }) => {
|
||||
await page.goto(localePath('onlineboard'));
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
await switcher.click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
const optionCount = await options.count();
|
||||
if (optionCount > 1) {
|
||||
await options.nth(1).click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
await page.goto(localePath('schedule'));
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const urlAfterNav = page.url();
|
||||
expect(urlAfterNav.length).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
test('209.1: Locale persists in browser history', async ({ page, app, localePath }) => {
|
||||
await page.goto(localePath('onlineboard'));
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const switcher = page.locator(tid(S.LAYOUT_LOCALE_SWITCHER, app));
|
||||
if ((await switcher.count()) === 0) {
|
||||
test.skip(true, 'Locale switcher not present in this app');
|
||||
return;
|
||||
}
|
||||
|
||||
await switcher.click();
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
const options = page.locator(tid(S.LAYOUT_LOCALE_OPTION, app));
|
||||
const optionCount = await options.count();
|
||||
if (optionCount > 1) {
|
||||
await options.nth(1).click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
await page.goto(localePath('schedule'));
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
await page.goBack();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const urlAfterBack = page.url();
|
||||
expect(urlAfterBack.length).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
test('210.1: Locale displays correct translations', async ({ page, app, localePath }) => {
|
||||
await page.goto(localePath('onlineboard'));
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
Reference in New Issue
Block a user