Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5198097
Initted Playwright
renatodellosso Mar 29, 2025
f53844e
Move old tests into tests/unit
renatodellosso Mar 29, 2025
a222904
Config web server for playwright
renatodellosso Mar 29, 2025
7898a8f
Add tests for index page
renatodellosso Mar 29, 2025
766450d
1.2.26
gearbox4026 Mar 29, 2025
c153ece
Update Jest configuration and CI workflows for Playwright tests
renatodellosso Mar 29, 2025
aa1a0af
Merge branch 'e2e-testing' of github.com:Decatur-Robotics/Gearbox int…
renatodellosso Mar 29, 2025
1691b78
Fix package.json formatting
renatodellosso Mar 29, 2025
1a34bce
Don't error if ROLLBAR_TOKEN isn't set
renatodellosso Mar 29, 2025
ae8a167
Update environment configuration and CI workflows for Playwright tests
renatodellosso Mar 29, 2025
a761475
Set up sign in function for e2e tests
renatodellosso Mar 30, 2025
b66169e
Use mongodb in e2e tests
renatodellosso Mar 30, 2025
5aebd52
No more Resend errors when API key is missing
renatodellosso Mar 30, 2025
aa4cf8c
Fewer Rollbar errors, no request helper constructor logs
renatodellosso Mar 30, 2025
a488833
Add API key check in request method and safeguard user ID assignment …
renatodellosso Mar 30, 2025
e510aec
Fix error in allCompetitionsToPairings when TBA is disabled
renatodellosso Mar 30, 2025
bfadfff
Add NextAuth vars to .env.test
renatodellosso Mar 30, 2025
0403029
Merge branch 'main' into e2e-testing
renatodellosso Mar 31, 2025
c4410ed
Log Mongo connection string
renatodellosso Mar 31, 2025
3d612e6
Merge branch 'e2e-testing' of github.com:Decatur-Robotics/Gearbox int…
renatodellosso Mar 31, 2025
2b10cb1
Log on mongo connection
renatodellosso Mar 31, 2025
5b57044
Clean up uri determination
renatodellosso Mar 31, 2025
008acf3
Fix sign in
renatodellosso Mar 31, 2025
6e7f841
Fixed some profile tests
renatodellosso Mar 31, 2025
f690bf6
Increase retries and workers for CI in Playwright configuration
renatodellosso Mar 31, 2025
a5953b9
Don't add BASE_URL twice
renatodellosso Apr 1, 2025
a571a31
Shard playwright CI tests
renatodellosso Apr 1, 2025
a78dc1f
Update Playwright test command to use npm script
renatodellosso Apr 1, 2025
36389f9
Update CI workflow to set permissions and modify Playwright test command
renatodellosso Apr 1, 2025
51c018d
Bump version to 1.3.0, add note about requiring individual shard in G…
renatodellosso Apr 1, 2025
bfcd395
Repeat tests in CI
renatodellosso Apr 1, 2025
7e7324d
Merge branch 'main' into e2e-testing
renatodellosso Apr 1, 2025
0812bce
Fix signUp and signIn being flaky
renatodellosso Apr 1, 2025
3f845bf
Merge branch 'e2e-testing' of github.com:Decatur-Robotics/Gearbox int…
renatodellosso Apr 1, 2025
bcac56f
Tweak line breaks
renatodellosso Apr 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
NEXT_PUBLIC_API_URL=/api/
NEXT_PUBLIC_SLACK_CLIENT_ID=10831824934.7404945710466
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=G-1BFJYBDC76
NEXT_PUBLIC_RECAPTCHA_KEY=6Le63OUqAAAAABxxDrbaU9OywDLLHqutVwbw7a9d
NEXT_PUBLIC_RECAPTCHA_KEY=6Le63OUqAAAAABxxDrbaU9OywDLLHqutVwbw7a9d

ENV_FILE=.env.production
15 changes: 13 additions & 2 deletions .env.test
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
NEXT_PUBLIC_API_URL=http://localhost:3000/api
NEXTAUTH_URL=http://localhost:3000/
NEXTAUTH_SECRET=testsecret

NEXT_PUBLIC_API_URL=/api/

DEVELOPER_EMAILS=["test@gmail.com"]

TOA_URL=https://example.com
TOA_APP_ID=123
TOA_KEY=456

DEFAULT_IMAGE=https://example.com/default.jpg
DEFAULT_IMAGE=https://example.com/default.jpg

BASE_URL_FOR_PLAYWRIGHT=http://localhost:3000/
ENABLE_TEST_SIGNIN_ROUTE=true
FALLBACK_MONGODB_URI=mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000

ENV_FILE=.env.test

