Skip to content

Commit 6adbe5d

Browse files
authored
Merge branch 'master' into feature/group-invite-link
2 parents 7bde325 + c52a1d6 commit 6adbe5d

File tree

140 files changed

+1975
-819
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

140 files changed

+1975
-819
lines changed

mwdb/web/jest.config.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
11
module.exports = {
2+
preset: "ts-jest",
23
testEnvironment: "jsdom",
4+
moduleNameMapper: {
5+
"^@/(.*)$": "<rootDir>/src/$1",
6+
},
7+
transform: {
8+
"^.+\\.(js|jsx|ts|tsx)$": "ts-jest",
9+
},
10+
testMatch: [
11+
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
12+
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}",
13+
],
14+
moduleFileExtensions: ["js", "jsx", "ts", "tsx"],
15+
moduleNameMapper: {
16+
"^@mwdb-web/commons/(.*)$": "<rootDir>/src/commons/$1",
17+
"^@mwdb-web/plugins$": "<rootDir>/src/mocks/plugins.ts",
18+
},
19+
resetMocks: true,
320
};

mwdb/web/package-lock.json

Lines changed: 553 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mwdb/web/package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"dev": "vite",
77
"build": "vite build",
88
"preview": "vite preview",
9-
"test": "jest"
9+
"test": "jest",
10+
"lint": "tsc --watch"
1011
},
1112
"dependencies": {
1213
"@fortawesome/fontawesome-svg-core": "^6.1.1",
@@ -47,15 +48,23 @@
4748
"@babel/preset-env": "^7.21.4",
4849
"@babel/preset-react": "^7.18.6",
4950
"@testing-library/react": "^14.0.0",
51+
"@types/identicon.js": "^2.3.1",
52+
"@types/jest": "^29.5.1",
5053
"@types/react": "^18.0.26",
54+
"@types/react-copy-to-clipboard": "^5.0.4",
5155
"@types/react-dom": "^18.0.9",
56+
"@types/react-js-pagination": "^3.0.4",
57+
"@types/react-modal": "^3.16.0",
58+
"@types/sha1": "^1.1.3",
5259
"@vitejs/plugin-react": "^3.0.0",
5360
"babel-jest": "^29.5.0",
5461
"dpdm": "^3.9.0",
5562
"jest": "^29.5.0",
5663
"jest-environment-jsdom": "^29.5.0",
5764
"prettier": "^2.4.1",
5865
"react-test-renderer": "^18.2.0",
66+
"ts-jest": "^29.1.0",
67+
"ts-node": "^10.9.1",
5968
"vite": "^4.0.0",
6069
"vite-plugin-checker": "^0.5.6"
6170
},

mwdb/web/src/App.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,12 @@ import UserCapabilities from "./components/Settings/Views/UserCapabilities";
6767
import UserAPIKeys from "./components/Settings/Views/UserAPIKeys";
6868
import { AttributeEditTemplate } from "./components/Settings/Views/AttributeEditTemplate";
6969

70-
import { Capability } from "./commons/auth";
7170
import { ConfigContext } from "./commons/config";
7271
import { fromPlugins, Extendable } from "./commons/plugins";
7372
import { ErrorBoundary, RequiresAuth, RequiresCapability } from "./commons/ui";
7473

