diff --git a/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-each.php b/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-each.php new file mode 100644 index 0000000000000..eea7f3f9fe8e7 --- /dev/null +++ b/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-each.php @@ -0,0 +1,681 @@ +interactivity = new WP_Interactivity_API(); + $this->interactivity->state( 'myPlugin', array( 'list' => array( 1, 2 ) ) ); + $this->interactivity->state( 'myPlugin', array( 'after' => 'after-wp-each' ) ); + } + + /** + * Tests that the `data-wp-each` directive doesn't do anything if it's not on + * a template tag. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_doesnt_do_anything_on_non_template_tags() { + $original = ' +
+ +
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $original, $new ); + } + + /** + * Tests that the `data-wp-each` directive doesn't do anything if the array + * is associative instead of indexed. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_doesnt_do_anything_on_associative_arrays() { + $this->interactivity->state( + 'myPlugin', + array( + 'assoc' => array( + 'one' => 1, + 'two' => 2, + ), + ) + ); + $original = ' + '; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $original, $new ); + } + + /** + * Tests that the `data-wp-each` directive works with simple tags. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_simple_tags() { + $original = '' . + '' . + '
Text
'; + $expected = '' . + '' . + '1' . + '2' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive doesn't do anything if the array is + * empty. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_empty_array() { + $this->interactivity->state( 'myPlugin', array( 'empty' => array() ) ); + $original = '' . + '' . + '
Text
'; + $expected = '' . + '' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive merges the item with the previous + * context correctly. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_merges_context_correctly() { + $original = '' . + '
' . + '' . + '
Text
' . + '
'; + $expected = '' . + '
' . + '' . + '1' . + '2' . + '
New text
' . + '
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive works with arrays from the context. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_gets_arrays_from_context() { + $original = '' . + '
' . + '' . + '
Text
' . + '
'; + $expected = '' . + '
' . + '' . + '1' . + '2' . + '
Text
' . + '
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive works with the default namespace. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_default_namespace() { + $original = '' . + '
' . + '' . + '
Text
' . + '
'; + $expected = '' . + '
' . + '' . + '1' . + '2' . + '
Text
' . + '
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive works with multiple tags per item. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_multiple_tags_per_item() { + $original = '' . + '' . + '
Text
'; + $expected = '' . + '' . + '1' . + '1' . + '2' . + '2' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive works with void tags. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_void_tags() { + $original = '' . + '' . + '
Text
'; + $expected = '' . + '' . + '' . + '' . + '' . + '' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive works with combinations of void and + * non-void tags. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_void_and_non_void_tags() { + $original = '' . + '' . + '
Text
'; + $expected = '' . + '' . + '' . + '1' . + '' . + '2' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive works with nested tags. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_nested_tags() { + $original = '' . + '' . + '
Text
'; + $expected = '' . + '' . + '
' . + 'id: 1' . + '
' . + '
' . + 'id: 2' . + '
' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive works with nested item properties. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_nested_item_properties() { + $this->interactivity->state( + 'myPlugin', + array( + 'list' => array( + array( + 'id' => 1, + 'name' => 'one', + ), + array( + 'id' => 2, + 'name' => 'two', + ), + ), + ) + ); + $original = '' . + '' . + '
Text
'; + $expected = '' . + '' . + '1' . + 'one' . + '2' . + 'two' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive works with different item names. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_different_item_names() { + $original = '' . + '' . + '
Text
'; + $expected = '' . + '' . + '1' . + '2' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive transforms kebab-case into + * camelCase. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_different_item_names_transforms_camelcase() { + $original = '' . + '' . + '
Text
'; + $expected = '' . + '' . + '1' . + '2' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive doesn't work with top-level texts. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_doesnt_work_with_top_level_text() { + $original = '' . + ''; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $original, $new ); + + $original = '' . + ''; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $original, $new ); + + // But it should work fine with spaces and linebreaks. + $original = ' + '; + $new = $this->interactivity->process_directives( $original ); + $p = new WP_HTML_Tag_Processor( $new ); + $p->next_tag( array( 'class_name' => 'test' ) ); + $p->next_tag( array( 'class_name' => 'test' ) ); + $this->assertEquals( '1', $p->get_attribute( 'id' ) ); + $p->next_tag( array( 'class_name' => 'test' ) ); + $this->assertEquals( '2', $p->get_attribute( 'id' ) ); + } + + /** + * Tests that the `data-wp-each` directive works with nested template tags. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_nested_template_tags() { + $this->interactivity->state( 'myPlugin', array( 'list2' => array( 3, 4 ) ) ); + $original = '' . + '' . + '
Text
'; + $expected = '' . + '' . + '1' . + '' . + '3' . + '4' . + '2' . + '' . + '3' . + '4' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive works with directly nested template + * tags. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_directly_nested_template_tags() { + $this->interactivity->state( 'myPlugin', array( 'list2' => array( 3, 4 ) ) ); + $original = '' . + '' . + '
Text
'; + $expected = '' . + '' . + '' . + '1' . + '3' . + '1' . + '4' . + '' . + '2' . + '3' . + '2' . + '4' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive works with nestded template tags + * that use a previous item as a list. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_nested_template_tags_using_previous_item_as_list() { + $this->interactivity->state( 'myPlugin', array( 'list2' => array( array( 1, 2 ), array( 3, 4 ) ) ) ); + $original = '' . + '' . + '
Text
'; + $expected = '' . + '' . + '' . + '1' . + '2' . + '' . + '3' . + '4' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive doesn't process unbalanced tags. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_unbalanced_tags() { + $original = '' . + '' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $original, $new ); + } + + /** + * Tests that the `data-wp-each` directive doesn't process unbalanced tags in + * nested templates. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_unbalanced_tags_in_nested_template_tags() { + $this->interactivity->state( 'myPlugin', array( 'list2' => array( 3, 4 ) ) ); + $original = '' . + '' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $original, $new ); + } + + /** + * Tests that the `data-wp-each` directive doesn't process if it doesn't get + * an array. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_doesnt_process_if_not_array() { + $original = '' . + '' . + '
Text
'; + $expected = '' . + '' . + '
Text
'; + + $this->interactivity->state( 'myPlugin', array( 'list' => null ) ); + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + + $this->interactivity->state( 'myPlugin', array( 'list' => 'Text' ) ); + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + + $this->interactivity->state( 'myPlugin', array( 'list' => 100 ) ); + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + + $this->interactivity->state( 'myPlugin', array( 'list' => false ) ); + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + + $this->interactivity->state( 'myPlugin', array( 'list' => true ) ); + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } + + /** + * Tests that the `data-wp-each` directive doesn't process anything if it + * detects manual server-side processing. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_each_doesnt_process_with_manual_server_directive_processing() { + $original = '' . + '' . + '1' . + '2' . + '
Text
'; + $expected = '' . + '' . + '1' . + '2' . + '
Text
'; + $new = $this->interactivity->process_directives( $original ); + $this->assertEquals( $expected, $new ); + } +} diff --git a/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-router-region.php b/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-router-region.php new file mode 100644 index 0000000000000..9387f6e0f209a --- /dev/null +++ b/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-router-region.php @@ -0,0 +1,159 @@ +interactivity = new WP_Interactivity_API(); + + // Removes all hooks set for `wp_footer`. + global $wp_filter; + $this->original_wp_footer = $wp_filter['wp_footer']; + $wp_filter['wp_footer'] = new WP_Hook(); + } + + /** + * Tear down. + */ + public function tear_down() { + // Restores all previous hooks set for `wp_footer`. + global $wp_filter; + $wp_filter['wp_footer'] = $this->original_wp_footer; + + parent::tear_down(); + } + + /** + * Executes the hooks associated to `wp_footer`. + */ + protected function render_wp_footer() { + ob_start(); + do_action( 'wp_footer' ); + return ob_get_clean(); + } + + /** + * Tests that no elements are added if the `data-wp-router-region` is + * missing. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_router_region_missing() { + $html = '
Nothing here
'; + $new_html = $this->interactivity->process_directives( $html ); + $footer = $this->render_wp_footer(); + $this->assertEquals( $html, $new_html ); + $this->assertEquals( '', $footer ); + } + + /** + * Tests that the `data-wp-router-region` directive adds a loading bar and a + * region for screen reader announcements in the footer. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_router_region_adds_loading_bar_aria_live_region() { + $html = '
Interactive region
'; + $new_html = $this->interactivity->process_directives( $html ); + $footer = $this->render_wp_footer(); + + $this->assertEquals( $html, $new_html ); + + $query = array( 'tag_name' => 'style' ); + + $p = new WP_HTML_Tag_Processor( $footer ); + $this->assertTrue( $p->next_tag( $query ) ); + $this->assertEquals( 'wp-interactivity-router_animations', $p->get_attribute( 'id' ) ); + $this->assertFalse( $p->next_tag( $query ) ); + + $query = array( + 'tag_name' => 'div', + 'class_name' => 'wp-interactivity-router_loading-bar', + ); + + $p = new WP_HTML_Tag_Processor( $footer ); + $this->assertTrue( $p->next_tag( $query ) ); + $this->assertFalse( $p->next_tag( $query ) ); + + $query = array( + 'tag_name' => 'div', + 'class_name' => 'screen-reader-text', + ); + + $p = new WP_HTML_Tag_Processor( $footer ); + $this->assertTrue( $p->next_tag( $query ) ); + $this->assertFalse( $p->next_tag( $query ) ); + } + + /** + * Tests that the `data-wp-router-region` directive only adds the elements + * once, independently of the number of directives processed. + * + * @ticket 60356 + * + * @covers ::process_directives + */ + public function test_wp_router_region_adds_loading_bar_aria_live_region_only_once() { + $html = ' +
Interactive region
+
Another interactive region
+ '; + $new_html = $this->interactivity->process_directives( $html ); + $footer = $this->render_wp_footer(); + + $this->assertEquals( $html, $new_html ); + + $query = array( 'tag_name' => 'style' ); + + $p = new WP_HTML_Tag_Processor( $footer ); + $this->assertTrue( $p->next_tag( $query ) ); + $this->assertEquals( 'wp-interactivity-router_animations', $p->get_attribute( 'id' ) ); + $this->assertFalse( $p->next_tag( $query ) ); + + $query = array( + 'tag_name' => 'div', + 'class_name' => 'wp-interactivity-router_loading-bar', + ); + + $p = new WP_HTML_Tag_Processor( $footer ); + $this->assertTrue( $p->next_tag( $query ) ); + $this->assertFalse( $p->next_tag( $query ) ); + + $query = array( + 'tag_name' => 'div', + 'class_name' => 'screen-reader-text', + ); + + $p = new WP_HTML_Tag_Processor( $footer ); + $this->assertTrue( $p->next_tag( $query ) ); + $this->assertFalse( $p->next_tag( $query ) ); + } +}