@simplysm/excel 13.0.69 → 13.0.71
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 +219 -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/fixtures//354/264/210/352/270/260/355/231/224.xlsx +0 -0
- package/tests/image-insert.spec.ts +190 -0
- package/tests/utils/excel-utils.spec.ts +242 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { ExcelWorkbook } from "../src/excel-workbook";
|
|
3
|
+
import { ExcelXmlWorksheet } from "../src/xml/excel-xml-worksheet";
|
|
4
|
+
import { DateOnly, DateTime, Time } from "@simplysm/core-common";
|
|
5
|
+
|
|
6
|
+
describe("ExcelXmlWorksheet.getCellVal - inline string", () => {
|
|
7
|
+
it("should read plain string inline text (no attributes)", () => {
|
|
8
|
+
const ws = new ExcelXmlWorksheet({
|
|
9
|
+
worksheet: {
|
|
10
|
+
$: { xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main" },
|
|
11
|
+
sheetData: [{
|
|
12
|
+
row: [{
|
|
13
|
+
$: { r: "1" },
|
|
14
|
+
c: [{
|
|
15
|
+
$: { r: "A1", t: "inlineStr" },
|
|
16
|
+
is: [{ t: ["ID"] }],
|
|
17
|
+
}],
|
|
18
|
+
}],
|
|
19
|
+
}],
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
expect(ws.getCellVal({ r: 0, c: 0 })).toBe("ID");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should read object-form inline text (with attributes)", () => {
|
|
27
|
+
const ws = new ExcelXmlWorksheet({
|
|
28
|
+
worksheet: {
|
|
29
|
+
$: { xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main" },
|
|
30
|
+
sheetData: [{
|
|
31
|
+
row: [{
|
|
32
|
+
$: { r: "1" },
|
|
33
|
+
c: [{
|
|
34
|
+
$: { r: "A1", t: "inlineStr" },
|
|
35
|
+
is: [{ t: [{ _: "Hello" }] }],
|
|
36
|
+
}],
|
|
37
|
+
}],
|
|
38
|
+
}],
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
expect(ws.getCellVal({ r: 0, c: 0 })).toBe("Hello");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("ExcelCell", () => {
|
|
47
|
+
describe("Cell Value Read/Write - Basic Types", () => {
|
|
48
|
+
it("Can read and write string values", async () => {
|
|
49
|
+
const wb = new ExcelWorkbook();
|
|
50
|
+
const ws = await wb.createWorksheet("Test");
|
|
51
|
+
|
|
52
|
+
await ws.cell(0, 0).setVal("Hello World");
|
|
53
|
+
const val = await ws.cell(0, 0).getVal();
|
|
54
|
+
|
|
55
|
+
expect(val).toBe("Hello World");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("Can read and write number values", async () => {
|
|
59
|
+
const wb = new ExcelWorkbook();
|
|
60
|
+
const ws = await wb.createWorksheet("Test");
|
|
61
|
+
|
|
62
|
+
await ws.cell(0, 0).setVal(12345);
|
|
63
|
+
await ws.cell(0, 1).setVal(3.14159);
|
|
64
|
+
await ws.cell(0, 2).setVal(-100);
|
|
65
|
+
await ws.cell(0, 3).setVal(0);
|
|
66
|
+
|
|
67
|
+
expect(await ws.cell(0, 0).getVal()).toBe(12345);
|
|
68
|
+
expect(await ws.cell(0, 1).getVal()).toBe(3.14159);
|
|
69
|
+
expect(await ws.cell(0, 2).getVal()).toBe(-100);
|
|
70
|
+
expect(await ws.cell(0, 3).getVal()).toBe(0);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("Can read and write boolean values", async () => {
|
|
74
|
+
const wb = new ExcelWorkbook();
|
|
75
|
+
const ws = await wb.createWorksheet("Test");
|
|
76
|
+
|
|
77
|
+
await ws.cell(0, 0).setVal(true);
|
|
78
|
+
await ws.cell(0, 1).setVal(false);
|
|
79
|
+
|
|
80
|
+
expect(await ws.cell(0, 0).getVal()).toBe(true);
|
|
81
|
+
expect(await ws.cell(0, 1).getVal()).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("Setting undefined value deletes the cell", async () => {
|
|
85
|
+
const wb = new ExcelWorkbook();
|
|
86
|
+
const ws = await wb.createWorksheet("Test");
|
|
87
|
+
|
|
88
|
+
await ws.cell(0, 0).setVal("Initial");
|
|
89
|
+
expect(await ws.cell(0, 0).getVal()).toBe("Initial");
|
|
90
|
+
|
|
91
|
+
await ws.cell(0, 0).setVal(undefined);
|
|
92
|
+
expect(await ws.cell(0, 0).getVal()).toBeUndefined();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("Can handle very large numbers", async () => {
|
|
96
|
+
const wb = new ExcelWorkbook();
|
|
97
|
+
const ws = await wb.createWorksheet("Test");
|
|
98
|
+
|
|
99
|
+
// Large number below MAX_SAFE_INTEGER
|
|
100
|
+
const bigNumber = Number.MAX_SAFE_INTEGER;
|
|
101
|
+
await ws.cell(0, 0).setVal(bigNumber);
|
|
102
|
+
|
|
103
|
+
const val = await ws.cell(0, 0).getVal();
|
|
104
|
+
expect(val).toBe(bigNumber);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("Can handle very small decimals", async () => {
|
|
108
|
+
const wb = new ExcelWorkbook();
|
|
109
|
+
const ws = await wb.createWorksheet("Test");
|
|
110
|
+
|
|
111
|
+
// Small decimal within Excel's precision range
|
|
112
|
+
const smallDecimal = 0.0001;
|
|
113
|
+
await ws.cell(0, 0).setVal(smallDecimal);
|
|
114
|
+
|
|
115
|
+
const val = await ws.cell(0, 0).getVal();
|
|
116
|
+
expect(val).toBeCloseTo(smallDecimal, 6);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("Throws error when setting unsupported type", async () => {
|
|
120
|
+
const wb = new ExcelWorkbook();
|
|
121
|
+
const ws = await wb.createWorksheet("Test");
|
|
122
|
+
|
|
123
|
+
await expect(ws.cell(0, 0).setVal({} as any)).rejects.toThrow("Unsupported type");
|
|
124
|
+
|
|
125
|
+
await expect(ws.cell(0, 1).setVal([] as any)).rejects.toThrow("Unsupported type");
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe("Cell Value Read/Write - Date/Time Types", () => {
|
|
130
|
+
it("Can read and write DateOnly values", async () => {
|
|
131
|
+
const wb = new ExcelWorkbook();
|
|
132
|
+
const ws = await wb.createWorksheet("Test");
|
|
133
|
+
|
|
134
|
+
const date = new DateOnly(2024, 6, 15);
|
|
135
|
+
await ws.cell(0, 0).setVal(date);
|
|
136
|
+
|
|
137
|
+
const val = await ws.cell(0, 0).getVal();
|
|
138
|
+
expect(val).toBeInstanceOf(DateOnly);
|
|
139
|
+
expect((val as DateOnly).year).toBe(2024);
|
|
140
|
+
expect((val as DateOnly).month).toBe(6);
|
|
141
|
+
expect((val as DateOnly).day).toBe(15);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("Can read and write DateTime values", async () => {
|
|
145
|
+
const wb = new ExcelWorkbook();
|
|
146
|
+
const ws = await wb.createWorksheet("Test");
|
|
147
|
+
|
|
148
|
+
const dateTime = new DateTime(2024, 6, 15, 14, 30, 45);
|
|
149
|
+
await ws.cell(0, 0).setVal(dateTime);
|
|
150
|
+
|
|
151
|
+
const val = await ws.cell(0, 0).getVal();
|
|
152
|
+
expect(val).toBeInstanceOf(DateTime);
|
|
153
|
+
expect((val as DateTime).year).toBe(2024);
|
|
154
|
+
expect((val as DateTime).month).toBe(6);
|
|
155
|
+
expect((val as DateTime).day).toBe(15);
|
|
156
|
+
expect((val as DateTime).hour).toBe(14);
|
|
157
|
+
expect((val as DateTime).minute).toBe(30);
|
|
158
|
+
expect((val as DateTime).second).toBe(45);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("Can read and write Time values", async () => {
|
|
162
|
+
const wb = new ExcelWorkbook();
|
|
163
|
+
const ws = await wb.createWorksheet("Test");
|
|
164
|
+
|
|
165
|
+
const time = new Time(14, 30, 45);
|
|
166
|
+
await ws.cell(0, 0).setVal(time);
|
|
167
|
+
|
|
168
|
+
const val = await ws.cell(0, 0).getVal();
|
|
169
|
+
expect(val).toBeInstanceOf(Time);
|
|
170
|
+
expect((val as Time).hour).toBe(14);
|
|
171
|
+
expect((val as Time).minute).toBe(30);
|
|
172
|
+
expect((val as Time).second).toBe(45);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("DateOnly values persist after round-trip", async () => {
|
|
176
|
+
const wb = new ExcelWorkbook();
|
|
177
|
+
const ws = await wb.createWorksheet("Test");
|
|
178
|
+
|
|
179
|
+
const date = new DateOnly(2024, 6, 15);
|
|
180
|
+
await ws.cell(0, 0).setVal(date);
|
|
181
|
+
|
|
182
|
+
const bytes = await wb.getBytes();
|
|
183
|
+
await wb.close();
|
|
184
|
+
|
|
185
|
+
const wb2 = new ExcelWorkbook(bytes);
|
|
186
|
+
const ws2 = await wb2.getWorksheet(0);
|
|
187
|
+
|
|
188
|
+
const val = await ws2.cell(0, 0).getVal();
|
|
189
|
+
expect(val).toBeInstanceOf(DateOnly);
|
|
190
|
+
expect((val as DateOnly).year).toBe(2024);
|
|
191
|
+
expect((val as DateOnly).month).toBe(6);
|
|
192
|
+
expect((val as DateOnly).day).toBe(15);
|
|
193
|
+
await wb2.close();
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("DateTime values persist after round-trip", async () => {
|
|
197
|
+
const wb = new ExcelWorkbook();
|
|
198
|
+
const ws = await wb.createWorksheet("Test");
|
|
199
|
+
|
|
200
|
+
const dateTime = new DateTime(2024, 6, 15, 14, 30, 45);
|
|
201
|
+
await ws.cell(0, 0).setVal(dateTime);
|
|
202
|
+
|
|
203
|
+
const bytes = await wb.getBytes();
|
|
204
|
+
await wb.close();
|
|
205
|
+
|
|
206
|
+
const wb2 = new ExcelWorkbook(bytes);
|
|
207
|
+
const ws2 = await wb2.getWorksheet(0);
|
|
208
|
+
|
|
209
|
+
const val = await ws2.cell(0, 0).getVal();
|
|
210
|
+
expect(val).toBeInstanceOf(DateTime);
|
|
211
|
+
expect((val as DateTime).year).toBe(2024);
|
|
212
|
+
expect((val as DateTime).month).toBe(6);
|
|
213
|
+
expect((val as DateTime).day).toBe(15);
|
|
214
|
+
expect((val as DateTime).hour).toBe(14);
|
|
215
|
+
expect((val as DateTime).minute).toBe(30);
|
|
216
|
+
expect((val as DateTime).second).toBe(45);
|
|
217
|
+
await wb2.close();
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("Time values persist after round-trip", async () => {
|
|
221
|
+
const wb = new ExcelWorkbook();
|
|
222
|
+
const ws = await wb.createWorksheet("Test");
|
|
223
|
+
|
|
224
|
+
const time = new Time(14, 30, 45);
|
|
225
|
+
await ws.cell(0, 0).setVal(time);
|
|
226
|
+
|
|
227
|
+
const bytes = await wb.getBytes();
|
|
228
|
+
await wb.close();
|
|
229
|
+
|
|
230
|
+
const wb2 = new ExcelWorkbook(bytes);
|
|
231
|
+
const ws2 = await wb2.getWorksheet(0);
|
|
232
|
+
|
|
233
|
+
const val = await ws2.cell(0, 0).getVal();
|
|
234
|
+
expect(val).toBeInstanceOf(Time);
|
|
235
|
+
expect((val as Time).hour).toBe(14);
|
|
236
|
+
expect((val as Time).minute).toBe(30);
|
|
237
|
+
expect((val as Time).second).toBe(45);
|
|
238
|
+
await wb2.close();
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
describe("Formulas", () => {
|
|
243
|
+
it("Can set formulas", async () => {
|
|
244
|
+
const wb = new ExcelWorkbook();
|
|
245
|
+
const ws = await wb.createWorksheet("Test");
|
|
246
|
+
|
|
247
|
+
await ws.cell(0, 0).setVal(10);
|
|
248
|
+
await ws.cell(0, 1).setVal(20);
|
|
249
|
+
await ws.cell(0, 2).setFormula("A1+B1");
|
|
250
|
+
|
|
251
|
+
// Verify formula directly
|
|
252
|
+
const formula = await ws.cell(0, 2).getFormula();
|
|
253
|
+
expect(formula).toBe("A1+B1");
|
|
254
|
+
|
|
255
|
+
// Also verify with round-trip
|
|
256
|
+
const buffer = await wb.getBytes();
|
|
257
|
+
|
|
258
|
+
const wb2 = new ExcelWorkbook(buffer);
|
|
259
|
+
const ws2 = await wb2.getWorksheet(0);
|
|
260
|
+
// Formula exists but value must be calculated by Excel
|
|
261
|
+
expect(ws2).toBeDefined();
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it("Formulas persist after round-trip", async () => {
|
|
265
|
+
const wb = new ExcelWorkbook();
|
|
266
|
+
const ws = await wb.createWorksheet("Test");
|
|
267
|
+
|
|
268
|
+
await ws.cell(0, 0).setVal(10);
|
|
269
|
+
await ws.cell(0, 1).setVal(20);
|
|
270
|
+
await ws.cell(0, 2).setFormula("SUM(A1:B1)");
|
|
271
|
+
|
|
272
|
+
const buffer = await wb.getBytes();
|
|
273
|
+
await wb.close();
|
|
274
|
+
|
|
275
|
+
const wb2 = new ExcelWorkbook(buffer);
|
|
276
|
+
const ws2 = await wb2.getWorksheet(0);
|
|
277
|
+
|
|
278
|
+
// Verify that formula string is saved
|
|
279
|
+
const formula = await ws2.cell(0, 2).getFormula();
|
|
280
|
+
expect(formula).toBe("SUM(A1:B1)");
|
|
281
|
+
await wb2.close();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("Setting formula to undefined deletes it", async () => {
|
|
285
|
+
const wb = new ExcelWorkbook();
|
|
286
|
+
const ws = await wb.createWorksheet("Test");
|
|
287
|
+
|
|
288
|
+
await ws.cell(0, 0).setFormula("A1+B1");
|
|
289
|
+
await ws.cell(0, 0).setFormula(undefined);
|
|
290
|
+
|
|
291
|
+
expect(await ws.cell(0, 0).getVal()).toBeUndefined();
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
describe("Cell Merge", () => {
|
|
296
|
+
it("Can merge cells", async () => {
|
|
297
|
+
const wb = new ExcelWorkbook();
|
|
298
|
+
const ws = await wb.createWorksheet("Test");
|
|
299
|
+
|
|
300
|
+
await ws.cell(0, 0).setVal("Merged");
|
|
301
|
+
await ws.cell(0, 0).merge(2, 3); // Merge 2 rows x 3 columns
|
|
302
|
+
|
|
303
|
+
// Verify merge with round-trip
|
|
304
|
+
const buffer = await wb.getBytes();
|
|
305
|
+
const wb2 = new ExcelWorkbook(buffer);
|
|
306
|
+
const ws2 = await wb2.getWorksheet(0);
|
|
307
|
+
|
|
308
|
+
const val = await ws2.cell(0, 0).getVal();
|
|
309
|
+
expect(val).toBe("Merged");
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it("Throws error when attempting to merge overlapping ranges", async () => {
|
|
313
|
+
const wb = new ExcelWorkbook();
|
|
314
|
+
const ws = await wb.createWorksheet("Test");
|
|
315
|
+
|
|
316
|
+
await ws.cell(0, 0).merge(2, 2); // Merge A1:B2
|
|
317
|
+
|
|
318
|
+
// Attempt to merge overlapping range (B2:C3)
|
|
319
|
+
await expect(ws.cell(1, 1).merge(2, 2)).rejects.toThrow("Merged cell overlaps with existing merge range");
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
describe("Cell Style", () => {
|
|
324
|
+
it("Can set background color", async () => {
|
|
325
|
+
const wb = new ExcelWorkbook();
|
|
326
|
+
const ws = await wb.createWorksheet("Test");
|
|
327
|
+
|
|
328
|
+
await ws.cell(0, 0).setVal("Colored");
|
|
329
|
+
await ws.cell(0, 0).setStyle({ background: "00FF0000" }); // Red
|
|
330
|
+
|
|
331
|
+
const styleId = await ws.cell(0, 0).getStyleId();
|
|
332
|
+
expect(styleId).toBeDefined();
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it("Can set borders", async () => {
|
|
336
|
+
const wb = new ExcelWorkbook();
|
|
337
|
+
const ws = await wb.createWorksheet("Test");
|
|
338
|
+
|
|
339
|
+
await ws.cell(0, 0).setVal("Bordered");
|
|
340
|
+
await ws.cell(0, 0).setStyle({ border: ["left", "right", "top", "bottom"] });
|
|
341
|
+
|
|
342
|
+
const styleId = await ws.cell(0, 0).getStyleId();
|
|
343
|
+
expect(styleId).toBeDefined();
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it("Can set alignment", async () => {
|
|
347
|
+
const wb = new ExcelWorkbook();
|
|
348
|
+
const ws = await wb.createWorksheet("Test");
|
|
349
|
+
|
|
350
|
+
await ws.cell(0, 0).setVal("Aligned");
|
|
351
|
+
await ws.cell(0, 0).setStyle({
|
|
352
|
+
horizontalAlign: "center",
|
|
353
|
+
verticalAlign: "center",
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const styleId = await ws.cell(0, 0).getStyleId();
|
|
357
|
+
expect(styleId).toBeDefined();
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it("Can set number format", async () => {
|
|
361
|
+
const wb = new ExcelWorkbook();
|
|
362
|
+
const ws = await wb.createWorksheet("Test");
|
|
363
|
+
|
|
364
|
+
await ws.cell(0, 0).setVal(12345.6789);
|
|
365
|
+
await ws.cell(0, 0).setStyle({ numberFormat: "number" });
|
|
366
|
+
|
|
367
|
+
const styleId = await ws.cell(0, 0).getStyleId();
|
|
368
|
+
expect(styleId).toBeDefined();
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it("Can set multiple styles simultaneously", async () => {
|
|
372
|
+
const wb = new ExcelWorkbook();
|
|
373
|
+
const ws = await wb.createWorksheet("Test");
|
|
374
|
+
|
|
375
|
+
await ws.cell(0, 0).setVal("Multi-Style");
|
|
376
|
+
await ws.cell(0, 0).setStyle({
|
|
377
|
+
background: "00FFFF00",
|
|
378
|
+
border: ["left", "right"],
|
|
379
|
+
horizontalAlign: "center",
|
|
380
|
+
verticalAlign: "top",
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
const styleId = await ws.cell(0, 0).getStyleId();
|
|
384
|
+
expect(styleId).toBeDefined();
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
it("Throws error for invalid color format", async () => {
|
|
388
|
+
const wb = new ExcelWorkbook();
|
|
389
|
+
const ws = await wb.createWorksheet("Test");
|
|
390
|
+
|
|
391
|
+
await ws.cell(0, 0).setVal("Test");
|
|
392
|
+
await expect(ws.cell(0, 0).setStyle({ background: "invalid" })).rejects.toThrow();
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it("Styles persist after round-trip", async () => {
|
|
396
|
+
const wb = new ExcelWorkbook();
|
|
397
|
+
const ws = await wb.createWorksheet("Test");
|
|
398
|
+
|
|
399
|
+
// Set various styles
|
|
400
|
+
await ws.cell(0, 0).setVal("Styled");
|
|
401
|
+
await ws.cell(0, 0).setStyle({
|
|
402
|
+
background: "00FF0000", // Red
|
|
403
|
+
border: ["left", "right", "top", "bottom"],
|
|
404
|
+
horizontalAlign: "center",
|
|
405
|
+
verticalAlign: "top",
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
const bytes = await wb.getBytes();
|
|
409
|
+
|
|
410
|
+
// Verify styles after round-trip
|
|
411
|
+
const wb2 = new ExcelWorkbook(bytes);
|
|
412
|
+
const ws2 = await wb2.getWorksheet("Test");
|
|
413
|
+
|
|
414
|
+
// Verify value
|
|
415
|
+
const val = await ws2.cell(0, 0).getVal();
|
|
416
|
+
expect(val).toBe("Styled");
|
|
417
|
+
|
|
418
|
+
// Verify style ID exists
|
|
419
|
+
const styleId = await ws2.cell(0, 0).getStyleId();
|
|
420
|
+
expect(styleId).toBeDefined();
|
|
421
|
+
|
|
422
|
+
// Verify style data at XML level
|
|
423
|
+
const styleData = await (wb2 as any).zipCache.get("xl/styles.xml");
|
|
424
|
+
const styleIdNum = parseInt(styleId!, 10);
|
|
425
|
+
const xf = styleData.data.styleSheet.cellXfs[0].xf[styleIdNum];
|
|
426
|
+
|
|
427
|
+
// Verify background color
|
|
428
|
+
expect(xf.$.fillId).toBeDefined();
|
|
429
|
+
const fillId = parseInt(xf.$.fillId, 10);
|
|
430
|
+
const fill = styleData.data.styleSheet.fills[0].fill[fillId];
|
|
431
|
+
expect(fill.patternFill[0].fgColor[0].$.rgb).toBe("00FF0000");
|
|
432
|
+
|
|
433
|
+
// Verify borders
|
|
434
|
+
expect(xf.$.borderId).toBeDefined();
|
|
435
|
+
const borderId = parseInt(xf.$.borderId, 10);
|
|
436
|
+
const border = styleData.data.styleSheet.borders[0].border[borderId];
|
|
437
|
+
expect(border.left).toBeDefined();
|
|
438
|
+
expect(border.right).toBeDefined();
|
|
439
|
+
expect(border.top).toBeDefined();
|
|
440
|
+
expect(border.bottom).toBeDefined();
|
|
441
|
+
|
|
442
|
+
// Verify alignment
|
|
443
|
+
expect(xf.alignment).toBeDefined();
|
|
444
|
+
expect(xf.alignment[0].$.horizontal).toBe("center");
|
|
445
|
+
expect(xf.alignment[0].$.vertical).toBe("top");
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { ExcelWorkbook } from "../src/excel-workbook";
|
|
3
|
+
|
|
4
|
+
describe("ExcelCol", () => {
|
|
5
|
+
describe("cell()", () => {
|
|
6
|
+
it("Returns cell corresponding to row index", async () => {
|
|
7
|
+
const wb = new ExcelWorkbook();
|
|
8
|
+
const ws = await wb.createWorksheet("Test");
|
|
9
|
+
|
|
10
|
+
const col = ws.col(0);
|
|
11
|
+
const cell = col.cell(0);
|
|
12
|
+
|
|
13
|
+
await cell.setVal("Hello");
|
|
14
|
+
expect(await cell.getVal()).toBe("Hello");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("Returns same instance for same index (caching)", async () => {
|
|
18
|
+
const wb = new ExcelWorkbook();
|
|
19
|
+
const ws = await wb.createWorksheet("Test");
|
|
20
|
+
|
|
21
|
+
const col = ws.col(0);
|
|
22
|
+
const cell1 = col.cell(0);
|
|
23
|
+
const cell2 = col.cell(0);
|
|
24
|
+
|
|
25
|
+
expect(cell1).toBe(cell2);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("Returns different instance for different index", async () => {
|
|
29
|
+
const wb = new ExcelWorkbook();
|
|
30
|
+
const ws = await wb.createWorksheet("Test");
|
|
31
|
+
|
|
32
|
+
const col = ws.col(0);
|
|
33
|
+
const cell1 = col.cell(0);
|
|
34
|
+
const cell2 = col.cell(1);
|
|
35
|
+
|
|
36
|
+
expect(cell1).not.toBe(cell2);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe("getCells()", () => {
|
|
41
|
+
it("Returns all cells within range", async () => {
|
|
42
|
+
const wb = new ExcelWorkbook();
|
|
43
|
+
const ws = await wb.createWorksheet("Test");
|
|
44
|
+
|
|
45
|
+
// Set data to define range
|
|
46
|
+
await ws.cell(0, 0).setVal("A1");
|
|
47
|
+
await ws.cell(1, 0).setVal("A2");
|
|
48
|
+
await ws.cell(2, 0).setVal("A3");
|
|
49
|
+
|
|
50
|
+
const col = ws.col(0);
|
|
51
|
+
const cells = await col.getCells();
|
|
52
|
+
|
|
53
|
+
expect(cells.length).toBeGreaterThanOrEqual(3);
|
|
54
|
+
expect(await cells[0].getVal()).toBe("A1");
|
|
55
|
+
expect(await cells[1].getVal()).toBe("A2");
|
|
56
|
+
expect(await cells[2].getVal()).toBe("A3");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("Returns cell corresponding to default range (0,0) from empty worksheet", async () => {
|
|
60
|
+
const wb = new ExcelWorkbook();
|
|
61
|
+
const ws = await wb.createWorksheet("Test");
|
|
62
|
+
|
|
63
|
+
const col = ws.col(0);
|
|
64
|
+
const cells = await col.getCells();
|
|
65
|
+
|
|
66
|
+
// Default range of empty worksheet is (0,0)-(0,0), so returns one cell
|
|
67
|
+
expect(cells.length).toBe(1);
|
|
68
|
+
expect(await cells[0].getVal()).toBeUndefined();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("setWidth()", () => {
|
|
73
|
+
it("Can set column width", async () => {
|
|
74
|
+
const wb = new ExcelWorkbook();
|
|
75
|
+
const ws = await wb.createWorksheet("Test");
|
|
76
|
+
|
|
77
|
+
// Add data and set width
|
|
78
|
+
await ws.cell(0, 0).setVal("Test");
|
|
79
|
+
await ws.col(0).setWidth(20);
|
|
80
|
+
|
|
81
|
+
// Verify settings via round-trip
|
|
82
|
+
const bytes = await wb.getBytes();
|
|
83
|
+
const wb2 = new ExcelWorkbook(bytes);
|
|
84
|
+
const ws2 = await wb2.getWorksheet(0);
|
|
85
|
+
|
|
86
|
+
// Verify value is preserved (width is hard to verify directly, so just check it works without error)
|
|
87
|
+
expect(await ws2.cell(0, 0).getVal()).toBe("Test");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("Can set different widths for multiple columns", async () => {
|
|
91
|
+
const wb = new ExcelWorkbook();
|
|
92
|
+
const ws = await wb.createWorksheet("Test");
|
|
93
|
+
|
|
94
|
+
await ws.cell(0, 0).setVal("A");
|
|
95
|
+
await ws.cell(0, 1).setVal("B");
|
|
96
|
+
await ws.cell(0, 2).setVal("C");
|
|
97
|
+
|
|
98
|
+
await ws.col(0).setWidth(10);
|
|
99
|
+
await ws.col(1).setWidth(20);
|
|
100
|
+
await ws.col(2).setWidth(30);
|
|
101
|
+
|
|
102
|
+
// Can round-trip without error
|
|
103
|
+
const bytes = await wb.getBytes();
|
|
104
|
+
const wb2 = new ExcelWorkbook(bytes);
|
|
105
|
+
const ws2 = await wb2.getWorksheet(0);
|
|
106
|
+
|
|
107
|
+
expect(await ws2.cell(0, 0).getVal()).toBe("A");
|
|
108
|
+
expect(await ws2.cell(0, 1).getVal()).toBe("B");
|
|
109
|
+
expect(await ws2.cell(0, 2).getVal()).toBe("C");
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { ExcelWorkbook } from "../src/excel-workbook";
|
|
3
|
+
|
|
4
|
+
describe("ExcelRow", () => {
|
|
5
|
+
describe("cell()", () => {
|
|
6
|
+
it("returns cell corresponding to column index", async () => {
|
|
7
|
+
const wb = new ExcelWorkbook();
|
|
8
|
+
const ws = await wb.createWorksheet("Test");
|
|
9
|
+
|
|
10
|
+
const row = ws.row(0);
|
|
11
|
+
const cell = row.cell(0);
|
|
12
|
+
|
|
13
|
+
await cell.setVal("Hello");
|
|
14
|
+
expect(await cell.getVal()).toBe("Hello");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("returns same instance for same index (caching)", async () => {
|
|
18
|
+
const wb = new ExcelWorkbook();
|
|
19
|
+
const ws = await wb.createWorksheet("Test");
|
|
20
|
+
|
|
21
|
+
const row = ws.row(0);
|
|
22
|
+
const cell1 = row.cell(0);
|
|
23
|
+
const cell2 = row.cell(0);
|
|
24
|
+
|
|
25
|
+
expect(cell1).toBe(cell2);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("returns different instances for different indices", async () => {
|
|
29
|
+
const wb = new ExcelWorkbook();
|
|
30
|
+
const ws = await wb.createWorksheet("Test");
|
|
31
|
+
|
|
32
|
+
const row = ws.row(0);
|
|
33
|
+
const cell1 = row.cell(0);
|
|
34
|
+
const cell2 = row.cell(1);
|
|
35
|
+
|
|
36
|
+
expect(cell1).not.toBe(cell2);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe("getCells()", () => {
|
|
41
|
+
it("returns all cells within range", async () => {
|
|
42
|
+
const wb = new ExcelWorkbook();
|
|
43
|
+
const ws = await wb.createWorksheet("Test");
|
|
44
|
+
|
|
45
|
+
// Set range by configuring data
|
|
46
|
+
await ws.cell(0, 0).setVal("A1");
|
|
47
|
+
await ws.cell(0, 1).setVal("B1");
|
|
48
|
+
await ws.cell(0, 2).setVal("C1");
|
|
49
|
+
|
|
50
|
+
const row = ws.row(0);
|
|
51
|
+
const cells = await row.getCells();
|
|
52
|
+
|
|
53
|
+
expect(cells.length).toBeGreaterThanOrEqual(3);
|
|
54
|
+
expect(await cells[0].getVal()).toBe("A1");
|
|
55
|
+
expect(await cells[1].getVal()).toBe("B1");
|
|
56
|
+
expect(await cells[2].getVal()).toBe("C1");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("returns cell corresponding to default range (0,0) in empty worksheet", async () => {
|
|
60
|
+
const wb = new ExcelWorkbook();
|
|
61
|
+
const ws = await wb.createWorksheet("Test");
|
|
62
|
+
|
|
63
|
+
const row = ws.row(0);
|
|
64
|
+
const cells = await row.getCells();
|
|
65
|
+
|
|
66
|
+
// Empty worksheet default range is (0,0)-(0,0) so returns one cell
|
|
67
|
+
expect(cells.length).toBe(1);
|
|
68
|
+
expect(await cells[0].getVal()).toBeUndefined();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|