Customize: Introduce drafting and scheduling for Customizer changesets.

* Incorporates code from the Customize Snapshots and Customize Posts feature plugins.
* Adds a new Publish Settings section for managing the changeset status, scheduled date, and frontend preview link.
* Updates Publish button to reflect the status selected in the Publish Settings (including Save Draft and Schedule).
* Deactivates the Themes section when a non-publish status selected, and deactivates the Publish Settings section when previewing a theme switch.
* Introduces an `outer` section type (`wp.customize.OuterSection` in JS) for the Publish Settings section to use and for available widgets and available nav menu panels to use in the future. These sections can be expanded while other sections are expanded.
* Introduces `WP_Customize_Date_Time_Control` in PHP and `wp.customize.DateTimeControl` in JS for managing a date/time value.
* Keeps track of scheduled time and proactively publish from the client when the time arrives, as opposed to waiting for WP Cron.
* Auto-publishes a scheduled changeset when attempting to access one that missed its schedule.
* Starts a new changeset if attempting to save a changeset that was previously publish.
* Adds `force` arg to `requestChangesetUpdate()` to force an update request even when there are no pending changes.
* Adds utils methods for `getCurrentTimestamp` and `getRemainingTime`.
* Adds new state values for `selectedChangesetStatus`, `changesetDate`, `selectedChangesetDate`.
* Fixes logic for when to short-circuit check to close Customizer when there are unsaved changes.
* Adds getter methods for `autosaved` and `branching` parameters, with the latter applying the `customize_changeset_branching` filter.
* Call to `establish_loaded_changeset` on the fly when `changeset_uuid()` is called if no changeset UUID was specififed.
* De-duplicates logic for dismissing auto-draft changesets.
* Includes unit tests.

Builds on [41597].
Props sayedwp, westonruter, melchoyce, JoshuaWold, folletto, stubgo, karmatosed, dlh, paaljoachim, afercia, johnregan3, utkarshpatel, valendesigns.
See #30937.
Fixes #39896, #28721, #39275.


git-svn-id: https://develop.svn.wordpress.org/trunk@41626 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Weston Ruter
2017-09-27 22:24:37 +00:00
parent 621a95a23f
commit a92bb89f4f
13 changed files with 2590 additions and 202 deletions
+173 -6
View File
@@ -165,7 +165,10 @@ class Tests_Ajax_CustomizeManager extends WP_Ajax_UnitTestCase {
$this->make_ajax_call( 'customize_save' );
$this->assertFalse( $this->_last_response_parsed['success'] );
$this->assertEquals( 'changeset_already_published', $this->_last_response_parsed['data']['code'] );
wp_update_post( array( 'ID' => $wp_customize->changeset_post_id(), 'post_status' => 'auto-draft' ) );
wp_update_post( array(
'ID' => $wp_customize->changeset_post_id(),
'post_status' => 'auto-draft',
) );
// User cannot edit.
$post_type_obj = get_post_type_object( 'customize_changeset' );
@@ -222,8 +225,10 @@ class Tests_Ajax_CustomizeManager extends WP_Ajax_UnitTestCase {
$this->make_ajax_call( 'customize_save' );
$this->assertTrue( $this->_last_response_parsed['success'] );
$this->assertEquals( 'future', get_post_status( $wp_customize->changeset_post_id() ) );
wp_update_post( array( 'ID' => $wp_customize->changeset_post_id(), 'post_status' => 'auto-draft' ) );
wp_update_post( array(
'ID' => $wp_customize->changeset_post_id(),
'post_status' => 'auto-draft',
) );
}
/**
@@ -254,7 +259,6 @@ class Tests_Ajax_CustomizeManager extends WP_Ajax_UnitTestCase {
function test_save_success_publish_create() {
$wp_customize = $this->set_up_valid_state();
// Successful future.
$_POST['customize_changeset_status'] = 'publish';
$_POST['customize_changeset_title'] = 'Success Changeset';
$_POST['customize_changeset_data'] = wp_json_encode( array(
@@ -268,9 +272,9 @@ class Tests_Ajax_CustomizeManager extends WP_Ajax_UnitTestCase {
$this->assertEquals( 'publish', $this->_last_response_parsed['data']['changeset_status'] );
$this->assertArrayHasKey( 'next_changeset_uuid', $this->_last_response_parsed['data'] );
$this->assertTrue( wp_is_uuid( $this->_last_response_parsed['data']['next_changeset_uuid'], 4 ) );
$this->assertEquals( 'Success Changeset', get_post( $wp_customize->changeset_post_id() )->post_title );
$this->assertEquals( 'Successful Site Title', get_option( 'blogname' ) );
}
/**
@@ -295,7 +299,6 @@ class Tests_Ajax_CustomizeManager extends WP_Ajax_UnitTestCase {
) );
$wp_customize = $this->set_up_valid_state( $uuid );
// Successful future.
$_POST['customize_changeset_status'] = 'publish';
$_POST['customize_changeset_title'] = 'Published';
$this->make_ajax_call( 'customize_save' );
@@ -304,6 +307,7 @@ class Tests_Ajax_CustomizeManager extends WP_Ajax_UnitTestCase {
$this->assertEquals( 'publish', $this->_last_response_parsed['data']['changeset_status'] );
$this->assertArrayHasKey( 'next_changeset_uuid', $this->_last_response_parsed['data'] );
$this->assertTrue( wp_is_uuid( $this->_last_response_parsed['data']['next_changeset_uuid'], 4 ) );
$this->assertEquals( 'New Site Title', get_option( 'blogname' ) );
$this->assertEquals( 'Published', get_post( $post_id )->post_title );
}
@@ -336,6 +340,7 @@ class Tests_Ajax_CustomizeManager extends WP_Ajax_UnitTestCase {
$_POST['customize_changeset_date'] = $future_date;
$this->make_ajax_call( 'customize_save' );
$this->assertTrue( $this->_last_response_parsed['success'] );
$this->assertArrayHasKey( 'changeset_date', $this->_last_response_parsed['data'] );
$changeset_post_schedule = get_post( $post_id );
$this->assertEquals( $future_date, $changeset_post_schedule->post_date );
@@ -344,6 +349,7 @@ class Tests_Ajax_CustomizeManager extends WP_Ajax_UnitTestCase {
$_POST['customize_changeset_status'] = 'draft';
$this->make_ajax_call( 'customize_save' );
$this->assertTrue( $this->_last_response_parsed['success'] );
$this->assertArrayNotHasKey( 'changeset_date', $this->_last_response_parsed['data'] );
$changeset_post_draft = get_post( $post_id );
$this->assertEquals( $future_date, $changeset_post_draft->post_date );
@@ -351,6 +357,7 @@ class Tests_Ajax_CustomizeManager extends WP_Ajax_UnitTestCase {
$_POST['customize_changeset_status'] = 'future';
$this->make_ajax_call( 'customize_save' );
$this->assertTrue( $this->_last_response_parsed['success'] );
$this->assertArrayHasKey( 'changeset_date', $this->_last_response_parsed['data'] );
$changeset_post_schedule = get_post( $post_id );
$this->assertEquals( $future_date, $changeset_post_schedule->post_date );
// Success if draft with past date.
@@ -380,7 +387,167 @@ class Tests_Ajax_CustomizeManager extends WP_Ajax_UnitTestCase {
$_POST['customize_changeset_status'] = 'publish';
$this->make_ajax_call( 'customize_save' );
$this->assertTrue( $this->_last_response_parsed['success'] );
$this->assertArrayHasKey( 'next_changeset_uuid', $this->_last_response_parsed['data'] );
$this->assertTrue( wp_is_uuid( $this->_last_response_parsed['data']['next_changeset_uuid'], 4 ) );
$changeset_post_publish = get_post( $post_id );
$this->assertNotEquals( $future_date, $changeset_post_publish->post_date );
// Check response when trying to update an already-published post.
$this->assertEquals( 'trash', get_post_status( $post_id ) );
$_POST['customize_changeset_status'] = 'publish';
$this->make_ajax_call( 'customize_save' );
$this->assertFalse( $this->_last_response_parsed['success'] );
$this->assertEquals( 'changeset_already_published', $this->_last_response_parsed['data']['code'] );
$this->assertArrayHasKey( 'next_changeset_uuid', $this->_last_response_parsed['data'] );
$this->assertTrue( wp_is_uuid( $this->_last_response_parsed['data']['next_changeset_uuid'], 4 ) );
}
/**
* Test WP_Customize_Manager::save().
*
* @ticket 39896
* @covers WP_Customize_Manager::save()
*/
public function test_save_autosave() {
$uuid = wp_generate_uuid4();
$post_id = $this->factory()->post->create( array(
'post_name' => $uuid,
'post_type' => 'customize_changeset',
'post_status' => 'draft',
'post_content' => wp_json_encode( array(
'blogname' => array(
'value' => 'New Site Title',
),
) ),
) );
$this->set_up_valid_state( $uuid );
$this->assertFalse( wp_get_post_autosave( $post_id ) );
$_POST['customize_changeset_data'] = wp_json_encode( array(
'blogname' => array(
'value' => 'Autosaved Site Title',
),
) );
$_POST['customize_changeset_autosave'] = 'on';
$this->make_ajax_call( 'customize_save' );
$this->assertTrue( $this->_last_response_parsed['success'] );
$this->assertEquals( 'draft', $this->_last_response_parsed['data']['changeset_status'] );
$autosave_revision = wp_get_post_autosave( $post_id );
$this->assertInstanceOf( 'WP_Post', $autosave_revision );
$this->assertContains( 'New Site Title', get_post( $post_id )->post_content );
$this->assertContains( 'Autosaved Site Title', $autosave_revision->post_content );
}
/**
* Test request for dismissing autosave changesets.
*
* @ticket 39896
* @covers WP_Customize_Manager::handle_dismiss_changeset_autosave_request()
* @covers WP_Customize_Manager::dismiss_user_auto_draft_changesets()
*/
public function test_handle_dismiss_changeset_autosave_request() {
$uuid = wp_generate_uuid4();
$wp_customize = $this->set_up_valid_state( $uuid );
$this->make_ajax_call( 'dismiss_customize_changeset_autosave' );
$this->assertFalse( $this->_last_response_parsed['success'] );
$this->assertEquals( 'invalid_nonce', $this->_last_response_parsed['data'] );
$nonce = wp_create_nonce( 'dismiss_customize_changeset_autosave' );
$_POST['nonce'] = $_GET['nonce'] = $_REQUEST['nonce'] = $nonce;
$this->make_ajax_call( 'dismiss_customize_changeset_autosave' );
$this->assertFalse( $this->_last_response_parsed['success'] );
$this->assertEquals( 'no_auto_draft_to_delete', $this->_last_response_parsed['data'] );
$other_user_id = $this->factory()->user->create();
// Create auto-drafts.
$user_auto_draft_ids = array();
for ( $i = 0; $i < 3; $i++ ) {
$user_auto_draft_ids[] = $this->factory()->post->create( array(
'post_name' => wp_generate_uuid4(),
'post_type' => 'customize_changeset',
'post_status' => 'auto-draft',
'post_author' => self::$admin_user_id,
'post_content' => wp_json_encode( array() ),
) );
}
$other_user_auto_draft_ids = array();
for ( $i = 0; $i < 3; $i++ ) {
$other_user_auto_draft_ids[] = $this->factory()->post->create( array(
'post_name' => wp_generate_uuid4(),
'post_type' => 'customize_changeset',
'post_status' => 'auto-draft',
'post_author' => $other_user_id,
'post_content' => wp_json_encode( array() ),
) );
}
foreach ( array_merge( $user_auto_draft_ids, $other_user_auto_draft_ids ) as $post_id ) {
$this->assertFalse( (bool) get_post_meta( $post_id, '_customize_restore_dismissed', true ) );
}
$this->make_ajax_call( 'dismiss_customize_changeset_autosave' );
$this->assertTrue( $this->_last_response_parsed['success'] );
$this->assertEquals( 'auto_draft_dismissed', $this->_last_response_parsed['data'] );
foreach ( $user_auto_draft_ids as $post_id ) {
$this->assertEquals( 'auto-draft', get_post_status( $post_id ) );
$this->assertTrue( (bool) get_post_meta( $post_id, '_customize_restore_dismissed', true ) );
}
foreach ( $other_user_auto_draft_ids as $post_id ) {
$this->assertEquals( 'auto-draft', get_post_status( $post_id ) );
$this->assertFalse( (bool) get_post_meta( $post_id, '_customize_restore_dismissed', true ) );
}
// Subsequent test results in none dismissed.
$this->make_ajax_call( 'dismiss_customize_changeset_autosave' );
$this->assertFalse( $this->_last_response_parsed['success'] );
$this->assertEquals( 'no_auto_draft_to_delete', $this->_last_response_parsed['data'] );
// Save a changeset as a draft.
$r = $wp_customize->save_changeset_post( array(
'data' => array(
'blogname' => array(
'value' => 'Foo',
),
),
'status' => 'draft',
) );
$this->assertNotInstanceOf( 'WP_Error', $r );
$this->assertFalse( wp_get_post_autosave( $wp_customize->changeset_post_id() ) );
$this->assertContains( 'Foo', get_post( $wp_customize->changeset_post_id() )->post_content );
// Since no autosave yet, confirm no action.
$this->make_ajax_call( 'dismiss_customize_changeset_autosave' );
$this->assertFalse( $this->_last_response_parsed['success'] );
$this->assertEquals( 'no_autosave_revision_to_delete', $this->_last_response_parsed['data'] );
// Add the autosave revision.
$r = $wp_customize->save_changeset_post( array(
'data' => array(
'blogname' => array(
'value' => 'Bar',
),
),
'autosave' => true,
) );
$this->assertNotInstanceOf( 'WP_Error', $r );
$autosave_revision = wp_get_post_autosave( $wp_customize->changeset_post_id() );
$this->assertInstanceOf( 'WP_Post', $autosave_revision );
$this->assertContains( 'Foo', get_post( $wp_customize->changeset_post_id() )->post_content );
$this->assertContains( 'Bar', $autosave_revision->post_content );
// Confirm autosave gets deleted.
$this->make_ajax_call( 'dismiss_customize_changeset_autosave' );
$this->assertTrue( $this->_last_response_parsed['success'] );
$this->assertEquals( 'autosave_revision_deleted', $this->_last_response_parsed['data'] );
$this->assertFalse( wp_get_post_autosave( $wp_customize->changeset_post_id() ) );
// Since no autosave yet, confirm no action.
$this->make_ajax_call( 'dismiss_customize_changeset_autosave' );
$this->assertFalse( $this->_last_response_parsed['success'] );
$this->assertEquals( 'no_autosave_revision_to_delete', $this->_last_response_parsed['data'] );
}
}
+220 -4
View File
@@ -120,6 +120,13 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase {
$this->assertEquals( $uuid, $wp_customize->changeset_uuid() );
$this->assertEquals( $theme, $wp_customize->get_stylesheet() );
$this->assertEquals( $messenger_channel, $wp_customize->get_messenger_channel() );
$this->assertFalse( $wp_customize->autosaved() );
$this->assertTrue( $wp_customize->branching() );
$wp_customize = new WP_Customize_Manager( array(
'changeset_uuid' => null,
) );
$this->assertTrue( wp_is_uuid( $wp_customize->changeset_uuid(), 4 ) );
$theme = 'twentyfourteen';
$messenger_channel = 'preview-456';
@@ -133,7 +140,35 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase {
$_REQUEST['customize_theme'] = $theme;
$wp_customize = new WP_Customize_Manager();
$this->assertEquals( $theme, $wp_customize->get_stylesheet() );
$this->assertNotEmpty( $wp_customize->changeset_uuid() );
$this->assertTrue( wp_is_uuid( $wp_customize->changeset_uuid(), 4 ) );
}
/**
* Test constructor when deferring UUID.
*
* @ticket 39896
* @covers WP_Customize_Manager::establish_loaded_changeset()
* @covers WP_Customize_Manager::__construct()
*/
public function test_constructor_deferred_changeset_uuid() {
$data = array(
'blogname' => array(
'value' => 'Test',
),
);
$uuid = wp_generate_uuid4();
$post_id = $this->factory()->post->create( array(
'post_type' => 'customize_changeset',
'post_name' => $uuid,
'post_status' => 'draft',
'post_content' => wp_json_encode( $data ),
) );
$wp_customize = new WP_Customize_Manager( array(
'changeset_uuid' => false, // Cause UUID to be deferred.
'branching' => false, // To cause drafted changeset to be autoloaded.
) );
$this->assertEquals( $uuid, $wp_customize->changeset_uuid() );
$this->assertEquals( $post_id, $wp_customize->changeset_post_id() );
}
/**
@@ -253,6 +288,45 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase {
$this->assertSame( true, $wp_customize->settings_previewed() );
}
/**
* Test WP_Customize_Manager::autosaved().
*
* @ticket 39896
* @covers WP_Customize_Manager::autosaved()
*/
public function test_autosaved() {
$wp_customize = new WP_Customize_Manager();
$this->assertFalse( $wp_customize->autosaved() );
$wp_customize = new WP_Customize_Manager( array( 'autosaved' => false ) );
$this->assertFalse( $wp_customize->autosaved() );
$wp_customize = new WP_Customize_Manager( array( 'autosaved' => true ) );
$this->assertTrue( $wp_customize->autosaved() );
}
/**
* Test WP_Customize_Manager::branching().
*
* @ticket 39896
* @covers WP_Customize_Manager::branching()
*/
public function test_branching() {
$wp_customize = new WP_Customize_Manager();
$this->assertTrue( $wp_customize->branching(), 'Branching should default to true since it is original behavior in 4.7.' );
$wp_customize = new WP_Customize_Manager( array( 'branching' => false ) );
$this->assertFalse( $wp_customize->branching() );
add_filter( 'customize_changeset_branching', '__return_true' );
$this->assertTrue( $wp_customize->branching() );
remove_filter( 'customize_changeset_branching', '__return_true' );
$wp_customize = new WP_Customize_Manager( array( 'branching' => true ) );
$this->assertTrue( $wp_customize->branching() );
add_filter( 'customize_changeset_branching', '__return_false' );
$this->assertFalse( $wp_customize->branching() );
}
/**
* Test WP_Customize_Manager::changeset_uuid().
*
@@ -337,20 +411,56 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase {
* @covers WP_Customize_Manager::changeset_data()
*/
function test_changeset_data() {
wp_set_current_user( self::$admin_user_id );
$uuid = wp_generate_uuid4();
$wp_customize = new WP_Customize_Manager( array( 'changeset_uuid' => $uuid ) );
$this->assertEquals( array(), $wp_customize->changeset_data() );
$uuid = wp_generate_uuid4();
$data = array( 'blogname' => array( 'value' => 'Hello World' ) );
$data = array(
'blogname' => array( 'value' => 'Hello World' ),
'blogdescription' => array( 'value' => 'Greet the world' ),
);
$this->factory()->post->create( array(
'post_name' => $uuid,
'post_type' => 'customize_changeset',
'post_status' => 'auto-draft',
'post_status' => 'draft',
'post_content' => wp_json_encode( $data ),
) );
$wp_customize = new WP_Customize_Manager( array( 'changeset_uuid' => $uuid ) );
$this->assertEquals( $data, $wp_customize->changeset_data() );
// Autosave.
$wp_customize->set_post_value( 'blogname', 'Hola Mundo' );
$wp_customize->register_controls(); // That is, settings, so blogname setting is registered.
$r = $wp_customize->save_changeset_post( array(
'autosave' => true,
) );
$this->assertNotInstanceOf( 'WP_Error', $r );
// No change to data if not requesting autosave.
$wp_customize = new WP_Customize_Manager( array(
'changeset_uuid' => $uuid,
'autosaved' => false,
) );
$wp_customize->register_controls(); // That is, settings.
$this->assertFalse( $wp_customize->autosaved() );
$this->assertEquals( $data, $wp_customize->changeset_data() );
// No change to data if not requesting autosave.
$wp_customize = new WP_Customize_Manager( array(
'changeset_uuid' => $uuid,
'autosaved' => true,
) );
$this->assertTrue( $wp_customize->autosaved() );
$this->assertNotEquals( $data, $wp_customize->changeset_data() );
$this->assertEquals(
array_merge(
wp_list_pluck( $data, 'value' ),
array( 'blogname' => 'Hola Mundo' )
),
wp_list_pluck( $wp_customize->changeset_data(), 'value' )
);
}
/**
@@ -1272,6 +1382,98 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase {
$this->assertEquals( $other_admin_user_id, $data['scratchpad']['user_id'] );
}
/**
* Test writing changesets when user supplies unchanged values.
*
* @ticket 39896
* @covers WP_Customize_Manager::save_changeset_post()
* @covers WP_Customize_Manager::grant_edit_post_capability_for_changeset()
*/
public function test_save_changeset_post_with_autosave() {
wp_set_current_user( self::$admin_user_id );
$uuid = wp_generate_uuid4();
$changeset_post_id = wp_insert_post( array(
'post_type' => 'customize_changeset',
'post_content' => wp_json_encode( array(
'blogname' => array(
'value' => 'Auto-draft Title',
),
) ),
'post_author' => self::$admin_user_id,
'post_name' => $uuid,
'post_status' => 'auto-draft',
) );
$wp_customize = new WP_Customize_Manager( array(
'changeset_uuid' => $uuid,
) );
$wp_customize->register_controls(); // And settings too.
// Autosave of an auto-draft overwrites original.
$wp_customize->save_changeset_post( array(
'data' => array(
'blogname' => array(
'value' => 'Autosaved Auto-draft Title',
),
),
'autosave' => true,
) );
$this->assertFalse( wp_get_post_autosave( $changeset_post_id ) );
$this->assertContains( 'Autosaved Auto-draft Title', get_post( $changeset_post_id )->post_content );
// Update status to draft for subsequent tests.
$wp_customize->save_changeset_post( array(
'data' => array(
'blogname' => array(
'value' => 'Draft Title',
),
),
'status' => 'draft',
'autosave' => false,
) );
$this->assertContains( 'Draft Title', get_post( $changeset_post_id )->post_content );
// Fail: illegal_autosave_with_date_gmt.
$r = $wp_customize->save_changeset_post( array(
'autosave' => true,
'date_gmt' => ( gmdate( 'Y' ) + 1 ) . '-12-01 00:00:00',
) );
$this->assertInstanceOf( 'WP_Error', $r );
$this->assertEquals( 'illegal_autosave_with_date_gmt', $r->get_error_code() );
// Fail: illegal_autosave_with_status.
$r = $wp_customize->save_changeset_post( array(
'autosave' => true,
'status' => 'pending',
) );
$this->assertEquals( 'illegal_autosave_with_status', $r->get_error_code() );
// Fail: illegal_autosave_with_non_current_user.
$r = $wp_customize->save_changeset_post( array(
'autosave' => true,
'user_id' => $this->factory()->user->create( array( 'role' => 'administrator' ) ),
) );
$this->assertEquals( 'illegal_autosave_with_non_current_user', $r->get_error_code() );
// Try autosave.
$this->assertFalse( wp_get_post_autosave( $changeset_post_id ) );
$r = $wp_customize->save_changeset_post( array(
'data' => array(
'blogname' => array(
'value' => 'Autosave Title',
),
),
'autosave' => true,
) );
$this->assertInternalType( 'array', $r );
// Verify that autosave happened.
$autosave_revision = wp_get_post_autosave( $changeset_post_id );
$this->assertInstanceOf( 'WP_Post', $autosave_revision );
$this->assertContains( 'Draft Title', get_post( $changeset_post_id )->post_content );
$this->assertContains( 'Autosave Title', $autosave_revision->post_content );
}
/**
* Test passing `null` for a setting ID to remove it from the changeset.
*
@@ -2351,10 +2553,24 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase {
$data = json_decode( $json, true );
$this->assertNotEmpty( $data );
$this->assertEqualSets( array( 'theme', 'url', 'browser', 'panels', 'sections', 'nonce', 'autofocus', 'documentTitleTmpl', 'previewableDevices', 'changeset', 'timeouts' ), array_keys( $data ) );
$this->assertEqualSets( array( 'theme', 'url', 'browser', 'panels', 'sections', 'nonce', 'autofocus', 'documentTitleTmpl', 'previewableDevices', 'changeset', 'timeouts', 'initialClientTimestamp', 'initialServerDate', 'initialServerTimestamp' ), array_keys( $data ) );
$this->assertEquals( $autofocus, $data['autofocus'] );
$this->assertArrayHasKey( 'save', $data['nonce'] );
$this->assertArrayHasKey( 'preview', $data['nonce'] );
$this->assertEqualSets(
array(
'branching',
'autosaved',
'hasAutosaveRevision',
'latestAutoDraftUuid',
'status',
'uuid',
'currentUserCanPublish',
'publishDate',
),
array_keys( $data['changeset'] )
);
}
/**