@gitlab/ui 78.9.0 → 78.10.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/CHANGELOG.md +15 -0
- package/dist/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.js +51 -14
- package/dist/components/experimental/duo/chat/components/duo_chat_message/utils.js +8 -0
- package/dist/components/experimental/duo/chat/duo_chat.js +2 -2
- package/dist/components/experimental/duo/chat/mock_data.js +18 -4
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/tokens/css/tokens.css +1 -1
- package/dist/tokens/css/tokens.dark.css +1 -1
- package/dist/tokens/js/tokens.dark.js +1 -1
- package/dist/tokens/js/tokens.js +1 -1
- package/dist/tokens/scss/_tokens.dark.scss +1 -1
- package/dist/tokens/scss/_tokens.scss +1 -1
- package/package.json +2 -2
- package/src/components/base/label/label.scss +1 -1
- package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.spec.js +258 -138
- package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.vue +46 -17
- package/src/components/experimental/duo/chat/components/duo_chat_message/utils.js +9 -0
- package/src/components/experimental/duo/chat/components/duo_chat_message/utils.spec.js +24 -0
- package/src/components/experimental/duo/chat/duo_chat.spec.js +1 -0
- package/src/components/experimental/duo/chat/duo_chat.stories.js +14 -31
- package/src/components/experimental/duo/chat/duo_chat.vue +4 -1
- package/src/components/experimental/duo/chat/mock_data.js +18 -3
package/dist/tokens/js/tokens.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "78.
|
|
3
|
+
"version": "78.10.1",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"@gitlab/eslint-plugin": "19.5.0",
|
|
103
103
|
"@gitlab/fonts": "^1.3.0",
|
|
104
104
|
"@gitlab/stylelint-config": "6.1.0",
|
|
105
|
-
"@gitlab/svgs": "3.
|
|
105
|
+
"@gitlab/svgs": "3.95.0",
|
|
106
106
|
"@rollup/plugin-commonjs": "^11.1.0",
|
|
107
107
|
"@rollup/plugin-node-resolve": "^7.1.3",
|
|
108
108
|
"@rollup/plugin-replace": "^2.3.2",
|
|
@@ -17,7 +17,7 @@ $label-close-button: '.gl-label-close.gl-button';
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
&:focus-within {
|
|
20
|
-
@include gl-focus($color: var(--label-background-color), $important: true);
|
|
20
|
+
@include gl-focus($color: var(--label-background-color, $white), $important: true);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
.gl-label-link {
|
package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.spec.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { nextTick } from 'vue';
|
|
2
2
|
import { shallowMount } from '@vue/test-utils';
|
|
3
3
|
import GlDuoUserFeedback from '../../../user_feedback/user_feedback.vue';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
MOCK_USER_PROMPT_MESSAGE,
|
|
6
|
+
MOCK_RESPONSE_MESSAGE,
|
|
7
|
+
generateSeparateChunks,
|
|
8
|
+
} from '../../mock_data';
|
|
5
9
|
import DocumentationSources from '../duo_chat_message_sources/duo_chat_message_sources.vue';
|
|
6
10
|
import GlDuoChatMessage from './duo_chat_message.vue';
|
|
7
11
|
|
|
@@ -35,7 +39,7 @@ describe('DuoChatMessage', () => {
|
|
|
35
39
|
};
|
|
36
40
|
|
|
37
41
|
beforeEach(() => {
|
|
38
|
-
renderMarkdown = jest.fn().mockImplementation((val) =>
|
|
42
|
+
renderMarkdown = jest.fn().mockImplementation((val) => val);
|
|
39
43
|
renderGFM = jest.fn();
|
|
40
44
|
});
|
|
41
45
|
|
|
@@ -49,18 +53,26 @@ describe('DuoChatMessage', () => {
|
|
|
49
53
|
expect(customElements.get('copy-code')).toBeDefined();
|
|
50
54
|
});
|
|
51
55
|
|
|
52
|
-
describe('rendering
|
|
56
|
+
describe('rendering', () => {
|
|
53
57
|
beforeEach(() => {
|
|
54
58
|
renderMarkdown.mockImplementation(() => mockMarkdownContent);
|
|
55
|
-
createComponent();
|
|
56
59
|
});
|
|
57
60
|
|
|
58
|
-
it('
|
|
59
|
-
|
|
61
|
+
it('renders html content of the message by default', () => {
|
|
62
|
+
createComponent();
|
|
63
|
+
expect(renderMarkdown).not.toHaveBeenCalled();
|
|
64
|
+
expect(wrapper.html()).toContain(MOCK_USER_PROMPT_MESSAGE.contentHtml);
|
|
60
65
|
});
|
|
61
66
|
|
|
62
|
-
it('
|
|
63
|
-
|
|
67
|
+
it('converts the message `content` to Markdown if there is no contentHtml', () => {
|
|
68
|
+
createComponent({
|
|
69
|
+
message: {
|
|
70
|
+
...MOCK_USER_PROMPT_MESSAGE,
|
|
71
|
+
contentHtml: undefined,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
expect(renderMarkdown).toHaveBeenCalledWith(MOCK_USER_PROMPT_MESSAGE.content);
|
|
75
|
+
expect(findContent().text()).toBe(mockMarkdownContent);
|
|
64
76
|
});
|
|
65
77
|
|
|
66
78
|
it('does not render the documentation sources component', () => {
|
|
@@ -135,8 +147,6 @@ describe('DuoChatMessage', () => {
|
|
|
135
147
|
...MOCK_USER_PROMPT_MESSAGE,
|
|
136
148
|
errors,
|
|
137
149
|
contentHtml: 'fooHtml barHtml',
|
|
138
|
-
content: 'foo bar',
|
|
139
|
-
chunks: ['a', 'b', 'c'],
|
|
140
150
|
},
|
|
141
151
|
});
|
|
142
152
|
|
|
@@ -155,7 +165,6 @@ describe('DuoChatMessage', () => {
|
|
|
155
165
|
errors: [],
|
|
156
166
|
contentHtml: 'fooHtml barHtml',
|
|
157
167
|
content: 'foo bar',
|
|
158
|
-
chunks: ['a', 'b', 'c'],
|
|
159
168
|
},
|
|
160
169
|
});
|
|
161
170
|
|
|
@@ -169,47 +178,14 @@ describe('DuoChatMessage', () => {
|
|
|
169
178
|
message: {
|
|
170
179
|
...MOCK_USER_PROMPT_MESSAGE,
|
|
171
180
|
errors: [],
|
|
172
|
-
contentHtml:
|
|
181
|
+
contentHtml: undefined,
|
|
173
182
|
content: 'foo bar',
|
|
174
|
-
chunks: ['a', 'b', 'c'],
|
|
175
183
|
},
|
|
176
184
|
});
|
|
177
185
|
|
|
178
186
|
await nextTick();
|
|
179
187
|
|
|
180
|
-
expect(findContent().text()).toContain('
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it('outputs chunks if there is no content', async () => {
|
|
184
|
-
createComponent({
|
|
185
|
-
message: {
|
|
186
|
-
...MOCK_USER_PROMPT_MESSAGE,
|
|
187
|
-
errors: [],
|
|
188
|
-
contentHtml: '',
|
|
189
|
-
content: '',
|
|
190
|
-
chunks: ['a', 'b', 'c'],
|
|
191
|
-
},
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
await nextTick();
|
|
195
|
-
|
|
196
|
-
expect(findContent().text()).toContain('markdown: abc');
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it('outputs chunks until first undefined', async () => {
|
|
200
|
-
createComponent({
|
|
201
|
-
message: {
|
|
202
|
-
...MOCK_USER_PROMPT_MESSAGE,
|
|
203
|
-
errors: [],
|
|
204
|
-
contentHtml: '',
|
|
205
|
-
content: '',
|
|
206
|
-
chunks: ['a', undefined, 'c'],
|
|
207
|
-
},
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
await nextTick();
|
|
211
|
-
|
|
212
|
-
expect(findContent().text()).toContain('markdown: a');
|
|
188
|
+
expect(findContent().text()).toContain('foo bar');
|
|
213
189
|
});
|
|
214
190
|
|
|
215
191
|
it('hydrates the message with GFM when mounting with contentHtml', async () => {
|
|
@@ -231,44 +207,33 @@ describe('DuoChatMessage', () => {
|
|
|
231
207
|
},
|
|
232
208
|
});
|
|
233
209
|
|
|
234
|
-
wrapper.setProps({
|
|
210
|
+
await wrapper.setProps({
|
|
235
211
|
message: {
|
|
236
212
|
...MOCK_USER_PROMPT_MESSAGE,
|
|
237
213
|
contentHtml: 'foo bar',
|
|
238
214
|
},
|
|
239
215
|
});
|
|
240
|
-
|
|
241
|
-
await nextTick();
|
|
242
216
|
expect(renderGFM).toHaveBeenCalled();
|
|
243
217
|
});
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
describe('default renderers', () => {
|
|
247
|
-
it('outputs errors if they are present', async () => {
|
|
248
|
-
const errors = ['error1', 'error2', 'error3'];
|
|
249
218
|
|
|
219
|
+
it('sanitizes html produced by errors', async () => {
|
|
250
220
|
createComponent({
|
|
251
221
|
options: {
|
|
252
222
|
provide: null,
|
|
253
223
|
},
|
|
254
224
|
message: {
|
|
255
225
|
...MOCK_USER_PROMPT_MESSAGE,
|
|
256
|
-
errors,
|
|
257
|
-
contentHtml:
|
|
258
|
-
content: '
|
|
259
|
-
chunks: ['a', 'b', 'c'],
|
|
226
|
+
errors: ['[click here](javascript:prompt(1))'],
|
|
227
|
+
contentHtml: undefined,
|
|
228
|
+
content: '',
|
|
260
229
|
},
|
|
261
230
|
});
|
|
262
231
|
|
|
263
232
|
await nextTick();
|
|
264
|
-
|
|
265
|
-
const contentText = findContent().text();
|
|
266
|
-
expect(contentText).toContain(errors[0]);
|
|
267
|
-
expect(contentText).toContain(errors[1]);
|
|
268
|
-
expect(contentText).toContain(errors[2]);
|
|
233
|
+
expect(findContent().html()).toContain('<p><a>click here</a></p>');
|
|
269
234
|
});
|
|
270
235
|
|
|
271
|
-
it('
|
|
236
|
+
it('sanitizes html produced by content', async () => {
|
|
272
237
|
createComponent({
|
|
273
238
|
options: {
|
|
274
239
|
provide: null,
|
|
@@ -276,20 +241,17 @@ describe('DuoChatMessage', () => {
|
|
|
276
241
|
message: {
|
|
277
242
|
...MOCK_USER_PROMPT_MESSAGE,
|
|
278
243
|
errors: [],
|
|
279
|
-
contentHtml:
|
|
280
|
-
content: '
|
|
281
|
-
chunks: ['a', 'b', 'c'],
|
|
244
|
+
contentHtml: undefined,
|
|
245
|
+
content: '[click here](javascript:prompt(1))',
|
|
282
246
|
},
|
|
283
247
|
});
|
|
284
248
|
|
|
285
249
|
await nextTick();
|
|
286
250
|
|
|
287
|
-
expect(findContent().html()).
|
|
288
|
-
'<div class="gl-markdown gl-compact-markdown">fooHtml barHtml</div>'
|
|
289
|
-
);
|
|
251
|
+
expect(findContent().html()).toContain('<p><a>click here</a></p>');
|
|
290
252
|
});
|
|
291
253
|
|
|
292
|
-
it('
|
|
254
|
+
it('deprecated: sanitizes html produced by chunks', async () => {
|
|
293
255
|
createComponent({
|
|
294
256
|
options: {
|
|
295
257
|
provide: null,
|
|
@@ -297,18 +259,18 @@ describe('DuoChatMessage', () => {
|
|
|
297
259
|
message: {
|
|
298
260
|
...MOCK_USER_PROMPT_MESSAGE,
|
|
299
261
|
errors: [],
|
|
300
|
-
contentHtml:
|
|
301
|
-
content: '
|
|
302
|
-
chunks: ['
|
|
262
|
+
contentHtml: undefined,
|
|
263
|
+
content: '',
|
|
264
|
+
chunks: ['[click here]', '(javascript:prompt(1))'],
|
|
303
265
|
},
|
|
304
266
|
});
|
|
305
267
|
|
|
306
268
|
await nextTick();
|
|
307
269
|
|
|
308
|
-
expect(findContent().html()).
|
|
270
|
+
expect(findContent().html()).toContain('<p><a>click here</a></p>');
|
|
309
271
|
});
|
|
310
272
|
|
|
311
|
-
it('
|
|
273
|
+
it('sanitizes contentHtml', async () => {
|
|
312
274
|
createComponent({
|
|
313
275
|
options: {
|
|
314
276
|
provide: null,
|
|
@@ -316,92 +278,250 @@ describe('DuoChatMessage', () => {
|
|
|
316
278
|
message: {
|
|
317
279
|
...MOCK_USER_PROMPT_MESSAGE,
|
|
318
280
|
errors: [],
|
|
319
|
-
contentHtml:
|
|
281
|
+
contentHtml: `<a href="javascript:prompt(1)">click here</a>`,
|
|
320
282
|
content: '',
|
|
321
|
-
chunks: [
|
|
283
|
+
chunks: [],
|
|
322
284
|
},
|
|
323
285
|
});
|
|
324
286
|
|
|
325
287
|
await nextTick();
|
|
326
288
|
|
|
327
|
-
expect(findContent().html()).toBe(
|
|
289
|
+
expect(findContent().html()).toBe(
|
|
290
|
+
'<div class="gl-markdown gl-compact-markdown"><a>click here</a></div>'
|
|
291
|
+
);
|
|
328
292
|
});
|
|
329
293
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
},
|
|
335
|
-
message: {
|
|
336
|
-
...MOCK_USER_PROMPT_MESSAGE,
|
|
337
|
-
errors: ['[click here](javascript:prompt(1))'],
|
|
338
|
-
contentHtml: '',
|
|
339
|
-
content: '',
|
|
340
|
-
chunks: [],
|
|
341
|
-
},
|
|
294
|
+
describe('message updates watcher', () => {
|
|
295
|
+
const newContent = 'new foo content';
|
|
296
|
+
beforeEach(() => {
|
|
297
|
+
createComponent();
|
|
342
298
|
});
|
|
343
299
|
|
|
344
|
-
|
|
300
|
+
it('listens to the message changes', async () => {
|
|
301
|
+
expect(findContent().text()).toContain(MOCK_USER_PROMPT_MESSAGE.content);
|
|
302
|
+
// setProps is justified here because we are testing the component's
|
|
303
|
+
// reactive behavior which consistutes an exception
|
|
304
|
+
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
305
|
+
await wrapper.setProps({
|
|
306
|
+
message: {
|
|
307
|
+
...MOCK_USER_PROMPT_MESSAGE,
|
|
308
|
+
contentHtml: `<p>${newContent}</p>`,
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
expect(findContent().text()).not.toContain(MOCK_USER_PROMPT_MESSAGE.content);
|
|
312
|
+
expect(findContent().text()).toContain(newContent);
|
|
313
|
+
});
|
|
345
314
|
|
|
346
|
-
|
|
347
|
-
|
|
315
|
+
it('prioritises the output of contentHtml over content', async () => {
|
|
316
|
+
// setProps is justified here because we are testing the component's
|
|
317
|
+
// reactive behavior which consistutes an exception
|
|
318
|
+
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
319
|
+
await wrapper.setProps({
|
|
320
|
+
message: {
|
|
321
|
+
...MOCK_USER_PROMPT_MESSAGE,
|
|
322
|
+
contentHtml: `<p>${MOCK_USER_PROMPT_MESSAGE.content}</p>`,
|
|
323
|
+
content: newContent,
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
expect(findContent().text()).not.toContain(newContent);
|
|
327
|
+
expect(findContent().text()).toContain(MOCK_USER_PROMPT_MESSAGE.content);
|
|
328
|
+
});
|
|
348
329
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
330
|
+
it('outputs errors if message has no content', async () => {
|
|
331
|
+
// setProps is justified here because we are testing the component's
|
|
332
|
+
// reactive behavior which consistutes an exception
|
|
333
|
+
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
334
|
+
await wrapper.setProps({
|
|
335
|
+
message: {
|
|
336
|
+
...MOCK_USER_PROMPT_MESSAGE,
|
|
337
|
+
contentHtml: '',
|
|
338
|
+
content: '',
|
|
339
|
+
errors: ['error'],
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
expect(findContent().text()).not.toContain(newContent);
|
|
343
|
+
expect(findContent().text()).not.toContain(MOCK_USER_PROMPT_MESSAGE.content);
|
|
344
|
+
expect(findContent().text()).toContain('error');
|
|
361
345
|
});
|
|
362
346
|
|
|
363
|
-
|
|
347
|
+
it('merges all the errors for output', async () => {
|
|
348
|
+
const errors = ['foo', 'bar', 'baz'];
|
|
349
|
+
// setProps is justified here because we are testing the component's
|
|
350
|
+
// reactive behavior which consistutes an exception
|
|
351
|
+
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
352
|
+
await wrapper.setProps({
|
|
353
|
+
message: {
|
|
354
|
+
...MOCK_USER_PROMPT_MESSAGE,
|
|
355
|
+
contentHtml: '',
|
|
356
|
+
content: '',
|
|
357
|
+
errors,
|
|
358
|
+
},
|
|
359
|
+
});
|
|
360
|
+
expect(findContent().text()).toContain(errors[0]);
|
|
361
|
+
expect(findContent().text()).toContain(errors[1]);
|
|
362
|
+
expect(findContent().text()).toContain(errors[2]);
|
|
363
|
+
});
|
|
364
364
|
|
|
365
|
-
|
|
365
|
+
it('hydrates the output message with GLFM if its not a chunk', async () => {
|
|
366
|
+
// setProps is justified here because we are testing the component's
|
|
367
|
+
// reactive behavior which consistutes an exception
|
|
368
|
+
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
369
|
+
await wrapper.setProps({
|
|
370
|
+
message: {
|
|
371
|
+
...MOCK_USER_PROMPT_MESSAGE,
|
|
372
|
+
contentHtml: `<p>${newContent}</p>`,
|
|
373
|
+
},
|
|
374
|
+
});
|
|
375
|
+
expect(renderGFM).toHaveBeenCalled();
|
|
376
|
+
});
|
|
366
377
|
});
|
|
367
378
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
message:
|
|
374
|
-
...MOCK_USER_PROMPT_MESSAGE,
|
|
375
|
-
errors: [],
|
|
376
|
-
contentHtml: '',
|
|
377
|
-
content: '',
|
|
378
|
-
chunks: ['[click here]', '(javascript:prompt(1))'],
|
|
379
|
-
},
|
|
379
|
+
describe('updates to the message', () => {
|
|
380
|
+
const [CHUNK1, CHUNK2, CHUNK3] = generateSeparateChunks(3);
|
|
381
|
+
const consolidatedContent = CHUNK1.content + CHUNK2.content;
|
|
382
|
+
|
|
383
|
+
beforeEach(() => {
|
|
384
|
+
createComponent({ message: MOCK_RESPONSE_MESSAGE });
|
|
380
385
|
});
|
|
381
386
|
|
|
382
|
-
|
|
387
|
+
it('does not handle message updates with chunks for the user messages', async () => {
|
|
388
|
+
createComponent({ message: MOCK_USER_PROMPT_MESSAGE });
|
|
389
|
+
expect(findContent().text()).toContain(MOCK_USER_PROMPT_MESSAGE.content);
|
|
390
|
+
// setProps is justified here because we are testing the component's
|
|
391
|
+
// reactive behavior which consistutes an exception
|
|
392
|
+
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
393
|
+
await wrapper.setProps({
|
|
394
|
+
message: {
|
|
395
|
+
...MOCK_USER_PROMPT_MESSAGE,
|
|
396
|
+
content: 'foo bar',
|
|
397
|
+
chunkId: 1,
|
|
398
|
+
},
|
|
399
|
+
});
|
|
400
|
+
expect(findContent().text()).toContain(MOCK_USER_PROMPT_MESSAGE.content);
|
|
401
|
+
});
|
|
383
402
|
|
|
384
|
-
|
|
385
|
-
|
|
403
|
+
it('does not fail if the message has no chunkId', async () => {
|
|
404
|
+
// setProps is justified here because we are testing the component's
|
|
405
|
+
// reactive behavior which consistutes an exception
|
|
406
|
+
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
407
|
+
await wrapper.setProps({
|
|
408
|
+
message: {
|
|
409
|
+
...CHUNK1,
|
|
410
|
+
chunkId: null,
|
|
411
|
+
},
|
|
412
|
+
});
|
|
413
|
+
expect(findContent().text()).toContain(CHUNK1.content);
|
|
414
|
+
});
|
|
386
415
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
416
|
+
it('renders chunks correctly when the chunks arrive out of order', async () => {
|
|
417
|
+
expect(CHUNK1.content).toBe('chunk #1');
|
|
418
|
+
expect(CHUNK2.content).toBe('chunk #2');
|
|
419
|
+
expect(CHUNK3.content).toBe('chunk #3');
|
|
420
|
+
// setProps is justified here because we are testing the component's
|
|
421
|
+
// reactive behavior which consistutes an exception
|
|
422
|
+
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
423
|
+
await wrapper.setProps({
|
|
424
|
+
message: CHUNK2,
|
|
425
|
+
});
|
|
426
|
+
expect(findContent().text()).toBe('');
|
|
427
|
+
|
|
428
|
+
await wrapper.setProps({
|
|
429
|
+
message: CHUNK1,
|
|
430
|
+
});
|
|
431
|
+
expect(findContent().text()).toBe(CHUNK1.content + CHUNK2.content);
|
|
432
|
+
|
|
433
|
+
await wrapper.setProps({
|
|
434
|
+
message: CHUNK3,
|
|
435
|
+
});
|
|
436
|
+
expect(findContent().text()).toBe(CHUNK1.content + CHUNK2.content + CHUNK3.content);
|
|
399
437
|
});
|
|
400
438
|
|
|
401
|
-
|
|
439
|
+
it('renders the chunks as they arrive when they arrive in the correct order', async () => {
|
|
440
|
+
// setProps is justified here because we are testing the component's
|
|
441
|
+
// reactive behavior which consistutes an exception
|
|
442
|
+
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
443
|
+
await wrapper.setProps({
|
|
444
|
+
message: CHUNK1,
|
|
445
|
+
});
|
|
446
|
+
expect(findContent().text()).toBe(CHUNK1.content);
|
|
402
447
|
|
|
403
|
-
|
|
404
|
-
|
|
448
|
+
await wrapper.setProps({
|
|
449
|
+
message: CHUNK2,
|
|
450
|
+
});
|
|
451
|
+
expect(findContent().text()).toBe(consolidatedContent);
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
it('treats the initial message content as chunk if message has chunkId', async () => {
|
|
455
|
+
createComponent({
|
|
456
|
+
message: CHUNK1,
|
|
457
|
+
});
|
|
458
|
+
await nextTick();
|
|
459
|
+
expect(findContent().text()).toBe(CHUNK1.content);
|
|
460
|
+
|
|
461
|
+
// setProps is justified here because we are testing the component's
|
|
462
|
+
// reactive behavior which consistutes an exception
|
|
463
|
+
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
464
|
+
await wrapper.setProps({
|
|
465
|
+
message: CHUNK2,
|
|
466
|
+
});
|
|
467
|
+
expect(findContent().text()).toBe(consolidatedContent);
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it('does not hydrate the chunk messages with GLFM', async () => {
|
|
471
|
+
createComponent({
|
|
472
|
+
propsData: {
|
|
473
|
+
message: CHUNK1,
|
|
474
|
+
},
|
|
475
|
+
});
|
|
476
|
+
await nextTick();
|
|
477
|
+
renderGFM.mockClear();
|
|
478
|
+
expect(renderGFM).not.toHaveBeenCalled();
|
|
479
|
+
|
|
480
|
+
// setProps is justified here because we are testing the component's
|
|
481
|
+
// reactive behavior which consistutes an exception
|
|
482
|
+
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
483
|
+
await wrapper.setProps({
|
|
484
|
+
message: CHUNK2,
|
|
485
|
+
});
|
|
486
|
+
expect(renderGFM).not.toHaveBeenCalled();
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it.each`
|
|
490
|
+
content | contentHtml | errors | expectedContent
|
|
491
|
+
${'alpha'} | ${'beta'} | ${['foo', 'bar']} | ${'foo; bar'}
|
|
492
|
+
${'alpha'} | ${'beta'} | ${[]} | ${'beta'}
|
|
493
|
+
${'alpha'} | ${undefined} | ${['foo', 'bar']} | ${'foo; bar'}
|
|
494
|
+
${'alpha'} | ${undefined} | ${[]} | ${'alpha'}
|
|
495
|
+
${''} | ${'beta'} | ${['foo', 'bar']} | ${'foo; bar'}
|
|
496
|
+
${''} | ${'beta'} | ${[]} | ${'beta'}
|
|
497
|
+
${''} | ${undefined} | ${['foo', 'bar']} | ${'foo; bar'}
|
|
498
|
+
`(
|
|
499
|
+
'outputs "$expectedContent" and hydrates this content when content is "$content", contentHtml is "$contentHtml" and errors is "$errors" with "chunkId: null"',
|
|
500
|
+
async ({ content, contentHtml, errors, expectedContent } = {}) => {
|
|
501
|
+
createComponent({
|
|
502
|
+
propsData: {
|
|
503
|
+
message: CHUNK1,
|
|
504
|
+
},
|
|
505
|
+
});
|
|
506
|
+
await nextTick();
|
|
507
|
+
renderGFM.mockClear();
|
|
508
|
+
expect(renderGFM).not.toHaveBeenCalled();
|
|
509
|
+
|
|
510
|
+
// setProps is justified here because we are testing the component's
|
|
511
|
+
// reactive behavior which consistutes an exception
|
|
512
|
+
// See https://docs.gitlab.com/ee/development/fe_guide/style/vue.html#setting-component-state
|
|
513
|
+
await wrapper.setProps({
|
|
514
|
+
message: {
|
|
515
|
+
...CHUNK2,
|
|
516
|
+
chunkId: null,
|
|
517
|
+
content,
|
|
518
|
+
contentHtml,
|
|
519
|
+
errors,
|
|
520
|
+
},
|
|
521
|
+
});
|
|
522
|
+
expect(renderGFM).toHaveBeenCalled();
|
|
523
|
+
expect(findContent().text()).toBe(expectedContent);
|
|
524
|
+
}
|
|
405
525
|
);
|
|
406
526
|
});
|
|
407
527
|
});
|