Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/components/Select/__snapshots__/select.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Select Component should match snapshot 1`] = `
<DocumentFragment>
<div
class="MuiFormControl-root css-6bv9qa-MuiFormControl-root-SelectFormControl-root"
>
<div
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-formControl css-8r70ge-MuiInputBase-root-MuiOutlinedInput-root-MuiSelect-root"
data-testid="sort-select"
>
<div
aria-controls=":r5:"
aria-expanded="false"
aria-haspopup="listbox"
class="MuiSelect-select MuiSelect-outlined MuiInputBase-input MuiOutlinedInput-input css-1hhzsab-MuiSelect-select-MuiInputBase-input-MuiOutlinedInput-input"
role="combobox"
tabindex="0"
>
Sort By
</div>
<input
aria-hidden="true"
aria-invalid="false"
class="MuiSelect-nativeInput css-j0riat-MuiSelect-nativeInput"
tabindex="-1"
value=""
/>
<svg
aria-hidden="true"
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium MuiSelect-icon MuiSelect-iconOutlined css-1exavk5-MuiSvgIcon-root-MuiSelect-icon"
data-testid="ArrowDropDownIcon"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M7 10l5 5 5-5z"
/>
</svg>
<fieldset
aria-hidden="true"
class="MuiOutlinedInput-notchedOutline css-1v24f9t-MuiOutlinedInput-notchedOutline"
>
<legend
class="css-w4cd9x"
>
<span
class="notranslate"
>
</span>
</legend>
</fieldset>
</div>
</div>
</DocumentFragment>
`;
60 changes: 60 additions & 0 deletions src/components/Select/select.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from "react";

import { act, customRender, fireEvent, screen } from "@/jest/utils/testUtils";

import Select from "./select";
import { SelectProps } from "./types";

describe("Select Component", () => {
const mockHandleChange = jest.fn();

const setup = (props?: Partial<SelectProps>) => {
const defaultProps: SelectProps = {
menuItems: ["Option 1", "Option 2", "Option 3"],
handleChange: mockHandleChange,
value: "",
};

return customRender(<Select {...defaultProps} {...props} />);
};

it("should render the select component with default option", () => {
setup();
expect(screen.getByText("Sort By")).toBeInTheDocument();
});

it("should render all menu items", async () => {
const { getByRole, getByTestId } = setup();
fireEvent.mouseDown(getByRole("combobox"));
await act(async () => {
expect(getByTestId("Option 1")).toBeInTheDocument();
expect(getByTestId("Option 2")).toBeInTheDocument();
expect(getByTestId("Option 3")).toBeInTheDocument();
});
});

it("should call handleChange when an option is selected", async () => {
const { getByTestId, getByRole } = setup();
fireEvent.mouseDown(getByRole("combobox"));
await act(async () => {
getByTestId("Option 1").click();
});
expect(mockHandleChange).toHaveBeenCalledTimes(1);
});

it("should display the selected value correctly", () => {
const { getByRole } = setup({ value: "Option 3" });
expect(getByRole("combobox")).toHaveTextContent("Option 3");
});

it("should not crash if menuItems is empty", () => {
const { getByRole } = setup({ menuItems: [] });
fireEvent.mouseDown(getByRole("combobox"));
expect(screen.queryByText("Option 1")).not.toBeInTheDocument();
});

test("should match snapshot", () => {
const { asFragment } = setup();
expect(asFragment()).toMatchSnapshot();
});
});
4 changes: 2 additions & 2 deletions src/components/Select/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { SelectProps } from "./types";
const Select: React.FC<SelectProps> = ({ handleChange, value = "", menuItems }) => {
return (
<SelectFormControl>
<MuiSelect value={value as string} onChange={handleChange} displayEmpty>
<MuiSelect value={value as string} onChange={handleChange} displayEmpty data-testid="sort-select">
<MenuItem value="">Sort By</MenuItem>
{menuItems.map((item) => (
<MenuItem key={item} value={10}>
<MenuItem data-testid={item} key={item} value={item}>
{item}
</MenuItem>
))}
Expand Down
10 changes: 5 additions & 5 deletions src/components/Select/styled.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import FormControl from "@mui/material/FormControl";
import { inputClasses } from "@mui/material/Input";
import { selectClasses } from "@mui/material/Select";
import { styled, css } from "@mui/material/styles";
import { styled, css, alpha } from "@mui/material/styles";

export const SelectFormControl = styled(FormControl, {
name: "SelectFormControl",
})(
() => css`
({ theme }) => css`
min-width: 124px;
.${selectClasses.select} {
background-color: ${alpha(theme.palette.colors.white, 0.2)};
border-radius: 6px;
background-color: #50515a;
padding: 8px 10px;
font-size: 14px;
font-weight: 600;
padding: 8px 10px;
}

.${inputClasses.input} {
border: 1px solid #50515a;
border-radius: 8px 10px;
border: 1px solid ${alpha(theme.palette.colors.white, 0.2)};
}
`
);
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ exports[`VideoCard should matches snapshot 1`] = `
class="MuiCardContent-root css-1lt5qva-MuiCardContent-root"
>
<div
class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation1 MuiCard-root css-dt9jx5-MuiPaper-root-MuiCard-root-ImageWrapper-root"
class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation1 MuiCard-root css-jmpm0q-MuiPaper-root-MuiCard-root-ImageWrapper-root"
style="--Paper-shadow: var(--mui-shadows-1); --Paper-overlay: var(--mui-overlays-1);"
>
<span
Expand Down
4 changes: 3 additions & 1 deletion src/components/VideoCard/styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,16 @@ export const ImageWrapper = styled(Card, {
shouldForwardProp,
})(({ theme }) => {
return css`
background: transparent;
display: inline-flex;
position: relative;
width: 100%;

