Completed
Pull Request — master (#6)
by aguevaraIL
18:47
created

AbstractResourceCest::checkSuccessCreateResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace roaresearch\yii2\roa\test;
4
5
use Codeception\{Example, Util\HttpCode};
6
use roaresearch\yii2\roa\urlRules\Resource as ResourceUrlRule;
7
use yii\web\UrlManager;
8
9
abstract class AbstractResourceCest
10
{
11
    /**
12
     * @var UrlManager url manager used to parse Route's for the services.
13
     */
14
    protected $urlManager;
15
16
    /**
17
     * Initializes the `$urlManager` object
18
     */
19
    public function __construct()
20
    {
21
        $this->urlManager = new UrlManager([
22
            'enablePrettyUrl' => true,
23
            'showScriptName' => false,
24
            'cache' => false,
25
            'rules' => [
26
                $this->getRoutePattern() . '/<id:\d+>'=> 'test/action',
27
                $this->getRoutePattern() => 'test/action',
28
            ],
29
        ]);
30
    }
31
32
    /**
33
     * Authenticates a user identified by 'authUser' index in the `$example`.
34
     *
35
     * @param Tester $I
36
     * @param Example $example data used for the testing. It uses the keys
37
     * - tokenName: (optional) string name of the token used to authenticate.
38
     */
39 15
    protected function authUser(Tester $I, Example $example)
40
    {
41 15
        if (!empty($example['tokenName'])) {
42
            $I->amAuthByToken($example['tokenName']);
43
        }
44 15
    }
45
46
    /**
47
     * Parses the Route for the test using `$urlManager` and `getRoutePattern()`
48
     *
49
     * @param Example $example data used for the testing. It uses the keys
50
     * - url: (optional) string if provided it will be used directly.
51
     * - urlParams: (optional) string[] GET params to parse the url rule with
52
     *   `getRoutePattern()`.
53
     * @return string the url which will be used for the service.
54
     */
55 15
    protected function parseUrl(Example $example): string
56
    {
57 15
        if (isset($example['url'])) {
58 6
            return $example['url'];
59
        }
60 10
        $params = $example['urlParams'] ?? : [];
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected ':' on line 60 at column 43
Loading history...
61 10
        $params[0] = 'test/action';
62
63 10
        return $this->urlManager->createUrl($params);
64
    }
65
66
    /**
67
     * Handles the internal logic when running a test on a collection resource.
68
     *
69
     * @param Tester $I
70
     * @param Example $example data used for the testing. It uses the keys
71
     * - tokenName: (optional) string name of the token used to authenticate.
72
     * - url: (optional) string if provided it will be used directly.
73
     * - urlParams: (optional) string[] GET params to parse the url rule with
74
     *   `getRoutePattern()`.
75
     * - headers: (optional) string[] pairs of header => value expected in the
76
     *   response.
77
     */
78 2
    protected function internalIndex(Tester $I, Example $example)
79
    {
80
        // Authenticates configured user.
81 2
        $this->authUser($I, $example);
82
83
        // Send request
84 2
        $I->sendGET($this->parseUrl($example));
85
86
        // Checks the response has the required headers and body.
87 2
        $this->checkResponse([
88 2
            HttpCode::OK => 'checkSuccessIndexResponse',
89 2
            HttpCode::UNPROCESSABLE_ENTITY => 'checkValidationResponse',
90 2
        ], $I, $example);
91 2
    }
92
93
    /**
94
     * Handles the internal logic when running a test on a creating a record.
95
     *
96
     * @param Tester $I
97
     * @param Example $example data used for the testing. It uses the keys
98
     * - tokenName: (optional) string name of the token used to authenticate.
99
     * - url: (optional) string if provided it will be used directly.
100
     * - urlParams: (optional) string[] GET params to parse the url rule with
101
     *   `getRoutePattern()`.
102
     * - data: (optional) POST data sent on the request.
103
     * - headers: (optional) string[] pairs of header => value expected in the
104
     *   response.
105
     */
106 2
    protected function internalCreate(Tester $I, Example $example)
107
    {
108
        // Authenticates configured user.
109 2
        $this->authUser($I, $example);
110
111
        // Send request
112 2
        $I->sendPOST(
113 2
            $this->parseUrl($example),
114 2
            $example['data'] ?? []
115
        );
116
117
        // Checks the response has the required headers and body.
118 2
        $this->checkResponse([
119 2
            HttpCode::CREATED => 'checkSuccessCreateResponse',
120 2
            HttpCode::UNPROCESSABLE_ENTITY => 'checkValidationResponse',
121 2
        ], $I, $example);
122 2
    }
123
124
    /**
125
     * Handles the internal logic when running a test on a record resource.
126
     *
127
     * @param Tester $I
128
     * @param Example $example data used for the testing. It uses the keys
129
     * - tokenName: (optional) string name of the token used to authenticate.
130
     * - url: string if provided it will be used directly.
131
     * - urlParams: string[] GET params to parse the url rule with
132
     *   `getRoutePattern()`.
133
     * - httpCode: integer expected Http Code response. If the httpCode is
134
     *   a key in `$responses` parameter then the method defined there will be
135
     *   used to analyze the response. Otherwise `checkErrorResponse()` will be
136
     *   used.
137
     * - error: string|string[] expected json being contained in the response.
138
     * - headers: (optional) string[] pairs of header => value expected in the
139
     *   response.
140
     */
141 2
    protected function internalView(Tester $I, Example $example)
142
    {
143
        // Authenticates configured user.
144 2
        $this->authUser($I, $example);
145
146
        // Send request
147 2
        $I->sendGET($this->parseUrl($example));
148
149
        // Checks the response has the required headers and body.
150 2
        $this->checkResponse([
151 2
            HttpCode::OK => 'checkSuccessViewResponse',
152 2
        ], $I, $example);
153 2
    }
154
155
    /**
156
     * Handles the internal logic when running a test on a updating a record.
157
     *
158
     * @param Tester $I
159
     * @param Example $example data used for the testing. It uses the keys
160
     * - tokenName: (optional) string name of the token used to authenticate.
161
     * - url: (optional) string if provided it will be used directly.
162
     * - urlParams: (optional) string[] GET params to parse the url rule with
163
     *   `getRoutePattern()`.
164
     * - data: (optional) POST data sent on the request.
165
     * - expected: (optional) expected in the JSON response body.
166
     * - headers: (optional) string[] pairs of header => value expected in the
167
     *   response.
168
     */
169 4
    protected function internalUpdate(Tester $I, Example $example)
170
    {
171
        // Authenticates configured user.
172 4
        $this->authUser($I, $example);
173
174
        // Send request
175 4
        $I->sendPATCH($this->parseUrl($example), $example['data']);
176
177
        // Checks the response has the required headers and body.
178 4
        $this->checkResponse([
179 4
            HttpCode::OK => 'checkSuccessViewResponse',
180 4
            HttpCode::UNPROCESSABLE_ENTITY => 'checkValidationResponse',
181 4
        ], $I, $example);
182
183 4
        if (isset($example['expected'])) {
184
            $I->seeResponseContainsJson($example['expected']);
185
        }
186 4
    }
187
188
    /**
189
     * Handles the internal logic when running a test on a updating a record.
190
     *
191
     * @param Tester $I
192
     * @param Example $example data used for the testing. It uses the keys
193
     * - tokenName: (optional) string name of the token used to authenticate.
194
     * - url: (optional) string if provided it will be used directly.
195
     * - urlParams: (optional) string[] GET params to parse the url rule with
196
     *   `getRoutePattern()`.
197
     * - httpCode: integer expected Http Code response.
198
     */
199 5
    protected function internalDelete(Tester $I, Example $example)
200
    {
201
        // Authenticates configured user.
202 5
        $this->authUser($I, $example);
203
204
        // Send request
205 5
        $I->sendDELETE($this->parseUrl($example));
206
207
        // Check response code.
208 5
        $I->seeResponseCodeIs($example['httpCode']);
209 5
    }
210
211
    /**
212
     * Checks the response Http code and the response based on the Http code and
213
     * a list of pairs 'httpCode' => 'responseMethod' provided in the
214
     * `$responses` parameter.
215
     *
216
     * If the Http Code in the response doesn't match any of the keys in
217
     * `$responses` then `checkErrorResponse` will be used instead.
218
     *
219
     * @param array $responses pairs of 'httpCode' => 'responseMethod' which
220
     * will determine how to check the response.
221
     * @param Tester $I
222
     * @param Example $example data used for the testing. It uses the keys
223
     * - httpCode: integer expected Http Code response. If the httpCode is
224
     *   a key in `$responses` parameter then the method defined there will be
225
     *   used to analyze the response. Otherwise `checkErrorResponse()` will be
226
     *   used.
227
     * - error: (optional) mixed expected json being contained in the response.
228
     * - headers: (optional) string[] pairs of header => value expected in the
229
     *   response.
230
     */
231 10
    protected function checkResponse(
232
        array $responses,
233
        Tester $I,
234
        Example $example
235
    ) {
236 10
        $I->seeResponseCodeIs($example['httpCode']);
237 10
        if (isset($responses[$example['httpCode']])) {
238 10
            $responseMethod = $responses[$example['httpCode']];
239 10
            $this->$responseMethod($I, $example);
240
        } else {
241 3
            $this->checkErrorResponse($I, $example);
242
        }
243 10
        if (isset($example['headers'])) {
244 2
            foreach ($example['headers'] as $header => $value) {
245 2
                $I->seeHttpHeader($header, $value);
246
            }
247
        }
248 10
    }
249
250
    /**
251
     * Checks an expected success collection response.
252
     *
253
     * @param Tester $I
254
     * @param Example $example
255
     */
256 2
    protected function checkSuccessIndexResponse(Tester $I, Example $example)
257
    {
258 2
        $I->seeResponseMatchesJsonType($this->recordJsonType());
259 2
        $I->seeContentTypeHttpHeader();
260 2
        $I->seePaginationHttpHeaders();
261 2
    }
262
263
    /**
264
     * Checks an expected success record response.
265
     *
266
     * @param Tester $I
267
     * @param Example $example
268
     */
269 8
    protected function checkSuccessViewResponse(Tester $I, Example $example)
270
    {
271 8
        $I->seeResponseMatchesJsonType($this->recordJsonType());
272 8
        $I->seeContentTypeHttpHeader();
273 8
    }
274
275
    /**
276
     * Checks an expected success record creation response.
277
     *
278
     * @param Tester $I
279
     * @param Example $example
280
     */
281 2
    protected function checkSuccessCreateResponse(Tester $I, Example $example)
282
    {
283 2
        $this->checkSuccessViewResponse($I, $example);
284 2
        $I->seeHttpHeaderOnce('Location');
285 2
        $this->checkSelfLink($I, $I->grabHttpHeader('Location'));
286 2
    }
287
288
    /**
289
     * Checks an expected response containing validation errors.
290
     *
291
     * @param Tester $I
292
     * @param Example $example data used for the testing. It uses the keys
293
     * - validationErrors: string[] (optional) pairs of field => message
294
     *   validation errors.
295
     */
296 5
    protected function checkValidationResponse(Tester $I, Example $example)
297
    {
298 5
        $I->seeResponseMatchesJsonType([
299 5
            'field' => 'string',
300
            'message' => 'string',
301
        ]);
302 5
        if (empty($example['validationErrors'])) {
303
            return;
304
        }
305 5
        $expected = [];
306 5
        foreach ($example['validationErrors'] as $field => $message) {
307 5
            $expected[] = [
308 5
                'field' => $field,
309 5
                'message' => $message,
310
            ];
311
        }
312 5
        $I->seeResponseContainsJson($expected);
313
314 5
    }
315
316
    /**
317
     * Checks an expected error response from user input.
318
     *
319
     * @param Tester $I
320
     * @param Example $example data used for the testing. It uses the keys
321
     * - error: (optional) mixed expected json being contained in the response.
322
     */
323 3
    protected function checkErrorResponse(Tester $I, Example $example)
324
    {
325 3
        $I->seeResponseMatchesJsonType([
326 3
            'name' => 'string',
327
            'message' => 'string',
328
            'code' => 'integer',
329
        ]);
330 3
        if (isset($example['error'])) {
331
            $I->seeResponseContainsJson($example['error']);
332
        }
333 3
    }
334
335
    /**
336
     * @param Tester $I
337
     * @param string $expected the expected self link.
338
     */
339 2
    protected function checkSelfLink(Tester $I, string $expected)
340
    {
341 2
        if ('' == $path = $this->selfLinkPath()) {
342
            return;
343
        }
344 2
        verify($I->grabDataFromResponseByJsonPath($path))
345 2
            ->arrayContains($expected);
346 2
    }
347
348
    /**
349
     * @return string the path which will be used to obtain the self link of a
350
     * record. Return empty string to skip that check.
351
     */
352 2
    protected function selfLinkPath(): string
353
    {
354 2
        return '$._links.self.href';
355
    }
356
357
    /**
358
     * Expected Json Type for each resource.
359
     *
360
     * @return array
361
     * @see http://codeception.com/docs/modules/REST#seeResponseMatchesJsonType
362
     */
363
    abstract protected function recordJsonType(): array;
364
365
    /**
366
     * @return string route pattern to create the
367
     */
368
    abstract protected function getRoutePattern(): string;
369
}
370