Skip to content

Commit 429f895

Browse files
committed
Headless tests for tutorial apps
1 parent e8e8fee commit 429f895

File tree

13 files changed

+429
-3
lines changed

13 files changed

+429
-3
lines changed

examples/streaming/headless-tests/playwright.config.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export default defineConfig({
4545
/* Run your local dev server before starting the tests */
4646
webServer: {
4747
command:
48-
"wasp-app-runner --app-path=../ --app-name=examples-waspleau --db-type sqlite",
48+
"wasp-app-runner --app-path=../ --app-name=examples-streaming --db-type sqlite",
4949

5050
// Wait for the backend to start
5151
url: "http://localhost:3001",

examples/tutorials/TodoApp/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ node_modules/
99
# Don't ignore example dotenv files.
1010
!.env.example
1111
!.env.*.example
12+
13+
# Headless tests
14+
test-results/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { defineConfig, devices } from "@playwright/test";
2+
3+
/**
4+
* Read environment variables from file.
5+
* https://github.com/motdotla/dotenv
6+
*/
7+
// require('dotenv').config();
8+
9+
/**
10+
* See https://playwright.dev/docs/test-configuration.
11+
*/
12+
export default defineConfig({
13+
testDir: "./tests",
14+
/* Run tests in files in parallel */
15+
fullyParallel: true,
16+
/* Fail the build on CI if you accidentally left test.only in the source code. */
17+
forbidOnly: !!process.env.CI,
18+
/* Retry on CI only */
19+
retries: process.env.CI ? 2 : 0,
20+
/* Opt out of parallel tests on CI. */
21+
workers: process.env.CI ? 1 : undefined,
22+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
23+
reporter: process.env.CI ? "dot" : "list",
24+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
25+
use: {
26+
/* Base URL to use in actions like `await page.goto('/')`. */
27+
baseURL: "http://localhost:3000",
28+
29+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
30+
trace: "on-first-retry",
31+
},
32+
33+
projects: [
34+
{
35+
name: "chromium",
36+
use: { ...devices["Desktop Chrome"] },
37+
},
38+
/* Test against mobile viewports. */
39+
{
40+
name: "Mobile Chrome",
41+
use: { ...devices["Pixel 5"] },
42+
},
43+
],
44+
45+
/* Run your local dev server before starting the tests */
46+
webServer: {
47+
command:
48+
"wasp-app-runner --app-path=../ --app-name=examples-tutorials-TodoApp --db-type sqlite",
49+
50+
// Wait for the backend to start
51+
url: "http://localhost:3001",
52+
reuseExistingServer: !process.env.CI,
53+
timeout: 180 * 1000,
54+
gracefulShutdown: { signal: "SIGTERM", timeout: 500 },
55+
},
56+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import type { Page } from "@playwright/test";
2+
3+
export async function performSignup(
4+
page: Page,
5+
{ username, password }: { username: string; password: string }
6+
) {
7+
await page.goto("/signup");
8+
9+
await page.waitForSelector("text=Create a new account");
10+
11+
await page.locator("input[name='username']").fill(username);
12+
await page.locator("input[type='password']").fill(password);
13+
await page.locator("button").click();
14+
}
15+
16+
export async function performLogin(
17+
page: Page,
18+
{
19+
username,
20+
password,
21+
}: {
22+
username: string;
23+
password: string;
24+
}
25+
) {
26+
await page.goto("/login");
27+
28+
await page.waitForSelector("text=Log in to your account");
29+
30+
await page.locator("input[name='username']").fill(username);
31+
await page.locator("input[type='password']").fill(password);
32+
await page.getByRole("button", { name: "Log in" }).click();
33+
}
34+
35+
export function generateRandomCredentials(): {
36+
username: string;
37+
password: string;
38+
} {
39+
return {
40+
username: `test${Math.random().toString(36).substring(7)}`,
41+
password: "12345678",
42+
};
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { test, expect } from "@playwright/test";
2+
import {
3+
generateRandomCredentials,
4+
performLogin,
5+
performSignup,
6+
} from "./helpers";
7+
8+
test.describe("auth and work with tasks", () => {
9+
const { username, password } = generateRandomCredentials();
10+
11+
test.describe.configure({ mode: "serial" });
12+
13+
test("can sign up", async ({ page }) => {
14+
await performSignup(page, {
15+
username,
16+
password,
17+
});
18+
19+
await expect(page).toHaveURL("/");
20+
21+
await page.getByText("Logout").click();
22+
23+
await expect(page).toHaveURL("/login");
24+
});
25+
26+
test("can log in and cast a vote", async ({ page }) => {
27+
await performLogin(page, {
28+
username,
29+
password: "12345678xxx",
30+
});
31+
32+
await expect(page.locator("body")).toContainText("Invalid credentials");
33+
34+
await performLogin(page, {
35+
username,
36+
password,
37+
});
38+
39+
await expect(page).toHaveURL("/");
40+
41+
const randomTask = `New Task ${Math.random().toString(36).substring(7)}`;
42+
// Fill input[name="description"] with random task
43+
await page.locator("input[name='description']").fill(randomTask);
44+
// Click input[type="submit"] to submit the form
45+
await page.locator("input[type='submit']").click();
46+
// Expect to see the task on the page
47+
await expect(page.locator("body")).toContainText(randomTask);
48+
// Check the task as done input[type="checkbox"]
49+
await page.locator("input[type='checkbox']").click();
50+
// Reload the page
51+
await page.reload();
52+
// Expect the task to be checked
53+
await expect(page.locator("input[type='checkbox']")).toBeChecked();
54+
});
55+
});

examples/tutorials/TodoApp/package-lock.json

+56-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/tutorials/TodoApp/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "TodoApp",
33
"type": "module",
44
"dependencies": {
5+
"@playwright/test": "^1.50.1",
56
"react": "^18.2.0",
67
"react-dom": "^18.2.0",
78
"react-router-dom": "^6.26.2",

examples/tutorials/TodoAppTs/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ node_modules/
99
# Don't ignore example dotenv files.
1010
!.env.example
1111
!.env.*.example
12+
13+
# Headless tests
14+
test-results/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { defineConfig, devices } from "@playwright/test";
2+
3+
/**
4+
* Read environment variables from file.
5+
* https://github.com/motdotla/dotenv
6+
*/
7+
// require('dotenv').config();
8+
9+
/**
10+
* See https://playwright.dev/docs/test-configuration.
11+
*/
12+
export default defineConfig({
13+
testDir: "./tests",
14+
/* Run tests in files in parallel */
15+
fullyParallel: true,
16+
/* Fail the build on CI if you accidentally left test.only in the source code. */
17+
forbidOnly: !!process.env.CI,
18+
/* Retry on CI only */
19+
retries: process.env.CI ? 2 : 0,
20+
/* Opt out of parallel tests on CI. */
21+
workers: process.env.CI ? 1 : undefined,
22+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
23+
reporter: process.env.CI ? "dot" : "list",
24+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
25+
use: {
26+
/* Base URL to use in actions like `await page.goto('/')`. */
27+
baseURL: "http://localhost:3000",
28+
29+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
30+
trace: "on-first-retry",
31+
},
32+
33+
projects: [
34+
{
35+
name: "chromium",
36+
use: { ...devices["Desktop Chrome"] },
37+
},
38+
/* Test against mobile viewports. */
39+
{
40+
name: "Mobile Chrome",
41+
use: { ...devices["Pixel 5"] },
42+
},
43+
],
44+
45+
/* Run your local dev server before starting the tests */
46+
webServer: {
47+
command:
48+
"wasp-app-runner --app-path=../ --app-name=examples-tutorials-TodoAppTs --db-type sqlite",
49+
50+
// Wait for the backend to start
51+
url: "http://localhost:3001",
52+
reuseExistingServer: !process.env.CI,
53+
timeout: 180 * 1000,
54+
gracefulShutdown: { signal: "SIGTERM", timeout: 500 },
55+
},
56+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import type { Page } from "@playwright/test";
2+
3+
export async function performSignup(
4+
page: Page,
5+
{ username, password }: { username: string; password: string }
6+
) {
7+
await page.goto("/signup");
8+
9+
await page.waitForSelector("text=Create a new account");
10+
11+
await page.locator("input[name='username']").fill(username);
12+
await page.locator("input[type='password']").fill(password);
13+
await page.locator("button").click();
14+
}
15+
16+
export async function performLogin(
17+
page: Page,
18+
{
19+
username,
20+
password,
21+
}: {
22+
username: string;
23+
password: string;
24+
}
25+
) {
26+
await page.goto("/login");
27+
28+
await page.waitForSelector("text=Log in to your account");
29+
30+
await page.locator("input[name='username']").fill(username);
31+
await page.locator("input[type='password']").fill(password);
32+
await page.getByRole("button", { name: "Log in" }).click();
33+
}
34+
35+
export function generateRandomCredentials(): {
36+
username: string;
37+
password: string;
38+
} {
39+
return {
40+
username: `test${Math.random().toString(36).substring(7)}`,
41+
password: "12345678",
42+
};
43+
}

0 commit comments

Comments
 (0)