From a880232d93ec411f595b101ebe1aa95597fdef8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ladislav=20Slez=C3=A1k?= Date: Thu, 23 Mar 2023 09:21:51 +0100 Subject: [PATCH] Test fixes, improved Playwright tests --- .github/workflows/ci.yml | 8 +++ playwright/README.md | 72 ++++++++++++++++++++++++++ playwright/global-setup.ts | 14 ++++- playwright/lib/installer.ts | 15 ++++++ playwright/tests/main_page.spec.ts | 3 +- playwright/tests/root_password.spec.ts | 28 +++++++--- 6 files changed, 131 insertions(+), 9 deletions(-) create mode 100644 playwright/lib/installer.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1513f61c0e..3fd8207e74 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,6 +83,10 @@ jobs: - name: Git Checkout uses: actions/checkout@v3 + - name: Configure and refresh repositories + # disable unused repositories to have faster refresh + run: zypper modifyrepo -d repo-non-oss repo-openh264 repo-update && ( zypper ref || zypper ref || zypper ref ) + - name: Install Ruby development files run: zypper --non-interactive install gcc gcc-c++ make openssl-devel ruby-devel npm augeas-devel @@ -148,6 +152,10 @@ jobs: - name: Git Checkout uses: actions/checkout@v3 + - name: Configure and refresh repositories + # disable unused repositories to have faster refresh + run: zypper modifyrepo -d repo-non-oss repo-openh264 repo-update && ( zypper ref || zypper ref || zypper ref ) + - name: Install Ruby development files run: zypper --non-interactive install gcc gcc-c++ make openssl-devel ruby-devel npm augeas-devel diff --git a/playwright/README.md b/playwright/README.md index 285aa0bf61..0beed6131d 100644 --- a/playwright/README.md +++ b/playwright/README.md @@ -1,3 +1,75 @@ +## Integration Tests + +This directory contains integration tests which use the [Playwright]( +https://playwright.dev/) testing framework. + +## Installation + +To install the Playwright tool run this command in the `playwright` subdirectory: + +```shell +npm install +``` + +This will install the NPM packages into the `node_modules` subdirectory +and download the browsers into the `~/.cache/ms-playwright` directory. + +*Note: The downloaded browsers need almost 1GB, make sure you have enough +space in your `$HOME` directory.* + +## Files + +- `playwright.config.ts` - Playwright configuration, see [documentation]( + https://playwright.dev/docs/test-configuration) for more details +- `global-setup.ts` - a helper for logging-in +- `tests/\*.spec.ts` - individual test files +- `lib/*` - shared library files + +## Running the Tests + +To run all tests use this command: + +``` +npx playwright test +``` + +To run just a specific test: + +``` +npx playwright test tests/root_password.spec.ts +``` + +## Target Server + +By default the tests use the installer instance running locally at +`http://localhost:9090`. If you want to run the tests against +another instance set the `BASE_URL` environment variable: + +``` +BASE_URL=https://192.168.1.12:9090 npx playwright ... +``` + +You can use it also with the [webpack development server]( +../web/README.md#using-a-development-server): + +``` +BASE_URL=https://localhost:8080/ npx playwright ... +``` + +### Options + +The tests by default run in a headless mode, if you want to see the actions +in the browser use the `--headed` option. + +If you want to manually run a test step by step use the `--debug` option. This +also allows to easily get the object selectors using the `Explore` button. + +## Links + +- https://playwright.dev/docs/intro - Playwright Documentation +- https://playwright.dev/docs/test-assertions - Test assetions (`expect`) +- https://playwright.dev/docs/api/class-locator - Finding the elements on the page + ## Troubleshooting Failed Integration Tests in CI ### Single Test Failure diff --git a/playwright/global-setup.ts b/playwright/global-setup.ts index 9c486e4c75..bd1be04af5 100644 --- a/playwright/global-setup.ts +++ b/playwright/global-setup.ts @@ -2,6 +2,8 @@ import { expect, chromium, FullConfig } from '@playwright/test'; async function globalSetup(config: FullConfig) { + // explicitly skip login if you know it is not needed, + // this avoids waiting for the timeout if (process.env.SKIP_LOGIN) return; const browser = await chromium.launch(); @@ -10,7 +12,17 @@ async function globalSetup(config: FullConfig) { ignoreHTTPSErrors: true }); - await page.goto('/cockpit/@localhost/d-installer/index.html'); + // go to the terminal app to see if the user needs to log into the system + await page.goto("/cockpit/@localhost/system/terminal.html"); + + // login page displayed? + try { + await page.waitForSelector("#login-user-input", { timeout: 5000 }); + } + catch { + // form not found, login not required + return; + } await page.getByLabel('User name').fill('root'); await page.getByLabel('Password').fill('linux'); diff --git a/playwright/lib/installer.ts b/playwright/lib/installer.ts new file mode 100644 index 0000000000..7f6bf67e4d --- /dev/null +++ b/playwright/lib/installer.ts @@ -0,0 +1,15 @@ +// shared functions + +// return the URL path to the installer plugin +function mainPagePath():string { + let baseURL = new URL(process.env.BASE_URL || "http://localhost:9090"); + + // when running at the default cockpit port use the full cockpit path, + // otherwise expect the webpack development server where the installer + // is available at the root path + return (baseURL.port == "9090") ? "/cockpit/@localhost/d-installer/index.html" : "/"; +} + +export { + mainPagePath +}; diff --git a/playwright/tests/main_page.spec.ts b/playwright/tests/main_page.spec.ts index 7b56fa11af..75eb9e4ff6 100644 --- a/playwright/tests/main_page.spec.ts +++ b/playwright/tests/main_page.spec.ts @@ -1,8 +1,9 @@ import { test, expect } from '@playwright/test'; +import { mainPagePath } from "../lib/installer"; test.describe('The main page', () => { test.beforeEach(async ({ page }) => { - await page.goto('/cockpit/@localhost/d-installer/index.html'); + await page.goto(mainPagePath()); }); test('has the "D-Installer" title', async ({ page }) => { diff --git a/playwright/tests/root_password.spec.ts b/playwright/tests/root_password.spec.ts index ed85b21ac5..8d48c80c1b 100644 --- a/playwright/tests/root_password.spec.ts +++ b/playwright/tests/root_password.spec.ts @@ -1,24 +1,38 @@ import { test, expect } from '@playwright/test'; +import { mainPagePath } from "../lib/installer"; test.describe('The user section', () => { test.beforeEach(async ({ page }) => { - await page.goto('/cockpit/@localhost/d-installer/index.html'); + await page.goto(mainPagePath()); }); test('can set the root password', async ({ page }) => { - // See https://playwright.dev/docs/selectors#text-selector - // click the button - await page.locator('text=Root password is not set').locator('button').click(); + // See https://playwright.dev/docs/api/class-locator + + // initial expectation - the root password is not configured yet + await expect(page.getByText("None authentication method defined for root user")).toBeVisible(); + + // click the "Users" header + await page.locator("a[href='#/users']").click(); + + // display the actions menu for the root password + await page.locator("#actions-for-root-password").click(); + + // click the "Set" item + await page.getByRole("menuitem", { name: "Set" }).click(); // fill a new password await page.locator('#password').fill('d-installer'); await page.locator('#passwordConfirmation').fill('d-installer'); await page.locator('button[type="submit"]').click(); - // wait until the dialog is closed - await expect(page.locator('[role="dialog"]')).toHaveCount(0); + // wait until the popup is closed + await expect(page.locator('[role="dialog"]')).not.toBeVisible(); + + // go back to the main page + await page.getByText('Back').click(); // check the summary text - await expect(page.locator('text=Root password is set')).toHaveCount(1); + await expect(page.getByText("Root authentication set")).toBeVisible(); }); })