Skip to content

Commit a746d13

Browse files
committed
chore: Add integration test example
1 parent 21f9859 commit a746d13

9 files changed

Lines changed: 141 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
node_modules
22
dist
33
.DS_Store
4+
data
45

56
# Zola Docs
67
#

bun.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,9 @@ To run an example, clone the repo and run the `examples/{name}/main.ts` file wit
55
```sh
66
bun examples/request-logger/main.ts
77
```
8+
9+
For examples with tests, run `bun test examples/{name}`:
10+
11+
```sh
12+
bun test examples/integration-tests
13+
```
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { beforeEach, describe, expect, it, mock } from "bun:test";
2+
import { HttpStatus } from "../../src";
3+
import { openDb } from "./db";
4+
5+
// Mock any external dependencies
6+
mock.module("./dependencies", async () => {
7+
// In this case, use a real SQLite instance, but keep it in-memory
8+
const db = await openDb(":memory:");
9+
10+
return { db };
11+
});
12+
13+
describe("App", async () => {
14+
// With bun:test, modules that depend on mocked modules or the mocked modules
15+
// themselves must be dynamically imported after the call to `mock.module`.
16+
const { app } = await import("./app");
17+
const { db } = await import("./dependencies");
18+
19+
const fetch = app.build();
20+
21+
beforeEach(() => {
22+
// Reset the DB before each test
23+
db.run("DELETE FROM request_history");
24+
});
25+
26+
it("should track all requests in SQLite", async () => {
27+
const url1 = new URL("http://localhost/one");
28+
const url2 = new URL("http://localhost/two");
29+
const url3 = new URL("http://localhost/three");
30+
31+
// Make the fetch requests
32+
await fetch(new Request(url1));
33+
await fetch(new Request(url2));
34+
await fetch(new Request(url3));
35+
36+
// Wait for onGlobalAfterResponse timeouts to be fired
37+
await Bun.sleep(1);
38+
39+
const history = db
40+
.query("SELECT method, path, status_code FROM request_history")
41+
.all();
42+
43+
expect(history).toHaveLength(3);
44+
expect(history).toContainEqual({
45+
method: "GET",
46+
path: "/one",
47+
status_code: HttpStatus.Ok,
48+
});
49+
expect(history).toContainEqual({
50+
method: "GET",
51+
path: "/two",
52+
status_code: HttpStatus.Ok,
53+
});
54+
expect(history).toContainEqual({
55+
method: "GET",
56+
path: "/three",
57+
status_code: HttpStatus.NotFound,
58+
});
59+
});
60+
});

examples/integration-tests/app.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { createApp } from "@aklinker1/zeta";
2+
import { db } from "./dependencies";
3+
4+
export const app = createApp()
5+
.onGlobalRequest(() => ({ startTime: new Date() }))
6+
.onGlobalAfterResponse(({ method, path, response, startTime }) => {
7+
db.run(
8+
`
9+
INSERT INTO request_history (id, start_time, path, method, status_code)
10+
VALUES (?, ?, ?, ?, ?)
11+
`,
12+
[
13+
crypto.randomUUID(),
14+
startTime.toISOString(),
15+
path,
16+
method,
17+
response.status,
18+
],
19+
);
20+
})
21+
.get("/", () =>
22+
db
23+
.query("SELECT * FROM request_history ORDER BY datetime(start_time) DESC")
24+
.all(),
25+
)
26+
.get("/one", () => "OK")
27+
.get("/two", () => "OK");

examples/integration-tests/db.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Database } from "bun:sqlite";
2+
import { mkdir } from "node:fs/promises";
3+
import { dirname } from "node:path";
4+
5+
export async function openDb(
6+
filename = "data/integration-tests-app.db",
7+
): Promise<Database> {
8+
console.log({ filename });
9+
if (filename !== ":memory:") {
10+
await mkdir(dirname(filename), { recursive: true });
11+
}
12+
13+
const db = new Database(filename);
14+
15+
db.run(`
16+
CREATE TABLE IF NOT EXISTS request_history (
17+
id TEXT PRIMARY KEY,
18+
start_time TEXT NOT NULL,
19+
path TEXT NOT NULL,
20+
method TEXT NOT NULL,
21+
status_code INTEGER NOT NULL
22+
)
23+
`);
24+
25+
return db;
26+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { openDb } from "./db";
2+
3+
export const db = await openDb();

examples/integration-tests/main.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import dedent from "dedent";
2+
import { app } from "./app";
3+
4+
app.listen(3000, () => {
5+
console.log(dedent`
6+
Integration test example started.
7+
8+
- Visit http://localhost:3000 to view request history.
9+
- Visit other endpoints to populate the history:
10+
- http://localhost:3000/one
11+
- http://localhost:3000/two
12+
- http://localhost:3000/three
13+
`);
14+
});

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"@typescript/native-preview": "^7.0.0-dev.20251114.1",
6363
"changelogen": "^0.6.2",
6464
"cookie": "^1.1.1",
65+
"dedent": "^1.7.1",
6566
"elysia": "^1.4.19",
6667
"expect-type": "^1.2.1",
6768
"hono": "^4.11.2",

0 commit comments

Comments
 (0)