What is the best way to simulate an unexported function in Javascript jest environments?

Testing a module in my vuejs project is what I'm currently focusing on.

import { getBaseUrl } from "@/application/api/baseUrl";

export default (
  uri: string,
  requestBody: Record<string, string | number>
): void => {
  let form = document.createElement("form";

  form.method = "POST";
  form.action = `${getBaseUrl()}/${uri}`;

  form = convertToFormData(form, requestBody);
  submitForm(form);
};

function convertToFormData(
  form: HTMLFormElement,
  requestBody: Record<string, string | number>
) {
  for (const [key, value] of Object.entries(requestBody)) {
    const element = document.createElement("input");
    element.name = key;
    element.value = value.toString();
    form.appendChild(element);
  }
  return form;
}

function submitForm(form: HTMLFormElement) {
  document.body.appendChild(form);
  form.submit();
}

I need to test the behavior without actually redirecting. To achieve this, I plan to mock submitForm using jest.fn() and then analyze its behavior.

I attempted to implement rewire with babel for ts, but it didn't work with the new vue-cli 5.*. The babel packages appear to be outdated. Are there other methods to test this behavior effectively?

Below is my current testing scenario:

import postRedirect from "@/application/util/postRedirect";

const submitFormMock = jest.fn();
jest.mock("@/application/util/postRedirect", () => ({
  ...jest.requireActual('@/application/util/postRedirect'),
  submitForm: submitFormMock,
}));


describe("PostRedirect", () => {
  it("", () => {
    postRedirect("test", { foo: "bar", baz: "foo" });

    expect(submitFormMock).toBeCalled();
    const formDataObject = {} as Record<string, unknown>;

    for (const [key, value] of new FormData(
      submitFormMock.mock.calls[0][0]
    ).entries()) {
      formDataObject[key] = value;
    }

    expect(formDataObject.foo).toBe("bar");
    expect(formDataObject.baz).toBe("foo");
  });
});

I tried mocking submitForm, but that approach seems ineffective. Any suggestions on how to correctly mock this behavior would be appreciated.

Update: I'm also exploring the option of exporting submitForm even if it's not intended for export. However, I'm facing challenges with this approach as well, especially since I need to mock only one named export rather than the default export.

Answer №1

After being inspired by @jonrsharpe, I decided to try a new testing approach where private methods are not tested.

Although it may seem unconventional, I wanted to verify that when my function triggers a redirect via a POST call, it actually submits and generates the correct form attributes.

I am open to exploring different perspectives on this testing method and alternative ways to accomplish a post redirection to another application.

import postRedirect from "@/application/util/postRedirect";

describe("PostRedirect", () => {
  it("", () => {
    const mockSubmit = jest.fn();
    window.HTMLFormElement.prototype.submit = mockSubmit
    postRedirect("test", { foo: "bar", baz: "foo" });
    expect(mockSubmit).toBeCalled();

    // @ts-ignore
    const values = Array.from(new FormData(document.getElementsByTagName("form")[0] as HTMLFormElement));
    
    expect(values[0][0]).toBe("foo");
    expect(values[0][1]).toBe("bar");
    expect(values[1][0]).toBe("baz");
    expect(values[1][1]).toBe("foo");
  });
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Generating Legible JavaScript Code from TypeScript

I am looking to maintain the readability of my compiled JS code, similar to how I originally wrote it, in order to make debugging easier. However, the typescript compiler introduces several changes that I would like to disable. For instance: During compi ...

What is the best way to customize the interval time for my specific situation?

I'm working on setting an interval in my app and I have the following code: HTML <div class="text"> {{currentItem.name}} </div> <ul> <li ng-repeat="item in items" ng-click="pickItem($index)">{{item.type}}</li> ...

The presence of an Angular Element within an Angular application can lead to a problematic cycle of constant reloading,

, I am encountering issues with integrating Angular Elements as plugins into my Angular application. The problem arises when building the element with "--prod" - it functions properly with "ng serve" in my development setup but causes infinite reloading wh ...

Automate table column width adjustments in HTML using Selenium WebDriver

As of now, I am working on automating the process of increasing the width of an HTML table column using Selenium WebDriver. I discovered that I can retrieve the coordinates of x and y by using findElement(By.cssSelector("<Css locator>").getLocation( ...

Getting the x-axis points on Google charts to start at the far left point

I have integrated the Google API for charts into my application and am using multiple charts on the same page. However, I am facing an issue with setting padding for the charts. When I include more data points, the chart area occupies more space in the div ...

The hyperlink appears to be malfunctioning with an additional border surrounding it within a pop-up window

I am facing an issue with a link <a> not functioning properly with a popup dialog on . Additionally, there seems to be a border that appears around the <a> when the popup initially displays. If you click on "Leer más" for any product, you can ...

Arranging a string array in JavaScript according to an integer array

Looking at the provided javascript arrays: letterArray ['a', 'e', 'i', 'o', 'u'] We also have another array that corresponds to it: valueArray [12, 22, 7, 7, 3] The goal is to sort the valueArray into: ...

Collapse the mobile nav bar upon clicking an item

I'm currently facing a challenge with the navigation bar on my event landing page. The issue is that when I open the navbar in mobile view, it does not collapse back after clicking on an item. Instead, it remains open and covers almost 3/4 of the scre ...

What is the best way to turn off jQuery UI (widget) for a particular element?

Is it possible to disable the Jquery-UI selectmenu widget for a specific element in my project so that it reverts back to its native look and functionality? I have tried various solutions suggested in a Stack Overflow thread about disabling theming for a ...

Retrieve the original content of a file uploaded by a user in Node.js using Express

Can we extract the raw file contents from a user uploaded file using Node.js Express? app.post('/images', upload.single('image'), async (req, res) => { const file = req.file ... I have come to realize that the file variable in t ...

What is the best way to showcase multiple selected values in a div using jQuery?

Is there a way to use jquery to populate an empty div with the values selected from a multi-select dropdown? How can I achieve this in the context of the provided code snippet? <select multiple data-style="bg-white rounded-pill px-4 py-3 shadow-sm" c ...

What causes the Object expected error in jQuery?

Looking for a way to demo horizontal collapse pane with a simple web page that includes html, css, and jquery. <html> <head> <script type="text/javascript" src="//code.jquery.com/jquery-1.10.1.js"></script> <title>Sa ...

Align boxes in the center within a DIV container

Here is the box design that I have created: The green color boxes are generated dynamically inside a "col-md-10" div. If there are less than 3 boxes in the second row, I would like to center align them. For example, in this case, I want the "Bi-monthly" b ...

Setting up multiple versions of npm application

Can I have multiple versions of npm installed for different projects on Windows 10, or are npm installations always global? I attempted to install different versions using https://github.com/marcelklehr/nodist, but it only affected the node version and no ...

Is there a gentle approach to transferring calendar event variables in JavaScript?

The example provided below showcases a @model that contains data. To utilize specific portions of the data, I have transformed it into a Json object using Json.Serialize. This was necessary because the events:[ ] section requires data in a particular form ...

What is the best way to implement rate limiting for Next.js server actions?

In my current project, I have implemented server actions in next.js following the guidelines provided on Server Actions Although everything is functioning properly, I am now looking to add rate limiting to the server action to prevent potential spam or at ...

Once the AJAX callback is complete, the onblur event will revert back to the original field or the updated field

I am currently working with an AJAX callback: Here is the HTML snippet: <a onCLick="loadXMLDoc(id1,id2)">(Add)</a> This function triggers an AJAX method that replaces the "(Add)" text with a basic HTML input field. Subsequently, when there ...

Calculating numbers with Math.ceil will result in an increase of 1

After using Math.ceil, one value was rounded up to 50 and the other to 80. However, when I added these two values together, the result unexpectedly turned out to be 131. console.log(Math.ceil(e.currentTarget.clientHeight) // 50 console.log(Math.ceil(e.cu ...

What is the method to provide function parameters without executing the function?

I'm searching for a solution to obtain a function that requires a parameter without actually invoking the function. Example of current malfunctioning code: const _validations = { userID: (req) => check('userID').isString().isUUID(&apo ...

How come useEffect runs only once even when multiple states in the dependency array of useEffect change simultaneously?

<div onClick={() => { updateValue1((x: number) => x + 1); updateValue2((x: number) => x + 3); }} > one? two? </div> const [value1, updateValue1] = useState(1); const [value2, updateValue2] = useState(1 ...