Skip to content

Modal controller issue with react testing library #2969

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

Closed
rawadnasr opened this issue Mar 8, 2023 · 3 comments · Fixed by #2861
Closed

Modal controller issue with react testing library #2969

rawadnasr opened this issue Mar 8, 2023 · 3 comments · Fixed by #2861
Labels
content Issues related to the contents of the documentation website

Comments

@rawadnasr
Copy link

Ionic version:
[x] 6.0

I'm submitting a ...

[x] bug report
[ ] feature request

Current behavior:

I'm working with react ionic library to test a button click that present Ion modal programatically (using modal controller). The issue is that the content of Ion Modal is not rendered and i can't reach any element in the modal, while when using inline Modals it is working normally.

Expected behavior:

Ion modal content should be rendered normally and I should be able to get any element from the modal

Steps to reproduce:

git clone https://github.com/rawadnasr/Modal-Controller-Issue.git
npm install
npm test

Related code:

import {
    fireEvent,
    render, 
    screen, 
    waitFor
} from '@testing-library/react';
import Home from './Home';


describe('renders normally', () => {
    it('Should open the modal onClick', async () => {
        render(<Home />);
        const btn = screen.getByText('Open')
        fireEvent.click(btn)
        await waitFor(() => {
            expect(screen.getByText("Modal Content")).toBeInTheDocument()
        })
    }
    )
});

Other information:

Screenshot from 2023-03-08 21-34-30

Ionic info:

Ionic:

   Ionic CLI       : 6.20.3 (/home/rawad/.nvm/versions/node/v14.18.1/lib/node_modules/@ionic/cli)
   Ionic Framework : @ionic/react 6.6.1

Capacitor:

   Capacitor CLI      : 4.7.0
   @capacitor/android : not installed
   @capacitor/core    : 4.7.0
   @capacitor/ios     : not installed

Utility:

   cordova-res : 0.15.4
   native-run  : 1.7.2

System:

   NodeJS : v14.18.1 (/home/rawad/.nvm/versions/node/v14.18.1/bin/node)
   npm    : 6.14.15
   OS     : Linux 5.19
@ionitron-bot ionitron-bot bot added the triage New issues label Mar 8, 2023
@sean-perkins
Copy link
Contributor

sean-perkins commented Mar 28, 2023

@rawadnasr thanks for reporting this issue!

I am having trouble getting the same error logged locally, when I run the tests I receive:

RangeError: Invalid string length

However I noticed in your reproduction you are using Ionic 6, but your test setup is not calling setupIonicRect. Could you try adding:

import { setupIonicReact } from "@ionic/react";

setupIonicReact();

to src/setupTests.ts?

Additionally, Jest defaults to the node test environment, can you try enabling jsdom by updating your package.json scripts:

"test": "react-scripts test --env=jsdom --transformIgnorePatterns 'node_modules/(?!(@ionic/react|@ionic/react-router|@ionic/core|@stencil/core|ionicons)/)'",

Lastly, you appear to be on an older version of both Node and NPM. I would recommend updating to:

  • Node v18
  • npm v9

Can you try this and let me know if you continue to experience the same error?

@sean-perkins sean-perkins added the needs: reply Issues that need more information from the author label Mar 28, 2023
@ionitron-bot ionitron-bot bot removed the triage New issues label Mar 28, 2023
@sean-perkins
Copy link
Contributor

Ok, I debugged this a little further and the issue is that we do not mock the implementation of useIonModal.

You can do this manually in your implementation. For instance here is an example test that mocks the hook implementation and checks that the component is passed to the hook & that the present method is invoked when the button is clicked:

import { fireEvent, render, screen } from "@testing-library/react";

import Home, { ModalContent } from "./Home";

const mockPresent = jest.fn();
const mockUseIonModal = jest.fn();

jest.mock("@ionic/react", () => {
  const rest = jest.requireActual("@ionic/react");
  return {
    ...rest,
    useIonModal: (component: any) => {
      mockUseIonModal(component);
      return [mockPresent];
    },
  };
});

test("should present ModalContent when button is clicked", async () => {
  render(<Home />);

  fireEvent.click(screen.getByText("Open"));

  expect(mockUseIonModal).toHaveBeenCalledWith(ModalContent);
  expect(mockPresent).toHaveBeenCalled();
});

Can you try this out and let me know if you run into any issues?

@ionitron-bot ionitron-bot bot added triage New issues and removed needs: reply Issues that need more information from the author labels Mar 29, 2023
@sean-perkins sean-perkins added the needs: reply Issues that need more information from the author label Mar 29, 2023
@ionitron-bot ionitron-bot bot added triage New issues and removed triage New issues needs: reply Issues that need more information from the author labels Mar 29, 2023
@rawadnasr
Copy link
Author

Ok, I debugged this a little further and the issue is that we do not mock the implementation of useIonModal.

You can do this manually in your implementation. For instance here is an example test that mocks the hook implementation and checks that the component is passed to the hook & that the present method is invoked when the button is clicked:

import { fireEvent, render, screen } from "@testing-library/react";

import Home, { ModalContent } from "./Home";

const mockPresent = jest.fn();
const mockUseIonModal = jest.fn();

jest.mock("@ionic/react", () => {
  const rest = jest.requireActual("@ionic/react");
  return {
    ...rest,
    useIonModal: (component: any) => {
      mockUseIonModal(component);
      return [mockPresent];
    },
  };
});

test("should present ModalContent when button is clicked", async () => {
  render(<Home />);

  fireEvent.click(screen.getByText("Open"));

  expect(mockUseIonModal).toHaveBeenCalledWith(ModalContent);
  expect(mockPresent).toHaveBeenCalled();
});

Can you try this out and let me know if you run into any issues?

Thank you @sean-perkins for your response.
That's exactly what I end up doing to test useIonModal and useIonToast.

@thetaPC thetaPC transferred this issue from ionic-team/ionic-framework May 22, 2023
@thetaPC thetaPC added content Issues related to the contents of the documentation website and removed triage New issues labels May 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
content Issues related to the contents of the documentation website
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants