diff --git a/playwright.config.ts b/playwright.config.ts index acaec088..04e30920 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -12,7 +12,7 @@ export default defineConfig({ ], use: { headless: true, - baseURL: 'http://127.0.0.1:9090', + baseURL: process.env.BASE_URL ? process.env.BASE_URL : 'http://127.0.0.1:9090', video: 'retain-on-failure', trace: 'on-first-retry', diff --git a/playwright/lib/lib.ts b/playwright/lib/lib.ts index 93bbfff7..bdbcf5ed 100644 --- a/playwright/lib/lib.ts +++ b/playwright/lib/lib.ts @@ -1,21 +1,40 @@ import { expect, type Page, type FrameLocator } from '@playwright/test'; -export const ibFrame = (page: Page): FrameLocator => { +export const ibFrame = (page: Page): FrameLocator | Page => { + if (isHosted()) { + return page + } return page.locator('iframe[name="cockpit1\\:localhost\\/cockpit-image-builder"]').contentFrame(); } -export const loginCockpit = async ( - page: Page, - username?: string, - password?: string +export const login = async ( + page: Page ) => { - if (!username || !password) { - throw new Error('Username or password not found'); + if (!process.env.USER || !process.env.PASSWORD) { + throw new Error('user or password not set in environment'); } + const user = process.env.USER; + const password = process.env.PASSWORD; + + if (isHosted()) { + return loginConsole(page, user, password); + } + return loginCockpit(page, user, password); +} + +export const isHosted = (): Boolean => { + return process.env.BASE_URL?.includes('redhat.com') || false; +} + +const loginCockpit = async ( + page: Page, + user: string, + password: string +) => { await page.goto('/cockpit-image-builder'); - await page.getByRole('textbox', { name: 'User name' }).fill(username); + await page.getByRole('textbox', { name: 'User name' }).fill(user); await page.getByRole('textbox', { name: 'Password' }).fill(password); // cockpit-image-builder needs superuser @@ -24,3 +43,33 @@ export const loginCockpit = async ( await page.getByText('Close').click(); await page.getByRole('button', { name: 'Administrative access' }); }; + +const loginConsole = async ( + page: Page, + user: string, + password: string +) => { + await page.goto('/insights/image-builder/landing'); + await page.getByRole('textbox', { name: 'Red Hat login or email' }).fill(user); + await page.getByRole('button', { name: 'Next' }).click(); + await page.getByRole('textbox', { name: 'Password' }).fill(password); + await page.getByRole('button', { name: 'Log in' }).click(); + await closePopupsIfExist(page); + await page.locator('#preview-toggle').check(); + await page.getByRole('heading', { name: 'All images' }); +} + +const closePopupsIfExist = async (page: Page) => { + const locatorsToCheck = [ + page.locator('.pf-v5-c-alert.notification-item button'), // This closes all toast pop-ups + page.locator(`button[id^="pendo-close-guide-"]`), // This closes the pendo guide pop-up + page.locator(`button[id="truste-consent-button"]`), // This closes the trusted consent pop-up + page.getByLabel('close-notification'), // This closes a one off info notification (May be covered by the toast above, needs recheck.) + ]; + + for (const locator of locatorsToCheck) { + await page.addLocatorHandler(locator, async () => { + await locator.first().click(); // There can be multiple toast pop-ups + }); + } +}; diff --git a/playwright/test.spec.ts b/playwright/test.spec.ts index 874c5932..78ebba55 100644 --- a/playwright/test.spec.ts +++ b/playwright/test.spec.ts @@ -1,28 +1,45 @@ import { expect, test } from '@playwright/test'; +import { v4 as uuidv4 } from 'uuid'; + import { - loginCockpit, + login, ibFrame, + isHosted, } from './lib/lib'; -test.describe('test', () => { +test.describe.serial('test', () => { + let blueprintName = uuidv4(); test('create blueprint', async ({ page }) => { - await loginCockpit(page, 'admin', 'foobar'); - // await enableComposer(page); + await login(page) const frame = await ibFrame(page); - // image output await frame.getByRole('heading', { name: 'Images About image builder' }); await frame.getByRole('heading', { name: 'Blueprints' }); - await frame.getByRole('heading', { name: 'No blueprints yet' }); - await frame.getByTestId('create-blueprint-action-emptystate').click(); + await frame.getByTestId('blueprints-create-button').click(); + await frame.getByRole('heading', { name: 'Image output' }); await frame.getByTestId('checkbox-guest-image').click(); await frame.getByRole('button', { name: 'Next', exact: true }).click(); + if (isHosted()) { + await frame.getByRole('heading', { name: 'Register systems using this image' }); + await page.getByTestId('automatically-register-checkbox').uncheck(); + await frame.getByRole('button', { name: 'Next', exact: true }).click(); + await frame.getByRole('heading', { name: 'Compliance' }); + await frame.getByRole('button', { name: 'Next', exact: true }).click(); + } + await frame.getByRole('heading', { name: 'File system configuration' }); await frame.getByRole('button', { name: 'Next', exact: true }).click(); + if (isHosted()) { + await frame.getByRole('heading', { name: 'Repository snapshot' }); + await frame.getByRole('button', { name: 'Next', exact: true }).click(); + await frame.getByRole('heading', { name: 'Custom repositories' }); + await frame.getByRole('button', { name: 'Next', exact: true }).click(); + } + await frame.getByRole('heading', { name: 'Additional packages' }); await frame.getByRole('button', { name: 'Next', exact: true }).click(); @@ -47,25 +64,33 @@ test.describe('test', () => { await frame.getByRole('heading', { name: 'Systemd services' }); await frame.getByRole('button', { name: 'Next', exact: true }).click(); + if (isHosted()) { + await frame.getByRole('heading', { name: 'First boot configuration' }); + await frame.getByRole('button', { name: 'Next', exact: true }).click(); + } + await frame.getByRole('heading', { name: 'Details' }); - await frame.getByTestId('blueprint').fill('test-blueprint'); - await expect(frame.getByTestId('blueprint')).toHaveValue('test-blueprint'); + await frame.getByTestId('blueprint').fill(blueprintName); + await expect(frame.getByTestId('blueprint')).toHaveValue(blueprintName); await frame.getByRole('button', { name: 'Next', exact: true }).click(); await frame.getByRole('button', { name: 'Create blueprint' }).click(); await frame.getByTestId('close-button-saveandbuild-modal').click(); await frame.getByRole('button', { name: 'Create blueprint' }).click(); - await frame.getByText('test-blueprint'); + await frame.getByText(blueprintName); }); test('edit blueprint', async ({ page }) => { - // package searching is really slow the first time - test.setTimeout(300000) + // package searching is really slow the first time in cockpit + if (!isHosted()) { + test.setTimeout(300000); + } - await loginCockpit(page, 'admin', 'foobar'); + await login(page); const frame = await ibFrame(page); - await frame.getByText('test-blueprint').click(); + await frame.getByRole('textbox', { name: 'Search input' }).fill(blueprintName); + await frame.getByText(blueprintName, { exact: true }).first().click(); await frame.getByRole('button', { name: 'Edit blueprint' }).click(); await frame.getByRole('button', { name: 'Additional packages' }).click(); @@ -86,21 +111,22 @@ test.describe('test', () => { }); test('build blueprint', async ({ page }) => { - // add time enough for depsolving - test.setTimeout(60 * 1000); - await loginCockpit(page, 'admin', 'foobar'); + await login(page); const frame = await ibFrame(page); - await frame.getByText('test-blueprint').click(); + await frame.getByRole('textbox', { name: 'Search input' }).fill(blueprintName); + await frame.getByText(blueprintName, { exact: true }).first().click(); await frame.getByTestId('blueprint-build-image-menu-option').click(); // make sure the image is present - await frame.getByTestId('images-table').getByText('Fedora'); + await frame.getByTestId('images-table').getByRole('button', { name: 'Details' }).click(); + await frame.getByText('Build Information'); }); test('delete blueprint', async ({ page }) => { - await loginCockpit(page, 'admin', 'foobar'); + await login(page); const frame = await ibFrame(page); - await frame.getByText('test-blueprint').click(); + await frame.getByRole('textbox', { name: 'Search input' }).fill(blueprintName); + await frame.getByText(blueprintName, { exact: true }).first().click(); await frame.getByTestId('blueprint-action-menu-toggle').click(); await frame.getByRole('menuitem', { name: 'Delete blueprint' }).click(); await frame.getByRole('button', { name: 'Delete' }).click(); diff --git a/schutzbot/playwright_tests.sh b/schutzbot/playwright_tests.sh index cd2f39fa..100e53c1 100755 --- a/schutzbot/playwright_tests.sh +++ b/schutzbot/playwright_tests.sh @@ -71,6 +71,8 @@ sudo systemctl start osbuild-worker@1 sudo podman run \ -e "PLAYWRIGHT_HTML_OPEN=never" \ -e "CI=true" \ + -e "USER=admin" \ + -e "PASSWORD=foobar" \ --net=host \ -v "$PWD:/tests" \ --privileged \