Skip to content

Commit

Permalink
Fixed tests
Browse files Browse the repository at this point in the history
Added options
  • Loading branch information
serbanghita committed Dec 18, 2023
1 parent 879c2ee commit 91c9387
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 86 deletions.
22 changes: 18 additions & 4 deletions src/FormToObject.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {HTMLFormField, IFormToObjectOptions, NodeResult} from "./types";
import {
getAllFormElementsAsArray,
isCheckbox,
isChecked,
isDomElementNode,
Expand All @@ -17,9 +18,18 @@ export class FormToObject {
public $form: HTMLFormElement | null = null;
public $formElements: HTMLFormField[] = [];

// Experimental. Don't rely on them yet.
public settings = {
includeEmptyValuedElements: false,
/**
* It doesn't make sense to include submit buttons,
* but if the use-case requires, we keep this option open.
*/
includeSubmitButton: false,
/**
* By default, we don't include key:value pair from disabled fields.
*
*/
includeDisabledFields: false,
w3cSuccessfulControlsOnly: false,
/**
* In case of a multiple select, e.g. <select name="multiple[]" multiple>
Expand Down Expand Up @@ -79,7 +89,7 @@ export class FormToObject {
if (typeof this.formSelector === 'string') {
this.$form = document.getElementById(this.formSelector) as HTMLFormElement;
return isDomElementNode(this.$form);
} else if (isDomElementNode(this.formSelector)) { // @todo: Should I check for DOM.nodeType?
} else if (isDomElementNode(this.formSelector)) {
this.$form = this.formSelector as HTMLFormElement;
return true;
}
Expand All @@ -89,7 +99,8 @@ export class FormToObject {

// Set the elements we need to parse.
public initFormElements(): boolean {
this.$formElements = [...(this.$form?.querySelectorAll('input, textarea, select') as NodeListOf<HTMLFormField>)];
// Note: https://caniuse.com/?search=querySelectorAll
this.$formElements = getAllFormElementsAsArray(this.$form as HTMLFormElement);
return this.$formElements.length > 0;
}

Expand All @@ -109,7 +120,7 @@ export class FormToObject {
if (
!$domNode.name ||
$domNode.name === '' ||
$domNode.disabled ||
($domNode.disabled && !this.settings.includeDisabledFields) ||
(isRadio($domNode as HTMLInputElement) && !isChecked($domNode as HTMLInputElement))
) {
continue;
Expand Down Expand Up @@ -231,6 +242,9 @@ export class FormToObject {

// We're only interested if the button is type="submit"
if (isSubmitButton($domNode as HTMLButtonElement)) {
if (!this.settings.includeSubmitButton) {
return false;
}
if (($domNode as HTMLButtonElement).value && ($domNode as HTMLButtonElement).value !== '') {
return ($domNode as HTMLButtonElement).value;
}
Expand Down
25 changes: 24 additions & 1 deletion src/dom.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
import {HTMLFormField} from "./types";

/**
* Extract an array with all the DOM fields representing form fields.
* Make sure we are backward compatible with older browsers.
*
* @param $form
*/
export function getAllFormElementsAsArray($form: HTMLFormElement) {
if ('querySelectorAll' in $form) {
return [...($form?.querySelectorAll('input, textarea, select') as NodeListOf<HTMLFormField>)];
} else if ('getElementsByTagName' in $form) {
return [
// @ts-expect-error for older browsers
...$form.getElementsByTagName('input'),
// @ts-expect-error for older browsers
[...$form.getElementsByTagName('textarea')],
// @ts-expect-error for older browsers
...$form.getElementsByTagName('select')
];
}

throw new Error('The <form> is either not a valid DOM element or the browser is very old.');
}

/**
* Check to see if the object is an HTML node.
*
Expand Down Expand Up @@ -39,7 +62,7 @@ export function isSelectMultiple($domNode: HTMLFormField) {
}

export function isSubmitButton($domNode: HTMLButtonElement) {
return $domNode.nodeName === 'BUTTON' && $domNode.type === 'submit';
return ($domNode.nodeName === 'BUTTON' || $domNode.nodeName === 'INPUT') && $domNode.type === 'submit';
}

export function isChecked($domNode: HTMLInputElement) {
Expand Down
37 changes: 0 additions & 37 deletions test/integration/exceptions.test.ts

This file was deleted.

12 changes: 0 additions & 12 deletions test/integration/textarea.test.ts

This file was deleted.

32 changes: 0 additions & 32 deletions test/integration/unexpected.test.ts

This file was deleted.

6 changes: 6 additions & 0 deletions test/manual/playground.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@
<label><input type="checkbox" name="checkboxGroup[]" value="option1" id="checkboxGroup-1" checked> Option 1</label>
<label><input type="checkbox" name="checkboxGroup[]" value="option2" id="checkboxGroup-2" checked> Option 2</label>
<label><input type="checkbox" name="checkboxGroup[]" value="option3" id="checkboxGroup-3" checked> Option 3</label>

<input type="submit" name="button" value="value">
<button type="submit" name="button2">value</button>

<p>Disabled</p>
<input type="text" name="text-disabled" value="value" disabled>
</form>

<!--<script src="./js/formToObject.min.js"></script>-->
Expand Down
62 changes: 62 additions & 0 deletions test/unit/constructor.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {FormToObject} from "../../src/FormToObject";

describe('constructor', () => {
describe('An invalid or non existing selector', () => {
it('null, should throw error', () => {
expect(() => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
new FormToObject(null);
}).toThrowError('No selector was passed.');
});

it('empty string, should throw error', () => {
expect(() => {
new FormToObject('');
}).toThrowError('No selector was passed.');
});

it('undefined, should throw error', () => {
expect(() => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
new FormToObject();
}).toThrowError('No selector was passed.');
});

it('non-existent selector should throw error', () => {
expect(() => {
new FormToObject('non-existing-selector');
}).toThrowError('The <form> DOM element could not be found.');
});

it('invalid DOM element ref should throw error', () => {
expect(() => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
new FormToObject(document.createTextNode('text'));
}).toThrowError('The <form> DOM element could not be found.');
});

it('invalid class should throw error', () => {
expect(() => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
new FormToObject({nodeType: 1});
}).toThrowError('The <form> is either not a valid DOM element or the browser is very old.');
});

});

describe('An empty HTML form', () => {
it('should return throw error', () => {
expect(() => {
const $form = document.createElement('form');
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
new FormToObject($form);
}).toThrowError('No <form> DOM elements were found. Form is empty.');
});
});
});

22 changes: 22 additions & 0 deletions test/unit/getObjLength.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,26 @@ describe('getObjLength', function() {
expect(getObjLength([])).toBe(0);
expect(getObjLength({name: 'Serban', job: 'programmer'})).toBe(2);
});

it('when provided an object with prototype, it only includes values from the object', function() {
const objParent = { p: 'p' };
const obj = { a: 'a' };
Object.setPrototypeOf(obj, objParent);

expect(getObjLength(obj)).toBe(1);
});

it.skip('when Object.keys is missing, it only includes values from the object', function() {
const objParent = { p: 'p' };
const obj = { a: 'a' };
Object.setPrototypeOf(obj, objParent);

const k = Object.keys;
// @ts-expect-error Exception test
delete Object.keys;

expect(getObjLength(obj)).toBe(1);

Object.keys = k;
});
});
36 changes: 36 additions & 0 deletions test/unit/submit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {FormToObject} from "../../src/FormToObject";

describe('submit', () => {
it('input with includeSubmitButton: true', () => {
const $form = document.createElement('form');
$form.innerHTML = `
<input type="submit" name="submit" value="go">
`;
const formToObject = new FormToObject($form, {includeSubmitButton: true});

expect(formToObject.convertToObj()).toEqual({'submit':'go'});
});

it('input with includeSubmitButton: false (default)', () => {
const $form = document.createElement('form');
$form.innerHTML = `
<input type="submit" name="submit" value="go">
`;
const formToObject = new FormToObject($form);

expect(formToObject.convertToObj()).toEqual({});
});

// Currently we don't support <button>. Should we?
it('button', () => {
expect(() => {
const $form = document.createElement('form');
$form.innerHTML = `
<button type="submit" name="submit">go</button>
`;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
new FormToObject($form);
}).toThrowError('No <form> DOM elements were found. Form is empty.');
});
});
13 changes: 13 additions & 0 deletions test/unit/textarea.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {FormToObject} from "../../src/FormToObject";

describe('textarea', ()=> {
it('should return an object', () => {
const $form = document.createElement('form');
$form.innerHTML = `
<textarea name="address">address</textarea>
`;
const formToObject = new FormToObject($form);

expect(formToObject.convertToObj()).toEqual({'address':'address'});
});
});
Loading

0 comments on commit 91c9387

Please sign in to comment.