Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
62 changes: 61 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ jobs:
tests:
name: "Unit and E2E Tests"
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -28,10 +31,16 @@ jobs:
run: docker compose up -d

- name: Wait for container to be ready
id: container-startup
run: |
START_TIME=$(date +%s%3N)
for i in {1..30}; do
if curl -f http://localhost:3000/v1/health > /dev/null 2>&1; then
echo "Container is ready!"
END_TIME=$(date +%s%3N)
STARTUP_TIME_MS=$((END_TIME - START_TIME))
STARTUP_TIME=$(echo "scale=2; $STARTUP_TIME_MS / 1000" | bc)
echo "startup_time=$STARTUP_TIME" >> $GITHUB_OUTPUT
echo "Container is ready in ${STARTUP_TIME}s!"
exit 0
fi
echo "Waiting for container... ($i/30)"
Expand All @@ -42,6 +51,57 @@ jobs:
docker compose logs
exit 1

- name: Collect Docker stats
if: github.event_name == 'pull_request'
continue-on-error: true
id: docker-stats
run: |
# Get image size
IMAGE_SIZE=$(docker images appwrite/browser:local --format "{{.Size}}")

# Get container stats
CONTAINER_ID=$(docker compose ps -q appwrite-browser)
MEMORY_USAGE=$(docker stats $CONTAINER_ID --no-stream --format "{{.MemUsage}}" | cut -d'/' -f1 | xargs)

# Quick screenshot benchmark (3 runs, average)
TOTAL=0
for i in {1..3}; do
START=$(date +%s%3N)
curl -s -X POST http://localhost:3000/v1/screenshots \
-H "Content-Type: application/json" \
-d '{"url":"https://appwrite.io"}' \
-o /dev/null
END=$(date +%s%3N)
DURATION=$((END - START))
TOTAL=$((TOTAL + DURATION))
done
SCREENSHOT_AVG_MS=$((TOTAL / 3))
SCREENSHOT_AVG=$(echo "scale=2; $SCREENSHOT_AVG_MS / 1000" | bc)

# Store in GitHub output
echo "image_size=$IMAGE_SIZE" >> $GITHUB_OUTPUT
echo "memory_usage=$MEMORY_USAGE" >> $GITHUB_OUTPUT
echo "screenshot_time=$SCREENSHOT_AVG" >> $GITHUB_OUTPUT

- name: Comment PR with stats
if: github.event_name == 'pull_request' && steps.docker-stats.outcome == 'success'
continue-on-error: true
uses: marocchino/sticky-pull-request-comment@v2
with:
header: docker-image-stats
skip_unchanged: true
message: |
## Docker Image Stats

| Metric | Value |
|--------|-------|
| Image Size | ${{ steps.docker-stats.outputs.image_size }} |
| Memory Usage | ${{ steps.docker-stats.outputs.memory_usage }} |
| Cold Start Time | ${{ steps.container-startup.outputs.startup_time }}s |
| Screenshot Time | ${{ steps.docker-stats.outputs.screenshot_time }}s |

<sub>Screenshot benchmark: Average of 3 runs on https://appwrite.io</sub>

- name: Run e2e tests
run: bun test:e2e

Expand Down
2 changes: 1 addition & 1 deletion src/schemas/screenshot.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const screenshotSchema = z.object({
url: z.string().url(),
theme: z.enum(["light", "dark"]).default("light"),
headers: z.record(z.string(), z.any()).optional(),
sleep: z.number().min(0).max(60000).default(3000),
sleep: z.number().min(0).max(60000).default(0),
// Viewport options
viewport: z
.object({
Expand Down
32 changes: 8 additions & 24 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,17 @@ import {
handleScreenshotsRequest,
handleTestRequest,
} from "./routes";
import { Router } from "./utils/router";

const router = new Router();
router.add("POST", "/v1/screenshots", handleScreenshotsRequest);
router.add("POST", "/v1/reports", handleReportsRequest);
router.add("GET", "/v1/health", handleHealthRequest);
router.add("GET", "/v1/test", handleTestRequest);

const server = Bun.serve({
port,
async fetch(req) {
const url = new URL(req.url);
const path = url.pathname;

// Route matching
if (path === "/v1/screenshots" && req.method === "POST") {
return await handleScreenshotsRequest(req);
}

if (path === "/v1/reports" && req.method === "POST") {
return await handleReportsRequest(req);
}

if (path === "/v1/health" && req.method === "GET") {
return await handleHealthRequest(req);
}

if (path === "/v1/test" && req.method === "GET") {
return await handleTestRequest(req);
}

// 404 Not Found
return new Response("Not Found", { status: 404 });
},
fetch: (request) => router.handle(request),
});

console.log(`Server running on http://0.0.0.0:${server.port}`);
2 changes: 1 addition & 1 deletion src/utils/clean-modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ async function removeUnnecessaryFiles(): Promise<void> {
);
await deletePath(`${NODE_MODULES}/@sentry`);
await deletePath(`${NODE_MODULES}/@opentelemetry`);
await deletePath(`${NODE_MODULES}/axe-core/axe.js`);
await deletePath(`${NODE_MODULES}/axe-core/axe.js`);
await deletePath(`${NODE_MODULES}/lighthouse/cli`);
await deletePath(`${NODE_MODULES}/lighthouse/build-tracker.config.js`);
await deletePath(`${NODE_MODULES}/lighthouse/commitlint.config.js`);
Expand Down
40 changes: 40 additions & 0 deletions src/utils/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
type HTTPMethod =
| "GET"
| "POST"
| "PUT"
| "PATCH"
| "DELETE"
| "OPTIONS"
| "HEAD";

type RouteHandler = (req: Request) => Promise<Response>;

type Route = {
method: HTTPMethod;
pattern: RegExp;
handler: RouteHandler;
};

export class Router {
private routes: Route[] = [];

add(method: HTTPMethod, path: string, handler: RouteHandler): void {
this.routes.push({
method,
pattern: new RegExp(`^${path}$`),
handler,
});
}

async handle(req: Request): Promise<Response> {
const url = new URL(req.url);

for (const route of this.routes) {
if (route.method === req.method && route.pattern.test(url.pathname)) {
return await route.handler(req);
}
}

return new Response("Not Found", { status: 404 });
}
}
2 changes: 1 addition & 1 deletion tests/unit/screenshot.schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe("screenshotSchema", () => {
expect(result.quality).toBe(90);
expect(result.waitUntil).toBe("domcontentloaded");
expect(result.timeout).toBe(30000);
expect(result.sleep).toBe(3000);
expect(result.sleep).toBe(0);
});

test("should validate custom viewport", () => {
Expand Down