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

onChange is not called when using Cypress's type command #3476

Closed
achou11 opened this issue Jan 30, 2020 · 10 comments
Closed

onChange is not called when using Cypress's type command #3476

achou11 opened this issue Jan 30, 2020 · 10 comments

Comments

@achou11
Copy link

achou11 commented Jan 30, 2020

Do you want to request a feature or report a bug?

bug

What's the current behavior?

Using Cypress's type command to insert some text in a Slate editor. The Slate onChange handler doesn't seem to be called while typing (note how the placeholder is never removed):

cypress-slate-issue

Here's some console output for the onChange handler for the duration of this interaction:

onchange-console-slate-issue

This was only logged once (presumably when the editor mounted). Instead, this should've been logged several times and the leaf should've ended up with a text value equivalent to what was typed.

Slate: 0.57.1
Browser: Chrome (in a Cypress environment)
OS: Mac

What's the expected behavior?

onChange should be called as the value changes when typing. There's some documentation about how events are handled for Cypress's type command here.

@achou11
Copy link
Author

achou11 commented Jan 30, 2020

Update: looks like the type command is inserting the text into an unexpected element i.e. the element that accompanies the placeholder and contains zero width character:

text-insert-dom

Not sure if this is a Slate issue or a Cypress issue at this point.

@mattapperson
Copy link

@achou11 do you by any chance have a small test-case of this issue?

@Jmaharman
Copy link

There is an ongoing thread of users finding their appropriate hacks to get it working. Some may lead to a solution of how to support it natively.

https://slate-js.slack.com/archives/C1RH7AXSS/p1579110773288500

@cameracker
Copy link
Collaborator

cameracker commented Mar 4, 2020

Slate is relying more heavily on the beforeInput event to deal with user interaction.

I havent had the time to dive into this problem, but reading the documentation on cypress I noticed:

https://docs.cypress.io/api/commands/type.html#Events-that-fire

beforeinput is not fired even though it is in the spec because no browser has adopted it.

And this is probably because firefox still does not declare they support beforeInput

https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/beforeinput_event

Firefox has released a preview version that does have beforeinput support so that might work out soon

https://bugzilla.mozilla.org/show_bug.cgi?id=970802

Cypress does not yet have an issue for this on their backlog as far as I could tell.

https://github.com/cypress-io/cypress

I'm uncertain I have enough information to make a report.

@reydelo
Copy link

reydelo commented Apr 22, 2020

The Cypress input commands (e.g. cy.type() and cy.clear()) work by dispatching input and change events - in the case of cy.type(), one per character. This mimics the behavior of a real browser as a user types on their keyboard and is enough to trigger the behavior of most application JavaScript.

However, Slate relies almost exclusively on the beforeinput event (see here https://docs.slatejs.org/concepts/xx-migrating#beforeinput) which is a new browser technology and an event which the Cypress input commands don’t simulate. Hopefully the Cypress team will update their input commands to dispatch the beforeinput event, but until they do I’ve created a couple of simple custom commands which will trigger Slate’s input event listeners and make it respond.

// commands.js
Cypress.Commands.add('getEditor', (selector) => {
  return cy.get(selector)
    .click();
});

Cypress.Commands.add('typeInSlate', { prevSubject: true }, (subject, text) => {
  return cy.wrap(subject)
    .then(subject => {
      subject[0].dispatchEvent(new InputEvent('beforeinput', { inputType: 'insertText', data: text }));
      return subject;
    })
});
 
Cypress.Commands.add('clearInSlate', { prevSubject: true }, (subject) => {
  return cy.wrap(subject)
    .then(subject => {
      subject[0].dispatchEvent(new InputEvent('beforeinput', { inputType: 'deleteHardLineBackward' }))
      return subject;
    })
});

// slateEditor.spec.js
cy.getEditor('[data-testid=slateEditor1] [contenteditable]')
    .typeInSlate('Some input text ');

cy.getEditor('[data-testid=slateEditor2] [contenteditable]')
    .clearInSlate()
    .typeInSlate('http://httpbin.org/status/409');

If you need to support other inputTypes, all of the inputTypes supported by Slate are listed here

@alexmonteirocastro
Copy link

@reydelo Tried that approach but it didn't work.

@mwood23
Copy link
Contributor

mwood23 commented Apr 26, 2020

@alexmonteirocastro I couldn't get it to work for me either and chased it down into the source. The solution posted works and goes through all the code paths you'd want as long as your Editable component has autoFocus on it. I'm using Storybook and had to cy.wait(200) on render for mine to work. To test your setup you can try running cypress against the Slate example.

// Spec file to be ran in Cypress
describe('Test that setup works', () => {
  beforeEach(function() {
    cy.visit('https://www.slatejs.org/examples/richtext')
  })

  it('Can type in Slate using helper commands', function() {
    cy.getEditor('[contenteditable=true]').typeInSlate('Some text here')
  })
})

Here's a snippet from the examples on usage.

@BrentFarese
Copy link
Collaborator

Closing this since, as noted above, it really is a Cypress issue with Cypress not firing beforeinput and there are listed workarounds above for folks that need to test using Cypress.

@lavaldi
Copy link

lavaldi commented Oct 28, 2020

Someone was able to test the editor with CyPress without the autoFocus property?

@appsgodfather
Copy link

Is someone knows how to simulate the enter button click in the slate input? For example, the comment input field which posts a comment after click Enter

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests