Browse Source

Make coverage 100%

Include all tests for the primary functions as well as the utilities.
master
TheoryOfNekomata 1 year ago
parent
commit
5fa727bf45
8 changed files with 1109 additions and 86 deletions
  1. +218
    -2
      cypress/integration/checkbox.test.ts
  2. +13
    -0
      cypress/integration/date.test.ts
  3. +13
    -0
      cypress/integration/datetime-local.test.ts
  4. +214
    -2
      cypress/integration/misc.test.ts
  5. +13
    -0
      cypress/integration/month.test.ts
  6. +186
    -1
      cypress/integration/select.test.ts
  7. +265
    -0
      cypress/integration/time.test.ts
  8. +187
    -81
      src/index.ts

+ 218
- 2
cypress/integration/checkbox.test.ts View File

@@ -55,7 +55,7 @@ describe('checkbox', () => {
} }
}); });
}); });
})
});


describe('checked', () => { describe('checked', () => {
beforeEach(utils.setup(` beforeEach(utils.setup(`
@@ -93,7 +93,6 @@ describe('checkbox', () => {
}); });
}); });



describe('duplicate', () => { describe('duplicate', () => {
beforeEach(utils.setup(` beforeEach(utils.setup(`
<!DOCTYPE html> <!DOCTYPE html>
@@ -165,4 +164,221 @@ describe('checkbox', () => {
}); });
}); });
}); });

describe('setting values', () => {
beforeEach(utils.setup(`
<!DOCTYPE html>
<html lang="en-PH">
<head>
<meta charset="UTF-8">
<title>Checkbox/Setting Values</title>
</head>
<body>
<form>
<label>
<span>Hello</span>
<input type="checkbox" name="enabled" />
</label>
<button type="submit">Submit</button>
</form>
</body>
</html>
`))

it('should check for boolean "true"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: true, })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).toBe('on');
},
expectedStaticValue: 'enabled=on',
});
});

it('should check for string "true"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: 'true', })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).toBe('on');
},
expectedStaticValue: 'enabled=on',
});
});

it('should check for string "yes"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: 'yes', })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).toBe('on');
},
expectedStaticValue: 'enabled=on',
});
});

it('should check for string "on"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: 'on', })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).toBe('on');
},
expectedStaticValue: 'enabled=on',
});
});

it('should uncheck for boolean "false"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: false, })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).not.toBe('on');
},
expectedStaticValue: '',
});
});

it('should uncheck for string "false"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: 'false', })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).not.toBe('on');
},
expectedStaticValue: '',
});
});

it('should uncheck for string "no"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: 'no', })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).not.toBe('on');
},
expectedStaticValue: '',
});
});

it('should uncheck for string "off"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: 'off', })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).not.toBe('on');
},
expectedStaticValue: '',
});
});

it('should check for number "1"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: 1, })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).toBe('on');
},
expectedStaticValue: 'enabled=on',
});
});

it('should check for string "1"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: '1', })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).toBe('on');
},
expectedStaticValue: 'enabled=on',
});
});

it('should uncheck for number "0"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: 0, })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).not.toBe('on');
},
expectedStaticValue: '',
});
});

it('should uncheck for string "0"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: '0', })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).not.toBe('on');
},
expectedStaticValue: '',
});
});

it('should uncheck for object "null"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: null, })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).not.toBe('on');
},
expectedStaticValue: '',
});
});

it('should uncheck for string "null"', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { enabled: 'null', })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter })
expect(values['enabled']).not.toBe('on');
},
expectedStaticValue: '',
});
});
});
}); });

+ 13
- 0
cypress/integration/date.test.ts View File

@@ -38,6 +38,19 @@ describe('date', () => {
}, },
}); });
}); });

it('should enable Date representation', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter, forceDateValues: true });
// somehow, checking instanceof Date fails here, because we're using an artificial date
// object?
const testDate = new Date(values.hello as Date);
expect((values.hello as Date).getTime()).toBe(testDate.getTime());
},
});
});
}) })


describe('disabled', () => { describe('disabled', () => {


+ 13
- 0
cypress/integration/datetime-local.test.ts View File

@@ -38,6 +38,19 @@ describe('date', () => {
}, },
}); });
}); });

it('should enable Date representation', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter, forceDateValues: true });
// somehow, checking instanceof Date fails here, because we're using an artificial date
// object?
const testDate = new Date(values.hello as Date);
expect((values.hello as Date).getTime()).toBe(testDate.getTime());
},
});
});
}) })


describe('disabled', () => { describe('disabled', () => {


+ 214
- 2
cypress/integration/misc.test.ts View File

@@ -1,4 +1,10 @@
import getFormValuesDeprecated, { getFormValues, setFormValues } from '../../src';
import getFormValuesDeprecated, {
getFormValues,
setFormValues,
isFieldElement,
isElementValueIncludedInFormSubmit,
getValue,
} from '../../src';
import * as utils from '../utils' import * as utils from '../utils'


describe('misc', () => { describe('misc', () => {
@@ -177,7 +183,213 @@ describe('misc', () => {
}, },
}); });
}); });
})
});

