summaryrefslogtreecommitdiff
path: root/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 15:44:42 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 15:44:42 +0000
commit4555e1b21c365ed8303ffb7a3325d773c9b8bf31 (patch)
tree5423a1c7516cffe36384133ade12572cf709398d /spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
parente570267f2f6b326480d284e0164a6464ba4081bc (diff)
downloadgitlab-ce-4555e1b21c365ed8303ffb7a3325d773c9b8bf31.tar.gz
Add latest changes from gitlab-org/gitlab@13-12-stable-eev13.12.0-rc42
Diffstat (limited to 'spec/frontend/pages/shared/wikis/components/wiki_form_spec.js')
-rw-r--r--spec/frontend/pages/shared/wikis/components/wiki_form_spec.js269
1 files changed, 254 insertions, 15 deletions
diff --git a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
index 8ab0b87d2ee..1cac8ef8ee2 100644
--- a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
+++ b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
@@ -1,9 +1,16 @@
+import { GlLoadingIcon, GlModal } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
+import axios from 'axios';
+import MockAdapter from 'axios-mock-adapter';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import ContentEditor from '~/content_editor/components/content_editor.vue';
import WikiForm from '~/pages/shared/wikis/components/wiki_form.vue';
+import MarkdownField from '~/vue_shared/components/markdown/field.vue';
describe('WikiForm', () => {
let wrapper;
+ let mock;
const findForm = () => wrapper.find('form');
const findTitle = () => wrapper.find('#wiki_title');
@@ -11,10 +18,28 @@ describe('WikiForm', () => {
const findContent = () => wrapper.find('#wiki_content');
const findMessage = () => wrapper.find('#wiki_message');
const findSubmitButton = () => wrapper.findByTestId('wiki-submit-button');
- const findCancelButton = () => wrapper.findByTestId('wiki-cancel-button');
- const findTitleHelpLink = () => wrapper.findByTestId('wiki-title-help-link');
+ const findCancelButton = () => wrapper.findByRole('link', { name: 'Cancel' });
+ const findUseNewEditorButton = () => wrapper.findByRole('button', { name: 'Use new editor' });
+ const findSwitchToOldEditorButton = () =>
+ wrapper.findByRole('button', { name: 'Switch to old editor' });
+ const findTitleHelpLink = () => wrapper.findByRole('link', { name: 'More Information.' });
const findMarkdownHelpLink = () => wrapper.findByTestId('wiki-markdown-help-link');
+ const setFormat = (value) => {
+ const format = findFormat();
+ format.find(`option[value=${value}]`).setSelected();
+ format.element.dispatchEvent(new Event('change'));
+ };
+
+ const triggerFormSubmit = () => findForm().element.dispatchEvent(new Event('submit'));
+
+ const dispatchBeforeUnload = () => {
+ const e = new Event('beforeunload');
+ jest.spyOn(e, 'preventDefault');
+ window.dispatchEvent(e);
+ return e;
+ };
+
const pageInfoNew = {
persisted: false,
uploadsPath: '/project/path/-/wikis/attachments',
@@ -35,7 +60,10 @@ describe('WikiForm', () => {
path: '/project/path/-/wikis/home',
};
- function createWrapper(persisted = false, pageInfo = {}) {
+ function createWrapper(
+ persisted = false,
+ { pageInfo, glFeatures } = { glFeatures: { wikiContentEditor: false } },
+ ) {
wrapper = extendedWrapper(
mount(
WikiForm,
@@ -51,16 +79,20 @@ describe('WikiForm', () => {
...(persisted ? pageInfoPersisted : pageInfoNew),
...pageInfo,
},
+ glFeatures,
},
},
{ attachToDocument: true },
),
);
-
- jest.spyOn(wrapper.vm, 'onBeforeUnload');
}
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
afterEach(() => {
+ mock.restore();
wrapper.destroy();
wrapper = null;
});
@@ -101,7 +133,7 @@ describe('WikiForm', () => {
`('updates the link help message when format=$value is selected', async ({ value, text }) => {
createWrapper();
- findFormat().find(`option[value=${value}]`).setSelected();
+ setFormat(value);
await wrapper.vm.$nextTick();
@@ -113,9 +145,9 @@ describe('WikiForm', () => {
await wrapper.vm.$nextTick();
- window.dispatchEvent(new Event('beforeunload'));
-
- expect(wrapper.vm.onBeforeUnload).not.toHaveBeenCalled();
+ const e = dispatchBeforeUnload();
+ expect(typeof e.returnValue).not.toBe('string');
+ expect(e.preventDefault).not.toHaveBeenCalled();
});
it.each`
@@ -156,19 +188,18 @@ describe('WikiForm', () => {
});
it('sets before unload warning', () => {
- window.dispatchEvent(new Event('beforeunload'));
+ const e = dispatchBeforeUnload();
- expect(wrapper.vm.onBeforeUnload).toHaveBeenCalled();
+ expect(e.preventDefault).toHaveBeenCalledTimes(1);
});
it('when form submitted, unsets before unload warning', async () => {
- findForm().element.dispatchEvent(new Event('submit'));
+ triggerFormSubmit();
await wrapper.vm.$nextTick();
- window.dispatchEvent(new Event('beforeunload'));
-
- expect(wrapper.vm.onBeforeUnload).not.toHaveBeenCalled();
+ const e = dispatchBeforeUnload();
+ expect(e.preventDefault).not.toHaveBeenCalled();
});
});
@@ -219,4 +250,212 @@ describe('WikiForm', () => {
},
);
});
+
+ describe('when feature flag wikiContentEditor is enabled', () => {
+ beforeEach(() => {
+ createWrapper(true, { glFeatures: { wikiContentEditor: true } });
+ });
+
+ it.each`
+ format | buttonExists
+ ${'markdown'} | ${true}
+ ${'rdoc'} | ${false}
+ `(
+ 'switch to new editor button exists: $buttonExists if format is $format',
+ async ({ format, buttonExists }) => {
+ setFormat(format);
+
+ await wrapper.vm.$nextTick();
+
+ expect(findUseNewEditorButton().exists()).toBe(buttonExists);
+ },
+ );
+
+ const assertOldEditorIsVisible = () => {
+ expect(wrapper.findComponent(ContentEditor).exists()).toBe(false);
+ expect(wrapper.findComponent(MarkdownField).exists()).toBe(true);
+ expect(findSubmitButton().props('disabled')).toBe(false);
+
+ expect(wrapper.text()).not.toContain(
+ "Switching will discard any changes you've made in the new editor.",
+ );
+ expect(wrapper.text()).not.toContain(
+ "This editor is in beta and may not display the page's contents properly.",
+ );
+ };
+
+ it('shows old editor by default', assertOldEditorIsVisible);
+
+ describe('switch format to rdoc', () => {
+ beforeEach(async () => {
+ setFormat('rdoc');
+
+ await wrapper.vm.$nextTick();
+ });
+
+ it('continues to show the old editor', assertOldEditorIsVisible);
+
+ describe('switch format back to markdown', () => {
+ beforeEach(async () => {
+ setFormat('rdoc');
+
+ await wrapper.vm.$nextTick();
+ });
+
+ it(
+ 'still shows the old editor and does not automatically switch to the content editor ',
+ assertOldEditorIsVisible,
+ );
+ });
+ });
+
+ describe('clicking "use new editor": editor fails to load', () => {
+ beforeEach(async () => {
+ mock.onPost(/preview-markdown/).reply(400);
+
+ await findUseNewEditorButton().trigger('click');
+
+ // try waiting for content editor to load (but it will never actually load)
+ await waitForPromises();
+ });
+
+ it('editor is shown in a perpetual loading state', () => {
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.findComponent(ContentEditor).exists()).toBe(false);
+ });
+
+ it('disables the submit button', () => {
+ expect(findSubmitButton().props('disabled')).toBe(true);
+ });
+
+ describe('clicking "switch to old editor"', () => {
+ beforeEach(() => {
+ return findSwitchToOldEditorButton().trigger('click');
+ });
+
+ it('switches to old editor directly without showing a modal', () => {
+ expect(wrapper.findComponent(ContentEditor).exists()).toBe(false);
+ expect(wrapper.findComponent(MarkdownField).exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('clicking "use new editor": editor loads successfully', () => {
+ beforeEach(() => {
+ mock.onPost(/preview-markdown/).reply(200, { body: '<p>hello <strong>world</strong></p>' });
+
+ findUseNewEditorButton().trigger('click');
+ });
+
+ it('shows a loading indicator for the rich text editor', () => {
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
+ });
+
+ it('shows warnings that the rich text editor is in beta and may not work properly', () => {
+ expect(wrapper.text()).toContain(
+ "Switching will discard any changes you've made in the new editor.",
+ );
+ expect(wrapper.text()).toContain(
+ "This editor is in beta and may not display the page's contents properly.",
+ );
+ });
+
+ it('shows the rich text editor when loading finishes', async () => {
+ // wait for content editor to load
+ await waitForPromises();
+
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
+ expect(wrapper.findComponent(ContentEditor).exists()).toBe(true);
+ });
+
+ it('disables the format dropdown', () => {
+ expect(findFormat().element.getAttribute('disabled')).toBeDefined();
+ });
+
+ describe('when wiki content is updated', () => {
+ beforeEach(async () => {
+ // wait for content editor to load
+ await waitForPromises();
+
+ wrapper.vm.contentEditor.tiptapEditor.commands.setContent(
+ '<p>hello __world__ from content editor</p>',
+ true,
+ );
+
+ return wrapper.vm.$nextTick();
+ });
+
+ it('sets before unload warning', () => {
+ const e = dispatchBeforeUnload();
+ expect(e.preventDefault).toHaveBeenCalledTimes(1);
+ });
+
+ it('unsets before unload warning on form submit', async () => {
+ triggerFormSubmit();
+
+ await wrapper.vm.$nextTick();
+
+ const e = dispatchBeforeUnload();
+ expect(e.preventDefault).not.toHaveBeenCalled();
+ });
+ });
+
+ it('updates content from content editor on form submit', async () => {
+ // old value
+ expect(findContent().element.value).toBe('My page content');
+
+ // wait for content editor to load
+ await waitForPromises();
+
+ triggerFormSubmit();
+
+ await wrapper.vm.$nextTick();
+
+ expect(findContent().element.value).toBe('hello **world**');
+ });
+
+ describe('clicking "switch to old editor"', () => {
+ let modal;
+
+ beforeEach(async () => {
+ modal = wrapper.findComponent(GlModal);
+ jest.spyOn(modal.vm, 'show');
+
+ findSwitchToOldEditorButton().trigger('click');
+ });
+
+ it('shows a modal confirming the change', () => {
+ expect(modal.vm.show).toHaveBeenCalled();
+ });
+
+ describe('confirming "switch to old editor" in the modal', () => {
+ beforeEach(async () => {
+ wrapper.vm.contentEditor.tiptapEditor.commands.setContent(
+ '<p>hello __world__ from content editor</p>',
+ true,
+ );
+
+ wrapper.findComponent(GlModal).vm.$emit('primary');
+
+ await wrapper.vm.$nextTick();
+ });
+
+ it('switches to old editor', () => {
+ expect(wrapper.findComponent(ContentEditor).exists()).toBe(false);
+ expect(wrapper.findComponent(MarkdownField).exists()).toBe(true);
+ });
+
+ it('does not show a warning about content editor', () => {
+ expect(wrapper.text()).not.toContain(
+ "This editor is in beta and may not display the page's contents properly.",
+ );
+ });
+
+ it('the old editor retains its old value and does not use the content from the content editor', () => {
+ expect(findContent().element.value).toBe('My page content');
+ });
+ });
+ });
+ });
+ });
});