-
-
Notifications
You must be signed in to change notification settings - Fork 68
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
chore(commands): laid out groundwork for state tracking #210
base: main
Are you sure you want to change the base?
Conversation
@@ -0,0 +1,36 @@ | |||
import {mouseButtonNumbers} from './mouseButtonNumbers' |
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.
this is the main reason behind the PR - I'd like to make "state" (like button mask and pressed keys) to be tracked by the library, it's a chore to maintain this on the consumer's side and this would match how Playwright works
|
||
const { clickCount = 1 } = options | ||
|
||
for (let currentClick = 1; currentClick <= clickCount; currentClick++) { |
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.
this loop is a fix - gonna prepare a separate PR with this in a moment and when it lands I will rebase this PR on top of 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.
And there it is: #212
@@ -26,6 +27,32 @@ export interface realMouseDownOptions { | |||
button?: keyof typeof mouseButtonNumbers; | |||
} | |||
|
|||
export async function rawMouseDown({ |
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 extracted this so the "composite" realClick
command can benefit from the state tracking
return { | ||
keyCode: keyCode, | ||
key: keyDefinition?.key ?? "", | ||
text: keyDefinition.key.length === 1 ? keyDefinition.key : undefined, |
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.
this line is why this was needed: 5978a6e , after the change to:
- text: keyDefinition.key.length === 1 ? keyDefinition.key : undefined,
+ text: 'text' in keyDefinition ? keyDefinition.text : undefined,
the special-casing of Enter is not needed anymore, so I've basically reverted the referenced commit
if (key.code === "Enter") { | ||
await fireCdpCommand("Input.dispatchKeyEvent", { | ||
type: "char", | ||
unmodifiedText: "\r", | ||
text: "\r", | ||
}); | ||
} |
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.
@@ -52,8 +43,7 @@ export async function realType(text: string, options: RealTypeOptions = {}) { | |||
}, [] as string[]); | |||
|
|||
for (const char of chars) { | |||
assertChar(char); |
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.
this isn't needed as getKeyCodeDefinitions
throws on unknown characters anyway
@@ -52,8 +43,7 @@ export async function realType(text: string, options: RealTypeOptions = {}) { | |||
}, [] as string[]); | |||
|
|||
for (const char of chars) { | |||
assertChar(char); | |||
await realPress(char, { |
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 refactored this to use rawRealPress
(that I've introduced in this PR) since I believe that "composite" commands should use "raw" commands over the ones that are exposed publicly as Cypress commands
@@ -0,0 +1,36 @@ | |||
import { keyCodeDefinitions } from "./keyCodeDefinitions"; | |||
|
|||
export type Key = keyof typeof keyCodeDefinitions; |
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.
just moved this around and tweaked slightly so both realPress
and realType
can use this
src/mouseButtonNumbers.ts
Outdated
@@ -1,8 +1,7 @@ | |||
export const mouseButtonNumbers = { | |||
"none": 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.
Since my plan is to track the state - there should be no way to configure "none" mouse buttons for commands like realMouseDown
and stuff. Unless this is needed by some kind of mouse input virtualization but I would expect such things to be pretend that some button is pressed so I'm not sure when in practice the none button could be actually used
import { realMouseDown } from "./commands/realMouseDown"; | ||
import { realMouseUp } from "./commands/realMouseUp"; |
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 renamed those files to match other file names
|
||
Cypress.on('window:before:load', InternalState.clear) |
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 like a reasonable hook to clear the state. I think that this should work (although it's weird):
it('foo', () => {
cy.visit('https://...')
cy.get('.btn').realMouseDown()
})
it('bar', () => {
// no visit or anything, piggybacking on the state from the previous test block
// performing anything here should assume that the mouse button is still down
})
622c9fa
to
827e084
Compare
…` and `realMouseUp` (#201)
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 do not understand how this should work on the user side. Can you describe the high level API and the benefits this will bring to the users.
Thanks
827e084
to
48a22b4
Compare
My main motivation is that with test scenarios like this: cy.realKeyDown('ShiftLeft')
cy.realClick()
cy.realKeyUp('ShiftLeft') I would expect the click to be performed with the shift key being pressed down ( |
I don't really like storing a state between commands because:
For something like this I'd like to see something like this cy.withRealEventsContext(() => {
cy.realKeyDown('ShiftLeft')
cy.realClick()
cy.realKeyUp('ShiftLeft')
}) In this case if user wants he can do it's own test function that will wrap all the internal commands inside this function. Like const testReal = (name, fn) => it(name, () => cy.withRealEventsContext(fn))
/// then in test
testReal("it works", () => {
cy.realKeyDown('ShiftLeft')
cy.realClick()
cy.realKeyUp('ShiftLeft')
}) Naming is TBD have no preference there but I'd really like to have control over the mutations that can affect future command |
I agree that this is implicit but I would argue that this actually helps developers. The very same argument can be said about the opposite - I was actually confused that this sort of stuff is not handled automatically. The consumer of this package is completely not aware of the implementation details, the intricacies of the CDP protocol etc and I think that it makes perfect sense to expect a "lock" (like a key being pressed down) to stay "locked" as long as the lock is not released. This would match the behavior of a lot of existing lock-like APIs out there. This would also match the behavior of both Puppeteer and Playwright.
It's a valid concern but also... when would you like to turn this off? At the moment I don't find any compelling scenarios when this would actually be desirable. I expect people to write tests mimicking the user. If a particular sequence of commands cannot be performed by the user then it shouldn't be allowed by the API of this library.
Agreed, but is it a bad thing? Some breaking changes are expected - we can batch this together with some other work. Progress requires breaking changes from time to time - we grow and learn new things about the underlying tools here and it would be a waste not to learn from that and get stuck with the older API for an undefined amount of time, right? |
@dmtrKovalenko any more thoughts about this one? |
Again sorry for long answering but:
The same works opposite. I personally will expect all the commands to be completely standalone and do not imply on the other commands
I would like to avoid this behavior as much as possible and execute one command at a time. Because I know too much about how testing drivers works inside :D. But in fact yes it can confuse somebody when you execute a command and 3 commands after it affects something else. Make sure that user can do the keydown in a shared command which is out of context
I don't think this is a valid reason to make a breaking change for this type of feature |
04b8a35
to
2282480
Compare
This builds on top of #201