@alloy-js/core 0.19.0-dev.2 → 0.19.0

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 (98) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/src/components/AppendFile.d.ts +90 -0
  3. package/dist/src/components/AppendFile.d.ts.map +1 -0
  4. package/dist/src/components/AppendFile.js +226 -0
  5. package/dist/src/components/CopyFile.d.ts +12 -0
  6. package/dist/src/components/CopyFile.d.ts.map +1 -0
  7. package/dist/src/components/CopyFile.js +15 -0
  8. package/dist/src/components/TemplateFile.d.ts +84 -0
  9. package/dist/src/components/TemplateFile.d.ts.map +1 -0
  10. package/dist/src/components/TemplateFile.js +133 -0
  11. package/dist/src/components/UpdateFile.d.ts +34 -0
  12. package/dist/src/components/UpdateFile.d.ts.map +1 -0
  13. package/dist/src/components/UpdateFile.js +66 -0
  14. package/dist/src/components/index.d.ts +4 -0
  15. package/dist/src/components/index.d.ts.map +1 -1
  16. package/dist/src/components/index.js +4 -0
  17. package/dist/src/components/stc/index.d.ts +4 -0
  18. package/dist/src/components/stc/index.d.ts.map +1 -1
  19. package/dist/src/components/stc/index.js +4 -0
  20. package/dist/src/context/source-directory.d.ts +3 -3
  21. package/dist/src/context/source-directory.d.ts.map +1 -1
  22. package/dist/src/context/source-file.d.ts +4 -0
  23. package/dist/src/context/source-file.d.ts.map +1 -1
  24. package/dist/src/debug.d.ts.map +1 -1
  25. package/dist/src/debug.js +4 -1
  26. package/dist/src/host/alloy-host.browser.d.ts +11 -0
  27. package/dist/src/host/alloy-host.browser.d.ts.map +1 -0
  28. package/dist/src/host/alloy-host.browser.js +31 -0
  29. package/dist/src/host/alloy-host.d.ts +11 -0
  30. package/dist/src/host/alloy-host.d.ts.map +1 -0
  31. package/dist/src/host/alloy-host.js +143 -0
  32. package/dist/src/host/interface.d.ts +144 -0
  33. package/dist/src/host/interface.d.ts.map +1 -0
  34. package/dist/src/host/interface.js +1 -0
  35. package/dist/src/index.browser.d.ts +1 -1
  36. package/dist/src/index.browser.d.ts.map +1 -1
  37. package/dist/src/index.browser.js +2 -2
  38. package/dist/src/reactivity.js +2 -2
  39. package/dist/src/render.d.ts +10 -2
  40. package/dist/src/render.d.ts.map +1 -1
  41. package/dist/src/render.js +20 -1
  42. package/dist/src/resource.d.ts +80 -0
  43. package/dist/src/resource.d.ts.map +1 -0
  44. package/dist/src/resource.js +118 -0
  45. package/dist/src/scheduler.d.ts +6 -0
  46. package/dist/src/scheduler.d.ts.map +1 -1
  47. package/dist/src/scheduler.js +36 -0
  48. package/dist/src/write-output.d.ts +1 -1
  49. package/dist/src/write-output.d.ts.map +1 -1
  50. package/dist/src/write-output.js +40 -21
  51. package/dist/test/components/append-file.test.d.ts +2 -0
  52. package/dist/test/components/append-file.test.d.ts.map +1 -0
  53. package/dist/test/components/append-file.test.js +281 -0
  54. package/dist/test/components/copy-file.test.d.ts +2 -0
  55. package/dist/test/components/copy-file.test.d.ts.map +1 -0
  56. package/dist/test/components/copy-file.test.js +94 -0
  57. package/dist/test/components/source-file.test.d.ts.map +1 -1
  58. package/dist/test/components/template-file.test.d.ts +2 -0
  59. package/dist/test/components/template-file.test.d.ts.map +1 -0
  60. package/dist/test/components/template-file.test.js +133 -0
  61. package/dist/test/components/update-file.test.d.ts +2 -0
  62. package/dist/test/components/update-file.test.d.ts.map +1 -0
  63. package/dist/test/components/update-file.test.js +169 -0
  64. package/dist/test/rendering/formatting.test.d.ts.map +1 -1
  65. package/dist/testing/extend-expect.js +60 -54
  66. package/dist/tsconfig.tsbuildinfo +1 -1
  67. package/package.json +6 -6
  68. package/src/components/AppendFile.tsx +294 -0
  69. package/src/components/CopyFile.tsx +29 -0
  70. package/src/components/TemplateFile.tsx +193 -0
  71. package/src/components/UpdateFile.tsx +86 -0
  72. package/src/components/index.tsx +4 -0
  73. package/src/components/stc/index.ts +4 -0
  74. package/src/context/source-directory.ts +5 -3
  75. package/src/context/source-file.ts +5 -0
  76. package/src/debug.ts +4 -1
  77. package/src/host/alloy-host.browser.ts +56 -0
  78. package/src/host/alloy-host.ts +160 -0
  79. package/src/host/interface.ts +153 -0
  80. package/src/index.browser.ts +1 -1
  81. package/src/reactivity.ts +2 -2
  82. package/src/render.ts +44 -5
  83. package/src/resource.ts +152 -0
  84. package/src/scheduler.ts +39 -0
  85. package/src/write-output.ts +49 -19
  86. package/temp/api.json +2009 -546
  87. package/test/components/append-file.test.tsx +275 -0
  88. package/test/components/copy-file.test.tsx +98 -0
  89. package/test/components/source-file.test.tsx +5 -2
  90. package/test/components/template-file.test.tsx +127 -0
  91. package/test/components/update-file.test.tsx +214 -0
  92. package/test/rendering/formatting.test.tsx +9 -3
  93. package/testing/extend-expect.ts +74 -58
  94. package/testing/vitest.d.ts +4 -0
  95. package/dist/src/write-output.browser.d.ts +0 -2
  96. package/dist/src/write-output.browser.d.ts.map +0 -1
  97. package/dist/src/write-output.browser.js +0 -4
  98. package/src/write-output.browser.ts +0 -4
@@ -0,0 +1,275 @@
1
+ import { existsSync, unlinkSync, writeFileSync } from "fs";
2
+ import { tmpdir } from "os";
3
+ import { join } from "path";
4
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
+ import { AppendFile, AppendRegion } from "../../src/components/AppendFile.jsx";
6
+ import { render, renderAsync } from "../../src/render.js";
7
+ import "../../testing/extend-expect.js";
8
+ import { d } from "../../testing/render.js";
9
+
10
+ describe("AppendFile", () => {
11
+ let testFilePath: string;
12
+
13
+ beforeEach(() => {
14
+ // Create a unique temporary file path for each test
15
+ testFilePath = join(tmpdir(), `test-append-file-${Date.now()}.txt`);
16
+ });
17
+
18
+ afterEach(() => {
19
+ // Clean up test file after each test
20
+ if (existsSync(testFilePath)) {
21
+ unlinkSync(testFilePath);
22
+ }
23
+ });
24
+
25
+ it("should append content to end of file when no sigils present", async () => {
26
+ // Create initial file content
27
+ writeFileSync(testFilePath, "Initial content", "utf-8");
28
+
29
+ const result = (
30
+ <AppendFile path={testFilePath}>
31
+ <AppendRegion id="append">New content</AppendRegion>
32
+ </AppendFile>
33
+ );
34
+
35
+ await expect(result).toRenderToAsync("Initial content\nNew content");
36
+ });
37
+ it("should append content to end of file when no sigils present with no explicit append region", async () => {
38
+ // Create initial file content
39
+ writeFileSync(testFilePath, "Initial content", "utf-8");
40
+
41
+ const result = <AppendFile path={testFilePath}>New content</AppendFile>;
42
+
43
+ await expect(result).toRenderToAsync("Initial content\nNew content");
44
+ });
45
+
46
+ it("should append content within region sigils", async () => {
47
+ const initialContent = d`
48
+ Header content
49
+ <!-- alloy-main-start -->
50
+ <!-- alloy-main-end -->
51
+ Footer content
52
+ `;
53
+
54
+ writeFileSync(testFilePath, initialContent, "utf-8");
55
+
56
+ const result = (
57
+ <AppendFile path={testFilePath} regions={["main"]}>
58
+ <AppendRegion id="main">New main content</AppendRegion>
59
+ </AppendFile>
60
+ );
61
+
62
+ await expect(result).toRenderToAsync(d`
63
+ Header content
64
+ <!-- alloy-main-start -->
65
+ New main content
66
+ <!-- alloy-main-end -->
67
+ Footer content
68
+ `);
69
+ });
70
+
71
+ it("should handle multiple regions", async () => {
72
+ const initialContent = d`
73
+ <!-- alloy-header-start -->
74
+ <!-- alloy-header-end -->
75
+ Main content
76
+ <!-- alloy-footer-start -->
77
+ <!-- alloy-footer-end -->
78
+ `;
79
+
80
+ writeFileSync(testFilePath, initialContent, "utf-8");
81
+
82
+ const result = (
83
+ <AppendFile path={testFilePath} regions={["header", "footer"]}>
84
+ <AppendRegion id="header">Header text</AppendRegion>
85
+ <AppendRegion id="footer">Footer text</AppendRegion>
86
+ </AppendFile>
87
+ );
88
+
89
+ await expect(result).toRenderToAsync(d`
90
+ <!-- alloy-header-start -->
91
+ Header text
92
+ <!-- alloy-header-end -->
93
+ Main content
94
+ <!-- alloy-footer-start -->
95
+ Footer text
96
+ <!-- alloy-footer-end -->
97
+ `);
98
+ });
99
+
100
+ it("should preserve existing content and append new content", async () => {
101
+ const initialContent = d`
102
+ Header
103
+ <!-- alloy-main-start -->
104
+ Existing content
105
+ <!-- alloy-main-end -->
106
+ Footer
107
+ `;
108
+
109
+ writeFileSync(testFilePath, initialContent, "utf-8");
110
+
111
+ const result = (
112
+ <AppendFile path={testFilePath} regions={["main"]}>
113
+ <AppendRegion id="main">New appended content</AppendRegion>
114
+ </AppendFile>
115
+ );
116
+
117
+ await expect(result).toRenderToAsync(d`
118
+ Header
119
+ <!-- alloy-main-start -->
120
+ Existing content
121
+ New appended content
122
+ <!-- alloy-main-end -->
123
+ Footer
124
+ `);
125
+ });
126
+
127
+ it("should use content prop instead of children", async () => {
128
+ writeFileSync(testFilePath, "Start ", "utf-8");
129
+
130
+ const result = (
131
+ <AppendFile path={testFilePath}>
132
+ <AppendRegion id="append" content="End" />
133
+ </AppendFile>
134
+ );
135
+
136
+ await expect(result).toRenderToAsync("Start\nEnd");
137
+ });
138
+
139
+ it("should default to 'append' region when no regions specified", async () => {
140
+ writeFileSync(testFilePath, "Content", "utf-8");
141
+
142
+ const result = (
143
+ <AppendFile path={testFilePath}>
144
+ <AppendRegion id="append">default region</AppendRegion>
145
+ </AppendFile>
146
+ );
147
+
148
+ await expect(result).toRenderToAsync("Content\ndefault region");
149
+ });
150
+
151
+ it("should throw error when region is missing corresponding AppendRegion", async () => {
152
+ writeFileSync(testFilePath, "content", "utf-8");
153
+
154
+ expect(() =>
155
+ render(
156
+ <AppendFile path={testFilePath} regions={["missing"]}>
157
+ <AppendRegion id="append">content</AppendRegion>
158
+ </AppendFile>,
159
+ ),
160
+ ).toThrow(
161
+ 'Region "missing" specified but no corresponding AppendRegion child found',
162
+ );
163
+ });
164
+
165
+ it("should throw error when AppendRegion has neither children nor content", async () => {
166
+ writeFileSync(testFilePath, "content", "utf-8");
167
+
168
+ expect(() =>
169
+ render(
170
+ <AppendFile path={testFilePath}>
171
+ <AppendRegion id="append" />
172
+ </AppendFile>,
173
+ ),
174
+ ).toThrow('AppendRegion "append" must have either children or content');
175
+ });
176
+
177
+ it("should throw error when region has missing start sigil", async () => {
178
+ const contentWithOnlyEnd = d`
179
+ Content
180
+ <!-- alloy-incomplete-end -->
181
+ `;
182
+
183
+ writeFileSync(testFilePath, contentWithOnlyEnd, "utf-8");
184
+
185
+ const result = (
186
+ <AppendFile path={testFilePath} regions={["incomplete"]}>
187
+ <AppendRegion id="incomplete">content</AppendRegion>
188
+ </AppendFile>
189
+ );
190
+
191
+ // Should insert before the end sigil
192
+ await expect(result).toRenderToAsync(d`
193
+ Content
194
+ content
195
+ <!-- alloy-incomplete-end -->
196
+ `);
197
+ });
198
+
199
+ it("should throw error when region has missing end sigil", async () => {
200
+ const contentWithOnlyStart = d`
201
+ Content
202
+ <!-- alloy-incomplete-start -->
203
+ `;
204
+
205
+ writeFileSync(testFilePath, contentWithOnlyStart, "utf-8");
206
+
207
+ await expect(async () =>
208
+ renderAsync(
209
+ <AppendFile path={testFilePath} regions={["incomplete"]}>
210
+ <AppendRegion id="incomplete">content</AppendRegion>
211
+ </AppendFile>,
212
+ ),
213
+ ).rejects.toThrow(
214
+ 'Region "incomplete" has start sigil but no corresponding end sigil',
215
+ );
216
+ });
217
+
218
+ it("should handle complex nested content", async () => {
219
+ const initialContent = d`
220
+ <!-- alloy-config-start -->
221
+ <!-- alloy-config-end -->
222
+ `;
223
+
224
+ writeFileSync(testFilePath, initialContent, "utf-8");
225
+
226
+ const jsonContent = d`
227
+ {
228
+ "newProperty": "value",
229
+ "nested": {
230
+ "key": "data"
231
+ }
232
+ }
233
+ `;
234
+
235
+ const result = (
236
+ <AppendFile path={testFilePath} regions={["config"]}>
237
+ <AppendRegion id="config">{jsonContent}</AppendRegion>
238
+ </AppendFile>
239
+ );
240
+
241
+ await expect(result).toRenderToAsync(d`
242
+ <!-- alloy-config-start -->
243
+ {
244
+ "newProperty": "value",
245
+ "nested": {
246
+ "key": "data"
247
+ }
248
+ }
249
+ <!-- alloy-config-end -->
250
+ `);
251
+ });
252
+
253
+ it("should preserve indentation level of the end sigil", async () => {
254
+ const initialContent = d`
255
+ base
256
+ <!-- alloy-indented-start -->
257
+ <!-- alloy-indented-end -->
258
+ `;
259
+
260
+ writeFileSync(testFilePath, initialContent, "utf-8");
261
+
262
+ const result = (
263
+ <AppendFile path={testFilePath} regions={["indented"]}>
264
+ <AppendRegion id="indented">new content</AppendRegion>
265
+ </AppendFile>
266
+ );
267
+
268
+ await expect(result).toRenderToAsync(d`
269
+ base
270
+ <!-- alloy-indented-start -->
271
+ new content
272
+ <!-- alloy-indented-end -->
273
+ `);
274
+ });
275
+ });
@@ -0,0 +1,98 @@
1
+ import { existsSync, readFileSync, unlinkSync, writeFileSync } from "fs";
2
+ import { tmpdir } from "os";
3
+ import { join } from "path";
4
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
+ import { CopyFile } from "../../src/components/CopyFile.jsx";
6
+ import { SourceDirectory } from "../../src/components/SourceDirectory.jsx";
7
+ import { CopyOutputFile, render } from "../../src/render.js";
8
+ import { writeOutput } from "../../src/write-output.js";
9
+ import "../../testing/extend-expect.js";
10
+
11
+ describe("CopyFile", () => {
12
+ let testDir: string;
13
+ let sourceFile: string;
14
+ let targetFile: string;
15
+
16
+ beforeEach(() => {
17
+ // Create unique temporary paths for each test
18
+ testDir = tmpdir();
19
+ sourceFile = join(testDir, "source.txt");
20
+ targetFile = join(testDir, "target.txt");
21
+ });
22
+
23
+ afterEach(() => {
24
+ // Clean up test files after each test
25
+ if (existsSync(sourceFile)) {
26
+ unlinkSync(sourceFile);
27
+ }
28
+ if (existsSync(targetFile)) {
29
+ unlinkSync(targetFile);
30
+ }
31
+ });
32
+
33
+ it("should create copy file context with correct paths", async () => {
34
+ writeFileSync(sourceFile, "Hello, World!", "utf-8");
35
+
36
+ const result = (
37
+ <SourceDirectory path={testDir}>
38
+ <CopyFile src={sourceFile} path="target.txt" />
39
+ </SourceDirectory>
40
+ );
41
+
42
+ const output = render(result);
43
+ await writeOutput(output);
44
+
45
+ expect(output.contents).toHaveLength(1);
46
+ const copyFileOutput = output.contents[0] as CopyOutputFile;
47
+ expect(copyFileOutput.kind).toBe("file");
48
+ expect(copyFileOutput.sourcePath).toBe(sourceFile);
49
+ expect(copyFileOutput.path).toBe(join(testDir, "target.txt"));
50
+ expect(existsSync(targetFile)).toBe(true);
51
+ const targetContent = readFileSync(targetFile, "utf-8");
52
+ expect(targetContent).toBe("Hello, World!");
53
+ });
54
+
55
+ it("should handle relative paths correctly", async () => {
56
+ // Create source file
57
+ writeFileSync(sourceFile, "Relative path test", "utf-8");
58
+
59
+ const result = (
60
+ <SourceDirectory path={testDir}>
61
+ <SourceDirectory path="subdir">
62
+ <CopyFile src={sourceFile} path="nested-target.txt" />
63
+ </SourceDirectory>
64
+ </SourceDirectory>
65
+ );
66
+
67
+ const output = render(result);
68
+
69
+ // Find the copy file in the nested directory
70
+ const subdir = output.contents.find(
71
+ (item) =>
72
+ item.kind === "directory" && item.path === join(testDir, "subdir"),
73
+ );
74
+ expect(subdir).toBeDefined();
75
+
76
+ if (subdir && subdir.kind === "directory") {
77
+ expect(subdir.contents).toHaveLength(1);
78
+ const copyFile = subdir.contents[0];
79
+ expect(copyFile.kind).toBe("file");
80
+
81
+ if (copyFile.kind === "file" && "sourcePath" in copyFile) {
82
+ expect(copyFile.sourcePath).toBe(sourceFile);
83
+ expect(copyFile.path).toBe(
84
+ join(testDir, "subdir", "nested-target.txt"),
85
+ );
86
+ }
87
+ }
88
+ });
89
+
90
+ it("should throw error when used without SourceDirectory context", () => {
91
+ // Create source file
92
+ writeFileSync(sourceFile, "Error test", "utf-8");
93
+
94
+ expect(() => {
95
+ render(<CopyFile src={sourceFile} path="target.txt" />);
96
+ }).toThrow("Copy file doesn't have parent directory");
97
+ });
98
+ });
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  computed,
3
+ ContentOutputFile,
3
4
  Output,
