/*
* 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 { render, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import { ThemeProvider } from "@mui/material/styles";
import { createTheme } from "@mui/material/styles";
import Metric from "./Metric";
const template = {
layout: {
colorscale: {
diverging: [
[0, "#8e0152"],
[0.1, "#c51b7d"],
[0.2, "#de77ae"],
[0.3, "#f1b6da"],
[0.4, "#fde0ef"],
[0.5, "#f7f7f7"],
[0.6, "#e6f5d0"],
[0.7, "#b8e186"],
[0.8, "#7fbc41"],
[0.9, "#4d9221"],
[1, "#276419"],
],
sequential: [
[0, "#0d0887"],
[0.1111111111111111, "#46039f"],
[0.2222222222222222, "#7201a8"],
[0.3333333333333333, "#9c179e"],
[0.4444444444444444, "#bd3786"],
[0.5555555555555556, "#d8576b"],
[0.6666666666666666, "#ed7953"],
[0.7777777777777778, "#fb9f3a"],
[0.8888888888888888, "#fdca26"],
[1, "#f0f921"],
],
sequentialminus: [
[0, "#0d0887"],
[0.1111111111111111, "#46039f"],
[0.2222222222222222, "#7201a8"],
[0.3333333333333333, "#9c179e"],
[0.4444444444444444, "#bd3786"],
[0.5555555555555556, "#d8576b"],
[0.6666666666666666, "#ed7953"],
[0.7777777777777778, "#fb9f3a"],
[0.8888888888888888, "#fdca26"],
[1, "#f0f921"],
],
},
paper_bgcolor: "rgb(255,0,0)",
},
};
const colorMap = {
20: "red",
40: null,
60: "blue",
80: null,
};
const darkTemplate = {
layout: {
colorscale: {
diverging: [
[0, "#8e0152"],
[0.1, "#c51b7d"],
[0.2, "#de77ae"],
[0.3, "#f1b6da"],
[0.4, "#fde0ef"],
[0.5, "#f7f7f7"],
[0.6, "#e6f5d0"],
[0.7, "#b8e186"],
[0.8, "#7fbc41"],
[0.9, "#4d9221"],
[1, "#276419"],
],
sequential: [
[0, "#0d0887"],
[0.1111111111111111, "#46039f"],
[0.2222222222222222, "#7201a8"],
[0.3333333333333333, "#9c179e"],
[0.4444444444444444, "#bd3786"],
[0.5555555555555556, "#d8576b"],
[0.6666666666666666, "#ed7953"],
[0.7777777777777778, "#fb9f3a"],
[0.8888888888888888, "#fdca26"],
[1, "#f0f921"],
],
sequentialminus: [
[0, "#0d0887"],
[0.1111111111111111, "#46039f"],
[0.2222222222222222, "#7201a8"],
[0.3333333333333333, "#9c179e"],
[0.4444444444444444, "#bd3786"],
[0.5555555555555556, "#d8576b"],
[0.6666666666666666, "#ed7953"],
[0.7777777777777778, "#fb9f3a"],
[0.8888888888888888, "#fdca26"],
[1, "#f0f921"],
],
},
paper_bgcolor: "rgb(31,47,68)",
},
};
const lightTemplate = {
layout: {
colorscale: {
diverging: [
[0, "#053061"],
[0.1, "#2166ac"],
[0.2, "#4393c3"],
[0.3, "#92c5de"],
[0.4, "#d1e5f0"],
[0.5, "#f7f7f7"],
[0.6, "#fddbc7"],
[0.7, "#f4a582"],
[0.8, "#d6604d"],
[0.9, "#b2182b"],
[1, "#67001f"],
],
sequential: [
[0, "#f7fcf5"],
[0.1111111111111111, "#e5f5e0"],
[0.2222222222222222, "#c7e9c0"],
[0.3333333333333333, "#a1d99b"],
[0.4444444444444444, "#74c476"],
[0.5555555555555556, "#41ab5d"],
[0.6666666666666666, "#238b45"],
[0.7777777777777778, "#006d2c"],
[0.8888888888888888, "#00441b"],
[1, "#000000"],
],
sequentialminus: [
[0, "#f7fcf5"],
[0.1111111111111111, "#e5f5e0"],
[0.2222222222222222, "#c7e9c0"],
[0.3333333333333333, "#a1d99b"],
[0.4444444444444444, "#74c476"],
[0.5555555555555556, "#41ab5d"],
[0.6666666666666666, "#238b45"],
[0.7777777777777778, "#006d2c"],
[0.8888888888888888, "#00441b"],
[1, "#000000"],
],
},
paper_bgcolor: "rgb(255,255,255)",
},
};
describe("Metric Component", () => {
it("renders", async () => {
const { container } = render();
const elt = container.querySelector(".test");
expect(elt?.tagName).toBe("DIV");
});
it("displays the right info for class", async () => {
const { container } = render();
const elt = container.querySelector(".test");
expect(elt).toHaveClass("test");
});
it("sets the title when provided", async () => {
const title = "Test Title";
const { container } = render();
await waitFor(() => {
const titleElement = container.querySelector(".gtitle");
if (!titleElement) {
throw new Error("Title element not found");
}
expect(titleElement.textContent).toContain(title);
});
});
it("logs an error when template prop is a malformed JSON string", () => {
const consoleSpy = jest.spyOn(console, "info");
const malformedJson = "{ key: 'value'";
render();
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Error while parsing Metric.template"));
consoleSpy.mockRestore();
});
it("logs an error when colorMap prop is a malformed JSON string", () => {
const consoleSpy = jest.spyOn(console, "info");
const malformedJson = "{ key: 'value'"; // missing closing brace
render();
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Error parsing color_map value (metric)"));
consoleSpy.mockRestore();
});
it("sets the template when provided", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".main-svg");
expect(elt).toHaveStyle({
backgroundColor: "rgb(255, 0, 0)",
});
});
});
it("processes colorMap prop correctly", async () => {
const { container } = render();
await waitFor(() => {
const elements = container.querySelectorAll(".bg-arc");
const redElt = Array.from(elements[1].children);
const redEltHasRedFill = redElt.some((elt) => (elt as HTMLElement).style.fill === "rgb(255, 0, 0)");
expect(redEltHasRedFill).toBeTruthy();
const blueElt = Array.from(elements[2].children);
const blueEltHasBlueFill = blueElt.some((elt) => (elt as HTMLElement).style.fill === "rgb(0, 0, 255)");
expect(blueEltHasBlueFill).toBeTruthy();
});
});
it("processes delta prop correctly when delta is defined", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".delta");
if (elt) {
expect(elt.textContent).toContain("10");
} else {
throw new Error("Element with class .delta not found");
}
});
});
it("applies style correctly when deltaColor is set", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".delta");
expect(elt).toHaveStyle({
fill: "rgb(255, 65, 54)",
});
});
});
it("applies style correctly when deltaColor is set invert", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".delta");
expect(elt).toHaveStyle({
fill: "rgb(255, 65, 54)",
});
});
});
it("processes type and threshold props correctly when type is linear", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".bullet");
expect(elt).toBeInTheDocument();
});
});
it("processes type and threshold props correctly when type is not linear", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".angular");
expect(elt).toBeInTheDocument();
});
});
it("applies style correctly when height and width are undefined", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".js-plotly-plot");
expect(elt).toHaveStyle({
width: "20vw",
height: "20vh",
});
});
});
it("applies style correctly when height is set to 100px", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".js-plotly-plot");
expect(elt).toHaveStyle({
height: "100px",
});
});
});
it("applies style correctly when height is set to 30em", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".js-plotly-plot");
expect(elt).toHaveStyle({
height: "30em",
});
});
});
it("applies style correctly when height is set to 30%", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".js-plotly-plot");
expect(elt).toHaveStyle({
height: "30%",
});
});
});
it("applies style correctly when height is set to 30vh", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".js-plotly-plot");
expect(elt).toHaveStyle({
height: "30vh",
});
});
});
it("applies style correctly when height is set to 30vw", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".js-plotly-plot");
expect(elt).toHaveStyle({
height: "30vw",
});
});
});
it("applies style correctly when width is set to 100px", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".js-plotly-plot");
expect(elt).toHaveStyle({
width: "100px",
});
});
});
it("applies style correctly when width is set to 30em", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".js-plotly-plot");
expect(elt).toHaveStyle({
width: "30em",
});
});
});
it("applies style correctly when width is set to 30%", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".js-plotly-plot");
expect(elt).toHaveStyle({
width: "30%",
});
});
});
it("applies style correctly when width is set to 30vh", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".js-plotly-plot");
expect(elt).toHaveStyle({
width: "30vh",
});
});
});
it("applies style correctly when width is set to 30vw", async () => {
const { container } = render();
await waitFor(() => {
const elt = container.querySelector(".js-plotly-plot");
expect(elt).toHaveStyle({
width: "30vw",
});
});
});
it("processes type prop correctly when type is none (string)", async () => {
const { container } = render();
await waitFor(() => {
const angularElm = container.querySelector(".angular");
const angularAxis = container.querySelector(".angularaxis");
expect(angularElm).not.toBeInTheDocument();
expect(angularAxis).not.toBeInTheDocument();
});
});
it("processes type prop correctly when type is None", async () => {
const { container } = render();
await waitFor(() => {
const angularElm = container.querySelector(".angular");
const angularAxis = container.querySelector(".angularaxis");
expect(angularElm).not.toBeInTheDocument();
expect(angularAxis).not.toBeInTheDocument();
});
});
it("processes template_Dark_ prop correctly when theme is dark", async () => {
const darkTheme = createTheme({
palette: {
mode: "dark",
},
});
const { container } = render(
,
);
await waitFor(() => {
const elt = container.querySelector(".main-svg");
expect(elt).toHaveStyle({
backgroundColor: "rgb(31, 47, 68)",
});
});
});
it("processes template_Light_ prop correctly when theme is not dark", async () => {
const lightTheme = createTheme({
palette: {
mode: "light",
},
});
const { container } = render(
,
);
await waitFor(() => {
const elt = container.querySelector(".main-svg");
expect(elt).toHaveStyle({
backgroundColor: "rgb(255, 255, 255)",
});
});
});
it.skip("logs an error when template_Dark_ prop is not a valid JSON string", () => {
const consoleSpy = jest.spyOn(console, "info");
render();
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Error while parsing Metric.template"));
consoleSpy.mockRestore();
}); // TODO: Not working at the moment, need to fix
it("logs an error when template_Light_ prop is not a valid JSON string", () => {
const consoleSpy = jest.spyOn(console, "info");
render();
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Error while parsing Metric.template"));
consoleSpy.mockRestore();
});
});