diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-29 09:07:58 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-29 09:07:58 +0300 |
commit | 95085ac5cdbf6fcb12c6bdb167f663844d05147d (patch) | |
tree | a0107e379526090ec3be43eb81929e159b912a4c /spec | |
parent | 111f9a7cc6834edfeb81c4b91bcf43df332096a7 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
24 files changed, 491 insertions, 169 deletions
diff --git a/spec/frontend/content_editor/components/bubble_menus/bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/bubble_menu_spec.js index 85eafa9e85c..53c098ee153 100644 --- a/spec/frontend/content_editor/components/bubble_menus/bubble_menu_spec.js +++ b/spec/frontend/content_editor/components/bubble_menus/bubble_menu_spec.js @@ -65,7 +65,7 @@ describe('content_editor/components/bubble_menus/bubble_menu', () => { onHidden: expect.any(Function), onShow: expect.any(Function), strategy: 'fixed', - maxWidth: 'auto', + maxWidth: '400px', ...tippyOptions, }), }); diff --git a/spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js index c79df9c9ed8..b219c506753 100644 --- a/spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js +++ b/spec/frontend/content_editor/components/bubble_menus/link_bubble_menu_spec.js @@ -206,7 +206,7 @@ describe('content_editor/components/bubble_menus/link_bubble_menu', () => { await buildWrapperAndDisplayMenu(); await wrapper.findByTestId('remove-link').vm.$emit('click'); - expect(tiptapEditor.getHTML()).toBe('<p>Download PDF File</p>'); + expect(tiptapEditor.getHTML()).toBe('<p dir="auto">Download PDF File</p>'); }); }); diff --git a/spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js index 89beb76a6f2..002e19ee8cf 100644 --- a/spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js +++ b/spec/frontend/content_editor/components/bubble_menus/media_bubble_menu_spec.js @@ -22,19 +22,19 @@ import { PROJECT_WIKI_ATTACHMENT_DRAWIO_DIAGRAM_HTML, } from '../../test_constants'; -const TIPTAP_AUDIO_HTML = `<p> +const TIPTAP_AUDIO_HTML = `<p dir="auto"> <span class="media-container audio-container"><audio src="https://gitlab.com/favicon.png" controls="true" data-setup="{}" data-title="gitlab favicon"></audio><a href="https://gitlab.com/favicon.png" class="with-attachment-icon">gitlab favicon</a></span> </p>`; -const TIPTAP_DIAGRAM_HTML = `<p> - <img src="https://gitlab.com/favicon.png" alt="gitlab favicon" title="gitlab favicon"> +const TIPTAP_DIAGRAM_HTML = `<p dir="auto"> + <img src="https://gitlab.com/favicon.png" alt="gitlab favicon"> </p>`; -const TIPTAP_IMAGE_HTML = `<p> - <img src="https://gitlab.com/favicon.png" alt="gitlab favicon" title="gitlab favicon"> +const TIPTAP_IMAGE_HTML = `<p dir="auto"> + <img src="https://gitlab.com/favicon.png" alt="gitlab favicon"> </p>`; -const TIPTAP_VIDEO_HTML = `<p> +const TIPTAP_VIDEO_HTML = `<p dir="auto"> <span class="media-container video-container"><video src="https://gitlab.com/favicon.png" controls="true" data-setup="{}" data-title="gitlab favicon"></video><a href="https://gitlab.com/favicon.png" class="with-attachment-icon">gitlab favicon</a></span> </p>`; @@ -101,9 +101,7 @@ describe.each` const expectLinkButtonsToExist = (exist = true) => { expect(wrapper.findComponent(GlLink).exists()).toBe(exist); - expect(wrapper.findByTestId('copy-media-src').exists()).toBe(exist); expect(wrapper.findByTestId('edit-media').exists()).toBe(exist); - expect(wrapper.findByTestId('delete-media').exists()).toBe(exist); }; beforeEach(() => { @@ -128,14 +126,11 @@ describe.each` await buildWrapperAndDisplayMenu(); const link = wrapper.findComponent(GlLink); - expect(link.attributes()).toEqual( - expect.objectContaining({ - href: `/group1/project1/-/wikis/${filePath}`, - 'aria-label': filePath, - title: filePath, - target: '_blank', - }), - ); + expect(link.attributes()).toMatchObject({ + href: `/group1/project1/-/wikis/${filePath}`, + 'aria-label': filePath, + target: '_blank', + }); expect(link.text()).toBe(filePath); }); @@ -190,28 +185,6 @@ describe.each` }); }); - describe('copy button', () => { - it(`copies the canonical link to the ${mediaType} to clipboard`, async () => { - await buildWrapperAndDisplayMenu(); - - jest.spyOn(navigator.clipboard, 'writeText'); - - await wrapper.findByTestId('copy-media-src').vm.$emit('click'); - - expect(navigator.clipboard.writeText).toHaveBeenCalledWith(filePath); - }); - }); - - describe(`remove ${mediaType} button`, () => { - it(`removes the ${mediaType}`, async () => { - await buildWrapperAndDisplayMenu(); - - await wrapper.findByTestId('delete-media').vm.$emit('click'); - - expect(tiptapEditor.getHTML()).toBe('<p>\n \n</p>'); - }); - }); - describe(`replace ${mediaType} button`, () => { beforeEach(buildWrapperAndDisplayMenu); @@ -252,7 +225,6 @@ describe.each` describe('edit button', () => { let mediaSrcInput; - let mediaTitleInput; let mediaAltInput; beforeEach(async () => { @@ -261,7 +233,6 @@ describe.each` await wrapper.findByTestId('edit-media').vm.$emit('click'); mediaSrcInput = wrapper.findByTestId('media-src'); - mediaTitleInput = wrapper.findByTestId('media-title'); mediaAltInput = wrapper.findByTestId('media-alt'); }); @@ -269,11 +240,10 @@ describe.each` expectLinkButtonsToExist(false); }); - it(`shows a form to edit the ${mediaType} src/title/alt`, () => { + it(`shows a form to edit the ${mediaType} src/alt`, () => { expect(wrapper.findComponent(GlForm).exists()).toBe(true); expect(mediaSrcInput.element.value).toBe(filePath); - expect(mediaTitleInput.element.value).toBe(''); expect(mediaAltInput.element.value).toBe('test-file'); }); @@ -281,7 +251,6 @@ describe.each` beforeEach(async () => { mediaSrcInput.setValue('https://gitlab.com/favicon.png'); mediaAltInput.setValue('gitlab favicon'); - mediaTitleInput.setValue('gitlab favicon'); contentEditor.resolveUrl.mockResolvedValue('https://gitlab.com/favicon.png'); @@ -294,14 +263,11 @@ describe.each` it(`updates the link to the ${mediaType} in the bubble menu`, () => { const link = wrapper.findComponent(GlLink); - expect(link.attributes()).toEqual( - expect.objectContaining({ - href: 'https://gitlab.com/favicon.png', - 'aria-label': 'https://gitlab.com/favicon.png', - title: 'https://gitlab.com/favicon.png', - target: '_blank', - }), - ); + expect(link.attributes()).toMatchObject({ + href: 'https://gitlab.com/favicon.png', + 'aria-label': 'https://gitlab.com/favicon.png', + target: '_blank', + }); expect(link.text()).toBe('https://gitlab.com/favicon.png'); }); }); @@ -310,7 +276,6 @@ describe.each` beforeEach(async () => { mediaSrcInput.setValue('https://gitlab.com/favicon.png'); mediaAltInput.setValue('gitlab favicon'); - mediaTitleInput.setValue('gitlab favicon'); await wrapper.findByTestId('cancel-editing-media').vm.$emit('click'); }); @@ -324,12 +289,10 @@ describe.each` await wrapper.findByTestId('edit-media').vm.$emit('click'); mediaSrcInput = wrapper.findByTestId('media-src'); - mediaTitleInput = wrapper.findByTestId('media-title'); mediaAltInput = wrapper.findByTestId('media-alt'); expect(mediaSrcInput.element.value).toBe(filePath); expect(mediaAltInput.element.value).toBe('test-file'); - expect(mediaTitleInput.element.value).toBe(''); }); }); }); diff --git a/spec/frontend/content_editor/components/bubble_menus/reference_bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/reference_bubble_menu_spec.js index 169f77dc054..c46aa1b657e 100644 --- a/spec/frontend/content_editor/components/bubble_menus/reference_bubble_menu_spec.js +++ b/spec/frontend/content_editor/components/bubble_menus/reference_bubble_menu_spec.js @@ -241,7 +241,7 @@ describe('content_editor/components/bubble_menus/reference_bubble_menu', () => { await buildWrapperAndDisplayMenu(); await wrapper.findByTestId('remove-reference').trigger('click'); - expect(tiptapEditor.getHTML()).toBe('<p></p>'); + expect(tiptapEditor.getHTML()).toBe('<p dir="auto"></p>'); }); }); }); diff --git a/spec/frontend/content_editor/components/wrappers/image_spec.js b/spec/frontend/content_editor/components/wrappers/image_spec.js new file mode 100644 index 00000000000..0ac3b7e9465 --- /dev/null +++ b/spec/frontend/content_editor/components/wrappers/image_spec.js @@ -0,0 +1,100 @@ +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import ImageWrapper from '~/content_editor/components/wrappers/image.vue'; +import { createTestEditor, mockChainedCommands } from '../../test_utils'; + +describe('content/components/wrappers/image_spec', () => { + let wrapper; + let tiptapEditor; + + const createWrapper = (node = {}) => { + tiptapEditor = createTestEditor(); + wrapper = shallowMountExtended(ImageWrapper, { + propsData: { + editor: tiptapEditor, + node, + getPos: jest.fn().mockReturnValue(12), + }, + }); + }; + + const findHandle = (handle) => wrapper.findByTestId(`image-resize-${handle}`); + const findImage = () => wrapper.find('img'); + + it('renders an image with the given attributes', () => { + createWrapper({ + type: 'image', + attrs: { src: 'image.png', alt: 'My Image', width: 200, height: 200 }, + }); + + expect(findImage().attributes()).toMatchObject({ + src: 'image.png', + alt: 'My Image', + height: '200', + width: '200', + }); + }); + + it('sets width and height to auto if not provided', () => { + createWrapper({ type: 'image', attrs: { src: 'image.png', alt: 'My Image' } }); + + expect(findImage().attributes()).toMatchObject({ + src: 'image.png', + alt: 'My Image', + height: 'auto', + width: 'auto', + }); + }); + + it('renders corner resize handles', () => { + createWrapper({ type: 'image', attrs: { src: 'image.png', alt: 'My Image' } }); + + expect(findHandle('nw').exists()).toBe(true); + expect(findHandle('ne').exists()).toBe(true); + expect(findHandle('sw').exists()).toBe(true); + expect(findHandle('se').exists()).toBe(true); + }); + + describe.each` + handle | htmlElementAttributes | tiptapNodeAttributes + ${'nw'} | ${{ width: '300', height: '75' }} | ${{ width: 300, height: 75 }} + ${'ne'} | ${{ width: '500', height: '125' }} | ${{ width: 500, height: 125 }} + ${'sw'} | ${{ width: '300', height: '75' }} | ${{ width: 300, height: 75 }} + ${'se'} | ${{ width: '500', height: '125' }} | ${{ width: 500, height: 125 }} + `('resizing using $handle', ({ handle, htmlElementAttributes, tiptapNodeAttributes }) => { + let handleEl; + + const initialMousePosition = { screenX: 200, screenY: 200 }; + const finalMousePosition = { screenX: 300, screenY: 300 }; + + beforeEach(() => { + createWrapper({ + type: 'image', + attrs: { src: 'image.png', alt: 'My Image', width: 400, height: 100 }, + }); + + handleEl = findHandle(handle); + handleEl.element.dispatchEvent(new MouseEvent('mousedown', initialMousePosition)); + document.dispatchEvent(new MouseEvent('mousemove', finalMousePosition)); + }); + + it('resizes the image properly on mousedown+mousemove', () => { + expect(findImage().attributes()).toMatchObject(htmlElementAttributes); + }); + + it('updates prosemirror doc state on mouse release with final size', () => { + const commands = mockChainedCommands(tiptapEditor, [ + 'focus', + 'updateAttributes', + 'setNodeSelection', + 'run', + ]); + + document.dispatchEvent(new MouseEvent('mouseup')); + + expect(commands.focus).toHaveBeenCalled(); + expect(commands.updateAttributes).toHaveBeenCalledWith('image', tiptapNodeAttributes); + expect(commands.setNodeSelection).toHaveBeenCalledWith(12); + expect(commands.run).toHaveBeenCalled(); + }); + }); +}); diff --git a/spec/frontend/content_editor/extensions/hard_break_spec.js b/spec/frontend/content_editor/extensions/hard_break_spec.js index 9e2e28b6e72..6a57e7eaa9b 100644 --- a/spec/frontend/content_editor/extensions/hard_break_spec.js +++ b/spec/frontend/content_editor/extensions/hard_break_spec.js @@ -3,35 +3,21 @@ import { createTestEditor, createDocBuilder } from '../test_utils'; describe('content_editor/extensions/hard_break', () => { let tiptapEditor; - let eq; + let doc; let p; - let hardBreak; beforeEach(() => { tiptapEditor = createTestEditor({ extensions: [HardBreak] }); ({ - builders: { doc, p, hardBreak }, - eq, + builders: { doc, p }, } = createDocBuilder({ tiptapEditor, names: { hardBreak: { nodeType: HardBreak.name } }, })); }); - describe('Shift-Enter shortcut', () => { - it('inserts a hard break when shortcut is executed', () => { - const initialDoc = doc(p('')); - const expectedDoc = doc(p(hardBreak())); - - tiptapEditor.commands.setContent(initialDoc.toJSON()); - tiptapEditor.commands.keyboardShortcut('Shift-Enter'); - - expect(eq(tiptapEditor.state.doc, expectedDoc)).toBe(true); - }); - }); - describe('Mod-Enter shortcut', () => { it('does not insert a hard break when shortcut is executed', () => { const initialDoc = doc(p('')); @@ -40,7 +26,7 @@ describe('content_editor/extensions/hard_break', () => { tiptapEditor.commands.setContent(initialDoc.toJSON()); tiptapEditor.commands.keyboardShortcut('Mod-Enter'); - expect(eq(tiptapEditor.state.doc, expectedDoc)).toBe(true); + expect(tiptapEditor.state.doc.toJSON()).toEqual(expectedDoc.toJSON()); }); }); }); diff --git a/spec/frontend/content_editor/extensions/html_nodes_spec.js b/spec/frontend/content_editor/extensions/html_nodes_spec.js index 24c68239025..3fe496aa708 100644 --- a/spec/frontend/content_editor/extensions/html_nodes_spec.js +++ b/spec/frontend/content_editor/extensions/html_nodes_spec.js @@ -28,9 +28,9 @@ describe('content_editor/extensions/html_nodes', () => { }); it.each` - input | insertedNodes - ${'<div><p>foo</p></div>'} | ${() => div(p('foo'))} - ${'<pre><p>foo</p></pre>'} | ${() => pre(p('foo'))} + input | insertedNodes + ${'<div><p dir="auto">foo</p></div>'} | ${() => div(p('foo'))} + ${'<pre><p dir="auto">foo</p></pre>'} | ${() => pre(p('foo'))} `('parses and creates nodes for $input', ({ input, insertedNodes }) => { const expectedDoc = doc(insertedNodes()); diff --git a/spec/frontend/content_editor/extensions/image_spec.js b/spec/frontend/content_editor/extensions/image_spec.js index f73b0143fd9..69f4f4c6d65 100644 --- a/spec/frontend/content_editor/extensions/image_spec.js +++ b/spec/frontend/content_editor/extensions/image_spec.js @@ -35,7 +35,7 @@ describe('content_editor/extensions/image', () => { tiptapEditor.commands.setContent(initialDoc.toJSON()); expect(tiptapEditor.getHTML()).toEqual( - '<p><img src="/-/wikis/uploads/image.jpg" alt="image" title="this is an image"></p>', + '<p dir="auto"><img src="/-/wikis/uploads/image.jpg" alt="image" title="this is an image"></p>', ); }); }); diff --git a/spec/frontend/content_editor/extensions/paragraph_spec.js b/spec/frontend/content_editor/extensions/paragraph_spec.js new file mode 100644 index 00000000000..d04dda1871d --- /dev/null +++ b/spec/frontend/content_editor/extensions/paragraph_spec.js @@ -0,0 +1,29 @@ +import { createTestEditor, createDocBuilder } from '../test_utils'; + +describe('content_editor/extensions/paragraph', () => { + let tiptapEditor; + let doc; + let p; + + beforeEach(() => { + tiptapEditor = createTestEditor(); + + ({ + builders: { doc, p }, + } = createDocBuilder({ tiptapEditor })); + }); + + describe('Shift-Enter shortcut', () => { + it('inserts a new paragraph when shortcut is executed', async () => { + const initialDoc = doc(p('hello')); + const expectedDoc = doc(p('hello'), p('')); + + tiptapEditor.commands.setContent(initialDoc.toJSON()); + tiptapEditor.commands.keyboardShortcut('Shift-Enter'); + + await Promise.resolve(); + + expect(tiptapEditor.state.doc.toJSON()).toEqual(expectedDoc.toJSON()); + }); + }); +}); diff --git a/spec/frontend/content_editor/extensions/paste_markdown_spec.js b/spec/frontend/content_editor/extensions/paste_markdown_spec.js index baf0919fec8..10e456d4b4e 100644 --- a/spec/frontend/content_editor/extensions/paste_markdown_spec.js +++ b/spec/frontend/content_editor/extensions/paste_markdown_spec.js @@ -16,7 +16,8 @@ const CODE_BLOCK_HTML = '<pre class="js-syntax-highlight" lang="javascript">var const DIAGRAM_HTML = '<img data-diagram="nomnoml" data-diagram-src="data:text/plain;base64,WzxmcmFtZT5EZWNvcmF0b3IgcGF0dGVybl0=">'; const FRONTMATTER_HTML = '<pre lang="yaml" data-lang-params="frontmatter">key: value</pre>'; -const PARAGRAPH_HTML = '<p>Some text with <strong>bold</strong> and <em>italic</em> text.</p>'; +const PARAGRAPH_HTML = + '<p dir="auto">Some text with <strong>bold</strong> and <em>italic</em> text.</p>'; describe('content_editor/extensions/paste_markdown', () => { let tiptapEditor; diff --git a/spec/frontend/content_editor/remark_markdown_processing_spec.js b/spec/frontend/content_editor/remark_markdown_processing_spec.js index d4a02ab2202..3d4d5b13120 100644 --- a/spec/frontend/content_editor/remark_markdown_processing_spec.js +++ b/spec/frontend/content_editor/remark_markdown_processing_spec.js @@ -1337,13 +1337,13 @@ content alert("Hello world") </script> `, - expectedHtml: '<p></p>', + expectedHtml: '<p dir="auto"></p>', }, { markdown: ` <foo>Hello</foo> `, - expectedHtml: '<p></p>', + expectedHtml: '<p dir="auto"></p>', }, { markdown: ` @@ -1356,7 +1356,7 @@ alert("Hello world") <a id="link-id">Header</a> and other text `, expectedHtml: - '<p><a target="_blank" rel="noopener noreferrer nofollow">Header</a> and other text</p>', + '<p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow">Header</a> and other text</p>', }, { markdown: ` @@ -1366,11 +1366,11 @@ body { } </style> `, - expectedHtml: '<p></p>', + expectedHtml: '<p dir="auto"></p>', }, { markdown: '<div style="transform">div</div>', - expectedHtml: '<div><p>div</p></div>', + expectedHtml: '<div><p dir="auto">div</p></div>', }, ])( 'removes unknown tags and unsupported attributes from HTML output', diff --git a/spec/frontend/content_editor/test_utils.js b/spec/frontend/content_editor/test_utils.js index 2184a829cf0..00aee32753b 100644 --- a/spec/frontend/content_editor/test_utils.js +++ b/spec/frontend/content_editor/test_utils.js @@ -1,7 +1,4 @@ import { Node } from '@tiptap/core'; -import { Document } from '@tiptap/extension-document'; -import { Paragraph } from '@tiptap/extension-paragraph'; -import { Text } from '@tiptap/extension-text'; import { Editor } from '@tiptap/vue-2'; import { builders, eq } from 'prosemirror-test-builder'; import { nextTick } from 'vue'; @@ -18,6 +15,7 @@ import DescriptionList from '~/content_editor/extensions/description_list'; import Details from '~/content_editor/extensions/details'; import DetailsContent from '~/content_editor/extensions/details_content'; import Diagram from '~/content_editor/extensions/diagram'; +import Document from '~/content_editor/extensions/document'; import DrawioDiagram from '~/content_editor/extensions/drawio_diagram'; import Emoji from '~/content_editor/extensions/emoji'; import FootnoteDefinition from '~/content_editor/extensions/footnote_definition'; @@ -36,6 +34,7 @@ import Italic from '~/content_editor/extensions/italic'; import Link from '~/content_editor/extensions/link'; import ListItem from '~/content_editor/extensions/list_item'; import OrderedList from '~/content_editor/extensions/ordered_list'; +import Paragraph from '~/content_editor/extensions/paragraph'; import ReferenceDefinition from '~/content_editor/extensions/reference_definition'; import Reference from '~/content_editor/extensions/reference'; import ReferenceLabel from '~/content_editor/extensions/reference_label'; @@ -47,6 +46,7 @@ import TableRow from '~/content_editor/extensions/table_row'; import TableOfContents from '~/content_editor/extensions/table_of_contents'; import TaskItem from '~/content_editor/extensions/task_item'; import TaskList from '~/content_editor/extensions/task_list'; +import Text from '~/content_editor/extensions/text'; import Video from '~/content_editor/extensions/video'; import HTMLMarks from '~/content_editor/extensions/html_marks'; import HTMLNodes from '~/content_editor/extensions/html_nodes'; diff --git a/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap b/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap index 43050e6edc9..14efe253bd0 100644 --- a/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap +++ b/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap @@ -6,7 +6,9 @@ exports[`Design note component should match the snapshot 1`] = ` id="note_123" > <glavatarlink-stub - class="gl-float-left gl-mr-3 link-inherit-color" + class="gl-float-left gl-mr-3 link-inherit-color js-user-link" + data-user-id="1" + data-username="foo-bar" href="https://gitlab.com/user" > <glavatar-stub diff --git a/spec/frontend/design_management/components/design_notes/design_note_spec.js b/spec/frontend/design_management/components/design_notes/design_note_spec.js index 661d1ac4087..51007483caf 100644 --- a/spec/frontend/design_management/components/design_notes/design_note_spec.js +++ b/spec/frontend/design_management/components/design_notes/design_note_spec.js @@ -92,7 +92,11 @@ describe('Design note component', () => { entityName: note.author.username, }); - expect(findUserAvatarLink().attributes('href')).toBe(note.author.webUrl); + expect(findUserAvatarLink().attributes()).toMatchObject({ + href: note.author.webUrl, + 'data-user-id': '1', + 'data-username': `${note.author.username}`, + }); }); it('should render author details', () => { diff --git a/spec/frontend/notes/components/diff_discussion_header_spec.js b/spec/frontend/notes/components/diff_discussion_header_spec.js index 7a60e7246f1..123d53de3f3 100644 --- a/spec/frontend/notes/components/diff_discussion_header_spec.js +++ b/spec/frontend/notes/components/diff_discussion_header_spec.js @@ -34,9 +34,17 @@ describe('diff_discussion_header component', () => { const findAvatarLink = () => wrapper.findComponent(GlAvatarLink); const findAvatar = () => wrapper.findComponent(GlAvatar); - it('should render user avatar and user avatar link', () => { + it('should render user avatar and user avatar link with popover support', () => { expect(findAvatar().exists()).toBe(true); - expect(findAvatarLink().exists()).toBe(true); + + const avatarLink = findAvatarLink(); + expect(avatarLink.exists()).toBe(true); + expect(avatarLink.classes()).toContain('js-user-link'); + expect(avatarLink.attributes()).toMatchObject({ + href: firstNoteAuthor.path, + 'data-user-id': `${firstNoteAuthor.id}`, + 'data-username': `${firstNoteAuthor.username}`, + }); }); it('renders avatar of the first note author', () => { diff --git a/spec/frontend/notes/components/noteable_note_spec.js b/spec/frontend/notes/components/noteable_note_spec.js index d50fb130a69..0a01e76c2bd 100644 --- a/spec/frontend/notes/components/noteable_note_spec.js +++ b/spec/frontend/notes/components/noteable_note_spec.js @@ -1,6 +1,6 @@ import Vue, { nextTick } from 'vue'; import Vuex from 'vuex'; -import { GlAvatar } from '@gitlab/ui'; +import { GlAvatarLink, GlAvatar } from '@gitlab/ui'; import { clone } from 'lodash'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; @@ -218,6 +218,18 @@ describe('issue_note', () => { }); }); + it('should render user avatar link with popover support', () => { + const { author } = note; + const avatarLink = wrapper.findComponent(GlAvatarLink); + + expect(avatarLink.classes()).toContain('js-user-link'); + expect(avatarLink.attributes()).toMatchObject({ + href: author.path, + 'data-user-id': `${author.id}`, + 'data-username': `${author.username}`, + }); + }); + it('should render user avatar', () => { const { author } = note; const avatar = wrapper.findComponent(GlAvatar); diff --git a/spec/frontend/work_items/components/notes/work_item_note_spec.js b/spec/frontend/work_items/components/notes/work_item_note_spec.js index 09299f1733c..59158d2ba15 100644 --- a/spec/frontend/work_items/components/notes/work_item_note_spec.js +++ b/spec/frontend/work_items/components/notes/work_item_note_spec.js @@ -1,6 +1,7 @@ import { shallowMount } from '@vue/test-utils'; import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; +import { GlAvatarLink } from '@gitlab/ui'; import mockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; import { updateDraft, clearDraft } from '~/lib/utils/autosave'; @@ -270,6 +271,19 @@ describe('Work Item Note', () => { createComponent(); }); + it('should show avatar link with popover support', () => { + const avatarLink = findTimelineEntryItem().findComponent(GlAvatarLink); + const { author } = mockWorkItemCommentNote; + + expect(avatarLink.exists()).toBe(true); + expect(avatarLink.classes()).toContain('js-user-link'); + expect(avatarLink.attributes()).toMatchObject({ + href: author.webUrl, + 'data-user-id': '1', + 'data-username': `${author.username}`, + }); + }); + it('should have the note header, actions and body', () => { expect(findTimelineEntryItem().exists()).toBe(true); expect(findNoteHeader().exists()).toBe(true); diff --git a/spec/lib/api/entities/bulk_imports/export_batch_status_spec.rb b/spec/lib/api/entities/bulk_imports/export_batch_status_spec.rb new file mode 100644 index 00000000000..df190a1306f --- /dev/null +++ b/spec/lib/api/entities/bulk_imports/export_batch_status_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe API::Entities::BulkImports::ExportBatchStatus, feature_category: :importers do + let_it_be(:batch) { create(:bulk_import_export_batch) } + + let(:entity) { described_class.new(batch, request: double) } + + subject { entity.as_json } + + it 'has the correct attributes' do + expect(subject).to eq( + status: batch.status, + batch_number: batch.batch_number, + objects_count: batch.objects_count, + error: batch.error, + updated_at: batch.updated_at + ) + end +end diff --git a/spec/lib/api/entities/bulk_imports/export_status_spec.rb b/spec/lib/api/entities/bulk_imports/export_status_spec.rb index 7d79e372027..b7dbf525a3d 100644 --- a/spec/lib/api/entities/bulk_imports/export_status_spec.rb +++ b/spec/lib/api/entities/bulk_imports/export_status_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe API::Entities::BulkImports::ExportStatus do +RSpec.describe API::Entities::BulkImports::ExportStatus, feature_category: :importers do let_it_be(:export) { create(:bulk_import_export) } let(:entity) { described_class.new(export, request: double) } @@ -10,11 +10,22 @@ RSpec.describe API::Entities::BulkImports::ExportStatus do subject { entity.as_json } it 'has the correct attributes' do - expect(subject).to eq({ + expect(subject).to eq( relation: export.relation, status: export.status, error: export.error, - updated_at: export.updated_at - }) + updated_at: export.updated_at, + batched: export.batched?, + batches_count: export.batches_count, + total_objects_count: export.total_objects_count + ) + end + + context 'when export is batched' do + let_it_be(:export) { create(:bulk_import_export, :batched) } + + it 'exposes batches' do + expect(subject).to match(hash_including(batches: [])) + end end end diff --git a/spec/models/award_emoji_spec.rb b/spec/models/award_emoji_spec.rb index 99006f8ddce..586ec8f723a 100644 --- a/spec/models/award_emoji_spec.rb +++ b/spec/models/award_emoji_spec.rb @@ -141,36 +141,51 @@ RSpec.describe AwardEmoji do end end - describe 'expiring ETag cache' do + describe 'broadcasting updates' do context 'on a note' do let(:note) { create(:note_on_issue) } let(:award_emoji) { build(:award_emoji, user: build(:user), awardable: note) } - it 'calls expire_etag_cache on the note when saved' do + it 'broadcasts updates on the note when saved' do expect(note).to receive(:expire_etag_cache) + expect(note).to receive(:trigger_note_subscription_update) award_emoji.save! end - it 'calls expire_etag_cache on the note when destroyed' do + it 'broadcasts updates on the note when destroyed' do expect(note).to receive(:expire_etag_cache) + expect(note).to receive(:trigger_note_subscription_update) award_emoji.destroy! end + + context 'when importing' do + let(:award_emoji) { build(:award_emoji, user: build(:user), awardable: note, importing: true) } + + it 'does not broadcast updates on the note when saved' do + expect(note).not_to receive(:expire_etag_cache) + expect(note).not_to receive(:trigger_note_subscription_update) + + award_emoji.save! + end + end end context 'on another awardable' do let(:issue) { create(:issue) } let(:award_emoji) { build(:award_emoji, user: build(:user), awardable: issue) } - it 'does not call expire_etag_cache on the issue when saved' do + it 'does not broadcast updates on the issue when saved' do expect(issue).not_to receive(:expire_etag_cache) + expect(issue).not_to receive(:trigger_note_subscription_update) award_emoji.save! end - it 'does not call expire_etag_cache on the issue when destroyed' do + it 'does not broadcast updates on the issue when destroyed' do expect(issue).not_to receive(:expire_etag_cache) + expect(issue).not_to receive(:trigger_note_subscription_update) award_emoji.destroy! end diff --git a/spec/requests/api/group_export_spec.rb b/spec/requests/api/group_export_spec.rb index 9dd5fe6f7c4..b4add2494b0 100644 --- a/spec/requests/api/group_export_spec.rb +++ b/spec/requests/api/group_export_spec.rb @@ -168,8 +168,9 @@ RSpec.describe API::GroupExport, feature_category: :importers do end describe 'relations export' do + let(:relation) { 'labels' } let(:path) { "/groups/#{group.id}/export_relations" } - let(:download_path) { "/groups/#{group.id}/export_relations/download?relation=labels" } + let(:download_path) { "/groups/#{group.id}/export_relations/download?relation=#{relation}" } let(:status_path) { "/groups/#{group.id}/export_relations/status" } before do @@ -196,46 +197,131 @@ RSpec.describe API::GroupExport, feature_category: :importers do expect(response).to have_gitlab_http_status(:error) end end + + context 'when request is to export in batches' do + it 'accepts the request' do + expect(BulkImports::ExportService) + .to receive(:new) + .with(portable: group, user: user, batched: true) + .and_call_original + + post api(path, user), params: { batched: true } + + expect(response).to have_gitlab_http_status(:accepted) + end + end end describe 'GET /groups/:id/export_relations/download' do - let(:export) { create(:bulk_import_export, group: group, relation: 'labels') } - let(:upload) { create(:bulk_import_export_upload, export: export) } + context 'when export request is not batched' do + let(:export) { create(:bulk_import_export, group: group, relation: 'labels') } + let(:upload) { create(:bulk_import_export_upload, export: export) } + + context 'when export file exists' do + it 'downloads exported group archive' do + upload.update!(export_file: fixture_file_upload('spec/fixtures/bulk_imports/gz/labels.ndjson.gz')) + + get api(download_path, user) + + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when export_file.file does not exist' do + it 'returns 404' do + allow(export).to receive(:upload).and_return(nil) + + get api(download_path, user) + + expect(response).to have_gitlab_http_status(:not_found) + expect(json_response['message']).to eq('Export file not found') + end + end + + context 'when export is batched' do + let(:relation) { 'milestones' } + + let_it_be(:export) { create(:bulk_import_export, :batched, group: group, relation: 'milestones') } + + it 'returns 400' do + export.update!(batched: true) + + get api(download_path, user) + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['message']).to eq('Export is batched') + end + end + end - context 'when export file exists' do - it 'downloads exported group archive' do + context 'when export request is batched' do + let(:export) { create(:bulk_import_export, :batched, group: group, relation: 'labels') } + let(:upload) { create(:bulk_import_export_upload) } + let!(:batch) { create(:bulk_import_export_batch, export: export, upload: upload) } + + it 'downloads exported batch' do upload.update!(export_file: fixture_file_upload('spec/fixtures/bulk_imports/gz/labels.ndjson.gz')) - get api(download_path, user) + get api(download_path, user), params: { batched: true, batch_number: batch.batch_number } expect(response).to have_gitlab_http_status(:ok) + expect(response.header['Content-Disposition']) + .to eq("attachment; filename=\"labels.ndjson.gz\"; filename*=UTF-8''labels.ndjson.gz") end - end - context 'when export_file.file does not exist' do - it 'returns 404' do - allow(export).to receive(:upload).and_return(nil) + context 'when request is to download not batched export' do + it 'returns 400' do + get api(download_path, user) - get api(download_path, user) + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['message']).to eq('Export is batched') + end + end - expect(response).to have_gitlab_http_status(:not_found) - expect(json_response['message']).to eq('404 Not found') + context 'when batch cannot be found' do + it 'returns 404' do + get api(download_path, user), params: { batched: true, batch_number: 0 } + + expect(response).to have_gitlab_http_status(:not_found) + expect(json_response['message']).to eq('Batch not found') + end + end + + context 'when batch file cannot be found' do + it 'returns 404' do + batch.upload.destroy! + + get api(download_path, user), params: { batched: true, batch_number: batch.batch_number } + + expect(response).to have_gitlab_http_status(:not_found) + expect(json_response['message']).to eq('Batch file not found') + end end end end describe 'GET /groups/:id/export_relations/status' do - it 'returns a list of relation export statuses' do - create(:bulk_import_export, :started, group: group, relation: 'labels') - create(:bulk_import_export, :finished, group: group, relation: 'milestones') - create(:bulk_import_export, :failed, group: group, relation: 'badges') + let_it_be(:started_export) { create(:bulk_import_export, :started, group: group, relation: 'labels') } + let_it_be(:finished_export) { create(:bulk_import_export, :finished, group: group, relation: 'milestones') } + let_it_be(:failed_export) { create(:bulk_import_export, :failed, group: group, relation: 'badges') } + it 'returns a list of relation export statuses' do get api(status_path, user) expect(response).to have_gitlab_http_status(:ok) expect(json_response.pluck('relation')).to contain_exactly('labels', 'milestones', 'badges') expect(json_response.pluck('status')).to contain_exactly(-1, 0, 1) end + + context 'when relation is specified' do + it 'return a single relation export status' do + get api(status_path, user), params: { relation: 'labels' } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['relation']).to eq('labels') + expect(json_response['status']).to eq(0) + end + end end context 'when bulk import is disabled' do diff --git a/spec/requests/api/project_export_spec.rb b/spec/requests/api/project_export_spec.rb index 434936c0ee7..3603a71151e 100644 --- a/spec/requests/api/project_export_spec.rb +++ b/spec/requests/api/project_export_spec.rb @@ -567,54 +567,138 @@ RSpec.describe API::ProjectExport, :aggregate_failures, :clean_gitlab_redis_cach expect(response).to have_gitlab_http_status(:error) end end + + context 'when request is to export in batches' do + it 'accepts the request' do + expect(BulkImports::ExportService) + .to receive(:new) + .with(portable: project, user: user, batched: true) + .and_call_original + + post api(path, user), params: { batched: true } + + expect(response).to have_gitlab_http_status(:accepted) + end + end end describe 'GET /projects/:id/export_relations/download' do - let_it_be(:export) { create(:bulk_import_export, project: project, relation: 'labels') } - let_it_be(:upload) { create(:bulk_import_export_upload, export: export) } + context 'when export request is not batched' do + let_it_be(:export) { create(:bulk_import_export, project: project, relation: 'labels') } + let_it_be(:upload) { create(:bulk_import_export_upload, export: export) } + + context 'when export file exists' do + it 'downloads exported project relation archive' do + upload.update!(export_file: fixture_file_upload('spec/fixtures/bulk_imports/gz/labels.ndjson.gz')) + + get api(download_path, user) + + expect(response).to have_gitlab_http_status(:ok) + expect(response.header['Content-Disposition']).to eq("attachment; filename=\"labels.ndjson.gz\"; filename*=UTF-8''labels.ndjson.gz") + end + end + + context 'when relation is not portable' do + let(:relation) { ::BulkImports::FileTransfer::ProjectConfig.new(project).skipped_relations.first } + + it_behaves_like '400 response' do + subject(:request) { get api(download_path, user) } + end + end + + context 'when export file does not exist' do + it 'returns 404' do + allow(upload).to receive(:export_file).and_return(nil) + + get api(download_path, user) + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when export is batched' do + let(:relation) { 'issues' } + + let_it_be(:export) { create(:bulk_import_export, :batched, project: project, relation: 'issues') } - context 'when export file exists' do - it 'downloads exported project relation archive' do + it 'returns 400' do + export.update!(batched: true) + + get api(download_path, user) + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['message']).to eq('Export is batched') + end + end + end + + context 'when export request is batched' do + let(:export) { create(:bulk_import_export, :batched, project: project, relation: 'labels') } + let(:upload) { create(:bulk_import_export_upload) } + let!(:batch) { create(:bulk_import_export_batch, export: export, upload: upload) } + + it 'downloads exported batch' do upload.update!(export_file: fixture_file_upload('spec/fixtures/bulk_imports/gz/labels.ndjson.gz')) - get api(download_path, user) + get api(download_path, user), params: { batched: true, batch_number: batch.batch_number } expect(response).to have_gitlab_http_status(:ok) expect(response.header['Content-Disposition']).to eq("attachment; filename=\"labels.ndjson.gz\"; filename*=UTF-8''labels.ndjson.gz") end - end - context 'when relation is not portable' do - let(:relation) { ::BulkImports::FileTransfer::ProjectConfig.new(project).skipped_relations.first } + context 'when request is to download not batched export' do + it 'returns 400' do + get api(download_path, user) - it_behaves_like '400 response' do - subject(:request) { get api(download_path, user) } + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['message']).to eq('Export is batched') + end end - end - context 'when export file does not exist' do - it 'returns 404' do - allow(upload).to receive(:export_file).and_return(nil) + context 'when batch cannot be found' do + it 'returns 404' do + get api(download_path, user), params: { batched: true, batch_number: 0 } - get api(download_path, user) + expect(response).to have_gitlab_http_status(:not_found) + expect(json_response['message']).to eq('Batch not found') + end + end + + context 'when batch file cannot be found' do + it 'returns 404' do + batch.upload.destroy! + + get api(download_path, user), params: { batched: true, batch_number: batch.batch_number } - expect(response).to have_gitlab_http_status(:not_found) + expect(response).to have_gitlab_http_status(:not_found) + expect(json_response['message']).to eq('Batch file not found') + end end end end describe 'GET /projects/:id/export_relations/status' do - it 'returns a list of relation export statuses' do - create(:bulk_import_export, :started, project: project, relation: 'labels') - create(:bulk_import_export, :finished, project: project, relation: 'milestones') - create(:bulk_import_export, :failed, project: project, relation: 'project_badges') + let_it_be(:started_export) { create(:bulk_import_export, :started, project: project, relation: 'labels') } + let_it_be(:finished_export) { create(:bulk_import_export, :finished, project: project, relation: 'milestones') } + let_it_be(:failed_export) { create(:bulk_import_export, :failed, project: project, relation: 'project_badges') } + it 'returns a list of relation export statuses' do get api(status_path, user) expect(response).to have_gitlab_http_status(:ok) expect(json_response.pluck('relation')).to contain_exactly('labels', 'milestones', 'project_badges') expect(json_response.pluck('status')).to contain_exactly(-1, 0, 1) end + + context 'when relation is specified' do + it 'return a single relation export status' do + get api(status_path, user), params: { relation: 'labels' } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['relation']).to eq('labels') + expect(json_response['status']).to eq(0) + end + end end context 'with bulk_import is disabled' do diff --git a/spec/scripts/lib/glfm/update_example_snapshots_spec.rb b/spec/scripts/lib/glfm/update_example_snapshots_spec.rb index 87b2c42c5b8..78ea31c8e39 100644 --- a/spec/scripts/lib/glfm/update_example_snapshots_spec.rb +++ b/spec/scripts/lib/glfm/update_example_snapshots_spec.rb @@ -312,7 +312,7 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process', feature_category: :team static: |- <p>This is the manually modified static HTML which will be preserved</p> wysiwyg: |- - <p>This is the manually modified WYSIWYG HTML which will be preserved</p> + <p dir="auto">This is the manually modified WYSIWYG HTML which will be preserved</p> YAML end @@ -631,33 +631,33 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process', feature_category: :team static: |- <p data-sourcepos="1:1-1:8" dir="auto"><strong>bold</strong></p> wysiwyg: |- - <p><strong>bold</strong></p> + <p dir="auto"><strong>bold</strong></p> 02_01_00__inlines__strong__002: canonical: | <p><strong>bold with more text</strong></p> static: |- <p data-sourcepos="1:1-1:23" dir="auto"><strong>bold with more text</strong></p> wysiwyg: |- - <p><strong>bold with more text</strong></p> + <p dir="auto"><strong>bold with more text</strong></p> 02_03_00__inlines__strikethrough_extension__001: canonical: | <p><del>Hi</del> Hello, world!</p> static: |- <p data-sourcepos="1:1-1:20" dir="auto"><del>Hi</del> Hello, world!</p> wysiwyg: |- - <p><s>Hi</s> Hello, world!</p> + <p dir="auto"><s>Hi</s> Hello, world!</p> 03_01_00__first_gitlab_specific_section_with_examples__strong_but_with_two_asterisks__001: canonical: | <p><strong>bold</strong></p> wysiwyg: |- - <p><strong>bold</strong></p> + <p dir="auto"><strong>bold</strong></p> 03_02_01__first_gitlab_specific_section_with_examples__h2_which_contains_an_h3__example_in_an_h3__001: canonical: | <p>Example in an H3</p> static: |- <p data-sourcepos="1:1-1:16" dir="auto">Example in an H3</p> wysiwyg: |- - <p>Example in an H3</p> + <p dir="auto">Example in an H3</p> 04_01_00__second_gitlab_specific_section_with_examples__strong_but_with_html__001: canonical: | <p><strong> @@ -673,42 +673,42 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process', feature_category: :team static: |- <p>This is the manually modified static HTML which will be preserved</p> wysiwyg: |- - <p>This is the manually modified WYSIWYG HTML which will be preserved</p> + <p dir="auto">This is the manually modified WYSIWYG HTML which will be preserved</p> 06_01_00__api_request_overrides__group_upload_link__001: canonical: | <p><a href="groups-test-file">groups-test-file</a></p> static: |- <p data-sourcepos="1:1-1:45" dir="auto"><a href="/groups/glfm_group/-/uploads/groups-test-file" data-canonical-src="/uploads/groups-test-file" data-link="true" class="gfm">groups-test-file</a></p> wysiwyg: |- - <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uploads/groups-test-file">groups-test-file</a></p> + <p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="/uploads/groups-test-file">groups-test-file</a></p> 06_02_00__api_request_overrides__project_repo_link__001: canonical: | <p><a href="projects-test-file">projects-test-file</a></p> static: |- <p data-sourcepos="1:1-1:40" dir="auto"><a href="/glfm_group/glfm_project/-/blob/master/projects-test-file" class="gfm">projects-test-file</a></p> wysiwyg: |- - <p><a target="_blank" rel="noopener noreferrer nofollow" href="projects-test-file">projects-test-file</a></p> + <p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="projects-test-file">projects-test-file</a></p> 06_03_00__api_request_overrides__project_snippet_ref__001: canonical: | <p>This project snippet ID reference IS filtered: <a href="/glfm_group/glfm_project/-/snippets/88888">$88888</a> static: |- <p data-sourcepos="1:1-1:53" dir="auto">This project snippet ID reference IS filtered: <a href="/glfm_group/glfm_project/-/snippets/88888" data-reference-type="snippet" data-original="$88888" data-link="false" data-link-reference="false" data-project="77777" data-snippet="88888" data-container="body" data-placement="top" title="glfm_project_snippet" class="gfm gfm-snippet has-tooltip">$88888</a></p> wysiwyg: |- - <p>This project snippet ID reference IS filtered: $88888</p> + <p dir="auto">This project snippet ID reference IS filtered: $88888</p> 06_04_00__api_request_overrides__personal_snippet_ref__001: canonical: | <p>This personal snippet ID reference is NOT filtered: $99999</p> static: |- <p data-sourcepos="1:1-1:58" dir="auto">This personal snippet ID reference is NOT filtered: $99999</p> wysiwyg: |- - <p>This personal snippet ID reference is NOT filtered: $99999</p> + <p dir="auto">This personal snippet ID reference is NOT filtered: $99999</p> 06_05_00__api_request_overrides__project_wiki_link__001: canonical: | <p><a href="project-wikis-test-file">project-wikis-test-file</a></p> static: |- <p data-sourcepos="1:1-1:50" dir="auto"><a href="/glfm_group/glfm_project/-/wikis/project-wikis-test-file" data-canonical-src="project-wikis-test-file">project-wikis-test-file</a></p> wysiwyg: |- - <p><a target="_blank" rel="noopener noreferrer nofollow" href="project-wikis-test-file">project-wikis-test-file</a></p> + <p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="project-wikis-test-file">project-wikis-test-file</a></p> YAML end diff --git a/spec/workers/bulk_imports/relation_export_worker_spec.rb b/spec/workers/bulk_imports/relation_export_worker_spec.rb index f91db0388a4..646af6c2a9c 100644 --- a/spec/workers/bulk_imports/relation_export_worker_spec.rb +++ b/spec/workers/bulk_imports/relation_export_worker_spec.rb @@ -47,28 +47,14 @@ RSpec.describe BulkImports::RelationExportWorker, feature_category: :importers d context 'when export is batched' do let(:batched) { true } - context 'when bulk_imports_batched_import_export feature flag is disabled' do - before do - stub_feature_flags(bulk_imports_batched_import_export: false) - end - - include_examples 'export service', BulkImports::RelationExportService + context 'when relation is batchable' do + include_examples 'export service', BulkImports::BatchedRelationExportService end - context 'when bulk_imports_batched_import_export feature flag is enabled' do - before do - stub_feature_flags(bulk_imports_batched_import_export: true) - end - - context 'when relation is batchable' do - include_examples 'export service', BulkImports::BatchedRelationExportService - end + context 'when relation is not batchable' do + let(:relation) { 'namespace_settings' } - context 'when relation is not batchable' do - let(:relation) { 'namespace_settings' } - - include_examples 'export service', BulkImports::RelationExportService - end + include_examples 'export service', BulkImports::RelationExportService end end |