summaryrefslogtreecommitdiff
path: root/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js')
-rw-r--r--spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js301
1 files changed, 301 insertions, 0 deletions
diff --git a/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js b/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js
new file mode 100644
index 00000000000..8b2051008d7
--- /dev/null
+++ b/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js
@@ -0,0 +1,301 @@
+import { times } from 'lodash';
+import { shallowMount } from '@vue/test-utils';
+import SnippetBlobActionsEdit from '~/snippets/components/snippet_blob_actions_edit.vue';
+import SnippetBlobEdit from '~/snippets/components/snippet_blob_edit.vue';
+import {
+ SNIPPET_MAX_BLOBS,
+ SNIPPET_BLOB_ACTION_CREATE,
+ SNIPPET_BLOB_ACTION_MOVE,
+} from '~/snippets/constants';
+import { testEntries, createBlobFromTestEntry } from '../test_utils';
+
+const TEST_BLOBS = [
+ createBlobFromTestEntry(testEntries.updated),
+ createBlobFromTestEntry(testEntries.deleted),
+];
+
+const TEST_BLOBS_UNLOADED = TEST_BLOBS.map(blob => ({ ...blob, content: '', isLoaded: false }));
+
+describe('snippets/components/snippet_blob_actions_edit', () => {
+ let wrapper;
+
+ const createComponent = (props = {}, snippetMultipleFiles = true) => {
+ wrapper = shallowMount(SnippetBlobActionsEdit, {
+ propsData: {
+ initBlobs: TEST_BLOBS,
+ ...props,
+ },
+ provide: {
+ glFeatures: {
+ snippetMultipleFiles,
+ },
+ },
+ });
+ };
+
+ const findLabel = () => wrapper.find('label');
+ const findBlobEdits = () => wrapper.findAll(SnippetBlobEdit);
+ const findBlobsData = () =>
+ findBlobEdits().wrappers.map(x => ({
+ blob: x.props('blob'),
+ classes: x.classes(),
+ }));
+ const findFirstBlobEdit = () => findBlobEdits().at(0);
+ const findAddButton = () => wrapper.find('[data-testid="add_button"]');
+ const getLastActions = () => {
+ const events = wrapper.emitted().actions;
+
+ return events[events.length - 1]?.[0];
+ };
+ const buildBlobsDataExpectation = blobs =>
+ blobs.map((blob, index) => ({
+ blob: {
+ ...blob,
+ id: expect.stringMatching('blob_local_'),
+ },
+ classes: index > 0 ? ['gl-mt-3'] : [],
+ }));
+ 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.each`
+ featureFlag | label | showDelete | showAdd
+ ${true} | ${'Files'} | ${true} | ${true}
+ ${false} | ${'File'} | ${false} | ${false}
+ `('with feature flag = $featureFlag', ({ featureFlag, label, showDelete, showAdd }) => {
+ beforeEach(() => {
+ createComponent({}, featureFlag);
+ });
+
+ it('renders label', () => {
+ expect(findLabel().text()).toBe(label);
+ });
+
+ it(`renders delete button (show=${showDelete})`, () => {
+ expect(findFirstBlobEdit().props()).toMatchObject({
+ showDelete,
+ canDelete: true,
+ });
+ });
+
+ it(`renders add button (show=${showAdd})`, () => {
+ expect(findAddButton().exists()).toBe(showAdd);
+ });
+ });
+
+ describe('with default', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('emits no actions', () => {
+ expect(getLastActions()).toEqual([]);
+ });
+
+ it('shows blobs', () => {
+ expect(findBlobsData()).toEqual(buildBlobsDataExpectation(TEST_BLOBS_UNLOADED));
+ });
+
+ it('shows add button', () => {
+ const button = findAddButton();
+
+ expect(button.text()).toBe(`Add another file ${TEST_BLOBS.length}/${SNIPPET_MAX_BLOBS}`);
+ expect(button.props('disabled')).toBe(false);
+ });
+
+ describe('when add is clicked', () => {
+ beforeEach(() => {
+ findAddButton().vm.$emit('click');
+ });
+
+ it('adds blob with empty content', () => {
+ expect(findBlobsData()).toEqual(
+ buildBlobsDataExpectation([
+ ...TEST_BLOBS_UNLOADED,
+ {
+ content: '',
+ isLoaded: true,
+ path: '',
+ },
+ ]),
+ );
+ });
+
+ it('emits action', () => {
+ expect(getLastActions()).toEqual([
+ expect.objectContaining({
+ action: SNIPPET_BLOB_ACTION_CREATE,
+ }),
+ ]);
+ });
+ });
+
+ describe('when blob is deleted', () => {
+ beforeEach(() => {
+ triggerBlobDelete(1);
+ });
+
+ it('removes blob', () => {
+ expect(findBlobsData()).toEqual(buildBlobsDataExpectation(TEST_BLOBS_UNLOADED.slice(0, 1)));
+ });
+
+ it('emits action', () => {
+ expect(getLastActions()).toEqual([
+ expect.objectContaining({
+ ...testEntries.deleted.diff,
+ content: '',
+ }),
+ ]);
+ });
+ });
+
+ describe('when blob changes path', () => {
+ beforeEach(() => {
+ triggerBlobUpdate(0, { path: 'new/path' });
+ });
+
+ it('renames blob', () => {
+ expect(findBlobsData()[0]).toMatchObject({
+ blob: {
+ path: 'new/path',
+ },
+ });
+ });
+
+ it('emits action', () => {
+ expect(getLastActions()).toMatchObject([
+ {
+ action: SNIPPET_BLOB_ACTION_MOVE,
+ filePath: 'new/path',
+ previousPath: testEntries.updated.diff.filePath,
+ },
+ ]);
+ });
+ });
+
+ describe('when blob emits new content', () => {
+ const { content } = testEntries.updated.diff;
+ const originalContent = `${content}\noriginal content\n`;
+
+ beforeEach(() => {
+ triggerBlobUpdate(0, { content: originalContent });
+ });
+
+ it('loads new content', () => {
+ expect(findBlobsData()[0]).toMatchObject({
+ blob: {
+ content: originalContent,
+ isLoaded: true,
+ },
+ });
+ });
+
+ it('does not emit an action', () => {
+ expect(getLastActions()).toEqual([]);
+ });
+
+ it('emits an action when content changes again', async () => {
+ triggerBlobUpdate(0, { content });
+
+ await wrapper.vm.$nextTick();
+
+ expect(getLastActions()).toEqual([testEntries.updated.diff]);
+ });
+ });
+ });
+
+ describe('with 1 blob', () => {
+ beforeEach(() => {
+ createComponent({ initBlobs: [createBlobFromTestEntry(testEntries.created)] });
+ });
+
+ it('disables delete button', () => {
+ expect(findBlobEdits()).toHaveLength(1);
+ expect(
+ findBlobEdits()
+ .at(0)
+ .props(),
+ ).toMatchObject({
+ showDelete: true,
+ canDelete: false,
+ });
+ });
+
+ describe(`when added ${SNIPPET_MAX_BLOBS} files`, () => {
+ let addButton;
+
+ beforeEach(() => {
+ addButton = findAddButton();
+
+ times(SNIPPET_MAX_BLOBS - 1, () => addButton.vm.$emit('click'));
+ });
+
+ it('should have blobs', () => {
+ expect(findBlobsData()).toHaveLength(SNIPPET_MAX_BLOBS);
+ });
+
+ it('should disable add button', () => {
+ expect(addButton.props('disabled')).toBe(true);
+ });
+ });
+ });
+
+ describe('with 0 init blob', () => {
+ beforeEach(() => {
+ createComponent({ initBlobs: [] });
+ });
+
+ it('shows 1 blob by default', () => {
+ expect(findBlobsData()).toEqual([
+ expect.objectContaining({
+ blob: {
+ id: expect.stringMatching('blob_local_'),
+ content: '',
+ path: '',
+ isLoaded: true,
+ },
+ }),
+ ]);
+ });
+
+ it('emits create action', () => {
+ expect(getLastActions()).toEqual([
+ {
+ action: SNIPPET_BLOB_ACTION_CREATE,
+ content: '',
+ filePath: '',
+ previousPath: '',
+ },
+ ]);
+ });
+ });
+
+ describe(`with ${SNIPPET_MAX_BLOBS} files`, () => {
+ beforeEach(() => {
+ const initBlobs = Array(SNIPPET_MAX_BLOBS)
+ .fill(1)
+ .map(() => createBlobFromTestEntry(testEntries.created));
+
+ createComponent({ initBlobs });
+ });
+
+ it('should have blobs', () => {
+ expect(findBlobsData()).toHaveLength(SNIPPET_MAX_BLOBS);
+ });
+
+ it('should disable add button', () => {
+ expect(findAddButton().props('disabled')).toBe(true);
+ });
+ });
+});