@serenity-js/rest 3.10.4 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/lib/index.d.ts +0 -1
  3. package/lib/index.d.ts.map +1 -1
  4. package/lib/index.js +0 -1
  5. package/lib/index.js.map +1 -1
  6. package/lib/screenplay/abilities/AxiosRequestConfigDefaults.d.ts +14 -0
  7. package/lib/screenplay/abilities/AxiosRequestConfigDefaults.d.ts.map +1 -0
  8. package/lib/screenplay/abilities/AxiosRequestConfigDefaults.js +3 -0
  9. package/lib/screenplay/abilities/AxiosRequestConfigDefaults.js.map +1 -0
  10. package/lib/screenplay/abilities/CallAnApi.d.ts +297 -38
  11. package/lib/screenplay/abilities/CallAnApi.d.ts.map +1 -1
  12. package/lib/screenplay/abilities/CallAnApi.js +353 -44
  13. package/lib/screenplay/abilities/CallAnApi.js.map +1 -1
  14. package/lib/screenplay/abilities/index.d.ts +1 -0
  15. package/lib/screenplay/abilities/index.d.ts.map +1 -1
  16. package/lib/screenplay/abilities/index.js +1 -0
  17. package/lib/screenplay/abilities/index.js.map +1 -1
  18. package/lib/screenplay/abilities/proxy/ProxyAgent.d.ts +55 -0
  19. package/lib/screenplay/abilities/proxy/ProxyAgent.d.ts.map +1 -0
  20. package/lib/screenplay/abilities/proxy/ProxyAgent.js +107 -0
  21. package/lib/screenplay/abilities/proxy/ProxyAgent.js.map +1 -0
  22. package/lib/screenplay/abilities/proxy/axiosProxyOverridesFor.d.ts +12 -0
  23. package/lib/screenplay/abilities/proxy/axiosProxyOverridesFor.d.ts.map +1 -0
  24. package/lib/screenplay/abilities/proxy/axiosProxyOverridesFor.js +35 -0
  25. package/lib/screenplay/abilities/proxy/axiosProxyOverridesFor.js.map +1 -0
  26. package/lib/screenplay/abilities/proxy/createUrl.d.ts +10 -0
  27. package/lib/screenplay/abilities/proxy/createUrl.d.ts.map +1 -0
  28. package/lib/screenplay/abilities/proxy/createUrl.js +30 -0
  29. package/lib/screenplay/abilities/proxy/createUrl.js.map +1 -0
  30. package/lib/screenplay/abilities/proxy/index.d.ts +2 -0
  31. package/lib/screenplay/abilities/proxy/index.d.ts.map +1 -0
  32. package/lib/screenplay/abilities/proxy/index.js +18 -0
  33. package/lib/screenplay/abilities/proxy/index.js.map +1 -0
  34. package/lib/screenplay/index.d.ts +1 -0
  35. package/lib/screenplay/index.d.ts.map +1 -1
  36. package/lib/screenplay/index.js +1 -0
  37. package/lib/screenplay/index.js.map +1 -1
  38. package/lib/screenplay/interactions/Send.d.ts +3 -3
  39. package/lib/screenplay/interactions/Send.js +3 -3
  40. package/lib/{models → screenplay/models}/DeleteRequest.d.ts +1 -1
  41. package/lib/screenplay/models/DeleteRequest.d.ts.map +1 -0
  42. package/lib/{models → screenplay/models}/DeleteRequest.js +1 -1
  43. package/lib/screenplay/models/DeleteRequest.js.map +1 -0
  44. package/lib/{models → screenplay/models}/GetRequest.d.ts +1 -1
  45. package/lib/screenplay/models/GetRequest.d.ts.map +1 -0
  46. package/lib/{models → screenplay/models}/GetRequest.js +1 -1
  47. package/lib/screenplay/models/GetRequest.js.map +1 -0
  48. package/lib/screenplay/models/HTTPRequest.d.ts.map +1 -0
  49. package/lib/screenplay/models/HTTPRequest.js.map +1 -0
  50. package/lib/{models → screenplay/models}/HeadRequest.d.ts +1 -1
  51. package/lib/screenplay/models/HeadRequest.d.ts.map +1 -0
  52. package/lib/{models → screenplay/models}/HeadRequest.js +1 -1
  53. package/lib/screenplay/models/HeadRequest.js.map +1 -0
  54. package/lib/{models → screenplay/models}/OptionsRequest.d.ts +1 -1
  55. package/lib/screenplay/models/OptionsRequest.d.ts.map +1 -0
  56. package/lib/{models → screenplay/models}/OptionsRequest.js +1 -1
  57. package/lib/screenplay/models/OptionsRequest.js.map +1 -0
  58. package/lib/{models → screenplay/models}/PatchRequest.d.ts +1 -1
  59. package/lib/screenplay/models/PatchRequest.d.ts.map +1 -0
  60. package/lib/{models → screenplay/models}/PatchRequest.js +1 -1
  61. package/lib/screenplay/models/PatchRequest.js.map +1 -0
  62. package/lib/{models → screenplay/models}/PostRequest.d.ts +1 -1
  63. package/lib/screenplay/models/PostRequest.d.ts.map +1 -0
  64. package/lib/{models → screenplay/models}/PostRequest.js +1 -1
  65. package/lib/screenplay/models/PostRequest.js.map +1 -0
  66. package/lib/{models → screenplay/models}/PutRequest.d.ts +2 -2
  67. package/lib/screenplay/models/PutRequest.d.ts.map +1 -0
  68. package/lib/{models → screenplay/models}/PutRequest.js +2 -2
  69. package/lib/screenplay/models/PutRequest.js.map +1 -0
  70. package/lib/screenplay/models/index.d.ts.map +1 -0
  71. package/lib/screenplay/models/index.js.map +1 -0
  72. package/lib/screenplay/questions/LastResponse.d.ts +2 -2
  73. package/lib/screenplay/questions/LastResponse.js +2 -2
  74. package/package.json +11 -6
  75. package/src/index.ts +0 -1
  76. package/src/screenplay/abilities/AxiosRequestConfigDefaults.ts +15 -0
  77. package/src/screenplay/abilities/CallAnApi.ts +355 -48
  78. package/src/screenplay/abilities/index.ts +1 -0
  79. package/src/screenplay/abilities/proxy/ProxyAgent.ts +129 -0
  80. package/src/screenplay/abilities/proxy/axiosProxyOverridesFor.ts +39 -0
  81. package/src/screenplay/abilities/proxy/createUrl.ts +39 -0
  82. package/src/screenplay/abilities/proxy/index.ts +1 -0
  83. package/src/screenplay/index.ts +1 -0
  84. package/src/screenplay/interactions/Send.ts +3 -3
  85. package/src/{models → screenplay/models}/DeleteRequest.ts +1 -1
  86. package/src/{models → screenplay/models}/GetRequest.ts +1 -1
  87. package/src/{models → screenplay/models}/HeadRequest.ts +1 -1
  88. package/src/{models → screenplay/models}/OptionsRequest.ts +1 -1
  89. package/src/{models → screenplay/models}/PatchRequest.ts +1 -1
  90. package/src/{models → screenplay/models}/PostRequest.ts +1 -1
  91. package/src/{models → screenplay/models}/PutRequest.ts +2 -2
  92. package/src/screenplay/questions/LastResponse.ts +2 -2
  93. package/lib/models/DeleteRequest.d.ts.map +0 -1
  94. package/lib/models/DeleteRequest.js.map +0 -1
  95. package/lib/models/GetRequest.d.ts.map +0 -1
  96. package/lib/models/GetRequest.js.map +0 -1
  97. package/lib/models/HTTPRequest.d.ts.map +0 -1
  98. package/lib/models/HTTPRequest.js.map +0 -1
  99. package/lib/models/HeadRequest.d.ts.map +0 -1
  100. package/lib/models/HeadRequest.js.map +0 -1
  101. package/lib/models/OptionsRequest.d.ts.map +0 -1
  102. package/lib/models/OptionsRequest.js.map +0 -1
  103. package/lib/models/PatchRequest.d.ts.map +0 -1
  104. package/lib/models/PatchRequest.js.map +0 -1
  105. package/lib/models/PostRequest.d.ts.map +0 -1
  106. package/lib/models/PostRequest.js.map +0 -1
  107. package/lib/models/PutRequest.d.ts.map +0 -1
  108. package/lib/models/PutRequest.js.map +0 -1
  109. package/lib/models/index.d.ts.map +0 -1
  110. package/lib/models/index.js.map +0 -1
  111. /package/lib/{models → screenplay/models}/HTTPRequest.d.ts +0 -0
  112. /package/lib/{models → screenplay/models}/HTTPRequest.js +0 -0
  113. /package/lib/{models → screenplay/models}/index.d.ts +0 -0
  114. /package/lib/{models → screenplay/models}/index.js +0 -0
  115. /package/src/{models → screenplay/models}/HTTPRequest.ts +0 -0
  116. /package/src/{models → screenplay/models}/index.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [3.11.0](https://github.com/serenity-js/serenity-js/compare/v3.10.4...v3.11.0) (2023-10-03)
7
+
8
+
9
+ ### Features
10
+
11
+ * **playwright-test:** explicit proxy config will override env variables for REST interaction ([1c277d6](https://github.com/serenity-js/serenity-js/commit/1c277d6e45064fbb4ab3432c11d125f529268b5c)), closes [#1949](https://github.com/serenity-js/serenity-js/issues/1949)
12
+ * **rest:** automatic proxy server configuration for CallAnApi ([27a1630](https://github.com/serenity-js/serenity-js/commit/27a163024120068bc4d5b7ec07704fb774b2e312)), closes [#1949](https://github.com/serenity-js/serenity-js/issues/1949)
13
+
14
+
15
+
16
+
17
+
6
18
  ## [3.10.4](https://github.com/serenity-js/serenity-js/compare/v3.10.3...v3.10.4) (2023-09-22)
7
19
 
8
20
  **Note:** Version bump only for package @serenity-js/rest
package/lib/index.d.ts CHANGED
@@ -1,3 +1,2 @@
1
- export * from './models';
2
1
  export * from './screenplay';
3
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
package/lib/index.js CHANGED
@@ -14,6 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./models"), exports);
18
17
  __exportStar(require("./screenplay"), exports);
19
18
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,+CAA6B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B"}
@@ -0,0 +1,14 @@
1
+ import { type CreateAxiosDefaults } from 'axios';
2
+ export type AxiosRequestConfigProxyDefaults = {
3
+ host: string;
4
+ port?: number;
5
+ auth?: {
6
+ username: string;
7
+ password: string;
8
+ };
9
+ protocol?: string;
10
+ };
11
+ export type AxiosRequestConfigDefaults<Data = any> = Omit<CreateAxiosDefaults<Data>, 'proxy'> & {
12
+ proxy?: AxiosRequestConfigProxyDefaults | false;
13
+ };
14
+ //# sourceMappingURL=AxiosRequestConfigDefaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AxiosRequestConfigDefaults.d.ts","sourceRoot":"","sources":["../../../src/screenplay/abilities/AxiosRequestConfigDefaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAEjD,MAAM,MAAM,+BAA+B,GAAG;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE;QACH,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB,CAAA;AAED,MAAM,MAAM,0BAA0B,CAAC,IAAI,GAAG,GAAG,IAAI,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,GAAG;IAC5F,KAAK,CAAC,EAAE,+BAA+B,GAAG,KAAK,CAAC;CACnD,CAAA"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=AxiosRequestConfigDefaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AxiosRequestConfigDefaults.js","sourceRoot":"","sources":["../../../src/screenplay/abilities/AxiosRequestConfigDefaults.ts"],"names":[],"mappings":""}
@@ -1,11 +1,21 @@
1
+ /// <reference types="node" />
1
2
  import { Ability } from '@serenity-js/core';
2
- import type { AxiosDefaults, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
3
+ import { type AxiosDefaults, type AxiosInstance, type AxiosRequestConfig, type AxiosResponse } from 'axios';
4
+ import type { AxiosRequestConfigDefaults } from './AxiosRequestConfigDefaults';
3
5
  /**
4
- * An {@apilink Ability} that enables the {@apilink Actor} to call an HTTP API.
6
+ * An {@apilink Ability} that wraps [axios client](https://axios-http.com/docs/api_intro) and enables
7
+ * the {@apilink Actor} to {@apilink Send} {@apilink HTTPRequest|HTTP requests} to HTTP APIs.
5
8
  *
6
- * If you need to connect via a proxy, check out ["Using Axios behind corporate proxies"](https://janmolak.com/node-js-axios-behind-corporate-proxies-8b17a6f31f9d).
9
+ * `CallAnApi` uses [`proxy-from-env`](https://www.npmjs.com/package/proxy-from-env) and an approach
10
+ * described in ["Node.js Axios behind corporate proxies"](https://janmolak.com/node-js-axios-behind-corporate-proxies-8b17a6f31f9d)
11
+ * to automatically detect proxy server configuration based
12
+ * on your [environment variables](https://www.npmjs.com/package/proxy-from-env#environment-variables).
13
+ * You can override this configuration if needed.
7
14
  *
8
- * ## Using the default Axios HTTP client
15
+ * ## Configuring the ability to call an API
16
+ *
17
+ * The easiest way to configure the ability to `CallAnApi` is to provide the `baseURL` of your HTTP API,
18
+ * and rely on Serenity/JS to offer other sensible defaults:
9
19
  *
10
20
  * ```ts
11
21
  * import { actorCalled } from '@serenity-js/core'
@@ -17,30 +27,128 @@ import type { AxiosDefaults, AxiosInstance, AxiosRequestConfig, AxiosResponse }
17
27
  * CallAnApi.at('https://api.example.org/')
18
28
  * )
19
29
  * .attemptsTo(
30
+ * Send.a(GetRequest.to('/v1/users/2')), // GET https://api.example.org/v1/users/2
31
+ * Ensure.that(LastResponse.status(), equals(200)),
32
+ * )
33
+ * ```
34
+ *
35
+ * ### Resolving relative URLs
36
+ *
37
+ * Serenity/JS resolves request URLs using Node.js [WHATWG URL API](https://nodejs.org/api/url.html#new-urlinput-base).
38
+ * This means that the request URL is determined using the resource path resolved in the context of base URL, i.e. `new URL(resourcePath, [baseURL])`.
39
+ *
40
+ * Consider the following example:
41
+ *
42
+ * ```ts
43
+ * import { actorCalled } from '@serenity-js/core'
44
+ * import { CallAnApi, GetRequest, LastResponse, Send } from '@serenity-js/rest'
45
+ * import { Ensure, equals } from '@serenity-js/assertions'
46
+ *
47
+ * await actorCalled('Apisitt')
48
+ * .whoCan(
49
+ * CallAnApi.at(baseURL)
50
+ * )
51
+ * .attemptsTo(
52
+ * Send.a(GetRequest.to(resourcePath)),
53
+ * Ensure.that(LastResponse.status(), equals(200)),
54
+ * )
55
+ * ```
56
+ *
57
+ * In the above example:
58
+ * - when `resourcePath` is defined as a full URL, it overrides the base URL
59
+ * - when `resourcePath` starts with a forward slash `/`, it replaces any path defined in the base URL
60
+ * - when `resourcePath` is not a full URL and doesn't start with a forward slash, it gets appended to the base URL
61
+ *
62
+ * | baseURL | resourcePath | result |
63
+ * | ----------------------------- | -------------------------- | ------------------------------------ |
64
+ * | `https://api.example.org/` | `/v1/users/2` | `https://api.example.org/v1/users/2` |
65
+ * | `https://example.org/api/v1/` | `users/2` | `https://example.org/api/v1/users/2` |
66
+ * | `https://example.org/api/v1/` | `/secure/oauth` | `https://example.org/secure/oauth` |
67
+ * | `https://v1.example.org/api/` | `https://v2.example.org/` | `https://v2.example.org/` |
68
+ *
69
+ * ### Using Axios configuration object
70
+ *
71
+ * When you need more control over how your Axios instance is configured, provide
72
+ * an [Axios configuration object](https://axios-http.com/docs/req_config). For example:
73
+ *
74
+ * ```ts
75
+ * import { actorCalled } from '@serenity-js/core'
76
+ * import { CallAnApi, GetRequest, LastResponse, Send } from '@serenity-js/rest'
77
+ * import { Ensure, equals } from '@serenity-js/assertions'
78
+ *
79
+ * await actorCalled('Apisitt')
80
+ * .whoCan(
81
+ * CallAnApi.using({
82
+ * baseURL: 'https://api.example.org/',
83
+ * timeout: 30_000,
84
+ * // ... other configuration options
85
+ * })
86
+ * )
87
+ * .attemptsTo(
88
+ * Send.a(GetRequest.to('/users/2')),
89
+ * Ensure.that(LastResponse.status(), equals(200)),
90
+ * )
91
+ * ```
92
+ *
93
+ * ### Working with proxy servers
94
+ *
95
+ * `CallAnApi` uses [`proxy-from-env`](https://www.npmjs.com/package/proxy-from-env) to automatically
96
+ * detect proxy server configuration based on your [environment variables](https://www.npmjs.com/package/proxy-from-env#environment-variables).
97
+ *
98
+ * This default behaviour can be overridden by providing explicit proxy configuration:
99
+ *
100
+ * ```ts
101
+ * import { actorCalled } from '@serenity-js/core'
102
+ * import { CallAnApi, GetRequest, LastResponse, Send } from '@serenity-js/rest'
103
+ * import { Ensure, equals } from '@serenity-js/assertions'
104
+ *
105
+ * await actorCalled('Apisitt')
106
+ * .whoCan(
107
+ * CallAnApi.using({
108
+ * baseURL: 'https://api.example.org/',
109
+ * proxy: {
110
+ * protocol: 'http',
111
+ * host: 'proxy.example.org',
112
+ * port: 9000,
113
+ * auth: { // `auth` is optional
114
+ * username: 'proxy-username',
115
+ * password: 'proxy-password',
116
+ * }
117
+ * }
118
+ * // ... other configuration options
119
+ * })
120
+ * )
121
+ * .attemptsTo(
20
122
  * Send.a(GetRequest.to('/users/2')),
21
123
  * Ensure.that(LastResponse.status(), equals(200)),
22
124
  * )
23
125
  * ```
24
126
  *
25
- * ## Using Axios client with custom configuration
127
+ * Please note that Serenity/JS uses [proxy-agents](https://github.com/TooTallNate/proxy-agents)
128
+ * and the approach described in ["Node.js Axios behind corporate proxies"](https://janmolak.com/node-js-axios-behind-corporate-proxies-8b17a6f31f9d)
129
+ * to work around [limited proxy support capabilities](https://github.com/axios/axios/issues?q=is%3Aissue+is%3Aopen+proxy) in Axios itself.
130
+ *
131
+ * ### Using Axios instance with proxy support
132
+ *
133
+ * To have full control over the Axios instance used by the ability to `CallAnApi`, you can create it yourself
134
+ * and inject it into the ability.
135
+ * This approach allows you to still benefit from automated proxy detection in configuration, while taking advantage
136
+ * of the many [Axios plugins](https://www.npmjs.com/search?q=axios).
26
137
  *
27
138
  * ```ts
28
139
  * import { actorCalled } from '@serenity-js/core'
29
140
  * import { CallAnApi, GetRequest, LastResponse, Send } from '@serenity-js/rest'
30
141
  * import { Ensure, equals } from '@serenity-js/assertions'
31
142
  *
32
- * import * as axios from 'axios'
143
+ * import axios from 'axios'
144
+ * import axiosRetry from 'axios-retry'
33
145
  *
34
- * const axiosInstance = axios.create({
35
- * timeout: 5 * 1000,
36
- * headers: {
37
- * 'X-Custom-Api-Key': 'secret-key',
38
- * },
39
- * });
146
+ * const instance = axios.create({ baseURL 'https://api.example.org/' })
147
+ * axiosRetry(axios, { retries: 3 })
40
148
  *
41
149
  * await actorCalled('Apisitt')
42
150
  * .whoCan(
43
- * CallAnApi.using(axiosInstance),
151
+ * CallAnApi.using(instance)
44
152
  * )
45
153
  * .attemptsTo(
46
154
  * Send.a(GetRequest.to('/users/2')),
@@ -48,43 +156,195 @@ import type { AxiosDefaults, AxiosInstance, AxiosRequestConfig, AxiosResponse }
48
156
  * )
49
157
  * ```
50
158
  *
159
+ * ### Using raw Axios instance
160
+ *
161
+ * If you don't want Serenity/JS to enhance your Axios instance with proxy support, instantiate the ability to
162
+ * `CallAnApi` using its constructor directly.
163
+ * Note, however, that by using this approach you're taking the responsibility for all the aspects of configuring Axios.
164
+ *
165
+ * ```ts
166
+ * import { actorCalled } from '@serenity-js/core'
167
+ * import { CallAnApi, GetRequest, LastResponse, Send } from '@serenity-js/rest'
168
+ * import { Ensure, equals } from '@serenity-js/assertions'
169
+ *
170
+ * import axios from 'axios'
171
+ * import axiosRetry from 'axios-retry'
172
+ *
173
+ * const instance = axios.create({ baseURL 'https://api.example.org/' })
174
+ * axiosRetry(axios, { retries: 3 })
175
+ *
176
+ * await actorCalled('Apisitt')
177
+ * .whoCan(
178
+ * new CallAnApi(instance) // using the constructor ensures your axios instance is not modified in any way.
179
+ * )
180
+ * .attemptsTo(
181
+ * // ...
182
+ * )
183
+ * ```
184
+ *
185
+ * ### Serenity/JS defaults
186
+ *
187
+ * When using {@apilink CallAnApi.at} or {@apilink CallAnApi.using} with a configuration object, Serenity/JS
188
+ * merges your [Axios request configuration](https://axios-http.com/docs/req_config) with the following defaults:
189
+ * - `timeout`: 10 seconds
190
+ *
191
+ *
192
+ * You can override them by specifying the given property in your configuration object, for example:
193
+ * ```ts
194
+ * import { actorCalled } from '@serenity-js/core'
195
+ * import { CallAnApi, GetRequest, LastResponse, Send } from '@serenity-js/rest'
196
+ * import { Ensure, equals } from '@serenity-js/assertions'
197
+ *
198
+ * await actorCalled('Apisitt')
199
+ * .whoCan(
200
+ * CallAnApi.using({
201
+ * baseURL: 'https://api.example.org/',
202
+ * timeout: 30_000
203
+ * })
204
+ * )
205
+ * .attemptsTo(
206
+ * Send.a(GetRequest.to('/users/2')),
207
+ * Ensure.that(LastResponse.status(), equals(200)),
208
+ * )
209
+ * ```
210
+ *
211
+ * ## Interacting with multiple APIs
212
+ *
213
+ * Some test scenarios might require you to interact with multiple HTTP APIs. With Serenity/JS you can do this
214
+ * using either API-specific actors, or by specifying full URLs when performing the requests.
215
+ *
216
+ * The following examples will assume that the test scenarios needs to interact with the following APIs:
217
+ * - `https://testdata.example.org/api/v1/`
218
+ * - `https://shop.example.org/api/v1/`
219
+ *
220
+ * Let's also assume that the `testdata` API allows the automation to manage the test data used by the `shop` API.
221
+ *
222
+ * ### Using API-specific actors
223
+ *
224
+ * To create API-specific actors, configure your [test runner](/handbook/test-runners/) with a {@apilink Cast}
225
+ * that gives your actors appropriate abilities based, for example, on their name:
226
+ *
227
+ * ```ts
228
+ * import { beforeEach } from 'mocha'
229
+ * import { Actor, Cast, engage } from '@serenity-js/core'
230
+ * import { CallAnApi } from '@serenity-js/rest'
231
+ *
232
+ * export class MyActors implements Cast {
233
+ * prepare(actor: Actor): Actor {
234
+ * switch(actor.name) {
235
+ * case 'Ted':
236
+ * return actor.whoCan(CallAnApi.at('https://testdata.example.org/api/v1/'))
237
+ * case 'Shelly':
238
+ * return actor.whoCan(CallAnApi.at('https://shop.example.org/api/v1/'))
239
+ * default:
240
+ * return actor;
241
+ * }
242
+ * }
243
+ * }
244
+ *
245
+ * beforeEach(() => engage(new MyActors()))
246
+ * ```
247
+ *
248
+ * Next, retrieve the appropriate actor in your test scenario using {@apilink actorCalled}, for example:
249
+ *
250
+ * ```ts
251
+ * import { describe, it, beforeEach } from 'mocha'
252
+ * import { actorCalled, engage } from '@serenity-js/core
253
+ * import { Send, GetRequest, PostRequest, LastResponse } from '@serenity-js/rest'
254
+ * import { Ensure, equals } from '@serenity-js/assertions'
255
+ *
256
+ * describe('Multi-actor API testing', () => {
257
+ * beforeEach(() => engage(new MyActors()))
258
+ *
259
+ * it('allows each actor to interact with their API', async () => {
260
+ *
261
+ * await actorCalled('Ted').attemptsTo(
262
+ * Send.a(PostRequest.to('products').with({ name: 'Apples', price: '£2.50' })),
263
+ * Ensure.that(LastResponse.status(), equals(201)),
264
+ * )
265
+ *
266
+ * await actorCalled('Shelly').attemptsTo(
267
+ * Send.a(GetRequest.to('?product=Apples')),
268
+ * Ensure.that(LastResponse.status(), equals(200)),
269
+ * Ensure.that(LastResponse.body(), equals([
270
+ * { name: 'Apples', price: '£2.50' }
271
+ * ])),
272
+ * )
273
+ * })
274
+ * })
275
+ * ```
276
+ *
277
+ * ### Using full URLs
278
+ *
279
+ * If you prefer to have a single actor interacting with multiple APIs, you can specify the full URL for every request:
280
+ *
281
+ * ```ts
282
+ * import { describe, it, beforeEach } from 'mocha'
283
+ * import { actorCalled, Cast, engage } from '@serenity-js/core
284
+ * import { CallAnApi, Send, GetRequest, PostRequest, LastResponse } from '@serenity-js/rest'
285
+ * import { Ensure, equals } from '@serenity-js/assertions'
286
+ *
287
+ * describe('Multi-actor API testing', () => {
288
+ * beforeEach(() => engage(
289
+ * Cast.where(actor => actor.whoCan(CallAnApi.using({})))
290
+ * ))
291
+ *
292
+ * it('allows each actor to interact with their API', async () => {
293
+ *
294
+ * await actorCalled('Alice').attemptsTo(
295
+ * Send.a(PostRequest.to('https://testdata.example.org/api/v1/products')
296
+ * .with({ name: 'Apples', price: '£2.50' })),
297
+ * Ensure.that(LastResponse.status(), equals(201)),
298
+ *
299
+ * Send.a(GetRequest.to('https://shop.example.org/api/v1/?product=Apples')),
300
+ * Ensure.that(LastResponse.status(), equals(200)),
301
+ * Ensure.that(LastResponse.body(), equals([
302
+ * { name: 'Apples', price: '£2.50' }
303
+ * ])),
304
+ * )
305
+ * })
306
+ * })
307
+ * ```
308
+ *
51
309
  * ## Learn more
52
- * - https://github.com/axios/axios
53
- * - https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
310
+ * - [Axios: Configuring requests](https://axios-http.com/docs/req_config)
311
+ * - [MDN: HTTP methods documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)
54
312
  *
55
313
  * @group Abilities
56
314
  */
57
315
  export declare class CallAnApi extends Ability {
58
316
  private readonly axiosInstance;
59
- /** @private */
60
317
  private lastResponse;
318
+ private static readonly defaults;
61
319
  /**
62
- * Produces an {@apilink Ability|ability} to call a REST api at a specified baseUrl
320
+ * Produces an {@apilink Ability|ability} to call a REST API at a specified `baseURL`;
63
321
  *
64
- * Default timeout is set to 2s.
65
- *
66
- * Default request headers:
67
- * - `Accept`: `application/json,application/xml`
322
+ * This is the same as invoking `CallAnApi.using({ baseURL: 'https://example.org' })`
68
323
  *
69
324
  * @param baseURL
70
325
  */
71
- static at(baseURL: string): CallAnApi;
326
+ static at(baseURL: URL | string): CallAnApi;
72
327
  /**
73
- * Produces an {@apilink Ability|ability} to call a REST API using a given axios instance.
328
+ * Produces an {@apilink Ability|ability} to call an HTTP API using the given Axios instance,
329
+ * or an Axios request configuration object.
74
330
  *
75
- * Useful when you need to customise Axios to
76
- * [make it aware of proxies](https://janmolak.com/node-js-axios-behind-corporate-proxies-8b17a6f31f9d),
77
- * for example.
331
+ * When you provide an [Axios configuration object](https://axios-http.com/docs/req_config),
332
+ * it gets shallow-merged with the following defaults:
333
+ * - request timeout of 10 seconds
334
+ * - automatic proxy support based on
335
+ * your [environment variables](https://www.npmjs.com/package/proxy-from-env#environment-variables)
78
336
  *
79
- * #### Learn more
80
- * - [AxiosInstance](https://github.com/axios/axios/blob/v0.27.2/index.d.ts#L235-L238)
337
+ * When you provide an Axios instance, it's enhanced with proxy support and no other modifications are made.
81
338
  *
82
- * @param axiosInstance
339
+ * If you don't want Serenity/JS to augment or modify your Axios instance in any way,
340
+ * please use the {@apilink CallAnApi.constructor} directly.
341
+ *
342
+ * @param axiosInstanceOrConfig
83
343
  */
84
- static using(axiosInstance: AxiosInstance): CallAnApi;
344
+ static using(axiosInstanceOrConfig: AxiosInstance | AxiosRequestConfigDefaults): CallAnApi;
85
345
  /**
86
346
  * #### Learn more
87
- * - [AxiosInstance](https://github.com/axios/axios/blob/v0.27.2/index.d.ts#L235-L238)
347
+ * - [AxiosInstance](https://axios-http.com/docs/instance)
88
348
  *
89
349
  * @param axiosInstance
90
350
  * A pre-configured instance of the Axios HTTP client
@@ -96,7 +356,7 @@ export declare class CallAnApi extends Ability {
96
356
  * has been instantiated and given to the {@apilink Actor}.
97
357
  *
98
358
  * #### Learn more
99
- * - [AxiosRequestConfig](https://github.com/axios/axios/blob/v0.27.2/index.d.ts#L75-L113)
359
+ * - [AxiosRequestConfig](https://axios-http.com/docs/req_config)
100
360
  *
101
361
  * @param fn
102
362
  */
@@ -106,8 +366,8 @@ export declare class CallAnApi extends Ability {
106
366
  * Response will be cached and available via {@apilink mapLastResponse}
107
367
  *
108
368
  * #### Learn more
109
- * - [AxiosRequestConfig](https://github.com/axios/axios/blob/v0.27.2/index.d.ts#L75-L113)
110
- * - [AxiosResponse](https://github.com/axios/axios/blob/v0.27.2/index.d.ts#L133-L140)
369
+ * - [AxiosRequestConfig](https://axios-http.com/docs/req_config)
370
+ * - [AxiosResponse](https://axios-http.com/docs/res_schema)
111
371
  *
112
372
  * @param config
113
373
  * Axios request configuration, which can be used to override the defaults
@@ -118,9 +378,8 @@ export declare class CallAnApi extends Ability {
118
378
  * Resolves the final URL, based on the {@apilink AxiosRequestConfig} provided
119
379
  * and any defaults that the {@apilink AxiosInstance} has been configured with.
120
380
  *
121
- * #### Learn more
122
- * - [AxiosRequestConfig](https://github.com/axios/axios/blob/v0.27.2/index.d.ts#L75-L113)
123
- * - [AxiosInstance](https://github.com/axios/axios/blob/v0.27.2/index.d.ts#L235-L238)
381
+ * Note that unlike Axios, this method uses the Node.js [WHATWG URL API](https://nodejs.org/api/url.html#new-urlinput-base)
382
+ * to ensure URLs are correctly resolved.
124
383
  *
125
384
  * @param config
126
385
  */
@@ -130,7 +389,7 @@ export declare class CallAnApi extends Ability {
130
389
  * Useful when you need to extract a portion of the {@apilink AxiosResponse} object.
131
390
  *
132
391
  * #### Learn more
133
- * - [AxiosResponse](https://github.com/axios/axios/blob/v0.27.2/index.d.ts#L133-L140)
392
+ * - [AxiosResponse](https://axios-http.com/docs/res_schema)
134
393
  *
135
394
  * @param mappingFunction
136
395
  */
@@ -1 +1 @@
1
- {"version":3,"file":"CallAnApi.d.ts","sourceRoot":"","sources":["../../../src/screenplay/abilities/CallAnApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAwD,MAAM,mBAAmB,CAAC;AAClG,OAAO,KAAK,EAAE,aAAa,EAAc,aAAa,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAGzG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,qBAAa,SAAU,SAAQ,OAAO;IA8CtB,OAAO,CAAC,QAAQ,CAAC,aAAa;IA5C1C,eAAe;IACf,OAAO,CAAC,YAAY,CAAgB;IAEpC;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS;IAQrC;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,aAAa,GAAG,SAAS;IAIrD;;;;;;OAMG;gBAC0B,aAAa,EAAE,aAAa;IAIzD;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,IAAI;IAI7D;;;;;;;;;;;OAWG;IACG,OAAO,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC;IAgCjE;;;;;;;;;OASG;IACH,UAAU,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM;IAQ9C;;;;;;;;OAQG;IACH,eAAe,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,CAAC,GAAG,CAAC;CAOzE"}
1
+ {"version":3,"file":"CallAnApi.d.ts","sourceRoot":"","sources":["../../../src/screenplay/abilities/CallAnApi.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAkE,MAAM,mBAAmB,CAAC;AAC5G,OAAc,EAEV,KAAK,aAAa,EAElB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAErB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,0BAA0B,EAAmC,MAAM,8BAA8B,CAAC;AAGhH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqTG;AACH,qBAAa,SAAU,SAAQ,OAAO;IAsEtB,OAAO,CAAC,QAAQ,CAAC,aAAa;IApE1C,OAAO,CAAC,YAAY,CAAgB;IAEpC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAE9B;IAEF;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS;IAQ3C;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,KAAK,CAAC,qBAAqB,EAAE,aAAa,GAAG,0BAA0B,GAAG,SAAS;IAuB1F;;;;;;OAMG;gBAC0B,aAAa,EAAE,aAAa;IAIzD;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,IAAI;IAI7D;;;;;;;;;;;OAWG;IACG,OAAO,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC;IAgCjE;;;;;;;;OAQG;IACH,UAAU,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM;IAQ9C;;;;;;;;OAQG;IACH,eAAe,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,CAAC,GAAG,CAAC;CAOzE"}