mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-14 22:33:44 -05:00
Add basic art upload E2E test (#2708)
This commit is contained in:
20
.github/workflows/e2e-tests.yml
vendored
20
.github/workflows/e2e-tests.yml
vendored
@@ -22,6 +22,22 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Start MinIO
|
||||
run: docker compose up -d minio
|
||||
|
||||
- name: Wait for MinIO to be ready
|
||||
run: |
|
||||
for i in {1..30}; do
|
||||
if curl -sf http://127.0.0.1:9000/minio/health/live; then
|
||||
echo "MinIO is ready"
|
||||
exit 0
|
||||
fi
|
||||
echo "Waiting for MinIO... ($i/30)"
|
||||
sleep 2
|
||||
done
|
||||
echo "MinIO failed to start"
|
||||
exit 1
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
@@ -36,6 +52,10 @@ jobs:
|
||||
- name: Run E2E tests
|
||||
run: npm run test:e2e
|
||||
|
||||
- name: Stop MinIO
|
||||
if: always()
|
||||
run: docker compose down
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -25,5 +25,6 @@ dump
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
||||
.e2e-minio-started
|
||||
|
||||
notepad.txt
|
||||
|
||||
@@ -176,6 +176,7 @@ const basicSeeds = (variation?: SeedVariation | null) => [
|
||||
nzapUser,
|
||||
users,
|
||||
fixAdminId,
|
||||
makeArtists,
|
||||
adminUserWeaponPool,
|
||||
userProfiles,
|
||||
userMapModePreferences,
|
||||
@@ -264,6 +265,8 @@ function wipeDB() {
|
||||
"GroupMatchMap",
|
||||
"GroupMatch",
|
||||
"Group",
|
||||
"TaggedArt",
|
||||
"ArtTag",
|
||||
"ArtUserMetadata",
|
||||
"Art",
|
||||
"UnvalidatedUserSubmittedImage",
|
||||
@@ -348,6 +351,14 @@ function makeAdminTournamentOrganizer() {
|
||||
.run();
|
||||
}
|
||||
|
||||
function makeArtists() {
|
||||
sql
|
||||
.prepare(
|
||||
`update "User" set "isArtist" = 1 where id in (${ADMIN_ID}, ${NZAP_TEST_ID})`,
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
function adminUserWeaponPool() {
|
||||
for (const [i, weaponSplId] of [200, 1100, 2000, 4000].entries()) {
|
||||
sql
|
||||
|
||||
46
e2e/art.spec.ts
Normal file
46
e2e/art.spec.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { NZAP_TEST_ID } from "~/db/seed/constants";
|
||||
import { expect, impersonate, navigate, seed, test } from "~/utils/playwright";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
test.describe("Art", () => {
|
||||
test("uploads art as NZAP, admin approves, art displays on user page", async ({
|
||||
page,
|
||||
}) => {
|
||||
await seed(page);
|
||||
await impersonate(page, NZAP_TEST_ID);
|
||||
|
||||
await navigate({ page, url: "/art/new" });
|
||||
|
||||
const testImagePath = path.join(__dirname, "fixtures/test-image.png");
|
||||
await page.locator('input[type="file"]').setInputFiles(testImagePath);
|
||||
|
||||
await expect(page.locator("form img")).toBeVisible();
|
||||
|
||||
await page.getByRole("button", { name: "Save" }).click();
|
||||
|
||||
await expect(page).toHaveURL(/\/u\/.*\/art/);
|
||||
await expect(page.getByText(/pending moderator approval/i)).toBeVisible();
|
||||
|
||||
await impersonate(page);
|
||||
await navigate({ page, url: "/upload/admin" });
|
||||
|
||||
await expect(page.locator("img").first()).toBeVisible();
|
||||
|
||||
await page.getByRole("button", { name: /All .* above ok/ }).click();
|
||||
|
||||
await expect(page.getByText("All validated!")).toBeVisible();
|
||||
|
||||
await navigate({ page, url: "/u/nzap/art" });
|
||||
|
||||
const artImage = page.locator("img").first();
|
||||
await expect(artImage).toBeVisible();
|
||||
|
||||
const box = await artImage.boundingBox();
|
||||
expect(box).not.toBeNull();
|
||||
expect(box!.width).toBeGreaterThan(0);
|
||||
expect(box!.height).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
BIN
e2e/fixtures/test-image.png
Normal file
BIN
e2e/fixtures/test-image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1006 B |
@@ -6,11 +6,57 @@ import { E2E_BASE_PORT } from "~/utils/playwright";
|
||||
const WORKER_COUNT = Number(process.env.E2E_WORKERS) || 4;
|
||||
const DEBUG = process.env.E2E_DEBUG === "true";
|
||||
const SERVER_PROCESSES: ChildProcess[] = [];
|
||||
const MINIO_MARKER_FILE = ".e2e-minio-started";
|
||||
|
||||
declare global {
|
||||
var __E2E_SERVERS__: ChildProcess[];
|
||||
}
|
||||
|
||||
async function waitForMinio(timeout = 60000): Promise<boolean> {
|
||||
const start = Date.now();
|
||||
while (Date.now() - start < timeout) {
|
||||
try {
|
||||
const response = await fetch("http://127.0.0.1:9000/minio/health/live");
|
||||
if (response.ok) {
|
||||
return true;
|
||||
}
|
||||
} catch {
|
||||
// MinIO not ready yet
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function ensureMinioRunning(): Promise<boolean> {
|
||||
// Check if MinIO is already running
|
||||
try {
|
||||
const response = await fetch("http://127.0.0.1:9000/minio/health/live");
|
||||
if (response.ok) {
|
||||
// biome-ignore lint/suspicious/noConsole: CLI script output
|
||||
console.log("MinIO is already running");
|
||||
return false;
|
||||
}
|
||||
} catch {
|
||||
// MinIO not running, we need to start it
|
||||
}
|
||||
|
||||
// biome-ignore lint/suspicious/noConsole: CLI script output
|
||||
console.log("Starting MinIO...");
|
||||
execSync("docker compose up -d minio", { stdio: "inherit" });
|
||||
|
||||
const isReady = await waitForMinio();
|
||||
if (!isReady) {
|
||||
throw new Error("MinIO failed to start within timeout");
|
||||
}
|
||||
|
||||
// biome-ignore lint/suspicious/noConsole: CLI script output
|
||||
console.log("MinIO is ready");
|
||||
|
||||
fs.writeFileSync(MINIO_MARKER_FILE, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
function killProcessOnPort(port: number): void {
|
||||
try {
|
||||
// Try to find and kill any process on this port (macOS/Linux)
|
||||
@@ -43,6 +89,9 @@ async function globalSetup(_config: FullConfig) {
|
||||
// biome-ignore lint/suspicious/noConsole: CLI script output
|
||||
console.log(`\nStarting e2e test setup with ${WORKER_COUNT} workers...`);
|
||||
|
||||
// Start MinIO if not already running
|
||||
await ensureMinioRunning();
|
||||
|
||||
// Build the app once with E2E test flag so VITE_E2E_TEST_RUN is embedded
|
||||
// Use port 6173 as the base - tests will rewrite URLs as needed
|
||||
// biome-ignore lint/suspicious/noConsole: CLI script output
|
||||
@@ -92,6 +141,11 @@ async function globalSetup(_config: FullConfig) {
|
||||
SESSION_SECRET: "secret",
|
||||
VITE_SITE_DOMAIN: `http://localhost:${port}`,
|
||||
VITE_E2E_TEST_RUN: "true",
|
||||
STORAGE_END_POINT: "http://127.0.0.1:9000",
|
||||
STORAGE_ACCESS_KEY: "minio-user",
|
||||
STORAGE_SECRET: "minio-password",
|
||||
STORAGE_REGION: "us-east-1",
|
||||
STORAGE_BUCKET: "sendou",
|
||||
},
|
||||
detached: false,
|
||||
});
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { execSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import type { FullConfig } from "@playwright/test";
|
||||
|
||||
const MINIO_MARKER_FILE = ".e2e-minio-started";
|
||||
|
||||
declare global {
|
||||
var __E2E_SERVERS__: import("node:child_process").ChildProcess[];
|
||||
}
|
||||
@@ -19,6 +23,18 @@ async function globalTeardown(_config: FullConfig) {
|
||||
// Give processes a moment to clean up
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
|
||||
// Stop MinIO if we started it (check for marker file)
|
||||
if (fs.existsSync(MINIO_MARKER_FILE)) {
|
||||
// biome-ignore lint/suspicious/noConsole: CLI script output
|
||||
console.log("Stopping MinIO...");
|
||||
try {
|
||||
execSync("docker compose stop minio", { stdio: "inherit" });
|
||||
} catch {
|
||||
// Ignore errors - MinIO might already be stopped
|
||||
}
|
||||
fs.unlinkSync(MINIO_MARKER_FILE);
|
||||
}
|
||||
|
||||
// biome-ignore lint/suspicious/noConsole: CLI script output
|
||||
console.log("All servers stopped.\n");
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user