validator.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. $(function () {
  2. $.mockjaxSettings.logging = false
  3. $.mockjax({
  4. url: '/success',
  5. status: 200,
  6. responseText: 'cool'
  7. })
  8. $.mockjax({
  9. url: '/error',
  10. status: 418,
  11. responseText: 'dang'
  12. })
  13. QUnit.module("validator")
  14. QUnit.test("should provide no conflict", function (assert) {
  15. var validator = $.fn.validator.noConflict()
  16. assert.ok(!$.fn.validator, 'validator was set back to undefined (org value)')
  17. $.fn.validator = validator
  18. })
  19. QUnit.test("should be defined on jquery object", function (assert) {
  20. var div = $('<div></div>')
  21. assert.ok(div.validator, 'validator method is defined')
  22. })
  23. QUnit.test("should return element", function (assert) {
  24. var form = $('<form></form>')
  25. assert.ok(form.validator()[0] == form[0], 'same element returned')
  26. })
  27. QUnit.test("should expose defaults var for settings", function (assert) {
  28. assert.ok($.fn.validator.Constructor.DEFAULTS, 'default object exposed')
  29. })
  30. QUnit.test('should not fire validated when validate is prevented', function (assert) {
  31. var done = assert.async()
  32. $('<form><input type="email"></form>')
  33. .on('validate.bs.validator', function (e) {
  34. e.preventDefault()
  35. assert.ok(true)
  36. done()
  37. })
  38. .on('validated.bs.validator', function (e) {
  39. assert.ok(false)
  40. })
  41. .validator('validate')
  42. })
  43. QUnit.test('should validate match', 2, function (assert) {
  44. var done = assert.async()
  45. var form = '<form>'
  46. + '<input type="text" id="canon" value="pizza">'
  47. + '<input type="text" id="wannabe" value="hotpocket" data-match="#canon">'
  48. + '</form>'
  49. form = $(form)
  50. .appendTo($('#qunit-fixture'))
  51. .on('invalid.bs.validator', function (e) {
  52. var $el = $(e.relatedTarget)
  53. if ($el.attr('id') !== 'wannabe') return
  54. assert.ok(true)
  55. $el.val('pizza').trigger('input')
  56. })
  57. .on('valid.bs.validator', function (e) {
  58. var $el = $(e.relatedTarget)
  59. if ($el.attr('id') !== 'wannabe') return
  60. assert.ok(true)
  61. done()
  62. })
  63. .validator('validate')
  64. })
  65. QUnit.test('should validate minlength', 2, function (assert) {
  66. var done = assert.async()
  67. $('<form><input type="text" data-minlength="6" value="pizza"></form>')
  68. .on('invalid.bs.validator', function (e) {
  69. assert.ok(true)
  70. $(e.relatedTarget).val('pizzas').trigger('input')
  71. })
  72. .on('valid.bs.validator', function (e) {
  73. assert.ok(true)
  74. done()
  75. })
  76. .validator('validate')
  77. })
  78. QUnit.test('should allow custom generic error message', function (assert) {
  79. var done = assert.async()
  80. var form = '<form>'
  81. + '<div class="form-group">'
  82. + '<input type="text" data-minlength="6" data-error="generic error" value="pizza">'
  83. + '<div class="help-block with-errors">6 characters</div>'
  84. + '</div>'
  85. + '</form>'
  86. $(form)
  87. .on('invalid.bs.validator', function (e) {
  88. assert.ok($(this).find('.help-block.with-errors').text() == 'generic error', 'generic error message was set')
  89. done()
  90. })
  91. .validator('validate')
  92. })
  93. QUnit.test('should allow custom error-specific message for standard attribute validators', function (assert) {
  94. var form = '<form>'
  95. + '<div class="form-group">'
  96. + '<input type="email" data-type-error="type" value="pizza">'
  97. + '<div id="type" class="help-block with-errors"></div>'
  98. + '</div>'
  99. + '<div class="form-group">'
  100. + '<input type="text" pattern="burger" data-pattern-error="pattern" value="pizza">'
  101. + '<div id="pattern" class="help-block with-errors"></div>'
  102. + '</div>'
  103. + '<div class="form-group">'
  104. + '<input type="number" min="5" data-min-error="min" value="0">'
  105. + '<div id="min" class="help-block with-errors"></div>'
  106. + '</div>'
  107. + '<div class="form-group">'
  108. + '<input type="number" max="5" data-max-error="max" value="10">'
  109. + '<div id="max" class="help-block with-errors"></div>'
  110. + '</div>'
  111. + '<div class="form-group">'
  112. + '<input type="number" min="0" step="5" data-step-error="step" value="3">'
  113. + '<div id="step" class="help-block with-errors"></div>'
  114. + '</div>'
  115. + '<div class="form-group">'
  116. + '<input type="text" data-required-error="required" required>'
  117. + '<div id="required" class="help-block with-errors"></div>'
  118. + '</div>'
  119. + '</form>'
  120. $(form)
  121. .appendTo('#qunit-fixture')
  122. .validator('validate')
  123. assert.equal($('#type').text(), 'type', 'type error message was set')
  124. assert.equal($('#pattern').text(), 'pattern', 'pattern error message was set')
  125. assert.equal($('#min').text(), 'min', 'min error message was set')
  126. assert.equal($('#max').text(), 'max', 'max error message was set')
  127. assert.equal($('#step').text(), 'step', 'step error message was set')
  128. assert.equal($('#required').text(), 'required', 'required error message was set')
  129. })
  130. QUnit.test('should allow custom error-specific message for non-standard validators', function (assert) {
  131. var done = assert.async()
  132. var form = '<form>'
  133. + '<div class="form-group">'
  134. + '<input type="text" data-minlength="6" data-minlength-error="minlength error" value="pizza">'
  135. + '<div class="help-block with-errors">6 characters</div>'
  136. + '</div>'
  137. + '</form>'
  138. $(form)
  139. .on('invalid.bs.validator', function (e) {
  140. assert.ok($(this).find('.help-block.with-errors').text() == 'minlength error', 'specific error message was set')
  141. done()
  142. })
  143. .validator('validate')
  144. })
  145. QUnit.test('should give precedence to specific error message over generic error message', function (assert) {
  146. var done = assert.async()
  147. var form = '<form>'
  148. + '<div class="form-group">'
  149. + '<input type="text" data-minlength="6" data-error="generic error" data-minlength-error="minlength error" value="pizza">'
  150. + '<div class="help-block with-errors">6 characters</div>'
  151. + '</div>'
  152. + '</form>'
  153. $(form)
  154. .on('invalid.bs.validator', function (e) {
  155. assert.ok($(this).find('.help-block.with-errors').text() == 'minlength error', 'specific error message displayed instead of generic error')
  156. done()
  157. })
  158. .validator('validate')
  159. })
  160. QUnit.test('should escape html in error messages if html option is false', function (assert) {
  161. var done = assert.async()
  162. var form = '<form>'
  163. + '<div class="form-group">'
  164. + '<input type="text" data-minlength="6" data-minlength-error="<em>Too short</em>" value="pizza">'
  165. + '<div class="help-block with-errors"></div>'
  166. + '</div>'
  167. + '</form>'
  168. $(form)
  169. .on('invalid.bs.validator', function (e) {
  170. assert.ok($(this).find('.help-block.with-errors').text() == '<em>Too short</em>', 'html escaped from error message')
  171. done()
  172. })
  173. .validator({html: false})
  174. .validator('validate')
  175. })
  176. QUnit.test('should allow html in error messages if html option is true', function (assert) {
  177. var done = assert.async()
  178. var form = '<form>'
  179. + '<div class="form-group">'
  180. + '<input type="text" data-minlength="6" data-minlength-error="<em>Too short</em>" value="pizza">'
  181. + '<div class="help-block with-errors"></div>'
  182. + '</div>'
  183. + '</form>'
  184. $(form)
  185. .on('invalid.bs.validator', function (e) {
  186. assert.ok($(this).find('.help-block.with-errors').text() == 'Too short', 'html allowed in error message')
  187. done()
  188. })
  189. .validator({html: true})
  190. .validator('validate')
  191. })
  192. QUnit.test('should restore .help-block content once valid', function (assert) {
  193. var done = assert.async()
  194. var form = '<form>'
  195. + '<div class="form-group">'
  196. + '<input type="text" data-minlength="6" value="pizza">'
  197. + '<div class="help-block with-errors">6 characters</div>'
  198. + '</div>'
  199. + '</form>'
  200. $(form)
  201. .on('invalid.bs.validator', function (e) {
  202. assert.ok($(this).find('.help-block.with-errors').text() != '6 characters', 'error message was set')
  203. $(e.relatedTarget).val('pizzas').trigger('input')
  204. })
  205. .on('valid.bs.validator', function (e) {
  206. assert.ok($(this).find('.help-block.with-errors').text() == '6 characters', 'help text was restored')
  207. done()
  208. })
  209. .validator('validate')
  210. })
  211. QUnit.test('should add .has-error class to the closest .form-group', function (assert) {
  212. var done = assert.async()
  213. var form = '<form>'
  214. + '<div class="form-group">'
  215. + '<input type="text" data-minlength="6" value="pizza">'
  216. + '</div>'
  217. + '</form>'
  218. $(form)
  219. .on('invalid.bs.validator', function (e) {
  220. assert.ok($(this).find('.form-group').hasClass('has-error'), '.has-error class added to form-group')
  221. $(e.relatedTarget).val('pizzas').trigger('input')
  222. })
  223. .on('valid.bs.validator', function (e) {
  224. assert.ok(!$(this).find('.form-group').hasClass('has-error'), '.has-error class removed from form-group')
  225. done()
  226. })
  227. .validator('validate')
  228. })
  229. QUnit.test('should add feedback classes to .form-control-feedback elements when the form group .has-feedback', function (assert) {
  230. var done = assert.async()
  231. var form = '<form>'
  232. + '<div class="form-group has-feedback">'
  233. + '<input type="text" data-minlength="6" value="pizza">'
  234. + '<div class="form-control-feedback"></div>'
  235. + '</div>'
  236. + '</form>'
  237. $(form)
  238. .on('invalid.bs.validator', function (e) {
  239. assert.ok($(this).find('.form-control-feedback').hasClass('glyphicon-remove'), 'error feedback class added to .form-control-feedback')
  240. $(e.relatedTarget).val('pizzas').trigger('input')
  241. })
  242. .on('valid.bs.validator', function (e) {
  243. assert.ok($(this).find('.form-control-feedback').hasClass('glyphicon-ok'), 'success feedback class added to .form-control-feedback')
  244. done()
  245. })
  246. .validator('validate')
  247. })
  248. QUnit.test('should not add feedback classes to .form-control-feedback elements when the form group does not .has-feedback', function (assert) {
  249. var done = assert.async()
  250. var form = '<form>'
  251. + '<div class="form-group">'
  252. + '<input type="text" data-minlength="6" value="pizza">'
  253. + '<div class="form-control-feedback"></div>'
  254. + '</div>'
  255. + '</form>'
  256. $(form)
  257. .on('invalid.bs.validator', function (e) {
  258. assert.ok(!$(this).find('.form-control-feedback').hasClass('glyphicon-remove'), 'error feedback class not added to .form-control-feedback')
  259. $(e.relatedTarget).val('pizzas').trigger('input')
  260. })
  261. .on('valid.bs.validator', function (e) {
  262. assert.ok(!$(this).find('.form-control-feedback').hasClass('glyphicon-ok'), 'success feedback class not added to .form-control-feedback')
  263. done()
  264. })
  265. .validator('validate')
  266. })
  267. QUnit.test('should not add success feedback classes to empty fields', function (assert) {
  268. var done = assert.async()
  269. var form = '<form>'
  270. + '<div class="form-group has-feedback">'
  271. + '<input type="text" data-minlength="6" value="pizza">'
  272. + '<div class="form-control-feedback"></div>'
  273. + '</div>'
  274. + '</form>'
  275. $(form)
  276. .on('invalid.bs.validator', function (e) {
  277. assert.ok($(this).find('.form-control-feedback').hasClass('glyphicon-remove'), 'error feedback class added to .form-control-feedback')
  278. $(e.relatedTarget).val('').trigger('input')
  279. })
  280. .on('valid.bs.validator', function (e) {
  281. assert.ok(!$(this).find('.form-control-feedback').hasClass('glyphicon-ok'), 'success feedback class not added to .form-control-feedback')
  282. assert.ok(!$(this).find('.form-group').hasClass('has-success'), '.has-success not added to .form-group')
  283. done()
  284. })
  285. .validator('validate')
  286. })
  287. QUnit.test('should disable submit button unless form is complete and valid', function (assert) {
  288. var form = '<form>'
  289. + '<input id="required" type="text" required>'
  290. + '<input id="minlength" type="text" data-minlength="6">'
  291. + '<button type="submit" id="btn">Submit</button>'
  292. + '</form>'
  293. form = $(form)
  294. .appendTo('#qunit-fixture')
  295. .validator()
  296. var $btn = $('#btn')
  297. assert.ok($btn.hasClass('disabled'), 'submit button disabled because form is incomplete and invalid')
  298. $('#required').val('hamburgers').trigger('input')
  299. assert.ok(!$btn.hasClass('disabled'), 'submit button enabled because form is sufficiently complete and no fields are invalid')
  300. $('#minlength').val('pizza').trigger('input')
  301. assert.ok($btn.hasClass('disabled'), 'submit button disabled because form is invalid')
  302. $('#minlength').val('pizzas').trigger('input')
  303. assert.ok(!$btn.hasClass('disabled'), 'submit button enabled because form is complete and valid')
  304. })
  305. QUnit.test('should not disable submit button if disable option is set to false', function (assert) {
  306. var form = '<form>'
  307. + '<input id="required" type="text" required>'
  308. + '<input id="minlength" type="text" data-minlength="6">'
  309. + '<button type="submit" id="btn">Submit</button>'
  310. + '</form>'
  311. form = $(form)
  312. .appendTo('#qunit-fixture')
  313. .validator({ disable: false })
  314. var $btn = $('#btn')
  315. assert.ok($btn.not('.disabled'), 'submit button enabled although form is incomplete and invalid because disabling of submit is disabled')
  316. $('#required').val('hamburgers').trigger('input')
  317. $('#minlength').val('pizza').trigger('input')
  318. assert.ok($btn.not('.disabled'), 'submit button enabled although form is invalid because disabling of submit is disable')
  319. })
  320. QUnit.test('should only disable the submit buttons', function (assert) {
  321. var form = '<form>'
  322. + '<input id="required" type="text" required>'
  323. + '<button type="submit" id="submit">Submit</button>'
  324. + '<button type="button" id="cancel">Cancel</button>'
  325. + '<button id="btn">Undefined Type</button>'
  326. + '</form>'
  327. form = $(form)
  328. .appendTo('#qunit-fixture')
  329. .validator()
  330. var $submit = $('#submit')
  331. var $cancel = $('#cancel')
  332. var $btn = $('#btn')
  333. assert.ok($submit.hasClass('disabled'), 'submit button disabled')
  334. assert.ok(!$cancel.hasClass('disabled'), 'cancel button not disabled')
  335. assert.ok(!$btn.hasClass('disabled'), 'button without a type not disabled')
  336. })
  337. QUnit.test('should respect the required attribute on checkboxes', function (assert) {
  338. var form = '<form>'
  339. + '<input id="required" type="checkbox" required>'
  340. + '<button type="submit" id="btn">Submit</button>'
  341. + '</form>'
  342. form = $(form)
  343. .appendTo('#qunit-fixture')
  344. .validator()
  345. var $btn = $('#btn')
  346. assert.ok($btn.hasClass('disabled'), 'submit button disabled because form is incomplete')
  347. $('#required').prop('checked', true).trigger('change')
  348. assert.ok(!$btn.hasClass('disabled'), 'submit button enabled because form is complete')
  349. $('#required').prop('checked', false).trigger('change')
  350. assert.ok($btn.hasClass('disabled'), 'submit button disabled because form is incomplete')
  351. $('#required').prop('checked', true).trigger('change')
  352. assert.ok(!$btn.hasClass('disabled'), 'submit button enabled because form is complete')
  353. })
  354. QUnit.test('should respect the required attribute on radio button groups', function (assert) {
  355. var form = '<form>'
  356. + '<input type="radio" id="required1" name="radioGroup" required>'
  357. + '<input type="radio" id="required2" name="radioGroup" required>'
  358. + '<button type="submit" id="btn">Submit</button>'
  359. + '</form>'
  360. form = $(form)
  361. .appendTo('#qunit-fixture')
  362. .validator()
  363. var $btn = $('#btn')
  364. assert.ok($btn.hasClass('disabled'), 'submit button disabled because form is incomplete')
  365. $('#required1').prop('checked', true).trigger('change')
  366. assert.ok(!$btn.hasClass('disabled'), 'submit button enabled because form is complete')
  367. $('#required2').prop('checked', false).trigger('change')
  368. assert.ok(!$btn.hasClass('disabled'), 'submit button still enabled')
  369. })
  370. QUnit.test('should support [form] attribute on submit buttons outside of form element', function (assert) {
  371. var form = '<form id="myForm">'
  372. + '<input type="text" id="input" required>'
  373. + '</form>'
  374. + '<button type="submit" form="myForm" id="btn">Submit</button>'
  375. form = $(form)
  376. .appendTo('#qunit-fixture')
  377. .validator()
  378. var $btn = $('#btn')
  379. assert.ok($btn.hasClass('disabled'), 'submit button outside of referenced form is disabled')
  380. $('#input').val('sup').trigger('change')
  381. assert.ok(!$btn.hasClass('disabled'), 'submit button outside of referenced form reacted to changes')
  382. })
  383. QUnit.test('should ignore button fields', function (assert) {
  384. var form = '<form>'
  385. + '<div class="form-group">'
  386. + '<input type="text" data-error="error" required>'
  387. + '<input type="submit" value="Submit">'
  388. + '<div id="errors" class="help-block with-errors">valid</div>'
  389. + '</div>'
  390. + '</form>'
  391. form = $(form)
  392. .appendTo('#qunit-fixture')
  393. .validator('validate')
  394. var $errors = $('#errors')
  395. assert.equal($errors.text(), 'error', 'buttons did not inadvertently get validated and clear the form-group errors')
  396. })
  397. QUnit.test('should validate remote endpoints with success if response is 200', function (assert) {
  398. var done = assert.async()
  399. var form = '<form>'
  400. + '<input id="remote" type="text" value="foo" data-remote="/success">'
  401. + '</form>'
  402. form = $(form)
  403. .appendTo('#qunit-fixture')
  404. .on('valid.bs.validator', function (e) {
  405. assert.ok(e.relatedTarget === $('#remote')[0], 'remote endpoint validated successfully with a 200 response')
  406. done()
  407. })
  408. .validator('validate')
  409. })
  410. QUnit.test('should validate remote endpoints with error if response is 4xx', function (assert) {
  411. var done = assert.async()
  412. var form = '<form>'
  413. + '<input id="remote" type="text" value="foo" data-remote="/error">'
  414. + '</form>'
  415. form = $(form)
  416. .appendTo('#qunit-fixture')
  417. .on('invalid.bs.validator', function (e) {
  418. assert.ok(e.relatedTarget === $('#remote')[0], 'remote endpoint validated with error with a 4xx response')
  419. done()
  420. })
  421. .validator('validate')
  422. })
  423. QUnit.test('should clean up after itself when destroy called', function (assert) {
  424. var done = assert.async()
  425. var form = '<form>'
  426. + '<div class="form-group has-feedback">'
  427. + '<input type="text" data-error="error message" required>'
  428. + '<div class="form-control-feedback"></div>'
  429. + '<div class="help-block with-errors">original content</div>'
  430. + '</div>'
  431. + '<button type="submit">Submit</button>'
  432. + '</form>'
  433. form = $(form)
  434. .appendTo('#qunit-fixture')
  435. .validator('validate')
  436. var validator = form.data('bs.validator')
  437. window.setTimeout(function () {
  438. form.validator('destroy')
  439. Object.keys(validator).forEach(function (key) {
  440. assert.ok(validator[key] === null, 'removed ' + key + ' reference from plugin instance')
  441. })
  442. assert.ok(!form.data('bs.validator'), 'removed data reference to plugin instance')
  443. assert.ok(!form.attr('novalidate'), 'removed novalidate browser override')
  444. assert.ok(Object.keys(form.find('input').data()).length === 1, 'removed data left on inputs (excluding data-* attrs)')
  445. assert.ok(!form.find('.has-error').length, 'removed has-error class from all inputs')
  446. assert.ok(!form.find('.glyphicon-remove').length, 'removed feedback class from all inputs')
  447. assert.ok(form.find('.help-block').html() === 'original content', 'help block content restored')
  448. assert.ok(!form.find('button').is('.disabled'), 're-enabled submit button')
  449. done()
  450. })
  451. })
  452. QUnit.test('should run custom validators', function (assert) {
  453. var form = '<form>'
  454. + '<div class="form-group">'
  455. + '<input type="text" id="foo" data-foo="foo" value="foo">'
  456. + '<div class="help-block with-errors"></div>'
  457. + '</div>'
  458. + '<div class="form-group">'
  459. + '<input type="text" id="bar" data-foo="foo" value="bar">'
  460. + '<div class="help-block with-errors"></div>'
  461. + '</div>'
  462. + '<div class="form-group">'
  463. + '<input type="text" id="baz" data-foo value="baz">'
  464. + '<div class="help-block with-errors"></div>'
  465. + '</div>'
  466. + '<button type="submit">Submit</button>'
  467. + '</form>'
  468. var options = {
  469. custom: {
  470. foo: function ($el) {
  471. if ($el.data('foo') != $el.val()) return 'not equal to ' + $el.data('foo')
  472. }
  473. }
  474. }
  475. form = $(form)
  476. .appendTo('#qunit-fixture')
  477. .validator(options)
  478. .validator('validate')
  479. assert.ok($('#foo').data('bs.validator.errors').length === 0, 'foo input is valid')
  480. assert.ok($('#bar').data('bs.validator.errors').length === 1, 'bar input is invalid')
  481. assert.ok($('#bar').data('bs.validator.errors')[0] === 'not equal to foo', 'bar error is custom error')
  482. assert.ok($('#baz').data('bs.validator.errors').length === 1, 'baz ran validator even though data-foo has no attr value')
  483. })
  484. QUnit.test('should update set of fields', function (assert) {
  485. var form = '<form><button id="btn" type="submit">Submit</button></form>'
  486. var group = '<div class="form-group">'
  487. + '<input type="text" data-error="error" required>'
  488. + '<div id="errors" class="help-block with-errors"></div>'
  489. + '</div>'
  490. form = $(form)
  491. .appendTo('#qunit-fixture')
  492. .validator()
  493. .append(group)
  494. .validator('validate')
  495. var $errors = $('#errors')
  496. assert.equal($errors.text(), '', 'field was not validated since it was added after the validator was initialized')
  497. form.validator('update')
  498. assert.ok($('#btn').hasClass('disabled'), 'submit was disabled after update because form is now incomplete')
  499. form.validator('validate')
  500. assert.equal($errors.text(), 'error', 'field was validated after a call to .validator(\'update\')')
  501. })
  502. QUnit.test('should respect data-validate attr to force validation on an input', function (assert) {
  503. var inputSelector = $.fn.validator.Constructor.INPUT_SELECTOR
  504. $.fn.validator.Constructor.INPUT_SELECTOR = inputSelector + ':not(.skip-validation)'
  505. var form = '<form>'
  506. + '<div class="form-group">'
  507. + '<input type="text" class="skip-validation" data-error="error" data-validate="true" required>'
  508. + '<div id="validated" class="help-block with-errors"></div>'
  509. + '</div>'
  510. + '<div class="form-group">'
  511. + '<input type="text" data-error="error" data-validate="false" required>'
  512. + '<div id="skipped" class="help-block with-errors"></div>'
  513. + '</div>'
  514. + '<button type="submit">Submit</button>'
  515. + '</form>'
  516. form = $(form)
  517. .appendTo('#qunit-fixture')
  518. .validator('validate')
  519. assert.equal($('#validated').text(), 'error', 'validation of skipped field was forced due to data-validate="true"')
  520. assert.equal($('#skipped').text(), '', 'validation of field was bypassed due to data-validate="false"')
  521. $('[data-validate="true"]').attr('data-validate', false)
  522. form.validator('update')
  523. assert.equal($('#validated').text(), '', 'error is cleared when data-validate="false" and the form is updated')
  524. $.fn.validator.Constructor.INPUT_SELECTOR = inputSelector
  525. })
  526. QUnit.test('should not trim spaces off of the end of input values when running validators', function (assert) {
  527. var form = '<form>'
  528. + '<div class="form-group">'
  529. + '<input type="text" data-error="error" pattern="foo" value="foo " required>'
  530. + '<div id="errors" class="help-block with-errors"></div>'
  531. + '</div>'
  532. + '</form>'
  533. form = $(form)
  534. .appendTo('#qunit-fixture')
  535. .validator('validate')
  536. assert.equal($('#errors').text(), 'error', 'space at the end of input is not being trimmed off')
  537. })
  538. QUnit.test('should re-run match validator on source input change', function (assert) {
  539. var form = '<form>'
  540. + '<div class="form-group">'
  541. + '<input type="text" id="source" value="foo" required>'
  542. + '<div class="help-block with-errors"></div>'
  543. + '</div>'
  544. + '<div class="form-group">'
  545. + '<input type="text" id="confirm" data-error="error" data-match="#source" value="foo" required>'
  546. + '<div id="errors" class="help-block with-errors"></div>'
  547. + '</div>'
  548. + '</form>'
  549. form = $(form)
  550. .appendTo('#qunit-fixture')
  551. .validator('validate')
  552. assert.equal($('#errors').text(), '', 'fields are initially matching')
  553. $('#source').val('bar')
  554. form.validator('validate')
  555. assert.equal($('#errors').text(), 'error', 'error is raised on source change')
  556. })
  557. QUnit.test('should reinitialize plugin on form reset', function (assert) {
  558. var done = assert.async()
  559. var form = '<form>'
  560. + '<div class="form-group">'
  561. + '<input type="text" data-minlength="6">'
  562. + '<div id="errors" class="help-block with-errors"></div>'
  563. + '</div>'
  564. + '</form>'
  565. form = $(form)
  566. .appendTo('#qunit-fixture')
  567. .validator()
  568. form.find('input').val('foo')
  569. form.validator('validate')
  570. form.trigger('reset')
  571. window.setTimeout(function () {
  572. assert.equal($('#errors').text(), '', 'error is cleared on form reset')
  573. done()
  574. }, 0)
  575. })
  576. QUnit.test('should validate select elements', function (assert) {
  577. var form = '<form>'
  578. + '<div class="form-group">'
  579. + '<select required>'
  580. + '<option value=""></option>'
  581. + '<option id="option" value="foo">Foo</option>'
  582. + '</select>'
  583. + '</div>'
  584. + '<button type="submit" id="btn">Submit</button>'
  585. + '</form>'
  586. var $form = $(form)
  587. .appendTo('#qunit-fixture')
  588. .validator('validate')
  589. var $btn = $('#btn')
  590. assert.ok($form.find('.form-group').hasClass('has-error'), '.has-error class is added to form-group')
  591. assert.ok($btn.hasClass('disabled'), 'submit button disabled because form is incomplete')
  592. $('#option').prop('selected', true)
  593. $('select').trigger('input')
  594. assert.ok(!$form.find('.form-group').hasClass('has-error'), '.has-error class is removed from form-group')
  595. assert.ok(!$btn.hasClass('disabled'), 'submit button enabled because form is complete')
  596. })
  597. QUnit.test('should not add .has-error class to the pristine select with required and multiple attribute', function (assert) {
  598. var form = '<form>'
  599. + '<div class="form-group">'
  600. + '<select required multiple>'
  601. + '<option value="foo">Foo</option>'
  602. + '</select>'
  603. + '</div>'
  604. + '</form>'
  605. var $form = $(form)
  606. .appendTo('#qunit-fixture')
  607. .validator()
  608. assert.ok(!$form.find('.form-group').hasClass('has-error'), '.has-error class is not added to form-group')
  609. })
  610. QUnit.test('should not clobber server-side errors', function (assert) {
  611. var form = '<form>'
  612. + '<div class="form-group has-error">'
  613. + '<input type="text" value="foo" required>'
  614. + '<div class="help-block with-errors">server says foo is invalid</div>'
  615. + '</div>'
  616. + '</form>'
  617. var $form = $(form)
  618. .appendTo('#qunit-fixture')
  619. .validator()
  620. assert.ok($form.find('.form-group').hasClass('has-error'), '.has-error class is not removed from form-group')
  621. })
  622. })