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 / Toolbar / AdminTest.php

AdminTest.php in Extendify 3.1.0, at tests/Integration/Toolbar/AdminTest.php

204 lines 8.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\Toolbar;
4
5 use Extendify\Toolbar\Admin;
6 use Extendify\Toolbar\Frontend;
7 use WP_UnitTestCase;
8
9 /**
10 * Characterizes the user-profile "Toolbar Style" row + persistence
11 * + the print-footer reorder script.
12 *
13 * Findings pinned (versus what someone might assume from product
14 * framing):
15 *
16 * - The Simple/Full radios use the literal user-meta key
17 * `extendify_toolbar_style` (Frontend::STYLE_META). Any rename
18 * breaks compatibility for users who already saved a choice.
19 * - saveProfileRow defaults to 'simple' when no POST value comes
20 * through — not to the Launch-aware default. Once a user posts
21 * their profile, the launchCompleted-driven default is gone for
22 * them forever (the stored 'simple' overrides anything dynamic).
23 * - reorderRow inserts our row AFTER the core
24 * `user-admin-bar-front-wrap` row, not before — the script reads
25 * `anchor.nextSibling` and uses `insertBefore` against it.
26 */
27 class AdminTest extends WP_UnitTestCase
28 {
29 public static function setUpBeforeClass(): void
30 {
31 parent::setUpBeforeClass();
32 if (!defined('EXTENDIFY_REQUIRED_CAPABILITY')) {
33 define('EXTENDIFY_REQUIRED_CAPABILITY', 'manage_options');
34 }
35 }
36
37 public function tearDown(): void
38 {
39 remove_all_actions('personal_options');
40 remove_all_actions('personal_options_update');
41 remove_all_actions('edit_user_profile_update');
42 remove_all_actions('admin_print_footer_scripts-profile.php');
43 remove_all_actions('admin_print_footer_scripts-user-edit.php');
44 parent::tearDown();
45 }
46
47 public function test_constructor_hooks_all_five_actions()
48 {
49 $admin = new Admin();
50
51 $this->assertNotFalse(has_action('personal_options', [$admin, 'renderProfileRow']));
52 $this->assertNotFalse(has_action('personal_options_update', [$admin, 'saveProfileRow']));
53 $this->assertNotFalse(has_action('edit_user_profile_update', [$admin, 'saveProfileRow']));
54 $this->assertNotFalse(has_action('admin_print_footer_scripts-profile.php', [$admin, 'reorderRow']));
55 $this->assertNotFalse(has_action('admin_print_footer_scripts-user-edit.php', [$admin, 'reorderRow']));
56 }
57
58 public function test_render_profile_row_marks_simple_radio_checked_when_user_meta_is_simple()
59 {
60 $userId = self::factory()->user->create(['role' => 'administrator']);
61 update_user_meta($userId, Frontend::STYLE_META, 'simple');
62 $user = get_user_by('id', $userId);
63
64 $html = $this->capture(fn () => (new Admin())->renderProfileRow($user));
65
66 $this->assertStringContainsString('class="extendify-toolbar-style-wrap"', $html);
67 $this->assertStringContainsString('Toolbar Style', $html);
68 $this->assertMatchesRegularExpression(
69 "/value=\"simple\"[^>]*checked='checked'/",
70 $html,
71 'Simple radio should be checked when the user meta is simple.'
72 );
73 $this->assertDoesNotMatchRegularExpression(
74 "/value=\"full\"[^>]*checked='checked'/",
75 $html,
76 'Full radio must not be checked when the user picked simple.'
77 );
78 }
79
80 public function test_render_profile_row_marks_full_radio_checked_when_user_meta_is_full()
81 {
82 $userId = self::factory()->user->create(['role' => 'administrator']);
83 update_user_meta($userId, Frontend::STYLE_META, 'full');
84 $user = get_user_by('id', $userId);
85
86 $html = $this->capture(fn () => (new Admin())->renderProfileRow($user));
87
88 $this->assertMatchesRegularExpression("/value=\"full\"[^>]*checked='checked'/", $html);
89 $this->assertDoesNotMatchRegularExpression("/value=\"simple\"[^>]*checked='checked'/", $html);
90 }
91
92 public function test_render_profile_row_uses_launch_aware_default_when_meta_unset()
93 {
94 update_option('extendify_onboarding_completed', false);
95 \Extendify\Config::$launchCompleted = false;
96
97 $userId = self::factory()->user->create(['role' => 'administrator']);
98 delete_user_meta($userId, Frontend::STYLE_META);
99 $user = get_user_by('id', $userId);
100
101 $html = $this->capture(fn () => (new Admin())->renderProfileRow($user));
102
103 $this->assertMatchesRegularExpression("/value=\"full\"[^>]*checked='checked'/", $html);
104 $this->assertDoesNotMatchRegularExpression("/value=\"simple\"[^>]*checked='checked'/", $html);
105 }
106
107 public function test_render_profile_row_uses_meta_key_extendify_toolbar_style()
108 {
109 $userId = self::factory()->user->create(['role' => 'administrator']);
110 $user = get_user_by('id', $userId);
111
112 $html = $this->capture(fn () => (new Admin())->renderProfileRow($user));
113
114 $this->assertStringContainsString('name="extendify_toolbar_style"', $html);
115 $this->assertSame(Frontend::STYLE_META, 'extendify_toolbar_style');
116 }
117
118 public function test_save_profile_row_persists_simple()
119 {
120 $userId = self::factory()->user->create(['role' => 'administrator']);
121 wp_set_current_user($userId);
122 $_POST[Frontend::STYLE_META] = 'simple';
123
124 (new Admin())->saveProfileRow($userId);
125
126 $this->assertSame('simple', get_user_meta($userId, Frontend::STYLE_META, true));
127 unset($_POST[Frontend::STYLE_META]);
128 }
129
130 public function test_save_profile_row_persists_full()
131 {
132 $userId = self::factory()->user->create(['role' => 'administrator']);
133 wp_set_current_user($userId);
134 $_POST[Frontend::STYLE_META] = 'full';
135
136 (new Admin())->saveProfileRow($userId);
137
138 $this->assertSame('full', get_user_meta($userId, Frontend::STYLE_META, true));
139 unset($_POST[Frontend::STYLE_META]);
140 }
141
142 public function test_save_profile_row_normalizes_unknown_value_to_simple()
143 {
144 $userId = self::factory()->user->create(['role' => 'administrator']);
145 wp_set_current_user($userId);
146 $_POST[Frontend::STYLE_META] = 'something-else';
147
148 (new Admin())->saveProfileRow($userId);
149
150 $this->assertSame('simple', get_user_meta($userId, Frontend::STYLE_META, true));
151 unset($_POST[Frontend::STYLE_META]);
152 }
153
154 public function test_save_profile_row_defaults_to_simple_when_post_key_missing()
155 {
156 // Characterization: not "leave the existing value alone" —
157 // a save with no key overwrites the stored value to 'simple'.
158 $userId = self::factory()->user->create(['role' => 'administrator']);
159 wp_set_current_user($userId);
160 update_user_meta($userId, Frontend::STYLE_META, 'full');
161 unset($_POST[Frontend::STYLE_META]);
162
163 (new Admin())->saveProfileRow($userId);
164
165 $this->assertSame('simple', get_user_meta($userId, Frontend::STYLE_META, true));
166 }
167
168 public function test_save_profile_row_rejects_when_current_user_cannot_edit_target_user()
169 {
170 $targetId = self::factory()->user->create(['role' => 'administrator']);
171 update_user_meta($targetId, Frontend::STYLE_META, 'full');
172
173 $editorId = self::factory()->user->create(['role' => 'editor']);
174 wp_set_current_user($editorId);
175 $_POST[Frontend::STYLE_META] = 'simple';
176
177 (new Admin())->saveProfileRow($targetId);
178
179 $this->assertSame(
180 'full',
181 get_user_meta($targetId, Frontend::STYLE_META, true),
182 'Editor must not be able to overwrite an admin user’s toolbar style.'
183 );
184 unset($_POST[Frontend::STYLE_META]);
185 }
186
187 public function test_reorder_row_outputs_script_that_targets_user_admin_bar_front_wrap()
188 {
189 $html = $this->capture(fn () => (new Admin())->reorderRow());
190
191 $this->assertStringContainsString('<script>', $html);
192 $this->assertStringContainsString("document.querySelector('tr.extendify-toolbar-style-wrap')", $html);
193 $this->assertStringContainsString("document.querySelector('tr.user-admin-bar-front-wrap')", $html);
194 $this->assertStringContainsString('insertBefore(ours, anchor.nextSibling)', $html);
195 }
196
197 private function capture(callable $fn): string
198 {
199 ob_start();
200 $fn();
201 return (string) ob_get_clean();
202 }
203 }
204