Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
11 changes: 11 additions & 0 deletions e2e/editor-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,17 @@ export default class EditorPage {
}, index );
}

/**
* Call the bridge's `getTitleAndContent()` and return the result.
*
* @return {Promise<{title: string, content: string, changed: boolean}>} The editor state.
*/
async getTitleAndContent() {
return await this.#page.evaluate( () =>
window.editor.getTitleAndContent()
);
}

/**
* Retrieve all blocks from the editor via the WP data store.
*
Expand Down
182 changes: 182 additions & 0 deletions e2e/get-title-and-content.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/**
* External dependencies
*/
import { test, expect } from '@playwright/test';

/**
* Internal dependencies
*/
import EditorPage from './editor-page';

test.describe( 'getTitleAndContent', () => {
test( 'returns correct title and content before any edits', async ( {
page,
} ) => {
const editor = new EditorPage( page );
await editor.setup( {
post: {
id: 1,
type: 'post',
status: 'draft',
title: 'Initial Title',
content:
'<!-- wp:paragraph -->\n<p>Hello</p>\n<!-- /wp:paragraph -->',
},
} );

const result = await editor.getTitleAndContent();

expect( typeof result.title ).toBe( 'string' );
expect( typeof result.content ).toBe( 'string' );
expect( result.title ).toBe( 'Initial Title' );
expect( result.content ).toBe(
'<!-- wp:paragraph -->\n<p>Hello</p>\n<!-- /wp:paragraph -->'
);
expect( result.changed ).toBe( false );
} );

test( 'returns plain strings after editing the title', async ( {
page,
} ) => {
const editor = new EditorPage( page );
await editor.setup( {
post: {
id: 1,
type: 'post',
status: 'draft',
title: 'Original',
content: '',
},
} );

const titleInput = page.getByRole( 'textbox', {
name: 'Add title',
} );
await titleInput.click();
await page.keyboard.press( 'ControlOrMeta+a' );
await page.keyboard.type( 'Updated Title' );

const result = await editor.getTitleAndContent();

expect( typeof result.title ).toBe( 'string' );
expect( result.title ).toBe( 'Updated Title' );
expect( result.changed ).toBe( true );
} );

test( 'returns plain strings after editing content', async ( { page } ) => {
const editor = new EditorPage( page );
await editor.setup( {
post: {
id: 1,
type: 'post',
status: 'draft',
title: 'Title',
content: '',
},
} );

await editor.clickBlockAppender();
await page.keyboard.type( 'New paragraph' );

const result = await editor.getTitleAndContent();

expect( typeof result.title ).toBe( 'string' );
expect( typeof result.content ).toBe( 'string' );
expect( result.title ).toBe( 'Title' );
expect( result.content ).toContain( 'New paragraph' );
expect( result.changed ).toBe( true );
} );

test( 'returns plain strings with empty initial state', async ( {
page,
} ) => {
const editor = new EditorPage( page );
await editor.setup();

const result = await editor.getTitleAndContent();

expect( typeof result.title ).toBe( 'string' );
expect( typeof result.content ).toBe( 'string' );
expect( result.title ).toBe( '' );
expect( result.content ).toBe( '' );
expect( result.changed ).toBe( false );
} );

test( 'returns plain strings when data store title is a {raw, rendered} object', async ( {
page,
} ) => {
const editor = new EditorPage( page );
await editor.setup( {
post: {
id: 1,
type: 'post',
status: 'draft',
title: 'Initial Title',
content: '',
},
} );

// Inject an object-shaped title edit via editEntityRecord.
// This simulates the Gutenberg data store bug where
// getEditedPostAttribute bypasses getPostRawValue normalization
// for values in the edits layer.
await page.evaluate( () => {
window.wp.data
.dispatch( 'core' )
.editEntityRecord( 'postType', 'post', 1, {
title: {
raw: 'Object Title',
rendered: '<b>Object Title</b>',
},
} );
} );

const result = await editor.getTitleAndContent();

expect( typeof result.title ).toBe( 'string' );
expect( result.title ).toBe( 'Object Title' );
expect( result.changed ).toBe( true );

// Second call should report no further changes.
const second = await editor.getTitleAndContent();
expect( second.changed ).toBe( false );
} );

test( 'returns plain strings when data store content is a {raw, rendered} object', async ( {
page,
} ) => {
const editor = new EditorPage( page );
await editor.setup( {
post: {
id: 1,
type: 'post',
status: 'draft',
title: 'Title',
content: '',
},
} );

await page.evaluate( () => {
window.wp.data
.dispatch( 'core' )
.editEntityRecord( 'postType', 'post', 1, {
content: {
raw: '<!-- wp:paragraph --><p>Test</p><!-- /wp:paragraph -->',
rendered: '<p>Test</p>',
},
} );
} );

const result = await editor.getTitleAndContent();

expect( typeof result.content ).toBe( 'string' );
expect( result.content ).toContain(
'<!-- wp:paragraph --><p>Test</p><!-- /wp:paragraph -->'
);
expect( result.changed ).toBe( true );

// Second call should report no further changes.
const second = await editor.getTitleAndContent();
expect( second.changed ).toBe( false );
} );
} );
6 changes: 0 additions & 6 deletions ios/Sources/GutenbergKit/Sources/EditorViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -374,12 +374,6 @@ public final class EditorViewController: UIViewController, GutenbergEditorContro
evaluate("editor.setContent('\(escapedString)');", isCritical: true)
}

/// Returns the current editor content.
public func getContent() async throws -> String {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It appears there is one location using this method that we need to update: the unused comment editor.

guard isReady else { throw EditorNotReadyError() }
return try await webView.evaluateJavaScript("editor.getContent();") as! String
}

public struct EditorTitleAndContent: Decodable {
public let title: String
public let content: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public protocol EditorViewControllerDelegate: AnyObject {

/// Notifies the client about the new edits.
///
/// - note: To get the latest content, call ``EditorViewController/getContent()``.
/// - note: To get the latest content, call ``EditorViewController/getTitleAndContent()``.
/// Retrieving the content is a relatively expensive operation and should not
/// be performed too frequently during editing.
///
Expand Down
Loading
Loading