Improved & added email auth E2E testing
This commit is contained in:
parent
833130628e
commit
b407553f0d
5 changed files with 120 additions and 19 deletions
|
@ -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)
|
||||
})
|
||||
|
|
57
leaky-ships/__tests__/email.js
Normal file
57
leaky-ships/__tests__/email.js
Normal 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)
|
||||
})
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue