question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Component test using `cypress/react18` behaves differently than `cypress/react`

See original GitHub issue

Current behavior

I have a component test that is testing a slate (slatejs.org) editor by simply typing some text. Using the import cypress/react the test works fine. Using the import cypress/react18 the test fails. The issue seems to be something due to it calling setFocus and updating the react state when focus is gained. The test fails as no text is ever entered in to the editor.

Commenting out the setFocus state update means the test passes under react 18.

Desired behavior

The test should pass the same using cypress/react and cypress/react18.

Test code to reproduce

import React, { useState } from 'react';
import { Slate, Editable, withReact } from 'slate-react';
import { mount } from 'cypress/react18';
import { createEditor, Descendant } from 'slate';

const MyComponent = () => {
    const [, setFocused] = useState<true | false>();
    const [editor] = useState(() => withReact(createEditor()));
    const [editorValue, setEditorValue] = useState<Descendant[]>([{
        type: 'paragraph',
        children: [{ text: '' }],
    }]);
    return (
        <Slate
            editor={editor}
            value={editorValue}
            onChange={(newValue) => {
                setEditorValue(newValue);
            }}>
            <Editable
                data-testid="styled-text-input"
                placeholder="Please enter a value..."
                onFocus={(event) => {
                    setFocused(true);
                }} />
        </Slate>
    );
};

describe('MyComponent', () => {
    it('should render text when typed', () => {
        mount(
            <MyComponent />,
        );

        // Check component is in it's default state.
        cy.get('[data-testid="styled-text-input"]').should('be.visible');
        cy.get('[data-testid="styled-text-input"]').should('contain.text', 'Please enter a value...');

        // Brag about some coconuts.
        cy.get('[data-testid="styled-text-input"]').click();
        cy.get('[data-testid="styled-text-input"]').type('I\'ve got a lovely bunch of coconuts');
        cy.get('[data-testid="styled-text-input"]').should('have.text', 'I\'ve got a lovely bunch of coconuts');
    });
});

Cypress Version

10.6.0

Node version

18.3.0

Operating System

macOS 12.4

Debug Logs

No response

Other

React: 18.2.0 Slate: 0.72.8

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
lmiller1990commented, Sep 13, 2022

Hm this is strange. Nice that you’ve found a work around, but this is definitely not ideal and seems like a bug.

I will look into this a bit more, but I can’t commit to patching this in the near future, since I’m unsure of the scope of changes required.

I find it very strange this only impacts React 18. Something obviously has changed internally - our React 18 adapter code is identical except for using react-dom/client (new, recommended API).

We should try reproducing this with a regular input controlled by React - I’ve got a sneaking suspicion this is something to do with how react-slate is implemented. Is this a react-slate only bug?

0reactions
lmiller1990commented, Sep 16, 2022

https://github.com/cypress-io/cypress/issues/23589 is similar. Both related to React and Cypress typing really fast, this one is React 17, though.

I don’t know how React 18 works internally, but iirc older versions of React (and maybe v18) has a kind of synthetic event system (not just regular DOM events, it wraps or intercepts them in some fashion). I wonder if this is related to that. Regular DOM events are synchronous, which Cypress assumes to be the case - perhaps there is something specific about React that doesn’t play well with rapidly fired DOM events.

I wonder if we could write a custom command that does something like typeAndWait where it will not trigger the net character input until the previous one is actually rendered. Something like

Cypress.Commands.add('typeAndWait', (el, str) => {
  let typed = ""
  for (const s of str) {
    cy.get(el).type(s).then(() => {
      typed += s
      cy.get(el).should('have.text', typed)
    })
  }

  return cy.get(el)
})

// usage
cy.get('slate-element').typeAndWait('some coconuts')

Just throwing ideas out there, since it’s not entirely clear if this is a bug in Cypress, or just a side effect of a series of assumptions Cypress makes about typing and DOM events (or something entirely different).

Read more comments on GitHub >

github_iconTop Results From Across the Web

React Component Testing Using Cypress
In this type of testing, objects can be tested independently as individual components without integrating with other components e.g., modules, ...
Read more >
My Vision for Component Tests in Cypress - Gleb Bahmutov
The component test directly imports TodoForm from the application code and mounts it using mount method from the cypress-react-unit-test .
Read more >
Testing Environments - React
End-to-end tests are used for testing longer flows across multiple pages, ... like Cypress, puppeteer and webdriver are useful for running end-to-end tests....
Read more >
How to Test React Components: the Complete Guide
Mount/render is typically used for integration testing and shallow is used for unit testing. shallow rendering only renders the single component ...
Read more >
Getting Started with Cypress Component Testing (React)
As of Cypress 7.0, the new Component Test Runner is now bundled with Cypress! It builds on our learnings from the original component...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found