Skip to content

Commit 4ef61b0

Browse files
committed
Add first integration test
1 parent eac5aca commit 4ef61b0

File tree

7 files changed

+121
-12
lines changed

7 files changed

+121
-12
lines changed

.github/workflows/server-test.yml

+24-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,23 @@ jobs:
2020
test:
2121
name: Server Typecheck, Lint, and Tests
2222
runs-on: ubuntu-latest
23-
timeout-minutes: 3
23+
timeout-minutes: 5
24+
25+
services:
26+
postgres:
27+
image: postgres:15
28+
env:
29+
POSTGRES_USER: postgres
30+
POSTGRES_PASSWORD: postgres
31+
POSTGRES_DB: test_db
32+
ports:
33+
- 5432:5432
34+
options: >-
35+
--health-cmd pg_isready
36+
--health-interval 10s
37+
--health-timeout 5s
38+
--health-retries 5
39+
2440
steps:
2541
- uses: actions/checkout@v4
2642

@@ -30,6 +46,13 @@ jobs:
3046
- name: Install dependencies
3147
run: bun install
3248

49+
- name: Setup environment
50+
run: |
51+
echo "DATABASE_URL=postgres://postgres:postgres@localhost:5432/test_db" >> $GITHUB_ENV
52+
53+
- name: Run database migrations
54+
run: bun db:migrate
55+
3356
- name: Run tests
3457
run: bun test
3558

server/scripts/migrate.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ try {
1515
})
1616

1717
console.info("🚧 Migrations applied successfully")
18-
migrationClient.end({ timeout: 5_000 })
18+
await migrationClient.end({ timeout: 5_000 })
19+
process.exit(0)
1920
} catch (error) {
2021
console.error("🔥 Error applying migrations", error)
2122
process.exit(1)

server/src/__tests__/api.test.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import "./setup"
2+
3+
import { describe, expect, it, beforeAll, afterAll } from "bun:test"
4+
import { app } from "../index" // Adjust this import based on your app structure
5+
6+
describe("API Endpoints", () => {
7+
const testServer = app // Your Elysia app instance
8+
9+
// Example test
10+
it(
11+
"should return 200 for health check",
12+
async () => {
13+
const response = await testServer.handle(new Request("http://localhost/"))
14+
expect(response.status).toBe(200)
15+
expect(await response.text()).toContain("running")
16+
},
17+
{ timeout: 10000 },
18+
)
19+
20+
// Add more endpoint tests here
21+
// Example:
22+
// it("should create a new user", async () => {
23+
// const response = await testServer.handle(
24+
// new Request("http://localhost/api/users", {
25+
// method: "POST",
26+
// headers: {
27+
// "Content-Type": "application/json",
28+
// },
29+
// body: JSON.stringify({
30+
// name: "Test User",
31+
// email: "[email protected]",
32+
// }),
33+
// })
34+
// );
35+
// expect(response.status).toBe(201);
36+
// });
37+
})

server/src/__tests__/setup.ts

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { mock } from "bun:test"
2+
3+
// Mock external services for testing
4+
process.env.NODE_ENV = "test"
5+
6+
if (!process.env.RESEND_API_KEY) {
7+
process.env.RESEND_API_KEY = "test-key"
8+
}
9+
10+
if (!process.env.ENCRYPTION_KEY) {
11+
process.env.ENCRYPTION_KEY = "test-key"
12+
}
13+
// If some services are not needed during testing, you can use dummy values
14+
if (!process.env.AMAZON_ACCESS_KEY) {
15+
process.env.AMAZON_ACCESS_KEY = "test-key"
16+
}
17+
if (!process.env.AMAZON_SECRET_ACCESS_KEY) {
18+
process.env.AMAZON_SECRET_ACCESS_KEY = "test-secret"
19+
}
20+
// ... add other environment variables as needed
21+
22+
// You might want to mock external services
23+
mock.module("../libs/resend", () => ({
24+
sendEmail: mock().mockResolvedValue(true),
25+
}))
26+
27+
// doesn't work
28+
// mock.module("../libs/apn.ts", () => ({
29+
// apnProvider: mock().mockReturnValue(undefined),
30+
// }))

server/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ if (process.env.NODE_ENV !== "development") {
2727
console.info(`🚧 Starting server • ${process.env.NODE_ENV}${version}${gitCommitHash}`)
2828
}
2929

30-
const app = new Elysia()
30+
export const app = new Elysia()
3131
.use(root)
3232
.use(apiV1)
3333
.use(webSocket)

server/src/libs/apn.ts

+20-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
import APN from "apn"
22

33
// Configure APN provider
4-
export const apnProvider = new APN.Provider({
5-
token: {
6-
key: Buffer.from(process.env["APN_KEY"] ?? "", "base64").toString("utf-8"),
7-
keyId: process.env["APN_KEY_ID"] as string,
8-
teamId: process.env["APN_TEAM_ID"] as string,
9-
},
10-
production: process.env["NODE_ENV"] === "production",
11-
})
4+
let apnProvider: APN.Provider | undefined
5+
6+
export const getApnProvider = () => {
7+
if (process.env["NODE_ENV"] === "test") {
8+
return undefined
9+
}
10+
11+
if (!apnProvider) {
12+
apnProvider = new APN.Provider({
13+
token: {
14+
key: Buffer.from(process.env["APN_KEY"] ?? "", "base64").toString("utf-8"),
15+
keyId: process.env["APN_KEY_ID"] as string,
16+
teamId: process.env["APN_TEAM_ID"] as string,
17+
},
18+
production: process.env["NODE_ENV"] === "production",
19+
})
20+
}
21+
return apnProvider
22+
}
23+
1224
// Shutdown provider TODO: call on server close
1325
// apnProvider.shutdown()

server/src/methods/sendMessage.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { connectionManager } from "@in/server/ws/connections"
1919
import { getUpdateGroup } from "@in/server/utils/updates"
2020
import * as APN from "apn"
2121
import type { HandlerContext } from "../controllers/v1/helpers"
22-
import { apnProvider } from "../libs/apn"
22+
import { apnProvider, getApnProvider } from "../libs/apn"
2323
import { SessionsModel } from "@in/server/db/models/sessions"
2424
import { encryptMessage } from "@in/server/utils/encryption/encryptMessage"
2525
import { TInputId } from "@in/server/types/methods"
@@ -298,6 +298,12 @@ const sendPushNotificationToUser = async ({
298298
body: message,
299299
}
300300

301+
let apnProvider = getApnProvider()
302+
if (!apnProvider) {
303+
Log.shared.error("APN provider not found", { userId })
304+
return
305+
}
306+
301307
try {
302308
const result = await apnProvider.send(notification, session.applePushToken)
303309
if (result.failed.length > 0) {

0 commit comments

Comments
 (0)