@simplysm/excel 13.0.0-beta.4 → 13.0.0-beta.44

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.
Files changed (163) hide show
  1. package/README.md +15 -0
  2. package/dist/excel-cell.d.ts.map +1 -0
  3. package/dist/excel-cell.js +3 -3
  4. package/dist/excel-col.d.ts.map +1 -0
  5. package/dist/excel-col.js +1 -1
  6. package/dist/excel-row.d.ts.map +1 -0
  7. package/dist/excel-row.js +1 -1
  8. package/dist/excel-workbook.d.ts.map +1 -0
  9. package/dist/excel-workbook.js +7 -7
  10. package/dist/excel-workbook.js.map +2 -2
  11. package/dist/excel-worksheet.d.ts.map +1 -0
  12. package/dist/excel-worksheet.js +4 -4
  13. package/dist/excel-wrapper.d.ts.map +1 -0
  14. package/dist/excel-wrapper.js +1 -1
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +8 -8
  17. package/dist/types.d.ts.map +1 -0
  18. package/dist/utils/excel-utils.d.ts.map +1 -0
  19. package/dist/utils/zip-cache.d.ts.map +1 -0
  20. package/dist/utils/zip-cache.js +8 -8
  21. package/dist/xml/excel-xml-content-type.d.ts.map +1 -0
  22. package/dist/xml/excel-xml-drawing.d.ts.map +1 -0
  23. package/dist/xml/excel-xml-relationship.d.ts.map +1 -0
  24. package/dist/xml/excel-xml-shared-string.d.ts.map +1 -0
  25. package/dist/xml/excel-xml-style.d.ts.map +1 -0
  26. package/dist/xml/excel-xml-unknown.d.ts.map +1 -0
  27. package/dist/xml/excel-xml-workbook.d.ts.map +1 -0
  28. package/dist/xml/excel-xml-worksheet.d.ts.map +1 -0
  29. package/dist/xml/excel-xml-worksheet.js +1 -1
  30. package/package.json +7 -4
  31. package/.cache/typecheck-browser.tsbuildinfo +0 -1
  32. package/.cache/typecheck-node.tsbuildinfo +0 -1
  33. package/.cache/typecheck-tests-browser.tsbuildinfo +0 -1
  34. package/.cache/typecheck-tests-node.tsbuildinfo +0 -1
  35. package/dist/core-common/src/common.types.d.ts +0 -74
  36. package/dist/core-common/src/common.types.d.ts.map +0 -1
  37. package/dist/core-common/src/env.d.ts +0 -6
  38. package/dist/core-common/src/env.d.ts.map +0 -1
  39. package/dist/core-common/src/errors/argument-error.d.ts +0 -25
  40. package/dist/core-common/src/errors/argument-error.d.ts.map +0 -1
  41. package/dist/core-common/src/errors/not-implemented-error.d.ts +0 -29
  42. package/dist/core-common/src/errors/not-implemented-error.d.ts.map +0 -1
  43. package/dist/core-common/src/errors/sd-error.d.ts +0 -27
  44. package/dist/core-common/src/errors/sd-error.d.ts.map +0 -1
  45. package/dist/core-common/src/errors/timeout-error.d.ts +0 -31
  46. package/dist/core-common/src/errors/timeout-error.d.ts.map +0 -1
  47. package/dist/core-common/src/extensions/arr-ext.d.ts +0 -15
  48. package/dist/core-common/src/extensions/arr-ext.d.ts.map +0 -1
  49. package/dist/core-common/src/extensions/arr-ext.helpers.d.ts +0 -19
  50. package/dist/core-common/src/extensions/arr-ext.helpers.d.ts.map +0 -1
  51. package/dist/core-common/src/extensions/arr-ext.types.d.ts +0 -215
  52. package/dist/core-common/src/extensions/arr-ext.types.d.ts.map +0 -1
  53. package/dist/core-common/src/extensions/map-ext.d.ts +0 -57
  54. package/dist/core-common/src/extensions/map-ext.d.ts.map +0 -1
  55. package/dist/core-common/src/extensions/set-ext.d.ts +0 -36
  56. package/dist/core-common/src/extensions/set-ext.d.ts.map +0 -1
  57. package/dist/core-common/src/features/debounce-queue.d.ts +0 -53
  58. package/dist/core-common/src/features/debounce-queue.d.ts.map +0 -1
  59. package/dist/core-common/src/features/event-emitter.d.ts +0 -66
  60. package/dist/core-common/src/features/event-emitter.d.ts.map +0 -1
  61. package/dist/core-common/src/features/serial-queue.d.ts +0 -47
  62. package/dist/core-common/src/features/serial-queue.d.ts.map +0 -1
  63. package/dist/core-common/src/index.d.ts +0 -32
  64. package/dist/core-common/src/index.d.ts.map +0 -1
  65. package/dist/core-common/src/types/date-only.d.ts +0 -152
  66. package/dist/core-common/src/types/date-only.d.ts.map +0 -1
  67. package/dist/core-common/src/types/date-time.d.ts +0 -96
  68. package/dist/core-common/src/types/date-time.d.ts.map +0 -1
  69. package/dist/core-common/src/types/lazy-gc-map.d.ts +0 -80
  70. package/dist/core-common/src/types/lazy-gc-map.d.ts.map +0 -1
  71. package/dist/core-common/src/types/time.d.ts +0 -68
  72. package/dist/core-common/src/types/time.d.ts.map +0 -1
  73. package/dist/core-common/src/types/uuid.d.ts +0 -35
  74. package/dist/core-common/src/types/uuid.d.ts.map +0 -1
  75. package/dist/core-common/src/utils/bytes.d.ts +0 -51
  76. package/dist/core-common/src/utils/bytes.d.ts.map +0 -1
  77. package/dist/core-common/src/utils/date-format.d.ts +0 -90
  78. package/dist/core-common/src/utils/date-format.d.ts.map +0 -1
  79. package/dist/core-common/src/utils/json.d.ts +0 -34
  80. package/dist/core-common/src/utils/json.d.ts.map +0 -1
  81. package/dist/core-common/src/utils/num.d.ts +0 -60
  82. package/dist/core-common/src/utils/num.d.ts.map +0 -1
  83. package/dist/core-common/src/utils/obj.d.ts +0 -258
  84. package/dist/core-common/src/utils/obj.d.ts.map +0 -1
  85. package/dist/core-common/src/utils/path.d.ts +0 -23
  86. package/dist/core-common/src/utils/path.d.ts.map +0 -1
  87. package/dist/core-common/src/utils/primitive.d.ts +0 -18
  88. package/dist/core-common/src/utils/primitive.d.ts.map +0 -1
  89. package/dist/core-common/src/utils/str.d.ts +0 -103
  90. package/dist/core-common/src/utils/str.d.ts.map +0 -1
  91. package/dist/core-common/src/utils/template-strings.d.ts +0 -84
  92. package/dist/core-common/src/utils/template-strings.d.ts.map +0 -1
  93. package/dist/core-common/src/utils/transferable.d.ts +0 -47
  94. package/dist/core-common/src/utils/transferable.d.ts.map +0 -1
  95. package/dist/core-common/src/utils/wait.d.ts +0 -19
  96. package/dist/core-common/src/utils/wait.d.ts.map +0 -1
  97. package/dist/core-common/src/utils/xml.d.ts +0 -36
  98. package/dist/core-common/src/utils/xml.d.ts.map +0 -1
  99. package/dist/core-common/src/zip/sd-zip.d.ts +0 -80
  100. package/dist/core-common/src/zip/sd-zip.d.ts.map +0 -1
  101. package/dist/excel/src/excel-cell.d.ts.map +0 -1
  102. package/dist/excel/src/excel-col.d.ts.map +0 -1
  103. package/dist/excel/src/excel-row.d.ts.map +0 -1
  104. package/dist/excel/src/excel-workbook.d.ts.map +0 -1
  105. package/dist/excel/src/excel-worksheet.d.ts.map +0 -1
  106. package/dist/excel/src/excel-wrapper.d.ts.map +0 -1
  107. package/dist/excel/src/index.d.ts.map +0 -1
  108. package/dist/excel/src/types.d.ts.map +0 -1
  109. package/dist/excel/src/utils/excel-utils.d.ts.map +0 -1
  110. package/dist/excel/src/utils/zip-cache.d.ts.map +0 -1
  111. package/dist/excel/src/xml/excel-xml-content-type.d.ts.map +0 -1
  112. package/dist/excel/src/xml/excel-xml-drawing.d.ts.map +0 -1
  113. package/dist/excel/src/xml/excel-xml-relationship.d.ts.map +0 -1
  114. package/dist/excel/src/xml/excel-xml-shared-string.d.ts.map +0 -1
  115. package/dist/excel/src/xml/excel-xml-style.d.ts.map +0 -1
  116. package/dist/excel/src/xml/excel-xml-unknown.d.ts.map +0 -1
  117. package/dist/excel/src/xml/excel-xml-workbook.d.ts.map +0 -1
  118. package/dist/excel/src/xml/excel-xml-worksheet.d.ts.map +0 -1
  119. package/src/excel-cell.ts +0 -326
  120. package/src/excel-col.ts +0 -43
  121. package/src/excel-row.ts +0 -37
  122. package/src/excel-workbook.ts +0 -206
  123. package/src/excel-worksheet.ts +0 -380
  124. package/src/excel-wrapper.ts +0 -219
  125. package/src/index.ts +0 -13
  126. package/src/types.ts +0 -396
  127. package/src/utils/excel-utils.ts +0 -201
  128. package/src/utils/zip-cache.ts +0 -103
  129. package/src/xml/excel-xml-content-type.ts +0 -64
  130. package/src/xml/excel-xml-drawing.ts +0 -87
  131. package/src/xml/excel-xml-relationship.ts +0 -86
  132. package/src/xml/excel-xml-shared-string.ts +0 -80
  133. package/src/xml/excel-xml-style.ts +0 -393
  134. package/src/xml/excel-xml-unknown.ts +0 -11
  135. package/src/xml/excel-xml-workbook.ts +0 -112
  136. package/src/xml/excel-xml-worksheet.ts +0 -544
  137. package/tests/excel-cell.spec.ts +0 -407
  138. package/tests/excel-col.spec.ts +0 -112
  139. package/tests/excel-row.spec.ts +0 -71
  140. package/tests/excel-workbook.spec.ts +0 -166
  141. package/tests/excel-worksheet.spec.ts +0 -389
  142. package/tests/excel-wrapper.spec.ts +0 -275
  143. package/tests/fixtures/logo.png +0 -0
  144. package/tests/image-insert.spec.ts +0 -188
  145. package/tests/utils/excel-utils.spec.ts +0 -240
  146. /package/dist/{excel/src/excel-cell.d.ts → excel-cell.d.ts} +0 -0
  147. /package/dist/{excel/src/excel-col.d.ts → excel-col.d.ts} +0 -0
  148. /package/dist/{excel/src/excel-row.d.ts → excel-row.d.ts} +0 -0
  149. /package/dist/{excel/src/excel-workbook.d.ts → excel-workbook.d.ts} +0 -0
  150. /package/dist/{excel/src/excel-worksheet.d.ts → excel-worksheet.d.ts} +0 -0
  151. /package/dist/{excel/src/excel-wrapper.d.ts → excel-wrapper.d.ts} +0 -0
  152. /package/dist/{excel/src/index.d.ts → index.d.ts} +0 -0
  153. /package/dist/{excel/src/types.d.ts → types.d.ts} +0 -0
  154. /package/dist/{excel/src/utils → utils}/excel-utils.d.ts +0 -0
  155. /package/dist/{excel/src/utils → utils}/zip-cache.d.ts +0 -0
  156. /package/dist/{excel/src/xml → xml}/excel-xml-content-type.d.ts +0 -0
  157. /package/dist/{excel/src/xml → xml}/excel-xml-drawing.d.ts +0 -0
  158. /package/dist/{excel/src/xml → xml}/excel-xml-relationship.d.ts +0 -0
  159. /package/dist/{excel/src/xml → xml}/excel-xml-shared-string.d.ts +0 -0
  160. /package/dist/{excel/src/xml → xml}/excel-xml-style.d.ts +0 -0
  161. /package/dist/{excel/src/xml → xml}/excel-xml-unknown.d.ts +0 -0
  162. /package/dist/{excel/src/xml → xml}/excel-xml-workbook.d.ts +0 -0
  163. /package/dist/{excel/src/xml → xml}/excel-xml-worksheet.d.ts +0 -0
