Skip to content

Running tests after a change

After you change Server, Lib, or Agent Studio, run the suite that actually covers that change. Do not wait until a PR review to discover a broken Admin route or a Lib API that no longer round-trips.

This page is the contributor loop. The in-repo catalogs (which class covers which route, how to add a test) live in the Server and Lib repositories; links are at the bottom.

After you finish a change

  1. Identify which repository you edited.
  2. Run the unit tests for that area (seconds).
  3. Run the matching integration tests (in-process host, no SaaS).
  4. If the change touches agents, Temporal, or Xians.Lib APIs, run the matching Lib-backed Server cycle.
  5. Before opening a PR, run the full suite for that repository.
You changed Run at least
Server logic with no HTTP (validators, resolvers, caches) Server unit tests for that type
Server HTTP / Mongo (Admin, Web, Agent, User APIs) Matching *EndpointsTests class
Server auth (Admin API keys, roles, tenant scope) AdminAuthEndpointsTests plus related unit tests
Temporal HTTP, activations, schedules, HITL AdminApiTemporal (or the specific class)
Agent SDK behaviour on a live worker (chat, knowledge, secrets, documents, webhooks, files, custom workflows, schedules, HITL, cross-agent, activations, metrics, logging) The matching Lib-backed cycle
Xians.Lib internals Lib dotnet test (unit + mock; RealServer excluded)
Agent Studio UI npm test and npm run lint
An agent you author (not the platform) Unit Testing Workflows (Local Mode)

Two different “Lib” suites

Server Lib-backed tests start a real Xians.Lib agent against an in-process Server and a local Temporal CLI. They need no .env and no hosted cluster. That is the default after-dev path for agent SDK behaviour.

Lib RealServer tests (Category=RealServer) call SERVER_URL from a .env file. They are not included in Lib’s plain dotnet test. Opt in with --filter "Category=RealServer".

Prerequisites

  • .NET 10 SDK
  • Node.js 20+ if you changed Agent Studio
  • Clone Server and Lib as siblings. The Server test project references ../XiansAi.Lib/Xians.Lib/Xians.Lib.csproj:
Text Only
your-work-dir/
  XiansAi.Server/
  XiansAi.Lib/
  agent-studio/     # only if you work on Studio

No MongoDB install, no Temporal cluster, and no Auth0 / Azure AD credentials are required for the default Server suite. Integration tests start an ephemeral Mongo replica set (Mongo2Go). Temporal tests start a local Temporal CLI the first time they run (later runs reuse the cache).

Do not point tests at shared environments

Do not set MongoDB__ConnectionString or Temporal__FlowServerUrl to a staging or production cluster for dotnet test. The Server factory pins fixture values. Leftover Temporal__* environment variables are overridden only when a Temporal fixture is present.

Server (XiansAi.Server)

All Server tests live in XiansAi.Server.Tests. From the Server repo root:

Bash
dotnet test

That runs unit + Mongo integration + Temporal + Lib-backed cycles. Use filters while iterating.

Bash
# One class
dotnet test --filter "FullyQualifiedName~AdminAuthEndpointsTests"

# One test
dotnet test --filter "FullyQualifiedName~AdminAuthEndpointsTests.MissingBearer_ReturnsUnauthorized"

# HTML report (written under TestResults/)
dotnet test --logger "html;LogFileName=test-results.html"

Unit tests

Where: XiansAi.Server.Tests/UnitTests/

What they are: Isolated tests of services, validators, auth resolvers, and similar types. They do not start the ASP.NET host or Mongo.

When to run: After any logic change; always as the first check.

Bash
dotnet test --filter "FullyQualifiedName~Tests.UnitTests"

Examples: JWT claim extraction, secret-vault rules, AdminRoleTenantResolver, SSRF URL validation.

Integration tests (Mongo only)

Where: XiansAi.Server.Tests/IntegrationTests/ (AdminApi, WebApi, AgentApi, UserApi, AppsApi)

What they are: Real HTTP through the mapped endpoints (routing, authentication, validation, persistence) against an in-process host and Mongo2Go. Temporal, email, and certificate generation are mocked.

When to run: After endpoint, authz, or Mongo-backed CRUD changes. Workflow success paths that need a cluster belong in Temporal tests, not here.

Bash
# All integration tests except Temporal / Lib-backed
dotnet test --filter "FullyQualifiedName~Tests.IntegrationTests&FullyQualifiedName!~AdminApiTemporal"

# One surface
dotnet test --filter "FullyQualifiedName~Tests.IntegrationTests.AdminApi"

Admin tests authenticate with a real sk-Xnai-… API key (ConfigureAdminApiClientAsync). Web and Agent tests use a stub Test scheme. User API keeps its real apikey policy.

Class names follow {Surface}{Area}EndpointsTests (for example AdminKnowledgeEndpointsTests, AdminAuthEndpointsTests). The catalog is API suites.

Temporal tests

Where: classes in the AdminApiTemporal collection

What they are: The same in-process Server + Mongo, but Temporal is not mocked. One local Temporal CLI/dev server (WorkflowEnvironment.StartLocalAsync) is shared for the collection.

When to run: After changes to activations, workflow HTTP, schedules, HITL, worker deployments, or anything that must talk to Temporal.

Bash
dotnet test --filter "FullyQualifiedName~AdminApiTemporal"

The first run may download the Temporal CLI into the user cache. To use an existing binary:

Bash
export XIANS_TEMPORAL_CLI_PATH=/usr/local/bin/temporal
# or TEMPORAL_CLI_PATH
dotnet test --filter "FullyQualifiedName~AdminApiTemporal"

These tests do not run in parallel with each other (same xUnit collection), so workflow ids stay unique.

Details: Temporal tests.

Lib-backed tests

Most Temporal Admin tests drive an in-process stub workflow. Lib-backed cycles instead register a real agent with sibling Xians.Lib — the same SDK production agents use — then deploy, activate, and exercise it through Admin HTTP (and live SSE / SignalR where that is the product path).

When to run: After you change a Server API that agents call, or Lib behaviour those cycles cover. Pick the cycle that matches the feature:

Feature Filter
Chat, Admin SSE, UserApi SSE, /ws/chat EchoAgent
Knowledge overrides KnowledgeAgent
Secret Vault isolation SecretVaultAgent
Secret Vault from workflow and activity SecretVaultSdkAgent
Document DB DocumentDbAgent
Builtin webhooks WebhookAgent
File messages both ways FileMessagingAgent
Custom workflows / activable onboarding CustomWorkflowAgent
Schedules (Admin HTTP) SchedulerAgent
ScheduleCollection from workflow and activity ScheduleSdkAgent
HITL tasks (Admin HTTP) HitlTaskAgent
HITL TaskCollection from workflow and activity HitlTaskSdkAgent
Cross-agent workflows CrossAgentWorkflow
Activations SDK ActivationSdkAgent
Metrics MetricsAgent
Logging LoggingAgent
Bash
dotnet test --filter "FullyQualifiedName~EchoAgent"
dotnet test --filter "FullyQualifiedName~KnowledgeAgent"

If restore fails with a missing Xians.Lib.csproj, clone Lib next to Server (see Prerequisites).

What each cycle asserts: Lib agent workflows.

What this suite does not cover

  • Real identity providers (Auth0, Azure AD, Keycloak)
  • A remote Temporal cluster or a shared MongoDB
  • Native WebSocket transport (SignalR tests use long polling against TestServer)

Manual .http files under XiansAi.Server.Tests/http/ are for exploring APIs by hand. They are not part of dotnet test.

Xians.Lib (XiansAi.Lib)

Lib has its own project, Xians.Lib.Tests. From the Lib repo:

Bash
# Default loop: unit + mock integration. Does not hit a live Server.
dotnet test

# Unit only
dotnet test --filter "Category!=Integration&Category!=RealServer"

