Extract and set form values through the DOM—no frameworks required! https://github.com/TheoryOfNekomata/formxtra
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 

677 行
19 KiB

  1. import getFormValuesDeprecated, {
  2. getFormValues,
  3. setFormValues,
  4. isFieldElement,
  5. isElementValueIncludedInFormSubmit,
  6. getValue,
  7. } from '../../src';
  8. import * as utils from '../utils'
  9. describe('misc', () => {
  10. describe('core', () => {
  11. beforeEach(utils.setup(`
  12. <!DOCTYPE html>
  13. <html lang="en-PH">
  14. <head>
  15. <meta charset="UTF-8">
  16. <title>Misc/Blank</title>
  17. </head>
  18. <body>
  19. <form>
  20. <button type="submit">Submit</button>
  21. </form>
  22. </body>
  23. </html>
  24. `))
  25. it('should call console.warn for deprecated default import usage', () => {
  26. utils.test({
  27. action: (cy: any) => cy.get('[type="submit"]'),
  28. test: (form: HTMLFormElement, submitter: any, search: any) => {
  29. let consoleWarnCalled = false
  30. const defaultConsoleWarn = console.warn
  31. console.warn = (...args: unknown[]) => {
  32. consoleWarnCalled = true
  33. };
  34. getFormValuesDeprecated(form, { submitter });
  35. expect(consoleWarnCalled).toBe(true);
  36. console.warn = defaultConsoleWarn;
  37. },
  38. });
  39. });
  40. it('should throw an error when providing invalid argument type as form to getFormValues', () => {
  41. utils.test({
  42. action: (cy: any) => cy.get('[type="submit"]'),
  43. test: (form: HTMLFormElement, submitter: any, search: any) => {
  44. let isThrown = false;
  45. try {
  46. getFormValues(0 as unknown as HTMLFormElement, {});
  47. } catch {
  48. isThrown = true;
  49. }
  50. expect(isThrown).toBe(true);
  51. },
  52. });
  53. });
  54. it('should throw an error when providing null as form to getFormValues', () => {
  55. utils.test({
  56. action: (cy: any) => cy.get('[type="submit"]'),
  57. test: (form: HTMLFormElement, submitter: any, search: any) => {
  58. let isThrown = false;
  59. try {
  60. getFormValues(null as unknown as HTMLFormElement, {});
  61. } catch {
  62. isThrown = true;
  63. }
  64. expect(isThrown).toBe(true);
  65. },
  66. });
  67. });
  68. it('should throw an error when providing a different element type as form to getFormValues', () => {
  69. utils.test({
  70. action: (cy: any) => cy.get('[type="submit"]'),
  71. test: (form: HTMLFormElement, submitter: any, search: any) => {
  72. let isThrown = false;
  73. try {
  74. getFormValues(document.body as unknown as HTMLFormElement, {});
  75. } catch {
  76. isThrown = true;
  77. }
  78. expect(isThrown).toBe(true);
  79. },
  80. });
  81. });
  82. it('should throw an error when providing invalid argument type as form to setFormValues', () => {
  83. utils.test({
  84. action: (cy: any) => cy.get('[type="submit"]'),
  85. test: (form: HTMLFormElement, submitter: any, search: any) => {
  86. let isThrown = false;
  87. try {
  88. setFormValues(0 as unknown as HTMLFormElement, {});
  89. } catch {
  90. isThrown = true;
  91. }
  92. expect(isThrown).toBe(true);
  93. },
  94. });
  95. });
  96. it('should throw an error when providing null as form to setFormValues', () => {
  97. utils.test({
  98. action: (cy: any) => cy.get('[type="submit"]'),
  99. test: (form: HTMLFormElement, submitter: any, search: any) => {
  100. let isThrown = false;
  101. try {
  102. setFormValues(null as unknown as HTMLFormElement, {});
  103. } catch {
  104. isThrown = true;
  105. }
  106. expect(isThrown).toBe(true);
  107. },
  108. });
  109. });
  110. it('should throw an error when providing a different element type as form to setFormValues', () => {
  111. utils.test({
  112. action: (cy: any) => cy.get('[type="submit"]'),
  113. test: (form: HTMLFormElement, submitter: any, search: any) => {
  114. let isThrown = false;
  115. try {
  116. setFormValues(document.body as unknown as HTMLFormElement, {});
  117. } catch {
  118. isThrown = true;
  119. }
  120. expect(isThrown).toBe(true);
  121. },
  122. });
  123. });
  124. it('should throw an error when providing invalid argument type as values to setFormValues', () => {
  125. utils.test({
  126. action: (cy: any) => cy.get('[type="submit"]'),
  127. test: (form: HTMLFormElement, submitter: any, search: any) => {
  128. let isThrown = false;
  129. try {
  130. setFormValues(form, 0);
  131. } catch {
  132. isThrown = true;
  133. }
  134. expect(isThrown).toBe(true);
  135. },
  136. });
  137. });
  138. it('should not throw an error when providing null as form to setFormValues', () => {
  139. utils.test({
  140. action: (cy: any) => cy.get('[type="submit"]'),
  141. test: (form: HTMLFormElement, submitter: any, search: any) => {
  142. let isThrown = false;
  143. try {
  144. setFormValues(form, null);
  145. } catch (e) {
  146. isThrown = true;
  147. }
  148. expect(isThrown).toBe(false);
  149. },
  150. });
  151. });
  152. it('should throw an error when providing undefined as form to setFormValues', () => {
  153. utils.test({
  154. action: (cy: any) => cy.get('[type="submit"]'),
  155. test: (form: HTMLFormElement, submitter: any, search: any) => {
  156. let isThrown = false;
  157. try {
  158. setFormValues(form, undefined);
  159. } catch (e) {
  160. isThrown = true;
  161. }
  162. expect(isThrown).toBe(true);
  163. },
  164. });
  165. });
  166. });
  167. describe('utilities', () => {
  168. beforeEach(utils.setup(`
  169. <!DOCTYPE html>
  170. <html lang="en-PH">
  171. <head>
  172. <meta charset="UTF-8">
  173. <title>Misc/Utilities</title>
  174. </head>
  175. <body>
  176. <form>
  177. <input id="input" type="text" name="foobar" />
  178. <input id="notField" type="text" />
  179. <input id="disabled" disabled type="text" name="disabled" />
  180. <meter id="meter" min="1" max="10" value="5" />
  181. <button type="submit">Submit</button>
  182. </form>
  183. </body>
  184. </html>
  185. `));
  186. it('should check for valid field elements value', () => {
  187. utils.test({
  188. action: (cy: any) => cy.get('[type="submit"]'),
  189. test: (form: HTMLFormElement, submitter: any, search: any) => {
  190. const meter = document.getElementById('meter');
  191. expect(getValue(meter)).toBe(5);
  192. },
  193. });
  194. });
  195. it('should check for invalid field elements value', () => {
  196. utils.test({
  197. action: (cy: any) => cy.get('[type="submit"]'),
  198. test: (form: HTMLFormElement, submitter: any, search: any) => {
  199. expect(getValue(document.body)).toBe(null);
  200. },
  201. });
  202. });
  203. it('should check for elements as included fields', () => {
  204. utils.test({
  205. action: (cy: any) => cy.get('[type="submit"]'),
  206. test: (form: HTMLFormElement, submitter: any, search: any) => {
  207. const input = document.getElementById('input');
  208. expect(isElementValueIncludedInFormSubmit(input)).toBe(true);
  209. },
  210. });
  211. });
  212. it('should check for elements as excluded fields', () => {
  213. utils.test({
  214. action: (cy: any) => cy.get('[type="submit"]'),
  215. test: (form: HTMLFormElement, submitter: any, search: any) => {
  216. const notField = document.getElementById('notField');
  217. expect(isElementValueIncludedInFormSubmit(notField)).toBe(false);
  218. const disabled = document.getElementById('disabled');
  219. expect(isElementValueIncludedInFormSubmit(disabled)).toBe(false);
  220. const meter = document.getElementById('meter');
  221. expect(isElementValueIncludedInFormSubmit(meter)).toBe(false);
  222. },
  223. });
  224. });
  225. it('should check for elements as valid for fields', () => {
  226. utils.test({
  227. action: (cy: any) => cy.get('[type="submit"]'),
  228. test: (form: HTMLFormElement, submitter: any, search: any) => {
  229. const input = document.getElementById('input');
  230. expect(isFieldElement(input)).toBe(true);
  231. const disabled = document.getElementById('disabled');
  232. expect(isFieldElement(disabled)).toBe(true);
  233. },
  234. });
  235. });
  236. it('should check for elements as invalid for fields', () => {
  237. utils.test({
  238. action: (cy: any) => cy.get('[type="submit"]'),
  239. test: (form: HTMLFormElement, submitter: any, search: any) => {
  240. const meter = document.getElementById('meter');
  241. expect(isFieldElement(meter)).toBe(false);
  242. const notField = document.getElementById('notField');
  243. expect(isFieldElement(notField)).toBe(false);
  244. },
  245. });
  246. });
  247. });
  248. describe('setting values', () => {
  249. beforeEach(utils.setup(`
  250. <!DOCTYPE html>
  251. <html lang="en-PH">
  252. <head>
  253. <meta charset="UTF-8">
  254. <title>Misc/Blank</title>
  255. </head>
  256. <body>
  257. <form>
  258. <input type="text" name="foobar" />
  259. <button type="submit">Submit</button>
  260. </form>
  261. </body>
  262. </html>
  263. `))
  264. it('should parse string values for setFormValues', () => {
  265. utils.test({
  266. action: (cy: any) => cy.get('[type="submit"]'),
  267. test: (form: HTMLFormElement, submitter: any, search: any) => {
  268. let isThrown = false;
  269. try {
  270. setFormValues(form, 'foobar=baz');
  271. } catch (e) {
  272. isThrown = true;
  273. }
  274. expect(isThrown).toBe(false);
  275. expect(getFormValues(form)).toEqual({ foobar: 'baz', });
  276. },
  277. })
  278. });
  279. it('should parse entries values for setFormValues', () => {
  280. utils.test({
  281. action: (cy: any) => cy.get('[type="submit"]'),
  282. test: (form: HTMLFormElement, submitter: any, search: any) => {
  283. let isThrown = false;
  284. try {
  285. setFormValues(form, [['foobar', 'baz']]);
  286. } catch (e) {
  287. isThrown = true;
  288. }
  289. expect(isThrown).toBe(false);
  290. expect(getFormValues(form)).toEqual({ foobar: 'baz', });
  291. },
  292. })
  293. });
  294. it('should parse URLSearchParams values for setFormValues', () => {
  295. utils.test({
  296. action: (cy: any) => cy.get('[type="submit"]'),
  297. test: (form: HTMLFormElement, submitter: any, search: any) => {
  298. let isThrown = false;
  299. try {
  300. setFormValues(form, new URLSearchParams('foobar=baz'));
  301. } catch (e) {
  302. isThrown = true;
  303. }
  304. expect(isThrown).toBe(false);
  305. expect(getFormValues(form)).toEqual({ foobar: 'baz', });
  306. },
  307. })
  308. });
  309. it('should parse object values for setFormValues', () => {
  310. utils.test({
  311. action: (cy: any) => cy.get('[type="submit"]'),
  312. test: (form: HTMLFormElement, submitter: any, search: any) => {
  313. let isThrown = false;
  314. try {
  315. setFormValues(form, { foobar: 'baz', });
  316. } catch (e) {
  317. isThrown = true;
  318. }
  319. expect(isThrown).toBe(false);
  320. expect(getFormValues(form)).toEqual({ foobar: 'baz', });
  321. },
  322. })
  323. });
  324. });
  325. describe('duplicates', () => {
  326. beforeEach(utils.setup(`
  327. <!DOCTYPE html>
  328. <html lang="en-PH">
  329. <head>
  330. <meta charset="UTF-8">
  331. <title>Misc/Blank</title>
  332. </head>
  333. <body>
  334. <form>
  335. <input type="text" name="foobar" />
  336. <input type="text" name="foobar" />
  337. <input type="text" name="foobar" />
  338. <button type="submit">Submit</button>
  339. </form>
  340. </body>
  341. </html>
  342. `));
  343. it('should parse duplicates correctly', () => {
  344. utils.test({
  345. preAction: (form: HTMLFormElement) => {
  346. setFormValues(form, { foobar: ['foo', 'bar', 'baz']})
  347. },
  348. action: (cy: any) => cy.get('[type="submit"]'),
  349. test: (form: HTMLFormElement, submitter: any, search: any) => {
  350. expect(getFormValues(form)).toEqual({ foobar: ['foo', 'bar', 'baz'], });
  351. },
  352. })
  353. });
  354. });
  355. describe('blank', () => {
  356. beforeEach(utils.setup(`
  357. <!DOCTYPE html>
  358. <html lang="en-PH">
  359. <head>
  360. <meta charset="UTF-8">
  361. <title>Misc/Blank</title>
  362. </head>
  363. <body>
  364. <form>
  365. <button type="submit">Submit</button>
  366. </form>
  367. </body>
  368. </html>
  369. `))
  370. it('should have blank form value', () => {
  371. utils.test({
  372. action: (cy: any) => cy.get('[type="submit"]'),
  373. test: (form: HTMLFormElement, submitter: any, search: any) => {
  374. const before = utils.makeSearchParams(getFormValues(form, { submitter }))
  375. .toString();
  376. const after = utils.makeSearchParams(search)
  377. .toString();
  378. expect(before)
  379. .toEqual(after);
  380. },
  381. expectedStaticValue: {},
  382. });
  383. });
  384. })
  385. describe('everything', () => {
  386. beforeEach(utils.setup(`
  387. <!DOCTYPE html>
  388. <html lang="en-PH">
  389. <head>
  390. <meta charset="UTF-8">
  391. <title>Misc/Everything</title>
  392. </head>
  393. <body>
  394. <article>
  395. <h2></h2>
  396. <form>
  397. <fieldset>
  398. <legend>Name</legend>
  399. <div>
  400. <input type="text" placeholder="First Name" name="first_name" />
  401. </div>
  402. <div>
  403. <input type="text" placeholder="Middle Name" name="middle_name" />
  404. </div>
  405. <div>
  406. <input type="text" placeholder="Last Name" name="last_name" />
  407. </div>
  408. </fieldset>
  409. <fieldset>
  410. <legend>Gender</legend>
  411. <div>
  412. <label>
  413. <input type="radio" name="gender" value="m" />
  414. Male
  415. </label>
  416. <label>
  417. <input type="radio" name="gender" value="f" />
  418. Female
  419. </label>
  420. </div>
  421. </fieldset>
  422. <fieldset>
  423. <legend>Birthday</legend>
  424. <div>
  425. <input type="date" placeholder="Birthday" name="birthday" />
  426. </div>
  427. </fieldset>
  428. <fieldset>
  429. <legend>Civil Status</legend>
  430. <div>
  431. <select name="civil_status">
  432. <option value="">Select Civil Status</option>
  433. <option value="single">Single</option>
  434. <option value="married">Married</option>
  435. <option value="divorced">Divorced</option>
  436. <option value="separated">Separated</option>
  437. </select>
  438. </div>
  439. </fieldset>
  440. <fieldset>
  441. <legend>New Registration</legend>
  442. <div>
  443. <label>
  444. <input type="checkbox" name="new_registration" />
  445. New Registration
  446. </label>
  447. </div>
  448. </fieldset>
  449. <fieldset>
  450. <legend>Last Appointment Date</legend>
  451. <div>
  452. <input type="datetime-local" placeholder="Last Appointment Date" name="last_appointment_datetime" />
  453. </div>
  454. </fieldset>
  455. <fieldset>
  456. <legend>New Appointment Week</legend>
  457. <div>
  458. <input type="week" placeholder="New Appointment Week" name="new_appointment_week" />
  459. </div>
  460. </fieldset>
  461. <fieldset>
  462. <legend>Start Month</legend>
  463. <div>
  464. <input type="month" placeholder="Start Month" name="start_month" />
  465. </div>
  466. </fieldset>
  467. <div>
  468. <label>
  469. <input type="checkbox" value="filipino" name="nationality" />
  470. Filipino
  471. </label>
  472. </div>
  473. <div>
  474. <input type="number" placeholder="Gross Salary" name="gross" />
  475. </div>
  476. <fieldset>
  477. <legend>
  478. Default Dependents
  479. </legend>
  480. <div>
  481. <label>
  482. <input type="radio" value="James" name="dependent" />
  483. James
  484. </label>
  485. <label>
  486. <input type="radio" value="Jun" name="dependent" />
  487. Jun
  488. </label>
  489. </div>
  490. </fieldset>
  491. <div>
  492. <button type="button" class="dependents">
  493. Add Dependents
  494. </button>
  495. </div>
  496. <div>
  497. <textarea name="notes" placeholder="Notes"></textarea>
  498. </div>
  499. <fieldset>
  500. <legend>
  501. Quality of Service
  502. </legend>
  503. <input type="range" min="0" max="10" step="0.5" placeholder="Quality of Service" name="qos" />
  504. </fieldset>
  505. <div>
  506. <button name="submit" value="Hello" type="submit">Hello</button>
  507. <button name="submit" value="Hi" type="submit">Hi</button>
  508. </div>
  509. </form>
  510. </article>
  511. <script>
  512. Array.from(document.getElementsByClassName('dependents')).forEach(d => {
  513. d.addEventListener('click', e => {
  514. const container = document.createElement('div')
  515. const input = document.createElement('input')
  516. input.name = 'dependent'
  517. input.type = 'text'
  518. input.placeholder = 'Dependent'
  519. container.classList.add('additional-dependent')
  520. container.appendChild(input)
  521. e.target.parentElement.parentElement.insertBefore(container, e.target.parentElement)
  522. })
  523. })
  524. </script>
  525. </body>
  526. </html>
  527. `))
  528. it('should have correct form values', () => {
  529. utils.test({
  530. action: (cy) => {
  531. cy.get('[name="first_name"]')
  532. .type('John')
  533. cy.get('[name="middle_name"]')
  534. .type('Marcelo')
  535. cy.get('[name="last_name"]')
  536. .type('Dela Cruz')
  537. cy.get('[name="gender"][value="m"]')
  538. .check()
  539. cy.get('[name="birthday"]')
  540. .type('1989-06-04')
  541. cy.get('[name="civil_status"]')
  542. .select('Married')
  543. cy.get('[name="new_registration"]')
  544. .check()
  545. cy.get('[name="last_appointment_datetime"]')
  546. .type('2001-09-11T06:09')
  547. cy.get('[name="new_appointment_week"]')
  548. .type('2001-W51')
  549. cy.get('[name="start_month"]')
  550. .type('2002-03')
  551. cy.get('[name="nationality"][value="filipino"]')
  552. .check()
  553. cy.get('[name="gross"]')
  554. .type('131072')
  555. cy.get('[name="dependent"][value="Jun"]')
  556. .check()
  557. cy.get('button.dependents')
  558. .click()
  559. cy.get('.additional-dependent [name="dependent"][type="text"]')
  560. .last()
  561. .type('Juana')
  562. cy.get('button.dependents')
  563. .click()
  564. cy.get('.additional-dependent [name="dependent"][type="text"]')
  565. .last()
  566. .type('Jane')
  567. cy.get('button.dependents')
  568. .click()
  569. cy.get('.additional-dependent [name="dependent"][type="text"]')
  570. .last()
  571. .type('Josh')
  572. cy.get('[name="qos"]')
  573. .invoke('val', 9.5)
  574. .trigger('change')
  575. cy.get('[name="notes"]')
  576. .type('Test content\n\nNew line\n\nAnother line')
  577. return cy.get('[name="submit"][value="Hi"]')
  578. },
  579. test: (form: HTMLFormElement, submitter: any, search: any) => {
  580. const before = utils.makeSearchParams(getFormValues(form, { submitter }))
  581. .toString();
  582. const after = utils.makeSearchParams(search)
  583. .toString();
  584. expect(before)
  585. .toEqual(after);
  586. },
  587. expectedStaticValue: 'first_name=John&middle_name=Marcelo&last_name=Dela+Cruz&gender=m&birthday=1989-06-04&civil_status=married&new_registration=on&last_appointment_datetime=2001-09-11T06%3A09&new_appointment_week=2001-W51&start_month=2002-03&nationality=filipino&gross=131072&dependent=Jun&notes=Test+content%0D%0A%0D%0ANew+line%0D%0A%0D%0AAnother+line&qos=9.5&submit=Hi',
  588. });
  589. });
  590. it('should have filled form values', () => {
  591. utils.test({
  592. action: (cy) => cy.wait(3000).get('[name="submit"][value="Hi"]'),
  593. test: (form: HTMLFormElement, submitter: any, search: any) => {
  594. const before = utils.makeSearchParams(getFormValues(form, { submitter }))
  595. .toString();
  596. const after = utils.makeSearchParams(search)
  597. .toString();
  598. expect(before)
  599. .toEqual(after);
  600. },
  601. preAction: (form: HTMLFormElement) => {
  602. setFormValues(form, {
  603. first_name: 'John',
  604. middle_name: 'Marcelo',
  605. last_name: 'Dela Cruz',
  606. gender: 'm',
  607. birthday: new Date('1989-06-04'),
  608. civil_status: 'married',
  609. new_registration: 'on',
  610. last_appointment_datetime: new Date('2001-09-11T06:09:00'),
  611. new_appointment_week: '2001-W51',
  612. start_month: '2002-03',
  613. nationality: 'filipino',
  614. gross: 131072,
  615. dependent: 'Jun',
  616. notes: `Test content
  617. New line
  618. Another line`,
  619. qos: 9.5,
  620. });
  621. },
  622. expectedStaticValue: 'first_name=John&middle_name=Marcelo&last_name=Dela+Cruz&gender=m&birthday=1989-06-04&civil_status=married&new_registration=on&last_appointment_datetime=2001-09-11T06%3A09&new_appointment_week=2001-W51&start_month=2002-03&nationality=filipino&gross=131072&dependent=Jun&notes=Test+content%0D%0A%0D%0ANew+line%0D%0A%0D%0AAnother+line&qos=9.5&submit=Hi',
  623. });
  624. });
  625. });
  626. // TODO implement tests for multiple values
  627. });