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,197 +0,0 @@
1
- /** @jsxImportSource effect-start */
2
- import * as test from "bun:test"
3
- import * as Effect from "effect/Effect"
4
- import * as Entity from "../Entity.ts"
5
- import * as Http from "../Http.ts"
6
- import * as Route from "../Route.ts"
7
- import * as RouteHttp from "../RouteHttp.ts"
8
- import * as HyperRoute from "./HyperRoute.ts"
9
-
10
- test.describe("HyperRoute.html", () => {
11
- test.it("renders JSX to HTML string", async () => {
12
- const handler = RouteHttp.toWebHandler(
13
- Route.get(
14
- HyperRoute.html(
15
- <div>
16
- Hello World
17
- </div>,
18
- ),
19
- ),
20
- )
21
-
22
- const response = await Http.fetch(handler, { path: "/" })
23
-
24
- test.expect(response.status).toBe(200)
25
- test.expect(response.headers.get("Content-Type")).toBe("text/html; charset=utf-8")
26
- test.expect(await response.text()).toBe("<div>Hello World</div>")
27
- })
28
-
29
- test.it("renders nested JSX elements", async () => {
30
- const handler = RouteHttp.toWebHandler(
31
- Route.get(
32
- HyperRoute.html(
33
- <div class="container">
34
- <h1>
35
- Title
36
- </h1>
37
- <p>
38
- Paragraph
39
- </p>
40
- </div>,
41
- ),
42
- ),
43
- )
44
-
45
- const response = await Http.fetch(handler, { path: "/" })
46
-
47
- test.expect(await response.text()).toBe(
48
- "<div class=\"container\"><h1>Title</h1><p>Paragraph</p></div>",
49
- )
50
- })
51
-
52
- test.it("renders JSX from Effect", async () => {
53
- const handler = RouteHttp.toWebHandler(
54
- Route.get(
55
- HyperRoute.html(
56
- Effect.succeed(
57
- <span>
58
- From Effect
59
- </span>,
60
- ),
61
- ),
62
- ),
63
- )
64
-
65
- const response = await Http.fetch(handler, { path: "/" })
66
-
67
- test.expect(await response.text()).toBe("<span>From Effect</span>")
68
- })
69
-
70
- test.it("renders JSX from generator function", async () => {
71
- const handler = RouteHttp.toWebHandler(
72
- Route.get(
73
- HyperRoute.html(
74
- Effect.gen(function*() {
75
- const name = yield* Effect.succeed("World")
76
- return (
77
- <div>
78
- Hello {name}
79
- </div>
80
- )
81
- }),
82
- ),
83
- ),
84
- )
85
-
86
- const response = await Http.fetch(handler, { path: "/" })
87
-
88
- test.expect(await response.text()).toBe("<div>Hello World</div>")
89
- })
90
-
91
- test.it("renders JSX from handler function", async () => {
92
- const handler = RouteHttp.toWebHandler(
93
- Route.get(
94
- HyperRoute.html((context) =>
95
- Effect.succeed(
96
- <div>
97
- Request received
98
- </div>,
99
- )
100
- ),
101
- ),
102
- )
103
-
104
- const response = await Http.fetch(handler, { path: "/" })
105
-
106
- test.expect(await response.text()).toBe("<div>Request received</div>")
107
- })
108
-
109
- test.it("renders JSX with dynamic content", async () => {
110
- const items = ["Apple", "Banana", "Cherry"]
111
-
112
- const handler = RouteHttp.toWebHandler(
113
- Route.get(
114
- HyperRoute.html(
115
- <ul>
116
- {items.map((item) => (
117
- <li>
118
- {item}
119
- </li>
120
- ))}
121
- </ul>,
122
- ),
123
- ),
124
- )
125
-
126
- const response = await Http.fetch(handler, { path: "/" })
127
-
128
- test.expect(await response.text()).toBe(
129
- "<ul><li>Apple</li><li>Banana</li><li>Cherry</li></ul>",
130
- )
131
- })
132
-
133
- test.it("handles Entity with JSX body", async () => {
134
- const handler = RouteHttp.toWebHandler(
135
- Route.get(
136
- HyperRoute.html(
137
- Entity.make(
138
- <div>
139
- With Entity
140
- </div>,
141
- { status: 201 },
142
- ),
143
- ),
144
- ),
145
- )
146
-
147
- const response = await Http.fetch(handler, { path: "/" })
148
-
149
- test.expect(response.status).toBe(201)
150
- test.expect(await response.text()).toBe("<div>With Entity</div>")
151
- })
152
-
153
- test.it("renders data-* attributes with object values as JSON", async () => {
154
- const handler = RouteHttp.toWebHandler(
155
- Route.get(
156
- HyperRoute.html(
157
- <div
158
- data-signals={{
159
- draft: "",
160
- pendingDraft: "",
161
- username: "User123",
162
- }}
163
- >
164
- Content
165
- </div>,
166
- ),
167
- ),
168
- )
169
-
170
- const response = await Http.fetch(handler, { path: "/" })
171
-
172
- test.expect(await response.text()).toBe(
173
- "<div data-signals=\"{&quot;draft&quot;:&quot;&quot;,&quot;pendingDraft&quot;:&quot;&quot;,&quot;username&quot;:&quot;User123&quot;}\">Content</div>",
174
- )
175
- })
176
-
177
- test.it("renders script with function child as IIFE", async () => {
178
- const handler = RouteHttp.toWebHandler(
179
- Route.get(
180
- HyperRoute.html(
181
- <script>
182
- {(window) => {
183
- console.log("Hello from", window.document.title)
184
- }}
185
- </script>,
186
- ),
187
- ),
188
- )
189
-
190
- const response = await Http.fetch(handler, { path: "/" })
191
- const text = await response.text()
192
-
193
- test.expect(text).toContain("<script>(")
194
- test.expect(text).toContain(")(window)</script>")
195
- test.expect(text).toContain("window.document.title")
196
- })
197
- })
@@ -1,84 +0,0 @@
1
- import * as HttpServerRequest from "@effect/platform/HttpServerRequest"
2
- import * as HttpServerResponse from "@effect/platform/HttpServerResponse"
3
- import * as test from "bun:test"
4
- import * as Effect from "effect/Effect"
5
- import * as BasicAuthMiddleware from "./BasicAuthMiddleware.js"
6
-
7
- const mockApp = Effect.succeed(
8
- HttpServerResponse.text("OK", { status: 200 }),
9
- )
10
-
11
- const config: BasicAuthMiddleware.BasicAuthConfig = {
12
- username: "admin",
13
- password: "secret",
14
- }
15
-
16
- const runWithAuth = (authHeader: string | undefined) => {
17
- const middleware = BasicAuthMiddleware.make(config)
18
- const wrappedApp = middleware(mockApp)
19
-
20
- const headers: Record<string, string> = {}
21
- if (authHeader !== undefined) {
22
- headers.authorization = authHeader
23
- }
24
-
25
- const mockRequest = HttpServerRequest.fromWeb(
26
- new Request("http://localhost/test", { headers }),
27
- )
28
-
29
- return wrappedApp.pipe(
30
- Effect.provideService(HttpServerRequest.HttpServerRequest, mockRequest),
31
- Effect.runPromise,
32
- )
33
- }
34
-
35
- test.describe("BasicAuthMiddleware", () => {
36
- test.it("returns 401 when no authorization header is present", async () => {
37
- const response = await runWithAuth(undefined)
38
- test
39
- .expect(response.status)
40
- .toBe(401)
41
- test
42
- .expect(response.headers["www-authenticate"])
43
- .toBe("Basic")
44
- })
45
-
46
- test.it("returns 401 when authorization header does not start with Basic", async () => {
47
- const response = await runWithAuth("Bearer token")
48
- test
49
- .expect(response.status)
50
- .toBe(401)
51
- })
52
-
53
- test.it("returns 401 when credentials are invalid", async () => {
54
- const invalidCredentials = btoa("wrong:credentials")
55
- const response = await runWithAuth(`Basic ${invalidCredentials}`)
56
- test
57
- .expect(response.status)
58
- .toBe(401)
59
- })
60
-
61
- test.it("returns 401 when username is wrong", async () => {
62
- const invalidCredentials = btoa("wronguser:secret")
63
- const response = await runWithAuth(`Basic ${invalidCredentials}`)
64
- test
65
- .expect(response.status)
66
- .toBe(401)
67
- })
68
-
69
- test.it("returns 401 when password is wrong", async () => {
70
- const invalidCredentials = btoa("admin:wrongpassword")
71
- const response = await runWithAuth(`Basic ${invalidCredentials}`)
72
- test
73
- .expect(response.status)
74
- .toBe(401)
75
- })
76
-
77
- test.it("passes through to app when credentials are valid", async () => {
78
- const validCredentials = btoa("admin:secret")
79
- const response = await runWithAuth(`Basic ${validCredentials}`)
80
- test
81
- .expect(response.status)
82
- .toBe(200)
83
- })
84
- })
@@ -1,83 +0,0 @@
1
- import * as HttpServerRequest from "@effect/platform/HttpServerRequest"
2
- import * as HttpServerResponse from "@effect/platform/HttpServerResponse"
3
- import * as test from "bun:test"
4
- import * as Effect from "effect/Effect"
5
- import { effectFn } from "./index.ts"
6
- import * as TestHttpClient from "./TestHttpClient.ts"
7
-
8
- const App = Effect.gen(function*() {
9
- const req = yield* HttpServerRequest.HttpServerRequest
10
-
11
- if (req.url == "/") {
12
- return HttpServerResponse.text("Hello, World!")
13
- }
14
-
15
- return HttpServerResponse.text("Not Found", {
16
- status: 404,
17
- })
18
- })
19
-
20
- const AppClient = TestHttpClient.make(App)
21
-
22
- const effect = effectFn()
23
-
24
- test.it("ok", () =>
25
- effect(function*() {
26
- const res = yield* AppClient.get("/")
27
-
28
- test
29
- .expect(res.status)
30
- .toEqual(200)
31
- test
32
- .expect(yield* res.text)
33
- .toEqual("Hello, World!")
34
- }))
35
-
36
- test.it("not found", () =>
37
- effect(function*() {
38
- const res = yield* AppClient.get("/nope")
39
-
40
- test
41
- .expect(res.status)
42
- .toEqual(404)
43
- test
44
- .expect(yield* res.text)
45
- .toEqual("Not Found")
46
- }))
47
-
48
- test.describe("FetchHandler", () => {
49
- const FetchClient = TestHttpClient.make((req) =>
50
- new Response(`Hello from ${req.url}`, { status: 200 })
51
- )
52
-
53
- test.it("works with sync handler", () =>
54
- effect(function*() {
55
- const res = yield* FetchClient.get("/test")
56
-
57
- test
58
- .expect(res.status)
59
- .toEqual(200)
60
- test
61
- .expect(yield* res.text)
62
- .toContain("/test")
63
- }))
64
-
65
- const AsyncFetchClient = TestHttpClient.make(async (req) => {
66
- await Promise.resolve()
67
- return new Response(`Async: ${req.method} ${new URL(req.url).pathname}`, {
68
- status: 201,
69
- })
70
- })
71
-
72
- test.it("works with async handler", () =>
73
- effect(function*() {
74
- const res = yield* AsyncFetchClient.post("/async-path")
75
-
76
- test
77
- .expect(res.status)
78
- .toEqual(201)
79
- test
80
- .expect(yield* res.text)
81
- .toEqual("Async: POST /async-path")
82
- }))
83
- })
@@ -1,51 +0,0 @@
1
- import * as test from "bun:test"
2
- import * as Effect from "effect/Effect"
3
- import * as Ref from "effect/Ref"
4
- import * as TestLogger from "./TestLogger.ts"
5
-
6
- test.it("TestLogger captures log messages", () =>
7
- Effect
8
- .gen(function*() {
9
- const logger = yield* TestLogger.TestLogger
10
-
11
- yield* Effect.logError("This is an error")
12
- yield* Effect.logWarning("This is a warning")
13
- yield* Effect.logInfo("This is info")
14
-
15
- const messages = yield* Ref.get(logger.messages)
16
-
17
- test
18
- .expect(messages)
19
- .toHaveLength(3)
20
- test
21
- .expect(messages[0])
22
- .toContain("[Error]")
23
- test
24
- .expect(messages[0])
25
- .toContain("This is an error")
26
- test
27
- .expect(messages[1])
28
- .toContain("[Warning]")
29
- test
30
- .expect(messages[1])
31
- .toContain("This is a warning")
32
- test
33
- .expect(messages[2])
34
- .toContain("[Info]")
35
- test
36
- .expect(messages[2])
37
- .toContain("This is info")
38
- })
39
- .pipe(Effect.provide(TestLogger.layer()), Effect.runPromise))
40
-
41
- test.it("TestLogger starts with empty messages", () =>
42
- Effect
43
- .gen(function*() {
44
- const logger = yield* TestLogger.TestLogger
45
- const messages = yield* Ref.get(logger.messages)
46
-
47
- test
48
- .expect(messages)
49
- .toHaveLength(0)
50
- })
51
- .pipe(Effect.provide(TestLogger.layer()), Effect.runPromise))
@@ -1,266 +0,0 @@
1
- import * as test from "bun:test"
2
- import * as HyperHtml from "../../hyper/HyperHtml.ts"
3
- import * as HyperNode from "../../hyper/HyperNode.ts"
4
- import { jsx } from "../../hyper/jsx-runtime.ts"
5
- import * as Datastar from "./Datastar.ts"
6
-
7
- test.it("data-signals object serialization", () => {
8
- const node = HyperNode.make("div", {
9
- "data-signals": { foo: 1, bar: { baz: "hello" } } as any,
10
- })
11
-
12
- const html = HyperHtml.renderToString(node, Datastar.HyperHooks)
13
-
14
- test
15
- .expect(html)
16
- .toBe(
17
- "<div data-signals=\"{&quot;foo&quot;:1,&quot;bar&quot;:{&quot;baz&quot;:&quot;hello&quot;}}\"></div>",
18
- )
19
- })
20
-
21
- test.it("data-signals string passthrough", () => {
22
- const node = HyperNode.make("div", {
23
- "data-signals": "$mySignal",
24
- })
25
-
26
- const html = HyperHtml.renderToString(node, Datastar.HyperHooks)
27
-
28
- test
29
- .expect(html)
30
- .toBe("<div data-signals=\"$mySignal\"></div>")
31
- })
32
-
33
- test.it("data-signals-* object serialization", () => {
34
- const node = HyperNode.make("div", {
35
- "data-signals-user": { name: "John", age: 30 } as any,
36
- })
37
-
38
- const html = HyperHtml.renderToString(node, Datastar.HyperHooks)
39
-
40
- test
41
- .expect(html)
42
- .toBe(
43
- "<div data-signals-user=\"{&quot;name&quot;:&quot;John&quot;,&quot;age&quot;:30}\"></div>",
44
- )
45
- })
46
-
47
- test.it("non-data attributes unchanged", () => {
48
- const node = HyperNode.make("div", {
49
- id: "test",
50
- class: "my-class",
51
- "data-text": "$count",
52
- "data-signals": { count: 0 } as any,
53
- })
54
-
55
- const html = HyperHtml.renderToString(node, Datastar.HyperHooks)
56
-
57
- test
58
- .expect(html)
59
- .toContain("id=\"test\"")
60
- test
61
- .expect(html)
62
- .toContain("class=\"my-class\"")
63
- test
64
- .expect(html)
65
- .toContain("data-text=\"$count\"")
66
- test
67
- .expect(html)
68
- .toContain("data-signals=\"{&quot;count&quot;:0}\"")
69
- })
70
-
71
- test.it("null and undefined values ignored", () => {
72
- const node = HyperNode.make("div", {
73
- "data-signals": null,
74
- "data-other": undefined,
75
- })
76
-
77
- const html = HyperHtml.renderToString(node, Datastar.HyperHooks)
78
-
79
- test
80
- .expect(html)
81
- .toBe("<div></div>")
82
- })
83
-
84
- test.it("complex nested objects serialization", () => {
85
- const complexObject = {
86
- user: { name: "John Doe", preferences: { theme: "dark" } },
87
- items: [1, 2, 3],
88
- }
89
-
90
- const node = HyperNode.make("div", {
91
- "data-signals": complexObject as any,
92
- })
93
-
94
- const html = HyperHtml.renderToString(node, Datastar.HyperHooks)
95
-
96
- test
97
- .expect(html)
98
- .toContain("data-signals=")
99
- test
100
- .expect(html)
101
- .toContain("John Doe")
102
- })
103
-
104
- test.it("non-signals data attributes serialized", () => {
105
- const node = HyperNode.make("div", {
106
- "data-class": { hidden: true, visible: false } as any,
107
- "data-style": { color: "red", display: "none" } as any,
108
- "data-show": true as any,
109
- "data-text": "$count",
110
- })
111
-
112
- const html = HyperHtml.renderToString(node, Datastar.HyperHooks)
113
-
114
- test
115
- .expect(html)
116
- .toContain(
117
- "data-class=\"{&quot;hidden&quot;:true,&quot;visible&quot;:false}\"",
118
- )
119
- test
120
- .expect(html)
121
- .toContain(
122
- "data-style=\"{&quot;color&quot;:&quot;red&quot;,&quot;display&quot;:&quot;none&quot;}\"",
123
- )
124
- test
125
- .expect(html)
126
- .toContain("data-show=\"true\"")
127
- test
128
- .expect(html)
129
- .toContain("data-text=\"$count\"")
130
- })
131
-
132
- test.it("data-attr object serialization", () => {
133
- const node = HyperNode.make("div", {
134
- "data-attr": { disabled: true, tabindex: 0 } as any,
135
- })
136
-
137
- const html = HyperHtml.renderToString(node, Datastar.HyperHooks)
138
-
139
- test
140
- .expect(html)
141
- .toBe(
142
- "<div data-attr=\"{&quot;disabled&quot;:true,&quot;tabindex&quot;:0}\"></div>",
143
- )
144
- })
145
-
146
- test.it("boolean attributes converted to strings", () => {
147
- const node = HyperNode.make("div", {
148
- "data-ignore": false as any,
149
- "data-ignore-morph": true as any,
150
- })
151
-
152
- const html = HyperHtml.renderToString(node, Datastar.HyperHooks)
153
-
154
- test
155
- .expect(html)
156
- .not
157
- .toContain("data-ignore=\"")
158
- test
159
- .expect(html)
160
- .toContain("data-ignore-morph")
161
- test
162
- .expect(html)
163
- .not
164
- .toContain("data-ignore-morph=")
165
- })
166
-
167
- test.it("data-ignore attributes only present when true", () => {
168
- const nodeTrue = HyperNode.make("div", {
169
- "data-ignore": true as any,
170
- })
171
-
172
- const nodeFalse = HyperNode.make("div", {
173
- "data-ignore": false as any,
174
- })
175
-
176
- const htmlTrue = HyperHtml.renderToString(nodeTrue, Datastar.HyperHooks)
177
- const htmlFalse = HyperHtml.renderToString(nodeFalse, Datastar.HyperHooks)
178
-
179
- test
180
- .expect(htmlTrue)
181
- .toContain("data-ignore")
182
- test
183
- .expect(htmlTrue)
184
- .not
185
- .toContain("data-ignore=")
186
- test
187
- .expect(htmlFalse)
188
- .not
189
- .toContain("data-ignore")
190
- })
191
-
192
- test.it("dynamic attributes with suffixes", () => {
193
- const node = HyperNode.make("div", {
194
- "data-class-active": "hidden" as any,
195
- "data-attr-tabindex": "5" as any,
196
- "data-style-opacity": "0.5" as any,
197
- })
198
-
199
- const html = HyperHtml.renderToString(node, Datastar.HyperHooks)
200
-
201
- test
202
- .expect(html)
203
- .toContain("data-class-active=\"hidden\"")
204
- test
205
- .expect(html)
206
- .toContain("data-attr-tabindex=\"5\"")
207
- test
208
- .expect(html)
209
- .toContain("data-style-opacity=\"0.5\"")
210
- })
211
-
212
- test.it("JSX with data-signals object", () => {
213
- const node = jsx("div", {
214
- "data-signals": { isOpen: false, count: 42 } as any,
215
- children: "content",
216
- })
217
-
218
- const html = HyperHtml.renderToString(node, Datastar.HyperHooks)
219
-
220
- test
221
- .expect(html)
222
- .toBe(
223
- "<div data-signals=\"{&quot;isOpen&quot;:false,&quot;count&quot;:42}\">content</div>",
224
- )
225
- test
226
- .expect(html)
227
- .not
228
- .toContain("[object Object]")
229
- })
230
-
231
- test.it("JSX component returning element with data-signals", () => {
232
- function TestComponent() {
233
- return jsx("div", {
234
- "data-signals": { isOpen: false } as any,
235
- children: jsx("span", { children: "nested content" }),
236
- })
237
- }
238
-
239
- const node = jsx(TestComponent, {})
240
-
241
- const html = HyperHtml.renderToString(node, Datastar.HyperHooks)
242
-
243
- test
244
- .expect(html)
245
- .toBe(
246
- "<div data-signals=\"{&quot;isOpen&quot;:false}\"><span>nested content</span></div>",
247
- )
248
- test
249
- .expect(html)
250
- .not
251
- .toContain("[object Object]")
252
- })
253
-
254
- test.it("debug hook execution", () => {
255
- const node = jsx("div", {
256
- "data-signals": { isOpen: false, count: 42 } as any,
257
- children: "content",
258
- })
259
-
260
- const html = HyperHtml.renderToString(node, Datastar.HyperHooks)
261
-
262
- test
263
- .expect(html)
264
- .not
265
- .toContain("[object Object]")
266
- })