-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Migrate post privacy confirmation from confirm()
to ConfirmDialog
#37602
Migrate post privacy confirmation from confirm()
to ConfirmDialog
#37602
Conversation
cb75532
to
60d22f3
Compare
Updated this PR to simplify the implementation of ConfirmDialog (cc @ciampo) |
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.
Hey @chad1008 , thank you for working on this!
I noticed that the dropdown with the Post visibility options sits on top of the confirm dialog.
Otherwise, my feedback is basically the same as the one I left in PR 37491, including the consideration about unit/e2e tests.
Thanks for the review @ciampo!
I also tried lifting the
Excellent, thank you again. I'll look into the e2e side of things and circle back. |
Regarding the There's a z-index issue behind this that I've proposed a change for in #37959. |
Update:
Thank you for looking into the problem and opening #37959! As also explained in #37535 (comment), we'll likely have to wait until this issue is fixed before being able to merge this PR. |
Agreed on adding a new E2E with some examples to test the |
Ah, there's already an E2E for this feature here (and it's currently failing in this PR), though I don't understand at first glance how it was supposed to deal with the blocking |
It looks like it was bypassing the logic that shows the native |
45dd8ac
to
2d0cfa5
Compare
I've updated I'd also like to add a test that ensures the For some reason
fails and returns that the node is either not clickable or not an HTMLElement... but
works perfectly. Not sure why Puppeteer's |
await page.waitForSelector( '.components-confirm-dialog' ); | ||
|
||
const cancelButton = await page.waitForSelector( | ||
'.components-confirm-dialog button.is-tertiary' |
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.
I'd prefer to locate the Cancel button using an xpath selection rather than CSS, but for reasons I haven't yet identified,
page.$x( '//button[text()="Cancel"]' )
and
page.waitForXPath( '//button[text()="Cancel"]' )
both cause Puppeteer's ElementHandle.click()
to error out stating the node being passed in isn't visible or isn't an HTML element. The only way I've found to get either of those to successfully click the button is to swap out the click()
method as described previously.
So basically it seems like a choice between the alternate click()
method, or the CSS selector... I'm not sure which would be the lesser of two evils...
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.
I'm not an expert of Puppeteer and XPath.
the node being passed in isn't visible or isn't an HTML element.
This, paired with the previous comment about having to await
, makes me think that you may be trying to access the Cancel button too early? Maybe the dialog is still opening?
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.
I've found out what's wrong: there are actually two buttons on the page with the Cancel
inner text that happened to match that XPath expression. We were selecting the wrong one, which happened to not be accessible at the time puppeteer tried to click it (haven't dug into it, though).
The fix is as simple as changing the XPath expression to //div[contains(@class, "components-confirm-dialog")]//button[text()="Cancel"]')
. This still has the downside of relying on a CSS class (components-confirm-dialog
) which might change in the future but is slightly better than relying on two CSS classes, which is the case with the CSS selector now. We could also traverse to the dialog div by role
(which has a value of dialog
atm).
On the other hand, I think it's not a huge deal to leave it with the CSS selector you've used, @chad1008.
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.
Instead of using the components-confirm-dialog
classname, could we use something like role="dialog"
?
Alternatively, if/when we will add props for confirm/cancel button labels, we'll be able to add a unique label that will avoid the problem altogether
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.
Instead of using the components-confirm-dialog classname, could we use something like role="dialog" ?
Yep, we can do that 👍🏻
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.
I think the best trade-off is to use the //div[contains(@class, "components-confirm-dialog")]//button[text()="Cancel"]')
xpath.
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.
It seems there are more divs on the page with the same role, so it's not specific enough for our use-case :(
This may be worth looking into a little bit — it's weird that there are 2 open dialogs in the page (with 2 cancel buttons). It almost sounds as if the ConfirmDialog
is being rendered twice? And if not the same ConfirmDialog
, it's still weird that there are 2 open dialogs in the same page?
I think the best trade-off is to use the
//div[contains(@class, "components-confirm-dialog")]//button[text()="Cancel"]')
xpath.
One last attempt: what about[role='dialog'] > [role='document'] > button[text='Cancel
]` (of course translated to the correct xpath syntax)?
If nothing else works, we can definitely go with your suggestion. But I'd definitely look a bit more into why there isn't only one "Cancelbutton inside a
dialog` in 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.
But I'd definitely look a bit more into why there isn't only one "Cancelbutton inside adialog` in the page.
Found it. It's the core UI link inserter:
It gets rendered when the page loads, but is hidden by a couple of display: none
on #wp-link-wrap
(one inline style and one added via editor.css
). The modal (and our phantom button) only actually appear on screen in the Classic Editor when adding a link to text on the page.
I'll work on an alternate XPath with this in mind and update when I have something!
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.
//*[@role="dialog"][not(@id="wp-link-wrap")]//button[text()="Cancel"]
should do the trick. (423ff74)
We're relying on the other button's wrapper not to go and change its ID on us, but I don't know that we have a better way to differentiate between the two. Thoughts? 🙂
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.
Of all alternatives, this is my favourite! This test will break only if:
- the dialog's id changes
- a new dialog with a "Cancel" button is added
In both scenarios, it should be quite easy to understand that the change caused the test failure.
I also think that we should update this test as soon as we introduce props for changing the confirm/cancel button labels on ConfirmDialog
:
Alternatively, if/when we will add props for confirm/cancel button labels, we'll be able to add a unique label that will avoid the problem altogether
8601043
to
e2511b0
Compare
I'll give this PR a proper look tomorrow and hopefully we'll be able to merge! |
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.
Code changes LGTM, and the dialog now appears correctly on top of the post visibility dropdown — also extra props for updating and improving the e2e tests!
I just left a few minor comments regarding the selectors used in the e2e tests, but once those are addressed this PR is ready to be merged 🎉
packages/e2e-tests/specs/editor/various/post-visibility.test.js
Outdated
Show resolved
Hide resolved
packages/e2e-tests/specs/editor/various/post-visibility.test.js
Outdated
Show resolved
Hide resolved
packages/e2e-tests/specs/editor/various/post-visibility.test.js
Outdated
Show resolved
Hide resolved
packages/e2e-tests/specs/editor/various/post-visibility.test.js
Outdated
Show resolved
Hide resolved
Thanks for the e2e review @ciampo. I was focused on tests for one of the other PRs today, but I'll address your suggestions here in the morning! |
Co-authored-by: Marco Ciampini <[email protected]>
…ing post visibility
423ff74
to
68e2a04
Compare
Updated tests based on @ciampo's helpful suggestions ✅ |
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.
Thank you @chad1008 for addressing all feedback! Changes LGTM and test well as per instruction (and the newly added e2e tests!)
As next steps, I see 2 separate tasks:
- Add props to
ConfirmDialog
to allow its consumers to set custom text labels forConfirm
andCancel
buttons (which will also allow us to remove some of "hacky" CSS selectors in the e2e tests) - Make sure that we have a good UX in place when setting the post visibility fails for some reason (more details in the comment below)
confirmPrivate = () => { | ||
const { onUpdateVisibility, onSave } = this.props; | ||
|
||
onUpdateVisibility( 'private' ); | ||
this.setState( { hasPassword: false } ); | ||
this.setState( { | ||
hasPassword: false, | ||
showPrivateConfirmDialog: false, | ||
} ); | ||
onSave(); | ||
} | ||
}; |
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.
As a future improvement, it'd be good to investigate what happens in case of failure to set the post visibility to private
(for example, if the internet connection stops working of is the server returns an error).
How do the onUpdateVisibility
and onSave
functions behave? In case of error, should we close the dialog and display a message? Or should we keep the dialog open until we have a confirmation of success, and potentially show an error message within the dialog?
This task is actually partially related to the conversation in #37492 (comment) regarding adding a isDisabled
prop to the ConfirmDialog
component
Description
This PR aims to migrate the post editor's
Switch to draft
button away from the currentconfirm()
implementation and instead use the new experimentalConfirmDialog
component.How has this been tested?
Before testing, cherrypick #37959 on top of this PR. That will ensure the
ConfirmDialog
has the proper z-index to render on top of its parent component.Running WordPress 5.8.2 via
wp-env
:I've tested in the latest Chrome, Firefox, and Safari.
Checklist:
*.native.js
files for terms that need renaming or removal).ironment, tests ran to see how -->