Completed
Pull Request — master (#976)
by wiese
61:34
created

testGivenDonationReceiptOptOutRequest_applicationHoldsThisValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 0
1
<?php
2
3
declare( strict_types = 1 );
4
5
namespace WMDE\Fundraising\Frontend\Tests\EdgeToEdge\Routes;
6
7
use Symfony\Component\BrowserKit\Cookie;
8
use Symfony\Component\HttpFoundation\Request;
9
use Symfony\Component\HttpKernel\Client;
10
use WMDE\Fundraising\Entities\MembershipApplication;
11
use WMDE\Fundraising\Frontend\App\RouteHandlers\ShowMembershipConfirmationHandler;
12
use WMDE\Fundraising\Frontend\Factories\FunFunFactory;
13
use WMDE\Fundraising\Frontend\MembershipContext\Tests\Data\ValidMembershipApplication;
14
use WMDE\Fundraising\Frontend\PaymentContext\Domain\Model\PayPalData;
15
use WMDE\Fundraising\Frontend\PaymentContext\Domain\PaymentDelayCalculator;
16
use WMDE\Fundraising\Frontend\Tests\EdgeToEdge\WebRouteTestCase;
17
use WMDE\Fundraising\Frontend\Tests\Fixtures\FixedPaymentDelayCalculator;
18
use WMDE\Fundraising\Frontend\Tests\Fixtures\FixedTokenGenerator;
19
20
/**
21
 * @licence GNU GPL v2+
22
 * @author Jeroen De Dauw < [email protected] >
23
 * @author Kai Nissen < [email protected] >
24
 *
25
 * @requires extension konto_check
26
 */
27
class ApplyForMembershipRouteTest extends WebRouteTestCase {
28
29
	private const FIXED_TOKEN = 'fixed_token';
30
	private const FIRST_PAYMENT_DATE = '2017-09-21';
31
32
	private const APPLY_FOR_MEMBERSHIP_PATH = 'apply-for-membership';
33
34
	public function testGivenGetRequestMembership_formIsShown(): void {
35
		$client = $this->createClient();
36
37
		$crawler = $client->request( 'GET', 'apply-for-membership' );
38
39
		$this->assertCount(
40
			1,
41
			$crawler->filter( 'form#memForm[method="POST"][action="/apply-for-membership"]' )
42
		);
43
		$this->assertCount(
44
			1,
45
			$crawler->filter( 'input[name="showMembershipTypeOption"][type="hidden"][value="true"]' )
46
		);
47
	}
48
49
	public function testGivenGetRequestSustainingMembership_formIsShown(): void {
50
		$client = $this->createClient();
51
52
		$crawler = $client->request( 'GET', 'apply-for-membership', ['type' => 'sustaining'] );
53
54
		$this->assertCount(
55
			1,
56
			$crawler->filter( 'form#memForm[method="POST"][action="/apply-for-membership"]' )
57
		);
58
		$this->assertCount(
59
			1,
60
			$crawler->filter( 'input[name="showMembershipTypeOption"][type="hidden"][value="false"]' )
61
		);
62
	}
63
64
	private function newValidHttpParameters(): array {
65
		return [
66
			'membership_type' => ValidMembershipApplication::MEMBERSHIP_TYPE,
67
68
			'adresstyp' => 'person',
69
			'anrede' => ValidMembershipApplication::APPLICANT_SALUTATION,
70
			'titel' => ValidMembershipApplication::APPLICANT_TITLE,
71
			'vorname' => ValidMembershipApplication::APPLICANT_FIRST_NAME,
72
			'nachname' => ValidMembershipApplication::APPLICANT_LAST_NAME,
73
			'firma' => '',
74
75
			'strasse' => ValidMembershipApplication::APPLICANT_STREET_ADDRESS,
76
			'postcode' => ValidMembershipApplication::APPLICANT_POSTAL_CODE,
77
			'ort' => ValidMembershipApplication::APPLICANT_CITY,
78
			'country' => ValidMembershipApplication::APPLICANT_COUNTRY_CODE,
79
80
			'email' => ValidMembershipApplication::APPLICANT_EMAIL_ADDRESS,
81
			'phone' => ValidMembershipApplication::APPLICANT_PHONE_NUMBER,
82
			'dob' => ValidMembershipApplication::APPLICANT_DATE_OF_BIRTH,
83
84
			'payment_type' => (string)ValidMembershipApplication::PAYMENT_TYPE_DIRECT_DEBIT,
85
			'membership_fee_interval' => (string)ValidMembershipApplication::PAYMENT_PERIOD_IN_MONTHS,
86
			'membership_fee' => (string)ValidMembershipApplication::PAYMENT_AMOUNT_IN_EURO, // TODO: change to localized
87
88
			'bank_name' => ValidMembershipApplication::PAYMENT_BANK_NAME,
89
			'iban' => ValidMembershipApplication::PAYMENT_IBAN,
90
			'bic' => ValidMembershipApplication::PAYMENT_BIC,
91
			'account_number' => ValidMembershipApplication::PAYMENT_BANK_ACCOUNT,
92
			'bank_code' => ValidMembershipApplication::PAYMENT_BANK_CODE,
93
94
			'templateCampaign' => ValidMembershipApplication::TEMPLATE_CAMPAIGN,
95
			'templateName' => ValidMembershipApplication::TEMPLATE_NAME,
96
		];
97
	}
98
99
	public function testGivenRequestWithInsufficientAmount_failureResponseIsReturned(): void {
100
		$client = $this->createClient();
101
102
		$httpParameters = $this->newValidHttpParameters();
103
		$httpParameters['membership_fee'] = '1.00'; // TODO: change to localized
104
105
		$client->request( 'POST', 'apply-for-membership', $httpParameters );
106
107
		$this->assertInitialFormValues(
108
			[
109
				'addressType' => 'person',
110
				'salutation' => 'Herr',
111
				'title' => '',
112
				'firstName' => 'Potato',
113
				'lastName' => 'The Great',
114
				'companyName' => '',
115
				'street' => 'Nyan street',
116
				'postcode' => '1234',
117
				'city' => 'Berlin',
118
				'country' => 'DE',
119
				'email' => '[email protected]',
120
				'iban' => 'DE12500105170648489890',
121
				'bic' => 'INGDDEFFXXX',
122
				'accountNumber' => '0648489890',
123
				'bankCode' => '50010517',
124
				'bankname' => 'ING-DiBa',
125
				'paymentType' => 'BEZ'
126
			],
127
			$client
128
		);
129
	}
130
131
	public function testFlagForShowingMembershipTypeOptionGetsPassedAround(): void {
132
		$client = $this->createClient();
133
134
		$httpParameters = $this->newValidHttpParameters();
135
		$httpParameters['membership_fee'] = '0';
136
		$httpParameters['showMembershipTypeOption'] = 'true';
137
138
		$crawler = $client->request(
139
			'POST',
140
			'apply-for-membership',
141
			$httpParameters
142
		);
143
144
		$this->assertCount(
145
			1,
146
			$crawler->filter( 'input[type="hidden"][name="showMembershipTypeOption"][value="true"]' )
147
		);
148
	}
149
150
	public function testGivenValidRequest_applicationIsPersisted(): void {
151
		$this->createEnvironment( [], function ( Client $client, FunFunFactory $factory ): void {
152
			$factory->setPaymentDelayCalculator( $this->newFixedPaymentDelayCalculator() );
153
154
			$client->request(
155
				'POST',
156
				'apply-for-membership',
157
				$this->newValidHttpParameters()
158
			);
159
160
			$application = $factory->getMembershipApplicationRepository()->getApplicationById( 1 );
161
162
			$this->assertNotNull( $application );
163
164
			$expectedApplication = ValidMembershipApplication::newAutoConfirmedDomainEntity();
165
			$expectedApplication->assignId( 1 );
166
167
			$this->assertEquals( $expectedApplication, $application );
168
		} );
169
	}
170
171
	public function testGivenValidRequest_confirmationPageContainsCancellationParameters(): void {
172
		$this->createEnvironment( [], function ( Client $client, FunFunFactory $factory ): void {
173
			$factory->setTokenGenerator( new FixedTokenGenerator( self::FIXED_TOKEN ) );
174
175
			$client->request(
176
				'POST',
177
				'apply-for-membership',
178
				$this->newValidHttpParameters()
179
			);
180
181
			$responseContent = $client->getResponse()->getContent();
182
183
			$this->assertContains( 'id=1', $responseContent );
184
			$this->assertContains( 'accessToken=' . self::FIXED_TOKEN, $responseContent );
185
		} );
186
	}
187
188
	public function testGivenValidRequest_requestIsRedirected(): void {
189
		$client = $this->createClient();
190
		$client->followRedirects( false );
191
192
		$client->request(
193
			'POST',
194
			'apply-for-membership',
195
			$this->newValidHttpParameters()
196
		);
197
198
		$response = $client->getResponse();
199
		$this->assertTrue( $response->isRedirect() );
200
		$this->assertContains( 'show-membership-confirmation', $response->headers->get( 'Location' ) );
201
	}
202
203
	public function testWhenApplicationGetsPersisted_timestampIsStoredInCookie(): void {
204
		$client = $this->createClient();
205
		$client->request(
206
			'POST',
207
			'/apply-for-membership',
208
			$this->newValidHttpParameters()
209
		);
210
211
		$cookie = $client->getCookieJar()->get( 'memapp_timestamp' );
212
		$this->assertNotNull( $cookie );
213
		$donationTimestamp = new \DateTime( $cookie->getValue() );
214
		$this->assertEquals( time(), $donationTimestamp->getTimestamp(), 'Timestamp should be not more than 5 seconds old', 5.0 );
215
	}
216
217
	public function testWhenMultipleMembershipFormSubmissions_requestGetsRejected(): void {
218
		$client = $this->createClient();
219
		$client->getCookieJar()->set( new Cookie( 'memapp_timestamp', $this->getPastTimestamp() ) );
220
221
		$client->request(
222
			'POST',
223
			'/apply-for-membership',
224
			$this->newValidHttpParameters()
225
		);
226
227
		$this->assertContains( 'membership_application_rejected_limit', $client->getResponse()->getContent() );
228
	}
229
230
	public function testWhenMultipleMembershipInAccordanceToTimeLimit_isNotRejected(): void {
231
		$client = $this->createClient();
232
		$client->getCookieJar()->set( new Cookie( 'memapp_timestamp', $this->getPastTimestamp( 'PT12M' ) ) );
233
234
		$client->request(
235
			'POST',
236
			'/apply-for-membership',
237
			$this->newValidHttpParameters()
238
		);
239
240
		$this->assertNotContains( 'membership_application_rejected_limit', $client->getResponse()->getContent() );
241
	}
242
243
	private function getPastTimestamp( string $interval = 'PT10S' ): string {
244
		return ( new \DateTime() )->sub( new \DateInterval( $interval ) )->format( 'Y-m-d H:i:s' );
245
	}
246
247
	public function testWhenTrackingCookieExists_valueIsPersisted(): void {
248
		$this->createEnvironment( [], function ( Client $client, FunFunFactory $factory ): void {
249
			$client->getCookieJar()->set( new Cookie( 'spenden_tracking', 'test/blue' ) );
250
251
			$client->request(
252
				'POST',
253
				'/apply-for-membership',
254
				$this->newValidHttpParameters()
255
			);
256
257
			$application = $this->getApplicationFromDatabase( $factory );
258
			$this->assertSame( 'test/blue', $application->getTracking() );
259
		} );
260
	}
261
262
	private function getApplicationFromDatabase( FunFunFactory $factory ): MembershipApplication {
263
		$repository = $factory->getEntityManager()->getRepository( MembershipApplication::class );
264
		$application = $repository->find( 1 );
265
		$this->assertInstanceOf( MembershipApplication::class, $application );
266
		return $application;
267
	}
268
269
	public function testGivenValidRequestUsingPayPal_applicationIsPersisted(): void {
270
		$this->createEnvironment( [], function ( Client $client, FunFunFactory $factory ): void {
271
			$factory->setPaymentDelayCalculator( $this->newFixedPaymentDelayCalculator() );
272
273
			$client->request(
274
				'POST',
275
				'apply-for-membership',
276
				$this->newValidHttpParametersUsingPayPal()
277
			);
278
279
			$application = $factory->getMembershipApplicationRepository()->getApplicationById( 1 );
280
281
			$this->assertNotNull( $application );
282
283
			$payPalData = new PayPalData();
284
			$payPalData->setFirstPaymentDate( self::FIRST_PAYMENT_DATE );
285
			$payPalData->freeze();
286
287
			$expectedApplication = ValidMembershipApplication::newDomainEntityUsingPayPal( $payPalData );
288
			$expectedApplication->assignId( 1 );
289
290
			$this->assertEquals( $expectedApplication, $application );
291
		} );
292
	}
293
294
	private function newValidHttpParametersUsingPayPal(): array {
295
		return [
296
			'membership_type' => ValidMembershipApplication::MEMBERSHIP_TYPE,
297
298
			'adresstyp' => 'person',
299
			'anrede' => ValidMembershipApplication::APPLICANT_SALUTATION,
300
			'titel' => ValidMembershipApplication::APPLICANT_TITLE,
301
			'vorname' => ValidMembershipApplication::APPLICANT_FIRST_NAME,
302
			'nachname' => ValidMembershipApplication::APPLICANT_LAST_NAME,
303
			'firma' => '',
304
305
			'strasse' => ValidMembershipApplication::APPLICANT_STREET_ADDRESS,
306
			'postcode' => ValidMembershipApplication::APPLICANT_POSTAL_CODE,
307
			'ort' => ValidMembershipApplication::APPLICANT_CITY,
308
			'country' => ValidMembershipApplication::APPLICANT_COUNTRY_CODE,
309
310
			'email' => ValidMembershipApplication::APPLICANT_EMAIL_ADDRESS,
311
			'phone' => ValidMembershipApplication::APPLICANT_PHONE_NUMBER,
312
			'dob' => ValidMembershipApplication::APPLICANT_DATE_OF_BIRTH,
313
314
			'payment_type' => (string)ValidMembershipApplication::PAYMENT_TYPE_PAYPAL,
315
			'membership_fee_interval' => (string)ValidMembershipApplication::PAYMENT_PERIOD_IN_MONTHS,
316
			'membership_fee' => (string)ValidMembershipApplication::PAYMENT_AMOUNT_IN_EURO, // TODO: change to localized
317
318
			'templateCampaign' => ValidMembershipApplication::TEMPLATE_CAMPAIGN,
319
			'templateName' => ValidMembershipApplication::TEMPLATE_NAME,
320
		];
321
	}
322
323
	public function testGivenValidRequestUsingPayPal_requestIsRedirectedToPayPalUrl(): void {
324
		$client = $this->createClient();
325
		$client->followRedirects( false );
326
327
		$client->request(
328
			'POST',
329
			'apply-for-membership',
330
			$this->newValidHttpParametersUsingPayPal()
331
		);
332
333
		$response = $client->getResponse();
334
		$this->assertTrue( $response->isRedirect() );
335
		$this->assertContains( 'sandbox.paypal.com', $response->headers->get( 'Location' ) );
336
	}
337
338
	public function testWhenRedirectingToPayPal_translatedItemNameIsPassed(): void {
339
		$client = $this->createClient();
340
		$client->followRedirects( false );
341
342
		$client->request(
343
			'POST',
344
			'/apply-for-membership',
345
			$this->newValidHttpParametersUsingPayPal()
346
		);
347
348
		$response = $client->getResponse();
349
		$this->assertSame( 302, $response->getStatusCode() );
350
		$this->assertContains( 'item_name=item_name_membership', $response->getContent() );
351
	}
352
353
	public function testCommasInStreetNamesAreRemoved(): void {
354
		$this->createEnvironment( [], function ( Client $client, FunFunFactory $factory ): void {
355
356
			$params = $this->newValidHttpParameters();
357
			$params['strasse'] = 'Nyan, street, ';
358
			$client->request(
359
				'POST',
360
				'apply-for-membership',
361
				$params
362
			);
363
364
			$application = $factory->getMembershipApplicationRepository()->getApplicationById( 1 );
365
366
			$this->assertNotNull( $application );
367
368
			$expectedApplication = ValidMembershipApplication::newDomainEntity();
369
			$expectedApplication->assignId( 1 );
370
			$expectedApplication->confirm();
371
372
			$this->assertEquals( $expectedApplication, $application );
373
		} );
374
	}
375
376
	public function testWhenCompaniesApply_salutationIsSetToFixedValue(): void {
377
		$this->createEnvironment( [], function ( Client $client, FunFunFactory $factory ): void {
378
379
			$params = $this->newValidHttpParametersForCompanies();
380
			$client->request(
381
				'POST',
382
				'apply-for-membership',
383
				$params
384
			);
385
386
			$application = $factory->getMembershipApplicationRepository()->getApplicationById( 1 );
387
388
			$this->assertNotNull( $application );
389
390
			$expectedApplication = ValidMembershipApplication::newCompanyApplication();
391
			$expectedApplication->assignId( 1 );
392
			$expectedApplication->confirm();
393
394
			$this->assertEquals( $expectedApplication, $application );
395
		} );
396
	}
397
398
	private function newValidHttpParametersForCompanies(): array {
399
		return [
400
			'membership_type' => ValidMembershipApplication::MEMBERSHIP_TYPE,
401
402
			'adresstyp' => 'firma',
403
			'firma' => ValidMembershipApplication::APPLICANT_COMPANY_NAME,
404
405
			'strasse' => ValidMembershipApplication::APPLICANT_STREET_ADDRESS,
406
			'postcode' => ValidMembershipApplication::APPLICANT_POSTAL_CODE,
407
			'ort' => ValidMembershipApplication::APPLICANT_CITY,
408
			'country' => ValidMembershipApplication::APPLICANT_COUNTRY_CODE,
409
410
			'email' => ValidMembershipApplication::APPLICANT_EMAIL_ADDRESS,
411
			'phone' => ValidMembershipApplication::APPLICANT_PHONE_NUMBER,
412
			'dob' => ValidMembershipApplication::APPLICANT_DATE_OF_BIRTH,
413
414
			'payment_type' => (string)ValidMembershipApplication::PAYMENT_TYPE_DIRECT_DEBIT,
415
			'membership_fee_interval' => (string)ValidMembershipApplication::PAYMENT_PERIOD_IN_MONTHS,
416
			'membership_fee' => (string)ValidMembershipApplication::COMPANY_PAYMENT_AMOUNT_IN_EURO, // TODO: change to localized
417
418
			'bank_name' => ValidMembershipApplication::PAYMENT_BANK_NAME,
419
			'iban' => ValidMembershipApplication::PAYMENT_IBAN,
420
			'bic' => ValidMembershipApplication::PAYMENT_BIC,
421
			'account_number' => ValidMembershipApplication::PAYMENT_BANK_ACCOUNT,
422
			'bank_code' => ValidMembershipApplication::PAYMENT_BANK_CODE,
423
		];
424
	}
425
426
	private function newFixedPaymentDelayCalculator(): PaymentDelayCalculator {
427
		return new FixedPaymentDelayCalculator(
428
			new \DateTime( self::FIRST_PAYMENT_DATE )
429
		);
430
	}
431
432
	public function testCookieFlagsSecureAndHttpOnlyAreSet(): void {
433
		$client = new Client(
434
			$this->createSilexApplication(),
435
			[ 'HTTPS' => true ]
436
		);
437
438
		$client->request(
439
			'POST',
440
			'apply-for-membership',
441
			$this->newValidHttpParameters()
442
		);
443
444
		$cookieJar = $client->getCookieJar();
445
		$cookieJar->updateFromResponse( $client->getInternalResponse() );
0 ignored issues
show
Bug introduced by
It seems like $client->getInternalResponse() can be null; however, updateFromResponse() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
446
		$cookie = $cookieJar->get( ShowMembershipConfirmationHandler::SUBMISSION_COOKIE_NAME );
447
448
		$this->assertTrue( $cookie->isHttpOnly() );
449
		$this->assertTrue( $cookie->isSecure() );
450
	}
451
452
	public function testGivenDonationReceiptOptOutRequest_applicationHoldsThisValue(): void {
453
		$this->createEnvironment( [], function ( Client $client, FunFunFactory $factory ): void {
454
			$parameters = $this->newValidHttpParameters();
455
			$parameters['donationReceipt'] = '0';
456
457
			$client->request( Request::METHOD_POST, self::APPLY_FOR_MEMBERSHIP_PATH, $parameters );
458
459
			$this->assertFalse( $factory->getMembershipApplicationRepository()->getApplicationById( 1 )->getDonationReceipt() );
460
		} );
461
	}
462
}
463