Improved & added email auth E2E testing

This commit is contained in:
aronmal 2023-07-25 19:23:53 +02:00
parent 833130628e
commit b407553f0d
Signed by: aronmal
GPG key ID: 816B7707426FC612
5 changed files with 120 additions and 19 deletions

View file

@ -1,17 +1,19 @@
describe("Check Azure AD auth", () => {
const callbackUrl = "https://leaky-ships.mal-noh.de/"
const callbackUrl = process.env.NEXTAUTH_URL + "/"
it("Login process...", async () => {
let redirected = false
let thirdParty = false
page.on("framenavigated", (frame) => {
if (redirected) return
const frameUrl = frame.url()
// console.log("Window Location Changed:", frameUrl)
if (frameUrl === callbackUrl) redirected = true
})
try {
await page.goto("https://leaky-ships.mal-noh.de/signin")
await page.goto(callbackUrl + "signin")
await page.waitForSelector("#microsoft")
await page.click("#microsoft")
@ -43,10 +45,39 @@ describe("Check Azure AD auth", () => {
} catch (e) {
if (!redirected || thirdParty) throw e
}
}, 15000)
}, 60000)
it("Is logged in", async () => {
await page.goto("https://leaky-ships.mal-noh.de/signin")
await page.goto(callbackUrl + "signin")
await page.waitForFunction(`window.location.href === '${callbackUrl}'`)
})
}, 30000)
it("Is logged out", async () => {
await page.goto(
"https://login.microsoftonline.com/common/oauth2/v2.0/logout",
)
await page.waitForSelector(`div[data-test-id="${process.env.AUTH_EMAIL}"]`)
const signoutDiv = await page.$(
`div[data-test-id="${process.env.AUTH_EMAIL}"]`,
)
await signoutDiv.click()
await page.waitForFunction(
`window.location.href === 'https://login.microsoftonline.com/common/oauth2/v2.0/logoutsession'`,
)
// Wait for the element to be visible in the page
await page.waitForSelector("#login_workload_logo_text")
// Get the element handle
const elementHandle = await page.$("#login_workload_logo_text")
// Get the inner text of the element
const innerText = await page.evaluate(
(element) => element.innerText,
elementHandle,
)
// Assert that the inner text matches the expected text
expect(innerText.trim()).toBe("You signed out of your account")
}, 30000)
})

View file

@ -0,0 +1,57 @@
const { PrismaClient } = require("@prisma/client")
const prisma = new PrismaClient()
const { createHash, randomBytes } = require("crypto")
describe("Check Email auth", () => {
const callbackUrl = process.env.NEXTAUTH_URL + "/"
const player1Email = "player1@example.com"
it("Email login process...", async () => {
await page.goto(callbackUrl + "signin")
await page.waitForSelector('input[type="email"]')
const emailInput = await page.$('input[type="email"]')
await emailInput.type(player1Email)
await page.click('button[type="submit"]')
await page.waitForFunction(
`window.location.href === '${callbackUrl}api/auth/verify-request?provider=email&type=email'`,
)
}, 30000)
it("Verify Email...", async () => {
const token = randomBytes(32).toString("hex")
const hash = createHash("sha256")
// Prefer provider specific secret, but use default secret if none specified
.update(`${token}${process.env.NEXTAUTH_SECRET}`)
.digest("hex")
// Use Prisma to fetch the latest token for the email
const latestToken = await prisma.VerificationToken.findFirst({
where: { identifier: player1Email },
orderBy: { expires: "desc" },
})
await prisma.VerificationToken.update({
where: {
identifier_token: {
identifier: player1Email,
token: latestToken.token,
},
},
data: { token: hash },
})
const params = new URLSearchParams({
callbackUrl,
token,
email: player1Email,
})
const url = callbackUrl + "api/auth/callback/email?" + params
await page.goto(url)
await page.waitForFunction(`window.location.href === '${callbackUrl}'`)
}, 30000)
})

View file

@ -3,14 +3,25 @@
# Build the project
pnpm run build
# Function to kill the server process
function kill_server {
local server_pid=$(lsof -i :3000 -t)
if [[ -n $server_pid ]]; then
echo "Killing server..." $server_pid
kill -15 $server_pid
fi
}
# Function to run the tests
function run_tests {
pnpm test
}
# Start the server in the background
pnpm run start &
# Store the process ID (PID) of the server
SERVER_PID=$!
# Capture exit signals and execute the kill_server function
trap kill_server EXIT ERR
# Run the tests
pnpm test
# Abort the server process
kill $SERVER_PID
run_tests

View file

@ -32,7 +32,7 @@ const options: NextAuthOptions = {
}),
],
adapter: PrismaAdapter(prisma),
secret: process.env.SECRET,
secret: process.env.NEXTAUTH_SECRET,
callbacks: {
signIn: ({ user, account }) => {
// Custom signIn callback to add username to email provider

View file

@ -2,7 +2,7 @@ import { faLeftLong } from "@fortawesome/pro-solid-svg-icons"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { signIn, useSession } from "next-auth/react"
import { useRouter } from "next/router"
import { useEffect, useState } from "react"
import { FormEvent, useEffect, useState } from "react"
import { toast } from "react-toastify"
type SignInErrorTypes =
@ -51,7 +51,8 @@ function Login() {
}, [router, status])
function login(provider: "email" | "azure-ad") {
return () => {
return (e?: FormEvent) => {
e?.preventDefault()
signIn(provider, { email, callbackUrl: "/" })
}
}
@ -71,26 +72,27 @@ function Login() {
</div>
{errorType && <hr className="mb-8 border-gray-400" />}
<div className="flex flex-col">
<div className="flex flex-col">
<form className="flex flex-col" onSubmit={login("email")}>
<label htmlFor="email" className="mx-2 text-lg">
Email
</label>
<input
className="my-1 rounded-lg border-2 border-gray-500 bg-slate-800 bg-opacity-60 px-6 py-2 text-center text-inherit placeholder-slate-400 shadow-lg outline-none backdrop-blur-md focus-within:border-blue-500"
type="text"
type="email"
name="email"
id="email"
placeholder="user@example.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<button
id="email"
onClick={login("email")}
id="email-submit"
type="submit"
className="my-1 rounded-lg bg-blue-500 bg-opacity-75 px-10 py-3 text-white shadow-inner drop-shadow-md backdrop-blur-md transition-colors duration-300 hover:bg-blue-600"
>
Sign in with Email
</button>
</div>
</form>
<div className="flex flex-row items-center">
<hr className="w-full" />