|
5 | 5 | * @package Jetpack
|
6 | 6 | */
|
7 | 7 |
|
| 8 | +use PHPUnit\Framework\Attributes\DataProvider; |
8 | 9 | use WpOrg\Requests\Requests;
|
9 | 10 |
|
10 | 11 | require_once dirname( __DIR__, 2 ) . '/lib/Jetpack_REST_TestCase.php';
|
@@ -450,4 +451,186 @@ public function test_preserved_scripts_maintain_properties() {
|
450 | 451 | public function enqueue_complex_test_script() {
|
451 | 452 | wp_enqueue_script( 'jetpack-complex-test-script' );
|
452 | 453 | }
|
| 454 | + |
| 455 | + /** |
| 456 | + * Test the make_url_absolute method converts URLs correctly. |
| 457 | + * |
| 458 | + * @param string $input_url The input URL. |
| 459 | + * @param string $expected_url The expected URL after conversion. |
| 460 | + * @dataProvider url_conversion_data_provider |
| 461 | + */ |
| 462 | + #[DataProvider( 'url_conversion_data_provider' )] |
| 463 | + public function test_make_url_absolute( $input_url, $expected_url ) { |
| 464 | + // Use the public method directly |
| 465 | + $result = $this->instance->make_url_absolute( $input_url ); |
| 466 | + $this->assertSame( $expected_url, $result ); |
| 467 | + } |
| 468 | + |
| 469 | + /** |
| 470 | + * Data provider for URL conversion tests. |
| 471 | + * |
| 472 | + * @return array Test data. |
| 473 | + */ |
| 474 | + public static function url_conversion_data_provider() { |
| 475 | + $site_url = site_url(); |
| 476 | + return array( |
| 477 | + 'relative URL starting with /' => array( '/wp-admin/script.js', $site_url . '/wp-admin/script.js' ), |
| 478 | + 'relative URL with wp-includes' => array( '/wp-includes/js/jquery.js', $site_url . '/wp-includes/js/jquery.js' ), |
| 479 | + 'protocol-relative URL' => array( '//example.com/script.js', '//example.com/script.js' ), |
| 480 | + 'absolute URL with http' => array( 'http://example.com/script.js', 'http://example.com/script.js' ), |
| 481 | + 'absolute URL with https' => array( 'https://example.com/script.js', 'https://example.com/script.js' ), |
| 482 | + 'empty string' => array( '', '' ), |
| 483 | + 'relative path without leading slash' => array( 'script.js', 'script.js' ), |
| 484 | + 'URL with query parameters' => array( '/wp-admin/script.js?ver=1.0', $site_url . '/wp-admin/script.js?ver=1.0' ), |
| 485 | + 'URL with hash' => array( '/wp-admin/page#section', $site_url . '/wp-admin/page#section' ), |
| 486 | + ); |
| 487 | + } |
| 488 | + |
| 489 | + /** |
| 490 | + * Test that URL conversion filters are applied during asset generation. |
| 491 | + */ |
| 492 | + public function test_url_conversion_filters_are_applied() { |
| 493 | + wp_set_current_user( self::factory()->user->create( array( 'role' => 'editor' ) ) ); |
| 494 | + |
| 495 | + // Track filter application |
| 496 | + $filters_applied = array( |
| 497 | + 'script' => false, |
| 498 | + 'style' => false, |
| 499 | + ); |
| 500 | + |
| 501 | + // Add tracking filters at priority 5 (before our filter at 10) |
| 502 | + add_filter( |
| 503 | + 'script_loader_src', |
| 504 | + function ( $src ) use ( &$filters_applied ) { |
| 505 | + $filters_applied['script'] = true; |
| 506 | + return $src; |
| 507 | + }, |
| 508 | + 5, |
| 509 | + 2 |
| 510 | + ); |
| 511 | + |
| 512 | + add_filter( |
| 513 | + 'style_loader_src', |
| 514 | + function ( $src ) use ( &$filters_applied ) { |
| 515 | + $filters_applied['style'] = true; |
| 516 | + return $src; |
| 517 | + }, |
| 518 | + 5, |
| 519 | + 2 |
| 520 | + ); |
| 521 | + |
| 522 | + $request = new WP_REST_Request( Requests::GET, '/wpcom/v2/editor-assets' ); |
| 523 | + $this->server->dispatch( $request ); |
| 524 | + |
| 525 | + $this->assertTrue( $filters_applied['script'], 'Script filter was not applied' ); |
| 526 | + $this->assertTrue( $filters_applied['style'], 'Style filter was not applied' ); |
| 527 | + |
| 528 | + // Clean up |
| 529 | + remove_all_filters( 'script_loader_src', 5 ); |
| 530 | + remove_all_filters( 'style_loader_src', 5 ); |
| 531 | + } |
| 532 | + |
| 533 | + /** |
| 534 | + * Test that relative URLs in assets are converted to absolute URLs. |
| 535 | + */ |
| 536 | + public function test_relative_urls_are_converted_to_absolute() { |
| 537 | + wp_set_current_user( self::factory()->user->create( array( 'role' => 'editor' ) ) ); |
| 538 | + |
| 539 | + // Register assets with relative URLs |
| 540 | + add_action( |
| 541 | + 'enqueue_block_editor_assets', |
| 542 | + function () { |
| 543 | + wp_register_script( 'jetpack-relative-test', '/wp-content/plugins/test/script.js', array(), '1.0', true ); |
| 544 | + wp_register_style( 'jetpack-relative-style', '/wp-content/plugins/test/style.css', array(), '1.0' ); |
| 545 | + |
| 546 | + wp_enqueue_script( 'jetpack-relative-test' ); |
| 547 | + wp_enqueue_style( 'jetpack-relative-style' ); |
| 548 | + } |
| 549 | + ); |
| 550 | + |
| 551 | + $request = new WP_REST_Request( Requests::GET, '/wpcom/v2/editor-assets' ); |
| 552 | + $response = $this->server->dispatch( $request ); |
| 553 | + $data = $response->get_data(); |
| 554 | + |
| 555 | + // Check that relative URLs have been converted to absolute |
| 556 | + $site_url = site_url(); |
| 557 | + $this->assertStringContainsString( $site_url . '/wp-content/plugins/test/script.js', $data['scripts'] ); |
| 558 | + $this->assertStringContainsString( $site_url . '/wp-content/plugins/test/style.css', $data['styles'] ); |
| 559 | + |
| 560 | + // Ensure no relative URLs remain in src/href attributes |
| 561 | + $this->assertDoesNotMatchRegularExpression( '/src=[\'"]\//', $data['scripts'], 'Found relative URL in script src' ); |
| 562 | + $this->assertDoesNotMatchRegularExpression( '/href=[\'"]\//', $data['styles'], 'Found relative URL in style href' ); |
| 563 | + } |
| 564 | + |
| 565 | + /** |
| 566 | + * Test that core WordPress assets with relative URLs are converted to absolute. |
| 567 | + */ |
| 568 | + public function test_core_assets_urls_are_absolute() { |
| 569 | + wp_set_current_user( self::factory()->user->create( array( 'role' => 'editor' ) ) ); |
| 570 | + |
| 571 | + $request = new WP_REST_Request( Requests::GET, '/wpcom/v2/editor-assets' ); |
| 572 | + $response = $this->server->dispatch( $request ); |
| 573 | + $data = $response->get_data(); |
| 574 | + |
| 575 | + $site_url = site_url(); |
| 576 | + |
| 577 | + // Check that any wp-includes or wp-admin paths are absolute (either local or CDN) |
| 578 | + if ( strpos( $data['scripts'], 'wp-includes' ) !== false || strpos( $data['scripts'], 'wp-admin' ) !== false ) { |
| 579 | + // Verify URLs are absolute (not relative) |
| 580 | + preg_match_all( '/(?:src|href)=[\'"]([^\'"]+)[\'"]/', $data['scripts'], $script_urls ); |
| 581 | + foreach ( $script_urls[1] as $url ) { |
| 582 | + if ( strpos( $url, 'wp-includes' ) !== false || strpos( $url, 'wp-admin' ) !== false ) { |
| 583 | + // URL should be absolute - either starts with site URL, http://, https://, or // (protocol-relative) |
| 584 | + $is_absolute = ( |
| 585 | + strpos( $url, $site_url ) === 0 || |
| 586 | + strpos( $url, 'http://' ) === 0 || |
| 587 | + strpos( $url, 'https://' ) === 0 || |
| 588 | + strpos( $url, '//' ) === 0 |
| 589 | + ); |
| 590 | + $this->assertTrue( $is_absolute, "Core script URL should be absolute, got: {$url}" ); |
| 591 | + |
| 592 | + // Ensure it's not a relative URL (starting with / but not //) |
| 593 | + if ( strpos( $url, '/' ) === 0 ) { |
| 594 | + $this->assertStringStartsWith( '//', $url, "URL starting with / should be protocol-relative (//), got: {$url}" ); |
| 595 | + } |
| 596 | + } |
| 597 | + } |
| 598 | + } |
| 599 | + |
| 600 | + if ( strpos( $data['styles'], 'wp-includes' ) !== false || strpos( $data['styles'], 'wp-admin' ) !== false ) { |
| 601 | + // Verify URLs are absolute (not relative) |
| 602 | + preg_match_all( '/(?:src|href)=[\'"]([^\'"]+)[\'"]/', $data['styles'], $style_urls ); |
| 603 | + foreach ( $style_urls[1] as $url ) { |
| 604 | + if ( strpos( $url, 'wp-includes' ) !== false || strpos( $url, 'wp-admin' ) !== false ) { |
| 605 | + // URL should be absolute - either starts with site URL, http://, https://, or // (protocol-relative) |
| 606 | + $is_absolute = ( |
| 607 | + strpos( $url, $site_url ) === 0 || |
| 608 | + strpos( $url, 'http://' ) === 0 || |
| 609 | + strpos( $url, 'https://' ) === 0 || |
| 610 | + strpos( $url, '//' ) === 0 |
| 611 | + ); |
| 612 | + $this->assertTrue( $is_absolute, "Core style URL should be absolute, got: {$url}" ); |
| 613 | + |
| 614 | + // Ensure it's not a relative URL (starting with / but not //) |
| 615 | + if ( strpos( $url, '/' ) === 0 ) { |
| 616 | + $this->assertStringStartsWith( '//', $url, "URL starting with / should be protocol-relative (//), got: {$url}" ); |
| 617 | + } |
| 618 | + } |
| 619 | + } |
| 620 | + } |
| 621 | + } |
| 622 | + |
| 623 | + /** |
| 624 | + * Test that URL conversion filters are removed after processing. |
| 625 | + */ |
| 626 | + public function test_url_conversion_filters_are_removed_after_processing() { |
| 627 | + wp_set_current_user( self::factory()->user->create( array( 'role' => 'editor' ) ) ); |
| 628 | + |
| 629 | + $request = new WP_REST_Request( Requests::GET, '/wpcom/v2/editor-assets' ); |
| 630 | + $this->server->dispatch( $request ); |
| 631 | + |
| 632 | + // Check that our filters are not present after the request |
| 633 | + $this->assertFalse( has_filter( 'script_loader_src', array( $this->instance, 'make_url_absolute' ) ), 'Script filter should be removed after processing' ); |
| 634 | + $this->assertFalse( has_filter( 'style_loader_src', array( $this->instance, 'make_url_absolute' ) ), 'Style filter should be removed after processing' ); |
| 635 | + } |
453 | 636 | }
|
0 commit comments