DB=playwright_tests
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,9 @@ jobs:

- name: Lint
run: npm run lint

e2e_test:
uses: ./.github/workflows/e2e_test.yml
permissions:
contents: read
pull-requests: write
71 changes: 71 additions & 0 deletions .github/workflows/e2e_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Playwright Tests
on: [workflow_dispatch, workflow_call]
jobs:
e2e_tests:
timeout-minutes: 60
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Make sure to require each shard in GitHub!
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: lts/*

- name: Install dependencies
run: npm ci

- name: Install Playwright browsers
run: npx playwright install --with-deps

- name: Start MongoDB
uses: supercharge/mongodb-github-action@1.12.0
with:
mongodb-version: "8.0"

- name: Run Playwright tests
run: npx cross-env NODE_ENV=test playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}

- name: Upload blob report to GitHub Actions Artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: blob-report-${{ matrix.shardIndex }}
path: blob-report
retention-days: 1

merge_reports:
Comment on lines +5 to +42

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
# Merge reports after playwright-tests, even if some shards have failed
if: ${{ !cancelled() }}
needs: [e2e_tests]

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Install dependencies
run: npm ci

- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@v4
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true

- name: Merge into HTML Report
run: npx playwright merge-reports --reporter html ./all-blob-reports

- name: Upload HTML report
uses: actions/upload-artifact@v4
with:
name: html-report--attempt-${{ github.run_attempt }}
path: playwright-report
retention-days: 14
Comment on lines +44 to +71

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,11 @@ next-env.d.ts

# PWA
public/sw.js
public/swe-worker*
public/swe-worker*

# Playwright
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
3 changes: 2 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"pmneo.tsimporter",
"austenc.tailwind-docs",
"bradlc.vscode-tailwindcss",
"Orta.vscode-jest"
"Orta.vscode-jest",
"ms-playwright.playwright"
]
}
4 changes: 4 additions & 0 deletions environment.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ declare global {

DEPLOY_ID: string;

BASE_URL_FOR_PLAYWRIGHT: string | undefined;
ENABLE_TEST_SIGNIN_ROUTE: string | undefined;
FALLBACK_MONGODB_URI: string | undefined;

NODE_ENV: "development" | "production";
}
}
Expand Down
26 changes: 17 additions & 9 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,26 @@ import {
createServer as createServerHttp,
} from "http";
import Logger from "./lib/client/Logger";
import { configDotenv } from "dotenv";
import getRollbar from "./lib/client/RollbarUtils";
import reportDeploymentToRollbar from "./lib/reportDeploymentToRollbar";
import { loadEnvConfig } from "@next/env";
import getRollbar, {
reportDeploymentToRollbar,
} from "./lib/client/RollbarUtils";

configDotenv();
const projectDir = process.cwd();
loadEnvConfig(projectDir);

const logger = new Logger(["STARTUP"]);

logger.log("Starting server...");

const dev = process.env.NODE_ENV !== "production";
const mode = process.env.NODE_ENV;

logger.debug("Constants set");
logger.info("Constants set. Using mode:", mode);

const useHttps =
existsSync("./certs/key.pem") && existsSync("./certs/cert.pem");
mode !== "test" &&
existsSync("./certs/key.pem") &&
existsSync("./certs/cert.pem");

const httpsOptions = useHttps
? {
Expand All @@ -32,10 +36,14 @@ const httpsOptions = useHttps
}
: {};

const port = useHttps ? 443 : 80;
const port = useHttps ? 443 : mode == "test" ? 3000 : 80;
logger.debug(`Using port ${port}`);

const app = next({ dev, port });
const app = next({
dev: mode == "development",
port,
turbopack: mode == "development",
});
const handle = app.getRequestHandler();

logger.debug("App preparing...");
Expand Down
7 changes: 2 additions & 5 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ const config: Config = {
// runner: "jest-runner",

// The paths to modules that run some code to configure or set up the testing environment before each test
setupFiles: ["<rootDir>/lib/testutils/setup.ts"],
setupFiles: ["<rootDir>/lib/testutils/JestSetup.ts"],

// A list of paths to modules that run some code to configure or set up the testing framework before each test
// setupFilesAfterEnv: [],
Expand All @@ -164,10 +164,7 @@ const config: Config = {
// testLocationInResults: false,

// The glob patterns Jest uses to detect test files
// testMatch: [
// "**/__tests__/**/*.[jt]s?(x)",
// "**/?(*.)+(spec|test).[tj]s?(x)"
// ],
testMatch: ["**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(test).[tj]s?(x)"],

// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [
Expand Down
39 changes: 22 additions & 17 deletions lib/MongoDB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,29 @@ import { default as BaseMongoDbInterface } from "mongo-anywhere/MongoDbInterface
import CachedDbInterface from "./client/dbinterfaces/CachedDbInterface";
import { cacheOptions } from "./client/dbinterfaces/CachedDbInterface";
import { findObjectBySlugLookUp } from "./slugToId";
import { loadEnvConfig } from "@next/env";

if (!process.env.MONGODB_URI) {
let uri = process.env.MONGODB_URI ?? process.env.FALLBACK_MONGODB_URI;

if (!uri) {
// Necessary to allow connections from files running outside of Next
require("dotenv").config();
const projectDir = process.cwd();
loadEnvConfig(projectDir);

uri = process.env.MONGODB_URI ?? process.env.FALLBACK_MONGODB_URI;

if (!process.env.MONGODB_URI)
console.error('Invalid/Missing environment variable: "MONGODB_URI"');
if (!uri)
console.warn(
'Invalid/Missing environment variables: "MONGODB_URI", "FALLBACK_MONGODB_URI". Using default connection string.',
);
}

const uri = process.env.MONGODB_URI ?? "mongodb://localhost:27017";
const options: MongoClientOptions = { maxPoolSize: 3 };

let client;
let clientPromise: Promise<MongoClient>;

if (!global.clientPromise) {
if (uri && !global.clientPromise) {
client = new MongoClient(uri, options);
global.clientPromise = client.connect();
}
Expand All @@ -37,21 +44,19 @@ export { clientPromise };
export async function getDatabase(
useCache: boolean = true,
): Promise<DbInterface> {
if (!global.interface) {
await clientPromise;
if (global.interface) return global.interface; // Return the existing instance if already created

const mongo = new MongoDBInterface(clientPromise);
await clientPromise;

const dbInterface = useCache
? new CachedDbInterface(mongo, cacheOptions)
: mongo;
await dbInterface.init();
global.interface = dbInterface;
const mongo = new MongoDBInterface(clientPromise);

return dbInterface;
}
const dbInterface = useCache
? new CachedDbInterface(mongo, cacheOptions)
: mongo;
await dbInterface.init();
global.interface = dbInterface;

return global.interface;
return dbInterface;
}

export class MongoDBInterface
Expand Down
11 changes: 6 additions & 5 deletions lib/ResendUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ export interface ResendInterface {
}

export class ResendUtils implements ResendInterface {
private static resend: Resend;
private static resend: Resend | undefined;

constructor() {
ResendUtils.resend ??= new Resend(process.env.SMTP_PASSWORD);
if (process.env.SMTP_PASSWORD)
ResendUtils.resend ??= new Resend(process.env.SMTP_PASSWORD);
}

async createContact(rawUser: NextAuthUser) {
Expand All @@ -31,15 +32,15 @@ export class ResendUtils implements ResendInterface {

const nameParts = user.name?.split(" ");

const res = await ResendUtils.resend.contacts.create({
const res = await ResendUtils.resend?.contacts.create({
email: user.email,
firstName: nameParts[0],
lastName: nameParts.length > 1 ? nameParts[1] : "",
unsubscribed: false,
audienceId: process.env.RESEND_AUDIENCE_ID,
});

if (!res.data?.id) {
if (!res?.data?.id) {
console.error("Failed to create contact for", user.email);
console.error(res);
return;
Expand All @@ -64,7 +65,7 @@ export class ResendUtils implements ResendInterface {
return;
}

ResendUtils.resend.emails.send({
ResendUtils.resend?.emails.send({
from: "Gearbox Server <server-no-reply@4026.org>",
to: JSON.parse(process.env.DEVELOPER_EMAILS), // Environment variables are always strings, so we need to parse it
subject,
Expand Down
4 changes: 3 additions & 1 deletion lib/TheBlueAlliance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ export namespace TheBlueAlliance {
}

async request(suburl: string): Promise<any> {
if (!this.apiKey) return;

var res = await fetch(this.baseUrl + suburl, {
method: "GET",
headers: {
Expand Down Expand Up @@ -334,7 +336,7 @@ export namespace TheBlueAlliance {
async allCompetitionsToPairings(year: number) {
var allCompetitions = await this.req.getEvents(year);
var pairings: CompetitonNameIdPair[] = [];
allCompetitions.forEach((comp) => {
allCompetitions?.forEach((comp) => {
pairings.push({ name: comp.name, tbaId: comp.key });
});

Expand Down
3 changes: 3 additions & 0 deletions lib/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ export interface Session extends NextAuthSession {
_id: string;
sessionToken: string;
userId: ObjectId;
/**
* Should actually be a Date
*/
expires: string;
}

Expand Down
Loading