PluginProbe
Extendify / 3.1.0
Extendify v3.1.0
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / tests / Integration / QuickEdit / Controllers / WPFormsControllerTest.php

WPFormsControllerTest.php in Extendify 3.1.0, at tests/Integration/QuickEdit/Controllers/WPFormsControllerTest.php

346 lines 12.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Extendify\Tests\Integration\QuickEdit\Controllers;
4
5 use Extendify\QuickEdit\Controllers\WPFormsController;
6 use WP_UnitTestCase;
7
8 class WPFormsControllerTest extends WP_UnitTestCase
9 {
10 public function setUp(): void
11 {
12 parent::setUp();
13 if (!defined('EXTENDIFY_REQUIRED_CAPABILITY')) {
14 define('EXTENDIFY_REQUIRED_CAPABILITY', 'manage_options');
15 }
16 // Mirror WPForms' production CPT registration (class-form.php) so
17 // any code that checks edit_post against a wpforms post fails here
18 // exactly the way it fails on a real site — map_meta_cap=false means
19 // edit_post resolves to the primitive cap edit_wpforms_form, which
20 // admins don't hold via core. A bare register_post_type('wpforms')
21 // silently grants admins edit_post and hides the regression.
22 register_post_type('wpforms', [
23 'capability_type' => 'wpforms_form',
24 'map_meta_cap' => false,
25 'supports' => ['title', 'author', 'revisions'],
26 ]);
27 $this->loginAsAdmin();
28 }
29
30 public function test_permission_callback_requires_admin_capability()
31 {
32 wp_set_current_user(0);
33 $this->assertFalse(WPFormsController::permissionCallback());
34
35 $sub = self::factory()->user->create(['role' => 'subscriber']);
36 wp_set_current_user($sub);
37 $this->assertFalse(WPFormsController::permissionCallback());
38
39 $editor = self::factory()->user->create(['role' => 'editor']);
40 wp_set_current_user($editor);
41 $this->assertFalse(WPFormsController::permissionCallback());
42
43 $admin = self::factory()->user->create(['role' => 'administrator']);
44 wp_set_current_user($admin);
45 $this->assertTrue(WPFormsController::permissionCallback());
46 }
47
48 public function test_get_without_form_id_returns_400()
49 {
50 $res = WPFormsController::handleGet($this->getRequest([]));
51 $this->assertSame(400, $res->get_status());
52 $this->assertSame('form_id + field_id required', $res->get_data()['error']);
53 }
54
55 public function test_get_with_missing_field_id_returns_400()
56 {
57 $res = WPFormsController::handleGet($this->getRequest(['form_id' => 1]));
58 $this->assertSame(400, $res->get_status());
59 }
60
61 public function test_get_with_non_wpforms_post_returns_404()
62 {
63 $postId = self::factory()->post->create();
64
65 $res = WPFormsController::handleGet($this->getRequest([
66 'form_id' => $postId,
67 'field_id' => 1,
68 ]));
69
70 $this->assertSame(404, $res->get_status());
71 $this->assertSame('wpforms form not found', $res->get_data()['error']);
72 }
73
74 public function test_get_with_unparseable_form_json_returns_404()
75 {
76 $formId = $this->createForm('not valid json');
77
78 $res = WPFormsController::handleGet($this->getRequest([
79 'form_id' => $formId,
80 'field_id' => 1,
81 ]));
82
83 $this->assertSame(404, $res->get_status());
84 $this->assertSame('wpforms form content is not valid JSON', $res->get_data()['error']);
85 }
86
87 public function test_get_missing_field_returns_404()
88 {
89 $formId = $this->createForm(wp_json_encode(['fields' => []]));
90
91 $res = WPFormsController::handleGet($this->getRequest([
92 'form_id' => $formId,
93 'field_id' => 7,
94 ]));
95
96 $this->assertSame(404, $res->get_status());
97 $this->assertSame('field not found', $res->get_data()['error']);
98 }
99
100 public function test_get_returns_four_editable_props_for_a_field()
101 {
102 $formId = $this->createForm(wp_json_encode([
103 'fields' => [
104 3 => [
105 'id' => 3,
106 'type' => 'text',
107 'label' => 'Your Name',
108 'placeholder' => 'Enter name',
109 'description' => 'Required field',
110 'required' => '1',
111 // Extra props must be ignored by GET.
112 'choices' => [['label' => 'a']],
113 'conditional_logic' => ['x' => 'y'],
114 'default_value' => 'foo',
115 ],
116 ],
117 ]));
118
119 $res = WPFormsController::handleGet($this->getRequest([
120 'form_id' => $formId,
121 'field_id' => 3,
122 ]));
123
124 $this->assertSame(200, $res->get_status());
125 $data = $res->get_data();
126 $this->assertSame([
127 'id', 'type', 'label', 'placeholder', 'required', 'description',
128 ], array_keys($data));
129 $this->assertSame(3, $data['id']);
130 $this->assertSame('text', $data['type']);
131 $this->assertSame('Your Name', $data['label']);
132 $this->assertSame('Enter name', $data['placeholder']);
133 $this->assertTrue($data['required']);
134 $this->assertSame('Required field', $data['description']);
135 }
136
137 public function test_get_decodes_required_truthy_strings_and_falsy()
138 {
139 $formId = $this->createForm(wp_json_encode([
140 'fields' => [
141 1 => ['id' => 1, 'required' => ''],
142 2 => ['id' => 2, 'required' => 'yes'],
143 3 => ['id' => 3, 'required' => true],
144 ],
145 ]));
146
147 $this->assertFalse($this->getField($formId, 1)->get_data()['required']);
148 $this->assertTrue($this->getField($formId, 2)->get_data()['required']);
149 $this->assertTrue($this->getField($formId, 3)->get_data()['required']);
150 }
151
152 public function test_post_requires_form_id_field_id_and_changes()
153 {
154 $res = WPFormsController::handlePost($this->postRequest([
155 'form_id' => 1,
156 'field_id' => 1,
157 ]));
158
159 $this->assertSame(400, $res->get_status());
160 $this->assertSame('form_id, field_id, changes required', $res->get_data()['error']);
161 }
162
163 public function test_post_updates_label_placeholder_description_required()
164 {
165 $formId = $this->createForm(wp_json_encode([
166 'fields' => [
167 5 => [
168 'id' => 5,
169 'type' => 'text',
170 'label' => 'Old',
171 'placeholder' => 'old',
172 'description' => 'old',
173 'required' => '',
174 ],
175 ],
176 ]));
177
178 $res = WPFormsController::handlePost($this->postRequest([
179 'form_id' => $formId,
180 'field_id' => 5,
181 'changes' => [
182 'label' => 'New Label',
183 'placeholder' => 'new',
184 'description' => '<strong>desc</strong>',
185 'required' => true,
186 ],
187 ]));
188
189 $this->assertSame(200, $res->get_status());
190 $field = $this->reloadField($formId, 5);
191 $this->assertSame('New Label', $field['label']);
192 $this->assertSame('new', $field['placeholder']);
193 $this->assertSame('<strong>desc</strong>', $field['description']);
194 // existing required was a string ⇒ preserve string shape.
195 $this->assertSame('1', $field['required']);
196 }
197
198 public function test_post_required_preserves_bool_shape_when_existing_was_bool()
199 {
200 $formId = $this->createForm(wp_json_encode([
201 'fields' => [1 => ['id' => 1, 'required' => false]],
202 ]));
203
204 WPFormsController::handlePost($this->postRequest([
205 'form_id' => $formId,
206 'field_id' => 1,
207 'changes' => ['required' => '1'],
208 ]));
209
210 $this->assertSame(true, $this->reloadField($formId, 1)['required']);
211 }
212
213 public function test_post_does_not_drop_choices_validation_conditional_logic_defaults()
214 {
215 $formId = $this->createForm(wp_json_encode([
216 'fields' => [
217 2 => [
218 'id' => 2,
219 'type' => 'select',
220 'label' => 'Pick',
221 'choices' => [['label' => 'A'], ['label' => 'B']],
222 'conditional_logic' => ['enabled' => true],
223 'default_value' => 'A',
224 'validation' => ['min' => 1],
225 ],
226 ],
227 ]));
228
229 WPFormsController::handlePost($this->postRequest([
230 'form_id' => $formId,
231 'field_id' => 2,
232 'changes' => ['label' => 'Pick One'],
233 ]));
234
235 $field = $this->reloadField($formId, 2);
236 $this->assertSame('Pick One', $field['label']);
237 $this->assertSame([['label' => 'A'], ['label' => 'B']], $field['choices']);
238 $this->assertSame(['enabled' => true], $field['conditional_logic']);
239 $this->assertSame('A', $field['default_value']);
240 $this->assertSame(['min' => 1], $field['validation']);
241 }
242
243 public function test_post_with_unknown_change_keys_silently_drops_them()
244 {
245 $formId = $this->createForm(wp_json_encode([
246 'fields' => [1 => ['id' => 1, 'label' => 'L']],
247 ]));
248
249 $res = WPFormsController::handlePost($this->postRequest([
250 'form_id' => $formId,
251 'field_id' => 1,
252 'changes' => ['bogus' => 'x', 'choices' => [['label' => 'evil']]],
253 ]));
254
255 $this->assertSame(200, $res->get_status());
256 $field = $this->reloadField($formId, 1);
257 $this->assertSame('L', $field['label']);
258 $this->assertArrayNotHasKey('bogus', $field);
259 $this->assertArrayNotHasKey('choices', $field);
260 }
261
262 public function test_post_sanitizes_label_strips_script()
263 {
264 $formId = $this->createForm(wp_json_encode([
265 'fields' => [1 => ['id' => 1, 'label' => '']],
266 ]));
267
268 WPFormsController::handlePost($this->postRequest([
269 'form_id' => $formId,
270 'field_id' => 1,
271 'changes' => ['label' => '<script>x</script>Hi'],
272 ]));
273
274 $this->assertSame('Hi', $this->reloadField($formId, 1)['label']);
275 }
276
277 public function test_post_returns_404_for_unknown_field()
278 {
279 $formId = $this->createForm(wp_json_encode(['fields' => [1 => ['id' => 1]]]));
280
281 $res = WPFormsController::handlePost($this->postRequest([
282 'form_id' => $formId,
283 'field_id' => 999,
284 'changes' => ['label' => 'x'],
285 ]));
286
287 $this->assertSame(404, $res->get_status());
288 }
289
290 public function test_init_hooks_registerRoutes_into_rest_api_init()
291 {
292 remove_all_filters('rest_api_init');
293 WPFormsController::init();
294
295 $this->assertNotFalse(
296 has_action('rest_api_init', [WPFormsController::class, 'registerRoutes'])
297 );
298 }
299
300 private function createForm(string $jsonContent): int
301 {
302 return self::factory()->post->create([
303 'post_type' => 'wpforms',
304 'post_status' => 'publish',
305 'post_content' => wp_slash($jsonContent),
306 ]);
307 }
308
309 private function getField(int $formId, int $fieldId): \WP_REST_Response
310 {
311 return WPFormsController::handleGet($this->getRequest([
312 'form_id' => $formId,
313 'field_id' => $fieldId,
314 ]));
315 }
316
317 private function reloadField(int $formId, int $fieldId): array
318 {
319 $form = json_decode(get_post($formId)->post_content, true);
320 return $form['fields'][$fieldId];
321 }
322
323 private function getRequest(array $params): \WP_REST_Request
324 {
325 $req = new \WP_REST_Request('GET', '/extendify/v1/quick-edit/wpforms');
326 foreach ($params as $k => $v) {
327 $req->set_param($k, $v);
328 }
329 return $req;
330 }
331
332 private function postRequest(array $body): \WP_REST_Request
333 {
334 $req = new \WP_REST_Request('POST', '/extendify/v1/quick-edit/wpforms');
335 $req->set_header('Content-Type', 'application/json');
336 $req->set_body(wp_json_encode($body));
337 return $req;
338 }
339
340 private function loginAsAdmin(): void
341 {
342 $admin = self::factory()->user->create(['role' => 'administrator']);
343 wp_set_current_user($admin);
344 }
345 }
346