375bcfb0fa
Copies Playwright e2e tests (58 specs, 300+ tests) designed for cross-app testing. Adapts API mocks to match real Aeroflot dictionary format (title objects with multilingual keys), adds board/schedule/days endpoint mocks, and provides Angular-specific Playwright config on port 4203.
580 lines
22 KiB
TypeScript
580 lines
22 KiB
TypeScript
import { test, expect } from '../support/cross-app-fixtures';
|
|
import { mockAllAPIs } from '../support/cross-app-fixtures';
|
|
import { S, tid } from '../support/selectors';
|
|
|
|
/**
|
|
* Flight Details Tests (147-181)
|
|
*
|
|
* Tests the flight details page at /:locale/onlineboard/:flightSlug
|
|
* e.g., /ru-ru/onlineboard/SU1234-20260406
|
|
*
|
|
* The flight details page is accessed either by:
|
|
* 1. Clicking a flight result from a search results page
|
|
* 2. Direct URL navigation to /onlineboard/{flight-slug}
|
|
*
|
|
* Since the Angular reference app may not have real flight data,
|
|
* we navigate to a flight that exists (if any) or skip gracefully.
|
|
*/
|
|
|
|
/** Helper: today formatted as YYYYMMDD */
|
|
function formatToday(): string {
|
|
const d = new Date();
|
|
return `${d.getFullYear()}${String(d.getMonth() + 1).padStart(2, '0')}${String(d.getDate()).padStart(2, '0')}`;
|
|
}
|
|
|
|
/** Helper: tomorrow formatted as YYYYMMDD */
|
|
function formatTomorrow(): string {
|
|
const d = new Date();
|
|
d.setDate(d.getDate() + 1);
|
|
return `${d.getFullYear()}${String(d.getMonth() + 1).padStart(2, '0')}${String(d.getDate()).padStart(2, '0')}`;
|
|
}
|
|
|
|
/**
|
|
* Mock flight details endpoint.
|
|
* Global mocks are already applied via fixture.
|
|
* Must be called BEFORE page.goto().
|
|
*/
|
|
async function mockFlightDetailsAPIs(page: import('@playwright/test').Page) {
|
|
// Mock flight details endpoint: /api/Requests/{id}/getflight
|
|
// The Angular app calls this endpoint when navigating to /onlineboard/{flightSlug}
|
|
await page.route('**/api/Requests/*/getflight', (route) => {
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
id: 'SU1234-20260406',
|
|
flightNumber: 'SU 1234',
|
|
airlineName: 'Aeroflot',
|
|
status: 'On Time',
|
|
lastUpdated: '2026-04-07 15:30',
|
|
departure: {
|
|
cityCode: 'MOW',
|
|
cityName: 'Moscow',
|
|
terminal: '1',
|
|
stationCode: 'SVO',
|
|
},
|
|
arrival: {
|
|
cityCode: 'SPB',
|
|
cityName: 'Saint Petersburg',
|
|
terminal: '1',
|
|
stationCode: 'LED',
|
|
},
|
|
aircraft: {
|
|
model: 'Boeing 737-800',
|
|
registration: 'VP-BDZ',
|
|
},
|
|
schedule: {
|
|
scheduledDeparture: '10:30',
|
|
scheduledArrival: '12:00',
|
|
duration: '1h 30m',
|
|
operatingDays: [1, 2, 3, 4, 5],
|
|
utcOffset: '+03:00',
|
|
},
|
|
checkin: {
|
|
status: 'Completed',
|
|
startTime: '09:00',
|
|
endTime: '10:00',
|
|
},
|
|
boarding: {
|
|
status: 'In Progress',
|
|
startTime: '10:00',
|
|
endTime: '10:20',
|
|
},
|
|
deplaning: {
|
|
status: 'Completed',
|
|
startTime: '12:05',
|
|
endTime: '12:20',
|
|
transfer: 'T1',
|
|
gate: '5',
|
|
baggageBelt: '3',
|
|
},
|
|
catering: {
|
|
available: true,
|
|
services: ['Food', 'Drinks'],
|
|
},
|
|
}),
|
|
});
|
|
});
|
|
|
|
// Mock flight search endpoints for navigation
|
|
await page.route('**/api/flights/**', (route) => {
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify([]),
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Navigate to a flight details page.
|
|
* If the flight slug is not provided, we attempt to navigate via search.
|
|
*/
|
|
async function navigateToFlightDetails(
|
|
page: import('@playwright/test').Page,
|
|
app: 'angular' | 'react',
|
|
localePath: (path: string) => string,
|
|
flightSlug: string = 'SU1234-20260406',
|
|
) {
|
|
// Try to navigate directly to flight details
|
|
const detailsURL = localePath(`onlineboard/${flightSlug}`);
|
|
await page.goto(detailsURL, { waitUntil: 'networkidle' });
|
|
|
|
// Verify the page loaded by checking for critical elements
|
|
// If flight details page has a header, we're good
|
|
// If we get a 404 or the page doesn't render, the test will skip
|
|
}
|
|
|
|
test.describe('Flight Details (Cross-App)', () => {
|
|
test.beforeEach(async ({ page, app, localePath }) => {
|
|
await mockAllAPIs(page);
|
|
await mockFlightDetailsAPIs(page);
|
|
// Navigate to flight details
|
|
await navigateToFlightDetails(page, app, localePath, 'SU1234-20260406');
|
|
});
|
|
|
|
// ────────────────────────────────────────────────────────────────────────
|
|
// Navigation & Page Load (6 tests: 147-152)
|
|
// ────────────────────────────────────────────────────────────────────────
|
|
|
|
test('147: Flight details page loads without errors', async ({ page }) => {
|
|
// Verify page is not in an error state
|
|
const errorElements = page.locator('[data-testid*="error"], .error-container, [role="alert"]');
|
|
const errorCount = await errorElements.count();
|
|
expect(errorCount).toBe(0);
|
|
|
|
// Verify page title or header is present
|
|
const header = page.locator('h1, h2, [data-testid*="header"], [data-testid*="flight"]').first();
|
|
const headerCount = await header.count();
|
|
expect(headerCount).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
test('148: Flight details URL contains correct flight slug', async ({ page, locale }) => {
|
|
const url = page.url();
|
|
expect(url).toMatch(new RegExp(`/${locale}/onlineboard/SU\\d+-\\d+`));
|
|
});
|
|
|
|
test('149: Page title displays flight number', async ({ page }) => {
|
|
// Check for flight number in page title or heading
|
|
const flightNumber = page.locator('h1, h2, [data-testid*="flight-number"]').first();
|
|
if ((await flightNumber.count()) > 0) {
|
|
const text = await flightNumber.textContent();
|
|
expect(text).toMatch(/SU\s*1234|SU1234/i);
|
|
}
|
|
});
|
|
|
|
test('150: Back button navigates to previous search results', async ({ page, app }) => {
|
|
// Some implementations may not have explicit back buttons
|
|
const backButton = page.locator(
|
|
`${tid(S.BOARD_CANCEL_BUTTON, app)}, button[aria-label*="Back"i], a[href*="back"]`,
|
|
);
|
|
if ((await backButton.count()) > 0) {
|
|
const urlBefore = page.url();
|
|
await backButton.first().click();
|
|
await page.waitForTimeout(500);
|
|
const urlAfter = page.url();
|
|
// URL should have changed
|
|
expect(urlAfter).not.toBe(urlBefore);
|
|
} else {
|
|
test.skip(true, 'Back button not found in this app');
|
|
}
|
|
});
|
|
|
|
test('151: Page renders with correct layout (header + content)', async ({ page }) => {
|
|
// Look for main layout structure
|
|
const body = page.locator('body');
|
|
expect(await body.count()).toBeGreaterThan(0);
|
|
|
|
// Should have some content beyond just empty page
|
|
const content = page.locator('main, [role="main"], .container, .content, .page-content');
|
|
const contentCount = await content.count();
|
|
expect(contentCount).toBeGreaterThanOrEqual(0);
|
|
});
|
|
|
|
test('152: All text content matches current locale', async ({ page, locale }) => {
|
|
// Check that locale is reflected in visible content or attributes
|
|
const html = page.locator('html');
|
|
const langAttr = await html.getAttribute('lang');
|
|
if (langAttr) {
|
|
expect(langAttr.toLowerCase()).toMatch(/ru|en/i);
|
|
}
|
|
});
|
|
|
|
// ────────────────────────────────────────────────────────────────────────
|
|
// Flight Header & Basic Info (8 tests: 153-160)
|
|
// ────────────────────────────────────────────────────────────────────────
|
|
|
|
test('153: Flight number is displayed with correct formatting', async ({ page, app }) => {
|
|
const flightNumber = page.locator(tid(S.DETAILS_FLIGHT_NUMBER, app));
|
|
if ((await flightNumber.count()) > 0) {
|
|
await expect(flightNumber).toBeVisible();
|
|
const text = await flightNumber.textContent();
|
|
expect(text).toMatch(/SU\s*1234|SU1234/i);
|
|
} else {
|
|
test.skip(true, 'Flight number selector not found');
|
|
}
|
|
});
|
|
|
|
test('154: Flight status badge shows current status', async ({ page, app }) => {
|
|
const statusBadge = page.locator(tid(S.DETAILS_STATUS, app));
|
|
if ((await statusBadge.count()) > 0) {
|
|
await expect(statusBadge).toBeVisible();
|
|
const text = await statusBadge.textContent();
|
|
expect(text).toBeTruthy();
|
|
} else {
|
|
test.skip(true, 'Status badge not found');
|
|
}
|
|
});
|
|
|
|
test('155: Airline logo is displayed', async ({ page, app }) => {
|
|
const logo = page.locator(tid(S.DETAILS_OPERATOR_LOGO, app));
|
|
if ((await logo.count()) > 0) {
|
|
await expect(logo).toBeVisible();
|
|
} else {
|
|
// Fallback: look for any image or logo element
|
|
const altLogo = page.locator('img[alt*="airline" i], img[alt*="aeroflot" i]');
|
|
if ((await altLogo.count()) > 0) {
|
|
await expect(altLogo.first()).toBeVisible();
|
|
} else {
|
|
test.skip(true, 'Airline logo not found');
|
|
}
|
|
}
|
|
});
|
|
|
|
test('156: Aircraft model is displayed', async ({ page, app }) => {
|
|
const aircraftModel = page.locator(tid(S.DETAILS_AIRCRAFT_MODEL, app));
|
|
if ((await aircraftModel.count()) > 0) {
|
|
await expect(aircraftModel).toBeVisible();
|
|
const text = await aircraftModel.textContent();
|
|
expect(text).toBeTruthy();
|
|
} else {
|
|
// Fallback: look for aircraft text
|
|
const altAircraft = page.locator('[data-testid*="aircraft"], [data-testid*="equipment"]');
|
|
if ((await altAircraft.count()) > 0) {
|
|
await expect(altAircraft.first()).toBeVisible();
|
|
} else {
|
|
test.skip(true, 'Aircraft model not found');
|
|
}
|
|
}
|
|
});
|
|
|
|
test('157: Departure time is displayed with timezone', async ({ page, app }) => {
|
|
const depTime = page.locator(tid(S.DETAILS_DEPARTURE_TIME, app));
|
|
if ((await depTime.count()) > 0) {
|
|
await expect(depTime).toBeVisible();
|
|
const text = await depTime.textContent();
|
|
expect(text).toMatch(/\d+:\d+/);
|
|
} else {
|
|
test.skip(true, 'Departure time selector not found');
|
|
}
|
|
});
|
|
|
|
test('158: Arrival time is displayed with timezone', async ({ page, app }) => {
|
|
const arrTime = page.locator(tid(S.DETAILS_ARRIVAL_TIME, app));
|
|
if ((await arrTime.count()) > 0) {
|
|
await expect(arrTime).toBeVisible();
|
|
const text = await arrTime.textContent();
|
|
expect(text).toMatch(/\d+:\d+/);
|
|
} else {
|
|
test.skip(true, 'Arrival time selector not found');
|
|
}
|
|
});
|
|
|
|
test('159: Flight duration is displayed', async ({ page, app }) => {
|
|
const duration = page.locator(tid(S.DETAILS_DURATION, app));
|
|
if ((await duration.count()) > 0) {
|
|
await expect(duration).toBeVisible();
|
|
const text = await duration.textContent();
|
|
expect(text).toMatch(/\d+h/);
|
|
} else {
|
|
// Fallback: look for duration text
|
|
const altDuration = page.locator('text=/\\d+h\\s*\\d*m/i');
|
|
if ((await altDuration.count()) > 0) {
|
|
await expect(altDuration.first()).toBeVisible();
|
|
} else {
|
|
test.skip(true, 'Duration not found');
|
|
}
|
|
}
|
|
});
|
|
|
|
test('160: Days of operation info is displayed', async ({ page }) => {
|
|
// Look for day badges or operating schedule info
|
|
const dayBadges = page.locator(
|
|
'[data-testid*="day" i], .day-badge, [data-testid*="operating" i]',
|
|
);
|
|
if ((await dayBadges.count()) > 0) {
|
|
await expect(dayBadges.first()).toBeVisible();
|
|
} else {
|
|
test.skip(true, 'Days of operation info not displayed');
|
|
}
|
|
});
|
|
|
|
// ────────────────────────────────────────────────────────────────────────
|
|
// Departure & Arrival Section (6 tests: 161-166)
|
|
// ────────────────────────────────────────────────────────────────────────
|
|
|
|
test('161: Departure station code is displayed', async ({ page, app }) => {
|
|
const depStation = page.locator(tid(S.DETAILS_DEPARTURE_STATION, app));
|
|
if ((await depStation.count()) > 0) {
|
|
await expect(depStation).toBeVisible();
|
|
const text = await depStation.textContent();
|
|
expect(text).toMatch(/MOW|LED|SVO/i);
|
|
} else {
|
|
test.skip(true, 'Departure station selector not found');
|
|
}
|
|
});
|
|
|
|
test('162: Departure station name is displayed', async ({ page }) => {
|
|
// Look for city name (e.g., "Moscow") or station name
|
|
const depName = page.locator('[data-testid*="departure"] [data-testid*="name"]');
|
|
if ((await depName.count()) > 0) {
|
|
await expect(depName.first()).toBeVisible();
|
|
} else {
|
|
test.skip(true, 'Departure station name not found');
|
|
}
|
|
});
|
|
|
|
test('163: Departure terminal is displayed', async ({ page, app }) => {
|
|
const terminal = page.locator(tid(S.DETAILS_TERMINAL_LINK, app));
|
|
if ((await terminal.count()) > 0) {
|
|
await expect(terminal).toBeVisible();
|
|
} else {
|
|
// Fallback: look for terminal text
|
|
const altTerminal = page.locator('text=/Terminal\\s*\\d+/i');
|
|
if ((await altTerminal.count()) > 0) {
|
|
await expect(altTerminal.first()).toBeVisible();
|
|
} else {
|
|
test.skip(true, 'Terminal info not displayed (may be optional)');
|
|
}
|
|
}
|
|
});
|
|
|
|
test('164: Arrival station code is displayed', async ({ page, app }) => {
|
|
const arrStation = page.locator(tid(S.DETAILS_ARRIVAL_STATION, app));
|
|
if ((await arrStation.count()) > 0) {
|
|
await expect(arrStation).toBeVisible();
|
|
const text = await arrStation.textContent();
|
|
expect(text).toMatch(/MOW|LED|SVO|VKO/i);
|
|
} else {
|
|
test.skip(true, 'Arrival station selector not found');
|
|
}
|
|
});
|
|
|
|
test('165: Arrival station name is displayed', async ({ page }) => {
|
|
// Look for city name
|
|
const arrName = page.locator('[data-testid*="arrival"] [data-testid*="name"]');
|
|
if ((await arrName.count()) > 0) {
|
|
await expect(arrName.first()).toBeVisible();
|
|
} else {
|
|
test.skip(true, 'Arrival station name not found');
|
|
}
|
|
});
|
|
|
|
test('166: Arrival terminal is displayed', async ({ page }) => {
|
|
// Look for terminal information in arrival section
|
|
const terminal = page.locator('[data-testid*="arrival"]').locator('text=/Terminal/');
|
|
if ((await terminal.count()) > 0) {
|
|
await expect(terminal.first()).toBeVisible();
|
|
} else {
|
|
test.skip(true, 'Arrival terminal not displayed (may be optional)');
|
|
}
|
|
});
|
|
|
|
// ────────────────────────────────────────────────────────────────────────
|
|
// Route & Transfer Info (4 tests: 167-170)
|
|
// ────────────────────────────────────────────────────────────────────────
|
|
|
|
test('167: Direct flight shows no intermediate stops', async ({ page, app }) => {
|
|
// For a direct flight, there should be no transfer section visible
|
|
// or the transfer section should explicitly state "Direct"
|
|
const transferSection = page.locator(tid(S.DETAILS_TRANSFER_SECTION, app));
|
|
if ((await transferSection.count()) > 0) {
|
|
const text = await transferSection.textContent();
|
|
expect(text).toMatch(/Direct|no transfer|прямой/i);
|
|
} else {
|
|
test.skip(true, 'Transfer section not found (expected for direct flight)');
|
|
}
|
|
});
|
|
|
|
test('168: Transfer flight shows transfer station', async ({ page, app }) => {
|
|
// If flight has transfers, the transfer station should be shown
|
|
const transferSection = page.locator(tid(S.DETAILS_TRANSFER_SECTION, app));
|
|
if ((await transferSection.count()) > 0) {
|
|
const text = await transferSection.textContent();
|
|
// Should contain either a station code or explicit transfer info
|
|
expect(text).toBeTruthy();
|
|
} else {
|
|
test.skip(true, 'Transfer section not shown (flight may be direct)');
|
|
}
|
|
});
|
|
|
|
test('169: Full route section shows all segments', async ({ page, app }) => {
|
|
const fullRoute = page.locator(tid(S.DETAILS_FULL_ROUTE, app));
|
|
if ((await fullRoute.count()) > 0) {
|
|
await expect(fullRoute).toBeVisible();
|
|
} else {
|
|
test.skip(true, 'Full route section not found');
|
|
}
|
|
});
|
|
|
|
test('170: Transfer time is displayed for multi-segment flights', async ({ page }) => {
|
|
// Look for transfer time information
|
|
const transferTime = page.locator('[data-testid*="transfer"]');
|
|
if ((await transferTime.count()) > 0) {
|
|
await expect(transferTime.first()).toBeVisible();
|
|
} else {
|
|
test.skip(true, 'Transfer time not displayed (may be direct flight)');
|
|
}
|
|
});
|
|
|
|
// ────────────────────────────────────────────────────────────────────────
|
|
// Action Buttons (7 tests: 171-177)
|
|
// ────────────────────────────────────────────────────────────────────────
|
|
|
|
test('171: "Buy Ticket" button is visible and clickable', async ({ page, app }) => {
|
|
const buyBtn = page.locator(tid(S.DETAILS_BUY_TICKET_BUTTON, app));
|
|
if ((await buyBtn.count()) > 0) {
|
|
await expect(buyBtn).toBeVisible();
|
|
await expect(buyBtn).toBeEnabled();
|
|
} else {
|
|
test.skip(true, 'Buy Ticket button not found');
|
|
}
|
|
});
|
|
|
|
test('172: "Register" button is visible and clickable', async ({ page, app }) => {
|
|
const regBtn = page.locator(tid(S.DETAILS_REGISTRATION_BUTTON, app));
|
|
if ((await regBtn.count()) > 0) {
|
|
await expect(regBtn).toBeVisible();
|
|
await expect(regBtn).toBeEnabled();
|
|
} else {
|
|
test.skip(true, 'Registration button not found');
|
|
}
|
|
});
|
|
|
|
test('173: "Print" button is visible and clickable', async ({ page, app }) => {
|
|
const printBtn = page.locator(tid(S.DETAILS_PRINT_BUTTON, app));
|
|
if ((await printBtn.count()) > 0) {
|
|
await expect(printBtn).toBeVisible();
|
|
await expect(printBtn).toBeEnabled();
|
|
} else {
|
|
test.skip(true, 'Print button not found');
|
|
}
|
|
});
|
|
|
|
test('174: "Share" button is visible and clickable', async ({ page, app }) => {
|
|
const shareBtn = page.locator(tid(S.DETAILS_SHARE_BUTTON, app));
|
|
if ((await shareBtn.count()) > 0) {
|
|
await expect(shareBtn).toBeVisible();
|
|
await expect(shareBtn).toBeEnabled();
|
|
} else {
|
|
test.skip(true, 'Share button not found');
|
|
}
|
|
});
|
|
|
|
test('175: "Flight Status" button is visible and clickable', async ({ page, app }) => {
|
|
const statusBtn = page.locator(tid(S.DETAILS_FLIGHT_STATUS_BUTTON, app));
|
|
if ((await statusBtn.count()) > 0) {
|
|
await expect(statusBtn).toBeVisible();
|
|
await expect(statusBtn).toBeEnabled();
|
|
} else {
|
|
test.skip(true, 'Flight Status button not found');
|
|
}
|
|
});
|
|
|
|
test('176: "Book Now" button leads to booking page', async ({ page }) => {
|
|
// Look for a button that triggers booking
|
|
const bookBtn = page.locator('button[data-testid*="booking"], a[href*="book"]');
|
|
if ((await bookBtn.count()) > 0) {
|
|
const href = await bookBtn.first().getAttribute('href');
|
|
if (href) {
|
|
expect(href).toBeTruthy();
|
|
}
|
|
} else {
|
|
test.skip(true, 'Book Now button not found');
|
|
}
|
|
});
|
|
|
|
test('177: Share button opens share dialog', async ({ page, app }) => {
|
|
const shareBtn = page.locator(tid(S.DETAILS_SHARE_BUTTON, app));
|
|
if ((await shareBtn.count()) > 0) {
|
|
await shareBtn.first().click();
|
|
await page.waitForTimeout(500);
|
|
// Check if a dialog or modal opened
|
|
const dialog = page.locator('[role="dialog"], .modal, .share-dialog');
|
|
const dialogOrClipboard =
|
|
(await dialog.count()) > 0 ||
|
|
(await page.evaluate(() => navigator.clipboard !== undefined));
|
|
expect(dialogOrClipboard).toBeTruthy();
|
|
} else {
|
|
test.skip(true, 'Share button not found');
|
|
}
|
|
});
|
|
|
|
// ────────────────────────────────────────────────────────────────────────
|
|
// Additional Info & Details (4 tests: 178-181)
|
|
// ────────────────────────────────────────────────────────────────────────
|
|
|
|
test('178: Equipment info (aircraft type) is displayed', async ({ page }) => {
|
|
// Look for aircraft/equipment information
|
|
const equipment = page.locator('[data-testid*="equipment"], [data-testid*="aircraft"]');
|
|
if ((await equipment.count()) > 0) {
|
|
await expect(equipment.first()).toBeVisible();
|
|
} else {
|
|
test.skip(true, 'Equipment info not displayed');
|
|
}
|
|
});
|
|
|
|
test('179: Codeshare info (if applicable) is displayed', async ({ page }) => {
|
|
// Look for codeshare information
|
|
const codeshare = page.locator('[data-testid*="codeshare"]');
|
|
if ((await codeshare.count()) > 0) {
|
|
await expect(codeshare.first()).toBeVisible();
|
|
} else {
|
|
test.skip(true, 'Codeshare info not displayed (may not apply)');
|
|
}
|
|
});
|
|
|
|
test('180: Frequent flyer/baggage info is displayed', async ({ page }) => {
|
|
// Look for baggage or frequent flyer information
|
|
const baggage = page.locator(
|
|
'[data-testid*="baggage"], [data-testid*="miles"], [data-testid*="frequent"]',
|
|
);
|
|
if ((await baggage.count()) > 0) {
|
|
await expect(baggage.first()).toBeVisible();
|
|
} else {
|
|
test.skip(true, 'Baggage/frequent flyer info not displayed (may be optional)');
|
|
}
|
|
});
|
|
|
|
test('181: Page renders without console errors', async ({ page }) => {
|
|
// Collect all console messages from the page
|
|
const errors: string[] = [];
|
|
page.on('console', (msg) => {
|
|
if (msg.type() === 'error') {
|
|
errors.push(msg.text());
|
|
}
|
|
});
|
|
|
|
// Check for uncaught exceptions
|
|
page.on('pageerror', (error) => {
|
|
errors.push(error.toString());
|
|
});
|
|
|
|
// Wait a bit for any delayed errors
|
|
await page.waitForTimeout(500);
|
|
|
|
// Filter out known safe errors and network-related errors
|
|
const safeErrors = errors.filter(
|
|
(err) =>
|
|
!err.includes('Loading chunk') &&
|
|
!err.includes('NetworkError') &&
|
|
!err.includes('404') &&
|
|
!err.includes('CORS') &&
|
|
!err.includes('Failed to fetch') &&
|
|
!err.includes('aeroflot.ru'),
|
|
);
|
|
|
|
expect(safeErrors).toEqual([]);
|
|
});
|
|
});
|