Completed
Push — master ( 43dba6...416142 )
by Mahmoud
09:25 queued 05:38
created

TestingTrait::getLoggedInTestingAdmin()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 0
1
<?php
2
3
namespace App\Port\Tests\PHPUnit\Traits;
4
5
use App;
6
use App\Containers\Authorization\Models\Role;
7
use App\Containers\User\Actions\CreateUserAction;
8
use Dingo\Api\Http\Response as DingoAPIResponse;
9
use Illuminate\Http\Response;
10
use Illuminate\Support\Arr as LaravelArr;
11
use Illuminate\Support\Str as LaravelStr;
12
use Mockery;
13
use Symfony\Component\Debug\Exception\UndefinedMethodException;
14
15
/**
16
 * Class TestingTrait.
17
 *
18
 * All the functions in this trait are accessible from all your tests.
19
 *
20
 * @author  Mahmoud Zalt <[email protected]>
21
 */
22
trait TestingTrait
23
{
24
25
    /**
26
     * the Logged in user, used for protected routes.
27
     *
28
     * @var User
29
     */
30
    public $loggedInTestingUser;
31
32
    /**
33
     * @param           $endpoint
34
     * @param string    $verb
35
     * @param array     $data
36
     * @param bool|true $protected
37
     * @param array     $header
38
     *
39
     * @throws \Symfony\Component\Debug\Exception\UndefinedMethodException
40
     *
41
     * @return mixed
42
     */
43
    public function apiCall($endpoint, $verb = 'get', array $data = [], $protected = true, array $header = [])
44
    {
45
        $content = json_encode($data);
46
47
        $headers = array_merge([
48
            'CONTENT_LENGTH' => mb_strlen($content, '8bit'),
49
//            'CONTENT_TYPE' => 'application/json',
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
50
            'Accept'         => 'application/json',
51
        ], $header);
52
53
        // if endpoint is protected (requires token to access it's functionality)
54
        if ($protected && !array_has($header, 'Authorization')) {
55
            // append the token to the header
56
            $headers['Authorization'] = 'Bearer ' . $this->getLoggedInTestingUserToken();
57
        }
58
59
        $verb = strtolower($verb);
60
61
        switch ($verb) {
62
            case 'get':
63
                $endpoint = $data ? $endpoint . '?' . http_build_query($data) : $endpoint;
64
                $response = $this->get($endpoint, $headers)->response;
0 ignored issues
show
Bug introduced by
It seems like get() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
65
                break;
66
            case 'post':
67
            case 'put':
68
            case 'patch':
69
            case 'delete':
70
                $response = $this->{$verb}($endpoint, $data, $headers)->response;
71
                break;
72
            default:
73
                throw new UndefinedMethodException('Undefined HTTP Verb (' . $verb . ').');
0 ignored issues
show
Bug introduced by
The call to UndefinedMethodException::__construct() misses a required argument $previous.

This check looks for function calls that miss required arguments.

Loading history...
74
        }
75
76
        return $response;
77
    }
78
79
    /**
80
     * @param \Dingo\Api\Http\Response $response
81
     * @param array                    $messages
82
     */
83
    public function assertValidationErrorContain(DingoAPIResponse $response, array $messages)
84
    {
85
86
        $arrayResponse = json_decode($response->getContent());
87
88
        foreach ($messages as $key => $value) {
89
            $this->assertEquals($arrayResponse->errors->{$key}[0], $value);
0 ignored issues
show
Bug introduced by
It seems like assertEquals() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
90
        }
91
    }
92
93
    /**
94
     * get teh current logged in user.
95
     *
96
     * @return \App\Port\Tests\PHPUnit\Traits\User|mixed
97
     */
98
    public function getLoggedInTestingUser()
99
    {
100
        $user = $this->loggedInTestingUser;
101
102
        if (!$user) {
103
            $user = $this->registerAndLoginTestingUser();
104
        }
105
106
        return $user;
107
    }
108
109
    /**
110
     * This returned visitor is a normal user, with `visitor_id` means
111
     * before he became a registered user (can login) was a visitor.
112
     * So this can be used to test endpoints that are protected by visitors
113
     * access.
114
     *
115
     * @return  \App\Port\Tests\PHPUnit\Traits\User|mixed
116
     */
117
    public function getVisitor()
118
    {
119
        $user = $this->getLoggedInTestingUser();
120
121
        $user->visitor_id = str_random('20');
122
        unset($user->token);
123
        $user->save();
124
125
        return $user;
126
    }
127
128
    /**
129
     * @return  \App\Port\Tests\PHPUnit\Traits\User|mixed
130
     */
131
    public function getLoggedInTestingAdmin()
132
    {
133
        $user = $this->getLoggedInTestingUser();
134
135
        $user = $this->makeAdmin($user);
136
137
        return $user;
138
    }
139
140
    /**
141
     * @param $user
142
     *
143
     * @return  mixed
144
     */
145
    public function makeAdmin($user)
146
    {
147
        $adminRole = Role::where('name', 'admin')->first();
148
149
        $user->attachRole($adminRole);
150
151
        return $user;
152
    }
153
154
    /**
155
     * get teh current logged in user token.
156
     *
157
     * @return string
158
     */
159
    public function getLoggedInTestingUserToken()
160
    {
161
        return $this->getLoggedInTestingUser()->token;
162
    }
163
164
    /**
165
     * @param null $userDetails
166
     *
167
     * @return mixed
168
     */
169
    public function registerAndLoginTestingUser($userDetails = null)
170
    {
171
        // if no user detail provided, use the default details.
172
        if (!$userDetails) {
173
            $userDetails = [
174
                'name'     => 'Mahmoud Zalt',
175
                'email'    => '[email protected]',
176
                'password' => 'secret.Pass7',
177
            ];
178
        }
179
180
        $createUserAction = App::make(CreateUserAction::class);
181
182
        // create new user and login (true)
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
183
        $user = $createUserAction->run(
184
            $userDetails['email'],
185
            $userDetails['password'],
186
            $userDetails['name'],
187
            null,
188
            null,
189
            true
190
        );
191
192
        return $this->loggedInTestingUser = $user;
193
    }
194
195
    /**
196
     * @param null $userDetails
197
     *
198
     * @return  mixed
199
     */
200
    public function registerAndLoginTestingAdmin($userDetails = null)
201
    {
202
        $user = $this->registerAndLoginTestingUser($userDetails);
203
204
        $user = $this->makeAdmin($user);
205
206
        return $user;
207
    }
208
209
    /**
210
     * @param $keys
211
     * @param $response
212
     */
213
    public function assertResponseContainKeys($keys, $response)
214
    {
215
        if (!is_array($keys)) {
216
            $keys = (array)$keys;
217
        }
218
219
        foreach ($keys as $key) {
220
            $this->assertTrue(array_key_exists($key, $this->responseToArray($response)));
0 ignored issues
show
Bug introduced by
It seems like assertTrue() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
221
        }
222
    }
223
224
    /**
225
     * @param $values
226
     * @param $response
227
     */
228
    public function assertResponseContainValues($values, $response)
229
    {
230
        if (!is_array($values)) {
231
            $values = (array)$values;
232
        }
233
234
        foreach ($values as $value) {
235
            $this->assertTrue(in_array($value, $this->responseToArray($response)));
0 ignored issues
show
Bug introduced by
It seems like assertTrue() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
236
        }
237
    }
238
239
    /**
240
     * @param $data
241
     * @param $response
242
     */
243
    public function assertResponseContainKeyValue($data, $response)
244
    {
245
        $response = json_encode(LaravelArr::sortRecursive(
246
            (array)$this->responseToArray($response)
247
        ));
248
249
        foreach (LaravelArr::sortRecursive($data) as $key => $value) {
250
            $expected = $this->formatToExpectedJson($key, $value);
0 ignored issues
show
Bug introduced by
It seems like formatToExpectedJson() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
251
            $this->assertTrue(LaravelStr::contains($response, $expected),
0 ignored issues
show
Bug introduced by
It seems like assertTrue() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
252
                "The JSON fragment [ {$expected} ] does not exist in the response [ {$response} ].");
253
        }
254
    }
255
256
    /**
257
     * Migrate the database.
258
     */
259
    public function migrateDatabase()
260
    {
261
        \Artisan::call('migrate');
262
    }
263
264
    /**
265
     * @param $response
266
     *
267
     * @return mixed
268
     */
269
    private function responseToArray($response)
270
    {
271
        if ($response instanceof \Illuminate\Http\Response) {
272
            $response = json_decode($response->getContent(), true);
273
        }
274
275
        if (array_key_exists('data', $response)) {
276
            $response = $response['data'];
277
        }
278
279
        return $response;
280
    }
281
282
    /**
283
     * Format the given key and value into a JSON string for expectation checks.
284
     *
285
     * @param string $key
286
     * @param mixed  $value
287
     *
288
     * @return string
289
     */
290
    private function formatToKeyValueToString($key, $value)
291
    {
292
        $expected = json_encode([$key => $value]);
293
294
        if (LaravelStr::startsWith($expected, '{')) {
295
            $expected = substr($expected, 1);
296
        }
297
298
        if (LaravelStr::endsWith($expected, '}')) {
299
            $expected = substr($expected, 0, -1);
300
        }
301
302
        return $expected;
303
    }
304
305
    /**
306
     * Mocking helper
307
     *
308
     * @param $class
309
     *
310
     * @return  \Mockery\MockInterface
311
     */
312
    public function mock($class)
313
    {
314
        $mock = Mockery::mock($class);
315
        App::instance($class, $mock);
316
317
        return $mock;
318
    }
319
320
    /**
321
     * get response object, get the string content from it and convert it to an std object
322
     * making it easier to read
323
     *
324
     * @param $response
325
     *
326
     * @return  mixed
327
     */
328
    public function getResponseObject(Response $response)
329
    {
330
        return json_decode($response->getContent());
331
    }
332
333
    /**
334
     * Inject the ID in the Endpoint URI
335
     *
336
     * Example: you give it ('users/{id}/stores', 100) it returns 'users/100/stores'
337
     *
338
     * @param $endpoint
339
     * @param $id
340
     *
341
     * @return  mixed
342
     */
343
    public function injectEndpointId($endpoint, $id)
344
    {
345
        return str_replace("{id}", $id, $endpoint);
346
    }
347
348
}
349