node-turbo 1.1.1 → 1.2.1

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 CHANGED
@@ -2,6 +2,5 @@
2
2
  "ui": "bdd",
3
3
  "recursive": true,
4
4
  "check-leaks": true,
5
- "parallel": false,
6
- "spec": "./test/**/*.test.js"
5
+ "parallel": false
7
6
  }
package/README.md CHANGED
@@ -51,14 +51,14 @@ 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.4 |
59
+ | [Hotwire Turbo](https://turbo.hotwired.dev/) | 7.3.0 - 8.0.6 |
60
60
  | [Koa](https://koajs.com/) | 2.14.2 - 2.15.3 |
61
- | [Express](https://expressjs.com/) | 4.18.2 - 4.19.2 |
61
+ | [Express](https://expressjs.com/) | 4.18.2 - 4.21.0 |
62
62
  | [ws](https://github.com/websockets/ws) | 8.15.1 - 8.18.0 |
63
63
 
64
64
  ## API docs
@@ -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`, `morph` and `refresh`), there are chainable 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` 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
- .morph({
136
+ .update({
133
137
  target: 'target-id',
134
- 'children-only': null,
135
- custom: 'attribute'
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="morph" target="target-id" children-only custom="attribute">
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 when using the `refresh` action):
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 doesn not make any hard checks. Returns `true` or `false`.
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 doesn not make any hard checks.
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.1.0
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
 
@@ -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.1.1",
3
+ "version": "1.2.1",
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,17 +48,17 @@
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 --ignore \"./test/integration/**\" --ignore \"./test/*\"",
53
- "test:integration": "NODE_ENV=testing mocha --ignore \"./test/unit/**\" --ignore \"./test/*\"",
54
- "test:package": "NODE_ENV=testing mocha --ignore \"./test/unit/**\" --ignore \"./test/integration/**\"",
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"
59
59
  },
60
60
  "dependencies": {
61
- "debug": "^4.3.5",
61
+ "debug": "^4.3.7",
62
62
  "is-plain-object": "^5.0.0",
63
63
  "negotiator": "^0.6.3"
64
64
  },
@@ -67,22 +67,20 @@
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.4",
71
- "@playwright/test": "^1.45.1",
70
+ "@hotwired/turbo": "^8.0.6",
72
71
  "@vividvisions/esdoc-api-doc-markdown-plugin": "file:../esdoc-api-doc-markdown-plugin",
73
72
  "c8": "^10.1.2",
74
- "chai": "^4.4.1",
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",
79
- "express": "^4.19.2",
77
+ "express": "^4.21.0",
80
78
  "git-repo-info": "^2.1.1",
81
79
  "koa": "^2.15.3",
82
80
  "koa-route": "^4.0.1",
83
81
  "koa-static": "^5.0.0",
84
- "mocha": "^10.6.0",
85
- "node-mocks-http": "^1.15.0",
82
+ "mocha": "^10.7.3",
83
+ "node-mocks-http": "^1.16.0",
86
84
  "nunjucks": "^3.2.4",
87
85
  "supertest": "^7.0.0",
88
86
  "ws": "^8.18.0"
package/test/chai.js ADDED
@@ -0,0 +1,8 @@
1
+
2
+ import * as chaiModule from 'chai';
3
+ import chaiSpies from 'chai-spies';
4
+
5
+ const chai = chaiModule.use(chaiSpies);
6
+
7
+ export default chai;
8
+ export const { spy, expect } = chai;
@@ -1,5 +1,5 @@
1
1
 
2
- import { expect } from 'chai';
2
+ import { expect } from '../chai.js';
3
3
  import request from 'supertest';
4
4
  import express from 'express';
5
5
  import { TurboStream, TurboFrame } from '#core';
@@ -1,5 +1,5 @@
1
1
 
2
- import { expect } from 'chai';
2
+ import { expect } from '../chai.js';
3
3
  import request from 'supertest';
4
4
  import Koa from 'koa';
5
5
  import route from 'koa-route';
@@ -1,5 +1,5 @@
1
1
 
2
- import { expect } from 'chai';
2
+ import { expect } from '../chai.js';
3
3
  import request from 'supertest';
4
4
  import Koa from 'koa';
5
5
  import EventSource from 'eventsource';
@@ -1,5 +1,5 @@
1
1
 
2
- import { expect } from 'chai';
2
+ import { expect } from '../chai.js';
3
3
  import request from 'supertest';
4
4
  import { TurboStream } from '#core';
5
5
  import { WsTurboStream } from '#ws';
@@ -1,5 +1,5 @@
1
1
 
2
- import { expect } from 'chai';
2
+ import { expect } from '../../chai.js';
3
3
  import * as hlp from '../../../lib/request-helpers.js';
4
4
  import httpMocks from 'node-mocks-http';
5
5
 
@@ -1,5 +1,5 @@
1
1
 
2
- import { expect } from 'chai';
2
+ import { expect } from '../../chai.js';
3
3
  import { TurboElement } from '#core';
4
4
 
5
5
 
@@ -1,5 +1,5 @@
1
1
 
2
- import { expect } from 'chai';
2
+ import { expect } from '../../chai.js';
3
3
  import { TurboFrame } from '#core';
4
4
  import { AttributeMissingError, AttributeMalformedError } from '#errors';
5
5
 
@@ -1,11 +1,8 @@
1
1
 
2
- import chai, { expect } from 'chai';
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
- chai.spy.on(this.readable, 'push');
20
+ spy.on(this.readable, 'push');
24
21
  });
25
22
 
26
23
 
27
24
  afterEach(function() {
28
- chai.spy.restore(this.readable, 'push');
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
- chai.spy.on(readable, '_destroy');
73
+ spy.on(readable, '_destroy');
77
74
  readable.destroy();
78
75
 
79
76
  expect(readable._destroy).to.have.been.called();
80
- chai.spy.restore(readable, '_destroy');
77
+ spy.restore(readable, '_destroy');
81
78
  });
82
79
 
83
80
 
@@ -1,5 +1,5 @@
1
1
 
2
- import { expect } from 'chai';
2
+ import { expect } from '../../chai.js';
3
3
  import { TurboStreamElement } from '#core';
4
4
 
5
5
  describe('TurboStreamElement', function() {
@@ -1,11 +1,8 @@
1
1
 
2
- import chai, { expect } from 'chai';
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
- const ts = new TurboStream({ action: 'a', target: 't' }, 'c');
64
- expect(ts).to.emit('element', { withArgs: (element) => element instanceof TurboStreamElement });
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().updateConfig({ foo: 'bar' });
88
- expect(ts).to.emit('config', { withArgs: ts.config });
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
- const ts = new TurboStream({ action: 'a', target: 't' }, 'c');
108
- ts.clear();
109
- expect(ts).to.emit('clear');
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 ts = new TurboStream({ action: 'a', target: 't' }, 'c');
151
- const html = ts.render();
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(ts).to.emit('render', { withArgs: html });
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
- const
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
- expect(ts)
181
- .to.emit('render', { withArgs: html })
182
- .to.emit('clear');
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
- const ts = new TurboStream();
232
- ts.append({ target: 't', foo: 'bar' }, 'c');
233
-
234
- expect(ts).to.emit('element');
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 chai, { expect } from 'chai';
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
- chai.use(spies);
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 chai, { expect } from 'chai';
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
- chai.use(spies);
9
- const sandbox = chai.spy.sandbox();
7
+ const sandbox = spy.sandbox();
10
8
 
11
9
  describe('turbochargeExpress()', function() {
12
10
 
@@ -1,5 +1,5 @@
1
1
 
2
- import { expect } from 'chai';
2
+ import { expect } from '../../chai.js';
3
3
  import { KoaTurboStream } from '#koa';
4
4
  import { TurboStream } from '#core';
5
5
 
@@ -1,14 +1,10 @@
1
1
 
2
- import chai, { expect } from 'chai';
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
- chai.spy.on(this.mockKoaApp.context, 'set');
24
+ spy.on(this.mockKoaApp.context, 'set');
29
25
  });
30
26
 
31
27
 
32
28
  afterEach(function() {
33
29
  // sandbox.restore();
34
- chai.spy.restore(this.mockKoaApp.context, 'set');
30
+ spy.restore(this.mockKoaApp.context, 'set');
35
31
  });
36
32
 
37
33
 
@@ -1,5 +1,5 @@
1
1
 
2
- import { expect } from 'chai';
2
+ import { expect } from '../../chai.js';
3
3
  import { SseTurboStream } from '#sse';
4
4
  import { Transform } from 'node:stream';
5
5
 
@@ -1,10 +1,8 @@
1
1
 
2
- import chai, { expect } from 'chai';
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
- chai.spy.on(mockWs, 'send');
17
+ spy.on(mockWs, 'send');
20
18
  });
21
19
 
22
20
 
23
21
  afterEach(() => {
24
- chai.spy.restore(mockWs, 'send');
22
+ spy.restore(mockWs, 'send');
25
23
  });
26
24
 
27
25