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