/* * Copyright 2021-2024 Avaiga Private Limited * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ import React from "react"; import { fireEvent, render, waitFor } from "@testing-library/react"; import "@testing-library/jest-dom"; import userEvent from "@testing-library/user-event"; import FileSelector from "./FileSelector"; import { TaipyContext } from "../../context/taipyContext"; import { TaipyState, INITIAL_STATE } from "../../context/taipyReducers"; import { uploadFile } from "../../workers/fileupload"; jest.mock("../../workers/fileupload", () => ({ uploadFile: jest.fn().mockResolvedValue("mocked response"), // returns a Promise that resolves to 'mocked response' })); describe("FileSelector Component", () => { it("renders", async () => { const { getByText } = render(); const elt = getByText("toto"); expect(elt.tagName).toBe("SPAN"); }); it("displays the right info for string", async () => { const { getByText } = render(); const elt = getByText("toto"); expect(elt.parentElement).toHaveClass("taipy-file-selector"); }); it("displays the default value", async () => { const { getByText } = render(); getByText("titi"); }); it("is disabled", async () => { const { getByText } = render(); const elt = getByText("val"); expect(elt).toHaveClass("Mui-disabled"); }); it("is enabled by default", async () => { const { getByText } = render(); const elt = getByText("val"); expect(elt).not.toHaveClass("Mui-disabled"); }); it("is enabled by active", async () => { const { getByText } = render(); const elt = getByText("val"); expect(elt).not.toHaveClass("Mui-disabled"); }); //looks like userEvent upload does not fire onchange xit("dispatch a well formed message on file selection", async () => { const file = new File(["(⌐□_□)"], "chucknorris.png", { type: "image/png" }); const dispatch = jest.fn(); const state: TaipyState = INITIAL_STATE; const { getByText } = render( , ); const elt = getByText("FileSelector"); const inputElt = elt.parentElement?.querySelector("input"); expect(inputElt).toBeInTheDocument(); inputElt && (await userEvent.upload(inputElt, file)); expect(dispatch).toHaveBeenCalledWith({ name: "", payload: { args: [], action: "on_action" }, type: "SEND_ACTION_ACTION", }); }); it("dispatch a specific text on file drop", async () => { const file = new File(["(⌐□_□)"], "chucknorris2.png", { type: "image/png" }); const { getByRole, getByText } = render(); const elt = getByRole("button"); const inputElt = elt.parentElement?.querySelector("input"); expect(inputElt).toBeInTheDocument(); waitFor(() => getByText("Drop here to Upload")); inputElt && fireEvent.drop(inputElt, { dataTransfer: { files: [file], }, }); }); it("displays a dropped custom message", async () => { const file = new File(["(⌐□_□)"], "chucknorris2.png", { type: "image/png" }); const { getByRole, getByText } = render( , ); const elt = getByRole("button"); const inputElt = elt.parentElement?.querySelector("input"); expect(inputElt).toBeInTheDocument(); waitFor(() => getByText("drop here those files")); inputElt && fireEvent.drop(inputElt, { dataTransfer: { files: [file], }, }); }); it("handles drag over event", () => { const { getByRole } = render(); const fileSelector = getByRole("button"); // Create a mock DragEvent and add a dataTransfer object const mockEvent = new Event("dragover", { bubbles: true }) as unknown as DragEvent; Object.assign(mockEvent, { dataTransfer: { dropEffect: "", }, }); // Dispatch the mock event fireEvent(fileSelector, mockEvent); // Add assertion to check if dropEffect is set to "copy" expect(mockEvent.dataTransfer!.dropEffect).toBe("copy"); }); it("handles file drop", async () => { // Create a mock file const file = new File(["(⌐□_□)"], "chucknorris.png", { type: "image/png" }); const { getByRole } = render(); const elt = getByRole("button"); // Create a mock DragEvent and add the mock file to the event's dataTransfer.files property const mockEvent = new Event("drop", { bubbles: true }) as unknown as DragEvent; Object.assign(mockEvent, { dataTransfer: { files: [file], }, }); // Dispatch the mock event fireEvent(elt, mockEvent); expect(uploadFile).toHaveBeenCalledTimes(1); }); it("resets dropLabel and dropSx on drag leave", async () => { const { getByRole, getByTestId } = render(); const elt = getByRole("button"); // Create a mock DragEvent const mockEvent = new Event("dragleave", { bubbles: true }) as unknown as DragEvent; // Dispatch the mock event fireEvent(elt, mockEvent); // Add assertions to check if dropLabel and dropSx have been reset const dropLabelElement = getByTestId("file-selector"); expect(dropLabelElement.textContent).toBe(" "); const buttonElement = getByTestId("upload-button"); expect(buttonElement).toHaveStyle("min-width: 0px"); }); it("checks if notification is dispatched on file upload completion", async () => { const mockDispatch = jest.fn(); const { getByTestId } = render( , ); // Simulate file upload const file = new File(["(⌐□_□)"], "chucknorris.png", { type: "image/png" }); const inputElement = getByTestId("file-selector").querySelector("input"); if (inputElement) { fireEvent.change(inputElement, { target: { files: [file] } }); } // Wait for the upload to complete await waitFor(() => expect(mockDispatch).toHaveBeenCalled()); // Check if the alert action has been dispatched expect(mockDispatch).toHaveBeenCalledWith( expect.objectContaining({ type: "SET_ALERT", atype: "success", duration: 3000, message: "mocked response", system: false, }), ); }); it("checks if error notification is dispatched on file upload failure", async () => { const mockUploadFile = uploadFile as jest.Mock; mockUploadFile.mockImplementation(() => { return new Promise((resolve, reject) => { reject("Upload failed"); }); }); const mockDispatch = jest.fn(); const { getByTestId } = render( , ); // Simulate file upload const file = new File(["(⌐□_□)"], "chucknorris.png", { type: "image/png" }); const inputElement = getByTestId("file-selector").querySelector("input"); if (inputElement) { fireEvent.change(inputElement, { target: { files: [file] } }); } // Wait for the upload to complete await waitFor(() => expect(mockDispatch).toHaveBeenCalled()); // Check if the alert action has been dispatched expect(mockDispatch).toHaveBeenCalledWith( expect.objectContaining({ type: "SET_ALERT", atype: "error", duration: 3000, message: "Upload failed", system: false, }), ); }); it("checks if dispatch is called correctly", async () => { // Mock the uploadFile function to resolve with a success message (uploadFile as jest.Mock).mockImplementation(() => Promise.resolve("mocked response")); const mockDispatch = jest.fn(); const { getByTestId, queryByRole } = render( , ); // Simulate file upload const file = new File(["(⌐□_□)"], "chucknorris.png", { type: "image/png" }); const inputElement = getByTestId("file-selector").querySelector("input"); if (inputElement) { fireEvent.change(inputElement, { target: { files: [file] } }); } // Check if the progress bar is displayed during the upload process expect(queryByRole("progressbar")).toBeInTheDocument(); // Wait for the upload to complete await waitFor(() => expect(mockDispatch).toHaveBeenCalled()); // Check if the progress bar is not displayed after the upload is completed expect(queryByRole("progressbar")).not.toBeInTheDocument(); // Check if the dispatch function has been called with the correct action expect(mockDispatch).toHaveBeenCalledWith( expect.objectContaining({ type: "SEND_ACTION_ACTION", name: "", payload: { args: [], action: "testAction" }, }), ); }); it("checks if no action is taken when no file is uploaded", async () => { const mockDispatch = jest.fn(); const { getByTestId } = render( , ); // Simulate file upload without providing a file const inputElement = getByTestId("file-selector").querySelector("input"); if (inputElement) { fireEvent.change(inputElement, { target: { files: [] } }); } // Check if the dispatch function has not been called expect(mockDispatch).not.toHaveBeenCalled(); }); });