Q32 of 40 · REST Assured
How do you handle long-polling or async API responses in REST Assured?
Short answer
Short answer: Poll the status endpoint with Awaitility — define a condition (statusEquals("COMPLETE")), a poll interval, and a timeout. REST Assured fires the GET inside the Awaitility lambda; Awaitility handles retries. Never Thread.sleep() in tests — it makes them slow, brittle, and sensitive to environment speed.
Detail
Async APIs (job queues, document processing, webhooks) return a job ID immediately and the result asynchronously. Tests need to wait for completion without a fixed sleep:
// Awaitility + REST Assured
await().atMost(30, SECONDS).pollInterval(2, SECONDS)
.untilAsserted(() ->
given(reqSpec)
.when().get("/jobs/" + jobId)
.then().statusCode(200)
.body("status", equalTo("COMPLETE"))
.body("result.recordsProcessed", greaterThan(0))
);
untilAsserted runs the entire lambda (including REST Assured assertions) — if any assertion fails, Awaitility retries up to the timeout. If it succeeds, the test moves on immediately.
until vs untilAsserted:
until— expects a boolean-returning lambda; good for simple state checksuntilAsserted— expects a lambda that throws on failure; best with REST Assured assertions
Configuring poll intervals: use exponential backoff (pollInSameThread().pollDelay(Duration.ofSeconds(1)).pollInterval(fibonacci())) for jobs with variable completion times.
Webhook testing: start a mock server (WireMock), trigger the action, wait for WireMock to capture the incoming webhook, then assert its payload.
// EXAMPLE
@Test
void importJob_completesWithinTimeout_andReportsCount() {
File csvFile = new File("src/test/resources/1000-users.csv");
// Trigger async job
String jobId = given(reqSpec)
.multiPart("file", csvFile, "text/csv")
.when()
.post("/imports")
.then()
.statusCode(202)
.body("status", equalTo("QUEUED"))
.extract().path("jobId");
// Poll until complete (max 60s, check every 3s)
await().atMost(60, SECONDS).pollInterval(3, SECONDS)
.untilAsserted(() ->
given(reqSpec)
.when().get("/imports/" + jobId)
.then()
.statusCode(200)
.body("status", equalTo("COMPLETE"))
.body("result.successCount", equalTo(1000))
.body("result.errorCount", equalTo(0))
);
}