Commit 0e4ccc19 authored by Olena Horal-Koretska's avatar Olena Horal-Koretska

Merge branch '288329-wiki-submit-btn' into 'master'

Disable submit button on wiki if no title and content

See merge request gitlab-org/gitlab!51272
parents 74c54817 4d4f6797
......@@ -26,6 +26,7 @@ export default class Wikis {
this.isNewWikiPage = Boolean(document.querySelector('.js-new-wiki-page'));
this.editTitleInput = document.querySelector('form.wiki-form #wiki_title');
this.commitMessageInput = document.querySelector('form.wiki-form #wiki_message');
this.submitButton = document.querySelector('.js-wiki-btn-submit');
this.commitMessageI18n = this.isNewWikiPage
? s__('WikiPageCreate|Create %{pageTitle}')
: s__('WikiPageEdit|Update %{pageTitle}');
......@@ -50,13 +51,11 @@ export default class Wikis {
});
}
const wikiTextarea = document.querySelector('form.wiki-form #wiki_content');
this.wikiTextarea = document.querySelector('form.wiki-form #wiki_content');
const wikiForm = document.querySelector('form.wiki-form');
if (wikiTextarea) {
wikiTextarea.addEventListener('input', () => {
window.onbeforeunload = () => '';
});
if (this.wikiTextarea) {
this.wikiTextarea.addEventListener('input', () => this.handleWikiContentChange());
wikiForm.addEventListener('submit', () => {
window.onbeforeunload = null;
......@@ -65,12 +64,29 @@ export default class Wikis {
Wikis.trackPageView();
Wikis.showToasts();
this.updateSubmitButton();
}
handleWikiContentChange() {
this.updateSubmitButton();
window.onbeforeunload = () => '';
}
handleWikiTitleChange(e) {
this.updateSubmitButton();
this.setWikiCommitMessage(e.target.value);
}
updateSubmitButton() {
if (!this.wikiTextarea) return;
const isEnabled = Boolean(this.wikiTextarea.value.trim() && this.editTitleInput.value.trim());
if (isEnabled) this.submitButton.removeAttribute('disabled');
else this.submitButton.setAttribute('disabled', 'true');
}
setWikiCommitMessage(rawTitle) {
let title = rawTitle;
......
......@@ -70,10 +70,10 @@
.form-actions
- if @page && @page.persisted?
= f.submit _("Save changes"), class: 'btn gl-button btn-success qa-save-changes-button'
= f.submit _("Save changes"), class: 'btn gl-button btn-success qa-save-changes-button js-wiki-btn-submit', disabled: 'true'
.float-right
= link_to _("Cancel"), wiki_page_path(@wiki, @page), class: 'btn gl-button btn-cancel btn-default'
- else
= f.submit s_("Wiki|Create page"), class: 'btn-success gl-button btn qa-create-page-button rspec-create-page-button'
= f.submit s_("Wiki|Create page"), class: 'btn-success gl-button btn qa-create-page-button rspec-create-page-button js-wiki-btn-submit', disabled: 'true'
.float-right
= link_to _("Cancel"), wiki_path(@wiki), class: 'btn gl-button btn-cancel btn-default'
---
title: Disable submit button on wiki if no title and content
merge_request: 51272
author:
type: changed
......@@ -4,125 +4,157 @@ import Wikis from '~/pages/shared/wikis/wikis';
import Tracking from '~/tracking';
describe('Wikis', () => {
describe('setting the commit message when the title changes', () => {
const editFormHtmlFixture = (args) => `<form class="wiki-form ${
args.newPage ? 'js-new-wiki-page' : ''
}">
<input type="text" id="wiki_title" value="My title" />
<input type="text" id="wiki_message" />
<select class="form-control select-control" name="wiki[format]" id="wiki_format">
<option value="markdown">Markdown</option>
<option selected="selected" value="rdoc">RDoc</option>
<option value="asciidoc">AsciiDoc</option>
<option value="org">Org</option>
</select>
<textarea id="wiki_content"></textarea>
<code class="js-markup-link-example">{Link title}[link:page-slug]</code>
</form>
`;
let wikis;
let titleInput;
let messageInput;
let changeFormatSelect;
let linkExample;
const findBeforeUnloadWarning = () => window.onbeforeunload?.();
const findContent = () => document.getElementById('wiki_content');
const findForm = () => document.querySelector('.wiki-form');
describe('when the wiki page is being created', () => {
const formHtmlFixture = editFormHtmlFixture({ newPage: true });
const editFormHtmlFixture = (args) => `<form class="wiki-form ${
args.newPage ? 'js-new-wiki-page' : ''
}">
<input type="text" id="wiki_title" value="My title" />
<input type="text" id="wiki_message" />
<select class="form-control select-control" name="wiki[format]" id="wiki_format">
<option value="markdown">Markdown</option>
<option selected="selected" value="rdoc">RDoc</option>
<option value="asciidoc">AsciiDoc</option>
<option value="org">Org</option>
</select>
<textarea id="wiki_content"></textarea>
<code class="js-markup-link-example">{Link title}[link:page-slug]</code>
<input type="submit" class="js-wiki-btn-submit">
</input>
</form>
`;
let wikis;
let titleInput;
let contentInput;
let messageInput;
let changeFormatSelect;
let linkExample;
const findBeforeUnloadWarning = () => window.onbeforeunload?.();
const findForm = () => document.querySelector('.wiki-form');
const findSubmitButton = () => document.querySelector('.js-wiki-btn-submit');
describe('when the wiki page is being created', () => {
const formHtmlFixture = editFormHtmlFixture({ newPage: true });
beforeEach(() => {
setHTMLFixture(formHtmlFixture);
beforeEach(() => {
setHTMLFixture(formHtmlFixture);
titleInput = document.getElementById('wiki_title');
messageInput = document.getElementById('wiki_message');
changeFormatSelect = document.querySelector('#wiki_format');
linkExample = document.querySelector('.js-markup-link-example');
wikis = new Wikis();
});
titleInput = document.getElementById('wiki_title');
messageInput = document.getElementById('wiki_message');
changeFormatSelect = document.querySelector('#wiki_format');
linkExample = document.querySelector('.js-markup-link-example');
wikis = new Wikis();
});
it('binds an event listener to the title input', () => {
wikis.handleWikiTitleChange = jest.fn();
it('binds an event listener to the title input', () => {
wikis.handleWikiTitleChange = jest.fn();
titleInput.dispatchEvent(new Event('keyup'));
titleInput.dispatchEvent(new Event('keyup'));
expect(wikis.handleWikiTitleChange).toHaveBeenCalled();
});
expect(wikis.handleWikiTitleChange).toHaveBeenCalled();
});
it('sets the commit message when title changes', () => {
titleInput.value = 'My title';
messageInput.value = '';
it('sets the commit message when title changes', () => {
titleInput.value = 'My title';
messageInput.value = '';
titleInput.dispatchEvent(new Event('keyup'));
titleInput.dispatchEvent(new Event('keyup'));
expect(messageInput.value).toEqual('Create My title');
});
expect(messageInput.value).toEqual('Create My title');
});
it('replaces hyphens with spaces', () => {
titleInput.value = 'my-hyphenated-title';
titleInput.dispatchEvent(new Event('keyup'));
it('replaces hyphens with spaces', () => {
titleInput.value = 'my-hyphenated-title';
titleInput.dispatchEvent(new Event('keyup'));
expect(messageInput.value).toEqual('Create my hyphenated title');
});
expect(messageInput.value).toEqual('Create my hyphenated title');
});
});
describe('when the wiki page is being updated', () => {
const formHtmlFixture = editFormHtmlFixture({ newPage: false });
describe('when the wiki page is being updated', () => {
const formHtmlFixture = editFormHtmlFixture({ newPage: false });
beforeEach(() => {
setHTMLFixture(formHtmlFixture);
beforeEach(() => {
setHTMLFixture(formHtmlFixture);
titleInput = document.getElementById('wiki_title');
messageInput = document.getElementById('wiki_message');
wikis = new Wikis();
});
titleInput = document.getElementById('wiki_title');
messageInput = document.getElementById('wiki_message');
wikis = new Wikis();
});
it('sets the commit message when title changes, prefixing with "Update"', () => {
titleInput.value = 'My title';
messageInput.value = '';
it('sets the commit message when title changes, prefixing with "Update"', () => {
titleInput.value = 'My title';
messageInput.value = '';
titleInput.dispatchEvent(new Event('keyup'));
titleInput.dispatchEvent(new Event('keyup'));
expect(messageInput.value).toEqual('Update My title');
expect(messageInput.value).toEqual('Update My title');
});
it.each`
value | text
${'markdown'} | ${'[Link Title](page-slug)'}
${'rdoc'} | ${'{Link title}[link:page-slug]'}
${'asciidoc'} | ${'link:page-slug[Link title]'}
${'org'} | ${'[[page-slug]]'}
`('updates a message when value=$value is selected', ({ value, text }) => {
changeFormatSelect.value = value;
changeFormatSelect.dispatchEvent(new Event('change'));
expect(linkExample.innerHTML).toBe(text);
});
it('starts with no unload warning', () => {
expect(findBeforeUnloadWarning()).toBeUndefined();
});
describe('when wiki content is updated', () => {
beforeEach(() => {
contentInput = document.getElementById('wiki_content');
contentInput.value = 'Lorem ipsum dolar sit!';
contentInput.dispatchEvent(new Event('input'));
});
it.each`
value | text
${'markdown'} | ${'[Link Title](page-slug)'}
${'rdoc'} | ${'{Link title}[link:page-slug]'}
${'asciidoc'} | ${'link:page-slug[Link title]'}
${'org'} | ${'[[page-slug]]'}
`('updates a message when value=$value is selected', ({ value, text }) => {
changeFormatSelect.value = value;
changeFormatSelect.dispatchEvent(new Event('change'));
expect(linkExample.innerHTML).toBe(text);
it('sets before unload warning', () => {
expect(findBeforeUnloadWarning()).toBe('');
});
it('starts with no unload warning', () => {
it('when form submitted, unsets before unload warning', () => {
findForm().dispatchEvent(new Event('submit'));
expect(findBeforeUnloadWarning()).toBeUndefined();
});
});
});
describe('when wiki content is updated', () => {
beforeEach(() => {
const content = findContent();
content.value = 'Lorem ipsum dolar sit!';
content.dispatchEvent(new Event('input'));
});
it('sets before unload warning', () => {
expect(findBeforeUnloadWarning()).toBe('');
});
it('when form submitted, unsets before unload warning', () => {
findForm().dispatchEvent(new Event('submit'));
expect(findBeforeUnloadWarning()).toBeUndefined();
});
});
describe('submit button state', () => {
beforeEach(() => {
setHTMLFixture(editFormHtmlFixture({ newPage: true }));
titleInput = document.getElementById('wiki_title');
contentInput = document.getElementById('wiki_content');
wikis = new Wikis();
});
it.each`
title | text | buttonState | disabledAttr
${'something'} | ${'something'} | ${'enabled'} | ${null}
${''} | ${'something'} | ${'disabled'} | ${'true'}
${'something'} | ${''} | ${'disabled'} | ${'true'}
${''} | ${''} | ${'disabled'} | ${'true'}
${' '} | ${' '} | ${'disabled'} | ${'true'}
`(
"when title='$title', content='$content', then, buttonState='$buttonState'",
({ title, text, disabledAttr }) => {
titleInput.value = title;
titleInput.dispatchEvent(new Event('keyup'));
contentInput.value = text;
contentInput.dispatchEvent(new Event('input'));
expect(findSubmitButton().getAttribute('disabled')).toBe(disabledAttr);
},
);
});
describe('trackPageView', () => {
......
......@@ -20,15 +20,25 @@ RSpec.shared_examples 'User creates wiki page' do
click_link "Create your first page"
end
it "shows validation error message" do
it "shows validation error message if the form is force submitted", :js do
page.within(".wiki-form") do
fill_in(:wiki_content, with: "")
click_on("Create page")
page.execute_script("window.onbeforeunload = null")
page.execute_script("document.querySelector('.wiki-form').submit()")
end
expect(page).to have_content("The form contains the following error:").and have_content("Content can't be blank")
end
it "disables the submit button", :js do
page.within(".wiki-form") do
fill_in(:wiki_content, with: "")
expect(page).to have_button('Create page', disabled: true)
end
end
it "makes sure links to unknown pages work correctly", :js do
page.within(".wiki-form") do
fill_in(:wiki_content, with: "[link test](test)")
......@@ -42,7 +52,7 @@ RSpec.shared_examples 'User creates wiki page' do
expect(page).to have_content("Create New Page")
end
it "shows non-escaped link in the pages list" do
it "shows non-escaped link in the pages list", :js do
fill_in(:wiki_title, with: "one/two/three-test")
page.within(".wiki-form") do
......@@ -61,7 +71,7 @@ RSpec.shared_examples 'User creates wiki page' do
expect(page).to have_field("wiki[message]", with: "Create home")
end
it "creates a page from the home page" do
it "creates a page from the home page", :js do
fill_in(:wiki_content, with: "[test](test)\n[GitLab API doc](api)\n[Rake tasks](raketasks)\n# Wiki header\n")
fill_in(:wiki_message, with: "Adding links to wiki")
......@@ -142,7 +152,7 @@ RSpec.shared_examples 'User creates wiki page' do
end
end
it 'creates a wiki page with Org markup', :aggregate_failures do
it 'creates a wiki page with Org markup', :aggregate_failures, :js do
org_content = <<~ORG
* Heading
** Subheading
......@@ -170,7 +180,7 @@ RSpec.shared_examples 'User creates wiki page' do
visit wiki_path(wiki)
end
context "via the `new wiki page` page" do
context "via the `new wiki page` page", :js do
it "creates a page with a single word" do
click_link("New page")
......@@ -189,7 +199,7 @@ RSpec.shared_examples 'User creates wiki page' do
.and have_content("My awesome wiki!")
end
it "creates a page with spaces in the name" do
it "creates a page with spaces in the name", :js do
click_link("New page")
page.within(".wiki-form") do
......@@ -207,7 +217,7 @@ RSpec.shared_examples 'User creates wiki page' do
.and have_content("My awesome wiki!")
end
it "creates a page with hyphens in the name" do
it "creates a page with hyphens in the name", :js do
click_link("New page")
page.within(".wiki-form") do
......
......@@ -90,9 +90,11 @@ RSpec.shared_examples 'User updates wiki page' do
expect(page).to have_field('wiki[message]', with: 'Update Wiki title')
end
it 'shows a validation error message' do
it 'shows a validation error message if the form is force submitted', :js do
fill_in(:wiki_content, with: '')
click_button('Save changes')
page.execute_script("window.onbeforeunload = null")
page.execute_script("document.querySelector('.wiki-form').submit()")
expect(page).to have_selector('.wiki-form')
expect(page).to have_content('Edit Page')
......@@ -101,6 +103,13 @@ RSpec.shared_examples 'User updates wiki page' do
expect(find('textarea#wiki_content').value).to eq('')
end
it "disables the submit button", :js do
page.within(".wiki-form") do
fill_in(:wiki_content, with: "")
expect(page).to have_button('Save changes', disabled: true)
end
end
it 'shows the emoji autocompletion dropdown', :js do
find('#wiki_content').native.send_keys('')
fill_in(:wiki_content, with: ':')
......@@ -108,7 +117,7 @@ RSpec.shared_examples 'User updates wiki page' do
expect(page).to have_selector('.atwho-view')
end
it 'shows the error message' do
it 'shows the error message', :js do
wiki_page.update(content: 'Update') # rubocop:disable Rails/SaveBang
click_button('Save changes')
......@@ -116,7 +125,7 @@ RSpec.shared_examples 'User updates wiki page' do
expect(page).to have_content('Someone edited the page the same time you did.')
end
it 'updates a page' do
it 'updates a page', :js do
fill_in('Content', with: 'Updated Wiki Content')
click_on('Save changes')
......@@ -147,7 +156,7 @@ RSpec.shared_examples 'User updates wiki page' do
visit wiki_page_path(wiki, wiki_page, action: :edit)
end
it 'moves the page to the root folder' do
it 'moves the page to the root folder', :js do
fill_in(:wiki_title, with: "/#{page_name}")
click_button('Save changes')
......@@ -155,7 +164,7 @@ RSpec.shared_examples 'User updates wiki page' do
expect(current_path).to eq(wiki_page_path(wiki, page_name))
end
it 'moves the page to other dir' do
it 'moves the page to other dir', :js do
new_page_dir = "foo1/bar1/#{page_name}"
fill_in(:wiki_title, with: new_page_dir)
......@@ -165,7 +174,7 @@ RSpec.shared_examples 'User updates wiki page' do
expect(current_path).to eq(wiki_page_path(wiki, new_page_dir))
end
it 'remains in the same place if title has not changed' do
it 'remains in the same place if title has not changed', :js do
original_path = wiki_page_path(wiki, wiki_page)
fill_in(:wiki_title, with: page_name)
......@@ -175,7 +184,7 @@ RSpec.shared_examples 'User updates wiki page' do
expect(current_path).to eq(original_path)
end
it 'can be moved to a different dir with a different name' do
it 'can be moved to a different dir with a different name', :js do
new_page_dir = "foo1/bar1/new_page_name"
fill_in(:wiki_title, with: new_page_dir)
......@@ -185,7 +194,7 @@ RSpec.shared_examples 'User updates wiki page' do
expect(current_path).to eq(wiki_page_path(wiki, new_page_dir))
end
it 'can be renamed and moved to the root folder' do
it 'can be renamed and moved to the root folder', :js do
new_name = 'new_page_name'
fill_in(:wiki_title, with: "/#{new_name}")
......@@ -195,7 +204,7 @@ RSpec.shared_examples 'User updates wiki page' do
expect(current_path).to eq(wiki_page_path(wiki, new_name))
end
it 'squishes the title before creating the page' do
it 'squishes the title before creating the page', :js do
new_page_dir = " foo1 / bar1 / #{page_name} "
fill_in(:wiki_title, with: new_page_dir)
......@@ -224,7 +233,7 @@ RSpec.shared_examples 'User updates wiki page' do
expect(page).to have_content('Wiki page was successfully updated.')
end
it 'shows a validation error when trying to change the content' do
it 'shows a validation error when trying to change the content', :js do
fill_in 'Content', with: 'new content'
click_on 'Save changes'
......
......@@ -53,7 +53,7 @@ RSpec.shared_examples 'User views empty wiki' do
if writable
element.click_link 'Create your first page'
expect(page).to have_button('Create page')
expect(page).to have_button('Create page', disabled: true)
else
expect(element).not_to have_link('Create your first page')
end
......
......@@ -29,7 +29,7 @@ RSpec.shared_examples 'User views wiki sidebar' do
end
end
it 'can create a custom sidebar' do
it 'can create a custom sidebar', :js do
click_on 'Edit sidebar'
fill_in :wiki_content, with: 'My custom sidebar'
click_on 'Create page'
......@@ -55,7 +55,7 @@ RSpec.shared_examples 'User views wiki sidebar' do
end
end
it 'can edit the custom sidebar' do
it 'can edit the custom sidebar', :js do
click_on 'Edit sidebar'
expect(page).to have_field(:wiki_content, with: 'My custom sidebar')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment