effect-start 0.17.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 (80) hide show
  1. package/dist/Development.d.ts +7 -2
  2. package/dist/Development.js +12 -6
  3. package/dist/PlatformRuntime.d.ts +4 -0
  4. package/dist/PlatformRuntime.js +9 -0
  5. package/dist/Route.d.ts +6 -2
  6. package/dist/Route.js +22 -0
  7. package/dist/RouteHttp.d.ts +1 -1
  8. package/dist/RouteHttp.js +12 -19
  9. package/dist/RouteMount.d.ts +2 -1
  10. package/dist/Start.d.ts +1 -5
  11. package/dist/Start.js +1 -8
  12. package/dist/Unique.d.ts +50 -0
  13. package/dist/Unique.js +187 -0
  14. package/dist/bun/BunHttpServer.js +5 -6
  15. package/dist/bun/BunRoute.d.ts +1 -1
  16. package/dist/bun/BunRoute.js +2 -2
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.js +1 -0
  19. package/dist/node/Effectify.d.ts +209 -0
  20. package/dist/node/Effectify.js +19 -0
  21. package/dist/node/FileSystem.d.ts +3 -5
  22. package/dist/node/FileSystem.js +42 -62
  23. package/dist/node/PlatformError.d.ts +46 -0
  24. package/dist/node/PlatformError.js +43 -0
  25. package/dist/testing/TestLogger.js +1 -1
  26. package/package.json +10 -5
  27. package/src/Development.ts +13 -18
  28. package/src/PlatformRuntime.ts +11 -0
  29. package/src/Route.ts +31 -2
  30. package/src/RouteHttp.ts +15 -31
  31. package/src/RouteMount.ts +1 -1
  32. package/src/Start.ts +1 -15
  33. package/src/Unique.ts +232 -0
  34. package/src/bun/BunHttpServer.ts +6 -9
  35. package/src/bun/BunRoute.ts +3 -3
  36. package/src/index.ts +1 -0
  37. package/src/node/Effectify.ts +262 -0
  38. package/src/node/FileSystem.ts +59 -97
  39. package/src/node/PlatformError.ts +102 -0
  40. package/src/testing/TestLogger.ts +1 -1
  41. package/dist/Random.d.ts +0 -5
  42. package/dist/Random.js +0 -49
  43. package/src/Commander.test.ts +0 -1639
  44. package/src/ContentNegotiation.test.ts +0 -603
  45. package/src/Development.test.ts +0 -119
  46. package/src/Entity.test.ts +0 -592
  47. package/src/FileRouterPattern.test.ts +0 -147
  48. package/src/FileRouter_files.test.ts +0 -64
  49. package/src/FileRouter_path.test.ts +0 -145
  50. package/src/FileRouter_tree.test.ts +0 -132
  51. package/src/Http.test.ts +0 -319
  52. package/src/HttpAppExtra.test.ts +0 -103
  53. package/src/HttpUtils.test.ts +0 -85
  54. package/src/PathPattern.test.ts +0 -648
  55. package/src/Random.ts +0 -59
  56. package/src/RouteBody.test.ts +0 -232
  57. package/src/RouteHook.test.ts +0 -40
  58. package/src/RouteHttp.test.ts +0 -2909
  59. package/src/RouteMount.test.ts +0 -481
  60. package/src/RouteSchema.test.ts +0 -427
  61. package/src/RouteSse.test.ts +0 -249
  62. package/src/RouteTree.test.ts +0 -494
  63. package/src/RouteTrie.test.ts +0 -322
  64. package/src/RouterPattern.test.ts +0 -676
  65. package/src/Values.test.ts +0 -263
  66. package/src/bun/BunBundle.test.ts +0 -268
  67. package/src/bun/BunBundle_imports.test.ts +0 -48
  68. package/src/bun/BunHttpServer.test.ts +0 -251
  69. package/src/bun/BunImportTrackerPlugin.test.ts +0 -77
  70. package/src/bun/BunRoute.test.ts +0 -162
  71. package/src/bundler/BundleHttp.test.ts +0 -132
  72. package/src/effect/HttpRouter.test.ts +0 -548
  73. package/src/experimental/EncryptedCookies.test.ts +0 -488
  74. package/src/hyper/HyperHtml.test.ts +0 -209
  75. package/src/hyper/HyperRoute.test.tsx +0 -197
  76. package/src/middlewares/BasicAuthMiddleware.test.ts +0 -84
  77. package/src/testing/TestHttpClient.test.ts +0 -83
  78. package/src/testing/TestLogger.test.ts +0 -51
  79. package/src/x/datastar/Datastar.test.ts +0 -266
  80. package/src/x/tailwind/TailwindPlugin.test.ts +0 -333
@@ -1,488 +0,0 @@
1
- import * as Cookies from "@effect/platform/Cookies"
2
- import * as test from "bun:test"
3
- import * as ConfigProvider from "effect/ConfigProvider"
4
- import * as Effect from "effect/Effect"
5
- import * as EncryptedCookies from "./EncryptedCookies.ts"
6
-
7
- test.describe(`${EncryptedCookies.encrypt.name}`, () => {
8
- test.test("return encrypted string in correct format", async () => {
9
- const value = "hello world"
10
-
11
- const result = await Effect.runPromise(
12
- EncryptedCookies.encrypt(value, { secret: "test-secret" }),
13
- )
14
-
15
- // Check format: three base64url segments separated by .
16
- const segments = result.split(".")
17
- test
18
- .expect(segments)
19
- .toHaveLength(3)
20
-
21
- // Each segment should be base64url (no +, /, or = characters
22
- // so cookie values are not escaped)
23
- segments.forEach((segment: string) => {
24
- test
25
- .expect(segment)
26
- .not
27
- .toMatch(/[+/=]/)
28
- // Should be valid base64url that can be decoded
29
- const base64 = segment.replace(/-/g, "+").replace(/_/g, "/")
30
- const paddedBase64 = base64 + "=".repeat((4 - base64.length % 4) % 4)
31
- test
32
- .expect(() => atob(paddedBase64))
33
- .not
34
- .toThrow()
35
- })
36
- })
37
-
38
- test.test("produce different results for same input due to random IV", async () => {
39
- const value = "same value"
40
-
41
- const result1 = await Effect.runPromise(
42
- EncryptedCookies.encrypt(value, { secret: "test-secret" }),
43
- )
44
- const result2 = await Effect.runPromise(
45
- EncryptedCookies.encrypt(value, { secret: "test-secret" }),
46
- )
47
-
48
- test
49
- .expect(result1)
50
- .not
51
- .toBe(result2)
52
-
53
- // But both should have correct format
54
- test
55
- .expect(result1.split("."))
56
- .toHaveLength(3)
57
- test
58
- .expect(result2.split("."))
59
- .toHaveLength(3)
60
- })
61
-
62
- test.test("handle empty string", async () => {
63
- const value = ""
64
-
65
- const result = await Effect.runPromise(
66
- EncryptedCookies.encrypt(value, { secret: "test-secret" }),
67
- )
68
-
69
- test
70
- .expect(result.split("."))
71
- .toHaveLength(3)
72
- })
73
-
74
- test.test("handle special characters", async () => {
75
- const value = "hello 世界! @#$%^&*()"
76
-
77
- const result = await Effect.runPromise(
78
- EncryptedCookies.encrypt(value, { secret: "test-secret" }),
79
- )
80
-
81
- test
82
- .expect(result.split("."))
83
- .toHaveLength(3)
84
- })
85
-
86
- test.test("handle object with undefined properties", async () => {
87
- const value = { id: "some", optional: undefined }
88
-
89
- const encrypted = await Effect.runPromise(
90
- EncryptedCookies.encrypt(value, { secret: "test-secret" }),
91
- )
92
- const decrypted = await Effect.runPromise(
93
- EncryptedCookies.decrypt(encrypted, { secret: "test-secret" }),
94
- )
95
-
96
- // JSON.stringify removes undefined properties
97
- test
98
- .expect(decrypted)
99
- .toEqual({ id: "some" })
100
- })
101
- })
102
-
103
- test.describe(`${EncryptedCookies.decrypt.name}`, () => {
104
- test.test("decrypt encrypted string successfully", async () => {
105
- const originalValue = "hello world"
106
-
107
- const encrypted = await Effect.runPromise(
108
- EncryptedCookies.encrypt(originalValue, { secret: "test-secret" }),
109
- )
110
- const decrypted = await Effect.runPromise(
111
- EncryptedCookies.decrypt(encrypted, { secret: "test-secret" }),
112
- )
113
-
114
- test
115
- .expect(decrypted)
116
- .toBe(originalValue)
117
- })
118
-
119
- test.test("handle empty string round-trip", async () => {
120
- const originalValue = ""
121
-
122
- const encrypted = await Effect.runPromise(
123
- EncryptedCookies.encrypt(originalValue, { secret: "test-secret" }),
124
- )
125
- const decrypted = await Effect.runPromise(
126
- EncryptedCookies.decrypt(encrypted, { secret: "test-secret" }),
127
- )
128
-
129
- test
130
- .expect(decrypted)
131
- .toBe(originalValue)
132
- })
133
-
134
- test.test("handle special characters round-trip", async () => {
135
- const originalValue = "hello 世界! @#$%^&*()"
136
-
137
- const encrypted = await Effect.runPromise(
138
- EncryptedCookies.encrypt(originalValue, { secret: "test-secret" }),
139
- )
140
- const decrypted = await Effect.runPromise(
141
- EncryptedCookies.decrypt(encrypted, { secret: "test-secret" }),
142
- )
143
-
144
- test
145
- .expect(decrypted)
146
- .toBe(originalValue)
147
- })
148
-
149
- test.test("fail with invalid format", () => {
150
- const invalidValue = "not-encrypted"
151
-
152
- test
153
- .expect(
154
- Effect.runPromise(
155
- EncryptedCookies.decrypt(invalidValue, { secret: "test-secret" }),
156
- ),
157
- )
158
- .rejects
159
- .toThrow()
160
- })
161
-
162
- test.test("fail with wrong number of segments", () => {
163
- const invalidValue = "one.two"
164
-
165
- test
166
- .expect(
167
- Effect.runPromise(
168
- EncryptedCookies.decrypt(invalidValue, { secret: "test-secret" }),
169
- ),
170
- )
171
- .rejects
172
- .toThrow()
173
- })
174
-
175
- test.test("fail with invalid base64", () => {
176
- const invalidValue = "invalid.base64.data"
177
-
178
- test
179
- .expect(
180
- Effect.runPromise(
181
- EncryptedCookies.decrypt(invalidValue, { secret: "test-secret" }),
182
- ),
183
- )
184
- .rejects
185
- .toThrow()
186
- })
187
-
188
- test.test("fail with null value", () => {
189
- test
190
- .expect(
191
- Effect.runPromise(
192
- EncryptedCookies.encrypt(null, { secret: "test-secret" }),
193
- ),
194
- )
195
- .rejects
196
- .toThrow()
197
- })
198
-
199
- test.test("fail with undefined value", () => {
200
- test
201
- .expect(
202
- Effect.runPromise(
203
- EncryptedCookies.encrypt(undefined, { secret: "test-secret" }),
204
- ),
205
- )
206
- .rejects
207
- .toThrow()
208
- })
209
-
210
- test.test("fail with empty encrypted value", () => {
211
- test
212
- .expect(
213
- Effect.runPromise(
214
- EncryptedCookies.decrypt("", { secret: "test-secret" }),
215
- ),
216
- )
217
- .rejects
218
- .toThrow()
219
- })
220
- })
221
-
222
- test.describe(`${EncryptedCookies.encryptCookie.name}`, () => {
223
- test.test("preserve cookie properties and encrypt value", async () => {
224
- const cookie = Cookies.unsafeMakeCookie("test", "hello world")
225
-
226
- const result = await Effect.runPromise(
227
- EncryptedCookies.encryptCookie(cookie, { secret: "test-secret" }),
228
- )
229
-
230
- // Cookie properties should be preserved
231
- test
232
- .expect(result.name)
233
- .toBe("test")
234
-
235
- // Value should be encrypted (different from original)
236
- test
237
- .expect(result.value)
238
- .not
239
- .toBe("hello world")
240
-
241
- // Should be in encrypted format
242
- test
243
- .expect(result.value.split("."))
244
- .toHaveLength(3)
245
- })
246
- })
247
-
248
- test.describe(`${EncryptedCookies.decryptCookie.name}`, () => {
249
- test.test("preserve cookie properties and decrypt value", async () => {
250
- const originalCookie = Cookies.unsafeMakeCookie("test", "hello world")
251
-
252
- const encrypted = await Effect.runPromise(
253
- EncryptedCookies.encryptCookie(originalCookie, { secret: "test-secret" }),
254
- )
255
- const decrypted = await Effect.runPromise(
256
- EncryptedCookies.decryptCookie(encrypted, { secret: "test-secret" }),
257
- )
258
-
259
- // Cookie properties should be preserved
260
- test
261
- .expect(decrypted.name)
262
- .toBe("test")
263
-
264
- // Value should be JSON stringified (string values are now always serialized)
265
- test
266
- .expect(decrypted.value)
267
- .toBe("\"hello world\"")
268
- })
269
- })
270
-
271
- test.describe("service", () => {
272
- test.test("service uses pre-calculated key material", async () => {
273
- const testSecret = "test-secret-key"
274
- const testValue = "hello world"
275
-
276
- const program = Effect.gen(function*() {
277
- const service = yield* EncryptedCookies.EncryptedCookies
278
-
279
- const encrypted = yield* service.encrypt(testValue)
280
- const decrypted = yield* service.decrypt(encrypted)
281
-
282
- return { encrypted, decrypted }
283
- })
284
-
285
- const result = await Effect.runPromise(
286
- program.pipe(
287
- Effect.provide(EncryptedCookies.layer({ secret: testSecret })),
288
- ),
289
- )
290
-
291
- test
292
- .expect(result.decrypted)
293
- .toBe(testValue)
294
- test
295
- .expect(result.encrypted)
296
- .not
297
- .toBe(testValue)
298
- test
299
- .expect(result.encrypted.split("."))
300
- .toHaveLength(3)
301
- })
302
-
303
- test.test("service cookie functions work with pre-calculated key", async () => {
304
- const testSecret = "test-secret-key"
305
- const originalCookie = Cookies.unsafeMakeCookie("test", "hello world")
306
-
307
- const program = Effect.gen(function*() {
308
- const service = yield* EncryptedCookies.EncryptedCookies
309
-
310
- const encrypted = yield* service.encryptCookie(originalCookie)
311
- const decrypted = yield* service.decryptCookie(encrypted)
312
-
313
- return { encrypted, decrypted }
314
- })
315
-
316
- const result = await Effect.runPromise(
317
- program.pipe(
318
- Effect.provide(EncryptedCookies.layer({ secret: testSecret })),
319
- ),
320
- )
321
-
322
- test
323
- .expect(result.decrypted.name)
324
- .toBe("test")
325
- test
326
- .expect(result.decrypted.value)
327
- .toBe("\"hello world\"")
328
- test
329
- .expect(result.encrypted.value)
330
- .not
331
- .toBe("hello world")
332
- })
333
-
334
- test.test("functions work with pre-derived keys passed as options", async () => {
335
- const testSecret = "test-secret-key"
336
- const testValue = "hello world"
337
-
338
- // Pre-derive keys manually
339
- const program = Effect.gen(function*() {
340
- const keyMaterial = yield* Effect.tryPromise({
341
- try: () =>
342
- crypto.subtle.importKey(
343
- "raw",
344
- new TextEncoder().encode(testSecret),
345
- { name: "HKDF" },
346
- false,
347
- ["deriveKey"],
348
- ),
349
- catch: (error) => error,
350
- })
351
-
352
- const encryptKey = yield* Effect.tryPromise({
353
- try: () =>
354
- crypto.subtle.deriveKey(
355
- {
356
- name: "HKDF",
357
- salt: new TextEncoder().encode("cookie-encryption"),
358
- info: new TextEncoder().encode("aes-256-gcm"),
359
- hash: "SHA-256",
360
- },
361
- keyMaterial,
362
- { name: "AES-GCM", length: 256 },
363
- false,
364
- ["encrypt"],
365
- ),
366
- catch: (error) => error,
367
- })
368
-
369
- const decryptKey = yield* Effect.tryPromise({
370
- try: () =>
371
- crypto.subtle.deriveKey(
372
- {
373
- name: "HKDF",
374
- salt: new TextEncoder().encode("cookie-encryption"),
375
- info: new TextEncoder().encode("aes-256-gcm"),
376
- hash: "SHA-256",
377
- },
378
- keyMaterial,
379
- { name: "AES-GCM", length: 256 },
380
- false,
381
- ["decrypt"],
382
- ),
383
- catch: (error) => error,
384
- })
385
-
386
- // Use functions with pre-derived keys
387
- const encrypted = yield* EncryptedCookies.encrypt(testValue, {
388
- key: encryptKey,
389
- })
390
- const decrypted = yield* EncryptedCookies.decrypt(encrypted, {
391
- key: decryptKey,
392
- })
393
-
394
- return { encrypted, decrypted }
395
- })
396
-
397
- const result = await Effect.runPromise(program)
398
-
399
- test
400
- .expect(result.decrypted)
401
- .toBe(testValue)
402
- test
403
- .expect(result.encrypted)
404
- .not
405
- .toBe(testValue)
406
- test
407
- .expect(result.encrypted.split("."))
408
- .toHaveLength(3)
409
- })
410
- })
411
-
412
- test.describe("layerConfig", () => {
413
- test.test("succeed with valid SECRET_KEY_BASE", async () => {
414
- const validSecret = "a".repeat(40)
415
-
416
- const program = Effect.gen(function*() {
417
- const service = yield* EncryptedCookies.EncryptedCookies
418
- const encrypted = yield* service.encrypt("test")
419
- const decrypted = yield* service.decrypt(encrypted)
420
- return decrypted
421
- })
422
-
423
- const result = await Effect.runPromise(
424
- program.pipe(
425
- Effect.provide(
426
- EncryptedCookies.layerConfig("SECRET_KEY_BASE"),
427
- ),
428
- Effect.withConfigProvider(
429
- ConfigProvider.fromMap(
430
- new Map([["SECRET_KEY_BASE", validSecret]]),
431
- ),
432
- ),
433
- ),
434
- )
435
-
436
- test
437
- .expect(result)
438
- .toBe("test")
439
- })
440
-
441
- test.test("fail with short SECRET_KEY_BASE", async () => {
442
- const shortSecret = "short"
443
-
444
- const program = Effect.gen(function*() {
445
- const service = yield* EncryptedCookies.EncryptedCookies
446
- return yield* service.encrypt("test")
447
- })
448
-
449
- test
450
- .expect(
451
- Effect.runPromise(
452
- program.pipe(
453
- Effect.provide(
454
- EncryptedCookies.layerConfig("SECRET_KEY_BASE"),
455
- ),
456
- Effect.withConfigProvider(
457
- ConfigProvider.fromMap(
458
- new Map([["SECRET_KEY_BASE", shortSecret]]),
459
- ),
460
- ),
461
- ),
462
- ),
463
- )
464
- .rejects
465
- .toThrow("SECRET_KEY_BASE must be at least 40 characters")
466
- })
467
-
468
- test.test("fail with missing SECRET_KEY_BASE", async () => {
469
- const program = Effect.gen(function*() {
470
- const service = yield* EncryptedCookies.EncryptedCookies
471
- return yield* service.encrypt("test")
472
- })
473
-
474
- test
475
- .expect(
476
- Effect.runPromise(
477
- program.pipe(
478
- Effect.provide(
479
- EncryptedCookies.layerConfig("SECRET_KEY_BASE"),
480
- ),
481
- Effect.withConfigProvider(ConfigProvider.fromMap(new Map())),
482
- ),
483
- ),
484
- )
485
- .rejects
486
- .toThrow("SECRET_KEY_BASE must be at least 40 characters")
487
- })
488
- })
@@ -1,209 +0,0 @@
1
- import * as test from "bun:test"
2
- import * as HyperHtml from "./HyperHtml.ts"
3
- import * as HyperNode from "./HyperNode.ts"
4
-
5
- test.it("boolean true attributes render without value (React-like)", () => {
6
- const node = HyperNode.make("div", {
7
- hidden: true,
8
- disabled: true,
9
- "data-active": true,
10
- })
11
-
12
- const html = HyperHtml.renderToString(node)
13
-
14
- test
15
- .expect(html)
16
- .toBe("<div hidden disabled data-active></div>")
17
- })
18
-
19
- test.it("boolean false attributes are omitted", () => {
20
- const node = HyperNode.make("div", {
21
- hidden: false,
22
- disabled: false,
23
- "data-active": false,
24
- })
25
-
26
- const html = HyperHtml.renderToString(node)
27
-
28
- test
29
- .expect(html)
30
- .toBe("<div></div>")
31
- })
32
-
33
- test.it("string attributes render with values", () => {
34
- const node = HyperNode.make("div", {
35
- id: "test",
36
- class: "my-class",
37
- "data-value": "hello",
38
- })
39
-
40
- const html = HyperHtml.renderToString(node)
41
-
42
- test
43
- .expect(html)
44
- .toBe("<div id=\"test\" class=\"my-class\" data-value=\"hello\"></div>")
45
- })
46
-
47
- test.it("number attributes render with values", () => {
48
- const node = HyperNode.make("input", {
49
- type: "number",
50
- min: 0,
51
- max: 100,
52
- value: 50,
53
- })
54
-
55
- const html = HyperHtml.renderToString(node)
56
-
57
- test
58
- .expect(html)
59
- .toBe("<input type=\"number\" min=\"0\" max=\"100\" value=\"50\">")
60
- })
61
-
62
- test.it("null and undefined attributes are omitted", () => {
63
- const node = HyperNode.make("div", {
64
- id: null,
65
- class: undefined,
66
- "data-test": "value",
67
- })
68
-
69
- const html = HyperHtml.renderToString(node)
70
-
71
- test
72
- .expect(html)
73
- .toBe("<div data-test=\"value\"></div>")
74
- })
75
-
76
- test.it("mixed boolean and string attributes", () => {
77
- const node = HyperNode.make("input", {
78
- type: "checkbox",
79
- checked: true,
80
- disabled: false,
81
- name: "test",
82
- value: "on",
83
- })
84
-
85
- const html = HyperHtml.renderToString(node)
86
-
87
- test
88
- .expect(html)
89
- .toBe("<input type=\"checkbox\" checked name=\"test\" value=\"on\">")
90
- })
91
-
92
- test.it("data-* attributes with object values are JSON stringified", () => {
93
- const node = HyperNode.make("div", {
94
- "data-signals": {
95
- draft: "",
96
- pendingDraft: "",
97
- username: "User123",
98
- },
99
- })
100
-
101
- const html = HyperHtml.renderToString(node)
102
-
103
- test
104
- .expect(html)
105
- .toBe(
106
- "<div data-signals=\"{&quot;draft&quot;:&quot;&quot;,&quot;pendingDraft&quot;:&quot;&quot;,&quot;username&quot;:&quot;User123&quot;}\"></div>",
107
- )
108
- })
109
-
110
- test.it("data-* attributes with array values are JSON stringified", () => {
111
- const node = HyperNode.make("div", {
112
- "data-items": [1, 2, 3],
113
- })
114
-
115
- const html = HyperHtml.renderToString(node)
116
-
117
- test
118
- .expect(html)
119
- .toBe("<div data-items=\"[1,2,3]\"></div>")
120
- })
121
-
122
- test.it("data-* attributes with nested object values", () => {
123
- const node = HyperNode.make("div", {
124
- "data-config": {
125
- user: { name: "John", active: true },
126
- settings: { theme: "dark" },
127
- },
128
- })
129
-
130
- const html = HyperHtml.renderToString(node)
131
-
132
- test
133
- .expect(html)
134
- .toBe(
135
- "<div data-config=\"{&quot;user&quot;:{&quot;name&quot;:&quot;John&quot;,&quot;active&quot;:true},&quot;settings&quot;:{&quot;theme&quot;:&quot;dark&quot;}}\"></div>",
136
- )
137
- })
138
-
139
- test.it("data-* string values are not JSON stringified", () => {
140
- const node = HyperNode.make("div", {
141
- "data-value": "hello world",
142
- })
143
-
144
- const html = HyperHtml.renderToString(node)
145
-
146
- test
147
- .expect(html)
148
- .toBe("<div data-value=\"hello world\"></div>")
149
- })
150
-
151
- test.it("non-data attributes with object values are not JSON stringified", () => {
152
- const node = HyperNode.make("div", {
153
- style: "color: red",
154
- })
155
-
156
- const html = HyperHtml.renderToString(node)
157
-
158
- test
159
- .expect(html)
160
- .toBe("<div style=\"color: red\"></div>")
161
- })
162
-
163
- test.it("script with function child renders as IIFE", () => {
164
- const handler = (window: Window) => {
165
- console.log("Hello from", window.document.title)
166
- }
167
-
168
- const node = HyperNode.make("script", {
169
- children: handler,
170
- })
171
-
172
- const html = HyperHtml.renderToString(node)
173
-
174
- test
175
- .expect(html)
176
- .toBe(`<script>(${handler.toString()})(window)</script>`)
177
- })
178
-
179
- test.it("script with arrow function child renders as IIFE", () => {
180
- const node = HyperNode.make("script", {
181
- children: (window: Window) => {
182
- window.alert("test")
183
- },
184
- })
185
-
186
- const html = HyperHtml.renderToString(node)
187
-
188
- test
189
- .expect(html)
190
- .toContain("<script>(")
191
- test
192
- .expect(html)
193
- .toContain(")(window)</script>")
194
- test
195
- .expect(html)
196
- .toContain("window.alert")
197
- })
198
-
199
- test.it("script with string child renders normally", () => {
200
- const node = HyperNode.make("script", {
201
- children: "console.log('hello')",
202
- })
203
-
204
- const html = HyperHtml.renderToString(node)
205
-
206
- test
207
- .expect(html)
208
- .toBe("<script>console.log(&apos;hello&apos;)</script>")
209
- })