React Vitest - testing the click event function and redirection to other page (expected "spy" to be called 1 times)

Viewed 15

I am trying to test a button click and buttons functionality which navigates the page to another page. But I think my button clic in testing is not firing and also don't know how to do test if its rendering the target page on click or not

my component

 import {
      TextInput,
      Stack,
      Form,
      SelectItem,
      Select,
      TextArea,
      Theme,
      Button
    } from '@carbon/react';
    import { useNavigate } from 'react-router-dom';
    import axios from 'axios';
    import { API_PREFIX } from '../../config/api-routes';
    import styles from './AddVaultInstance.module.scss';
    import { useSelector } from 'react-redux';
    import React, { useState } from 'react';
    import {
      isJsonString,
      onlyLettersAndNumbersAndUnderscodeAndHyphen,
      isValidConfigString
    } from '../../utils/ValidationUtil';
    
    function AddVaultInstance() {
      const instanceOUapi = `${API_PREFIX}/instance`;
      const navigate = useNavigate();
    
      const ouOwner = useSelector((state) => state.root.ouOwner);
      const [errors, setErrors] = useState({});
    
      const options = {
        headers: {
          'Content-Type': 'application/json',
          'x-tenant': ouOwner
        }
      };
    
      const formDataToJson = (formData) => {
        var object = {};
        formData.forEach((value, key) => {
          if (!Reflect.has(object, key)) {
            object[key] = value;
            return;
          }
          if (!Array.isArray(object[key])) {
            object[key] = [object[key]];
          }
          object[key].push(value);
        });
        return object;
      };
    
      const createInstancesByOu = async (formData) => {
        const res = await axios.post(instanceOUapi, formData, options);
        console.log('results', res);
      };
    
      const handleSubmit = (e) => {
        e.preventDefault();
        const form = e.target;
        const formData = new FormData(form);
        const formDataJson = formDataToJson(formData);
    
        // starting validation
        if (!onlyLettersAndNumbersAndUnderscodeAndHyphen(formDataJson.id)) {
          errors['id'] = true;
        } else {
          errors['id'] = false;
        }
        if (!onlyLettersAndNumbersAndUnderscodeAndHyphen(formDataJson.name)) {
          errors['name'] = true;
        } else {
          errors['name'] = false;
        }
    
        if (typeof formDataJson.instance_type === 'undefined') {
          errors['type'] = true;
        } else {
          errors['type'] = false;
        }
        if (!isJsonString(formDataJson.config)) {
          errors['config'] = true;
        } else {
          if (
            isValidConfigString(formDataJson.instance_type, formDataJson.config)
          ) {
            errors['config'] = false;
          } else {
            errors['config'] = true;
          }
        }
        setErrors(errors);
        console.log(errors);
    
        if (
          errors['id'] === false &&
          errors['name'] === false &&
          errors['type'] === false &&
          errors['config'] === false
        ) {
          const configuration = JSON.parse(formDataJson.config);
          formDataJson.config = configuration;
          createInstancesByOu(formDataJson);
          navigate('/');
        }
      };
      const handleCancel = (e) => {
        e.preventDefault();
        navigate('/');
      };
      return (
        <>
          <Theme theme="white">
            <Form className={styles.form} onSubmit={(e) => handleSubmit(e)}>
              <Stack gap={7}>
                <h3>Vault Registration</h3>
                <TextInput
                  readOnly
                  defaultValue="tenant"
                  id="tenant"
                  labelText="Tenant"
                  name="tenant"
                  style={{
                    border: '0',
                    box: 'none',
                    background: 'transparent'
                  }}
                />
                <TextInput
                  readOnly
                  defaultValue={ouOwner}
                  id="orgnization_unit_id"
                  labelText="Organization Unit"
                  name="orgnization_unit_id"
                  style={{
                    border: '0',
                    box: 'none',
                    background: 'transparent'
                  }}
                />
                <TextInput
                  id="id"
                  labelText="ID"
                  name="id"
                  placeholder="Vault Identification"
                  invalid={errors.id}
                  invalidText="Id only allows letters, numbers '-' or  '_' and length from 8 to 1024 characters"
                  required
                />
                <TextInput
                  id="name"
                  labelText="Name"
                  name="name"
                  placeholder="Vault Name"
                  invalid={errors.name}
                  invalidText="Name only allows letters, numbers '-' or  '_' and length from 8 to 1024 characters"
                  required
                />
                <Select
                  id="instance_type"
                  name="instance_type"
                  labelText="Type"
                  defaultValue="placeholder-item"
                  helperText="Type of backing vault being registered"
                  invalid={errors.type}
                  invalidText="Please select a type"
                >
                  <SelectItem
                    disabled
                    hidden
                    value="placeholder-item"
                    text="Select Vault Instance"
                  />
                  <SelectItem value="ibmcloud" text="IBM Cloud Secrets Manager" />
                  <SelectItem value="hashicorp" text="Hashi Corp Vault" />
                </Select>
                <TextArea
                  name="config"
                  labelText="Configuration"
                  helperText="HostName, credentials etc"
                  cols={50}
                  rows={4}
                  id="config"
                  placeholder="Placeholder Text"
                  invalid={errors.config}
                  invalidText="Invalid JSON String."
                  required
                />
                <div className={styles.formActions}>
                  <Button kind="secondary" onClick={handleCancel} role="cancel">
                    Cancel
                  </Button>
                  <Button type="submit">Create</Button>
                </div>
              </Stack>
            </Form>
          </Theme>
        </>
      );
    }
    
    export default AddVaultInstance;

