Add Playwright e2e test setup and configs
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Auth helpers for Playwright e2e tests.
|
||||
*
|
||||
* Provides utilities for logging in as a test user.
|
||||
* The app uses email-only registration (magic-link flow for initial confirmation)
|
||||
* and email+password for subsequent logins.
|
||||
*/
|
||||
|
||||
import { Page } from "@playwright/test";
|
||||
|
||||
export const TEST_USER = {
|
||||
email: process.env.PLAYWRIGHT_EMAIL || "test@firehose.test",
|
||||
password: process.env.PLAYWRIGHT_PASSWORD || "testpassword123!",
|
||||
};
|
||||
|
||||
/**
|
||||
* Navigate to the login page, fill in credentials, and submit.
|
||||
* Returns the page after successful login (redirected to home).
|
||||
*/
|
||||
export async function loginAsTestUser(page: Page) {
|
||||
await page.goto("/users/log-in");
|
||||
// Use the password-based login form
|
||||
await page.getByLabel("Email").fill(TEST_USER.email);
|
||||
await page.getByLabel("Password").fill(TEST_USER.password);
|
||||
// Click "Log in and stay logged in"
|
||||
await page.getByRole("button", { name: /log in and stay logged in/i }).click();
|
||||
await page.waitForURL("/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to the registration page, fill in email, and submit.
|
||||
* Note: In dev mode, registration is invite-only by default. Set
|
||||
* `PLAYWRIGHT_ALLOW_REGISTRATION=true` to run tests against a server
|
||||
* with open registration enabled.
|
||||
*/
|
||||
export async function registerTestUser(page: Page) {
|
||||
await page.goto("/users/register");
|
||||
await page.getByLabel("Email").fill(TEST_USER.email);
|
||||
await page.getByRole("button", { name: /create an account/i }).click();
|
||||
await page.waitForURL("/users/log-in");
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { test, expect } from "./fixtures";
|
||||
import { loginAsTestUser } from "./auth-helpers";
|
||||
|
||||
test.describe("Authenticated pages", () => {
|
||||
test("redirects unauthenticated users to login page", async ({ page }) => {
|
||||
const response = await page.goto("/editor/dashboard");
|
||||
// Should redirect to login
|
||||
expect(response?.url()).toContain("/users/log-in");
|
||||
});
|
||||
|
||||
test("can log in and access the editor dashboard", async ({ page }) => {
|
||||
await loginAsTestUser(page);
|
||||
|
||||
// After login, we should be on the home page
|
||||
await expect(page).toHaveURL("/");
|
||||
await expect(page.locator("body")).not.toBeEmpty();
|
||||
});
|
||||
|
||||
test("can log out", async ({ page }) => {
|
||||
await loginAsTestUser(page);
|
||||
|
||||
// Now log out
|
||||
await page.goto("/users/log-out");
|
||||
|
||||
// Should redirect to home
|
||||
await expect(page).toHaveURL("/");
|
||||
|
||||
// Try accessing an authenticated page
|
||||
await page.goto("/editor/dashboard");
|
||||
// Should redirect to login
|
||||
await expect(page).toHaveURL(/\/users\/log-in/);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Custom Playwright test fixtures.
|
||||
*
|
||||
* Provides a `test` function that connects to a remote Chrome via CDP
|
||||
* when PLAYWRIGHT_CDP_URL is set (Docker Chrome mode).
|
||||
* Falls back to the default local browser otherwise.
|
||||
*/
|
||||
|
||||
import { test as base, chromium } from "@playwright/test";
|
||||
|
||||
type Fixtures = {
|
||||
// Browser is provided by Playwright Test by default.
|
||||
// We only override it when connecting to remote Docker Chrome.
|
||||
};
|
||||
|
||||
const cdpUrl = process.env.PLAYWRIGHT_CDP_URL;
|
||||
|
||||
export const test = cdpUrl
|
||||
? base.extend<Fixtures>({
|
||||
browser: async ({}, use) => {
|
||||
const browser = await chromium.connectOverCDP(cdpUrl);
|
||||
await use(browser);
|
||||
await browser.close();
|
||||
},
|
||||
})
|
||||
: base;
|
||||
|
||||
export { expect } from "@playwright/test";
|
||||
@@ -0,0 +1,29 @@
|
||||
import { test, expect } from "./fixtures";
|
||||
|
||||
test.describe("Connectivity smoke test", () => {
|
||||
test("visits the homepage and verifies it loads", async ({ page }) => {
|
||||
const response = await page.goto("/");
|
||||
expect(response?.ok()).toBeTruthy();
|
||||
|
||||
// Verify the page has content
|
||||
await expect(page).toHaveTitle(/Firehose/);
|
||||
});
|
||||
|
||||
test("visits the contact page", async ({ page }) => {
|
||||
const response = await page.goto("/contact");
|
||||
expect(response?.ok()).toBeTruthy();
|
||||
await expect(page.locator("body")).not.toBeEmpty();
|
||||
});
|
||||
|
||||
test("visits the blog engineering index", async ({ page }) => {
|
||||
const response = await page.goto("/blog/engineering");
|
||||
expect(response?.ok()).toBeTruthy();
|
||||
await expect(page.locator("body")).not.toBeEmpty();
|
||||
});
|
||||
|
||||
test("visits the blog releases index", async ({ page }) => {
|
||||
const response = await page.goto("/blog/releases");
|
||||
expect(response?.ok()).toBeTruthy();
|
||||
await expect(page.locator("body")).not.toBeEmpty();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,139 @@
|
||||
{
|
||||
"extends": [
|
||||
"default"
|
||||
],
|
||||
"meta": {
|
||||
"name": "playwright",
|
||||
"version": "",
|
||||
"description": "Playwright e2e testing — browser binaries on host, connects to localhost Phoenix server",
|
||||
"author": null
|
||||
},
|
||||
"security": {
|
||||
"signal_mode": null,
|
||||
"process_info_mode": null,
|
||||
"ipc_mode": null,
|
||||
"capability_elevation": null,
|
||||
"wsl2_proxy_policy": null
|
||||
},
|
||||
"groups": {
|
||||
"include": [
|
||||
"deny_credentials"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
"commands": {
|
||||
"allow": [],
|
||||
"deny": []
|
||||
},
|
||||
"filesystem": {
|
||||
"allow": [
|
||||
"$HOME/Library/Caches/ms-playwright",
|
||||
"$HOME/.local/share/mise/",
|
||||
"~/Library/Caches/mise/clang/22.1.7",
|
||||
"~/Library/Caches/mise/dotnet/8.0.300",
|
||||
"~/Library/Caches/mise/elixir/1.14.3",
|
||||
"~/Library/Caches/mise/elixir/1.15.8",
|
||||
"~/Library/Caches/mise/elixir/1.16.0-otp-26",
|
||||
"~/Library/Caches/mise/elixir/1.16.1-otp-26",
|
||||
"~/Library/Caches/mise/elixir/1.17-otp-26",
|
||||
"~/Library/Caches/mise/elixir/1.17.3-otp-27",
|
||||
"~/Library/Caches/mise/elixir/1.18-otp-27",
|
||||
"~/Library/Caches/mise/elixir/1.18.3",
|
||||
"~/Library/Caches/mise/elixir/1.18.3-otp-27",
|
||||
"~/Library/Caches/mise/elixir/1.19.5-otp-28",
|
||||
"~/Library/Caches/mise/erlang/25.2.1",
|
||||
"~/Library/Caches/mise/erlang/26.2.1",
|
||||
"~/Library/Caches/mise/php"
|
||||
],
|
||||
"read": [
|
||||
"~/.cargo/bin",
|
||||
"~/.config",
|
||||
"~/Library/Caches/mise/elixir"
|
||||
],
|
||||
"write": [],
|
||||
"allow_file": [
|
||||
"~/Library/Caches/mise/clang/22.1.7/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/dotnet/8.0.300/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/elixir/1.14.3/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/elixir/1.15.8/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/elixir/1.16.0-otp-26/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/elixir/1.16.1-otp-26/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/elixir/1.17-otp-26/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/elixir/1.17.3-otp-27/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/elixir/1.18-otp-27/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/elixir/1.18.3-otp-27/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/elixir/1.18.3/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/elixir/1.19.5-otp-28/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/elixir/idiomatic_filenames-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/erlang/25.2.1/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/erlang/26.2.1/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/erlang/26.2.2/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/erlang/27.3.3/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/erlang/27.3.4/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/erlang/28.4.2/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/erlang/28.5/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/ghc/8.10.7/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/php/8.4.0RC1/list_bin_paths-67c49.msgpack.z",
|
||||
"~/Library/Caches/mise/php/remote_versions-67c49.msgpack.z"
|
||||
],
|
||||
"read_file": [
|
||||
"$HOME/.gitconfig",
|
||||
"~/.config/mise/config.toml",
|
||||
"~/dev/elixir/firehose/mise.toml"
|
||||
],
|
||||
"write_file": [],
|
||||
"unix_socket": [],
|
||||
"unix_socket_bind": [],
|
||||
"unix_socket_dir": [],
|
||||
"unix_socket_dir_bind": [],
|
||||
"unix_socket_subtree": [],
|
||||
"unix_socket_subtree_bind": [],
|
||||
"deny": [],
|
||||
"bypass_protection": [],
|
||||
"suppress_save_prompt": []
|
||||
},
|
||||
"network": {
|
||||
"block": false,
|
||||
"allow_http2": false,
|
||||
"allow_domain": [],
|
||||
"open_port": [],
|
||||
"listen_port": [],
|
||||
"connect_port": [],
|
||||
"custom_credentials": {},
|
||||
"tls_intercept": null,
|
||||
"upstream_proxy": null,
|
||||
"upstream_bypass": []
|
||||
},
|
||||
"diagnostics": {
|
||||
"suppress_system_services": []
|
||||
},
|
||||
"linux": {
|
||||
"af_unix_mediation": null,
|
||||
"sandbox_policy": null
|
||||
},
|
||||
"env_credentials": {},
|
||||
"environment": null,
|
||||
"command_policies": null,
|
||||
"credential_capture": {},
|
||||
"credential_providers": {},
|
||||
"credential_routes": [],
|
||||
"workdir": {
|
||||
"access": "readwrite"
|
||||
},
|
||||
"hooks": {},
|
||||
"session_hooks": {},
|
||||
"rollback": {
|
||||
"exclude_patterns": [],
|
||||
"exclude_globs": []
|
||||
},
|
||||
"open_urls": null,
|
||||
"allow_launch_services": null,
|
||||
"allow_gpu": null,
|
||||
"allow_parent_of_protected": null,
|
||||
"interactive": false,
|
||||
"skipdirs": [],
|
||||
"packs": [],
|
||||
"binary": null,
|
||||
"command_args": [],
|
||||
"unsafe_macos_seatbelt_rules": []
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"meta": {
|
||||
"name": "playwright",
|
||||
"description": "Playwright e2e testing — browser binaries on host, connects to localhost Phoenix server"
|
||||
},
|
||||
"extends": "default",
|
||||
"groups": {
|
||||
"include": ["deny_credentials"]
|
||||
},
|
||||
"workdir": {
|
||||
"access": "readwrite"
|
||||
},
|
||||
"filesystem": {
|
||||
"allow": [
|
||||
"$HOME/Library/Caches/ms-playwright"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user