# Add Missing Tests to Every Pull Request in an Express API

Yes. An agent reads each pull request to your Express API, writes Jest tests for the article routes it changes, runs npm test and pushes them back.

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

## What the agent does

The agent checks out the pull request and reads what it changes in the article routes. In an Express API like gothinkster/node-express-realworld-example-app those live in `src/app/routes/article/`: `article.controller.ts` registers the handlers (`GET /articles`, `POST /articles`, the `PUT` and `DELETE` on a slug, comments and favorites), and `article.service.ts` holds the logic they call, from `getArticles` and `getFeed` to `addComment`, `deleteComment`, `favoriteArticle` and `unfavoriteArticle`. The agent maps each changed handler to the service function behind it and lists the branches no test reaches, such as a new filter in `getArticles` or a new ownership check in `updateArticle`.

Next it reads how the repository tests services today. `package.json` runs `nx test` as its `test` script, and `jest.config.ts` uses `ts-jest` with `tsconfig.spec.json` and matches any `*.test.ts` or `*.spec.ts` under `src/`. The existing tests live in `src/tests/services/` (`article.service.test.ts`, `auth.service.test.ts`, `profile.service.test.ts`, `tag.service.test.ts`) and in `src/tests/utils/`. They import `prismaMock` from `src/tests/prisma-mock.ts`, a `mockDeep<PrismaClient>()` from `jest-mock-extended` that is reset before every test, and set the Prisma calls each case expects, such as `prismaMock.comment.findFirst.mockResolvedValue(null)`.

The agent writes the new cases into `article.service.test.ts` in the same Given, When, Then shape, one `describe` per service function, with the Prisma rows typed the way `src/prisma/schema.prisma` defines them. Each case asserts what the caller sees: the mapped article, the thrown `HttpException` with its status, or the arguments the service passed to Prisma when that is the behavior the pull request changed. It awaits every promise it asserts on, so a rejected call fails the test instead of passing silently.

Then it runs `npm test` and reads the Jest output. A test that fails because it set up the mock wrong gets fixed. A test that fails because the service now does the wrong thing stays out of the commit, since the prompt says not to change application code, and the agent explains the failure in its comment instead.

## Start it with one API call

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

```json
{
  "agent": "codex",
  "input": "This pull request changes the article routes. Read the diff against the base branch and list the new or changed behavior in src/app/routes/article/ (the controller and article.service.ts) that no existing test covers. Write Jest tests for each item in src/tests/services/article.service.test.ts, following the existing style: the prismaMock from src/tests/prisma-mock.ts, one describe per service function, Given/When/Then, and await every promise you assert on. Run npm test until the new tests pass. Do not change application code: if a test fails because the code is wrong, leave it out of the commit and describe the failure. Push the tests to this pull request's branch and post a comment listing each test and the behavior it covers.",
  "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 that only touches files under `src/tests/`. In a repository shaped like the Express RealWorld API that is usually `src/tests/services/article.service.test.ts`, with a new `describe` block for each service function the pull request added and new `test` cases inside the blocks it changed. No package is added: Jest, `ts-jest` and `jest-mock-extended` are already in `devDependencies`.

The agent's comment on the pull request lists every test, the behavior it covers ("rejects an update from a user who is not the author") and the `npm test` run it made. If a test exposed a bug in the change, the comment says which assertion failed and which line of `article.service.ts` it points to. Your CI then runs the suite on the pushed commit, and that check is the proof the tests pass outside the sandbox.

Before merging, a reviewer checks that the mocked Prisma calls match the queries the service really makes, so a test cannot pass against a query the code never runs. They also check that the tests assert behavior a client of the API depends on, not incidental details such as the order of keys in a Prisma `include`.

## Run it on every pull request opened

Put this prompt in an automation on the Project bound to your API's repository and add a GitHub trigger on `pull_request.opened`. Each pull request opened by someone who can write to the repository starts a run, and the run's prompt names the pull request, its URL, title, author and base branch. Pull requests from forks never fire it. Add `pull_request.synchronize` to the same trigger if you want new pushes covered as well.

From your own server, the equivalent is GitHub's `pull_request` webhook: on `opened`, send this request with the pull request's URL in `resources`, which clones its branch, and the delivery id as `Idempotency-Key`. Set a webhook URL on the API key and Rush POSTs `run.completed` or `run.failed` when the run's turn finishes, with the session URL to read the full answer.

## Why run it on Rush?

Writing tests for someone else's pull request usually means stashing your own work, switching branches, reinstalling `node_modules` for the Nx workspace and running Jest until the mocks line up. On Rush the agent does that in its own sandbox with its own clone at the pull request's branch, so your checkout and your running dev server stay where they were, and several pull requests get tests at the same time.

Every claim in its comment can be checked. The trajectory keeps each `npm test` command with its full output, including the runs that failed before the agent fixed a mock, and the CI run on the pushed commit repeats them on your own runner. The tests reach the reviewer in the same pull request as the change, instead of in a coverage cleanup weeks later.

## Frequently asked questions

### Does it test the Express routes or only the services?

It follows the repository. The Express RealWorld API tests its services with a mocked Prisma client and keeps HTTP-level tests in a separate `e2e` project, so the new tests go into `src/tests/services/`. If your repository already uses `supertest` against the Express app, the agent adds route tests there instead.

### Will it start a real database?

Not for these tests. They run against the `mockDeep<PrismaClient>()` in `src/tests/prisma-mock.ts`, which is how the existing suite works, so `npm test` needs no database. If your suite runs against Postgres, say so in the prompt and the agent starts one in its sandbox and applies your Prisma migrations first.

### Does it work with Vitest or Mocha instead of Jest?

Yes. It reads the test script and config the repository has and writes tests for that runner. Change `npm test` and the runner's name in the prompt to match, and the pushed tests use the same imports and assertion style as the files next to them.

### What does it do with a pull request that has nothing to test?

It says so in a comment and pushes nothing. A change to types, logging or documentation does not get a test written to raise a number.
