vitest react-testing-library: how to test xlsx file upload and handling?

60 views Asked by At

i have a react component where the user can select a xlsx file and that parses it and shows the data in a table. and i would like to create a simple end-to-end test for it:

  • upload a known xlsx file from disc
  • check that the known data is rendered in the table

i have three questions regarding this

  • with the below code the excel parsing does not work iam unsure if iam doing the file reading correctly - and if there is any nicer vite / vitest build in import/loading function for such a use case?
  • (if the parsing would work) is the waitFor the correct way? / do i need the extra act to trigger the rerender?
  • as iam new to testing - is my idea of the test in any way meaningful? or are there better ways to accomplish this?
import { act, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

import MyImportFile from ".";


import path from "node:path";
import { openAsBlob } from "node:fs";

describe("MyImportFile", () => {
  test("does the upload work?", async () => {
    const user = userEvent.setup();
    render(<MyImportFile />);

    expect(screen.getByText(/person_forename/i)).toBeInTheDocument();

    const input = screen.getByLabelText(/Import XLSX/i);
    expect(input).toBeInTheDocument();

    console.log("__dirname", __dirname);
    const xlsx_file_path = path.join(__dirname, "people_10_min.xlsx");
    // const xlsx_file_path_abs = path.resolve(xlsx_file_path);
    let blob = undefined;
    try {
      blob = await openAsBlob(xlsx_file_path, {
        type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      });
    } catch (error) {
      console.log(error);
    }

    console.log("blob", blob);
    // https://reactjs.org/link/wrap-tests-with-act
    await act(async () => {
      /* fire events that update state */
      await user.upload(input, blob);
    });

    //const data_content = await vi.waitFor(() => screen.getByText(/Friedmann/i));
    //expect(data_content).toBeInTheDocument();
  });
});


i have created a more or less minimal example at codesandbox

and hope to learn a bunch of things :-)

i also posted question relating this to

1

There are 1 answers

0
Stefan Krüger s-light On

solved - with using vite-plugin-arraybuffer: for the file loading.

then i could

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

import MyImportFile from ".";

import xlsx_file from "../../../dev_tests/people_10.xlsx?arraybuffer";

describe("MyImportFile", () => {
    test("does the upload work?", async () => {
        const user = userEvent.setup();
        render(
            <MyImportFile />
        );

        expect(screen.getByText(/person_forename/i)).toBeInTheDocument();

        const input = screen.getByLabelText(/Import XLSX/i);
        expect(input).toBeInTheDocument();
        await user.upload(input, xlsx_file);
        const data_content = await screen.getByText(/^Friedmann/i)
        expect(data_content).toBeInTheDocument();
    });
});

they key was to strip out all Blob and File in between steps. as the promised based blob.arrayBuffer() did not resolve correctly.. (i missed or did not get the await for this correctly..) therefore the fflate got an empty array: resulting in Error: invalid zip data


How i got there:

got there on a very long journey - i tested a bunch of things

  • different plugins and loading / importing versions for the file
  • converting the file to a base64 representation and store this as javascript file
  • this way i could load it in the browser to cross test that the base64 and back decoding to a file did run fine
  • so i could exclude errors on my site and track down to browser / node.js
  • found i had to import import { Blob } from "node:buffer"; to get the Blob creation to work for me
  • but this did not solve the Error: invalid zip data
  • tracked down where the error came from in the code
  • recreated this part in my test case to look at every single step
  • found basically the .arrayBuffer() did not resolve.
  • so back to the beginning.. clean up all (see above.)