Completed
Push — update/idc-endpoint-migration ( b3b716...4fc7c1 )
by
unknown
11:31
created

Test_Atomic_Admin_Menu::test_add_page_menu()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 8
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 View Code Duplication
	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
	}
74
75
	/**
76
	 * Set up data.
77
	 */
78
	public function setUp() {
79
		parent::setUp();
80
		global $menu, $submenu;
81
82
		// Initialize in setUp so it registers hooks for every test.
83
		static::$admin_menu = Atomic_Admin_Menu::get_instance();
84
85
		$menu    = static::$menu_data;
86
		$submenu = static::$submenu_data;
87
88
		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...
89
	}
90
91
	/**
92
	 * Test get_instance.
93
	 *
94
	 * @covers ::get_instance
95
	 * @covers ::__construct
96
	 */
97 View Code Duplication
	public function test_get_instance() {
98
		$instance = Atomic_Admin_Menu::get_instance();
99
100
		$this->assertInstanceOf( Atomic_Admin_Menu::class, $instance );
101
		$this->assertSame( $instance, static::$admin_menu );
102
103
		$this->assertSame( 99998, has_action( 'admin_menu', array( $instance, 'reregister_menu_items' ) ) );
104
		$this->assertSame( 11, has_action( 'admin_enqueue_scripts', array( $instance, 'enqueue_scripts' ) ) );
105
	}
106
107
	/**
108
	 * Tests add_browse_sites_link.
109
	 *
110
	 * @covers ::add_browse_sites_link
111
	 */
112
	public function test_add_browse_sites_link() {
113
		global $menu;
114
115
		// No output when executed in single site mode.
116
		static::$admin_menu->add_browse_sites_link();
117
		$this->assertArrayNotHasKey( 0, $menu );
118
	}
119
120
	/**
121
	 * Tests add_browse_sites_link.
122
	 *
123
	 * @covers ::add_browse_sites_link
124
	 */
125
	public function test_add_browse_sites_link_multisite() {
126
		if ( ! is_multisite() ) {
127
			$this->markTestSkipped( 'Only used on multisite' );
128
		}
129
130
		global $menu;
131
132
		// No output when user has just one site.
133
		static::$admin_menu->add_browse_sites_link();
134
		$this->assertArrayNotHasKey( 0, $menu );
135
136
		// Give user a second site.
137
		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...
138
139
		static::$admin_menu->add_browse_sites_link();
140
141
		$browse_sites_menu_item = array(
142
			'Browse sites',
143
			'read',
144
			'https://wordpress.com/home',
145
			'site-switcher',
146
			'menu-top toplevel_page_https://wordpress.com/home',
147
			'toplevel_page_https://wordpress.com/home',
148
			'dashicons-arrow-left-alt2',
149
		);
150
		$this->assertSame( $menu[0], $browse_sites_menu_item );
151
152
		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...
153
	}
154
155
	/**
156
	 * Tests add_new_site_link.
157
	 *
158
	 * @covers ::add_new_site_link
159
	 */
160
	public function test_add_new_site_link() {
161
		global $menu;
162
163
		// Set jetpack user data.
164
		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...
165
166
		static::$admin_menu->add_new_site_link();
167
168
		$new_site_menu_item = array(
169
			'Add New Site',
170
			'read',
171
			'https://wordpress.com/start?ref=calypso-sidebar',
172
			'Add New Site',
173
			'menu-top toplevel_page_https://wordpress.com/start?ref=calypso-sidebar',
174
			'toplevel_page_https://wordpress.com/start?ref=calypso-sidebar',
175
			'dashicons-plus-alt',
176
		);
177
		$this->assertSame( array_pop( $menu ), $new_site_menu_item );
178
179
		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...
180
	}
181
182
	/**
183
	 * Tests add_site_card_menu
184
	 *
185
	 * @covers ::add_site_card_menu
186
	 */
187
	public function test_add_site_card_menu() {
188
		global $menu;
189
190
		if ( ! function_exists( 'site_is_private' ) ) {
191
			function site_is_private() { // phpcs:ignore
192
				return false;
193
			}
194
		}
195
		static::$admin_menu->add_site_card_menu();
196
197
		$home_url            = home_url();
198
		$site_card_menu_item = array(
199
			// phpcs:ignore Squiz.Strings.DoubleQuoteUsage.NotRequired
200
			'
201
<div class="site__info">
202
	<div class="site__title">' . get_option( 'blogname' ) . '</div>
203
	<div class="site__domain">' . static::$domain . "</div>\n\t\n</div>",
204
			'read',
205
			$home_url,
206
			'site-card',
207
			'menu-top toplevel_page_' . $home_url,
208
			'toplevel_page_' . $home_url,
209
			'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',
210
		);
211
212
		$this->assertEquals( $menu[1], $site_card_menu_item );
213
	}
