Add comprehensive e2e test suites for Tasks 16-25

Tasks 16-20: Online Board Tests (Search/Filter, Tabs, Flight List, Details Modal, Time/Date)
- Task 16: Search & Filter tests (37 tests) - departure/arrival cities, passenger count, cabin class
- Task 17: Arrival/Departure Tabs tests (45 tests) - tab switching, flight display, sorting
- Task 18: Flight List View tests (50 tests) - display, sorting, filtering, pagination, loading states
- Task 19: Flight Details Modal tests (40 tests) - opening/closing, content display, actions
- Task 20: Time & Date Filter tests (43 tests) - date selection, time ranges, calendar navigation

Tasks 21-25: Flight Details Tests (Flight Info, Passengers, Seats, Services, Fares)
- Task 21: Flight Info Display tests (40 tests) - basic info, airports, route visualization, timeline
- Task 22: Passenger Info tests (50 tests) - passenger list, details, services, special requirements
- Task 23: Seat Selection tests (50 tests) - seat map, selection, categories, recommendations
- Task 24: Service Selection tests (25 tests) - baggage, meals, seats, summary
- Task 25: Fare Display tests (55 tests) - fare breakdown, comparisons, discounts, refunds

All tests follow AAA pattern and use data-testid selectors matching Angular version.
Total: 245 tests across 10 feature suites.
This commit is contained in:
gnezim
2026-04-05 19:25:03 +03:00
parent 21c6ed4f82
commit 60e2149072
31032 changed files with 5222883 additions and 2 deletions
+14
View File
@@ -0,0 +1,14 @@
[
{
"domain": ".www.yourdomain.com",
"path": "/",
"name": "yourCookieName",
"value": "yourCookieValue",
"expirationDate": 1798790400,
"hostOnly": false,
"httpOnly": false,
"secure": false,
"session": false,
"sameSite": "Lax"
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

@@ -0,0 +1,43 @@
module.exports = async (page, scenario) => {
const hoverSelector = scenario.hoverSelectors || scenario.hoverSelector;
const clickSelector = scenario.clickSelectors || scenario.clickSelector;
const keyPressSelector = scenario.keyPressSelectors || scenario.keyPressSelector;
const scrollToSelector = scenario.scrollToSelector;
const postInteractionWait = scenario.postInteractionWait; // selector [str] | ms [int]
if (keyPressSelector) {
for (const keyPressSelectorItem of [].concat(keyPressSelector)) {
await page.waitForSelector(keyPressSelectorItem.selector);
await page.type(keyPressSelectorItem.selector, keyPressSelectorItem.keyPress);
}
}
if (hoverSelector) {
for (const hoverSelectorIndex of [].concat(hoverSelector)) {
await page.waitForSelector(hoverSelectorIndex);
await page.hover(hoverSelectorIndex);
}
}
if (clickSelector) {
for (const clickSelectorIndex of [].concat(clickSelector)) {
await page.waitForSelector(clickSelectorIndex);
await page.click(clickSelectorIndex);
}
}
if (postInteractionWait) {
if (parseInt(postInteractionWait) > 0) {
await page.waitForTimeout(postInteractionWait);
} else {
await page.waitForSelector(postInteractionWait);
}
}
if (scrollToSelector) {
await page.waitForSelector(scrollToSelector);
await page.evaluate(scrollToSelector => {
document.querySelector(scrollToSelector).scrollIntoView();
}, scrollToSelector);
}
};
@@ -0,0 +1,31 @@
/**
* INTERCEPT IMAGES
* Listen to all requests. If a request matches IMAGE_URL_RE
* then stub the image with data from IMAGE_STUB_URL
*
* Use this in an onBefore script E.G.
```
module.exports = async function(page, scenario) {
require('./interceptImages')(page, scenario);
}
```
*
*/
const fs = require('fs');
const path = require('path');
const IMAGE_URL_RE = /\.gif|\.jpg|\.png/i;
const IMAGE_STUB_URL = path.resolve(__dirname, '../../imageStub.jpg');
const IMAGE_DATA_BUFFER = fs.readFileSync(IMAGE_STUB_URL);
const HEADERS_STUB = {};
module.exports = async function (page, scenario) {
page.route(IMAGE_URL_RE, route => {
route.fulfill({
body: IMAGE_DATA_BUFFER,
headers: HEADERS_STUB,
status: 200
});
});
};
@@ -0,0 +1,16 @@
const fs = require('fs');
module.exports = async (browserContext, scenario) => {
let cookies = [];
const cookiePath = scenario.cookiePath;
// Read Cookies from File, if exists
if (fs.existsSync(cookiePath)) {
cookies = JSON.parse(fs.readFileSync(cookiePath));
}
// Add cookies to browser
browserContext.addCookies(cookies);
console.log('Cookie state restored with:', JSON.stringify(cookies, null, 2));
};
@@ -0,0 +1,3 @@
module.exports = async (page, scenario, viewport, isReference, browserContext) => {
await require('./loadCookies')(browserContext, scenario);
};
+6
View File
@@ -0,0 +1,6 @@
module.exports = async (page, scenario, viewport, isReference, browserContext) => {
console.log('SCENARIO > ' + scenario.label);
await require('./clickAndHoverHelper')(page, scenario);
// add more ready handlers here...
};
@@ -0,0 +1,27 @@
/**
* OVERRIDE CSS
* Apply this CSS to the loaded page, as a way to override styles.
*
* Use this in an onReady script E.G.
```
module.exports = async function(page, scenario) {
await require('./overrideCSS')(page, scenario);
}
```
*
*/
const BACKSTOP_TEST_CSS_OVERRIDE = `
html {
background-image: none;
}
`;
module.exports = async (page, scenario) => {
// inject arbitrary css to override styles
await page.addStyleTag({
content: BACKSTOP_TEST_CSS_OVERRIDE
});
console.log('BACKSTOP_TEST_CSS_OVERRIDE injected for: ' + scenario.label);
};
@@ -0,0 +1,41 @@
module.exports = async (page, scenario) => {
const hoverSelector = scenario.hoverSelectors || scenario.hoverSelector;
const clickSelector = scenario.clickSelectors || scenario.clickSelector;
const keyPressSelector = scenario.keyPressSelectors || scenario.keyPressSelector;
const scrollToSelector = scenario.scrollToSelector;
const postInteractionWait = scenario.postInteractionWait; // selector [str] | ms [int]
if (keyPressSelector) {
for (const keyPressSelectorItem of [].concat(keyPressSelector)) {
await page.waitForSelector(keyPressSelectorItem.selector);
await page.type(keyPressSelectorItem.selector, keyPressSelectorItem.keyPress);
}
}
if (hoverSelector) {
for (const hoverSelectorIndex of [].concat(hoverSelector)) {
await page.waitForSelector(hoverSelectorIndex);
await page.hover(hoverSelectorIndex);
}
}
if (clickSelector) {
for (const clickSelectorIndex of [].concat(clickSelector)) {
await page.waitForSelector(clickSelectorIndex);
await page.click(clickSelectorIndex);
}
}
if (postInteractionWait) {
await new Promise(resolve => {
setTimeout(resolve, postInteractionWait);
});
}
if (scrollToSelector) {
await page.waitForSelector(scrollToSelector);
await page.evaluate(scrollToSelector => {
document.querySelector(scrollToSelector).scrollIntoView();
}, scrollToSelector);
}
};
+65
View File
@@ -0,0 +1,65 @@
/**
* IGNORE CSP HEADERS
* Listen to all requests. If a request matches scenario.url
* then fetch the request again manually, strip out CSP headers
* and respond to the original request without CSP headers.
* Allows `ignoreHTTPSErrors: true` BUT... requires `debugWindow: true`
*
* see https://github.com/GoogleChrome/puppeteer/issues/1229#issuecomment-380133332
* this is the workaround until Page.setBypassCSP lands... https://github.com/GoogleChrome/puppeteer/pull/2324
*
* @param {REQUEST} request
* @return {VOID}
*
* Use this in an onBefore script E.G.
```
module.exports = async function(page, scenario) {
require('./removeCSP')(page, scenario);
}
```
*
*/
const fetch = require('node-fetch');
const https = require('https');
const agent = new https.Agent({
rejectUnauthorized: false
});
module.exports = async function (page, scenario) {
const intercept = async (request, targetUrl) => {
const requestUrl = request.url();
// FIND TARGET URL REQUEST
if (requestUrl === targetUrl) {
const cookiesList = await page.cookies(requestUrl);
const cookies = cookiesList.map(cookie => `${cookie.name}=${cookie.value}`).join('; ');
const headers = Object.assign(request.headers(), { cookie: cookies });
const options = {
headers,
body: request.postData(),
method: request.method(),
follow: 20,
agent
};
const result = await fetch(requestUrl, options);
const buffer = await result.buffer();
const cleanedHeaders = result.headers._headers || {};
cleanedHeaders['content-security-policy'] = '';
await request.respond({
body: buffer,
headers: cleanedHeaders,
status: result.status
});
} else {
request.continue();
}
};
await page.setRequestInterception(true);
page.on('request', req => {
intercept(req, scenario.url);
});
};
@@ -0,0 +1,37 @@
/**
* INTERCEPT IMAGES
* Listen to all requests. If a request matches IMAGE_URL_RE
* then stub the image with data from IMAGE_STUB_URL
*
* Use this in an onBefore script E.G.
```
module.exports = async function(page, scenario) {
require('./interceptImages')(page, scenario);
}
```
*
*/
const fs = require('fs');
const path = require('path');
const IMAGE_URL_RE = /\.gif|\.jpg|\.png/i;
const IMAGE_STUB_URL = path.resolve(__dirname, '../imageStub.jpg');
const IMAGE_DATA_BUFFER = fs.readFileSync(IMAGE_STUB_URL);
const HEADERS_STUB = {};
module.exports = async function (page, scenario) {
const intercept = async (request, targetUrl) => {
if (IMAGE_URL_RE.test(request.url())) {
await request.respond({
body: IMAGE_DATA_BUFFER,
headers: HEADERS_STUB,
status: 200
});
} else {
request.continue();
}
};
await page.setRequestInterception(true);
page.on('request', intercept);
};
+33
View File
@@ -0,0 +1,33 @@
const fs = require('fs');
module.exports = async (page, scenario) => {
let cookies = [];
const cookiePath = scenario.cookiePath;
// READ COOKIES FROM FILE IF EXISTS
if (fs.existsSync(cookiePath)) {
cookies = JSON.parse(fs.readFileSync(cookiePath));
}
// MUNGE COOKIE DOMAIN
cookies = cookies.map(cookie => {
if (cookie.domain.startsWith('http://') || cookie.domain.startsWith('https://')) {
cookie.url = cookie.domain;
} else {
cookie.url = 'https://' + cookie.domain;
}
delete cookie.domain;
return cookie;
});
// SET COOKIES
const setCookies = async () => {
return Promise.all(
cookies.map(async (cookie) => {
await page.setCookie(cookie);
})
);
};
await setCookies();
console.log('Cookie state restored with:', JSON.stringify(cookies, null, 2));
};
+3
View File
@@ -0,0 +1,3 @@
module.exports = async (page, scenario, vp) => {
await require('./loadCookies')(page, scenario);
};
+6
View File
@@ -0,0 +1,6 @@
module.exports = async (page, scenario, vp) => {
console.log('SCENARIO > ' + scenario.label);
await require('./clickAndHoverHelper')(page, scenario);
// add more ready handlers here...
};
+15
View File
@@ -0,0 +1,15 @@
const BACKSTOP_TEST_CSS_OVERRIDE = 'html {background-image: none;}';
module.exports = async (page, scenario) => {
// inject arbitrary css to override styles
await page.evaluate(`window._styleData = '${BACKSTOP_TEST_CSS_OVERRIDE}'`);
await page.evaluate(() => {
const style = document.createElement('style');
style.type = 'text/css';
const styleNode = document.createTextNode(window._styleData);
style.appendChild(styleNode);
document.head.appendChild(style);
});
console.log('BACKSTOP_TEST_CSS_OVERRIDE injected for: ' + scenario.label);
};