diff options
Diffstat (limited to 'spec/frontend/static_site_editor')
8 files changed, 242 insertions, 86 deletions
diff --git a/spec/frontend/static_site_editor/components/app_spec.js b/spec/frontend/static_site_editor/components/app_spec.js new file mode 100644 index 00000000000..bbdffeae68f --- /dev/null +++ b/spec/frontend/static_site_editor/components/app_spec.js @@ -0,0 +1,34 @@ +import { shallowMount } from '@vue/test-utils'; +import App from '~/static_site_editor/components/app.vue'; + +describe('static_site_editor/components/app', () => { + const mergeRequestsIllustrationPath = 'illustrations/merge_requests.svg'; + const RouterView = { + template: '<div></div>', + }; + let wrapper; + + const buildWrapper = () => { + wrapper = shallowMount(App, { + stubs: { + RouterView, + }, + propsData: { + mergeRequestsIllustrationPath, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + it('passes merge request illustration path to the router view component', () => { + buildWrapper(); + + expect(wrapper.find(RouterView).attributes()).toMatchObject({ + 'merge-requests-illustration-path': mergeRequestsIllustrationPath, + }); + }); +}); 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 11c5abf1b08..f4be911171e 100644 --- a/spec/frontend/static_site_editor/components/edit_area_spec.js +++ b/spec/frontend/static_site_editor/components/edit_area_spec.js @@ -15,8 +15,11 @@ import { returnUrl, } from '../mock_data'; +jest.mock('~/static_site_editor/services/formatter', () => jest.fn(str => `${str} format-pass`)); + describe('~/static_site_editor/components/edit_area.vue', () => { let wrapper; + const formattedBody = `${body} format-pass`; const savingChanges = true; const newBody = `new ${body}`; @@ -50,9 +53,9 @@ describe('~/static_site_editor/components/edit_area.vue', () => { expect(findEditHeader().props('title')).toBe(title); }); - it('renders rich content editor', () => { + it('renders rich content editor with a format pass', () => { expect(findRichContentEditor().exists()).toBe(true); - expect(findRichContentEditor().props('content')).toBe(body); + expect(findRichContentEditor().props('content')).toBe(formattedBody); }); it('renders publish toolbar', () => { @@ -94,7 +97,7 @@ describe('~/static_site_editor/components/edit_area.vue', () => { }); it('sets publish toolbar as not saveable when content changes are rollback', () => { - findRichContentEditor().vm.$emit('input', body); + findRichContentEditor().vm.$emit('input', formattedBody); return wrapper.vm.$nextTick().then(() => { expect(findPublishToolbar().props('saveable')).toBe(false); @@ -103,31 +106,53 @@ describe('~/static_site_editor/components/edit_area.vue', () => { }); describe('when the mode changes', () => { + let resetInitialValue; + const setInitialMode = mode => { wrapper.setData({ editorMode: mode }); }; + const buildResetInitialValue = () => { + resetInitialValue = jest.fn(); + findRichContentEditor().setMethods({ resetInitialValue }); + }; + afterEach(() => { setInitialMode(EDITOR_TYPES.wysiwyg); + resetInitialValue = null; }); it.each` initialMode | targetMode | resetValue - ${EDITOR_TYPES.wysiwyg} | ${EDITOR_TYPES.markdown} | ${content} - ${EDITOR_TYPES.markdown} | ${EDITOR_TYPES.wysiwyg} | ${body} + ${EDITOR_TYPES.wysiwyg} | ${EDITOR_TYPES.markdown} | ${`${content} format-pass format-pass`} + ${EDITOR_TYPES.markdown} | ${EDITOR_TYPES.wysiwyg} | ${`${body} format-pass format-pass`} `( 'sets editorMode from $initialMode to $targetMode', ({ initialMode, targetMode, resetValue }) => { setInitialMode(initialMode); + buildResetInitialValue(); - const resetInitialValue = jest.fn(); - - findRichContentEditor().setMethods({ resetInitialValue }); findRichContentEditor().vm.$emit('modeChange', targetMode); expect(resetInitialValue).toHaveBeenCalledWith(resetValue); expect(wrapper.vm.editorMode).toBe(targetMode); }, ); + + it('should format the content', () => { + buildResetInitialValue(); + + findRichContentEditor().vm.$emit('modeChange', EDITOR_TYPES.markdown); + + expect(resetInitialValue).toHaveBeenCalledWith(`${content} format-pass format-pass`); + }); + }); + + describe('when content is submitted', () => { + it('should format the content', () => { + findPublishToolbar().vm.$emit('submit', content); + + expect(wrapper.emitted('submit')[0][0].content).toBe(`${content} format-pass format-pass`); + }); }); }); 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 deleted file mode 100644 index a63c3a83395..00000000000 --- a/spec/frontend/static_site_editor/components/saved_changes_message_spec.js +++ /dev/null @@ -1,56 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; - -import SavedChangesMessage from '~/static_site_editor/components/saved_changes_message.vue'; - -import { returnUrl, savedContentMeta } from '../mock_data'; - -describe('~/static_site_editor/components/saved_changes_message.vue', () => { - let wrapper; - const { branch, commit, mergeRequest } = savedContentMeta; - const props = { - branch, - commit, - mergeRequest, - returnUrl, - }; - const findReturnToSiteButton = () => wrapper.find({ ref: 'returnToSiteButton' }); - const findMergeRequestButton = () => wrapper.find({ ref: 'mergeRequestButton' }); - const findBranchLink = () => wrapper.find({ ref: 'branchLink' }); - const findCommitLink = () => wrapper.find({ ref: 'commitLink' }); - const findMergeRequestLink = () => wrapper.find({ ref: 'mergeRequestLink' }); - - beforeEach(() => { - wrapper = shallowMount(SavedChangesMessage, { - propsData: props, - }); - }); - - afterEach(() => { - wrapper.destroy(); - }); - - it.each` - text | findEl | url - ${'Return to site'} | ${findReturnToSiteButton} | ${props.returnUrl} - ${'View merge request'} | ${findMergeRequestButton} | ${props.mergeRequest.url} - `('renders "$text" button link', ({ text, findEl, url }) => { - const btn = findEl(); - - expect(btn.exists()).toBe(true); - expect(btn.text()).toBe(text); - expect(btn.attributes('href')).toBe(url); - }); - - it.each` - desc | findEl | prop - ${'branch'} | ${findBranchLink} | ${props.branch} - ${'commit'} | ${findCommitLink} | ${props.commit} - ${'merge request'} | ${findMergeRequestLink} | ${props.mergeRequest} - `('renders $desc link', ({ findEl, prop }) => { - const el = findEl(); - - expect(el.exists()).toBe(true); - expect(el.text()).toBe(prop.label); - expect(el.attributes('href')).toBe(prop.url); - }); -}); diff --git a/spec/frontend/static_site_editor/pages/home_spec.js b/spec/frontend/static_site_editor/pages/home_spec.js index d3ee70785d1..c5473596df8 100644 --- a/spec/frontend/static_site_editor/pages/home_spec.js +++ b/spec/frontend/static_site_editor/pages/home_spec.js @@ -1,5 +1,6 @@ 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'; import SkeletonLoader from '~/static_site_editor/components/skeleton_loader.vue'; import EditArea from '~/static_site_editor/components/edit_area.vue'; @@ -7,7 +8,6 @@ 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 { diff --git a/spec/frontend/static_site_editor/pages/success_spec.js b/spec/frontend/static_site_editor/pages/success_spec.js index d62b67bfa83..3e19e2413e7 100644 --- a/spec/frontend/static_site_editor/pages/success_spec.js +++ b/spec/frontend/static_site_editor/pages/success_spec.js @@ -1,17 +1,12 @@ -import Vuex from 'vuex'; -import { shallowMount, createLocalVue } from '@vue/test-utils'; +import { shallowMount } from '@vue/test-utils'; +import { GlEmptyState, GlButton } from '@gitlab/ui'; 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 { savedContentMeta, returnUrl, sourcePath } from '../mock_data'; import { HOME_ROUTE } from '~/static_site_editor/router/constants'; -const localVue = createLocalVue(); - -localVue.use(Vuex); - describe('static_site_editor/pages/success', () => { + const mergeRequestsIllustrationPath = 'illustrations/merge_requests.svg'; let wrapper; - let store; let router; const buildRouter = () => { @@ -22,16 +17,22 @@ describe('static_site_editor/pages/success', () => { const buildWrapper = (data = {}) => { wrapper = shallowMount(Success, { - localVue, - store, mocks: { $router: router, }, + stubs: { + GlEmptyState, + GlButton, + }, + propsData: { + mergeRequestsIllustrationPath, + }, data() { return { savedContentMeta, appData: { returnUrl, + sourcePath, }, ...data, }; @@ -39,7 +40,8 @@ describe('static_site_editor/pages/success', () => { }); }; - const findSavedChangesMessage = () => wrapper.find(SavedChangesMessage); + const findEmptyState = () => wrapper.find(GlEmptyState); + const findReturnUrlButton = () => wrapper.find(GlButton); beforeEach(() => { buildRouter(); @@ -50,29 +52,50 @@ describe('static_site_editor/pages/success', () => { wrapper = null; }); - it('renders saved changes message', () => { + 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, + }); + }); + + it('displays merge request instructions in the empty state', () => { buildWrapper(); - expect(findSavedChangesMessage().exists()).toBe(true); + 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('passes returnUrl to the saved changes message', () => { + it('displays return to site button', () => { buildWrapper(); - expect(findSavedChangesMessage().props('returnUrl')).toBe(returnUrl); + expect(findReturnUrlButton().text()).toBe('Return to site'); + expect(findReturnUrlButton().attributes().href).toBe(returnUrl); }); - it('passes saved content metadata to the saved changes message', () => { + it('displays source path', () => { buildWrapper(); - expect(findSavedChangesMessage().props('branch')).toBe(savedContentMeta.branch); - expect(findSavedChangesMessage().props('commit')).toBe(savedContentMeta.commit); - expect(findSavedChangesMessage().props('mergeRequest')).toBe(savedContentMeta.mergeRequest); + expect(wrapper.text()).toContain(`Update ${sourcePath} file`); }); it('redirects to the HOME route when content has not been submitted', () => { buildWrapper({ savedContentMeta: null }); expect(router.push).toHaveBeenCalledWith(HOME_ROUTE); + expect(wrapper.html()).toBe(''); }); }); diff --git a/spec/frontend/static_site_editor/services/formatter_spec.js b/spec/frontend/static_site_editor/services/formatter_spec.js new file mode 100644 index 00000000000..b7600798db9 --- /dev/null +++ b/spec/frontend/static_site_editor/services/formatter_spec.js @@ -0,0 +1,26 @@ +import formatter from '~/static_site_editor/services/formatter'; + +describe('formatter', () => { + const source = `Some text +<br> + +And some more text + + +<br> + + +And even more text`; + const sourceWithoutBrTags = `Some text + +And some more text + + + + +And even more text`; + + it('removes extraneous <br> tags', () => { + expect(formatter(source)).toMatch(sourceWithoutBrTags); + }); +}); 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 a9169eb3e16..645ccedf7e7 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,6 +1,6 @@ +import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; import Api from '~/api'; import { convertObjectPropsToSnakeCase } from '~/lib/utils/common_utils'; -import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; import { DEFAULT_TARGET_BRANCH, diff --git a/spec/frontend/static_site_editor/services/templater_spec.js b/spec/frontend/static_site_editor/services/templater_spec.js new file mode 100644 index 00000000000..1e7ae872b7e --- /dev/null +++ b/spec/frontend/static_site_editor/services/templater_spec.js @@ -0,0 +1,104 @@ +/* eslint-disable no-useless-escape */ +import templater from '~/static_site_editor/services/templater'; + +describe('templater', () => { + const source = `Below this line is a simple ERB (single-line erb block) example. + +<% some erb code %> + +Below this line is a complex ERB (multi-line erb block) example. + +<% if apptype.maturity && (apptype.maturity != "planned") %> + <% maturity = "This application type is at the \"#{apptype.maturity}\" level of maturity." %> +<% end %> + +Below this line is a non-erb (single-line HTML) markup example that also has erb. + +<a href="<%= compensation_roadmap.role_path %>"><%= compensation_roadmap.role_path %></a> + +Below this line is a non-erb (multi-line HTML block) markup example that also has erb. + +<ul> +<% compensation_roadmap.recommendation.recommendations.each do |recommendation| %> + <li><%= recommendation %></li> +<% end %> +</ul> + +Below this line is a block of HTML. + +<div> + <h1>Heading</h1> + <p>Some paragraph...</p> +</div> + +Below this line is a codeblock of the same HTML that should be ignored and preserved. + +\`\`\` html +<div> + <h1>Heading</h1> + <p>Some paragraph...</p> +</div> +\`\`\` +`; + const sourceTemplated = `Below this line is a simple ERB (single-line erb block) example. + +\`\`\` sse +<% some erb code %> +\`\`\` + +Below this line is a complex ERB (multi-line erb block) example. + +\`\`\` sse +<% if apptype.maturity && (apptype.maturity != "planned") %> + <% maturity = "This application type is at the \"#{apptype.maturity}\" level of maturity." %> +<% end %> +\`\`\` + +Below this line is a non-erb (single-line HTML) markup example that also has erb. + +\`\`\` sse +<a href="<%= compensation_roadmap.role_path %>"><%= compensation_roadmap.role_path %></a> +\`\`\` + +Below this line is a non-erb (multi-line HTML block) markup example that also has erb. + +\`\`\` sse +<ul> +<% compensation_roadmap.recommendation.recommendations.each do |recommendation| %> + <li><%= recommendation %></li> +<% end %> +</ul> +\`\`\` + +Below this line is a block of HTML. + +\`\`\` sse +<div> + <h1>Heading</h1> + <p>Some paragraph...</p> +</div> +\`\`\` + +Below this line is a codeblock of the same HTML that should be ignored and preserved. + +\`\`\` html +<div> + <h1>Heading</h1> + <p>Some paragraph...</p> +</div> +\`\`\` +`; + + it.each` + fn | initial | target + ${'wrap'} | ${source} | ${sourceTemplated} + ${'wrap'} | ${sourceTemplated} | ${sourceTemplated} + ${'unwrap'} | ${sourceTemplated} | ${source} + ${'unwrap'} | ${source} | ${source} + `( + 'wraps $initial in a templated sse codeblocks if $fn is wrap, unwraps otherwise', + ({ fn, initial, target }) => { + expect(templater[fn](initial)).toMatch(target); + }, + ); +}); |