diff --git a/includes/rules/empty_link.php b/includes/rules/empty_link.php index 38bb151f..8d875034 100644 --- a/includes/rules/empty_link.php +++ b/includes/rules/empty_link.php @@ -45,25 +45,32 @@ function edac_rule_empty_link( $content, $post ) { // phpcs:ignore -- $post is r // does not have a name. $image = $link->find( 'img' ); - if ( ! $error && isset( $input[0] ) && empty( trim( $image[0]->getAttribute( 'alt' ) ) ) ) { + $input = $link->find( 'input' ); + $i = $link->find( 'i' ); + + // If there's no image, input or i tag it's just an empty link and should be flagged. + if ( empty( $image ) && empty( $input ) && empty( $i ) ) { + $error = $a_tag_code; + } + + if ( ! $error && isset( $image[0] ) && empty( trim( $image[0]->getAttribute( 'alt' ) ) ) ) { // The first image inside the link does not have an alt. // Throw error. $error = $a_tag_code; } - $input = $link->find( 'input' ); - if ( ! $error && isset( $input[0] ) && empty( trim( $image[0]->getAttribute( 'value' ) ) ) ) { + if ( ! $error && isset( $input[0] ) && empty( trim( $input[0]->getAttribute( 'value' ) ) ) ) { // The first input inside the link does not have a value. // Throw error. $error = $a_tag_code; } - $i = $link->find( 'i' ); - if ( ! $error && isset( $input[0] ) && - empty( trim( $i[0]->getAttribute( 'title' ) ) ) && - empty( trim( $i[0]->getAttribute( 'aria-label' ) ) ) + if ( ! $error && + isset( $i[0] ) && + empty( trim( $i[0]->getAttribute( 'title' ) ) ) && + empty( trim( $i[0]->getAttribute( 'aria-label' ) ) ) ) { // The first i inside the link does not have a title & diff --git a/tests/phpunit/includes/rules/EmptyLinkTest.php b/tests/phpunit/includes/rules/EmptyLinkTest.php new file mode 100644 index 00000000..7137177b --- /dev/null +++ b/tests/phpunit/includes/rules/EmptyLinkTest.php @@ -0,0 +1,111 @@ +'; + + $not_expected_error = 'Some content'; + + + $dom = new EDAC_Dom(); + $dom->load( $expected_error . PHP_EOL . $not_expected_error ); + + $errors = edac_rule_empty_link( [ 'html' => $dom ], null ); + + $this->assertContains( $expected_error, $errors ); + $this->assertNotContains( $not_expected_error, $errors ); + } + + /** + * Test that a link with no content, no aria-label, no title, no id, no name, and no alt text throws an error. + */ + public function test_empty_link_with_img() { + $expected_errors = [ + '', + ' ', + ]; + + $not_expected_error = 'A filled alt'; + + $dom = new EDAC_Dom(); + $dom->load( implode( PHP_EOL, $expected_errors ) . PHP_EOL . $not_expected_error ); + + $errors = edac_rule_empty_link( [ 'html' => $dom ], null ); + + foreach ( $expected_errors as $expected_error ) { + $this->assertContains( $expected_error, $errors ); + } + + $this->assertNotContains( $not_expected_error, $errors ); + } + + /** + * Test that a link with no content, no aria-label, no title, no id, no name, and no alt text throws an error. + */ + public function test_empty_link_with_input() { + + $expected_errors = [ + '', + '', + '', // whitespace should be stripped, this is still empty. + ]; + + $not_expected_error = ''; + + $dom = new EDAC_Dom(); + $dom->load( implode( PHP_EOL, $expected_errors ) . PHP_EOL . $not_expected_error ); + + $errors = edac_rule_empty_link( [ 'html' => $dom ], null ); + + foreach ( $expected_errors as $expected_error ) { + $this->assertContains( $expected_error, $errors ); + } + $this->assertNotContains( $not_expected_error, $errors ); + } + + /** + * Test that a link with no content, no aria-label, no title, no id, no name, and no alt text throws an error. + */ + public function test_empty_link_with_i() { + $expected_errors = [ + '', + '', + '', + '', // whitespace should be stripped, this is still empty. + '', // whitespace should be stripped, this is still empty. + ]; + + $not_expected_errors = [ + '', + '', + '', + ]; + + $dom = new EDAC_Dom(); + $dom->load( implode( PHP_EOL, $expected_errors ) . PHP_EOL . implode( PHP_EOL, $not_expected_errors ) ); + + $errors = edac_rule_empty_link( [ 'html' => $dom ], null ); + + foreach ( $expected_errors as $expected_error ) { + $this->assertContains( $expected_error, $errors ); + } + foreach ( $not_expected_errors as $not_expected_error ) { + $this->assertNotContains( $not_expected_error, $errors ); + } + } +}