// Ported from chibistar/automation/starr/test-advertisements-doc.cjs — see // ~/Downloads/ADMIN_Advertisements_Test_Case_Documentation.txt. // // Not ported here (dropped, not silently): TC-ADV-013/014/015/016/017/018 // (archived-table sort/filter/refresh/export/columns — generic DataTable // behavior already covered structurally by the Courses admin spec's // equivalent checks) and test-client-advertisements-live.cjs / // test-ad-image-select.cjs, both hardcoded against specific live-site rows // (a real advertisement_id, a real course_id, user_id 132's live DB state) // that don't exist on a fresh local dev DB and can't be faithfully // recreated without fabricating the exact scenario they were checking. const { test, expect } = require('@playwright/test'); const { APP_URL, USERS } = require('../../helpers/env'); const { generateClientSession, buildCookies } = require('../../helpers/session'); const { cleanupQaTestFixtures } = require('../../helpers/cleanup'); async function settle(page, ms = 1200) { await page.waitForLoadState('networkidle').catch(() => {}); await page.waitForTimeout(ms); } const TS = Date.now().toString().slice(-6); const QA_HEADLINE = `[QA-TEST] Advertisements Doc Pass ${TS}`; const QA_HEADLINE_EDITED = `${QA_HEADLINE} (edited)`; test.describe.serial('Advertisements (admin)', () => { test.setTimeout(120_000); let adminCookies; test.beforeAll(async () => { test.setTimeout(60_000); const { refreshToken } = await generateClientSession(USERS.admin.email); adminCookies = buildCookies(refreshToken); }); test.afterAll(async () => { const removed = await cleanupQaTestFixtures(); console.log('QA-TEST fixtures removed:', removed); }); test.beforeEach(async ({ page }) => { await page.context().addCookies(adminCookies); }); test('TC-ADV-006/007/008: New Advertisement wizard blocks missing placement, happy-path create as Draft', async ({ page }) => { await page.goto(`${APP_URL}/admin/advertisements/add`, { waitUntil: 'networkidle' }); await settle(page, 1000); await expect(page.getByText('Choose where this ad appears')).toBeVisible(); // TC-ADV-007: missing placement blocks Next await page.getByRole('button', { name: 'Next' }).click(); await page.waitForTimeout(1200); await expect(page.getByText('Choose where this ad appears')).toBeVisible(); // TC-ADV-008: happy path await page.locator('button').filter({ hasText: 'Select a placement' }).click(); await page.getByRole('option', { name: /Tier Plans/ }).click(); await page.waitForTimeout(400); await page.getByRole('button', { name: 'Next' }).click(); await page.waitForTimeout(400); await page.getByText('Content + image', { exact: false }).click(); await page.getByPlaceholder('e.g. Advertisement').fill('QA-TEST Badge'); await page.getByPlaceholder(/Discover the World/).fill(QA_HEADLINE); await page.getByPlaceholder('Supporting text under the headline').fill('QA-TEST description for the Advertisements doc pass.'); await page.getByRole('button', { name: 'Next' }).click(); await page.waitForTimeout(400); if (await page.getByText('build an internal landing page').isVisible().catch(() => false)) { await page.getByPlaceholder('e.g. Why upgrade to Pro').fill('QA-TEST Landing Page'); await page.getByPlaceholder('Short summary shown under the title').fill('QA-TEST landing summary.'); await page.getByPlaceholder('Main page content').fill('QA-TEST landing body content.'); await page.getByRole('button', { name: 'Next' }).click(); await page.waitForTimeout(400); } const activeSwitch = page.locator('button[role="switch"]'); if (await activeSwitch.isVisible().catch(() => false)) { if ((await activeSwitch.getAttribute('aria-checked')) === 'true') await activeSwitch.click(); // force Draft } await page.waitForTimeout(300); await page.getByRole('button', { name: 'Next' }).click(); await page.waitForTimeout(400); await expect(page.getByText(QA_HEADLINE)).toBeVisible(); await page.getByRole('button', { name: 'Create advertisement' }).click(); await page.waitForURL('**/admin/advertisements', { timeout: 15000 }); await settle(page, 1500); await expect(page.getByText(QA_HEADLINE).first()).toBeVisible(); }); test('TC-ADV-002/009: view then edit the advertisement', async ({ page }) => { await page.goto(`${APP_URL}/admin/advertisements`, { waitUntil: 'networkidle' }); await settle(page); await page.getByText(QA_HEADLINE).first().click(); await page.waitForURL('**/admin/advertisements/*/view', { timeout: 10000 }); await settle(page, 800); await expect(page.getByRole('heading', { name: QA_HEADLINE })).toBeVisible(); await page.getByRole('button', { name: 'Edit' }).click(); await page.waitForURL('**/admin/advertisements/*/edit', { timeout: 10000 }); await settle(page, 800); const hInput = page.getByPlaceholder(/Discover the World/); await hInput.fill(''); await hInput.fill(QA_HEADLINE_EDITED); await page.getByRole('button', { name: /save changes/i }).click(); await page.waitForTimeout(1200); await page.goto(`${APP_URL}/admin/advertisements`, { waitUntil: 'networkidle' }); await settle(page, 1200); await expect(page.getByText(QA_HEADLINE_EDITED).first()).toBeVisible(); }); test('TC-ADV-010/011/012: archive, appears in Archived, restore back to active', async ({ page }) => { await page.goto(`${APP_URL}/admin/advertisements`, { waitUntil: 'networkidle' }); await settle(page); const qaCard = page.locator('div.rounded-lg.border').filter({ hasText: QA_HEADLINE_EDITED }).first(); await qaCard.getByLabel('Delete').click(); await page.getByText('will be moved to archived advertisements').waitFor({ timeout: 8000 }); await expect(page.getByText('QA-TEST', { exact: false })).toBeVisible(); await page.getByRole('button', { name: 'Archive' }).click(); await settle(page, 2500); await expect(page.locator('div.rounded-lg.border').filter({ hasText: QA_HEADLINE_EDITED })).toHaveCount(0); await page.getByRole('button', { name: 'Archived' }).click(); await page.waitForURL('**/admin/advertisements/archived', { timeout: 10000 }); await settle(page, 1200); await expect(page.getByText(QA_HEADLINE_EDITED).first()).toBeVisible(); const row = page.locator('table tbody tr').filter({ hasText: QA_HEADLINE_EDITED }).first(); await row.locator('button').last().click(); await page.waitForTimeout(500); await page.getByText('Restore', { exact: true }).click(); await page.waitForTimeout(500); await page.getByRole('button', { name: /^restore$/i }).click(); await settle(page, 1800); await page.goto(`${APP_URL}/admin/advertisements`, { waitUntil: 'networkidle' }); await settle(page); await expect(page.locator('div.rounded-lg.border').filter({ hasText: QA_HEADLINE_EDITED })).toBeVisible(); }); test('TC-ADV-019: archive then permanently delete (cleanup path)', async ({ page }) => { await page.goto(`${APP_URL}/admin/advertisements`, { waitUntil: 'networkidle' }); await settle(page); const qaCard = page.locator('div.rounded-lg.border').filter({ hasText: QA_HEADLINE_EDITED }).first(); await qaCard.getByLabel('Delete').click(); await page.waitForTimeout(600); await page.getByRole('button', { name: 'Archive' }).click(); await settle(page, 2500); await page.goto(`${APP_URL}/admin/advertisements/archived`, { waitUntil: 'networkidle' }); await settle(page, 1500); const row = page.locator('table tbody tr').filter({ hasText: QA_HEADLINE_EDITED }).first(); await row.locator('button').last().click(); await page.waitForTimeout(500); await page.getByText('Delete', { exact: true }).click(); await page.waitForTimeout(500); await page.getByRole('button', { name: /delete permanently/i }).click(); await settle(page, 2000); await page.reload({ waitUntil: 'networkidle' }); await settle(page, 1000); await expect(page.getByText(QA_HEADLINE_EDITED)).toHaveCount(0); }); });