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
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { fireEvent } from "@testing-library/dom";
import { cleanup } from "@testing-library/react";

import { PointsSystemAdministration }
from "components/administration/points-system-administration/points-system-administration.controller";

import { useBulkUpdatePointsBase } from "x-hooks/api/points";

import { render } from "__tests__/utils/custom-render";

jest.mock("x-hooks/api/points", () => ({
useBulkUpdatePointsBase: jest.fn(),
useGetPointsBase: jest.fn().mockReturnValue([
{ id: 1, actionName: "action1", scalingFactor: 1, pointsPerAction: 1, counter: "1" },
{ id: 2, actionName: "action2", scalingFactor: 1, pointsPerAction: 1, counter: "1" },
])
}))

describe("PointsSystemAdministration", () => {
beforeEach(() => {
cleanup();
jest.clearAllMocks();
});

it("Should bulk update scalingFactor successfully", async () => {
const result = render(<PointsSystemAdministration />);

const scalingFactorInput = result.getByTestId("scaling-factor-input");
fireEvent.change(scalingFactorInput, { target: { value: "2" } });

const updateAllButton = result.getByTestId("update-all-button");
fireEvent.click(updateAllButton);

expect(useBulkUpdatePointsBase).toHaveBeenCalledWith({
rows: [
{ id: 1, actionName: "action1", scalingFactor: "2" },
{ id: 2, actionName: "action2", scalingFactor: "2" },
]
});
});

it("Should update changed rows successfully", async () => {
const result = render(<PointsSystemAdministration />);

const scalingFactorRow1 = result.getByTestId("table-row-0-scalingFactor-input");
fireEvent.change(scalingFactorRow1, { target: { value: "3" } });

const counterRow2 = result.getByTestId("table-row-1-counter-input");
fireEvent.change(counterRow2, { target: { value: "3" } });

const saveChangesButton = result.getByTestId("save-changes-button");
fireEvent.click(saveChangesButton);

expect(useBulkUpdatePointsBase).toHaveBeenCalledWith({
rows: [
{ id: 1, actionName: "action1", scalingFactor: "3", pointsPerAction: 1, counter: "1" },
{ id: 2, actionName: "action2", scalingFactor: 1, pointsPerAction: 1, counter: "3" },
]
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import models from "db/models";

import { bulkUpdatePointsBase } from "server/common/points-base/bulk-update/bulk-update-points-base";
import { HttpBadRequestError } from "server/errors/http-errors";

jest.mock("db/models", () => ({
pointsBase: {
update: jest.fn()
}
}));

describe("BulkUpdatePointsBase", () => {
let request = null;

beforeEach(() => {
jest.clearAllMocks();
request = {
body: {
rows: [
{
id: 1,
actionName: "action1",
scalingFactor: 1,
pointsPerAction: 1,
counter: "1"
}
]
}
}
});

it("Should update sucessfully", async () => {
await bulkUpdatePointsBase(request);
expect(models.pointsBase.update)
.toHaveBeenCalledWith({
scalingFactor: 1,
pointsPerAction: 1,
counter: "1"
}, {
where: {
id: 1
}
});
});

it("Should throws because no rows was sent", async () => {
request.body = {};
await expect(() =>
bulkUpdatePointsBase(request)).rejects.toThrow(new HttpBadRequestError("Missing rows to update"));
});

it("Should throws because id was not provided", async () => {
request.body = {
rows: [
{
actionName: "action1",
scalingFactor: 1,
pointsPerAction: 1,
counter: "1"
}
]
};
await expect(() =>
bulkUpdatePointsBase(request)).rejects.toThrow(new HttpBadRequestError("Missing paramaters for action1"));
});

it("Should throws because no changed column was provided", async () => {
request.body = {
rows: [
{
id: 1,
actionName: "action1"
}
]
};
await expect(() =>
bulkUpdatePointsBase(request)).rejects.toThrow(new HttpBadRequestError("Missing paramaters for action1"));
});

it("Should throws because scalingFactor is invalid", async () => {
request.body = {
rows: [
{
id: 1,
actionName: "action1",
scalingFactor: 0,
}
]
};
await expect(() =>
bulkUpdatePointsBase(request)).rejects.toThrow(new HttpBadRequestError("Invalid paramaters for action1"));
});

it("Should throws because pointsPerAction is invalid", async () => {
request.body = {
rows: [
{
id: 1,
actionName: "action1",
pointsPerAction: 0,
}
]
};
await expect(() =>
bulkUpdatePointsBase(request)).rejects.toThrow(new HttpBadRequestError("Invalid paramaters for action1"));
});

it("Should throws because counter is invalid", async () => {
request.body = {
rows: [
{
id: 1,
actionName: "action1",
counter: "B",
}
]
};
await expect(() =>
bulkUpdatePointsBase(request)).rejects.toThrow(new HttpBadRequestError("Invalid paramaters for action1"));
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { useEffect, useState } from "react";

import { AxiosError } from "axios";
import { useTranslation } from "next-i18next";

import { PointsSystemAdministrationView }
from "components/administration/points-system-administration/points-system-administration.view";

import { QueryKeys } from "helpers/query-keys";

import { PointsBase } from "interfaces/points-system";

import { useBulkUpdatePointsBase, useGetPointsBase } from "x-hooks/api/points";
import { useToastStore } from "x-hooks/stores/toasts/toasts.store";
import useReactQuery from "x-hooks/use-react-query";
import useReactQueryMutation from "x-hooks/use-react-query-mutation";

export type Header = {
label: string,
property: keyof PointsBase,
}

export function PointsSystemAdministration() {
const { t } = useTranslation("administration");

const [list, setList] = useState<PointsBase[]>([]);
const [scalingFactor, setScalingFactor] = useState();
const [changedRows, setChangedRows] = useState<PointsBase[]>([]);

const { addError, addSuccess } = useToastStore();

const { data } = useReactQuery(QueryKeys.pointsBase(), useGetPointsBase);

function getUpdateMethod(type: "bulk" | "changed") {
const rows = {
bulk: list.map(({ id, actionName }) => ({ id, actionName, scalingFactor })),
changed: changedRows
}[type];

return async () => useBulkUpdatePointsBase({
rows,
});
}

const { mutate: hanleBulkUpdate, isPending: isBulkUpdating } = useReactQueryMutation({
queryKey: QueryKeys.pointsBase(),
mutationFn: getUpdateMethod("bulk"),
onSettled: (data, error) => {
if (error) {
addError(t("failed"), t("points-system.scaling-factor-greater-than-0"));
return;
}
addSuccess(t("success"), t("points-system.scaling-factor-updated"));
setScalingFactor(null);
},
});

const { mutate: handleChangedUpdate, isPending: isUpdatingChanged } = useReactQueryMutation({
queryKey: QueryKeys.pointsBase(),
mutationFn: getUpdateMethod("changed"),
onSettled: (data, error: AxiosError<{ message: string }>) => {
if (error) {
addError(t("failed"), `${error?.response?.data?.message}`);
return;
}
addSuccess(t("success"), t("points-system.changed-rules-updated"));
setChangedRows([]);
}
});

const headers: Header[] = [
{ label: t("points-system.action-name"), property: "actionName" },
{ label: t("points-system.scaling-factor"), property: "scalingFactor" },
{ label: t("points-system.points-per-action"), property: "pointsPerAction" },
{ label: t("points-system.counter"), property: "counter" },
];

const onScalingFactorChange = values => setScalingFactor(values.value);
const isUpdateButtonDisabled = !scalingFactor || isBulkUpdating || !list?.length || isUpdatingChanged;
const isSaveChangesButtonDisabled = !changedRows?.length || isUpdatingChanged || isBulkUpdating;

function onRowChange(row: PointsBase) {
setChangedRows(previous => {
const tmp = [...previous];
const index = tmp.findIndex(i => i.id === row.id);
if (index > -1)
tmp[index] = row;
else
tmp.push(row);
return tmp;
});
setList(previous => {
const tmp = [...previous];
const index = tmp.findIndex(i => i.id === row.id);
tmp[index] = row;
return tmp;
});
}

useEffect(() => {
setList(data || []);
}, [data]);

return(
<PointsSystemAdministrationView
headers={headers}
list={list}
scalingFactor={scalingFactor}
isUpdateButtonDisabled={isUpdateButtonDisabled}
isBulkUpdating={isBulkUpdating}
isSaveChangesButtonDisabled={isSaveChangesButtonDisabled}
isUpdatingChanged={isUpdatingChanged}
onScalingFactorChange={onScalingFactorChange}
onBulkUpdateClick={hanleBulkUpdate}
onSaveChangedClick={handleChangedUpdate}
onRowChange={onRowChange}
/>
);
}
Loading