summaryrefslogtreecommitdiff
path: root/spec/frontend/snippets
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/snippets')
-rw-r--r--spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap6
-rw-r--r--spec/frontend/snippets/components/__snapshots__/snippet_visibility_edit_spec.js.snap8
-rw-r--r--spec/frontend/snippets/components/edit_spec.js23
-rw-r--r--spec/frontend/snippets/components/embed_dropdown_spec.js70
-rw-r--r--spec/frontend/snippets/components/show_spec.js12
-rw-r--r--spec/frontend/snippets/components/snippet_blob_edit_spec.js17
-rw-r--r--spec/frontend/snippets/components/snippet_header_spec.js8
-rw-r--r--spec/frontend/snippets/components/snippet_visibility_edit_spec.js118
8 files changed, 211 insertions, 51 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 6020d595e3f..3b101e9e815 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
@@ -41,7 +41,7 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
>
<textarea
aria-label="Description"
- class="note-textarea js-gfm-input js-autosize markdown-area"
+ class="note-textarea js-gfm-input js-autosize markdown-area js-gfm-input-initialized"
data-qa-selector="snippet_description_field"
data-supports-quick-actions="false"
dir="auto"
@@ -63,8 +63,8 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
class="zen-control zen-control-leave js-zen-leave gl-text-gray-500"
href="#"
>
- <icon-stub
- name="screen-normal"
+ <gl-icon-stub
+ name="minimize"
size="16"
/>
</a>
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 be75a5bfbdc..8446f0f50c4 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
@@ -20,6 +20,7 @@ exports[`Snippet Visibility Edit component rendering matches the snapshot 1`] =
</label>
<gl-form-group-stub
+ class="gl-mb-0"
id="visibility-level-setting"
>
<gl-form-radio-group-stub
@@ -90,5 +91,12 @@ exports[`Snippet Visibility Edit component rendering matches the snapshot 1`] =
</gl-form-radio-stub>
</gl-form-radio-group-stub>
</gl-form-group-stub>
+
+ <div
+ class="text-muted"
+ data-testid="restricted-levels-info"
+ >
+ <!---->
+ </div>
</div>
`;
diff --git a/spec/frontend/snippets/components/edit_spec.js b/spec/frontend/snippets/components/edit_spec.js
index ebab6aa84f6..b6abb9f389a 100644
--- a/spec/frontend/snippets/components/edit_spec.js
+++ b/spec/frontend/snippets/components/edit_spec.js
@@ -47,6 +47,8 @@ const createTestSnippet = () => ({
describe('Snippet Edit app', () => {
let wrapper;
+ const relativeUrlRoot = '/foo/';
+ const originalRelativeUrlRoot = gon.relative_url_root;
const mutationTypes = {
RESOLVE: jest.fn().mockResolvedValue({
@@ -100,16 +102,25 @@ describe('Snippet Edit app', () => {
markdownDocsPath: 'http://docs.foo.bar',
...props,
},
+ data() {
+ return {
+ snippet: {
+ visibilityLevel: SNIPPET_VISIBILITY_PRIVATE,
+ },
+ };
+ },
});
}
beforeEach(() => {
+ gon.relative_url_root = relativeUrlRoot;
jest.spyOn(urlUtils, 'redirectTo').mockImplementation();
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
+ gon.relative_url_root = originalRelativeUrlRoot;
});
const findBlobActions = () => wrapper.find(SnippetBlobActionsEdit);
@@ -164,10 +175,10 @@ describe('Snippet Edit app', () => {
props => {
createComponent(props);
- expect(wrapper.contains(TitleField)).toBe(true);
- expect(wrapper.contains(SnippetDescriptionEdit)).toBe(true);
- expect(wrapper.contains(SnippetVisibilityEdit)).toBe(true);
- expect(wrapper.contains(FormFooterActions)).toBe(true);
+ expect(wrapper.find(TitleField).exists()).toBe(true);
+ expect(wrapper.find(SnippetDescriptionEdit).exists()).toBe(true);
+ expect(wrapper.find(SnippetVisibilityEdit).exists()).toBe(true);
+ expect(wrapper.find(FormFooterActions).exists()).toBe(true);
expect(findBlobActions().exists()).toBe(true);
},
);
@@ -196,8 +207,8 @@ describe('Snippet Edit app', () => {
it.each`
projectPath | snippetArg | expectation
- ${''} | ${[]} | ${'/-/snippets'}
- ${'project/path'} | ${[]} | ${'/project/path/-/snippets'}
+ ${''} | ${[]} | ${urlUtils.joinPaths('/', relativeUrlRoot, '-', 'snippets')}
+ ${'project/path'} | ${[]} | ${urlUtils.joinPaths('/', relativeUrlRoot, 'project/path/-', 'snippets')}
${''} | ${[createTestSnippet()]} | ${TEST_WEB_URL}
${'project/path'} | ${[createTestSnippet()]} | ${TEST_WEB_URL}
`(
diff --git a/spec/frontend/snippets/components/embed_dropdown_spec.js b/spec/frontend/snippets/components/embed_dropdown_spec.js
new file mode 100644
index 00000000000..8eb44965692
--- /dev/null
+++ b/spec/frontend/snippets/components/embed_dropdown_spec.js
@@ -0,0 +1,70 @@
+import { escape as esc } from 'lodash';
+import { mount } from '@vue/test-utils';
+import { GlFormInputGroup } from '@gitlab/ui';
+import { TEST_HOST } from 'helpers/test_constants';
+import EmbedDropdown from '~/snippets/components/embed_dropdown.vue';
+
+const TEST_URL = `${TEST_HOST}/test/no">'xss`;
+
+describe('snippets/components/embed_dropdown', () => {
+ let wrapper;
+
+ const createComponent = () => {
+ wrapper = mount(EmbedDropdown, {
+ propsData: {
+ url: TEST_URL,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findSectionsData = () => {
+ const sections = [];
+ let current = {};
+
+ wrapper.findAll('[data-testid="header"],[data-testid="input"]').wrappers.forEach(x => {
+ const type = x.attributes('data-testid');
+
+ if (type === 'header') {
+ current = {
+ header: x.text(),
+ };
+
+ sections.push(current);
+ } else {
+ const value = x.find(GlFormInputGroup).props('value');
+ const copyValue = x.find('button[title="Copy"]').attributes('data-clipboard-text');
+
+ Object.assign(current, {
+ value,
+ copyValue,
+ });
+ }
+ });
+
+ return sections;
+ };
+
+ it('renders dropdown items', () => {
+ createComponent();
+
+ const embedValue = `<script src="${esc(TEST_URL)}.js"></script>`;
+
+ expect(findSectionsData()).toEqual([
+ {
+ header: 'Embed',
+ value: embedValue,
+ copyValue: embedValue,
+ },
+ {
+ header: 'Share',
+ value: TEST_URL,
+ copyValue: TEST_URL,
+ },
+ ]);
+ });
+});
diff --git a/spec/frontend/snippets/components/show_spec.js b/spec/frontend/snippets/components/show_spec.js
index 8cccbb83d54..b5ab7def753 100644
--- a/spec/frontend/snippets/components/show_spec.js
+++ b/spec/frontend/snippets/components/show_spec.js
@@ -2,7 +2,7 @@ import { GlLoadingIcon } from '@gitlab/ui';
import { Blob, BinaryBlob } from 'jest/blob/components/mock_data';
import { shallowMount } from '@vue/test-utils';
import SnippetApp from '~/snippets/components/show.vue';
-import BlobEmbeddable from '~/blob/components/blob_embeddable.vue';
+import EmbedDropdown from '~/snippets/components/embed_dropdown.vue';
import SnippetHeader from '~/snippets/components/snippet_header.vue';
import SnippetTitle from '~/snippets/components/snippet_title.vue';
import SnippetBlob from '~/snippets/components/snippet_blob_view.vue';
@@ -57,7 +57,7 @@ describe('Snippet view app', () => {
expect(wrapper.find(SnippetTitle).exists()).toBe(true);
});
- it('renders embeddable component if visibility allows', () => {
+ it('renders embed dropdown component if visibility allows', () => {
createComponent({
data: {
snippet: {
@@ -66,7 +66,7 @@ describe('Snippet view app', () => {
},
},
});
- expect(wrapper.contains(BlobEmbeddable)).toBe(true);
+ expect(wrapper.find(EmbedDropdown).exists()).toBe(true);
});
it('renders correct snippet-blob components', () => {
@@ -88,7 +88,7 @@ describe('Snippet view app', () => {
${SNIPPET_VISIBILITY_PRIVATE} | ${'not render'} | ${false}
${'foo'} | ${'not render'} | ${false}
${SNIPPET_VISIBILITY_PUBLIC} | ${'render'} | ${true}
- `('does $condition blob-embeddable by default', ({ visibilityLevel, isRendered }) => {
+ `('does $condition embed-dropdown by default', ({ visibilityLevel, isRendered }) => {
createComponent({
data: {
snippet: {
@@ -97,7 +97,7 @@ describe('Snippet view app', () => {
},
},
});
- expect(wrapper.contains(BlobEmbeddable)).toBe(isRendered);
+ expect(wrapper.find(EmbedDropdown).exists()).toBe(isRendered);
});
});
@@ -119,7 +119,7 @@ describe('Snippet view app', () => {
},
},
});
- expect(wrapper.contains(CloneDropdownButton)).toBe(isRendered);
+ expect(wrapper.find(CloneDropdownButton).exists()).toBe(isRendered);
},
);
});
diff --git a/spec/frontend/snippets/components/snippet_blob_edit_spec.js b/spec/frontend/snippets/components/snippet_blob_edit_spec.js
index 188f9ae5cf1..fc4da46d722 100644
--- a/spec/frontend/snippets/components/snippet_blob_edit_spec.js
+++ b/spec/frontend/snippets/components/snippet_blob_edit_spec.js
@@ -17,6 +17,7 @@ const TEST_PATH = 'foo/bar/test.md';
const TEST_RAW_PATH = '/gitlab/raw/path/to/blob/7';
const TEST_FULL_PATH = joinPaths(TEST_HOST, TEST_RAW_PATH);
const TEST_CONTENT = 'Lorem ipsum dolar sit amet,\nconsectetur adipiscing elit.';
+const TEST_JSON_CONTENT = '{"abc":"lorem ipsum"}';
const TEST_BLOB = {
id: TEST_ID,
@@ -66,7 +67,7 @@ describe('Snippet Blob Edit component', () => {
});
describe('with not loaded blob', () => {
- beforeEach(async () => {
+ beforeEach(() => {
createComponent();
});
@@ -100,6 +101,20 @@ describe('Snippet Blob Edit component', () => {
});
});
+ describe('with unloaded blob and JSON content', () => {
+ beforeEach(() => {
+ axiosMock.onGet(TEST_FULL_PATH).reply(200, TEST_JSON_CONTENT);
+ createComponent();
+ });
+
+ // This checks against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/241199
+ it('emits raw content', async () => {
+ await waitForPromises();
+
+ expect(getLastUpdatedArgs()).toEqual({ content: TEST_JSON_CONTENT });
+ });
+ });
+
describe('with error', () => {
beforeEach(() => {
axiosMock.reset();
diff --git a/spec/frontend/snippets/components/snippet_header_spec.js b/spec/frontend/snippets/components/snippet_header_spec.js
index da8cb2e6a8d..5836de1fdbe 100644
--- a/spec/frontend/snippets/components/snippet_header_spec.js
+++ b/spec/frontend/snippets/components/snippet_header_spec.js
@@ -5,6 +5,7 @@ import { Blob, BinaryBlob } from 'jest/blob/components/mock_data';
import waitForPromises from 'helpers/wait_for_promises';
import DeleteSnippetMutation from '~/snippets/mutations/deleteSnippet.mutation.graphql';
import SnippetHeader from '~/snippets/components/snippet_header.vue';
+import { differenceInMilliseconds } from '~/lib/utils/datetime_utility';
describe('Snippet header component', () => {
let wrapper;
@@ -14,6 +15,7 @@ describe('Snippet header component', () => {
let errorMsg;
let err;
+ const originalRelativeUrlRoot = gon.relative_url_root;
function createComponent({
loading = false,
@@ -50,6 +52,7 @@ describe('Snippet header component', () => {
}
beforeEach(() => {
+ gon.relative_url_root = '/foo/';
snippet = {
id: 'gid://gitlab/PersonalSnippet/50',
title: 'The property of Thor',
@@ -65,7 +68,7 @@ describe('Snippet header component', () => {
name: 'Thor Odinson',
},
blobs: [Blob],
- createdAt: new Date(Date.now() - 32 * 24 * 3600 * 1000).toISOString(),
+ createdAt: new Date(differenceInMilliseconds(32 * 24 * 3600 * 1000)).toISOString(),
};
mutationVariables = {
@@ -86,6 +89,7 @@ describe('Snippet header component', () => {
afterEach(() => {
wrapper.destroy();
+ gon.relative_url_root = originalRelativeUrlRoot;
});
it('renders itself', () => {
@@ -213,7 +217,7 @@ describe('Snippet header component', () => {
it('redirects to dashboard/snippets for personal snippet', () => {
return createDeleteSnippet().then(() => {
expect(wrapper.vm.closeDeleteModal).toHaveBeenCalled();
- expect(window.location.pathname).toBe('dashboard/snippets');
+ expect(window.location.pathname).toBe(`${gon.relative_url_root}dashboard/snippets`);
});
});
diff --git a/spec/frontend/snippets/components/snippet_visibility_edit_spec.js b/spec/frontend/snippets/components/snippet_visibility_edit_spec.js
index a8df13787a5..3919e4d7993 100644
--- a/spec/frontend/snippets/components/snippet_visibility_edit_spec.js
+++ b/spec/frontend/snippets/components/snippet_visibility_edit_spec.js
@@ -1,31 +1,55 @@
import { GlFormRadio, GlIcon, GlFormRadioGroup, GlLink } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
import SnippetVisibilityEdit from '~/snippets/components/snippet_visibility_edit.vue';
+import { defaultSnippetVisibilityLevels } from '~/snippets/utils/blob';
import {
SNIPPET_VISIBILITY,
SNIPPET_VISIBILITY_PRIVATE,
SNIPPET_VISIBILITY_INTERNAL,
SNIPPET_VISIBILITY_PUBLIC,
+ SNIPPET_LEVELS_RESTRICTED,
+ SNIPPET_LEVELS_DISABLED,
} from '~/snippets/constants';
describe('Snippet Visibility Edit component', () => {
let wrapper;
const defaultHelpLink = '/foo/bar';
const defaultVisibilityLevel = 'private';
-
- function createComponent(propsData = {}, deep = false) {
+ const defaultVisibility = defaultSnippetVisibilityLevels([0, 10, 20]);
+
+ function createComponent({
+ propsData = {},
+ visibilityLevels = defaultVisibility,
+ multipleLevelsRestricted = false,
+ deep = false,
+ } = {}) {
const method = deep ? mount : shallowMount;
+ const $apollo = {
+ queries: {
+ defaultVisibility: {
+ loading: false,
+ },
+ },
+ };
+
wrapper = method.call(this, SnippetVisibilityEdit, {
+ mock: { $apollo },
propsData: {
helpLink: defaultHelpLink,
isProjectSnippet: false,
value: defaultVisibilityLevel,
...propsData,
},
+ data() {
+ return {
+ visibilityLevels,
+ multipleLevelsRestricted,
+ };
+ },
});
}
- const findLabel = () => wrapper.find('label');
+ const findLink = () => wrapper.find('label').find(GlLink);
const findRadios = () => wrapper.find(GlFormRadioGroup).findAll(GlFormRadio);
const findRadiosData = () =>
findRadios().wrappers.map(x => {
@@ -47,56 +71,84 @@ describe('Snippet Visibility Edit component', () => {
expect(wrapper.element).toMatchSnapshot();
});
- it('renders visibility options', () => {
- createComponent({}, true);
+ it('renders label help link', () => {
+ createComponent();
+
+ expect(findLink().attributes('href')).toBe(defaultHelpLink);
+ });
+
+ it('when helpLink is not defined, does not render label help link', () => {
+ createComponent({ propsData: { helpLink: null } });
- expect(findRadiosData()).toEqual([
- {
+ expect(findLink().exists()).toBe(false);
+ });
+
+ describe('Visibility options', () => {
+ const findRestrictedInfo = () => wrapper.find('[data-testid="restricted-levels-info"]');
+ const RESULTING_OPTIONS = {
+ 0: {
value: SNIPPET_VISIBILITY_PRIVATE,
icon: SNIPPET_VISIBILITY.private.icon,
text: SNIPPET_VISIBILITY.private.label,
description: SNIPPET_VISIBILITY.private.description,
},
- {
+ 10: {
value: SNIPPET_VISIBILITY_INTERNAL,
icon: SNIPPET_VISIBILITY.internal.icon,
text: SNIPPET_VISIBILITY.internal.label,
description: SNIPPET_VISIBILITY.internal.description,
},
- {
+ 20: {
value: SNIPPET_VISIBILITY_PUBLIC,
icon: SNIPPET_VISIBILITY.public.icon,
text: SNIPPET_VISIBILITY.public.label,
description: SNIPPET_VISIBILITY.public.description,
},
- ]);
- });
-
- it('when project snippet, renders special private description', () => {
- createComponent({ isProjectSnippet: true }, true);
+ };
- expect(findRadiosData()[0]).toEqual({
- value: SNIPPET_VISIBILITY_PRIVATE,
- icon: SNIPPET_VISIBILITY.private.icon,
- text: SNIPPET_VISIBILITY.private.label,
- description: SNIPPET_VISIBILITY.private.description_project,
+ it.each`
+ levels | resultOptions
+ ${undefined} | ${[]}
+ ${''} | ${[]}
+ ${[]} | ${[]}
+ ${[0]} | ${[RESULTING_OPTIONS[0]]}
+ ${[0, 10]} | ${[RESULTING_OPTIONS[0], RESULTING_OPTIONS[10]]}
+ ${[0, 10, 20]} | ${[RESULTING_OPTIONS[0], RESULTING_OPTIONS[10], RESULTING_OPTIONS[20]]}
+ ${[0, 20]} | ${[RESULTING_OPTIONS[0], RESULTING_OPTIONS[20]]}
+ ${[10, 20]} | ${[RESULTING_OPTIONS[10], RESULTING_OPTIONS[20]]}
+ `('renders correct visibility options for $levels', ({ levels, resultOptions }) => {
+ createComponent({ visibilityLevels: defaultSnippetVisibilityLevels(levels), deep: true });
+ expect(findRadiosData()).toEqual(resultOptions);
});
- });
- it('renders label help link', () => {
- createComponent();
-
- expect(
- findLabel()
- .find(GlLink)
- .attributes('href'),
- ).toBe(defaultHelpLink);
- });
+ it.each`
+ levels | levelsRestricted | resultText
+ ${[]} | ${false} | ${SNIPPET_LEVELS_DISABLED}
+ ${[]} | ${true} | ${SNIPPET_LEVELS_DISABLED}
+ ${[0]} | ${true} | ${SNIPPET_LEVELS_RESTRICTED}
+ ${[0]} | ${false} | ${''}
+ ${[0, 10, 20]} | ${false} | ${''}
+ `(
+ 'renders correct information about restricted visibility levels for $levels',
+ ({ levels, levelsRestricted, resultText }) => {
+ createComponent({
+ visibilityLevels: defaultSnippetVisibilityLevels(levels),
+ multipleLevelsRestricted: levelsRestricted,
+ });
+ expect(findRestrictedInfo().text()).toBe(resultText);
+ },
+ );
- it('when helpLink is not defined, does not render label help link', () => {
- createComponent({ helpLink: null });
+ it('when project snippet, renders special private description', () => {
+ createComponent({ propsData: { isProjectSnippet: true }, deep: true });
- expect(findLabel().contains(GlLink)).toBe(false);
+ expect(findRadiosData()[0]).toEqual({
+ value: SNIPPET_VISIBILITY_PRIVATE,
+ icon: SNIPPET_VISIBILITY.private.icon,
+ text: SNIPPET_VISIBILITY.private.label,
+ description: SNIPPET_VISIBILITY.private.description_project,
+ });
+ });
});
});
@@ -104,7 +156,7 @@ describe('Snippet Visibility Edit component', () => {
it('pre-selects correct option in the list', () => {
const value = SNIPPET_VISIBILITY_INTERNAL;
- createComponent({ value });
+ createComponent({ propsData: { value } });
expect(wrapper.find(GlFormRadioGroup).attributes('checked')).toBe(value);
});