All jobs

Write API Integration Tests for a NestJS App

Yes. An agent starts your NestJS API against a real database in its sandbox and writes tests that call every endpoint, including auth and validation errors.

Run this on RushIn a Project that has your repository.

What the agent does

The agent begins with an inventory of the HTTP surface, read from the code rather than from documentation. In lujakob/nestjs-realworld-example-app, src/main.ts sets the global prefix api, and the controllers declare 20 routes: @Controller('articles') with list, feed, get, create, update, delete, comments and favorites, @Controller('profiles') with get, follow and unfollow, @Controller('tags'), and UserController with GET and PUT /user, POST /users, POST /users/login and DELETE /users/:slug. Each feature module's configure() lists the routes that run AuthMiddleware in forRoutes(...), so the agent knows which ones should answer 401 without a token.

Next it sets up the real dependencies. app.module.ts calls TypeOrmModule.forRoot() with no arguments, which reads ormconfig.json; the repository ships only ormconfig.json.example, pointing at MySQL with synchronize: true, and src/config.ts.example holding the JWT SECRET. The agent starts MySQL in its sandbox, writes a test ormconfig that points at a fresh nestjsrealworld_test database, and copies the config example, so TypeORM 0.2 creates the schema from the entities on startup. Nothing is mocked: the tests run against the same UserService, ArticleService and repositories the app uses.

Then it writes the suite with what the project already has. package.json already lists @nestjs/testing 7, supertest 3.4 and Jest 25 with jest.json matching /src/.*\.(test|spec), and the only test today is tag.controller.spec.ts, which spies on TagService.findAll. The agent builds the full ApplicationModule with Test.createTestingModule, calls app.setGlobalPrefix('api') as main.ts does, and drives it with supertest: register and log in a user to get a token, then for each route a success case, a missing or bad token where the route is protected, a validation error where a ValidationPipe applies (an empty username, email or password on CreateUserDto), and a not-found slug or username.

Before writing assertions it runs each request once to see the real response, then pins the status and body shape. Reading the modules, it notices that DELETE /api/users/:slug is not in UserModule's forRoutes, so it runs without AuthMiddleware. It writes the test for the behavior a RealWorld API should have, marks it as a known failure, and reports it rather than changing the controller. It runs npm test until every other test passes and the database is reset between files.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "Write integration tests that start this NestJS API against a real database in the sandbox and cover every endpoint: success, validation error, missing auth and not found. Read every controller and each module's AuthMiddleware forRoutes to build the route list, start the database ormconfig.json.example names, create test copies of ormconfig.json and src/config.ts, and boot the full ApplicationModule with @nestjs/testing and the 'api' prefix from main.ts. Drive it with supertest and reuse the project's Jest config. Reset the database between test files. If an endpoint behaves in a way that looks like a bug, such as a route with no auth check, write the test for the correct behavior, mark it as a known failure and list it in the pull request instead of changing application code. Run the suite and open a pull request with the results.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
  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

The pull request adds an integration suite under src/ that jest.json already picks up, for example src/article/article.e2e-spec.ts, src/user/user.e2e-spec.ts and src/profile/profile.e2e-spec.ts, a shared helper that boots the app and registers a user, and an ormconfig for the test database. If the suite needs a script, such as test:e2e with --runInBand so files do not share the database at once, it adds that to package.json and explains it. It does not touch the controllers, services or entities.

The description has a table with one row per endpoint and a column per case (success, validation, 401, 404), so a reviewer sees coverage at a glance and which cells do not apply. Beneath it is the list of findings, such as the unprotected DELETE /api/users/:slug, each with the request that shows it. The session's record holds every npm test run with Jest's output, including the first runs where database setup failed and what changed.

A reviewer checks the database the suite expects in CI (the pull request names the service container and environment it needs, or adds a workflow if you asked for one), that each test cleans up the rows it creates, and that the findings are real before merging the tests that are marked as failing.

Run it on every new controller added

The suite only stays complete if new endpoints get tests too. A GitHub trigger on pull_request.opened with a branch pattern for main can start this run with a prompt that names the pull request and asks for tests of any controller it adds or changes. Because the suite and its helper already exist after the first run, later runs extend them instead of building a second harness.

For a team that would rather batch it, a schedule trigger on Monday morning can ask for the endpoints added in the last week that have no integration test. Either way, Rush sends run.completed or run.failed to the webhook on the API key, so your server can post the pull request link where the team reviews tests.

The use case this job follows, with its automation and trigger: Write the missing tests.

Why run it on Rush?

Integration tests are the ones developers skip on a laptop, because they need a running MySQL, a config file that is not committed, and a test database you are not afraid to wipe. In a Rush sandbox the agent starts that database itself, boots the actual NestJS application against it and throws the whole machine away afterwards, so no local database or ormconfig.json is touched.

Every claim in the pull request has its output behind it. The route table comes from the controllers, the status codes come from real responses, and the session's record keeps each Jest run. A finding such as an endpoint missing its auth check arrives with the exact request that shows it, which is more useful than a test suite that simply asserts whatever the code happens to do.

Frequently asked questions

Does it mock the database or the services?

No. It boots the whole ApplicationModule with TypeORM pointed at a real database in the sandbox, so a request goes through the middleware, pipes, services and SQL. Mocks would only show the controller calls the service, which a type checker already tells you.

We use Postgres and Prisma, not MySQL and TypeORM.

It starts whatever database your configuration names and applies your schema the way your project does, with prisma migrate deploy or TypeORM migrations. The RealWorld example is MySQL because its ormconfig.json.example says so; the agent reads that file rather than assuming.

Will these tests run in our CI?

They need a database there too. The pull request names the service container and environment variables the suite expects, and if you ask in the prompt it adds a GitHub Actions job with a MySQL or Postgres service that runs them on every pull request.

What does it do with an old Jest or ts-jest setup?

It uses the versions you have. If the Jest config refers to a transform the installed ts-jest no longer ships, it switches that one entry to the ts-jest preset so the suite can run, and says so in the pull request, rather than upgrading Jest across the project.