-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Position caret at end of previous block for any type of block removal #8961
Conversation
Adding Andrew as a reviewer because he worked recently on the merge/split which also can be impacted by removal actions. The changes look good to me, I just worry about unexpected side effects, I'll try to test a bit. |
The general idea here seems quite sensible on a glance to me as well. Will give a deep review shortly. |
In all cases, an e2e test covering the bug fixed by this PR would be a good idea :) |
b4c9018
to
1644fe3
Compare
Could you look in to the failing end-to-end test? I expect it may be legitimate. Generally speaking, I'm still thinking this looks to be a very good refactor 👍 |
I'm going to punt this to 3.7 :( because I don't think it's ready for 3.6 |
e2e test seems to be passing now. I'll write a test to cover this functionality today :) |
7edc8ba
to
508177a
Compare
Hey @aduth & @youknowriad, I've added e2e tests, sorry for the delay. Hope they look ok, the only way I could think to test caret position was to type some additional text to make sure it was added in the correct place. I think it should adequately guard against regressions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the end-to-end tests. They are very thorough! In fact, I'd expected we might only need to add a test case or two to the existing splitting-merging.test.js
file. Upon examination of these test cases though, deletion seems to have quite a few specific behaviors, so perhaps a standalone file is appropriate.
I've left a few remarks for you to consider.
test/e2e/support/utils.js
Outdated
*/ | ||
export async function clickOnBlockSettingsMenuItem( buttonLabel ) { | ||
await expect( page ).toClick( '.editor-block-settings-menu__toggle' ); | ||
const itemButton = ( await page.$x( `//button[contains(text(), '${ buttonLabel }')]` ) )[ 0 ]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way we could improve this to limit the selector to the context of the block settings menu? Currently it could match any button on the page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very true - I've improved the selector in a way that I think resolves this.
test/e2e/support/utils.js
Outdated
export async function clickOnBlockSettingsMenuItem( buttonLabel ) { | ||
await expect( page ).toClick( '.editor-block-settings-menu__toggle' ); | ||
const itemButton = ( await page.$x( `//button[contains(text(), '${ buttonLabel }')]` ) )[ 0 ]; | ||
await itemButton.click( 'button' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the argument necessary? Seems click()
would occur on the button anyways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now removed.
test/e2e/support/utils.js
Outdated
@@ -272,6 +290,17 @@ export async function clickOnMoreMenuItem( buttonLabel ) { | |||
await itemButton.click( 'button' ); | |||
} | |||
|
|||
/** | |||
* Clicks on Block Settings Menu item, searches for the button with the text provided and clicks it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aside: Generally speaking we might consider making these utilities less specific to the specific interaction and more toward the task (triggering a block settings menu item). Opens up future refactoring, and we want to avoid expecting a particular mode of interaction (i.e. couldn't this be implemented with a keyboard? And if not, is that a problem we should be aware of?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I don't think we need to rush to add functions to utils.js
. If we're using them only in one test, it seems fine to define them in that one test, and move things as common patterns emerge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is already a test using the keyboard shortcut for the menu item, so it might be unnecessary to also have a version that clicks the menu item.
Anyway - I've moved the code out of utils now (for this and the modifier keys mentioned above).
test/e2e/support/utils.js
Outdated
* | ||
* @type {string} | ||
*/ | ||
export const PRIMARY_ALT_MODIFIER_KEYS = process.platform === 'darwin' ? [ 'Alt', 'Meta' ] : [ 'Control', 'Alt' ]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this? Or is it sufficient to do [ 'Alt', META_KEY ]
? Same applies for the constant defined below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
If #9190 is merged first, I'll have to update the new tests to use the right shortcut. |
expect( await getEditedPostContent() ).toMatchSnapshot(); | ||
} ); | ||
|
||
it( 'positions the caret at the end of the second block as evidenced by typing additional text', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An it
test should be standalone, and not make any assumptions about other it
s being run or the order in which they're run (for example, to enable parallelization of test execution). This seems like it should be part of the previous test case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also FWIW it's fine for a single test case to contain multiple toMatchSnapshot
} ); | ||
|
||
describe( 'deleting the third block using the Remove Block shortcut', () => { | ||
beforeAll( addThreeParagraphsToNewPost ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically we shouldn't want to see beforeAll( addThreeParagraphsToNewPost );
as it implies we have multiple tests operating on the same sets of blocks, which presumably are being manipulated by the individual test cases.
It should be a beforeEach
to ensure that each test case has a consistently fresh (un-tampered) set of blocks to work with.
await page.keyboard.press( 'Backspace' ); | ||
expect( await getEditedPostContent() ).toMatchSnapshot(); | ||
|
||
expect( await getEditedPostContent() ).toMatchSnapshot(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessarily duplicated? Nothing occurs between this and the previous toMatchSnapshot
assertion?
@aduth - thanks for the feedback. I wasn't aware test cases could be parallelized. I've combined them now. It's a shame we lose the descriptiveness of the test cases, particularly in the snapshots, but so be it. When I made that change, the |
@aduth - If you get a moment to re-review it would be much appreciated. I believe I've addressed all the feedback. |
This looks great, except I'm not fond of the changes to We should plan to understand better the issue here. What was the error? Was the default block appender not available on the initial page load after |
The issue I had was still very unusual and I wish I could explain what caused it and why it happened in the one test case and not others. The exact line that caused the latency is this one: With that line present, the next test would fail. When I commented it out the next test passed. It seems very unlikely to be an issue in Gutenberg, but I am surprised it happened—the tests aren't doing anything extraordinary. Anyway, a bit of further investigation and I've pushed a commit that removes the
Perhaps if we don't expect any latency issues we should top using page.click. |
- See REMOVE_BLOCKS effect in editor store's effect.js file. Final action when removing blocks is to handle selection of the previous block
- Replace `expect( page ).toClick` with `page.click`. The former won't show errors when used in a before/after. The latter also seems to better handle latency issues, the former was failing when used too soon after a page load. - Add waitForSelector to ensure the block appender is render before attempts to click it.
…rst step of a call to page.click
dfc9709
to
ef01a14
Compare
This does seem ready to me, would you mind having a final look @aduth? |
The changes look good. It's not immediately obvious to me by the link where Puppeteer is waiting for the element's presence? The Anyways, since the code looks good and tests are passing, I'm assuming it's a non-issue now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great. Thanks for the patience in the delays working through the tests for an otherwise-simple change 😄
@talldan This is really really nice, thanks so much for working on this. Since you've touched this, there's one other thing I would love fixed that's tangential to this. Right now, if you select all blocks on a page and delete them, you've lost focus. It would be nice if when deleting all blocks on the page you simply set focus on the first appender. In other words, steps to reproduce:
Notice how after deleting those blocks, focus is lost — it would be nice if focus was simply restored to the appender: |
@jasmussen This seems like a very reasonable expectation. Do we / should we have an issue tracking it? |
@jasmussen A new issue would be good 👍 |
Description
As pointed out on #8805 - when removing a block (using either the keyboard shortcut or block settings menu), the caret ends up at the beginning of a preceding paragraph block. It feels natural that the cursor should instead be at the end of the block.
This ticket features a couple of simple changes to improve the situation, placing the cursor by default at the end of the the next selected block in the REMOVE_BLOCKS effect.
Some duplicated code is also removed.
There still seem to be a few cases where the flow is not quite right:
These issues still exist in master, so will create separate issues.
How has this been tested?
Types of changes
Bug fix (non-breaking change which fixes an issue)
Checklist: