Skip to content

Commit 24c66e2

Browse files
committed
test: Adding E2E tests for authentication with Playwright.
1 parent da80741 commit 24c66e2

7 files changed

+118
-37
lines changed

.env.local-example

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
AUTH_SECRET=
22

33
AUTH_GITHUB_ID=
4-
AUTH_GITHUB_SECRET=
4+
AUTH_GITHUB_SECRET=
5+
6+
TEST_PASSWORD=

auth.ts

+47-16
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import GitHub from "next-auth/providers/github";
22
import NextAuth, { type DefaultSession } from "next-auth";
33
import { DefaultJWT } from "next-auth/jwt";
44
import { AdapterSession } from 'next-auth/adapters';
5+
import { Provider } from "next-auth/providers";
6+
import Credentials from "next-auth/providers/credentials";
57

68
// We need to add the role to the JWT inside `NextAuth` below, so the `middleware.ts` can have access to it.
79
// The problem is that it wasn't added this `role` custom field, even if we defined it in `auth.ts`.
@@ -43,23 +45,52 @@ declare module "next-auth/jwt" {
4345

4446
// ----------
4547

46-
export const { handlers, signIn, signOut, auth } = NextAuth({
47-
providers: [
48-
GitHub({
49-
profile(profile) {
50-
// GitHub's OAuth apps don't allow you to define roles.
51-
// So `profile` here doesn't have a `role` property.
52-
// But on other providers, you'd add the role here through it.
53-
return {
54-
id: profile.id.toString(),
55-
name: profile.name ?? profile.login,
56-
email: profile.email,
57-
image: profile.avatar_url,
58-
role: "user",
59-
};
48+
// OAuth providers to sign-in
49+
const providers: Provider[] = [
50+
GitHub({
51+
profile(profile) {
52+
// GitHub's OAuth apps don't allow you to define roles.
53+
// So `profile` here doesn't have a `role` property.
54+
// But on other providers, you'd add the role here through it.
55+
return {
56+
id: profile.id.toString(),
57+
name: profile.name ?? profile.login,
58+
email: profile.email,
59+
image: profile.avatar_url,
60+
role: "user",
61+
};
62+
},
63+
}),
64+
]
65+
66+
// Be sure to not put a development version in production!
67+
// See https://authjs.dev/guides/testing#credentials-provider-in-development.
68+
if (process.env.NODE_ENV === "development") {
69+
providers.push(
70+
Credentials({
71+
id: "password",
72+
name: "Password",
73+
credentials: {
74+
password: { label: "Password", type: "password" },
75+
},
76+
authorize: (credentials) => {
77+
if (credentials.password === process.env.TEST_PASSWORD) {
78+
return {
79+
80+
name: "Bob Alice",
81+
image: "",
82+
}
83+
}
84+
return null
6085
},
61-
}),
62-
],
86+
})
87+
)
88+
}
89+
90+
91+
// The important part: where the `NextAuth` config is exported
92+
export const { handlers, signIn, signOut, auth } = NextAuth({
93+
providers: providers,
6394
callbacks: {
6495
jwt({ token, user, account, profile }) {
6596
// Normally, it would be like this

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"devDependencies": {
2121
"@playwright/test": "^1.44.1",
2222
"@types/node": "20.14.5",
23+
"dotenv": "^16.4.5",
2324
"fast-glob": "^3.3.2",
2425
"monocart-reporter": "^2.5.0",
2526
"open-cli": "^8.0.0",

playwright.config.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import { getMonocartReporterOptions } from "./playwright.monocart-reporter";
66
* Read environment variables from file.
77
* https://github.com/motdotla/dotenv
88
*/
9-
// import dotenv from 'dotenv';
10-
// dotenv.config({ path: path.resolve(__dirname, '.env') });
9+
import dotenv from 'dotenv';
10+
dotenv.config({ path: "./.env.local" });
11+
1112

1213
const _testResultsDir = path.resolve("./e2e-test-results");
1314
const _codeCoverageDir = path.resolve(_testResultsDir, "code-coverage");

pnpm-lock.yaml

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

tests/e2e/homepage.spec.ts

-18
This file was deleted.

tests/e2e/test.spec.ts

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// !! PLEASE READ !!
2+
/*
3+
Coverage for E2E effectively works, but the coverage is not using the sourcemaps properly, so coverage doesn't mean much.
4+
We've decided to leave the infrastructure (coverage uses `monocart`) with its configuration for posteriority in case we need them.
5+
E2E testing is more relevant knowing **if they pass or not**.
6+
*/
7+
8+
import { test, expect } from "../_shared/app-fixtures"; // we use the overriden functions to get coverage
9+
10+
const BASE_URL = "http://localhost:3000"
11+
12+
test.describe("homepage", () => {
13+
test("is mounted", async ({ page }) => {
14+
await page.goto("/");
15+
16+
// Expect a title "to contain" a substring.
17+
await expect(page).toHaveTitle(/Welcome to Nextra Documentation/);
18+
});
19+
});
20+
21+
test("Basic auth", async ({ page, browser }) => {
22+
if (!process.env.TEST_PASSWORD) throw new TypeError("Missing TEST_PASSWORD");
23+
24+
await test.step("should login", async () => {
25+
await page.goto(`${BASE_URL}/api/auth/signin`);
26+
await page.getByLabel("Password").fill(process.env.TEST_PASSWORD ?? "");
27+
await page.getByRole("button", { name: "Sign in with Password" }).click();
28+
await page.waitForURL(`${BASE_URL}`);
29+
30+
const sessionResponse = await page.goto(
31+
`${BASE_URL}/api/auth/session`
32+
)
33+
const session = await sessionResponse?.json() ?? {}
34+
expect(session.user.email).toEqual("[email protected]")
35+
expect(session.user.name).toEqual("Bob Alice")
36+
expect(session.user.image).toEqual("")
37+
});
38+
39+
await test.step("should logout", async () => {
40+
// Move to the homepage to log out
41+
await page.goto("/");
42+
43+
await page.getByText("SIGN OUT").click();
44+
expect(page.url()).toBe(`${BASE_URL}/`)
45+
46+
await page.waitForURL(`${BASE_URL}`)
47+
await page.waitForTimeout(1000); // wait for sign out to persist in IDP
48+
49+
const sessionResponse = await page.goto(
50+
`${BASE_URL}/api/auth/session`
51+
)
52+
const session = await sessionResponse?.json()
53+
expect(session).toBe(null)
54+
});
55+
});

0 commit comments

Comments
 (0)