import { GlLoadingIcon } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; 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 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'); const TEST_ID = 'blob_local_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, rawPath: TEST_RAW_PATH, path: TEST_PATH, content: '', isLoaded: false, }; const TEST_BLOB_LOADED = { ...TEST_BLOB, content: TEST_CONTENT, isLoaded: true, }; describe('Snippet Blob Edit component', () => { let wrapper; let axiosMock; const createComponent = (props = {}) => { wrapper = shallowMount(SnippetBlobEdit, { propsData: { blob: TEST_BLOB, ...props, }, }); }; const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); const findHeader = () => wrapper.findComponent(BlobHeaderEdit); const findContent = () => wrapper.findComponent(SourceEditor); const getLastUpdatedArgs = () => { const event = wrapper.emitted()['blob-updated']; return event?.[event.length - 1][0]; }; beforeEach(() => { axiosMock = new AxiosMockAdapter(axios); axiosMock.onGet(TEST_FULL_PATH).reply(HTTP_STATUS_OK, TEST_CONTENT); }); afterEach(() => { wrapper.destroy(); wrapper = null; axiosMock.restore(); }); describe('with not loaded blob', () => { beforeEach(() => { createComponent(); }); it('shows blob header', () => { expect(findHeader().props()).toMatchObject({ value: TEST_BLOB.path, }); expect(findHeader().attributes('id')).toBe(`${TEST_ID}_file_path`); }); it('emits delete when deleted', () => { expect(wrapper.emitted().delete).toBeUndefined(); findHeader().vm.$emit('delete'); expect(wrapper.emitted().delete).toHaveLength(1); }); it('emits update when path changes', () => { const newPath = 'new/path.md'; findHeader().vm.$emit('input', newPath); expect(getLastUpdatedArgs()).toEqual({ path: newPath }); }); it('emits update when content is loaded', async () => { await waitForPromises(); expect(getLastUpdatedArgs()).toEqual({ content: TEST_CONTENT }); }); }); describe('with unloaded blob and JSON content', () => { beforeEach(() => { axiosMock.onGet(TEST_FULL_PATH).reply(HTTP_STATUS_OK, 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(); axiosMock.onGet(TEST_FULL_PATH).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR); createComponent(); }); it('should call flash', async () => { await waitForPromises(); expect(createAlert).toHaveBeenCalledWith({ message: "Can't fetch content for the blob: Error: Request failed with status code 500", }); }); }); describe('with loaded blob', () => { beforeEach(() => { createComponent({ blob: TEST_BLOB_LOADED }); }); it('matches snapshot', () => { expect(wrapper.element).toMatchSnapshot(); }); it('does not make API request', () => { expect(axiosMock.history.get).toHaveLength(0); }); }); describe.each` props | showLoading | showContent ${{ blob: TEST_BLOB, canDelete: true, showDelete: true }} | ${true} | ${false} ${{ blob: TEST_BLOB, canDelete: false, showDelete: false }} | ${true} | ${false} ${{ blob: TEST_BLOB_LOADED }} | ${false} | ${true} `('with $props', ({ props, showLoading, showContent }) => { beforeEach(() => { createComponent(props); }); it('shows blob header', () => { const { canDelete = true, showDelete = true } = props; expect(findHeader().props()).toMatchObject({ canDelete, showDelete, }); }); it(`handles loading icon (show=${showLoading})`, () => { expect(findLoadingIcon().exists()).toBe(showLoading); }); it(`handles content (show=${showContent})`, () => { expect(findContent().exists()).toBe(showContent); if (showContent) { expect(findContent().props()).toEqual( expect.objectContaining({ value: TEST_BLOB_LOADED.content, fileGlobalId: TEST_BLOB_LOADED.id, fileName: TEST_BLOB_LOADED.path, }), ); } }); }); });