Add jest E2E testing
This commit is contained in:
parent
0291e6656e
commit
c71d74dd18
12 changed files with 2624 additions and 87 deletions
2
leaky-ships/.gitignore
vendored
2
leaky-ships/.gitignore
vendored
|
@ -1,5 +1,7 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
__tests__/screenshots/*
|
||||||
|
|
||||||
# logs
|
# logs
|
||||||
/log
|
/log
|
||||||
|
|
||||||
|
|
70
leaky-ships/__tests__/auth.js
Normal file
70
leaky-ships/__tests__/auth.js
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
describe("Azure AD", () => {
|
||||||
|
it("Go to MS sign in", async () => {
|
||||||
|
await page.goto("https://leaky-ships.mal-noh.de/")
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/a.png" })
|
||||||
|
await page.click("#start")
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/b.png" })
|
||||||
|
await page.waitForSelector("#login")
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/c.png" })
|
||||||
|
await page.click("#login")
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/d.png" })
|
||||||
|
await page.waitForSelector("#microsoft")
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/e.png" })
|
||||||
|
await page.click("#microsoft")
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/f.png" })
|
||||||
|
}, 10000)
|
||||||
|
|
||||||
|
it("MS sign in", async () => {
|
||||||
|
// Listen for frame navigations and log the URL changes
|
||||||
|
// page.on("framenavigated", (frame) => {
|
||||||
|
// const frameUrl = frame.url()
|
||||||
|
// console.log("Window Location Changed:", frameUrl)
|
||||||
|
// })
|
||||||
|
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/1.png" })
|
||||||
|
await page.waitForNavigation()
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/2.png" })
|
||||||
|
// await page.screenshot({ path: "__tests__/screenshots/4.png" })
|
||||||
|
const email = process.env.AUTH_EMAIL
|
||||||
|
const password = process.env.AUTH_PW
|
||||||
|
|
||||||
|
console.log(email)
|
||||||
|
|
||||||
|
await page.waitForSelector('input[type="email"]')
|
||||||
|
await page.waitForSelector('input[type="password"]')
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/3.png" })
|
||||||
|
|
||||||
|
// Find the email input field and type the email
|
||||||
|
const emailInput = await page.$('input[type="email"]')
|
||||||
|
await emailInput.type(email)
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/4.png" })
|
||||||
|
|
||||||
|
await page.waitForSelector('input[value="Next"]')
|
||||||
|
// Submit the form (if necessary)
|
||||||
|
const submitInput1 = await page.$('input[type="submit"]')
|
||||||
|
await submitInput1.click()
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/5.png" })
|
||||||
|
|
||||||
|
// Find the password input field and type the password
|
||||||
|
const passwordInput = await page.$('input[type="password"]')
|
||||||
|
await passwordInput.type(password)
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/6.png" })
|
||||||
|
|
||||||
|
await page.waitForSelector('input[value="Sign in"]')
|
||||||
|
// Submit the form (if necessary)
|
||||||
|
const submitInput = await page.$('input[value="Sign in"]')
|
||||||
|
await submitInput.click()
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/7.png" })
|
||||||
|
|
||||||
|
await page.waitForSelector('input[value="No"]')
|
||||||
|
// Submit the form (if necessary)
|
||||||
|
const noInput = await page.$('input[value="No"]')
|
||||||
|
await noInput.click()
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/8.png" })
|
||||||
|
|
||||||
|
const callbackUrl = "https://leaky-ships.mal-noh.de/"
|
||||||
|
await page.waitForFunction(`window.location.href === '${callbackUrl}'`)
|
||||||
|
// await page.waitForNavigation({ waitUntil: "networkidle0" })
|
||||||
|
await page.screenshot({ path: "__tests__/screenshots/9.png" })
|
||||||
|
}, 15000)
|
||||||
|
})
|
|
@ -10,6 +10,7 @@ function BurgerMenu({
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
|
id="menu"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"absolute left-4 top-4 flex h-16 w-16 items-center justify-center rounded-lg border-b-2 border-shield-gray bg-grayish shadow-lg duration-100 active:border-b-0 active:border-t-2 md:left-6 md:top-6 md:h-20 md:w-20 md:rounded-xl md:border-b-4 md:active:border-t-4 lg:left-8 lg:top-8 xl:left-12 xl:top-12 xl:h-24 xl:w-24",
|
"absolute left-4 top-4 flex h-16 w-16 items-center justify-center rounded-lg border-b-2 border-shield-gray bg-grayish shadow-lg duration-100 active:border-b-0 active:border-t-2 md:left-6 md:top-6 md:h-20 md:w-20 md:rounded-xl md:border-b-4 md:active:border-t-4 lg:left-8 lg:top-8 xl:left-12 xl:top-12 xl:h-24 xl:w-24",
|
||||||
{ "blur-sm": blur }
|
{ "blur-sm": blur }
|
||||||
|
|
|
@ -3,17 +3,18 @@ import {
|
||||||
FontAwesomeIconProps,
|
FontAwesomeIconProps,
|
||||||
} from "@fortawesome/react-fontawesome"
|
} from "@fortawesome/react-fontawesome"
|
||||||
import classNames from "classnames"
|
import classNames from "classnames"
|
||||||
import { ReactNode } from "react"
|
|
||||||
|
|
||||||
function OptionButton({
|
function OptionButton({
|
||||||
|
id,
|
||||||
icon,
|
icon,
|
||||||
callback,
|
callback,
|
||||||
children,
|
node,
|
||||||
disabled,
|
disabled,
|
||||||
}: {
|
}: {
|
||||||
|
id: string
|
||||||
icon: FontAwesomeIconProps["icon"]
|
icon: FontAwesomeIconProps["icon"]
|
||||||
callback?: () => void
|
callback?: () => void
|
||||||
children: ReactNode
|
node?: JSX.Element
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
|
@ -28,7 +29,7 @@ function OptionButton({
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
title={!disabled ? "" : "Please login"}
|
title={!disabled ? "" : "Please login"}
|
||||||
>
|
>
|
||||||
<span className="mx-auto">{children}</span>
|
<span className="mx-auto">{node ? node : id}</span>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
className="ml-2 w-10 text-xl sm:ml-12 sm:text-4xl"
|
className="ml-2 w-10 text-xl sm:ml-12 sm:text-4xl"
|
||||||
icon={icon}
|
icon={icon}
|
||||||
|
|
6
leaky-ships/jest-puppeteer.config.js
Normal file
6
leaky-ships/jest-puppeteer.config.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
/** @type {import('jest-environment-puppeteer').JestPuppeteerConfig} */
|
||||||
|
module.exports = {
|
||||||
|
launch: {
|
||||||
|
headless: "new",
|
||||||
|
},
|
||||||
|
}
|
9
leaky-ships/jest.config.js
Normal file
9
leaky-ships/jest.config.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
module.exports = {
|
||||||
|
verbose: true,
|
||||||
|
preset: "jest-puppeteer",
|
||||||
|
watchPathIgnorePatterns: [
|
||||||
|
"<rootDir>/(?!__tests__)/", // Exclude all paths except for __tests__
|
||||||
|
"<rootDir>/(?!\\.next/)/", // Exclude all paths except for .next/
|
||||||
|
],
|
||||||
|
setupFiles: ["dotenv/config"],
|
||||||
|
}
|
|
@ -6,7 +6,8 @@
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint"
|
"lint": "next lint",
|
||||||
|
"test": "jest --watchAll"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||||
|
@ -51,7 +52,10 @@
|
||||||
"@types/react-dom": "^18.2.4",
|
"@types/react-dom": "^18.2.4",
|
||||||
"@types/web-bluetooth": "^0.0.16",
|
"@types/web-bluetooth": "^0.0.16",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
|
"dotenv": "^16.3.1",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
|
"jest": "^29.6.1",
|
||||||
|
"jest-puppeteer": "^9.0.0",
|
||||||
"postcss": "^8.4.24",
|
"postcss": "^8.4.24",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"prettier-plugin-tailwindcss": "^0.2.8",
|
"prettier-plugin-tailwindcss": "^0.2.8",
|
||||||
|
|
|
@ -17,6 +17,7 @@ export default function Home() {
|
||||||
</video>
|
</video>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
id="start"
|
||||||
className="font-farro rounded-lg border-b-4 border-orange-400 bg-warn px-12 pb-4 pt-5 text-2xl font-bold duration-100 active:border-b-0 active:border-t-4 sm:rounded-xl sm:border-b-[6px] sm:px-14 sm:pb-5 sm:pt-6 sm:text-3xl sm:active:border-t-[6px] md:rounded-2xl md:border-b-8 md:px-20 md:pb-6 md:pt-7 md:text-4xl md:active:border-t-8 xl:px-24 xl:pb-8 xl:pt-10 xl:text-5xl"
|
className="font-farro rounded-lg border-b-4 border-orange-400 bg-warn px-12 pb-4 pt-5 text-2xl font-bold duration-100 active:border-b-0 active:border-t-4 sm:rounded-xl sm:border-b-[6px] sm:px-14 sm:pb-5 sm:pt-6 sm:text-3xl sm:active:border-t-[6px] md:rounded-2xl md:border-b-8 md:px-20 md:pb-6 md:pt-7 md:text-4xl md:active:border-t-8 xl:px-24 xl:pb-8 xl:pt-10 xl:text-5xl"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
|
@ -84,6 +84,7 @@ function Login() {
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
|
id="email"
|
||||||
onClick={login("email")}
|
onClick={login("email")}
|
||||||
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"
|
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"
|
||||||
>
|
>
|
||||||
|
@ -111,6 +112,7 @@ function Login() {
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
<button
|
<button
|
||||||
|
id="microsoft"
|
||||||
onClick={login("azure-ad")}
|
onClick={login("azure-ad")}
|
||||||
className="flex w-full justify-evenly rounded-lg border border-gray-400 bg-slate-100 px-5 py-3 text-black drop-shadow-md duration-300 hover:bg-slate-200"
|
className="flex w-full justify-evenly rounded-lg border border-gray-400 bg-slate-100 px-5 py-3 text-black drop-shadow-md duration-300 hover:bg-slate-200"
|
||||||
>
|
>
|
||||||
|
@ -129,6 +131,7 @@ function Login() {
|
||||||
{errorType && (
|
{errorType && (
|
||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
<button
|
<button
|
||||||
|
id="back"
|
||||||
onClick={() => router.push("/")}
|
onClick={() => router.push("/")}
|
||||||
className="mt-10 rounded-lg border-2 border-gray-400 bg-gray-500 bg-opacity-75 px-16 py-2 text-white shadow-inner drop-shadow-md backdrop-blur-md transition-colors duration-300 hover:border-blue-600"
|
className="mt-10 rounded-lg border-2 border-gray-400 bg-gray-500 bg-opacity-75 px-16 py-2 text-white shadow-inner drop-shadow-md backdrop-blur-md transition-colors duration-300 hover:border-blue-600"
|
||||||
>
|
>
|
||||||
|
|
|
@ -27,6 +27,7 @@ function Logout() {
|
||||||
<div className="flex flex-col justify-start gap-4">
|
<div className="flex flex-col justify-start gap-4">
|
||||||
<span>Are you sure you want to sign out?</span>
|
<span>Are you sure you want to sign out?</span>
|
||||||
<button
|
<button
|
||||||
|
id="signout"
|
||||||
onClick={() => signOut({ callbackUrl: "/" })}
|
onClick={() => signOut({ callbackUrl: "/" })}
|
||||||
className="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"
|
className="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"
|
||||||
>
|
>
|
||||||
|
|
|
@ -140,6 +140,7 @@ export default function Start() {
|
||||||
<div className="flex flex-col items-center rounded-xl border-4 border-black bg-grayish px-4 py-6 shadow-lg sm:mx-8 sm:p-12 md:w-full">
|
<div className="flex flex-col items-center rounded-xl border-4 border-black bg-grayish px-4 py-6 shadow-lg sm:mx-8 sm:p-12 md:w-full">
|
||||||
<div className="flex w-full justify-between">
|
<div className="flex w-full justify-between">
|
||||||
<button
|
<button
|
||||||
|
id="back"
|
||||||
className="-mt-2 h-14 w-20 self-start rounded-xl border-b-4 border-shield-gray bg-voidDark text-2xl text-grayish duration-100 active:border-b-0 active:border-t-4 sm:-mt-6 sm:w-40 sm:px-2 sm:text-5xl"
|
className="-mt-2 h-14 w-20 self-start rounded-xl border-b-4 border-shield-gray bg-voidDark text-2xl text-grayish duration-100 active:border-b-0 active:border-t-4 sm:-mt-6 sm:w-40 sm:px-2 sm:text-5xl"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -151,6 +152,7 @@ export default function Start() {
|
||||||
</button>
|
</button>
|
||||||
{!session?.user.id && (
|
{!session?.user.id && (
|
||||||
<button
|
<button
|
||||||
|
id="login"
|
||||||
className="-mt-2 h-14 w-20 self-start rounded-xl border-b-4 border-orange-500 bg-yellow-500 text-2xl active:border-b-0 active:border-t-4 sm:-mt-6 sm:w-40 sm:px-2 sm:text-4xl"
|
className="-mt-2 h-14 w-20 self-start rounded-xl border-b-4 border-orange-500 bg-yellow-500 text-2xl active:border-b-0 active:border-t-4 sm:-mt-6 sm:w-40 sm:px-2 sm:text-4xl"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -164,13 +166,13 @@ export default function Start() {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col items-center gap-6 sm:gap-12">
|
<div className="flex flex-col items-center gap-6 sm:gap-12">
|
||||||
<OptionButton
|
<OptionButton
|
||||||
|
id="Raum erstellen"
|
||||||
callback={() => gameFetch()}
|
callback={() => gameFetch()}
|
||||||
icon={faPlus}
|
icon={faPlus}
|
||||||
disabled={!session}
|
disabled={!session}
|
||||||
>
|
/>
|
||||||
Raum erstellen
|
|
||||||
</OptionButton>
|
|
||||||
<OptionButton
|
<OptionButton
|
||||||
|
id="Raum beitreten"
|
||||||
callback={() => {
|
callback={() => {
|
||||||
router.push({
|
router.push({
|
||||||
pathname: router.pathname,
|
pathname: router.pathname,
|
||||||
|
@ -179,8 +181,8 @@ export default function Start() {
|
||||||
}}
|
}}
|
||||||
icon={faUserPlus}
|
icon={faUserPlus}
|
||||||
disabled={!session}
|
disabled={!session}
|
||||||
>
|
node={
|
||||||
{query.join && session ? (
|
query.join && session ? (
|
||||||
<OtpInput
|
<OtpInput
|
||||||
shouldAutoFocus
|
shouldAutoFocus
|
||||||
containerStyle={{ color: "initial" }}
|
containerStyle={{ color: "initial" }}
|
||||||
|
@ -193,11 +195,11 @@ export default function Start() {
|
||||||
renderSeparator={<span>-</span>}
|
renderSeparator={<span>-</span>}
|
||||||
renderInput={(props) => <input {...props} />}
|
renderInput={(props) => <input {...props} />}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : undefined
|
||||||
"Raum beitreten"
|
}
|
||||||
)}
|
/>
|
||||||
</OptionButton>
|
|
||||||
<OptionButton
|
<OptionButton
|
||||||
|
id="Zuschauen"
|
||||||
icon={faEye}
|
icon={faEye}
|
||||||
callback={() => {
|
callback={() => {
|
||||||
router.push({
|
router.push({
|
||||||
|
@ -205,8 +207,8 @@ export default function Start() {
|
||||||
query: { q: "watch" },
|
query: { q: "watch" },
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
node={
|
||||||
{query.watch ? (
|
query.watch ? (
|
||||||
<OtpInput
|
<OtpInput
|
||||||
shouldAutoFocus
|
shouldAutoFocus
|
||||||
containerStyle={{ color: "initial" }}
|
containerStyle={{ color: "initial" }}
|
||||||
|
@ -219,10 +221,9 @@ export default function Start() {
|
||||||
renderSeparator={<span>-</span>}
|
renderSeparator={<span>-</span>}
|
||||||
renderInput={(props) => <input {...props} />}
|
renderInput={(props) => <input {...props} />}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : undefined
|
||||||
"Zuschauen"
|
}
|
||||||
)}
|
/>
|
||||||
</OptionButton>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
2524
leaky-ships/pnpm-lock.yaml
generated
2524
leaky-ships/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue