diff --git a/lib/experimental/class-wp-webfonts-utils.php b/lib/experimental/class-wp-webfonts-utils.php new file mode 100644 index 0000000000000..cf506209bc8a0 --- /dev/null +++ b/lib/experimental/class-wp-webfonts-utils.php @@ -0,0 +1,113 @@ +registered[ $font_family_handle ] ) ) { if ( ! $this->add( $font_family_handle, false ) ) { - return false; + return null; } } @@ -162,22 +172,30 @@ public function add_variation( $font_family_handle, array $variation, $variation // Variation validation failed. if ( ! $variation ) { - return false; + return null; } if ( '' === $variation_handle ) { - $variation_handle = static::get_variation_handle( $font_family_handle, $variation ); + $variation_handle = WP_Webfonts_Utils::convert_variation_into_handle( $font_family_handle, $variation ); + if ( is_null( $variation_handle ) ) { + return null; + } + } + + // Bail out if the variant is already registered. + if ( $this->is_variation_registered( $font_family_handle, $variation_handle ) ) { + return $variation_handle; } - if ( $variation['src'] ) { + if ( array_key_exists( 'src', $variation ) ) { $result = $this->add( $variation_handle, $variation['src'] ); } else { - $result = $this->add( $variation_handle ); + $result = $this->add( $variation_handle, false ); } // Bail out if the registration failed. if ( ! $result ) { - return false; + return null; } $this->add_data( $variation_handle, 'font-properties', $variation ); @@ -190,6 +208,23 @@ public function add_variation( $font_family_handle, array $variation, $variation return $variation_handle; } + /** + * Checks if the variation is registered. + * + * @since 6.1.0 + * + * @param string $font_family_handle The font family's handle for this variation. + * @param string $variant_handle Variation's handle. + * @return bool + */ + private function is_variation_registered( $font_family_handle, $variant_handle ) { + if ( ! isset( $this->registered[ $font_family_handle ] ) ) { + return array(); + } + + return in_array( $variant_handle, $this->registered[ $font_family_handle ]->deps ); + } + /** * Adds a variation as a dependency to the given font family. * @@ -248,7 +283,7 @@ private function validate_variation( $font_family_handle, $variation ) { // Check the font-weight. if ( ! is_string( $variation['font-weight'] ) && ! is_int( $variation['font-weight'] ) ) { - trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.', 'gutenberg' ) ); + trigger_error( __( 'Webfont font-weight must be a properly formatted string or integer.', 'gutenberg' ) ); return false; } @@ -425,38 +460,24 @@ private function get_enqueued_fonts_for_provider( $provider_id ) { /** * Get the font slug. * - * @since 6.1.0 + * @since X.X.X + * @deprecated Use WP_Webfonts_Utils::convert_font_family_into_handle() * * @param array|string $to_convert The value to convert into a slug. Expected as the web font's array * or a font-family as a string. * @return string|false The font slug on success, or false if the font-family cannot be determined. */ public static function get_font_slug( $to_convert ) { - if ( is_array( $to_convert ) ) { - if ( isset( $to_convert['font-family'] ) ) { - $to_convert = $to_convert['font-family']; - } elseif ( isset( $to_convert['fontFamily'] ) ) { - $to_convert = $to_convert['fontFamily']; - } else { - _doing_it_wrong( __METHOD__, __( 'Could not determine the font family name.', 'gutenberg' ), '6.0.0' ); - return false; - } - } + _deprecated_function( + __METHOD__, + 'X.X.X', // Gutenberg version, not Core as this method will not be backported to Core. + 'Use WP_Webfonts_Utils::get_font_family_from_variation() to get the font family from an array and WP_Webfonts_Utils::convert_font_family_into_handle() to get the handle' + ); - return sanitize_title( $to_convert ); - } + $font_family = is_array( $to_convert ) + ? WP_Webfonts_Utils::get_font_family_from_variation( $to_convert ) + : $to_convert; - /** - * Gets a handle for the given variation. - * - * @since 6.1.0 - * - * @param string $font_family The font family's handle for this variation. - * @param array $variation An array of variation properties. - * @return string The variation handle. - */ - public static function get_variation_handle( $font_family, array $variation ) { - $handle = sprintf( '%s-%s', $font_family, implode( ' ', array( $variation['font-weight'], $variation['font-style'] ) ) ); - return sanitize_title( $handle ); + return WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); } } diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 44032e31515a5..d0281708bbf13 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -82,10 +82,16 @@ function gutenberg_register_webfonts_from_theme_json() { } } - $font_family_handle = array_key_exists( 'fontFamily', $font_face ) - ? WP_Webfonts::get_font_slug( $font_face['fontFamily'] ) - : $font_family['slug']; - $handles[] = $font_family_handle; + $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $font_face ); + if ( empty( $font_family_handle ) ) { + $font_family = $font_family['slug']; + } + $font_family_handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); + if ( is_null( $font_family_handle ) ) { + _doing_it_wrong( __FUNCTION__, __( 'Font family not defined in the variation or "slug".', 'gutenberg' ), '6.1.0' ); + } + + $handles[] = $font_family_handle; if ( ! array_key_exists( $font_family_handle, $webfonts ) ) { $webfonts[ $font_family_handle ] = array(); } diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index 0c0246397fe2c..f687d3ec07bbf 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -35,15 +35,21 @@ function wp_webfonts() { * * @since 6.1.0 * - * @param string $font_family The font family to register. - * @return bool Whether the font family has been registered. True on success, false on failure. + * @param string $font_family The font family's name or handle to register. + * @return string|null The font family handle when successfully registered. Else null. */ function wp_register_font_family( $font_family ) { - return wp_webfonts()->add( sanitize_title( $font_family ), false ); + $handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); + if ( ! $handle ) { + return null; + } + + $result = wp_webfonts()->add( $handle, false ) ? $handle : null; + return $result ? $handle : null; } } -if ( ! function_exists( 'wp_register_font_variation' ) ) { +if ( ! function_exists( 'wp_register_webfont_variation' ) ) { /** * Registers a variation to the given font family. * @@ -54,7 +60,7 @@ function wp_register_font_family( $font_family ) { * @param string $variation_handle Optional. The variation's handle. When none is provided, the * handle will be dynamically generated. * Default empty string. - * @return string|bool Variation handle on success. Else false. + * @return string|null Variation handle on success. Else null. */ function wp_register_webfont_variation( $font_family_handle, array $variation, $variation_handle = '' ) { return wp_webfonts()->add_variation( $font_family_handle, $variation, $variation_handle ); @@ -68,29 +74,43 @@ function wp_register_webfont_variation( $font_family_handle, array $variation, $ * @since 6.1.0 * * @param array[] $webfonts Web fonts to be registered. - * @return string[] The font family handle of the registered webfonts. + * @return string[] The font family handle of the registered web fonts. */ function wp_register_webfonts( array $webfonts ) { - $registered = array(); - $wp_webfonts = wp_webfonts(); + $registered = array(); foreach ( $webfonts as $font_family => $variations ) { - // Skip if the font family is not defined as a key. - if ( ! is_string( $font_family ) || empty( $font_family ) ) { + /* + * Handle the deprecated web font's structure but alert developers + * to modify their web font structure to group and key by font family. + * + * Note: This code block will not be backported to Core. + */ + if ( ! WP_Webfonts_Utils::is_defined( $font_family ) ) { + _doing_it_wrong( + __FUNCTION__, + __( 'Variations must be grouped and keyed by their font family.', 'gutenberg' ), + '6.1.0' + ); + $font_family_handle = wp_register_webfont( $variations ); + if ( ! $font_family_handle ) { + continue; + } + $registered[ $font_family_handle ] = true; continue; - } + } // end of code block for deprecated web fonts structure. - $font_family_handle = sanitize_title( $font_family ); - $is_registered = $wp_webfonts->add( $font_family_handle, false ); - if ( ! $is_registered ) { + $font_family_handle = wp_register_font_family( $font_family ); + if ( ! $font_family_handle ) { continue; } + // Register each of the variations for this font family. foreach ( $variations as $handle => $variation ) { - $wp_webfonts->add_variation( - $font_family_handle, + wp_register_webfont( $variation, - is_string( $handle ) && '' !== $handle ? $handle : '' + $font_family_handle, + WP_Webfonts_Utils::is_defined( $handle ) ? $handle : '' ); } @@ -103,31 +123,33 @@ function wp_register_webfonts( array $webfonts ) { if ( ! function_exists( 'wp_register_webfont' ) ) { /** - * Registers a single webfont. - * - * Example of how to register Source Serif Pro font with font-weight range of 200-900: - * - * If the font file is contained within the theme: + * Registers a single web font. * - * - * wp_register_webfont( - * array( - * 'provider' => 'local', - * 'font-family' => 'Source Serif Pro', - * 'font-weight' => '200 900', - * 'font-style' => 'normal', - * 'src' => get_theme_file_uri( 'assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2' ), - * ) - * ); - * - * - * @since 6.0.0 + * @since 6.1.0 * - * @param array $webfont Webfont to be registered. - * @return string|false The font family slug if successfully registered, else false. + * @param array $variation Array of variation properties to be registered. + * @param string $font_family_handle Optional. Font family handle for the given variation. + * Default empty string. + * @param string $variation_handle Optional. Handle for the variation to register. + * @return string|null The font family slug if successfully registered. Else null. */ - function wp_register_webfont( array $webfont ) { - return wp_webfonts()->register_webfont( $webfont ); + function wp_register_webfont( array $variation, $font_family_handle = '', $variation_handle = '' ) { + // When font family's handle is not passed, attempt to get it from the variation. + if ( ! WP_Webfonts_Utils::is_defined( $font_family_handle ) ) { + $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $variation ); + if ( $font_family ) { + $font_family_handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); + } + } + + if ( empty( $font_family_handle ) ) { + trigger_error( 'Font family handle must be a non-empty string.' ); + return null; + } + + return wp_webfonts()->add_variation( $font_family_handle, $variation, $variation_handle ) + ? $font_family_handle + : null; } } diff --git a/lib/load.php b/lib/load.php index 9600d3100d3b7..9f274ab9dc2eb 100644 --- a/lib/load.php +++ b/lib/load.php @@ -96,6 +96,7 @@ function gutenberg_is_experiment_enabled( $name ) { // Experimental features. remove_action( 'plugins_loaded', '_wp_theme_json_webfonts_handler' ); // Turns off WP 6.0's stopgap handler for Webfonts API. require __DIR__ . '/experimental/block-editor-settings-mobile.php'; +require __DIR__ . '/experimental/class-wp-webfonts-utils.php'; require __DIR__ . '/experimental/register-webfonts-from-theme-json.php'; require __DIR__ . '/experimental/class-wp-theme-json-gutenberg.php'; require __DIR__ . '/experimental/class-wp-theme-json-resolver-gutenberg.php'; diff --git a/phpunit/bootstrap.php b/phpunit/bootstrap.php index 9423c5a1efc5c..1b7967118a603 100644 --- a/phpunit/bootstrap.php +++ b/phpunit/bootstrap.php @@ -5,6 +5,10 @@ * @package Gutenberg */ +if ( ! defined( 'WP_DEBUG' ) ) { + define( 'WP_DEBUG', true ); +} + // Require composer dependencies. require_once dirname( __DIR__ ) . '/vendor/autoload.php'; diff --git a/phpunit/class-wp-webfonts-test.php b/phpunit/class-wp-webfonts-test.php deleted file mode 100644 index d900797b0274f..0000000000000 --- a/phpunit/class-wp-webfonts-test.php +++ /dev/null @@ -1,410 +0,0 @@ -old_wp_webfonts = $wp_webfonts; - - $wp_webfonts = null; - } - - public function tear_down() { - global $wp_webfonts; - - $wp_webfonts = $this->old_wp_webfonts; - parent::tear_down(); - } - - /** - * Test wp_register_webfont() register a single webfont. - * - * @covers wp_register_webfont - * @covers WP_Webfonts::register_font - * @covers WP_Webfonts::get_registered_fonts - * @covers WP_Webfonts::get_enqueued_fonts - */ - public function test_wp_register_webfont() { - $font_family_name = 'Source Serif Pro'; - - $font = array( - 'provider' => 'local', - 'font-family' => $font_family_name, - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ); - - $expected = array( - wp_webfonts()->get_font_slug( $font_family_name ) => array( $font ), - ); - - wp_register_webfont( $font ); - $this->assertEquals( $expected, wp_webfonts()->get_registered_webfonts() ); - $this->assertEquals( array(), wp_webfonts()->get_enqueued_webfonts() ); - } - - /** - * Test wp_register_webfont() does not enqueue the webfont on registration. - * - * @covers wp_register_webfont - * @covers WP_Webfonts::register_font - * @covers WP_Webfonts::get_registered_fonts - * @covers WP_Webfonts::get_enqueued_fonts - */ - public function test_wp_register_webfont_does_not_enqueue_on_registration() { - $font_family_name = 'Source Serif Pro'; - - $font = array( - 'provider' => 'local', - 'font-family' => $font_family_name, - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ); - - $expected = array( - wp_webfonts()->get_font_slug( $font_family_name ) => array( $font ), - ); - - wp_register_webfont( $font ); - $this->assertEquals( $expected, wp_webfonts()->get_registered_webfonts() ); - $this->assertEquals( array(), wp_webfonts()->get_enqueued_webfonts() ); - } - - /** - * Test wp_enqueue_webfonts() bulk enqueue webfonts. - * - * @covers wp_enqueue_webfonts - * @covers WP_Webfonts::enqueue_font - * @covers WP_Webfonts::get_enqueued_fonts - * @covers WP_Webfonts::get_registered_fonts - */ - public function test_wp_enqueue_webfonts() { - $source_serif_pro = array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ); - - wp_register_webfont( $source_serif_pro ); - - $roboto = array( - 'provider' => 'local', - 'font-family' => 'Roboto', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/roboto/Roboto.ttf.woff2', - 'font-display' => 'fallback', - ); - - wp_register_webfont( $roboto ); - - $expected = array( - wp_webfonts()->get_font_slug( $source_serif_pro['font-family'] ) => array( $source_serif_pro ), - wp_webfonts()->get_font_slug( $roboto['font-family'] ) => array( $roboto ), - ); - - wp_enqueue_webfonts( - array( - $source_serif_pro['font-family'], - $roboto['font-family'], - ) - ); - - $this->assertEquals( $expected, wp_webfonts()->get_enqueued_webfonts() ); - $this->assertEquals( array(), wp_webfonts()->get_registered_webfonts() ); - } - - /** - * Test wp_enqueue_font() enqueues a registered webfont. - * - * @covers wp_enqueue_webfont - * @covers WP_Webfonts::enqueued_font - * @covers WP_Webfonts::get_enqueued_fonts - * @covers WP_Webfonts::get_registered_fonts - */ - public function test_wp_enqueue_webfont_enqueues_registered_webfont() { - $font_family_name = 'Source Serif Pro'; - - $font = array( - 'provider' => 'local', - 'font-family' => $font_family_name, - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ); - - $expected = array( - wp_webfonts()->get_font_slug( $font_family_name ) => array( $font ), - ); - - wp_register_webfont( $font ); - wp_enqueue_webfont( $font_family_name ); - - $this->assertEquals( array(), wp_webfonts()->get_registered_webfonts() ); - $this->assertEquals( $expected, wp_webfonts()->get_enqueued_webfonts() ); - } - - /** - * Test wp_enqueue_font() does not enqueue a webfont that was not registered. - * - * @covers wp_enqueue_webfont - * @covers WP_Webfonts::enqueued_font - * @covers WP_Webfonts::get_enqueued_fonts - * @covers WP_Webfonts::get_registered_fonts - * - * @expectedIncorrectUsage WP_Webfonts::enqueue_webfont - */ - public function test_wp_enqueue_webfont_does_not_enqueue_unregistered_webfont() { - $font_family_name = 'Source Serif Pro'; - - wp_enqueue_webfont( $font_family_name ); - - $this->assertSame( array(), wp_webfonts()->get_registered_webfonts(), 'WP_Webfonts::get_registered_webfonts should return an empty array' ); - $this->assertSame( array(), wp_webfonts()->get_enqueued_webfonts(), 'WP_Webfonts::get_enqueued_webfonts should return an empty array' ); - } - - /** - * @covers wp_register_webfont - * @covers WP_Webfonts::register_provider - * @covers WP_Webfonts::get_providers - */ - public function test_get_providers() { - wp_register_webfont_provider( 'test-provider', 'Test_Provider' ); - $this->assertEquals( - array( - 'local' => 'WP_Webfonts_Provider_Local', - 'test-provider' => 'Test_Provider', - ), - wp_get_webfont_providers() - ); - } - - /** - * @dataProvider data_get_font_slug_when_cannot_determine_fontfamily - * @covers WP_Webfonts::get_font_slug - * - * @expectedIncorrectUsage WP_Webfonts::get_font_slug - */ - public function test_get_font_slug_when_cannot_determine_fontfamily( $to_convert ) { - $this->assertFalse( wp_webfonts()->get_font_slug( $to_convert ) ); - } - - /** - * Data provider. - * - * @return array[] - */ - public function data_get_font_slug_when_cannot_determine_fontfamily() { - return array( - 'empty array' => array( array() ), - 'array without a font-family key' => array( - array( - 'provider' => 'local', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-display' => 'fallback', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - ), - ), - "array with 'font family' key" => array( - array( 'font family' => 'Source Serif Pro' ), - ), - "array with 'Font-Family' key" => array( - array( 'Font-Family' => 'Source Serif Pro' ), - ), - "array with 'FontFamily' key" => array( - array( 'FontFamily' => 'Source Serif Pro' ), - ), - ); - } - - /** - * @dataProvider data_get_font_slug - * @covers WP_Webfonts::get_font_slug - */ - public function test_get_font_slug( $to_convert, $expected ) { - $this->assertSame( $expected, wp_webfonts()->get_font_slug( $to_convert ) ); - } - - /** - * Data provider. - * - * @return array[] - */ - public function data_get_font_slug() { - return array( - "array using 'fontFamily' format" => array( - 'to_convert' => array( 'fontFamily' => 'Source Serif Pro' ), - 'expected' => 'source-serif-pro', - ), - "array using 'font-family' format" => array( - 'to_convert' => array( 'font-family' => 'Source Serif Pro' ), - 'expected' => 'source-serif-pro', - ), - 'string with font family name' => array( - 'to_convert' => 'Source Serif Pro', - 'expected' => 'source-serif-pro', - ), - 'empty string' => array( - 'to_convert' => '', - 'expected' => '', - ), - ); - } - - /** - * @covers WP_Webfonts::validate_webfont - */ - public function test_validate_webfont() { - // Test empty array. - $this->assertFalse( wp_webfonts()->validate_webfont( array() ) ); - - $font = array( - 'font-family' => 'Test Font 1', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - ); - - // Test missing provider fallback to local. - $this->assertEquals( 'local', wp_webfonts()->validate_webfont( $font )['provider'] ); - - // Test missing font-weight fallback to 400. - $this->assertEquals( '400', wp_webfonts()->validate_webfont( $font )['font-weight'] ); - - // Test missing font-style fallback to normal. - $this->assertEquals( 'normal', wp_webfonts()->validate_webfont( $font )['font-style'] ); - - // Test missing font-display fallback to fallback. - $this->assertEquals( 'fallback', wp_webfonts()->validate_webfont( $font )['font-display'] ); - - // Test local font with missing "src". - $this->assertFalse( wp_webfonts()->validate_webfont( array( 'font-family' => 'Test Font 2' ) ) ); - - // Test valid src URL, without a protocol. - $font['src'] = '//example.com/SourceSerif4Variable-Roman.ttf.woff2'; - $this->assertEquals( wp_webfonts()->validate_webfont( $font )['src'], $font['src'] ); - - // Test font-weight. - $font_weights = array( 100, '100', '100 900', 'normal' ); - foreach ( $font_weights as $value ) { - $font['font-weight'] = $value; - $this->assertEquals( wp_webfonts()->validate_webfont( $font )['font-weight'], $value ); - } - - // Test that invalid keys get removed from the font. - $font['invalid-key'] = 'invalid'; - $this->assertArrayNotHasKey( 'invalid-key', wp_webfonts()->validate_webfont( $font ) ); - } - - /** - * Test generate_and_enqueue_styles outputs only enqueued webfonts. - * - * @covers WP_Webfonts::generate_and_enqueue_styles - */ - public function test_generate_and_enqueue_styles() { - wp_register_webfonts( - array( - array( - 'provider' => 'local', - 'font-family' => 'Roboto', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/roboto/Roboto-Regular.ttf', - 'font-display' => 'fallback', - ), - array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ), - ) - ); - - wp_enqueue_webfont( 'Source Serif Pro' ); - - wp_webfonts()->generate_and_enqueue_styles(); - - $expected = <<assertStringContainsString( - $expected, - get_echo( 'wp_print_styles' ) - ); - } - - /** - * Test generate_and_enqueue_editor_styles outputs registered and enqueued webfonts. - * Both are necessary so the editor correctly loads webfonts picked while in the editor. - * - * @covers WP_Webfonts::generate_and_enqueue_editor_styles - */ - public function test_generate_and_enqueue_editor_styles() { - wp_register_webfonts( - array( - array( - 'provider' => 'local', - 'font-family' => 'Roboto', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/roboto/Roboto-Regular.ttf', - 'font-display' => 'fallback', - ), - array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ), - ) - ); - - wp_enqueue_webfont( 'Source Serif Pro' ); - - wp_webfonts()->generate_and_enqueue_editor_styles(); - - $expected = <<assertStringContainsString( - $expected, - get_echo( 'wp_print_styles' ) - ); - } -} diff --git a/phpunit/old/class-wp-webfonts.php b/phpunit/old/class-wp-webfonts.php new file mode 100644 index 0000000000000..8e4bcf50e0747 --- /dev/null +++ b/phpunit/old/class-wp-webfonts.php @@ -0,0 +1,151 @@ +old_wp_webfonts = $wp_webfonts; + + $wp_webfonts = null; + } + + public function tear_down() { + global $wp_webfonts; + + $wp_webfonts = $this->old_wp_webfonts; + parent::tear_down(); + } + + /** + * Test wp_enqueue_webfonts() bulk enqueue webfonts. + * + * @covers wp_enqueue_webfonts + * @covers WP_Webfonts::enqueue_font + * @covers WP_Webfonts::get_enqueued_fonts + * @covers WP_Webfonts::get_registered_fonts + */ + public function test_wp_enqueue_webfonts() { + $source_serif_pro = array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ); + + wp_register_webfont( $source_serif_pro ); + + $roboto = array( + 'provider' => 'local', + 'font-family' => 'Roboto', + 'font-style' => 'normal', + 'font-weight' => '400', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/roboto/Roboto.ttf.woff2', + 'font-display' => 'fallback', + ); + + wp_register_webfont( $roboto ); + + $expected = array( + wp_webfonts()->get_font_slug( $source_serif_pro['font-family'] ) => array( $source_serif_pro ), + wp_webfonts()->get_font_slug( $roboto['font-family'] ) => array( $roboto ), + ); + + wp_enqueue_webfonts( + array( + $source_serif_pro['font-family'], + $roboto['font-family'], + ) + ); + + $this->assertEquals( $expected, wp_webfonts()->get_enqueued_webfonts() ); + $this->assertEquals( array(), wp_webfonts()->get_registered_webfonts() ); + } + + /** + * Test wp_enqueue_font() enqueues a registered webfont. + * + * @covers wp_enqueue_webfont + * @covers WP_Webfonts::enqueued_font + * @covers WP_Webfonts::get_enqueued_fonts + * @covers WP_Webfonts::get_registered_fonts + */ + public function test_wp_enqueue_webfont_enqueues_registered_webfont() { + $font_family_name = 'Source Serif Pro'; + + $font = array( + 'provider' => 'local', + 'font-family' => $font_family_name, + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ); + + $expected = array( + wp_webfonts()->get_font_slug( $font_family_name ) => array( $font ), + ); + + wp_register_webfont( $font ); + wp_enqueue_webfont( $font_family_name ); + + $this->assertEquals( array(), wp_webfonts()->get_registered_webfonts() ); + $this->assertEquals( $expected, wp_webfonts()->get_enqueued_webfonts() ); + } + + /** + * Test wp_enqueue_font() does not enqueue a webfont that was not registered. + * + * @covers wp_enqueue_webfont + * @covers WP_Webfonts::enqueued_font + * @covers WP_Webfonts::get_enqueued_fonts + * @covers WP_Webfonts::get_registered_fonts + * + * @expectedIncorrectUsage WP_Webfonts::enqueue_webfont + */ + public function test_wp_enqueue_webfont_does_not_enqueue_unregistered_webfont() { + $font_family_name = 'Source Serif Pro'; + + wp_enqueue_webfont( $font_family_name ); + + $this->assertSame( array(), wp_webfonts()->get_registered_webfonts(), 'WP_Webfonts::get_registered_webfonts should return an empty array' ); + $this->assertSame( array(), wp_webfonts()->get_enqueued_webfonts(), 'WP_Webfonts::get_enqueued_webfonts should return an empty array' ); + } + + /** + * @covers wp_register_webfont + * @covers WP_Webfonts::register_provider + * @covers WP_Webfonts::get_providers + */ + public function test_get_providers() { + wp_register_webfont_provider( 'test-provider', 'Test_Provider' ); + $this->assertEquals( + array( + 'local' => 'WP_Webfonts_Provider_Local', + 'test-provider' => 'Test_Provider', + ), + wp_get_webfont_providers() + ); + } +} diff --git a/phpunit/webfonts/wp-webfonts-testcase.php b/phpunit/webfonts/wp-webfonts-testcase.php new file mode 100644 index 0000000000000..1f861fe1e850b --- /dev/null +++ b/phpunit/webfonts/wp-webfonts-testcase.php @@ -0,0 +1,80 @@ +old_wp_webfonts = $GLOBALS['wp_webfonts']; + $GLOBALS['wp_webfonts'] = null; + } + + public function tear_down() { + $GLOBALS['wp_webfonts'] = $this->old_wp_webfonts; + parent::tear_down(); + } + + protected function set_up_mock( $method ) { + if ( is_string( $method ) ) { + $method = array( $method ); + } + $mock = $this->getMockBuilder( WP_Webfonts::class )->setMethods( $method )->getMock(); + + // Set the global. + $GLOBALS['wp_webfonts'] = $mock; + + return $mock; + } + + protected function get_registered_handles() { + return array_keys( $this->get_registered() ); + } + + protected function get_registered() { + return wp_webfonts()->registered; + } + + protected function get_variations( $font_family, $wp_webfonts = null ) { + if ( ! $wp_webfonts ) { + $wp_webfonts = wp_webfonts(); + } + return $wp_webfonts->registered[ $font_family ]->deps; + } + + protected function get_enqueued_handles() { + return wp_webfonts()->queue; + } + + protected function get_queued_before_register() { + return $this->get_property_value( 'queued_before_register', WP_Dependencies::class ); + } + + protected function get_property_value( $property_name, $class, $wp_webfonts = null ) { + $property = new ReflectionProperty( $class, $property_name ); + $property->setAccessible( true ); + + if ( ! $wp_webfonts ) { + $wp_webfonts = wp_webfonts(); + } + return $property->getValue( $wp_webfonts ); + } +} diff --git a/phpunit/webfonts/wp-webfonts-tests-dataset.php b/phpunit/webfonts/wp-webfonts-tests-dataset.php new file mode 100644 index 0000000000000..15d3abce1b2ef --- /dev/null +++ b/phpunit/webfonts/wp-webfonts-tests-dataset.php @@ -0,0 +1,299 @@ + array( + 'expected' => 'lato-400-normal', + 'font_family_handle' => 'lato', + 'variation' => array( + 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', + ), + ), + + 'font-weight and font-style not defined; with variation handle' => array( + 'expected' => 'my-custom-handle', + 'font_family_handle' => 'lato', + 'variation' => array( + 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', + ), + 'variation_handle' => 'my-custom-handle', + ), + + 'font-weight defined; without variation handle' => array( + 'expected' => 'source-serif-pro-200-900-normal', + 'font_family_handle' => 'source-serif-pro', + 'variation' => array( + 'font-family' => 'Source Serif Pro', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + ), + ), + + 'font-weight defined; with variation handle' => array( + 'expected' => 'my_custom_handle', + 'font_family_handle' => 'source-serif-pro', + 'variation' => array( + 'font-family' => 'Source Serif Pro', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + ), + 'variation_handle' => 'my_custom_handle', + ), + + 'font-weight defined; without variation handle' => array( + 'expected' => 'source-serif-pro-200-900-normal', + 'font_family_handle' => 'source-serif-pro', + 'variation' => array( + 'font-family' => 'Source Serif Pro', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + ), + ), + + 'font-weight defined; with variation handle' => array( + 'expected' => 'my_custom_handle', + 'font_family_handle' => 'source-serif-pro', + 'variation' => array( + 'font-family' => 'Source Serif Pro', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + ), + 'variation_handle' => 'my_custom_handle', + ), + + 'font-weight defined; without variation handle' => array( + 'expected' => 'source-serif-pro-200-900-normal', + 'font_family_handle' => 'source-serif-pro', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + + 'more variation properties; with variation handle' => array( + 'expected' => 'my-custom-handle', + 'font_family_handle' => 'source-serif-pro', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'variation_handle' => 'my-custom-handle', + ), + ); + } + + /** + * Data provider for testing registration of variations where the font family is not defined. + * + * @return array + */ + public function data_font_family_not_define_in_variation() { + return array( + 'empty string font family handle' => array( + 'font_family_handle' => '', + 'variation' => array( + 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', + ), + 'expected_message' => 'Font family handle must be a non-empty string', + ), + 'empty string font family handle with font-family defined in variant' => array( + 'font_family_handle' => '', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Lato', + 'font-weight' => '200', + 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', + ), + 'expected_message' => 'Font family handle must be a non-empty string', + ), + 'non string font family handle' => array( + 'font_family_handle' => 10, + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family handle must be a non-empty string', + ), + ); + } + + /** + * Data provider for testing when the variation's handle can't be determine from the given input. + * + * @return array + */ + public function data_unable_determine_variation_handle() { + return array( + 'integer values' => array( + 'font_family_handle' => 'lato', + 'variation' => array( + 'font-weight' => 400, + 'font-style' => 0, + 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2', + ), + 'expected_message' => 'Variant handle could not be determined as font-weight and/or font-style are require', + ), + 'with empty string font-weight and font-style' => array( + 'font_family_handle' => 'merriweather', + 'variation' => array( + 'font-weight' => '', + 'font-style' => '', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + 'expected_message' => 'Variant handle could not be determined as font-weight and/or font-style are require', + ), + 'integer font-weight, empty string font-style' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-weight' => 400, + 'font-style' => '', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + 'expected_message' => 'Variant handle could not be determined as font-weight and/or font-style are require', + ), + 'empty string font-weight, integer font-style' => array( + 'font_family' => 'lato', + 'variation' => array( + 'font-weight' => '', + 'font-style' => 400, + 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2', + ), + 'expected_message' => 'Variant handle could not be determined as font-weight and/or font-style are require', + ), + ); + } + + /** + * Data provider for testing an invalid variation. + * + * @return array + */ + public function data_invalid_variation() { + return array( + 'src: undefined' => array( + 'expected' => 'Webfont src must be a non-empty string or an array of strings.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Some font', + 'font-weight' => '200', + ), + ), + 'src: null' => array( + 'expected' => 'Webfont src must be a non-empty string or an array of strings.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Some font', + 'font-weight' => '200', + 'src' => null, + ), + ), + 'src: empty string' => array( + 'expected' => 'Webfont src must be a non-empty string or an array of strings.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Some font', + 'font-weight' => '200', + 'src' => '', + ), + ), + 'src: empty array' => array( + 'expected' => 'Webfont src must be a non-empty string or an array of strings.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-weight' => '200', + 'src' => array(), + ), + ), + 'src: array of an empty string' => array( + 'expected' => 'Each webfont src must be a non-empty string.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-weight' => '200', + 'src' => array( '' ), + ), + ), + 'src: array of a non-string' => array( + 'expected' => 'Each webfont src must be a non-empty string.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-weight' => '200', + 'src' => array( null ), + ), + ), + 'src: array with an empty string' => array( + 'expected' => 'Each webfont src must be a non-empty string.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-weight' => '200', + 'src' => array( + 'https://example.com/assets/fonts/merriweather.ttf.woff2', + '', + 'https://example.com/assets/fonts/lato.ttf.woff2', + ), + ), + ), + 'src: array with a non-string' => array( + 'expected' => 'Each webfont src must be a non-empty string.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-weight' => '200', + 'src' => array( + 'https://example.com/assets/fonts/merriweather.ttf.woff2', + null, + 'https://example.com/assets/fonts/lato.ttf.woff2', + ), + ), + ), + 'provider does not exist' => array( + 'expected' => 'The provider class specified does not exist.', + 'font_family_handle' => 'merriweather', + 'variation' => array( + 'provider' => 'doesnotexit', + 'font-weight' => '200 900', + ), + ), + 'font-weight: null' => array( + 'expected' => 'Webfont font-weight must be a properly formatted string or integer.', + 'font_family_handle' => 'merriweather', + 'variation' => array( + 'font-weight' => null, + 'font-style' => 'normal', + 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2', + ), + ), + ); + } +} diff --git a/phpunit/webfonts/wpEnqueueWebfont-test.php b/phpunit/webfonts/wpEnqueueWebfont-test.php new file mode 100644 index 0000000000000..7b61e9057867e --- /dev/null +++ b/phpunit/webfonts/wpEnqueueWebfont-test.php @@ -0,0 +1,147 @@ +set_up_mock( 'enqueue' ); + $mock->expects( $this->once() ) + ->method( 'enqueue' ) + ->with( + $this->identicalTo( $font_family ) + ); + + wp_enqueue_webfont( $font_family ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_unit_enqueue() { + return array( + 'single word handle' => array( 'lato' ), + 'multiple word handle' => array( 'source-sans-pro' ), + 'single word name' => array( 'Merriweather' ), + 'multiple word name' => array( 'My Cool Font' ), + ); + } + + /** + * Integration test for enqueuing a font family and all of its variations. + * + * @dataProvider data_enqueue + * + * @param string $font_family Font family to test. + * @param array $variations Variations. + * @param array $expected_handles Array of expected handles. + */ + public function test_enqueue_after_registration( $font_family, $variations, $expected_handles ) { + $this->setup_register( $font_family, $variations ); + + wp_enqueue_webfont( $font_family ); + $this->assertSame( $expected_handles, $this->get_enqueued_handles() ); + } + + /** + * Integration test for enqueuing before registering a font family and all of its variations. + * + * @dataProvider data_enqueue + * + * @param string $font_family Font family to test. + */ + public function test_enqueue_before_registration( $font_family ) { + wp_enqueue_webfont( $font_family ); + + $expected = array( $font_family => null ); + $this->assertSame( $expected, $this->get_queued_before_register(), 'Font family should be added to before registered queue' ); + $this->assertEmpty( $this->get_enqueued_handles(), 'Font family should not be added to the enqueue queue' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_enqueue() { + return array( + 'one family family without variations' => array( + 'font_family' => 'lato', + 'variations' => array(), + 'expected_handles' => array( 'lato' ), + ), + 'one family family with 1 variation' => array( + 'font_family' => 'merriweather', + 'variations' => array( + 'merriweather-200-900-normal' => array( + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + ), + 'expected_handles' => array( 'merriweather' ), + ), + 'font family keyed with name' => array( + 'font_family' => 'Source Serif Pro', + 'variations' => array( + 'Source Serif Pro-300-normal' => array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '300', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'Source Serif Pro-900-italic' => array( + 'provider' => 'local', + 'font-style' => 'italic', + 'font-weight' => '900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + 'expected_handles' => array( 'Source Serif Pro' ), + ), + ); + } + + /** + * Register one or more font-family and its variations to set up a test. + * + * @param string $font_family Font family to test. + * @param array $variations Variations. + */ + private function setup_register( $font_family, $variations ) { + $wp_webfonts = wp_webfonts(); + + $wp_webfonts->add( $font_family, false ); + + foreach ( $variations as $variation_handle => $variation ) { + if ( ! is_string( $variation_handle ) ) { + $variation_handle = ''; + } + $wp_webfonts->add_variation( $font_family, $variation, $variation_handle ); + } + } +} diff --git a/phpunit/webfonts/wpRegisterFontFamily-test.php b/phpunit/webfonts/wpRegisterFontFamily-test.php index 63d5281e525ce..6064fbac37c76 100644 --- a/phpunit/webfonts/wpRegisterFontFamily-test.php +++ b/phpunit/webfonts/wpRegisterFontFamily-test.php @@ -2,56 +2,132 @@ /** * Register font family tests. * - * @package WordPress + * @package WordPress * @subpackage Webfonts */ +require_once __DIR__ . '/wp-webfonts-testcase.php'; + /** * @group webfonts * @covers ::wp_register_font_family */ -class Tests_Webfonts_WpRegisterFontFamily extends WP_UnitTestCase { +class Tests_Webfonts_WpRegisterFontFamily extends WP_Webfonts_TestCase { + /** - * WP_Webfonts instance reference + * Unit test for registering a font-family that mocks WP_Webfonts. * - * @var WP_Webfonts + * @dataProvider data_font_family + * + * @param string $font_family Font family to test. + * @param string $expected_handle Expected registered handle. */ - private $old_wp_webfonts; + public function test_unit_register( $font_family, $expected_handle ) { + $mock = $this->set_up_mock( 'add' ); + $mock->expects( $this->once() ) + ->method( 'add' ) + ->with( + $this->identicalTo( $expected_handle ), + $this->identicalTo( false ) + ) + ->will( $this->returnValue( $expected_handle ) ); - public function set_up() { - parent::set_up(); + $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family should return true after registering' ); + } - global $wp_webfonts; - $this->old_wp_webfonts = $wp_webfonts; + /** + * Integration test for registering a font family. + * + * @dataProvider data_font_family + * + * @covers WP_Webfonts::add + * + * @param string $font_family Font family to test. + * @param string $expected_handle Expected registered handle. + */ + public function test_register( $font_family, $expected_handle ) { + $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family should return true after registering' ); + $this->assertSame( array( $expected_handle ), $this->get_registered_handles(), 'After registering, the registry should contain the font family handle' ); + } - $wp_webfonts = null; + /** + * Data provider. + * + * @return array + */ + public function data_font_family() { + return array( + 'single word name' => array( + 'font_family' => 'Lato', + 'expected_handle' => 'lato', + ), + 'multiple word name' => array( + 'font_family' => 'Source Sans Pro', + 'expected_handle' => 'source-sans-pro', + ), + 'handle' => array( + 'font_family' => 'source-serif-pro', + 'expected_handle' => 'source-serif-pro', + ), + ); } - public function tear_down() { - global $wp_webfonts; + /** + * Unit test for registering a font-family that mocks WP_Webfonts. + * + * @dataProvider data_invalid_font_family + * + * @param string $invalid_input Invalid input to test. + */ + public function test_unit_register_fails( $invalid_input ) { + $mock = $this->set_up_mock( 'add' ); + $mock->expects( $this->never() )->method( 'add' ); - $wp_webfonts = $this->old_wp_webfonts; - parent::tear_down(); + $this->assertNull( wp_register_font_family( $invalid_input ), 'Registering an invalid input should return null' ); } /** - * @dataProvider data_font_family_registers + * Integration test for registering a font family. + * + * @dataProvider data_invalid_font_family * - * @param string $font_family Text to test. + * @covers WP_Webfonts::add + * + * @param string $invalid_input Invalid input to test. */ - public function test_font_family_registers( $font_family ) { - $this->assertTrue( wp_register_font_family( $font_family ) ); + public function test_register_fails( $invalid_input ) { + $this->assertNull( wp_register_font_family( $invalid_input ), 'Registering an invalid input should return null' ); + $this->assertEmpty( $this->get_registered(), 'Invalid input should not register' ); } /** - * Data Provider + * Data provider. * * @return array */ - public function data_font_family_registers() { + public function data_invalid_font_family() { return array( - 'Proper name' => array( 'Lato' ), - 'as a slug' => array( 'source-serif-pro' ), + 'non-string' => array( null ), + 'empty string' => array( '' ), ); } + + /** + * Integration test for attempting to re-register a font family. + * + * @dataProvider data_font_family + * + * @covers WP_Webfonts::add + * + * @param string $font_family Font family to test. + * @param string $expected_handle Expected registered handle. + */ + public function test_re_register( $font_family, $expected_handle ) { + // Register the font family. + wp_register_font_family( $font_family ); + + // Attempt to re-register it. + $this->assertNull( wp_register_font_family( $font_family ), 'Font family should return true after registering' ); + $this->assertSame( array( $expected_handle ), $this->get_registered_handles(), 'The font family should only be registered once' ); + } } diff --git a/phpunit/webfonts/wpRegisterVariant-test.php b/phpunit/webfonts/wpRegisterVariant-test.php deleted file mode 100644 index 8dfd0adf969e7..0000000000000 --- a/phpunit/webfonts/wpRegisterVariant-test.php +++ /dev/null @@ -1,105 +0,0 @@ -old_wp_webfonts = $wp_webfonts; - - $wp_webfonts = null; - } - - public function tear_down() { - global $wp_webfonts; - - $wp_webfonts = $this->old_wp_webfonts; - parent::tear_down(); - } - - /** - * @dataProvider data_variation_registers - * - * @param string|bool $expected Expected results. - * @param string $font_family_handle The font family's handle for this variation. - * @param array $variation An array of variation properties to add. - * @param string $variation_handle Optional. The variation's handle. - */ - public function test_variation_registers( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { - $this->assertSame( $expected, wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle ) ); - } - - /** - * Data Provider - * - * @return array - */ - public function data_variation_registers() { - return array( - 'fewer variation properties; without variation handle' => array( - 'expected' => 'lato-200-normal', - 'font_family_handle' => 'lato', - 'variation' => array( - 'font-style' => 'normal', - 'font-weight' => '200', - 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', - ), - ), - 'fewer variation properties; with variation handle' => array( - 'expected' => 'lato-my-custom-handle', - 'font_family_handle' => 'lato', - 'variation' => array( - 'font-style' => 'normal', - 'font-weight' => '200', - 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', - ), - 'variation_handle' => 'lato-my-custom-handle', - ), - 'more variation properties; without variation handle' => array( - 'expected' => 'source-serif-pro-200-900-normal', - 'font_family_handle' => 'source-serif-pro', - 'variation' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ), - ), - 'more variation properties; with variation handle' => array( - 'expected' => 'my-custom-handle', - 'font_family_handle' => 'source-serif-pro', - 'variation' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ), - 'variation_handle' => 'my-custom-handle', - ), - ); - } -} diff --git a/phpunit/webfonts/wpRegisterWebfont-test.php b/phpunit/webfonts/wpRegisterWebfont-test.php new file mode 100644 index 0000000000000..837e454ab75ba --- /dev/null +++ b/phpunit/webfonts/wpRegisterWebfont-test.php @@ -0,0 +1,281 @@ +add( $handle, false ); + } + + /** + * Unit test for registering a variation with a variation handle given. + * + * @dataProvider data_register + * + * @param string $font_family_handle Font family for this variation. + * @param array $variation Web font to test. + * @param array $expected Expected results. + */ + public function test_register_with_mock_when_handle_given( $font_family_handle, array $variation, $expected ) { + $mock = $this->set_up_mock(); + $variation_handle = $expected[1]; + + $mock->expects( $this->once() ) + ->method( 'add_variation' ) + ->with( + $this->identicalTo( $font_family_handle ), + $this->identicalTo( $variation ), + $this->identicalTo( $variation_handle ) + ) + ->will( $this->returnValue( $font_family_handle ) ); + + $this->assertSame( $font_family_handle, wp_register_webfont( $variation, $font_family_handle, $variation_handle ) ); + } + + /** + * Integration test for registering a variation when the font family was previously registered. + * + * @dataProvider data_register + * + * @covers WP_Webfonts::add_variation + * + * @param string $font_family_handle Font family for this variation. + * @param array $variation Web font to test. + * @param array $expected Expected results. + */ + public function test_register( $font_family_handle, array $variation, $expected ) { + $this->setup_font_family( $font_family_handle ); + + $this->assertSame( $font_family_handle, wp_register_webfont( $variation, $font_family_handle ), 'Registering should return the font family handle' ); + $this->assertSame( $expected, $this->get_registered_handles(), 'Registry should contain the font family and variant handles' ); + } + + /** + * Integration test for testing the font family is registered during the variation registration process. + * + * @dataProvider data_register_with_deprecated_structure + * + * @covers WP_Webfonts::add + * @covers WP_Webfonts::add_variation + * + * @param array $variation Web font to test. + * @param array $expected Expected results. + */ + public function test_registers_font_family( array $variation, $expected ) { + $font_family_handle = $expected[0]; + + wp_register_webfont( $variation ); + $this->assertContains( $font_family_handle, $this->get_registered_handles() ); + } + + /** + * Integration test to ensure registration does not automatically enqueue. + * + * @dataProvider data_register + * + * @covers WP_Webfonts::add_variation + * + * @param string $font_family_handle Font family handle. + * @param array $variation Variation. + */ + public function test_does_not_enqueue_when_registering( $font_family_handle, array $variation ) { + $this->setup_font_family( $font_family_handle ); + wp_register_webfont( $variation, $font_family_handle ); + + $this->assertEmpty( $this->get_enqueued_handles() ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_register() { + return array( + 'Source Serif Pro' => array( + 'font_family' => 'source-serif-pro', + 'variation' => array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected' => array( + 'source-serif-pro', + 'source-serif-pro-200-900-normal', + ), + ), + 'Merriweather' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-style' => 'italic', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + 'expected' => array( + 'merriweather', + 'merriweather-400-italic', + ), + ), + ); + } + + /** + * @dataProvider data_register_with_deprecated_structure + * + * @covers WP_Webfonts::add_variation + * + * @param array $variation Web font to test. + * @param array $expected Expected results. + */ + public function test_registers_with_deprecated_structure( + array $variation, $expected + ) { + $font_family_handle = $expected[0]; + $this->setup_font_family( $font_family_handle ); + + $this->assertSame( $font_family_handle, wp_register_webfont( $variation ), 'Registering should return the registered font family handle' ); + $this->assertSame( $expected, $this->get_registered_handles(), 'Registry should contain the font family and variant handles' ); + } + + /** + * @dataProvider data_register_with_deprecated_structure + * + * @covers WP_Webfonts::add_variation + * + * @param array $variation Web font to test. + * @param array $expected Expected results. + */ + public function test_registers_font_family_with_deprecated_structure( + array $variation, $expected + ) { + $font_family_handle = $expected[0]; + + wp_register_webfont( $variation ); + $this->assertContains( $font_family_handle, $this->get_registered_handles() ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_register_with_deprecated_structure() { + return array( + 'font-family as name' => array( + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-weight' => '200 900', + 'src' => 'https://example.com/assets/fonts/font.ttf.woff2', + ), + 'expected' => array( + 'source-serif-pro', + 'source-serif-pro-200-900-normal', + ), + ), + 'font-family as handle/slug' => array( + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'my-font-family', + 'font-style' => 'italic', + 'src' => 'https://example.com/assets/fonts/font.ttf.woff2', + ), + 'expected' => array( + 'my-font-family', + 'my-font-family-400-italic', + ), + ), + ); + } + + /** + * Integration test for testing when font family registration fails. + * + * @dataProvider data_invalid_font_family + * + * @param string $font_family_handle Font family for this variation. + * @param array $variation Web font to test. + * @param string $expected_meessage Expected notice message. + */ + public function test_font_family_registration_fails( $font_family_handle, array $variation, $expected_meessage ) { + $this->expectNotice(); + $this->expectNoticeMessage( $expected_meessage ); + + $this->assertNull( wp_register_webfont( $variation, $font_family_handle ), 'Should return null when invalid font family given' ); + $this->assertEmpty( $this->get_registered_handles(), 'Font family and variation should not be registered' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_invalid_font_family() { + return array( + 'non-string' => array( + 'font_family_handle' => null, + 'variation' => array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family not found.', + 'font-family' => null, + ), + 'empty string' => array( + 'font_family_handle' => '', + 'variation' => array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family not found.', + ), + 'non-string in deprecated structure' => array( + 'font_family_handle' => '', + 'variation' => array( + 'provider' => 'local', + 'font-family' => null, + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family not defined in the variation.', + ), + 'empty string in deprecated structure' => array( + 'font_family_handle' => '', + 'variation' => array( + 'provider' => 'local', + 'font-family' => '', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family not defined in the variation.', + ), + ); + } +} diff --git a/phpunit/webfonts/wpRegisterWebfontVariation-test.php b/phpunit/webfonts/wpRegisterWebfontVariation-test.php new file mode 100644 index 0000000000000..d2445f86fe5f4 --- /dev/null +++ b/phpunit/webfonts/wpRegisterWebfontVariation-test.php @@ -0,0 +1,133 @@ +add( $font_family_handle, false ); + + $variation_handle = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle ); + $this->assertSame( $expected, $variation_handle, 'Variation should return handle' ); + $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle ), 'Variation should be registered to font family' ); + } + + /** + * @dataProvider data_valid_variation + * + * @param string|bool $expected Expected results. + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $variation_handle Optional. The variation's handle. + */ + public function test_variation_already_registered( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { + wp_webfonts()->add( $font_family_handle, false ); + + // Set up the test. + $variation_handle = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle ); + + // Run the test. + $variant_handle_on_reregister = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle ); + $this->assertSame( $expected, $variant_handle_on_reregister, 'Variation should be registered to font family' ); + $this->assertSame( $variation_handle, $variant_handle_on_reregister, 'Variation should return the previously registered variant handle' ); + $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle ), 'Variation should only be registered once' ); + $expected = array( $font_family_handle, $variation_handle ); + $this->assertSameSets( $expected, $this->get_registered_handles(), 'Register queue should contain the font family and its one variant' ); + } + + /** + * @dataProvider data_valid_variation + * + * @param string|bool $expected Expected results. + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $variation_handle Optional. The variation's handle. + */ + public function test_register_font_family_and_variation( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { + $variation_handle = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle ); + $this->assertSame( $expected, $variation_handle, 'Variation should return its registered handle' ); + + // Extra checks to ensure both are registered. + $expected = array( $font_family_handle, $variation_handle ); + $this->assertSame( $expected, wp_webfonts()->get_registered(), 'Font family and variation should be registered' ); + $this->assertSame( array( $variation_handle ), wp_webfonts()->get_variations( $font_family_handle ), 'Variation should be registered to the font family' ); + } + + /** + * @dataProvider data_font_family_not_define_in_variation + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + */ + public function test_should_not_register_font_family_or_variant( $font_family_handle, array $variation ) { + $this->expectNotice(); + $this->expectNoticeMessage( 'Font family handle must be a non-empty string.' ); + + wp_register_webfont_variation( $font_family_handle, $variation ); + $this->assertEmpty( wp_webfonts()->get_registered(), 'Registered queue should be empty' ); + $this->assertEmpty( wp_webfonts()->get_variations( $font_family_handle ), 'Variation should not be registered to the font family' ); + } + + /** + * @dataProvider data_font_family_not_define_in_variation + * @dataProvider data_unable_determine_variation_handle + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $expected_message Expected notice message. + */ + public function test_should_not_register_variation_when_font_family_not_defined( $font_family_handle, array $variation, $expected_message ) { + $this->expectNotice(); + $this->expectNoticeMessage( $expected_message ); + + $this->assertNull( wp_register_webfont_variation( $font_family_handle, $variation ) ); + } + + /** + * @dataProvider data_unable_determine_variation_handle + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + */ + public function test_should_register_font_family_when_variant_fails_to_register( $font_family_handle, array $variation ) { + $this->expectNotice(); + $this->expectNoticeMessage( 'Variant handle could not be determined as font-weight and/or font-style are require' ); + + wp_register_webfont_variation( $font_family_handle, $variation ); + $expected = $font_family_handle; + $this->assertContains( $expected, wp_webfonts()->get_registered() ); + } + + /** + * @dataProvider data_invalid_variation + * + * @param string $expected_message Expected notice message. + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + */ + public function test_should_not_register_when_variation_fails_validation( $expected_message, $font_family_handle, array $variation ) { + $this->expectNotice(); + $this->expectNoticeMessage( $expected_message ); + + $this->assertNull( wp_register_webfont_variation( $font_family_handle, $variation ) ); + } +} diff --git a/phpunit/webfonts/wpRegisterWebfonts-test.php b/phpunit/webfonts/wpRegisterWebfonts-test.php index 4354afda8b7b9..5a85e746b0921 100644 --- a/phpunit/webfonts/wpRegisterWebfonts-test.php +++ b/phpunit/webfonts/wpRegisterWebfonts-test.php @@ -6,84 +6,66 @@ * @subpackage Webfonts */ +require_once __DIR__ . '/wp-webfonts-testcase.php'; + /** * @group webfonts * @covers ::wp_register_webfonts + * @covers WP_Webfonts::add + * @covers WP_Webfonts::add_variation */ -class Tests_Webfonts_WpRegisterWebfonts extends WP_UnitTestCase { +class Tests_Webfonts_WpRegisterWebfonts extends WP_Webfonts_TestCase { + use WP_Webfonts_Tests_Datasets; + /** - * WP_Webfonts instance reference + * @dataProvider data_webfonts * - * @var WP_Webfonts + * @param array $webfonts Array of webfonts to test. + * @param array $expected Expected results. */ - private $old_wp_webfonts; - - public function set_up() { - parent::set_up(); - - global $wp_webfonts; - $this->old_wp_webfonts = $wp_webfonts; - - $wp_webfonts = null; - } - - public function tear_down() { - global $wp_webfonts; - - $wp_webfonts = $this->old_wp_webfonts; - parent::tear_down(); + public function test_register( array $webfonts, array $expected ) { + $this->assertSame( $expected['wp_register_webfonts'], wp_register_webfonts( $webfonts ), 'Font family handle(s) should be returned' ); + $this->assertSame( $expected['get_registered'], $this->get_registered_handles(), 'Web fonts should match registered queue' ); } /** - * Test wp_register_webfonts() bulk register webfonts. + * @dataProvider data_deprecated_structure * - * @dataProvider data_wp_register_webfonts - * - * @covers wp_register_webfonts - * @covers WP_Webfonts::add - * @covers WP_Webfonts::add_variation + * @expectedIncorrectUsage wp_register_webfonts * * @param array $webfonts Array of webfonts to test. * @param array $expected Expected results. */ - public function test_wp_register_webfonts( array $webfonts, array $expected ) { + public function test_register_with_deprecated_structure( array $webfonts, array $expected ) { + $this->expectNotice(); + $this->expectNoticeMessage( $expected['message'] ); + $this->assertSame( $expected['wp_register_webfonts'], wp_register_webfonts( $webfonts ), 'Font family handle(s) should be returned' ); - $this->assertSame( $expected['get_registered'], wp_webfonts()->get_registered(), 'Web fonts should match registered queue' ); - $this->assertSame( array(), wp_webfonts()->get_enqueued(), 'No web fonts should be enqueued' ); + $this->assertSame( $expected['get_registered'], $this->get_registered_handles(), 'Web fonts should match registered queue' ); + } + + /** + * @dataProvider data_webfonts + * + * @param array $webfonts Array of webfonts to test. + */ + public function test_web_fonts_do_not_enqueue_on_registration( array $webfonts ) { + wp_register_webfonts( $webfonts ); + $this->assertEmpty( $this->get_enqueued_handles() ); } /** * Data provider. * - * @return array[] + * @return array */ - public function data_wp_register_webfonts() { + public function data_webfonts() { return array( - 'font family not keyed' => array( - 'webfonts' => array( - array( - array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ), - ), - ), - 'expected' => array( - 'wp_register_webfonts' => array(), - 'get_registered' => array(), - ), - ), 'font family keyed with slug' => array( 'webfonts' => array( 'source-serif-pro' => array( array( 'provider' => 'local', - 'font-family' => 'Source Serif Pro', 'font-style' => 'normal', 'font-weight' => '200 900', 'font-stretch' => 'normal', @@ -105,7 +87,6 @@ public function data_wp_register_webfonts() { 'Source Serif Pro' => array( array( 'provider' => 'local', - 'font-family' => 'Source Serif Pro', 'font-style' => 'normal', 'font-weight' => '200 900', 'font-stretch' => 'normal', @@ -114,7 +95,6 @@ public function data_wp_register_webfonts() { ), array( 'provider' => 'local', - 'font-family' => 'Source Serif Pro', 'font-style' => 'italic', 'font-weight' => '200 900', 'font-stretch' => 'normal', @@ -134,4 +114,34 @@ public function data_wp_register_webfonts() { ), ); } + + /** + * Data provider. + * + * @return array + */ + public function data_deprecated_structure() { + return array( + 'font family not keyed' => array( + 'webfonts' => array( + array( + array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + ), + 'expected' => array( + 'wp_register_webfonts' => array(), + 'get_registered' => array(), + 'message' => 'Font family not found.', + ), + ), + ); + } } diff --git a/phpunit/webfonts/wpWebfonts-test.php b/phpunit/webfonts/wpWebfonts-test.php new file mode 100644 index 0000000000000..a7df633f6d96e --- /dev/null +++ b/phpunit/webfonts/wpWebfonts-test.php @@ -0,0 +1,188 @@ +assertEmpty( wp_webfonts()->get_registered() ); + } + + /** + * @covers WP_Webfonts::get_enqueued + */ + public function test_enqueued_is_empty() { + $this->assertEmpty( wp_webfonts()->get_enqueued() ); + } + + /** + * @covers WP_Webfonts::get_providers + */ + public function test_local_provider_is_automatically_registered() { + $expected = array( + 'local' => array( + 'class' => 'WP_Webfonts_Provider_Local', + 'fonts' => array(), + ), + ); + $this->assertSame( $expected, wp_webfonts()->get_providers() ); + } + + /** + * @dataProvider data_handles + * + * @covers WP_Webfonts::add + * + * @param string $handle Handle to register. + */ + public function test_add( $handle ) { + $wp_webfonts = new WP_Webfonts(); + + $this->assertTrue( $wp_webfonts->add( $handle, false ), 'Registering a handle should return true' ); + $this->assertCount( 1, $wp_webfonts->registered ); + $this->assertArrayHasKey( $handle, $wp_webfonts->registered, 'Font family handle should be in the registry after registration' ); + + } + + /** + * Data provider. + * + * @return array + */ + public function data_handles() { + return array( + 'name: multiple' => array( 'Source Serif Pro' ), + 'handle: multiple' => array( 'source-serif-pro' ), + 'name: single' => array( 'Merriweather' ), + 'handle: single' => array( 'merriweather' ), + 'handle: variation' => array( 'my-custom-font-200-900-normal' ), + ); + } + + /** + * @dataProvider data_valid_variation + * + * @covers WP_Webfonts::add_variation + * @covers WP_Webfonts::add + * + * @param string|bool $expected Expected results. + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $variation_handle Optional. The variation's handle. + */ + public function test_add_variation( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { + $wp_webfonts = new WP_Webfonts(); + $wp_webfonts->add( $font_family_handle, false ); + + $variation_handle = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle ); + $this->assertSame( $expected, $variation_handle, 'Registering a variation should return its handle' ); + $this->assertArrayHasKey( $variation_handle, $wp_webfonts->registered, 'Variation handle should be in the registry after registration' ); + $this->assertSame( $expected, $$this->get_variations( $font_family_handle, $wp_webfonts ), 'Variation should be registered to font family' ); + } + + /** + * @dataProvider data_valid_variation + * + * @param string|bool $expected Expected results. + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $variation_handle Optional. The variation's handle. + */ + public function test_variation_already_registered( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { + $wp_webfonts = new WP_Webfonts(); + $wp_webfonts->add( $font_family_handle, false ); + + // Set up the test. + $variation_handle = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle ); + + // Run the test. + $variant_handle_on_reregister = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle ); + $this->assertSame( $expected, $variant_handle_on_reregister, 'Variation should be registered to font family' ); + $this->assertSame( $variation_handle, $variant_handle_on_reregister, 'Variation should return the previously registered variant handle' ); + $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle, $wp_webfonts ), 'Variation should only be registered once' ); + + $this->assertCount( 2, $wp_webfonts->registered ); + $this->assertArrayHasKey( $variation_handle, $wp_webfonts->registered, 'Variation handle should be in the registry after registration' ); + } + + /** + * @dataProvider data_valid_variation + * + * @param string|bool $expected Expected results. + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $variation_handle Optional. The variation's handle. + */ + public function test_register_font_family_and_variation( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { + $wp_webfonts = new WP_Webfonts(); + + $variation_handle = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle ); + $this->assertSame( $expected, $variation_handle, 'Variation should return its registered handle' ); + + // Extra checks to ensure both are registered. + $this->assertCount( 2, $wp_webfonts->registered ); + $this->assertArrayHasKey( $font_family_handle, $wp_webfonts->registered, 'Font family handle should be in the registry after registration' ); + $this->assertArrayHasKey( $variation_handle, $wp_webfonts->registered, 'Variation handle should be in the registry after registration' ); + $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle ), 'Variation should be registered to the font family' ); + + } + + /** + * @dataProvider data_font_family_not_define_in_variation + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + */ + public function test_should_not_register_font_family_or_variant( $font_family_handle, array $variation ) { + $this->expectNotice(); + $this->expectNoticeMessage( 'Font family handle must be a non-empty string.' ); + + $wp_webfonts = new WP_Webfonts(); + $wp_webfonts->add_variation( $font_family_handle, $variation ); + + $this->assertEmpty( $wp_webfonts->registered, 'Registered queue should be empty' ); + $this->assertEmpty( $this->get_variations( $font_family_handle, $wp_webfonts ), 'Variation should not be registered to the font family' ); + } + + /** + * @dataProvider data_font_family_not_define_in_variation + * @dataProvider data_unable_determine_variation_handle + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $expected_message Expected notice message. + */ + public function test_should_not_register_variation_when_font_family_not_defined( $font_family_handle, array $variation, $expected_message ) { + $this->expectNotice(); + $this->expectNoticeMessage( $expected_message ); + + $wp_webfonts = new WP_Webfonts(); + $this->assertNull( $wp_webfonts->add_variation( $font_family_handle, $variation ) ); + } + + /** + * @dataProvider data_unable_determine_variation_handle + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + */ + public function test_should_register_font_family_when_variant_fails_to_register( $font_family_handle, array $variation ) { + $this->expectNotice(); + $this->expectNoticeMessage( 'Variant handle could not be determined as font-weight and/or font-style are require' ); + + $wp_webfonts = new WP_Webfonts(); + $wp_webfonts->add_variation( $font_family_handle, $variation ); + + $this->assertCount( 1, $wp_webfonts->registered ); + $this->assertArrayHasKey( $font_family_handle, $wp_webfonts->registered ); + } +} diff --git a/phpunit/class-wp-webfonts-local-provider-test.php b/phpunit/webfonts/wpWebfontsProviderLocal-test.php similarity index 95% rename from phpunit/class-wp-webfonts-local-provider-test.php rename to phpunit/webfonts/wpWebfontsProviderLocal-test.php index c9ab3e2cd8b95..8a87c03a8e3eb 100644 --- a/phpunit/class-wp-webfonts-local-provider-test.php +++ b/phpunit/webfonts/wpWebfontsProviderLocal-test.php @@ -2,9 +2,9 @@ /** * @group webfonts - * @covers WP_WebfontsLocal_Provider + * @covers WP_Webfonts_Provider_Local */ -class WP_Webfonts_Provider_Local_Test extends WP_UnitTestCase { +class Tests_Webfonts_WpWebfontsProviderLocal extends WP_UnitTestCase { private $provider; private $theme_root; private $orig_theme_dir; @@ -17,27 +17,6 @@ public function set_up() { $this->set_up_theme(); } - /** - * Local `src` paths to need to be relative to the theme. This method sets up the - * `wp-content/themes/` directory to ensure consistency when running tests. - */ - private function set_up_theme() { - $this->theme_root = realpath( DIR_TESTDATA . '/themedir1' ); - $this->orig_theme_dir = $GLOBALS['wp_theme_directories']; - $GLOBALS['wp_theme_directories'] = array( $this->theme_root ); - - $theme_root_callback = function () { - return $this->theme_root; - }; - add_filter( 'theme_root', $theme_root_callback ); - add_filter( 'stylesheet_root', $theme_root_callback ); - add_filter( 'template_root', $theme_root_callback ); - - // Clear caches. - wp_clean_themes_cache(); - unset( $GLOBALS['wp_themes'] ); - } - function tear_down() { // Restore the original theme directory setup. $GLOBALS['wp_theme_directories'] = $this->orig_theme_dir; @@ -109,7 +88,10 @@ public function data_get_css() { ), ), 'expected' => << @font-face{font-family:"Open Sans";font-style:italic;font-weight:bold;src:local("Open Sans"), url('http://example.org/assets/fonts/OpenSans-Italic-VariableFont_wdth,wght.ttf') format('truetype');} + + CSS , ), @@ -133,13 +115,37 @@ public function data_get_css() { ), ), 'expected' => << @font-face{font-family:"Source Serif Pro";font-style:normal;font-weight:200 900;font-stretch:normal;src:local("Source Serif Pro"), url('http://example.org/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2') format('woff2');}@font-face{font-family:"Source Serif Pro";font-style:italic;font-weight:200 900;font-stretch:normal;src:local("Source Serif Pro"), url('http://example.org/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2') format('woff2');} + + CSS , ), ); } + /** + * Local `src` paths to need to be relative to the theme. This method sets up the + * `wp-content/themes/` directory to ensure consistency when running tests. + */ + private function set_up_theme() { + $this->theme_root = realpath( DIR_TESTDATA . '/themedir1' ); + $this->orig_theme_dir = $GLOBALS['wp_theme_directories']; + $GLOBALS['wp_theme_directories'] = array( $this->theme_root ); + + $theme_root_callback = function () { + return $this->theme_root; + }; + add_filter( 'theme_root', $theme_root_callback ); + add_filter( 'stylesheet_root', $theme_root_callback ); + add_filter( 'template_root', $theme_root_callback ); + + // Clear caches. + wp_clean_themes_cache(); + unset( $GLOBALS['wp_themes'] ); + } + private function get_webfonts_property() { $property = new ReflectionProperty( $this->provider, 'webfonts' ); $property->setAccessible( true ); diff --git a/phpunit/webfonts/wpWebfontsUtils-test.php b/phpunit/webfonts/wpWebfontsUtils-test.php new file mode 100644 index 0000000000000..ce626b9bb60f8 --- /dev/null +++ b/phpunit/webfonts/wpWebfontsUtils-test.php @@ -0,0 +1,366 @@ +assertSame( $expected, WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_convert_font_family_into_handle() { + return array( + 'font family single word name' => array( + 'font_family' => 'Merriweather', + 'expected' => 'merriweather', + ), + 'font family multiword name' => array( + 'font_family' => 'Source Sans Pro', + 'expected' => 'source-sans-pro', + ), + 'font family handle delimited by hyphens' => array( + 'font_family' => 'source-serif-pro', + 'expected' => 'source-serif-pro', + ), + 'font family handle delimited by underscore' => array( + 'font_family' => 'source_serif_pro', + 'expected' => 'source_serif_pro', + ), + 'font family handle delimited by hyphens and underscore' => array( + 'font_family' => 'my-custom_font_family', + 'expected' => 'my-custom_font_family', + ), + 'font family handle delimited mixture' => array( + 'font_family' => 'My custom_font-family', + 'expected' => 'my-custom_font-family', + ), + ); + } + + /** + * @dataProvider data_convert_font_family_into_handle_with_invalid_input + * + * @covers WP_Webfonts_Utils::convert_font_family_into_handle + * + * @param mixed $invalid_input Invalid input. + */ + public function test_convert_font_family_into_handle_with_invalid_input( $invalid_input ) { + $this->assertNull( WP_Webfonts_Utils::convert_font_family_into_handle( $invalid_input ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_convert_font_family_into_handle_with_invalid_input() { + return array( + 'empty string' => array( '' ), + 'integer' => array( 10 ), + 'font family wrapped in an array' => array( array( 'source-serif-pro' ) ), + ); + } + + /** + * @dataProvider data_convert_variation_into_handle + * + * @covers WP_Webfonts_Utils::convert_variation_into_handle + * + * @param string $font_family Font family to test. + * @param array $variation Variation to test. + * @param string $expected Expected results. + */ + public function test_convert_variation_into_handlee( $font_family, array $variation, $expected ) { + $this->assertSame( $expected, WP_Webfonts_Utils::convert_variation_into_handle( $font_family, $variation ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_convert_variation_into_handle() { + return array( + 'with only font-weight' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-weight' => '400', + ), + 'expected' => 'merriweather-400', + ), + 'with no font-style' => array( + 'font_family' => 'source-sans-pro', + 'variation' => array( + 'font-weight' => '200 900', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'provider' => 'local', + ), + 'expected' => 'source-sans-pro-200-900', + ), + 'with font family name and full variant' => array( + 'font_family' => 'source-sans-pro', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected' => 'source-sans-pro-200-900-normal', + ), + ); + } + + /** + * @dataProvider data_convert_variation_into_handle_with_invalid_variation + * + * @covers WP_Webfonts_Utils::convert_variation_into_handle + * + * @param string $font_family Font family to test. + * @param array $invalid_input Variation to test. + */ + public function tests_convert_variation_into_handle_with_invalid_variation( $font_family, $invalid_input ) { + $this->expectNotice(); + $this->expectNoticeMessage( 'Variant handle could not be determined as font-weight and/or font-style are require' ); + + $this->assertNull( WP_Webfonts_Utils::convert_variation_into_handle( $font_family, $invalid_input ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_convert_variation_into_handle_with_invalid_variation() { + return array( + 'with no font-weight or font-style' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'provider' => 'local', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + 'with non-string font-weight' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-weight' => 400, + ), + ), + 'with non-string font-style' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-style' => 0, + ), + ), + 'with empty string font-weight' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-weight' => '', + ), + ), + 'with empty string font-style' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-style' => '', + ), + ), + ); + } + + /** + * @dataProvider data_get_font_family_from_variation + * + * @covers WP_Webfonts_Utils::convert_variation_into_handle + * + * @param array $variation Variation to test. + * @param string $expected Expected results. + */ + public function test_get_font_family_from_variation( array $variation, $expected ) { + $this->assertSame( $expected, WP_Webfonts_Utils::get_font_family_from_variation( $variation ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_get_font_family_from_variation() { + return array( + 'keyed by font-family' => array( + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected' => 'Source Serif Pro', + ), + 'keyed by fontFamily and as a handle' => array( + 'variation' => array( + 'fontFamily' => 'source-sans-pro', + 'font-weight' => '200 900', + 'src' => 'https://example.com/assets/fonts/source-sans-pro/source-sans-pro.ttf.woff2', + 'provider' => 'local', + ), + 'expected' => 'source-sans-pro', + ), + 'with font family name and full variant' => array( + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Merriweather', + 'font-style' => 'normal', + 'font-weight' => '400 600', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected' => 'Merriweather', + ), + ); + } + + /** + * @dataProvider data_get_font_family_from_variation_with_invalid_input + * + * @covers WP_Webfonts_Utils::get_font_family_from_variation + * + * @param array $invalid_variation Variation to test. + * @param string $expected_message Expected notice message. + */ + public function test_get_font_family_from_variation_with_invalid_input( array $invalid_variation, $expected_message ) { + $this->expectNotice(); + $this->expectNoticeMessage( $expected_message ); + + $this->assertNull( WP_Webfonts_Utils::get_font_family_from_variation( $invalid_variation ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_get_font_family_from_variation_with_invalid_input() { + return array( + 'keyed with underscore' => array( + 'variation' => array( + 'provider' => 'local', + 'font_family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family not found.', + ), + 'keyed with space' => array( + 'variation' => array( + 'font family' => 'Source Sans Pro', + 'font-weight' => '200 900', + 'src' => 'https://example.com/assets/fonts/source-sans-pro/source-sans-pro.ttf.woff2', + 'provider' => 'local', + ), + 'expected_message' => 'Font family not found.', + ), + 'fontFamily => empty string' => array( + 'variation' => array( + 'fontFamily' => '', + 'font-weight' => '200 900', + 'src' => 'https://example.com/assets/fonts/source-sans-pro/source-sans-pro.ttf.woff2', + 'provider' => 'local', + ), + 'expected_message' => 'Font family not defined in the variation.', + ), + 'font-family => empty string' => array( + 'variation' => array( + 'provider' => 'local', + 'font-family' => '', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family not defined in the variation.', + ), + ); + } + + /** + * @dataProvider data_is_defined + * + * @covers WP_Webfonts_Utils::is_defined + * + * @param mixed $input Input to test. + */ + public function test_is_defined( $input ) { + $this->assertTrue( WP_Webfonts_Utils::is_defined( $input ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_is_defined() { + return array( + 'name: non empty string' => array( 'Some Font Family' ), + 'handle: non empty string' => array( 'some-font-family' ), + ); + } + + /** + * @dataProvider data_is_defined_when_not_defined + * + * @covers WP_Webfonts_Utils::is_defined + * + * @param mixed $invalid_input Input to test. + */ + public function test_is_defined_when_not_defined( $invalid_input ) { + $this->assertFalse( WP_Webfonts_Utils::is_defined( $invalid_input ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_is_defined_when_not_defined() { + return array( + 'empty string' => array( '' ), + 'string 0' => array( '0' ), + 'integer' => array( 10 ), + 'name wrapped in an array' => array( array( 'Some Font Family' ) ), + 'handle wrapped in an array' => array( array( 'some-font-family' ) ), + ); + } +}