From f695de459e32637f52b59bc0cf971fd39661ce77 Mon Sep 17 00:00:00 2001 From: Diego Imbert Date: Wed, 7 Jan 2026 11:07:39 +0100 Subject: [PATCH] log in e2e --- frontend/.gitignore | 7 ++++ frontend/e2e/login.spec.ts | 46 ++++++++++++++++++++ frontend/package.json | 5 ++- frontend/playwright.config.ts | 79 +++++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 frontend/e2e/login.spec.ts create mode 100644 frontend/playwright.config.ts diff --git a/frontend/.gitignore b/frontend/.gitignore index 2e81ffd6f8..a6e21743cf 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -17,3 +17,10 @@ ui_builder_serve/ src/lib/components/copilot/chat/__tests__/flow/results/ src/lib/components/copilot/chat/__tests__/app/results/ .npmrc + +# Playwright +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +/playwright/.auth/ diff --git a/frontend/e2e/login.spec.ts b/frontend/e2e/login.spec.ts new file mode 100644 index 0000000000..5674cbe054 --- /dev/null +++ b/frontend/e2e/login.spec.ts @@ -0,0 +1,46 @@ +import { test, expect } from '@playwright/test' + +test('log in correctly', async ({ page }) => { + await page.goto('/') + + // Wait for and fill the email input + const emailInput = page.locator('input#email[type="email"]') + await emailInput.waitFor({ state: 'visible' }) + await emailInput.fill('admin@windmill.dev') + + // Wait for and fill the password input + const passwordInput = page.locator('input#password[type="password"]') + await passwordInput.waitFor({ state: 'visible' }) + await passwordInput.fill('changeme') + + // Verify the inputs are filled correctly + await expect(emailInput).toHaveValue('admin@windmill.dev') + await expect(passwordInput).toHaveValue('changeme') + + // Click the sign-in button + const signInButton = page.locator('button:has-text("Sign in")') + await signInButton.click() + + // Handle potential first-time user flow + await page.waitForURL(/\/user\/(first-time|workspaces)/) + if (page.url().includes('/user/first-time')) { + const skipButton = page.locator('button:has-text("Skip")') + await skipButton.click() + } + + // Wait for navigation to workspaces page + await page.waitForURL('**/user/workspaces') + await expect(page).toHaveURL(/\/user\/workspaces$/) + + // Click on the "Admins" workspace + const adminsWorkspace = page.locator('text=Admins').first() + await adminsWorkspace.waitFor({ state: 'visible' }) + await adminsWorkspace.click() + + // Verify we're on the root path of the workspace + await page.waitForURL('**/') + await expect(page).toHaveURL(/\/$/) + + // Wait for the page to load and verify it contains "Home" + await expect(page.locator('text=Home').first()).toBeVisible() +}) diff --git a/frontend/package.json b/frontend/package.json index be419cf75f..987d590a87 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,13 +16,15 @@ "generate-backend-client-mac": "openapi-ts --input ../backend/windmill-api/openapi.yaml --output ./src/lib/gen --useOptions --enums javascript", "pretest": "tsc --incremental -p tests/tsconfig.json", "filter-classes": "node filterTailwindClasses.js", - "test:unit": "vitest" + "test:unit": "vitest", + "test:e2e": "playwright test" }, "devDependencies": { "@floating-ui/core": "^1.3.1", "@hey-api/openapi-ts": "^0.43.0", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.2", + "@playwright/test": "^1.57.0", "@sveltejs/adapter-static": "^3.0.6", "@sveltejs/kit": "^2.49.2", "@sveltejs/package": "^2.3.7", @@ -33,6 +35,7 @@ "@types/d3-zoom": "^3.0.3", "@types/diff": "^7.0.1", "@types/lodash": "^4.14.195", + "@types/node": "^25.0.3", "@types/vscode": "^1.83.5", "@typescript-eslint/eslint-plugin": "^5.59.8", "@typescript-eslint/parser": "^5.60.0", diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts new file mode 100644 index 0000000000..51210c33bf --- /dev/null +++ b/frontend/playwright.config.ts @@ -0,0 +1,79 @@ +import { defineConfig, devices } from '@playwright/test' + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// import path from 'path'; +// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './e2e', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('')`. */ + baseURL: process.env.BASE_URL || 'http://localhost:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry' + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] } + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] } + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] } + } + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ] + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // url: 'http://localhost:3000', + // reuseExistingServer: !process.env.CI, + // }, +})