Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cypress testing a Material-UI datepicker is not working on Github actions

We have a strange behavior when running our cypress tests in a github action. MUI datepicker the datepicker is in readonly mode and we can't enter any date (it's fine in other environments).

  1. Error in Cypress

    CypressError: Timed out retrying after 4000ms: cy.clear() failed because this element is readonly: <input aria-invalid="false" readonly="" type="text" aria-readonly="true" aria-label="Choose date" class="MuiOutlinedInput-input MuiInputBase-input css-1x5jdmq" value="">

  2. Visually looks the date picker does not have any button (something is going on) :

enter image description here

  1. The console logs show no error or warning

On other environments, windows/linux, the tests work fine, even though we launch the test in headless mode (all desktops with a UI). The MUI datepicker looks as nice as in MUI documentation (link).

Github action looks like :

on:
  workflow_dispatch:

defaults:
  run:
    working-directory: ic3-test
jobs:
  build:
    runs-on: ubuntu-latest
    container: cypress/included:8.6.0

    steps:    
    - uses: actions/checkout@v2
    - uses: actions/setup-node@v2
      with:
         node-version: '16'
    
    - name: Install dependencies
      run: npm install
      working-directory: ic3-test
                
    - name: Cypress run with env
      uses: cypress-io/github-action@v2
      with:
          # headless: true
          browser: chrome
          record: true
          working-directory: ic3-test

The Cypress line that generates the error :

 cy.getWidget(widgetId).  // this is getting a div with wid = widgetId , works fine
        .find("input.MuiInputBase-input")
        .clear()
        .type(date). // date is a string

Some hints are welcomed

like image 427
ic3 Avatar asked Nov 01 '21 15:11

ic3


3 Answers

We had the same error when running cypress test in azure devops pipelines. And I think its the same reason, looking at your screenshot of the date picker without any button.

The input which was giving us the error was @mui/lab/DatePicker.

We found that this component is rendering as @mui/lab/MobileDatePicker when we ran the cypress tests in azure devops pipelines. It's explained here: docs. That version not accept direct text input, but opens a dialog to pick/input date, therefore cypress test fails when trying to type into the input.

Our solution was to use @mui/lab/DesktopDatePicker directly.

like image 186
Tobias Avatar answered Oct 19 '22 21:10

Tobias


The reason behind this is that Material UI renders the MobileDatePicker component, since the query @media (pointer: fine) doesn't match on the headless Chrome used by our Github Actions Workflow. The mobile component only has readonly inputs, therefore it can't be cleared or typed into with .type() and .clear() (as opposed to the DesktopDatePicker component, which has typable and clearable inputs).

Since we don't want to remove the MobileDatePicker component, we've created a custom command so it checks if the mobile date picker is currently being rendered. If on mobile, the test opens the date picker, clicks on the edit button, so the mobile input view is opened.

And in that input view, the input field is not readonly anymore. Using that command, no matter if desktop or mobile, the input field can be cleared and typed into.

Cypress.Commands.add(
  'chooseDatePicker',
  (selector: string, value: string) => {
    cy.get('body')
      .then(($body) => {
        const mobilePickerSelector = `${selector} input[readonly]`;
        const isMobile = $body.find(mobilePickerSelector).length > 0;
        if (isMobile) {
          // The MobileDatePicker component has readonly inputs and needs to
          // be opened and clicked on edit so its inputs can be edited
          cy.get(mobilePickerSelector)
            .click();
          cy.get('[role="dialog"] [aria-label="calendar view is open, go to text input view"]')
            .click();
          cy.get(`[role="dialog"] ${selector}`)
            .find('input')
            .clear()
            .type(value);
          cy.contains('[role="dialog"] button', 'OK')
            .click();
        } else {
          cy.get(selector)
            .find('input')
            .clear()
            .type(value);
        }
      });
  },
);

// Usage: 
const datePickerValue = '2021-01-03';
cy.chooseDatePicker('[data-testid="my-datepicker"]', datePickerValue);
like image 21
Elektropepi Avatar answered Oct 19 '22 21:10

Elektropepi


Since I haven't seen all the code, I will try to comment as specific as I can, I would like you to review few topics.

1- Examine the properties in the transformed code. Make sure a Property such as helperText={null} is should not set.

2- You might need to install polyfills. For instance for the popper.js (transitive dependency). Although MUI claims that it is (polly) not needed. Technology is advancing every day and there may be changes that they cannot catch.

3- Be sure working right mode. Even test it with Jest. Such window.matchMedia.

like image 24
Hamit YILDIRIM Avatar answered Oct 19 '22 21:10

Hamit YILDIRIM