diff options
Diffstat (limited to 'spec/frontend/static_site_editor')
6 files changed, 202 insertions, 72 deletions
diff --git a/spec/frontend/static_site_editor/mock_data.js b/spec/frontend/static_site_editor/mock_data.js index d861f6c9cd7..0f2456cd9ea 100644 --- a/spec/frontend/static_site_editor/mock_data.js +++ b/spec/frontend/static_site_editor/mock_data.js @@ -23,7 +23,10 @@ export const username = 'gitlabuser'; export const projectId = '123456'; export const returnUrl = 'https://www.gitlab.com'; export const sourcePath = 'foobar.md.html'; - +export const mergeRequestMeta = { + title: `Update ${sourcePath} file`, + description: 'Copy update', +}; export const savedContentMeta = { branch: { label: 'foobar', diff --git a/spec/frontend/static_site_editor/pages/home_spec.js b/spec/frontend/static_site_editor/pages/home_spec.js index 41f8a1075c0..10d34d9651c 100644 --- a/spec/frontend/static_site_editor/pages/home_spec.js +++ b/spec/frontend/static_site_editor/pages/home_spec.js @@ -1,4 +1,3 @@ -import Vuex from 'vuex'; import { shallowMount, createLocalVue } from '@vue/test-utils'; import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; import Home from '~/static_site_editor/pages/home.vue'; @@ -7,6 +6,7 @@ import EditArea from '~/static_site_editor/components/edit_area.vue'; import InvalidContentMessage from '~/static_site_editor/components/invalid_content_message.vue'; 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 hasSubmittedChangesMutation from '~/static_site_editor/graphql/mutations/has_submitted_changes.mutation.graphql'; import { SUCCESS_ROUTE } from '~/static_site_editor/router/constants'; import { TRACKING_ACTION_INITIALIZE_EDITOR } from '~/static_site_editor/constants'; @@ -17,6 +17,7 @@ import { sourceContentTitle as title, sourcePath, username, + mergeRequestMeta, savedContentMeta, submitChangesError, trackingCategory, @@ -24,8 +25,6 @@ import { const localVue = createLocalVue(); -localVue.use(Vuex); - describe('static_site_editor/pages/home', () => { let wrapper; let store; @@ -33,6 +32,19 @@ describe('static_site_editor/pages/home', () => { let $router; let mutateMock; let trackingSpy; + const defaultAppData = { + isSupportedContent: true, + hasSubmittedChanges: false, + returnUrl, + project, + username, + sourcePath, + }; + const hasSubmittedChangesMutationPayload = { + data: { + appData: { ...defaultAppData, hasSubmittedChanges: true }, + }, + }; const buildApollo = (queries = {}) => { mutateMock = jest.fn(); @@ -64,7 +76,7 @@ describe('static_site_editor/pages/home', () => { }, data() { return { - appData: { isSupportedContent: true, returnUrl, project, username, sourcePath }, + appData: { ...defaultAppData }, sourceContent: { title, content }, ...data, }; @@ -152,8 +164,14 @@ describe('static_site_editor/pages/home', () => { }); describe('when submitting changes fails', () => { + const setupMutateMock = () => { + mutateMock + .mockResolvedValueOnce(hasSubmittedChangesMutationPayload) + .mockRejectedValueOnce(new Error(submitChangesError)); + }; + beforeEach(() => { - mutateMock.mockRejectedValue(new Error(submitChangesError)); + setupMutateMock(); buildWrapper(); findEditArea().vm.$emit('submit', { content }); @@ -166,6 +184,8 @@ describe('static_site_editor/pages/home', () => { }); it('retries submitting changes when retry button is clicked', () => { + setupMutateMock(); + findSubmitChangesError().vm.$emit('retry'); expect(mutateMock).toHaveBeenCalled(); @@ -190,7 +210,11 @@ describe('static_site_editor/pages/home', () => { const newContent = `new ${content}`; beforeEach(() => { - mutateMock.mockResolvedValueOnce({ data: { submitContentChanges: savedContentMeta } }); + mutateMock.mockResolvedValueOnce(hasSubmittedChangesMutationPayload).mockResolvedValueOnce({ + data: { + submitContentChanges: savedContentMeta, + }, + }); buildWrapper(); findEditArea().vm.$emit('submit', { content: newContent }); @@ -198,8 +222,19 @@ describe('static_site_editor/pages/home', () => { return wrapper.vm.$nextTick(); }); + it('dispatches hasSubmittedChanges mutation', () => { + expect(mutateMock).toHaveBeenNthCalledWith(1, { + mutation: hasSubmittedChangesMutation, + variables: { + input: { + hasSubmittedChanges: true, + }, + }, + }); + }); + it('dispatches submitContentChanges mutation', () => { - expect(mutateMock).toHaveBeenCalledWith({ + expect(mutateMock).toHaveBeenNthCalledWith(2, { mutation: submitContentChangesMutation, variables: { input: { @@ -207,6 +242,8 @@ describe('static_site_editor/pages/home', () => { project, sourcePath, username, + images: undefined, + mergeRequestMeta, }, }, }); diff --git a/spec/frontend/static_site_editor/pages/success_spec.js b/spec/frontend/static_site_editor/pages/success_spec.js index 3e19e2413e7..3fc69dc4586 100644 --- a/spec/frontend/static_site_editor/pages/success_spec.js +++ b/spec/frontend/static_site_editor/pages/success_spec.js @@ -1,10 +1,10 @@ import { shallowMount } from '@vue/test-utils'; -import { GlEmptyState, GlButton } from '@gitlab/ui'; +import { GlButton, GlEmptyState, GlLoadingIcon } from '@gitlab/ui'; import Success from '~/static_site_editor/pages/success.vue'; import { savedContentMeta, returnUrl, sourcePath } from '../mock_data'; import { HOME_ROUTE } from '~/static_site_editor/router/constants'; -describe('static_site_editor/pages/success', () => { +describe('~/static_site_editor/pages/success.vue', () => { const mergeRequestsIllustrationPath = 'illustrations/merge_requests.svg'; let wrapper; let router; @@ -15,14 +15,15 @@ describe('static_site_editor/pages/success', () => { }; }; - const buildWrapper = (data = {}) => { + const buildWrapper = (data = {}, appData = {}) => { wrapper = shallowMount(Success, { mocks: { $router: router, }, stubs: { - GlEmptyState, GlButton, + GlEmptyState, + GlLoadingIcon, }, propsData: { mergeRequestsIllustrationPath, @@ -33,6 +34,8 @@ describe('static_site_editor/pages/success', () => { appData: { returnUrl, sourcePath, + hasSubmittedChanges: true, + ...appData, }, ...data, }; @@ -40,8 +43,9 @@ describe('static_site_editor/pages/success', () => { }); }; - const findEmptyState = () => wrapper.find(GlEmptyState); const findReturnUrlButton = () => wrapper.find(GlButton); + const findEmptyState = () => wrapper.find(GlEmptyState); + const findLoadingIcon = () => wrapper.find(GlLoadingIcon); beforeEach(() => { buildRouter(); @@ -52,50 +56,76 @@ describe('static_site_editor/pages/success', () => { wrapper = null; }); - it('renders empty state with a link to the created merge request', () => { - buildWrapper(); + describe('when savedContentMeta is valid', () => { + it('renders empty state with a link to the created merge request', () => { + buildWrapper(); + + expect(findEmptyState().exists()).toBe(true); + expect(findEmptyState().props()).toMatchObject({ + primaryButtonText: 'View merge request', + primaryButtonLink: savedContentMeta.mergeRequest.url, + title: 'Your merge request has been created', + svgPath: mergeRequestsIllustrationPath, + svgHeight: 146, + }); + }); - expect(findEmptyState().exists()).toBe(true); - expect(findEmptyState().props()).toMatchObject({ - primaryButtonText: 'View merge request', - primaryButtonLink: savedContentMeta.mergeRequest.url, - title: 'Your merge request has been created', - svgPath: mergeRequestsIllustrationPath, + it('displays merge request instructions in the empty state', () => { + buildWrapper(); + + expect(findEmptyState().text()).toContain( + 'To see your changes live you will need to do the following things:', + ); + expect(findEmptyState().text()).toContain('1. Add a clear title to describe the change.'); + expect(findEmptyState().text()).toContain( + '2. Add a description to explain why the change is being made.', + ); + expect(findEmptyState().text()).toContain( + '3. Assign a person to review and accept the merge request.', + ); }); - }); - it('displays merge request instructions in the empty state', () => { - buildWrapper(); - - expect(findEmptyState().text()).toContain( - 'To see your changes live you will need to do the following things:', - ); - expect(findEmptyState().text()).toContain('1. Add a clear title to describe the change.'); - expect(findEmptyState().text()).toContain( - '2. Add a description to explain why the change is being made.', - ); - expect(findEmptyState().text()).toContain( - '3. Assign a person to review and accept the merge request.', - ); - }); + it('displays return to site button', () => { + buildWrapper(); + + expect(findReturnUrlButton().text()).toBe('Return to site'); + expect(findReturnUrlButton().attributes().href).toBe(returnUrl); + }); - it('displays return to site button', () => { - buildWrapper(); + it('displays source path', () => { + buildWrapper(); - expect(findReturnUrlButton().text()).toBe('Return to site'); - expect(findReturnUrlButton().attributes().href).toBe(returnUrl); + expect(wrapper.text()).toContain(`Update ${sourcePath} file`); + }); }); - it('displays source path', () => { - buildWrapper(); + describe('when savedContentMeta is invalid', () => { + it('renders empty state with a loader', () => { + buildWrapper({ savedContentMeta: null }); - expect(wrapper.text()).toContain(`Update ${sourcePath} file`); - }); + expect(findEmptyState().exists()).toBe(true); + expect(findEmptyState().props()).toMatchObject({ + title: 'Creating your merge request', + svgPath: mergeRequestsIllustrationPath, + }); + expect(findLoadingIcon().exists()).toBe(true); + }); - it('redirects to the HOME route when content has not been submitted', () => { - buildWrapper({ savedContentMeta: null }); + it('displays helper info in the empty state', () => { + buildWrapper({ savedContentMeta: null }); - expect(router.push).toHaveBeenCalledWith(HOME_ROUTE); - expect(wrapper.html()).toBe(''); + expect(findEmptyState().text()).toContain( + 'You can set an assignee to get your changes reviewed and deployed once your merge request is created', + ); + expect(findEmptyState().text()).toContain( + 'A link to view the merge request will appear once ready', + ); + }); + + it('redirects to the HOME route when content has not been submitted', () => { + buildWrapper({ savedContentMeta: null }, { hasSubmittedChanges: false }); + + expect(router.push).toHaveBeenCalledWith(HOME_ROUTE); + }); }); }); diff --git a/spec/frontend/static_site_editor/services/front_matterify_spec.js b/spec/frontend/static_site_editor/services/front_matterify_spec.js new file mode 100644 index 00000000000..dbaedc30849 --- /dev/null +++ b/spec/frontend/static_site_editor/services/front_matterify_spec.js @@ -0,0 +1,47 @@ +import { + sourceContentYAML as content, + sourceContentHeaderObjYAML as yamlFrontMatterObj, + sourceContentSpacing as spacing, + sourceContentBody as body, +} from '../mock_data'; + +import { frontMatterify, stringify } from '~/static_site_editor/services/front_matterify'; + +describe('static_site_editor/services/front_matterify', () => { + const frontMatterifiedContent = { + source: content, + matter: yamlFrontMatterObj, + spacing, + content: body, + delimiter: '---', + type: 'yaml', + }; + const frontMatterifiedBody = { + source: body, + matter: null, + spacing: null, + content: body, + delimiter: null, + type: null, + }; + + describe('frontMatterify', () => { + it.each` + frontMatterified | target + ${frontMatterify(content)} | ${frontMatterifiedContent} + ${frontMatterify(body)} | ${frontMatterifiedBody} + `('returns $target from $frontMatterified', ({ frontMatterified, target }) => { + expect(frontMatterified).toEqual(target); + }); + }); + + describe('stringify', () => { + it.each` + stringified | target + ${stringify(frontMatterifiedContent)} | ${content} + ${stringify(frontMatterifiedBody)} | ${body} + `('returns $target from $stringified', ({ stringified, target }) => { + expect(stringified).toBe(target); + }); + }); +}); 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 d464e6b1895..5018da7300b 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 @@ -19,6 +19,7 @@ import { commitBranchResponse, commitMultipleResponse, createMergeRequestResponse, + mergeRequestMeta, sourcePath, sourceContentYAML as content, trackingCategory, @@ -28,11 +29,20 @@ import { jest.mock('~/static_site_editor/services/generate_branch_name'); describe('submitContentChanges', () => { - const mergeRequestTitle = `Update ${sourcePath} file`; const branch = 'branch-name'; let trackingSpy; let origPage; + const buildPayload = (overrides = {}) => ({ + username, + projectId, + sourcePath, + content, + images, + mergeRequestMeta, + ...overrides, + }); + beforeEach(() => { jest.spyOn(Api, 'createBranch').mockResolvedValue({ data: commitBranchResponse }); jest.spyOn(Api, 'commitMultiple').mockResolvedValue({ data: commitMultipleResponse }); @@ -53,7 +63,7 @@ describe('submitContentChanges', () => { }); it('creates a branch named after the username and target branch', () => { - return submitContentChanges({ username, projectId }).then(() => { + return submitContentChanges(buildPayload()).then(() => { expect(Api.createBranch).toHaveBeenCalledWith(projectId, { ref: DEFAULT_TARGET_BRANCH, branch, @@ -64,16 +74,16 @@ describe('submitContentChanges', () => { it('notifies error when branch could not be created', () => { Api.createBranch.mockRejectedValueOnce(); - return expect(submitContentChanges({ username, projectId })).rejects.toThrow( + return expect(submitContentChanges(buildPayload())).rejects.toThrow( SUBMIT_CHANGES_BRANCH_ERROR, ); }); it('commits the content changes to the branch when creating branch succeeds', () => { - return submitContentChanges({ username, projectId, sourcePath, content, images }).then(() => { + return submitContentChanges(buildPayload()).then(() => { expect(Api.commitMultiple).toHaveBeenCalledWith(projectId, { branch, - commit_message: mergeRequestTitle, + commit_message: mergeRequestMeta.title, actions: [ { action: 'update', @@ -93,16 +103,11 @@ describe('submitContentChanges', () => { it('does not commit an image if it has been removed from the content', () => { const contentWithoutImages = '## Content without images'; - return submitContentChanges({ - username, - projectId, - sourcePath, - content: contentWithoutImages, - images, - }).then(() => { + const payload = buildPayload({ content: contentWithoutImages }); + return submitContentChanges(payload).then(() => { expect(Api.commitMultiple).toHaveBeenCalledWith(projectId, { branch, - commit_message: mergeRequestTitle, + commit_message: mergeRequestMeta.title, actions: [ { action: 'update', @@ -117,17 +122,19 @@ describe('submitContentChanges', () => { it('notifies error when content could not be committed', () => { Api.commitMultiple.mockRejectedValueOnce(); - return expect(submitContentChanges({ username, projectId, images })).rejects.toThrow( + return expect(submitContentChanges(buildPayload())).rejects.toThrow( SUBMIT_CHANGES_COMMIT_ERROR, ); }); - it('creates a merge request when commiting changes succeeds', () => { - return submitContentChanges({ username, projectId, sourcePath, content, images }).then(() => { + it('creates a merge request when committing changes succeeds', () => { + return submitContentChanges(buildPayload()).then(() => { + const { title, description } = mergeRequestMeta; expect(Api.createProjectMergeRequest).toHaveBeenCalledWith( projectId, convertObjectPropsToSnakeCase({ - title: mergeRequestTitle, + title, + description, targetBranch: DEFAULT_TARGET_BRANCH, sourceBranch: branch, }), @@ -138,7 +145,7 @@ describe('submitContentChanges', () => { it('notifies error when merge request could not be created', () => { Api.createProjectMergeRequest.mockRejectedValueOnce(); - return expect(submitContentChanges({ username, projectId, images })).rejects.toThrow( + return expect(submitContentChanges(buildPayload())).rejects.toThrow( SUBMIT_CHANGES_MERGE_REQUEST_ERROR, ); }); @@ -147,11 +154,9 @@ describe('submitContentChanges', () => { let result; beforeEach(() => { - return submitContentChanges({ username, projectId, sourcePath, content, images }).then( - _result => { - result = _result; - }, - ); + return submitContentChanges(buildPayload()).then(_result => { + result = _result; + }); }); it('returns the branch name', () => { @@ -179,7 +184,7 @@ describe('submitContentChanges', () => { describe('sends the correct tracking event', () => { beforeEach(() => { - return submitContentChanges({ username, projectId, sourcePath, content, images }); + return submitContentChanges(buildPayload()); }); it('for committing changes', () => { diff --git a/spec/frontend/static_site_editor/services/templater_spec.js b/spec/frontend/static_site_editor/services/templater_spec.js index 1e7ae872b7e..cb3a0a0c106 100644 --- a/spec/frontend/static_site_editor/services/templater_spec.js +++ b/spec/frontend/static_site_editor/services/templater_spec.js @@ -39,6 +39,10 @@ Below this line is a codeblock of the same HTML that should be ignored and prese <p>Some paragraph...</p> </div> \`\`\` + +Below this line is a iframe that should be ignored and preserved + +<iframe></iframe> `; const sourceTemplated = `Below this line is a simple ERB (single-line erb block) example. @@ -87,6 +91,10 @@ Below this line is a codeblock of the same HTML that should be ignored and prese <p>Some paragraph...</p> </div> \`\`\` + +Below this line is a iframe that should be ignored and preserved + +<iframe></iframe> `; it.each` |