diff --git a/Dockerfile b/Dockerfile index e5693d90..1bf7ab50 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,6 +47,20 @@ COPY . /usr/local/apache2/htdocs/ FROM base AS tests +# Install necessary packages for Playwright +RUN apt-get update && apt-get install -y \ + libnss3 \ + libatk-bridge2.0-0 \ + libdrm2 \ + libxkbcommon0 \ + libgtk-3-0 \ + libgbm1 \ + libasound2 \ + && rm -rf /var/lib/apt/lists/* + +# Install Playwright browsers +RUN npx playwright install chromium --with-deps + # Set default command to run BDD tests CMD ["npm", "run", "test:bdd"] diff --git a/package-lock.json b/package-lock.json index 9d409619..9557ed97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "markdown-it-attrs": "^4.3.1", "mini-css-extract-plugin": "^2.9.1", "moment": "^2.30.1", + "playwright": "^1.54.2", "postcss-loader": "^8.1.1", "sass": "^1.89.1", "sass-loader": "^16.0.2", @@ -4602,6 +4603,53 @@ "node": ">=8" } }, + "node_modules/playwright": { + "version": "1.54.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.2.tgz", + "integrity": "sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.54.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.54.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.2.tgz", + "integrity": "sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/please-upgrade-node": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", diff --git a/package.json b/package.json index c88faa5b..70d897e7 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "markdown-it-attrs": "^4.3.1", "mini-css-extract-plugin": "^2.9.1", "moment": "^2.30.1", + "playwright": "^1.54.2", "postcss-loader": "^8.1.1", "sass": "^1.89.1", "sass-loader": "^16.0.2", diff --git a/tests/staging/step_definitions/website_steps.js b/tests/staging/step_definitions/website_steps.js index 8f4b5d17..5e5f55d0 100644 --- a/tests/staging/step_definitions/website_steps.js +++ b/tests/staging/step_definitions/website_steps.js @@ -1,21 +1,78 @@ -// Basic step definitions for BDD tests -// These are intentionally minimal placeholders to demonstrate the test framework setup +// Basic step definitions for BDD tests using Playwright +const { Given, When, Then, BeforeAll, AfterAll } = require('@cucumber/cucumber'); +const { chromium } = require('playwright'); -const { Given, When, Then } = require('@cucumber/cucumber'); +let browser; +let context; +let page; -// This step definition is intentionally empty to show the framework works -// but tests still fail due to missing implementation -Given('the Staging site is started', function () { - // TODO: Implement step to start/verify staging site - return 'pending'; +// Set up BASE_URL with default value for staging service in Docker network +const BASE_URL = process.env.BASE_URL || 'http://staging'; + +BeforeAll(async function () { + browser = await chromium.launch({ + headless: true, + args: ['--no-sandbox', '--disable-setuid-sandbox'] + }); + context = await browser.newContext({ + // Increase timeout for slower Docker environments + timeout: 30000 + }); +}); + +AfterAll(async function () { + if (context) await context.close(); + if (browser) await browser.close(); +}); + +Given('the Staging site is started', async function () { + page = await context.newPage(); + + try { + // Verify that the BASE_URL can be reached (allow redirects) + const response = await page.goto(BASE_URL, { + waitUntil: 'networkidle', + timeout: 30000 + }); + + if (!response || !response.ok()) { + throw new Error(`Failed to reach staging site at ${BASE_URL}. Status: ${response ? response.status() : 'No response'}`); + } + } catch (error) { + throw new Error(`Unable to connect to staging site at ${BASE_URL}: ${error.message}`); + } }); -When('the index page is visited', function () { - // TODO: Implement step to visit index page - return 'pending'; +When('the index page is visited', async function () { + if (!page) { + throw new Error('Page not initialized. Make sure "Given the Staging site is started" step is executed first.'); + } + + // Navigate to the index page and ensure it loads without HTTP errors + const response = await page.goto(BASE_URL, { + waitUntil: 'networkidle', + timeout: 30000 + }); + + if (!response || !response.ok()) { + throw new Error(`Index page failed to load. Status: ${response ? response.status() : 'No response'}`); + } + + // Verify the page has loaded by checking for basic HTML structure + await page.waitForSelector('html', { timeout: 10000 }); }); -Then('the Logo should be displayed in the top left corner', function () { - // TODO: Implement step to verify logo presence and position - return 'pending'; +Then('the Logo should be displayed in the top left corner', async function () { + if (!page) { + throw new Error('Page not initialized. Make sure previous steps are executed first.'); + } + + // Check that favicon.png is somewhere nested under a