diff options
Diffstat (limited to 'spec/frontend/static_site_editor')
13 files changed, 468 insertions, 492 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 new file mode 100644 index 00000000000..bfe41f65d6e --- /dev/null +++ b/spec/frontend/static_site_editor/components/edit_area_spec.js @@ -0,0 +1,76 @@ +import { shallowMount } from '@vue/test-utils'; + +import RichContentEditor from '~/vue_shared/components/rich_content_editor/rich_content_editor.vue'; + +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 { sourceContentTitle as title, sourceContent as content, returnUrl } from '../mock_data'; + +describe('~/static_site_editor/components/edit_area.vue', () => { + let wrapper; + const savingChanges = true; + const newContent = `new ${content}`; + + const buildWrapper = (propsData = {}) => { + wrapper = shallowMount(EditArea, { + propsData: { + title, + content, + returnUrl, + savingChanges, + ...propsData, + }, + }); + }; + + const findEditHeader = () => wrapper.find(EditHeader); + const findRichContentEditor = () => wrapper.find(RichContentEditor); + const findPublishToolbar = () => wrapper.find(PublishToolbar); + + beforeEach(() => { + buildWrapper(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders edit header', () => { + expect(findEditHeader().exists()).toBe(true); + expect(findEditHeader().props('title')).toBe(title); + }); + + it('renders rich content editor', () => { + expect(findRichContentEditor().exists()).toBe(true); + expect(findRichContentEditor().props('value')).toBe(content); + }); + + 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); + }); + + describe('when content changes', () => { + beforeEach(() => { + findRichContentEditor().vm.$emit('input', newContent); + + return wrapper.vm.$nextTick(); + }); + + it('sets publish toolbar as saveable when content changes', () => { + expect(findPublishToolbar().props('saveable')).toBe(true); + }); + + it('sets publish toolbar as not saveable when content changes are rollback', () => { + findRichContentEditor().vm.$emit('input', content); + + return wrapper.vm.$nextTick().then(() => { + expect(findPublishToolbar().props('saveable')).toBe(false); + }); + }); + }); +}); diff --git a/spec/frontend/static_site_editor/components/publish_toolbar_spec.js b/spec/frontend/static_site_editor/components/publish_toolbar_spec.js index 82eb12d4c4d..5428ed23266 100644 --- a/spec/frontend/static_site_editor/components/publish_toolbar_spec.js +++ b/spec/frontend/static_site_editor/components/publish_toolbar_spec.js @@ -1,5 +1,5 @@ import { shallowMount } from '@vue/test-utils'; -import { GlButton, GlLoadingIcon } from '@gitlab/ui'; +import { GlButton } from '@gitlab/ui'; import PublishToolbar from '~/static_site_editor/components/publish_toolbar.vue'; @@ -19,7 +19,6 @@ describe('Static Site Editor Toolbar', () => { const findReturnUrlLink = () => wrapper.find({ ref: 'returnUrlLink' }); const findSaveChangesButton = () => wrapper.find(GlButton); - const findLoadingIndicator = () => wrapper.find(GlLoadingIcon); beforeEach(() => { buildWrapper(); @@ -37,8 +36,8 @@ describe('Static Site Editor Toolbar', () => { expect(findSaveChangesButton().attributes('disabled')).toBe('true'); }); - it('does not display saving changes indicator', () => { - expect(findLoadingIndicator().classes()).toContain('invisible'); + it('does not render the Submit Changes button with a loader', () => { + expect(findSaveChangesButton().props('loading')).toBe(false); }); it('does not render returnUrl link', () => { @@ -62,15 +61,11 @@ describe('Static Site Editor Toolbar', () => { describe('when saving changes', () => { beforeEach(() => { - buildWrapper({ saveable: true, savingChanges: true }); + buildWrapper({ savingChanges: true }); }); - it('disables Submit Changes button', () => { - expect(findSaveChangesButton().attributes('disabled')).toBe('true'); - }); - - it('displays saving changes indicator', () => { - expect(findLoadingIndicator().classes()).not.toContain('invisible'); + it('renders the Submit Changes button with a loading indicator', () => { + expect(findSaveChangesButton().props('loading')).toBe(true); }); }); diff --git a/spec/frontend/static_site_editor/components/saved_changes_message_spec.js b/spec/frontend/static_site_editor/components/saved_changes_message_spec.js index 659e9be59d2..a63c3a83395 100644 --- a/spec/frontend/static_site_editor/components/saved_changes_message_spec.js +++ b/spec/frontend/static_site_editor/components/saved_changes_message_spec.js @@ -46,14 +46,11 @@ describe('~/static_site_editor/components/saved_changes_message.vue', () => { ${'branch'} | ${findBranchLink} | ${props.branch} ${'commit'} | ${findCommitLink} | ${props.commit} ${'merge request'} | ${findMergeRequestLink} | ${props.mergeRequest} - `('renders $desc link', ({ desc, findEl, prop }) => { + `('renders $desc link', ({ findEl, prop }) => { const el = findEl(); expect(el.exists()).toBe(true); expect(el.text()).toBe(prop.label); - - if (desc !== 'branch') { - expect(el.attributes('href')).toBe(prop.url); - } + expect(el.attributes('href')).toBe(prop.url); }); }); diff --git a/spec/frontend/static_site_editor/components/static_site_editor_spec.js b/spec/frontend/static_site_editor/components/static_site_editor_spec.js deleted file mode 100644 index 5d4e3758557..00000000000 --- a/spec/frontend/static_site_editor/components/static_site_editor_spec.js +++ /dev/null @@ -1,247 +0,0 @@ -import Vuex from 'vuex'; -import { shallowMount, createLocalVue } from '@vue/test-utils'; -import { GlSkeletonLoader } from '@gitlab/ui'; - -import createState from '~/static_site_editor/store/state'; - -import StaticSiteEditor from '~/static_site_editor/components/static_site_editor.vue'; -import EditArea from '~/static_site_editor/components/edit_area.vue'; -import EditHeader from '~/static_site_editor/components/edit_header.vue'; -import InvalidContentMessage from '~/static_site_editor/components/invalid_content_message.vue'; -import PublishToolbar from '~/static_site_editor/components/publish_toolbar.vue'; -import SubmitChangesError from '~/static_site_editor/components/submit_changes_error.vue'; -import SavedChangesMessage from '~/static_site_editor/components/saved_changes_message.vue'; - -import { - returnUrl, - sourceContent, - sourceContentTitle, - savedContentMeta, - submitChangesError, -} from '../mock_data'; - -const localVue = createLocalVue(); - -localVue.use(Vuex); - -describe('StaticSiteEditor', () => { - let wrapper; - let store; - let loadContentActionMock; - let setContentActionMock; - let submitChangesActionMock; - let dismissSubmitChangesErrorActionMock; - - const buildStore = ({ initialState, getters } = {}) => { - loadContentActionMock = jest.fn(); - setContentActionMock = jest.fn(); - submitChangesActionMock = jest.fn(); - dismissSubmitChangesErrorActionMock = jest.fn(); - - store = new Vuex.Store({ - state: createState({ - isSupportedContent: true, - ...initialState, - }), - getters: { - contentChanged: () => false, - ...getters, - }, - actions: { - loadContent: loadContentActionMock, - setContent: setContentActionMock, - submitChanges: submitChangesActionMock, - dismissSubmitChangesError: dismissSubmitChangesErrorActionMock, - }, - }); - }; - const buildContentLoadedStore = ({ initialState, getters } = {}) => { - buildStore({ - initialState: { - isContentLoaded: true, - ...initialState, - }, - getters: { - ...getters, - }, - }); - }; - - const buildWrapper = () => { - wrapper = shallowMount(StaticSiteEditor, { - localVue, - store, - }); - }; - - const findEditArea = () => wrapper.find(EditArea); - const findEditHeader = () => wrapper.find(EditHeader); - const findInvalidContentMessage = () => wrapper.find(InvalidContentMessage); - const findPublishToolbar = () => wrapper.find(PublishToolbar); - const findSkeletonLoader = () => wrapper.find(GlSkeletonLoader); - const findSubmitChangesError = () => wrapper.find(SubmitChangesError); - const findSavedChangesMessage = () => wrapper.find(SavedChangesMessage); - - beforeEach(() => { - buildStore(); - buildWrapper(); - }); - - afterEach(() => { - wrapper.destroy(); - }); - - it('renders the saved changes message when changes are submitted successfully', () => { - buildStore({ initialState: { returnUrl, savedContentMeta } }); - buildWrapper(); - - expect(findSavedChangesMessage().exists()).toBe(true); - expect(findSavedChangesMessage().props()).toEqual({ - returnUrl, - ...savedContentMeta, - }); - }); - - describe('when content is not loaded', () => { - it('does not render edit area', () => { - expect(findEditArea().exists()).toBe(false); - }); - - it('does not render edit header', () => { - expect(findEditHeader().exists()).toBe(false); - }); - - it('does not render toolbar', () => { - expect(findPublishToolbar().exists()).toBe(false); - }); - - it('does not render saved changes message', () => { - expect(findSavedChangesMessage().exists()).toBe(false); - }); - }); - - describe('when content is loaded', () => { - const content = sourceContent; - const title = sourceContentTitle; - - beforeEach(() => { - buildContentLoadedStore({ initialState: { content, title } }); - buildWrapper(); - }); - - it('renders the edit area', () => { - expect(findEditArea().exists()).toBe(true); - }); - - it('renders the edit header', () => { - expect(findEditHeader().exists()).toBe(true); - }); - - it('does not render skeleton loader', () => { - expect(findSkeletonLoader().exists()).toBe(false); - }); - - it('passes page content to edit area', () => { - expect(findEditArea().props('value')).toBe(content); - }); - - it('passes page title to edit header', () => { - expect(findEditHeader().props('title')).toBe(title); - }); - - it('renders toolbar', () => { - expect(findPublishToolbar().exists()).toBe(true); - }); - }); - - it('sets toolbar as saveable when content changes', () => { - buildContentLoadedStore({ - getters: { - contentChanged: () => true, - }, - }); - buildWrapper(); - - expect(findPublishToolbar().props('saveable')).toBe(true); - }); - - it('displays skeleton loader when loading content', () => { - buildStore({ initialState: { isLoadingContent: true } }); - buildWrapper(); - - expect(findSkeletonLoader().exists()).toBe(true); - }); - - it('does not display submit changes error when an error does not exist', () => { - buildContentLoadedStore(); - buildWrapper(); - - expect(findSubmitChangesError().exists()).toBe(false); - }); - - it('sets toolbar as saving when saving changes', () => { - buildContentLoadedStore({ - initialState: { - isSavingChanges: true, - }, - }); - buildWrapper(); - - expect(findPublishToolbar().props('savingChanges')).toBe(true); - }); - - it('displays invalid content message when content is not supported', () => { - buildStore({ initialState: { isSupportedContent: false } }); - buildWrapper(); - - expect(findInvalidContentMessage().exists()).toBe(true); - }); - - describe('when submitting changes fail', () => { - beforeEach(() => { - buildContentLoadedStore({ - initialState: { - submitChangesError, - }, - }); - buildWrapper(); - }); - - it('displays submit changes error message', () => { - expect(findSubmitChangesError().exists()).toBe(true); - }); - - it('dispatches submitChanges action when error message emits retry event', () => { - findSubmitChangesError().vm.$emit('retry'); - - expect(submitChangesActionMock).toHaveBeenCalled(); - }); - - it('dispatches dismissSubmitChangesError action when error message emits dismiss event', () => { - findSubmitChangesError().vm.$emit('dismiss'); - - expect(dismissSubmitChangesErrorActionMock).toHaveBeenCalled(); - }); - }); - - it('dispatches load content action', () => { - expect(loadContentActionMock).toHaveBeenCalled(); - }); - - it('dispatches setContent action when edit area emits input event', () => { - buildContentLoadedStore(); - buildWrapper(); - - findEditArea().vm.$emit('input', sourceContent); - - expect(setContentActionMock).toHaveBeenCalledWith(expect.anything(), sourceContent, undefined); - }); - - it('dispatches submitChanges action when toolbar emits submit event', () => { - buildContentLoadedStore(); - buildWrapper(); - findPublishToolbar().vm.$emit('submit'); - - expect(submitChangesActionMock).toHaveBeenCalled(); - }); -}); diff --git a/spec/frontend/static_site_editor/graphql/resolvers/file_spec.js b/spec/frontend/static_site_editor/graphql/resolvers/file_spec.js new file mode 100644 index 00000000000..8504d09e0f1 --- /dev/null +++ b/spec/frontend/static_site_editor/graphql/resolvers/file_spec.js @@ -0,0 +1,25 @@ +import fileResolver from '~/static_site_editor/graphql/resolvers/file'; +import loadSourceContent from '~/static_site_editor/services/load_source_content'; + +import { + projectId, + sourcePath, + sourceContentTitle as title, + sourceContent as content, +} from '../../mock_data'; + +jest.mock('~/static_site_editor/services/load_source_content', () => jest.fn()); + +describe('static_site_editor/graphql/resolvers/file', () => { + it('returns file content and title when fetching file successfully', () => { + loadSourceContent.mockResolvedValueOnce({ title, content }); + + return fileResolver({ fullPath: projectId }, { path: sourcePath }).then(file => { + expect(file).toEqual({ + __typename: 'File', + title, + content, + }); + }); + }); +}); diff --git a/spec/frontend/static_site_editor/graphql/resolvers/submit_content_changes_spec.js b/spec/frontend/static_site_editor/graphql/resolvers/submit_content_changes_spec.js new file mode 100644 index 00000000000..515b5394594 --- /dev/null +++ b/spec/frontend/static_site_editor/graphql/resolvers/submit_content_changes_spec.js @@ -0,0 +1,37 @@ +import savedContentMetaQuery from '~/static_site_editor/graphql/queries/saved_content_meta.query.graphql'; +import submitContentChanges from '~/static_site_editor/services/submit_content_changes'; +import submitContentChangesResolver from '~/static_site_editor/graphql/resolvers/submit_content_changes'; + +import { + projectId as project, + sourcePath, + username, + sourceContent as content, + savedContentMeta, +} from '../../mock_data'; + +jest.mock('~/static_site_editor/services/submit_content_changes', () => jest.fn()); + +describe('static_site_editor/graphql/resolvers/submit_content_changes', () => { + it('writes savedContentMeta query with the data returned by the submitContentChanges service', () => { + const cache = { writeQuery: jest.fn() }; + + submitContentChanges.mockResolvedValueOnce(savedContentMeta); + + return submitContentChangesResolver( + {}, + { input: { path: sourcePath, project, sourcePath, content, username } }, + { cache }, + ).then(() => { + expect(cache.writeQuery).toHaveBeenCalledWith({ + query: savedContentMetaQuery, + data: { + savedContentMeta: { + __typename: 'SavedContentMeta', + ...savedContentMeta, + }, + }, + }); + }); + }); +}); diff --git a/spec/frontend/static_site_editor/mock_data.js b/spec/frontend/static_site_editor/mock_data.js index 962047e6dd2..371695e913e 100644 --- a/spec/frontend/static_site_editor/mock_data.js +++ b/spec/frontend/static_site_editor/mock_data.js @@ -34,6 +34,9 @@ export const savedContentMeta = { }; export const submitChangesError = 'Could not save changes'; +export const commitBranchResponse = { + web_url: '/tree/root-master-patch-88195', +}; export const commitMultipleResponse = { short_id: 'ed899a2f4b5', web_url: '/commit/ed899a2f4b5', @@ -42,3 +45,5 @@ export const createMergeRequestResponse = { iid: '123', web_url: '/merge_requests/123', }; + +export const trackingCategory = 'projects:static_site_editor:show'; diff --git a/spec/frontend/static_site_editor/pages/home_spec.js b/spec/frontend/static_site_editor/pages/home_spec.js new file mode 100644 index 00000000000..8c9c54f593e --- /dev/null +++ b/spec/frontend/static_site_editor/pages/home_spec.js @@ -0,0 +1,211 @@ +import Vuex from 'vuex'; +import { shallowMount, createLocalVue } from '@vue/test-utils'; +import Home from '~/static_site_editor/pages/home.vue'; +import SkeletonLoader from '~/static_site_editor/components/skeleton_loader.vue'; +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 { SUCCESS_ROUTE } from '~/static_site_editor/router/constants'; + +import { + projectId as project, + returnUrl, + sourceContent as content, + sourceContentTitle as title, + sourcePath, + username, + savedContentMeta, + submitChangesError, +} from '../mock_data'; + +const localVue = createLocalVue(); + +localVue.use(Vuex); + +describe('static_site_editor/pages/home', () => { + let wrapper; + let store; + let $apollo; + let $router; + let mutateMock; + + const buildApollo = (queries = {}) => { + mutateMock = jest.fn(); + + $apollo = { + queries: { + sourceContent: { + loading: false, + }, + ...queries, + }, + mutate: mutateMock, + }; + }; + + const buildRouter = () => { + $router = { + push: jest.fn(), + }; + }; + + const buildWrapper = (data = {}) => { + wrapper = shallowMount(Home, { + localVue, + store, + mocks: { + $apollo, + $router, + }, + data() { + return { + appData: { isSupportedContent: true, returnUrl, project, username, sourcePath }, + sourceContent: { title, content }, + ...data, + }; + }, + }); + }; + + const findEditArea = () => wrapper.find(EditArea); + const findInvalidContentMessage = () => wrapper.find(InvalidContentMessage); + const findSkeletonLoader = () => wrapper.find(SkeletonLoader); + const findSubmitChangesError = () => wrapper.find(SubmitChangesError); + + beforeEach(() => { + buildApollo(); + buildRouter(); + }); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + $apollo = null; + }); + + describe('when content is loaded', () => { + beforeEach(() => { + buildWrapper(); + }); + + it('renders edit area', () => { + expect(findEditArea().exists()).toBe(true); + }); + + it('provides source content, returnUrl, and isSavingChanges to the edit area', () => { + expect(findEditArea().props()).toMatchObject({ + title, + content, + returnUrl, + savingChanges: false, + }); + }); + }); + + it('does not render edit area when content is not loaded', () => { + buildWrapper({ sourceContent: null }); + + expect(findEditArea().exists()).toBe(false); + }); + + it('renders skeleton loader when content is not loading', () => { + buildApollo({ + sourceContent: { + loading: true, + }, + }); + buildWrapper(); + + expect(findSkeletonLoader().exists()).toBe(true); + }); + + it('does not render skeleton loader when content is not loading', () => { + buildApollo({ + sourceContent: { + loading: false, + }, + }); + buildWrapper(); + + expect(findSkeletonLoader().exists()).toBe(false); + }); + + it('displays invalid content message when content is not supported', () => { + buildWrapper({ appData: { isSupportedContent: false } }); + + expect(findInvalidContentMessage().exists()).toBe(true); + }); + + it('does not display invalid content message when content is supported', () => { + buildWrapper({ appData: { isSupportedContent: true } }); + + expect(findInvalidContentMessage().exists()).toBe(false); + }); + + describe('when submitting changes fails', () => { + beforeEach(() => { + mutateMock.mockRejectedValue(new Error(submitChangesError)); + + buildWrapper(); + findEditArea().vm.$emit('submit', { content }); + + return wrapper.vm.$nextTick(); + }); + + it('displays submit changes error message', () => { + expect(findSubmitChangesError().exists()).toBe(true); + }); + + it('retries submitting changes when retry button is clicked', () => { + findSubmitChangesError().vm.$emit('retry'); + + expect(mutateMock).toHaveBeenCalled(); + }); + + it('hides submit changes error message when dismiss button is clicked', () => { + findSubmitChangesError().vm.$emit('dismiss'); + + return wrapper.vm.$nextTick().then(() => { + expect(findSubmitChangesError().exists()).toBe(false); + }); + }); + }); + + it('does not display submit changes error when an error does not exist', () => { + buildWrapper(); + + expect(findSubmitChangesError().exists()).toBe(false); + }); + + describe('when submitting changes succeeds', () => { + const newContent = `new ${content}`; + + beforeEach(() => { + mutateMock.mockResolvedValueOnce({ data: { submitContentChanges: savedContentMeta } }); + + buildWrapper(); + findEditArea().vm.$emit('submit', { content: newContent }); + + return wrapper.vm.$nextTick(); + }); + + it('dispatches submitContentChanges mutation', () => { + expect(mutateMock).toHaveBeenCalledWith({ + mutation: submitContentChangesMutation, + variables: { + input: { + content: newContent, + project, + sourcePath, + username, + }, + }, + }); + }); + + it('transitions to the SUCCESS route', () => { + expect($router.push).toHaveBeenCalledWith(SUCCESS_ROUTE); + }); + }); +}); diff --git a/spec/frontend/static_site_editor/pages/success_spec.js b/spec/frontend/static_site_editor/pages/success_spec.js new file mode 100644 index 00000000000..d62b67bfa83 --- /dev/null +++ b/spec/frontend/static_site_editor/pages/success_spec.js @@ -0,0 +1,78 @@ +import Vuex from 'vuex'; +import { shallowMount, createLocalVue } from '@vue/test-utils'; +import Success from '~/static_site_editor/pages/success.vue'; +import SavedChangesMessage from '~/static_site_editor/components/saved_changes_message.vue'; +import { savedContentMeta, returnUrl } from '../mock_data'; +import { HOME_ROUTE } from '~/static_site_editor/router/constants'; + +const localVue = createLocalVue(); + +localVue.use(Vuex); + +describe('static_site_editor/pages/success', () => { + let wrapper; + let store; + let router; + + const buildRouter = () => { + router = { + push: jest.fn(), + }; + }; + + const buildWrapper = (data = {}) => { + wrapper = shallowMount(Success, { + localVue, + store, + mocks: { + $router: router, + }, + data() { + return { + savedContentMeta, + appData: { + returnUrl, + }, + ...data, + }; + }, + }); + }; + + const findSavedChangesMessage = () => wrapper.find(SavedChangesMessage); + + beforeEach(() => { + buildRouter(); + }); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + it('renders saved changes message', () => { + buildWrapper(); + + expect(findSavedChangesMessage().exists()).toBe(true); + }); + + it('passes returnUrl to the saved changes message', () => { + buildWrapper(); + + expect(findSavedChangesMessage().props('returnUrl')).toBe(returnUrl); + }); + + it('passes saved content metadata to the saved changes message', () => { + buildWrapper(); + + expect(findSavedChangesMessage().props('branch')).toBe(savedContentMeta.branch); + expect(findSavedChangesMessage().props('commit')).toBe(savedContentMeta.commit); + expect(findSavedChangesMessage().props('mergeRequest')).toBe(savedContentMeta.mergeRequest); + }); + + it('redirects to the HOME route when content has not been submitted', () => { + buildWrapper({ savedContentMeta: null }); + + expect(router.push).toHaveBeenCalledWith(HOME_ROUTE); + }); +}); 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 9a0bd88b57d..a1e9ff4ec4c 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 @@ -1,11 +1,13 @@ import Api from '~/api'; import { convertObjectPropsToSnakeCase } from '~/lib/utils/common_utils'; +import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; import { DEFAULT_TARGET_BRANCH, SUBMIT_CHANGES_BRANCH_ERROR, SUBMIT_CHANGES_COMMIT_ERROR, SUBMIT_CHANGES_MERGE_REQUEST_ERROR, + TRACKING_ACTION_CREATE_COMMIT, } 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'; @@ -13,10 +15,12 @@ import submitContentChanges from '~/static_site_editor/services/submit_content_c import { username, projectId, + commitBranchResponse, commitMultipleResponse, createMergeRequestResponse, sourcePath, sourceContent as content, + trackingCategory, } from '../mock_data'; jest.mock('~/static_site_editor/services/generate_branch_name'); @@ -24,15 +28,26 @@ jest.mock('~/static_site_editor/services/generate_branch_name'); describe('submitContentChanges', () => { const mergeRequestTitle = `Update ${sourcePath} file`; const branch = 'branch-name'; + let trackingSpy; + let origPage; beforeEach(() => { - jest.spyOn(Api, 'createBranch').mockResolvedValue(); + jest.spyOn(Api, 'createBranch').mockResolvedValue({ data: commitBranchResponse }); jest.spyOn(Api, 'commitMultiple').mockResolvedValue({ data: commitMultipleResponse }); jest .spyOn(Api, 'createProjectMergeRequest') .mockResolvedValue({ data: createMergeRequestResponse }); generateBranchName.mockReturnValue(branch); + + origPage = document.body.dataset.page; + document.body.dataset.page = trackingCategory; + trackingSpy = mockTracking(document.body.dataset.page, undefined, jest.spyOn); + }); + + afterEach(() => { + document.body.dataset.page = origPage; + unmockTracking(); }); it('creates a branch named after the username and target branch', () => { @@ -47,7 +62,7 @@ describe('submitContentChanges', () => { it('notifies error when branch could not be created', () => { Api.createBranch.mockRejectedValueOnce(); - expect(submitContentChanges({ username, projectId })).rejects.toThrow( + return expect(submitContentChanges({ username, projectId })).rejects.toThrow( SUBMIT_CHANGES_BRANCH_ERROR, ); }); @@ -68,10 +83,19 @@ 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(); - expect(submitContentChanges({ username, projectId })).rejects.toThrow( + return expect(submitContentChanges({ username, projectId })).rejects.toThrow( SUBMIT_CHANGES_COMMIT_ERROR, ); }); @@ -92,7 +116,7 @@ describe('submitContentChanges', () => { it('notifies error when merge request could not be created', () => { Api.createProjectMergeRequest.mockRejectedValueOnce(); - expect(submitContentChanges({ username, projectId })).rejects.toThrow( + return expect(submitContentChanges({ username, projectId })).rejects.toThrow( SUBMIT_CHANGES_MERGE_REQUEST_ERROR, ); }); diff --git a/spec/frontend/static_site_editor/store/actions_spec.js b/spec/frontend/static_site_editor/store/actions_spec.js deleted file mode 100644 index 6b0b77f59b7..00000000000 --- a/spec/frontend/static_site_editor/store/actions_spec.js +++ /dev/null @@ -1,152 +0,0 @@ -import testAction from 'helpers/vuex_action_helper'; -import createState from '~/static_site_editor/store/state'; -import * as actions from '~/static_site_editor/store/actions'; -import * as mutationTypes from '~/static_site_editor/store/mutation_types'; -import loadSourceContent from '~/static_site_editor/services/load_source_content'; -import submitContentChanges from '~/static_site_editor/services/submit_content_changes'; - -import createFlash from '~/flash'; - -import { - username, - projectId, - sourcePath, - sourceContentTitle as title, - sourceContent as content, - savedContentMeta, - submitChangesError, -} from '../mock_data'; - -jest.mock('~/flash'); -jest.mock('~/static_site_editor/services/load_source_content', () => jest.fn()); -jest.mock('~/static_site_editor/services/submit_content_changes', () => jest.fn()); - -describe('Static Site Editor Store actions', () => { - let state; - - beforeEach(() => { - state = createState({ - projectId, - sourcePath, - }); - }); - - describe('loadContent', () => { - describe('on success', () => { - const payload = { title, content }; - - beforeEach(() => { - loadSourceContent.mockResolvedValueOnce(payload); - }); - - it('commits receiveContentSuccess', () => { - testAction( - actions.loadContent, - null, - state, - [ - { type: mutationTypes.LOAD_CONTENT }, - { type: mutationTypes.RECEIVE_CONTENT_SUCCESS, payload }, - ], - [], - ); - - expect(loadSourceContent).toHaveBeenCalledWith({ projectId, sourcePath }); - }); - }); - - describe('on error', () => { - const expectedMutations = [ - { type: mutationTypes.LOAD_CONTENT }, - { type: mutationTypes.RECEIVE_CONTENT_ERROR }, - ]; - - beforeEach(() => { - loadSourceContent.mockRejectedValueOnce(); - }); - - it('commits receiveContentError', () => { - testAction(actions.loadContent, null, state, expectedMutations); - }); - - it('displays flash communicating error', () => { - return testAction(actions.loadContent, null, state, expectedMutations).then(() => { - expect(createFlash).toHaveBeenCalledWith( - 'An error ocurred while loading your content. Please try again.', - ); - }); - }); - }); - }); - - describe('setContent', () => { - it('commits setContent mutation', () => { - testAction(actions.setContent, content, state, [ - { - type: mutationTypes.SET_CONTENT, - payload: content, - }, - ]); - }); - }); - - describe('submitChanges', () => { - describe('on success', () => { - beforeEach(() => { - state = createState({ - projectId, - content, - username, - sourcePath, - }); - submitContentChanges.mockResolvedValueOnce(savedContentMeta); - }); - - it('commits submitChangesSuccess mutation', () => { - testAction( - actions.submitChanges, - null, - state, - [ - { type: mutationTypes.SUBMIT_CHANGES }, - { type: mutationTypes.SUBMIT_CHANGES_SUCCESS, payload: savedContentMeta }, - ], - [], - ); - - expect(submitContentChanges).toHaveBeenCalledWith({ - username, - projectId, - content, - sourcePath, - }); - }); - }); - - describe('on error', () => { - const error = new Error(submitChangesError); - const expectedMutations = [ - { type: mutationTypes.SUBMIT_CHANGES }, - { type: mutationTypes.SUBMIT_CHANGES_ERROR, payload: error.message }, - ]; - - beforeEach(() => { - submitContentChanges.mockRejectedValueOnce(error); - }); - - it('dispatches receiveContentError', () => { - testAction(actions.submitChanges, null, state, expectedMutations); - }); - }); - }); - - describe('dismissSubmitChangesError', () => { - it('commits dismissSubmitChangesError', () => { - testAction(actions.dismissSubmitChangesError, null, state, [ - { - type: mutationTypes.DISMISS_SUBMIT_CHANGES_ERROR, - }, - ]); - }); - }); -}); diff --git a/spec/frontend/static_site_editor/store/getters_spec.js b/spec/frontend/static_site_editor/store/getters_spec.js deleted file mode 100644 index 5793e344784..00000000000 --- a/spec/frontend/static_site_editor/store/getters_spec.js +++ /dev/null @@ -1,19 +0,0 @@ -import createState from '~/static_site_editor/store/state'; -import { contentChanged } from '~/static_site_editor/store/getters'; -import { sourceContent as content } from '../mock_data'; - -describe('Static Site Editor Store getters', () => { - describe('contentChanged', () => { - it('returns true when content and originalContent are different', () => { - const state = createState({ content, originalContent: 'something else' }); - - expect(contentChanged(state)).toBe(true); - }); - - it('returns false when content and originalContent are the same', () => { - const state = createState({ content, originalContent: content }); - - expect(contentChanged(state)).toBe(false); - }); - }); -}); diff --git a/spec/frontend/static_site_editor/store/mutations_spec.js b/spec/frontend/static_site_editor/store/mutations_spec.js deleted file mode 100644 index 2441f317d90..00000000000 --- a/spec/frontend/static_site_editor/store/mutations_spec.js +++ /dev/null @@ -1,54 +0,0 @@ -import createState from '~/static_site_editor/store/state'; -import mutations from '~/static_site_editor/store/mutations'; -import * as types from '~/static_site_editor/store/mutation_types'; -import { - sourceContentTitle as title, - sourceContent as content, - savedContentMeta, - submitChangesError, -} from '../mock_data'; - -describe('Static Site Editor Store mutations', () => { - let state; - const contentLoadedPayload = { title, content }; - - beforeEach(() => { - state = createState(); - }); - - it.each` - mutation | stateProperty | payload | expectedValue - ${types.LOAD_CONTENT} | ${'isLoadingContent'} | ${undefined} | ${true} - ${types.RECEIVE_CONTENT_SUCCESS} | ${'isLoadingContent'} | ${contentLoadedPayload} | ${false} - ${types.RECEIVE_CONTENT_SUCCESS} | ${'isContentLoaded'} | ${contentLoadedPayload} | ${true} - ${types.RECEIVE_CONTENT_SUCCESS} | ${'title'} | ${contentLoadedPayload} | ${title} - ${types.RECEIVE_CONTENT_SUCCESS} | ${'content'} | ${contentLoadedPayload} | ${content} - ${types.RECEIVE_CONTENT_SUCCESS} | ${'originalContent'} | ${contentLoadedPayload} | ${content} - ${types.RECEIVE_CONTENT_ERROR} | ${'isLoadingContent'} | ${undefined} | ${false} - ${types.SET_CONTENT} | ${'content'} | ${content} | ${content} - ${types.SUBMIT_CHANGES} | ${'isSavingChanges'} | ${undefined} | ${true} - ${types.SUBMIT_CHANGES_SUCCESS} | ${'savedContentMeta'} | ${savedContentMeta} | ${savedContentMeta} - ${types.SUBMIT_CHANGES_SUCCESS} | ${'isSavingChanges'} | ${savedContentMeta} | ${false} - ${types.SUBMIT_CHANGES_ERROR} | ${'isSavingChanges'} | ${undefined} | ${false} - ${types.SUBMIT_CHANGES_ERROR} | ${'submitChangesError'} | ${submitChangesError} | ${submitChangesError} - ${types.DISMISS_SUBMIT_CHANGES_ERROR} | ${'submitChangesError'} | ${undefined} | ${''} - `( - '$mutation sets $stateProperty to $expectedValue', - ({ mutation, stateProperty, payload, expectedValue }) => { - mutations[mutation](state, payload); - expect(state[stateProperty]).toBe(expectedValue); - }, - ); - - it(`${types.SUBMIT_CHANGES_SUCCESS} sets originalContent to content current value`, () => { - const editedContent = `${content} plus something else`; - - state = createState({ - originalContent: content, - content: editedContent, - }); - mutations[types.SUBMIT_CHANGES_SUCCESS](state); - - expect(state.originalContent).toBe(state.content); - }); -}); |