mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
Basic Unit Tests (#15)
* added basic api testing framework * added credential signup test * added current user test * added github action * fixed bugs in action file * updated action * added pnpm setup * added dependency install * updated pnpm lock * only run server tests * added new package for e2e test * removed unused tests * updated action * updated test command * added env var reading * fixed typo * fixed typo * fixed unit tests with staging * added delay e2e test * added start server to action * fixed typo * fix aciton * updated github action * fixed bugs * fixed eslint error
This commit is contained in:
parent
8dae0fd60c
commit
66f6c86ddf
53
.github/workflows/e2e-api-tests.yaml
vendored
Normal file
53
.github/workflows/e2e-api-tests.yaml
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
name: Runs E2E API Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev]
|
||||
pull_request:
|
||||
branches: [main, dev]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
SERVER_BASE_URL: http://localhost:8101
|
||||
PROJECT_CLIENT_ID: ${{ secrets.PROJECT_CLIENT_ID }}
|
||||
PROJECT_CLIENT_KEY: ${{ secrets.PROJECT_CLIENT_KEY }}
|
||||
|
||||
NEXT_PUBLIC_STACK_URL: http://localhost:8101
|
||||
NEXT_PUBLIC_STACK_PROJECT_ID: ${{ secrets.PROJECT_CLIENT_ID }}
|
||||
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY: ${{ secrets.PROJECT_CLIENT_KEY }}
|
||||
STACK_SECRET_SERVER_KEY: test
|
||||
SERVER_SECRET: 23-wuNpik0gIW4mruTz25rbIvhuuvZFrLOLtL7J4tyo
|
||||
|
||||
EMAIL_HOST: 0.0.0.0
|
||||
EMAIL_PORT: 2500
|
||||
EMAIL_SECURE: false
|
||||
EMAIL_USERNAME: test
|
||||
EMAIL_PASSWORD: none
|
||||
EMAIL_SENDER: noreply@test.com
|
||||
|
||||
DATABASE_CONNECTION_STRING: ${{ secrets.DATABASE_CONNECTION_STRING }}
|
||||
DIRECT_DATABASE_CONNECTION_STRING: ${{ secrets.DATABASE_CONNECTION_STRING }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [20.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
with:
|
||||
version: 8
|
||||
- name: Install dependencies
|
||||
run: pnpm install && pnpm install -g wait-on
|
||||
- name: Build
|
||||
run: pnpm build:server
|
||||
- name: Start server & run tests
|
||||
run: pnpm -C packages/stack-server start & wait-on http://localhost:8101 && pnpm -C apps/e2e test:ci
|
||||
3
apps/e2e/.env
Normal file
3
apps/e2e/.env
Normal file
@ -0,0 +1,3 @@
|
||||
PROJECT_CLIENT_ID=internal
|
||||
PROJECT_CLIENT_KEY=client_key
|
||||
SERVER_BASE_URL=http://localhost:8101
|
||||
14
apps/e2e/package.json
Normal file
14
apps/e2e/package.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "e2e-tests",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "dotenv -c -- vitest run",
|
||||
"test:ci": "vitest run"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"dotenv-cli": "7.4.1"
|
||||
}
|
||||
}
|
||||
74
apps/e2e/tests/basic.test.ts
Normal file
74
apps/e2e/tests/basic.test.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import request from "supertest";
|
||||
import { BASE_URL, PROJECT_CLIENT_KEY, PROJECT_ID } from "./helpers";
|
||||
|
||||
const AUTH_HEADER = {
|
||||
"x-stack-project-id": PROJECT_ID,
|
||||
"x-stack-publishable-client-key": PROJECT_CLIENT_KEY,
|
||||
};
|
||||
|
||||
const JSON_HEADER = {
|
||||
"content-type": "application/json"
|
||||
}
|
||||
|
||||
function randomString() {
|
||||
return Math.random().toString(36);
|
||||
}
|
||||
|
||||
async function signUpWithEmailPassword() {
|
||||
const email = randomString() + "@example.com";
|
||||
const password = randomString();
|
||||
const response = await request(BASE_URL).post("/api/v1/auth/signup").set(AUTH_HEADER).set(JSON_HEADER).send({
|
||||
email,
|
||||
password,
|
||||
emailVerificationRedirectUrl: 'https://localhost:3000/verify-email',
|
||||
});
|
||||
|
||||
return { email, password, response };
|
||||
}
|
||||
|
||||
async function signInWithEmailPassword(email: string, password: string) {
|
||||
const response = await request(BASE_URL).post("/api/v1/auth/signin").set(AUTH_HEADER).set(JSON_HEADER).send({
|
||||
email,
|
||||
password,
|
||||
});
|
||||
|
||||
return { email, password, response };
|
||||
}
|
||||
|
||||
describe("Basic", () => {
|
||||
test("Main Page", async () => {
|
||||
const response = await request(BASE_URL).get("/");
|
||||
expect(response.status).toBe(307);
|
||||
});
|
||||
|
||||
test("Test API", async () => {
|
||||
const response = await request(BASE_URL).get("/api/v1");
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.text).contains("Stack API")
|
||||
});
|
||||
|
||||
test("Credential Sign Up", async () => {
|
||||
const { response } = await signUpWithEmailPassword();
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
test("Credential Sign In", async () => {
|
||||
const { email, password } = await signUpWithEmailPassword();
|
||||
const { response } = await signInWithEmailPassword(email, password);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
|
||||
test("Get Current User", async () => {
|
||||
const { email, password, response } = await signUpWithEmailPassword();
|
||||
await signInWithEmailPassword(email, password);
|
||||
|
||||
const response2 = await request(BASE_URL).get("/api/v1/current-user").set({
|
||||
...AUTH_HEADER,
|
||||
'authorization': 'StackSession ' + response.body.accessToken,
|
||||
});
|
||||
expect(response2.status).toBe(200);
|
||||
expect(response2.body.primaryEmail).toBe(email)
|
||||
});
|
||||
});
|
||||
11
apps/e2e/tests/helpers.ts
Normal file
11
apps/e2e/tests/helpers.ts
Normal file
@ -0,0 +1,11 @@
|
||||
function getEnvVar(name: string): string {
|
||||
const value = process.env[name]
|
||||
if (!value) {
|
||||
throw new Error(`Missing environment variable: ${name}`)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
export const BASE_URL = getEnvVar("SERVER_BASE_URL")
|
||||
export const PROJECT_ID = getEnvVar("PROJECT_CLIENT_ID")
|
||||
export const PROJECT_CLIENT_KEY = getEnvVar("PROJECT_CLIENT_KEY")
|
||||
9
apps/e2e/vitest.config.ts
Normal file
9
apps/e2e/vitest.config.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { defineConfig } from 'vitest/config'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
test: {
|
||||
environment: 'node',
|
||||
},
|
||||
})
|
||||
18
package.json
18
package.json
@ -22,13 +22,17 @@
|
||||
"lint": "turbo run lint --no-cache -- --max-warnings=0",
|
||||
"release": "release",
|
||||
"peek": "pnpm release --peek",
|
||||
"changeset": "changeset"
|
||||
"changeset": "changeset",
|
||||
"test": "turbo run test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.27.1",
|
||||
"@testing-library/react": "^15.0.2",
|
||||
"@types/node": "^20.8.10",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^6.x",
|
||||
"@typescript-eslint/parser": "^6.x",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"eslint": "8.30.0",
|
||||
"eslint-config-next": "^14",
|
||||
"eslint-config-standard-with-typescript": "^43",
|
||||
@ -36,17 +40,19 @@
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^6.0.0",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"jsdom": "^24.0.0",
|
||||
"rimraf": "^5.0.5",
|
||||
"supertest": "^6.3.4",
|
||||
"turbo": "^1.11.3",
|
||||
"typescript": "5.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.8.0"
|
||||
"typescript": "5.3.3",
|
||||
"vitest": "^1.5.0"
|
||||
},
|
||||
"packageManager": "pnpm@8.9.2",
|
||||
"pnpm": {
|
||||
"overrides": {}
|
||||
},
|
||||
"dependencies": {
|
||||
"engines": {
|
||||
"npm": ">=10.0.0",
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
"name": "@stackframe/stack-server",
|
||||
"version": "0.3.3",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"clean": "rimraf .next && rimraf node_modules",
|
||||
"typecheck": "tsc --noEmit",
|
||||
@ -26,10 +27,6 @@
|
||||
"prisma": {
|
||||
"seed": "npm run with-env -- ts-node prisma/seed.ts"
|
||||
},
|
||||
"engines": {
|
||||
"npm": ">=10.0.0",
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.11.3",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
|
||||
@ -6,7 +6,7 @@ import { useEffect } from "react";
|
||||
|
||||
export function Confetti() {
|
||||
useEffect(() => {
|
||||
confetti.default();
|
||||
confetti.default()?.catch((e) => console.error(e));
|
||||
}, []);
|
||||
|
||||
return (<></>);
|
||||
|
||||
25
packages/stack-server/src/server.ts
Normal file
25
packages/stack-server/src/server.ts
Normal file
@ -0,0 +1,25 @@
|
||||
// server.js
|
||||
import { Server, createServer } from 'http';
|
||||
import next from 'next';
|
||||
|
||||
const app = next({ dev: true });
|
||||
const handle = app.getRequestHandler();
|
||||
|
||||
let serverInstance: Server | null = null;
|
||||
|
||||
export function startServer(port: number) {
|
||||
return app.prepare().then(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
const server = createServer((req, res) => handle(req, res).catch((err) => console.error(err)));
|
||||
serverInstance = server.listen(port);
|
||||
console.log(`> Ready on http://localhost:${port}`);
|
||||
return server;
|
||||
});
|
||||
}
|
||||
|
||||
export function stopServer() {
|
||||
if (serverInstance) {
|
||||
serverInstance.close();
|
||||
console.log('> Server stopped');
|
||||
}
|
||||
}
|
||||
1336
pnpm-lock.yaml
1336
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -38,6 +38,9 @@
|
||||
},
|
||||
"email": {
|
||||
"cache": false
|
||||
},
|
||||
"test": {
|
||||
"cache": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user