214
215
	/**
216
	 * Tests set_site_card_menu_class
217
	 *
218
	 * @covers ::set_site_card_menu_class
219
	 */
220
	public function test_set_site_card_menu_class() {
221
		global $menu;
222
223
		if ( ! function_exists( 'site_is_private' ) ) {
224
			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 (L191-193) 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...
225
				return false;
226
			}
227
		}
228
229
		static::$admin_menu->add_site_card_menu();
230
231
		$menu = static::$admin_menu->set_site_card_menu_class( $menu );
232
		$this->assertNotContains( 'has-site-icon', $menu[1][4] );
233
234
		// Atomic fallback site icon counts as no site icon.
235
		add_filter( 'get_site_icon_url', array( $this, 'wpcomsh_site_icon_url' ) );
236
		$menu = static::$admin_menu->set_site_card_menu_class( $menu );
237
		remove_filter( 'get_site_icon_url', array( $this, 'wpcomsh_site_icon_url' ) );
238
		$this->assertNotContains( 'has-site-icon', $menu[1][4] );
239
240
		// Custom site icon triggers CSS class.
241
		add_filter( 'get_site_icon_url', array( $this, 'custom_site_icon_url' ) );
242
		$menu = static::$admin_menu->set_site_card_menu_class( $menu );
243
		remove_filter( 'get_site_icon_url', array( $this, 'custom_site_icon_url' ) );
244
		$this->assertContains( 'has-site-icon', $menu[1][4] );
245
	}
246
247
	/**
248
	 * Shim wpcomsh fallback site icon.
249
	 *
250
	 * @return string
251
	 */
252
	public function wpcomsh_site_icon_url() {
253
		return 'https://s0.wp.com/i/webclip.png';
254
	}
255
256
	/**
257
	 * Custom site icon.
258
	 *
259
	 * @return string
260
	 */
261
	public function custom_site_icon_url() {
262
		return 'https://s0.wp.com/i/jetpack.png';
263
	}
264
265
	/**
266
	 * Tests add_posts_menu
267
	 *
268
	 * @covers ::add_posts_menu
269
	 */
270
	public function test_add_posts_menu() {
271
		global $submenu;
272
273
		// Make sure menu items link to WP Admin.
274
		static::$admin_menu->add_posts_menu( false );
0 ignored issues
show
Unused Code introduced by
The call to the method Automattic\Jetpack\Dashb..._Menu::add_posts_menu() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
275
		$this->assertSame( 'edit.php', $submenu['edit.php'][5][2] );
276
		$this->assertSame( 'post-new.php', $submenu['edit.php'][10][2] );
277
	}
278
279
	/**
280
	 * Tests add_page_menu
281
	 *
282
	 * @covers ::add_page_menu
283
	 */
284
	public function test_add_page_menu() {
285
		global $submenu;
286
287
		// Make sure menu items link to WP Admin.
288
		static::$admin_menu->add_page_menu( false );
0 ignored issues
show
Unused Code introduced by
The call to the method Automattic\Jetpack\Dashb...n_Menu::add_page_menu() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
289
		$this->assertSame( 'edit.php?post_type=page', $submenu['edit.php?post_type=page'][5][2] );
290
		$this->assertSame( 'post-new.php?post_type=page', $submenu['edit.php?post_type=page'][10][2] );
291
	}
292
293
	/**
294
	 * Tests add_upgrades_menu
295
	 *
296
	 * @covers ::add_upgrades_menu
297
	 */