4
5
  render,
5
6
  renderTree,
@@ -50,7 +51,9 @@ it("has reactive context", () => {
50
51
  </Output>,
51
52
  );
52
53
 
53
- expect(tree.contents[1].contents).toEqual("hi.txt contents.txt");
54
+ expect((tree.contents[1] as ContentOutputFile).contents).toEqual(
55
+ "hi.txt contents.txt",
56
+ );
54
57
  });
55
58
 
56
59
  it("Includes header", () => {
@@ -63,7 +66,7 @@ it("Includes header", () => {
63
66
  </Output>,
64
67
  );
65
68
 
66
- expect(tree.contents[0].contents).toEqual(d`
69
+ expect((tree.contents[0] as ContentOutputFile).contents).toEqual(d`
67
70
  # This is a header
68
71
  hello!
69
72
  `);
@@ -0,0 +1,127 @@
1
+ import { writeFileSync } from "fs";
2
+ import { tmpdir } from "os";
3
+ import { join } from "path";
4
+ import { describe, expect, it } from "vitest";
5
+ import {
6
+ TemplateFile,
7
+ TemplateVariable,
8
+ } from "../../src/components/TemplateFile.jsx";
9
+ import { renderAsync } from "../../src/render.js";
10
+ import "../../testing/extend-expect.js";
11
+ import { d } from "../../testing/render.js";
12
+
13
+ describe("TemplateFile", () => {
14
+ it("should replace template variables with values", async () => {
15
+ // Create a temporary template file
16
+ const templatePath = join(tmpdir(), "test-template.txt");
17
+ const templateContent = "Hello {{ name }}! You are {{ age }} years old.";
18
+ writeFileSync(templatePath, templateContent);
19
+
20
+ const result = (
21
+ <TemplateFile src={templatePath} path="output.txt">
22
+ <TemplateVariable name="name" value="John" />
23
+ <TemplateVariable name="age" value="25" />
24
+ </TemplateFile>
25
+ );
26
+
27
+ await expect(result).toRenderToAsync("Hello John! You are 25 years old.");
28
+ });
29
+
30
+ it("should handle template variables with children", async () => {
31
+ const templatePath = join(tmpdir(), "test-template-children.txt");
32
+ const templateContent = "Welcome {{ greeting }}!";
33
+ writeFileSync(templatePath, templateContent);
34
+
35
+ const result = (
36
+ <TemplateFile src={templatePath} path="output.txt">
37
+ <TemplateVariable name="greeting">Hello World</TemplateVariable>
38
+ </TemplateFile>
39
+ );
40
+
41
+ await expect(result).toRenderToAsync("Welcome Hello World!");
42
+ });
43
+
44
+ it("should handle complex templates with multiple variables", async () => {
45
+ const templatePath = join(tmpdir(), "test-complex-template.txt");
46
+ const templateContent = d`
47
+ Name: {{ name }}
48
+ Age: {{ age }}
49
+ Location: {{ location }}
50
+ Status: {{ status }}
51
+ `;
52
+ writeFileSync(templatePath, templateContent);
53
+
54
+ const result = (
55
+ <TemplateFile src={templatePath} path="output.txt">
56
+ <TemplateVariable name="name" value="Alice" />
57
+ <TemplateVariable name="age">30</TemplateVariable>
58
+ <TemplateVariable name="location" value="New York" />
59
+ <TemplateVariable name="status" value="Active" />
60
+ </TemplateFile>
61
+ );
62
+
63
+ await expect(result).toRenderToAsync(d`
64
+ Name: Alice
65
+ Age: 30
66
+ Location: New York
67
+ Status: Active
68
+ `);
69
+ });
70
+
71
+ it("should handle templates with whitespace around variable names", async () => {
72
+ const templatePath = join(tmpdir(), "test-whitespace-template.txt");
73
+ const templateContent = "Hello {{ name }}!";
74
+ writeFileSync(templatePath, templateContent);
75
+
76
+ const result = (
77
+ <TemplateFile src={templatePath} path="output.txt">
78
+ <TemplateVariable name="name" value="Bob" />
79
+ </TemplateFile>
80
+ );
81
+
82
+ await expect(result).toRenderToAsync("Hello Bob!");
83
+ });
84
+
85
+ it("should throw error for missing template variables", async () => {
86
+ const templatePath = join(tmpdir(), "test-missing-var-template.txt");
87
+ const templateContent = "Hello {{ name }}! Your age is {{ age }}.";
88
+ writeFileSync(templatePath, templateContent);
89
+
90
+ await expect(
91
+ async () =>
92
+ await renderAsync(
93
+ <TemplateFile src={templatePath} path="output.txt">
94
+ <TemplateVariable name="name" value="Charlie" />
95
+ </TemplateFile>,
96
+ ),
97
+ ).rejects.toThrow(
98
+ 'Template variable "age" not found in TemplateVariable children',
99
+ );
100
+ });
101
+
102
+ it("should handle template with no variables", async () => {
103
+ const templatePath = join(tmpdir(), "test-no-vars-template.txt");
104
+ const templateContent = "This is just plain text with no variables.";
105
+ writeFileSync(templatePath, templateContent);
106
+
107
+ const result = (
108
+ <TemplateFile src={templatePath} path="output.txt"></TemplateFile>
109
+ );
110
+
111
+ await expect(result).toRenderToAsync(
112
+ "This is just plain text with no variables.",
113
+ );
114
+ });
115
+
116
+ it("should handle empty template", async () => {
117
+ const templatePath = join(tmpdir(), "test-empty-template.txt");
118
+ const templateContent = "";
119
+ writeFileSync(templatePath, templateContent);
120
+
121
+ const result = (
122
+ <TemplateFile src={templatePath} path="output.txt"></TemplateFile>
123
+ );
124
+
125
+ await expect(result).toRenderToAsync("");
126
+ });
127
+ });