@simplysm/excel 13.0.69 → 13.0.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -516
- package/dist/excel-cell.d.ts +28 -28
- package/dist/excel-cell.d.ts.map +1 -1
- package/dist/excel-cell.js +24 -24
- package/dist/excel-cell.js.map +1 -1
- package/dist/excel-col.d.ts +4 -4
- package/dist/excel-col.d.ts.map +1 -1
- package/dist/excel-col.js +3 -3
- package/dist/excel-row.d.ts +3 -3
- package/dist/excel-row.d.ts.map +1 -1
- package/dist/excel-row.js +2 -2
- package/dist/excel-workbook.d.ts +23 -23
- package/dist/excel-workbook.d.ts.map +1 -1
- package/dist/excel-workbook.js +15 -15
- package/dist/excel-workbook.js.map +1 -1
- package/dist/excel-worksheet.d.ts +32 -32
- package/dist/excel-worksheet.d.ts.map +1 -1
- package/dist/excel-worksheet.js +32 -32
- package/dist/excel-worksheet.js.map +1 -1
- package/dist/excel-wrapper.d.ts +7 -7
- package/dist/excel-wrapper.js +7 -7
- package/dist/excel-wrapper.js.map +1 -1
- package/dist/types.d.ts +16 -16
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/excel-utils.d.ts +23 -23
- package/dist/utils/excel-utils.d.ts.map +1 -1
- package/dist/utils/excel-utils.js +25 -25
- package/dist/utils/excel-utils.js.map +1 -1
- package/dist/utils/zip-cache.d.ts +6 -6
- package/dist/xml/excel-xml-content-type.d.ts +2 -2
- package/dist/xml/excel-xml-drawing.d.ts +2 -2
- package/dist/xml/excel-xml-relationship.d.ts +2 -2
- package/dist/xml/excel-xml-relationship.js +1 -1
- package/dist/xml/excel-xml-relationship.js.map +1 -1
- package/dist/xml/excel-xml-shared-string.d.ts +2 -2
- package/dist/xml/excel-xml-style.d.ts +2 -2
- package/dist/xml/excel-xml-style.js +6 -6
- package/dist/xml/excel-xml-style.js.map +1 -1
- package/dist/xml/excel-xml-unknown.d.ts +2 -2
- package/dist/xml/excel-xml-workbook.d.ts +2 -2
- package/dist/xml/excel-xml-workbook.js +1 -1
- package/dist/xml/excel-xml-workbook.js.map +1 -1
- package/dist/xml/excel-xml-worksheet.d.ts +6 -6
- package/dist/xml/excel-xml-worksheet.d.ts.map +1 -1
- package/dist/xml/excel-xml-worksheet.js +9 -8
- package/dist/xml/excel-xml-worksheet.js.map +1 -1
- package/package.json +6 -5
- package/src/excel-cell.ts +35 -35
- package/src/excel-col.ts +4 -4
- package/src/excel-row.ts +3 -3
- package/src/excel-workbook.ts +30 -30
- package/src/excel-worksheet.ts +47 -47
- package/src/excel-wrapper.ts +18 -18
- package/src/index.ts +3 -3
- package/src/types.ts +15 -17
- package/src/utils/excel-utils.ts +38 -38
- package/src/utils/zip-cache.ts +6 -6
- package/src/xml/excel-xml-content-type.ts +3 -3
- package/src/xml/excel-xml-drawing.ts +2 -2
- package/src/xml/excel-xml-relationship.ts +3 -3
- package/src/xml/excel-xml-shared-string.ts +2 -2
- package/src/xml/excel-xml-style.ts +11 -11
- package/src/xml/excel-xml-unknown.ts +2 -2
- package/src/xml/excel-xml-workbook.ts +5 -5
- package/src/xml/excel-xml-worksheet.ts +44 -43
- package/tests/excel-cell.spec.ts +448 -0
- package/tests/excel-col.spec.ts +112 -0
- package/tests/excel-row.spec.ts +71 -0
- package/tests/excel-workbook.spec.ts +160 -0
- package/tests/excel-worksheet.spec.ts +389 -0
- package/tests/excel-wrapper.spec.ts +296 -0
- package/tests/fixtures/logo.png +0 -0
- package/tests/image-insert.spec.ts +190 -0
- package/tests/utils/excel-utils.spec.ts +242 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { ExcelWorkbook } from "../src/excel-workbook";
|
|
3
|
+
import type { Bytes } from "@simplysm/core-common";
|
|
4
|
+
|
|
5
|
+
describe("ExcelWorkbook", () => {
|
|
6
|
+
describe("Creating empty workbook", () => {
|
|
7
|
+
it("Can create a worksheet", async () => {
|
|
8
|
+
const wb = new ExcelWorkbook();
|
|
9
|
+
const ws = await wb.createWorksheet("TestSheet");
|
|
10
|
+
|
|
11
|
+
expect(ws).toBeDefined();
|
|
12
|
+
const name = await ws.getName();
|
|
13
|
+
expect(name).toBe("TestSheet");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("Can create multiple worksheets", async () => {
|
|
17
|
+
const wb = new ExcelWorkbook();
|
|
18
|
+
await wb.createWorksheet("Sheet1");
|
|
19
|
+
await wb.createWorksheet("Sheet2");
|
|
20
|
+
await wb.createWorksheet("Sheet3");
|
|
21
|
+
|
|
22
|
+
const names = await wb.getWorksheetNames();
|
|
23
|
+
expect(names).toEqual(["Sheet1", "Sheet2", "Sheet3"]);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe("Accessing worksheets", () => {
|
|
28
|
+
it("Can get worksheet by index", async () => {
|
|
29
|
+
const wb = new ExcelWorkbook();
|
|
30
|
+
await wb.createWorksheet("First");
|
|
31
|
+
await wb.createWorksheet("Second");
|
|
32
|
+
|
|
33
|
+
const ws = await wb.getWorksheet(1);
|
|
34
|
+
const name = await ws.getName();
|
|
35
|
+
expect(name).toBe("Second");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("Can get worksheet by name", async () => {
|
|
39
|
+
const wb = new ExcelWorkbook();
|
|
40
|
+
await wb.createWorksheet("MySheet");
|
|
41
|
+
|
|
42
|
+
const ws = await wb.getWorksheet("MySheet");
|
|
43
|
+
const name = await ws.getName();
|
|
44
|
+
expect(name).toBe("MySheet");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("Error when accessing non-existent sheet", async () => {
|
|
48
|
+
const wb = new ExcelWorkbook();
|
|
49
|
+
await wb.createWorksheet("Sheet1");
|
|
50
|
+
|
|
51
|
+
await expect(wb.getWorksheet("NotExist")).rejects.toThrow();
|
|
52
|
+
await expect(wb.getWorksheet(10)).rejects.toThrow();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe("Bytes/Blob export", () => {
|
|
57
|
+
it("Can export as Bytes", async () => {
|
|
58
|
+
const wb = new ExcelWorkbook();
|
|
59
|
+
const ws = await wb.createWorksheet("Test");
|
|
60
|
+
await ws.cell(0, 0).setVal("Hello");
|
|
61
|
+
|
|
62
|
+
const bytes: Bytes = await wb.getBytes();
|
|
63
|
+
expect(bytes).toBeInstanceOf(Uint8Array);
|
|
64
|
+
expect(bytes.length).toBeGreaterThan(0);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("Can export as Blob", async () => {
|
|
68
|
+
const wb = new ExcelWorkbook();
|
|
69
|
+
const ws = await wb.createWorksheet("Test");
|
|
70
|
+
await ws.cell(0, 0).setVal("Hello");
|
|
71
|
+
|
|
72
|
+
const blob = await wb.getBlob();
|
|
73
|
+
expect(blob).toBeInstanceOf(Blob);
|
|
74
|
+
expect(blob.type).toBe("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
75
|
+
expect(blob.size).toBeGreaterThan(0);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe("Workbook read/write round-trip", () => {
|
|
80
|
+
it("Can create workbook from Blob", async () => {
|
|
81
|
+
// First create workbook with Bytes
|
|
82
|
+
const wb1 = new ExcelWorkbook();
|
|
83
|
+
const ws1 = await wb1.createWorksheet("Test");
|
|
84
|
+
await ws1.cell(0, 0).setVal("BlobTest");
|
|
85
|
+
const bytes = await wb1.getBytes();
|
|
86
|
+
await wb1.close();
|
|
87
|
+
|
|
88
|
+
// Convert to Blob
|
|
89
|
+
const blob = new Blob([new Uint8Array(bytes)], {
|
|
90
|
+
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Read workbook from Blob
|
|
94
|
+
const wb2 = new ExcelWorkbook(blob);
|
|
95
|
+
const ws2 = await wb2.getWorksheet(0);
|
|
96
|
+
const val = await ws2.cell(0, 0).getVal();
|
|
97
|
+
|
|
98
|
+
expect(val).toBe("BlobTest");
|
|
99
|
+
await wb2.close();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("Can save created workbook as Bytes and read again", async () => {
|
|
103
|
+
// Create
|
|
104
|
+
const wb1 = new ExcelWorkbook();
|
|
105
|
+
const ws1 = await wb1.createWorksheet("RoundTrip");
|
|
106
|
+
await ws1.cell(0, 0).setVal("TestValue");
|
|
107
|
+
await ws1.cell(0, 1).setVal(12345);
|
|
108
|
+
|
|
109
|
+
// Save
|
|
110
|
+
const bytes = await wb1.getBytes();
|
|
111
|
+
await wb1.close();
|
|
112
|
+
|
|
113
|
+
// Read again
|
|
114
|
+
const wb2 = new ExcelWorkbook(bytes);
|
|
115
|
+
const names = await wb2.getWorksheetNames();
|
|
116
|
+
expect(names).toContain("RoundTrip");
|
|
117
|
+
|
|
118
|
+
const ws2 = await wb2.getWorksheet("RoundTrip");
|
|
119
|
+
const val1 = await ws2.cell(0, 0).getVal();
|
|
120
|
+
const val2 = await ws2.cell(0, 1).getVal();
|
|
121
|
+
|
|
122
|
+
expect(val1).toBe("TestValue");
|
|
123
|
+
expect(val2).toBe(12345);
|
|
124
|
+
|
|
125
|
+
await wb2.close();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe("Error after resource cleanup", () => {
|
|
130
|
+
it("Error when calling getWorksheetNames() after close()", async () => {
|
|
131
|
+
const wb = new ExcelWorkbook();
|
|
132
|
+
await wb.createWorksheet("Test");
|
|
133
|
+
await wb.close();
|
|
134
|
+
|
|
135
|
+
await expect(wb.getWorksheetNames()).rejects.toThrow();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("Error when calling createWorksheet() after close()", async () => {
|
|
139
|
+
const wb = new ExcelWorkbook();
|
|
140
|
+
await wb.close();
|
|
141
|
+
|
|
142
|
+
await expect(wb.createWorksheet("New")).rejects.toThrow();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("Error when calling getWorksheet() after close()", async () => {
|
|
146
|
+
const wb = new ExcelWorkbook();
|
|
147
|
+
await wb.createWorksheet("Test");
|
|
148
|
+
await wb.close();
|
|
149
|
+
|
|
150
|
+
await expect(wb.getWorksheet(0)).rejects.toThrow();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("Error when calling getBytes() after close()", async () => {
|
|
154
|
+
const wb = new ExcelWorkbook();
|
|
155
|
+
await wb.close();
|
|
156
|
+
|
|
157
|
+
await expect(wb.getBytes()).rejects.toThrow();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
});
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { ExcelWorkbook } from "../src/excel-workbook";
|
|
3
|
+
|
|
4
|
+
describe("ExcelWorksheet", () => {
|
|
5
|
+
describe("Sheet name", () => {
|
|
6
|
+
it("should get sheet name", async () => {
|
|
7
|
+
const wb = new ExcelWorkbook();
|
|
8
|
+
const ws = await wb.createWorksheet("MySheet");
|
|
9
|
+
|
|
10
|
+
const name = await ws.getName();
|
|
11
|
+
expect(name).toBe("MySheet");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should change sheet name", async () => {
|
|
15
|
+
const wb = new ExcelWorkbook();
|
|
16
|
+
const ws = await wb.createWorksheet("OldName");
|
|
17
|
+
|
|
18
|
+
await ws.setName("NewName");
|
|
19
|
+
const name = await ws.getName();
|
|
20
|
+
expect(name).toBe("NewName");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should preserve changed sheet name after roundtrip", async () => {
|
|
24
|
+
const wb = new ExcelWorkbook();
|
|
25
|
+
const ws = await wb.createWorksheet("OldName");
|
|
26
|
+
await ws.setName("NewName");
|
|
27
|
+
|
|
28
|
+
const bytes = await wb.getBytes();
|
|
29
|
+
|
|
30
|
+
const wb2 = new ExcelWorkbook(bytes);
|
|
31
|
+
const names = await wb2.getWorksheetNames();
|
|
32
|
+
expect(names).toContain("NewName");
|
|
33
|
+
expect(names).not.toContain("OldName");
|
|
34
|
+
|
|
35
|
+
const ws2 = await wb2.getWorksheet("NewName");
|
|
36
|
+
const name = await ws2.getName();
|
|
37
|
+
expect(name).toBe("NewName");
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("Row/Column copy", () => {
|
|
42
|
+
it("should copy row", async () => {
|
|
43
|
+
const wb = new ExcelWorkbook();
|
|
44
|
+
const ws = await wb.createWorksheet("Test");
|
|
45
|
+
|
|
46
|
+
// Set source row
|
|
47
|
+
await ws.cell(0, 0).setVal("A");
|
|
48
|
+
await ws.cell(0, 1).setVal("B");
|
|
49
|
+
await ws.cell(0, 2).setVal("C");
|
|
50
|
+
|
|
51
|
+
// Copy row
|
|
52
|
+
await ws.copyRow(0, 2);
|
|
53
|
+
|
|
54
|
+
expect(await ws.cell(2, 0).getVal()).toBe("A");
|
|
55
|
+
expect(await ws.cell(2, 1).getVal()).toBe("B");
|
|
56
|
+
expect(await ws.cell(2, 2).getVal()).toBe("C");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("should copy cell", async () => {
|
|
60
|
+
const wb = new ExcelWorkbook();
|
|
61
|
+
const ws = await wb.createWorksheet("Test");
|
|
62
|
+
|
|
63
|
+
await ws.cell(0, 0).setVal("Original");
|
|
64
|
+
await ws.copyCell({ r: 0, c: 0 }, { r: 1, c: 1 });
|
|
65
|
+
|
|
66
|
+
expect(await ws.cell(1, 1).getVal()).toBe("Original");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("should copy only row style", async () => {
|
|
70
|
+
const wb = new ExcelWorkbook();
|
|
71
|
+
const ws = await wb.createWorksheet("Test");
|
|
72
|
+
|
|
73
|
+
// Set styles
|
|
74
|
+
await ws.cell(0, 0).setVal("Styled");
|
|
75
|
+
await ws.cell(0, 0).setStyle({ background: "00FF0000" });
|
|
76
|
+
await ws.cell(0, 1).setVal("Also Styled");
|
|
77
|
+
await ws.cell(0, 1).setStyle({ background: "0000FF00" });
|
|
78
|
+
|
|
79
|
+
// Copy only styles
|
|
80
|
+
await ws.copyRowStyle(0, 2);
|
|
81
|
+
|
|
82
|
+
// Values should not be copied
|
|
83
|
+
expect(await ws.cell(2, 0).getVal()).toBeUndefined();
|
|
84
|
+
expect(await ws.cell(2, 1).getVal()).toBeUndefined();
|
|
85
|
+
|
|
86
|
+
// Styles should be copied
|
|
87
|
+
const styleId0 = await ws.cell(0, 0).getStyleId();
|
|
88
|
+
const styleId2 = await ws.cell(2, 0).getStyleId();
|
|
89
|
+
expect(styleId2).toBe(styleId0);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("should insert copy row when srcR < targetR", async () => {
|
|
93
|
+
const wb = new ExcelWorkbook();
|
|
94
|
+
const ws = await wb.createWorksheet("Test");
|
|
95
|
+
|
|
96
|
+
await ws.cell(0, 0).setVal("Row0");
|
|
97
|
+
await ws.cell(1, 0).setVal("Row1");
|
|
98
|
+
await ws.cell(2, 0).setVal("Row2");
|
|
99
|
+
|
|
100
|
+
// Insert copy row 0 at position 1 (existing rows are shifted)
|
|
101
|
+
await ws.insertCopyRow(0, 1);
|
|
102
|
+
|
|
103
|
+
expect(await ws.cell(0, 0).getVal()).toBe("Row0");
|
|
104
|
+
expect(await ws.cell(1, 0).getVal()).toBe("Row0"); // copied
|
|
105
|
+
expect(await ws.cell(2, 0).getVal()).toBe("Row1"); // shifted
|
|
106
|
+
expect(await ws.cell(3, 0).getVal()).toBe("Row2"); // shifted
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should insert copy row when srcR > targetR", async () => {
|
|
110
|
+
const wb = new ExcelWorkbook();
|
|
111
|
+
const ws = await wb.createWorksheet("Test");
|
|
112
|
+
|
|
113
|
+
await ws.cell(0, 0).setVal("Row0");
|
|
114
|
+
await ws.cell(1, 0).setVal("Row1");
|
|
115
|
+
await ws.cell(2, 0).setVal("Row2");
|
|
116
|
+
await ws.cell(3, 0).setVal("Row3");
|
|
117
|
+
|
|
118
|
+
// Insert copy row 2 at position 1 (existing rows are shifted)
|
|
119
|
+
await ws.insertCopyRow(2, 1);
|
|
120
|
+
|
|
121
|
+
expect(await ws.cell(0, 0).getVal()).toBe("Row0");
|
|
122
|
+
expect(await ws.cell(1, 0).getVal()).toBe("Row2"); // copied
|
|
123
|
+
expect(await ws.cell(2, 0).getVal()).toBe("Row1"); // shifted
|
|
124
|
+
expect(await ws.cell(3, 0).getVal()).toBe("Row2"); // shifted (original Row2)
|
|
125
|
+
expect(await ws.cell(4, 0).getVal()).toBe("Row3"); // shifted
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should insert copy row when srcR == targetR", async () => {
|
|
129
|
+
const wb = new ExcelWorkbook();
|
|
130
|
+
const ws = await wb.createWorksheet("Test");
|
|
131
|
+
|
|
132
|
+
await ws.cell(0, 0).setVal("Row0");
|
|
133
|
+
await ws.cell(1, 0).setVal("Row1");
|
|
134
|
+
await ws.cell(2, 0).setVal("Row2");
|
|
135
|
+
|
|
136
|
+
// Insert copy row 1 at position 1 (copy itself)
|
|
137
|
+
await ws.insertCopyRow(1, 1);
|
|
138
|
+
|
|
139
|
+
expect(await ws.cell(0, 0).getVal()).toBe("Row0");
|
|
140
|
+
expect(await ws.cell(1, 0).getVal()).toBe("Row1"); // copied
|
|
141
|
+
expect(await ws.cell(2, 0).getVal()).toBe("Row1"); // shifted (original Row1)
|
|
142
|
+
expect(await ws.cell(3, 0).getVal()).toBe("Row2"); // shifted
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe("Range and cell access", () => {
|
|
147
|
+
it("should get data range", async () => {
|
|
148
|
+
const wb = new ExcelWorkbook();
|
|
149
|
+
const ws = await wb.createWorksheet("Test");
|
|
150
|
+
|
|
151
|
+
await ws.cell(0, 0).setVal("A");
|
|
152
|
+
await ws.cell(2, 3).setVal("D");
|
|
153
|
+
|
|
154
|
+
const range = await ws.getRange();
|
|
155
|
+
expect(range.s.r).toBe(0);
|
|
156
|
+
expect(range.s.c).toBe(0);
|
|
157
|
+
expect(range.e.r).toBe(2);
|
|
158
|
+
expect(range.e.c).toBe(3);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("should get all cells", async () => {
|
|
162
|
+
const wb = new ExcelWorkbook();
|
|
163
|
+
const ws = await wb.createWorksheet("Test");
|
|
164
|
+
|
|
165
|
+
await ws.cell(0, 0).setVal("A");
|
|
166
|
+
await ws.cell(0, 1).setVal("B");
|
|
167
|
+
await ws.cell(1, 0).setVal("C");
|
|
168
|
+
await ws.cell(1, 1).setVal("D");
|
|
169
|
+
|
|
170
|
+
const cells = await ws.getCells();
|
|
171
|
+
expect(cells.length).toBe(2);
|
|
172
|
+
expect(cells[0].length).toBeGreaterThanOrEqual(2);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe("Data table", () => {
|
|
177
|
+
it("should get data table", async () => {
|
|
178
|
+
const wb = new ExcelWorkbook();
|
|
179
|
+
const ws = await wb.createWorksheet("Test");
|
|
180
|
+
|
|
181
|
+
// Headers
|
|
182
|
+
await ws.cell(0, 0).setVal("Name");
|
|
183
|
+
await ws.cell(0, 1).setVal("Age");
|
|
184
|
+
// Data
|
|
185
|
+
await ws.cell(1, 0).setVal("Alice");
|
|
186
|
+
await ws.cell(1, 1).setVal(30);
|
|
187
|
+
await ws.cell(2, 0).setVal("Bob");
|
|
188
|
+
await ws.cell(2, 1).setVal(25);
|
|
189
|
+
|
|
190
|
+
const data = await ws.getDataTable();
|
|
191
|
+
expect(data.length).toBe(2);
|
|
192
|
+
expect(data[0]["Name"]).toBe("Alice");
|
|
193
|
+
expect(data[0]["Age"]).toBe(30);
|
|
194
|
+
expect(data[1]["Name"]).toBe("Bob");
|
|
195
|
+
expect(data[1]["Age"]).toBe(25);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("should filter specific headers only", async () => {
|
|
199
|
+
const wb = new ExcelWorkbook();
|
|
200
|
+
const ws = await wb.createWorksheet("Test");
|
|
201
|
+
|
|
202
|
+
await ws.cell(0, 0).setVal("Name");
|
|
203
|
+
await ws.cell(0, 1).setVal("Age");
|
|
204
|
+
await ws.cell(0, 2).setVal("Ignore");
|
|
205
|
+
await ws.cell(1, 0).setVal("Alice");
|
|
206
|
+
await ws.cell(1, 1).setVal(30);
|
|
207
|
+
await ws.cell(1, 2).setVal("X");
|
|
208
|
+
|
|
209
|
+
const data = await ws.getDataTable({
|
|
210
|
+
usableHeaderNameFn: (name) => name !== "Ignore",
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
expect(data[0]["Name"]).toBe("Alice");
|
|
214
|
+
expect(data[0]["Age"]).toBe(30);
|
|
215
|
+
expect(data[0]["Ignore"]).toBeUndefined();
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("should set data matrix", async () => {
|
|
219
|
+
const wb = new ExcelWorkbook();
|
|
220
|
+
const ws = await wb.createWorksheet("Test");
|
|
221
|
+
|
|
222
|
+
const matrix = [
|
|
223
|
+
["A", "B", "C"],
|
|
224
|
+
[1, 2, 3],
|
|
225
|
+
[4, 5, 6],
|
|
226
|
+
];
|
|
227
|
+
|
|
228
|
+
await ws.setDataMatrix(matrix);
|
|
229
|
+
|
|
230
|
+
expect(await ws.cell(0, 0).getVal()).toBe("A");
|
|
231
|
+
expect(await ws.cell(0, 2).getVal()).toBe("C");
|
|
232
|
+
expect(await ws.cell(2, 2).getVal()).toBe(6);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("should set records array", async () => {
|
|
236
|
+
const wb = new ExcelWorkbook();
|
|
237
|
+
const ws = await wb.createWorksheet("Test");
|
|
238
|
+
|
|
239
|
+
const records = [
|
|
240
|
+
{ Name: "Alice", Age: 30 },
|
|
241
|
+
{ Name: "Bob", Age: 25 },
|
|
242
|
+
];
|
|
243
|
+
|
|
244
|
+
await ws.setRecords(records);
|
|
245
|
+
|
|
246
|
+
// Check headers
|
|
247
|
+
const headers = [await ws.cell(0, 0).getVal(), await ws.cell(0, 1).getVal()];
|
|
248
|
+
expect(headers).toContain("Name");
|
|
249
|
+
expect(headers).toContain("Age");
|
|
250
|
+
|
|
251
|
+
// Check data (order may vary)
|
|
252
|
+
const data = await ws.getDataTable();
|
|
253
|
+
expect(data.length).toBe(2);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
describe("View settings", () => {
|
|
258
|
+
it("should set zoom level", async () => {
|
|
259
|
+
const wb = new ExcelWorkbook();
|
|
260
|
+
const ws = await wb.createWorksheet("Test");
|
|
261
|
+
|
|
262
|
+
await ws.setZoom(85);
|
|
263
|
+
// Success if set without error
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("should set pane freeze", async () => {
|
|
267
|
+
const wb = new ExcelWorkbook();
|
|
268
|
+
const ws = await wb.createWorksheet("Test");
|
|
269
|
+
|
|
270
|
+
await ws.setFix({ r: 1 }); // Freeze 1 row
|
|
271
|
+
await ws.setFix({ c: 2 }); // Freeze 2 columns
|
|
272
|
+
await ws.setFix({ r: 1, c: 1 }); // Freeze 1 row and 1 column
|
|
273
|
+
// Success if set without error
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
describe("Column width", () => {
|
|
278
|
+
it("should set column width", async () => {
|
|
279
|
+
const wb = new ExcelWorkbook();
|
|
280
|
+
const ws = await wb.createWorksheet("Test");
|
|
281
|
+
|
|
282
|
+
await ws.col(0).setWidth(20);
|
|
283
|
+
// Success if set without error
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it("should preserve column width after roundtrip", async () => {
|
|
287
|
+
const wb = new ExcelWorkbook();
|
|
288
|
+
const ws = await wb.createWorksheet("Test");
|
|
289
|
+
|
|
290
|
+
await ws.cell(0, 0).setVal("A1");
|
|
291
|
+
await ws.col(0).setWidth(25);
|
|
292
|
+
await ws.col(2).setWidth(30);
|
|
293
|
+
|
|
294
|
+
const bytes = await wb.getBytes();
|
|
295
|
+
|
|
296
|
+
const wb2 = new ExcelWorkbook(bytes);
|
|
297
|
+
await wb2.getWorksheet("Test");
|
|
298
|
+
|
|
299
|
+
// Check cols data in XML structure
|
|
300
|
+
const wsData = await (wb2 as any).zipCache.get("xl/worksheets/sheet1.xml");
|
|
301
|
+
const cols = wsData.data.worksheet.cols?.[0]?.col ?? [];
|
|
302
|
+
|
|
303
|
+
// Check width of column A (index 0, 1-based=1)
|
|
304
|
+
const colA = cols.find((c: any) => c.$.min === "1" && c.$.max === "1");
|
|
305
|
+
expect(colA).toBeDefined();
|
|
306
|
+
expect(colA.$.width).toBe("25");
|
|
307
|
+
|
|
308
|
+
// Check width of column C (index 2, 1-based=3)
|
|
309
|
+
const colC = cols.find((c: any) => c.$.min === "3" && c.$.max === "3");
|
|
310
|
+
expect(colC).toBeDefined();
|
|
311
|
+
expect(colC.$.width).toBe("30");
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
describe("Column access", () => {
|
|
316
|
+
it("should get all cells in column", async () => {
|
|
317
|
+
const wb = new ExcelWorkbook();
|
|
318
|
+
const ws = await wb.createWorksheet("Test");
|
|
319
|
+
|
|
320
|
+
await ws.cell(0, 0).setVal("A1");
|
|
321
|
+
await ws.cell(1, 0).setVal("A2");
|
|
322
|
+
await ws.cell(2, 0).setVal("A3");
|
|
323
|
+
|
|
324
|
+
const cells = await ws.col(0).getCells();
|
|
325
|
+
expect(cells.length).toBe(3);
|
|
326
|
+
expect(await cells[0].getVal()).toBe("A1");
|
|
327
|
+
expect(await cells[1].getVal()).toBe("A2");
|
|
328
|
+
expect(await cells[2].getVal()).toBe("A3");
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
describe("Data table edge cases", () => {
|
|
333
|
+
it("should return empty array when calling getDataTable on empty sheet", async () => {
|
|
334
|
+
const wb = new ExcelWorkbook();
|
|
335
|
+
const ws = await wb.createWorksheet("Empty");
|
|
336
|
+
const data = await ws.getDataTable();
|
|
337
|
+
expect(data).toEqual([]);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it("should return empty array when only headers exist without data", async () => {
|
|
341
|
+
const wb = new ExcelWorkbook();
|
|
342
|
+
const ws = await wb.createWorksheet("Test");
|
|
343
|
+
await ws.cell(0, 0).setVal("Header1");
|
|
344
|
+
await ws.cell(0, 1).setVal("Header2");
|
|
345
|
+
const data = await ws.getDataTable();
|
|
346
|
+
expect(data).toEqual([]);
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
describe("Data table options", () => {
|
|
351
|
+
it("should specify header row with headerRowIndex", async () => {
|
|
352
|
+
const wb = new ExcelWorkbook();
|
|
353
|
+
const ws = await wb.createWorksheet("Test");
|
|
354
|
+
|
|
355
|
+
// Row 0 is title
|
|
356
|
+
await ws.cell(0, 0).setVal("Title");
|
|
357
|
+
// Row 1 is header
|
|
358
|
+
await ws.cell(1, 0).setVal("Name");
|
|
359
|
+
await ws.cell(1, 1).setVal("Age");
|
|
360
|
+
// Data starts from row 2
|
|
361
|
+
await ws.cell(2, 0).setVal("Alice");
|
|
362
|
+
await ws.cell(2, 1).setVal(30);
|
|
363
|
+
|
|
364
|
+
const data = await ws.getDataTable({ headerRowIndex: 1 });
|
|
365
|
+
expect(data.length).toBe(1);
|
|
366
|
+
expect(data[0]["Name"]).toBe("Alice");
|
|
367
|
+
expect(data[0]["Age"]).toBe(30);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it("should detect data end with checkEndColIndex", async () => {
|
|
371
|
+
const wb = new ExcelWorkbook();
|
|
372
|
+
const ws = await wb.createWorksheet("Test");
|
|
373
|
+
|
|
374
|
+
await ws.cell(0, 0).setVal("Name");
|
|
375
|
+
await ws.cell(0, 1).setVal("Age");
|
|
376
|
+
await ws.cell(1, 0).setVal("Alice");
|
|
377
|
+
await ws.cell(1, 1).setVal(30);
|
|
378
|
+
await ws.cell(2, 0).setVal("Bob");
|
|
379
|
+
await ws.cell(2, 1).setVal(25);
|
|
380
|
+
// Row 3 has empty Name column -> data end
|
|
381
|
+
await ws.cell(3, 1).setVal(999);
|
|
382
|
+
|
|
383
|
+
const data = await ws.getDataTable({ checkEndColIndex: 0 });
|
|
384
|
+
expect(data.length).toBe(2);
|
|
385
|
+
expect(data[0]["Name"]).toBe("Alice");
|
|
386
|
+
expect(data[1]["Name"]).toBe("Bob");
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
});
|