74+
import { Capability } from "@mwdb-web/types/types";
75+
7576
function NavigateFor404() {
7677
/**
7778
* Fallback route for unknown routes

mwdb/web/src/__tests__/helpers/index.test.js renamed to mwdb/web/src/__tests__/helpers/index.test.tsx

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import { GenericOrJSX } from "@mwdb-web/types/types";
12
import { capitalize, intersperse, mapObjectType } from "../../commons/helpers";
23

34
describe("capitalize", () => {
45
test("should return empty string when param is not typeof string", () => {
56
const string = {};
67
const expected = "";
7-
const result = capitalize(string);
8+
const result = capitalize(string as string);
89
expect(result).toEqual(expected);
910
});
1011

@@ -25,20 +26,32 @@ describe("capitalize", () => {
2526

2627
describe("intersperse", () => {
2728
test("should return an empty array when passed an empty array", () => {
28-
const expected = [];
29+
const expected: GenericOrJSX<string>[] = [];
2930
const result = intersperse([], "-");
3031
expect(result).toEqual(expected);
3132
});
3233

3334
it("should intersperse a single item in an array", () => {
34-
const expected = [1, "-", 2, "-", 3];
35-
const result = intersperse([1, 2, 3], "-");
35+
const expected = ["1", "-", "2", "-", "3"];
36+
const result = intersperse(["1", "2", "3"], "-");
3637
expect(result).toEqual(expected);
3738
});
3839

3940
it("should intersperse multiple items in an array", () => {
40-
const expected = [1, "-", ".", 2, "-", ".", 3];
41-
const result = intersperse([1, 2, 3], ["-", "."]);
41+
const expected = ["1", "-", ".", "2", "-", ".", "3"];
42+
const result = intersperse(["1", "2", "3"], ["-", "."]);
43+
expect(expected).toEqual(result);
44+
});
45+
46+
it("should intersperse a single JSX item in an array", () => {
47+
const expected = [1, <br />, 2, <br />, 3];
48+
const result = intersperse([1, 2, 3], <br />);
49+
expect(expected).toEqual(result);
50+
});
51+
52+
it("should intersperse a multiple JSX items in an array", () => {
53+
const expected = [1, <br />, <div />, 2, <br />, <div />, 3];
54+
const result = intersperse([1, 2, 3], [<br />, <div />]);
4255
expect(expected).toEqual(result);
4356
});
4457
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { renderHook } from "@testing-library/react";
2+
import { useCheckCapabilities } from "@mwdb-web/commons/hooks";
3+
import { AuthContextValues, Capability } from "@mwdb-web/types/types";
4+
import { AuthContext } from "@mwdb-web/commons/auth";
5+
import { AuthProviderProps } from "@mwdb-web/types/props";
6+
7+
describe("useCheckCapabilities", () => {
8+
const authContextValue = {
9+
user: {
10+
capabilities: [
11+
Capability.accessAllObjects,
12+
Capability.accessAllObjects,
13+
Capability.addingTags,
14+
],
15+
},
16+
} as AuthContextValues;
17+
18+
const wrapperWithInitValues =
19+
(initValues: AuthContextValues) => (props: AuthProviderProps) =>
20+
(
21+
<AuthContext.Provider value={initValues}>
22+
{props.children}
23+
</AuthContext.Provider>
24+
);
25+
26+
it("should return true if user has the capability", () => {
27+
const wrapper = wrapperWithInitValues(authContextValue);
28+
const { result } = renderHook(() => useCheckCapabilities(), {
29+
wrapper,
30+
});
31+
const { userHasCapabilities } = result.current;
32+
33+
expect(userHasCapabilities(Capability.accessAllObjects)).toBe(true);
34+
});
35+
36+
it("should return false if user doesn't have the capability", () => {
37+
const wrapper = wrapperWithInitValues(authContextValue);
38+
const { result } = renderHook(() => useCheckCapabilities(), {
39+
wrapper,
40+
});
41+
const { userHasCapabilities } = result.current;
42+
43+
expect(userHasCapabilities(Capability.removingKarton)).toBe(false);
44+
});
45+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from "react";
2+
import { renderHook, act } from "@testing-library/react";
3+
import { useComponentState } from "@mwdb-web/commons/hooks";
4+
5+
describe("useComponentState", () => {
6+
test("should initialize with React.Fragment as the default component", () => {
7+
const { result } = renderHook(() => useComponentState());
8+
expect(result.current.Component).toBe(React.Fragment);
9+
});
10+
11+
test("should update the component when setComponent is called", () => {
12+
const { result } = renderHook(() => useComponentState());
13+
const newComponent = () => <div>New Component</div>;
14+
act(() => {
15+
result.current.setComponent(newComponent);
16+
});
17+
expect(result.current.Component).toBe(newComponent);
18+
});
19+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { useNavRedirect } from "@mwdb-web/commons/hooks";
2+
import { renderHook, act } from "@testing-library/react";
3+
4+
const navigateMock = jest.fn();
5+
const locationMock = { state: { prevLocation: "/" } };
6+
7+
jest.mock("react-router-dom", () => ({
8+
useNavigate: () => navigateMock,
9+
useLocation: () => locationMock,
10+
}));
11+
12+
describe("useNavRedirect", () => {
13+
beforeEach(() => {
14+
navigateMock.mockClear();
15+
});
16+
17+
afterEach(() => {
18+
jest.clearAllMocks();
19+
});
20+
21+
test("should call navigate with the provided URL", () => {
22+
const { result } = renderHook(() => useNavRedirect());
23+
const url = "/redirect";
24+
act(() => {
25+
result.current.redirectTo(url);
26+
});
27+
expect(navigateMock).toHaveBeenCalledWith(url);
28+
});
29+
30+
test("should call navigate with the previous location", () => {
31+
const { result } = renderHook(() => useNavRedirect());
32+
act(() => {
33+
result.current.goBackToPrevLocation();
34+
});
35+
expect(navigateMock).toHaveBeenCalledWith("/");
36+
});
37+
});
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { useViewAlert } from "@mwdb-web/commons/hooks";
2+
import {
3+
RedirectToAlertProps,
4+
SetAlertProps,
5+
} from "@mwdb-web/commons/hooks/useViewAlert";
6+
import { renderHook } from "@testing-library/react";
7+
import { useNavigate, useLocation } from "react-router-dom";
8+
import { toast } from "react-toastify";
9+
10+
jest.mock("react-router-dom", () => ({
11+
...(jest.requireActual("react-router-dom") as any),
12+
useNavigate: jest.fn(),
13+
useLocation: jest.fn(),
14+
}));
15+
16+
jest.mock("react-toastify", () => ({
17+
toast: jest.fn(),
18+
}));
19+
20+
const mockNavigate = jest.fn();
21+
const mockLocation = {
22+
pathname: "/",
23+
search: "",
24+
state: {},
25+
};
26+
27+
describe("useViewAlert", () => {
28+
beforeEach(() => {
29+
jest.clearAllMocks();
30+
(useNavigate as jest.Mock).mockReturnValue(mockNavigate);
31+
(useLocation as jest.Mock).mockReturnValue(mockLocation);
32+
});
33+
34+
test("should set alert and navigate with state", () => {
35+
const { result } = renderHook(() => useViewAlert());
36+
37+
const setAlertProps: SetAlertProps = {
38+
success: "Success message",
39+
state: { additionalState: true },
40+
};
41+
42+
result.current.setAlert(setAlertProps);
43+
44+
expect(toast).toHaveBeenCalledWith("Success message", {
45+
type: "success",
46+
});
47+
48+
expect(mockNavigate).toHaveBeenCalledWith(
49+
{ pathname: "/", search: "" },
50+
{ replace: true, state: { additionalState: true } }
51+
);
52+
});
53+
54+
test("should set error alert and navigate without state", () => {
55+
const { result } = renderHook(() => useViewAlert());
56+
57+
const setAlertProps = {
58+
error: {
59+
response: {
60+
data: {
61+
message: "Error message",
62+
},
63+
},
64+
},
65+
} as SetAlertProps;
66+
67+
result.current.setAlert(setAlertProps);
68+
69+
expect(toast).toHaveBeenCalledWith("Error message", { type: "error" });
70+
71+
expect(mockNavigate).toHaveBeenCalledWith(
72+
{ pathname: "/", search: "" },
73+
{ replace: true, state: {} }
74+
);
75+
});
76+
77+
test("should set error as a string alert", () => {
78+
const { result } = renderHook(() => useViewAlert());
79+
80+
const setAlertProps: SetAlertProps = {
81+
error: "String Error Message",
82+
};
83+
84+
result.current.setAlert(setAlertProps);
85+
86+
expect(toast).toHaveBeenCalledWith("String Error Message", {
87+
type: "error",
88+
});
89+
});
90+
91+
test("should redirect with alert and state", () => {
92+
const { result } = renderHook(() => useViewAlert());
93+
94+
const redirectToAlertProps: RedirectToAlertProps = {
95+
warning: "Warning message",
96+
target: "/target",
97+
state: { additionalState: true },
98+
};
99+
100+
result.current.redirectToAlert(redirectToAlertProps);
101+
102+
expect(toast).toHaveBeenCalledWith("Warning message", {
103+
type: "warning",
104+
});
105+
106+
expect(mockNavigate).toHaveBeenCalledWith("/target", {
107+
state: { additionalState: true },
108+
});
109+
});
110+
});

mwdb/web/src/commons/auth/capabilities.jsx renamed to mwdb/web/src/commons/auth/capabilities.tsx

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,7 @@
11
import { afterPluginsLoaded, fromPlugins } from "../plugins";
2+
import { Capability } from "@mwdb-web/types/types";
23

3-
export const Capability = {
4-
manageUsers: "manage_users",
5-
shareQueriedObjects: "share_queried_objects",
6-
accessAllObjects: "access_all_objects",
7-
sharingWithAll: "sharing_with_all",
8-
accessUploaderInfo: "access_uploader_info",
9-
addingTags: "adding_tags",
10-
removingTags: "removing_tags",
11-
addingComments: "adding_comments",
12-
removingComments: "removing_comments",
13-
addingParents: "adding_parents",
14-
removingParents: "removing_parents",
15-
readingAllAttributes: "reading_all_attributes",
16-
addingAllAttributes: "adding_all_attributes",
17-
removingAttributes: "removing_attributes",
18-
addingFiles: "adding_files",
19-
addingConfigs: "adding_configs",
20-
addingBlobs: "adding_blobs",
21-
unlimitedRequests: "unlimited_requests",
22-
removingObjects: "removing_objects",
23-
manageProfile: "manage_profile",
24-
personalize: "personalize",
25-
kartonAssign: "karton_assign",
26-
kartonReanalyze: "karton_reanalyze",
27-
removingKarton: "karton_unassign",
28-
modify3rdPartySharing: "modify_3rd_party_sharing",
29-
};
30-
31-
export let capabilitiesList = {
4+
export let capabilitiesList: Record<Capability, string> = {
325
[Capability.manageUsers]:
336
"Managing users and groups (system administration)",
347
[Capability.shareQueriedObjects]: "Query for all objects in system",

mwdb/web/src/commons/auth/context.jsx

Lines changed: 0 additions & 3 deletions
This file was deleted.

mwdb/web/src/commons/auth/context.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { AuthContextValues } from "@mwdb-web/types/types";
2+
import React from "react";
3+
4+
export const AuthContext = React.createContext<AuthContextValues>(
5+
{} as AuthContextValues
6+
);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export { AuthContext } from "./context";
22
export { AuthProvider, localStorageAuthKey } from "./provider";
3-
export { Capability, capabilitiesList } from "./capabilities";
3+
export { capabilitiesList } from "./capabilities";

0 commit comments

Comments
 (0)