Conversation
- Add objectstack-ai/hotcrm as git submodule at server/hotcrm/ - Create shell scripts for starting/stopping/waiting for the server - Create integration test files (auth, CRUD, metadata) with helpers - Add separate jest.integration.config.js for server integration tests - Add integration test CI workflow (.github/workflows/integration.yml) - Add test:integration:server and server management scripts to package.json - Update .gitignore for submodule artifacts and server runtime files - Exclude hotcrm submodule and integration tests from regular jest run - Install ts-jest for the integration test runner Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…port Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds the HotCRM server as a git submodule and introduces an integration-test harness (scripts + Jest config + CI) to run tests against a live HotCRM instance.
Changes:
- Added
server/hotcrmsubmodule and excluded it from TS/ESLint/Jest default tooling. - Added lifecycle scripts to start/wait/stop the HotCRM integration server.
- Added dedicated Jest integration config, integration test suites, and a GitHub Actions workflow to run them.
Reviewed changes
Copilot reviewed 13 out of 17 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Excludes the HotCRM submodule from TypeScript compilation. |
| server/hotcrm | Adds HotCRM as a git submodule pointer. |
| scripts/wait-for-server.sh | Polls an HTTP endpoint until the integration server is reachable/ready. |
| scripts/start-integration-server.sh | Installs/builds HotCRM and starts it (foreground or background with PID). |
| scripts/stop-integration-server.sh | Stops background server via PID file with graceful wait/force kill fallback. |
| package.json | Adds scripts for server lifecycle + integration tests; adds ts-jest. |
| jest.integration.config.js | Creates a separate Jest config for live-server integration tests. |
| jest.config.js | Excludes integration tests and the HotCRM submodule from default Jest runs. |
| tests/integration/server/helpers.ts | Adds shared fetch/auth helpers for integration tests. |
| tests/integration/server/auth.integration.test.ts | Adds authentication lifecycle integration tests. |
| tests/integration/server/crud.integration.test.ts | Adds CRUD integration tests for common objects. |
| tests/integration/server/metadata.integration.test.ts | Adds metadata integration tests (packages/objects/fields/views). |
| .gitmodules | Registers the server/hotcrm submodule source URL. |
| .gitignore | Ignores HotCRM build artifacts and integration runtime PID/log files. |
| .github/workflows/integration.yml | Runs HotCRM-backed integration tests in CI, including submodule checkout. |
| .eslintrc.js | Ignores linting the HotCRM submodule directory. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // The server sets session cookies on successful registration | ||
| const setCookie = regRes.headers.get("set-cookie") ?? ""; | ||
|
|
||
| // If we already have a session cookie from registration, use it | ||
| if (setCookie) { | ||
| return { email, cookie: setCookie }; | ||
| } | ||
|
|
||
| // Otherwise, login explicitly | ||
| const loginRes = await api("/api/v1/auth/sign-in/email", { | ||
| method: "POST", | ||
| body: JSON.stringify({ email, password }), | ||
| }); | ||
|
|
||
| if (!loginRes.ok) { | ||
| const body = await loginRes.text().catch(() => ""); | ||
| throw new Error(`Login failed (${loginRes.status}): ${body}`); | ||
| } | ||
|
|
||
| return { | ||
| email, | ||
| cookie: loginRes.headers.get("set-cookie") ?? "", | ||
| }; |
There was a problem hiding this comment.
registerAndLogin() is returning the raw Set-Cookie header value and later tests send it back as a Cookie header. This is not equivalent: Set-Cookie includes attributes (Path, HttpOnly, SameSite, etc.) that must not be echoed in Cookie, and if multiple cookies are set, headers.get("set-cookie") may collapse them into a single comma-delimited string that is not safely parseable. Convert response cookies into a proper Cookie header value (name=value pairs joined by ; ), ideally using Node/undici’s headers.getSetCookie() when available, and return that normalized cookie string from this helper so all tests reuse it consistently.
|
|
||
| ELAPSED=0 | ||
| while [ "$ELAPSED" -lt "$TIMEOUT" ]; do | ||
| if curl -sf -o /dev/null "$URL" 2>/dev/null; then |
There was a problem hiding this comment.
The readiness check uses curl -f, which treats non-2xx/3xx responses as failures. The default URL (/api/v1/auth/get-session) may legitimately return 401/403 when the server is up but unauthenticated, causing false negatives and timeouts. Consider treating “any HTTP response” as readiness (e.g., check that curl can connect and returns a non-000 status), or switch the default URL to a dedicated health endpoint that returns 200 without auth.
| if curl -sf -o /dev/null "$URL" 2>/dev/null; then | |
| HTTP_CODE="$(curl -s -o /dev/null -w "%{http_code}" "$URL" || echo "000")" | |
| if [ "$HTTP_CODE" != "000" ]; then |
|
|
||
| // Only match the server integration tests | ||
| testMatch: [ | ||
| "**/__tests__/integration/server/**/*.integration.test.(ts|tsx)", |
There was a problem hiding this comment.
Jest testMatch globs don’t support (ts|tsx) as an alternation group; this pattern typically won’t match and can result in zero tests being discovered. Use a brace expansion glob instead (e.g., **/*.integration.test.{ts,tsx}) or provide two explicit patterns.
| "**/__tests__/integration/server/**/*.integration.test.(ts|tsx)", | |
| "**/__tests__/integration/server/**/*.integration.test.{ts,tsx}", |
| # Install HotCRM submodule dependencies and build | ||
| - name: Setup HotCRM server | ||
| run: | | ||
| cd server/hotcrm | ||
| pnpm install | ||
| pnpm build | ||
|
|
There was a problem hiding this comment.
CI installs/builds HotCRM twice: once in “Setup HotCRM server”, then again inside start-integration-server.sh (which runs pnpm install + pnpm build). Drop the separate setup step and let the start script do it once, or add a flag/env to the start script (e.g., “skip install/build”) and use it in CI to avoid redundant work.
| # Install HotCRM submodule dependencies and build | |
| - name: Setup HotCRM server | |
| run: | | |
| cd server/hotcrm | |
| pnpm install | |
| pnpm build |
|
|
||
| echo "📦 Installing HotCRM dependencies…" | ||
| cd "$HOTCRM_DIR" | ||
| pnpm install --frozen-lockfile 2>/dev/null || pnpm install |
There was a problem hiding this comment.
Redirecting pnpm install --frozen-lockfile stderr to /dev/null can hide the actual reason the frozen install failed (making CI/local debugging harder). Prefer leaving stderr intact and explicitly handling the expected failure mode, or echo a brief message before falling back so failures remain diagnosable.
| pnpm install --frozen-lockfile 2>/dev/null || pnpm install | |
| pnpm install --frozen-lockfile || { | |
| status=$? | |
| echo "⚠️ pnpm install --frozen-lockfile failed with exit code $status; retrying without --frozen-lockfile…" | |
| pnpm install | |
| } |
Adds
objectstack-ai/hotcrmas a git submodule and scaffolds the integration test suite for running tests against a real HotCRM server.Submodule
server/hotcrm/— submodule trackingobjectstack-ai/hotcrmtsconfig.json,.eslintrc.js, andjest.config.jsso the mobile toolchain ignores it entirelyServer lifecycle scripts
scripts/start-integration-server.sh— installs deps, builds, starts server (supports--bgfor background mode)scripts/wait-for-server.sh— polls a URL with configurable timeoutscripts/stop-integration-server.sh— graceful shutdown via PID fileIntegration tests
Separate Jest config (
jest.integration.config.js) usingts-jestinnodeenv with 30s timeout. Three test suites under__tests__/integration/server/:Tests are resilient to server configuration differences — they assert success on supported endpoints and accept 404/501 for unregistered objects.
Usage
CI
New
.github/workflows/integration.yml— checks out submodules, installs + builds hotcrm, starts server, runs tests, tears down. Triggers on push/PR to main/develop and manual dispatch.✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.