Skip to content

Commit 5b0bda6

Browse files
Merge pull request #30 from sojinantony01/bug-fix-test-coverge
Bug fix test coverage
2 parents 274ed50 + d2eb2df commit 5b0bda6

File tree

11 files changed

+179
-31
lines changed

11 files changed

+179
-31
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-spread-sheet-excel",
3-
"version": "3.1.0",
3+
"version": "3.1.1",
44
"description": "A quick example of rendering large number of input boxes in table using React JS, React Spread-sheet (Excel sheet)",
55
"keywords": [
66
"React spreadsheet",

src/lib/__tests__/lib.test.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,21 @@ describe("Sheet imperative API", () => {
2323
expect(() => ref.current.exportCsv("test")).not.toThrow();
2424
rerender(<Sheet data={[[{ value: "b" }]]} ref={ref} />);
2525
});
26+
27+
it("exportCsv including headers", () => {
28+
const ref = createRef<any>();
29+
const { rerender } = render(<Sheet data={[[{ value: "a" }]]} ref={ref} />);
30+
// getData returns initial state
31+
expect(ref.current.getData()).toBeDefined();
32+
33+
// setData updates store
34+
act(() => {
35+
ref.current.setData([[{ value: "x" }]]);
36+
});
37+
expect(ref.current.getData()[0][0].value).toBe("x");
38+
39+
// exportCsv does not throw
40+
expect(() => ref.current.exportCsv("test", true)).not.toThrow();
41+
rerender(<Sheet data={[[{ value: "b" }]]} ref={ref} />);
42+
});
2643
});

src/lib/list/__tests__/index.test.tsx

Lines changed: 136 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,23 @@ describe("index tests", () => {
1313
});
1414

1515
test("Table render", async () => {
16-
render(<List data={generateDummyContent(310, 1)} />);
16+
render(
17+
<div style={{ height: "600px" }}>
18+
{`tr {height: 30}`}
19+
<List data={generateDummyContent(310, 1)} />
20+
</div>,
21+
); //Style required to find scroll height and fire onScroll
1722
expect(store.getState().data.length).toBe(310);
23+
1824
const tr = await screen.findAllByTestId("sheet-table-tr");
1925
expect(tr).toHaveLength(300);
20-
fireEvent.scroll(screen.getByTestId(`sheet-table-content`), { target: { scrollTo: 300 * 28 } });
21-
// Optional: Add waitFor/check for more rows if needed
26+
27+
const scrollable = screen.getByTestId(`sheet-table-content`);
28+
29+
fireEvent.scroll(scrollable, { target: { scrollTop: 4000 } });
30+
31+
const tr2 = await screen.findAllByTestId("sheet-table-tr");
32+
expect(tr2).toHaveLength(310);
2233
});
2334

