Skip to content

Commit 03c67f5

Browse files
committed
add unit test for rest api
1 parent 770d9a7 commit 03c67f5

File tree

1 file changed

+328
-0
lines changed

1 file changed

+328
-0
lines changed

tests/test-rest-api-snippets.php

Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
<?php
2+
3+
namespace Code_Snippets\Tests;
4+
5+
use Code_Snippets\Snippet;
6+
use WP_REST_Request;
7+
use function Code_Snippets\code_snippets;
8+
use function Code_Snippets\save_snippet;
9+
use function Code_Snippets\delete_snippet;
10+
11+
/**
12+
* Tests for the Snippets REST API endpoint.
13+
*
14+
* @group rest-api
15+
*/
16+
class REST_API_Snippets_Test extends TestCase {
17+
18+
/**
19+
* Array of created snippet IDs for cleanup.
20+
*
21+
* @var int[]
22+
*/
23+
protected $created_snippet_ids = [];
24+
25+
/**
26+
* REST API namespace and base route.
27+
*
28+
* @var string
29+
*/
30+
protected $namespace = 'code-snippets/v1';
31+
protected $base_route = 'snippets';
32+
33+
/**
34+
* Administrator user ID.
35+
*
36+
* @var int
37+
*/
38+
protected static $admin_user_id;
39+
40+
/**
41+
* Set up fixtures before any tests run.
42+
*
43+
* @param mixed $factory Factory object.
44+
*/
45+
public static function wpSetUpBeforeClass( $factory ) {
46+
self::$admin_user_id = $factory->user->create( [
47+
'role' => 'administrator',
48+
] );
49+
}
50+
51+
/**
52+
* Set up before each test.
53+
*/
54+
public function set_up() {
55+
parent::set_up();
56+
57+
// Set current user as admin for REST API permissions.
58+
wp_set_current_user( self::$admin_user_id );
59+
60+
// Clear all existing snippets first for clean testing environment.
61+
$this->clear_all_snippets();
62+
63+
// Seed 25 test snippets.
64+
$this->seed_test_snippets( 25 );
65+
}
66+
67+
/**
68+
* Clean up after each test.
69+
*/
70+
public function tear_down() {
71+
// Delete all created snippets.
72+
foreach ( $this->created_snippet_ids as $snippet_id ) {
73+
delete_snippet( $snippet_id );
74+
}
75+
$this->created_snippet_ids = [];
76+
77+
parent::tear_down();
78+
}
79+
80+
/**
81+
* Clear all snippets from the database.
82+
*/
83+
protected function clear_all_snippets() {
84+
global $wpdb;
85+
$table_name = code_snippets()->db->get_table_name();
86+
$wpdb->query( "TRUNCATE TABLE {$table_name}" );
87+
}
88+
89+
/**
90+
* Helper method to seed test snippets into the database.
91+
*
92+
* @param int $count Number of snippets to create.
93+
*/
94+
protected function seed_test_snippets( $count = 25 ) {
95+
for ( $i = 1; $i <= $count; $i++ ) {
96+
$snippet = new Snippet( [
97+
'name' => "Test Snippet {$i}",
98+
'desc' => "This is test snippet number {$i}",
99+
'code' => "// Test snippet {$i}\necho 'Hello World {$i}';",
100+
'scope' => 'global',
101+
'active' => false,
102+
'tags' => [ 'test', "batch-{$i}" ],
103+
] );
104+
105+
$saved_snippet = save_snippet( $snippet );
106+
107+
if ( $saved_snippet && $saved_snippet->id ) {
108+
$this->created_snippet_ids[] = $saved_snippet->id;
109+
}
110+
}
111+
}
112+
113+
/**
114+
* Helper method to make a REST API request.
115+
*
116+
* @param string $endpoint Endpoint to request.
117+
* @param array $params Query parameters.
118+
* @return WP_REST_Response
119+
*/
120+
protected function make_request( $endpoint, $params = [] ) {
121+
$request = new WP_REST_Request( 'GET', $endpoint );
122+
123+
foreach ( $params as $key => $value ) {
124+
$request->set_param( $key, $value );
125+
}
126+
127+
$response = rest_do_request( $request );
128+
return rest_get_server()->response_to_data( $response, false );
129+
}
130+
131+
/**
132+
* Test that we can retrieve all snippets without pagination.
133+
*/
134+
public function test_get_all_snippets_without_pagination() {
135+
$endpoint = "/{$this->namespace}/{$this->base_route}";
136+
$response = $this->make_request( $endpoint, [ 'network' => false ] );
137+
138+
// Should return all 25 snippets.
139+
$this->assertIsArray( $response );
140+
$this->assertCount( 25, $response, 'Should return all 25 snippets when no pagination params are provided' );
141+
142+
// Verify first snippet structure.
143+
$this->assertArrayHasKey( 'id', $response[0] );
144+
$this->assertArrayHasKey( 'name', $response[0] );
145+
$this->assertArrayHasKey( 'code', $response[0] );
146+
}
147+
148+
/**
149+
* Test pagination with per_page parameter only (first page).
150+
*/
151+
public function test_get_snippets_with_per_page() {
152+
$endpoint = "/{$this->namespace}/{$this->base_route}";
153+
$response = $this->make_request( $endpoint, [
154+
'network' => false,
155+
'per_page' => 2,
156+
] );
157+
158+
// Should return only 2 snippets (first page).
159+
$this->assertIsArray( $response );
160+
$this->assertCount( 2, $response, 'Should return exactly 2 snippets when per_page=2' );
161+
162+
// Verify we got the first 2 snippets.
163+
$this->assertStringContainsString( 'Test Snippet 1', $response[0]['name'] );
164+
$this->assertStringContainsString( 'Test Snippet 2', $response[1]['name'] );
165+
}
166+
167+
/**
168+
* Test pagination with per_page and page parameters.
169+
*/
170+
public function test_get_snippets_with_per_page_and_page() {
171+
$endpoint = "/{$this->namespace}/{$this->base_route}";
172+
$response = $this->make_request( $endpoint, [
173+
'network' => false,
174+
'per_page' => 2,
175+
'page' => 3,
176+
] );
177+
178+
// Should return 2 snippets from page 3.
179+
// Page 1: snippets 1-2, Page 2: snippets 3-4, Page 3: snippets 5-6.
180+
$this->assertIsArray( $response );
181+
$this->assertCount( 2, $response, 'Should return exactly 2 snippets for page 3 with per_page=2' );
182+
183+
// Verify we got snippets 5 and 6.
184+
$this->assertStringContainsString( 'Test Snippet 5', $response[0]['name'] );
185+
$this->assertStringContainsString( 'Test Snippet 6', $response[1]['name'] );
186+
}
187+
188+
/**
189+
* Test pagination with page parameter only (should use default per_page).
190+
*/
191+
public function test_get_snippets_with_page_only() {
192+
$endpoint = "/{$this->namespace}/{$this->base_route}";
193+
194+
// First, let's get page 1 to see the default per_page behavior.
195+
$page_1_response = $this->make_request( $endpoint, [
196+
'network' => false,
197+
'page' => 1,
198+
] );
199+
200+
// WordPress REST API default per_page is typically 10.
201+
$this->assertIsArray( $page_1_response );
202+
$this->assertGreaterThan( 0, count( $page_1_response ), 'Page 1 should have snippets' );
203+
204+
// Now get page 2.
205+
$page_2_response = $this->make_request( $endpoint, [
206+
'network' => false,
207+
'page' => 2,
208+
] );
209+
210+
$this->assertIsArray( $page_2_response );
211+
212+
// With 25 snippets and default per_page of 10, page 2 should have 10 snippets.
213+
$this->assertCount( 10, $page_2_response, 'Page 2 with default per_page should have 10 snippets' );
214+
}
215+
216+
/**
217+
* Test that headers contain correct pagination metadata.
218+
*/
219+
public function test_pagination_headers() {
220+
$endpoint = "/{$this->namespace}/{$this->base_route}";
221+
$request = new WP_REST_Request( 'GET', $endpoint );
222+
$request->set_param( 'network', false );
223+
$request->set_param( 'per_page', 5 );
224+
$request->set_param( 'page', 1 );
225+
226+
$response = rest_do_request( $request );
227+
228+
// Check headers.
229+
$headers = $response->get_headers();
230+
231+
$this->assertEquals( 25, $headers['X-WP-Total'], 'X-WP-Total header should show 25 total snippets' );
232+
$this->assertEquals( 5, $headers['X-WP-TotalPages'], 'X-WP-TotalPages should be 5 (25 snippets / 5 per_page)' );
233+
}
234+
235+
/**
236+
* Test that last page returns correct number of snippets.
237+
*/
238+
public function test_last_page_with_partial_results() {
239+
$endpoint = "/{$this->namespace}/{$this->base_route}";
240+
241+
// With 25 snippets and per_page=10, page 3 should have 5 snippets.
242+
$response = $this->make_request( $endpoint, [
243+
'network' => false,
244+
'per_page' => 10,
245+
'page' => 3,
246+
] );
247+
248+
$this->assertIsArray( $response );
249+
$this->assertCount( 5, $response, 'Last page should have only 5 remaining snippets (25 % 10)' );
250+
}
251+
252+
/**
253+
* Test that requesting a page beyond available pages returns empty array.
254+
*/
255+
public function test_page_beyond_available_returns_empty() {
256+
$endpoint = "/{$this->namespace}/{$this->base_route}";
257+
258+
// Request page 100 (way beyond our 25 snippets).
259+
$response = $this->make_request( $endpoint, [
260+
'network' => false,
261+
'per_page' => 10,
262+
'page' => 100,
263+
] );
264+
265+
$this->assertIsArray( $response );
266+
$this->assertCount( 0, $response, 'Requesting page beyond available should return empty array' );
267+
}
268+
269+
/**
270+
* Test per_page with value of 1.
271+
*/
272+
public function test_per_page_one() {
273+
$endpoint = "/{$this->namespace}/{$this->base_route}";
274+
$response = $this->make_request( $endpoint, [
275+
'network' => false,
276+
'per_page' => 1,
277+
'page' => 5,
278+
] );
279+
280+
$this->assertIsArray( $response );
281+
$this->assertCount( 1, $response, 'Should return exactly 1 snippet when per_page=1' );
282+
$this->assertStringContainsString( 'Test Snippet 5', $response[0]['name'] );
283+
}
284+
285+
/**
286+
* Test that per_page larger than total returns all snippets.
287+
*/
288+
public function test_per_page_larger_than_total() {
289+
$endpoint = "/{$this->namespace}/{$this->base_route}";
290+
$response = $this->make_request( $endpoint, [
291+
'network' => false,
292+
'per_page' => 100,
293+
'page' => 1,
294+
] );
295+
296+
$this->assertIsArray( $response );
297+
$this->assertCount( 25, $response, 'Should return all 25 snippets when per_page exceeds total' );
298+
}
299+
300+
/**
301+
* Test that snippet data structure is correct.
302+
*/
303+
public function test_snippet_data_structure() {
304+
$endpoint = "/{$this->namespace}/{$this->base_route}";
305+
$response = $this->make_request( $endpoint, [
306+
'network' => false,
307+
'per_page' => 1,
308+
] );
309+
310+
$this->assertIsArray( $response );
311+
$this->assertCount( 1, $response );
312+
313+
$snippet = $response[0];
314+
315+
// Check required fields exist.
316+
$required_fields = [ 'id', 'name', 'desc', 'code', 'scope', 'active', 'tags' ];
317+
foreach ( $required_fields as $field ) {
318+
$this->assertArrayHasKey( $field, $snippet, "Snippet should have '{$field}' field" );
319+
}
320+
321+
// Verify field types.
322+
$this->assertIsInt( $snippet['id'] );
323+
$this->assertIsString( $snippet['name'] );
324+
$this->assertIsString( $snippet['code'] );
325+
$this->assertIsBool( $snippet['active'] );
326+
$this->assertIsArray( $snippet['tags'] );
327+
}
328+
}

0 commit comments

Comments
 (0)