diff --git a/src/js/_enqueues/wp/emoji.js b/src/js/_enqueues/wp/emoji.js
index 274868f52d859..5d6fbcfbc9853 100644
--- a/src/js/_enqueues/wp/emoji.js
+++ b/src/js/_enqueues/wp/emoji.js
@@ -235,9 +235,18 @@
return false;
}
+ /*
+ * When only the flag test failed, replace flags and nothing else. The list covers
+ * every kind of flag that test checks (country, subdivision and ZWJ flags), so a
+ * failing flag is never left to a font that cannot draw it.
+ */
if ( settings.supports.everythingExceptFlag &&
- ! /^1f1(?:e[6-9a-f]|f[0-9a-f])-1f1(?:e[6-9a-f]|f[0-9a-f])$/.test( icon ) && // Country flags.
- ! /^(1f3f3-fe0f-200d-1f308|1f3f4-200d-2620-fe0f)$/.test( icon ) // Rainbow and pirate flags.
+ // Country flags.
+ ! /^1f1(?:e[6-9a-f]|f[0-9a-f])-1f1(?:e[6-9a-f]|f[0-9a-f])$/.test( icon ) &&
+ // Subdivision flags, such as England: a black flag, tag characters, and a cancel tag.
+ ! /^1f3f4(?:-e00[2-7][0-9a-f])+-e007f$/.test( icon ) &&
+ // Rainbow, transgender and pirate flags.
+ ! /^(1f3f3-fe0f-200d-1f308|1f3f3-fe0f-200d-26a7-fe0f|1f3f4-200d-2620-fe0f)$/.test( icon )
) {
return false;
}
diff --git a/tests/qunit/wp-includes/js/emoji-flags.html b/tests/qunit/wp-includes/js/emoji-flags.html
new file mode 100644
index 0000000000000..4e6691398b8ea
--- /dev/null
+++ b/tests/qunit/wp-includes/js/emoji-flags.html
@@ -0,0 +1,34 @@
+
+
+
+ wp.emoji flag fallback QUnit Test Suite
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qunit/wp-includes/js/emoji-flags.js b/tests/qunit/wp-includes/js/emoji-flags.js
new file mode 100644
index 0000000000000..b3cbb87bfe35a
--- /dev/null
+++ b/tests/qunit/wp-includes/js/emoji-flags.js
@@ -0,0 +1,78 @@
+( function( QUnit ) {
+ /*
+ * wp-emoji.js is loaded with `everythingExceptFlag`: the browser renders emoji but failed the
+ * flag test. Every kind of flag that test checks must then be replaced by an image, and nothing
+ * else. See https://core.trac.wordpress.org/ticket/63451.
+ */
+ QUnit.module( 'wp.emoji flag fallback' );
+
+ function imageSources( html ) {
+ var container = document.createElement( 'div' );
+
+ container.innerHTML = html;
+ return Array.prototype.map.call( container.querySelectorAll( 'img.emoji' ), function( img ) {
+ return img.getAttribute( 'src' );
+ } );
+ }
+
+ QUnit.test( 'replaces a country flag', function( assert ) {
+ var sources = imageSources( window.wp.emoji.parse( '\uD83C\uDDF0\uD83C\uDDF7' ) ); // Flag: South Korea.
+
+ assert.strictEqual( sources.length, 1, 'one image' );
+ assert.ok( /\/1f1f0-1f1f7\.(svg|png)$/.test( sources[0] ), 'for 1f1f0-1f1f7' );
+ } );
+
+ QUnit.test( 'replaces the England flag', function( assert ) {
+ var sources = imageSources( window.wp.emoji.parse( '\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67\uDB40\uDC7F' ) ); // Flag: England.
+
+ assert.strictEqual( sources.length, 1, 'one image' );
+ assert.ok( /\/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f\.(svg|png)$/.test( sources[0] ), 'for 1f3f4-e0067-e0062-e0065-e006e-e0067-e007f' );
+ } );
+
+ QUnit.test( 'replaces the Scotland flag', function( assert ) {
+ var sources = imageSources( window.wp.emoji.parse( '\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74\uDB40\uDC7F' ) ); // Flag: Scotland.
+
+ assert.strictEqual( sources.length, 1, 'one image' );
+ assert.ok( /\/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f\.(svg|png)$/.test( sources[0] ), 'for 1f3f4-e0067-e0062-e0073-e0063-e0074-e007f' );
+ } );
+
+ QUnit.test( 'replaces the Wales flag', function( assert ) {
+ var sources = imageSources( window.wp.emoji.parse( '\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73\uDB40\uDC7F' ) ); // Flag: Wales.
+
+ assert.strictEqual( sources.length, 1, 'one image' );
+ assert.ok( /\/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f\.(svg|png)$/.test( sources[0] ), 'for 1f3f4-e0067-e0062-e0077-e006c-e0073-e007f' );
+ } );
+
+ QUnit.test( 'replaces the transgender flag', function( assert ) {
+ var sources = imageSources( window.wp.emoji.parse( '\uD83C\uDFF3\uFE0F\u200D\u26A7\uFE0F' ) ); // Transgender flag.
+
+ assert.strictEqual( sources.length, 1, 'one image' );
+ assert.ok( /\/1f3f3-fe0f-200d-26a7-fe0f\.(svg|png)$/.test( sources[0] ), 'for 1f3f3-fe0f-200d-26a7-fe0f' );
+ } );
+
+ QUnit.test( 'replaces the rainbow flag', function( assert ) {
+ var sources = imageSources( window.wp.emoji.parse( '\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08' ) ); // Rainbow flag.
+
+ assert.strictEqual( sources.length, 1, 'one image' );
+ assert.ok( /\/1f3f3-fe0f-200d-1f308\.(svg|png)$/.test( sources[0] ), 'for 1f3f3-fe0f-200d-1f308' );
+ } );
+
+ QUnit.test( 'replaces the pirate flag', function( assert ) {
+ var sources = imageSources( window.wp.emoji.parse( '\uD83C\uDFF4\u200D\u2620\uFE0F' ) ); // Pirate flag.
+
+ assert.strictEqual( sources.length, 1, 'one image' );
+ assert.ok( /\/1f3f4-200d-2620-fe0f\.(svg|png)$/.test( sources[0] ), 'for 1f3f4-200d-2620-fe0f' );
+ } );
+
+ QUnit.test( 'leaves an emoji that is not a flag as text', function( assert ) {
+ var text = '\uD83D\uDE00'; // Grinning face.
+
+ assert.strictEqual( window.wp.emoji.parse( text ), text );
+ } );
+
+ QUnit.test( 'leaves a black flag on its own as text', function( assert ) {
+ var text = '\uD83C\uDFF4'; // Black flag.
+
+ assert.strictEqual( window.wp.emoji.parse( text ), text );
+ } );
+} )( window.QUnit );