node-turbo 1.1.1 → 1.2.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.
- package/.mocharc.json +1 -2
- package/README.md +14 -10
- package/docs/API.md +5 -29
- package/lib/turbo-stream.js +33 -3
- package/package.json +9 -11
- package/test/chai.js +8 -0
- package/test/integration/express.test.js +1 -1
- package/test/integration/koa.test.js +1 -1
- package/test/integration/sse.test.js +1 -1
- package/test/integration/ws.test.js +1 -1
- package/test/unit/core/request-helpers.test.js +1 -1
- package/test/unit/core/turbo-element.test.js +1 -1
- package/test/unit/core/turbo-frame.test.js +1 -1
- package/test/unit/core/turbo-readable.test.js +5 -8
- package/test/unit/core/turbo-stream-element.test.js +1 -1
- package/test/unit/core/turbo-stream.test.js +99 -28
- package/test/unit/express/express-turbo-stream.test.js +2 -5
- package/test/unit/express/turbocharge-express.test.js +2 -4
- package/test/unit/koa/koa-turbo-stream.test.js +1 -1
- package/test/unit/koa/turbocharge-koa.test.js +3 -7
- package/test/unit/sse/sse-turbo-stream.test.js +1 -1
- package/test/unit/ws/ws-turbo-stream.test.js +3 -5
package/.mocharc.json
CHANGED
package/README.md
CHANGED
|
@@ -51,12 +51,12 @@ This module has been built for Node.js only and does not work in the browser (no
|
|
|
51
51
|
node-turbo as been written as an ECMAScript module and all examples will use ES module syntax. If you want to use node-turbo within a CommonJS application, use dynamic [`import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) instead of `require()`.
|
|
52
52
|
|
|
53
53
|
### Tested
|
|
54
|
-
node-turbo has been tested with:
|
|
54
|
+
node-turbo has been tested with 100% code coverage with the following engines/libraries:
|
|
55
55
|
|
|
56
56
|
| Name | Version(s) |
|
|
57
57
|
| :--- | :--- |
|
|
58
58
|
| [Node.js](https://nodejs.org/) | 16.6 - 21.5.0 |
|
|
59
|
-
| [Hotwire Turbo](https://turbo.hotwired.dev/) | 7.3.0 - 8.0.
|
|
59
|
+
| [Hotwire Turbo](https://turbo.hotwired.dev/) | 7.3.0 - 8.0.5 |
|
|
60
60
|
| [Koa](https://koajs.com/) | 2.14.2 - 2.15.3 |
|
|
61
61
|
| [Express](https://expressjs.com/) | 4.18.2 - 4.19.2 |
|
|
62
62
|
| [ws](https://github.com/websockets/ws) | 8.15.1 - 8.18.0 |
|
|
@@ -92,7 +92,7 @@ This will render the following HTML fragment:
|
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
##### Action shortcut functions
|
|
95
|
-
For all supported [official actions](https://turbo.hotwired.dev/handbook/streams#stream-messages-and-actions) (`append`, `prepend`, `replace`, `update`, `remove`, `before`, `after
|
|
95
|
+
For all supported [official actions](https://turbo.hotwired.dev/handbook/streams#stream-messages-and-actions) (`append`, `prepend`, `replace`, `update`, `remove`, `before`, `after` and `refresh`), there are chainable shortcut functions:
|
|
96
96
|
|
|
97
97
|
```javascript
|
|
98
98
|
import { TurboStream } from 'node-turbo';
|
|
@@ -122,6 +122,10 @@ Result:
|
|
|
122
122
|
</turbo-stream>
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
+
> [!NOTE]
|
|
126
|
+
> There briefly was a `morph` action, which node-turbo supported since version 1.0.1. This action has been removed from Hotwire Turbo and its functionality integrated into the `update` and `replace` actions (when used with attribute `method="morph"`). Therefore the action shortcut functions `morph()` and `morphAll()` have been deprecated and will likely be removed in the future.
|
|
127
|
+
|
|
128
|
+
|
|
125
129
|
##### Additional attributes
|
|
126
130
|
If you want/need to add additional attributes to an Turbo Stream element, you can always pass an object instead of the target ID string. Attributes with value `null` will be rendered as boolean attributes.
|
|
127
131
|
|
|
@@ -129,10 +133,10 @@ If you want/need to add additional attributes to an Turbo Stream element, you ca
|
|
|
129
133
|
import { TurboStream } from 'node-turbo';
|
|
130
134
|
|
|
131
135
|
const ts = new TurboStream()
|
|
132
|
-
.
|
|
136
|
+
.update({
|
|
133
137
|
target: 'target-id',
|
|
134
|
-
'
|
|
135
|
-
custom:
|
|
138
|
+
method: 'morph',
|
|
139
|
+
custom: null
|
|
136
140
|
},
|
|
137
141
|
'<p>My content</p>');
|
|
138
142
|
|
|
@@ -142,7 +146,7 @@ const html = ts.render();
|
|
|
142
146
|
Result:
|
|
143
147
|
|
|
144
148
|
```html
|
|
145
|
-
<turbo-stream action="
|
|
149
|
+
<turbo-stream action="update" target="target-id" method="morph" custom>
|
|
146
150
|
<template>
|
|
147
151
|
<p>My content</p>
|
|
148
152
|
</template>
|
|
@@ -150,7 +154,7 @@ Result:
|
|
|
150
154
|
```
|
|
151
155
|
|
|
152
156
|
##### Target multiple elements
|
|
153
|
-
If you want to [target multiple elements](https://turbo.hotwired.dev/handbook/streams#actions-with-multiple-targets), you can use the `[action]All()` function (not available
|
|
157
|
+
If you want to [target multiple elements](https://turbo.hotwired.dev/handbook/streams#actions-with-multiple-targets), you can use the `[action]All()` function (not available for the `refresh` action):
|
|
154
158
|
|
|
155
159
|
```javascript
|
|
156
160
|
import { TurboStream } from 'node-turbo';
|
|
@@ -283,7 +287,7 @@ import { isTurboStreamRequest } from 'node-turbo';
|
|
|
283
287
|
|
|
284
288
|
const isTsReq = isTurboStreamRequest(req);
|
|
285
289
|
```
|
|
286
|
-
Checks if the request is a Turbo Stream request by looking if the HTTP header `Accept` includes the MIME type `text/vnd.turbo-stream.html`. Expects an object like an http.ClientRequest instance but
|
|
290
|
+
Checks if the request is a Turbo Stream request by looking if the HTTP header `Accept` includes the MIME type `text/vnd.turbo-stream.html`. Expects an object like an http.ClientRequest instance but does not make any hard checks. Returns `true` or `false`.
|
|
287
291
|
|
|
288
292
|
##### isTurboFrameRequest(request)
|
|
289
293
|
```javascript
|
|
@@ -299,7 +303,7 @@ import { getTurboFrameId } from 'node-turbo';
|
|
|
299
303
|
|
|
300
304
|
const tfId = getTurboFrameId(req);
|
|
301
305
|
```
|
|
302
|
-
Returns the content of the HTTP header `turbo-frame`, which holds the ID of the Turbo Frame which made the request. Expects an object like an `http.ClientRequest` instance but
|
|
306
|
+
Returns the content of the HTTP header `turbo-frame`, which holds the ID of the Turbo Frame which made the request. Expects an object like an `http.ClientRequest` instance but does not make any hard checks.
|
|
303
307
|
|
|
304
308
|
### Koa
|
|
305
309
|
You can add convencience functions to your Koa application by calling `turbochargeKoa(app)`. This adds the following functions to Koa's `context`:
|
package/docs/API.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# node-turbo API documentation
|
|
2
2
|
|
|
3
|
-
Version 1.
|
|
3
|
+
Version 1.2.0
|
|
4
4
|
|
|
5
5
|
## Table of Contents
|
|
6
6
|
|
|
@@ -284,9 +284,7 @@ Returns: {stream.Readable | TurboReadable} Either a readable stream or a TurboRe
|
|
|
284
284
|
|
|
285
285
|
#### turbostream.append(targetOrAttributes, content)
|
|
286
286
|
|
|
287
|
-
|
|
288
287
|
- `targetOrAttributes` {String | Object<String.String>} Either the target ID as string or all attributes as object.
|
|
289
|
-
|
|
290
288
|
- `content` {String} The HTML content of the element.
|
|
291
289
|
Adds a Turbo Stream element with the action `append` to the message.
|
|
292
290
|
|
|
@@ -294,9 +292,7 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
294
292
|
|
|
295
293
|
#### turbostream.appendAll(targetsOrAttributes, content)
|
|
296
294
|
|
|
297
|
-
|
|
298
295
|
- `targetsOrAttributes` {String | Object<String.String>} Either the query targeting multiple DOM elements as string or all attributes as object.
|
|
299
|
-
|
|
300
296
|
- `content` {String} The HTML content of the element.
|
|
301
297
|
Adds a Turbo Stream element with the action `append` to the message.
|
|
302
298
|
|
|
@@ -304,9 +300,7 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
304
300
|
|
|
305
301
|
#### turbostream.prepend(targetOrAttributes, content)
|
|
306
302
|
|
|
307
|
-
|
|
308
303
|
- `targetOrAttributes` {String | Object<String.String>} Either the target ID as string or all attributes as object.
|
|
309
|
-
|
|
310
304
|
- `content` {String} The HTML content of the element.
|
|
311
305
|
Adds a Turbo Stream element with the action `prepend` to the message.
|
|
312
306
|
|
|
@@ -314,9 +308,7 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
314
308
|
|
|
315
309
|
#### turbostream.prependAll(targetsOrAttributes, content)
|
|
316
310
|
|
|
317
|
-
|
|
318
311
|
- `targetsOrAttributes` {String | Object<String.String>} Either the query targeting multiple DOM elements as string or all attributes as object.
|
|
319
|
-
|
|
320
312
|
- `content` {String} The HTML content of the element.
|
|
321
313
|
Adds a Turbo Stream element with the action `prepend` to the message.
|
|
322
314
|
|
|
@@ -324,9 +316,7 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
324
316
|
|
|
325
317
|
#### turbostream.replace(targetOrAttributes, content)
|
|
326
318
|
|
|
327
|
-
|
|
328
319
|
- `targetOrAttributes` {String | Object<String.String>} Either the target ID as string or all attributes as object.
|
|
329
|
-
|
|
330
320
|
- `content` {String} The HTML content of the element.
|
|
331
321
|
Adds a Turbo Stream element with the action `replace` to the message.
|
|
332
322
|
|
|
@@ -334,9 +324,7 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
334
324
|
|
|
335
325
|
#### turbostream.replaceAll(targetsOrAttributes, content)
|
|
336
326
|
|
|
337
|
-
|
|
338
327
|
- `targetsOrAttributes` {String | Object<String.String>} Either the query targeting multiple DOM elements as string or all attributes as object.
|
|
339
|
-
|
|
340
328
|
- `content` {String} The HTML content of the element.
|
|
341
329
|
Adds a Turbo Stream element with the action `replace` to the message.
|
|
342
330
|
|
|
@@ -344,9 +332,7 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
344
332
|
|
|
345
333
|
#### turbostream.update(targetOrAttributes, content)
|
|
346
334
|
|
|
347
|
-
|
|
348
335
|
- `targetOrAttributes` {String | Object<String.String>} Either the target ID as string or all attributes as object.
|
|
349
|
-
|
|
350
336
|
- `content` {String} The HTML content of the element.
|
|
351
337
|
Adds a Turbo Stream element with the action `update` to the message.
|
|
352
338
|
|
|
@@ -354,9 +340,7 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
354
340
|
|
|
355
341
|
#### turbostream.updateAll(targetsOrAttributes, content)
|
|
356
342
|
|
|
357
|
-
|
|
358
343
|
- `targetsOrAttributes` {String | Object<String.String>} Either the query targeting multiple DOM elements as string or all attributes as object.
|
|
359
|
-
|
|
360
344
|
- `content` {String} The HTML content of the element.
|
|
361
345
|
Adds a Turbo Stream element with the action `update` to the message.
|
|
362
346
|
|
|
@@ -364,7 +348,6 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
364
348
|
|
|
365
349
|
#### turbostream.remove(targetOrAttributes)
|
|
366
350
|
|
|
367
|
-
|
|
368
351
|
- `targetOrAttributes` {String | Object<String.String>} Either the target ID as string or all attributes as object.
|
|
369
352
|
|
|
370
353
|
Adds a Turbo Stream element with the action `remove` to the message.
|
|
@@ -373,7 +356,6 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
373
356
|
|
|
374
357
|
#### turbostream.removeAll(targetsOrAttributes)
|
|
375
358
|
|
|
376
|
-
|
|
377
359
|
- `targetsOrAttributes` {String | Object<String.String>} Either the query targeting multiple DOM elements as string or all attributes as object.
|
|
378
360
|
|
|
379
361
|
Adds a Turbo Stream element with the action `remove` to the message.
|
|
@@ -382,9 +364,7 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
382
364
|
|
|
383
365
|
#### turbostream.before(targetOrAttributes, content)
|
|
384
366
|
|
|
385
|
-
|
|
386
367
|
- `targetOrAttributes` {String | Object<String.String>} Either the target ID as string or all attributes as object.
|
|
387
|
-
|
|
388
368
|
- `content` {String} The HTML content of the element.
|
|
389
369
|
Adds a Turbo Stream element with the action `before` to the message.
|
|
390
370
|
|
|
@@ -392,9 +372,7 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
392
372
|
|
|
393
373
|
#### turbostream.beforeAll(targetsOrAttributes, content)
|
|
394
374
|
|
|
395
|
-
|
|
396
375
|
- `targetsOrAttributes` {String | Object<String.String>} Either the query targeting multiple DOM elements as string or all attributes as object.
|
|
397
|
-
|
|
398
376
|
- `content` {String} The HTML content of the element.
|
|
399
377
|
Adds a Turbo Stream element with the action `before` to the message.
|
|
400
378
|
|
|
@@ -402,9 +380,7 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
402
380
|
|
|
403
381
|
#### turbostream.after(targetOrAttributes, content)
|
|
404
382
|
|
|
405
|
-
|
|
406
383
|
- `targetOrAttributes` {String | Object<String.String>} Either the target ID as string or all attributes as object.
|
|
407
|
-
|
|
408
384
|
- `content` {String} The HTML content of the element.
|
|
409
385
|
Adds a Turbo Stream element with the action `after` to the message.
|
|
410
386
|
|
|
@@ -412,9 +388,7 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
412
388
|
|
|
413
389
|
#### turbostream.afterAll(targetsOrAttributes, content)
|
|
414
390
|
|
|
415
|
-
|
|
416
391
|
- `targetsOrAttributes` {String | Object<String.String>} Either the query targeting multiple DOM elements as string or all attributes as object.
|
|
417
|
-
|
|
418
392
|
- `content` {String} The HTML content of the element.
|
|
419
393
|
Adds a Turbo Stream element with the action `after` to the message.
|
|
420
394
|
|
|
@@ -422,9 +396,10 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
422
396
|
|
|
423
397
|
#### turbostream.morph(targetOrAttributes, content)
|
|
424
398
|
|
|
399
|
+
> [!WARNING]
|
|
400
|
+
> Deprecated since v1.2.0! Use `update()` or `replace()` with attribute `{ method: 'morph' }` instead.
|
|
425
401
|
|
|
426
402
|
- `targetOrAttributes` {String | Object<String.String>} Either the target ID as string or all attributes as object.
|
|
427
|
-
|
|
428
403
|
- `content` {String} The HTML content of the element.
|
|
429
404
|
Adds a Turbo Stream element with the action `morph` to the message.
|
|
430
405
|
|
|
@@ -432,9 +407,10 @@ Returns: {TurboStream} The instance for chaining.
|
|
|
432
407
|
|
|
433
408
|
#### turbostream.morphAll(targetsOrAttributes, content)
|
|
434
409
|
|
|
410
|
+
> [!WARNING]
|
|
411
|
+
> Deprecated since v1.2.0! Use `updateAll()` or `replaceAll()` with attribute `{ method: 'morph' }` instead.
|
|
435
412
|
|
|
436
413
|
- `targetsOrAttributes` {String | Object<String.String>} Either the query targeting multiple DOM elements as string or all attributes as object.
|
|
437
|
-
|
|
438
414
|
- `content` {String} The HTML content of the element.
|
|
439
415
|
Adds a Turbo Stream element with the action `morph` to the message.
|
|
440
416
|
|
package/lib/turbo-stream.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { EventEmitter } from 'node:events';
|
|
3
3
|
import { TurboStreamElement, TurboReadable } from '#core';
|
|
4
4
|
import { Writable, Readable } from 'node:stream';
|
|
5
|
+
import { deprecate } from 'node:util';
|
|
5
6
|
import db from 'debug';
|
|
6
7
|
const debug = db('node-turbo:turbostream');
|
|
7
8
|
|
|
@@ -48,8 +49,7 @@ export class TurboStream extends EventEmitter {
|
|
|
48
49
|
|
|
49
50
|
/**
|
|
50
51
|
* List of all supported official actions:
|
|
51
|
-
* `append`, `prepend`, `replace`, `update`, `remove`, `before`, `after`
|
|
52
|
-
* and `refresh`.
|
|
52
|
+
* `append`, `prepend`, `replace`, `update`, `remove`, `before`, `after` and `refresh`.
|
|
53
53
|
*
|
|
54
54
|
* @see https://turbo.hotwired.dev/handbook/streams#stream-messages-and-actions
|
|
55
55
|
* @type {Array}
|
|
@@ -64,7 +64,6 @@ export class TurboStream extends EventEmitter {
|
|
|
64
64
|
'remove',
|
|
65
65
|
'before',
|
|
66
66
|
'after',
|
|
67
|
-
'morph',
|
|
68
67
|
'refresh'
|
|
69
68
|
];
|
|
70
69
|
|
|
@@ -80,6 +79,37 @@ export class TurboStream extends EventEmitter {
|
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Adds a Turbo Stream Element with the action 'morph' to the message.
|
|
84
|
+
*
|
|
85
|
+
* @param {String|Object<String, String>} requestIdOrAttributes - Either the request ID as string or all attributes as an object.
|
|
86
|
+
* @returns {TurboStream} The instance for chaining.
|
|
87
|
+
* @deprecated since version 1.2.0.
|
|
88
|
+
*/
|
|
89
|
+
morph = deprecate((targetOrAttributes, content) => {
|
|
90
|
+
if (typeof targetOrAttributes === 'string') {
|
|
91
|
+
return this.addElement({ action: 'morph', target: targetOrAttributes }, content);
|
|
92
|
+
}
|
|
93
|
+
/* c8 ignore next 3 */
|
|
94
|
+
else {
|
|
95
|
+
return this.addElement(Object.assign({ action: 'morph' }, targetOrAttributes), content);
|
|
96
|
+
}
|
|
97
|
+
}, 'morph() is deprecated. Use refresh() or replace() with attribute { method: "morph" }.');
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Adds a Turbo Stream Element with the action 'morph' to the message.
|
|
102
|
+
*
|
|
103
|
+
* @param {String} targets - The query string targeting multiple DOM elements.
|
|
104
|
+
* @param {String} content - The HTML content of the element.
|
|
105
|
+
* @returns {TurboStream} The instance for chaining.
|
|
106
|
+
* @deprecated since version 1.2.0.
|
|
107
|
+
*/
|
|
108
|
+
morphAll = deprecate((targets, content) => {
|
|
109
|
+
return this.addElement({ action: 'morph', targets }, content);
|
|
110
|
+
}, 'morphAll() is deprecated. Use refreshAll() or replaceAll() with attribute { method: "morph" }.');
|
|
111
|
+
|
|
112
|
+
|
|
83
113
|
/**
|
|
84
114
|
* If `attributes` and `content` are available, a Turbo Stream element is added to the buffer,
|
|
85
115
|
* pending validation.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-turbo",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A library for Node.js to assist with the server side of 37signals' Hotwire Turbo framework. It provides classes and functions for Web servers and also convenience functions for the frameworks Koa and Express as well as for WebSocket and SSE.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node",
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
"#errors": "./lib/errors/index.js"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
|
-
"test": "NODE_ENV=testing mocha --require \"./test/hooks.js\"",
|
|
52
|
-
"test:unit": "NODE_ENV=testing mocha
|
|
53
|
-
"test:integration": "NODE_ENV=testing mocha
|
|
54
|
-
"test:package": "NODE_ENV=testing mocha
|
|
55
|
-
"test:all": "NODE_ENV=testing mocha",
|
|
51
|
+
"test": "NODE_ENV=testing mocha --require \"./test/hooks.js\" \"./test/**/*.test.js\"",
|
|
52
|
+
"test:unit": "NODE_ENV=testing mocha \"./test/unit/**/*.test.js\"",
|
|
53
|
+
"test:integration": "NODE_ENV=testing mocha \"./test/integration/**/*.test.js\"",
|
|
54
|
+
"test:package": "NODE_ENV=testing mocha \"./test/package.test.js\"",
|
|
55
|
+
"test:all": "NODE_ENV=testing mocha \"./test/**/*.test.js\"",
|
|
56
56
|
"test:coverage": "c8 -c './.c8rc.json' npm test",
|
|
57
57
|
"docs": "esdoc -c ./.esdoc.json",
|
|
58
58
|
"postdocs": "cp -f ./docs/internal/API.md ./docs"
|
|
@@ -67,12 +67,10 @@
|
|
|
67
67
|
"@enterthenamehere/esdoc-external-nodejs-plugin": "^2.6.0-dev.1",
|
|
68
68
|
"@enterthenamehere/esdoc-importpath-plugin": "^2.6.0-dev.1",
|
|
69
69
|
"@enterthenamehere/esdoc-standard-plugin": "^2.6.0-dev.2",
|
|
70
|
-
"@hotwired/turbo": "^8.0.
|
|
71
|
-
"@playwright/test": "^1.45.1",
|
|
70
|
+
"@hotwired/turbo": "^8.0.5",
|
|
72
71
|
"@vividvisions/esdoc-api-doc-markdown-plugin": "file:../esdoc-api-doc-markdown-plugin",
|
|
73
72
|
"c8": "^10.1.2",
|
|
74
|
-
"chai": "^
|
|
75
|
-
"chai-eventemitter2": "^0.2.1",
|
|
73
|
+
"chai": "^5.1.1",
|
|
76
74
|
"chai-spies": "^1.1.0",
|
|
77
75
|
"colorette": "^2.0.20",
|
|
78
76
|
"eventsource": "^2.0.2",
|
|
@@ -81,7 +79,7 @@
|
|
|
81
79
|
"koa": "^2.15.3",
|
|
82
80
|
"koa-route": "^4.0.1",
|
|
83
81
|
"koa-static": "^5.0.0",
|
|
84
|
-
"mocha": "^10.
|
|
82
|
+
"mocha": "^10.7.0",
|
|
85
83
|
"node-mocks-http": "^1.15.0",
|
|
86
84
|
"nunjucks": "^3.2.4",
|
|
87
85
|
"supertest": "^7.0.0",
|
package/test/chai.js
ADDED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
import
|
|
3
|
-
import spies from 'chai-spies';
|
|
2
|
+
import { expect, spy } from '../../chai.js';
|
|
4
3
|
import { TurboStream, TurboElement, TurboStreamElement, TurboReadable } from '#core';
|
|
5
4
|
import { Readable } from 'node:stream';
|
|
6
5
|
|
|
7
|
-
chai.use(spies);
|
|
8
|
-
|
|
9
6
|
const attr = {
|
|
10
7
|
action: 'a',
|
|
11
8
|
target: 't'
|
|
@@ -20,12 +17,12 @@ describe('TurboReadable', function() {
|
|
|
20
17
|
|
|
21
18
|
|
|
22
19
|
beforeEach(function() {
|
|
23
|
-
|
|
20
|
+
spy.on(this.readable, 'push');
|
|
24
21
|
});
|
|
25
22
|
|
|
26
23
|
|
|
27
24
|
afterEach(function() {
|
|
28
|
-
|
|
25
|
+
spy.restore(this.readable, 'push');
|
|
29
26
|
});
|
|
30
27
|
|
|
31
28
|
|
|
@@ -73,11 +70,11 @@ describe('TurboReadable', function() {
|
|
|
73
70
|
|
|
74
71
|
it('_destroy() gets called when steam is destroyed', function() {
|
|
75
72
|
const readable = this.ts.createReadableStream();
|
|
76
|
-
|
|
73
|
+
spy.on(readable, '_destroy');
|
|
77
74
|
readable.destroy();
|
|
78
75
|
|
|
79
76
|
expect(readable._destroy).to.have.been.called();
|
|
80
|
-
|
|
77
|
+
spy.restore(readable, '_destroy');
|
|
81
78
|
});
|
|
82
79
|
|
|
83
80
|
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
import
|
|
3
|
-
import eventemitter2 from 'chai-eventemitter2';
|
|
2
|
+
import { expect } from '../../chai.js';
|
|
4
3
|
import { TurboStream, TurboElement, TurboStreamElement, TurboReadable } from '#core';
|
|
5
4
|
import { Readable } from 'node:stream';
|
|
6
5
|
|
|
7
|
-
chai.use(eventemitter2());
|
|
8
|
-
|
|
9
6
|
const attr = {
|
|
10
7
|
action: 'a',
|
|
11
8
|
target: 't'
|
|
@@ -58,10 +55,15 @@ describe('TurboStream', function() {
|
|
|
58
55
|
expect(ts.elements[0].content).to.be.equal('c');
|
|
59
56
|
});
|
|
60
57
|
|
|
61
|
-
|
|
62
58
|
it('emits event \'element\' with Turbo Stream element', function() {
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
return new Promise(resolve => {
|
|
60
|
+
const ts = new TurboStream();
|
|
61
|
+
ts.on('element', (el) => {
|
|
62
|
+
expect(el).to.be.an.instanceof(TurboStreamElement);
|
|
63
|
+
resolve();
|
|
64
|
+
});
|
|
65
|
+
ts.addElement({ action: 'a', target: 't' }, 'c');
|
|
66
|
+
});
|
|
65
67
|
});
|
|
66
68
|
|
|
67
69
|
|
|
@@ -83,9 +85,15 @@ describe('TurboStream', function() {
|
|
|
83
85
|
});
|
|
84
86
|
|
|
85
87
|
|
|
86
|
-
it('emits event \'config\' with config object', function() {
|
|
87
|
-
const ts = new TurboStream()
|
|
88
|
-
|
|
88
|
+
it('emits event \'config\' with config object', async function() {
|
|
89
|
+
const ts = new TurboStream();
|
|
90
|
+
|
|
91
|
+
const result = await new Promise(resolve => {
|
|
92
|
+
ts.on('config', resolve)
|
|
93
|
+
ts.updateConfig({ foo: 'bar' });
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(result).to.deep.equal(ts.config);
|
|
89
97
|
});
|
|
90
98
|
|
|
91
99
|
|
|
@@ -104,9 +112,14 @@ describe('TurboStream', function() {
|
|
|
104
112
|
});
|
|
105
113
|
|
|
106
114
|
it('emits event \'clear\'', function() {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
115
|
+
return new Promise(resolve => {
|
|
116
|
+
const ts = new TurboStream({ action: 'a', target: 't' }, 'c');
|
|
117
|
+
ts.on('clear', () => {
|
|
118
|
+
expect(true).to.be.true;
|
|
119
|
+
resolve();
|
|
120
|
+
});
|
|
121
|
+
ts.clear();
|
|
122
|
+
});
|
|
110
123
|
});
|
|
111
124
|
|
|
112
125
|
it('is chainable', function() {
|
|
@@ -146,11 +159,15 @@ describe('TurboStream', function() {
|
|
|
146
159
|
expect(ts.render()).to.be.null;
|
|
147
160
|
});
|
|
148
161
|
|
|
149
|
-
it('emits event \'render\' with HTML string', function() {
|
|
150
|
-
const
|
|
151
|
-
|
|
162
|
+
it('emits event \'render\' with HTML string', async function() {
|
|
163
|
+
const
|
|
164
|
+
ts = new TurboStream({ action: 'a', target: 't' }, 'c'),
|
|
165
|
+
result = await new Promise(resolve => {
|
|
166
|
+
ts.on('render', resolve);
|
|
167
|
+
ts.render();
|
|
168
|
+
});
|
|
152
169
|
|
|
153
|
-
expect(
|
|
170
|
+
expect(result).to.be.equal('<turbo-stream action="a" target="t"><template>c</template></turbo-stream>');
|
|
154
171
|
});
|
|
155
172
|
});
|
|
156
173
|
|
|
@@ -172,14 +189,20 @@ describe('TurboStream', function() {
|
|
|
172
189
|
expect(html).to.equal('<turbo-stream action="append" target="t"><template>c</template></turbo-stream>');
|
|
173
190
|
});
|
|
174
191
|
|
|
175
|
-
it('emits events \'render\' and \'clear\'', function() {
|
|
176
|
-
|
|
177
|
-
ts = new TurboStream({ action: 'a', target: 't' }, 'c'),
|
|
178
|
-
html = ts.flush();
|
|
192
|
+
it('emits events \'render\' and \'clear\'', async function() {
|
|
193
|
+
let flushHtml;
|
|
179
194
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
195
|
+
const result = await new Promise(resolve => {
|
|
196
|
+
const ts = new TurboStream({ action: 'a', target: 't' }, 'c');
|
|
197
|
+
let resultHtml;
|
|
198
|
+
|
|
199
|
+
ts.on('render', html => resultHtml = html);
|
|
200
|
+
ts.on('clear', resolve(resultHtml));
|
|
201
|
+
|
|
202
|
+
flushHtml = ts.flush();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
expect(result).to.deep.equal(flushHtml);
|
|
183
206
|
});
|
|
184
207
|
});
|
|
185
208
|
|
|
@@ -228,10 +251,11 @@ describe('TurboStream', function() {
|
|
|
228
251
|
});
|
|
229
252
|
|
|
230
253
|
it ('[action]() emits event \'element\'', function() {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
254
|
+
return new Promise(resolve => {
|
|
255
|
+
const ts = new TurboStream();
|
|
256
|
+
ts.on('element', resolve);
|
|
257
|
+
ts.append({ target: 't', foo: 'bar' }, 'c');
|
|
258
|
+
});
|
|
235
259
|
});
|
|
236
260
|
|
|
237
261
|
|
|
@@ -309,6 +333,53 @@ describe('TurboStream', function() {
|
|
|
309
333
|
expect(ts.elements[0].attributes).to.have.property('foo');
|
|
310
334
|
expect(ts.elements[0].attributes.foo).to.equal('bar');
|
|
311
335
|
});
|
|
336
|
+
|
|
337
|
+
// Test deprecated functions.
|
|
338
|
+
describe('Deprecated actions', function() {
|
|
339
|
+
|
|
340
|
+
it ('morph() warns about deprecation.', function() {
|
|
341
|
+
return new Promise(resolve => {
|
|
342
|
+
process.once('warning', err => {
|
|
343
|
+
expect(err).to.be.an('error');
|
|
344
|
+
expect(err.message).to.include('morph() is deprecated');
|
|
345
|
+
resolve();
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
const ts = new TurboStream();
|
|
349
|
+
ts.morph('t', 'c');
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it ('morph() adds TurboElement with action \'morph\'', function() {
|
|
354
|
+
const ts = new TurboStream();
|
|
355
|
+
ts.morph('t', 'c');
|
|
356
|
+
|
|
357
|
+
expect(ts.elements[0] instanceof TurboElement).to.be.true;
|
|
358
|
+
expect(ts.elements[0].attributes.action).to.equal('morph');
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
it ('morphAll() warns about deprecation.', function() {
|
|
362
|
+
return new Promise(resolve => {
|
|
363
|
+
process.once('warning', err => {
|
|
364
|
+
expect(err).to.be.an('error');
|
|
365
|
+
expect(err.message).to.include('morphAll() is deprecated');
|
|
366
|
+
resolve();
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
const ts = new TurboStream();
|
|
370
|
+
ts.morphAll('ts', 'c');
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it ('morphAll() adds TurboElement with action \'morph\'', function() {
|
|
375
|
+
const ts = new TurboStream();
|
|
376
|
+
ts.morphAll('ts', 'c');
|
|
377
|
+
|
|
378
|
+
expect(ts.elements[0] instanceof TurboElement).to.be.true;
|
|
379
|
+
expect(ts.elements[0].attributes.action).to.equal('morph');
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
});
|
|
312
383
|
});
|
|
313
384
|
|
|
314
385
|
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
import
|
|
3
|
-
import spies from 'chai-spies';
|
|
2
|
+
import { expect, spy } from '../../chai.js';
|
|
4
3
|
import { ExpressTurboStream } from '#express';
|
|
5
4
|
import { TurboStream } from '#core';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
const sandbox = chai.spy.sandbox();
|
|
9
|
-
|
|
6
|
+
const sandbox = spy.sandbox();
|
|
10
7
|
|
|
11
8
|
describe('ExpressTurboStream', function() {
|
|
12
9
|
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
|
|
2
|
-
import
|
|
3
|
-
import spies from 'chai-spies';
|
|
2
|
+
import { expect, spy } from '../../chai.js';
|
|
4
3
|
import { turbochargeExpress, ExpressTurboStream } from '#express';
|
|
5
4
|
import { TurboStream } from '#core';
|
|
6
5
|
import { SseTurboStream } from '#sse';
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
const sandbox = chai.spy.sandbox();
|
|
7
|
+
const sandbox = spy.sandbox();
|
|
10
8
|
|
|
11
9
|
describe('turbochargeExpress()', function() {
|
|
12
10
|
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
|
|
2
|
-
import
|
|
3
|
-
import spies from 'chai-spies';
|
|
2
|
+
import { expect, spy } from '../../chai.js';
|
|
4
3
|
import { turbochargeKoa } from '#koa';
|
|
5
4
|
import { TurboStream, TurboReadable } from '#core';
|
|
6
5
|
import { SseTurboStream } from '#sse';
|
|
7
6
|
import { Transform } from 'node:stream';
|
|
8
7
|
|
|
9
|
-
chai.use(spies);
|
|
10
|
-
const sandbox = chai.spy.sandbox();
|
|
11
|
-
|
|
12
8
|
describe('turbochargeKoa()', function() {
|
|
13
9
|
|
|
14
10
|
beforeEach(function() {
|
|
@@ -25,13 +21,13 @@ describe('turbochargeKoa()', function() {
|
|
|
25
21
|
};
|
|
26
22
|
|
|
27
23
|
// sandbox.on(this.mockKoaApp.context.req.socket, ['setTimeout', 'setNoDelay', 'setKeepAlive']);
|
|
28
|
-
|
|
24
|
+
spy.on(this.mockKoaApp.context, 'set');
|
|
29
25
|
});
|
|
30
26
|
|
|
31
27
|
|
|
32
28
|
afterEach(function() {
|
|
33
29
|
// sandbox.restore();
|
|
34
|
-
|
|
30
|
+
spy.restore(this.mockKoaApp.context, 'set');
|
|
35
31
|
});
|
|
36
32
|
|
|
37
33
|
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
import
|
|
3
|
-
import spies from 'chai-spies';
|
|
2
|
+
import { expect, spy } from '../../chai.js';
|
|
4
3
|
import { WsTurboStream } from '#ws';
|
|
5
4
|
import { TurboStream } from '#core';
|
|
6
5
|
|
|
7
|
-
chai.use(spies);
|
|
8
6
|
|
|
9
7
|
// Mock WebSocket instance.
|
|
10
8
|
const mockWs = {
|
|
@@ -16,12 +14,12 @@ const mockWs = {
|
|
|
16
14
|
describe('WsTurboStream', function() {
|
|
17
15
|
|
|
18
16
|
beforeEach(() => {
|
|
19
|
-
|
|
17
|
+
spy.on(mockWs, 'send');
|
|
20
18
|
});
|
|
21
19
|
|
|
22
20
|
|
|
23
21
|
afterEach(() => {
|
|
24
|
-
|
|
22
|
+
spy.restore(mockWs, 'send');
|
|
25
23
|
});
|
|
26
24
|
|
|
27
25
|
|