diff --git a/leaky-ships/__tests__/auth.js b/leaky-ships/__tests__/auth.js index 71f5efd..69e4c2d 100644 --- a/leaky-ships/__tests__/auth.js +++ b/leaky-ships/__tests__/auth.js @@ -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) }) diff --git a/leaky-ships/__tests__/email.js b/leaky-ships/__tests__/email.js new file mode 100644 index 0000000..541e02a --- /dev/null +++ b/leaky-ships/__tests__/email.js @@ -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) +}) diff --git a/leaky-ships/build-start-test.sh b/leaky-ships/build-start-test.sh index 23b9786..40416a9 100755 --- a/leaky-ships/build-start-test.sh +++ b/leaky-ships/build-start-test.sh @@ -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 diff --git a/leaky-ships/pages/api/auth/[...nextauth].ts b/leaky-ships/pages/api/auth/[...nextauth].ts index b2c893b..c631cde 100644 --- a/leaky-ships/pages/api/auth/[...nextauth].ts +++ b/leaky-ships/pages/api/auth/[...nextauth].ts @@ -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 diff --git a/leaky-ships/pages/signin.tsx b/leaky-ships/pages/signin.tsx index 6d76057..0e0aac1 100644 --- a/leaky-ships/pages/signin.tsx +++ b/leaky-ships/pages/signin.tsx @@ -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() { {errorType &&
}
-
+
setEmail(e.target.value)} /> -
+