3b35c29b9f
Improve text sanitization logic and update comments in test files to be more concise and informative. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 316e780f-e839-41c5-9826-be64a0fe9d70 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/dYJU04s Replit-Helium-Checkpoint-Created: true
163 lines
4.7 KiB
JavaScript
163 lines
4.7 KiB
JavaScript
import { test, expect } from "@playwright/test";
|
|
import pg from "pg";
|
|
|
|
const DATABASE_URL = process.env.DATABASE_URL;
|
|
if (!DATABASE_URL) {
|
|
throw new Error(
|
|
"DATABASE_URL must be set to run the cell-level subheading-chip UI test",
|
|
);
|
|
}
|
|
|
|
const pool = new pg.Pool({ connectionString: DATABASE_URL });
|
|
const createdMeetingIds = [];
|
|
|
|
const RANDOM_DATE_BASE_DAYS =
|
|
1900 + Math.floor(Math.random() * 1000) + ((Date.now() / 1000) | 0) % 500;
|
|
function uniqueFutureDate(offsetDays) {
|
|
const d = new Date();
|
|
d.setUTCDate(d.getUTCDate() + RANDOM_DATE_BASE_DAYS + offsetDays * 7);
|
|
return d.toISOString().slice(0, 10);
|
|
}
|
|
|
|
async function insertMeeting({
|
|
meetingDate,
|
|
dailyNumber,
|
|
titleEn,
|
|
titleAr,
|
|
startTime,
|
|
endTime,
|
|
}) {
|
|
const { rows } = await pool.query(
|
|
`INSERT INTO executive_meetings
|
|
(daily_number, title_ar, title_en, meeting_date, start_time, end_time, status)
|
|
VALUES ($1, $2, $3, $4, $5, $6, 'scheduled')
|
|
RETURNING id`,
|
|
[dailyNumber, titleAr, titleEn, meetingDate, startTime, endTime],
|
|
);
|
|
const id = rows[0].id;
|
|
createdMeetingIds.push(id);
|
|
return id;
|
|
}
|
|
|
|
async function insertAttendee({
|
|
meetingId,
|
|
name,
|
|
attendanceType,
|
|
sortOrder,
|
|
kind,
|
|
}) {
|
|
await pool.query(
|
|
`INSERT INTO executive_meeting_attendees
|
|
(meeting_id, name, attendance_type, sort_order, kind)
|
|
VALUES ($1, $2, $3, $4, $5)`,
|
|
[meetingId, name, attendanceType, sortOrder, kind ?? "person"],
|
|
);
|
|
}
|
|
|
|
async function loginViaUi(page) {
|
|
await page.goto("/login");
|
|
await page.locator("#username").fill("admin");
|
|
await page.locator("#password").fill("admin123");
|
|
await Promise.all([
|
|
page.waitForURL((url) => !url.pathname.endsWith("/login"), {
|
|
timeout: 15_000,
|
|
}),
|
|
page.locator('form button[type="submit"]').click(),
|
|
]);
|
|
}
|
|
|
|
async function ensureEditModeOn(page) {
|
|
const toggle = page.getByTestId("em-edit-mode-toggle");
|
|
await expect(toggle).toBeVisible();
|
|
if ((await toggle.getAttribute("aria-pressed")) === "false") {
|
|
await toggle.click();
|
|
}
|
|
await expect(toggle).toHaveAttribute("aria-pressed", "true");
|
|
}
|
|
|
|
test.afterAll(async () => {
|
|
if (createdMeetingIds.length > 0) {
|
|
await pool.query(
|
|
`DELETE FROM executive_meeting_attendees WHERE meeting_id = ANY($1::int[])`,
|
|
[createdMeetingIds],
|
|
);
|
|
await pool.query(
|
|
`DELETE FROM executive_meeting_audit_logs WHERE entity_type = 'meeting' AND entity_id = ANY($1::int[])`,
|
|
[createdMeetingIds],
|
|
);
|
|
await pool.query(
|
|
`DELETE FROM executive_meetings WHERE id = ANY($1::int[])`,
|
|
[createdMeetingIds],
|
|
);
|
|
}
|
|
await pool.end();
|
|
});
|
|
|
|
// #235: the cell-level "+ subheading" chip must hide while a pending
|
|
// subheading input is open and reappear after Escape cancels it.
|
|
test("Schedule: cell-level subheading chip stays hidden while a pending subheading input is open", async ({
|
|
page,
|
|
}) => {
|
|
await page.addInitScript(() => {
|
|
try {
|
|
window.localStorage.setItem("tx-lang", "en");
|
|
} catch {
|
|
/* localStorage may not be ready before navigation */
|
|
}
|
|
});
|
|
// hasSplit = virtual.length > 0 AND (internal.length > 0 OR external.length > 0).
|
|
const date = uniqueFutureDate(0);
|
|
const meetingId = await insertMeeting({
|
|
meetingDate: date,
|
|
dailyNumber: 1,
|
|
titleEn: `Subheading Chip Hidden ${Date.now().toString(36)}`,
|
|
titleAr: `إخفاء شارة العنوان الفرعي ${Date.now().toString(36)}`,
|
|
startTime: "09:00:00",
|
|
endTime: "10:00:00",
|
|
});
|
|
await insertAttendee({
|
|
meetingId,
|
|
name: "Virtual Person",
|
|
attendanceType: "virtual",
|
|
sortOrder: 0,
|
|
kind: "person",
|
|
});
|
|
await insertAttendee({
|
|
meetingId,
|
|
name: "Internal Person",
|
|
attendanceType: "internal",
|
|
sortOrder: 1,
|
|
kind: "person",
|
|
});
|
|
|
|
await loginViaUi(page);
|
|
await page.goto("/executive-meetings");
|
|
await ensureEditModeOn(page);
|
|
await page.locator('input[type="date"]').first().fill(date);
|
|
|
|
const row = page.getByTestId(`em-row-${meetingId}`);
|
|
await expect(row).toBeVisible({ timeout: 15_000 });
|
|
|
|
const chip = page.getByTestId(`em-add-subheading-cell-${meetingId}`);
|
|
await expect(chip).toBeVisible({ timeout: 10_000 });
|
|
await expect(
|
|
page.locator('[data-testid^="em-add-subheading-pending-"]'),
|
|
).toHaveCount(0);
|
|
|
|
await chip.click();
|
|
await expect(
|
|
page.locator('[data-testid^="em-add-subheading-pending-"]').first(),
|
|
).toBeVisible({ timeout: 5_000 });
|
|
await expect(
|
|
page.getByTestId(`em-add-subheading-cell-${meetingId}`),
|
|
).toHaveCount(0);
|
|
|
|
await page.keyboard.press("Escape");
|
|
await expect(
|
|
page.locator('[data-testid^="em-add-subheading-pending-"]'),
|
|
).toHaveCount(0, { timeout: 5_000 });
|
|
await expect(
|
|
page.getByTestId(`em-add-subheading-cell-${meetingId}`),
|
|
).toBeVisible({ timeout: 5_000 });
|
|
});
|