From 0f7044efcacb41a01c8cd23051e88a4786d4d26f Mon Sep 17 00:00:00 2001 From: what1s1ove Date: Sat, 9 Dec 2023 18:32:45 +0200 Subject: [PATCH] fix: cover uncovered tests areas & fix fieldset nesting & fix datetime input fp-68 --- readme.md | 6 +- ...m-operational-control-elements.constant.js | 5 - src/libs/constants/constants.js | 1 - src/libs/enums/control-type.enum.js | 2 +- .../element-name-to-element-instance.map.js | 6 + src/libs/maps/maps.js | 1 + .../get-form-control-payload.js | 4 +- .../check-is-refer-to-another-node.helper.js | 7 +- .../get-allowed-elements.helper.js | 18 +- tests/get-form-control-payload.test.js | 458 +++++++++++++----- tests/get-form-payload.test.js | 166 +++---- tests/libs/enums/element-name.enum.js | 10 - tests/libs/enums/enums.js | 1 - tests/libs/helpers/create-element.helper.js | 23 - .../helpers/create-form-element.helper.js | 20 - .../helpers/create-label-element.helper.js | 14 - .../helpers/create-options-elements.helper.js | 26 - tests/libs/helpers/helpers.js | 4 - 18 files changed, 440 insertions(+), 332 deletions(-) delete mode 100644 src/libs/constants/banned-form-operational-control-elements.constant.js create mode 100644 src/libs/maps/element-name-to-element-instance.map.js create mode 100644 src/libs/maps/maps.js delete mode 100644 tests/libs/enums/element-name.enum.js delete mode 100644 tests/libs/enums/enums.js delete mode 100644 tests/libs/helpers/create-element.helper.js delete mode 100644 tests/libs/helpers/create-form-element.helper.js delete mode 100644 tests/libs/helpers/create-label-element.helper.js delete mode 100644 tests/libs/helpers/create-options-elements.helper.js delete mode 100644 tests/libs/helpers/helpers.js diff --git a/readme.md b/readme.md index 66dfd32..fe1f1e3 100644 --- a/readme.md +++ b/readme.md @@ -72,6 +72,7 @@ PS. _The library works perfectly with any framework. Just use a valid [HTMLFormE | [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="url"` | ✅ | `string` | | [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="tel"` | ✅ | `string` | | [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="color"` | ✅ | `string` | +| [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="datetime-local"` | ✅ | `string` | | [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="radio"` | ✅ | `string` | | [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="hidden"` | ✅ | `string` | | [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="number"` | ✅ | `number` | @@ -79,7 +80,6 @@ PS. _The library works perfectly with any framework. Just use a valid [HTMLFormE | [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="checkbox"` | ✅ | `boolean` | | [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="date"` | ✅ | [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) | | [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="time"` | ✅ | [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) | -| [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="datetime-local"` | ✅ | [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) | | [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="month"` | ✅ | [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) | | [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="week"` | ✅ | [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) | | [HTMLInputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) | `type="file"` | ✅ | [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) or `null` | @@ -93,7 +93,5 @@ PS. _The library works perfectly with any framework. Just use a valid [HTMLFormE | [HTMLSelectElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement) | `multiple` | ✅ | `Array` | | [HTMLOutputElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLOutputElement) | – | ✅ | `string` | | [HTMLFieldsetElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFieldsetElement) | – | ✅ | `Object` (recursive values of nested elements) | -| [HTMLButtonElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement) | `type="button"` | ❌ | – | -| [HTMLButtonElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement) | `type="submit"` | ❌ | – | -| [HTMLButtonElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement) | `type="reset"` | ❌ | – | +| [HTMLButtonElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement) | – | ❌ | – | | [HTMLObjectElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement) | – | ❌ | – | diff --git a/src/libs/constants/banned-form-operational-control-elements.constant.js b/src/libs/constants/banned-form-operational-control-elements.constant.js deleted file mode 100644 index 6df280d..0000000 --- a/src/libs/constants/banned-form-operational-control-elements.constant.js +++ /dev/null @@ -1,5 +0,0 @@ -const BANNED_FORM_OPERATIONAL_CONTROL_ELEMENTS = /** @type {const} */ ([ - HTMLObjectElement, -]); - -export { BANNED_FORM_OPERATIONAL_CONTROL_ELEMENTS }; diff --git a/src/libs/constants/constants.js b/src/libs/constants/constants.js index ad909f4..36fd675 100644 --- a/src/libs/constants/constants.js +++ b/src/libs/constants/constants.js @@ -1,2 +1 @@ export { BANNED_CONTROL_TYPES } from './banned-control-types.constant.js'; -export { BANNED_FORM_OPERATIONAL_CONTROL_ELEMENTS } from './banned-form-operational-control-elements.constant.js'; diff --git a/src/libs/enums/control-type.enum.js b/src/libs/enums/control-type.enum.js index 418fd2e..488b5b0 100644 --- a/src/libs/enums/control-type.enum.js +++ b/src/libs/enums/control-type.enum.js @@ -6,6 +6,7 @@ const ControlType = /** @type {const} */ ({ URL: 'url', TEL: 'tel', COLOR: 'color', + DATETIME_LOCAL: 'datetime-local', RADIO: 'radio', HIDDEN: 'hidden', @@ -16,7 +17,6 @@ const ControlType = /** @type {const} */ ({ DATE: 'date', TIME: 'time', - DATETIME_LOCAL: 'datetime-local', MONTH: 'month', WEEK: 'week', diff --git a/src/libs/maps/element-name-to-element-instance.map.js b/src/libs/maps/element-name-to-element-instance.map.js new file mode 100644 index 0000000..e20ccfd --- /dev/null +++ b/src/libs/maps/element-name-to-element-instance.map.js @@ -0,0 +1,6 @@ +const bannedElementNameToElementInstance = /** @type {const} */ ({ + button: HTMLButtonElement, + object: HTMLObjectElement, +}); + +export { bannedElementNameToElementInstance }; diff --git a/src/libs/maps/maps.js b/src/libs/maps/maps.js new file mode 100644 index 0000000..4e9b308 --- /dev/null +++ b/src/libs/maps/maps.js @@ -0,0 +1 @@ +export { bannedElementNameToElementInstance } from './element-name-to-element-instance.map.js'; diff --git a/src/packages/get-form-control-payload/get-form-control-payload.js b/src/packages/get-form-control-payload/get-form-control-payload.js index 1c1524f..8d87df5 100644 --- a/src/packages/get-form-control-payload/get-form-control-payload.js +++ b/src/packages/get-form-control-payload/get-form-control-payload.js @@ -57,6 +57,7 @@ const getFormControlPayload = (controlNode) => { case ControlType.URL: case ControlType.TEL: case ControlType.COLOR: + case ControlType.DATETIME_LOCAL: case ControlType.RADIO: case ControlType.HIDDEN: case ControlType.TEXTAREA: @@ -84,7 +85,6 @@ const getFormControlPayload = (controlNode) => { } case ControlType.DATE: case ControlType.TIME: - case ControlType.DATETIME_LOCAL: case ControlType.MONTH: case ControlType.WEEK: { return getInputDateValue( @@ -113,7 +113,7 @@ const getFormControlPayload = (controlNode) => { } throw new FormPayloadError({ - message: 'Unknown control type.', + message: `Unsupported control type – ${controlNode.type}.`, }); }; diff --git a/src/packages/get-form-control-payload/helpers/check-is-refer-to-another-node/check-is-refer-to-another-node.helper.js b/src/packages/get-form-control-payload/helpers/check-is-refer-to-another-node/check-is-refer-to-another-node.helper.js index 4b16a3e..83b2f3e 100644 --- a/src/packages/get-form-control-payload/helpers/check-is-refer-to-another-node/check-is-refer-to-another-node.helper.js +++ b/src/packages/get-form-control-payload/helpers/check-is-refer-to-another-node/check-is-refer-to-another-node.helper.js @@ -8,13 +8,16 @@ */ const checkIsReferToAnotherNode = (currentNode, ...checkNodes) => { return checkNodes.some((checkNode) => { - const hasElements = 'elements' in checkNode; + const hasElements = + 'elements' in checkNode && checkNode.elements.length > 0; if (!hasElements) { return false; } - return Boolean(checkNode.elements.namedItem(currentNode.name)); + return [...checkNode.elements].some((element) => + element.contains(currentNode), + ); }); }; diff --git a/src/packages/get-form-control-payload/helpers/get-allowed-elements/get-allowed-elements.helper.js b/src/packages/get-form-control-payload/helpers/get-allowed-elements/get-allowed-elements.helper.js index 5b0bc7a..e1cb56c 100644 --- a/src/packages/get-form-control-payload/helpers/get-allowed-elements/get-allowed-elements.helper.js +++ b/src/packages/get-form-control-payload/helpers/get-allowed-elements/get-allowed-elements.helper.js @@ -1,7 +1,5 @@ -import { - BANNED_CONTROL_TYPES, - BANNED_FORM_OPERATIONAL_CONTROL_ELEMENTS, -} from '../../../../libs/constants/constants.js'; +import { BANNED_CONTROL_TYPES } from '../../../../libs/constants/constants.js'; +import { bannedElementNameToElementInstance } from '../../../../libs/maps/maps.js'; /** @typedef {import('../../../../libs/types/types.js').HTMLFormControlElement} HTMLFormControlElement */ /** @typedef {import('../../../../libs/types/types.js').HTMLFormOperationalControlElement} HTMLFormOperationalControlElement */ @@ -30,13 +28,13 @@ const checkControlFunctionMap = /** @type {const} */ ({ * @returns {boolean} */ checkIsAllowedElement(element) { - const isObjectNode = BANNED_FORM_OPERATIONAL_CONTROL_ELEMENTS.some( - (node) => { - return element instanceof node; - }, - ); + const isSameNode = Object.values( + bannedElementNameToElementInstance, + ).some((node) => { + return element instanceof node; + }); - return !isObjectNode; + return !isSameNode; }, }); diff --git a/tests/get-form-control-payload.test.js b/tests/get-form-control-payload.test.js index 94863c9..764ebb0 100644 --- a/tests/get-form-control-payload.test.js +++ b/tests/get-form-control-payload.test.js @@ -1,137 +1,222 @@ import { deepEqual, equal, throws } from 'node:assert/strict'; import { beforeEach, describe, test } from 'node:test'; -import { fireEvent, screen, waitFor } from '@testing-library/dom'; +import { fireEvent, waitFor } from '@testing-library/dom'; import { FormPayloadError, getFormControlPayload } from '../src/index.js'; import { ControlType } from '../src/libs/enums/enums.js'; -import { ElementName } from './libs/enums/enums.js'; -import { - createElement, - createLabelElement, - createOptionsElements, -} from './libs/helpers/helpers.js'; describe('getFormControlPayload should work correctly', () => { beforeEach(() => { document.body.innerHTML = ''; }); - describe('should work correctly with texts inputs', () => { - test('should get value from corresponding input type correctly', () => { - const inputs = [ - [ControlType.COLOR, '#999999'], - [ControlType.EMAIL, 'test@mail.com'], - [ControlType.HIDDEN, 'metrics'], + describe('should work with HTMLInputElement correctly', () => { + test('should get value from string inputs correctly', () => { + const inputs = /** @type {const} */ ([ + [ControlType.TEXT, 'Name'], [ControlType.PASSWORD, 'top-secret'], - [ControlType.RADIO, 'color-1'], + [ControlType.EMAIL, 'test@mail.com'], [ControlType.SEARCH, 'apples'], - [ControlType.TEL, '10000000000'], - [ControlType.TEXT, 'Name'], [ControlType.URL, 'form-payload.com'], - [ControlType.OUTPUT, 'empty'], - ]; + [ControlType.TEL, '10000000000'], + [ControlType.COLOR, '#999999'], + [ControlType.DATETIME_LOCAL, '2018-06-12T19:30'], + [ControlType.RADIO, 'color-1'], + [ControlType.HIDDEN, 'metrics'], + ]); for (const [type, value] of inputs) { - document.body.append( - createElement(ElementName.INPUT, { - name: /** @type {string} */ (type), - type: /** @type {string} */ (type), - value: /** @type {string} */ (value), - }), + document.body.innerHTML = /* HTML */ ` +
+ +
+ `; + + const control = /** @type {HTMLInputElement} */ ( + document.querySelector('input') ); - const control = - /** @type {HTMLInputElement | HTMLOutputElement} */ ( - screen.getByDisplayValue(/** @type {string} */ (value)) - ); const controlValue = getFormControlPayload(control); equal(typeof controlValue, 'string'); equal(controlValue, value); + + document.body.innerHTML = ''; } }); - }); - describe('should work correctly with file input', () => { - const INPUT_FILE_LABEL = 'Upload'; + test('should get value from number inputs correctly', () => { + const inputs = /** @type {const} */ ([ + [ControlType.NUMBER, 18], + [ControlType.RANGE, 69], + ]); - test('should get value from input type file correctly', async () => { - const file = [new File(['test-file'], 'test-file')]; + for (const [type, value] of inputs) { + document.body.innerHTML = /* HTML */ ` +
+ +
+ `; + + const control = /** @type {HTMLInputElement} */ ( + document.querySelector('input') + ); - document.body.append( - createLabelElement( - INPUT_FILE_LABEL, - createElement(ElementName.INPUT, { - type: ControlType.FILE, - }), - ), - ); + const controlValue = getFormControlPayload(control); - const control = /** @type {HTMLInputElement} */ ( - screen.getByLabelText(INPUT_FILE_LABEL) - ); + equal(typeof controlValue, 'number'); - equal(getFormControlPayload(control), null); + equal(controlValue, value); - await waitFor(() => - fireEvent.change(control, { - target: { - files: file, - }, - }), - ); + document.body.innerHTML = ''; + } + }); + + test('should get value from boolean inputs correctly', () => { + const inputs = /** @type {const} */ ([ + [ControlType.CHECKBOX, false], + ]); - equal(getFormControlPayload(control) instanceof File, true); + for (const [type, value] of inputs) { + document.body.innerHTML = /* HTML */ ` +
+ +
+ `; + + const control = /** @type {HTMLInputElement} */ ( + document.querySelector('input') + ); + + const controlValue = getFormControlPayload(control); + + equal(typeof controlValue, 'boolean'); + + equal(controlValue, value); + + document.body.innerHTML = ''; + } + }); + + test('should get value from date inputs correctly', () => { + const inputs = /** @type {const} */ ([ + [ControlType.DATE, '1998-08-03'], + [ControlType.TIME, '13:30'], + [ControlType.MONTH, '2001-06'], + [ControlType.WEEK, '2017-W01'], + ]); + + for (const [type, value] of inputs) { + document.body.innerHTML = /* HTML */ ` +
+ +
+ `; + + const control = /** @type {HTMLInputElement} */ ( + document.querySelector('input') + ); + + const controlValue = getFormControlPayload(control); + + equal(controlValue instanceof Date, true); + + document.body.innerHTML = ''; + } }); - test('should get value from multiple input type file correctly', async () => { - const files = [ - new File(['test-file-1'], 'test-file-1'), - new File(['test-file-2'], 'test-file-2'), - ]; - - document.body.append( - createLabelElement( - INPUT_FILE_LABEL, - createElement(ElementName.INPUT, { - multiple: true, - type: ControlType.FILE, + describe('should get value from file inputs correctly', () => { + test('should get value from singular file input correctly', async () => { + const file = [new File(['test-file'], 'test-file')]; + + document.body.innerHTML = /* HTML */ ` +
+ +
+ `; + + const control = /** @type {HTMLInputElement} */ ( + document.querySelector('input') + ); + + equal(getFormControlPayload(control), null); + + await waitFor(() => + fireEvent.change(control, { + target: { + files: file, + }, }), - ), - ); + ); - const control = /** @type {HTMLInputElement} */ ( - screen.getByLabelText(INPUT_FILE_LABEL) - ); + equal(getFormControlPayload(control) instanceof File, true); + }); - equal(Array.isArray(getFormControlPayload(control)), true); + test('should get value from multiple file input correctly', async () => { + const files = [ + new File(['test-file-1'], 'test-file-1'), + new File(['test-file-2'], 'test-file-2'), + ]; - await waitFor(() => - fireEvent.change(control, { - target: { - files, - }, - }), - ); + document.body.innerHTML = /* HTML */ ` +
+ +
+ `; - const controlValue = /** @type {File[]} */ ( - getFormControlPayload(control) - ); + const control = /** @type {HTMLInputElement} */ ( + document.querySelector('input') + ); - equal( - controlValue.every((file) => file instanceof File), - true, - ); + equal(Array.isArray(getFormControlPayload(control)), true); - equal(controlValue.length, controlValue.length); + await waitFor(() => + fireEvent.change(control, { + target: { + files, + }, + }), + ); + + const controlValue = /** @type {File[]} */ ( + getFormControlPayload(control) + ); + + equal( + controlValue.every((file) => file instanceof File), + true, + ); + + equal(controlValue.length, controlValue.length); + }); }); }); - describe('should work correctly with select', () => { - const SELECT_LABEL = 'Colors'; + describe('should work with HTMLTextAreaElement correctly', () => { + test('should get value from HTMLTextAreaElement correctly', () => { + const TEXTAREA_VALUE = 'Hello, World!'; + + document.body.innerHTML = /* HTML */ ` +
+ +
+ `; + + const control = /** @type {HTMLTextAreaElement} */ ( + document.querySelector('textarea') + ); + const controlValue = getFormControlPayload(control); + + equal(typeof controlValue, 'string'); + + equal(controlValue, TEXTAREA_VALUE); + }); + }); + + describe('should work with HTMLSelectElement correctly', () => { const Color = { BLUE: 'blue', RED: 'red', @@ -140,19 +225,30 @@ describe('getFormControlPayload should work correctly', () => { const options = Object.values(Color); - test('should get value from select correctly', () => { + test('should get value from singular select correctly', () => { const selectedValue = Color.RED; - const selectOptions = createOptionsElements(options, selectedValue); - document.body.append( - createLabelElement( - SELECT_LABEL, - createElement(ElementName.SELECT, {}, ...selectOptions), - ), - ); + document.body.innerHTML = /* HTML */ ` +
+ +
+ `; const control = /** @type {HTMLSelectElement} */ ( - screen.getByLabelText(SELECT_LABEL) + document.querySelector('select') ); const controlValue = getFormControlPayload(control); @@ -162,28 +258,30 @@ describe('getFormControlPayload should work correctly', () => { equal(controlValue, selectedValue); }); - test('should get values from multi-select correctly', () => { + test('should get value from multiple select correctly', () => { const selectedValues = [Color.BLUE, Color.RED]; - const selectOptions = createOptionsElements( - options, - ...selectedValues, - ); - document.body.append( - createLabelElement( - SELECT_LABEL, - createElement( - ElementName.SELECT, - { - multiple: true, - }, - ...selectOptions, - ), - ), - ); + document.body.innerHTML = /* HTML */ ` +
+ +
+ `; const control = /** @type {HTMLSelectElement} */ ( - screen.getByLabelText(SELECT_LABEL) + document.querySelector('select') ); const controlValue = getFormControlPayload(control); @@ -199,6 +297,136 @@ describe('getFormControlPayload should work correctly', () => { }); }); + describe('should work with HTMLOutputElement correctly', () => { + test('should get value from HTMLOutputElement correctly', () => { + const OUTPUT_VALUE = 'Hello, World!'; + + document.body.innerHTML = /* HTML */ ` +
+ ${OUTPUT_VALUE} +
+ `; + + const control = /** @type {HTMLOutputElement} */ ( + document.querySelector('output') + ); + + const controlValue = getFormControlPayload(control); + + equal(typeof controlValue, 'string'); + + equal(controlValue, OUTPUT_VALUE); + }); + }); + + describe('should work with HTMLFieldSetElement correctly', () => { + test('should get value from HTMLFieldSetElement correctly', () => { + const BirthdayDate = { + OWN: '1994-06-13', + SCHOOLFRIEND: '1995-03-18', + }; + + const FormPayloadKey = /** @type {const} */ ({ + BESTFRIEND: 'bestfriend', + BESTFRIEND_CHILD: 'child', + BESTFRIEND_CHILD_AGE: 'age', + BESTFRIEND_CHILD_IS_ADULT: 'isAdult', + BESTFRIEND_CHILD_NAME: 'name', + BESTFRIEND_HAS_FRIEND: 'hasFriend', + BESTFRIEND_NAME: 'name', + BIRTHDAY: 'birthday', + NAME: 'name', + SCHOOLFRIEND: 'schoolfriend', + SCHOOLFRIEND_BIRTHDAY: 'birthday', + SCHOOLFRIEND_NAME: 'name', + }); + + const formPayload = { + [FormPayloadKey.BESTFRIEND]: { + [FormPayloadKey.BESTFRIEND_CHILD]: { + [FormPayloadKey.BESTFRIEND_CHILD_AGE]: 18, + [FormPayloadKey.BESTFRIEND_CHILD_IS_ADULT]: true, + [FormPayloadKey.BESTFRIEND_CHILD_NAME]: 'Eva', + }, + [FormPayloadKey.BESTFRIEND_HAS_FRIEND]: true, + [FormPayloadKey.BESTFRIEND_NAME]: 'Jason', + }, + [FormPayloadKey.BIRTHDAY]: new Date(BirthdayDate.OWN), + [FormPayloadKey.NAME]: 'David', + [FormPayloadKey.SCHOOLFRIEND]: { + [FormPayloadKey.SCHOOLFRIEND_BIRTHDAY]: new Date( + BirthdayDate.SCHOOLFRIEND, + ), + [FormPayloadKey.SCHOOLFRIEND_NAME]: 'Ted', + }, + }; + + document.body.innerHTML = /* HTML */ ` +
+ + +
+ + +
+ + + +
+
+
+ + +
+
+ `; + + const control = /** @type {HTMLFieldSetElement} */ ( + document.querySelector('fieldset') + ); + + deepEqual(getFormControlPayload(control), formPayload); + }); + }); + describe('should work correctly with an unexpected control type', () => { test('should throw FormPayloadError with unknown input type', () => { const control = /** @type {HTMLInputElement} */ ({ diff --git a/tests/get-form-payload.test.js b/tests/get-form-payload.test.js index 8d2af42..fe5849a 100644 --- a/tests/get-form-payload.test.js +++ b/tests/get-form-payload.test.js @@ -1,143 +1,121 @@ import { deepEqual } from 'node:assert/strict'; import { beforeEach, describe, test } from 'node:test'; -import { screen } from '@testing-library/dom'; - import { getFormPayload } from '../src/index.js'; import { BANNED_CONTROL_TYPES } from '../src/libs/constants/constants.js'; import { ControlType } from '../src/libs/enums/enums.js'; -import { ElementName } from './libs/enums/enums.js'; -import { createElement, createFormElement } from './libs/helpers/helpers.js'; +import { bannedElementNameToElementInstance } from '../src/libs/maps/maps.js'; describe('getFormPayload should work correctly', () => { beforeEach(() => { document.body.innerHTML = ''; }); - test('should skip banned types', () => { - const bannedElements = BANNED_CONTROL_TYPES.map((type) => { - return createElement(ElementName.INPUT, { - name: type, - type: type, - }); - }); - - document.body.append(createFormElement(...bannedElements)); + test('should skip banned control types', () => { + document.body.innerHTML = /* HTML */ ` +
+ ${BANNED_CONTROL_TYPES.map( + (type) => ``, + ).join(',')} +
+ `; const formNode = /** @type {HTMLFormElement} */ ( - screen.queryByRole('form') + document.querySelector('form') ); deepEqual(getFormPayload(formNode), {}); }); - test('should skip controls without name', () => { - document.body.append( - createFormElement( - createElement(ElementName.INPUT, { - name: '', - }), - ), - ); + test('should skip banned elements', () => { + document.body.innerHTML = /* HTML */ ` +
+ ${Object.keys(bannedElementNameToElementInstance) + .map( + (elementName) => + `<${elementName} type="${elementName}" name="${elementName}">`, + ) + .join(',')} +
+ `; const formNode = /** @type {HTMLFormElement} */ ( - screen.queryByRole('form') + document.querySelector('form') ); deepEqual(getFormPayload(formNode), {}); }); - test('should return the correct object with values', () => { - const FormPayloadKey = /** @type {const} */ ({ - BIRTHDAY: 'birthday', - FRIENDS_COUNT: 'friendsCount', - NAME: 'name', - }); - - const formPayload = { - [FormPayloadKey.BIRTHDAY]: new Date('1992-06-13'), - [FormPayloadKey.FRIENDS_COUNT]: 3, - [FormPayloadKey.NAME]: 'Brad', - }; - - document.body.append( - createFormElement( - createElement(ElementName.INPUT, { - name: FormPayloadKey.NAME, - type: ControlType.TEXT, - value: formPayload.name, - }), - createElement(ElementName.INPUT, { - name: FormPayloadKey.FRIENDS_COUNT, - type: ControlType.NUMBER, - valueAsNumber: formPayload.friendsCount, - }), - createElement(ElementName.INPUT, { - name: FormPayloadKey.BIRTHDAY, - type: ControlType.DATE, - valueAsDate: formPayload.birthday, - }), - ), - ); + test('should skip controls without name', () => { + document.body.innerHTML = /* HTML */ ` +
+ +
+ `; const formNode = /** @type {HTMLFormElement} */ ( - screen.queryByRole('form') + document.querySelector('form') ); - deepEqual(getFormPayload(formNode), formPayload); + deepEqual(getFormPayload(formNode), {}); }); - test('should return the correct nested object with values', () => { + test('should return the correct object with values', () => { + const BIRTHDAY_DATE = '1992-06-13'; + const FormPayloadKey = /** @type {const} */ ({ BIRTHDAY: 'birthday', FRIENDS_COUNT: 'friendsCount', + HAS_FRIENDS: 'hasFriends', MAIN_FRIEND: 'mainFriend', - MAIN_FRIEND_NAME: 'friendName', + MAIN_FRIEND_NAME: 'name', NAME: 'name', }); const formPayload = { - [FormPayloadKey.BIRTHDAY]: new Date('1994-06-13'), - [FormPayloadKey.FRIENDS_COUNT]: 2, + [FormPayloadKey.BIRTHDAY]: new Date(BIRTHDAY_DATE), + [FormPayloadKey.FRIENDS_COUNT]: 3, + [FormPayloadKey.HAS_FRIENDS]: true, [FormPayloadKey.MAIN_FRIEND]: { - [FormPayloadKey.MAIN_FRIEND_NAME]: 'Jason', + [FormPayloadKey.MAIN_FRIEND_NAME]: 'John', }, - [FormPayloadKey.NAME]: 'David', + [FormPayloadKey.NAME]: 'Brad', }; - document.body.append( - createFormElement( - createElement(ElementName.INPUT, { - name: FormPayloadKey.NAME, - type: ControlType.TEXT, - value: formPayload.name, - }), - createElement(ElementName.INPUT, { - name: FormPayloadKey.FRIENDS_COUNT, - type: ControlType.NUMBER, - valueAsNumber: formPayload.friendsCount, - }), - createElement(ElementName.INPUT, { - name: FormPayloadKey.BIRTHDAY, - type: ControlType.DATE, - valueAsDate: formPayload.birthday, - }), - createElement( - ElementName.FIELDSET, - { - name: FormPayloadKey.MAIN_FRIEND, - }, - createElement(ElementName.INPUT, { - name: FormPayloadKey.MAIN_FRIEND_NAME, - type: ControlType.TEXT, - value: formPayload.mainFriend.friendName, - }), - ), - ), - ); + document.body.innerHTML = /* HTML */ ` +
+ + + + +
+ +
+
+ `; const formNode = /** @type {HTMLFormElement} */ ( - screen.queryByRole('form') + document.querySelector('form') ); deepEqual(getFormPayload(formNode), formPayload); diff --git a/tests/libs/enums/element-name.enum.js b/tests/libs/enums/element-name.enum.js deleted file mode 100644 index 12fb8eb..0000000 --- a/tests/libs/enums/element-name.enum.js +++ /dev/null @@ -1,10 +0,0 @@ -const ElementName = /** @type {const} */ ({ - FIELDSET: 'fieldset', - FORM: 'form', - INPUT: 'input', - LABEL: 'label', - OPTION: 'option', - SELECT: 'select', -}); - -export { ElementName }; diff --git a/tests/libs/enums/enums.js b/tests/libs/enums/enums.js deleted file mode 100644 index a7bcf60..0000000 --- a/tests/libs/enums/enums.js +++ /dev/null @@ -1 +0,0 @@ -export { ElementName } from './element-name.enum.js'; diff --git a/tests/libs/helpers/create-element.helper.js b/tests/libs/helpers/create-element.helper.js deleted file mode 100644 index 0e0e746..0000000 --- a/tests/libs/helpers/create-element.helper.js +++ /dev/null @@ -1,23 +0,0 @@ -/** @typedef {import('../../../src/libs/types/types.js').HTMLFormOperationalControlElement} HTMLFormOperationalControlElement */ - -/** - * @param {string} tagName - * @param {Partial} properties - * @param {...(HTMLElement | string)} children - * @returns {HTMLElement} - */ -const createElement = (tagName, properties, ...children) => { - const element = document.createElement(tagName); - - if (properties) { - Object.assign(element, properties); - } - - for (const child of children) { - element.append(child); - } - - return element; -}; - -export { createElement }; diff --git a/tests/libs/helpers/create-form-element.helper.js b/tests/libs/helpers/create-form-element.helper.js deleted file mode 100644 index 951557b..0000000 --- a/tests/libs/helpers/create-form-element.helper.js +++ /dev/null @@ -1,20 +0,0 @@ -import { ElementName } from '../../libs/enums/enums.js'; -import { createElement } from './create-element.helper.js'; - -/** - * @param {...(HTMLElement | string)} children - * @returns {HTMLFormElement} - */ -const createFormElement = (...children) => { - return /** @type {HTMLFormElement} */ ( - createElement( - ElementName.FORM, - { - name: '', - }, - ...children, - ) - ); -}; - -export { createFormElement }; diff --git a/tests/libs/helpers/create-label-element.helper.js b/tests/libs/helpers/create-label-element.helper.js deleted file mode 100644 index 112dc24..0000000 --- a/tests/libs/helpers/create-label-element.helper.js +++ /dev/null @@ -1,14 +0,0 @@ -import { ElementName } from '../../libs/enums/enums.js'; -import { createElement } from './create-element.helper.js'; - -/** - * @param {...(HTMLElement | string)} children - * @returns {HTMLLabelElement} - */ -const createLabelElement = (...children) => { - return /** @type {HTMLLabelElement} */ ( - createElement(ElementName.LABEL, {}, ...children) - ); -}; - -export { createLabelElement }; diff --git a/tests/libs/helpers/create-options-elements.helper.js b/tests/libs/helpers/create-options-elements.helper.js deleted file mode 100644 index 59a7bb0..0000000 --- a/tests/libs/helpers/create-options-elements.helper.js +++ /dev/null @@ -1,26 +0,0 @@ -import { ElementName } from '../../libs/enums/enums.js'; -import { createElement } from './create-element.helper.js'; - -/** - * @param {string[]} options - * @param {...string} selectedOptions - * @returns {HTMLOptionElement[]} - */ -const createOptionsElements = (options, ...selectedOptions) => { - return /** @type {HTMLOptionElement[]} */ ( - options.map((opt) => { - const isSelected = selectedOptions.includes(opt); - - return createElement( - ElementName.OPTION, - { - selected: isSelected, - value: opt, - }, - opt, - ); - }) - ); -}; - -export { createOptionsElements }; diff --git a/tests/libs/helpers/helpers.js b/tests/libs/helpers/helpers.js deleted file mode 100644 index 763369d..0000000 --- a/tests/libs/helpers/helpers.js +++ /dev/null @@ -1,4 +0,0 @@ -export { createElement } from './create-element.helper.js'; -export { createFormElement } from './create-form-element.helper.js'; -export { createLabelElement } from './create-label-element.helper.js'; -export { createOptionsElements } from './create-options-elements.helper.js';