Skip to content

Commit aea55e4

Browse files
authored
Merge pull request #44 from objectstack-ai/copilot/add-submodule-for-integration-tests
2 parents c0340e5 + a2a6724 commit aea55e4

17 files changed

+886
-2
lines changed

.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,5 @@ module.exports = {
3636
},
3737
},
3838
],
39-
ignorePatterns: ["node_modules/", ".expo/", "dist/", "*.config.js", "babel.config.js"],
39+
ignorePatterns: ["node_modules/", ".expo/", "dist/", "*.config.js", "babel.config.js", "server/hotcrm/"],
4040
};

.github/workflows/integration.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: Integration Tests
2+
3+
on:
4+
pull_request:
5+
branches: [main, develop]
6+
push:
7+
branches: [main, develop]
8+
# Allow manual trigger
9+
workflow_dispatch:
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
integration:
16+
name: Server Integration Tests
17+
runs-on: ubuntu-latest
18+
timeout-minutes: 20
19+
20+
steps:
21+
- uses: actions/checkout@v4
22+
with:
23+
submodules: recursive
24+
25+
- uses: pnpm/action-setup@v4
26+
with:
27+
version: 10
28+
29+
- uses: actions/setup-node@v4
30+
with:
31+
node-version: 20
32+
cache: pnpm
33+
34+
# Install mobile app dependencies
35+
- name: Install dependencies
36+
run: pnpm install
37+
38+
# Install HotCRM submodule dependencies and build
39+
- name: Setup HotCRM server
40+
run: |
41+
cd server/hotcrm
42+
pnpm install
43+
pnpm build
44+
45+
# Start the server in background
46+
- name: Start HotCRM server
47+
run: ./scripts/start-integration-server.sh --bg
48+
env:
49+
PORT: 4000
50+
51+
# Wait for server readiness
52+
- name: Wait for server
53+
run: ./scripts/wait-for-server.sh http://localhost:4000/api/v1/auth/get-session 60
54+
55+
# Run integration tests
56+
- name: Run integration tests
57+
run: pnpm test:integration:server
58+
env:
59+
INTEGRATION_SERVER_URL: http://localhost:4000
60+
61+
# Stop server
62+
- name: Stop HotCRM server
63+
if: always()
64+
run: ./scripts/stop-integration-server.sh

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,15 @@ coverage/
5353
apps/docs/.next/
5454
apps/docs/.source/
5555
apps/docs/node_modules/
56+
57+
# hotcrm submodule build artifacts
58+
server/hotcrm/node_modules/
59+
server/hotcrm/.pnpm-store/
60+
server/hotcrm/packages/*/dist/
61+
server/hotcrm/packages/*/node_modules/
62+
server/hotcrm/apps/*/node_modules/
63+
server/hotcrm/apps/*/.next/
64+
65+
# integration server runtime files
66+
.hotcrm-server.pid
67+
.hotcrm-server.log

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "server/hotcrm"]
2+
path = server/hotcrm
3+
url = https://github.com/objectstack-ai/hotcrm.git
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/**
2+
* Server Integration Tests — Authentication Flow
3+
*
4+
* These tests run against a real HotCRM server and validate the complete
5+
* authentication lifecycle: registration → login → session → logout.
6+
*
7+
* Prerequisites:
8+
* 1. HotCRM server running: `./scripts/start-integration-server.sh --bg`
9+
* 2. Server is ready: `./scripts/wait-for-server.sh`
10+
*
11+
* Run:
12+
* pnpm test:integration:server
13+
*/
14+
15+
import { api, uniqueEmail, BASE_URL } from "./helpers";
16+
17+
const TEST_PASSWORD = "IntTest_Passw0rd!";
18+
19+
describe("Authentication Flow", () => {
20+
const email = uniqueEmail();
21+
let sessionCookie = "";
22+
23+
it("should register a new user via /api/v1/auth/sign-up/email", async () => {
24+
const res = await api("/api/v1/auth/sign-up/email", {
25+
method: "POST",
26+
body: JSON.stringify({
27+
email,
28+
password: TEST_PASSWORD,
29+
name: "Integration Tester",
30+
}),
31+
});
32+
33+
expect(res.status).toBeLessThan(400);
34+
35+
const body = await res.json();
36+
// The response should contain user data (email or user object)
37+
expect(body).toBeDefined();
38+
39+
// Capture session cookie for later requests
40+
sessionCookie = res.headers.get("set-cookie") ?? "";
41+
});
42+
43+
it("should login with the registered credentials via /api/v1/auth/sign-in/email", async () => {
44+
const res = await api("/api/v1/auth/sign-in/email", {
45+
method: "POST",
46+
body: JSON.stringify({
47+
email,
48+
password: TEST_PASSWORD,
49+
}),
50+
});
51+
52+
expect(res.status).toBeLessThan(400);
53+
54+
const body = await res.json();
55+
expect(body).toBeDefined();
56+
57+
// Update session cookie
58+
const newCookie = res.headers.get("set-cookie");
59+
if (newCookie) {
60+
sessionCookie = newCookie;
61+
}
62+
});
63+
64+
it("should retrieve the current session via /api/v1/auth/get-session", async () => {
65+
const res = await api("/api/v1/auth/get-session", {
66+
headers: sessionCookie ? { Cookie: sessionCookie } : {},
67+
});
68+
69+
expect(res.status).toBeLessThan(400);
70+
71+
const body = await res.json();
72+
expect(body).toBeDefined();
73+
});
74+
75+
it("should sign out via /api/v1/auth/sign-out", async () => {
76+
const res = await api("/api/v1/auth/sign-out", {
77+
method: "POST",
78+
headers: sessionCookie ? { Cookie: sessionCookie } : {},
79+
});
80+
81+
expect(res.status).toBeLessThan(400);
82+
});
83+
84+
it("should reject login with wrong password", async () => {
85+
const res = await api("/api/v1/auth/sign-in/email", {
86+
method: "POST",
87+
body: JSON.stringify({
88+
email,
89+
password: "WrongPassword123!",
90+
}),
91+
});
92+
93+
// Should fail authentication
94+
expect(res.status).toBeGreaterThanOrEqual(400);
95+
});
96+
});
97+
98+
describe("Registration Validation", () => {
99+
it("should reject registration without email", async () => {
100+
const res = await api("/api/v1/auth/sign-up/email", {
101+
method: "POST",
102+
body: JSON.stringify({
103+
password: TEST_PASSWORD,
104+
name: "No Email User",
105+
}),
106+
});
107+
108+
expect(res.status).toBeGreaterThanOrEqual(400);
109+
});
110+
111+
it("should reject registration without password", async () => {
112+
const res = await api("/api/v1/auth/sign-up/email", {
113+
method: "POST",
114+
body: JSON.stringify({
115+
email: uniqueEmail(),
116+
name: "No Password User",
117+
}),
118+
});
119+
120+
expect(res.status).toBeGreaterThanOrEqual(400);
121+
});
122+
});
123+
124+
describe("Server Health", () => {
125+
it("should respond to requests on the base URL", async () => {
126+
// A basic connectivity check — the server should respond
127+
const res = await fetch(BASE_URL);
128+
// Even a 404 is fine — the server is alive
129+
expect(res.status).toBeDefined();
130+
});
131+
});

0 commit comments

Comments
 (0)