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

Block Editor: Assign Provider isSyncingOutcomingValue only when blocks changing #14955

Merged
merged 1 commit into from
Apr 15, 2019

Conversation

aduth
Copy link
Member

@aduth aduth commented Apr 12, 2019

Fixes #14950

This pull request seeks to resolve an issue where Undo may not behave as expected in response to creation of explicit undo levels. Additional debugging is available at #14950 (comment) and #14950 (comment) .

Implementation Notes:

As a controlled input, the BlockEditorProvider component assigns an instance variable to avoid resetting its own state when it knows blocks values are changing (when it is the source of those changes). However, because this was also assigned in response to the creation of an explicit persistence level, even when blocks did not change, it wasn't always correctly unset. The reason for this is that while normally the componentDidUpdate is called immediately after the value is assigned, because the blocks value doesn't actually change, it is not unassigned until the next change occurs. For this reason, by the time the user presses Undo, the instance value is still assigned and it (wrongly) skips resetting the blocks state with value reflecting the Undo.

The changes here simply assign the instance value only if blocks are actually changing, to better represent its intention to account for an expected componentDidUpdate in response to its own changed blocks state.

Testing Instructions:

Repeat Steps to Reproduce from #14950, verifying the Undo result is correct.

Ensure end-to-end tests pass:

npm run build && npm run test-e2e packages/e2e-tests/specs/undo.test.js

@aduth aduth added [Type] Bug An existing feature does not function as intended [Priority] High Used to indicate top priority items that need quick attention [Feature] History History, undo, redo, revisions, autosave. labels Apr 12, 2019
@aduth aduth added this to the 5.5 (Gutenberg) milestone Apr 12, 2019
// Issue is demonstrated by forcing state merges (multiple inputs) on
// an existing text after a fresh reload.
await selectBlockByClientId( ( await getAllBlocks() )[ 0 ].clientId );
await page.keyboard.press( 'End' );
Copy link
Member

Choose a reason for hiding this comment

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

Does it matter whether or not the input happens at the start or end?

Copy link
Member Author

Choose a reason for hiding this comment

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

Does it matter whether or not the input happens at the start or end?

I guess it doesn't matter. More on the point of the actual interaction of appending " World" to make "Hello World" 🤷‍♂️

@ellatrix
Copy link
Member

Looks good in my testing. I also confirmed that the e2e test would fail when running against master.

@ellatrix
Copy link
Member

There are two failing e2e tests though.

@aduth
Copy link
Member Author

aduth commented Apr 12, 2019

I'm struggling with the E2E failures. They pass for me locally, and the specific failures don't really make a whole lot of sense (though relevant in being "Undo" failures). I thought maybe something with the setTimeout and a race condition. Tried some weird hacks to try to monkey-patch the timeout to flush them immediately, but doesn't seem to work:

await page.evaluate( () => {
	let id = 0;

	window.timeouts = [];
	window.setTimeout = ( fn ) => {
		window.timeouts[ id ] = fn;
		return id++;
	};

	window.clearTimeout = ( idToRemove ) => {
		delete window.timeouts[ idToRemove ];
	};
} );

// ...

await page.evaluate( () => {
	window.timeouts.forEach( ( fn ) => fn() );
} );

Going to try restarting it once more. Not great obviously to have intermittent failures in tests being introduced, but curious just to learn whether it is flakey, or reliably failing.

// Issue is demonstrated from an edited post: create, save, and reload.
await clickBlockAppender();
await page.keyboard.type( 'before' );
await pressKeyWithModifier( 'primary', 's' );
Copy link
Member Author

Choose a reason for hiding this comment

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

Possible issue here being that we don't actually wait for the save to happen. I'm going to swap this out with using createNewPost to provide the content.

@aduth
Copy link
Member Author

aduth commented Apr 12, 2019

The fact that failures occur unpredictably in the middle of the revised texts might seem to indicate that some unexpected state change is occurring outside the user input to disrupt the state flattening behavior, which compares only the current and previous actions.

    Expected: "original"
    Received: "modoriginal"

My guess is this is the fetch of reusable blocks, similar to what was seen with #14766. It may in-fact be resolved by #14915. I might try to cherry-pick that commit into this branch temporarily just to see if it makes a difference.

@aduth
Copy link
Member Author

aduth commented Apr 12, 2019

There was one intermittent build failure after the cherry-picked commit for an unrelated test suite (block-deletion.test.js), but it's passing now the second time around.

In retrospect, this makes sense: When the reusable blocks are received, it causes a change in state. #14916 helped to ensure that this change isn't surfaced to the editor to be considered in creating an undo level or in marking the post as dirty, but for the block editor's own comparison of subsequent actions, the receive action will "break the chain" of updating the same block attribute.

I sense this is likely the reason the Undo end-to-end tests have been generally unstable lately.

There's a trade-off, but I'm generally inclined to merge #14915 and then rebase and merge this pull request. The trade-off is:

  • With Editor: Trigger reusable blocks autocomplete when options generated #14915, autocomplete won't fetch (and won't display results of) reusable blocks until the user enters the slash character. It's likely those results would be available by the time they finish typing their search query, and technically the same issue exists already, except that the fetch is triggered immediately upon focus of the paragraph block, so the likelihood of the race condition is lowered (but still present).
  • Without Editor: Trigger reusable blocks autocomplete when options generated #14915, this "breaking the chain" behavior will persist, meaning that Undo levels may be unpredictable not just for tests, but also affecting users, in response to merely focusing the paragraph block (and the subsequent receiving of reusable blocks).

As noted at #14910 (comment), the long-term solution for this is at least partly reflected in #7119, where reusable blocks state ideally does not need to coexist in the top-level block editor state.

The alternative is: This pull request is safe/correct on its own, but the tests are not stable. Therefore, we could opt to not merge #14915, then simply remove the tests here but merge the remainder of changes to resolve #14950.

@aduth aduth force-pushed the fix/14950-undo-explicit-persistence branch from 780d476 to 299313c Compare April 14, 2019 20:14
@aduth
Copy link
Member Author

aduth commented Apr 14, 2019

I rebased the branch to the minimal, safe fix of #14950.

If following #14955 (comment) , #14915 can be merged, then tests cherry-picked back in from commit b99908f.

Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

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

Thanks for the fix

@aduth
Copy link
Member Author

aduth commented Apr 18, 2019

If following #14955 (comment) , #14915 can be merged, then tests cherry-picked back in from commit b99908f.

#14915 was since merged, so I proposed a follow-up pull request at #15049 to introduce the test case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] History History, undo, redo, revisions, autosave. [Priority] High Used to indicate top priority items that need quick attention [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Undo: typing something after fresh post load cannot be undone
3 participants