Test Setup Failed
Push — main ( abdcb9...2e5f68 )
by Slawomir
04:37
created

PostIT::shouldUpdateExistingBlogPost()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 40
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 23
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 40
rs 9.552
1
<?php
2
3
namespace App\Tests\Modules\Posts\Integration;
4
5
use App\Modules\Posts\Api\Command\BaselinePostsCommand;
6
use App\Modules\Posts\Api\Command\CreatePostCommand;
7
use App\Modules\Posts\Api\Command\DeletePostCommand;
8
use App\Modules\Posts\Api\Command\Response\CreatePostCommandResponse;
9
use App\Modules\Posts\Api\Command\UpdatePostCommand;
10
use App\Modules\Posts\Api\Event\Inbound\CommentCreatedPostsIEvent;
11
use App\Modules\Posts\Api\Event\Inbound\CommentsBaselinedPostsIEvent;
12
use App\Modules\Posts\Api\Event\Inbound\UserRenamedPostsIEvent;
13
use App\Modules\Posts\Api\PostsApiInterface;
14
use App\Modules\Posts\Api\Query\FindAllPostsQuery;
15
use App\Modules\Posts\Api\Query\FindPostByIdQuery;
16
use App\Modules\Posts\Api\Query\Response\FindPostHeaderQueryResponse;
17
use App\Modules\Posts\Domain\Event\Outbound\PostCreatedOEvent;
18
use App\Modules\Posts\Domain\Event\Outbound\PostDeletedOEvent;
19
use App\Modules\Posts\Domain\Event\Outbound\PostUpdatedOEvent;
20
use App\Modules\Posts\Domain\Repository\PostsFindingRepositoryInterface;
21
use App\Tests\Modules\Posts\Integration\Http\PostsHttpTrait;
22
use App\Tests\TestUtils\Contracts\ApplicationEventContractLoader;
23
use App\Tests\TestUtils\Events\InMemoryEventPublisher;
24
use App\Tests\TestUtils\IntegrationTest;
25
use Symfony\Bundle\FrameworkBundle\Console\Application;
26
use Symfony\Component\Console\Tester\CommandTester;
27
use Symfony\Component\Uid\Ulid;
28
29
class PostIT extends IntegrationTest
30
{
31
    use PostsHttpTrait;
32
    use ApplicationEventContractLoader;
33
34
    /**
35
     * @test
36
     */
37
    public function shouldCreateNewBlogPost(): void
38
    {
39
        //given: User has written a new Blog Post
40
        $command = new CreatePostCommand('Post Title', 'Post Body', ['t1']);
41
42
        //when: User posts the Post
43
        $response = $this->createPost($command);
44
45
        //then: the response is OK
46
        self::assertResponseIsSuccessful();
47
48
        //and: the Response contains the proper Object
49
        self::assertInstanceOf(CreatePostCommandResponse::class, $response);
50
51
        //and: The Response Object contains ID of newly created Blog Post
52
        self::assertNotNull($response->getId());
53
54
        //and: a Post Created Output Event was Published
55
        $events = InMemoryEventPublisher::get(PostCreatedOEvent::class);
56
        self::assertCount(1, $events);
57
58
        //and: The Event has the correct data
59
        InMemoryEventPublisher::assertEventData([
60
            'title' => 'Post Title',
61
            'body' => 'Post Body',
62
            'tags' => ['t1'],
63
            'summary' => 'Post Body',
64
            'createdByName' => IntegrationTest::DEFAULT_USER_ID,
65
            'createdAt' => 'createdAt',
66
            'createdById' => 'createdById'
67
        ], $events[0]);
68
    }
69
70
    /**
71
     * @param Ulid $postId
72
     * @return Ulid
73
     * @test
74
     */
75
    public function shouldUpdateExistingBlogPost(): void
76
    {
77
        //given: There is a Post created
78
        $createCommand = new CreatePostCommand('Post Title', 'Post Body', ['t1']);
79
        $createResponse = $this->createPost($createCommand);
80
81
        //when: the Post is updated
82
        $updateCommand = new UpdatePostCommand('Post Title updated', 'Post Body updated', ['t2']);
83
        $updateCommand->setId($createResponse->getId());
84
        $this->updatePost($updateCommand);
85
86
        //then: the response is OK
87
        self::assertResponseIsSuccessful();
88
89
        //and: a Post Updated Output Event was Published
90
        $events = InMemoryEventPublisher::get(PostUpdatedOEvent::class);
91
        self::assertCount(1, $events);
92
93
        //and: The Event has the correct data
94
        InMemoryEventPublisher::assertEventData([
95
            'id' => $createResponse->getId(),
96
            'title' => 'Post Title updated',
97
            'body' => 'Post Body updated',
98
            'tags' => ['t2'],
99
            'summary' => 'Post Body updated',
100
            'updatedAt' => 'updatedAt',
101
        ], $events[0]);
102
103
        //when: the User Renamed Event is handled
104
        $data = $this->getInboundEvent("Posts/UserRenamedPostsIEvent");
105
        $event = new UserRenamedPostsIEvent($data);
106
        $this->getPostsApi()->onUserRenamed($event);
107
108
        //and: User fetches the Post
109
        $findResponse = $this->findPostById(new FindPostByIdQuery($createResponse->getId()));
110
111
        //then: Previously created Post is fetched with the Comment
112
        self::assertNotNull($findResponse);
113
        self::assertEquals($createResponse->getId(), $findResponse->getId());
114
        self::assertEquals($event->getNewLogin(), $findResponse->getCreatedByName());
115
    }
116
117
    /**
118
     * @param Ulid $postId
119
     * @test
120
     */
121
    public function shouldDeleteExistingBlogPost(): void
122
    {
123
        //given: There is a Post created
124
        $createCommand = new CreatePostCommand('Post Title', 'Post Body', ['t1']);
125
        $createResponse = $this->createPost($createCommand);
126
127
        //when:
128
        $updateCommand = new DeletePostCommand($createResponse->getId());
129
        $this->deletePost($updateCommand);
130
131
        //then: the response is OK
132
        self::assertResponseIsSuccessful();
133
134
        //and: a Post Updated Output Event was Published
135
        $events = InMemoryEventPublisher::get(PostDeletedOEvent::class);
136
        self::assertCount(1, $events);
137
138
        //and: The Event has the correct data
139
        InMemoryEventPublisher::assertEventData([
140
            'id' => $createResponse->getId(),
141
        ], $events[0]);
142
    }
143
144
    /**
145
     * @test
146
     */
147
    public function shouldFetchAllCreatedPosts(): void
148
    {
149
        //given: There is a Post created
150
        $command = new CreatePostCommand('Post Title', 'Post Body', ['t1']);
151
        $createResponse = $this->createPost($command);
152
153
        //when: User fetches all the Posts
154
        $page = $this->findAllPosts(new FindAllPostsQuery(1));
155
156
        //then: the response is OK
157
        self::assertResponseIsSuccessful();
158
159
        //and: Previously created Post is fetched
160
        self::assertNotNull($page);
161
        self::assertEquals(1, $page->getPageNo());
162
        self::assertEquals(1, $page->getCount());
163
        self::assertCount(1, $page->getData());
164
        self::assertEquals(PostsFindingRepositoryInterface::PAGE_SIZE, $page->getPageSize());
165
166
        self::assertTrue(isset($page->getData()[0]));
167
168
        //and: The fetched Post is valid
169
        $postHeader = $this->convert($page->getData()[0], FindPostHeaderQueryResponse::class);
170
        self::assertNotNull($postHeader);
171
        self::assertEquals('Post Title', $postHeader->getTitle());
172
        self::assertEquals('Post Body', $postHeader->getSummary());
173
        self::assertEquals(['t1'], $postHeader->getTags());
174
        self::assertEquals(0, $postHeader->getCommentsCount());
175
        self::assertEquals($createResponse->getId(), $postHeader->getId());
176
    }
177
178
    /**
179
     * @param Ulid $postId
180
     * @return Ulid
181
     * @test
182
     */
183
    public function shouldFetchSingleCreatedPost(): void
184
    {
185
        //given: There is a Post created
186
        $command = new CreatePostCommand('Post Title', 'Post Body', ['t1']);
187
        $createResponse = $this->createPost($command);
188
189
        //when: User fetches the Post
190
        $post = $this->findPostById(new FindPostByIdQuery($createResponse->getId()));
191
192
        //then: the response is OK
193
        self::assertResponseIsSuccessful();
194
195
        //and: Previously created Post is fetched
196
        self::assertNotNull($post);
197
        self::assertEquals('Post Title', $post->getTitle());
198
        self::assertEquals('Post Body', $post->getBody());
199
        self::assertEquals(['t1'], $post->getTags());
200
        self::assertEquals([], $post->getComments());
201
        self::assertEquals($createResponse->getId(), $post->getId());
202
    }
203
204
    /**
205
     * @param Ulid $postId
206
     * @return Ulid
207
     * @test
208
     */
209
    public function shouldUpdateCommentsOnExistingPost(): void
210
    {
211
        //given: There is a Post created
212
        $command = new CreatePostCommand('Post Title', 'Post Body', ['t1']);
213
        $createResponse = $this->createPost($command);
214
215
        //and: There was a Comment Created
216
        $data = $this->getInboundEvent("Posts/CommentCreatedPostsIEvent");
217
        $data['postId'] = $createResponse->getId();
218
        $event = new CommentCreatedPostsIEvent($data);
219
220
        //when: the Comment Created Event is handled
221
        $this->getPostsApi()->onCommentCreated($event);
222
223
        //and: User fetches the Post
224
        $post = $this->findPostById(new FindPostByIdQuery($createResponse->getId()));
225
226
        //then: the response is OK
227
        self::assertResponseIsSuccessful();
228
229
        //and: Previously created Post is fetched with the Comment
230
        self::assertNotNull($post);
231
        self::assertEquals('Post Title', $post->getTitle());
232
        self::assertEquals('Post Body', $post->getBody());
233
        self::assertEquals(['t1'], $post->getTags());
234
        self::assertCount(1, $post->getComments());
235
        self::assertEquals('Comment Author', $post->getComments()[0]['author']);
236
        self::assertEquals('Comment Body', $post->getComments()[0]['body']);
237
        self::assertEquals($createResponse->getId(), $post->getId());
238
239
        //when: User fetches all the Posts
240
        $page = $this->findAllPosts(new FindAllPostsQuery(1));
241
242
        //then: the response is OK
243
        self::assertResponseIsSuccessful();
244
245
        //and: Previously created Post is fetched with the correct Comments count
246
        self::assertNotNull($page);
247
        self::assertEquals(1, $page->getPageNo());
248
        self::assertEquals(1, $page->getCount());
249
        self::assertCount(1, $page->getData());
250
        self::assertEquals(PostsFindingRepositoryInterface::PAGE_SIZE, $page->getPageSize());
251
        self::assertTrue(isset($page->getData()[0]));
252
        $postHeader = $this->convert($page->getData()[0], FindPostHeaderQueryResponse::class);
253
        self::assertNotNull($postHeader);
254
        self::assertEquals(1, $postHeader->getCommentsCount());
255
        self::assertEquals($createResponse->getId(), $postHeader->getId());
256
257
        //and: There was a Comment Created
258
        $data = $this->getInboundEvent("Posts/CommentsBaselinedPostsIEvent");
259
        $data['postId'] = $createResponse->getId();
260
        $event = new CommentsBaselinedPostsIEvent($data);
261
262
        //when: the Comment Created Event is handled
263
        $this->getPostsApi()->onCommentsBaselined($event);
264
265
        //and: User fetches the Post
266
        $post = $this->findPostById(new FindPostByIdQuery($createResponse->getId()));
267
268
        //then: the response is OK
269
        self::assertResponseIsSuccessful();
270
271
        //and: Previously created Post is fetched with the Comment
272
        self::assertNotNull($post);
273
        self::assertCount(2, $post->getComments());
274
    }
275
276
    /**
277
     * @param Ulid $postId
278
     * @return Ulid
279
     * @test
280
     */
281
    public function shouldBaselineAllPosts(): void
282
    {
283
        //given: There is a Post created
284
        $command = new CreatePostCommand('Post Title', 'Post Body', ['t1']);
285
        $createResponse = $this->createPost($command);
286
287
        //when: Comments are baselined
288
        $application = $this->setupKernel();
289
        $command = $application->find('app:posts:baseline');
290
        $commandTester = new CommandTester($command);
291
        $commandTester->execute([]);
292
        $output = $commandTester->getDisplay();
293
294
        //then: Comments were baselined correctly
295
        self::assertStringStartsWith('Successfully base-lined all Posts', $output);
296
        $events = InMemoryEventPublisher::get(PostUpdatedOEvent::class);
297
        self::assertCount(1, $events);
298
        self::assertEquals($createResponse->getId(), $events[0]->getData()['id']);
299
    }
300
301
    private function getPostsApi(): PostsApiInterface
302
    {
303
        return self::getContainer()->get(PostsApiInterface::class);
1 ignored issue
show
Bug Best Practice introduced by
The expression return self::getContaine...stsApiInterface::class) could return the type null which is incompatible with the type-hinted return App\Modules\Posts\Api\PostsApiInterface. Consider adding an additional type-check to rule them out.
Loading history...
304
    }
305
306
    /**
307
     * @return Application
308
     */
309
    protected function setupKernel(): Application
310
    {
311
        $kernel = static::createKernel();
312
        $kernel->boot();
313
        $application = new Application($kernel);
314
        $application->add(new BaselinePostsCommand(
315
            $this->getContainer()->get(PostsApiInterface::class)
1 ignored issue
show
Bug introduced by
It seems like $this->getContainer()->g...stsApiInterface::class) can also be of type null; however, parameter $postsApi of App\Modules\Posts\Api\Co...sCommand::__construct() does only seem to accept App\Modules\Posts\Api\PostsApiInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

315
            /** @scrutinizer ignore-type */ $this->getContainer()->get(PostsApiInterface::class)
Loading history...
316
        ));
317
        return $application;
318
    }
319
}