2435
test("Table KeyboardActions", async () => {
@@ -40,6 +51,11 @@ describe("index tests", () => {
4051
expect(store.getState().data?.[0][0]?.styles?.["fontWeight"]).toBe("bold");
4152
});
4253

54+
fireEvent.keyDown(table, { code: "KeyB", ctrlKey: true });
55+
await waitFor(() => {
56+
expect(store.getState().data?.[0][0]?.styles?.["fontWeight"]).toBe(undefined);
57+
});
58+
4359
fireEvent.keyDown(table, { code: "KeyU", ctrlKey: true });
4460
await waitFor(() => {
4561
expect(store.getState().data?.[0][0]?.styles?.["text-decoration"]).toBe("underline");
@@ -49,7 +65,67 @@ describe("index tests", () => {
4965
await waitFor(() => {
5066
expect(store.getState().data?.[0][0]?.styles?.["fontStyle"]).toBe("italic");
5167
});
52-
expect(onChange).toHaveBeenCalledTimes(7);
68+
69+
const fontInput = screen.getByTestId("font-size-input");
70+
expect(fontInput).toBeInTheDocument();
71+
fireEvent.change(fontInput, { target: { value: "23" } });
72+
fireEvent.keyDown(fontInput);
73+
await waitFor(() => {
74+
expect(store.getState().data?.[0][0]?.styles?.["fontStyle"]).toBe("italic");
75+
});
76+
77+
const fontDecrease = screen.getByTestId("font-size-decrease");
78+
expect(fontDecrease).toBeInTheDocument();
79+
fireEvent.click(fontDecrease);
80+
await waitFor(() => {
81+
expect(store.getState().data?.[0][0]?.styles?.["fontSize"]).toBe("22px");
82+
});
83+
84+
const left = screen.getByTestId("align-left");
85+
expect(left).toBeInTheDocument();
86+
fireEvent.click(left);
87+
await waitFor(() => {
88+
expect(store.getState().data?.[0][0]?.styles?.["textAlign"]).toBe("left");
89+
});
90+
91+
const right = screen.getByTestId("align-right");
92+
expect(right).toBeInTheDocument();
93+
fireEvent.click(right);
94+
await waitFor(() => {
95+
expect(store.getState().data?.[0][0]?.styles?.["textAlign"]).toBe("right");
96+
});
97+
98+
const center = screen.getByTestId("align-center");
99+
expect(center).toBeInTheDocument();
100+
fireEvent.click(center);
101+
102+
await waitFor(() => {
103+
expect(store.getState().data?.[0][0]?.styles?.["textAlign"]).toBe("center");
104+
});
105+
106+
const justify = screen.getByTestId("align-justify");
107+
expect(justify).toBeInTheDocument();
108+
fireEvent.click(justify);
109+
await waitFor(() => {
110+
expect(store.getState().data?.[0][0]?.styles?.["textAlign"]).toBe("justify");
111+
});
112+
113+
const color = screen.getByTestId("font-color");
114+
expect(color).toBeInTheDocument();
115+
fireEvent.click(screen.getByTestId("font-color-button"));
116+
fireEvent.change(color, { target: { value: "#ffffff" } });
117+
await waitFor(() => {
118+
expect(store.getState().data?.[0][0]?.styles?.["color"]).toBe("#ffffff");
119+
});
120+
121+
const background = screen.getByTestId("background-color");
122+
expect(background).toBeInTheDocument();
123+
fireEvent.click(screen.getByTestId("background-color-button"));
124+
fireEvent.change(background, { target: { value: "#ffffff" } });
125+
await waitFor(() => {
126+
expect(store.getState().data?.[0][0]?.styles?.["background"]).toBe("#ffffff");
127+
});
128+
expect(onChange).toHaveBeenCalledTimes(17);
53129
});
54130

55131
test("Undo-Redo", async () => {
@@ -110,6 +186,7 @@ describe("index tests", () => {
110186
expect(screen.getByTestId(`3-0`)).toHaveValue("1");
111187
});
112188
expect(screen.getByTestId(`4-0`)).toHaveValue("2");
189+
113190
act(() => {
114191
store.dispatch(selectOneCell, { payload: { i: 0, j: 0 } });
115192
store.dispatch(selectCellsDrag, { payload: { i: 2, j: 0 } });
@@ -128,6 +205,50 @@ describe("index tests", () => {
128205
});
129206
});
130207

208+
test("select bottom to top and paste", async () => {
209+
userEvent.setup();
210+
render(<List data={generateDummyContent(10, 1)} />);
211+
mockAllIsIntersecting(true);
212+
act(() => {
213+
store.dispatch(selectOneCell, { payload: { i: 0, j: 0 } });
214+
});
215+
act(() => {
216+
store.dispatch(changeData, {
217+
payload: { value: "1", i: 0, j: 0 },
218+
});
219+
});
220+
act(() => {
221+
store.dispatch(changeData, {
222+
payload: { value: "2", i: 1, j: 0 },
223+
});
224+
});
225+
act(() => {
226+
store.dispatch(changeData, {
227+
payload: { value: "3", i: 2, j: 0 },
228+
});
229+
});
230+
const table = screen.getByTestId(`sheet-table`);
231+
232+
act(() => {
233+
store.dispatch(selectOneCell, { payload: { i: 2, j: 0 } });
234+
store.dispatch(selectCellsDrag, { payload: { i: 0, j: 0 } });
235+
});
236+
fireEvent.keyDown(table, { code: "KeyX", ctrlKey: true });
237+
await waitFor(() => {
238+
expect(screen.getByTestId(`0-0`)).toHaveValue("");
239+
});
240+
act(() => {
241+
store.dispatch(selectOneCell, { payload: { i: 3, j: 0 } });
242+
});
243+
fireEvent.keyDown(table, { key: "V", code: "KeyV", ctrlKey: true });
244+
245+
await waitFor(() => {
246+
expect(screen.getByTestId(`3-0`)).toHaveValue("1");
247+
});
248+
expect(screen.getByTestId(`4-0`)).toHaveValue("2");
249+
expect(screen.getByTestId(`5-0`)).toHaveValue("3");
250+
});
251+
131252
test("paste a normal value", async () => {
132253
userEvent.setup();
133254
render(<List data={generateDummyContent(10, 1)} />);
@@ -151,4 +272,15 @@ describe("index tests", () => {
151272
expect(screen.getByTestId(`1-0`)).toHaveValue(`[{"index":[],"data":["testValue"]}]`);
152273
});
153274
});
275+
276+
test("Context menu", () => {
277+
render(<List data={generateDummyContent(10, 1)} />);
278+
mockAllIsIntersecting(true);
279+
fireEvent.contextMenu(screen.getByTestId(`0-0`));
280+
expect(screen.getByText("Cut")).toBeInTheDocument();
281+
expect(screen.getByText("Copy")).toBeInTheDocument();
282+
expect(screen.getByText("Paste")).toBeInTheDocument();
283+
fireEvent.click(screen.getByTestId(`sheet-table-content`));
284+
expect(screen.queryByText("Cut")).not.toBeInTheDocument();
285+
});
154286
});

src/lib/list/__tests__/input.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,6 @@ describe("input tests", () => {
177177
</>,
178178
);
179179
await user.pointer({ keys: "[MouseRight>]", target: screen.getByTestId(`${i}-${j}`) });
180-
expect(screen.getByTestId(`${i}-${j}`)).not.toHaveClass("sheet-selected-td");
180+
expect(screen.getByTestId(`${i}-${j}`)).toHaveClass("sheet-selected-td");
181181
});
182182
});

src/lib/list/__tests__/utils.test.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getItemsToCopy, printToLetter, solveMathExpression } from "../utils";
1+
import { getCalculatedVal, getItemsToCopy, printToLetter, solveMathExpression } from "../utils";
22
describe("printToLetter", () => {
33
it("should convert a number to letters using the default alphabet", () => {
44
expect(printToLetter(1)).toEqual("A");
@@ -70,3 +70,10 @@ describe("getItemsToCopy", () => {
7070
{ data: { value: "test" }, index: [0, 0] },
7171
]);
7272
});
73+
74+
describe("getCalculatedVal", () => {
75+
expect(getCalculatedVal("nothing", [[{ value: 1 }]])).toBe(undefined);
76+
expect(getCalculatedVal("=A1 + A2", [[{ value: 1 }, { value: 2 }]])).toBe("A1 + A2"); //value does not exist in data
77+
expect(getCalculatedVal("=A1 + B1", [[{ value: 1 }, { value: 2 }]])).toBe("3");
78+
expect(getCalculatedVal("=AD + B1", [[{ value: 1 }, { value: 2 }]])).toBe("2"); // AS is undefined
79+
});

src/lib/list/index.tsx

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -212,31 +212,26 @@ const List = (props: Props) => {
212212
};
213213

214214
return (
215-
<div
216-
onKeyDown={handleKeyDown}
217-
className="sheet-table"
218-
data-testid="sheet-table"
219-
onContextMenu={handleContextMenu}
220-
>
215+
<div onKeyDown={handleKeyDown} className="sheet-table" data-testid="sheet-table">
221216
{!hideTools && <Tools changeStyle={changeStyle} onChange={onChange} />}
222217
<div
223218
className="sheet-table-table-container"
224219
ref={parentDivRef}
225220
onScroll={onsCroll}
226221
data-testid="sheet-table-content"
227222
>
228-
<div style={{ height: (itemLength + 1) * 32 }}>
223+
<div data-testid="sheet-table-content-scroll" style={{ height: (itemLength + 1) * 32 }}>
229224
<div ref={divRef}>
230225
{items.length && (
231226
<table>
232-
<tbody>
233-
{!hideXAxisHeader ? (
227+
{!hideXAxisHeader ? (
228+
<thead>
234229
<SheetXAxis resize={resize} headerValues={headerValues} />
235-
) : (
236-
""
237-
)}
238-
{items}
239-
</tbody>
230+
</thead>
231+
) : (
232+
""
233+
)}
234+
<tbody onContextMenu={handleContextMenu}>{items}</tbody>
240235
</table>
241236
)}
242237
</div>

src/lib/list/input.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ const Input = (props: Prop) => {
122122
}
123123
} else {
124124
e.preventDefault();
125+
!selected && dispatch(selectOneCell, { payload: { i, j } });
125126
}
126127
};
127128
const onDrag = (e: any) => {

src/lib/list/tools/tools.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,8 @@ const Tools = ({
5959
data-testid="fx-input"
6060
ref={calculationRef}
6161
value={selectedItemVal}
62-
readOnly={i == undefined || j == undefined}
62+
readOnly={i === undefined || j === undefined}
6363
onChange={onValChange}
64-
onKeyDown={(e) => {
65-
e.stopPropagation();
66-
}}
6764
/>
6865
</div>
6966
<div className="sheet-tools-text-style-container">

src/lib/reducer.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ const actions: DispatcherActions = {
9595
[action.payload.value.key]: action.payload.value.value,
9696
};
9797
} else {
98-
delete data[p[0]][p[1]]?.styles?.[action.payload.value.key];
98+
const styles = { ...data[p[0]][p[1]]?.styles };
99+
delete styles[action.payload.value.key];
100+
data[p[0]][p[1]].styles = styles;
99101
}
100102
});
101103
state.redo = [];

src/lib/svg/icons.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
const Icons = ({ type }: { type: string }) => {
1+
type AvailableIcons = "align-left" | "align-right" | "align-center" | "align-justify";
2+
const Icons = ({ type }: { type: AvailableIcons }) => {
23
switch (type) {
34
case "align-left":
45
return (
@@ -85,6 +86,5 @@ const Icons = ({ type }: { type: string }) => {
8586
</svg>
8687
);
8788
}
88-
return <></>;
8989
};
9090
export default Icons;

0 commit comments

Comments
 (0)