diff options
Diffstat (limited to 'spec/frontend/vue_shared/components/markdown_drawer/markdown_drawer_spec.js')
-rw-r--r-- | spec/frontend/vue_shared/components/markdown_drawer/markdown_drawer_spec.js | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/spec/frontend/vue_shared/components/markdown_drawer/markdown_drawer_spec.js b/spec/frontend/vue_shared/components/markdown_drawer/markdown_drawer_spec.js new file mode 100644 index 00000000000..8edcb905096 --- /dev/null +++ b/spec/frontend/vue_shared/components/markdown_drawer/markdown_drawer_spec.js @@ -0,0 +1,205 @@ +import { GlDrawer, GlAlert, GlSkeletonLoader } from '@gitlab/ui'; +import { nextTick } from 'vue'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import MarkdownDrawer, { cache } from '~/vue_shared/components/markdown_drawer/markdown_drawer.vue'; +import { getRenderedMarkdown } from '~/vue_shared/components/markdown_drawer/utils/fetch'; +import { contentTop } from '~/lib/utils/common_utils'; + +jest.mock('~/vue_shared/components/markdown_drawer/utils/fetch', () => ({ + getRenderedMarkdown: jest.fn().mockReturnValue({ + title: 'test title test', + body: `<div id="content-body"> + <div class="documentation md gl-mt-3"> + test body + </div> + </div>`, + }), +})); + +jest.mock('~/lib/utils/common_utils', () => ({ + contentTop: jest.fn(), +})); + +describe('MarkdownDrawer', () => { + let wrapper; + const defaultProps = { + documentPath: 'user/search/global_search/advanced_search_syntax.json', + }; + + const createComponent = (props) => { + wrapper = shallowMountExtended(MarkdownDrawer, { + propsData: { + ...defaultProps, + ...props, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + Object.keys(cache).forEach((key) => delete cache[key]); + }); + + const findDrawer = () => wrapper.findComponent(GlDrawer); + const findAlert = () => wrapper.findComponent(GlAlert); + const findSkeleton = () => wrapper.findComponent(GlSkeletonLoader); + const findDrawerTitle = () => wrapper.findComponent('[data-testid="title-element"]'); + const findDrawerBody = () => wrapper.findComponent({ ref: 'content-element' }); + + describe('component', () => { + beforeEach(() => { + createComponent(); + }); + + it('renders correctly', () => { + expect(findDrawer().exists()).toBe(true); + expect(findDrawerTitle().text()).toBe('test title test'); + expect(findDrawerBody().text()).toBe('test body'); + }); + }); + + describe.each` + hasNavbar | navbarHeight + ${false} | ${0} + ${true} | ${100} + `('computes offsetTop', ({ hasNavbar, navbarHeight }) => { + beforeEach(() => { + global.document.querySelector = jest.fn(() => + hasNavbar + ? { + dataset: { + page: 'test', + }, + } + : undefined, + ); + contentTop.mockReturnValue(navbarHeight); + createComponent(); + }); + + afterEach(() => { + contentTop.mockClear(); + }); + + it(`computes offsetTop ${hasNavbar ? 'with' : 'without'} .navbar-gitlab`, () => { + expect(findDrawer().attributes('headerheight')).toBe(`${navbarHeight}px`); + }); + }); + + describe('watcher', () => { + let renderGLFMSpy; + let fetchMarkdownSpy; + + beforeEach(async () => { + renderGLFMSpy = jest.spyOn(MarkdownDrawer.methods, 'renderGLFM'); + fetchMarkdownSpy = jest.spyOn(MarkdownDrawer.methods, 'fetchMarkdown'); + global.document.querySelector = jest.fn(() => ({ + getBoundingClientRect: jest.fn(() => ({ bottom: 100 })), + dataset: { + page: 'test', + }, + })); + createComponent(); + await nextTick(); + }); + + afterEach(() => { + renderGLFMSpy.mockClear(); + fetchMarkdownSpy.mockClear(); + }); + + it('for documentPath triggers fetch', async () => { + expect(fetchMarkdownSpy).toHaveBeenCalledTimes(1); + + await wrapper.setProps({ documentPath: '/test/me' }); + await nextTick(); + + expect(fetchMarkdownSpy).toHaveBeenCalledTimes(2); + }); + + it('for open triggers renderGLFM', async () => { + wrapper.vm.fetchMarkdown(); + wrapper.vm.openDrawer(); + await nextTick(); + expect(renderGLFMSpy).toHaveBeenCalled(); + }); + }); + + describe('Markdown fetching', () => { + let renderGLFMSpy; + + beforeEach(async () => { + renderGLFMSpy = jest.spyOn(MarkdownDrawer.methods, 'renderGLFM'); + createComponent(); + await nextTick(); + }); + + afterEach(() => { + renderGLFMSpy.mockClear(); + }); + + it('fetches the Markdown and caches it', async () => { + expect(getRenderedMarkdown).toHaveBeenCalledTimes(1); + expect(Object.keys(cache)).toHaveLength(1); + }); + + it('when the document changes, fetches it and caches it as well', async () => { + expect(getRenderedMarkdown).toHaveBeenCalledTimes(1); + expect(Object.keys(cache)).toHaveLength(1); + + await wrapper.setProps({ documentPath: '/test/me2' }); + await nextTick(); + + expect(getRenderedMarkdown).toHaveBeenCalledTimes(2); + expect(Object.keys(cache)).toHaveLength(2); + }); + + it('when re-using an already fetched document, gets it from the cache', async () => { + await wrapper.setProps({ documentPath: '/test/me2' }); + await nextTick(); + + expect(getRenderedMarkdown).toHaveBeenCalledTimes(2); + expect(Object.keys(cache)).toHaveLength(2); + + await wrapper.setProps({ documentPath: defaultProps.documentPath }); + await nextTick(); + + expect(getRenderedMarkdown).toHaveBeenCalledTimes(2); + expect(Object.keys(cache)).toHaveLength(2); + }); + }); + + describe('Markdown fetching returns error', () => { + beforeEach(async () => { + getRenderedMarkdown.mockReturnValue({ + hasFetchError: true, + }); + + createComponent(); + await nextTick(); + }); + afterEach(() => { + getRenderedMarkdown.mockClear(); + }); + it('shows alert', () => { + expect(findAlert().exists()).toBe(true); + }); + }); + + describe('While Markdown is fetching', () => { + beforeEach(async () => { + getRenderedMarkdown.mockReturnValue(new Promise(() => {})); + + createComponent(); + }); + + afterEach(() => { + getRenderedMarkdown.mockClear(); + }); + + it('shows skeleton', async () => { + expect(findSkeleton().exists()).toBe(true); + }); + }); +}); |