|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
declare( strict_types = 1 ); |
|
4
|
|
|
|
|
5
|
|
|
namespace WMDE\Fundraising\Frontend\DonationContext\Tests\Integration\UseCases\AddDonation; |
|
6
|
|
|
|
|
7
|
|
|
use PHPUnit_Framework_MockObject_MockObject; |
|
8
|
|
|
use WMDE\Euro\Euro; |
|
9
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\Authorization\DonationTokenFetcher; |
|
10
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\Authorization\DonationTokens; |
|
11
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\Domain\Model\Donation; |
|
12
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\Domain\Model\DonorName; |
|
13
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\Domain\Repositories\DonationRepository; |
|
14
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\Infrastructure\DonationConfirmationMailer; |
|
15
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\Tests\Fixtures\FakeDonationRepository; |
|
16
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\Tests\Fixtures\FixedDonationTokenFetcher; |
|
17
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationPolicyValidator; |
|
18
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationRequest; |
|
19
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationUseCase; |
|
20
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationValidationResult; |
|
21
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationValidator; |
|
22
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\ReferrerGeneralizer; |
|
23
|
|
|
use WMDE\Fundraising\Frontend\PaymentContext\Domain\Model\PaymentType; |
|
24
|
|
|
use WMDE\Fundraising\Frontend\PaymentContext\Domain\TransferCodeGenerator; |
|
25
|
|
|
use WMDE\Fundraising\Frontend\DonationContext\Tests\Data\ValidDonation; |
|
26
|
|
|
use WMDE\Fundraising\Frontend\Validation\ConstraintViolation; |
|
27
|
|
|
|
|
28
|
|
|
/** |
|
29
|
|
|
* @covers WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationUseCase |
|
30
|
|
|
* |
|
31
|
|
|
* @license GNU GPL v2+ |
|
32
|
|
|
* @author Kai Nissen < [email protected] > |
|
33
|
|
|
* @author Jeroen De Dauw < [email protected] > |
|
34
|
|
|
*/ |
|
35
|
|
|
class AddDonationUseCaseTest extends \PHPUnit\Framework\TestCase { |
|
36
|
|
|
|
|
37
|
|
|
private const UPDATE_TOKEN = 'a very nice token'; |
|
38
|
|
|
private const ACCESS_TOKEN = 'kindly allow me access'; |
|
39
|
|
|
|
|
40
|
|
|
/** |
|
41
|
|
|
* @var \DateTime |
|
42
|
|
|
*/ |
|
43
|
|
|
private $oneHourInTheFuture; |
|
44
|
|
|
|
|
45
|
|
|
public function setUp() { |
|
46
|
|
|
$this->oneHourInTheFuture = ( new \DateTime() )->add( $this->newOneHourInterval() ); |
|
47
|
|
|
} |
|
48
|
|
|
|
|
49
|
|
|
public function testWhenValidationSucceeds_successResponseIsCreated() { |
|
50
|
|
|
$useCase = $this->newValidationSucceedingUseCase(); |
|
51
|
|
|
|
|
52
|
|
|
$this->assertTrue( $useCase->addDonation( $this->newMinimumDonationRequest() )->isSuccessful() ); |
|
53
|
|
|
} |
|
54
|
|
|
|
|
55
|
|
|
private function newValidationSucceedingUseCase(): AddDonationUseCase { |
|
56
|
|
|
return new AddDonationUseCase( |
|
57
|
|
|
$this->newRepository(), |
|
58
|
|
|
$this->getSucceedingValidatorMock(), |
|
59
|
|
|
$this->getSucceedingPolicyValidatorMock(), |
|
60
|
|
|
new ReferrerGeneralizer( 'http://foo.bar', [] ), |
|
61
|
|
|
$this->newMailer(), |
|
|
|
|
|
|
62
|
|
|
$this->newTransferCodeGenerator(), |
|
63
|
|
|
$this->newTokenFetcher() |
|
64
|
|
|
); |
|
65
|
|
|
} |
|
66
|
|
|
|
|
67
|
|
|
/** |
|
68
|
|
|
* @return DonationConfirmationMailer|PHPUnit_Framework_MockObject_MockObject |
|
69
|
|
|
*/ |
|
70
|
|
|
private function newMailer(): DonationConfirmationMailer { |
|
71
|
|
|
return $this->getMockBuilder( DonationConfirmationMailer::class ) |
|
72
|
|
|
->disableOriginalConstructor() |
|
73
|
|
|
->getMock(); |
|
74
|
|
|
} |
|
75
|
|
|
|
|
76
|
|
|
private function newTokenFetcher(): DonationTokenFetcher { |
|
77
|
|
|
return new FixedDonationTokenFetcher( new DonationTokens( |
|
78
|
|
|
self::ACCESS_TOKEN, |
|
79
|
|
|
self::UPDATE_TOKEN |
|
80
|
|
|
) ); |
|
81
|
|
|
} |
|
82
|
|
|
|
|
83
|
|
|
private function newOneHourInterval(): \DateInterval { |
|
84
|
|
|
return new \DateInterval( 'PT1H' ); |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
private function newRepository(): DonationRepository { |
|
88
|
|
|
return new FakeDonationRepository(); |
|
89
|
|
|
} |
|
90
|
|
|
|
|
91
|
|
|
public function testValidationFails_responseObjectContainsViolations() { |
|
92
|
|
|
$useCase = new AddDonationUseCase( |
|
93
|
|
|
$this->newRepository(), |
|
94
|
|
|
$this->getFailingValidatorMock( new ConstraintViolation( 'foo', 'bar' ) ), |
|
95
|
|
|
$this->getSucceedingPolicyValidatorMock(), |
|
96
|
|
|
new ReferrerGeneralizer( 'http://foo.bar', [] ), |
|
97
|
|
|
$this->newMailer(), |
|
|
|
|
|
|
98
|
|
|
$this->newTransferCodeGenerator(), |
|
99
|
|
|
$this->newTokenFetcher() |
|
100
|
|
|
); |
|
101
|
|
|
|
|
102
|
|
|
$result = $useCase->addDonation( $this->newMinimumDonationRequest() ); |
|
103
|
|
|
$this->assertEquals( [ new ConstraintViolation( 'foo', 'bar' ) ], $result->getValidationErrors() ); |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
public function testValidationFails_responseObjectContainsRequestObject() { |
|
107
|
|
|
$useCase = new AddDonationUseCase( |
|
108
|
|
|
$this->newRepository(), |
|
109
|
|
|
$this->getFailingValidatorMock( new ConstraintViolation( 'foo', 'bar' ) ), |
|
110
|
|
|
$this->getSucceedingPolicyValidatorMock(), |
|
111
|
|
|
new ReferrerGeneralizer( 'http://foo.bar', [] ), |
|
112
|
|
|
$this->newMailer(), |
|
|
|
|
|
|
113
|
|
|
$this->newTransferCodeGenerator(), |
|
114
|
|
|
$this->newTokenFetcher() |
|
115
|
|
|
); |
|
116
|
|
|
|
|
117
|
|
|
$request = $this->newInvalidDonationRequest(); |
|
118
|
|
|
$useCase->addDonation( $request ); |
|
119
|
|
|
$this->assertEquals( $this->newInvalidDonationRequest(), $request ); |
|
120
|
|
|
} |
|
121
|
|
|
|
|
122
|
|
|
private function getSucceedingValidatorMock(): AddDonationValidator { |
|
123
|
|
|
$validator = $this->getMockBuilder( AddDonationValidator::class ) |
|
124
|
|
|
->disableOriginalConstructor() |
|
125
|
|
|
->getMock(); |
|
126
|
|
|
|
|
127
|
|
|
$validator->method( 'validate' )->willReturn( new AddDonationValidationResult() ); |
|
128
|
|
|
|
|
129
|
|
|
return $validator; |
|
130
|
|
|
} |
|
131
|
|
|
|
|
132
|
|
|
private function getFailingValidatorMock( ConstraintViolation $violation ): AddDonationValidator { |
|
133
|
|
|
$validator = $this->getMockBuilder( AddDonationValidator::class ) |
|
134
|
|
|
->disableOriginalConstructor() |
|
135
|
|
|
->getMock(); |
|
136
|
|
|
|
|
137
|
|
|
$validator->method( 'validate' )->willReturn( new AddDonationValidationResult( $violation ) ); |
|
138
|
|
|
|
|
139
|
|
|
return $validator; |
|
140
|
|
|
} |
|
141
|
|
|
|
|
142
|
|
|
private function getSucceedingPolicyValidatorMock(): AddDonationPolicyValidator { |
|
143
|
|
|
$validator = $this->getMockBuilder( AddDonationPolicyValidator::class ) |
|
144
|
|
|
->disableOriginalConstructor() |
|
145
|
|
|
->getMock(); |
|
146
|
|
|
|
|
147
|
|
|
$validator->method( 'needsModeration' )->willReturn( false ); |
|
148
|
|
|
|
|
149
|
|
|
return $validator; |
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
|
private function getFailingPolicyValidatorMock(): AddDonationPolicyValidator { |
|
153
|
|
|
$validator = $this->getMockBuilder( AddDonationPolicyValidator::class ) |
|
154
|
|
|
->disableOriginalConstructor() |
|
155
|
|
|
->getMock(); |
|
156
|
|
|
|
|
157
|
|
|
$validator->method( 'needsModeration' )->willReturn( true ); |
|
158
|
|
|
|
|
159
|
|
|
return $validator; |
|
160
|
|
|
} |
|
161
|
|
|
|
|
162
|
|
|
private function newMinimumDonationRequest(): AddDonationRequest { |
|
163
|
|
|
$donationRequest = new AddDonationRequest(); |
|
164
|
|
|
$donationRequest->setAmount( Euro::newFromString( '1.00' ) ); |
|
165
|
|
|
$donationRequest->setPaymentType( PaymentType::BANK_TRANSFER ); |
|
166
|
|
|
$donationRequest->setDonorType( DonorName::PERSON_ANONYMOUS ); |
|
167
|
|
|
return $donationRequest; |
|
168
|
|
|
} |
|
169
|
|
|
|
|
170
|
|
|
private function newInvalidDonationRequest(): AddDonationRequest { |
|
171
|
|
|
$donationRequest = new AddDonationRequest(); |
|
172
|
|
|
$donationRequest->setPaymentType( PaymentType::DIRECT_DEBIT ); |
|
173
|
|
|
$donationRequest->setAmount( Euro::newFromInt( 0 ) ); |
|
174
|
|
|
$donationRequest->setDonorType( DonorName::PERSON_ANONYMOUS ); |
|
175
|
|
|
return $donationRequest; |
|
176
|
|
|
} |
|
177
|
|
|
|
|
178
|
|
|
public function testGivenInvalidRequest_noConfirmationEmailIsSend() { |
|
179
|
|
|
$mailer = $this->newMailer(); |
|
180
|
|
|
|
|
181
|
|
|
$mailer->expects( $this->never() )->method( $this->anything() ); |
|
|
|
|
|
|
182
|
|
|
|
|
183
|
|
|
$useCase = new AddDonationUseCase( |
|
184
|
|
|
$this->newRepository(), |
|
185
|
|
|
$this->getFailingValidatorMock( new ConstraintViolation( 'foo', 'bar' ) ), |
|
186
|
|
|
$this->getSucceedingPolicyValidatorMock(), |
|
187
|
|
|
new ReferrerGeneralizer( 'http://foo.bar', [] ), |
|
188
|
|
|
$mailer, |
|
|
|
|
|
|
189
|
|
|
$this->newTransferCodeGenerator(), |
|
190
|
|
|
$this->newTokenFetcher() |
|
191
|
|
|
); |
|
192
|
|
|
|
|
193
|
|
|
$useCase->addDonation( $this->newMinimumDonationRequest() ); |
|
194
|
|
|
} |
|
195
|
|
|
|
|
196
|
|
|
private function newTransferCodeGenerator(): TransferCodeGenerator { |
|
197
|
|
|
return $this->createMock( TransferCodeGenerator::class ); |
|
198
|
|
|
} |
|
199
|
|
|
|
|
200
|
|
|
public function testGivenValidRequest_confirmationEmailIsSent() { |
|
201
|
|
|
$mailer = $this->newMailer(); |
|
202
|
|
|
$donation = $this->newValidAddDonationRequestWithEmail( '[email protected]' ); |
|
203
|
|
|
|
|
204
|
|
|
$mailer->expects( $this->once() ) |
|
|
|
|
|
|
205
|
|
|
->method( 'sendConfirmationMailFor' ) |
|
206
|
|
|
->with( $this->isInstanceOf( Donation::class ) ); |
|
207
|
|
|
|
|
208
|
|
|
$useCase = $this->newUseCaseWithMailer( $mailer ); |
|
|
|
|
|
|
209
|
|
|
|
|
210
|
|
|
$useCase->addDonation( $donation ); |
|
211
|
|
|
} |
|
212
|
|
|
|
|
213
|
|
|
public function testGivenValidRequestWithExternalPaymentType_confirmationEmailIsNotSent() { |
|
214
|
|
|
$mailer = $this->newMailer(); |
|
215
|
|
|
|
|
216
|
|
|
$mailer->expects( $this->never() )->method( $this->anything() ); |
|
|
|
|
|
|
217
|
|
|
|
|
218
|
|
|
$useCase = $this->newUseCaseWithMailer( $mailer ); |
|
|
|
|
|
|
219
|
|
|
|
|
220
|
|
|
$request = $this->newValidAddDonationRequestWithEmail( '[email protected]' ); |
|
221
|
|
|
$request->setPaymentType( 'PPL' ); |
|
222
|
|
|
$useCase->addDonation( $request ); |
|
223
|
|
|
} |
|
224
|
|
|
|
|
225
|
|
|
public function testGivenValidRequestWithPolicyViolation_donationIsModerated() { |
|
226
|
|
|
$useCase = new AddDonationUseCase( |
|
227
|
|
|
$this->newRepository(), |
|
228
|
|
|
$this->getSucceedingValidatorMock(), |
|
229
|
|
|
$this->getFailingPolicyValidatorMock(), |
|
230
|
|
|
new ReferrerGeneralizer( 'http://foo.bar', [] ), |
|
231
|
|
|
$this->newMailer(), |
|
|
|
|
|
|
232
|
|
|
$this->newTransferCodeGenerator(), |
|
233
|
|
|
$this->newTokenFetcher() |
|
234
|
|
|
); |
|
235
|
|
|
|
|
236
|
|
|
$response = $useCase->addDonation( $this->newValidAddDonationRequestWithEmail( '[email protected]' ) ); |
|
237
|
|
|
$this->assertTrue( $response->getDonation()->needsModeration() ); |
|
238
|
|
|
} |
|
239
|
|
|
|
|
240
|
|
|
public function testGivenPolicyViolationForExternalPaymentDonation_donationIsNotModerated() { |
|
241
|
|
|
$useCase = new AddDonationUseCase( |
|
242
|
|
|
$this->newRepository(), |
|
243
|
|
|
$this->getSucceedingValidatorMock(), |
|
244
|
|
|
$this->getFailingPolicyValidatorMock(), |
|
245
|
|
|
new ReferrerGeneralizer( 'http://foo.bar', [] ), |
|
246
|
|
|
$this->newMailer(), |
|
|
|
|
|
|
247
|
|
|
$this->newTransferCodeGenerator(), |
|
248
|
|
|
$this->newTokenFetcher() |
|
249
|
|
|
); |
|
250
|
|
|
|
|
251
|
|
|
$request = $this->newValidAddDonationRequestWithEmail( '[email protected]' ); |
|
252
|
|
|
$request->setPaymentType( 'PPL' ); |
|
253
|
|
|
$response = $useCase->addDonation( $request ); |
|
254
|
|
|
$this->assertFalse( $response->getDonation()->needsModeration() ); |
|
255
|
|
|
} |
|
256
|
|
|
|
|
257
|
|
|
private function newUseCaseWithMailer( DonationConfirmationMailer $mailer ) { |
|
258
|
|
|
return new AddDonationUseCase( |
|
259
|
|
|
$this->newRepository(), |
|
260
|
|
|
$this->getSucceedingValidatorMock(), |
|
261
|
|
|
$this->getSucceedingPolicyValidatorMock(), |
|
262
|
|
|
new ReferrerGeneralizer( 'http://foo.bar', [] ), |
|
263
|
|
|
$mailer, |
|
264
|
|
|
$this->newTransferCodeGenerator(), |
|
265
|
|
|
$this->newTokenFetcher() |
|
266
|
|
|
); |
|
267
|
|
|
} |
|
268
|
|
|
|
|
269
|
|
|
private function newValidAddDonationRequestWithEmail( string $email ): AddDonationRequest { |
|
270
|
|
|
$request = $this->newMinimumDonationRequest(); |
|
271
|
|
|
|
|
272
|
|
|
$request->setDonorType( DonorName::PERSON_PRIVATE ); |
|
273
|
|
|
$request->setDonorFirstName( ValidDonation::DONOR_FIRST_NAME ); |
|
274
|
|
|
$request->setDonorLastName( ValidDonation::DONOR_LAST_NAME ); |
|
275
|
|
|
$request->setDonorCompany( '' ); |
|
276
|
|
|
$request->setDonorSalutation( ValidDonation::DONOR_SALUTATION ); |
|
277
|
|
|
$request->setDonorTitle( ValidDonation::DONOR_TITLE ); |
|
278
|
|
|
$request->setDonorStreetAddress( ValidDonation::DONOR_STREET_ADDRESS ); |
|
279
|
|
|
$request->setDonorCity( ValidDonation::DONOR_CITY ); |
|
280
|
|
|
$request->setDonorPostalCode( ValidDonation::DONOR_POSTAL_CODE ); |
|
281
|
|
|
$request->setDonorCountryCode( ValidDonation::DONOR_COUNTRY_CODE ); |
|
282
|
|
|
$request->setDonorEmailAddress( $email ); |
|
283
|
|
|
|
|
284
|
|
|
return $request; |
|
285
|
|
|
} |
|
286
|
|
|
|
|
287
|
|
|
private function newValidCompanyDonationRequest(): AddDonationRequest { |
|
288
|
|
|
$request = $this->newMinimumDonationRequest(); |
|
289
|
|
|
|
|
290
|
|
|
$request->setDonorType( DonorName::PERSON_COMPANY ); |
|
291
|
|
|
$request->setDonorFirstName( '' ); |
|
292
|
|
|
$request->setDonorLastName( '' ); |
|
293
|
|
|
$request->setDonorCompany( ValidDonation::DONOR_LAST_NAME ); |
|
294
|
|
|
$request->setDonorSalutation( '' ); |
|
295
|
|
|
$request->setDonorTitle( '' ); |
|
296
|
|
|
$request->setDonorStreetAddress( ValidDonation::DONOR_STREET_ADDRESS ); |
|
297
|
|
|
$request->setDonorCity( ValidDonation::DONOR_CITY ); |
|
298
|
|
|
$request->setDonorPostalCode( ValidDonation::DONOR_POSTAL_CODE ); |
|
299
|
|
|
$request->setDonorCountryCode( ValidDonation::DONOR_COUNTRY_CODE ); |
|
300
|
|
|
$request->setDonorEmailAddress( ValidDonation::DONOR_EMAIL_ADDRESS ); |
|
301
|
|
|
|
|
302
|
|
|
return $request; |
|
303
|
|
|
} |
|
304
|
|
|
|
|
305
|
|
|
public function testWhenAdditionWorks_successResponseContainsTokens() { |
|
306
|
|
|
$useCase = $this->newValidationSucceedingUseCase(); |
|
307
|
|
|
|
|
308
|
|
|
$response = $useCase->addDonation( $this->newMinimumDonationRequest() ); |
|
309
|
|
|
|
|
310
|
|
|
$this->assertSame( self::UPDATE_TOKEN, $response->getUpdateToken() ); |
|
311
|
|
|
$this->assertSame( self::ACCESS_TOKEN, $response->getAccessToken() ); |
|
312
|
|
|
} |
|
313
|
|
|
|
|
314
|
|
|
public function testWhenAddingCompanyDonation_salutationFieldIsSet() { |
|
315
|
|
|
$useCase = $this->newValidationSucceedingUseCase(); |
|
316
|
|
|
|
|
317
|
|
|
$response = $useCase->addDonation( $this->newValidCompanyDonationRequest() ); |
|
318
|
|
|
|
|
319
|
|
|
$this->assertSame( DonorName::COMPANY_SALUTATION, $response->getDonation()->getDonor()->getName()->getSalutation() ); |
|
320
|
|
|
} |
|
321
|
|
|
|
|
322
|
|
|
} |
|
323
|
|
|
|
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.