Skip to content

Commit c391782

Browse files
feat(tests): implement end-to-end tests for API rendering and add new test configurations
1 parent 6ab6be6 commit c391782

3 files changed

Lines changed: 85 additions & 3 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"scripts": {
88
"test": "vitest run",
99
"coverage": "vitest run --coverage",
10-
"test:api": "node app/server.js & PID=$!; sleep 2; API_URL=http://localhost:3000 npm run coverage; STATUS=$?; kill $PID 2>/dev/null; exit $STATUS",
10+
"test:e2e": "API_URL=http://localhost:3000 vitest run tests/api.test.js --config vitest.e2e.config.js",
1111
"test:watch": "vitest",
1212
"start": "node app/server.js",
1313
"dev": "nodemon app/server.js",

tests/api.test.js

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,35 @@ import { describe, it, expect } from "vitest";
22

33
const API_URL = process.env.API_URL || "https://html2pdfapi.com";
44

5+
function isPNG(buffer) {
6+
// PNG magic bytes: 89 50 4E 47 0D 0A 1A 0A
7+
return buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4E && buffer[3] === 0x47;
8+
}
9+
10+
function isJPEG(buffer) {
11+
// JPEG magic bytes: FF D8 FF
12+
return buffer[0] === 0xFF && buffer[1] === 0xD8 && buffer[2] === 0xFF;
13+
}
14+
15+
function isWebP(buffer) {
16+
// WebP: starts with RIFF....WEBP
17+
const riff = String.fromCharCode(buffer[0], buffer[1], buffer[2], buffer[3]);
18+
const webp = String.fromCharCode(buffer[8], buffer[9], buffer[10], buffer[11]);
19+
return riff === "RIFF" && webp === "WEBP";
20+
}
21+
22+
function isPDF(buffer) {
23+
// PDF header: %PDF-
24+
const header = String.fromCharCode(buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
25+
return header === "%PDF-";
26+
}
27+
28+
function isMP4(buffer) {
29+
// MP4 ftyp box: bytes 4-7 are "ftyp"
30+
const ftyp = String.fromCharCode(buffer[4], buffer[5], buffer[6], buffer[7]);
31+
return ftyp === "ftyp";
32+
}
33+
534
describe("API integration tests", () => {
635
it("should render an image from URL", async () => {
736
const response = await fetch(`${API_URL}/render`, {
@@ -14,8 +43,9 @@ describe("API integration tests", () => {
1443
});
1544
expect(response.status).toBe(200);
1645
expect(response.headers.get("content-type")).toContain("image/");
17-
const buffer = await response.arrayBuffer();
46+
const buffer = new Uint8Array(await response.arrayBuffer());
1847
expect(buffer.byteLength).toBeGreaterThan(0);
48+
expect(isPNG(buffer)).toBe(true);
1949
});
2050

2151
it("should render a PDF from URL", async () => {
@@ -29,8 +59,9 @@ describe("API integration tests", () => {
2959
});
3060
expect(response.status).toBe(200);
3161
expect(response.headers.get("content-type")).toContain("application/pdf");
32-
const buffer = await response.arrayBuffer();
62+
const buffer = new Uint8Array(await response.arrayBuffer());
3363
expect(buffer.byteLength).toBeGreaterThan(0);
64+
expect(isPDF(buffer)).toBe(true);
3465
});
3566

3667
it("should render HTML content directly", async () => {
@@ -44,6 +75,9 @@ describe("API integration tests", () => {
4475
});
4576
expect(response.status).toBe(200);
4677
expect(response.headers.get("content-type")).toContain("image/");
78+
const buffer = new Uint8Array(await response.arrayBuffer());
79+
expect(buffer.byteLength).toBeGreaterThan(0);
80+
expect(isPNG(buffer)).toBe(true);
4781
});
4882

4983
it("should return 400 for missing url and html", async () => {
@@ -94,6 +128,9 @@ describe("API integration tests", () => {
94128
}),
95129
});
96130
expect(response.status).toBe(200);
131+
const buffer = new Uint8Array(await response.arrayBuffer());
132+
expect(buffer.byteLength).toBeGreaterThan(0);
133+
expect(isPNG(buffer)).toBe(true);
97134
});
98135

99136
it("should support webp output format", async () => {
@@ -108,6 +145,24 @@ describe("API integration tests", () => {
108145
});
109146
expect(response.status).toBe(200);
110147
expect(response.headers.get("content-type")).toContain("image/webp");
148+
const buffer = new Uint8Array(await response.arrayBuffer());
149+
expect(buffer.byteLength).toBeGreaterThan(0);
150+
expect(isWebP(buffer)).toBe(true);
151+
});
152+
153+
it("should capture HTML with embedded resources", async () => {
154+
const response = await fetch(`${API_URL}/render`, {
155+
method: "POST",
156+
headers: { "Content-Type": "application/json" },
157+
body: JSON.stringify({
158+
url: "https://example.com",
159+
type: "html",
160+
}),
161+
});
162+
expect(response.status).toBe(200);
163+
const text = await response.text();
164+
expect(text).toContain("<!DOCTYPE html>");
165+
expect(text).toContain("<html");
111166
});
112167

113168
it("should not expose internal error details", async () => {
@@ -176,3 +231,23 @@ describe("API performance tests", () => {
176231
expect(disposition).toContain("filename=");
177232
});
178233
});
234+
235+
describe("API video tests", () => {
236+
it("should render a video from URL", async () => {
237+
const response = await fetch(`${API_URL}/render`, {
238+
method: "POST",
239+
headers: { "Content-Type": "application/json" },
240+
body: JSON.stringify({
241+
url: "https://example.com",
242+
type: "video",
243+
video: { fps: 24 },
244+
render: { scroll: { animate: true, duration: 1000 } },
245+
}),
246+
});
247+
expect(response.status).toBe(200);
248+
expect(response.headers.get("content-type")).toContain("video/");
249+
const buffer = new Uint8Array(await response.arrayBuffer());
250+
expect(buffer.byteLength).toBeGreaterThan(1000);
251+
expect(isMP4(buffer)).toBe(true);
252+
}, 60000);
253+
});

vitest.e2e.config.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { defineConfig } from 'vitest/config';
2+
3+
export default defineConfig({
4+
test: {
5+
testTimeout: 30000,
6+
},
7+
});

0 commit comments

Comments
 (0)