Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Font Library: Add upload font test #60221

Merged
merged 17 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions packages/e2e-tests/plugins/delete-installed-fonts.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php
/**
* Plugin Name: Gutenberg Test Delete Installed Fonts
* Plugin URI: https://github.com/WordPress/gutenberg
* Author: Gutenberg Team
*
* @package gutenberg-test-delete-installed-fonts
*/

/**
* Saves a randomly generated temporary font directory to use for e2e tests.
*/
function gutenberg_e2e_set_temp_font_dir() {
update_option( 'gutenberg_e2e_font_dir', '/e2e_fonts_' . wp_generate_uuid4() );
}
register_activation_hook( __FILE__, 'gutenberg_e2e_set_temp_font_dir' );

/**
* Uses the randomly generated font directory for the duration of the font tests.
*/
function gutenberg_filter_e2e_font_dir( $font_dir ) {
$subdir = get_option( 'gutenberg_e2e_font_dir' );

$font_dir['path'] .= $subdir;
$font_dir['url'] .= $subdir;
$font_dir['basedir'] .= $subdir;
$font_dir['baseurl'] .= $subdir;

return $font_dir;
}
add_filter( 'font_dir', 'gutenberg_filter_e2e_font_dir' );

/**
* Deletes all user installed fonts, associated font files, the fonts directory, and user global styles typography
* setings for the current theme so that we can test uploading/installing fonts in a clean environment.
*/
function gutenberg_delete_installed_fonts() {
$font_family_ids = new WP_Query(
array(
'post_type' => 'wp_font_family',
'posts_per_page' => -1,
'fields' => 'ids',
)
);

// Delete all font families, their child font faces, and associated font files.
foreach ( $font_family_ids->posts as $font_family_id ) {
wp_delete_post( $font_family_id, true );
}
getdave marked this conversation as resolved.
Show resolved Hide resolved

// Delete the font directory, which should now be empty.
$font_path = wp_get_font_dir()['path'];

if ( is_dir( $font_path ) ) {
rmdir( $font_path );
}
Comment on lines +54 to +56
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some development environments the content and uploads folder is shared between the test suite and the developer's manual testing so deleting the directory will fail as it will contain files.

If the files are deleted beforehand then the manual testing environment will be busted.

For the test suite I suggest filtering the folder and cleaning it up afterwards. You can probably use wp_generate_uuid4() to generate the folder name.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, that part is brittle. I've modified the plugin to use a randomly generated directory for fonts during the duration of the test and to cleanup on plugin activation and deactivation. Let me know what you think!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Grant, that looks good. Is there an e2e tear down at the end that could be used to delete the temporary folder? It's no big deal if there isn't.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that because of the way we're testing here with a plugin to handle the server-side logic, the tear-down happens on deactivation on the plugin, i.e. on line 19 we deactivate the plugin after all tests:

test.afterAll( async ( { requestUtils } ) => {
	await requestUtils.deactivatePlugin(
		'gutenberg-test-delete-installed-fonts'
	);
} );

And the plugin handles the deletion of fonts and folders on deactivation:

register_deactivation_hook( __FILE__, 'gutenberg_delete_installed_fonts' );


// Delete any installed fonts from global styles.
$global_styles_post_id = WP_Theme_JSON_Resolver::get_user_global_styles_post_id();
$request = new WP_REST_Request( 'POST', '/wp/v2/global-styles/' . $global_styles_post_id );
$request->set_body_params( array( 'settings' => array( 'typography' => array( 'fontFamilies' => array() ) ) ) );

rest_do_request( $request );
}

// Clean up fonts on plugin activation and deactivation.
register_activation_hook( __FILE__, 'gutenberg_delete_installed_fonts' );
register_deactivation_hook( __FILE__, 'gutenberg_delete_installed_fonts' );
Binary file added test/e2e/assets/Exo2-Regular.woff
Binary file not shown.
Binary file added test/e2e/assets/Exo2-SemiBoldItalic.woff2
Binary file not shown.
116 changes: 101 additions & 15 deletions test/e2e/specs/site-editor/font-library.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ test.describe( 'Font Library', () => {
test.describe( 'When a blank theme is active', () => {
test.beforeAll( async ( { requestUtils } ) => {
await requestUtils.activateTheme( 'emptytheme' );
/*
* Delete all installed fonts, font files, the fonts directory, and user font settings
* in global styles for the active theme before and after starting the tests.
*/
await requestUtils.activatePlugin(
'gutenberg-test-delete-installed-fonts'
);
} );

test.afterAll( async ( { requestUtils } ) => {
await requestUtils.deactivatePlugin(
'gutenberg-test-delete-installed-fonts'
);
} );

test.beforeEach( async ( { admin, editor } ) => {
Expand All @@ -15,15 +28,88 @@ test.describe( 'Font Library', () => {
} );

test( 'should display the "Manage Fonts" icon', async ( { page } ) => {
await page.getByRole( 'button', { name: /styles/i } ).click();
await page.getByRole( 'button', { name: 'Styles' } ).click();
await page
.getByRole( 'button', { name: /typography styles/i } )
.getByRole( 'button', { name: 'Typography Styles' } )
.click();
const manageFontsIcon = page.getByRole( 'button', {
name: /manage fonts/i,
name: 'Manage Fonts',
} );
await expect( manageFontsIcon ).toBeVisible();
} );

test( 'should allow user to upload multiple local font files', async ( {
getdave marked this conversation as resolved.
Show resolved Hide resolved
page,
editor,
} ) => {
await page.getByRole( 'button', { name: 'Styles' } ).click();
await page
.getByRole( 'button', { name: 'Typography Styles' } )
.click();
await page
.getByRole( 'button', {
name: 'Manage Fonts',
} )
.click();

// Upload local fonts.
await page.getByRole( 'tab', { name: 'Upload' } ).click();
const fileChooserPromise = page.waitForEvent( 'filechooser' );
await page.getByRole( 'button', { name: 'Upload Font' } ).click();
const fileChooser = await fileChooserPromise;
// Provides coverage for https://github.com/WordPress/gutenberg/issues/59023.
await fileChooser.setFiles( [
mikachan marked this conversation as resolved.
Show resolved Hide resolved
'./test/e2e/assets/Exo2-Regular.woff',
'./test/e2e/assets/Exo2-SemiBoldItalic.woff2',
] );

// Check fonts were installed.
await expect(
page
.getByLabel( 'Upload' )
.getByText( 'Fonts were installed successfully.' )
).toBeVisible();
await page.getByRole( 'tab', { name: 'Library' } ).click();
// Provides coverage for https://github.com/WordPress/gutenberg/issues/60040.
getdave marked this conversation as resolved.
Show resolved Hide resolved
await page.getByRole( 'button', { name: 'Exo 2' } ).click();
await expect( page.getByLabel( 'Exo 2 Normal' ) ).toBeVisible();
await expect(
page.getByLabel( 'Exo 2 Semi-bold Italic' )
).toBeVisible();

// Check CSS preset was created.
await page.getByRole( 'button', { name: 'Close' } ).click();
await page
.getByRole( 'button', { name: 'Typography Headings styles' } )
.click();
await page.getByLabel( 'Font' ).selectOption( 'Exo 2' );
await expect(
editor.canvas.locator( '.is-root-container h1' )
).toHaveCSS( 'font-family', '"Exo 2"' );
} );

test( 'should allow user to delete installed fonts', async ( {
page,
} ) => {
await page.getByRole( 'button', { name: 'Styles' } ).click();
await page
.getByRole( 'button', { name: 'Typography Styles' } )
.click();
await page
.getByRole( 'button', {
name: 'Manage Fonts',
} )
.click();

await page.getByRole( 'button', { name: 'Exo 2' } ).click();
getdave marked this conversation as resolved.
Show resolved Hide resolved
await page.getByRole( 'button', { name: 'Delete' } ).click();
await page.getByRole( 'button', { name: 'Delete' } ).click();
await expect(
page
.getByLabel( 'Library' )
.getByText( 'Font family uninstalled successfully.' )
).toBeVisible();
} );
} );

test.describe( 'When a theme with bundled fonts is active', () => {
Expand All @@ -37,26 +123,26 @@ test.describe( 'Font Library', () => {
} );

test( 'should display the "Manage Fonts" icon', async ( { page } ) => {
await page.getByRole( 'button', { name: /styles/i } ).click();
await page.getByRole( 'button', { name: 'Styles' } ).click();
await page
.getByRole( 'button', { name: /typography styles/i } )
.getByRole( 'button', { name: 'Typography Styles' } )
.click();
const manageFontsIcon = page.getByRole( 'button', {
name: /manage fonts/i,
name: 'Manage Fonts',
} );
await expect( manageFontsIcon ).toBeVisible();
} );

test( 'should open the "Manage Fonts" modal when clicking the "Manage Fonts" icon', async ( {
page,
} ) => {
await page.getByRole( 'button', { name: /styles/i } ).click();
await page.getByRole( 'button', { name: 'Styles' } ).click();
await page
.getByRole( 'button', { name: /typography styles/i } )
.getByRole( 'button', { name: 'Typography Styles' } )
.click();
await page
.getByRole( 'button', {
name: /manage fonts/i,
name: 'Manage Fonts',
} )
.click();
await expect( page.getByRole( 'dialog' ) ).toBeVisible();
Expand All @@ -68,21 +154,21 @@ test.describe( 'Font Library', () => {
test( 'should show font variant panel when clicking on a font family', async ( {
page,
} ) => {
await page.getByRole( 'button', { name: /styles/i } ).click();
await page.getByRole( 'button', { name: 'Styles' } ).click();
await page
.getByRole( 'button', { name: /typography styles/i } )
.getByRole( 'button', { name: 'Typography Styles' } )
.click();
await page
.getByRole( 'button', {
name: /manage fonts/i,
name: 'Manage Fonts',
} )
.click();
await page.getByRole( 'button', { name: /system font/i } ).click();
await page.getByRole( 'button', { name: 'System Font' } ).click();
await expect(
page.getByRole( 'heading', { name: /system font/i } )
page.getByRole( 'heading', { name: 'System Font' } )
).toBeVisible();
await expect(
page.getByRole( 'checkbox', { name: /system font normal/i } )
page.getByRole( 'checkbox', { name: 'System Font Normal' } )
).toBeVisible();
} );
} );
Expand Down
Loading