Regalamiunsorriso/faceai/tests/live-site/live-site-test-utils.js

230 lines
No EOL
7.6 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const { expect } = require('@playwright/test');
const { loadLiveEnv } = require('./load-live-env');
loadLiveEnv();
const WORKSPACE_ROOT = path.resolve(__dirname, '..', '..', '..');
const LIVE_SITE_BASE_URL = process.env.LIVE_SITE_BASE_URL || 'https://www.regalamiunsorriso.it';
const LIVE_SITE_LOGIN_URL = process.env.LIVE_SITE_LOGIN_URL || `${LIVE_SITE_BASE_URL}/login_clienti-it.html`;
const LIVE_SITE_RACE_URL = process.env.LIVE_SITE_RACE_URL || `${LIVE_SITE_BASE_URL}/42%20HALF%20MARATHON%20FIRENZE_gara-1018545---96-1.html`;
const LIVE_FACEAI_BASE_URL = process.env.LIVE_FACEAI_BASE_URL || 'https://ai.regalamiunsorriso.it';
const LIVE_SITE_RESULT_URL_PATTERN = process.env.LIVE_SITE_RESULT_URL_PATTERN || `${LIVE_SITE_BASE_URL}/faceai_return.php`;
const LIVE_SITE_REQUIRE_AUTH = process.env.LIVE_SITE_REQUIRE_AUTH !== '0';
const LIVE_SITE_USERNAME = process.env.LIVE_SITE_USERNAME || '';
const LIVE_SITE_PASSWORD = process.env.LIVE_SITE_PASSWORD || '';
const LIVE_SITE_PORTRAIT_PATH = process.env.LIVE_SITE_PORTRAIT_PATH || path.join(WORKSPACE_ROOT, 'test_pkl', 'live', 'test_portrait_1.png');
const LIVE_SITE_RUN_UPLOAD_FLOW = process.env.LIVE_SITE_RUN_UPLOAD_FLOW === '1';
const LIVE_SITE_EXPECT_RACE_DATA_AVAILABLE = process.env.LIVE_SITE_EXPECT_RACE_DATA_AVAILABLE !== '0';
const LIVE_SITE_EXPECT_UNAVAILABLE_REASON_CODE = process.env.LIVE_SITE_EXPECT_UNAVAILABLE_REASON_CODE || 'RACE_DIRECTORY_NOT_FOUND';
const AUTH_FILE = path.join(__dirname, '.auth', 'user.json');
function parseOptionalCsv(value) {
return String(value || '')
.split(',')
.map((entry) => entry.trim())
.filter(Boolean);
}
function parseRaceIdFromUrl(value) {
const match = String(value || '').match(/_gara-(\d+)---/i);
return match ? match[1] : '';
}
const LIVE_SITE_RACE_ID = process.env.LIVE_SITE_RACE_ID || parseRaceIdFromUrl(LIVE_SITE_RACE_URL);
const LIVE_EXPECTED_RACE_STORAGE = {
year: String(process.env.LIVE_SITE_EXPECTED_RACE_YEAR || '').trim(),
monthFolder: String(process.env.LIVE_SITE_EXPECTED_RACE_MONTH_FOLDER || '').trim(),
raceFolder: String(process.env.LIVE_SITE_EXPECTED_RACE_FOLDER || '').trim(),
relativeDir: String(process.env.LIVE_SITE_EXPECTED_RACE_STORAGE_RELATIVE_DIR || '').trim()
};
const LIVE_SITE_SAMPLE_PHOTO_IDS = parseOptionalCsv(process.env.LIVE_SITE_SAMPLE_PHOTO_IDS);
function hasExpectedRaceStorage() {
return Boolean(
LIVE_EXPECTED_RACE_STORAGE.year
&& LIVE_EXPECTED_RACE_STORAGE.monthFolder
&& LIVE_EXPECTED_RACE_STORAGE.raceFolder
&& LIVE_EXPECTED_RACE_STORAGE.relativeDir
);
}
function ensureAuthDirectory() {
fs.mkdirSync(path.dirname(AUTH_FILE), { recursive: true });
}
function requireCredentials() {
if (!LIVE_SITE_USERNAME || !LIVE_SITE_PASSWORD) {
throw new Error('LIVE_SITE_USERNAME and LIVE_SITE_PASSWORD must be set before running the live-site Playwright suite.');
}
}
async function dismissCookieBanner(page) {
const cookieButton = page.getByRole('button', { name: /^(Accetto|Accept)$/i });
if (await cookieButton.count()) {
await cookieButton.first().click({ timeout: 5000 }).catch(() => {});
return;
}
const fallbackButton = page.locator('.cc-btn, .cc-dismiss, .cc-allow').filter({ hasText: /Accetto|Accept/i });
if (await fallbackButton.count()) {
await fallbackButton.first().click({ timeout: 5000 }).catch(() => {});
}
}
function loginSubmitLocator(page) {
return page.locator('a.btn').filter({ hasText: /Accedi|Sign in/i }).first();
}
function buildLoginFormData() {
requireCredentials();
return {
login: LIVE_SITE_USERNAME,
pwd: LIVE_SITE_PASSWORD,
cmdIU: 'check',
act: '',
thePage: ''
};
}
async function gotoWithRetry(page, url, options = {}, maxAttempts = 3) {
let lastError = null;
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
try {
await page.goto(url, options);
return;
} catch (error) {
lastError = error;
if (!/ERR_ABORTED/i.test(String(error)) || attempt === maxAttempts) {
throw error;
}
}
}
throw lastError;
}
async function performLiveLogin(page) {
if (!LIVE_SITE_REQUIRE_AUTH) {
return;
}
requireCredentials();
await gotoWithRetry(page, LIVE_SITE_LOGIN_URL, { waitUntil: 'commit' });
await dismissCookieBanner(page);
await page.locator('#login').fill(LIVE_SITE_USERNAME);
await page.locator('#pwd').fill(LIVE_SITE_PASSWORD);
await loginSubmitLocator(page).click();
await waitForLoggedInUi(page);
}
async function performLiveLoginRequest(requestContext) {
if (!LIVE_SITE_REQUIRE_AUTH) {
return;
}
const response = await requestContext.post(`${LIVE_SITE_BASE_URL}/Logon.abl`, {
form: buildLoginFormData(),
failOnStatusCode: false
});
const finalUrl = response.url();
const bodyText = await response.text();
if (!response.ok()) {
throw new Error(`Live login request failed with HTTP ${response.status()} at ${finalUrl}`);
}
if (/login_clienti|Username \/ Email|Password/iu.test(bodyText) && !/user_logout|dettaglio_clienti|Il mio account/iu.test(bodyText)) {
throw new Error(`Live login request appears to have remained on the login page at ${finalUrl}`);
}
}
async function waitForLoggedInUi(page) {
const accountMenu = page.locator('#navbarDropdownMenuLink');
const accountLink = page.locator('a[href*="dettaglio_clienti"]');
const logoutLink = page.locator('a[href*="user_logout"]');
await expect.poll(async () => {
if (await accountMenu.count() && await accountMenu.first().isVisible().catch(() => false)) {
return 'account-menu';
}
if (await accountLink.count() && await accountLink.first().isVisible().catch(() => false)) {
return 'account-link';
}
if (await logoutLink.count() && await logoutLink.first().isVisible().catch(() => false)) {
return 'logout-link';
}
return '';
}, {
timeout: 30 * 1000,
message: 'Expected the logged-in account UI to appear after authenticating.'
}).not.toBe('');
}
async function expectRacePageLoaded(page) {
await expect(page.locator('form[onsubmit="return searching()"]')).toBeVisible();
await expect(page.locator('#id_gara')).toHaveValue(/\d+/);
await expect(page.locator('script[src*="_js/rus-ecom-240621.js"]')).toHaveCount(1);
}
async function ensureLiveAuthenticatedRacePage(page) {
await gotoWithRetry(page, LIVE_SITE_RACE_URL, { waitUntil: 'commit' });
await dismissCookieBanner(page);
if (!LIVE_SITE_REQUIRE_AUTH) {
await expectRacePageLoaded(page);
return;
}
try {
await waitForLoggedInUi(page);
} catch (error) {
await performLiveLoginRequest(page.context().request);
await gotoWithRetry(page, LIVE_SITE_RACE_URL, { waitUntil: 'commit' });
await dismissCookieBanner(page);
await waitForLoggedInUi(page);
}
await expectRacePageLoaded(page);
}
function requirePortraitFixture() {
if (!fs.existsSync(LIVE_SITE_PORTRAIT_PATH)) {
throw new Error(`LIVE_SITE_PORTRAIT_PATH does not exist: ${LIVE_SITE_PORTRAIT_PATH}`);
}
}
module.exports = {
AUTH_FILE,
LIVE_FACEAI_BASE_URL,
LIVE_EXPECTED_RACE_STORAGE,
LIVE_SITE_BASE_URL,
LIVE_SITE_LOGIN_URL,
LIVE_SITE_PASSWORD,
LIVE_SITE_PORTRAIT_PATH,
LIVE_SITE_REQUIRE_AUTH,
LIVE_SITE_EXPECT_RACE_DATA_AVAILABLE,
LIVE_SITE_EXPECT_UNAVAILABLE_REASON_CODE,
LIVE_SITE_RACE_ID,
LIVE_SITE_RACE_URL,
LIVE_SITE_RESULT_URL_PATTERN,
LIVE_SITE_RUN_UPLOAD_FLOW,
LIVE_SITE_SAMPLE_PHOTO_IDS,
LIVE_SITE_USERNAME,
dismissCookieBanner,
ensureLiveAuthenticatedRacePage,
ensureAuthDirectory,
expectRacePageLoaded,
hasExpectedRaceStorage,
loginSubmitLocator,
parseRaceIdFromUrl,
performLiveLogin,
performLiveLoginRequest,
requirePortraitFixture,
requireCredentials,
waitForLoggedInUi
};