0

I've a jest test that is failing on addition of a new component to the page. The test is about showing of an error alert once error occurs. Code works in local environment but fails during commit.

Error Text:

TestingLibraryElementError: Unable to find an element with the text: Student is unable to perform register/unregister activities.. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

Test:

jest.mock('react-query', () => ({
      ...jest.requireActual('react-query'),
      useMutation: jest.fn((_key, cb) => {
        cb();
    
        return { data: null };
 })
 }));
    
 const useMutation = useMutationHook as ReturnType<typeof jest.fn>;
    
    describe('StatusAlert', () => {
      beforeEach(() => {
        useMutation.mockReturnValue({});
      });
    
      afterEach(() => {
        jest.restoreAllMocks();
      });

    it('should show error', () => {
        useMutation.mockReturnValueOnce({
          isError: true
        });
    
        const { getByText } = render(
          <StudentRegister
            students={[studentStub, studentStub]}
            onSuccess={jest.fn()}
          />
        );
        expect(getByText(ErrorDict.ErrorRequest)).toBeInTheDocument();
      });

StudentRegister:

Adding this component is causing the above mentioned error:

interface Props {
      selectedStudents: Array<Student>;
      onSuccessCallback: () => void;
    }
    
export const StudentSelectionBar: FC<Props> = ({
  selectedStudents,
  onSuccessCallback
}) => {
  const [isOpenDropCourseModal, setisOpenDropCourseModal] = 
      useState(false);
  const [studentIds, setStudentIds] = useState<string[]>([]);
  useEffect(() => {
        setStudentIds(selectedStudents.map((student) => 
      student.id));
  }, [selectedStudents]);

  const onToggleOpenDropCourseModal = useCallback(() => {
    setisOpenDropCourseModal(
      (state) => !state
    );
  }, []);

  
  const {
    isError: isDropCourseError,
    isSuccess: isDropCourseSuccess,
    isLoading: isDropCourseLoading,
    mutateAsync: DropCourseMutation,
    error: DropCourseError
  } = useMutation<void, ApiError>(
    () => dropCourse(selectedStudents.map((student) => 
       student.id)),
    {
      onSuccess() {
        onToggleOpenDropCourseModal();
        onSuccess();
      }
    }
  );

  return (
    <>
      <StatusAlert
        isError={isDropCourseError}
        isSuccess={isDropCourseSuccess}
        errorMessage={
          dropCourseError?.errorMessage || 
              ErrorMessages.FailedPostRequest
        }
        successMessage="Students successfully dropped from 
         course"
      />
      <StatusAlert
        isError={registerMutation.isError}
        isSuccess={registerMutation.isSuccess}
        errorMessage={
          registerMutation.error?.errorMessage ||
          ErrorDict.ErrorRequest
        }
        successMessage="Students successfully registered"
      />
      <StatusAlert
        isError={isError}
        isSuccess={isSuccess}
        errorMessage={
           error?.errorMessage ||
           ErrorDict.ErrorRequest
        }
        successMessage="Students successfully unregistered"
      />
      <Permissions scope={[DropCourseUsers]}>
        <LoadingButton
          color="error"
          variant="contained"
          onClick={onToggleDropCourseUserModal}
          className={styles['action-button']}
          loading={isDropCourseLoading}
          loadingPosition="center"
          disabled={registerMutation.isLoading || isLoading}
        >         
          drop Course
        </LoadingButton>
      </Permissions>
      <DropCourseModal
        isOpen={isOpenDropCourseModal}
        onCloseModal={onToggleOpenDropCourseModal}
        onArchiveUsers={DropCourseMutation}
        users={studentIds}
      />
    </>
  );
};

Update:

I've noticed that removing useEffect() hook from the component, makes it render correctly in the test. Its function is to update the state variable holding studentIds on every selection on the list.

Is there a way to mock following useEffect hook with dependency in the test?

const [studentIds, setStudentIds] = useState<string[]>([]);
useEffect(() => {
      setStudentIds(selectedStudents.map((student) => student.id));
}, [selectedStudents]);
SJaka
  • 712
  • 13
  • 40
  • 1
    You can use `screen.debug()` or `screen.logTestingPlaygroundURL()` in the test to see what is rendered: https://testing-library.com/docs/queries/about/#debugging. It might helps you understand why the text is not there. – colinD Oct 19 '22 at 12:42
  • Show the code of the `StudentRegister` component. Please provide a https://stackoverflow.com/help/minimal-reproducible-example – Lin Du Oct 20 '22 at 02:22
  • @slideshowp2 most of the code for `StudentRegister` is given in existing and new component. One of the difference between the new and existing components is that `onClick()`, new component opens a modal instead of simply a `mutate`. Does this behavior has to be mimicked in the test as well? – SJaka Oct 20 '22 at 02:49
  • @colinD. Thanks for your reply. I've updated the question with further info. Any thoughts? – SJaka Oct 24 '22 at 17:55
  • It's hard to tell, where is `selectedStudents` coming from? It only appears in the `useEffect`. – colinD Oct 24 '22 at 18:11
  • @colinD, it is coming from a parent component. I've updated code to reflect. – SJaka Oct 24 '22 at 19:30

0 Answers0