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

Editor: Fix move to trash redirect save race conditions. #18275

Merged
merged 5 commits into from
Nov 5, 2019

Conversation

epiqueras
Copy link
Contributor

Description

Two things were causing the unsaved changes warning to trigger when trashing a post:

  1. Posts are still dirty while saving and BrowserUrl was navigating away as soon as the new post status was received, causing the redirection to happen while the post was still technically dirty.

componentDidUpdate( prevProps ) {
const { postId, postStatus, postType } = this.props;
const { historyId } = this.state;
if ( postStatus === 'trash' ) {
this.setTrashURL( postId, postType );
return;
}

  1. Even after that was fixed by waiting for saving to finish completely before navigating away, the UnsavedChangesWarning listener fired immediately with stale values.

warnIfUnsavedChanges( event ) {
const { isDirty } = this.props;
if ( isDirty ) {
event.returnValue = __( 'You have unsaved changes. If you proceed, they will be lost.' );
return event.returnValue;
}
}

That was fixed by calling the selector from within the listener.

How has this been tested?

It was verified that trashing a post no longer triggers an unsaved changes warning.

Types of Changes

Bug Fix: Trashing a post no longer triggers an unsaved changes warning.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.

@epiqueras epiqueras added [Type] Bug An existing feature does not function as intended [Package] Editor /packages/editor labels Nov 4, 2019
@epiqueras epiqueras added this to the Future milestone Nov 4, 2019
@epiqueras epiqueras requested a review from talldan as a code owner November 4, 2019 19:09
@epiqueras epiqueras self-assigned this Nov 4, 2019
@aduth
Copy link
Member

aduth commented Nov 4, 2019

While I don't think it needs to be a blocker, we should definitely have an end-to-end test case covering this behavior.

My thinking was something in packages/e2e-tests/specs/editor/various/change-detection.test.js:

it( 'Should not prompt to confirm unsaved changes when trashing an existing post', async () => {
    await createNewPost( {
        title: 'My New Post',
    } );

    await saveDraft();
    
    // ...trash post and assert no dialog
} );

@aduth
Copy link
Member

aduth commented Nov 4, 2019

Per #17427 (comment), do we still have the potential that a 500 server response can occur when the save occurs after trashing the post? My thinking is something along the lines of:

  1. Add title
  2. Save post
  3. Edit title
  4. Trash post

At step 4, isn't it true that since the save occurs after the trashing, the payload (the edited title) may cause a failed response?

yield apiFetch(
{
path: `/wp/v2/${ postType.rest_base }/${ post.id }`,
method: 'DELETE',
}
);
yield dispatch(
STORE_KEY,
'savePost'
);

@aduth
Copy link
Member

aduth commented Nov 4, 2019

Even after that was fixed by waiting for saving to finish completely before navigating away, the UnsavedChangesWarning listener fired immediately with stale values.

Why are those values "stale" ? Is it that componentDidUpdate is triggered for BrowserURL before the same props can take effect for UnsavedChangesWarning ? It feels to me fragile or non-obvious, and at the very least I would suggest we add a comment explaining why we are calling the selector directly.

@epiqueras
Copy link
Contributor Author

While I don't think it needs to be a blocker, we should definitely have an end-to-end test case covering this behavior.

Done 😄

At step 4, isn't it true that since the save occurs after the trashing, the payload (the edited title) may cause a failed response?

Yeah, but you would want to know you have unsaved changes then.

Why are those values "stale" ? Is it that componentDidUpdate is triggered for BrowserURL before the same props can take effect for UnsavedChangesWarning ? It feels to me fragile or non-obvious, and at the very least I would suggest we add a comment explaining why we are calling the selector directly.

Yes, exactly. I already had a comment there, and I've made it clearer now.

@aduth
Copy link
Member

aduth commented Nov 5, 2019

Per #17427 (comment), do we still have the potential that a 500 server response can occur when the save occurs after trashing the post? My thinking is something along the lines of:

The current Travis test failure appears to suggest an issue exists:

FAIL packages/e2e-tests/specs/editor/various/change-detection.test.js (65.521s)
  ● Change detection › should not prompt to confirm unsaved changes when trashing an existing post
    expect(jest.fn()).not.toHaveErrored(expected)
    Expected mock function not to be called but it was called with:
    ["Failed to load resource: the server responded with a status of 500 (Internal Server Error)"]
      at Object.expect (../jest-console/build/@wordpress/jest-console/src/index.js:34:4)
          at runMicrotasks (<anonymous>)

It's also not surfaced to the user in any meaningful way: There is no notice, and the "Saving" button never changes back to a finished state.

await page.click( '.editor-post-trash.components-button' );

// Check that the dialog didn't show.
await assertIsDirty( false );
Copy link
Member

Choose a reason for hiding this comment

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

assertIsDirty does its check by performing a reload, which I sense would conflict with clicking the trash button. Rather, I think we probably want to press Trash and wait for the page to navigate to the post list (maybe check the success notice as well), optionally adding a 'dialog' even to short-cut the test failure when encountered.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This works because refreshing a page with a dialog doesn't get rid of the dialog. So if navigation didn't happen because the dialog stopped it, assertIsDirty wouldn't assert false.

await page.type( '.editor-post-title__input', 'Hello World' );

// Save
await Promise.all( [
Copy link
Member

Choose a reason for hiding this comment

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

Aside: There's a helper for this saveDraft. The file as a whole could do for some refactoring to use it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, good catch.

@aduth
Copy link
Member

aduth commented Nov 5, 2019

I suspect the 500 seen in the test log is a result of the fact that a draft save is issued via assertIsDirty (edit: this isn't the behavior that happens) at the same time the post is being trashed. Running through the behavior in my browser, it all works correctly, and I see no 500 error.

I will suggest that we revert the commit adding the test case, and reintroduce a fixed implementation in a subsequent pull request.

@aduth aduth merged commit 3c98627 into master Nov 5, 2019
@aduth aduth deleted the fix/move-to-trash-redirect-save-race-condition branch November 5, 2019 15:13
jorgefilipecosta pushed a commit that referenced this pull request Nov 5, 2019
* Editor: Fix move to trash redirect save race conditions.

* Editor: Add e2e test.

* Editor: Expand comment.

* Fix BrowserURL capitalization

* Revert "Editor: Add e2e test."

This reverts commit 4d58c79.
@epiqueras
Copy link
Contributor Author

We needed to wait for the post to save again before asserting:

#18290

This PR fixes and reintroduces the test case from #18275.

It also replaces some ad-hoc saving code with the correct e2e test util, saveDraft.

jorgefilipecosta pushed a commit that referenced this pull request Nov 5, 2019
* Editor: Fix move to trash redirect save race conditions.

* Editor: Add e2e test.

* Editor: Expand comment.

* Fix BrowserURL capitalization

* Revert "Editor: Add e2e test."

This reverts commit 4d58c79.
pento pushed a commit to WordPress/wordpress-develop that referenced this pull request Nov 5, 2019
nylen pushed a commit to nylen/wordpress-develop-svn that referenced this pull request Nov 5, 2019
markjaquith pushed a commit to markjaquith/WordPress that referenced this pull request Nov 5, 2019
gMagicScott pushed a commit to gMagicScott/core.wordpress-mirror that referenced this pull request Nov 5, 2019
@youknowriad youknowriad modified the milestones: Future, Gutenberg 6.9 Nov 11, 2019
miya0001 pushed a commit to cjk4wp/wordpress that referenced this pull request Feb 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Editor /packages/editor [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants