diff --git a/.env.test b/.env.test new file mode 100644 index 0000000..fa5d553 --- /dev/null +++ b/.env.test @@ -0,0 +1,8 @@ +APPLICATION_PORT=3000 +BASE_URL="http://localhost:3000" +JWT_SECRET="jwt_secret" +POSTGRES_USER="testing_user" +POSTGRES_PASSWORD="testing_password" +POSTGRES_HOST="localhost" +POSTGRES_PORT="5000" +POSTGRES_DATABASE_NAME="testing_db" diff --git a/.github/workflows/tsc.yml b/.github/workflows/build.yml similarity index 87% rename from .github/workflows/tsc.yml rename to .github/workflows/build.yml index 10f2991..779301b 100644 --- a/.github/workflows/tsc.yml +++ b/.github/workflows/build.yml @@ -7,12 +7,12 @@ on: branches: [ "master" ] jobs: - tsc: + build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v1 with: - bun-version: latest + bun-version: 1.0.30 - name: bun install run: bun install diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..88d7cf7 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,20 @@ +name: Run Server Tests + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v1 + with: + bun-version: 1.0.30 + - name: bun install + run: bun install + - name: bun run test_script + run: bun run test_script.ts diff --git a/bunfig.toml b/bunfig.toml new file mode 100644 index 0000000..1792969 --- /dev/null +++ b/bunfig.toml @@ -0,0 +1,2 @@ +[test] +coverage = true # always enable coverage diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..d14a26a --- /dev/null +++ b/compose.yaml @@ -0,0 +1,9 @@ +services: + postgres: + image: "postgres:14-alpine" + ports: + - "5000:5432" + environment: + - POSTGRES_DB=testing_db + - POSTGRES_USER=testing_user + - POSTGRES_PASSWORD=testing_password diff --git a/package.json b/package.json index 6c8d84c..e01135d 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,9 @@ "name": "elysia", "version": "1.0.50", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", + "test": "source .env.test && bun test", "dev": "bun run --watch src/index.ts", + "test-server": "source .env.test && bun run --watch src/index.ts", "build": "tsc" }, "dependencies": { diff --git a/src/index.ts b/src/index.ts index 3fe625c..2221af9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,7 @@ import "reflect-metadata"; // required for TypeORM -import { PostgresDataSourceSingleton } from "./postgres"; -import { createApplicationServer } from "./server"; import { ILogObj, Logger } from "tslog"; +import { startServer } from "./start_server"; /** * Application configuration object. @@ -20,7 +19,7 @@ export interface Config { } /** - * Helper function that fetches reads applicaion config values and returns it as a `Config` + * Helper function that fetches reads application config values and returns it as a `Config` * object. */ export function getConfig(): Config { @@ -44,18 +43,4 @@ export const logger: Logger = new Logger({ // Bun automatically masks sensitive password fields logger.info("App Configuration", getConfig()); -/** - * Initialize Postgres database connector, to be passed on to the application server creator. - */ -const dataSource = await PostgresDataSourceSingleton.getInstance(); - -/** - * Create the application server, passing in the TypeORM data source. - */ -const app = createApplicationServer(dataSource); - -app.listen(getConfig().applicationPort); - -logger.info( - `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port} with NODE_ENV ${process.env.NODE_ENV}`, -); +startServer(); diff --git a/src/postgres/index.ts b/src/postgres/index.ts index b24357c..79050fa 100644 --- a/src/postgres/index.ts +++ b/src/postgres/index.ts @@ -10,6 +10,7 @@ export class PostgresDataSourceSingleton { public static async getInstance(): Promise { logger.info("Fetching postgres datasource instance"); + logger.trace("Config", config); if (!PostgresDataSourceSingleton.dataSource) { const dataSource = new DataSource({ type: "postgres", @@ -37,6 +38,7 @@ export class PostgresDataSourceSingleton { const result = await dataSource.initialize(); if (result.isInitialized) { + logger.trace("Postgres dataSource successfully initialized"); PostgresDataSourceSingleton.dataSource = result; return PostgresDataSourceSingleton.dataSource; } else { diff --git a/src/server.ts b/src/server.ts index ce0fd9f..b095f18 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,5 +1,3 @@ -import "reflect-metadata"; // required for TypeORM - import { DataSource } from "typeorm"; import { Elysia } from "elysia"; import { cookie } from "@elysiajs/cookie"; diff --git a/src/start_server.ts b/src/start_server.ts new file mode 100644 index 0000000..1dcce5c --- /dev/null +++ b/src/start_server.ts @@ -0,0 +1,13 @@ +import { logger } from "."; +import { PostgresDataSourceSingleton } from "./postgres"; +import { createApplicationServer } from "./server"; + +export const startServer = async () => { + const dataSource = await PostgresDataSourceSingleton.getInstance(); + + const app = createApplicationServer(dataSource); + + logger.info( + `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port} with NODE_ENV ${process.env.NODE_ENV}`, + ); +}; diff --git a/test/index.test.ts b/test/index.test.ts new file mode 100644 index 0000000..ee558e4 --- /dev/null +++ b/test/index.test.ts @@ -0,0 +1,19 @@ +import "reflect-metadata"; // required for TypeORM + +import { describe, expect, it } from "bun:test"; + +import { createApplicationServer } from "../src/server.ts"; +import { PostgresDataSourceSingleton } from "../src/postgres/index.ts"; + +describe("Server Testing", async () => { + console.log("NODE_ENV: ", process.env.NODE_ENV); + const dataSource = await PostgresDataSourceSingleton.getInstance(); + console.log("Fetched postgres datasource"); + const app = createApplicationServer(dataSource); + it("Correcly loads up the test server", async () => { + const response = await app + .handle(new Request("http://localhost:3000")) + .then((res) => res.status); + expect(response).toBe(200); + }); +}); diff --git a/test_script.ts b/test_script.ts new file mode 100644 index 0000000..1d9800a --- /dev/null +++ b/test_script.ts @@ -0,0 +1,22 @@ +import { $ } from "bun"; +import { setTimeout } from "timers/promises"; + +// Use docker compose to set up a postgres database as specified in compose.yaml +await $`docker compose up -d`; + +// We might be running tests much faster than when our postgres container is ready to handle +// them. Set up a 5 second delay before starting testing. +await setTimeout(5000); + +// Run tests +const testResult = await $`bun run test`; +if (testResult.exitCode !== 0) { + console.error( + "An error occured while running bun tests", + testResult.stderr.toString(), + ); + throw new Error(testResult.stderr.toString()); +} + +// Destroy the postgres instance and ensure any created volumes are removed as well +await $`docker compose down --volumes`;