Commit efeaf3bd authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'ph-gl-form-js-modules' into 'master'

Moves form related JS modules out of global

See merge request gitlab-org/gitlab-ce!14780
parents e39aef73 556ef5ed
...@@ -80,6 +80,8 @@ import initChangesDropdown from './init_changes_dropdown'; ...@@ -80,6 +80,8 @@ import initChangesDropdown from './init_changes_dropdown';
import AbuseReports from './abuse_reports'; import AbuseReports from './abuse_reports';
import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils'; import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
import AjaxLoadingSpinner from './ajax_loading_spinner'; import AjaxLoadingSpinner from './ajax_loading_spinner';
import GlFieldErrors from './gl_field_errors';
import GLForm from './gl_form';
import U2FAuthenticate from './u2f/authenticate'; import U2FAuthenticate from './u2f/authenticate';
(function() { (function() {
...@@ -231,7 +233,7 @@ import U2FAuthenticate from './u2f/authenticate'; ...@@ -231,7 +233,7 @@ import U2FAuthenticate from './u2f/authenticate';
case 'groups:milestones:update': case 'groups:milestones:update':
new ZenMode(); new ZenMode();
new gl.DueDateSelectors(); new gl.DueDateSelectors();
new gl.GLForm($('.milestone-form'), true); new GLForm($('.milestone-form'), true);
break; break;
case 'projects:compare:show': case 'projects:compare:show':
new gl.Diff(); new gl.Diff();
...@@ -248,7 +250,7 @@ import U2FAuthenticate from './u2f/authenticate'; ...@@ -248,7 +250,7 @@ import U2FAuthenticate from './u2f/authenticate';
case 'projects:issues:new': case 'projects:issues:new':
case 'projects:issues:edit': case 'projects:issues:edit':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
new gl.GLForm($('.issue-form'), true); new GLForm($('.issue-form'), true);
new IssuableForm($('.issue-form')); new IssuableForm($('.issue-form'));
new LabelsSelect(); new LabelsSelect();
new MilestoneSelect(); new MilestoneSelect();
...@@ -272,7 +274,7 @@ import U2FAuthenticate from './u2f/authenticate'; ...@@ -272,7 +274,7 @@ import U2FAuthenticate from './u2f/authenticate';
case 'projects:merge_requests:edit': case 'projects:merge_requests:edit':
new gl.Diff(); new gl.Diff();
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
new gl.GLForm($('.merge-request-form'), true); new GLForm($('.merge-request-form'), true);
new IssuableForm($('.merge-request-form')); new IssuableForm($('.merge-request-form'));
new LabelsSelect(); new LabelsSelect();
new MilestoneSelect(); new MilestoneSelect();
...@@ -281,7 +283,7 @@ import U2FAuthenticate from './u2f/authenticate'; ...@@ -281,7 +283,7 @@ import U2FAuthenticate from './u2f/authenticate';
break; break;
case 'projects:tags:new': case 'projects:tags:new':
new ZenMode(); new ZenMode();
new gl.GLForm($('.tag-form'), true); new GLForm($('.tag-form'), true);
new RefSelectDropdown($('.js-branch-select')); new RefSelectDropdown($('.js-branch-select'));
break; break;
case 'projects:snippets:show': case 'projects:snippets:show':
...@@ -291,17 +293,17 @@ import U2FAuthenticate from './u2f/authenticate'; ...@@ -291,17 +293,17 @@ import U2FAuthenticate from './u2f/authenticate';
case 'projects:snippets:edit': case 'projects:snippets:edit':
case 'projects:snippets:create': case 'projects:snippets:create':
case 'projects:snippets:update': case 'projects:snippets:update':
new gl.GLForm($('.snippet-form'), true); new GLForm($('.snippet-form'), true);
break; break;
case 'snippets:new': case 'snippets:new':
case 'snippets:edit': case 'snippets:edit':
case 'snippets:create': case 'snippets:create':
case 'snippets:update': case 'snippets:update':
new gl.GLForm($('.snippet-form'), false); new GLForm($('.snippet-form'), false);
break; break;
case 'projects:releases:edit': case 'projects:releases:edit':
new ZenMode(); new ZenMode();
new gl.GLForm($('.release-form'), true); new GLForm($('.release-form'), true);
break; break;
case 'projects:merge_requests:show': case 'projects:merge_requests:show':
new gl.Diff(); new gl.Diff();
...@@ -607,7 +609,7 @@ import U2FAuthenticate from './u2f/authenticate'; ...@@ -607,7 +609,7 @@ import U2FAuthenticate from './u2f/authenticate';
new Wikis(); new Wikis();
shortcut_handler = new ShortcutsWiki(); shortcut_handler = new ShortcutsWiki();
new ZenMode(); new ZenMode();
new gl.GLForm($('.wiki-form'), true); new GLForm($('.wiki-form'), true);
break; break;
case 'snippets': case 'snippets':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
...@@ -658,7 +660,7 @@ import U2FAuthenticate from './u2f/authenticate'; ...@@ -658,7 +660,7 @@ import U2FAuthenticate from './u2f/authenticate';
Dispatcher.prototype.initFieldErrors = function() { Dispatcher.prototype.initFieldErrors = function() {
$('.gl-show-field-errors').each((i, form) => { $('.gl-show-field-errors').each((i, form) => {
new gl.GlFieldErrors(form); new GlFieldErrors(form);
}); });
}; };
......
...@@ -54,7 +54,7 @@ const inputErrorClass = 'gl-field-error-outline'; ...@@ -54,7 +54,7 @@ const inputErrorClass = 'gl-field-error-outline';
const errorAnchorSelector = '.gl-field-error-anchor'; const errorAnchorSelector = '.gl-field-error-anchor';
const ignoreInputSelector = '.gl-field-error-ignore'; const ignoreInputSelector = '.gl-field-error-ignore';
class GlFieldError { export default class GlFieldError {
constructor({ input, formErrors }) { constructor({ input, formErrors }) {
this.inputElement = $(input); this.inputElement = $(input);
this.inputDomElement = this.inputElement.get(0); this.inputDomElement = this.inputElement.get(0);
...@@ -159,6 +159,3 @@ class GlFieldError { ...@@ -159,6 +159,3 @@ class GlFieldError {
this.fieldErrorElement.hide(); this.fieldErrorElement.hide();
} }
} }
window.gl = window.gl || {};
window.gl.GlFieldError = GlFieldError;
/* eslint-disable comma-dangle, class-methods-use-this, max-len, space-before-function-paren, arrow-parens, no-param-reassign */ import GlFieldError from './gl_field_error';
import './gl_field_error';
const customValidationFlag = 'gl-field-error-ignore'; const customValidationFlag = 'gl-field-error-ignore';
class GlFieldErrors { export default class GlFieldErrors {
constructor(form) { constructor(form) {
this.form = $(form); this.form = $(form);
this.state = { this.state = {
inputs: [], inputs: [],
valid: false valid: false,
}; };
this.initValidators(); this.initValidators();
} }
initValidators () { initValidators() {
// register selectors here as needed // register selectors here as needed
const validateSelectors = [':text', ':password', '[type=email]'] const validateSelectors = [':text', ':password', '[type=email]']
.map((selector) => `input${selector}`).join(','); .map(selector => `input${selector}`).join(',');
this.state.inputs = this.form.find(validateSelectors).toArray() this.state.inputs = this.form.find(validateSelectors).toArray()
.filter((input) => !input.classList.contains(customValidationFlag)) .filter(input => !input.classList.contains(customValidationFlag))
.map((input) => new window.gl.GlFieldError({ input, formErrors: this })); .map(input => new GlFieldError({ input, formErrors: this }));
this.form.on('submit', this.catchInvalidFormSubmit); this.form.on('submit', GlFieldErrors.catchInvalidFormSubmit);
} }
/* Neccessary to prevent intercept and override invalid form submit /* Neccessary to prevent intercept and override invalid form submit
* because Safari & iOS quietly allow form submission when form is invalid * because Safari & iOS quietly allow form submission when form is invalid
* and prevents disabling of invalid submit button by application.js */ * and prevents disabling of invalid submit button by application.js */
catchInvalidFormSubmit (event) { static catchInvalidFormSubmit(e) {
const $form = $(event.currentTarget); const $form = $(e.currentTarget);
if (!$form.attr('novalidate')) { if (!$form.attr('novalidate')) {
if (!event.currentTarget.checkValidity()) { if (!e.currentTarget.checkValidity()) {
event.preventDefault(); e.preventDefault();
event.stopPropagation(); e.stopPropagation();
} }
} }
} }
...@@ -50,11 +48,9 @@ class GlFieldErrors { ...@@ -50,11 +48,9 @@ class GlFieldErrors {
}); });
} }
focusOnFirstInvalid () { focusOnFirstInvalid() {
const firstInvalid = this.state.inputs.filter((input) => !input.inputDomElement.validity.valid)[0]; const firstInvalid = this.state.inputs
.filter(input => !input.inputDomElement.validity.valid)[0];
firstInvalid.inputElement.focus(); firstInvalid.inputElement.focus();
} }
} }
window.gl = window.gl || {};
window.gl.GlFieldErrors = GlFieldErrors;
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-new, max-len */
/* global GitLab */
/* global DropzoneInput */ /* global DropzoneInput */
/* global autosize */ /* global autosize */
import GfmAutoComplete from './gfm_auto_complete'; import GfmAutoComplete from './gfm_auto_complete';
window.gl = window.gl || {}; export default class GLForm {
constructor(form, enableGFM = false) {
function GLForm(form, enableGFM = false) { this.form = form;
this.form = form; this.textarea = this.form.find('textarea.js-gfm-input');
this.textarea = this.form.find('textarea.js-gfm-input'); this.enableGFM = enableGFM;
this.enableGFM = enableGFM; // Before we start, we should clean up any previous data for this form
// Before we start, we should clean up any previous data for this form this.destroy();
this.destroy(); // Setup the form
// Setup the form this.setupForm();
this.setupForm(); this.form.data('gl-form', this);
this.form.data('gl-form', this);
}
GLForm.prototype.destroy = function() {
// Clean form listeners
this.clearEventListeners();
if (this.autoComplete) {
this.autoComplete.destroy();
} }
return this.form.data('gl-form', null);
};
GLForm.prototype.setupForm = function() { destroy() {
var isNewForm; // Clean form listeners
isNewForm = this.form.is(':not(.gfm-form)'); this.clearEventListeners();
this.form.removeClass('js-new-note-form'); if (this.autoComplete) {
if (isNewForm) { this.autoComplete.destroy();
this.form.find('.div-dropzone').remove(); }
this.form.addClass('gfm-form'); this.form.data('gl-form', null);
// remove notify commit author checkbox for non-commit notes
gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button, .js-note-new-discussion'));
this.autoComplete = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
this.autoComplete.setup(this.form.find('.js-gfm-input'), {
emojis: true,
members: this.enableGFM,
issues: this.enableGFM,
milestones: this.enableGFM,
mergeRequests: this.enableGFM,
labels: this.enableGFM,
});
new DropzoneInput(this.form);
autosize(this.textarea);
} }
// form and textarea event listeners
this.addEventListeners();
gl.text.init(this.form);
// hide discard button
this.form.find('.js-note-discard').hide();
this.form.show();
if (this.isAutosizeable) this.setupAutosize();
};
GLForm.prototype.setupAutosize = function () { setupForm() {
this.textarea.off('autosize:resized') const isNewForm = this.form.is(':not(.gfm-form)');
.on('autosize:resized', this.setHeightData.bind(this)); this.form.removeClass('js-new-note-form');
if (isNewForm) {
this.form.find('.div-dropzone').remove();
this.form.addClass('gfm-form');
// remove notify commit author checkbox for non-commit notes
gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button, .js-note-new-discussion'));
this.autoComplete = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
this.autoComplete.setup(this.form.find('.js-gfm-input'), {
emojis: true,
members: this.enableGFM,
issues: this.enableGFM,
milestones: this.enableGFM,
mergeRequests: this.enableGFM,
labels: this.enableGFM,
});
new DropzoneInput(this.form); // eslint-disable-line no-new
autosize(this.textarea);
}
// form and textarea event listeners
this.addEventListeners();
gl.text.init(this.form);
// hide discard button
this.form.find('.js-note-discard').hide();
this.form.show();
if (this.isAutosizeable) this.setupAutosize();
}
this.textarea.off('mouseup.autosize') setupAutosize() {
.on('mouseup.autosize', this.destroyAutosize.bind(this)); this.textarea.off('autosize:resized')
.on('autosize:resized', this.setHeightData.bind(this));
setTimeout(() => { this.textarea.off('mouseup.autosize')
autosize(this.textarea); .on('mouseup.autosize', this.destroyAutosize.bind(this));
this.textarea.css('resize', 'vertical');
}, 0);
};
GLForm.prototype.setHeightData = function () { setTimeout(() => {
this.textarea.data('height', this.textarea.outerHeight()); autosize(this.textarea);
}; this.textarea.css('resize', 'vertical');
}, 0);
}
GLForm.prototype.destroyAutosize = function () { setHeightData() {
const outerHeight = this.textarea.outerHeight(); this.textarea.data('height', this.textarea.outerHeight());
}
if (this.textarea.data('height') === outerHeight) return; destroyAutosize() {
const outerHeight = this.textarea.outerHeight();
autosize.destroy(this.textarea); if (this.textarea.data('height') === outerHeight) return;
this.textarea.data('height', outerHeight); autosize.destroy(this.textarea);
this.textarea.outerHeight(outerHeight);
this.textarea.css('max-height', window.outerHeight);
};
GLForm.prototype.clearEventListeners = function() { this.textarea.data('height', outerHeight);
this.textarea.off('focus'); this.textarea.outerHeight(outerHeight);
this.textarea.off('blur'); this.textarea.css('max-height', window.outerHeight);
return gl.text.removeListeners(this.form); }
};
GLForm.prototype.addEventListeners = function() { clearEventListeners() {
this.textarea.on('focus', function() { this.textarea.off('focus');
return $(this).closest('.md-area').addClass('is-focused'); this.textarea.off('blur');
}); gl.text.removeListeners(this.form);
return this.textarea.on('blur', function() { }
return $(this).closest('.md-area').removeClass('is-focused');
});
};
window.gl.GLForm = GLForm; addEventListeners() {
this.textarea.on('focus', function focusTextArea() {
$(this).closest('.md-area').addClass('is-focused');
});
this.textarea.on('blur', function blurTextArea() {
$(this).closest('.md-area').removeClass('is-focused');
});
}
}
...@@ -19,6 +19,7 @@ import 'vendor/jquery.atwho'; ...@@ -19,6 +19,7 @@ import 'vendor/jquery.atwho';
import AjaxCache from '~/lib/utils/ajax_cache'; import AjaxCache from '~/lib/utils/ajax_cache';
import Flash from './flash'; import Flash from './flash';
import CommentTypeToggle from './comment_type_toggle'; import CommentTypeToggle from './comment_type_toggle';
import GLForm from './gl_form';
import loadAwardsHandler from './awards_handler'; import loadAwardsHandler from './awards_handler';
import './autosave'; import './autosave';
import './dropzone_input'; import './dropzone_input';
...@@ -557,7 +558,7 @@ export default class Notes { ...@@ -557,7 +558,7 @@ export default class Notes {
*/ */
setupNoteForm(form) { setupNoteForm(form) {
var textarea, key; var textarea, key;
new gl.GLForm(form, this.enableGFM); this.glForm = new GLForm(form, this.enableGFM);
textarea = form.find('.js-note-text'); textarea = form.find('.js-note-text');
key = [ key = [
'Note', 'Note',
...@@ -1152,7 +1153,7 @@ export default class Notes { ...@@ -1152,7 +1153,7 @@ export default class Notes {
var targetId = $originalContentEl.data('target-id'); var targetId = $originalContentEl.data('target-id');
var targetType = $originalContentEl.data('target-type'); var targetType = $originalContentEl.data('target-type');
new gl.GLForm($editForm.find('form'), this.enableGFM); this.glForm = new GLForm($editForm.find('form'), this.enableGFM);
$editForm.find('form') $editForm.find('form')
.attr('action', postUrl) .attr('action', postUrl)
......
import Vue from 'vue'; import Vue from 'vue';
import Translate from '../vue_shared/translate'; import Translate from '../vue_shared/translate';
import GlFieldErrors from '../gl_field_errors';
import intervalPatternInput from './components/interval_pattern_input.vue'; import intervalPatternInput from './components/interval_pattern_input.vue';
import TimezoneDropdown from './components/timezone_dropdown'; import TimezoneDropdown from './components/timezone_dropdown';
import TargetBranchDropdown from './components/target_branch_dropdown'; import TargetBranchDropdown from './components/target_branch_dropdown';
...@@ -39,7 +40,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -39,7 +40,7 @@ document.addEventListener('DOMContentLoaded', () => {
gl.timezoneDropdown = new TimezoneDropdown(); gl.timezoneDropdown = new TimezoneDropdown();
gl.targetBranchDropdown = new TargetBranchDropdown(); gl.targetBranchDropdown = new TargetBranchDropdown();
gl.pipelineScheduleFieldErrors = new gl.GlFieldErrors(formElement); gl.pipelineScheduleFieldErrors = new GlFieldErrors(formElement);
setupPipelineVariableList($('.js-pipeline-variable-list')); setupPipelineVariableList($('.js-pipeline-variable-list'));
}); });
<script> <script>
import Flash from '../../../flash'; import Flash from '../../../flash';
import GLForm from '../../../gl_form';
import markdownHeader from './header.vue'; import markdownHeader from './header.vue';
import markdownToolbar from './toolbar.vue'; import markdownToolbar from './toolbar.vue';
...@@ -85,7 +86,7 @@ ...@@ -85,7 +86,7 @@
/* /*
GLForm class handles all the toolbar buttons GLForm class handles all the toolbar buttons
*/ */
return new gl.GLForm($(this.$refs['gl-form']), true); return new GLForm($(this.$refs['gl-form']), true);
}, },
beforeDestroy() { beforeDestroy() {
const glForm = $(this.$refs['gl-form']).data('gl-form'); const glForm = $(this.$refs['gl-form']).data('gl-form');
......
/* eslint-disable space-before-function-paren, arrow-body-style */ /* eslint-disable space-before-function-paren, arrow-body-style */
import '~/gl_field_errors'; import GlFieldErrors from '~/gl_field_errors';
((global) => { describe('GL Style Field Errors', function() {
preloadFixtures('static/gl_field_errors.html.raw'); preloadFixtures('static/gl_field_errors.html.raw');
describe('GL Style Field Errors', function() { beforeEach(function() {
beforeEach(function() { loadFixtures('static/gl_field_errors.html.raw');
loadFixtures('static/gl_field_errors.html.raw'); const $form = this.$form = $('form.gl-show-field-errors');
const $form = this.$form = $('form.gl-show-field-errors'); this.fieldErrors = new GlFieldErrors($form);
this.fieldErrors = new global.GlFieldErrors($form); });
});
it('should select the correct input elements', function() { it('should select the correct input elements', function() {
expect(this.$form).toBeDefined(); expect(this.$form).toBeDefined();
expect(this.$form.length).toBe(1); expect(this.$form.length).toBe(1);
expect(this.fieldErrors).toBeDefined(); expect(this.fieldErrors).toBeDefined();
const inputs = this.fieldErrors.state.inputs; const inputs = this.fieldErrors.state.inputs;
expect(inputs.length).toBe(4); expect(inputs.length).toBe(4);
}); });
it('should ignore elements with custom error handling', function() { it('should ignore elements with custom error handling', function() {
const customErrorFlag = 'gl-field-error-ignore'; const customErrorFlag = 'gl-field-error-ignore';
const customErrorElem = $(`.${customErrorFlag}`); const customErrorElem = $(`.${customErrorFlag}`);
expect(customErrorElem.length).toBe(1); expect(customErrorElem.length).toBe(1);
const customErrors = this.fieldErrors.state.inputs.filter((input) => { const customErrors = this.fieldErrors.state.inputs.filter((input) => {
return input.inputElement.hasClass(customErrorFlag); return input.inputElement.hasClass(customErrorFlag);
});
expect(customErrors.length).toBe(0);
}); });
expect(customErrors.length).toBe(0);
});
it('should not show any errors before submit attempt', function() { it('should not show any errors before submit attempt', function() {
this.$form.find('.email').val('not-a-valid-email').keyup(); this.$form.find('.email').val('not-a-valid-email').keyup();
this.$form.find('.text-required').val('').keyup(); this.$form.find('.text-required').val('').keyup();
this.$form.find('.alphanumberic').val('?---*').keyup(); this.$form.find('.alphanumberic').val('?---*').keyup();
const errorsShown = this.$form.find('.gl-field-error-outline'); const errorsShown = this.$form.find('.gl-field-error-outline');
expect(errorsShown.length).toBe(0); expect(errorsShown.length).toBe(0);
}); });
it('should show errors when input valid is submitted', function() { it('should show errors when input valid is submitted', function() {
this.$form.find('.email').val('not-a-valid-email').keyup(); this.$form.find('.email').val('not-a-valid-email').keyup();
this.$form.find('.text-required').val('').keyup(); this.$form.find('.text-required').val('').keyup();
this.$form.find('.alphanumberic').val('?---*').keyup(); this.$form.find('.alphanumberic').val('?---*').keyup();
this.$form.submit(); this.$form.submit();
const errorsShown = this.$form.find('.gl-field-error-outline'); const errorsShown = this.$form.find('.gl-field-error-outline');
expect(errorsShown.length).toBe(4); expect(errorsShown.length).toBe(4);
}); });
it('should properly track validity state on input after invalid submission attempt', function() { it('should properly track validity state on input after invalid submission attempt', function() {
this.$form.submit(); this.$form.submit();
const emailInputModel = this.fieldErrors.state.inputs[1]; const emailInputModel = this.fieldErrors.state.inputs[1];
const fieldState = emailInputModel.state; const fieldState = emailInputModel.state;
const emailInputElement = emailInputModel.inputElement; const emailInputElement = emailInputModel.inputElement;
// No input // No input
expect(emailInputElement).toHaveClass('gl-field-error-outline'); expect(emailInputElement).toHaveClass('gl-field-error-outline');
expect(fieldState.empty).toBe(true); expect(fieldState.empty).toBe(true);
expect(fieldState.valid).toBe(false); expect(fieldState.valid).toBe(false);
// Then invalid input // Then invalid input
emailInputElement.val('not-a-valid-email').keyup(); emailInputElement.val('not-a-valid-email').keyup();
expect(emailInputElement).toHaveClass('gl-field-error-outline'); expect(emailInputElement).toHaveClass('gl-field-error-outline');
expect(fieldState.empty).toBe(false); expect(fieldState.empty).toBe(false);
expect(fieldState.valid).toBe(false); expect(fieldState.valid).toBe(false);
// Then valid input // Then valid input
emailInputElement.val('email@gitlab.com').keyup(); emailInputElement.val('email@gitlab.com').keyup();
expect(emailInputElement).not.toHaveClass('gl-field-error-outline'); expect(emailInputElement).not.toHaveClass('gl-field-error-outline');
expect(fieldState.empty).toBe(false); expect(fieldState.empty).toBe(false);
expect(fieldState.valid).toBe(true); expect(fieldState.valid).toBe(true);
// Then invalid input // Then invalid input
emailInputElement.val('not-a-valid-email').keyup(); emailInputElement.val('not-a-valid-email').keyup();
expect(emailInputElement).toHaveClass('gl-field-error-outline'); expect(emailInputElement).toHaveClass('gl-field-error-outline');
expect(fieldState.empty).toBe(false); expect(fieldState.empty).toBe(false);
expect(fieldState.valid).toBe(false); expect(fieldState.valid).toBe(false);
// Then empty input // Then empty input
emailInputElement.val('').keyup(); emailInputElement.val('').keyup();
expect(emailInputElement).toHaveClass('gl-field-error-outline'); expect(emailInputElement).toHaveClass('gl-field-error-outline');
expect(fieldState.empty).toBe(true); expect(fieldState.empty).toBe(true);
expect(fieldState.valid).toBe(false); expect(fieldState.valid).toBe(false);
// Then valid input // Then valid input
emailInputElement.val('email@gitlab.com').keyup(); emailInputElement.val('email@gitlab.com').keyup();
expect(emailInputElement).not.toHaveClass('gl-field-error-outline'); expect(emailInputElement).not.toHaveClass('gl-field-error-outline');
expect(fieldState.empty).toBe(false); expect(fieldState.empty).toBe(false);
expect(fieldState.valid).toBe(true); expect(fieldState.valid).toBe(true);
}); });
it('should properly infer error messages', function() { it('should properly infer error messages', function() {
this.$form.submit(); this.$form.submit();
const trackedInputs = this.fieldErrors.state.inputs; const trackedInputs = this.fieldErrors.state.inputs;
const inputHasTitle = trackedInputs[1]; const inputHasTitle = trackedInputs[1];
const hasTitleErrorElem = inputHasTitle.inputElement.siblings('.gl-field-error'); const hasTitleErrorElem = inputHasTitle.inputElement.siblings('.gl-field-error');
const inputNoTitle = trackedInputs[2]; const inputNoTitle = trackedInputs[2];
const noTitleErrorElem = inputNoTitle.inputElement.siblings('.gl-field-error'); const noTitleErrorElem = inputNoTitle.inputElement.siblings('.gl-field-error');
expect(noTitleErrorElem.text()).toBe('This field is required.'); expect(noTitleErrorElem.text()).toBe('This field is required.');
expect(hasTitleErrorElem.text()).toBe('Please provide a valid email address.'); expect(hasTitleErrorElem.text()).toBe('Please provide a valid email address.');
});
}); });
})(window.gl || (window.gl = {})); });
import autosize from 'vendor/autosize'; import autosize from 'vendor/autosize';
import '~/gl_form'; import GLForm from '~/gl_form';
import '~/lib/utils/text_utility'; import '~/lib/utils/text_utility';
import '~/lib/utils/common_utils'; import '~/lib/utils/common_utils';
window.autosize = autosize; window.autosize = autosize;
describe('GLForm', () => { describe('GLForm', () => {
const global = window.gl || (window.gl = {});
const GLForm = global.GLForm;
it('should be defined in the global scope', () => {
expect(GLForm).toBeDefined();
});
describe('when instantiated', function () { describe('when instantiated', function () {
beforeEach((done) => { beforeEach((done) => {
this.form = $('<form class="gfm-form"><textarea class="js-gfm-input"></form>'); this.form = $('<form class="gfm-form"><textarea class="js-gfm-input"></form>');
......
...@@ -426,19 +426,17 @@ import '~/notes'; ...@@ -426,19 +426,17 @@ import '~/notes';
}); });
describe('putEditFormInPlace', () => { describe('putEditFormInPlace', () => {
it('should call gl.GLForm with GFM parameter passed through', () => { it('should call GLForm with GFM parameter passed through', () => {
spyOn(gl, 'GLForm'); const notes = new Notes('', []);
const $el = $(`
<div>
<form></form>
</div>
`);
const $el = jasmine.createSpyObj('$form', ['find', 'closest']); notes.putEditFormInPlace($el);
$el.find.and.returnValue($('<div>'));
$el.closest.and.returnValue($('<div>'));
Notes.prototype.putEditFormInPlace.call({ expect(notes.glForm.enableGFM).toBeTruthy();
getEditFormSelector: () => '',
enableGFM: true
}, $el);
expect(gl.GLForm).toHaveBeenCalledWith(jasmine.any(Object), true);
}); });
}); });
......
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