diff --git a/Tests/amd/Tests.htm b/Tests/amd/Tests.htm
new file mode 100644
index 0000000..4df893c
--- /dev/null
+++ b/Tests/amd/Tests.htm
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+ Knockout Viewmodel Plugin Unit Tests - AMD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/amd/amd-qunit-tests.js b/Tests/amd/amd-qunit-tests.js
new file mode 100644
index 0000000..dad32cf
--- /dev/null
+++ b/Tests/amd/amd-qunit-tests.js
@@ -0,0 +1,11 @@
+define(["knockout", "viewmodel"], function(ko) {
+ var run = function() {
+ module("AMD Tests");
+ test("Module Loading", function() {
+ ok(ko, "ko Defined");
+ ok(ko.viewmodel, "ko.viewmodel Defined");
+ ok(!window.ko, "Global ko Not Defined");
+ });
+ };
+ return {run: run};
+});
diff --git a/Tests/amd/array-qunit-tests.js b/Tests/amd/array-qunit-tests.js
new file mode 100644
index 0000000..1b88f9f
--- /dev/null
+++ b/Tests/amd/array-qunit-tests.js
@@ -0,0 +1,42 @@
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ var model;
+ module("toModel Basic", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+ model = {
+ array: []
+ };
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ model = undefined;
+ }
+ });
+
+
+ test("array push pop", function () {
+ var viewmodel, result;
+
+ viewmodel = ko.viewmodel.fromModel(model);
+ viewmodel.array.push({ test: true });
+ result = viewmodel.array.pop();
+
+ assert(result.test(), true);
+
+ });
+
+ test("array push pop", function () {
+ var viewmodel, result;
+
+ viewmodel = ko.viewmodel.fromModel(model);
+ viewmodel.array.push({ test: true }, true);
+ result = viewmodel.array.pop();
+
+ assert(result.test, true);
+
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/fromModel-Basic-qunit-tests.js b/Tests/amd/fromModel-Basic-qunit-tests.js
new file mode 100644
index 0000000..ebf3bed
--- /dev/null
+++ b/Tests/amd/fromModel-Basic-qunit-tests.js
@@ -0,0 +1,168 @@
+///
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ module("fromModel Basic", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+ if(ko.viewmodel.options.hasOwnProperty("makeChildArraysObservable")){
+ ko.viewmodel.options.makeChildArraysObservable = true;
+ }
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ }
+ });
+
+
+ test("Default simple types", function () {
+ var model, viewmodel;
+
+ model = {
+ stringProp: "test",
+ number: 5,
+ date: new Date("01/01/2001"),
+ emptyArray: []
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(viewmodel.stringProp(), model.stringProp, "String Test");
+ deepEqual(viewmodel.number(), model.number, "Number Test");
+ deepEqual(viewmodel.date(), model.date, "Date Test");
+ deepEqual(viewmodel.emptyArray(), model.emptyArray, "Array Test");
+ });
+
+
+ test("Default nested object", function () {
+ var model, viewmodel;
+
+ model = {
+ nestedObject: {
+ stringProp: "test",
+ number: 5,
+ date: new Date("01/01/2001"),
+ emptyArray: []
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(viewmodel.nestedObject.stringProp(), model.nestedObject.stringProp, "String Test");
+ deepEqual(viewmodel.nestedObject.number(), model.nestedObject.number, "Number Test");
+ deepEqual(viewmodel.nestedObject.date(), model.nestedObject.date, "Date Test");
+ deepEqual(viewmodel.nestedObject.emptyArray(), model.nestedObject.emptyArray, "Array Test");
+ });
+
+
+ test("Default object array", function () {
+ var model, viewmodel;
+
+ model = {
+ objectArray: [
+ {}
+ ]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(viewmodel.objectArray()[0], model.objectArray[0], "Object Test");
+ });
+
+
+ test("Default object array simple types", function () {
+ var model, viewmodel;
+
+ model = {
+ objectArray: [
+ {
+ stringProp: "test",
+ number: 5,
+ date: new Date("01/01/2001"),
+ emptyArray: []
+ }
+ ]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(viewmodel.objectArray()[0].stringProp(), model.objectArray[0].stringProp, "String Test");
+ deepEqual(viewmodel.objectArray()[0].number(), model.objectArray[0].number, "Number Test");
+ deepEqual(viewmodel.objectArray()[0].date(), model.objectArray[0].date, "Date Test");
+ deepEqual(viewmodel.objectArray()[0].emptyArray(), model.objectArray[0].emptyArray, "Array Test");
+ });
+
+
+ test("makeChildArraysObservable is false Mode Default nested array", function () {
+ var model, viewmodel;
+
+ model = {
+ nestedArray: [[]]
+ };
+
+ ko.viewmodel.options.makeChildArraysObservable = false;
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(ko.viewmodel.options.makeChildArraysObservable, false);
+ deepEqual(viewmodel.nestedArray()[0], model.nestedArray[0], "Array Test");
+ });
+
+ test("makeChildArraysObservable is false double nested array", function () {
+ var model, viewmodel;
+
+ model = {
+ nestedArray: [[[]]]
+ };
+
+ ko.viewmodel.options.makeChildArraysObservable = false;
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(ko.viewmodel.options.makeChildArraysObservable, false);
+ deepEqual(viewmodel.nestedArray()[0][0], model.nestedArray[0][0], "Array Test");
+ });
+
+ //if undefined then we are using facade around ko.mapping
+ //used to exclude tests that are incompatable with ko.mapping
+ if (ko.viewmodel.options.makeChildArraysObservable !== undefined) {
+ test("makeChildArraysObservable is true Default nested array", function () {
+ var model, viewmodel;
+
+ model = {
+ nestedArray: [[]]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(ko.viewmodel.options.makeChildArraysObservable, true);
+ deepEqual(viewmodel.nestedArray()[0](), model.nestedArray[0], "Array Test");
+ });
+
+ test("makeChildArraysObservable is true double nested array", function () {
+ var model, viewmodel;
+
+ model = {
+ nestedArray: [[[]]]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(ko.viewmodel.options.makeChildArraysObservable, true);
+ deepEqual(viewmodel.nestedArray()[0]()[0](), model.nestedArray[0][0], "Array Test");
+ });
+ }
+
+
+ test("Default string array", function () {
+ var model, viewmodel;
+
+ model = {
+ stringArray: ["Test", "Test"]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(viewmodel.stringArray()[0], model.stringArray[0], "String Array Test");
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/fromModel-Mapping-qunit-tests.js b/Tests/amd/fromModel-Mapping-qunit-tests.js
new file mode 100644
index 0000000..e391157
--- /dev/null
+++ b/Tests/amd/fromModel-Mapping-qunit-tests.js
@@ -0,0 +1,671 @@
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ module("fromModel Mapping", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ }
+ });
+
+ test("Extend full path", function () {
+ var model, viewmodel, modelResult;
+
+ model = {
+ test: {
+ stringProp: "test"
+ }
+ };
+
+ var customMapping = {
+ extend: {
+ "{root}.test.stringProp": function (obj) {
+ obj.repeat = ko.computed(function () {
+ return obj() + obj();
+ });
+ return obj;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel.test.stringProp.repeat(), viewmodel.test.stringProp() + viewmodel.test.stringProp());
+ });
+
+ test("Extend full path with shared", function () {
+ var model, viewmodel, modelResult;
+
+ model = {
+ test: {
+ stringProp: "test"
+ },
+ otherTest: {
+ stringProp: "test"
+ }
+ };
+
+ var customMapping = {
+ extend: {
+ "{root}.test.stringProp": "repeat",
+ "{root}.otherTest.stringProp": {
+ map: "repeat"
+ }
+ },
+ shared: {
+ "repeat": function (obj) {
+ obj.repeat = ko.computed(function () {
+ return obj() + obj();
+ });
+ return obj;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel.test.stringProp.repeat(), viewmodel.test.stringProp() + viewmodel.test.stringProp());
+ deepEqual(viewmodel.otherTest.stringProp.repeat(), viewmodel.otherTest.stringProp() + viewmodel.otherTest.stringProp());
+ });
+
+ test("Extend object property path", function () {
+ var model, viewmodel, modelResult;
+
+ model = {
+ test: {
+ stringProp: "test"
+ }
+ };
+
+ var customMapping = {
+ extend: {
+ "test.stringProp": function (obj) {
+ obj.repeat = ko.computed(function () {
+ return obj() + obj();
+ });
+ return obj;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel.test.stringProp.repeat(), viewmodel.test.stringProp() + viewmodel.test.stringProp());
+ });
+
+ test("Extend property path", function () {
+ var model, viewmodel, modelResult;
+
+ model = {
+ stringProp: "test"
+ };
+
+ var customMapping = {
+ extend: {
+ "stringProp": function (obj) {
+ obj.repeat = ko.computed(function () {
+ return obj() + obj();
+ });
+ return obj;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel.stringProp.repeat(), viewmodel.stringProp() + viewmodel.stringProp());
+ });
+
+ test("Extend full path wins over object property path", function () {
+ var model, viewmodel, modelResult;
+
+ model = {
+ test: {
+ stringProp: "test"
+ }
+ };
+
+ var customMapping = {
+ extend: {
+ "{root}.test.stringProp": function (obj) {
+ obj.repeat = ko.computed(function () {
+ return obj() + obj();
+ });
+ return obj;
+ },
+ "test.stringProp": function (obj) {
+ return null;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel.test.stringProp.repeat(), viewmodel.test.stringProp() + viewmodel.test.stringProp());
+ });
+
+ test("Extend full path wins over property path", function () {
+ var model, viewmodel, modelResult;
+
+ model = {
+ test: {
+ stringProp: "test"
+ }
+ };
+
+ var customMapping = {
+ extend: {
+ "{root}.test.stringProp": function (obj) {
+ obj.repeat = ko.computed(function () {
+ return obj() + obj();
+ });
+ return obj;
+ },
+ "stringProp": function (obj) {
+ return null;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel.test.stringProp.repeat(), viewmodel.test.stringProp() + viewmodel.test.stringProp());
+ });
+
+
+ test("Extend array array-item property path", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ extend: {
+ "items[i].test": function (obj) {
+ obj.repeat = ko.computed(function () {
+ return obj.stringProp() + obj.stringProp();
+ });
+ return obj;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ actual = viewmodel.items()[0].test.repeat();
+ expected = model.items[0].test.stringProp + model.items[0].test.stringProp;
+
+ deepEqual(actual, expected);
+ });
+
+ test("Extend array array-item property path wins over array-item property path", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ extend: {
+ "[i].test": function (obj) {
+ return null;
+ },
+ "items[i].test": function (obj) {
+ obj.repeat = ko.computed(function () {
+ return obj.stringProp() + obj.stringProp();
+ });
+ return obj;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ actual = viewmodel.items()[0].test.repeat();
+ expected = model.items[0].test.stringProp + model.items[0].test.stringProp;
+
+ deepEqual(actual, expected);
+ });
+
+ test("Extend array array-item property path wins over property path", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ extend: {
+ "test": function (obj) {
+ return null;
+ },
+ "items[i].test": function (obj) {
+ obj.repeat = ko.computed(function () {
+ return obj.stringProp() + obj.stringProp();
+ });
+ return obj;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ actual = viewmodel.items()[0].test.repeat();
+ expected = model.items[0].test.stringProp + model.items[0].test.stringProp;
+
+ deepEqual(actual, expected);
+ });
+
+ test("Extend all array items", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ extend: {
+ "[i]": function (obj) {
+ obj.IsNew = false;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ actual = viewmodel.items()[0].IsNew;
+ expected = false;
+
+ deepEqual(actual, expected);
+ });
+
+
+ test("Extended Array Push with Map", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ },
+ id: 1259
+ }]
+ };
+
+ var customMapping = {
+ extend: {
+ "{root}.items[i]": {
+ map: function (obj) {
+ obj.IsNew = (obj.id() > 0) ? false : true;
+ },
+ unmap: function (obj, vm) {
+ if (vm) {//not using this param but test will fail if not available, easy way to verify that it is passe in
+ delete obj.IsNew;
+ }
+ return obj;
+ }
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel.items()[0].IsNew, false, "Extend logic - object with id is not new");//1
+
+ viewmodel.items.pushFromModel({
+ test: {
+ stringProp: "test"
+ },
+ id: null
+ });
+
+ deepEqual(viewmodel.items()[1].IsNew, true, "Extend logic applied to pushFromModel - object with id OF null is not new");//2
+
+ actual = viewmodel.items()[0];
+ expected = viewmodel.items.pop()
+
+ notStrictEqual(actual, expected, "Pop does not change object");//3
+
+ viewmodel.items.push(expected);
+
+ actual = viewmodel.items()[0];
+ expected = viewmodel.items.pop()
+
+ notStrictEqual(actual, expected, "Pushing and popping does not change object");//4
+
+ expected = model.items[0];
+ actual = viewmodel.items.popToModel();
+
+ deepEqual(actual, expected, "popToModel calls unmap and removes IsNew property");//5
+
+ });
+
+ test("Extended Array Push without Map", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ extend: {
+ "[i]": function (obj) {
+ obj.IsNew = false;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ viewmodel.items.push({
+ test: {
+ stringProp: "test"
+ }
+ }, {map:false});
+
+ notEqual(viewmodel.items.pop(), viewmodel.items()[0]);
+ });
+
+ test("Exclude full path", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ exclude: ["{root}.items[i].test"]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(viewmodel.items()[0].test, undefined, "Item Not Mapped");
+ });
+
+ test("Exclude full path wins over append object-property path", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ exclude: ["{root}.items[i].test"],
+ append: ["items[i].test"]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(viewmodel.items()[0].test, undefined, "Item Not Mapped");
+ });
+
+ test("Exclude object-property path wins over append property path", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ exclude: ["items[i].test"],
+ append: ["test"]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(viewmodel.items()[0].test, undefined, "Item Not Mapped");
+ });
+
+
+ test("Same path Last in wins", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ exclude: ["items[i].test"],
+ append: ["items[i].test"]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ notEqual(viewmodel.items()[0].test, undefined, "Item Not Mapped");
+ });
+
+ test("Exclude array item property path", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ exclude: ["items[i].test"]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(viewmodel.items()[0].test, undefined, "Item Not Mapped");
+ });
+
+ test("Append property", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ append: ["items[i]"]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ actual = viewmodel.items()[0].test.stringProp;
+ expected = model.items[0].test.stringProp
+
+ deepEqual(actual, expected, "Item Not Mapped");
+ });
+
+ test("Override array", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ override: ["[i]"]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ actual = viewmodel.items()[0].test.stringProp();
+ expected = model.items[0].test.stringProp
+
+ deepEqual(actual, expected, "Item Not Mapped");
+ });
+
+ test("Override object", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ override: ["{root}"]
+ };
+
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ actual = viewmodel.items()[0].test.stringProp();
+ expected = model.items[0].test.stringProp
+
+ deepEqual(actual, expected, "Item Not Mapped");
+ });
+
+ test("Custom Success", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ custom: {
+ "test": function (obj) {
+ return obj ? true : false;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel.items()[0].test, true, "Item Not Mapped");
+ });
+
+ test("Custom Success with shared", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ custom: {
+ "test": "test"
+ },
+ shared: {
+ "test": function (obj) {
+ return obj ? true : false;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel.items()[0].test, true, "Item Not Mapped");
+ });
+
+ test("Custom Fail", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ custom: {
+ "test": function (obj) {
+
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel.items()[0].test, undefined, "Item Not Mapped");
+ });
+
+ test("Custom Obsevable", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ custom: {
+ "test": function (obj) {
+
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel.items()[0].test, undefined, "Item Not Mapped");
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/fromModelToModel-Basic-qunit-tests.js b/Tests/amd/fromModelToModel-Basic-qunit-tests.js
new file mode 100644
index 0000000..92d6c18
--- /dev/null
+++ b/Tests/amd/fromModelToModel-Basic-qunit-tests.js
@@ -0,0 +1,92 @@
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ module("fromModel toModel Basic", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ }
+ });
+
+ test("Default Basic Types", function () {
+ var model, viewmodel, modelResult;
+
+ model = {
+ stringProp: "test",
+ number: 5,
+ date: new Date("01/01/2001"),
+ emptyArray: []
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.stringProp, model.stringProp, "String Test");
+ deepEqual(modelResult.number, model.number, "Number Test");
+ deepEqual(modelResult.date, model.date, "Date Test");
+ deepEqual(modelResult.emptyArray, model.emptyArray, "Array Test");
+ });
+
+ test("Default Nested Object", function () {
+ var model, viewmodel, modelResult;
+
+ model = {
+ nestedObject: {
+ stringProp: "test",
+ number: 5,
+ date: new Date("01/01/2001"),
+ emptyArray: []
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.nestedObject.stringProp, model.nestedObject.stringProp, "String Test");
+ deepEqual(modelResult.nestedObject.number, model.nestedObject.number, "Number Test");
+ deepEqual(modelResult.nestedObject.date, model.nestedObject.date, "Date Test");
+ deepEqual(modelResult.nestedObject.emptyArray, model.nestedObject.emptyArray, "Array Test");
+ });
+
+ test("Default Object Array", function () {
+ var model, viewmodel, modelResult;
+
+ model = {
+ objectArray: [
+ {
+ stringProp: "test",
+ number: 5,
+ date: new Date("01/01/2001"),
+ emptyArray: []
+ }
+ ]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.objectArray[0].stringProp, model.objectArray[0].stringProp, "String Test");
+ deepEqual(modelResult.objectArray[0].number, model.objectArray[0].number, "Number Test");
+ deepEqual(modelResult.objectArray[0].date, model.objectArray[0].date, "Date Test");
+ deepEqual(modelResult.objectArray[0].emptyArray, model.objectArray[0].emptyArray, "Array Test");
+ });
+
+ test("Default Nested Array", function () {
+ var viewmodel, modelResult;
+
+ viewmodel = ko.observable({
+ nestedArray: ko.observableArray([ko.observableArray([])])
+ });
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.nestedArray[0], viewmodel().nestedArray()[0](), "Array Test");
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/fromModelToModel-Mapping-qunit-tests.js b/Tests/amd/fromModelToModel-Mapping-qunit-tests.js
new file mode 100644
index 0000000..69e7acd
--- /dev/null
+++ b/Tests/amd/fromModelToModel-Mapping-qunit-tests.js
@@ -0,0 +1,164 @@
+///
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ module("fromModel toModel Mapping", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ }
+ });
+
+ test("Extend full path", function () {
+ var model, viewmodel, modelResult;
+
+ model = {
+ test: {
+ stringProp: "test"
+ }
+ };
+
+ var customMapping = {
+ extend: {
+ "{root}.test.stringProp": function (obj) {
+ obj.repeat = ko.computed(function () {
+ return obj() + obj();
+ });
+ return obj;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel().test().stringProp.repeat(), viewmodel().test().stringProp() + viewmodel().test().stringProp(), "Extension Added");
+ });
+
+ test("Extend object property path", function () {
+ var model, viewmodel, modelResult;
+
+ model = {
+ test: {
+ stringProp: "test"
+ }
+ };
+
+ var customMapping = {
+ extend: {
+ "test.stringProp": function (obj) {
+ obj.repeat = ko.computed(function () {
+ return obj() + obj();
+ });
+ return obj;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel().test().stringProp.repeat(), viewmodel().test().stringProp() + viewmodel().test().stringProp(), "Extension Added");
+ });
+
+ test("Extend name path", function () {
+ var model, viewmodel, modelResult;
+
+ model = {
+ stringProp: "test"
+ };
+
+ var customMapping = {
+ extend: {
+ "stringProp": function (obj) {
+ obj.repeat = ko.computed(function () {
+ return obj() + obj();
+ });
+ return obj;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ deepEqual(viewmodel().stringProp.repeat(), viewmodel().stringProp() + viewmodel().stringProp(), "Extension Added");
+ });
+
+
+ test("Extend array item property", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ extend: {
+ "items[i].test": function (obj) {
+ obj.repeat = ko.computed(function () {
+ return obj().stringProp() + obj().stringProp();
+ });
+ return obj;
+ }
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ actual = viewmodel().items()[0]().test.repeat();
+ expected = model.items[0].test.stringProp + model.items[0].test.stringProp;
+
+ deepEqual(actual, expected);
+ });
+
+ test("Exclude property", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var options = {
+ exclude: ["items[i].test"]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, options);
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(viewmodel().items()[0]().test, undefined, "fromModel assert");
+ deepEqual(modelResult.items[0].test, undefined, "toModel assert");
+ });
+
+ test("Append property", function () {
+ var model, viewmodel, modelResult, actual, expected;
+
+ model = {
+ items: [{
+ test: {
+ stringProp: "test"
+ }
+ }]
+ };
+
+ var customMapping = {
+ append: ["items[i]"]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(viewmodel().items()[0].test.stringProp, model.items[0].test.stringProp, "fromModel assert");
+ deepEqual(modelResult.items[0].test.stringProp, model.items[0].test.stringProp, "toModel assert");
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/issues-qunit-tests.js b/Tests/amd/issues-qunit-tests.js
new file mode 100644
index 0000000..e9ea15a
--- /dev/null
+++ b/Tests/amd/issues-qunit-tests.js
@@ -0,0 +1,94 @@
+///
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ var model, viewmodel, updatedModel, modelResult;
+ module("Issue Tests", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ model = undefined;
+ updatedModel = undefined;
+ modelResult = undefined;
+ viewmodel = undefined
+ }
+ });
+
+
+ test("Issue 19 - empty array throws an exception on update", function () {
+
+ model = { items: [] };
+
+ updatedModel = {
+ items: [{
+ id: 5,
+ text: "test"
+ }]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.items().length, 1);
+
+ });
+
+ test("Issue 18 - toModel call fails to completely strip extended functions and internal properties", function () {
+
+ model = {
+ items: [{
+ id: 5,
+ text: "test"
+ }],
+ obj: {
+ text: "test"
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, {
+ id: ["{root}.items[i].id"],
+ extend: {
+ "{root}.obj": function (obj) {
+ obj.getTextLength = function () {
+ return obj.text().length;
+ };
+
+ obj.textLength = ko.computed(function () {
+ return obj.text().length;
+ });
+
+ }
+ }
+ });
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.items[0].hasOwnProperty("..idName"), false, "hasOwnProperty of internal idName property returns true");
+
+ deepEqual(typeof modelResult.obj.getTextLength, "undefined", "function not removed");
+ deepEqual(modelResult.obj.hasOwnProperty("getTextLength"), false, "hasOwnProperty of function extension returns true");
+
+ deepEqual(typeof modelResult.obj.textLength, "undefined", "property extension not removed");
+ deepEqual(modelResult.obj.hasOwnProperty("textLength"), false, "hasOwnProperty of property extension returns true");
+
+ });
+
+
+ test("Issue 17 - toModel call fails to correctly unwrap fromModel with nested observableArray of strings", function () {
+
+ model = { items: [["a", "b", "c", "d"]] };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(model, modelResult);
+
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/main-qunit-tests.js b/Tests/amd/main-qunit-tests.js
new file mode 100644
index 0000000..cf3e09b
--- /dev/null
+++ b/Tests/amd/main-qunit-tests.js
@@ -0,0 +1,48 @@
+require.config({
+ paths: {
+ knockout: "http://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.0/knockout-min",
+ qunit: "http://code.jquery.com/qunit/qunit-1.10.0",
+ viewmodel: "../../knockout.viewmodel"
+ },
+ shim: {
+ qunit: {
+ exports: "QUnit",
+ init: function() {
+ QUnit.config.autoload = false;
+ QUnit.config.autostart = false;
+ }
+ }
+ }
+});
+
+require(["qunit", "amd-qunit-tests", "undefined-Basic-qunit-tests",
+ "undefined-Mapping-qunit-tests", "null-Basic-qunit-tests",
+ "null-Mapping-qunit-tests", "simpleTypes-qunit-tests",
+ "nestedObject-qunit-tests", "fromModel-Basic-qunit-tests",
+ "fromModel-Mapping-qunit-tests", "toModel-Basic-qunit-tests",
+ "fromModelToModel-Basic-qunit-tests", "updateFromModel-Basic-qunit-tests",
+ "issues-qunit-tests", "updateFromModel-Mapping-contiguous-qunit-tests",
+ "updateFromModel-Mapping-noncontiguous-qunit-tests"],
+function(QUnit, amd, undefinedBasic, undefinedMapping, nullBasic, nullMapping,
+ simpleTypes, nestedObjects, fromModelBasic, fromModelMapping, toModelBasic,
+ fromModelToModelBasic, updateFromModelBasic, issues,
+ updateFromModelMappingContiguous, updateFromModelMappingNoncontiguous) {
+ QUnit.load();
+ QUnit.start();
+
+ amd.run();
+ undefinedBasic.run();
+ undefinedMapping.run();
+ nullBasic.run();
+ nullMapping.run();
+ simpleTypes.run();
+ nestedObjects.run();
+ fromModelBasic.run();
+ fromModelMapping.run();
+ toModelBasic.run();
+ fromModelToModelBasic.run();
+ updateFromModelBasic.run();
+ issues.run();
+ updateFromModelMappingContiguous.run();
+ updateFromModelMappingNoncontiguous.run();
+});
diff --git a/Tests/amd/nestedObject-qunit-tests.js b/Tests/amd/nestedObject-qunit-tests.js
new file mode 100644
index 0000000..6d823fa
--- /dev/null
+++ b/Tests/amd/nestedObject-qunit-tests.js
@@ -0,0 +1,249 @@
+///
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ var model, updatedModel, modelResult;
+ module("Nested Object Types", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+
+ model = {
+ data: {
+ stringProp: "test",
+ id: 5,
+ date: new Date("01/01/2001")
+ }
+ };
+
+ updatedModel = {
+ data: {
+ stringProp: "test2",
+ id: 6,
+ date: new Date("02/01/2002")
+ }
+ };
+
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ model = undefined;
+ updatedModel = undefined;
+ modelResult = undefined;
+ }
+ });
+
+
+ test("Basic", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(viewmodel.data.stringProp(), model.data.stringProp, "From Model String Test");
+ deepEqual(viewmodel.data.id(), model.data.id, "From Model Number Test");
+ deepEqual(viewmodel.data.date(), model.data.date, "From Model Date Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.data.stringProp(), updatedModel.data.stringProp, "Update String Test");
+ deepEqual(viewmodel.data.id(), updatedModel.data.id, "Update Number Test");
+ deepEqual(viewmodel.data.date(), updatedModel.data.date, "Update Date Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult, updatedModel, "Result Object Comparison");
+ });
+
+ test("Extend", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ extend: {
+ "{root}": function(root){
+ root.isValid = ko.computed(function () {
+ return root.data.stringProp.isValid() && root.data.id.isValid() && root.data.date.isValid();
+ });
+ },
+ "{root}.data.stringProp": function (stringProp) {
+ stringProp.isValid = ko.computed(function () {
+ return stringProp() && stringProp().length;
+ });
+ },
+ "{root}.data.id": function (id) {
+ id.isValid = ko.computed(function () {
+ return id() && id() > 0;
+ });
+ },
+ "{root}.data.date": function (date) {
+ date.isValid = ko.computed(function () {
+ return date() && date() < new Date();
+ });
+ }
+ }
+ });
+
+ deepEqual(viewmodel.data.stringProp(), model.data.stringProp, "From Model String Test");
+ deepEqual(viewmodel.data.id(), model.data.id, "From Model Number Test");
+ deepEqual(viewmodel.data.date(), model.data.date, "From Model Date Test");
+ deepEqual(viewmodel.isValid(), true, "Extension check");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.data.stringProp(), updatedModel.data.stringProp, "Update String Test");
+ deepEqual(viewmodel.data.id(), updatedModel.data.id, "Update Number Test");
+ deepEqual(viewmodel.data.date(), updatedModel.data.date, "Update Date Test");
+ deepEqual(viewmodel.isValid(), true, "Extension check");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(viewmodel.isValid(), true, "Extension check");
+ });
+
+ test("Append object", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ append: ["{root}.data"]
+ });
+
+ deepEqual(viewmodel, model, "From Model Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ notEqual(viewmodel, updatedModel, "Update Fail Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult, model, "Result");
+ });
+
+ test("Append object property", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ append: ["{root}.data.stringProp"]
+ });
+
+ deepEqual(viewmodel.data.stringProp, model.data.stringProp, "From Model String Test");
+ deepEqual(viewmodel.data.id(), model.data.id, "From Model Number Test");
+ deepEqual(viewmodel.data.date(), model.data.date, "From Model Date Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.data.stringProp, updatedModel.data.stringProp, "From Model String Test Fail");
+ deepEqual(viewmodel.data.id(), updatedModel.data.id, "Update Number Test");
+ deepEqual(viewmodel.data.date(), updatedModel.data.date, "Update Date Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.data.stringProp, updatedModel.data.stringProp, "To Model String Test");
+ deepEqual(modelResult.data.id, updatedModel.data.id, "To Model Number Test");
+ deepEqual(modelResult.data.date, updatedModel.data.date, "To Model Date Test");
+ });
+
+ test("Custom basic", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ custom: {
+ "{root}.data.date": function (date) {
+ return date.valueOf();
+ }
+ }
+ });
+
+ deepEqual(viewmodel.data.stringProp(), model.data.stringProp, "From Model String Test");
+ deepEqual(viewmodel.data.id(), model.data.id, "From Model Number Test");
+ deepEqual(viewmodel.data.date, model.data.date.valueOf(), "From Model Date Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.data.stringProp(), updatedModel.data.stringProp, "Update String Test");
+ deepEqual(viewmodel.data.id(), updatedModel.data.id, "Update Number Test");
+ deepEqual(viewmodel.data.date, updatedModel.data.date.valueOf(), "Update Date Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.data.stringProp, updatedModel.data.stringProp, "To Model String Test");
+ deepEqual(modelResult.data.id, updatedModel.data.id, "To Model Number Test");
+ deepEqual(modelResult.data.date, updatedModel.data.date.valueOf(), "To Model Date Test");
+ });
+
+ test("Custom basic", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ custom: {
+ "{root}.data.date": function (date) {
+ return date.valueOf();
+ }
+ }
+ });
+
+ deepEqual(viewmodel.data.stringProp(), model.data.stringProp, "From Model String Test");
+ deepEqual(viewmodel.data.id(), model.data.id, "From Model Number Test");
+ deepEqual(viewmodel.data.date, model.data.date.valueOf(), "From Model Date Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.data.stringProp(), updatedModel.data.stringProp, "Update String Test");
+ deepEqual(viewmodel.data.id(), updatedModel.data.id, "Update Number Test");
+ deepEqual(viewmodel.data.date, updatedModel.data.date.valueOf(), "Update Date Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.data.stringProp, updatedModel.data.stringProp, "To Model String Test");
+ deepEqual(modelResult.data.id, updatedModel.data.id, "To Model Number Test");
+ deepEqual(modelResult.data.date, updatedModel.data.date.valueOf(), "To Model Date Test");
+ });
+
+ test("Custom map and unmap", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ custom: {
+ "{root}.data.date": {
+ map: function (date) {
+ return ko.observable(date.valueOf());
+ },
+ unmap: function(date){
+ return new Date(date());
+ }
+ }
+ }
+ });
+
+ deepEqual(viewmodel.data.stringProp(), model.data.stringProp, "From Model String Test");
+ deepEqual(viewmodel.data.id(), model.data.id, "From Model Number Test");
+ deepEqual(viewmodel.data.date(), model.data.date.valueOf(), "From Model Date Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.data.stringProp(), updatedModel.data.stringProp, "Update String Test");
+ deepEqual(viewmodel.data.id(), updatedModel.data.id, "Update Number Test");
+ deepEqual(viewmodel.data.date(), updatedModel.data.date.valueOf(), "Update Date Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.data.stringProp, updatedModel.data.stringProp, "To Model String Test");
+ deepEqual(modelResult.data.id, updatedModel.data.id, "To Model Number Test");
+ deepEqual(modelResult.data.date, updatedModel.data.date, "To Model Date Test");
+ });
+
+ test("Exclude", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ exclude: ["{root}.data.stringProp"]
+ });
+
+ equal(viewmodel.data.hasOwnProperty("stringProp"), false, "From Model String Prop Not Exist");
+ deepEqual(viewmodel.data.id(), model.data.id, "From Model Number Test");
+ deepEqual(viewmodel.data.date(), model.data.date, "From Model Date Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ equal(viewmodel.data.hasOwnProperty("stringProp"), false, "Update... String Prop Not Exist");
+ deepEqual(viewmodel.data.id(), updatedModel.data.id, "Update Number Test");
+ deepEqual(viewmodel.data.date(), updatedModel.data.date, "Update Date Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ notEqual(modelResult.data.stringProp, updatedModel.data.stringProp, "To Model String Test");
+ deepEqual(modelResult.data.id, updatedModel.data.id, "To Model Number Test");
+ deepEqual(modelResult.data.date, updatedModel.data.date, "To Model Date Test");
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/null-Basic-qunit-tests.js b/Tests/amd/null-Basic-qunit-tests.js
new file mode 100644
index 0000000..ece464b
--- /dev/null
+++ b/Tests/amd/null-Basic-qunit-tests.js
@@ -0,0 +1,69 @@
+///
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ var model, updatedModel, modelResult;
+ module("Basic Null Tests", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+
+ model = {
+ Prop1: null,
+ Prop2: "test2",
+ Prop3: null,
+ Prop4: {},
+ Prop5: null,
+ Prop6: []
+ };
+
+ updatedModel = {
+ Prop1: "test2",
+ Prop2: null,
+ Prop3: {},
+ Prop4: null,
+ Prop5: [],
+ Prop6: null
+
+ };
+
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ model = undefined;
+ updatedModel = undefined;
+ modelResult = undefined;
+ }
+ });
+
+
+ test("Basic", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(viewmodel.Prop1(), model.Prop1, "Null Prop Test");//1
+ deepEqual(viewmodel.Prop2(), model.Prop2, "String Prop Test");//2
+ deepEqual(viewmodel.Prop4, model.Prop4, "Object Prop Test");//3
+ deepEqual(viewmodel.Prop6(), model.Prop6, "Array Prop Test");//4
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.Prop1(), updatedModel.Prop1, "Null to Value Update Test");//5
+ deepEqual(viewmodel.Prop2(), updatedModel.Prop2, "Value to Null Update Test");//6
+ deepEqual(viewmodel.Prop3(), updatedModel.Prop3, "Null to Object Update Test");//7
+ deepEqual(viewmodel.Prop4, updatedModel.Prop4, "Object to Null Update Test");//8
+ deepEqual(viewmodel.Prop5(), updatedModel.Prop5, "Null to Array Update Test");//9
+ notEqual(typeof viewmodel.Prop5.push, "function", "Null to Array Update Is Not Observable Array Test");//10
+ deepEqual(viewmodel.Prop6(), updatedModel.Prop6, "Array to Null Update Test");//11
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.Prop1, updatedModel.Prop1, "Null to Value Update Test");//12
+ deepEqual(modelResult.Prop2, updatedModel.Prop2, "Value to Null Update Test");//13
+ deepEqual(modelResult.Prop3, updatedModel.Prop3, "Null to Object Update Test");//14
+ deepEqual(modelResult.Prop4, updatedModel.Prop4, "Object to Null Update Test");//15
+ deepEqual(modelResult.Prop5, updatedModel.Prop5, "Null to Array Update Test");//16
+ deepEqual(modelResult.Prop6, updatedModel.Prop6, "Array to Null Update Test");//17
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/null-Mapping-qunit-tests.js b/Tests/amd/null-Mapping-qunit-tests.js
new file mode 100644
index 0000000..0bdaeaf
--- /dev/null
+++ b/Tests/amd/null-Mapping-qunit-tests.js
@@ -0,0 +1,280 @@
+///
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ var model, updatedModel, modelResult;
+ module("Null Mapping Tests", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+
+ model = {
+ Prop1: null,
+ Prop2: "test2",
+ Prop3: {},
+ Prop4: null
+ };
+
+ updatedModel = {
+ Prop1: "test2",
+ Prop2: null,
+ Prop3: null,
+ Prop4: {}
+ };
+
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ model = undefined;
+ updatedModel = undefined;
+ modelResult = undefined;
+ }
+ });
+
+ test("Extend String Null", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ extend: {
+ "{root}.Prop1": function (val) {
+ val.isValid = ko.computed(function () {
+ return val() != null && val().length > 0;
+ });
+ },
+ "{root}.Prop2": function (val) {
+ val.isValid = ko.computed(function () {
+ return val() != null && val().length > 0;
+ });
+ }
+ }
+ });
+
+ deepEqual(viewmodel.Prop1(), model.Prop1, "Null Prop Test");
+ deepEqual(viewmodel.Prop1.isValid(), false, "Null Prop Extend Test");
+ deepEqual(viewmodel.Prop2(), model.Prop2, "String Prop Test");
+ deepEqual(viewmodel.Prop2.isValid(), true, "Null Prop Extend Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.Prop1(), updatedModel.Prop1, "Null Prop Test");
+ deepEqual(viewmodel.Prop1.isValid(), true, "Null Prop Extend Test");
+ deepEqual(viewmodel.Prop2(), updatedModel.Prop2, "String Prop Test");
+ deepEqual(viewmodel.Prop2.isValid(), false, "Null Prop Extend Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult, updatedModel, "Result Object Comparison");
+ });
+
+ test("Extend Object Null", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ extend: {
+ "{root}.Prop3": function (val) {
+ val.isValid = ko.computed(function () {
+ return ko.utils.unwrapObservable(val) != null;
+ });
+ },
+ "{root}.Prop4": function (val) {
+ val.isValid = ko.computed(function () {
+ return ko.utils.unwrapObservable(val) != null;
+ });
+ }
+ }
+ });
+
+ deepEqual(typeof viewmodel.Prop3, "object", "Object Prop Test");
+ deepEqual(viewmodel.Prop3.isValid(), true, "Object Prop Extend Test");
+ deepEqual(viewmodel.Prop4(), null, "Null Prop Test");
+ deepEqual(viewmodel.Prop4.isValid(), false, "Null Prop Extend Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.Prop3, null, "Object to Null Prop Update Test");
+ deepEqual(viewmodel.Prop4(), updatedModel.Prop4, "Null to Object Update Prop Test");
+ deepEqual(viewmodel.Prop4.isValid(), true, "Null to Object Update Prop Extend Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult, updatedModel, "Result Object Comparison");
+ });
+
+ test("Extend Object Null", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ extend: {
+ "{root}.Prop1": function (val) {
+ if (!ko.isObservable(val)) {
+ val = ko.observable(val)
+ }
+ return val;
+ },
+ "{root}.Prop2": function (val) {
+ if (!ko.isObservable(val)) {
+ val = ko.observable(val)
+ }
+ return val;
+ },
+ "{root}.Prop3": function (val) {
+ if (!ko.isObservable(val)) {
+ val = ko.observable(val)
+ }
+ return val;
+ },
+ "{root}.Prop4": function (val) {
+ if (!ko.isObservable(val)) {
+ val = ko.observable(val)
+ }
+ return val;
+ }
+ }
+ });
+
+ deepEqual(viewmodel.Prop1(), model.Prop1);
+ deepEqual(viewmodel.Prop2(), model.Prop2);
+ deepEqual(viewmodel.Prop3(), model.Prop3);
+ deepEqual(viewmodel.Prop4(), model.Prop4);
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.Prop1(), updatedModel.Prop1);
+ deepEqual(viewmodel.Prop2(), updatedModel.Prop2);
+ deepEqual(viewmodel.Prop3(), updatedModel.Prop3);
+ deepEqual(viewmodel.Prop4(), updatedModel.Prop4);
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(updatedModel, modelResult);
+ });
+
+ test("Append property", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ append: ["{root}.Prop1", "{root}.Prop2"]
+ });
+
+ deepEqual(viewmodel.Prop1, model.Prop1, "Null to Value Update Test");
+ deepEqual(viewmodel.Prop2, model.Prop2, "Value to Null Update Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ equal(viewmodel.Prop1, updatedModel.Prop1, "Null to Value Update Test");
+ equal(viewmodel.Prop2, updatedModel.Prop2, "Value to Null Update Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ equal(modelResult.Prop1, updatedModel.Prop1, "Null to Value Update Test");
+ deepEqual(modelResult.Prop2, updatedModel.Prop2, "Value to Null Update Test");
+
+ });
+
+ test("Custom basic", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ custom: {
+ "{root}.Prop1":function (val) {
+ return ko.observable(val);
+ },
+ "{root}.Prop2": function (val) {
+ return ko.observable(val);
+ },
+ "{root}.Prop3": function (val) {
+ return ko.observable(val);
+ },
+ "{root}.Prop4": function (val) {
+ return ko.observable(val);
+ }
+ }
+ });
+
+ deepEqual(viewmodel.Prop1(), model.Prop1);
+ deepEqual(viewmodel.Prop2(), model.Prop2);
+ deepEqual(viewmodel.Prop3(), model.Prop3);
+ deepEqual(viewmodel.Prop4(), model.Prop4);
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.Prop1(), updatedModel.Prop1);
+ deepEqual(viewmodel.Prop2(), updatedModel.Prop2);
+ deepEqual(viewmodel.Prop3(), updatedModel.Prop3);
+ deepEqual(viewmodel.Prop4(), updatedModel.Prop4);
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(updatedModel, modelResult);
+
+ });
+
+ test("Custom map and unmap", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ custom: {
+ "{root}.Prop1": {
+ map: function (val) {
+ return ko.observable(val);
+ },
+ unmap: function (val) {
+ return val();
+ }
+ },
+ "{root}.Prop2": {
+ map: function (val) {
+ return ko.observable(val);
+ },
+ unmap: function (val) {
+ return val();
+ }
+ },
+ "{root}.Prop3": {
+ map: function (val) {
+ return ko.observable(val);
+ },
+ unmap: function (val) {
+ return val();
+ }
+ },
+ "{root}.Prop4": {
+ map: function (val) {
+ return ko.observable(val);
+ },
+ unmap: function (val) {
+ return val();
+ }
+ }
+ }
+ });
+
+ deepEqual(viewmodel.Prop1(), model.Prop1);
+ deepEqual(viewmodel.Prop2(), model.Prop2);
+ deepEqual(viewmodel.Prop3(), model.Prop3);
+ deepEqual(viewmodel.Prop4(), model.Prop4);
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.Prop1(), updatedModel.Prop1);
+ deepEqual(viewmodel.Prop2(), updatedModel.Prop2);
+ deepEqual(viewmodel.Prop3(), updatedModel.Prop3);
+ deepEqual(viewmodel.Prop4(), updatedModel.Prop4);
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(updatedModel, modelResult);
+ });
+
+ test("Exclude", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ exclude: ["{root}.Prop2"]
+ });
+
+ equal(viewmodel.hasOwnProperty("Prop2"), false, "From Model String Prop Not Exist");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ equal(viewmodel.hasOwnProperty("Prop2"), false, "Update... String Prop Not Exist");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ equal(modelResult.hasOwnProperty("Prop2"), false, "Update... String Prop Not Exist");
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/simpleTypes-qunit-tests.js b/Tests/amd/simpleTypes-qunit-tests.js
new file mode 100644
index 0000000..0b99927
--- /dev/null
+++ b/Tests/amd/simpleTypes-qunit-tests.js
@@ -0,0 +1,218 @@
+///
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ var model, updatedModel, modelResult;
+ module("Simple Types", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+
+ model = {
+ stringProp: "test",
+ id: 5,
+ date: new Date("01/01/2001")
+ };
+
+ updatedModel = {
+ stringProp: "test2",
+ id: 6,
+ date: new Date("02/01/2002")
+ };
+
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ model = undefined;
+ updatedModel = undefined;
+ modelResult = undefined;
+ }
+ });
+
+
+ test("Basic", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(viewmodel.stringProp(), model.stringProp, "From Model String Test");
+ deepEqual(viewmodel.id(), model.id, "From Model Number Test");
+ deepEqual(viewmodel.date(), model.date, "From Model Date Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.stringProp(), updatedModel.stringProp, "Update String Test");
+ deepEqual(viewmodel.id(), updatedModel.id, "Update Number Test");
+ deepEqual(viewmodel.date(), updatedModel.date, "Update Date Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult, updatedModel, "Result Object Comparison");
+ });
+
+ test("Extend", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ extend: {
+ "{root}": function(root){
+ root.isValid = ko.computed(function () {
+ return root.stringProp.isValid() && root.id.isValid() && root.date.isValid();
+ });
+ },
+ "{root}.stringProp": function (stringProp) {
+ stringProp.isValid = ko.computed(function () {
+ return stringProp() && stringProp().length;
+ });
+ },
+ "{root}.id": function (id) {
+ id.isValid = ko.computed(function () {
+ return id() && id() > 0;
+ });
+ },
+ "{root}.date": function (date) {
+ date.isValid = ko.computed(function () {
+ return date() && date() < new Date();
+ });
+ }
+ }
+ });
+
+ deepEqual(viewmodel.stringProp(), model.stringProp, "From Model String Test");
+ deepEqual(viewmodel.id(), model.id, "From Model Number Test");
+ deepEqual(viewmodel.date(), model.date, "From Model Date Test");
+ deepEqual(viewmodel.isValid(), true, "Extension check");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.stringProp(), updatedModel.stringProp, "Update String Test");
+ deepEqual(viewmodel.id(), updatedModel.id, "Update Number Test");
+ deepEqual(viewmodel.date(), updatedModel.date, "Update Date Test");
+ deepEqual(viewmodel.isValid(), true, "Extension check");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(viewmodel.isValid(), true, "Extension check");
+ });
+
+ test("Append root", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ append: ["{root}"]
+ });
+
+ deepEqual(viewmodel, model, "From Model Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ notEqual(viewmodel, updatedModel, "Update Fail Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult, model, "Result");
+ });
+
+ test("Append property", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ append: ["{root}.stringProp"]
+ });
+
+ deepEqual(viewmodel.stringProp, model.stringProp, "From Model String Test");
+ deepEqual(viewmodel.id(), model.id, "From Model Number Test");
+ deepEqual(viewmodel.date(), model.date, "From Model Date Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.stringProp, updatedModel.stringProp, "From Model String Test Fail");
+ deepEqual(viewmodel.id(), updatedModel.id, "Update Number Test");
+ deepEqual(viewmodel.date(), updatedModel.date, "Update Date Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.stringProp, updatedModel.stringProp, "To Model String Test");
+ deepEqual(modelResult.id, updatedModel.id, "To Model Number Test");
+ deepEqual(modelResult.date, updatedModel.date, "To Model Date Test");
+ });
+
+ test("Custom basic", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ custom: {
+ "{root}.date":function (date) {
+ return date.valueOf();
+ }
+ }
+ });
+
+ deepEqual(viewmodel.stringProp(), model.stringProp, "From Model String Test");
+ deepEqual(viewmodel.id(), model.id, "From Model Number Test");
+ deepEqual(viewmodel.date, model.date.valueOf(), "From Model Date Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.stringProp(), updatedModel.stringProp, "Update String Test");
+ deepEqual(viewmodel.id(), updatedModel.id, "Update Number Test");
+ deepEqual(viewmodel.date, updatedModel.date.valueOf(), "Update Date Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.stringProp, updatedModel.stringProp, "To Model String Test");
+ deepEqual(modelResult.id, updatedModel.id, "To Model Number Test");
+ deepEqual(modelResult.date, updatedModel.date.valueOf(), "To Model Date Test");
+ });
+
+ test("Custom map and unmap", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ custom: {
+ "{root}.date":{
+ map: function (date) {
+ return ko.observable(date.valueOf());
+ },
+ unmap: function(date){
+ return new Date(date());
+ }
+ }
+ }
+ });
+
+ deepEqual(viewmodel.stringProp(), model.stringProp, "From Model String Test");
+ deepEqual(viewmodel.id(), model.id, "From Model Number Test");
+ deepEqual(viewmodel.date(), model.date.valueOf(), "From Model Date Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.stringProp(), updatedModel.stringProp, "Update String Test");
+ deepEqual(viewmodel.id(), updatedModel.id, "Update Number Test");
+ deepEqual(viewmodel.date(), updatedModel.date.valueOf(), "Update Date Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.stringProp, updatedModel.stringProp, "To Model String Test");
+ deepEqual(modelResult.id, updatedModel.id, "To Model Number Test");
+ deepEqual(modelResult.date, updatedModel.date, "To Model Date Test");
+ });
+
+ test("Exclude", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ exclude: ["{root}.stringProp"]
+ });
+
+ equal(viewmodel.hasOwnProperty("stringProp"), false, "From Model String Prop Not Exist");
+ deepEqual(viewmodel.id(), model.id, "From Model Number Test");
+ deepEqual(viewmodel.date(), model.date, "From Model Date Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ equal(viewmodel.hasOwnProperty("stringProp"), false, "Update... String Prop Not Exist");
+ deepEqual(viewmodel.id(), updatedModel.id, "Update Number Test");
+ deepEqual(viewmodel.date(), updatedModel.date, "Update Date Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ notEqual(modelResult.stringProp, updatedModel.stringProp, "To Model String Test");
+ deepEqual(modelResult.id, updatedModel.id, "To Model Number Test");
+ deepEqual(modelResult.date, updatedModel.date, "To Model Date Test");
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/toModel-Basic-qunit-tests.js b/Tests/amd/toModel-Basic-qunit-tests.js
new file mode 100644
index 0000000..a7a0693
--- /dev/null
+++ b/Tests/amd/toModel-Basic-qunit-tests.js
@@ -0,0 +1,162 @@
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ module("toModel Basic", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ }
+ });
+
+
+ test("Default Basic Types", function () {
+ var viewmodel, modelResult;
+
+ viewmodel = {
+ stringProp: ko.observable("test"),
+ number: ko.observable(5),
+ date: ko.observable(new Date("01/01/2001")),
+ emptyArray: ko.observableArray([])
+ };
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.stringProp, viewmodel.stringProp(), "String Test");
+ deepEqual(modelResult.number, viewmodel.number(), "Number Test");
+ deepEqual(modelResult.date, viewmodel.date(), "Date Test");
+ deepEqual(modelResult.emptyArray, viewmodel.emptyArray(), "Array Test");
+ });
+
+ test("Default Nested Object", function () {
+ var viewmodel, modelResult;
+
+ viewmodel = {
+ nestedObject: {
+ stringProp: ko.observable("test"),
+ number: ko.observable(5),
+ date: ko.observable(new Date("01/01/2001")),
+ emptyArray: ko.observable([])
+ }
+ };
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.nestedObject.stringProp, viewmodel.nestedObject.stringProp(), "String Test");
+ deepEqual(modelResult.nestedObject.number, viewmodel.nestedObject.number(), "Number Test");
+ deepEqual(modelResult.nestedObject.date, viewmodel.nestedObject.date(), "Date Test");
+ deepEqual(modelResult.nestedObject.emptyArray, viewmodel.nestedObject.emptyArray(), "Array Test");
+ });
+
+ test("Default Object Array", function () {
+ var viewmodel, modelResult;
+
+ viewmodel = {
+ objectArray: ko.observableArray([
+ {
+ stringProp: ko.observable("test"),
+ number: ko.observable(5),
+ date: ko.observable(new Date("01/01/2001")),
+ emptyArray: ko.observableArray([])
+ }
+ ])
+ };
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.objectArray[0].stringProp, viewmodel.objectArray()[0].stringProp(), "String Test");
+ deepEqual(modelResult.objectArray[0].number, viewmodel.objectArray()[0].number(), "Number Test");
+ deepEqual(modelResult.objectArray[0].date, viewmodel.objectArray()[0].date(), "Date Test");
+ deepEqual(modelResult.objectArray[0].emptyArray, viewmodel.objectArray()[0].emptyArray(), "Array Test");
+ });
+
+ test("Default Nested Array", function () {
+ var viewmodel, modelResult;
+
+ viewmodel = {
+ nestedArray: ko.observableArray([ko.observableArray([])])
+ };
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.nestedArray[0], viewmodel.nestedArray()[0](), "Array Test");
+ });
+
+
+
+
+ test("Observable Object Basic Types", function () {
+ var viewmodel, modelResult;
+
+ viewmodel = ko.observable({
+ stringProp: ko.observable("test"),
+ number: ko.observable(5),
+ date: ko.observable(new Date("01/01/2001")),
+ emptyArray: ko.observableArray([])
+ });
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.stringProp, viewmodel().stringProp(), "String Test");
+ deepEqual(modelResult.number, viewmodel().number(), "Number Test");
+ deepEqual(modelResult.date, viewmodel().date(), "Date Test");
+ deepEqual(modelResult.emptyArray, viewmodel().emptyArray(), "Array Test");
+ });
+
+ test("Observable Object Nested Object", function () {
+ var viewmodel, modelResult;
+
+ viewmodel = ko.observable({
+ nestedObject: ko.observable({
+ stringProp: ko.observable("test"),
+ number: ko.observable(5),
+ date: ko.observable(new Date("01/01/2001")),
+ emptyArray: ko.observable([])
+ })
+ });
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.nestedObject.stringProp, viewmodel().nestedObject().stringProp(), "String Test");
+ deepEqual(modelResult.nestedObject.number, viewmodel().nestedObject().number(), "Number Test");
+ deepEqual(modelResult.nestedObject.date, viewmodel().nestedObject().date(), "Date Test");
+ deepEqual(modelResult.nestedObject.emptyArray, viewmodel().nestedObject().emptyArray(), "Array Test");
+ });
+
+ test("Observable Object Object Array", function () {
+ var viewmodel, modelResult;
+
+ viewmodel = ko.observable({
+ objectArray: ko.observableArray([
+ ko.observable({
+ stringProp: ko.observable("test"),
+ number: ko.observable(5),
+ date: ko.observable(new Date("01/01/2001")),
+ emptyArray: ko.observableArray([])
+ })
+ ])
+ });
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.objectArray[0].stringProp, viewmodel().objectArray()[0]().stringProp(), "String Test");
+ deepEqual(modelResult.objectArray[0].number, viewmodel().objectArray()[0]().number(), "Number Test");
+ deepEqual(modelResult.objectArray[0].date, viewmodel().objectArray()[0]().date(), "Date Test");
+ deepEqual(modelResult.objectArray[0].emptyArray, viewmodel().objectArray()[0]().emptyArray(), "Array Test");
+ });
+
+ test("Observable Object Nested Array", function () {
+ var viewmodel, modelResult;
+
+ viewmodel = ko.observable({
+ nestedArray: ko.observableArray([ko.observableArray([])])
+ });
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.nestedArray[0], viewmodel().nestedArray()[0](), "Array Test");
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/undefined-Basic-qunit-tests.js b/Tests/amd/undefined-Basic-qunit-tests.js
new file mode 100644
index 0000000..92e3f85
--- /dev/null
+++ b/Tests/amd/undefined-Basic-qunit-tests.js
@@ -0,0 +1,69 @@
+///
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ var model, updatedModel, modelResult;
+ module("Basic Undefined Tests", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+
+ model = {
+ Prop1: undefined,
+ Prop2: "test2",
+ Prop3: undefined,
+ Prop4: {},
+ Prop5: undefined,
+ Prop6: []
+ };
+
+ updatedModel = {
+ Prop1: "test2",
+ Prop2: undefined,
+ Prop3: {},
+ Prop4: undefined,
+ Prop5: [],
+ Prop6: undefined
+
+ };
+
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ model = undefined;
+ updatedModel = undefined;
+ modelResult = undefined;
+ }
+ });
+
+
+ test("Basic", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(viewmodel.Prop1(), model.Prop1, "Undefined Prop Test");//1
+ deepEqual(viewmodel.Prop2(), model.Prop2, "String Prop Test");//2
+ deepEqual(viewmodel.Prop4, model.Prop4, "Object Prop Test");//3
+ deepEqual(viewmodel.Prop6(), model.Prop6, "Array Prop Test");//4
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.Prop1(), updatedModel.Prop1, "Undefined to Value Update Test");//5
+ deepEqual(viewmodel.Prop2(), updatedModel.Prop2, "Value to Undefined Update Test");//6
+ deepEqual(viewmodel.Prop3(), updatedModel.Prop3, "Undefined to Object Update Test");//7
+ deepEqual(viewmodel.Prop4, updatedModel.Prop4, "Object to Undefined Update Test");//8
+ deepEqual(viewmodel.Prop5(), updatedModel.Prop5, "Undefined to Array Update Test");//9
+ notEqual(typeof viewmodel.Prop5.push, "function", "Undefined to Array Update Is Not Observable Array Test");//10
+ deepEqual(viewmodel.Prop6(), updatedModel.Prop6, "Array to Undefined Update Test");//11
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.Prop1, updatedModel.Prop1, "Undefined to Value Update Test");//12
+ deepEqual(modelResult.Prop2, updatedModel.Prop2, "Value to Undefined Update Test");//13
+ deepEqual(modelResult.Prop3, updatedModel.Prop3, "Undefined to Object Update Test");//14
+ deepEqual(modelResult.Prop4, updatedModel.Prop4, "Object to Undefined Update Test");//15
+ deepEqual(modelResult.Prop5, updatedModel.Prop5, "Undefined to Array Update Test");//16
+ deepEqual(modelResult.Prop6, updatedModel.Prop6, "Array to Undefined Update Test");//17
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/undefined-Mapping-qunit-tests.js b/Tests/amd/undefined-Mapping-qunit-tests.js
new file mode 100644
index 0000000..038ee8c
--- /dev/null
+++ b/Tests/amd/undefined-Mapping-qunit-tests.js
@@ -0,0 +1,280 @@
+///
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ var model, updatedModel, modelResult;
+ module("Undefined Mapping Tests", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+
+ model = {
+ Prop1: undefined,
+ Prop2: "test2",
+ Prop3: {},
+ Prop4: undefined
+ };
+
+ updatedModel = {
+ Prop1: "test2",
+ Prop2: undefined,
+ Prop3: undefined,
+ Prop4: {}
+ };
+
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ model = undefined;
+ updatedModel = undefined;
+ modelResult = undefined;
+ }
+ });
+
+ test("Extend String Undefined", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ extend: {
+ "{root}.Prop1": function (val) {
+ val.isValid = ko.computed(function () {
+ return val() != undefined && val().length > 0;
+ });
+ },
+ "{root}.Prop2": function (val) {
+ val.isValid = ko.computed(function () {
+ return val() != undefined && val().length > 0;
+ });
+ }
+ }
+ });
+
+ deepEqual(viewmodel.Prop1(), model.Prop1, "Undefined Prop Test");
+ deepEqual(viewmodel.Prop1.isValid(), false, "Undefined Prop Extend Test");
+ deepEqual(viewmodel.Prop2(), model.Prop2, "String Prop Test");
+ deepEqual(viewmodel.Prop2.isValid(), true, "Undefined Prop Extend Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.Prop1(), updatedModel.Prop1, "Undefined Prop Test");
+ deepEqual(viewmodel.Prop1.isValid(), true, "Undefined Prop Extend Test");
+ deepEqual(viewmodel.Prop2(), updatedModel.Prop2, "String Prop Test");
+ deepEqual(viewmodel.Prop2.isValid(), false, "Undefined Prop Extend Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult, updatedModel, "Result Object Comparison");
+ });
+
+ test("Extend Object Undefined", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ extend: {
+ "{root}.Prop3": function (val) {
+ val.isValid = ko.computed(function () {
+ return ko.utils.unwrapObservable(val) != undefined;
+ });
+ },
+ "{root}.Prop4": function (val) {
+ val.isValid = ko.computed(function () {
+ return ko.utils.unwrapObservable(val) != undefined;
+ });
+ }
+ }
+ });
+
+ deepEqual(typeof viewmodel.Prop3, "object", "Object Prop Test");
+ deepEqual(viewmodel.Prop3.isValid(), true, "Object Prop Extend Test");
+ deepEqual(viewmodel.Prop4(), undefined, "Undefined Prop Test");
+ deepEqual(viewmodel.Prop4.isValid(), false, "Undefined Prop Extend Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.Prop3, undefined, "Object to Undefined Prop Update Test");
+ deepEqual(viewmodel.Prop4(), updatedModel.Prop4, "Undefined to Object Update Prop Test");
+ deepEqual(viewmodel.Prop4.isValid(), true, "Undefined to Object Update Prop Extend Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult, updatedModel, "Result Object Comparison");
+ });
+
+ test("Extend Object Undefined", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ extend: {
+ "{root}.Prop1": function (val) {
+ if (!ko.isObservable(val)) {
+ val = ko.observable(val)
+ }
+ return val;
+ },
+ "{root}.Prop2": function (val) {
+ if (!ko.isObservable(val)) {
+ val = ko.observable(val)
+ }
+ return val;
+ },
+ "{root}.Prop3": function (val) {
+ if (!ko.isObservable(val)) {
+ val = ko.observable(val)
+ }
+ return val;
+ },
+ "{root}.Prop4": function (val) {
+ if (!ko.isObservable(val)) {
+ val = ko.observable(val)
+ }
+ return val;
+ }
+ }
+ });
+
+ deepEqual(viewmodel.Prop1(), model.Prop1);
+ deepEqual(viewmodel.Prop2(), model.Prop2);
+ deepEqual(viewmodel.Prop3(), model.Prop3);
+ deepEqual(viewmodel.Prop4(), model.Prop4);
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.Prop1(), updatedModel.Prop1);
+ deepEqual(viewmodel.Prop2(), updatedModel.Prop2);
+ deepEqual(viewmodel.Prop3(), updatedModel.Prop3);
+ deepEqual(viewmodel.Prop4(), updatedModel.Prop4);
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(updatedModel, modelResult);
+ });
+
+ test("Append property", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ append: ["{root}.Prop1", "{root}.Prop2"]
+ });
+
+ deepEqual(viewmodel.Prop1, model.Prop1, "Undefined to Value Update Test");
+ deepEqual(viewmodel.Prop2, model.Prop2, "Value to Undefined Update Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.Prop1, updatedModel.Prop1, "Undefined to Value Update Test");
+ deepEqual(viewmodel.Prop2, updatedModel.Prop2, "Value to Undefined Update Test");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(modelResult.Prop1, updatedModel.Prop1, "Undefined to Value Update Test");
+ deepEqual(modelResult.Prop2, updatedModel.Prop2, "Value to Undefined Update Test");
+
+ });
+
+ test("Custom basic", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ custom: {
+ "{root}.Prop1":function (val) {
+ return ko.observable(val);
+ },
+ "{root}.Prop2": function (val) {
+ return ko.observable(val);
+ },
+ "{root}.Prop3": function (val) {
+ return ko.observable(val);
+ },
+ "{root}.Prop4": function (val) {
+ return ko.observable(val);
+ }
+ }
+ });
+
+ deepEqual(viewmodel.Prop1(), model.Prop1);
+ deepEqual(viewmodel.Prop2(), model.Prop2);
+ deepEqual(viewmodel.Prop3(), model.Prop3);
+ deepEqual(viewmodel.Prop4(), model.Prop4);
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.Prop1(), updatedModel.Prop1);
+ deepEqual(viewmodel.Prop2(), updatedModel.Prop2);
+ deepEqual(viewmodel.Prop3(), updatedModel.Prop3);
+ deepEqual(viewmodel.Prop4(), updatedModel.Prop4);
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(updatedModel, modelResult);
+
+ });
+
+ test("Custom map and unmap", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ custom: {
+ "{root}.Prop1": {
+ map: function (val) {
+ return ko.observable(val);
+ },
+ unmap: function (val) {
+ return val();
+ }
+ },
+ "{root}.Prop2": {
+ map: function (val) {
+ return ko.observable(val);
+ },
+ unmap: function (val) {
+ return val();
+ }
+ },
+ "{root}.Prop3": {
+ map: function (val) {
+ return ko.observable(val);
+ },
+ unmap: function (val) {
+ return val();
+ }
+ },
+ "{root}.Prop4": {
+ map: function (val) {
+ return ko.observable(val);
+ },
+ unmap: function (val) {
+ return val();
+ }
+ }
+ }
+ });
+
+ deepEqual(viewmodel.Prop1(), model.Prop1);
+ deepEqual(viewmodel.Prop2(), model.Prop2);
+ deepEqual(viewmodel.Prop3(), model.Prop3);
+ deepEqual(viewmodel.Prop4(), model.Prop4);
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.Prop1(), updatedModel.Prop1);
+ deepEqual(viewmodel.Prop2(), updatedModel.Prop2);
+ deepEqual(viewmodel.Prop3(), updatedModel.Prop3);
+ deepEqual(viewmodel.Prop4(), updatedModel.Prop4);
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(updatedModel, modelResult);
+ });
+
+ test("Exclude", function () {
+
+ var viewmodel = ko.viewmodel.fromModel(model, {
+ exclude: ["{root}.Prop2"]
+ });
+
+ equal(viewmodel.hasOwnProperty("Prop2"), false, "From Model String Prop Not Exist");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ equal(viewmodel.hasOwnProperty("Prop2"), false, "Update... String Prop Not Exist");
+
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ equal(modelResult.hasOwnProperty("Prop2"), false, "Update... String Prop Not Exist");
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/updateFromModel-Basic-qunit-tests.js b/Tests/amd/updateFromModel-Basic-qunit-tests.js
new file mode 100644
index 0000000..bc82929
--- /dev/null
+++ b/Tests/amd/updateFromModel-Basic-qunit-tests.js
@@ -0,0 +1,286 @@
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ module("updateFromModel Basic", {
+ setup: function () {
+ //ko.viewmodel.options.logging = true;
+ },
+ teardown: function () {
+ //ko.viewmodel.options.logging = false;
+ }
+ });
+
+
+ test("Default simple types", function () {
+ var model, updatedModel, viewmodel;
+
+ model = {
+ stringProp: "test",
+ number: 5,
+ date: new Date("01/01/2001")
+ };
+
+ updatedModel = {
+ stringProp: "test2",
+ number: 6,
+ date: new Date("12/04/2001")
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.stringProp(), updatedModel.stringProp, "String Test");
+ deepEqual(viewmodel.number(), updatedModel.number, "Number Test");
+ deepEqual(viewmodel.date(), updatedModel.date, "Date Test");
+ });
+
+ test("nested object simple types", function () {
+ var model, updatedModel, viewmodel;
+
+ model = {
+ test:{
+ stringProp: "test",
+ number: 5,
+ date: new Date("01/01/2001")
+ }
+ };
+
+ updatedModel = {
+ test: {
+ stringProp: "test2",
+ number: 6,
+ date: new Date("12/04/2001")
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.test.stringProp(), updatedModel.test.stringProp, "String Test");
+ deepEqual(viewmodel.test.number(), updatedModel.test.number, "Number Test");
+ deepEqual(viewmodel.test.date(), updatedModel.test.date, "Date Test");
+ });
+
+ test("nested object override success simple types", function () {
+ var model, updatedModel, viewmodel, options;
+
+ options = {
+ override:["{root}.test"]
+ };
+
+ model = {
+ test: {
+ stringProp: "test",
+ number: 5,
+ date: new Date("01/01/2001")
+ }
+ };
+
+ updatedModel = {
+ test: {
+ stringProp: "test2",
+ number: 6,
+ date: new Date("12/04/2001")
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, options);
+ deepEqual(viewmodel.test.stringProp(), model.test.stringProp, "Viewmodel String Test");
+ deepEqual(viewmodel.test.number(), model.test.number, "Viewmodel Number Test");
+ deepEqual(viewmodel.test.date(), model.test.date, "Viewmodel Date Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.test.stringProp(), updatedModel.test.stringProp, "UpdatedModel String Test");
+ deepEqual(viewmodel.test.number(), updatedModel.test.number, "UpdatedModel Number Test");
+ deepEqual(viewmodel.test.date(), updatedModel.test.date, "UpdatedModel Date Test");
+ });
+
+ //if undefined then we are using facade around ko.mapping
+ //used to exclude tests that are incompatable with ko.mapping
+ if (ko.viewmodel.options.mappingCompatability !== undefined) {
+ test("ID arrayChildId match array object simple types", function () {
+ var model, updatedModel, viewmodel, options, originalArrayItem;
+
+ model = {
+ items: [
+ {
+ id: 5,
+ stringProp: "test",
+ number: 3,
+ date: new Date("2/04/2001")
+ }
+ ]
+ };
+
+ updatedModel = {
+ items: [
+ {
+ id: 5,
+ stringProp: "test2",
+ number: 6,
+ date: new Date("12/04/2001")
+ },
+ {
+ id: 6,
+ stringProp: "test",
+ number: 3,
+ date: new Date("2/04/2001")
+ }
+ ]
+ };
+
+ options = {
+ arrayChildId: {
+ "{root}.items": "id"
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, options);
+ originalArrayItem = viewmodel.items()[0];
+ deepEqual(originalArrayItem.id(), 5, "verify id before update");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.items()[0].id(), 5, "verify id after update");
+ deepEqual(viewmodel.items()[0] === originalArrayItem, true, "verify still same object");
+ deepEqual(viewmodel.items()[0].id(), updatedModel.items[0].id, "String Test");
+ deepEqual(viewmodel.items()[0].stringProp(), updatedModel.items[0].stringProp, "String Test");
+ deepEqual(viewmodel.items()[0].number(), updatedModel.items[0].number, "String Test");
+ deepEqual(viewmodel.items()[0].date(), updatedModel.items[0].date, "String Test");
+ });
+ }
+
+ test("No arrayChildId option array object simple types", function () {
+ var model, updatedModel, viewmodel, options, originalArrayItem;
+
+ model = {
+ items: [
+ {
+ id: 5,
+ stringProp: "test",
+ number: 3,
+ date: new Date("2/04/2001")
+ }
+ ]
+ };
+
+ updatedModel = {
+ items: [
+ {
+ id: 5,
+ stringProp: "test2",
+ number: 6,
+ date: new Date("12/04/2001")
+ },
+ {
+ id: 6,
+ stringProp: "test",
+ number: 3,
+ date: new Date("2/04/2001")
+ }
+ ]
+ };
+
+ options = {};
+
+ viewmodel = ko.viewmodel.fromModel(model, options);
+ originalArrayItem = viewmodel.items()[0];
+ deepEqual(originalArrayItem.id(), 5, "verify id before update");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.items()[0].id(), 5, "verify id after update");
+ deepEqual(viewmodel.items()[0] !== originalArrayItem, true, "verify not still same object");
+ deepEqual(viewmodel.items()[0].id(), updatedModel.items[0].id, "String Test");
+ deepEqual(viewmodel.items()[0].stringProp(), updatedModel.items[0].stringProp, "String Test");
+ deepEqual(viewmodel.items()[0].number(), updatedModel.items[0].number, "String Test");
+ deepEqual(viewmodel.items()[0].date(), updatedModel.items[0].date, "String Test");
+ });
+
+ test("arrayChildId option swapped array item item", function () {
+ var model, updatedModel, viewmodel, options, originalArrayItem;
+
+ model = {
+ items: [
+ {
+ id: 4,
+ stringProp: "test",
+ number: 3,
+ date: new Date("2/04/2001")
+ }
+ ]
+ };
+
+ updatedModel = {
+ items: [
+ {
+ id: 5,
+ stringProp: "test2",
+ number: 6,
+ date: new Date("12/04/2001")
+ }
+ ]
+ };
+
+ options = {
+ arrayChildId: {
+ "{root}.items": "id"
+ }
+ }
+
+ viewmodel = ko.viewmodel.fromModel(model, options);
+
+ originalArrayItem = viewmodel.items()[0];
+ deepEqual(originalArrayItem.id(), 4, "verify id before update");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.items()[0] !== originalArrayItem, true, "verify not still same object");
+ deepEqual(viewmodel.items()[0].id(), 5, "verify id before update");
+ deepEqual(viewmodel.items().length, updatedModel.items.length, "Array Length Test");
+ deepEqual(viewmodel.items()[0].id(), updatedModel.items[0].id, "Array Item id Test");
+ deepEqual(viewmodel.items()[0].stringProp(), updatedModel.items[0].stringProp, "String Test");
+ deepEqual(viewmodel.items()[0].number(), updatedModel.items[0].number, "String Test");
+ deepEqual(viewmodel.items()[0].date(), updatedModel.items[0].date, "String Test");
+ });
+ test("array item item", function () {
+ var model, updatedModel, viewmodel, options;
+
+ model = {
+ items: [
+ {
+ stringProp: "test",
+ number: 3,
+ date: new Date("2/04/2001")
+ }
+ ]
+ };
+
+ updatedModel = {
+ items: [
+ {
+ stringProp: "test2",
+ number: 6,
+ date: new Date("12/04/2001")
+ }
+ ]
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model);
+
+ deepEqual(viewmodel.items().length, model.items.length, "Array Length Test");
+ deepEqual(viewmodel.items()[0].stringProp(), model.items[0].stringProp, "String Test");
+ deepEqual(viewmodel.items()[0].number(), model.items[0].number, "String Test");
+ deepEqual(viewmodel.items()[0].date(), model.items[0].date, "String Test");
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedModel);
+
+ deepEqual(viewmodel.items().length, updatedModel.items.length, "Array Length Test");
+ deepEqual(viewmodel.items()[0].stringProp(), updatedModel.items[0].stringProp, "String Test");
+ deepEqual(viewmodel.items()[0].number(), updatedModel.items[0].number, "String Test");
+ deepEqual(viewmodel.items()[0].date(), updatedModel.items[0].date, "String Test");
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/updateFromModel-Mapping-contiguous-qunit-tests.js b/Tests/amd/updateFromModel-Mapping-contiguous-qunit-tests.js
new file mode 100644
index 0000000..9a704a1
--- /dev/null
+++ b/Tests/amd/updateFromModel-Mapping-contiguous-qunit-tests.js
@@ -0,0 +1,54 @@
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ var model, updatedmodel, viewmodel, customMapping, originalChildObject, modelResult, actual, newChildObject;
+
+ module("updateFromModel Contiguous Object Updates", {
+ setup: function () {
+
+ },
+ teardown: function () {
+
+ }
+ });
+
+
+ model = { items: [{ test: 5, Id: 3 }] };
+
+ var customMapping = {
+ extend: {
+ "{root}.items[i]": function (item) {
+ return ko.observable(item);
+ }
+ },
+ arrayChildId: {
+ "{root}.items": "Id"
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ originalChildObject = viewmodel.items()[0]();
+
+ updatedmodel = { items: [{ test: 9, Id: 3 }] };
+ test("Contiguous Test Fail", function () {
+
+ newChildObject = viewmodel.items()[0]();
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ notEqual(viewmodel.items()[0]().test(), updatedmodel.items[0].test, "Test value has been updated in viewmodel");
+ });
+
+
+ test("Contiguous Test Pass", function () {
+ ko.viewmodel.updateFromModel(viewmodel, updatedmodel);
+ newChildObject = viewmodel.items()[0]();
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(viewmodel.items()[0]().test(), updatedmodel.items[0].test, "Test value has been updated in viewmodel");
+ deepEqual(updatedmodel, modelResult, "Updated model and toModel have same values");
+ ok(originalChildObject == newChildObject, "Original child object was updated and not replaced.");
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/updateFromModel-Mapping-noncontiguous-qunit-tests.js b/Tests/amd/updateFromModel-Mapping-noncontiguous-qunit-tests.js
new file mode 100644
index 0000000..8f06894
--- /dev/null
+++ b/Tests/amd/updateFromModel-Mapping-noncontiguous-qunit-tests.js
@@ -0,0 +1,51 @@
+define(['knockout', 'viewmodel'], function (ko) {
+ var run = function () {
+ var model, updatedmodel, viewmodel, customMapping, originalChildObject, modelResult, actual, newChildObject;
+
+ module("updateFromModel Noncontiguous Object Updates", {
+ setup: function () {
+
+ },
+ teardown: function () {
+
+ }
+ });
+
+
+ model = { items: [{ test: 5, Id: 3 }] };
+
+ var customMapping = {
+ extend: {
+ "{root}.items[i]": function (item) {
+ return ko.observable(item);
+ }
+ },
+ arrayChildId: {
+ "{root}.items": "Id"
+ }
+ };
+
+ viewmodel = ko.viewmodel.fromModel(model, customMapping);
+
+ originalChildObject = viewmodel.items()[0]();
+
+
+ updatedmodel = { items: [{ test: 7, Id: 3 }] };
+
+ ko.viewmodel.updateFromModel(viewmodel, updatedmodel, true).onComplete(function () {
+ asyncTest("Noncontiguous Test", function () {
+ expect(4);
+ newChildObject = viewmodel.items()[0]();
+ modelResult = ko.viewmodel.toModel(viewmodel);
+
+ deepEqual(viewmodel.items()[0]().test(), updatedmodel.items[0].test, "Test value has been updated in viewmodel");
+ deepEqual(viewmodel.items()[0]().test(), 7, "Test value is what was expected");
+ deepEqual(updatedmodel, modelResult, "Updated model and toModel have same values");
+ ok(originalChildObject == newChildObject, "Original child object was updated and not replaced.");
+ start();
+ });
+ });
+ };
+
+ return {run: run}
+});
diff --git a/Tests/amd/updateFromModel-Mapping-qunit-tests.js b/Tests/amd/updateFromModel-Mapping-qunit-tests.js
new file mode 100644
index 0000000..e69de29
diff --git a/knockout.viewmodel.js b/knockout.viewmodel.js
index 91b75ec..4131e3a 100644
--- a/knockout.viewmodel.js
+++ b/knockout.viewmodel.js
@@ -4,7 +4,16 @@
/*jshint eqnull:true, boss:true, loopfunc:true, evil:true, laxbreak:true, undef:true, unused:true, browser:true, immed:true, devel:true, sub: true, maxerr:50 */
/*global ko:false */
-(function () {
+// Uses AMD or browser globals to create a Knockout plugin.
+(function (factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['knockout'], factory);
+ } else {
+ // Browser globals
+ factory(ko);
+ }
+}(function (ko) {
//Module declarations. For increased compression with simple settings on the closure compiler,
//the ko functions are stored in variables. These variable names will be shortened by the compiler,
//whereas references to ko would not be. There is also a performance savings from this.
@@ -491,4 +500,4 @@
return recursiveUpdate(model, viewmodel, rootContext, undefined, noncontiguousObjectUpdateCount);
}
};
-}());
+}));