System-level verification evaluates behavior with the system assembled enough to represent a complete or substantially complete deployed system. The assembly level should provide meaningful results and sufficient confidence that a feature works as expected. section 15.1.5
A common mistake is running every acceptance test against a fully assembled system in a production-like environment. Prefer the smallest meaningful assembly: use a web UI with mocked web services, or test individual UI components with Storybook or Playwright Component Tests when the scenario does not require the entire system. section 15.1.5
Signing up through different interfaces
A sign-up task can run through the user interface or through an HTTP API. The API variation posts traveler details to `/api/auth/register` and verifies a 201 response, while the UI variation locates, fills, and submits the registration form. When the product lacks a suitable API, create test-specific programmatic APIs for account registration, test-data setup, or state access. section 15.1.5
Listing 15.5 Implementing variations of a task interacting with different interfaces
import { Answerable, QuestionAdapter, Task } from '@serenity-js/core'
import { Send, PostRequest } from '@serenity-js/rest'
import { Ensure, equals } from '@serenity-js/assertions'
class SignUp {
using =(travelerDetails: QuestionAdapter<TravelerDetails>) =>
Task.where(`#actor signs up`,
LocateRegistrationForm(),
FillOutRegistrationForm.using(travelerDetails),
SubmitRegistrationForm(),
)
viaApiUsing = (travelerDetails: QuestionAdapter<TravelerDetails>) =>
Task.where(`#actor signs up (via API)`,
Send.a(PostRequest.to('/api/auth/register')
.with(travelerDetails)),
Ensure.that(LastResponse.status(), equals(201)),
)
}
Shows two Serenity/JS task implementations that express the same sign-up behavior through a UI or REST interaction. section 15.1.5