describe('utilities', () => {
beforeEach(utils.setup(`
<!DOCTYPE html>
<html lang="en-PH">
<head>
<meta charset="UTF-8">
<title>Misc/Utilities</title>
</head>
<body>
<form>
<input id="input" type="text" name="foobar" />
<input id="notField" type="text" />
<input id="disabled" disabled type="text" name="disabled" />
<meter id="meter" min="1" max="10" value="5" />
<button type="submit">Submit</button>
</form>
</body>
</html>
`));

it('should check for valid field elements value', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const meter = document.getElementById('meter');
expect(getValue(meter)).toBe(5);
},
});
});

it('should check for invalid field elements value', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
expect(getValue(document.body)).toBe(null);
},
});
});

it('should check for elements as included fields', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const input = document.getElementById('input');
expect(isElementValueIncludedInFormSubmit(input)).toBe(true);
},
});
});

it('should check for elements as excluded fields', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const notField = document.getElementById('notField');
expect(isElementValueIncludedInFormSubmit(notField)).toBe(false);
const disabled = document.getElementById('disabled');
expect(isElementValueIncludedInFormSubmit(disabled)).toBe(false);
const meter = document.getElementById('meter');
expect(isElementValueIncludedInFormSubmit(meter)).toBe(false);
},
});
});

it('should check for elements as valid for fields', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const input = document.getElementById('input');
expect(isFieldElement(input)).toBe(true);
const disabled = document.getElementById('disabled');
expect(isFieldElement(disabled)).toBe(true);
},
});
});

it('should check for elements as invalid for fields', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const meter = document.getElementById('meter');
expect(isFieldElement(meter)).toBe(false);
const notField = document.getElementById('notField');
expect(isFieldElement(notField)).toBe(false);
},
});
});
});

describe('setting values', () => {
beforeEach(utils.setup(`
<!DOCTYPE html>
<html lang="en-PH">
<head>
<meta charset="UTF-8">
<title>Misc/Blank</title>
</head>
<body>
<form>
<input type="text" name="foobar" />
<button type="submit">Submit</button>
</form>
</body>
</html>
`))

it('should parse string values for setFormValues', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
let isThrown = false;
try {
setFormValues(form, 'foobar=baz');
} catch (e) {
isThrown = true;
}

expect(isThrown).toBe(false);
expect(getFormValues(form)).toEqual({ foobar: 'baz', });
},
})
});

it('should parse entries values for setFormValues', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
let isThrown = false;
try {
setFormValues(form, [['foobar', 'baz']]);
} catch (e) {
isThrown = true;
}

expect(isThrown).toBe(false);
expect(getFormValues(form)).toEqual({ foobar: 'baz', });
},
})
});

it('should parse URLSearchParams values for setFormValues', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
let isThrown = false;
try {
setFormValues(form, new URLSearchParams('foobar=baz'));
} catch (e) {
isThrown = true;
}

expect(isThrown).toBe(false);
expect(getFormValues(form)).toEqual({ foobar: 'baz', });
},
})
});

it('should parse object values for setFormValues', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
let isThrown = false;
try {
setFormValues(form, { foobar: 'baz', });
} catch (e) {
isThrown = true;
}

expect(isThrown).toBe(false);
expect(getFormValues(form)).toEqual({ foobar: 'baz', });
},
})
});
});

describe('duplicates', () => {
beforeEach(utils.setup(`
<!DOCTYPE html>
<html lang="en-PH">
<head>
<meta charset="UTF-8">
<title>Misc/Blank</title>
</head>
<body>
<form>
<input type="text" name="foobar" />
<input type="text" name="foobar" />
<input type="text" name="foobar" />
<button type="submit">Submit</button>
</form>
</body>
</html>
`));

it('should parse duplicates correctly', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { foobar: ['foo', 'bar', 'baz']})
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
expect(getFormValues(form)).toEqual({ foobar: ['foo', 'bar', 'baz'], });
},
})
});
});


describe('blank', () => { describe('blank', () => {
beforeEach(utils.setup(` beforeEach(utils.setup(`


+ 13
- 0
cypress/integration/month.test.ts View File

@@ -38,6 +38,19 @@ describe('month', () => {
}, },
}); });
}); });

it('should enable Date representation', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const values = getFormValues(form, { submitter, forceDateValues: true });
// somehow, checking instanceof Date fails here, because we're using an artificial date
// object?
const testDate = new Date(values.hello as Date);
expect((values.hello as Date).getTime()).toBe(testDate.getTime());
},
});
});
}) })


describe('disabled', () => { describe('disabled', () => {


+ 186
- 1
cypress/integration/select.test.ts View File

@@ -1,4 +1,4 @@
import { getFormValues } from '../../src'
import { getFormValues, setFormValues } from '../../src';
import * as utils from '../utils' import * as utils from '../utils'


describe('select', () => { describe('select', () => {
@@ -41,6 +41,107 @@ describe('select', () => {
expectedStaticValue: 'hello=Bar&hello=Quux' expectedStaticValue: 'hello=Bar&hello=Quux'
}); });
}); });

it('should set values correctly', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { hello: ['Foo', 'Baz'] });
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: 'hello=Foo&hello=Baz'
});
});
})

