diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
commit | 8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch) | |
tree | a77e7fe7a93de11213032ed4ab1f33a3db51b738 /spec/frontend/static_site_editor | |
parent | 00b35af3db1abfe813a778f643dad221aad51fca (diff) | |
download | gitlab-ce-8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781.tar.gz |
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'spec/frontend/static_site_editor')
6 files changed, 178 insertions, 23 deletions
diff --git a/spec/frontend/static_site_editor/components/edit_area_spec.js b/spec/frontend/static_site_editor/components/edit_area_spec.js index bfe41f65d6e..d7c798e6620 100644 --- a/spec/frontend/static_site_editor/components/edit_area_spec.js +++ b/spec/frontend/static_site_editor/components/edit_area_spec.js @@ -5,13 +5,19 @@ import RichContentEditor from '~/vue_shared/components/rich_content_editor/rich_ import EditArea from '~/static_site_editor/components/edit_area.vue'; import PublishToolbar from '~/static_site_editor/components/publish_toolbar.vue'; import EditHeader from '~/static_site_editor/components/edit_header.vue'; +import UnsavedChangesConfirmDialog from '~/static_site_editor/components/unsaved_changes_confirm_dialog.vue'; -import { sourceContentTitle as title, sourceContent as content, returnUrl } from '../mock_data'; +import { + sourceContentTitle as title, + sourceContent as content, + sourceContentBody as body, + returnUrl, +} from '../mock_data'; describe('~/static_site_editor/components/edit_area.vue', () => { let wrapper; const savingChanges = true; - const newContent = `new ${content}`; + const newBody = `new ${body}`; const buildWrapper = (propsData = {}) => { wrapper = shallowMount(EditArea, { @@ -28,6 +34,7 @@ describe('~/static_site_editor/components/edit_area.vue', () => { const findEditHeader = () => wrapper.find(EditHeader); const findRichContentEditor = () => wrapper.find(RichContentEditor); const findPublishToolbar = () => wrapper.find(PublishToolbar); + const findUnsavedChangesConfirmDialog = () => wrapper.find(UnsavedChangesConfirmDialog); beforeEach(() => { buildWrapper(); @@ -44,29 +51,40 @@ describe('~/static_site_editor/components/edit_area.vue', () => { it('renders rich content editor', () => { expect(findRichContentEditor().exists()).toBe(true); - expect(findRichContentEditor().props('value')).toBe(content); + expect(findRichContentEditor().props('value')).toBe(body); }); it('renders publish toolbar', () => { expect(findPublishToolbar().exists()).toBe(true); - expect(findPublishToolbar().props('returnUrl')).toBe(returnUrl); - expect(findPublishToolbar().props('savingChanges')).toBe(savingChanges); - expect(findPublishToolbar().props('saveable')).toBe(false); + expect(findPublishToolbar().props()).toMatchObject({ + returnUrl, + savingChanges, + saveable: false, + }); + }); + + it('renders unsaved changes confirm dialog', () => { + expect(findUnsavedChangesConfirmDialog().exists()).toBe(true); + expect(findUnsavedChangesConfirmDialog().props('modified')).toBe(false); }); describe('when content changes', () => { beforeEach(() => { - findRichContentEditor().vm.$emit('input', newContent); + findRichContentEditor().vm.$emit('input', newBody); return wrapper.vm.$nextTick(); }); - it('sets publish toolbar as saveable when content changes', () => { + it('sets publish toolbar as saveable', () => { expect(findPublishToolbar().props('saveable')).toBe(true); }); + it('sets unsaved changes confirm dialog as modified', () => { + expect(findUnsavedChangesConfirmDialog().props('modified')).toBe(true); + }); + it('sets publish toolbar as not saveable when content changes are rollback', () => { - findRichContentEditor().vm.$emit('input', content); + findRichContentEditor().vm.$emit('input', body); return wrapper.vm.$nextTick().then(() => { expect(findPublishToolbar().props('saveable')).toBe(false); diff --git a/spec/frontend/static_site_editor/components/unsaved_changes_confirm_dialog_spec.js b/spec/frontend/static_site_editor/components/unsaved_changes_confirm_dialog_spec.js new file mode 100644 index 00000000000..9b8b22da693 --- /dev/null +++ b/spec/frontend/static_site_editor/components/unsaved_changes_confirm_dialog_spec.js @@ -0,0 +1,44 @@ +import { shallowMount } from '@vue/test-utils'; + +import UnsavedChangesConfirmDialog from '~/static_site_editor/components/unsaved_changes_confirm_dialog.vue'; + +describe('static_site_editor/components/unsaved_changes_confirm_dialog', () => { + let wrapper; + let event; + let returnValueSetter; + + const buildWrapper = (propsData = {}) => { + wrapper = shallowMount(UnsavedChangesConfirmDialog, { + propsData, + }); + }; + + beforeEach(() => { + event = new Event('beforeunload'); + + jest.spyOn(event, 'preventDefault'); + returnValueSetter = jest.spyOn(event, 'returnValue', 'set'); + }); + + afterEach(() => { + event.preventDefault.mockRestore(); + returnValueSetter.mockRestore(); + wrapper.destroy(); + }); + + it('displays confirmation dialog when modified = true', () => { + buildWrapper({ modified: true }); + window.dispatchEvent(event); + + expect(event.preventDefault).toHaveBeenCalled(); + expect(returnValueSetter).toHaveBeenCalledWith(''); + }); + + it('does not display confirmation dialog when modified = false', () => { + buildWrapper(); + window.dispatchEvent(event); + + expect(event.preventDefault).not.toHaveBeenCalled(); + expect(returnValueSetter).not.toHaveBeenCalled(); + }); +}); diff --git a/spec/frontend/static_site_editor/mock_data.js b/spec/frontend/static_site_editor/mock_data.js index 371695e913e..422048a5f69 100644 --- a/spec/frontend/static_site_editor/mock_data.js +++ b/spec/frontend/static_site_editor/mock_data.js @@ -1,16 +1,17 @@ -export const sourceContent = ` ---- +export const sourceContentHeader = `--- layout: handbook-page-toc title: Handbook twitter_image: '/images/tweets/handbook-gitlab.png' ---- - -## On this page +---`; +export const sourceContentSpacing = ` +`; +export const sourceContentBody = `## On this page {:.no_toc .hidden-md .hidden-lg} - TOC {:toc .hidden-md .hidden-lg} `; +export const sourceContent = `${sourceContentHeader}${sourceContentSpacing}${sourceContentBody}`; export const sourceContentTitle = 'Handbook'; export const username = 'gitlabuser'; diff --git a/spec/frontend/static_site_editor/pages/home_spec.js b/spec/frontend/static_site_editor/pages/home_spec.js index 8c9c54f593e..d3ee70785d1 100644 --- a/spec/frontend/static_site_editor/pages/home_spec.js +++ b/spec/frontend/static_site_editor/pages/home_spec.js @@ -7,6 +7,8 @@ import InvalidContentMessage from '~/static_site_editor/components/invalid_conte import SubmitChangesError from '~/static_site_editor/components/submit_changes_error.vue'; import submitContentChangesMutation from '~/static_site_editor/graphql/mutations/submit_content_changes.mutation.graphql'; import { SUCCESS_ROUTE } from '~/static_site_editor/router/constants'; +import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; +import { TRACKING_ACTION_INITIALIZE_EDITOR } from '~/static_site_editor/constants'; import { projectId as project, @@ -17,6 +19,7 @@ import { username, savedContentMeta, submitChangesError, + trackingCategory, } from '../mock_data'; const localVue = createLocalVue(); @@ -29,6 +32,7 @@ describe('static_site_editor/pages/home', () => { let $apollo; let $router; let mutateMock; + let trackingSpy; const buildApollo = (queries = {}) => { mutateMock = jest.fn(); @@ -76,10 +80,14 @@ describe('static_site_editor/pages/home', () => { beforeEach(() => { buildApollo(); buildRouter(); + + document.body.dataset.page = trackingCategory; + trackingSpy = mockTracking(document.body.dataset.page, undefined, jest.spyOn); }); afterEach(() => { wrapper.destroy(); + unmockTracking(); wrapper = null; $apollo = null; }); @@ -208,4 +216,12 @@ describe('static_site_editor/pages/home', () => { expect($router.push).toHaveBeenCalledWith(SUCCESS_ROUTE); }); }); + + it('tracks when editor is initialized on the mounted lifecycle hook', () => { + buildWrapper(); + expect(trackingSpy).toHaveBeenCalledWith( + document.body.dataset.page, + TRACKING_ACTION_INITIALIZE_EDITOR, + ); + }); }); diff --git a/spec/frontend/static_site_editor/services/parse_source_file_spec.js b/spec/frontend/static_site_editor/services/parse_source_file_spec.js new file mode 100644 index 00000000000..fe99c4f5334 --- /dev/null +++ b/spec/frontend/static_site_editor/services/parse_source_file_spec.js @@ -0,0 +1,64 @@ +import { + sourceContent as content, + sourceContentHeader as header, + sourceContentSpacing as spacing, + sourceContentBody as body, +} from '../mock_data'; + +import parseSourceFile from '~/static_site_editor/services/parse_source_file'; + +describe('parseSourceFile', () => { + const contentSimple = content; + const contentComplex = [content, content, content].join(''); + + describe('the editable shape and its expected values', () => { + it.each` + sourceContent | sourceHeader | sourceSpacing | sourceBody | desc + ${contentSimple} | ${header} | ${spacing} | ${body} | ${'extracts header'} + ${contentComplex} | ${header} | ${spacing} | ${[body, content, content].join('')} | ${'extracts body'} + `('$desc', ({ sourceContent, sourceHeader, sourceSpacing, sourceBody }) => { + const { editable } = parseSourceFile(sourceContent); + + expect(editable).toMatchObject({ + raw: sourceContent, + header: sourceHeader, + spacing: sourceSpacing, + body: sourceBody, + }); + }); + + it('returns the same front matter regardless of front matter duplication', () => { + const parsedSourceSimple = parseSourceFile(contentSimple); + const parsedSourceComplex = parseSourceFile(contentComplex); + + expect(parsedSourceSimple.editable.header).toBe(parsedSourceComplex.editable.header); + }); + }); + + describe('editable body to raw content default and changes', () => { + it.each` + sourceContent | desc + ${contentSimple} | ${'returns false by default for both raw and body'} + ${contentComplex} | ${'returns false by default for both raw and body'} + `('$desc', ({ sourceContent }) => { + const parsedSource = parseSourceFile(sourceContent); + + expect(parsedSource.isModifiedRaw()).toBe(false); + expect(parsedSource.isModifiedBody()).toBe(false); + }); + + it.each` + sourceContent | editableKey | syncKey | isModifiedKey | desc + ${contentSimple} | ${'body'} | ${'syncRaw'} | ${'isModifiedRaw'} | ${'returns true after modification and sync'} + ${contentSimple} | ${'raw'} | ${'syncBody'} | ${'isModifiedBody'} | ${'returns true after modification and sync'} + ${contentComplex} | ${'body'} | ${'syncRaw'} | ${'isModifiedRaw'} | ${'returns true after modification and sync'} + ${contentComplex} | ${'raw'} | ${'syncBody'} | ${'isModifiedBody'} | ${'returns true after modification and sync'} + `('$desc', ({ sourceContent, editableKey, syncKey, isModifiedKey }) => { + const parsedSource = parseSourceFile(sourceContent); + parsedSource.editable[editableKey] += 'Added content'; + parsedSource[syncKey](); + + expect(parsedSource[isModifiedKey]()).toBe(true); + }); + }); +}); diff --git a/spec/frontend/static_site_editor/services/submit_content_changes_spec.js b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js index a1e9ff4ec4c..3636de3fe70 100644 --- a/spec/frontend/static_site_editor/services/submit_content_changes_spec.js +++ b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js @@ -8,6 +8,7 @@ import { SUBMIT_CHANGES_COMMIT_ERROR, SUBMIT_CHANGES_MERGE_REQUEST_ERROR, TRACKING_ACTION_CREATE_COMMIT, + TRACKING_ACTION_CREATE_MERGE_REQUEST, } from '~/static_site_editor/constants'; import generateBranchName from '~/static_site_editor/services/generate_branch_name'; import submitContentChanges from '~/static_site_editor/services/submit_content_changes'; @@ -83,15 +84,6 @@ describe('submitContentChanges', () => { }); }); - it('sends the correct tracking event when committing content changes', () => { - return submitContentChanges({ username, projectId, sourcePath, content }).then(() => { - expect(trackingSpy).toHaveBeenCalledWith( - document.body.dataset.page, - TRACKING_ACTION_CREATE_COMMIT, - ); - }); - }); - it('notifies error when content could not be committed', () => { Api.commitMultiple.mockRejectedValueOnce(); @@ -152,4 +144,24 @@ describe('submitContentChanges', () => { }); }); }); + + describe('sends the correct tracking event', () => { + beforeEach(() => { + return submitContentChanges({ username, projectId, sourcePath, content }); + }); + + it('for committing changes', () => { + expect(trackingSpy).toHaveBeenCalledWith( + document.body.dataset.page, + TRACKING_ACTION_CREATE_COMMIT, + ); + }); + + it('for creating a merge request', () => { + expect(trackingSpy).toHaveBeenCalledWith( + document.body.dataset.page, + TRACKING_ACTION_CREATE_MERGE_REQUEST, + ); + }); + }); }); |