All jobs

Write Supertest Tests for an Express API

Yes. An agent maps your Express routes and middleware to the tests that exist, writes Supertest cases for the gaps against a real MongoDB, and opens a PR.

Run this on RushIn a Project that has your repository.

What the agent does

The agent starts by finding out what is already tested, because most Express APIs have some tests and the useful work is in the gaps. In an API like hagopj13/node-express-boilerplate it reads package.json and finds Jest 26 and Supertest 6, a test script of jest -i --colors --verbose --detectOpenHandles, and yarn.lock, so it installs with Yarn. tests/integration/auth.test.js and tests/integration/user.test.js already hold 87 test(...) cases between them, with a describe block for every route in src/routes/v1/auth.route.js and src/routes/v1/user.route.js. It lists each route with the status codes its tests assert, so the pull request can show what was missing rather than restate what was there.

Then it reads src/app.js, where most of the untested behaviour sits. Every request goes through helmet(), xss() from xss-clean, mongoSanitize(), cors() and passport's JWT strategy, then an unknown path falls through to an ApiError with 404. None of the existing tests send a body containing a $gt operator or a <script> tag, and none hit a path that does not exist. The authLimiter in src/middlewares/rateLimiter.js allows 20 failed requests per 15 minutes but is mounted only when config.env === 'production', so it is never exercised under NODE_ENV=test. The agent writes cases for each: a login with {"email": {"$gt": ""}} that must not log anyone in, a registration whose name contains markup that comes back escaped, a 404 with the error handler's body, and a rate-limit test that builds its own small Express app with the real authLimiter mounted, since the production check lives in app.js.

For auth it adds the token cases the suite skips: an access token signed with the right secret but expired, a refresh token used as an access token, and a user whose role is user calling the manageUsers routes defined in src/config/roles.js. It reuses the existing fixtures in tests/fixtures/user.fixture.js and token.fixture.js and the setupTestDB helper, which connects with config.mongoose.url (the MONGODB_URL with -test appended when NODE_ENV is test) and clears every collection before each test.

MongoDB runs for real. The agent starts mongod in its sandbox, sets MONGODB_URL and JWT_SECRET the way .env.example names them, and runs yarn test. The existing tests stub only emailService.transport.sendMail so no mail leaves the run, and the new tests follow that rule and nothing more: no mocked models or services. When a new case fails because of the application, the agent keeps it with test.skip and a comment saying what the API returned, and lists it in the pull request.

Start it with one API call

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

{
  "agent": "claude",
  "input": "Write Jest and Supertest integration tests for every route in this Express API that lacks them, against a real MongoDB started in the sandbox, covering auth failures and validation errors. First list each route and middleware in app.js and the routes directory with the cases the existing tests already cover, and only add what is missing: operator injection and markup in request bodies, unknown paths, expired and wrong-type tokens, role checks, and any middleware that only runs in production, tested by mounting it on a small app in the test. Reuse the existing fixtures and test database helper, and do not mock models, services or the database; stubbing outbound email is fine. Run yarn test. If a new test fails because of the application, keep it skipped with a comment saying what the API returned. Open a pull request with the before and after table of routes and cases.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-api"
    }
  ]
}
  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 test files under tests/integration/, for a repository shaped like this boilerplate typically security.test.js for sanitizing, escaping and the 404 fallback, and rateLimiter.test.js for the limiter, plus new test(...) cases appended to auth.test.js and user.test.js for tokens and roles. It changes nothing under src/. The description opens with the table of routes and middleware, the cases that existed and the cases added, so the reviewer reads the coverage change without opening every file.

The proof is the yarn test output kept in the session from the agent's own sandbox, with Jest's verbose list of every test name and its result, and the repository's CI on the pull request if it has one. A skipped test appears both in that output and in the description, with what the API returned.

Before merging, a reviewer checks that the injection and markup cases assert on the database state as well as the response, that the rate-limit test cannot leak its counters into other tests, and that each skipped test is a real defect the team wants to fix rather than a test written against the wrong expectation.

Run it on every pull request that adds a route

Run it from a GitHub pull_request webhook. When a pull request changes a file under src/routes/ and nothing under tests/, your server sends this request with the pull request URL in resources, so the agent checks out that branch and writes the missing cases for the routes it adds. Each pull request gets its own session in its own sandbox, with its own MongoDB.

Set a webhook URL on the API key and Rush POSTs run.completed or run.failed when the turn finishes, with the session URL, so your server can link the test pull request from the original one.

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

Why run it on Rush?

Testing an Express API against a real MongoDB on a laptop means a local mongod or Docker container, an .env file, and a test database that holds whatever the last interrupted run left behind. On Rush the agent starts MongoDB in its own sandbox, runs yarn test there with Jest's --detectOpenHandles on, and none of it touches your machine. Each run starts from an empty database, so a passing suite is not passing because of leftover rows.

What comes back is checkable. The session keeps each yarn test run with its full Jest output, so the claim that a $gt login is refused can be traced to the test and the run that shows it. The same request can go to several Express services at once, each in its own sandbox with its own database, each with a pull request someone reviews.

Frequently asked questions

My API already has tests. Will it duplicate them?

The prompt asks it to list what the existing tests cover first and add only what is missing, and the pull request description shows that table. In this boilerplate every route already has a describe block, so the new work is the middleware and token cases those blocks do not reach.

Does it need a MongoDB I host?

No. It starts MongoDB inside its own sandbox and points MONGODB_URL at it, the variable your config already reads. Nothing in the tests connects to your development or production database, and the database is gone when the sandbox is.

Will it use mongodb-memory-server?

Only if your repository already does. It runs the same mongod binary either way, but adding a package that downloads MongoDB on install changes your dependencies and CI, so by default the agent uses a real server started before the tests, matching how setupTestDB connects.

Does it work with Vitest or Mocha instead of Jest?

Yes. Supertest takes the Express app and works under any runner. The agent reads which runner your test script calls and writes the new cases in that style, with the same describe names and assertion library the existing files use.