298 View Code Duplication
	public function test_add_upgrades_menu() {
299
		global $submenu;
300
301
		static::$admin_menu->add_upgrades_menu();
302
303
		$this->assertSame( 'https://wordpress.com/plans/my-plan/' . static::$domain, $submenu['paid-upgrades.php'][1][2] );
304
		$this->assertSame( 'https://wordpress.com/domains/manage/' . static::$domain, $submenu['paid-upgrades.php'][2][2] );
305
306
		/** This filter is already documented in modules/masterbar/admin-menu/class-atomic-admin-menu.php */
307
		if ( apply_filters( 'jetpack_show_wpcom_upgrades_email_menu', false ) ) {
308
			$this->assertSame( 'https://wordpress.com/email/' . static::$domain, $submenu['paid-upgrades.php'][3][2] );
309
			$this->assertSame( 'https://wordpress.com/purchases/subscriptions/' . static::$domain, $submenu['paid-upgrades.php'][4][2] );
310
		} else {
311
			$this->assertSame( 'https://wordpress.com/purchases/subscriptions/' . static::$domain, $submenu['paid-upgrades.php'][3][2] );
312
		}
313
	}
314
315
	/**
316
	 * Tests add_tools_menu
317
	 *
318
	 * @covers ::add_tools_menu
319
	 */
320
	public function test_add_tools_menu() {
321
		global $submenu;
322
323
		static::$admin_menu->add_tools_menu();
324
325
		// Check Export menu item always links to WP Admin.
326
		$this->assertSame( 'export.php', $submenu['tools.php'][5][2] );
327
	}
328
329
	/**
330
	 * Tests add_options_menu
331
	 *
332
	 * @covers ::add_options_menu
333
	 */
334
	public function test_add_options_menu() {
335
		global $submenu;
336
337
		static::$admin_menu->add_options_menu();
338
		$this->assertSame( 'https://wordpress.com/hosting-config/' . static::$domain, $submenu['options-general.php'][6][2] );
339
		$this->assertSame( 'options-writing.php', array_pop( $submenu['options-general.php'] )[2] );
340
341
		// Reset.
342
		$submenu = static::$submenu_data;
343
344
		static::$admin_menu->add_options_menu( true );
345
		$last_submenu = array_pop( $submenu['options-general.php'] );
346
		$this->assertNotSame( 'options-writing.php', $last_submenu[2] );
347
	}
348
349
	/**
350
	 * Tests add_plugins_menu
351
	 *
352
	 * @covers ::add_plugins_menu
353
	 */
354
	public function test_add_plugins_menu() {
355
		global $menu;
356
357
		static::$admin_menu->add_plugins_menu( false );
358
359
		// Check Plugins menu always links to WP Admin.
360
		$this->assertSame( 'plugins.php', $menu[65][2] );
361
	}
362
363
	/**
364
	 * Tests add_appearance_menu
365
	 *
366
	 * @covers ::add_appearance_menu
367
	 */
368
	public function test_add_appearance_menu() {
369
		global $submenu;
370
371
		static::$admin_menu->add_appearance_menu();
372
373
		// Multisite users don't have the `install_themes` capability by default,
374
		// so we have to make a dynamic check based on whether the current user can
375
		// install themes.
376
		if ( current_user_can( 'install_themes' ) ) {
377
			$this->assertSame( 'theme-install.php', $submenu['themes.php'][1][2] );
378
			// Check Customize menu always links to WP Admin.
379
			$this->assertSame( 'customize.php?return', $submenu['themes.php'][3][2] );
380
		} else {
381
			// Check Customize menu always links to WP Admin.
382
			$this->assertSame( 'customize.php?return', $submenu['themes.php'][2][2] );
383
		}
384
	}
385
386
	/**
387
	 * Tests add_users_menu
388
	 *
389
	 * @covers ::add_users_menu
390
	 */
391
	public function test_add_users_menu() {
392
		global $submenu;
393
394
		static::$admin_menu->add_users_menu();
395
		$this->assertSame( 'users.php', $submenu['users.php'][2][2] );
396
	}
397
398
	/**
399
	 * Tests add_comments_menu
400
	 *
401
	 * @covers ::add_comments_menu
402
	 */
403
	public function test_add_comments_menu() {
404
		global $menu;
405
406
		// Make sure menu items link to WP Admin.
407
		static::$admin_menu->add_comments_menu( false );
408
		$this->assertSame( 'edit-comments.php', $menu[25][2] );
409
	}
410
411
	/**
412
	 * Tests add_gutenberg_menus
413
	 *
414
	 * @covers ::add_gutenberg_menus
415
	 */
416
	public function test_add_gutenberg_menus() {
417
		global $menu;
418
		static::$admin_menu->add_gutenberg_menus( false );
419
420
		// Gutenberg plugin menu should not be visible.
421
		$this->assertArrayNotHasKey( 101, $menu );
422
	}
423
}
424