.${skeletonClasses.root} {
border-radius: ${theme.shape.borderRadius + 8}px;
position: absolute;
z-index: -1;
top: 0;
z-index: -1;
}

img {
Expand Down
86 changes: 0 additions & 86 deletions src/redux/login/login.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { eventsApi } from "../events/apiSlice";
import { loginApi } from "../login/apiSlice";
import loginReducer, { loginActions } from "../login/slice";
import { getResetPasswordErrorMessage, parseError } from "../parseError";
import { store } from "../store/configureStore";

describe("Login API and Slice", () => {
Expand Down Expand Up @@ -97,88 +96,3 @@ describe("Login API and Slice", () => {
expect(store.getState().login).toEqual(initialState);
});
});

describe("getResetPasswordErrorMessage", () => {
it("should return null when error is undefined", () => {
expect(getResetPasswordErrorMessage({})).toBeNull();
});

it("should return null when error.data is undefined", () => {
expect(getResetPasswordErrorMessage({})).toBeNull();
});

it("should return joined uid error message", () => {
const error = { data: { uid: ["Invalid UID", "Another UID error"] } };
expect(getResetPasswordErrorMessage(error)).toBe("Invalid UID Another UID error");
});

it("should return joined token error message", () => {
const error = { data: { token: ["Invalid Token"] } };
expect(getResetPasswordErrorMessage(error)).toBe("Invalid Token");
});

it("should return default error message when neither uid nor token exists", () => {
const error = { data: {} };
expect(getResetPasswordErrorMessage(error)).toBe("Something went wrong. Please try again.");
});
});

describe("parseError", () => {
it("should return generic message when statusCode is not a number or is 500", () => {
expect(parseError("some error", "CUSTOM_ERROR")).toEqual([{ statusCode: "CUSTOM_ERROR", message: "Something went wrong." }]);
expect(parseError("server error", 500)).toEqual([{ statusCode: 500, message: "Something went wrong." }]);
});

it("should return the error message when error is a string", () => {
expect(parseError("Invalid request", 400)).toEqual([{ statusCode: 400, message: "Invalid request" }]);
});

it("should recursively parse errors when error is an array", () => {
expect(parseError(["Error 1", "Error 2"], 400)).toEqual([
{ statusCode: 400, message: "Error 1" },
{ statusCode: 400, message: "Error 2" },
]);
});

it("should handle object errors with simple key-value pairs", () => {
expect(parseError({ email: "Invalid email" }, 422)).toEqual([{ statusCode: 422, message: "Email: Invalid email" }]);
});

it("should handle object errors with array values", () => {
expect(parseError({ errors: ["Error 1", "Error 2"] }, 400)).toEqual([
{ statusCode: 400, message: "Errors: Error 1" },
{ statusCode: 400, message: "Errors: Error 2" },
]);
});

it("should handle object errors with nested object values", () => {
expect(parseError({ user: { name: "Required" } }, 400)).toEqual([{ statusCode: 400, message: "User: Name: Required" }]);
});

it("should handle object errors with null or undefined values", () => {
expect(parseError({ key1: null, key2: undefined }, 400)).toEqual([
{ statusCode: 400, message: "Key1: unknown value" },
{ statusCode: 400, message: "Key2: unknown value" },
]);
});

it("should handle deeply nested error structures", () => {
const error = {
user: {
profile: {
email: ["Invalid email"],
age: null,
},
},
};
expect(parseError(error, 400)).toEqual([
{ statusCode: 400, message: "User: Profile: Email: Invalid email" },
{ statusCode: 400, message: "User: Profile: Age: unknown value" },
]);
});

it("should return fallback error message for unknown types", () => {
expect(parseError(12345, 400)).toEqual([{ statusCode: 400, message: "Something went wrong." }]);
expect(parseError(undefined, 400)).toEqual([{ statusCode: 400, message: "Something went wrong." }]);
});
});
61 changes: 61 additions & 0 deletions src/redux/parseError.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { parseError } from "./parseError";

describe("parseError", () => {
it("should return generic message when statusCode is not a number or is 500", () => {
expect(parseError("some error", "CUSTOM_ERROR")).toEqual([{ statusCode: "CUSTOM_ERROR", message: "Something went wrong." }]);
expect(parseError("server error", 500)).toEqual([{ statusCode: 500, message: "Something went wrong." }]);
});

it("should return the error message when error is a string", () => {
expect(parseError("Invalid request", 400)).toEqual([{ statusCode: 400, message: "Invalid request" }]);
});

it("should recursively parse errors when error is an array", () => {
expect(parseError(["Error 1", "Error 2"], 400)).toEqual([
{ statusCode: 400, message: "Error 1" },
{ statusCode: 400, message: "Error 2" },
]);
});

it("should handle object errors with simple key-value pairs", () => {
expect(parseError({ email: "Invalid email" }, 422)).toEqual([{ statusCode: 422, message: "Email: Invalid email" }]);
});

it("should handle object errors with array values", () => {
expect(parseError({ errors: ["Error 1", "Error 2"] }, 400)).toEqual([
{ statusCode: 400, message: "Errors: Error 1" },
{ statusCode: 400, message: "Errors: Error 2" },
]);
});

it("should handle object errors with nested object values", () => {
expect(parseError({ user: { name: "Required" } }, 400)).toEqual([{ statusCode: 400, message: "User: Name: Required" }]);
});

it("should handle object errors with null or undefined values", () => {
expect(parseError({ key1: null, key2: undefined }, 400)).toEqual([
{ statusCode: 400, message: "Key1: unknown value" },
{ statusCode: 400, message: "Key2: unknown value" },
]);
});

it("should handle deeply nested error structures", () => {
const error = {
user: {
profile: {
email: ["Invalid email"],
age: null,
},
},
};
expect(parseError(error, 400)).toEqual([
{ statusCode: 400, message: "User: Profile: Email: Invalid email" },
{ statusCode: 400, message: "User: Profile: Age: unknown value" },
]);
});

it("should return fallback error message for unknown types", () => {
expect(parseError(12345, 400)).toEqual([{ statusCode: 400, message: "Something went wrong." }]);
expect(parseError(undefined, 400)).toEqual([{ statusCode: 400, message: "Something went wrong." }]);
});
});
17 changes: 0 additions & 17 deletions src/redux/parseError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,6 @@ export type ErrorType = {
details?: Record<string, string>;
};

export interface ResetPasswordErrorType {
data?: {
uid?: string[];
token?: string[];
};
}

export const getResetPasswordErrorMessage = (error: ResetPasswordErrorType) => {
if (!error || !error.data) return null;
const { uid, token } = error.data;

if (uid) return uid.join(" ");
if (token) return token.join(" ");

return "Something went wrong. Please try again.";
};

type ErrorStatus = number | string | "FETCH_ERROR" | "PARSING_ERROR" | "TIMEOUT_ERROR" | "CUSTOM_ERROR";

const isErrorAnObject = (err: unknown): err is Record<string, unknown> =>
Expand Down
Loading