UNPKG

doevisualizations

Version:

Data Visualization Library based on RequireJS and D3.js (v4+)

1,031 lines (942 loc) 71.6 kB
// serializeJSON describe("$.serializeJSON", function () { var obj, $form; it('accepts a jQuery or Zepto object with a form', function() { $form = $('<form>'); $form.append($('<input type="text" name="1" value="1"/>')); $form.append($('<input type="text" name="2" value="2"/>')); obj = $form.serializeJSON(); expect(obj).toEqual({"1": "1", "2": "2"}); }); if ($.fn.jquery) { // not supported on Zepto it('accepts a jQuery object with inputs', function() { $inputs = $('<input type="text" name="1" value="1"/>').add($('<input type="text" name="2" value="2"/>')); obj = $inputs.serializeJSON(); expect(obj).toEqual({"1": "1", "2": "2"}); }); it('accepts a jQuery object with forms and inputs', function() { var $form1, $form2, $els; $form1 = $('<form>'); $form1.append($('<input type="text" name="1" value="1"/>')); $form1.append($('<input type="text" name="2" value="2"/>')); $form2 = $('<form>'); $form2.append($('<input type="text" name="3" value="3"/>')); $form2.append($('<input type="text" name="4" value="4"/>')); $inputs = $('<input type="text" name="5" value="5"/>').add($('<input type="text" name="6" value="6"/>')); $els = $form1.add($form2).add($inputs); obj = $els.serializeJSON(); expect(obj).toEqual({"1": "1", "2": "2", "3": "3", "4": "4", "5": "5", "6": "6"}); }); } describe('with simple one-level attributes', function() { beforeEach(function() { $form = $('<form>'); $form.append($('<input type="text" name="firstName" value="Mario"/>')); $form.append($('<input type="text" name="lastName" value="Izquierdo"/>')); }); it("serializes into plain attributes", function() { obj = $form.serializeJSON(); expect(obj).toEqual({ firstName: "Mario", lastName: "Izquierdo" }); }); }); describe('with nested object attributes', function() { beforeEach(function() { $form = $('<form>'); $form.append($('<input type="text" name="address[city]" value="San Francisco"/>')); $form.append($('<input type="text" name="address[state][name]" value="California"/>')); $form.append($('<input type="text" name="address[state][abbr]" value="CA"/>')); }); it("serializes into nested object attributes", function() { obj = $form.serializeJSON(); expect(obj).toEqual({ address: { city: "San Francisco", state: { name: "California", abbr: "CA" } } }); }); }); describe('with empty brackets (arrays)', function() { beforeEach(function() { $form = $('<form>'); $form.append($('<input type="text" name="jobbies[]" value="code"/>')); $form.append($('<input type="text" name="jobbies[]" value="climbing"/>')); }); it("pushes elements into an array", function() { obj = $form.serializeJSON(); expect(obj).toEqual({ jobbies: ['code', 'climbing'] }); }); }); describe('with attribute names that are integers', function() { beforeEach(function() { $form = $('<form>'); $form.append($('<input type="text" name="foo[0]" value="zero"/>')); $form.append($('<input type="text" name="foo[1]" value="one"/>')); $form.append($('<input type="text" name="foo[2][0]" value="two-zero"/>')); $form.append($('<input type="text" name="foo[2][1]" value="two-one"/>')); }); it("still creates objects with keys that are strings", function() { obj = $form.serializeJSON(); expect(obj).toEqual({ 'foo': { '0': 'zero', '1': 'one', '2': { '0': 'two-zero', '1': 'two-one' } } }); }); }); describe('with a select multiple', function() { it("serializes all the selected elements", function() { $form = $('<form>'); $form.append($('<select name="camels[]" multiple><option value="1" selected>1</option><option value="2">2</option><option value="3" selected>3</option></select>')); obj = $form.serializeJSON(); expect(obj).toEqual({camels: ['1','3']}); // selected elements included as an array }); it("ignores the field if nothing is selected", function() { $form = $('<form>'); $form.append($('<select name="camels[]" multiple><option value="1">1</option><option value="2">2</option><option value="3">3</option></select>')); obj = $form.serializeJSON(); expect(obj).toEqual({ }); // nothing is serialized }); it("can be set to empty string using a hidden field", function() { $form = $('<form>'); $form.append($('<input type="hidden" name="camels:array" value="[]" />')); $form.append($('<select name="camels[]" multiple><option value="1">1</option><option value="2">2</option><option value="3">3</option></select>')); obj = $form.serializeJSON(); expect(obj).toEqual({camels: []}); // empty list }); }); describe('with complext array of objects', function() { beforeEach(function() { $form = $('<form>'); $form.append($('<input type="text" name="projects[][name]" value="serializeJSON" />')); $form.append($('<input type="text" name="projects[][language]" value="javascript" />')); $form.append($('<input type="text" name="projects[][name]" value="bettertabs" />')); $form.append($('<input type="text" name="projects[][language]" value="ruby" />')); $form.append($('<input type="text" name="projects[][name]" value="formwell" />')); $form.append($('<input type="text" name="projects[][languages][]" value="coffeescript" />')); $form.append($('<input type="text" name="projects[][languages][]" value="javascript" />')); }); it("serializes into array of objects", function() { obj = $form.serializeJSON(); expect(obj).toEqual({ projects: [ { name: "serializeJSON", language: "javascript" }, { name: "bettertabs", language: "ruby" }, { name: "formwell", languages: ["coffeescript", "javascript"] }, ] }); }); }); describe("with existing properties", function() { beforeEach(function() { $form = $('<form>'); $form.append($('<input type="text" name="str" value="String" />')); $form.append($('<input type="text" name="str" value="String Override" />')); $form.append($('<input type="text" name="array" value="a string that was there before" />')); $form.append($('<input type="text" name="array[]" value="one" />')); $form.append($('<input type="text" name="array[]" value="two" />')); $form.append($('<input type="text" name="crosstype" value="str" />')); $form.append($('<input type="text" name="crosstype:number" value="2" />')); $form.append($('<input type="text" name="crosstype:boolean" value="true" />')); $form.append($('<input type="hidden" name="object" value=""/>')); $form.append($('<input type="text" name="object[nested]" value="blabla" />')); $form.append($('<input type="text" name="object[nested][nested]" value="final value" />')); }); it("overrides to keep the last property value", function() { obj = $form.serializeJSON(); expect(obj).toEqual({ str: "String Override", array: ["one", "two"], crosstype: true, object: { nested: { nested: "final value" }} }); }); }); describe('unchecked checkboxes', function() { it('are ignored by default (same as regural HTML forms and the jQuery.serializeArray function)', function() { $form = $('<form>'); $form.append($('<input type="checkbox" name="check1" value="yes"/>')); $form.append($('<input type="checkbox" name="check2" value="yes"/>')); obj = $form.serializeJSON(); expect(obj).toEqual({}); // empty because unchecked checkboxes are ignored }); it('are ignored also in arrays', function() { $form = $('<form>'); $form.append($('<input type="checkbox" name="flags[]" value="green"/>')); $form.append($('<input type="checkbox" name="flags[]" value="red"/>')); obj = $form.serializeJSON(); expect(obj).toEqual({}); }); it('could use a hidden field and a custom parser to force an empty array in an array of unchecked checkboxes', function() { $form = $('<form>'); $form.append($('<input type="hidden" name="flags" value="[]"/>')); $form.append($('<input type="checkbox" name="flags[]" value="green"/>')); $form.append($('<input type="checkbox" name="flags[]" value="red"/>')); obj = $form.serializeJSON({parseWithFunction: function(val){ return val == '[]' ? [] : val }}); expect(obj).toEqual({'flags': []}); $form.find('input[value="red"]').prop('checked', true); obj = $form.serializeJSON({parseWithFunction: function(val){ return val == '[]' ? [] : val }}); expect(obj).toEqual({'flags': ['red']}); }); it('could use a hidden field with type :array to force an empty array in an array of unchecked checkboxes', function() { $form = $('<form>'); $form.append($('<input type="hidden" name="flags:array" value="[]"/>')); $form.append($('<input type="checkbox" name="flags[]" value="green"/>')); $form.append($('<input type="checkbox" name="flags[]" value="red"/>')); obj = $form.serializeJSON(); expect(obj).toEqual({'flags': []}); $form.find('input[value="red"]').prop('checked', true); obj = $form.serializeJSON(); expect(obj).toEqual({'flags': ['red']}); }); it('can be combined with hidden fields to set the false value', function() { $form = $('<form>'); $form.append($('<input type="hidden" name="truthy" value="0"/>')); $form.append($('<input type="checkbox" name="truthy" value="1" checked="checked"/>')); // should keep "1" $form.append($('<input type="hidden" name="falsy" value="0"/>')); $form.append($('<input type="checkbox" name="falsy" value="1"/>')); // should keep "0", from the hidden field obj = $form.serializeJSON(); expect(obj).toEqual({ truthy: '1', // from the checkbok falsy: '0' // from the hidden field }); }); it('should be ignored if they have no name', function() { $form = $('<form>'); $form.append($('<input type="checkbox" value="yes"/>')); $form.append($('<input type="checkbox" value="yes"/>')); obj = $form.serializeJSON({checkboxUncheckedValue: 'NOPE'}); expect(obj).toEqual({}); }); it('use the checkboxUncheckedValue option if defined', function() { $form = $('<form>'); $form.append($('<input type="checkbox" name="check1" value="yes"/>')); $form.append($('<input type="checkbox" name="check2" value="yes"/>')); obj = $form.serializeJSON({checkboxUncheckedValue: 'NOPE'}); expect(obj).toEqual({check1: 'NOPE', check2: 'NOPE'}); }); it('use the attr data-unchecked-value if defined', function() { $form = $('<form>'); $form.append($('<input type="checkbox" name="check1" value="yes"/>')); // ignored $form.append($('<input type="checkbox" name="check2" value="yes" data-unchecked-value="NOPE"/>')); // with data-unchecked-value uses that value obj = $form.serializeJSON(); // NOTE: no checkboxUncheckedValue used expect(obj).toEqual({check2: 'NOPE'}); }); }); describe('value types', function() { describe(':number', function() { it('parses numbers', function() { $form = $('<form>'); $form.append($('<input type="text" name="i1:number" value="10"/>')); $form.append($('<input type="text" name="i2:number" value="10.5"/>')); $form.append($('<input type="text" name="un" value="10"/>')); obj = $form.serializeJSON(); expect(obj).toEqual({i1: 10, i2: 10.5, un: '10'}); }); it('parses non numbers to NaN', function(){ $form = $('<form>'); $form.append($('<input type="text" name="i1:number" value="text"/>')); $form.append($('<input type="text" name="i2:number" value="null"/>')); $form.append($('<input type="text" name="i3:number" value="false"/>')); obj = $form.serializeJSON(); expect(obj).toEqual({i1: NaN, i2: NaN, i3: NaN}); }); }); describe(':boolean', function() { it('parses anything that looks truthy to true', function() { $form = $('<form>'); $form.append($('<input type="text" name="b1:boolean" value="true"/>')); $form.append($('<input type="text" name="b2:boolean" value="TRUE"/>')); $form.append($('<input type="text" name="b3:boolean" value="yes"/>')); $form.append($('<input type="text" name="b4:boolean" value="[1,2,3]"/>')); $form.append($('<input type="text" name="b5:boolean" value="Bla bla bla bla ..."/>')); obj = $form.serializeJSON(); expect(obj).toEqual({b1: true, b2: true, b3: true, b4: true, b5: true}); }); it('parses anything that looks falsy to false', function() { $form = $('<form>'); $form.append($('<input type="text" name="b1:boolean" value="false"/>')); $form.append($('<input type="text" name="b2:boolean" value="null"/>')); $form.append($('<input type="text" name="b3:boolean" value="undefined"/>')); $form.append($('<input type="text" name="b4:boolean" value=""/>')); $form.append($('<input type="text" name="b5:boolean" value="0"/>')); obj = $form.serializeJSON(); expect(obj).toEqual({b1: false, b2: false, b3: false, b4: false, b5: false}); }); }); describe(':null', function() { it('parses anything that looks falsy to null', function() { $form = $('<form>'); $form.append($('<input type="text" name="b1:null" value="false"/>')); $form.append($('<input type="text" name="b2:null" value="null"/>')); $form.append($('<input type="text" name="b3:null" value="undefined"/>')); $form.append($('<input type="text" name="b4:null" value=""/>')); $form.append($('<input type="text" name="b5:null" value="0"/>')); obj = $form.serializeJSON(); expect(obj).toEqual({b1: null, b2: null, b3: null, b4: null, b5: null}); }); it('keeps anything that looks truthy as string', function() { $form = $('<form>'); $form.append($('<input type="text" name="b1:null" value="true"/>')); $form.append($('<input type="text" name="b2:null" value="TRUE"/>')); $form.append($('<input type="text" name="b3:null" value="yes"/>')); $form.append($('<input type="text" name="b4:null" value="[1,2,3]"/>')); $form.append($('<input type="text" name="b5:null" value="Bla bla bla bla ..."/>')); obj = $form.serializeJSON(); expect(obj).toEqual({b1: 'true', b2: 'TRUE', b3: 'yes', b4: '[1,2,3]', b5: "Bla bla bla bla ..."}); }); }); describe(':string', function() { it('keeps everything as string', function() { $form = $('<form>'); $form.append($('<input type="text" name="b1:string" value="true"/>')); $form.append($('<input type="text" name="b2:string" value="TRUE"/>')); $form.append($('<input type="text" name="b3:string" value="yes"/>')); $form.append($('<input type="text" name="b4:string" value="[1,2,3]"/>')); $form.append($('<input type="text" name="b5:string" value="Bla bla bla bla ..."/>')); obj = $form.serializeJSON(); expect(obj).toEqual({b1: 'true', b2: 'TRUE', b3: 'yes', b4: '[1,2,3]', b5: "Bla bla bla bla ..."}); }); it('is useful to override other parse options', function() { $form = $('<form>'); $form.append($('<input type="text" name="b1:string" value="true"/>')); $form.append($('<input type="text" name="b2:string" value="1"/>')); $form.append($('<input type="text" name="b3:string" value="null"/>')); $form.append($('<input type="text" name="b4:string" value=""/>')); obj = $form.serializeJSON({parseAll: true, parseWithFunction: function(val){return val === '' ? null : val}}); expect(obj).toEqual({b1: 'true', b2: '1', b3: 'null', b4: ''}); }); }); describe(':array', function() { it('parses arrays with JSON.parse', function() { $form = $('<form>'); $form.append($('<input type="text" name="b1:array" value="[]"/>')); $form.append($('<input type="text" name="b2:array" value=\'["my", "stuff"]\'/>')); $form.append($('<input type="text" name="b3:array" value="[1,2,3]"/>')); $form.append($('<input type="text" name="b4:array" value="[1,[2,[3]]]"/>')); obj = $form.serializeJSON(); expect(obj).toEqual({b1: [], b2: ['my', 'stuff'], b3: [1,2,3], b4: [1,[2,[3]]]}); }); it('raises an error if the array can not be parsed', function() { $form = $('<form>'); $form.append($('<input type="text" name="b1:array" value="<NOT_AN_ARRAY>"/>')); expect(function(){$form.serializeJSON()}).toThrow(); }); }); describe(':object', function() { it('parses objects with JSON.parse', function() { $form = $('<form>'); $form.append($('<input type="text" name="b1:object" value="{}"/>')); $form.append($('<input type="text" name="b2:object" value=\'{"my": "stuff"}\'/>')); $form.append($('<input type="text" name="b3:object" value=\'{"my": {"nested": "stuff"}}\'/>')); obj = $form.serializeJSON(); expect(obj).toEqual({b1: {}, b2: {"my": "stuff"}, b3: {"my": {"nested": "stuff"}}}); }); it('raises an error if the obejct can not be parsed', function() { $form = $('<form>'); $form.append($('<input type="text" name="b1:object" value="<NOT_AN_OBJECT>"/>')); expect(function(){$form.serializeJSON()}).toThrow(); }); }); describe(':skip', function() { it('removes the field from the parsed result', function() { $form = $('<form>'); $form.append($('<input type="text" name="b1" value="Im in"/>')); $form.append($('<input type="text" name="b2:skip" value="Im out"/>')); $form.append($('<input type="text" name="b3[out]:skip" value="Im out"/>')); obj = $form.serializeJSON(); expect(obj).toEqual({b1: 'Im in'}); }); it('raises an error if the obejct can not be parsed', function() { $form = $('<form>'); $form.append($('<input type="text" name="b1:object" value="<NOT_AN_OBJECT>"/>')); expect(function(){$form.serializeJSON()}).toThrow(); }); }); describe(':auto', function() { it('parses Strings, Booleans and Nulls if they look like they could be one of them (same as parseAll option)', function() { $form = $('<form>'); $form.append($('<input type="text" name="Numeric 0:auto" value="0"/>')); $form.append($('<input type="text" name="Numeric 1:auto" value="1"/>')); $form.append($('<input type="text" name="Numeric 2.2:auto" value="2.2"/>')); $form.append($('<input type="text" name="Numeric -2.25:auto" value="-2.25"/>')); $form.append($('<input type="text" name="Bool true:auto" value="true"/>')); $form.append($('<input type="text" name="Bool false:auto" value="false"/>')); $form.append($('<input type="text" name="Null:auto" value="null"/>')); $form.append($('<input type="text" name="String:auto" value="text is always string"/>')); $form.append($('<input type="text" name="Empty:auto" value=""/>')); obj = $form.serializeJSON(); expect(obj).toEqual({ "Numeric 0": 0, "Numeric 1": 1, "Numeric 2.2": 2.2, "Numeric -2.25": -2.25, "Bool true": true, "Bool false": false, "Null": null, "String": "text is always string", "Empty": "" }); }); it('does not auto-recognize arrays or objects', function() { $form = $('<form>'); $form.append($('<input type="text" name="empty array:auto" value="[]"/>')); $form.append($('<input type="text" name="array:auto" value="[1,2,3]"/>')); $form.append($('<input type="text" name="empty object:auto" value="{}"/>')); $form.append($('<input type="text" name="object:auto" value="{one: 1}"/>')); obj = $form.serializeJSON(); expect(obj).toEqual({ "empty array": "[]", "array": "[1,2,3]", "empty object": "{}", "object": "{one: 1}" }); // they are still strings }); }); describe('invalid types', function() { it('raises an error if the type is not known', function() { $form = $('<form>'); $form.append($('<input type="text" name="b1:kaka" value="not a valid type"/>')); expect(function(){ $form.serializeJSON() }) .toThrow(new Error("serializeJSON ERROR: Invalid type kaka found in input name 'b1:kaka', please use one of string, number, boolean, null, array, object, auto, skip")); }); }); describe('form with multiple types', function() { it("parses every type as expected", function() { // EXAMPLE from the README file $form = $('<form>'); $form.append($('<input type="text" name="notype" value="default type is :string"/>')); $form.append($('<input type="text" name="string:string" value=":string type overrides parsing options"/>')); $form.append($('<input type="text" name="excludes:skip" value="Use :skip to not include this field in the result"/>')); $form.append($('<input type="text" name="number[1]:number" value="1"/>')); $form.append($('<input type="text" name="number[1.1]:number" value="1.1"/>')); $form.append($('<input type="text" name="number[other stuff]:number" value="other stuff"/>')); $form.append($('<input type="text" name="boolean[true]:boolean" value="true"/>')); $form.append($('<input type="text" name="boolean[false]:boolean" value="false"/>')); $form.append($('<input type="text" name="boolean[0]:boolean" value="0"/>')); $form.append($('<input type="text" name="null[null]:null" value="null"/>')); $form.append($('<input type="text" name="null[other stuff]:null" value="other stuff"/>')); $form.append($('<input type="text" name="auto[string]:auto" value="text with stuff"/>')); $form.append($('<input type="text" name="auto[0]:auto" value="0"/>')); $form.append($('<input type="text" name="auto[1]:auto" value="1"/>')); $form.append($('<input type="text" name="auto[true]:auto" value="true"/>')); $form.append($('<input type="text" name="auto[false]:auto" value="false"/>')); $form.append($('<input type="text" name="auto[null]:auto" value="null"/>')); $form.append($('<input type="text" name="auto[list]:auto" value="[1, 2, 3]"/>')); $form.append($('<input type="text" name="array[empty]:array" value="[]"/>')); $form.append($('<input type="text" name="array[not empty]:array" value="[1, 2, 3]"/>')); $form.append($('<input type="text" name="object[empty]:object" value="{}"/>')); $form.append($('<input type="text" name="object[not empty]:object" value=\'{"my": "stuff"}\'/>')); obj = $form.serializeJSON(); expect(obj).toEqual({ "notype": "default type is :string", "string": ":string type overrides parsing options", // :skip type removes the field from the output "number": { "1": 1, "1.1": 1.1, "other stuff": NaN, // <-- Other stuff parses as NaN (Not a Number) }, "boolean": { "true": true, "false": false, "0": false, // <-- "false", "null", "undefined", "", "0" parse as false }, "null": { "null": null, // <-- "false", "null", "undefined", "", "0" parse as null "other stuff": "other stuff" }, "auto": { // works as the parseAll option "string": "text with stuff", "0": 0, // <-- parsed as number "1": 1, // <-- parsed as number "true": true, // <-- parsed as boolean "false": false, // <-- parsed as boolean "null": null, // <-- parsed as null "list": "[1, 2, 3]" // <-- array and object types are not auto-parsed }, "array": { // <-- works using JSON.parse "empty": [], "not empty": [1,2,3] }, "object": { // <-- works using JSON.parse "empty": {}, "not empty": {"my": "stuff"} } }); }); }); describe('data-value-type attribute', function() { it("should set type if field name do not contain :type definition", function() { $form = $('<form>'); $form.append($('<input type="text" name="fooData" data-value-type="alwaysBoo" value="0"/>')); $form.append($('<input type="text" name="fooDataWithBrackets[kokoszka]" data-value-type="alwaysBoo" value="0"/>')); $form.append($('<input type="text" name="fooDataWithBrackets[kokoszka i cos innego]" data-value-type="alwaysBoo" value="0"/>')); $form.append($('<input type="text" name="foo:alwaysBoo" data-value-type="string" value="0"/>')); $form.append($('<input type="text" name="notype" value="default type is :string"/>')); $form.append($('<input type="text" name="stringData" data-value-type="string" value="data-value-type=string type overrides parsing options"/>')); $form.append($('<input type="text" name="string:string" data-value-type="boolean" value=":string type overrides parsing options"/>')); $form.append($('<input type="text" name="excludes" data-value-type="skip" value="Use :skip to not include this field in the result"/>')); $form.append($('<input type="text" name="numberData" data-value-type="number" value="1"/>')); $form.append($('<input type="text" name="numberData[A]" data-value-type="number" value="1"/>')); $form.append($('<input type="text" name="numberData[B][C]" data-value-type="number" value="2"/>')); $form.append($('<input type="text" name="numberData[D][E][F]" data-value-type="number" value="3"/>')); $form.append($('<input type="text" name="number" data-value-type="number" value="1"/>')); $form.append($('<select name="selectNumber" data-value-type="number"><option value="1">Value 1</option><option selected value="2">Value 2</option></select>')); obj = $form.serializeJSON({ customTypes: { alwaysBoo: function() { return "Boo" } } }); expect(obj).toEqual({ "fooDataWithBrackets": { kokoszka: "Boo", "kokoszka i cos innego": "Boo" }, "fooData": "Boo", "foo": "Boo", "notype": "default type is :string", "stringData": "data-value-type=string type overrides parsing options", "string": ":string type overrides parsing options", "numberData": { A: 1, B: { C: 2 }, D: { E: { F: 3 } } }, "number": 1, "selectNumber": 2 }); }); if ($.fn.jquery) { // not supported on Zepto it("also works for matched inputs (not just forms) if they have the data-value-type attribute", function () { $inputs = $( '<input type="text" name="fooData" data-value-type="alwaysBoo" value="0"/>' + '<input type="text" name="foo:alwaysBoo" data-value-type="string" value="0"/>' + '<input type="text" name="notype" value="default type is :string"/>' + '<input type="text" name="stringData" data-value-type="string" value="data-value-type=string type overrides parsing options"/>' + '<input type="text" name="number" data-value-type="number" value="1"/>' ); obj = $inputs.serializeJSON({ customTypes: { alwaysBoo: function() { return "Boo" } } }); expect(obj).toEqual({ "fooData": "Boo", "foo": "Boo", "notype": "default type is :string", "stringData": "data-value-type=string type overrides parsing options", "number": 1 }); }); } }); describe('data-skip-falsy attribute', function() { it("allows to skip faily fields, just like with the option skipFalsyValuesForFields", function() { $form2 = $('<form>'); $form2.append($('<input type="text" name="skipFalsyZero:number" data-skip-falsy="true" value="0"/>')); $form2.append($('<input type="text" name="skipFalsyFalse:boolean" data-skip-falsy="true" value="false"/>')); $form2.append($('<input type="text" name="skipFalsyNull:null" data-skip-falsy="true" value="null"/>')); $form2.append($('<input type="text" name="skipFalsyEmpty:string" data-skip-falsy="true" value=""/>')); $form2.append($('<input type="text" name="skipFalsyFoo:string" data-skip-falsy="true" value="foo"/>')); $form2.append($('<input type="text" name="zero:number" value="0"/>')); $form2.append($('<input type="text" name="foo:string" value="foo"/>')); $form2.append($('<input type="text" name="empty:string" value=""/>')); obj = $form2.serializeJSON(); expect(obj["skipFalsyZero"]).toEqual(undefined); // skip expect(obj["skipFalsyFalse"]).toEqual(undefined); // skip expect(obj["skipFalsyNull"]).toEqual(undefined); // skip expect(obj["skipFalsyEmpty"]).toEqual(undefined); // skip expect(obj["skipFalsyFoo"]).toEqual("foo"); expect(obj["zero"]).toEqual(0); expect(obj["foo"]).toEqual("foo"); expect(obj["empty"]).toEqual(""); }); it("overrides the option skipFalsyValuesForFields", function() { $form2 = $('<form>'); $form2.append($('<input type="text" name="skipFalsyZero:number" data-skip-falsy="true" value="0"/>')); $form2.append($('<input type="text" name="skipFalsyFalse:boolean" data-skip-falsy="false" value="false"/>')); $form2.append($('<input type="text" name="skipFalsyNull:null" data-skip-falsy="false" value="null"/>')); $form2.append($('<input type="text" name="skipFalsyEmpty:string" data-skip-falsy="true" value=""/>')); $form2.append($('<input type="text" name="skipFalsyFoo:string" data-skip-falsy="true" value="foo"/>')); $form2.append($('<input type="text" name="zero:number" value="0"/>')); $form2.append($('<input type="text" name="empty:string" value=""/>')); obj = $form2.serializeJSON({ skipFalsyValuesForFields: [ // using skipFalsyValuesForFields option 'skipFalsyZero', 'skipFalsyFalse', 'skipFalsyNull', 'zero' ]}); expect(obj["skipFalsyZero"]).toEqual(undefined); // skip from attr and opt expect(obj["skipFalsyFalse"]).toEqual(false); // not skip (attr override) expect(obj["skipFalsyNull"]).toEqual(null); // not skip (attr override) expect(obj["skipFalsyEmpty"]).toEqual(undefined); // skip from attr expect(obj["skipFalsyFoo"]).toEqual("foo"); expect(obj["zero"]).toEqual(undefined); // skip from opt expect(obj["empty"]).toEqual(""); }); it("overrides the option skipFalsyValuesForTypes", function() { $form2 = $('<form>'); $form2.append($('<input type="text" name="skipFalsyZero:number" data-skip-falsy="true" value="0"/>')); $form2.append($('<input type="text" name="skipFalsyFalse:boolean" data-skip-falsy="false" value="false"/>')); $form2.append($('<input type="text" name="skipFalsyNull:null" data-skip-falsy="false" value="null"/>')); $form2.append($('<input type="text" name="skipFalsyEmpty:string" data-skip-falsy="true" value=""/>')); $form2.append($('<input type="text" name="skipFalsyFoo:string" data-skip-falsy="true" value="foo"/>')); $form2.append($('<input type="text" name="zero:number" value="0"/>')); $form2.append($('<input type="text" name="empty:string" value=""/>')); $form2.append($('<input type="text" name="null:null" value="null"/>')); obj = $form2.serializeJSON({ skipFalsyValuesForTypes: [ // using skipFalsyValuesForFields option 'number', 'boolean', 'null' ]}); expect(obj["skipFalsyZero"]).toEqual(undefined); // skip from attr and opt expect(obj["skipFalsyFalse"]).toEqual(false); // not skip (attr override) expect(obj["skipFalsyNull"]).toEqual(null); // not skip (attr override) expect(obj["skipFalsyEmpty"]).toEqual(undefined); // skip from attr expect(obj["skipFalsyFoo"]).toEqual("foo"); expect(obj["zero"]).toEqual(undefined); // skip from opt expect(obj["empty"]).toEqual(""); expect(obj["null"]).toEqual(undefined); // skip from opt }); }); }); // options describe('options', function() { beforeEach(function() { $form = $('<form>'); $form.append($('<input type="text" name="Numeric 0" value="0"/>')); $form.append($('<input type="text" name="Numeric 1" value="1"/>')); $form.append($('<input type="text" name="Numeric 2.2" value="2.2"/>')); $form.append($('<input type="text" name="Numeric -2.25" value="-2.25"/>')); $form.append($('<input type="text" name="Bool true" value="true"/>')); $form.append($('<input type="text" name="Bool false" value="false"/>')); $form.append($('<input type="text" name="Null" value="null"/>')); $form.append($('<input type="text" name="String" value="text is always string"/>')); $form.append($('<input type="text" name="Empty" value=""/>')); }); describe('defaults (defaultOptions)', function() { it("returns strings", function() { obj = $form.serializeJSON({}); // empty object should be translated to default options expect(obj).toEqual({ "Numeric 0": "0", "Numeric 1": "1", "Numeric 2.2": "2.2", "Numeric -2.25": "-2.25", "Bool true": "true", "Bool false": "false", "Null": "null", "String": "text is always string", "Empty": "" }); }); }); describe('validateOptions', function() { it("should raise an error if the option is not one of the valid options", function() { expect(function(){ $form.serializeJSON({invalidOption: true}); }) .toThrow(new Error("serializeJSON ERROR: invalid option 'invalidOption'. Please use one of checkboxUncheckedValue, parseNumbers, parseBooleans, parseNulls, parseAll, parseWithFunction, skipFalsyValuesForTypes, skipFalsyValuesForFields, customTypes, defaultTypes, useIntKeysAsArrayIndex")); }); }); describe('parseNumbers', function() { it("returns numbers for the numeric string values", function() { obj = $form.serializeJSON({parseNumbers: true}); expect(obj).toEqual({ "Numeric 0": 0, "Numeric 1": 1, "Numeric 2.2": 2.2, "Numeric -2.25": -2.25, "Bool true": "true", "Bool false": "false", "Null": "null", "String": "text is always string", "Empty": "" }); }); }); describe('parseBooleans', function() { it("returns booleans for the 'true'/'false' values", function() { obj = $form.serializeJSON({parseBooleans: true}); expect(obj).toEqual({ "Numeric 0": "0", "Numeric 1": "1", "Numeric 2.2": "2.2", "Numeric -2.25": "-2.25", "Bool true": true, "Bool false": false, "Null": "null", "String": "text is always string", "Empty": "" }); }); }); describe('parseNulls', function() { it("returns null for the 'null' values", function() { obj = $form.serializeJSON({parseNulls: true}); // empty object should be translated to default options expect(obj).toEqual({ "Numeric 0": "0", "Numeric 1": "1", "Numeric 2.2": "2.2", "Numeric -2.25": "-2.25", "Bool true": "true", "Bool false": "false", "Null": null, "String": "text is always string", "Empty": "" }); }); }); describe('parseAll', function() { it("parses all possible values", function() { obj = $form.serializeJSON({parseAll: true}); expect(obj).toEqual({ "Numeric 0": 0, "Numeric 1": 1, "Numeric 2.2": 2.2, "Numeric -2.25": -2.25, "Bool true": true, "Bool false": false, "Null": null, "String": "text is always string", "Empty": "" }); }); }); describe('parseWithFunction custom parser', function() { it("uses the passed in function to parse values", function() { var myParser = function(val) { return val === "true" ? 1 : 0}; obj = $form.serializeJSON({parseWithFunction: myParser}); expect(obj).toEqual({ "Numeric 0": 0, "Numeric 1": 0, "Numeric 2.2": 0, "Numeric -2.25": 0, "Bool true": 1, "Bool false": 0, "Null": 0, "String": 0, "Empty": 0 }); }); it("can be combined with other parse options", function() { var myParser = function(val) { return typeof(val) === "number" ? 1 : 0}; obj = $form.serializeJSON({parseNumbers: true, parseWithFunction: myParser}); expect(obj).toEqual({ "Numeric 0": 1, "Numeric 1": 1, "Numeric 2.2": 1, "Numeric -2.25": 1, "Bool true": 0, "Bool false": 0, "Null": 0, "String": 0, "Empty": 0 }); }); }); describe('skipFalsyValuesForFields', function() { it("skips serialization of falsy values but only on inputs with given names", function() { obj = $form.serializeJSON({skipFalsyValuesForFields: ['Empty', 'Null', 'Numeric 0', 'String']}); expect(obj).toEqual({ "Numeric 0": "0", // "0" as :string is not falsy "Numeric 1": "1", "Numeric 2.2": "2.2", "Numeric -2.25": "-2.25", "Bool true": "true", "Bool false": "false", "Null": "null", // "null" as :string is not falsy "String": "text is always string" // "Empty" skip }); }); it("checks on values after they were parsed by the given types", function() { // with parseAll = true, the values are typed obj = $form.serializeJSON({parseAll: true, skipFalsyValuesForFields: ['Empty', 'Null', 'Numeric 0', 'String']}); expect(obj).toEqual({ // "Numeric 0" skip "Numeric 1": 1, "Numeric 2.2": 2.2, "Numeric -2.25": -2.25, "Bool true": true, "Bool false": false, // not skip because was not included in list of names "String": "text is always string" // "Null" skip // "Empty" skip }); }); }); describe('skipFalsyValuesForTypes', function() { it("skips serialization of falsy values for on inputs of the given types", function() { var $form2 = $('<form>'); $form2.append($('<input type="text" name="Num0:number" value="0"/>')); $form2.append($('<input type="text" name="Num1:number" value="1"/>')); $form2.append($('<input type="text" name="NaN:number" value="wololoo"/>')); $form2.append($('<input type="text" name="Num0attr" value="0" data-value-type="number"/>')); $form2.append($('<input type="text" name="Num1attr" value="1" data-value-type="number"/>')); $form2.append($('<input type="text" name="Bool true:boolean" value="true"/>')); $form2.append($('<input type="text" name="Bool false:boolean" value="false"/>')); $form2.append($('<input type="text" name="Text:string" value="text is always string"/>')); $form2.append($('<input type="text" name="Empty String:string" value=""/>')); $form2.append($('<input type="text" name="Empty Implicit" value=""/>')); // :string type is implicit $form2.append($('<input type="text" name="Array:array" value="[1, 2]"/>')); $form2.append($('<input type="text" name="Empty Array:array" value="[]"/>')); $form2.append($('<input type="text" name="Null:null" value="null"/>')); obj = $form2.serializeJSON({skipFalsyValuesForTypes: ["number", "boolean", "string", "array", "null"]}); expect(obj["Num0"]).toEqual(undefined); // skip expect(obj["Num1"]).toEqual(1); expect(obj["NaN"]).toEqual(undefined); // skip expect(obj["Num0attr"]).toEqual(undefined); // skip expect(obj["Num1attr"]).toEqual(1); expect(obj["Bool true"]).toEqual(true); expect(obj["Bool false"]).toEqual(undefined); // skip expect(obj["Text"]).toEqual("text is always string"); expect(obj["Empty String"]).toEqual(undefined); expect(obj["Empty Implicit"]).toEqual(undefined); expect(obj["Array"]).toEqual([1, 2]); expect(obj["Empty Array"]).toEqual([]); // Not skip! empty arrays are not falsy expect(obj["Null"]).toEqual(undefined); // skip obj = $form2.serializeJSON({skipFalsyValuesForTypes: ["number"]}); // skip only falsy numbers expect(obj["Num0"]).toEqual(undefined); // skip expect(obj["Num1"]).toEqual(1); expect(obj["NaN"]).toEqual(undefined); // skip expect(obj["Num0attr"]).toEqual(undefined); // skip expect(obj["Num1attr"]).toEqual(1); expect(obj["Bool true"]).toEqual(true); expect(obj["Bool false"]).toEqual(false); expect(obj["Text"]).toEqual("text is always string"); expect(obj["Empty String"]).toEqual(""); expect(obj["Empty Implicit"]).toEqual(""); expect(obj["Array"]).toEqual([1, 2]); expect(obj["Empty Array"]).toEqual([]); expect(obj["Null"]).toEqual(null); }); }); describe('checkboxUncheckedValue', function() { it('uses that value for unchecked checkboxes', function() { $form = $('<form>'); $form.append($('<input type="checkbox" name="check1" value="yes"/>')); $form.append($('<input type="checkbox" name="check2" value="yes"/>')); $form.append($('<input type="checkbox" name="check3" value="yes" checked/>')); obj = $form.serializeJSON({checkboxUncheckedValue: 'NOPE'}); expect(obj).toEqual({check1: 'NOPE', check2: 'NOPE', check3: 'yes'}); }); it('is overriden by data-unchecked-value attribute', function() { $form = $('<form>'); $form.append($('<input type="checkbox" name="check1" value="yes"/>')); $form.append($('<input type="checkbox" name="check2" value="yes" data-unchecked-value="OVERRIDE"/>')); $form.append($('<input type="checkbox" name="check3" value="yes" checked/>')); obj = $form.serializeJSON({checkboxUncheckedValue: 'NOPE'}); expect(obj).toEqual({check1: 'NOPE', check2: 'OVERRIDE', check3: 'yes'}); }); it('is parsed by parse options', function() { $form = $('<form>'); $form.append($('<input type="checkbox" name="check1" value="true"/>')); $form.append($('<input type="checkbox" name="check2" value="true" data-unchecked-value="0"/>')); $form.append($('<input type="checkbox" name="check3" value="true" checked/>')); obj = $form.serializeJSON({checkboxUncheckedValue: 'false', parseBooleans: true, parseNumbers: true}); expect(obj).toEqual({check1: false, check2: 0, check3: true}); }); it('is parsed by custom parseWithFunction', function() { $form = $('<form>'); $form.append($('<input type="checkbox" name="check1" value="yes"/>')); $form.append($('<input type="checkbox" name="check2" value="yes" data-unchecked-value="NOPE"/>')); $form.append($('<input type="checkbox" name="check3" value="yes" checked/>')); var parser = function(val) { return val == 'yes' }; obj = $form.serializeJSON({checkboxUncheckedValue: 'no', parseWithFunction: parser}); expect(obj).toEqual({check1: false, check2: false, check3: true}); }); if ($.fn.jquery) { // not supported on Zepto it('works on multiple forms and inputs', function() { var $form1, $form2, $els; $form1 = $('<form>'); $form1.append($('<input type="text" name="form1[title]" value="form1"/>')); $form1.append($('<input type="checkbox" name="form1[check1]" value="true"/>')); $form1.append($('<input type="checkbox" name="form1[check2]" value="true" data-unchecked-value="NOPE"/>')); $form2 = $('<form>'); $form1.append($('<input type="text" name="form2[title]" value="form2"/>')); $form2.append($('<input type="checkbox" name="form2[check1]" value="true" checked="checked"/>')); $form2.append($('<input type="checkbox" name="form2[check2]" value="true" />')); $inputs = $() .add($('<input type="text" name="inputs[title]" value="inputs"/>')) .add($('<input type="checkbox" name="inputs[check1]" value="true" checked="checked"/>')) .add($('<input type="checkbox" name="inputs[check2]" value="true"/>')) .add($('<input type="checkbox" name="inputs[check3]" value="true" data-unchecked-value="NOPE"/>')); $els = $form1.add($form2).add($inputs); obj = $els.serializeJSON({checkboxUncheckedValue: 'false'}); expect(obj).toEqual({ form1: { title: 'form1', check1: 'false', check2: 'NOPE', }, form2: { title: 'form2', check1: 'true', check2: 'false' }, inputs: { title: 'inputs', check1: 'true', check2: 'false', check3: 'NOPE' } }) }); } it('works on a list of checkboxes', function() { $form = $('<form>' + '<label class="checkbox-inline">' + ' <input type="checkbox" name="flags[]" value="input1"> Input 1' + '</label>' + '<label class="checkbox-inline">' + ' <input type="checkbox" name="flags[]" value="input2"> Input 2' + '</label>' + '</form>'); obj = $form.serializeJSON({checkboxUncheckedValue: 'false'}); expect(obj).toEqual({ 'flags': ['false', 'false'] }); $form.find('input[value="input1"]').prop('checked', true); obj = $form.serializeJSON({checkboxUncheckedValue: 'false'}); expect(obj).toEqual({ 'flags': ['input1', 'false'] }); }); it('works on a nested list of checkboxes', function() { $form = $('<form>'); $form.append($('<input type="text" name="form[title]" value="list of checkboxes"/>')); $form.append($('<input type="checkbox" name="form[check][]" value="true" checked/>')); $form.append($('<input type="checkbox" name="form[check][]" value="true"/>')); $form.append($('<input type="checkbox" name="form[check][]" value="true" data-unchecked-value="NOPE"/>')); obj = $form.serializeJSON({checkboxUncheckedValue: 'false'}); expect(obj).toEqual({ form: { title: 'list of checkboxes', check: ['true', 'false', 'NOPE'] } }); // also with parse options obj = $form.serializeJSON({checkboxUncheckedValue: 'false', parseBooleans: true}); expect(obj).toEqual({ form: { title: 'list of checkboxes', check: [true, false, 'NOPE'] } }); }); it('does not work on a nested list of objects', function() { $form = $('<form>'); $form.append($('<input type="checkbox" name="answers[][correct]:boolean" value="true" data-unchecked-value="false">')); $form.append($('<input type="text" name="answers[][text]" value="Blue">')); $form.append($('<input type="checkbox" name="answers[][correct]:boolean" value="true" data-unchecked-value="false">')); $form.append($('<input type="text" name="answers[][text]" value="Green">')); expect(function(){$form.serializeJSON()}).toThrow(); // it throws a descriptive error for the user }); it('does not serialize disabled checkboxes', function() {