import { Answerable, AnswersQuestions, CollectsArtifacts, Interaction, UsesAbilities } from '@serenity-js/core'; import { CallAnApi } from '../abilities'; /** * @desc * Changes the base URL the {@link CallAnApi} {@link @serenity-js/core/lib/screenplay~Ability} * has been configured with. Useful when we don't know the URL before the test is started, * for example when the URL is dynamically generated and needs to be read from the website under test. * * @example Changing the API URL * import { Actor } from '@serenity-js/core'; * import { Navigate, Target, Text } from '@serenity-js/protractor'; * import { CallAnApi, GetRequest, LastResponse, Send } from '@serenity-js/rest' * import { protractor, by } from 'protractor'; * * import axios from 'axios'; * * const actor = Actor.named('Apisit').whoCan( * BrowseTheWeb.using(protractor.browser), * * // Note: no default base URL is given when the axios instance is created * CallAnApi.using(axios.create()), * ); * * // Let's imagine that the website under test displays * // a dynamically generated API URL we'd like to use * const ApiDetailsWidget = { * Url: Target.the('API URL').located(by.id('api-url')), * } * * actor.attemptsTo( * Navigate.to('/profile'), * * // We change the API URL based on the text displayed in the widget * // (although we could change it to some arbitrary string too). * ChangeApiUrl.to(Text.of(ApiDetailsWidget.Url)), * * // Any subsequent request will be sent to the newly set URL * Send.a(GetRequest.to('/projects')), * Ensure.that(LastResponse.status(), equals(200)), * ); * * @extends {@serenity-js/core/lib/screenplay~Interaction} */ export class ChangeApiUrl extends Interaction { /** * @desc * Instantiates a new {@link ChangeApiUrl} {@link @serenity-js/core/lib/screenplay~Interaction}. * * @param {@serenity-js/core/lib/screenplay~Answerable} newApiUrl * @returns {@serenity-js/core/lib/screenplay~Interaction} */ static to(newApiUrl: Answerable): Interaction { return new ChangeApiUrl(newApiUrl); } /** * @param {@serenity-js/core/lib/screenplay~Answerable} newApiUrl */ constructor(private readonly newApiUrl: 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.newApiUrl) .then(newApiUrl => CallAnApi.as(actor).modifyConfig(config => config.baseURL = newApiUrl)); } /** * Description to be used when reporting this {@link @serenity-js/core/lib/screenplay~Interaction}. */ toString() { return `#actor changes the API URL to ${ this.newApiUrl.toString() }`; } }