describe('multiple duplicate', () => {
beforeEach(utils.setup(`
<!DOCTYPE html>
<html lang="en-PH">
<head>
<meta charset="UTF-8">
<title>Select/Multiple Duplicate</title>
</head>
<body>
<form>
<label>
<span>Hello</span>
<select name="hello" multiple>
<option>Foo</option>
<option selected>Bar</option>
<option>Baz</option>
<option selected>Quux</option>
</select>
<select name="hello" multiple>
<option>Chocolate</option>
<option selected>Mango</option>
<option>Vanilla</option>
<option selected>Ube</option>
</select>
</label>
<button type="submit">Submit</button>
</form>
</body>
</html>
`))

it('should have multiple form values on a single field', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: 'hello=Bar&hello=Quux&hello=Mango&hello=Ube'
});
});

it('should set multiple form values across all selects', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { hello: ['Foo', 'Baz', 'Chocolate', 'Vanilla'] })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: 'hello=Foo&hello=Baz&hello=Chocolate&hello=Vanilla'
});
});

it('should set multiple form values on each corresponding select element', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { hello: [['Foo', 'Baz', 'Chocolate'], ['Vanilla']] })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: 'hello=Foo&hello=Baz&hello=Vanilla'
});
});
}) })


describe('single', () => { describe('single', () => {
@@ -84,4 +185,88 @@ describe('select', () => {
}); });
}); });
}) })

describe('single duplicate', () => {
beforeEach(utils.setup(`
<!DOCTYPE html>
<html lang="en-PH">
<head>
<meta charset="UTF-8">
<title>Select/Single Duplicate</title>
</head>
<body>
<form>
<label>
<span>Hello</span>
<select name="hello">
<option>Foo</option>
<option selected>Bar</option>
<option>Baz</option>
<option>Quux</option>
</select>
<select name="hello">
<option>Chocolate</option>
<option>Mango</option>
<option>Vanilla</option>
<option selected>Ube</option>
<option>Foo</option>
</select>
</label>
<button type="submit">Submit</button>
</form>
</body>
</html>
`))

it('should have multiple form values on a single field', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: 'hello=Bar&hello=Ube'
});
});

it('should set multiple form values across all selects', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { hello: ['Foo', 'Chocolate'] })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: 'hello=Foo&hello=Chocolate'
});
});

it('should set multiple form values on each corresponding select element', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, { hello: ['Foo', 'Ube'] })
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: 'hello=Foo&hello=Ube'
});
});
})
}) })

+ 265
- 0
cypress/integration/time.test.ts View File

@@ -0,0 +1,265 @@
import { getFormValues, setFormValues } from '../../src';
import * as utils from '../utils'

describe('time', () => {
describe('basic', () => {
beforeEach(utils.setup(`
<!DOCTYPE html>
<html lang="en-PH">
<head>
<meta charset="UTF-8">
<title>Time/Basic</title>
</head>
<body>
<form>
<label>
<span>Hello</span>
<input type="time" name="hello" value="13:37" />
</label>
<button type="submit">Submit</button>
</form>
</body>
</html>
`))

it('should have single form value', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: {
hello: '13:37',
},
});
});
})

describe('disabled', () => {
beforeEach(utils.setup(`
<!DOCTYPE html>
<html lang="en-PH">
<head>
<meta charset="UTF-8">
<title>Time/Disabled</title>
</head>
<body>
<form>
<label>
<span>Hello</span>
<input
type="time" name="hello" value="13:37"
disabled
/>
</label>
<button type="submit">Submit</button>
</form>
</body>
</html>
`))

it('should have blank form value', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: {},
});
});
})

describe('outside', () => {
beforeEach(utils.setup(`
<!DOCTYPE html>
<html lang="en-PH">
<head>
<meta charset="UTF-8">
<title>Time/Outside</title>
</head>
<body>
<form id="form">
<button type="submit">Submit</button>
</form>
<label>
<span>Hello</span>
<input type="time" name="hello" value="13:37" form="form" />
</label>
</body>
</html>
`))

it('should have single form value', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: {
hello: '13:37',
},
});
});
});

describe('readonly', () => {
beforeEach(utils.setup(`
<!DOCTYPE html>
<html lang="en-PH">
<head>
<meta charset="UTF-8">
<title>Time/Readonly</title>
</head>
<body>
<form>
<label>
<span>Hello</span>
<input
type="time" name="hello" value="13:37"
readonly
/>
</label>
<button type="submit">Submit</button>
</form>
</body>
</html>
`))

it('should have single form value', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: {
hello: '13:37',
},
});
});
});

describe('programmatic value setting', () => {
beforeEach(utils.setup(`
<!DOCTYPE html>
<html lang="en-PH">
<head>
<meta charset="UTF-8">
<title>Time/Programmatic Value Setting</title>
</head>
<body>
<form>
<label>
<span>Hello</span>
<input type="time" name="hello" />
</label>
<button type="submit">Submit</button>
</form>
</body>
</html>
`));

it('should have form values set', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
preAction: (form: HTMLFormElement) => {
setFormValues(form, { hello: '13:37', })
},
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: {
hello: '13:37',
},
});
});
});

