node-turbo 1.0.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 (44) hide show
  1. package/.c8rc.json +5 -0
  2. package/.esdoc.json +83 -0
  3. package/.eslintrc.json +10 -0
  4. package/.mocharc.json +7 -0
  5. package/LICENSE +21 -0
  6. package/README.md +620 -0
  7. package/docs/API.md +857 -0
  8. package/lib/errors/index.js +36 -0
  9. package/lib/express/express-turbo-stream.js +41 -0
  10. package/lib/express/index.js +4 -0
  11. package/lib/express/turbocharge-express.js +108 -0
  12. package/lib/index.js +8 -0
  13. package/lib/koa/index.js +4 -0
  14. package/lib/koa/koa-turbo-stream.js +44 -0
  15. package/lib/koa/turbocharge-koa.js +122 -0
  16. package/lib/request-helpers.js +53 -0
  17. package/lib/sse/index.js +3 -0
  18. package/lib/sse/sse-turbo-stream.js +137 -0
  19. package/lib/turbo-element.js +71 -0
  20. package/lib/turbo-frame.js +79 -0
  21. package/lib/turbo-readable.js +125 -0
  22. package/lib/turbo-stream-element.js +67 -0
  23. package/lib/turbo-stream.js +350 -0
  24. package/lib/ws/index.js +4 -0
  25. package/lib/ws/ws-turbo-stream.js +112 -0
  26. package/package.json +75 -0
  27. package/test/hooks.js +46 -0
  28. package/test/integration/express.test.js +137 -0
  29. package/test/integration/koa.test.js +125 -0
  30. package/test/integration/sse.test.js +80 -0
  31. package/test/integration/ws.test.js +155 -0
  32. package/test/package.test.js +68 -0
  33. package/test/unit/core/request-helpers.test.js +97 -0
  34. package/test/unit/core/turbo-element.test.js +15 -0
  35. package/test/unit/core/turbo-frame.test.js +63 -0
  36. package/test/unit/core/turbo-readable.test.js +93 -0
  37. package/test/unit/core/turbo-stream-element.test.js +76 -0
  38. package/test/unit/core/turbo-stream.test.js +308 -0
  39. package/test/unit/express/express-turbo-stream.test.js +39 -0
  40. package/test/unit/express/turbocharge-express.test.js +123 -0
  41. package/test/unit/koa/koa-turbo-stream.test.js +56 -0
  42. package/test/unit/koa/turbocharge-koa.test.js +141 -0
  43. package/test/unit/sse/sse-turbo-stream.test.js +109 -0
  44. package/test/unit/ws/ws-turbo-stream.test.js +46 -0
