Completed
Push — master ( 216d34...8ed8a3 )
by Radoslav
01:58 queued 22s
created

WC_Stripe_Subscription_Initial_Test::tearDown()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * These tests assert various things about processing an initial payment for a WooCommerce Subscriptions.
4
 *
5
 * The responses from HTTP requests are mocked using the WP filter `pre_http_request`.
6
 *
7
 * There are a few methods that need to be mocked in the class WC_Stripe_Subs_Compat, which is
8
 * why that class is mocked even though the method under test is part of that class.
9
 *
10
 * @package WooCommerce_Stripe/Classes/WC_Stripe_Subscription_Initial_Test
11
 */
12
13
/**
14
 * WC_Stripe_Subscription_Initial_Test
15
 */
16
class WC_Stripe_Subscription_Initial_Test extends WP_UnitTestCase {
17
	/**
18
	 * System under test, and a mock object with some methods mocked for testing
19
	 *
20
	 * @var PHPUnit_Framework_MockObject_MockObject
21
	 */
22
	private $wc_stripe_subs_compat;
23
24
	/**
25
	 * The statement descriptor we'll use in a test.
26
	 *
27
	 * @var string
28
	 */
29
	private $statement_descriptor;
30
31
	/**
32
	 * Sets up things all tests need.
33
	 */
34
	public function setUp() {
35
		parent::setUp();
36
37
		$this->wc_stripe_subs_compat = $this->getMockBuilder( 'WC_Stripe_Subs_Compat' )
38
			->disableOriginalConstructor()
39
			->setMethods( array( 'prepare_source', 'has_subscription' ) )
40
			->getMock();
41
42
		// Mocked in order to get metadata[payment_type] = recurring in the HTTP request.
43
		$this->statement_descriptor = 'This is a statement descriptor.';
44
		update_option(
45
			'woocommerce_stripe_settings',
46
			array(
47
				'statement_descriptor' => $this->statement_descriptor,
48
			)
49
		);
50
	}
51
52
	/**
53
	 * Tears down the stuff we set up.
54
	 */
55
	public function tearDown() {
56
		parent::tearDown();
57
		delete_option( 'woocommerce_stripe_settings' );
58
	}
59
60
	/**
61
	 * Tests whether the initial payment succeeds and includes the `setup_future_usage` parameter.
62
	 *
63
	 * 1. Several things are set up or mocked.
64
	 * 2. A function that will mock an HTTP response for the payment_intents is created.
65
	 * 3. That same function has some assertions about the things we send to the
66
	 * payments_intents endpoint.
67
	 * 4. The function under test - `process_payment` - is called.
68
	 * 5. More assertions are made.
69
	 */
70
	public function test_initial_intent_parameters() {
71
		$initial_order        = WC_Helper_Order::create_order();
72
		$order_id             = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $initial_order->id : $initial_order->get_id();
73
		$stripe_amount        = WC_Stripe_Helper::get_stripe_amount( $initial_order->get_total() );
74
		$currency             = strtolower( WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $initial_order->get_order_currency() : $initial_order->get_currency() );
75
		$customer             = 'cus_123abc';
76
		$source               = 'src_123abc';
77
		$statement_descriptor = WC_Stripe_Helper::clean_statement_descriptor( $this->statement_descriptor );
78
		$intents_api_endpoint = 'https://api.stripe.com/v1/payment_intents';
79
		$urls_used            = array();
80
81
		if ( WC_Stripe_Helper::is_wc_lt( '3.0' ) ) {
82
			$initial_order->payment_method = 'stripe';
83
			update_post_meta( $order_id, '_payment_method', 'stripe' ); // for `wc_get_order()`.
84
		} else {
85
			$initial_order->set_payment_method( 'stripe' );
86
			$initial_order->save();
87
		}
88
89
		// Arrange: Mock prepare_source() so that we have a customer and source.
90
		$this->wc_stripe_subs_compat
91
			->expects( $this->any() )
92
			->method( 'prepare_source' )
93
			->will(
94
				$this->returnValue(
95
					(object) array(
96
						'token_id'      => false,
97
						'customer'      => $customer,
98
						'source'        => $source,
99
						'source_object' => (object) array(),
100
					)
101
				)
102
			);
103
104
		// Emulate a subscription.
105
		$this->wc_stripe_subs_compat
106
			->expects( $this->any() )
107
			->method( 'has_subscription' )
108
			->will( $this->returnValue( true ) );
109
110
		$pre_http_request_response_callback = function( $preempt, $request_args, $url ) use (
111
			$stripe_amount,
112
			$currency,
113
			$customer,
114
			$source,
115
			$intents_api_endpoint,
116
			$statement_descriptor,
117
			$order_id,
118
			&$urls_used
119
		) {
120
			// Add all urls to array so we can later make assertions about which endpoints were used.
121
			array_push( $urls_used, $url );
122
			// Continue without mocking the request if it's not the endpoint we care about.
123
			if ( 0 !== strpos( $url, $intents_api_endpoint ) ) {
124
				return false;
125
			}
126
127
			// Prepare the response early because it is used for confirmations too.
128
			$response = array(
129
				'headers'  => array(),
130
				// Too bad we aren't dynamically setting things 'cus_123abc' when using this file.
131
				'body'     => file_get_contents( 'tests/phpunit/dummy-data/subscription_signup_response_success.json' ),
132
				'response' => array(
133
					'code'    => 200,
134
					'message' => 'OK',
135
				),
136
				'cookies'  => array(),
137
				'filename' => null,
138
			);
139
140
			// Respond with a successfull intent for confirmations.
141
			if ( $url !== $intents_api_endpoint ) {
142
				$response['body'] = str_replace( 'requires_confirmation', 'succeeded', $response['body'] );
143
				return $response;
144
			}
145
146
			// Assert: the request method is POST.
147
			$this->assertArrayHasKey( 'method', $request_args );
148
			$this->assertSame( 'POST', $request_args['method'] );
149
150
			// Assert: the request has a body.
151
			$this->assertArrayHasKey( 'body', $request_args );
152
153
			// Assert: the request body contains these values.
154
			$expected_request_body_values = array(
155
				'source'               => $source,
156
				'amount'               => $stripe_amount,
157
				'currency'             => $currency,
158
				'statement_descriptor' => $statement_descriptor,
159
				'customer'             => $customer,
160
				'setup_future_usage'   => 'off_session',
161
				'payment_method_types' => array( 'card' ),
162
			);
163 View Code Duplication
			foreach ( $expected_request_body_values as $key => $value ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
164
				$this->assertArrayHasKey( $key, $request_args['body'] );
165
				$this->assertSame( $value, $request_args['body'][ $key ] );
166
			}
167
168
			// Assert: the request body contains these keys, without checking for their value.
169
			$expected_request_body_keys = array(
170
				'description',
171
				'capture_method',
172
			);
173
			foreach ( $expected_request_body_keys as $key ) {
174
				$this->assertArrayHasKey( $key, $request_args['body'] );
175
			}
176
177
			// Assert: the body metadata contains the order ID.
178
			$this->assertSame( $order_id, absint( $request_args['body']['metadata']['order_id'] ) );
179
180
			// // Assert: the body metadata has these keys, without checking for their value.
181
			$expected_metadata_keys = array(
182
				'customer_name',
183
				'customer_email',
184
			);
185
			foreach ( $expected_metadata_keys as $key ) {
186
				$this->assertArrayHasKey( $key, $request_args['body']['metadata'] );
187
			}
188
189
			// Return dummy content as the response.
190
			return $response;
191
		};
192
		add_filter( 'pre_http_request', $pre_http_request_response_callback, 10, 3 );
193
194
		// Act: call process_subscription_payment().
195
		// We need to use `wc_stripe_subs_compat` here because we mocked this class earlier.
196
		$result = $this->wc_stripe_subs_compat->process_payment( $order_id );
197
198
		// Assert: nothing was returned.
199
		$this->assertEquals( $result['result'], 'success' );
200
		$this->assertArrayHasKey( 'redirect', $result );
201
202
		$order      = wc_get_order( $order_id );
203
		$order_data = (
204
			WC_Stripe_Helper::is_wc_lt( '3.0' )
205
				? get_post_meta( $order_id, '_stripe_intent_id', true )
206
				: $order->get_meta( '_stripe_intent_id' )
207
		);
208
209
		$this->assertEquals( $order_data, 'pi_123abc' );
210
211
		// Assert: called payment intents.
212
		$this->assertTrue( in_array( $intents_api_endpoint, $urls_used, true ) );
213
214
		// Clean up.
215
		remove_filter( 'pre_http_request', array( $this, 'pre_http_request_response_success' ) );
216
	}
217
}
218