describe('duplicate', () => {
beforeEach(utils.setup(`
<!DOCTYPE html>
<html lang="en-PH">
<head>
<meta charset="UTF-8">
<title>Time/Duplicate</title>
</head>
<body>
<form>
<label>
<span>Hello 1</span>
<input id="hello1" type="time" value="13:37" name="hello"/>
</label>
<label>
<span>Hello 2</span>
<input id="hello2" type="time" value="06:09" name="hello"/>
</label>
<button type="submit">Submit</button>
</form>
</body>
</html>
`));

it('should get both values', () => {
utils.test({
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: {
hello: ['13:37', '06:09'],
},
});
});

it('should set both values', () => {
utils.test({
preAction: (form: HTMLFormElement) => {
setFormValues(form, {
hello: ['04:20', '05:30'],
})
},
action: (cy: any) => cy.get('[type="submit"]'),
test: (form: HTMLFormElement, submitter: any, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, { submitter }))
.toString();
const after = utils.makeSearchParams(search)
.toString();
expect(before)
.toEqual(after);
},
expectedStaticValue: {
hello: ['04:20', '05:30'],
},
});
});
});
})

+ 187
- 81
src/index.ts View File

@@ -44,8 +44,9 @@ const FORM_FIELD_INPUT_EXCLUDED_TYPES = ['submit', 'reset'] as const;
/** /**
* Checks if an element can hold a custom (user-inputted) field value. * Checks if an element can hold a custom (user-inputted) field value.
* @param el - The element. * @param el - The element.
* @returns Value determining if an element can hold a custom (user-inputted) field value.
*/ */
export const isFormFieldElement = (el: HTMLElement) => {
export const isFieldElement = (el: HTMLElement) => {
const { tagName } = el; const { tagName } = el;
if (FORM_FIELD_ELEMENT_TAG_NAMES.includes(tagName as typeof FORM_FIELD_ELEMENT_TAG_NAMES[0])) { if (FORM_FIELD_ELEMENT_TAG_NAMES.includes(tagName as typeof FORM_FIELD_ELEMENT_TAG_NAMES[0])) {
return true; return true;
@@ -92,15 +93,15 @@ const getTextAreaFieldValue = (
* @param textareaEl - The element. * @param textareaEl - The element.
* @param value - Value of the textarea element. * @param value - Value of the textarea element.
* @param nthOfName - What order is this field in with respect to fields of the same name? * @param nthOfName - What order is this field in with respect to fields of the same name?
* @param totalOfName - How many fields with the same name are in the form?
* @param elementsOfSameName - How many fields with the same name are in the form?
*/ */
const setTextAreaFieldValue = ( const setTextAreaFieldValue = (
textareaEl: HTMLTextAreaElement, textareaEl: HTMLTextAreaElement,
value: unknown, value: unknown,
nthOfName: number, nthOfName: number,
totalOfName: number,
elementsOfSameName: HTMLTextAreaElement[],
) => { ) => {
if (Array.isArray(value) && totalOfName > 1) {
if (Array.isArray(value) && elementsOfSameName.length > 1) {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
textareaEl.value = value[nthOfName]; textareaEl.value = value[nthOfName];
return; return;
@@ -128,19 +129,54 @@ const getSelectFieldValue = (
* Sets the value of a `<select>` element. * Sets the value of a `<select>` element.
* @param selectEl - The element. * @param selectEl - The element.
* @param value - Value of the select element. * @param value - Value of the select element.
* @param nthOfName - What order is this field in with respect to fields of the same name?
* @param elementsOfSameName - How many fields with the same name are in the form?
*/ */
const setSelectFieldValue = (selectEl: HTMLSelectElement, value: unknown) => {
Array.from(selectEl.options)
.filter((o) => {
if (Array.isArray(value)) {
return (value as string[]).includes(o.value);
}
return o.value === value;
})
.forEach((el) => {
const setSelectFieldValue = (
selectEl: HTMLSelectElement,
value: unknown,
nthOfName: number,
elementsOfSameName: HTMLSelectElement[],
) => {
if (elementsOfSameName.length > 1) {
const valueArray = value as unknown[];
const valueArrayDepth = valueArray.every((v) => Array.isArray(v)) ? 2 : 1;
if (valueArrayDepth > 1) {
// We check if values are [['foo', 'bar], ['baz', 'quux'], 'single value]
// If this happens, all values must correspond to a <select multiple> element.
const currentValue = valueArray[nthOfName] as string[];
Array.from(selectEl.options).forEach((el) => {
// eslint-disable-next-line no-param-reassign
el.selected = currentValue.includes(el.value);
});
return;
}

// Else we're just checking if these values are in the value array provided.
// They will apply across all select elements.

if (elementsOfSameName.some((el) => el.multiple)) {
Array.from(selectEl.options).forEach((el) => {
// eslint-disable-next-line no-param-reassign
el.selected = (value as string[]).includes(el.value);
});
return;
}

Array.from(selectEl.options).forEach((el) => {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
el.selected = true;
el.selected = el.value === (value as string[])[nthOfName];
}); });

return;
}

Array.from(selectEl.options).forEach((el) => {
// eslint-disable-next-line no-param-reassign
el.selected = Array.isArray(value)
? (value as string[]).includes(el.value)
: el.value === value;
});
}; };


/** /**
@@ -248,6 +284,45 @@ const getInputCheckboxFieldValue = (
return null; return null;
}; };


const parseBooleanValues = (value: unknown) => {
if (typeof value === 'boolean') {
return value;
}

if (typeof value === 'string') {
const normalizedValue = value.toLowerCase();
if (INPUT_CHECKBOX_FALSY_VALUES.includes(
normalizedValue as typeof INPUT_CHECKBOX_FALSY_VALUES[0],
)) {
return false;
}

if (INPUT_CHECKBOX_TRUTHY_VALUES.includes(
normalizedValue as typeof INPUT_CHECKBOX_TRUTHY_VALUES[0],
)) {
return true;
}
}

if (typeof value === 'number') {
if (value === 0) {
return false;
}

if (value === 1) {
return true;
}
}

if (typeof value === 'object') {
if (value === null) {
return false;
}
}

return undefined;
};

/** /**
* Sets the value of an `<input type="checkbox">` element. * Sets the value of an `<input type="checkbox">` element.
* @param inputEl - The element. * @param inputEl - The element.
@@ -269,26 +344,10 @@ const setInputCheckboxFieldValue = (
return; return;
} }


if (
INPUT_CHECKBOX_FALSY_VALUES.includes(
(value as string).toLowerCase() as typeof INPUT_CHECKBOX_FALSY_VALUES[0],
)
|| !value
) {
// eslint-disable-next-line no-param-reassign
inputEl.checked = false;
return;
}

if (
INPUT_CHECKBOX_TRUTHY_VALUES.includes(
(value as string).toLowerCase() as typeof INPUT_CHECKBOX_TRUTHY_VALUES[0],
)
|| value === true
|| value === 1
) {
const newValue = parseBooleanValues(value);
if (typeof newValue === 'boolean') {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
inputEl.checked = true;
inputEl.checked = newValue;
} }
}; };


@@ -324,9 +383,6 @@ const getInputFileFieldValue = (
options = {} as GetInputFileFieldValueOptions, options = {} as GetInputFileFieldValueOptions,
) => { ) => {
const { files } = inputEl; const { files } = inputEl;
if ((files as unknown) === null) {
return null;
}
if (options.getFileObjects) { if (options.getFileObjects) {
return files; return files;
} }
@@ -395,17 +451,17 @@ const getInputNumericFieldValue = (
* @param inputEl - The element. * @param inputEl - The element.
* @param value - Value of the input element. * @param value - Value of the input element.
* @param nthOfName - What order is this field in with respect to fields of the same name? * @param nthOfName - What order is this field in with respect to fields of the same name?
* @param totalOfName - How many fields with the same name are in the form?
* @param elementsWithSameName - How many fields with the same name are in the form?
*/ */
const setInputNumericFieldValue = ( const setInputNumericFieldValue = (
inputEl: HTMLInputNumericElement, inputEl: HTMLInputNumericElement,
value: unknown, value: unknown,
nthOfName: number, nthOfName: number,
totalOfName: number,
elementsWithSameName: HTMLInputNumericElement[],
) => { ) => {
const valueArray = Array.isArray(value) ? value : [value]; const valueArray = Array.isArray(value) ? value : [value];
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
inputEl.valueAsNumber = Number(valueArray[totalOfName > 1 ? nthOfName : 0]);
inputEl.valueAsNumber = Number(valueArray[elementsWithSameName.length > 1 ? nthOfName : 0]);
}; };


/** /**
@@ -472,7 +528,11 @@ const getInputDateLikeFieldValue = (
options = {} as GetInputDateFieldValueOptions, options = {} as GetInputDateFieldValueOptions,
) => { ) => {
if (options.forceDateValues) { if (options.forceDateValues) {
return inputEl.valueAsDate;
return (
// somehow datetime-local does not return us the current `valueAsDate` when the string
// representation in `value` is incomplete.
inputEl.type === INPUT_TYPE_DATETIME_LOCAL ? new Date(inputEl.value) : inputEl.valueAsDate
);
} }
return inputEl.value; return inputEl.value;
}; };
@@ -492,20 +552,22 @@ const DATE_FORMAT_ISO_MONTH = 'yyyy-MM' as const;
* @param inputEl - The element. * @param inputEl - The element.
* @param value - Value of the input element. * @param value - Value of the input element.
* @param nthOfName - What order is this field in with respect to fields of the same name? * @param nthOfName - What order is this field in with respect to fields of the same name?
* @param totalOfName - How many fields with the same name are in the form?
* @param elementsOfSameName - How many fields with the same name are in the form?
*/ */
const setInputDateLikeFieldValue = ( const setInputDateLikeFieldValue = (
inputEl: HTMLInputDateLikeElement, inputEl: HTMLInputDateLikeElement,
value: unknown, value: unknown,
nthOfName: number, nthOfName: number,
totalOfName: number,
elementsOfSameName: HTMLInputDateLikeElement[],
) => { ) => {
const valueArray = Array.isArray(value) ? value : [value]; const valueArray = Array.isArray(value) ? value : [value];
const hasMultipleElementsOfSameName = elementsOfSameName.length > 1;
const elementIndex = hasMultipleElementsOfSameName ? nthOfName : 0;


if (inputEl.type.toLowerCase() === INPUT_TYPE_DATE) { if (inputEl.type.toLowerCase() === INPUT_TYPE_DATE) {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
inputEl.value = new Date( inputEl.value = new Date(
valueArray[totalOfName > 1 ? nthOfName : 0] as ConstructorParameters<typeof Date>[0],
valueArray[elementIndex] as ConstructorParameters<typeof Date>[0],
) )
.toISOString() .toISOString()
.slice(0, DATE_FORMAT_ISO_DATE.length); .slice(0, DATE_FORMAT_ISO_DATE.length);
@@ -515,7 +577,7 @@ const setInputDateLikeFieldValue = (
if (inputEl.type.toLowerCase() === INPUT_TYPE_DATETIME_LOCAL) { if (inputEl.type.toLowerCase() === INPUT_TYPE_DATETIME_LOCAL) {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
inputEl.value = new Date( inputEl.value = new Date(
valueArray[totalOfName > 1 ? nthOfName : 0] as ConstructorParameters<typeof Date>[0],
valueArray[elementIndex] as ConstructorParameters<typeof Date>[0],
) )
.toISOString() .toISOString()
.slice(0, -1); // remove extra 'Z' suffix .slice(0, -1); // remove extra 'Z' suffix
@@ -524,7 +586,7 @@ const setInputDateLikeFieldValue = (
if (inputEl.type.toLowerCase() === INPUT_TYPE_MONTH) { if (inputEl.type.toLowerCase() === INPUT_TYPE_MONTH) {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
inputEl.value = new Date( inputEl.value = new Date(
valueArray[totalOfName > 1 ? nthOfName : 0] as ConstructorParameters<typeof Date>[0],
valueArray[elementIndex] as ConstructorParameters<typeof Date>[0],
) )
.toISOString() .toISOString()
.slice(0, DATE_FORMAT_ISO_MONTH.length); // remove extra 'Z' suffix .slice(0, DATE_FORMAT_ISO_MONTH.length); // remove extra 'Z' suffix
@@ -580,6 +642,11 @@ const INPUT_TYPE_HIDDEN = 'hidden' as const;
*/ */
const INPUT_TYPE_COLOR = 'color' as const; const INPUT_TYPE_COLOR = 'color' as const;


/**
* Value of the `type` attribute for `<input>` elements considered as time pickers.
*/
const INPUT_TYPE_TIME = 'time' as const;

/** /**
* Gets the value of an `<input>` element. * Gets the value of an `<input>` element.
* @param inputEl - The element. * @param inputEl - The element.
@@ -612,12 +679,13 @@ const getInputFieldValue = (
case INPUT_TYPE_PASSWORD: case INPUT_TYPE_PASSWORD:
case INPUT_TYPE_HIDDEN: case INPUT_TYPE_HIDDEN:
case INPUT_TYPE_COLOR: case INPUT_TYPE_COLOR:
case INPUT_TYPE_TIME:
default: default:
break; break;
} }


// force return `null` for custom elements supporting setting values.
return inputEl.value ?? null;
// don't force returning `null` for custom elements supporting setting values.
return inputEl.value;
}; };


/** /**
@@ -625,7 +693,7 @@ const getInputFieldValue = (
* @param inputEl - The element. * @param inputEl - The element.
* @param value - Value of the input element. * @param value - Value of the input element.
* @param nthOfName - What order is this field in with respect to fields of the same name? * @param nthOfName - What order is this field in with respect to fields of the same name?
* @param totalOfName - How many fields with the same name are in the form?
* @param elementsWithSameName - How many fields with the same name are in the form?
* @note This function is a noop for `<input type="file">` because by design, file inputs are not * @note This function is a noop for `<input type="file">` because by design, file inputs are not
* assignable programmatically. * assignable programmatically.
*/ */
@@ -633,7 +701,7 @@ const setInputFieldValue = (
inputEl: HTMLInputElement, inputEl: HTMLInputElement,
value: unknown, value: unknown,
nthOfName: number, nthOfName: number,
totalOfName: number,
elementsWithSameName: HTMLInputElement[],
) => { ) => {
switch (inputEl.type.toLowerCase()) { switch (inputEl.type.toLowerCase()) {
case INPUT_TYPE_CHECKBOX: case INPUT_TYPE_CHECKBOX:
@@ -651,7 +719,7 @@ const setInputFieldValue = (
inputEl as HTMLInputNumericElement, inputEl as HTMLInputNumericElement,
value, value,
nthOfName, nthOfName,
totalOfName,
elementsWithSameName as HTMLInputNumericElement[],
); );
return; return;
case INPUT_TYPE_DATE: case INPUT_TYPE_DATE:
@@ -661,7 +729,7 @@ const setInputFieldValue = (
inputEl as HTMLInputDateLikeElement, inputEl as HTMLInputDateLikeElement,
value, value,
nthOfName, nthOfName,
totalOfName,
elementsWithSameName as HTMLInputDateLikeElement[],
); );
return; return;
case INPUT_TYPE_TEXT: case INPUT_TYPE_TEXT:
@@ -672,11 +740,12 @@ const setInputFieldValue = (
case INPUT_TYPE_PASSWORD: case INPUT_TYPE_PASSWORD:
case INPUT_TYPE_HIDDEN: case INPUT_TYPE_HIDDEN:
case INPUT_TYPE_COLOR: case INPUT_TYPE_COLOR:
case INPUT_TYPE_TIME:
default: default:
break; break;
} }


if (Array.isArray(value) && totalOfName > 1) {
if (Array.isArray(value) && elementsWithSameName.length > 1) {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
inputEl.value = value[nthOfName]; inputEl.value = value[nthOfName];
return; return;
@@ -700,23 +769,24 @@ type HTMLElementWithName
= (HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | HTMLButtonElement); = (HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | HTMLButtonElement);


/** /**
* Gets the value of a field element.
* Gets the value of an element regardless if it's a field element or not.
* @param el - The field element. * @param el - The field element.
* @param options - The options. * @param options - The options.
* @returns Value of the field element.
* @returns Value of the element.
*/ */
export const getFieldValue = (el: HTMLElement, options = {} as GetFieldValueOptions) => {
export const getValue = (el: HTMLElement, options = {} as GetFieldValueOptions) => {
switch (el.tagName) { switch (el.tagName) {
case TAG_NAME_TEXTAREA: case TAG_NAME_TEXTAREA:
return getTextAreaFieldValue(el as HTMLTextAreaElement, options); return getTextAreaFieldValue(el as HTMLTextAreaElement, options);
case TAG_NAME_SELECT: case TAG_NAME_SELECT:
return getSelectFieldValue(el as HTMLSelectElement); return getSelectFieldValue(el as HTMLSelectElement);
case TAG_NAME_INPUT: case TAG_NAME_INPUT:
return getInputFieldValue(el as HTMLInputElement, options);
default: default:
break; break;
} }


return getInputFieldValue(el as HTMLInputElement, options);
return 'value' in el ? el.value : null;
}; };


/** /**
@@ -724,27 +794,42 @@ export const getFieldValue = (el: HTMLElement, options = {} as GetFieldValueOpti
* @param el - The field element. * @param el - The field element.
* @param value - Value of the field element. * @param value - Value of the field element.
* @param nthOfName - What order is this field in with respect to fields of the same name? * @param nthOfName - What order is this field in with respect to fields of the same name?
* @param totalOfName - How many fields with the same name are in the form?
* @param elementsWithSameName - How many fields with the same name are in the form?
*/ */
const setFieldValue = ( const setFieldValue = (
el: HTMLElement, el: HTMLElement,
value: unknown, value: unknown,
nthOfName: number, nthOfName: number,
totalOfName: number,
elementsWithSameName: HTMLElement[],
) => { ) => {
switch (el.tagName) { switch (el.tagName) {
case TAG_NAME_TEXTAREA: case TAG_NAME_TEXTAREA:
setTextAreaFieldValue(el as HTMLTextAreaElement, value, nthOfName, totalOfName);
setTextAreaFieldValue(
el as HTMLTextAreaElement,
value,
nthOfName,
elementsWithSameName as HTMLTextAreaElement[],
);
return; return;
case TAG_NAME_SELECT: case TAG_NAME_SELECT:
setSelectFieldValue(el as HTMLSelectElement, value);
setSelectFieldValue(
el as HTMLSelectElement,
value,
nthOfName,
elementsWithSameName as HTMLSelectElement[],
);
return; return;
case TAG_NAME_INPUT: case TAG_NAME_INPUT:
default: default:
break; break;
} }


setInputFieldValue(el as HTMLInputElement, value, nthOfName, totalOfName);
setInputFieldValue(
el as HTMLInputElement,
value,
nthOfName,
elementsWithSameName as HTMLInputElement[],
);
}; };


/** /**
@@ -758,17 +843,17 @@ const ATTRIBUTE_NAME = 'name' as const;
const ATTRIBUTE_DISABLED = 'disabled' as const; const ATTRIBUTE_DISABLED = 'disabled' as const;


/** /**
* Determines if an element is a named and enabled form field.
* Determines if an element's value is included when its form is submitted.
* @param el - The element. * @param el - The element.
* @returns Value determining if the element is a named and enabled form field.
* @returns Value determining if the element's value is included when its form is submitted.
*/ */
export const isNamedEnabledFormFieldElement = (el: HTMLElement) => {
export const isElementValueIncludedInFormSubmit = (el: HTMLElement) => {
const namedEl = el as unknown as Record<string, unknown>; const namedEl = el as unknown as Record<string, unknown>;
return ( return (
typeof namedEl[ATTRIBUTE_NAME] === 'string' typeof namedEl[ATTRIBUTE_NAME] === 'string'
&& namedEl[ATTRIBUTE_NAME].length > 0 && namedEl[ATTRIBUTE_NAME].length > 0
&& !(ATTRIBUTE_DISABLED in namedEl && Boolean(namedEl[ATTRIBUTE_DISABLED])) && !(ATTRIBUTE_DISABLED in namedEl && Boolean(namedEl[ATTRIBUTE_DISABLED]))
&& isFormFieldElement(namedEl as unknown as HTMLElement)
&& isFieldElement(namedEl as unknown as HTMLElement)
); );
}; };


@@ -829,7 +914,7 @@ const filterFieldElements = (form: HTMLFormElement) => {
!Number.isNaN(Number(k)) !Number.isNaN(Number(k))


// Only the enabled/read-only elements can be enumerated. // Only the enabled/read-only elements can be enumerated.
&& isNamedEnabledFormFieldElement(el)
&& isElementValueIncludedInFormSubmit(el)
)) as [string, HTMLElementWithName][]; )) as [string, HTMLElementWithName][];
}; };


@@ -845,7 +930,7 @@ export const getFormValues = (form: HTMLFormElement, options = {} as GetFormValu
const fieldElements = filterFieldElements(form); const fieldElements = filterFieldElements(form);
const fieldValues = fieldElements.reduce( const fieldValues = fieldElements.reduce(
(theFormValues, [, el]) => { (theFormValues, [, el]) => {
const fieldValue = getFieldValue(el, options);
const fieldValue = getValue(el, options);
if (fieldValue === null) { if (fieldValue === null) {
return theFormValues; return theFormValues;
} }
@@ -853,24 +938,35 @@ export const getFormValues = (form: HTMLFormElement, options = {} as GetFormValu
const { name: fieldName } = el; const { name: fieldName } = el;
const { [fieldName]: oldFormValue = null } = theFormValues; const { [fieldName]: oldFormValue = null } = theFormValues;


if (oldFormValue === null) {
if (oldFormValue !== null && !Array.isArray(oldFormValue)) {
return { return {
...theFormValues, ...theFormValues,
[fieldName]: fieldValue,
[fieldName]: [oldFormValue, fieldValue],
}; };
} }


if (!Array.isArray(oldFormValue)) {
if (Array.isArray(oldFormValue)) {
if (Array.isArray(fieldValue)) {
return {
...theFormValues,
[fieldName]: [...oldFormValue, ...fieldValue],
};
}
return { return {
...theFormValues, ...theFormValues,
[fieldName]: [oldFormValue, fieldValue],
[fieldName]: [...oldFormValue, fieldValue],
}; };
} }


return { return {
...theFormValues, ...theFormValues,
[fieldName]: [...oldFormValue, fieldValue],
[fieldName]: fieldValue,
}; };

// return {
// ...theFormValues,
// [fieldName]: [...oldFormValue, fieldValue],
// };
}, },
{} as Record<string, unknown>, {} as Record<string, unknown>,
); );
@@ -928,36 +1024,46 @@ export const setFormValues = (
const fieldElements = filterFieldElements(form); const fieldElements = filterFieldElements(form);
const objectValues = normalizeValues(values); const objectValues = normalizeValues(values);


const count = fieldElements
const elementsWithSameName = fieldElements
.filter(([, el]) => el.name in objectValues) .filter(([, el]) => el.name in objectValues)
.reduce( .reduce(
(currentCount, [, el]) => { (currentCount, [, el]) => {
if (el.tagName === TAG_NAME_INPUT && el.type === INPUT_TYPE_RADIO) { if (el.tagName === TAG_NAME_INPUT && el.type === INPUT_TYPE_RADIO) {
return { return {
...currentCount, ...currentCount,
[el.name]: 1,
[el.name]: [el],
}; };
} }


return { return {
...currentCount, ...currentCount,
[el.name]: ( [el.name]: (
typeof currentCount[el.name] === 'number'
? currentCount[el.name] + 1
: 1
Array.isArray(currentCount[el.name])
? [...currentCount[el.name], el]
: [el]
), ),
}; };
}, },
{} as Record<string, number>,
{} as Record<string, HTMLElement[]>,
); );


const counter = {} as Record<string, number>;
const nthElementOfName = {} as Record<string, number>;


fieldElements fieldElements
.filter(([, el]) => el.name in objectValues) .filter(([, el]) => el.name in objectValues)
.forEach(([, el]) => { .forEach(([, el]) => {
counter[el.name] = typeof counter[el.name] === 'number' ? counter[el.name] + 1 : 0;
setFieldValue(el, objectValues[el.name], counter[el.name], count[el.name]);
nthElementOfName[el.name] = (
typeof nthElementOfName[el.name] === 'number'
? nthElementOfName[el.name] + 1
: 0
);

setFieldValue(
el,
objectValues[el.name],
nthElementOfName[el.name],
elementsWithSameName[el.name],
);
}); });
}; };




Loading…
Cancel
Save