Skip to content

feat: add hotcrm submodule and server integration test infrastructure#44

Merged
hotlong merged 3 commits intomainfrom
copilot/add-submodule-for-integration-tests
Feb 12, 2026
Merged

feat: add hotcrm submodule and server integration test infrastructure#44
hotlong merged 3 commits intomainfrom
copilot/add-submodule-for-integration-tests

Conversation

Copy link
Contributor

Copilot AI commented Feb 12, 2026

Adds objectstack-ai/hotcrm as a git submodule and scaffolds the integration test suite for running tests against a real HotCRM server.

Submodule

  • server/hotcrm/ — submodule tracking objectstack-ai/hotcrm
  • Excluded from tsconfig.json, .eslintrc.js, and jest.config.js so the mobile toolchain ignores it entirely

Server lifecycle scripts

  • scripts/start-integration-server.sh — installs deps, builds, starts server (supports --bg for background mode)
  • scripts/wait-for-server.sh — polls a URL with configurable timeout
  • scripts/stop-integration-server.sh — graceful shutdown via PID file

Integration tests

Separate Jest config (jest.integration.config.js) using ts-jest in node env with 30s timeout. Three test suites under __tests__/integration/server/:

  • auth — register, login, session retrieval, logout, invalid credential rejection
  • crud — create/read/update/delete for Account, Contact, Lead objects
  • metadata — packages, object list, fields, views

Tests are resilient to server configuration differences — they assert success on supported endpoints and accept 404/501 for unregistered objects.

Usage

pnpm server:hotcrm:bg          # start server in background on :4000
./scripts/wait-for-server.sh   # block until ready
pnpm test:integration:server   # run integration suite
pnpm server:hotcrm:stop        # teardown

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.

Copilot AI and others added 2 commits February 12, 2026 15:46
- 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>
Copilot AI changed the title [WIP] Add submodule for server integration testing feat: add hotcrm submodule and server integration test infrastructure Feb 12, 2026
Copilot AI requested a review from hotlong February 12, 2026 15:57
@hotlong hotlong marked this pull request as ready for review February 12, 2026 16:11
Copilot AI review requested due to automatic review settings February 12, 2026 16:11
@hotlong hotlong merged commit aea55e4 into main Feb 12, 2026
3 of 6 checks passed
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/hotcrm submodule 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.

Comment on lines +76 to +98
// 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") ?? "",
};
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.

ELAPSED=0
while [ "$ELAPSED" -lt "$TIMEOUT" ]; do
if curl -sf -o /dev/null "$URL" 2>/dev/null; then
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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

Copilot uses AI. Check for mistakes.

// Only match the server integration tests
testMatch: [
"**/__tests__/integration/server/**/*.integration.test.(ts|tsx)",
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
"**/__tests__/integration/server/**/*.integration.test.(ts|tsx)",
"**/__tests__/integration/server/**/*.integration.test.{ts,tsx}",

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +44
# Install HotCRM submodule dependencies and build
- name: Setup HotCRM server
run: |
cd server/hotcrm
pnpm install
pnpm build

Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
# Install HotCRM submodule dependencies and build
- name: Setup HotCRM server
run: |
cd server/hotcrm
pnpm install
pnpm build

Copilot uses AI. Check for mistakes.

echo "📦 Installing HotCRM dependencies…"
cd "$HOTCRM_DIR"
pnpm install --frozen-lockfile 2>/dev/null || pnpm install
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants