summaryrefslogtreecommitdiff
path: root/spec/frontend/snippets/components
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-05-17 16:05:49 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2023-05-17 16:05:49 +0000
commit43a25d93ebdabea52f99b05e15b06250cd8f07d7 (patch)
treedceebdc68925362117480a5d672bcff122fb625b /spec/frontend/snippets/components
parent20c84b99005abd1c82101dfeff264ac50d2df211 (diff)
downloadgitlab-ce-16.0.0-rc42.tar.gz
Add latest changes from gitlab-org/gitlab@16-0-stable-eev16.0.0-rc4216-0-stable
Diffstat (limited to 'spec/frontend/snippets/components')
-rw-r--r--spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap7
-rw-r--r--spec/frontend/snippets/components/__snapshots__/snippet_visibility_edit_spec.js.snap2
-rw-r--r--spec/frontend/snippets/components/edit_spec.js31
-rw-r--r--spec/frontend/snippets/components/embed_dropdown_spec.js5
-rw-r--r--spec/frontend/snippets/components/show_spec.js4
-rw-r--r--spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js5
-rw-r--r--spec/frontend/snippets/components/snippet_blob_edit_spec.js8
-rw-r--r--spec/frontend/snippets/components/snippet_blob_view_spec.js222
-rw-r--r--spec/frontend/snippets/components/snippet_description_edit_spec.js4
-rw-r--r--spec/frontend/snippets/components/snippet_description_view_spec.js4
-rw-r--r--spec/frontend/snippets/components/snippet_header_spec.js138
-rw-r--r--spec/frontend/snippets/components/snippet_title_spec.js4
-rw-r--r--spec/frontend/snippets/components/snippet_visibility_edit_spec.js4
13 files changed, 227 insertions, 211 deletions
diff --git a/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap b/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap
index fec300ddd7e..c8d972b19a3 100644
--- a/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap
+++ b/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap
@@ -19,7 +19,7 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
<gl-form-input-stub
class="form-control"
data-qa-selector="description_placeholder"
- placeholder="Optionally add a description about what your snippet does or how to use it…"
+ placeholder="Describe what your snippet does or how to use it…"
/>
</div>
@@ -28,10 +28,13 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
data-uploads-path=""
>
<markdown-header-stub
+ data-testid="markdownHeader"
enablepreview="true"
linecontent=""
+ markdownpreviewpath="foo/"
restrictedtoolbaritems=""
suggestionstartindex="0"
+ uploadspath=""
/>
<div
@@ -87,7 +90,7 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
</div>
<div
- class="js-vue-md-preview md md-preview-holder"
+ class="js-vue-md-preview md md-preview-holder gl-px-5"
style="display: none;"
/>
diff --git a/spec/frontend/snippets/components/__snapshots__/snippet_visibility_edit_spec.js.snap b/spec/frontend/snippets/components/__snapshots__/snippet_visibility_edit_spec.js.snap
index f4ebc5c3e3f..ed54582ca29 100644
--- a/spec/frontend/snippets/components/__snapshots__/snippet_visibility_edit_spec.js.snap
+++ b/spec/frontend/snippets/components/__snapshots__/snippet_visibility_edit_spec.js.snap
@@ -13,7 +13,7 @@ exports[`Snippet Visibility Edit component rendering matches the snapshot 1`] =
target="_blank"
>
<gl-icon-stub
- name="question"
+ name="question-o"
size="12"
/>
</gl-link-stub>
diff --git a/spec/frontend/snippets/components/edit_spec.js b/spec/frontend/snippets/components/edit_spec.js
index e7dab0ad79d..d17e20ac227 100644
--- a/spec/frontend/snippets/components/edit_spec.js
+++ b/spec/frontend/snippets/components/edit_spec.js
@@ -9,7 +9,7 @@ import { stubPerformanceWebAPI } from 'helpers/performance';
import waitForPromises from 'helpers/wait_for_promises';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import GetSnippetQuery from 'shared_queries/snippet/snippet.query.graphql';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import * as urlUtils from '~/lib/utils/url_utility';
import SnippetEditApp from '~/snippets/components/edit.vue';
import SnippetBlobActionsEdit from '~/snippets/components/snippet_blob_actions_edit.vue';
@@ -25,7 +25,7 @@ import UpdateSnippetMutation from '~/snippets/mutations/update_snippet.mutation.
import FormFooterActions from '~/vue_shared/components/form/form_footer_actions.vue';
import { testEntries, createGQLSnippetsQueryResponse, createGQLSnippet } from '../test_utils';
-jest.mock('~/flash');
+jest.mock('~/alert');
const TEST_UPLOADED_FILES = ['foo/bar.txt', 'alpha/beta.js'];
const TEST_API_ERROR = new Error('TEST_API_ERROR');
@@ -94,7 +94,6 @@ describe('Snippet Edit app', () => {
let mutateSpy;
const relativeUrlRoot = '/foo/';
- const originalRelativeUrlRoot = gon.relative_url_root;
beforeEach(() => {
stubPerformanceWebAPI();
@@ -108,12 +107,6 @@ describe('Snippet Edit app', () => {
jest.spyOn(urlUtils, 'redirectTo').mockImplementation();
});
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- gon.relative_url_root = originalRelativeUrlRoot;
- });
-
const findBlobActions = () => wrapper.findComponent(SnippetBlobActionsEdit);
const findCancelButton = () => wrapper.findByTestId('snippet-cancel-btn');
const clickSubmitBtn = () => wrapper.findByTestId('snippet-edit-form').trigger('submit');
@@ -132,10 +125,6 @@ describe('Snippet Edit app', () => {
props = {},
selectedLevel = VISIBILITY_LEVEL_PRIVATE_STRING,
} = {}) => {
- if (wrapper) {
- throw new Error('wrapper already created');
- }
-
const requestHandlers = [
[GetSnippetQuery, getSpy],
// See `mutateSpy` declaration comment for why we send a key
@@ -267,7 +256,7 @@ describe('Snippet Edit app', () => {
VISIBILITY_LEVEL_PRIVATE_STRING,
VISIBILITY_LEVEL_INTERNAL_STRING,
VISIBILITY_LEVEL_PUBLIC_STRING,
- ])('marks %s visibility by default', async (visibility) => {
+ ])('marks %s visibility by default', (visibility) => {
createComponent({
props: { snippetGid: '' },
selectedLevel: visibility,
@@ -339,7 +328,7 @@ describe('Snippet Edit app', () => {
it('should redirect to snippet view on successful mutation', async () => {
await createComponentAndSubmit();
- expect(urlUtils.redirectTo).toHaveBeenCalledWith(TEST_WEB_URL);
+ expect(urlUtils.redirectTo).toHaveBeenCalledWith(TEST_WEB_URL); // eslint-disable-line import/no-deprecated
});
describe('when there are errors after creating a new snippet', () => {
@@ -347,7 +336,7 @@ describe('Snippet Edit app', () => {
projectPath
${'project/path'}
${''}
- `('should flash error (projectPath=$projectPath)', async ({ projectPath }) => {
+ `('should alert error (projectPath=$projectPath)', async ({ projectPath }) => {
mutateSpy.mockResolvedValue(createMutationResponseWithErrors('createSnippet'));
await createComponentAndLoad({
@@ -360,7 +349,7 @@ describe('Snippet Edit app', () => {
await waitForPromises();
- expect(urlUtils.redirectTo).not.toHaveBeenCalled();
+ expect(urlUtils.redirectTo).not.toHaveBeenCalled(); // eslint-disable-line import/no-deprecated
expect(createAlert).toHaveBeenCalledWith({
message: `Can't create snippet: ${TEST_MUTATION_ERROR}`,
});
@@ -373,7 +362,7 @@ describe('Snippet Edit app', () => {
${'project/path'}
${''}
`(
- 'should flash error with (snippet=$snippetGid, projectPath=$projectPath)',
+ 'should alert error with (snippet=$snippetGid, projectPath=$projectPath)',
async ({ projectPath }) => {
mutateSpy.mockResolvedValue(createMutationResponseWithErrors('updateSnippet'));
@@ -384,7 +373,7 @@ describe('Snippet Edit app', () => {
},
});
- expect(urlUtils.redirectTo).not.toHaveBeenCalled();
+ expect(urlUtils.redirectTo).not.toHaveBeenCalled(); // eslint-disable-line import/no-deprecated
expect(createAlert).toHaveBeenCalledWith({
message: `Can't update snippet: ${TEST_MUTATION_ERROR}`,
});
@@ -402,10 +391,10 @@ describe('Snippet Edit app', () => {
});
it('should not redirect', () => {
- expect(urlUtils.redirectTo).not.toHaveBeenCalled();
+ expect(urlUtils.redirectTo).not.toHaveBeenCalled(); // eslint-disable-line import/no-deprecated
});
- it('should flash', () => {
+ it('should alert', () => {
// Apollo automatically wraps the resolver's error in a NetworkError
expect(createAlert).toHaveBeenCalledWith({
message: `Can't update snippet: ${TEST_API_ERROR.message}`,
diff --git a/spec/frontend/snippets/components/embed_dropdown_spec.js b/spec/frontend/snippets/components/embed_dropdown_spec.js
index ed5ea6cab8a..d8c6ad3278a 100644
--- a/spec/frontend/snippets/components/embed_dropdown_spec.js
+++ b/spec/frontend/snippets/components/embed_dropdown_spec.js
@@ -17,11 +17,6 @@ describe('snippets/components/embed_dropdown', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
const findSectionsData = () => {
const sections = [];
let current = {};
diff --git a/spec/frontend/snippets/components/show_spec.js b/spec/frontend/snippets/components/show_spec.js
index 032dcf8e5f5..45a7c7b0b4a 100644
--- a/spec/frontend/snippets/components/show_spec.js
+++ b/spec/frontend/snippets/components/show_spec.js
@@ -50,10 +50,6 @@ describe('Snippet view app', () => {
stubPerformanceWebAPI();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders loader while the query is in flight', () => {
createComponent({ loading: true });
expect(findLoadingIcon().exists()).toBe(true);
diff --git a/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js b/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js
index a650353093d..58f47e8b0dc 100644
--- a/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js
+++ b/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js
@@ -56,11 +56,6 @@ describe('snippets/components/snippet_blob_actions_edit', () => {
const triggerBlobDelete = (idx) => findBlobEdits().at(idx).vm.$emit('delete');
const triggerBlobUpdate = (idx, props) => findBlobEdits().at(idx).vm.$emit('blob-updated', props);
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
describe('multi-file snippets rendering', () => {
beforeEach(() => {
createComponent();
diff --git a/spec/frontend/snippets/components/snippet_blob_edit_spec.js b/spec/frontend/snippets/components/snippet_blob_edit_spec.js
index 82c4a37ccc9..b699e056576 100644
--- a/spec/frontend/snippets/components/snippet_blob_edit_spec.js
+++ b/spec/frontend/snippets/components/snippet_blob_edit_spec.js
@@ -4,14 +4,14 @@ import AxiosMockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants';
import waitForPromises from 'helpers/wait_for_promises';
import BlobHeaderEdit from '~/blob/components/blob_edit_header.vue';
-import { createAlert } from '~/flash';
+import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { joinPaths } from '~/lib/utils/url_utility';
import SnippetBlobEdit from '~/snippets/components/snippet_blob_edit.vue';
import SourceEditor from '~/vue_shared/components/source_editor.vue';
-jest.mock('~/flash');
+jest.mock('~/alert');
const TEST_ID = 'blob_local_7';
const TEST_PATH = 'foo/bar/test.md';
@@ -62,8 +62,6 @@ describe('Snippet Blob Edit component', () => {
});
afterEach(() => {
- wrapper.destroy();
- wrapper = null;
axiosMock.restore();
});
@@ -123,7 +121,7 @@ describe('Snippet Blob Edit component', () => {
createComponent();
});
- it('should call flash', async () => {
+ it('should call alert', async () => {
await waitForPromises();
expect(createAlert).toHaveBeenCalledWith({
diff --git a/spec/frontend/snippets/components/snippet_blob_view_spec.js b/spec/frontend/snippets/components/snippet_blob_view_spec.js
index c7ff8c21d80..05ff64c2296 100644
--- a/spec/frontend/snippets/components/snippet_blob_view_spec.js
+++ b/spec/frontend/snippets/components/snippet_blob_view_spec.js
@@ -1,5 +1,6 @@
-import { mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { shallowMount } from '@vue/test-utils';
import {
Blob as BlobMock,
SimpleViewerMock,
@@ -7,6 +8,7 @@ import {
RichBlobContentMock,
SimpleBlobContentMock,
} from 'jest/blob/components/mock_data';
+import GetBlobContent from 'shared_queries/snippet/snippet_blob_content.query.graphql';
import BlobContent from '~/blob/components/blob_content.vue';
import BlobHeader from '~/blob/components/blob_header.vue';
import {
@@ -17,9 +19,13 @@ import {
import SnippetBlobView from '~/snippets/components/snippet_blob_view.vue';
import { VISIBILITY_LEVEL_PUBLIC_STRING } from '~/visibility_level/constants';
import { RichViewer, SimpleViewer } from '~/vue_shared/components/blob_viewers';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
describe('Blob Embeddable', () => {
let wrapper;
+ let requestHandlers;
+
const snippet = {
id: 'gid://foo.bar/snippet',
webUrl: 'https://foo.bar',
@@ -29,23 +35,47 @@ describe('Blob Embeddable', () => {
activeViewerType: SimpleViewerMock.type,
};
+ const mockDefaultHandler = ({ path, nodes } = { path: BlobMock.path }) => {
+ const renderedNodes = nodes || [
+ { __typename: 'Blob', path, richData: 'richData', plainData: 'plainData' },
+ ];
+
+ return jest.fn().mockResolvedValue({
+ data: {
+ snippets: {
+ __typename: 'Snippet',
+ id: '1',
+ nodes: [
+ {
+ __typename: 'Snippet',
+ id: '2',
+ blobs: {
+ __typename: 'Blob',
+ hasUnretrievableBlobs: false,
+ nodes: renderedNodes,
+ },
+ },
+ ],
+ },
+ },
+ });
+ };
+
+ const createMockApolloProvider = (handler) => {
+ Vue.use(VueApollo);
+
+ requestHandlers = handler;
+ return createMockApollo([[GetBlobContent, requestHandlers]]);
+ };
+
function createComponent({
snippetProps = {},
data = dataMock,
blob = BlobMock,
- contentLoading = false,
+ handler = mockDefaultHandler(),
} = {}) {
- const $apollo = {
- queries: {
- blobContent: {
- loading: contentLoading,
- refetch: jest.fn(),
- skip: true,
- },
- },
- };
-
- wrapper = mount(SnippetBlobView, {
+ wrapper = shallowMount(SnippetBlobView, {
+ apolloProvider: createMockApolloProvider(handler),
propsData: {
snippet: {
...snippet,
@@ -58,45 +88,56 @@ describe('Blob Embeddable', () => {
...data,
};
},
- mocks: { $apollo },
+ stubs: {
+ BlobHeader,
+ BlobContent,
+ },
});
}
- afterEach(() => {
- wrapper.destroy();
- });
+ const findBlobHeader = () => wrapper.findComponent(BlobHeader);
+ const findBlobContent = () => wrapper.findComponent(BlobContent);
+ const findSimpleViewer = () => wrapper.findComponent(SimpleViewer);
+ const findRichViewer = () => wrapper.findComponent(RichViewer);
describe('rendering', () => {
it('renders correct components', () => {
createComponent();
- expect(wrapper.findComponent(BlobHeader).exists()).toBe(true);
- expect(wrapper.findComponent(BlobContent).exists()).toBe(true);
+ expect(findBlobHeader().exists()).toBe(true);
+ expect(findBlobContent().exists()).toBe(true);
});
- it('sets simple viewer correctly', () => {
+ it('sets simple viewer correctly', async () => {
createComponent();
- expect(wrapper.findComponent(SimpleViewer).exists()).toBe(true);
+ await waitForPromises();
+
+ expect(findSimpleViewer().exists()).toBe(true);
});
- it('sets rich viewer correctly', () => {
+ it('sets rich viewer correctly', async () => {
const data = { ...dataMock, activeViewerType: RichViewerMock.type };
createComponent({
data,
});
- expect(wrapper.findComponent(RichViewer).exists()).toBe(true);
+ await waitForPromises();
+ expect(findRichViewer().exists()).toBe(true);
});
it('correctly switches viewer type', async () => {
createComponent();
- expect(wrapper.findComponent(SimpleViewer).exists()).toBe(true);
+ await waitForPromises();
+
+ expect(findSimpleViewer().exists()).toBe(true);
- wrapper.vm.switchViewer(RichViewerMock.type);
+ findBlobContent().vm.$emit(BLOB_RENDER_EVENT_SHOW_SOURCE, RichViewerMock.type);
+ await waitForPromises();
- await nextTick();
- expect(wrapper.findComponent(RichViewer).exists()).toBe(true);
- await wrapper.vm.switchViewer(SimpleViewerMock.type);
+ expect(findRichViewer().exists()).toBe(true);
- expect(wrapper.findComponent(SimpleViewer).exists()).toBe(true);
+ findBlobContent().vm.$emit(BLOB_RENDER_EVENT_SHOW_SOURCE, SimpleViewerMock.type);
+ await waitForPromises();
+
+ expect(findSimpleViewer().exists()).toBe(true);
});
it('passes information about render error down to blob header', () => {
@@ -110,7 +151,7 @@ describe('Blob Embeddable', () => {
},
});
- expect(wrapper.findComponent(BlobHeader).props('hasRenderError')).toBe(true);
+ expect(findBlobHeader().props('hasRenderError')).toBe(true);
});
describe('bob content in multi-file scenario', () => {
@@ -123,47 +164,38 @@ describe('Blob Embeddable', () => {
richData: 'Another Rich Foo',
};
+ const MixedSimpleBlobContentMock = {
+ ...SimpleBlobContentMock,
+ richData: '<h1>Rich</h1>',
+ };
+
+ const MixedRichBlobContentMock = {
+ ...RichBlobContentMock,
+ plainData: 'Plain',
+ };
+
it.each`
- snippetBlobs | description | currentBlob | expectedContent
- ${[SimpleBlobContentMock]} | ${'one existing textual blob'} | ${SimpleBlobContentMock} | ${SimpleBlobContentMock.plainData}
- ${[RichBlobContentMock]} | ${'one existing rich blob'} | ${RichBlobContentMock} | ${RichBlobContentMock.richData}
- ${[SimpleBlobContentMock, RichBlobContentMock]} | ${'mixed blobs with current textual blob'} | ${SimpleBlobContentMock} | ${SimpleBlobContentMock.plainData}
- ${[SimpleBlobContentMock, RichBlobContentMock]} | ${'mixed blobs with current rich blob'} | ${RichBlobContentMock} | ${RichBlobContentMock.richData}
- ${[SimpleBlobContentMock, SimpleBlobContentMock2]} | ${'textual blobs with current textual blob'} | ${SimpleBlobContentMock} | ${SimpleBlobContentMock.plainData}
- ${[RichBlobContentMock, RichBlobContentMock2]} | ${'rich blobs with current rich blob'} | ${RichBlobContentMock} | ${RichBlobContentMock.richData}
+ snippetBlobs | description | currentBlob | expectedContent | activeViewerType
+ ${[SimpleBlobContentMock]} | ${'one existing textual blob'} | ${SimpleBlobContentMock} | ${SimpleBlobContentMock.plainData} | ${SimpleViewerMock.type}
+ ${[RichBlobContentMock]} | ${'one existing rich blob'} | ${RichBlobContentMock} | ${RichBlobContentMock.richData} | ${RichViewerMock.type}
+ ${[SimpleBlobContentMock, MixedRichBlobContentMock]} | ${'mixed blobs with current textual blob'} | ${SimpleBlobContentMock} | ${SimpleBlobContentMock.plainData} | ${SimpleViewerMock.type}
+ ${[MixedSimpleBlobContentMock, RichBlobContentMock]} | ${'mixed blobs with current rich blob'} | ${RichBlobContentMock} | ${RichBlobContentMock.richData} | ${RichViewerMock.type}
+ ${[SimpleBlobContentMock, SimpleBlobContentMock2]} | ${'textual blobs with current textual blob'} | ${SimpleBlobContentMock} | ${SimpleBlobContentMock.plainData} | ${SimpleViewerMock.type}
+ ${[RichBlobContentMock, RichBlobContentMock2]} | ${'rich blobs with current rich blob'} | ${RichBlobContentMock} | ${RichBlobContentMock.richData} | ${RichViewerMock.type}
`(
'renders correct content for $description',
- async ({ snippetBlobs, currentBlob, expectedContent }) => {
- const apolloData = {
- snippets: {
- nodes: [
- {
- blobs: {
- nodes: snippetBlobs,
- },
- },
- ],
- },
- };
+ async ({ snippetBlobs, currentBlob, expectedContent, activeViewerType }) => {
createComponent({
+ handler: mockDefaultHandler({ path: currentBlob.path, nodes: snippetBlobs }),
+ data: { activeViewerType },
blob: {
...BlobMock,
path: currentBlob.path,
},
});
+ await waitForPromises();
- // mimic apollo's update
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- blobContent: wrapper.vm.onContentUpdate(apolloData),
- });
-
- await nextTick();
-
- const findContent = () => wrapper.findComponent(BlobContent);
-
- expect(findContent().props('content')).toBe(expectedContent);
+ expect(findBlobContent().props('content')).toBe(expectedContent);
},
);
});
@@ -178,28 +210,32 @@ describe('Blob Embeddable', () => {
window.location.hash = '#LC2';
});
- it('renders simple viewer by default', () => {
+ it('renders simple viewer by default', async () => {
createComponent({
data: {},
});
+ await waitForPromises();
- expect(wrapper.vm.activeViewerType).toBe(SimpleViewerMock.type);
- expect(wrapper.findComponent(SimpleViewer).exists()).toBe(true);
+ expect(findBlobHeader().props('activeViewerType')).toBe(SimpleViewerMock.type);
+ expect(findSimpleViewer().exists()).toBe(true);
});
describe('switchViewer()', () => {
it('switches to the passed viewer', async () => {
createComponent();
+ await waitForPromises();
+
+ findBlobContent().vm.$emit(BLOB_RENDER_EVENT_SHOW_SOURCE, RichViewerMock.type);
+ await waitForPromises();
- wrapper.vm.switchViewer(RichViewerMock.type);
+ expect(findBlobHeader().props('activeViewerType')).toBe(RichViewerMock.type);
+ expect(findRichViewer().exists()).toBe(true);
- await nextTick();
- expect(wrapper.vm.activeViewerType).toBe(RichViewerMock.type);
- expect(wrapper.findComponent(RichViewer).exists()).toBe(true);
+ findBlobContent().vm.$emit(BLOB_RENDER_EVENT_SHOW_SOURCE, SimpleViewerMock.type);
+ await waitForPromises();
- await wrapper.vm.switchViewer(SimpleViewerMock.type);
- expect(wrapper.vm.activeViewerType).toBe(SimpleViewerMock.type);
- expect(wrapper.findComponent(SimpleViewer).exists()).toBe(true);
+ expect(findBlobHeader().props('activeViewerType')).toBe(SimpleViewerMock.type);
+ expect(findSimpleViewer().exists()).toBe(true);
});
});
});
@@ -209,28 +245,32 @@ describe('Blob Embeddable', () => {
window.location.hash = '#last-headline';
});
- it('renders rich viewer by default', () => {
+ it('renders rich viewer by default', async () => {
createComponent({
data: {},
});
+ await waitForPromises();
- expect(wrapper.vm.activeViewerType).toBe(RichViewerMock.type);
- expect(wrapper.findComponent(RichViewer).exists()).toBe(true);
+ expect(findBlobHeader().props('activeViewerType')).toBe(RichViewerMock.type);
+ expect(findRichViewer().exists()).toBe(true);
});
describe('switchViewer()', () => {
it('switches to the passed viewer', async () => {
createComponent();
+ await waitForPromises();
- wrapper.vm.switchViewer(SimpleViewerMock.type);
+ findBlobContent().vm.$emit(BLOB_RENDER_EVENT_SHOW_SOURCE, SimpleViewerMock.type);
+ await waitForPromises();
- await nextTick();
- expect(wrapper.vm.activeViewerType).toBe(SimpleViewerMock.type);
- expect(wrapper.findComponent(SimpleViewer).exists()).toBe(true);
+ expect(findBlobHeader().props('activeViewerType')).toBe(SimpleViewerMock.type);
+ expect(findSimpleViewer().exists()).toBe(true);
- await wrapper.vm.switchViewer(RichViewerMock.type);
- expect(wrapper.vm.activeViewerType).toBe(RichViewerMock.type);
- expect(wrapper.findComponent(RichViewer).exists()).toBe(true);
+ findBlobContent().vm.$emit(BLOB_RENDER_EVENT_SHOW_SOURCE, RichViewerMock.type);
+ await waitForPromises();
+
+ expect(findBlobHeader().props('activeViewerType')).toBe(RichViewerMock.type);
+ expect(findRichViewer().exists()).toBe(true);
});
});
});
@@ -239,19 +279,21 @@ describe('Blob Embeddable', () => {
describe('functionality', () => {
describe('render error', () => {
- const findContentEl = () => wrapper.findComponent(BlobContent);
-
it('correctly sets blob on the blob-content-error component', () => {
createComponent();
- expect(findContentEl().props('blob')).toEqual(BlobMock);
+ expect(findBlobContent().props('blob')).toEqual(BlobMock);
});
- it(`refetches blob content on ${BLOB_RENDER_EVENT_LOAD} event`, () => {
+ it(`refetches blob content on ${BLOB_RENDER_EVENT_LOAD} event`, async () => {
createComponent();
+ await waitForPromises();
+
+ expect(requestHandlers).toHaveBeenCalledTimes(1);
+
+ findBlobContent().vm.$emit(BLOB_RENDER_EVENT_LOAD);
+ await waitForPromises();
- expect(wrapper.vm.$apollo.queries.blobContent.refetch).not.toHaveBeenCalled();
- findContentEl().vm.$emit(BLOB_RENDER_EVENT_LOAD);
- expect(wrapper.vm.$apollo.queries.blobContent.refetch).toHaveBeenCalledTimes(1);
+ expect(requestHandlers).toHaveBeenCalledTimes(2);
});
it(`sets '${SimpleViewerMock.type}' as active on ${BLOB_RENDER_EVENT_SHOW_SOURCE} event`, () => {
@@ -261,7 +303,7 @@ describe('Blob Embeddable', () => {
},
});
- findContentEl().vm.$emit(BLOB_RENDER_EVENT_SHOW_SOURCE);
+ findBlobContent().vm.$emit(BLOB_RENDER_EVENT_SHOW_SOURCE);
expect(wrapper.vm.activeViewerType).toEqual(SimpleViewerMock.type);
});
});
diff --git a/spec/frontend/snippets/components/snippet_description_edit_spec.js b/spec/frontend/snippets/components/snippet_description_edit_spec.js
index ff75515e71a..2b42eba19c2 100644
--- a/spec/frontend/snippets/components/snippet_description_edit_spec.js
+++ b/spec/frontend/snippets/components/snippet_description_edit_spec.js
@@ -30,10 +30,6 @@ describe('Snippet Description Edit component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('rendering', () => {
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
diff --git a/spec/frontend/snippets/components/snippet_description_view_spec.js b/spec/frontend/snippets/components/snippet_description_view_spec.js
index 14f116f2aaf..3c5d50ccaa6 100644
--- a/spec/frontend/snippets/components/snippet_description_view_spec.js
+++ b/spec/frontend/snippets/components/snippet_description_view_spec.js
@@ -17,10 +17,6 @@ describe('Snippet Description component', () => {
createComponent();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
diff --git a/spec/frontend/snippets/components/snippet_header_spec.js b/spec/frontend/snippets/components/snippet_header_spec.js
index c930c9f635b..4bf64bfd3cd 100644
--- a/spec/frontend/snippets/components/snippet_header_spec.js
+++ b/spec/frontend/snippets/components/snippet_header_spec.js
@@ -1,8 +1,9 @@
-import { GlButton, GlModal, GlDropdown } from '@gitlab/ui';
+import { GlModal, GlButton, GlDropdown } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
-import { ApolloMutation } from 'vue-apollo';
+import VueApollo from 'vue-apollo';
import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
+import Vue, { nextTick } from 'vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { Blob, BinaryBlob } from 'jest/blob/components/mock_data';
@@ -10,31 +11,41 @@ import { differenceInMilliseconds } from '~/lib/utils/datetime_utility';
import SnippetHeader, { i18n } from '~/snippets/components/snippet_header.vue';
import DeleteSnippetMutation from '~/snippets/mutations/delete_snippet.mutation.graphql';
import axios from '~/lib/utils/axios_utils';
-import { createAlert, VARIANT_DANGER, VARIANT_SUCCESS } from '~/flash';
+import { createAlert, VARIANT_DANGER, VARIANT_SUCCESS } from '~/alert';
+import CanCreateProjectSnippet from 'shared_queries/snippet/project_permissions.query.graphql';
+import CanCreatePersonalSnippet from 'shared_queries/snippet/user_permissions.query.graphql';
+import { getCanCreateProjectSnippetMock, getCanCreatePersonalSnippetMock } from '../mock_data';
-jest.mock('~/flash');
+const ERROR_MSG = 'Foo bar';
+const ERR = { message: ERROR_MSG };
+
+const MUTATION_TYPES = {
+ RESOLVE: jest.fn().mockResolvedValue({ data: { destroySnippet: { errors: [] } } }),
+ REJECT: jest.fn().mockRejectedValue(ERR),
+};
+
+jest.mock('~/alert');
+
+Vue.use(VueApollo);
describe('Snippet header component', () => {
let wrapper;
let snippet;
- let mutationTypes;
- let mutationVariables;
let mock;
+ let mockApollo;
- let errorMsg;
- let err;
- const originalRelativeUrlRoot = gon.relative_url_root;
const reportAbusePath = '/-/snippets/42/mark_as_spam';
const canReportSpam = true;
const GlEmoji = { template: '<img/>' };
function createComponent({
- loading = false,
permissions = {},
- mutationRes = mutationTypes.RESOLVE,
snippetProps = {},
provide = {},
+ canCreateProjectSnippetMock = jest.fn().mockResolvedValue(getCanCreateProjectSnippetMock()),
+ canCreatePersonalSnippetMock = jest.fn().mockResolvedValue(getCanCreatePersonalSnippetMock()),
+ deleteSnippetMock = MUTATION_TYPES.RESOLVE,
} = {}) {
const defaultProps = Object.assign(snippet, snippetProps);
if (permissions) {
@@ -42,17 +53,14 @@ describe('Snippet header component', () => {
...permissions,
});
}
- const $apollo = {
- queries: {
- canCreateSnippet: {
- loading,
- },
- },
- mutate: mutationRes,
- };
+
+ mockApollo = createMockApollo([
+ [CanCreateProjectSnippet, canCreateProjectSnippetMock],
+ [CanCreatePersonalSnippet, canCreatePersonalSnippetMock],
+ [DeleteSnippetMutation, deleteSnippetMock],
+ ]);
wrapper = mount(SnippetHeader, {
- mocks: { $apollo },
provide: {
reportAbusePath,
canReportSpam,
@@ -64,9 +72,9 @@ describe('Snippet header component', () => {
},
},
stubs: {
- ApolloMutation,
GlEmoji,
},
+ apolloProvider: mockApollo,
});
}
@@ -91,6 +99,7 @@ describe('Snippet header component', () => {
title: x.attributes('title'),
text: x.text(),
}));
+ const findDeleteModal = () => wrapper.findComponent(GlModal);
beforeEach(() => {
gon.relative_url_root = '/foo/';
@@ -113,28 +122,12 @@ describe('Snippet header component', () => {
createdAt: new Date(differenceInMilliseconds(32 * 24 * 3600 * 1000)).toISOString(),
};
- mutationVariables = {
- mutation: DeleteSnippetMutation,
- variables: {
- id: snippet.id,
- },
- };
-
- errorMsg = 'Foo bar';
- err = { message: errorMsg };
-
- mutationTypes = {
- RESOLVE: jest.fn(() => Promise.resolve({ data: { destroySnippet: { errors: [] } } })),
- REJECT: jest.fn(() => Promise.reject(err)),
- };
-
mock = new MockAdapter(axios);
});
afterEach(() => {
- wrapper.destroy();
+ mockApollo = null;
mock.restore();
- gon.relative_url_root = originalRelativeUrlRoot;
});
it('renders itself', () => {
@@ -238,15 +231,16 @@ describe('Snippet header component', () => {
});
it('with canCreateSnippet permission, renders create button', async () => {
- createComponent();
+ createComponent({
+ canCreateProjectSnippetMock: jest
+ .fn()
+ .mockResolvedValue(getCanCreateProjectSnippetMock(true)),
+ canCreatePersonalSnippetMock: jest
+ .fn()
+ .mockResolvedValue(getCanCreatePersonalSnippetMock(true)),
+ });
- // TODO: we should avoid `wrapper.setData` since they
- // are component internals. Let's use the apollo mock helpers
- // in a follow-up.
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ canCreateSnippet: true });
- await nextTick();
+ await waitForPromises();
expect(findButtonsAsModel()).toEqual(
expect.arrayContaining([
@@ -262,7 +256,7 @@ describe('Snippet header component', () => {
});
describe('submit snippet as spam', () => {
- beforeEach(async () => {
+ beforeEach(() => {
createComponent();
});
@@ -271,7 +265,7 @@ describe('Snippet header component', () => {
${200} | ${VARIANT_SUCCESS} | ${i18n.snippetSpamSuccess}
${500} | ${VARIANT_DANGER} | ${i18n.snippetSpamFailure}
`(
- 'renders a "$variant" flash message with "$text" message for a request with a "$request" response',
+ 'renders a "$variant" alert message with "$text" message for a request with a "$request" response',
async ({ request, variant, text }) => {
const submitAsSpamBtn = findButtons().at(2);
mock.onPost(reportAbusePath).reply(request);
@@ -329,21 +323,37 @@ describe('Snippet header component', () => {
});
describe('Delete mutation', () => {
- it('dispatches a mutation to delete the snippet with correct variables', () => {
+ const deleteSnippet = async () => {
+ // Click delete action
+ findButtons().at(1).trigger('click');
+ await nextTick();
+
+ expect(findDeleteModal().props().visible).toBe(true);
+
+ // Click delete button in delete modal
+ document.querySelector('[data-testid="delete-snippet"').click();
+ await waitForPromises();
+ };
+
+ it('dispatches a mutation to delete the snippet with correct variables', async () => {
createComponent();
- wrapper.vm.deleteSnippet();
- expect(mutationTypes.RESOLVE).toHaveBeenCalledWith(mutationVariables);
+
+ await deleteSnippet();
+
+ expect(MUTATION_TYPES.RESOLVE).toHaveBeenCalledWith({
+ id: snippet.id,
+ });
});
it('sets error message if mutation fails', async () => {
- createComponent({ mutationRes: mutationTypes.REJECT });
+ createComponent({ deleteSnippetMock: MUTATION_TYPES.REJECT });
expect(Boolean(wrapper.vm.errorMessage)).toBe(false);
- wrapper.vm.deleteSnippet();
-
- await waitForPromises();
+ await deleteSnippet();
- expect(wrapper.vm.errorMessage).toEqual(errorMsg);
+ expect(document.querySelector('[data-testid="delete-alert"').textContent.trim()).toBe(
+ ERROR_MSG,
+ );
});
describe('in case of successful mutation, closes modal and redirects to correct listing', () => {
@@ -353,15 +363,16 @@ describe('Snippet header component', () => {
createComponent({
snippetProps,
});
- wrapper.vm.closeDeleteModal = jest.fn();
- wrapper.vm.deleteSnippet();
- await nextTick();
+ await deleteSnippet();
};
it('redirects to dashboard/snippets for personal snippet', async () => {
await createDeleteSnippet();
- expect(wrapper.vm.closeDeleteModal).toHaveBeenCalled();
+
+ // Check that the modal is hidden after deleting the snippet
+ expect(findDeleteModal().props().visible).toBe(false);
+
expect(window.location.pathname).toBe(`${gon.relative_url_root}dashboard/snippets`);
});
@@ -372,7 +383,10 @@ describe('Snippet header component', () => {
fullPath,
},
});
- expect(wrapper.vm.closeDeleteModal).toHaveBeenCalled();
+
+ // Check that the modal is hidden after deleting the snippet
+ expect(findDeleteModal().props().visible).toBe(false);
+
expect(window.location.pathname).toBe(`${fullPath}/-/snippets`);
});
});
diff --git a/spec/frontend/snippets/components/snippet_title_spec.js b/spec/frontend/snippets/components/snippet_title_spec.js
index 7c40735d64e..0a3b57c9244 100644
--- a/spec/frontend/snippets/components/snippet_title_spec.js
+++ b/spec/frontend/snippets/components/snippet_title_spec.js
@@ -26,10 +26,6 @@ describe('Snippet header component', () => {
});
}
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders itself', () => {
createComponent();
expect(wrapper.find('.snippet-header').exists()).toBe(true);
diff --git a/spec/frontend/snippets/components/snippet_visibility_edit_spec.js b/spec/frontend/snippets/components/snippet_visibility_edit_spec.js
index 29eb002ef4a..70eb719f706 100644
--- a/spec/frontend/snippets/components/snippet_visibility_edit_spec.js
+++ b/spec/frontend/snippets/components/snippet_visibility_edit_spec.js
@@ -51,10 +51,6 @@ describe('Snippet Visibility Edit component', () => {
};
});
- afterEach(() => {
- wrapper.destroy();
- });
-
describe('rendering', () => {
it('matches the snapshot', () => {
createComponent();