Changeset 64317
- Timestamp:
- 10/12/2026 08:45:11 PM (14 hours ago)
- Location:
- trunk/tests/phpunit/tests/rest-api
- Files:
-
- 2 added
- 1 edited
-
wpRestUrlDetailsController (added)
-
wpRestUrlDetailsController.php (modified) (3 diffs)
-
wpRestUrlDetailsController/parsing.php (added)
Legend:
- Unmodified
- Added
- Removed
-
trunk/tests/phpunit/tests/rest-api/wpRestUrlDetailsController.php
r64278 r64317 488 488 } 489 489 490 /**491 * @dataProvider data_get_title492 *493 * @covers WP_REST_URL_Details_Controller::get_title494 *495 * @ticket 54358496 *497 * @param string $html Given HTML string.498 * @param string $expected Expected found title.499 */500 public function test_get_title( $html, $expected ) {501 $controller = new WP_REST_URL_Details_Controller();502 $method = $this->get_reflective_method( 'get_title' );503 504 $actual = $method->invoke(505 $controller,506 $this->wrap_html_in_doc( $html )507 );508 $this->assertSame( $expected, $actual );509 }510 511 /**512 * Data provider.513 *514 * @return array515 */516 public function data_get_title() {517 return array(518 519 // Happy path for default.520 'default' => array(521 '<title>Testing <title></title>',522 'Testing',523 ),524 'with attributes' => array(525 '<title data-test-title-attr-one="test" data-test-title-attr-two="test2">Testing <title></title>',526 'Testing',527 ),528 'with text whitespace' => array(529 '<title data-test-title-attr-one="test" data-test-title-attr-two="test2"> Testing <title> </title>',530 'Testing',531 ),532 'with whitespace in opening tag' => array(533 '<title >Testing <title>: with whitespace in opening tag</title>',534 'Testing : with whitespace in opening tag',535 ),536 'when whitepace in closing tag' => array(537 '<title>Testing <title>: with whitespace in closing tag</ title>',538 'Testing : with whitespace in closing tag',539 ),540 'with other elements' => array(541 '<meta name="viewport" content="width=device-width">542 <title>Testing <title></title>543 <link rel="shortcut icon" href="https://wordpress.org/favicon.ico" />',544 'Testing',545 ),546 'multiline' => array(547 '<title>548 Testing <title>549 </title>',550 'Testing',551 ),552 553 // Unhappy paths.554 'when opening tag is malformed' => array(555 '< title>Testing <title>: when opening tag is invalid</title>',556 '',557 ),558 );559 }560 561 /**562 * @dataProvider data_get_icon563 *564 * @covers WP_REST_URL_Details_Controller::get_icon565 *566 * @ticket 54358567 *568 * @param string $html Given HTML string.569 * @param string $expected Expected found icon.570 * @param string $target_url Optional. Target URL. Default 'https://wordpress.org'.571 */572 public function test_get_icon( $html, $expected, $target_url = 'https://wordpress.org' ) {573 $controller = new WP_REST_URL_Details_Controller();574 $method = $this->get_reflective_method( 'get_icon' );575 576 $actual = $method->invoke(577 $controller,578 $this->wrap_html_in_doc( $html ),579 $target_url580 );581 $this->assertSame( $expected, $actual );582 }583 584 /**585 * Data provider.586 *587 * @return array588 */589 public function data_get_icon() {590 return array(591 592 // Happy path for default.593 'default' => array(594 '<link rel="shortcut icon" href="https://wordpress.org/favicon.ico" />',595 'https://wordpress.org/favicon.ico',596 ),597 'default with no closing whitespace' => array(598 '<link rel="shortcut icon" href="https://wordpress.org/favicon.ico"/>',599 'https://wordpress.org/favicon.ico',600 ),601 'default without self-closing' => array(602 '<link rel="shortcut icon" href="https://wordpress.org/favicon.ico">',603 'https://wordpress.org/favicon.ico',604 ),605 'default with href first' => array(606 '<link href="https://wordpress.org/favicon.ico" rel="shortcut icon" />',607 'https://wordpress.org/favicon.ico',608 ),609 'default with type last' => array(610 '<link href="https://wordpress.org/favicon.png" rel="icon" type="image/png" />',611 'https://wordpress.org/favicon.png',612 ),613 'default with type first' => array(614 '<link type="image/png" href="https://wordpress.org/favicon.png" rel="icon" />',615 'https://wordpress.org/favicon.png',616 ),617 'default with single quotes' => array(618 '<link type="image/png" href=\'https://wordpress.org/favicon.png\' rel=\'icon\' />',619 'https://wordpress.org/favicon.png',620 ),621 622 // Happy paths.623 'with query string' => array(624 '<link rel="shortcut icon" href="https://wordpress.org/favicon.ico?somequerystring=foo&another=bar" />',625 'https://wordpress.org/favicon.ico?somequerystring=foo&another=bar',626 ),627 'with another link' => array(628 '<link rel="shortcut icon" href="https://wordpress.org/favicon.ico" /><link rel="canonical" href="https://example.com">',629 'https://wordpress.org/favicon.ico',630 ),631 'with multiple links' => array(632 '<link rel="manifest" href="/manifest.56b1cedc.json">633 <link rel="shortcut icon" href="https://wordpress.org/favicon.ico" />634 <link rel="canonical" href="https://example.com">',635 'https://wordpress.org/favicon.ico',636 ),637 'relative url' => array(638 '<link rel="shortcut icon" href="/favicon.ico" />',639 'https://wordpress.org/favicon.ico',640 ),641 'relative url no slash' => array(642 '<link rel="shortcut icon" href="favicon.ico" />',643 'https://wordpress.org/favicon.ico',644 ),645 'relative url with path' => array(646 '<link rel="shortcut icon" href="favicon.ico" />',647 'https://wordpress.org/favicon.ico',648 'https://wordpress.org/my/path/here/',649 ),650 'rel reverse order' => array(651 '<link rel="icon shortcut" href="https://wordpress.org/favicon.ico" />',652 'https://wordpress.org/favicon.ico',653 ),654 'rel icon only' => array(655 '<link rel="icon" href="https://wordpress.org/favicon.ico" />',656 'https://wordpress.org/favicon.ico',657 ),658 'rel icon only with whitespace' => array(659 '<link rel=" icon " href="https://wordpress.org/favicon.ico" />',660 'https://wordpress.org/favicon.ico',661 ),662 'multiline attributes' => array(663 '<link664 rel="icon"665 href="https://wordpress.org/favicon.ico"666 />',667 'https://wordpress.org/favicon.ico',668 ),669 'multiline attributes in reverse order' => array(670 '<link671 rel="icon"672 href="https://wordpress.org/favicon.ico"673 />',674 'https://wordpress.org/favicon.ico',675 ),676 'multiline attributes with type' => array(677 '<link678 rel="icon"679 href="https://wordpress.org/favicon.ico"680 type="image/x-icon"681 />',682 'https://wordpress.org/favicon.ico',683 ),684 'multiline with type first' => array(685 '<link686 type="image/x-icon"687 rel="icon"688 href="https://wordpress.org/favicon.ico"689 />',690 'https://wordpress.org/favicon.ico',691 ),692 'with data URL x-icon type' => array(693 '<link rel="icon" href="data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQEAYAAABPYyMiAAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAAF0lEQVRIx2NgGAWjYBSMglEwCkbBSAcACBAAAeaR9cIAAAAASUVORK5CYII=" type="image/x-icon" />',694 'data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQEAYAAABPYyMiAAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAAF0lEQVRIx2NgGAWjYBSMglEwCkbBSAcACBAAAeaR9cIAAAAASUVORK5CYII=',695 ),696 'with data URL png type' => array(697 '<link href="data:image/png;base64,iVBORw0KGgo=" rel="icon" type="image/png" />',698 'data:image/png;base64,iVBORw0KGgo=',699 ),700 701 // Unhappy paths.702 'empty rel' => array(703 '<link rel="" href="https://wordpress.org/favicon.ico" />',704 '',705 ),706 'empty href' => array(707 '<link rel="icon" href="" />',708 '',709 ),710 'no rel' => array(711 '<link href="https://wordpress.org/favicon.ico" />',712 '',713 ),714 'link to external stylesheet' => array(715 '<link rel="stylesheet" href="https://example.com/assets/style.css" />',716 '',717 'https://example.com',718 ),719 'multiline with no href' => array(720 '<link721 rel="icon"722 href=""723 />',724 '',725 ),726 'multiline with no rel' => array(727 '<link728 rel=""729 href="https://wordpress.org/favicon.ico"730 />',731 '',732 ),733 );734 }735 736 /**737 * @dataProvider data_get_description738 *739 * @covers WP_REST_URL_Details_Controller::get_description740 *741 * @ticket 54358742 *743 * @param string $html Given HTML string.744 * @param string $expected Expected found icon.745 */746 public function test_get_description( $html, $expected ) {747 $controller = new WP_REST_URL_Details_Controller();748 749 // Parse the meta elements from the given HTML.750 $method = $this->get_reflective_method( 'get_meta_with_content_elements' );751 $meta_elements = $method->invoke(752 $controller,753 $this->wrap_html_in_doc( $html )754 );755 756 $method = $this->get_reflective_method( 'get_description' );757 $actual = $method->invoke( $controller, $meta_elements );758 $this->assertEqualHTML( $expected, $actual );759 }760 761 /**762 * Data provider.763 *764 * @return array765 */766 public function data_get_description() {767 return array(768 769 // Happy paths.770 'default' => array(771 '<meta name="description" content="This is a description.">',772 'This is a description.',773 ),774 'with whitespace' => array(775 '<meta name=" description " content=" This is a description. " >',776 'This is a description.',777 ),778 'with self-closing' => array(779 '<meta name="description" content="This is a description."/>',780 'This is a description.',781 ),782 'with self-closing and whitespace' => array(783 '<meta name=" description " content=" This is a description. " />',784 'This is a description.',785 ),786 'with content first' => array(787 '<meta content="Content is first" name="description">',788 'Content is first',789 ),790 'with single quotes' => array(791 '<meta name=\'description\' content=\'with single quotes\'>',792 'with single quotes',793 ),794 'with another element' => array(795 '<meta name="description" content="This is a description."><meta name="viewport" content="width=device-width, initial-scale=1">',796 'This is a description.',797 ),798 'with multiple elements' => array(799 '<meta property="og:image" content="https://wordpress.org/images/myimage.jpg" />800 <link rel="stylesheet" href="https://example.com/assets/style.css" />801 <meta name="description" content="This is a description.">802 <meta name="viewport" content="width=device-width, initial-scale=1">',803 'This is a description.',804 ),805 'with other attributes' => array(806 '<meta first="first" name="description" third="third" content="description with other attributes" fifth="fifth">',807 'description with other attributes',808 ),809 'with open graph' => array(810 '<meta name="og:description" content="This is a OG description." />811 <meta name="description" content="This is a description.">',812 'This is a OG description.',813 ),814 815 // Happy paths with multiline attributes.816 'with multiline attributes' => array(817 '<meta818 name="description"819 content="with multiline attributes"820 >',821 'with multiline attributes',822 ),823 'with multiline attributes in reverse order' => array(824 '<meta825 content="with multiline attributes in reverse order"826 name="description"827 >',828 'with multiline attributes in reverse order',829 ),830 'with multiline attributes and another element' => array(831 '<meta832 name="description"833 content="with multiline attributes"834 >835 <meta name="viewport" content="width=device-width, initial-scale=1">',836 'with multiline attributes',837 ),838 'with multiline and other attributes' => array(839 '<meta840 first="first"841 name="description"842 third="third"843 content="description with multiline and other attributes"844 fifth="fifth"845 >',846 'description with multiline and other attributes',847 ),848 849 // Happy paths with HTML tags or entities in the description.850 'with HTML tags' => array(851 '<meta name="description" content="<strong>Description</strong>: has <em>HTML</em> tags">',852 'Description: has HTML tags',853 ),854 'with content first and HTML tags' => array(855 '<meta content="<strong>Description</strong>: has <em>HTML</em> tags" name="description">',856 'Description: has HTML tags',857 ),858 'with HTML tags and other attributes' => array(859 '<meta first="first" name="description" third="third" content="<strong>Description</strong>: has <em>HTML</em> tags" fifth="fifth>',860 'Description: has HTML tags',861 ),862 'with HTML entities' => array(863 '<meta name="description" content="The <strong>description</strong> meta & its attribute value"',864 'The description meta & its attribute value',865 ),866 867 // Unhappy paths.868 'with empty content' => array(869 '<meta name="description" content="">',870 '',871 ),872 'with empty name' => array(873 '<meta name="" content="name is empty">',874 '',875 ),876 'without a name attribute' => array(877 '<meta content="without a name attribute">',878 '',879 ),880 'without a content attribute' => array(881 '<meta name="description">',882 '',883 ),884 );885 }886 887 /**888 * @dataProvider data_get_image889 *890 * @covers WP_REST_URL_Details_Controller::get_image891 *892 * @ticket 54358893 *894 * @param string $html Given HTML string.895 * @param string $expected Expected found image.896 * @param string $target_url Optional. Target URL. Default 'https://wordpress.org'.897 */898 public function test_get_image( $html, $expected, $target_url = 'https://wordpress.org' ) {899 $controller = new WP_REST_URL_Details_Controller();900 901 // Parse the meta elements from the given HTML.902 $method = $this->get_reflective_method( 'get_meta_with_content_elements' );903 $meta_elements = $method->invoke(904 $controller,905 $this->wrap_html_in_doc( $html )906 );907 908 $method = $this->get_reflective_method( 'get_image' );909 $actual = $method->invoke( $controller, $meta_elements, $target_url );910 $this->assertSame( $expected, $actual );911 }912 913 /**914 * Data provider.915 *916 * @return array917 */918 public function data_get_image() {919 return array(920 921 // Happy paths.922 'default' => array(923 '<meta property="og:image" content="https://wordpress.org/images/myimage.jpg">',924 'https://wordpress.org/images/myimage.jpg',925 ),926 'with whitespace' => array(927 '<meta property=" og:image " content=" https://wordpress.org/images/myimage.jpg " >',928 'https://wordpress.org/images/myimage.jpg',929 ),930 'with self-closing' => array(931 '<meta property="og:image" content="https://wordpress.org/images/myimage.jpg"/>',932 'https://wordpress.org/images/myimage.jpg',933 ),934 'with self-closing and whitespace' => array(935 '<meta property=" og:image " content=" https://wordpress.org/images/myimage.jpg " />',936 'https://wordpress.org/images/myimage.jpg',937 ),938 'with single quotes' => array(939 "<meta property='og:image' content='https://wordpress.org/images/myimage.jpg'>",940 'https://wordpress.org/images/myimage.jpg',941 ),942 'without quotes' => array(943 '<meta property=og:image content="https://wordpress.org/images/myimage.jpg">',944 'https://wordpress.org/images/myimage.jpg',945 ),946 'with url modifier' => array(947 '<meta property="og:image:url" content="https://wordpress.org/images/url-modifier.jpg" />948 <meta property="og:image" content="https://wordpress.org/images/myimage.jpg">',949 'https://wordpress.org/images/url-modifier.jpg',950 ),951 'with query string' => array(952 '<meta property="og:image" content="https://wordpress.org/images/withquerystring.jpg?foo=bar&bar=foo" />',953 'https://wordpress.org/images/withquerystring.jpg?foo=bar&bar=foo',954 ),955 956 // Happy paths with changing attributes order or adding attributes.957 'with content first' => array(958 '<meta content="https://wordpress.org/images/myimage.jpg" property="og:image">',959 'https://wordpress.org/images/myimage.jpg',960 ),961 'with other attributes' => array(962 '<meta first="first" property="og:image" third="third" content="https://wordpress.org/images/myimage.jpg" fifth="fifth">',963 'https://wordpress.org/images/myimage.jpg',964 ),965 'with other og meta' => array(966 '<meta property="og:image:height" content="720" />967 <meta property="og:image:alt" content="Ignore this please" />968 <meta property="og:image" content="https://wordpress.org/images/myimage.jpg" />969 <link rel="stylesheet" href="https://example.com/assets/style.css" />',970 'https://wordpress.org/images/myimage.jpg',971 ),972 973 // Happy paths with relative url.974 'with relative url' => array(975 '<meta property="og:image" content="/images/myimage.jpg" />',976 'https://wordpress.org/images/myimage.jpg',977 ),978 'with relative url without starting slash' => array(979 '<meta property="og:image" content="images/myimage.jpg" />',980 'https://wordpress.org/images/myimage.jpg',981 ),982 'with relative url and path' => array(983 '<meta property="og:image" content="images/myimage.jpg" />',984 'https://wordpress.org/images/myimage.jpg',985 'https://wordpress.org/my/path/here/',986 ),987 988 // Happy paths with multiline attributes.989 'with multiline attributes' => array(990 '<meta991 property="og:image"992 content="https://wordpress.org/images/myimage.jpg"993 >',994 'https://wordpress.org/images/myimage.jpg',995 ),996 'with multiline attributes in reverse order' => array(997 '<meta998 content="https://wordpress.org/images/myimage.jpg"999 property="og:image"1000 >',1001 'https://wordpress.org/images/myimage.jpg',1002 ),1003 'with multiline attributes and other elements' => array(1004 '<meta1005 property="og:image:height"1006 content="720"1007 />1008 <meta1009 property="og:image:alt"1010 content="Ignore this please"1011 />1012 <meta1013 property="og:image"1014 content="https://wordpress.org/images/myimage.jpg"1015 >1016 <link rel="stylesheet" href="https://example.com/assets/style.css" />',1017 'https://wordpress.org/images/myimage.jpg',1018 ),1019 'with multiline and other attributes' => array(1020 '<meta1021 first="first"1022 property="og:image:url"1023 third="third"1024 content="https://wordpress.org/images/myimage.jpg"1025 fifth="fifth"1026 >',1027 'https://wordpress.org/images/myimage.jpg',1028 ),1029 1030 // Happy paths with HTML tags in the content.1031 'with other og meta and HTML content' => array(1032 '<meta property="og:image:height" content="720" />1033 <meta property="og:image:alt" content="<em>ignore this please</em>" />1034 <meta property="og:image" content="https://wordpress.org/images/myimage.jpg" />1035 <link rel="stylesheet" href="https://example.com/assets/style.css" />',1036 'https://wordpress.org/images/myimage.jpg',1037 ),1038 1039 // Unhappy paths.1040 'with empty content' => array(1041 '<meta property="og:image" content="">',1042 '',1043 ),1044 'without a property attribute' => array(1045 '<meta content="https://wordpress.org/images/myimage.jpg">',1046 '',1047 ),1048 'without a content attribute empty property' => array(1049 '<meta property="og:image" href="https://wordpress.org/images/myimage.jpg">',1050 '',1051 ),1052 );1053 }1054 490 1055 491 /** … … 1211 647 } 1212 648 1213 private function wrap_html_in_doc( $html, $with_body = false ) {1214 $doc = '<!DOCTYPE html>1215 <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">1216 <head>1217 <meta charset="utf-8" />' . $html . "\n" . '</head>';1218 1219 if ( $with_body ) {1220 $doc .= '1221 <body>1222 <h1>Example Website</h1>1223 <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>1224 </body>1225 </html>';1226 }1227 1228 return $doc;1229 }1230 1231 649 /** 1232 650 * Gets the transient name. … … 1237 655 return 'g_url_details_response_' . md5( static::URL_PLACEHOLDER ); 1238 656 } 1239 1240 /**1241 * Get reflective access to a private/protected method on1242 * the WP_REST_URL_Details_Controller class.1243 *1244 * @param string $method_name Method name for which to gain access.1245 * @return ReflectionMethod1246 * @throws ReflectionException Throws an exception if method does not exist.1247 */1248 protected function get_reflective_method( $method_name ) {1249 $class = new ReflectionClass( WP_REST_URL_Details_Controller::class );1250 $method = $class->getMethod( $method_name );1251 if ( PHP_VERSION_ID < 80100 ) {1252 $method->setAccessible( true );1253 }1254 return $method;1255 }1256 657 }
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)