# WireMock / in-process integration (not your hosted Server)
dotnet test --filter "Category=Integration"

Plain dotnet test applies Category!=RealServer in the test csproj. Live agent-against-Server coverage is the Server Lib-backed cycles above — not Lib’s RealServer trait.

Category Connects to a hosted Server? In default dotnet test? When
Unit No Yes Always, after Lib logic changes
Integration (Category=Integration) No (WireMock / local Temporal if enabled) Yes Before commit, with unit tests
RealServer (Category=RealServer) Yes — SERVER_URL / API_KEY from .env No Optional check against a running Server you own
Bash
# Opt-in only: local or dedicated Server plus a .env
dotnet test --filter "Category=RealServer"

# Everything, including RealServer
dotnet test --filter "Category!=RealServer|Category=RealServer"

RealServer tests use live credentials

Copy env.template to .env locally. Do not commit API keys. Do not point SERVER_URL at production unless that is an explicit, isolated check.

A --filter you pass replaces the default exclusion. dotnet test --filter "FullyQualifiedName~Knowledge" can include RealServerKnowledgeTests. Add &Category!=RealServer to stay off the live Server.

Lib Category=Integration tests do not read .env (except Temporal tests when RUN_INTEGRATION_TESTS=true). Passing them does not prove your hosted Server is healthy.

More detail: Running tests (Lib).

Agent Studio (agent-studio)

From the Studio repo:

Bash
npm install
npm test          # vitest, once
npm run lint

There is no in-process Server here. After a Studio change that depends on a new Admin API, still run the matching Server integration or Lib-backed test in XiansAi.Server.

Agent authors (not platform code)

If you are writing an agent (workflows and activities) rather than the control plane, use Xians Local Mode and Temporal’s time-skipping environment. That path does not start Server or Mongo.

See Unit Testing Workflows.

Filter cheat sheet

Bash
# --- Server (from XiansAi.Server/) ---
dotnet test
dotnet test --filter "FullyQualifiedName~Tests.UnitTests"
dotnet test --filter "FullyQualifiedName~Tests.IntegrationTests&FullyQualifiedName!~AdminApiTemporal"
dotnet test --filter "FullyQualifiedName~AdminApiTemporal"
dotnet test --filter "FullyQualifiedName~AdminAuthEndpointsTests"
dotnet test --filter "FullyQualifiedName~EchoAgent"

# --- Lib (from XiansAi.Lib/) ---
dotnet test
dotnet test --filter "Category!=Integration&Category!=RealServer"
dotnet test --filter "Category=Integration"
dotnet test --filter "Category=RealServer"

# --- Studio (from agent-studio/) ---
npm test

Before you open a PR

For Server changes: dotnet test in XiansAi.Server (includes Temporal and Lib-backed cycles).

For Lib changes: dotnet test in XiansAi.Lib (RealServer excluded), plus the matching Server Lib-backed cycle if you changed an API agents call.

For Studio changes: npm test and npm run lint.

If a test fails, fix that failure before adding a second scenario on the same path. Prefer one status code and the fields that prove the behaviour.

Troubleshooting

Xians.Lib.csproj not found
Clone XiansAi.Lib next to XiansAi.Server. Restore the Server tests project again.

First Temporal run is slow or waits on a download
Expected. The CLI is cached afterwards. Set XIANS_TEMPORAL_CLI_PATH if you already have temporal installed.

Mongo-only tests suddenly talk to Temporal
You ran a class whose name contains AdminApiTemporal, or you ran unfiltered dotnet test. Mongo-only classes must not take a TemporalFixture.

Lib RealServer tests ran during a name filter
Any --filter replaces Lib’s default Category!=RealServer. Add &Category!=RealServer if you meant to stay off a live Server, or run plain dotnet test with no filter.

Need a single failing test’s logs
Raise console logging only for that run; the factory defaults to Warning so dotnet test stays readable. See Host and fixtures.

In-repo documentation