Add jest E2E testing
This commit is contained in:
parent
92d1716f7f
commit
c392d1000c
12 changed files with 2601 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.
|
||||
|
||||
__tests__/screenshots/*
|
||||
|
||||
# logs
|
||||
/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 (
|
||||
<button
|
||||
id="menu"
|
||||
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",
|
||||
{ "blur-sm": blur }
|
||||
|
|
|
@ -3,17 +3,18 @@ import {
|
|||
FontAwesomeIconProps,
|
||||
} from "@fortawesome/react-fontawesome"
|
||||
import classNames from "classnames"
|
||||
import { ReactNode } from "react"
|
||||
|
||||
function OptionButton({
|
||||
id,
|
||||
icon,
|
||||
callback,
|
||||
children,
|
||||
node,
|
||||
disabled,
|
||||
}: {
|
||||
id: string
|
||||
icon: FontAwesomeIconProps["icon"]
|
||||
callback?: () => void
|
||||
children: ReactNode
|
||||
node?: JSX.Element
|
||||
disabled?: boolean
|
||||
}) {
|
||||
return (
|
||||
|
@ -28,7 +29,7 @@ function OptionButton({
|
|||
disabled={disabled}
|
||||
title={!disabled ? "" : "Please login"}
|
||||
>
|
||||
<span className="mx-auto">{children}</span>
|
||||
<span className="mx-auto">{node ? node : id}</span>
|
||||
<FontAwesomeIcon
|
||||
className="ml-2 w-10 text-xl sm:ml-12 sm:text-4xl"
|
||||
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",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"lint": "next lint",
|
||||
"test": "jest --watchAll"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||
|
@ -57,6 +58,8 @@
|
|||
"dotenv": "^16.3.1",
|
||||
"drizzle-kit": "^0.19.3",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"jest": "^29.6.1",
|
||||
"jest-puppeteer": "^9.0.0",
|
||||
"pg": "^8.11.1",
|
||||
"postcss": "^8.4.24",
|
||||
"prettier": "^2.8.8",
|
||||
|
|
|
@ -17,6 +17,7 @@ export default function Home() {
|
|||
</video>
|
||||
</div>
|
||||
<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"
|
||||
onClick={() =>
|
||||
setTimeout(() => {
|
||||
|
|
|
@ -84,6 +84,7 @@ function Login() {
|
|||
onChange={(e) => setEmail(e.target.value)}
|
||||
/>
|
||||
<button
|
||||
id="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"
|
||||
>
|
||||
|
@ -111,6 +112,7 @@ function Login() {
|
|||
/>
|
||||
</a>
|
||||
<button
|
||||
id="microsoft"
|
||||
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"
|
||||
>
|
||||
|
@ -129,6 +131,7 @@ function Login() {
|
|||
{errorType && (
|
||||
<div className="flex flex-col items-center">
|
||||
<button
|
||||
id="back"
|
||||
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"
|
||||
>
|
||||
|
|
|
@ -27,6 +27,7 @@ function Logout() {
|
|||
<div className="flex flex-col justify-start gap-4">
|
||||
<span>Are you sure you want to sign out?</span>
|
||||
<button
|
||||
id="signout"
|
||||
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"
|
||||
>
|
||||
|
|
|
@ -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 w-full justify-between">
|
||||
<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"
|
||||
onClick={() =>
|
||||
setTimeout(() => {
|
||||
|
@ -151,6 +152,7 @@ export default function Start() {
|
|||
</button>
|
||||
{!session?.user.id && (
|
||||
<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"
|
||||
onClick={() =>
|
||||
setTimeout(() => {
|
||||
|
@ -164,13 +166,13 @@ export default function Start() {
|
|||
</div>
|
||||
<div className="flex flex-col items-center gap-6 sm:gap-12">
|
||||
<OptionButton
|
||||
id="Raum erstellen"
|
||||
callback={() => gameFetch()}
|
||||
icon={faPlus}
|
||||
disabled={!session}
|
||||
>
|
||||
Raum erstellen
|
||||
</OptionButton>
|
||||
/>
|
||||
<OptionButton
|
||||
id="Raum beitreten"
|
||||
callback={() => {
|
||||
router.push({
|
||||
pathname: router.pathname,
|
||||
|
@ -179,25 +181,25 @@ export default function Start() {
|
|||
}}
|
||||
icon={faUserPlus}
|
||||
disabled={!session}
|
||||
>
|
||||
{query.join && session ? (
|
||||
<OtpInput
|
||||
shouldAutoFocus
|
||||
containerStyle={{ color: "initial" }}
|
||||
value={otp}
|
||||
onChange={setOtp}
|
||||
numInputs={4}
|
||||
inputType="number"
|
||||
inputStyle="inputStyle"
|
||||
placeholder="0000"
|
||||
renderSeparator={<span>-</span>}
|
||||
renderInput={(props) => <input {...props} />}
|
||||
/>
|
||||
) : (
|
||||
"Raum beitreten"
|
||||
)}
|
||||
</OptionButton>
|
||||
node={
|
||||
query.join && session ? (
|
||||
<OtpInput
|
||||
shouldAutoFocus
|
||||
containerStyle={{ color: "initial" }}
|
||||
value={otp}
|
||||
onChange={setOtp}
|
||||
numInputs={4}
|
||||
inputType="number"
|
||||
inputStyle="inputStyle"
|
||||
placeholder="0000"
|
||||
renderSeparator={<span>-</span>}
|
||||
renderInput={(props) => <input {...props} />}
|
||||
/>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
<OptionButton
|
||||
id="Zuschauen"
|
||||
icon={faEye}
|
||||
callback={() => {
|
||||
router.push({
|
||||
|
@ -205,24 +207,23 @@ export default function Start() {
|
|||
query: { q: "watch" },
|
||||
})
|
||||
}}
|
||||
>
|
||||
{query.watch ? (
|
||||
<OtpInput
|
||||
shouldAutoFocus
|
||||
containerStyle={{ color: "initial" }}
|
||||
value={otp}
|
||||
onChange={setOtp}
|
||||
numInputs={4}
|
||||
inputType="number"
|
||||
inputStyle="inputStyle"
|
||||
placeholder="0000"
|
||||
renderSeparator={<span>-</span>}
|
||||
renderInput={(props) => <input {...props} />}
|
||||
/>
|
||||
) : (
|
||||
"Zuschauen"
|
||||
)}
|
||||
</OptionButton>
|
||||
node={
|
||||
query.watch ? (
|
||||
<OtpInput
|
||||
shouldAutoFocus
|
||||
containerStyle={{ color: "initial" }}
|
||||
value={otp}
|
||||
onChange={setOtp}
|
||||
numInputs={4}
|
||||
inputType="number"
|
||||
inputStyle="inputStyle"
|
||||
placeholder="0000"
|
||||
renderSeparator={<span>-</span>}
|
||||
renderInput={(props) => <input {...props} />}
|
||||
/>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
2502
leaky-ships/pnpm-lock.yaml
generated
2502
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