@@ -1,275 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { z } from "zod";
3
- import { ExcelWrapper } from "../src/excel-wrapper";
4
- import { DateOnly, DateTime, Time } from "@simplysm/core-common";
5
-
6
- describe("ExcelWrapper", () => {
7
- const testSchema = z.object({
8
- name: z.string(),
9
- age: z.number(),
10
- email: z.string().optional(),
11
- active: z.boolean().default(false),
12
- });
13
-
14
- const displayNameMap = {
15
- name: "이름",
16
- age: "나이",
17
- email: "이메일",
18
- active: "활성화",
19
- };
20
-
21
- describe("write", () => {
22
- it("레코드를 Excel로 변환할 수 있다", async () => {
23
- const wrapper = new ExcelWrapper(testSchema, displayNameMap);
24
-
25
- const records = [
26
- { name: "홍길동", age: 30, email: "hong@test.com", active: true },
27
- { name: "김철수", age: 25 },
28
- ];
29
-
30
- const wb = await wrapper.write("Users", records);
31
- const ws = await wb.getWorksheet("Users");
32
-
33
- // 헤더 확인
34
- expect(await ws.cell(0, 0).getVal()).toBe("이름");
35
- expect(await ws.cell(0, 1).getVal()).toBe("나이");
36
- expect(await ws.cell(0, 2).getVal()).toBe("이메일");
37
- expect(await ws.cell(0, 3).getVal()).toBe("활성화");
38
-
39
- // 데이터 확인
40
- expect(await ws.cell(1, 0).getVal()).toBe("홍길동");
41
- expect(await ws.cell(1, 1).getVal()).toBe(30);
42
- expect(await ws.cell(2, 0).getVal()).toBe("김철수");
43
- expect(await ws.cell(2, 1).getVal()).toBe(25);
44
-
45
- await wb.close();
46
- });
47
-
48
- it("필수 필드에 노란색 배경이 적용된다", async () => {
49
- const wrapper = new ExcelWrapper(testSchema, displayNameMap);
50
- const wb = await wrapper.write("Test", [{ name: "Test", age: 20 }]);
51
- const ws = await wb.getWorksheet("Test");
52
-
53
- // 필수 필드 (name, age)는 스타일이 적용됨
54
- const nameStyleId = await ws.cell(0, 0).getStyleId();
55
- const ageStyleId = await ws.cell(0, 1).getStyleId();
56
-
57
- expect(nameStyleId).toBeDefined();
58
- expect(ageStyleId).toBeDefined();
59
-
60
- await wb.close();
61
- });
62
- });
63
-
64
- describe("read", () => {
65
- it("Excel에서 레코드를 읽을 수 있다", async () => {
66
- const wrapper = new ExcelWrapper(testSchema, displayNameMap);
67
-
68
- // 먼저 Excel 생성
69
- const records = [
70
- { name: "홍길동", age: 30, email: "hong@test.com", active: true },
71
- { name: "김철수", age: 25, active: false },
72
- ];
73
-
74
- const wb = await wrapper.write("Users", records);
75
- const buffer = await wb.getBytes();
76
- await wb.close();
77
-
78
- // Excel에서 읽기
79
- const readRecords = await wrapper.read(buffer, "Users");
80
-
81
- expect(readRecords.length).toBe(2);
82
- expect(readRecords[0].name).toBe("홍길동");
83
- expect(readRecords[0].age).toBe(30);
84
- expect(readRecords[0].email).toBe("hong@test.com");
85
- expect(readRecords[0].active).toBe(true);
86
- expect(readRecords[1].name).toBe("김철수");
87
- expect(readRecords[1].age).toBe(25);
88
- });
89
-
90
- it("인덱스로 워크시트를 지정할 수 있다", async () => {
91
- const wrapper = new ExcelWrapper(testSchema, displayNameMap);
92
-
93
- const records = [{ name: "Test", age: 20 }];
94
- const wb = await wrapper.write("Sheet1", records);
95
- const buffer = await wb.getBytes();
96
- await wb.close();
97
-
98
- const readRecords = await wrapper.read(buffer, 0);
99
- expect(readRecords.length).toBe(1);
100
- expect(readRecords[0].name).toBe("Test");
101
- });
102
- });
103
-
104
- describe("타입 변환", () => {
105
- it("문자열을 숫자로 변환할 수 있다", async () => {
106
- const wrapper = new ExcelWrapper(testSchema, displayNameMap);
107
-
108
- // 수동으로 문자열로 저장된 Excel 시뮬레이션
109
- const wb = await wrapper.write("Test", [{ name: "Test", age: 25 }]);
110
- const buffer = await wb.getBytes();
111
- await wb.close();
112
-
113
- const records = await wrapper.read(buffer);
114
- expect(typeof records[0].age).toBe("number");
115
- expect(records[0].age).toBe(25);
116
- });
117
-
118
- it("기본값이 적용된다", async () => {
119
- const wrapper = new ExcelWrapper(testSchema, displayNameMap);
120
-
121
- // active 필드 없이 저장
122
- const wb = await wrapper.write("Test", [{ name: "Test", age: 20 }]);
123
- const buffer = await wb.getBytes();
124
- await wb.close();
125
-
126
- const records = await wrapper.read(buffer);
127
- expect(records[0].active).toBe(false); // 기본값
128
- });
129
- });
130
-
131
- describe("날짜 타입 지원", () => {
132
- const dateSchema = z.object({
133
- title: z.string(),
134
- date: z.instanceof(DateOnly).optional(),
135
- });
136
-
137
- const dateDisplayMap = {
138
- title: "제목",
139
- date: "날짜",
140
- };
141
-
142
- it("DateOnly 타입을 읽고 쓸 수 있다", async () => {
143
- const wrapper = new ExcelWrapper(dateSchema, dateDisplayMap);
144
-
145
- const records = [{ title: "Event 1", date: new DateOnly(2024, 6, 15) }, { title: "Event 2" }];
146
-
147
- const wb = await wrapper.write("Events", records);
148
- const buffer = await wb.getBytes();
149
- await wb.close();
150
-
151
- const readRecords = await wrapper.read(buffer, "Events");
152
-
153
- expect(readRecords[0].title).toBe("Event 1");
154
- expect(readRecords[0].date).toBeInstanceOf(DateOnly);
155
- expect(readRecords[0].date!.year).toBe(2024);
156
- expect(readRecords[0].date!.month).toBe(6);
157
- expect(readRecords[0].date!.day).toBe(15);
158
- expect(readRecords[1].date).toBeUndefined();
159
- });
160
-
161
- it("DateTime 타입을 읽고 쓸 수 있다", async () => {
162
- const dateTimeSchema = z.object({
163
- title: z.string(),
164
- datetime: z.instanceof(DateTime).optional(),
165
- });
166
-
167
- const dateTimeDisplayMap = {
168
- title: "제목",
169
- datetime: "일시",
170
- };
171
-
172
- const wrapper = new ExcelWrapper(dateTimeSchema, dateTimeDisplayMap);
173
-
174
- const records = [{ title: "Meeting", datetime: new DateTime(2024, 6, 15, 14, 30, 0) }];
175
-
176
- const wb = await wrapper.write("Events", records);
177
- const buffer = await wb.getBytes();
178
- await wb.close();
179
-
180
- const readRecords = await wrapper.read(buffer, "Events");
181
-
182
- expect(readRecords[0].datetime).toBeInstanceOf(DateTime);
183
- expect(readRecords[0].datetime!.year).toBe(2024);
184
- expect(readRecords[0].datetime!.month).toBe(6);
185
- expect(readRecords[0].datetime!.day).toBe(15);
186
- expect(readRecords[0].datetime!.hour).toBe(14);
187
- expect(readRecords[0].datetime!.minute).toBe(30);
188
- });
189
-
190
- it("Time 타입을 읽고 쓸 수 있다", async () => {
191
- const timeSchema = z.object({
192
- title: z.string(),
193
- time: z.instanceof(Time).optional(),
194
- });
195
-
196
- const timeDisplayMap = {
197
- title: "제목",
198
- time: "시간",
199
- };
200
-
201
- const wrapper = new ExcelWrapper(timeSchema, timeDisplayMap);
202
-
203
- const records = [{ title: "Alarm", time: new Time(9, 30, 0) }];
204
-
205
- const wb = await wrapper.write("Events", records);
206
- const buffer = await wb.getBytes();
207
- await wb.close();
208
-
209
- const readRecords = await wrapper.read(buffer, "Events");
210
-
211
- expect(readRecords[0].time).toBeInstanceOf(Time);
212
- expect(readRecords[0].time!.hour).toBe(9);
213
- expect(readRecords[0].time!.minute).toBe(30);
214
- });
215
- });
216
-
217
- describe("에러 처리", () => {
218
- it("빈 데이터에서 읽으면 에러 발생", async () => {
219
- const wrapper = new ExcelWrapper(testSchema, displayNameMap);
220
-
221
- // 헤더만 있는 빈 Excel 생성
222
- const wb = await wrapper.write("Empty", []);
223
- const buffer = await wb.getBytes();
224
- await wb.close();
225
-
226
- await expect(wrapper.read(buffer, "Empty")).rejects.toThrow("엑셀파일에서 데이터를 찾을 수 없습니다");
227
- });
228
-
229
- it("존재하지 않는 워크시트 이름으로 읽으면 에러 발생", async () => {
230
- const wrapper = new ExcelWrapper(testSchema, displayNameMap);
231
-
232
- const wb = await wrapper.write("Test", [{ name: "Test", age: 20 }]);
233
- const buffer = await wb.getBytes();
234
- await wb.close();
235
-
236
- await expect(wrapper.read(buffer, "NotExist")).rejects.toThrow();
237
- });
238
-
239
- it("존재하지 않는 워크시트 인덱스로 읽으면 에러 발생", async () => {
240
- const wrapper = new ExcelWrapper(testSchema, displayNameMap);
241
-
242
- const wb = await wrapper.write("Test", [{ name: "Test", age: 20 }]);
243
- const buffer = await wb.getBytes();
244
- await wb.close();
245
-
246
- await expect(wrapper.read(buffer, 99)).rejects.toThrow();
247
- });
248
-
249
- it("스키마 검증 실패 시 워크시트 이름과 상세 오류가 포함된 에러 발생", async () => {
250
- const strictSchema = z.object({
251
- name: z.string().min(5), // 최소 5자 이상
252
- age: z.number().min(0).max(150), // 0~150 사이
253
- });
254
-
255
- const strictDisplayMap = {
256
- name: "이름",
257
- age: "나이",
258
- };
259
-
260
- // 유효한 데이터로 Excel 생성
261
- const wrapper = new ExcelWrapper(strictSchema, strictDisplayMap);
262
- const wb = await wrapper.write("Validation", [{ name: "홍길동홍길동", age: 30 }]);
263
-
264
- // 데이터를 직접 수정하여 검증 실패 유도
265
- const ws = await wb.getWorksheet("Validation");
266
- await ws.cell(1, 0).setVal("AB"); // 최소 5자 미만으로 변경
267
-
268
- const buffer = await wb.getBytes();
269
- await wb.close();
270
-
271
- // 검증 실패 에러가 발생해야 함
272
- await expect(wrapper.read(buffer, "Validation")).rejects.toThrow();
273
- });
274
- });
275
- });
Binary file
@@ -1,188 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { ExcelWorkbook } from "../src/excel-workbook";
3
-
4
- // globalThis.window가 없으면 Node.js 환경
5
- declare const window: unknown;
6
- // Node.js 전용 타입 (browser 환경에서도 타입체크가 통과되도록)
7
- declare const require: (id: string) => unknown;
8
-
9
- /**
10
- * PNG 파일 로드 (Node/브라우저 환경 분기)
11
- */
12
- async function loadPngFile(): Promise<Uint8Array> {
13
- const url = new URL("./fixtures/logo.png", import.meta.url);
14
-
15
- // Node 환경: fs 사용
16
- if (typeof window === "undefined") {
17
- const fs = require("fs") as { readFileSync: (path: string) => Uint8Array };
18
- const { fileURLToPath } = require("url") as { fileURLToPath: (url: URL) => string };
19
- const filePath = fileURLToPath(url);
20
- return new Uint8Array(fs.readFileSync(filePath));
21
- }
22
-
23
- // 브라우저 환경: fetch 사용
24
- const response = await fetch(url);
25
- const arrayBuffer = await response.arrayBuffer();
26
- return new Uint8Array(arrayBuffer);
27
- }
28
-
29
- /**
30
- * 통합 테스트: ExcelWorksheet.addImage 동작 검증
31
- */
32
-
33
- describe("ExcelWorksheet.addImage integration", () => {
34
- it("should write media, drawing, drawing rels, worksheet rel and content types", async () => {
35
- const wb = new ExcelWorkbook();
36
- const ws = await wb.createWorksheet("Sheet1");
37
-
38
- const bytes = await loadPngFile();
39
-
40
- // call addImage (the single entry API)
41
- await ws.addImage({
42
- bytes,
43
- ext: "png",
44
- from: { r: 0, c: 0 },
45
- to: { r: 2, c: 2 },
46
- });
47
-
48
- // --- 1) media 존재 및 내용 검사
49
- const mediaPath = `xl/media/image1.png`;
50
- const mediaObj = await (ws as any)._zipCache.get(mediaPath);
51
- expect(mediaObj).toBeDefined();
52
- expect(mediaObj instanceof Uint8Array).toBe(true);
53
- expect(mediaObj).toEqual(bytes);
54
-
55
- // --- 2) Content Types 에 media / drawing override 존재
56
- const types = await (ws as any)._zipCache.get("[Content_Types].xml");
57
- expect(types).toBeDefined();
58
- // types는 ExcelXmlContentType 인스턴스일 가능성이 높음
59
- const overrides = types.data?.Types?.Override ?? [];
60
- expect(overrides.some((o: any) => o.$.PartName === "/xl/media/image1.png")).toBeTruthy();
61
- expect(overrides.some((o: any) => o.$.PartName === "/xl/drawings/drawing1.xml")).toBeTruthy();
62
-
63
- // --- 3) drawing xml(객체) 존재 및 a:blip r:embed가 rId로 설정되어 있는지 확인
64
- const drawingPath = "xl/drawings/drawing1.xml";
65
- const drawingObj = await (ws as any)._zipCache.get(drawingPath);
66
- expect(drawingObj).toBeDefined();
67
-
68
- // drawingObj는 객체(ExcelXmlDrawing)일 가능성이 높음 — 내부 구조 확인
69
- const wsDr = drawingObj?.data?.wsDr;
70
- expect(wsDr).toBeDefined();
71
- const anchors = wsDr.twoCellAnchor ?? [];
72
- expect(anchors.length).toBeGreaterThan(0);
73
- const pic = anchors[0].pic?.[0];
74
- expect(pic).toBeDefined();
75
- const aBlip = pic?.blipFill?.[0]?.["a:blip"]?.[0];
76
- expect(aBlip).toBeDefined();
77
- const embedVal = aBlip?.$?.["r:embed"];
78
- expect(typeof embedVal === "string" && /^rId\d+$/.test(embedVal)).toBeTruthy();
79
-
80
- // --- 4) drawing rels 존재 및 media target 참조
81
- const drawingRels = await (ws as any)._zipCache.get("xl/drawings/_rels/drawing1.xml.rels");
82
- expect(drawingRels).toBeDefined();
83
- const relsArr = drawingRels?.data?.Relationships?.Relationship ?? [];
84
- expect(relsArr.some((r: any) => r.$.Target === "../media/image1.png")).toBeTruthy();
85
-
86
- // --- 5) worksheet rels에 drawing rel 추가 및 worksheet xml에 <drawing r:id="..."/> 존재
87
- const sheetFileName = (ws as any)._targetFileName; // e.g., "sheet1.xml"
88
- const sheetRelsPath = `xl/worksheets/_rels/${sheetFileName}.rels`;
89
- const sheetRels = await (ws as any)._zipCache.get(sheetRelsPath);
90
- expect(sheetRels).toBeDefined();
91
- const sheetRelsArr = sheetRels?.data?.Relationships?.Relationship ?? [];
92
- expect(
93
- sheetRelsArr.some((r: any) => r.$.Target != null && r.$.Target.indexOf("/drawings/drawing") !== -1),
94
- ).toBeTruthy();
95
-
96
- const wsXml = await (ws as any)._zipCache.get(`xl/worksheets/${sheetFileName}`);
97
- expect(wsXml).toBeDefined();
98
- expect(Array.isArray(wsXml.data?.worksheet?.drawing)).toBeTruthy();
99
- const drawingElems = wsXml.data.worksheet.drawing;
100
- expect(drawingElems.some((d: any) => d.$ != null && d.$["r:id"] != null)).toBeTruthy();
101
-
102
- // Buffer 생성 검증
103
- const resultBuffer = await wb.getBytes();
104
- expect(resultBuffer).toBeDefined();
105
- expect(resultBuffer.length).toBeGreaterThan(0);
106
- });
107
-
108
- it("같은 워크시트에 여러 이미지를 삽입할 수 있다", async () => {
109
- const wb = new ExcelWorkbook();
110
- const ws = await wb.createWorksheet("Sheet1");
111
-
112
- const bytes = await loadPngFile();
113
-
114
- // 첫 번째 이미지 삽입
115
- await ws.addImage({
116
- bytes,
117
- ext: "png",
118
- from: { r: 0, c: 0 },
119
- to: { r: 2, c: 2 },
120
- });
121
-
122
- // 두 번째 이미지 삽입 (다른 위치)
123
- await ws.addImage({
124
- bytes,
125
- ext: "png",
126
- from: { r: 3, c: 0 },
127
- to: { r: 5, c: 2 },
128
- });
129
-
130
- // --- 1) 두 개의 media 파일이 각각 생성되었는지 확인
131
- const media1 = await (ws as any)._zipCache.get("xl/media/image1.png");
132
- const media2 = await (ws as any)._zipCache.get("xl/media/image2.png");
133
- expect(media1).toBeDefined();
134
- expect(media2).toBeDefined();
135
- expect(media1 instanceof Uint8Array).toBe(true);
136
- expect(media2 instanceof Uint8Array).toBe(true);
137
-
138
- // --- 2) Content Types에 두 이미지가 모두 등록되었는지 확인
139
- const types = await (ws as any)._zipCache.get("[Content_Types].xml");
140
- const overrides = types.data?.Types?.Override ?? [];
141
- expect(overrides.some((o: any) => o.$.PartName === "/xl/media/image1.png")).toBeTruthy();
142
- expect(overrides.some((o: any) => o.$.PartName === "/xl/media/image2.png")).toBeTruthy();
143
-
144
- // --- 3) drawing xml에 두 개의 anchor가 있는지 확인
145
- const drawingObj = await (ws as any)._zipCache.get("xl/drawings/drawing1.xml");
146
- const anchors = drawingObj?.data?.wsDr?.twoCellAnchor ?? [];
147
- expect(anchors.length).toBe(2);
148
-
149
- // 첫 번째 이미지 anchor
150
- const pic1 = anchors[0].pic?.[0];
151
- expect(pic1).toBeDefined();
152
- const embed1 = pic1?.blipFill?.[0]?.["a:blip"]?.[0]?.$?.["r:embed"];
153
- expect(embed1).toBeDefined();
154
-
155
- // 두 번째 이미지 anchor
156
- const pic2 = anchors[1].pic?.[0];
157
- expect(pic2).toBeDefined();
158
- const embed2 = pic2?.blipFill?.[0]?.["a:blip"]?.[0]?.$?.["r:embed"];
159
- expect(embed2).toBeDefined();
160
-
161
- // 서로 다른 rId인지 확인
162
- expect(embed1).not.toBe(embed2);
163
-
164
- // --- 4) drawing rels에 두 이미지에 대한 관계가 있는지 확인
165
- const drawingRels = await (ws as any)._zipCache.get("xl/drawings/_rels/drawing1.xml.rels");
166
- const relsArr = drawingRels?.data?.Relationships?.Relationship ?? [];
167
- expect(relsArr.some((r: any) => r.$.Target === "../media/image1.png")).toBeTruthy();
168
- expect(relsArr.some((r: any) => r.$.Target === "../media/image2.png")).toBeTruthy();
169
-
170
- // Buffer 생성 검증
171
- const resultBuffer = await wb.getBytes();
172
- expect(resultBuffer).toBeDefined();
173
- expect(resultBuffer.length).toBeGreaterThan(0);
174
- });
175
-
176
- it("지원되지 않는 확장자는 에러 발생", async () => {
177
- const wb = new ExcelWorkbook();
178
- const ws = await wb.createWorksheet("Sheet1");
179
-
180
- await expect(
181
- ws.addImage({
182
- bytes: new Uint8Array([0, 1, 2, 3]),
183
- ext: "xyz123",
184
- from: { r: 0, c: 0 },
185
- }),
186
- ).rejects.toThrow("MIME 타입을 확인할 수 없습니다");
187
- });
188
- });