my test file: it has "AddVaultInstance is rendering and Cancel Button function is being called" this function, which is not working and I don't know how to perform the other step.

import React from 'react';
import { afterEach, beforeEach, describe, expect, it, test, vi } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import react from '@vitejs/plugin-react';
import { useSelector } from 'react-redux';

import AddVaultInstance from '../../../src/components/instance/AddVaultInstance';
import { ticks } from 'd3';

const mockedNavigator = vi.fn();
const mockReactReduxx = vi.fn();

it.todo('render AddVaultInstance');

//console.log('myscreen: ', screen);

vi.mock("react-redux", () => ({
  useSelector: vi.fn()
}));

test('AddVaultInstance Verify Cancel Button ', () => {
  render(<AddVaultInstance />);

 // expect(screen.getByRole("cancel", { name: "Cancel" })).toBeDefined();
 const mockCallBack = vi.fn();
  //both works
  // name in by Text is nont case sensitive
  expect(screen.getByRole("cancel")).toBeDefined();
  expect(screen.getByText(/cancel/i)).toBeDefined;
});

test('AddVaultInstance Verify Create Button ', () => {
  render(<AddVaultInstance />);

 const mockCallBack = vi.fn();
  //both works
  // name in by Text is nont case sensitive
  expect(screen.getByText(/Create/i)).toBeDefined;
});

test('AddVaultInstance is rendering and Cancel Button function is being called', () => {
  render(<AddVaultInstance />);

 // expect(screen.getByRole("cancel", { name: "Cancel" })).toBeDefined();

  const cancelButton =  screen.getByText(/cancel/i);
  
  const handleCancel = vi.fn();
  console.log("cancelButton: ", cancelButton);
  
  const isfired = fireEvent.click(cancelButton);
  console.log("isfired: ", isfired);

  expect(handleCancel).toHaveBeenCalledTimes(1);

  // TODO: how to test after click its navigating to this location "/""

});



beforeEach(() => {
  vi.mock('react-router-dom', () => ({
    ...vi.importActual('react-router-dom'), // technically it passes without this too, but I'm not sure if its there for other tests to use the real thing so I left it in
    useNavigate: () => mockedNavigator
  }));

  vi.mock('react-redux', () => ({
    ...vi.importActual('react-redux'),
    useSelector: vi.fn((fn) => fn())
  }));

// to handle the const in the component
vi.mock('react-redux', () => {
  const ouOwner = {
    data: {
      ouOwner: '34234.1'
    }
  }
});

vi.mock('react-redux', () => ({
  useSelector: vi.fn().mockImplementation((func) => func(ouOwner))
}));

}); // end of beforeEach

  




afterEach(() => {
  // restoring date after each test run
  vi.clearAllMocks();
}); // end of afterEach

I am getting following error: expected "spy" to be called 1 times Looking forward to hearing from you soon.

0 Answers
Related