Skip to content

Commit fa2cb8c

Browse files
committed
[Tests] Add tests for user me action
See #100
1 parent d67c8a3 commit fa2cb8c

File tree

5 files changed

+208
-0
lines changed

5 files changed

+208
-0
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
/*
3+
* Copyright 2021 Cloud Creativity Limited
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
declare(strict_types=1);
19+
20+
namespace App\Http\Controllers\Api\V1;
21+
22+
use App\Http\Controllers\Controller;
23+
use Illuminate\Http\Request;
24+
use LaravelJsonApi\Core\Responses\DataResponse;
25+
use LaravelJsonApi\Laravel\Http\Controllers\Actions;
26+
27+
class UserController extends Controller
28+
{
29+
30+
use Actions\FetchOne;
31+
32+
/**
33+
* Return the current user.
34+
*
35+
* @param Request $request
36+
* @return DataResponse
37+
*/
38+
public function me(Request $request): DataResponse
39+
{
40+
return DataResponse::make($request->user());
41+
}
42+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
/*
3+
* Copyright 2021 Cloud Creativity Limited
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
declare(strict_types=1);
19+
20+
namespace App\Policies;
21+
22+
use App\Models\User;
23+
24+
class UserPolicy
25+
{
26+
27+
/**
28+
* Determine if the user can view the other user.
29+
*
30+
* @param User $user
31+
* @param User $other
32+
* @return bool
33+
*/
34+
public function view(User $user, User $other): bool
35+
{
36+
return true;
37+
}
38+
}

tests/dummy/routes/api.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
$actions->withId()->post('publish');
1818
});
1919

20+
/** Users */
21+
$server->resource('users')->only('show')->actions(function ($actions) {
22+
// we use `-me` because `me` would match the hash-id pattern
23+
$actions->get('-me', 'me');
24+
});
25+
2026
/** Videos */
2127
$server->resource('videos')->relationships(function ($relationships) {
2228
$relationships->hasMany('tags');
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
/*
3+
* Copyright 2021 Cloud Creativity Limited
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
declare(strict_types=1);
19+
20+
namespace App\Tests\Api\V1\Users;
21+
22+
use App\Models\User;
23+
use App\Tests\Api\V1\TestCase;
24+
25+
class ReadTest extends TestCase
26+
{
27+
28+
public function test(): void
29+
{
30+
$user = User::factory()->createOne();
31+
32+
$expected = $this->serializer
33+
->user($user)
34+
->jsonSerialize();
35+
36+
$response = $this
37+
->actingAs(User::factory()->createOne())
38+
->jsonApi('users')
39+
->get(url('/api/v1/users', $expected['id']));
40+
41+
$response->assertFetchedOneExact($expected);
42+
}
43+
44+
public function testMe(): void
45+
{
46+
$user = User::factory()->createOne();
47+
48+
$expected = $this->serializer
49+
->user($user)
50+
->jsonSerialize();
51+
52+
$response = $this
53+
->actingAs($user)
54+
->jsonApi('users')
55+
->get(url('/api/v1/users/-me'));
56+
57+
$response->assertFetchedOneExact($expected);
58+
}
59+
}

tests/lib/Integration/Routing/ActionsTest.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,4 +271,67 @@ public function testWithMiddleware(): void
271271
$this->assertSame("api.v1.posts.image", $route->getName());
272272
$this->assertSame(['api', 'my-middleware1', 'jsonapi:v1', 'my-middleware2'], $route->action['middleware']);
273273
}
274+
275+
/**
276+
* This test was created from a question on Slack. In the test, we check that if an
277+
* action is registered without a URL prefix, the route matching can distinguish
278+
* between:
279+
*
280+
* DELETE /api/v1/posts/purge
281+
* DELETE /api/v1/posts/123
282+
*/
283+
public function testNoActionPrefixCanMatchIfActionDoesNotMatchIdPattern(): void
284+
{
285+
$server = $this->createServer('v1');
286+
$this->createSchema($server, 'posts', '\d+');
287+
288+
$this->defaultApiRoutes(function () {
289+
JsonApiRoute::server('v1')->prefix('v1')->resources(function ($server) {
290+
$server->resource('posts', PostController::class)
291+
->actions(function ($actions) {
292+
$actions->delete('purge');
293+
$actions->withId()->post('publish');
294+
});
295+
});
296+
});
297+
298+
$route = $this->assertMatch('DELETE', '/api/v1/posts/purge');
299+
$this->assertSame('App\Http\Controllers\Api\V1\PostController@purge', $route->action['controller']);
300+
$this->assertSame('v1.posts.purge', $route->getName());
301+
302+
$route = $this->assertMatch('DELETE', '/api/v1/posts/123');
303+
$this->assertSame('App\Http\Controllers\Api\V1\PostController@destroy', $route->action['controller']);
304+
$this->assertSame('v1.posts.destroy', $route->getName());
305+
306+
$route = $this->assertMatch('POST', '/api/v1/posts/123/publish');
307+
$this->assertSame('App\Http\Controllers\Api\V1\PostController@publish', $route->action['controller']);
308+
$this->assertSame('v1.posts.publish', $route->getName());
309+
}
310+
311+
/**
312+
* This is a common scenario that is seen in questions - registering a `me` action
313+
* on the users resource to return the current signed-in user.
314+
*/
315+
public function testUserMeDoesNotConflictWithRetrievingUser(): void
316+
{
317+
$server = $this->createServer('v1');
318+
$this->createSchema($server, 'users', '\d+');
319+
320+
$this->defaultApiRoutes(function () {
321+
JsonApiRoute::server('v1')->prefix('v1')->resources(function ($server) {
322+
$server->resource('users', 'App\Http\Controllers\Api\V1\UserController')
323+
->actions(function ($actions) {
324+
$actions->get('me');
325+
});
326+
});
327+
});
328+
329+
$route = $this->assertMatch('GET', '/api/v1/users/me');
330+
$this->assertSame('App\Http\Controllers\Api\V1\UserController@me', $route->action['controller']);
331+
$this->assertSame('v1.users.me', $route->getName());
332+
333+
$route = $this->assertMatch('GET', '/api/v1/users/1');
334+
$this->assertSame('App\Http\Controllers\Api\V1\UserController@show', $route->action['controller']);
335+
$this->assertSame('v1.users.show', $route->getName());
336+
}
274337
}

0 commit comments

Comments
 (0)