Skip to main content

Passing Data with Promise

Promise<T> lets a step produce a value that a later step consumes. Because all steps are registered before any execute, Promise bridges the gap between step registration time and step execution time.

The problem without Promise

Steps are compiled into the state machine at registration time. You cannot call rest.get("/some/url").getBody() during registration because the request hasn't happened yet. Promise is the solution.

How Promise works

  1. A producing step calls promiseResponse() / PromiseResponse(), which returns a Promise<T>.
  2. At execution time, the framework settles the promise after the step completes.
  3. A consuming step wraps promise.resolve() / promise.Resolve() inside a Supplier / Func — this lambda is not called until execution time.

Critical rule: Never call promise.resolve() / promise.Resolve() eagerly (outside a lambda). It will throw IllegalStateException / InvalidOperationException because the promise is not yet settled.

Passing a typed REST response to the next step

await XceptoTest.Given(scenario, builder =>
{
var rest = builder.RestAdapterBuilder()
.WithBaseUrl(scenario.ApiAddress)
.Build();

Promise<TokenResponse> token = rest.Post("/auth/login")
.WithRequestBody(() => new LoginRequest(username, password))
.WithResponseType<TokenResponse>()
.PromiseResponse();

rest.Get("/api/me")
.WithBearerTokenClient(() => token.Resolve().AccessToken) // lazy!
.AssertSuccess();
});

Passing HTML body from SSR to REST

await XceptoTest.Given(scenario, builder =>
{
var ssr = builder.SsrAdapterBuilder()
.WithBaseUrl(scenario.GuiAddress)
.Build();

var rest = builder.RestAdapterBuilder()
.WithBaseUrl(scenario.ApiAddress)
.Build();

Promise<string> pageHtml = ssr.Post("/token/create")
.WithFormContent(new TokenCreateRequest("deploy-key").ToForm())
.AssertSuccess()
.PromiseResponse(); // Promise<string> — full HTML body

rest.Post("/api/env/create")
.WithBearerTokenClient(
() => ExtractTokenFromPage(pageHtml.Resolve())) // lazy
.AssertSuccess();
});

Driving a dynamic path with Promise

Promise<ResourceRef> ref = rest.Get("/api/first")
.WithResponseType<ResourceRef>()
.PromiseResponse();

rest.Get(() => ref.Resolve().Path) // lazy path from first response
.AssertSuccess();

Promise types by adapter

AdapterpromiseResponse() typeContent
REST (no withResponseType)Promise<string> / Promise<String>Raw response body
REST (with withResponseType<T>)Promise<T>Deserialized object
SSRPromise<string> / Promise<String>Full HTML body