import { Answerable, AnswersQuestions, CollectsArtifacts, Interaction, UsesAbilities } from '@serenity-js/core';
import { Artifact, HTTPRequestResponse, Name, RequestAndResponse } from '@serenity-js/core/lib/model';
import { AxiosRequestConfig, AxiosResponse } from 'axios';
import { CallAnApi } from '../abilities';
/**
* @desc
* Sends a {@link HTTPRequest} to a specified url.
* The response to the request is made available via the {@link LastResponse}
* {@link @serenity-js/core/lib/screenplay~Question}s.
*
* @example
Send a GET request
* import { Actor } from '@serenity-js/core';
* import { CallAnApi, GetRequest, LastResponse, Send } from '@serenity-js/rest'
* import { Ensure, equals } from '@serenity-js/assertions';
*
* const actor = Actor.named('Apisit').whoCan(CallAnApi.at('https://myapp.com/api'));
*
* actor.attemptsTo(
* Send.a(GetRequest.to('/books/0-688-00230-7')),
* Ensure.that(LastResponse.status(), equals(200)),
* );
*
* @extends {Interaction}
*/
export class Send extends Interaction {
/**
* @desc
* Instantiates a new {@link Send} {@link @serenity-js/core/lib/screenplay~Interaction}.
*
* @param {@serenity-js/lib/core/screenplay~Answerable} request
* @returns {@serenity-js/core/lib/screenplay~Interaction}
*/
static a(request: Answerable): Interaction {
return new Send(request);
}
/**
* @param {@serenity-js/core/lib/screenplay~Answerable} request
*/
constructor(private readonly request: Answerable) {
super();
}
/**
* @desc
* Makes the provided {@link @serenity-js/core/lib/screenplay/actor~Actor}
* perform this {@link @serenity-js/core/lib/screenplay~Interaction}.
*
* @param {@serenity-js/core/lib/screenplay/actor~UsesAbilities & @serenity-js/core/lib/screenplay/actor~CollectsArtifacts & @serenity-js/core/lib/screenplay/actor~AnswersQuestions} actor
* @returns {Promise}
*
* @see {@link @serenity-js/core/lib/screenplay~Actor}
*/
performAs(actor: UsesAbilities & CollectsArtifacts & AnswersQuestions): Promise {
return actor.answer(this.request)
.then(config => CallAnApi.as(actor).request(config))
.then((response: AxiosResponse) => actor.collect(
this.responseToArtifact(response),
this.requestToArtifactName(response.config),
));
}
/**
* @desc
* Generates a description of the REST interaction
*
* @returns {string}
* Description of the {@link @serenity-js/core/lib/screenplay~Interaction}
*/
toString() {
return `#actor sends ${ this.request.toString() }`;
}
private responseToArtifact(response: AxiosResponse): Artifact {
const
request: AxiosRequestConfig = response.config,
requestAndResponse: RequestAndResponse = {
request: {
method: request.method,
url: request.url,
headers: request.headers,
data: request.data,
},
response: {
status: response.status,
headers: response.headers,
data: response.data,
},
};
return HTTPRequestResponse.fromJSON(requestAndResponse);
}
private requestToArtifactName(request: AxiosRequestConfig) {
return new Name(`request ${request.method} ${request.url}`);
}
}