# Add Missing Tests to Every Pull Request in a NestJS API

Yes. An agent reads each pull request to your NestJS API, writes Jest tests for the auth and users modules it changes, runs npm test and pushes them back.

[Run this on Rush](https://cloud.getrush.ai/run/test-every-pull-request/nestjs/), in a Project that has your repository.

## What the agent does

The agent reads the pull request's diff against the modules it touches. In a NestJS API like brocoders/nestjs-boilerplate the auth module is `src/auth/` (`auth.controller.ts`, `auth.service.ts`, its DTOs and strategies) and the users module is `src/users/` (`users.controller.ts`, `users.service.ts`, the `domain` entity and the `infrastructure/persistence` repositories for both a relational and a document database). `AuthService` alone has `validateLogin`, `register`, `confirmEmail`, `confirmNewEmail`, `forgotPassword`, `resetPassword`, `update`, `refreshToken`, `softDelete` and `logout`, so the agent lists exactly which of those the diff changes and which branch is new.

Then it reads how the project tests itself, and finds two different setups. The Jest config in `package.json` sets `rootDir` to `src` and matches `*.spec.ts`, which is what `npm test` runs, but the repository ships no unit specs under `src/` today. Its tests are end-to-end specs in `test/admin/auth.e2e-spec.ts`, `test/admin/users.e2e-spec.ts` and `test/user/auth.e2e-spec.ts`, run by `npm run test:e2e` with `test/jest-e2e.json`, and they use `supertest` against a running app at `APP_URL` built from `APP_PORT`, logging in as `admin@example.com` from `test/utils/constants.ts`. The `test:e2e:relational:docker` script brings that app up with Postgres and maildev through `docker-compose.relational.test.yaml`.

So the agent writes tests at both levels, each where it fits. For logic inside a service it adds a unit spec beside the source, such as `src/auth/auth.service.spec.ts`, using `Test.createTestingModule` from `@nestjs/testing` (already a dev dependency at 11.1.18) with `UsersService`, `SessionService`, `MailService`, `JwtService` and `ConfigService` provided as test doubles, and asserts what `validateLogin` or `register` returns or throws. For behavior a client sees over HTTP, such as a new field on `PATCH /api/v1/auth/me` or a new admin rule on `/api/v1/users`, it adds cases to the existing e2e specs in their `describe` blocks, with the same `request(app)` chains and `expect` calls.

It runs `npm test` for the unit specs, and starts the relational stack from `env-example-relational` to run `npm run test:e2e` for the e2e cases. When the stack cannot start in the sandbox, it says which e2e cases it wrote but could not run. A test that fails because a service is wrong stays out of the commit, as the prompt requires, and the failure goes into its comment.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "This pull request changes the auth and users modules. Read the diff against the base branch and list the new or changed behavior in src/auth and src/users that no existing test covers. For service logic, write Jest unit specs next to the source (for example src/auth/auth.service.spec.ts) with Test.createTestingModule from @nestjs/testing and test doubles for the injected services, and run npm test. For behavior visible over HTTP, add cases to the existing specs in test/admin and test/user in their style (supertest against APP_URL, the admin login from test/utils/constants.ts), start the relational stack with env-example-relational, and run npm run test:e2e. Do not change application code: if a test fails because the code is wrong, leave it out and describe the failure. Push the tests to this pull request's branch and post a comment listing each test, the behavior it covers and which command ran it.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app/pull/123"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

What comes back is a commit on the pull request's branch with two kinds of files, and no application code. New `*.spec.ts` files sit next to the services they test under `src/auth/` or `src/users/`, each building a testing module and checking one service method per `describe`. Existing files under `test/admin/` and `test/user/` gain new `it` cases that call the API with `supertest` and assert status codes and response bodies.

The agent's comment on the pull request lists every test, the behavior it covers, and whether it ran under `npm test` or `npm run test:e2e`, so a reviewer knows which ones the sandbox proved. When a test caught a bug, such as a login that succeeds for a user whose status is inactive, the comment quotes the failing expectation and points at the line in `auth.service.ts`. Your CI then runs both suites on the pushed commit.

Before merging, a reviewer checks that unit specs stub only the services injected into the class under test, so they test `AuthService` and not its doubles, and that e2e cases register their own users with unique emails, as the existing specs do with `Date.now()`, so reruns do not collide.

## Run it on every pull request opened

Add an automation with this prompt to the Project connected to your NestJS repository and give it a GitHub trigger on `pull_request.opened`. Every pull request opened by someone who can write to the repository starts one run, and the run's prompt carries the pull request's number, URL, title, author and base branch. Forked pull requests never fire it. `max_runs_per_hour`, from 1 to 30, keeps a day of many small pull requests from starting more runs than you want.

From your own backend, the same thing is a handler for GitHub's `pull_request` webhook that sends this request on `opened` with the pull request's URL in `resources`, so Rush clones its branch. With a webhook URL set on the API key, your backend hears `run.completed` or `run.failed` when each run's turn ends.

## Why run it on Rush?

The e2e half of this job needs the API, Postgres and a mail catcher running together, which on a laptop means Docker Compose stacks competing with your own. On Rush each pull request's run gets its own sandbox and its own clone at the pull request's branch, starts the stack it needs there, and leaves your machine alone, while other pull requests get their own runs at the same time.

The result says what was proven and how. The trajectory keeps each `npm test` and `npm run test:e2e` command with its output, the comment separates tests that ran from tests that only compiled, and your CI repeats both suites on the pushed commit. That is a stronger statement than a coverage number, and it reaches the reviewer inside the pull request.

## Frequently asked questions

### Why does it add unit specs if the repository only has e2e tests?

Because the Jest config in `package.json` already expects `*.spec.ts` files under `src/` and `npm test` runs them, and service logic like token refresh or password reset is cheaper to pin there than over HTTP. Behavior a client sees still gets an e2e case, in the files that already exist.

### Does it work with the document (MongoDB) setup too?

Yes. The boilerplate has `env-example-document` and `docker-compose.document.test.yaml` for MongoDB. Name the document stack in the prompt and the agent starts that one for the e2e cases; the unit specs do not touch a database either way.

### Will it mock TypeORM repositories?

In unit specs it replaces the services injected into the class under test, such as `UsersService` for `AuthService`, rather than reaching into TypeORM. The e2e cases use the real database the stack starts, the same way the existing specs do.

### Can I use Codex for this?

Yes. Change `agent` to `codex` in the request. The repository, the prompt and the shape of the result do not change.
