externalabstractQuestion <T>
Hierarchy
- Describable
- Question
Index
Methods
Questions
Screenplay Pattern
Methods
staticexternalabout
Factory method that simplifies the process of defining custom questions.
Defining a custom question
import { Question } from '@serenity-js/core'
const EnvVariable = (name: string) =>
Question.about(`the ${ name } env variable`, actor => process.env[name])Defining a question with extensions
When the third argument is an object, its entries are added as methods to the returned adapter, allowing it to expose domain-specific behaviour that the generic proxy wouldn't provide.
If the extensions include
of, it defines rescoping behaviour and all extensions are automatically propagated to the rescoped result. Extension methods receivethisbound to the proxy target, soactor.answer(this)resolves the current question.const Config = (path: string) =>
Question.about(`config at ${ path }`, actor => readConfig(path), {
of: (scope: string) =>
Question.about(`config at ${ path }`, actor => readConfig(`${ scope }/${ path }`)),
keys: function () {
return Question.about(`keys of ${ this }`, async actor => {
const config = await actor.answer(this);
return Object.keys(config);
});
},
})
// keys() is available on the adapter and after .of() rescoping:
Config('database').keys()
Config('database').of('production').keys()When the third argument is a function, it defines
.of()rescoping only — the original form, equivalent to{ of: thatFunction }.Type parameters
- Answer_Type
- Supported_Context_Type: unknown
Parameters
externaldescription: Answerable<string>
externalbody: (actor: AnswersQuestions & UsesAbilities & HasName) => Answer_Type | Promise<Answer_Type>
externalmetaQuestionBody: (answerable: Answerable<Supported_Context_Type>) => Question<Promise<Answer_Type>> | Question<Answer_Type>
Returns MetaQuestionAdapter<Supported_Context_Type, Awaited<Answer_Type>>
staticexternalfromObject
Generates a
QuestionAdapterthat recursively resolves anyAnswerablefields of the provided object, includingAnswerablefields of nested objects.Optionally, the method accepts
overridesto be shallow-merged with the fields of the originalsource, producing a new merged object.Overrides are applied from left to right, with subsequent objects overwriting property assignments of the previous ones.
Resolving an object recursively using
Question.fromObjectimport { actorCalled, Question } from '@serenity-js/core'
import { Send, PostRequest } from '@serenity-js/rest'
import { By, Text, PageElement } from '@serenity-js/web'
await actorCalled('Daisy')
.whoCan(CallAnApi.at('https://api.example.org'))
.attemptsTo(
Send.a(
PostRequest.to('/products/2')
.with(
Question.fromObject({
name: Text.of(PageElement.located(By.css('.name'))),
})
)
)
);Merging objects using
Question.fromObjectimport { actorCalled, Question } from '@serenity-js/core'
import { Send, PostRequest } from '@serenity-js/rest'
import { By, Text, PageElement } from '@serenity-js/web'
await actorCalled('Daisy')
.whoCan(CallAnApi.at('https://api.example.org'))
.attemptsTo(
Send.a(
PostRequest.to('/products/2')
.with(
Question.fromObject({
name: Text.of(PageElement.located(By.css('.name'))),
quantity: undefined,
}, {
quantity: 2,
})
)
)
);Learn more
Type parameters
- Source_Type: object
Parameters
externalsource: Answerable<WithAnswerableProperties<Source_Type>>
externalrest...overrides: Answerable<Partial<WithAnswerableProperties<Source_Type>>>[]
Returns QuestionAdapter<RecursivelyAnswered<Source_Type>>
staticexternalfromArray
Generates a
QuestionAdapterthat resolves anyAnswerableelements of the provided array.Type parameters
- Source_Type
Parameters
externalsource: Answerable<Source_Type>[]
externaloptionaloptions: DescriptionFormattingOptions
Returns QuestionAdapter<Source_Type[]>
staticexternalisAQuestion
staticexternalisAMetaQuestion
Checks if the value is a
MetaQuestion.Type parameters
- CT
- RQT: Question<unknown>
Parameters
externalmaybeMetaQuestion: unknown
The value to check
Returns maybeMetaQuestion is MetaQuestion<CT, RQT>
staticexternalformattedValue
Creates a
MetaQuestionthat can be composed with anyAnswerableto produce a single-line description of its value.import { actorCalled, Question } from '@serenity-js/core'
import { Ensure, equals } from '@serenity-js/assertions'
const accountDetails = () =>
Question.about('account details', actor => ({ name: 'Alice', age: 28 }))
await actorCalled('Alice').attemptsTo(
Ensure.that(
Question.formattedValue().of(accountDetails()),
equals('{ name: "Alice", age: 28 }'),
),
)Parameters
externaloptionaloptions: DescriptionFormattingOptions
Returns MetaQuestion<any, Question<Promise<string>>>
staticexternalvalue
Creates a
MetaQuestionthat can be composed with anyAnswerableto return its value when the answerable is aQuestion, or the answerable itself otherwise.The description of the resulting question is produced by calling
Question.describedByon the provided answerable.import { actorCalled, Question } from '@serenity-js/core'
import { Ensure, equals } from '@serenity-js/assertions'
const accountDetails = () =>
Question.about('account details', actor => ({ name: 'Alice', age: 28 }))
await actorCalled('Alice').attemptsTo(
Ensure.that(
Question.description().of(accountDetails()),
equals('account details'),
),
Ensure.that(
Question.value().of(accountDetails()),
equals({ name: 'Alice', age: 28 }),
),
)Type parameters
- Answer_Type
Returns MetaQuestion<Answer_Type, Question<Promise<Answer_Type>>>
externalabstractansweredBy
Parameters
externalactor: AnswersQuestions & UsesAbilities & HasName
Returns T
externaldescribedAs
Changes the description of this object, as returned by
Describable.describedByandDescribable.toString.Parameters
externaldescription: Answerable<string> | MetaQuestion<Awaited<T>, Question<Promise<string>>>
Replaces the current description according to the following rules:
- If
descriptionis anAnswerable, it replaces the current description - If
descriptionis aMetaQuestion, the current description is passed ascontexttodescription.of(context), and the result replaces the current description
- If
Returns this
externaldescribedBy
Resolves the description of this object in the context of the provided
actor.Parameters
externalactor: AnswersQuestions & UsesAbilities & HasName
Returns Promise<string>
externaltoString
Returns a human-readable description of this object.
Returns string
Questions
staticexternalcreateAdapter
Wraps a Question in a QuestionAdapter proxy.
The proxy intercepts property access on the resolved answer type, allowing the result to be used as both a Question and a transparent wrapper over the answer's own methods and properties.
Methods defined directly on the
statementobject (such as.isPresent(),.describedAs(), or custom methods on Question subclasses) take priority over proxied methods from the resolved answer type.Use this method when creating custom Question subclasses that need to expose domain-specific methods through the proxy. For example,
@serenity-js/webuses this to make.element()and.elements()available onPageElement.located()results.Type parameters
- AT
Parameters
externalstatement: Question<AT>
Returns QuestionAdapter<Awaited<AT>>
Screenplay Pattern
publicexternalas
Maps this question's resolved answer to a QuestionAdapter of a different type.
Provide a function to transform the resolved answer:
import { Question } from '@serenity-js/core'
const number = Question.about('number returned as text', () => '42')
.as(Number)
const name = Question.about('name with whitespace', () => ' Alice ')
.as(value => value.trim())
const firstValue = Question.about('available values', () => ['first', 'second'])
.as(values => values[0])Alternatively, provide a constructor. When you call
.as(MyClass), Serenity/JS passes the resolved answer asMyClass's sole constructor argument. This is particularly useful when wrapping a mounted UI component in an Interaction Object for component testing:const card = story('components/UserCard/Default', { name: 'Alice' }).as(UserCard)To distinguish a mapping function from a constructor, Serenity/JS calls the mapping as a function first. If that throws a
TypeErrorand the mapping has aprototype(indicating an ES6 class), Serenity/JS retries withnew. This preserves the primitive result ofNumber(42), rather than producing aNumberwrapper object.Learn more
Type parameters
- O
Parameters
externalmapping: (answer: Awaited<T>) => O | Promise<O>
A function that transforms the resolved answer, or a constructor that receives it as its sole argument.
Returns QuestionAdapter<O>
A QuestionAdapter that resolves to the mapped answer.
Questions describe how actors should query the system under test or the test environment to retrieve some information.
Questions are the core building block of the Screenplay Pattern, along with actors, abilities, interactions, and tasks.
Learn more about:
ActorAbilityInteractionQuestionAdapterImplementing a basic custom Question
However, it's worth noting that sometimes you don't even need a custom question. You can instead use a
QuestionAdapter, which proxies the known members of the type. In our list example, we can use a Serenity/JSListwhich conveniently already has alast().Implementing a Question that uses an Ability
Just like the interactions, a
Questionalso can use actor's abilities.Here, we use the ability to
CallAnApito retrieve a property of an HTTP response.Learn more
CallAnApiLastResponseMapping answers to other questions
Apart from retrieving information, questions can be used to transform information retrieved by other questions.
Here, we use the factory method
Question.aboutto produce a question that makes the received actor answerLastResponse.statusand then compare it against some expected value.Note that the above example is for demonstration purposes only, Serenity/JS provides an easier way to verify the response status of the
LastResponse: