to-have-form-values.js 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.toHaveFormValues = toHaveFormValues;
  7. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  8. var _isEqualWith = _interopRequireDefault(require("lodash/isEqualWith"));
  9. var _uniq = _interopRequireDefault(require("lodash/uniq"));
  10. var _css = _interopRequireDefault(require("css.escape"));
  11. var _utils = require("./utils");
  12. // Returns the combined value of several elements that have the same name
  13. // e.g. radio buttons or groups of checkboxes
  14. function getMultiElementValue(elements) {
  15. const types = (0, _uniq.default)(elements.map(element => element.type));
  16. if (types.length !== 1) {
  17. throw new Error('Multiple form elements with the same name must be of the same type');
  18. }
  19. switch (types[0]) {
  20. case 'radio':
  21. {
  22. const theChosenOne = elements.find(radio => radio.checked);
  23. return theChosenOne ? theChosenOne.value : undefined;
  24. }
  25. case 'checkbox':
  26. return elements.filter(checkbox => checkbox.checked).map(checkbox => checkbox.value);
  27. default:
  28. // NOTE: Not even sure this is a valid use case, but just in case...
  29. return elements.map(element => element.value);
  30. }
  31. }
  32. function getFormValue(container, name) {
  33. const elements = [...container.querySelectorAll(`[name="${(0, _css.default)(name)}"]`)];
  34. /* istanbul ignore if */
  35. if (elements.length === 0) {
  36. return undefined; // shouldn't happen, but just in case
  37. }
  38. switch (elements.length) {
  39. case 1:
  40. return (0, _utils.getSingleElementValue)(elements[0]);
  41. default:
  42. return getMultiElementValue(elements);
  43. }
  44. } // Strips the `[]` suffix off a form value name
  45. function getPureName(name) {
  46. return /\[\]$/.test(name) ? name.slice(0, -2) : name;
  47. }
  48. function getAllFormValues(container) {
  49. const names = Array.from(container.elements).map(element => element.name);
  50. return names.reduce((obj, name) => (0, _extends2.default)({}, obj, {
  51. [getPureName(name)]: getFormValue(container, name)
  52. }), {});
  53. }
  54. function toHaveFormValues(formElement, expectedValues) {
  55. (0, _utils.checkHtmlElement)(formElement, toHaveFormValues, this);
  56. if (!formElement.elements) {
  57. // TODO: Change condition to use instanceof against the appropriate element classes instead
  58. throw new Error('toHaveFormValues must be called on a form or a fieldset');
  59. }
  60. const formValues = getAllFormValues(formElement);
  61. return {
  62. pass: Object.entries(expectedValues).every(([name, expectedValue]) => (0, _isEqualWith.default)(formValues[name], expectedValue, _utils.compareArraysAsSet)),
  63. message: () => {
  64. const to = this.isNot ? 'not to' : 'to';
  65. const matcher = `${this.isNot ? '.not' : ''}.toHaveFormValues`;
  66. const commonKeyValues = Object.keys(formValues).filter(key => expectedValues.hasOwnProperty(key)).reduce((obj, key) => (0, _extends2.default)({}, obj, {
  67. [key]: formValues[key]
  68. }), {});
  69. return [this.utils.matcherHint(matcher, 'element', ''), `Expected the element ${to} have form values`, this.utils.diff(expectedValues, commonKeyValues)].join('\n\n');
  70. }
  71. };
  72. }