@@ -0,0 +1,308 @@
1
+
2
+ import chai, { expect } from 'chai';
3
+ import eventemitter2 from 'chai-eventemitter2';
4
+ import { TurboStream, TurboElement, TurboStreamElement, TurboReadable } from '#core';
5
+ import { Readable } from 'node:stream';
6
+
7
+ chai.use(eventemitter2());
8
+
9
+ const attr = {
10
+ action: 'a',
11
+ target: 't'
12
+ };
13
+
14
+ describe('TurboStream', function() {
15
+
16
+ before(function() {
17
+ this.stream = new TurboStream(attr, 'c');
18
+ });
19
+
20
+
21
+ describe('new TurboStream()', function() {
22
+ it('without arguments creates empty TurboStream instance', function() {
23
+ const ts = new TurboStream();
24
+
25
+ expect(ts).to.be.an.instanceof(TurboStream);
26
+ expect(ts.elements).to.be.empty;
27
+ });
28
+
29
+
30
+ it('with arguments adds TurboElement', function() {
31
+ expect(this.stream.elements[0]).to.be.an.instanceof(TurboElement);
32
+ });
33
+ });
34
+
35
+
36
+ describe('addElement()', function() {
37
+ it('addElement(obj, str) adds TurboElement', function() {
38
+ this.stream.addElement({ action: 'a2', target: 't2' }, 'c2');
39
+
40
+ expect(this.stream.elements[1]).to.be.an.instanceof(TurboElement);
41
+ expect(this.stream).to.have.lengthOf(2);
42
+ });
43
+
44
+
45
+ it('addElement(obj, str) assigns correct properties', function() {
46
+ const ts = new TurboStream().addElement({ action: 'a', target: 't' }, 'c');
47
+
48
+ expect(ts.elements[0].attributes).to.be.deep.equal({ action: 'a', target: 't' });
49
+ expect(ts.elements[0].content).to.be.equal('c');
50
+ });
51
+
52
+
53
+ it('addElement(element) adds element', function() {
54
+ const tse = new TurboStreamElement({ action: 'a', target: 't' }, 'c');
55
+ const ts = new TurboStream().addElement(tse);
56
+
57
+ expect(ts.elements[0].attributes).to.be.deep.equal({ action: 'a', target: 't' });
58
+ expect(ts.elements[0].content).to.be.equal('c');
59
+ });
60
+
61
+
62
+ 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 });
65
+ });
66
+
67
+
68
+ it('is chainable', function() {
69
+ const ts = new TurboStream().addElement(attr, 'c');
70
+
71
+ expect(ts).to.be.an.instanceof(TurboStream);
72
+ });
73
+ });
74
+
75
+
76
+ describe('updateConfig()', function() {
77
+ it('updates config object', function() {
78
+ const ts = new TurboStream().updateConfig({ foo: 'bar' });
79
+ expect(ts.config).to.deep.equal({
80
+ buffer: true,
81
+ foo: 'bar'
82
+ });
83
+ });
84
+
85
+
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 });
89
+ });
90
+
91
+
92
+ it('is chainable', function() {
93
+ const ts = new TurboStream().updateConfig({ foo: 'bar' });
94
+ expect(ts).to.be.an.instanceof(TurboStream);
95
+ });
96
+ });
97
+
98
+
99
+ describe('clear()', function() {
100
+ it('removes all elements', function() {
101
+ this.stream.clear();
102
+
103
+ expect(this.stream.elements).to.be.empty;
104
+ });
105
+
106
+ it('emits event \'clear\'', function() {
107
+ const ts = new TurboStream({ action: 'a', target: 't' }, 'c');
108
+ ts.clear();
109
+ expect(ts).to.emit('clear');
110
+ });
111
+
112
+ it('is chainable', function() {
113
+ const ts = new TurboStream(attr, 'c').clear();
114
+
115
+ expect(ts).to.be.an.instanceof(TurboStream);
116
+ });
117
+ });
118
+
119
+
120
+ describe('render()', function() {
121
+ it('creates correct HTML (single element)', function() {
122
+ const ts = new TurboStream(attr, 'c');
123
+
124
+ expect(ts.render()).to.equal('<turbo-stream action="a" target="t"><template>c</template></turbo-stream>');
125
+ });
126
+
127
+
128
+ it('creates correct HTML (multiple elements)', function() {
129
+ const ts = new TurboStream(attr, 'c')
130
+ .addElement({ action: 'a2', target: 't2' }, 'c2');
131
+
132
+ expect(ts.render()).to.equal('<turbo-stream action="a" target="t"><template>c</template></turbo-stream>\n<turbo-stream action="a2" target="t2"><template>c2</template></turbo-stream>');
133
+ });
134
+
135
+
136
+ it('creates correct HTML (additional parameters)', function() {
137
+ const ts = new TurboStream({ action: 'a', target: 't', foo: 'bar' }, 'c');
138
+
139
+ expect(ts.render()).to.equal('<turbo-stream action="a" target="t" foo="bar"><template>c</template></turbo-stream>');
140
+ });
141
+
142
+
143
+ it('returns null if there are no elements', function() {
144
+ const ts = new TurboStream();
145
+
146
+ expect(ts.render()).to.be.null;
147
+ });
148
+
149
+ it('emits event \'render\' with HTML string', function() {
150
+ const ts = new TurboStream({ action: 'a', target: 't' }, 'c');
151
+ const html = ts.render();
152
+
153
+ expect(ts).to.emit('render', { withArgs: html });
154
+ });
155
+ });
156
+
157
+
158
+ describe('flush()', function() {
159
+ it('removes all elements', function() {
160
+ const ts = new TurboStream().append('t', 'c');
161
+ expect(ts.elements).to.not.be.empty;
162
+ ts.flush();
163
+ expect(ts.elements).to.be.empty;
164
+ });
165
+
166
+
167
+ it('returns HTML', function() {
168
+ const
169
+ ts = new TurboStream().append('t', 'c'),
170
+ html = ts.flush();
171
+
172
+ expect(html).to.equal('<turbo-stream action="append" target="t"><template>c</template></turbo-stream>');
173
+ });
174
+
175
+ it('emits events \'render\' and \'clear\'', function() {
176
+ const
177
+ ts = new TurboStream({ action: 'a', target: 't' }, 'c'),
178
+ html = ts.flush();
179
+
180
+ expect(ts)
181
+ .to.emit('render', { withArgs: html })
182
+ .to.emit('clear');
183
+ });
184
+ });
185
+
186
+
187
+ describe('Custom actions', function() {
188
+
189
+ it('custom() adds TurboElement with custom action', function() {
190
+ const ts = new TurboStream().custom('custom-name', 't', 'c');
191
+ expect(ts.elements[0]).to.be.an.instanceof(TurboElement);
192
+ expect(ts.elements[0].attributes.action).to.equal('custom-name');
193
+ });
194
+
195
+
196
+ it('customAll() adds TurboElement with custom action and targets attribute', function() {
197
+ const ts = new TurboStream().customAll('custom-name', '.t', 'c');
198
+ expect(ts.elements[0]).to.be.an.instanceof(TurboElement);
199
+ expect(ts.elements[0].attributes.action).to.equal('custom-name');
200
+ expect(ts.elements[0].attributes.targets).to.equal('.t');
201
+ });
202
+
203
+ });
204
+
205
+
206
+ describe('Action convenience functions', function() {
207
+ it ('[action]() with target string adds correct target attribute', function() {
208
+ const ts = new TurboStream();
209
+ ts.append('t', 'c');
210
+
211
+ expect(ts.elements[0].attributes.target).to.equal('t');
212
+ });
213
+
214
+
215
+ it ('[action]() with attribute object adds correct target attribute', function() {
216
+ const ts = new TurboStream();
217
+ ts.append({ target: 't' }, 'c');
218
+
219
+ expect(ts.elements[0].attributes.target).to.equal('t');
220
+ });
221
+
222
+
223
+ it ('[action]() with attribute object can handle additional attributes', function() {
224
+ const ts = new TurboStream();
225
+ ts.append({ target: 't', foo: 'bar' }, 'c');
226
+
227
+ expect(ts.elements[0].attributes.foo).to.equal('bar');
228
+ });
229
+
230
+ 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');
235
+ });
236
+
237
+
238
+ it ('[action]() is chainable', function() {
239
+ const ts = new TurboStream();
240
+ const res = ts.append('t', 'c');
241
+
242
+ expect(res instanceof TurboStream).to.be.true;
243
+ });
244
+
245
+
246
+ it ('[action]All() is chainable', function() {
247
+ const ts = new TurboStream();
248
+ const res = ts.appendAll('t', 'c');
249
+
250
+ expect(res instanceof TurboStream).to.be.true;
251
+ });
252
+
253
+
254
+ TurboStream.ACTIONS.forEach(action => {
255
+ it (`${action}() adds TurboElement with action \'${action}\'`, function() {
256
+ const ts = new TurboStream();
257
+ ts[action].call(ts, { target: 't' }, 'c');
258
+
259
+ expect(ts.elements[0] instanceof TurboElement).to.be.true;
260
+ expect(ts.elements[0].attributes.action).to.equal(action);
261
+ });
262
+
263
+ if (action === 'remove') {
264
+ it ('remove() correctly omits <template> and content', function() {
265
+ const ts = new TurboStream({ action: 'remove', target: 't' });
266
+
267
+ expect(ts.render()).to.equal('<turbo-stream action="remove" target="t"></turbo-stream>');
268
+ });
269
+ }
270
+
271
+ it (`${action}All() adds TurboElement with action \'${action}\' and targets attribute`, function() {
272
+ const ts = new TurboStream();
273
+ ts[action + 'All'].call(ts, '.t', 'c');
274
+
275
+ expect(ts.elements[0]).to.be.an.instanceof(TurboElement);
276
+ expect(ts.elements[0].attributes.action).to.equal(action);
277
+ expect(ts.elements[0].attributes.targets).to.equal('.t');
278
+ });
279
+ });
280
+
281
+ });
282
+
283
+
284
+ describe('createReadableStream(opts)', function() {
285
+
286
+ it('returns new TurboReadable() when opts.continuous = true', function() {
287
+ const ts = new TurboStream();
288
+ const readable = ts.createReadableStream();
289
+ expect(readable).to.be.an.instanceof(TurboReadable);
290
+ });
291
+
292
+ it('returns new Readable() when opts.continuous = false', function() {
293
+ const ts = new TurboStream().append('t', 'c');
294
+ const readable = ts.createReadableStream({ continuous: false });
295
+ expect(readable).not.to.be.an.instanceof(TurboReadable);
296
+ expect(readable).to.be.an.instanceof(Readable);
297
+ });
298
+
299
+ it('returns new Readable() when opts.continuous = false even if empty', function() {
300
+ const ts = new TurboStream();
301
+ const readable = ts.createReadableStream({ continuous: false });
302
+ expect(readable).not.to.be.an.instanceof(TurboReadable);
303
+ expect(readable).to.be.an.instanceof(Readable);
304
+ });
305
+
306
+ });
307
+
308
+ });
@@ -0,0 +1,39 @@
1
+
2
+ import chai, { expect } from 'chai';
3
+ import spies from 'chai-spies';
4
+ import { ExpressTurboStream } from '#express';
5
+ import { TurboStream } from '#core';
6
+
7
+ chai.use(spies);
8
+ const sandbox = chai.spy.sandbox();
9
+
10
+
11
+ describe('ExpressTurboStream', function() {
12
+
13
+ beforeEach(function() {
14
+ this.response = {};
15
+ sandbox.on(this.response, ['send', 'type']);
16
+ });
17
+
18
+
19
+ afterEach(function() {
20
+ sandbox.restore();
21
+ });
22
+
23
+
24
+ it('send() sets correct Content-Type', function() {
25
+ const kts = new ExpressTurboStream(this.response);
26
+ kts.send();
27
+
28
+ expect(this.response.type).to.have.been.called.with(TurboStream.MIME_TYPE);
29
+ });
30
+
31
+
32
+ it('send() calls res.send()', function() {
33
+ const kts = new ExpressTurboStream(this.response);
34
+
35
+ kts.send();
36
+ expect(this.response.send).to.have.been.called();
37
+ });
38
+
39
+ });
@@ -0,0 +1,123 @@
1
+
2
+ import chai, { expect } from 'chai';
3
+ import spies from 'chai-spies';
4
+ import { turbochargeExpress, ExpressTurboStream } from '#express';
5
+ import { TurboStream } from '#core';
6
+ import { SseTurboStream } from '#sse';
7
+
8
+ chai.use(spies);
9
+ const sandbox = chai.spy.sandbox();
10
+
11
+ describe('turbochargeExpress()', function() {
12
+
13
+ beforeEach(function() {
14
+ this.mockExpressApp = {
15
+ request: {},
16
+ response: {
17
+ req: {
18
+ headers: {
19
+ 'turbo-frame': 'id'
20
+ }
21
+ },
22
+ send: function(content) {
23
+ this.output = content;
24
+ },
25
+ output: ''
26
+ }
27
+ };
28
+
29
+ sandbox.on(this.mockExpressApp.response, ['set', 'flushHeaders', 'on', 'once', 'emit']);
30
+ });
31
+
32
+ afterEach(function() {
33
+ sandbox.restore();
34
+ });
35
+
36
+
37
+ it('adds helper functions to Express\'s request prototype', function() {
38
+ turbochargeExpress(this.mockExpressApp);
39
+
40
+ expect(this.mockExpressApp.request.getTurboFrameId).to.be.a('function');
41
+ expect(this.mockExpressApp.request.isTurboFrameRequest).to.be.a('function');
42
+ expect(this.mockExpressApp.request.isTurboStreamRequest).to.be.a('function');
43
+ });
44
+
45
+
46
+ it('adds turboFrame() to Express\' response prototype', function() {
47
+ turbochargeExpress(this.mockExpressApp);
48
+
49
+ expect(this.mockExpressApp.response.turboFrame).to.be.a('function');
50
+ });
51
+
52
+
53
+ it('adds turboStream() to Express\' response prototype', function() {
54
+ turbochargeExpress(this.mockExpressApp);
55
+
56
+ expect(this.mockExpressApp.response.turboStream).to.be.a('function');
57
+ });
58
+
59
+ it('turboStream() returns TurboStream when autoSend = false', function() {
60
+ turbochargeExpress(this.mockExpressApp, { autoSend: false });
61
+ const ts = this.mockExpressApp.response.turboStream();
62
+
63
+ expect(ts).to.be.instanceof(ExpressTurboStream);
64
+ });
65
+
66
+ describe('turboFrame()', function() {
67
+
68
+ it('turboFrame(str, str) correctly calls response.send()', function() {
69
+ turbochargeExpress(this.mockExpressApp);
70
+ this.mockExpressApp.response.turboFrame('id', 'c');
71
+
72
+ expect(this.mockExpressApp.response.output).to.equal('<turbo-frame id="id">c</turbo-frame>');
73
+ });
74
+
75
+ it('turboFrame(str) correctly retrieves turbo-frame id and calls response.send()', function() {
76
+ turbochargeExpress(this.mockExpressApp);
77
+ // Update the mock Express app so response.req has all added
78
+ // helper functions of request.
79
+ Object.assign(this.mockExpressApp.response.req, this.mockExpressApp.request);
80
+
81
+ this.mockExpressApp.response.turboFrame('c');
82
+ expect(this.mockExpressApp.response.output).to.equal('<turbo-frame id="id">c</turbo-frame>');
83
+ });
84
+
85
+ it('correctly returns HTML when autoSend = false', function() {
86
+ turbochargeExpress(this.mockExpressApp, { autoSend: false });
87
+ const html = this.mockExpressApp.response.turboFrame('id', 'c');
88
+
89
+ expect(html).to.equal('<turbo-frame id="id">c</turbo-frame>');
90
+ });
91
+
92
+ });
93
+
94
+ describe('sseTurboStream()', function() {
95
+
96
+ it('returns SseTurboStream', function() {
97
+ turbochargeExpress(this.mockExpressApp);
98
+ const ssets = this.mockExpressApp.response.sseTurboStream();
99
+
100
+ expect(ssets).to.be.instanceof(SseTurboStream);
101
+ });
102
+
103
+
104
+ it('configures Express for an SSE connection', function() {
105
+ turbochargeExpress(this.mockExpressApp);
106
+ const ssets = this.mockExpressApp.response.sseTurboStream();
107
+
108
+ expect(this.mockExpressApp.response.set).to.have.been.called.with({ 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Content-Type': SseTurboStream.MIME_TYPE });
109
+ expect(this.mockExpressApp.response.flushHeaders).to.have.been.called();
110
+ });
111
+
112
+ it('pipes to response', function() {
113
+ turbochargeExpress(this.mockExpressApp);
114
+ const ssets = this.mockExpressApp.response.sseTurboStream();
115
+
116
+ // Pipe
117
+ expect(this.mockExpressApp.response.on).to.have.been.called();
118
+ });
119
+
120
+
121
+
122
+ });
123
+ });
@@ -0,0 +1,56 @@
1
+
2
+ import { expect } from 'chai';
3
+ import { KoaTurboStream } from '#koa';
4
+ import { TurboStream } from '#core';
5
+
6
+
7
+ describe('KoaTurboStream', function() {
8
+
9
+ beforeEach(function() {
10
+ this.ctx = {
11
+ type: null,
12
+ body: null,
13
+ status: null
14
+ };
15
+ });
16
+
17
+
18
+ // afterEach(function() {
19
+ // });
20
+
21
+
22
+ it('Turbo Stream adds element in constructor', function() {
23
+ const kts = new KoaTurboStream(this.ctx, { action: 'a', target: 't' }, 'c');
24
+
25
+ expect(this.ctx.body).to.not.be.null;
26
+ });
27
+
28
+
29
+ it('Turbo Stream element gets written to ctx.body', function() {
30
+ const equalTs = new TurboStream().append('t', 'c');
31
+ const kts = new KoaTurboStream(this.ctx).append('t', 'c');
32
+
33
+ expect(this.ctx.body).to.not.be.null;
34
+ expect(this.ctx.body.trim()).to.equal(equalTs.render().trim());
35
+ });
36
+
37
+
38
+ it('Turbo Stream elements don\'t get buffered', function() {
39
+ const kts = new KoaTurboStream(this.ctx).append('t', 'c');
40
+
41
+ expect(kts.elements).to.be.empty;
42
+ });
43
+
44
+ it('sets status', function() {
45
+ const kts = new KoaTurboStream(this.ctx);
46
+
47
+ expect(this.ctx.status).to.equal(200);
48
+ });
49
+
50
+ it('sets ctx.body to empty string when not set', function() {
51
+ const kts = new KoaTurboStream(this.ctx);
52
+
53
+ expect(this.ctx.body).to.equal('');
54
+ });
55
+
56
+ });
@@ -0,0 +1,141 @@
1
+
2
+ import chai, { expect } from 'chai';
3
+ import spies from 'chai-spies';
4
+ import { turbochargeKoa } from '#koa';
5
+ import { TurboStream, TurboReadable } from '#core';
6
+ import { SseTurboStream } from '#sse';
7
+ import { Transform } from 'node:stream';
8
+
9
+ chai.use(spies);
10
+ const sandbox = chai.spy.sandbox();
11
+
12
+ describe('turbochargeKoa()', function() {
13
+
14
+ beforeEach(function() {
15
+ this.mockKoaApp = {
16
+ context: {
17
+ compress: null,
18
+ body: null,
19
+ req: {
20
+ headers: {
21
+ 'turbo-frame': 'id'
22
+ }
23
+ }
24
+ }
25
+ };
26
+
27
+ // sandbox.on(this.mockKoaApp.context.req.socket, ['setTimeout', 'setNoDelay', 'setKeepAlive']);
28
+ chai.spy.on(this.mockKoaApp.context, 'set');
29
+ });
30
+
31
+
32
+ afterEach(function() {
33
+ // sandbox.restore();
34
+ chai.spy.restore(this.mockKoaApp.context, 'set');
35
+ });
36
+
37
+
38
+ it('adds helper functions to Koa\'s context prototype', function() {
39
+ turbochargeKoa(this.mockKoaApp);
40
+
41
+ expect(this.mockKoaApp.context.getTurboFrameId).to.be.a('function');
42
+ expect(this.mockKoaApp.context.isTurboFrameRequest).to.be.a('function');
43
+ expect(this.mockKoaApp.context.isTurboStreamRequest).to.be.a('function');
44
+ });
45
+
46
+
47
+ it('adds turboFrame() to Koa\'s context prototype', function() {
48
+ turbochargeKoa(this.mockKoaApp);
49
+
50
+ expect(this.mockKoaApp.context.turboFrame).to.be.a('function');
51
+ });
52
+
53
+
54
+ it('adds turboStream() to Koa\'s context prototype', function() {
55
+ turbochargeKoa(this.mockKoaApp);
56
+
57
+ expect(this.mockKoaApp.context.turboStream).to.be.a('function');
58
+ });
59
+
60
+
61
+ it('adds sseTurboStream() to Koa\'s context prototype', function() {
62
+ turbochargeKoa(this.mockKoaApp);
63
+
64
+ expect(this.mockKoaApp.context.sseTurboStream).to.be.a('function');
65
+ });
66
+
67
+
68
+ it('turboFrame(str, str) correctly writes to context.body', function() {
69
+ turbochargeKoa(this.mockKoaApp);
70
+ this.mockKoaApp.context.turboFrame('id', 'c');
71
+
72
+ expect(this.mockKoaApp.context.body).to.equal('<turbo-frame id="id">c</turbo-frame>');
73
+ });
74
+
75
+
76
+ it('turboFrame(str) correctly retrieves turbo-frame id and writes to context.body', function() {
77
+ turbochargeKoa(this.mockKoaApp);
78
+ this.mockKoaApp.context.turboFrame('c');
79
+
80
+ expect(this.mockKoaApp.context.body).to.equal('<turbo-frame id="id">c</turbo-frame>');
81
+ });
82
+
83
+
84
+ it('turboFrame() correctly returns HTML when autoRender = false', function() {
85
+ turbochargeKoa(this.mockKoaApp, { autoRender: false });
86
+ const html = this.mockKoaApp.context.turboFrame('id', 'c');
87
+
88
+ expect(html).to.equal('<turbo-frame id="id">c</turbo-frame>');
89
+ });
90
+
91
+
92
+ it('turboStream() correctly writes to context.body', function() {
93
+ turbochargeKoa(this.mockKoaApp);
94
+ this.mockKoaApp.context.turboStream().append('t', 'c');
95
+
96
+ expect(this.mockKoaApp.context.body.trim()).to.equal('<turbo-stream action="append" target="t"><template>c</template></turbo-stream>');
97
+ });
98
+
99
+
100
+ it('turboStream() returns TurboStream when autoRender = false', function() {
101
+ turbochargeKoa(this.mockKoaApp, { autoRender: false });
102
+ const ts = this.mockKoaApp.context.turboStream();
103
+
104
+ expect(ts).to.be.instanceof(TurboStream);
105
+ });
106
+
107
+
108
+ describe('sseTurboStream()', function() {
109
+
110
+ it('returns SseTurboStream', function() {
111
+ turbochargeKoa(this.mockKoaApp);
112
+ const ssets = this.mockKoaApp.context.sseTurboStream();//boundSseTurboStream();
113
+
114
+ expect(ssets).to.be.instanceof(SseTurboStream);
115
+ });
116
+
117
+
118
+ it('configures Koa for an SSE connection', function() {
119
+ turbochargeKoa(this.mockKoaApp);
120
+ const ssets = this.mockKoaApp.context.sseTurboStream();//boundSseTurboStream();
121
+
122
+ expect(this.mockKoaApp.context.compress).to.be.false;
123
+ // expect(this.mockKoaApp.context.req.socket.setTimeout).to.have.been.called.with(0);
124
+ // expect(this.mockKoaApp.context.req.socket.setNoDelay).to.have.been.called.with(true);
125
+ // expect(this.mockKoaApp.context.req.socket.setKeepAlive).to.have.been.called.with(true);
126
+ expect(this.mockKoaApp.context.set).to.have.been.called.with({ 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Content-Type': SseTurboStream.MIME_TYPE });
127
+ expect(this.mockKoaApp.context.status).to.equal(200);
128
+ // expect(this.mockKoaApp.context.type).to.equal(SseTurboStream.MIME_TYPE);
129
+ });
130
+
131
+
132
+ it('sets ctx.body to Transform stream', function() {
133
+ turbochargeKoa(this.mockKoaApp);
134
+ const ssets = this.mockKoaApp.context.sseTurboStream();//boundSseTurboStream();
135
+
136
+ expect(this.mockKoaApp.context.body).to.be.an.instanceof(Transform);
137
+ });
138
+
139
+ });
140
+
141
+ });