1 | <?php |
||
2 | /** |
||
3 | * REST API Endpoint Test base class. |
||
4 | * |
||
5 | * This class can be extended to add test coverage to REST API endpoints. |
||
6 | * |
||
7 | * For each endpoint, please test: |
||
8 | * - Create |
||
9 | * - Read |
||
10 | * - Update |
||
11 | * - Delete |
||
12 | * - How the API responds to logged out/unauthorised users |
||
13 | * - Schema |
||
14 | * - Routes |
||
15 | * - Collection params/queries |
||
16 | * |
||
17 | * @package Automattic/WooCommerce/RestApi/Tests |
||
18 | */ |
||
19 | |||
20 | namespace Automattic\WooCommerce\RestApi\UnitTests; |
||
21 | |||
22 | defined( 'ABSPATH' ) || exit; |
||
23 | |||
24 | use \WC_REST_Unit_Test_Case; |
||
25 | use Automattic\WooCommerce\RestApi\UnitTests\Helpers\CustomerHelper; |
||
26 | use Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper; |
||
27 | use Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper; |
||
28 | |||
29 | /** |
||
30 | * Abstract Rest API Test Class |
||
31 | * |
||
32 | * @extends WC_REST_Unit_Test_Case |
||
33 | */ |
||
34 | abstract class AbstractRestApiTest extends WC_REST_Unit_Test_Case { |
||
35 | |||
36 | /** |
||
37 | * The endpoint schema. |
||
38 | * |
||
39 | * @var array Keys are property names, values are supported context. |
||
40 | */ |
||
41 | protected $properties = []; |
||
42 | |||
43 | /** |
||
44 | * Routes that this endpoint creates. |
||
45 | * |
||
46 | * @var array |
||
47 | */ |
||
48 | protected $routes = []; |
||
49 | |||
50 | /** |
||
51 | * User variable. |
||
52 | * |
||
53 | * @var WP_User |
||
54 | */ |
||
55 | protected static $user; |
||
56 | |||
57 | /** |
||
58 | * Setup once before running tests. |
||
59 | * |
||
60 | * @param object $factory Factory object. |
||
61 | */ |
||
62 | public static function wpSetUpBeforeClass( $factory ) { |
||
63 | self::$user = $factory->user->create( |
||
64 | array( |
||
65 | 'role' => 'administrator', |
||
66 | ) |
||
67 | ); |
||
68 | } |
||
69 | |||
70 | /** |
||
71 | * Setup test class. |
||
72 | */ |
||
73 | public function setUp() { |
||
74 | parent::setUp(); |
||
75 | wp_set_current_user( self::$user ); |
||
76 | } |
||
77 | |||
78 | /** |
||
79 | * Test route registration. |
||
80 | */ |
||
81 | public function test_register_routes() { |
||
82 | $actual_routes = $this->server->get_routes(); |
||
83 | $expected_routes = $this->routes; |
||
84 | |||
85 | foreach ( $expected_routes as $expected_route ) { |
||
86 | $this->assertArrayHasKey( $expected_route, $actual_routes ); |
||
87 | } |
||
88 | } |
||
89 | |||
90 | /** |
||
91 | * Validate that the returned API schema matches what is expected. |
||
92 | * |
||
93 | * @return void |
||
94 | */ |
||
95 | public function test_schema_properties() { |
||
96 | $request = new \WP_REST_Request( 'OPTIONS', $this->routes[0] ); |
||
97 | $response = $this->server->dispatch( $request ); |
||
98 | $data = $response->get_data(); |
||
99 | $properties = $data['schema']['properties']; |
||
100 | |||
101 | $this->assertEquals( count( array_keys( $this->properties ) ), count( $properties ), print_r( array_diff( array_keys( $properties ), array_keys( $this->properties ) ), true ) ); |
||
102 | |||
103 | foreach ( array_keys( $this->properties ) as $property ) { |
||
104 | $this->assertArrayHasKey( $property, $properties ); |
||
105 | } |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * Test creation using this method. |
||
110 | * If read-only, test to confirm this. |
||
111 | */ |
||
112 | abstract public function test_create(); |
||
113 | |||
114 | /** |
||
115 | * Test get/read using this method. |
||
116 | */ |
||
117 | abstract public function test_read(); |
||
118 | |||
119 | /** |
||
120 | * Test updates using this method. |
||
121 | * If read-only, test to confirm this. |
||
122 | */ |
||
123 | abstract public function test_update(); |
||
124 | |||
125 | /** |
||
126 | * Test delete using this method. |
||
127 | * If read-only, test to confirm this. |
||
128 | */ |
||
129 | abstract public function test_delete(); |
||
130 | |||
131 | /** |
||
132 | * Perform a request and return the status and returned data. |
||
133 | * |
||
134 | * @param string $endpoint Endpoint to hit. |
||
135 | * @param string $type Type of request e.g GET or POST. |
||
136 | * @param array $params Request body or query. |
||
137 | * @return object |
||
138 | */ |
||
139 | protected function do_request( $endpoint, $type = 'GET', $params = [] ) { |
||
140 | $request = new \WP_REST_Request( $type, untrailingslashit( $endpoint ) ); |
||
141 | 'GET' === $type ? $request->set_query_params( $params ) : $request->set_body_params( $params ); |
||
142 | $response = $this->server->dispatch( $request ); |
||
143 | |||
144 | return (object) array( |
||
145 | 'status' => $response->get_status(), |
||
146 | 'data' => json_decode( wp_json_encode( $response->get_data() ), true ), |
||
147 | 'raw' => $response->get_data(), |
||
148 | ); |
||
149 | } |
||
150 | |||
151 | /** |
||
152 | * Test the request/response matched the data we sent. |
||
153 | * |
||
154 | * @param array $response Array of response data from do_request above. |
||
155 | * @param int $status_code Expected status code. |
||
156 | * @param array $data Array of expected data. |
||
157 | */ |
||
158 | protected function assertExpectedResponse( $response, $status_code = 200, $data = array() ) { |
||
159 | $this->assertObjectHasAttribute( 'status', $response ); |
||
160 | $this->assertObjectHasAttribute( 'data', $response ); |
||
161 | $this->assertEquals( $status_code, $response->status, print_r( $response->data, true ) ); |
||
162 | |||
163 | if ( $data ) { |
||
0 ignored issues
–
show
|
|||
164 | foreach ( $data as $key => $value ) { |
||
165 | if ( ! isset( $response->data[ $key ] ) ) { |
||
166 | continue; |
||
167 | } |
||
168 | switch ( $key ) { |
||
169 | case 'meta_data': |
||
170 | $this->assertMetaData( $value, $response->data[ $key ] ); |
||
171 | break; |
||
172 | default: |
||
173 | if ( is_array( $value ) ) { |
||
174 | $this->assertArraySubset( $value, $response->data[ $key ], print_r( array( 'key' => $key, 'data' => $response->data ), true ) ); |
||
175 | } else { |
||
176 | $this->assertEquals( $value, $response->data[ $key ], print_r( array( 'key' => $key, 'data' => $response->data ), true ) ); |
||
177 | } |
||
178 | } |
||
179 | } |
||
180 | } |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * Test meta data in a response matches what we expect. |
||
185 | * |
||
186 | * @param array $expected_meta_data Array of data. |
||
187 | * @param array $actual_meta_data Array of data. |
||
188 | */ |
||
189 | protected function assertMetaData( $expected_meta_data, $actual_meta_data ) { |
||
190 | $this->assertTrue( is_array( $actual_meta_data ) ); |
||
191 | $this->assertEquals( count( $expected_meta_data ), count( $actual_meta_data ) ); |
||
192 | |||
193 | foreach ( $actual_meta_data as $key => $meta ) { |
||
194 | $this->assertArrayHasKey( 'id', $meta ); |
||
195 | $this->assertArrayHasKey( 'key', $meta ); |
||
196 | $this->assertArrayHasKey( 'value', $meta ); |
||
197 | $this->assertEquals( $expected_meta_data[ $key ]['key'], $meta['key'] ); |
||
198 | $this->assertEquals( $expected_meta_data[ $key ]['value'], $meta['value'] ); |
||
199 | } |
||
200 | } |
||
201 | |||
202 | /** |
||
203 | * Return array of properties for a given context. |
||
204 | * |
||
205 | * @param string $context Context to use. |
||
206 | * @return array |
||
207 | */ |
||
208 | protected function get_properties( $context = 'edit' ) { |
||
209 | return array_keys( array_filter( $this->properties, function( $contexts ) use( $context ) { |
||
210 | return in_array( $context, $contexts ); |
||
211 | } ) ); |
||
212 | } |
||
213 | } |
||
214 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.