Completed
Push — update/admin-menu-sso-disabled ( 39bf4b...eefb5e )
by
unknown
10:52
created

Test_Atomic_Admin_Menu::tearDownAfterClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Tests for Atomic_Admin_Menu class.
4
 *
5
 * @package automattic/jetpack
6
 */
7
8
use Automattic\Jetpack\Dashboard_Customizations\Atomic_Admin_Menu;
9
use Automattic\Jetpack\Status;
10
11
require_jetpack_file( 'modules/masterbar/admin-menu/class-atomic-admin-menu.php' );
12
require_jetpack_file( 'tests/php/modules/masterbar/data/admin-menu.php' );
13
14
/**
15
 * Class Test_Atomic_Admin_Menu.
16
 *
17
 * @coversDefaultClass Automattic\Jetpack\Dashboard_Customizations\Atomic_Admin_Menu
18
 */
19
class Test_Atomic_Admin_Menu extends WP_UnitTestCase {
20
21
	/**
22
	 * Menu data fixture.
23
	 *
24
	 * @var array
25
	 */
26
	public static $menu_data;
27
28
	/**
29
	 * Submenu data fixture.
30
	 *
31
	 * @var array
32
	 */
33
	public static $submenu_data;
34
35
	/**
36
	 * Test domain.
37
	 *
38
	 * @var string
39
	 */
40
	public static $domain;
41
42
	/**
43
	 * Whether this testsuite is run on WP.com.
44
	 *
45
	 * @var bool
46
	 */
47
	public static $is_wpcom;
48
49
	/**
50
	 * Admin menu instance.
51
	 *
52
	 * @var Atomic_Admin_Menu
53
	 */
54
	public static $admin_menu;
55
56
	/**
57
	 * Mock user ID.
58
	 *
59
	 * @var int
60
	 */
61
	private static $user_id = 0;
62
63
	/**
64
	 * Create shared fixtures.
65
	 *
66
	 * @param WP_UnitTest_Factory $factory Fixture factory.
67
	 */
68
	public static function wpSetUpBeforeClass( $factory ) {
69
		static::$domain       = ( new Status() )->get_site_suffix();
70
		static::$user_id      = $factory->user->create( array( 'role' => 'administrator' ) );
0 ignored issues
show
Bug introduced by
Since $user_id is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $user_id to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
71
		static::$menu_data    = get_wpcom_menu_fixture();
72
		static::$submenu_data = get_submenu_fixture();
73
		add_filter( 'jetpack_active_modules', array( get_called_class(), 'mock_sso_module_enabled' ) );
74
	}
75
76
	/**
77
	 * Remove mocked filters.
78
	 */
79
	public static function tearDownAfterClass() {
80
		remove_filter( 'jetpack_active_modules', array( get_called_class(), 'mock_sso_module_enabled' ) );
81
	}
82
83
	/**
84
	 * Set up data.
85
	 */
86
	public function setUp() {
87
		parent::setUp();
88
		global $menu, $submenu;
89
90
		// Initialize in setUp so it registers hooks for every test.
91
		static::$admin_menu = Atomic_Admin_Menu::get_instance();
92
93
		$menu    = static::$menu_data;
94
		$submenu = static::$submenu_data;
95
96
		wp_set_current_user( static::$user_id );
0 ignored issues
show
Bug introduced by
Since $user_id is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $user_id to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
97
	}
98
99
	/**
100
	 * Test get_instance.
101
	 *
102
	 * @covers ::get_instance
103
	 * @covers ::__construct
104
	 */
105 View Code Duplication
	public function test_get_instance() {
106
		$instance = Atomic_Admin_Menu::get_instance();
107
108
		$this->assertInstanceOf( Atomic_Admin_Menu::class, $instance );
109
		$this->assertSame( $instance, static::$admin_menu );
110
111
		$this->assertSame( 99998, has_action( 'admin_menu', array( $instance, 'reregister_menu_items' ) ) );
112
		$this->assertSame( 11, has_action( 'admin_enqueue_scripts', array( $instance, 'enqueue_scripts' ) ) );
113
	}
114
115
	/**
116
	 * Tests add_browse_sites_link.
117
	 *
118
	 * @covers ::add_browse_sites_link
119
	 */
120
	public function test_add_browse_sites_link() {
121
		global $menu;
122
123
		// No output when executed in single site mode.
124
		static::$admin_menu->add_browse_sites_link();
125
		$this->assertArrayNotHasKey( 0, $menu );
126
	}
127
128
	/**
129
	 * Tests add_browse_sites_link.
130
	 *
131
	 * @covers ::add_browse_sites_link
132
	 */
133
	public function test_add_browse_sites_link_multisite() {
134
		if ( ! is_multisite() ) {
135
			$this->markTestSkipped( 'Only used on multisite' );
136
		}
137
138
		global $menu;
139
140
		// No output when user has just one site.
141
		static::$admin_menu->add_browse_sites_link();
142
		$this->assertArrayNotHasKey( 0, $menu );
143
144
		// Give user a second site.
145
		update_user_option( static::$user_id, 'wpcom_site_count', 2 );
0 ignored issues
show
Bug introduced by
Since $user_id is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $user_id to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
146
147
		static::$admin_menu->add_browse_sites_link();
148
149
		$browse_sites_menu_item = array(
150
			'Browse sites',
151
			'read',
152
			'https://wordpress.com/home',
153
			'site-switcher',
154
			'menu-top toplevel_page_https://wordpress.com/home',
155
			'toplevel_page_https://wordpress.com/home',
156
			'dashicons-arrow-left-alt2',
157
		);
158
		$this->assertSame( $menu[0], $browse_sites_menu_item );
159
160
		delete_user_option( static::$user_id, 'wpcom_site_count' );
0 ignored issues
show
Bug introduced by
Since $user_id is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $user_id to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
161
	}
162
163
	/**
164
	 * Tests add_new_site_link.
165
	 *
166
	 * @covers ::add_new_site_link
167
	 */
168
	public function test_add_new_site_link() {
169
		global $menu;
170
171
		// Set jetpack user data.
172
		update_user_option( static::$user_id, 'wpcom_site_count', 1 );
0 ignored issues
show
Bug introduced by
Since $user_id is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $user_id to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
173
174
		static::$admin_menu->add_new_site_link();
175
176
		$new_site_menu_item = array(
177
			'Add New Site',
178
			'read',
179
			'https://wordpress.com/start?ref=calypso-sidebar',
180
			'Add New Site',
181
			'menu-top toplevel_page_https://wordpress.com/start?ref=calypso-sidebar',
182
			'toplevel_page_https://wordpress.com/start?ref=calypso-sidebar',
183
			'dashicons-plus-alt',
184
		);
185
		$this->assertSame( array_pop( $menu ), $new_site_menu_item );
186
187
		delete_user_option( static::$user_id, 'wpcom_site_count' );
0 ignored issues
show
Bug introduced by
Since $user_id is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $user_id to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
188
	}
189
190
	/**
191
	 * Tests add_site_card_menu
192
	 *
193
	 * @covers ::add_site_card_menu
194
	 */
195
	public function test_add_site_card_menu() {
196
		global $menu;
197
198
		if ( ! function_exists( 'site_is_private' ) ) {
199
			function site_is_private() { // phpcs:ignore
200
				return false;
201
			}
202
		}
203
		static::$admin_menu->add_site_card_menu();
204
205
		$home_url            = home_url();
206
		$site_card_menu_item = array(
207
			// phpcs:ignore Squiz.Strings.DoubleQuoteUsage.NotRequired
208
			'
209
<div class="site__info">
210
	<div class="site__title">' . get_option( 'blogname' ) . '</div>
211
	<div class="site__domain">' . static::$domain . "</div>\n\t\n</div>",
212
			'read',
213
			$home_url,
214
			'site-card',
215
			'menu-top toplevel_page_' . $home_url,
216
			'toplevel_page_' . $home_url,
217
			'data:image/svg+xml,%3Csvg%20class%3D%22gridicon%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Ctitle%3EGlobe%3C%2Ftitle%3E%3Crect%20fill-opacity%3D%220%22%20x%3D%220%22%20width%3D%2224%22%20height%3D%2224%22%2F%3E%3Cg%3E%3Cpath%20fill%3D%22%23fff%22%20d%3D%22M12%202C6.477%202%202%206.477%202%2012s4.477%2010%2010%2010%2010-4.477%2010-10S17.523%202%2012%202zm0%2018l2-2%201-1v-2h-2v-1l-1-1H9v3l2%202v1.93c-3.94-.494-7-3.858-7-7.93l1%201h2v-2h2l3-3V6h-2L9%205v-.41C9.927%204.21%2010.94%204%2012%204s2.073.212%203%20.59V6l-1%201v2l1%201%203.13-3.13c.752.897%201.304%201.964%201.606%203.13H18l-2%202v2l1%201h2l.286.286C18.03%2018.06%2015.24%2020%2012%2020z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E',
218
		);
219
220
		$this->assertEquals( $menu[1], $site_card_menu_item );
221
	}
222
223
	/**
224
	 * Tests set_site_card_menu_class
225
	 *
226
	 * @covers ::set_site_card_menu_class
227
	 */
228
	public function test_set_site_card_menu_class() {
229
		global $menu;
230
231
		if ( ! function_exists( 'site_is_private' ) ) {
232
			function site_is_private() { // phpcs:ignore
0 ignored issues
show
Best Practice introduced by
The function site_is_private() has been defined more than once; this definition is ignored, only the first definition in this file (L199-201) is considered.

This check looks for functions that have already been defined in the same file.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
233
				return false;
234
			}
235
		}
236
237
		static::$admin_menu->add_site_card_menu();
238
239
		$menu = static::$admin_menu->set_site_card_menu_class( $menu );
240
		$this->assertNotContains( 'has-site-icon', $menu[1][4] );
241
242
		// Atomic fallback site icon counts as no site icon.
243
		add_filter( 'get_site_icon_url', array( $this, 'wpcomsh_site_icon_url' ) );
244
		$menu = static::$admin_menu->set_site_card_menu_class( $menu );
245
		remove_filter( 'get_site_icon_url', array( $this, 'wpcomsh_site_icon_url' ) );
246
		$this->assertNotContains( 'has-site-icon', $menu[1][4] );
247
248
		// Custom site icon triggers CSS class.
249
		add_filter( 'get_site_icon_url', array( $this, 'custom_site_icon_url' ) );
250
		$menu = static::$admin_menu->set_site_card_menu_class( $menu );
251
		remove_filter( 'get_site_icon_url', array( $this, 'custom_site_icon_url' ) );
252
		$this->assertContains( 'has-site-icon', $menu[1][4] );
253
	}
254
255
	/**
256
	 * Shim wpcomsh fallback site icon.
257
	 *
258
	 * @return string
259
	 */
260
	public function wpcomsh_site_icon_url() {
261
		return 'https://s0.wp.com/i/webclip.png';
262
	}
263
264
	/**
265
	 * Custom site icon.
266
	 *
267
	 * @return string
268
	 */
269
	public function custom_site_icon_url() {
270
		return 'https://s0.wp.com/i/jetpack.png';
271
	}
272
273
	/**
274
	 * Tests add_posts_menu
275
	 *
276
	 * @covers ::add_posts_menu
277
	 */
278
	public function test_add_posts_menu() {
279
		global $submenu;
280
281
		// Make sure menu items link to WP Admin.
282
		static::$admin_menu->add_posts_menu( false );
283
		$this->assertSame( 'edit.php', $submenu['edit.php'][5][2] );
284
		$this->assertSame( 'post-new.php', $submenu['edit.php'][10][2] );
285
	}
286
287
	/**
288
	 * Tests add_page_menu
289
	 *
290
	 * @covers ::add_page_menu
291
	 */
292
	public function test_add_page_menu() {
293
		global $submenu;
294
295
		// Make sure menu items link to WP Admin.
296
		static::$admin_menu->add_page_menu( false );
297
		$this->assertSame( 'edit.php?post_type=page', $submenu['edit.php?post_type=page'][5][2] );
298
		$this->assertSame( 'post-new.php?post_type=page', $submenu['edit.php?post_type=page'][10][2] );
299
	}
300
301
	/**
302
	 * Tests add_upgrades_menu
303
	 *
304
	 * @covers ::add_upgrades_menu
305
	 */
306 View Code Duplication
	public function test_add_upgrades_menu() {
307
		global $submenu;
308
309
		static::$admin_menu->add_upgrades_menu();
310
311
		$this->assertSame( 'https://wordpress.com/plans/my-plan/' . static::$domain, $submenu['paid-upgrades.php'][1][2] );
312
		$this->assertSame( 'https://wordpress.com/domains/manage/' . static::$domain, $submenu['paid-upgrades.php'][2][2] );
313
314
		/** This filter is already documented in modules/masterbar/admin-menu/class-atomic-admin-menu.php */
315
		if ( apply_filters( 'jetpack_show_wpcom_upgrades_email_menu', false ) ) {
316
			$this->assertSame( 'https://wordpress.com/email/' . static::$domain, $submenu['paid-upgrades.php'][3][2] );
317
			$this->assertSame( 'https://wordpress.com/purchases/subscriptions/' . static::$domain, $submenu['paid-upgrades.php'][4][2] );
318
		} else {
319
			$this->assertSame( 'https://wordpress.com/purchases/subscriptions/' . static::$domain, $submenu['paid-upgrades.php'][3][2] );
320
		}
321
	}
322
323
	/**
324
	 * Tests add_tools_menu
325
	 *
326
	 * @covers ::add_tools_menu
327
	 */
328
	public function test_add_tools_menu() {
329
		global $submenu;
330
331
		static::$admin_menu->add_tools_menu();
332
333
		// Check Export menu item always links to WP Admin.
334
		$this->assertSame( 'export.php', $submenu['tools.php'][5][2] );
335
	}
336
337
	/**
338
	 * Tests add_options_menu
339
	 *
340
	 * @covers ::add_options_menu
341
	 */
342
	public function test_add_options_menu() {
343
		global $submenu;
344
345
		static::$admin_menu->add_options_menu();
346
		$this->assertSame( 'https://wordpress.com/hosting-config/' . static::$domain, $submenu['options-general.php'][6][2] );
347
		$this->assertSame( 'options-writing.php', array_pop( $submenu['options-general.php'] )[2] );
348
349
		// Reset.
350
		$submenu = static::$submenu_data;
351
352
		static::$admin_menu->add_options_menu( true );
353
		$last_submenu = array_pop( $submenu['options-general.php'] );
354
		$this->assertNotSame( 'options-writing.php', $last_submenu[2] );
355
	}
356
357
	/**
358
	 * Tests add_plugins_menu
359
	 *
360
	 * @covers ::add_plugins_menu
361
	 */
362
	public function test_add_plugins_menu() {
363
		global $menu;
364
365
		static::$admin_menu->add_plugins_menu( false );
366
367
		// Check Plugins menu always links to WP Admin.
368
		$this->assertSame( 'plugins.php', $menu[65][2] );
369
	}
370
371
	/**
372
	 * Tests add_appearance_menu
373
	 *
374
	 * @covers ::add_appearance_menu
375
	 */
376
	public function test_add_appearance_menu() {
377
		global $submenu;
378
379
		static::$admin_menu->add_appearance_menu();
380
381
		// Multisite users don't have the `install_themes` capability by default,
382
		// so we have to make a dynamic check based on whether the current user can
383
		// install themes.
384
		if ( current_user_can( 'install_themes' ) ) {
385
			$this->assertSame( 'theme-install.php', $submenu['themes.php'][1][2] );
386
			// Check Customize menu always links to WP Admin.
387
			$this->assertSame( 'customize.php?return', $submenu['themes.php'][3][2] );
388
		} else {
389
			// Check Customize menu always links to WP Admin.
390
			$this->assertSame( 'customize.php?return', $submenu['themes.php'][2][2] );
391
		}
392
	}
393
394
	/**
395
	 * Tests add_users_menu
396
	 *
397
	 * @covers ::add_users_menu
398
	 */
399
	public function test_add_users_menu() {
400
		global $submenu;
401
402
		static::$admin_menu->add_users_menu();
403
		$this->assertSame( 'users.php', $submenu['users.php'][2][2] );
404
	}
405
406
	/**
407
	 * Tests add_comments_menu
408
	 *
409
	 * @covers ::add_comments_menu
410
	 */
411
	public function test_add_comments_menu() {
412
		global $menu;
413
414
		// Make sure menu items link to WP Admin.
415
		static::$admin_menu->add_comments_menu( false );
416
		$this->assertSame( 'edit-comments.php', $menu[25][2] );
417
	}
418
419
	/**
420
	 * Tests add_gutenberg_menus
421
	 *
422
	 * @covers ::add_gutenberg_menus
423
	 */
424
	public function test_add_gutenberg_menus() {
425
		global $menu;
426
		static::$admin_menu->add_gutenberg_menus( false );
427
428
		// Gutenberg plugin menu should not be visible.
429
		$this->assertArrayNotHasKey( 101, $menu );
430
	}
431
432
	/**
433
	 * Tests that Calypso links are forced on API requests when SSO is disabled.
434
	 */
435
	public function test_calypso_menu_when_sso_disabled() {
436
		global $menu, $submenu;
437
438
		// Set up.
439
		$admin_menu     = new ReflectionClass( static::$admin_menu );
440
		$is_api_request = $admin_menu->getProperty( 'is_api_request' );
441
		$is_api_request->setAccessible( true );
442
		$is_api_request->setValue( static::$admin_menu, true );
443
		$is_sso_enabled = $admin_menu->getProperty( 'is_sso_enabled' );
444
		$is_sso_enabled->setAccessible( true );
445
		$is_sso_enabled->setValue( static::$admin_menu, false );
446
447
		// Register menus.
448
		static::$admin_menu->add_posts_menu( true );
449
		static::$admin_menu->add_page_menu( true );
450
		static::$admin_menu->add_options_menu();
451
		static::$admin_menu->add_appearance_menu();
452
		static::$admin_menu->add_users_menu();
453
		static::$admin_menu->add_comments_menu();
454
455
		// Make sure menu items no WP Admin links are added for API requests when SSO is disabled.
456
		$this->assertSame( 'https://wordpress.com/posts/' . static::$domain, $submenu['edit.php'][0][2] );
457
		$this->assertSame( 'https://wordpress.com/post/' . static::$domain, $submenu['edit.php'][1][2] );
458
		$this->assertSame( 'https://wordpress.com/pages/' . static::$domain, $submenu['edit.php?post_type=page'][0][2] );
459
		$this->assertSame( 'https://wordpress.com/page/' . static::$domain, $submenu['edit.php?post_type=page'][1][2] );
460
		$last_options_submenu = array_pop( $submenu['options-general.php'] );
461
		$this->assertNotSame( 'options-writing.php', $last_options_submenu[2] );
462
		if ( current_user_can( 'install_themes' ) ) {
463
			$this->assertNotSame( 'theme-install.php', $submenu['themes.php'][1][2] );
464
		}
465
		$this->assertNotSame( 'users.php', $submenu['users.php'][2][2] );
466
		$this->assertSame( 'https://wordpress.com/comments/all/' . static::$domain, $menu[25][2] );
467
468
		// Reset.
469
		$is_api_request->setValue( static::$admin_menu, false );
470
		$is_sso_enabled->setValue( static::$admin_menu, true );
471
	}
472
473
	/**
474
	 * Adds the SSO module to the list of active modules.
475
	 *
476
	 * @param array $modules List of active modules.
477
	 *
478
	 * @return array
479
	 */
480
	public static function mock_sso_module_enabled( $modules ) {
481
		$modules[] = 'sso';
482
		return $modules;
483
	}
484
}
485