Skip to content

Commit

Permalink
Clean up options tests: create helper function for common "expects"; …
Browse files Browse the repository at this point in the history
…and remove unnecessary reference to "value" binding in one test.
  • Loading branch information
mbest committed Mar 12, 2013
1 parent 83bcca7 commit 2a4cfa8
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 27 deletions.
42 changes: 15 additions & 27 deletions spec/defaultBindings/optionsBehaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ describe('Binding: Options', function() {
var observable = new ko.observableArray(["A", "B", "C"]);
testNode.innerHTML = "<select data-bind='options:myValues'><option>should be deleted</option></select>";
ko.applyBindings({ myValues: observable }, testNode);
var displayedOptions = ko.utils.arrayMap(testNode.childNodes[0].childNodes, function (node) { return node.innerHTML; });
expect(displayedOptions).toEqual(["A", "B", "C"]);
expect(testNode.childNodes[0]).toHaveTexts(["A", "B", "C"]);
});

it('Should accept optionsText and optionsValue params to display subproperties of the model values', function() {
Expand All @@ -26,10 +25,8 @@ describe('Binding: Options', function() {
]);
testNode.innerHTML = "<select data-bind='options:myValues, optionsText: \"name\", optionsValue: \"id\"'><option>should be deleted</option></select>";
ko.applyBindings({ myValues: modelValues }, testNode);
var displayedText = ko.utils.arrayMap(testNode.childNodes[0].childNodes, function (node) { return node.innerHTML; });
var displayedValues = ko.utils.arrayMap(testNode.childNodes[0].childNodes, function (node) { return node.value; });
expect(displayedText).toEqual(["bob", "frank"]);
expect(displayedValues).toEqual(["6", "13"]);
expect(testNode.childNodes[0]).toHaveTexts(["bob", "frank"]);
expect(testNode.childNodes[0]).toHaveValues(["6", "13"]);
});

it('Should accept function in optionsText param to display subproperties of the model values', function() {
Expand All @@ -50,8 +47,7 @@ describe('Binding: Options', function() {
]);
testNode.innerHTML = "<select data-bind='options: myValues, optionsValue: function (v) { return v.name + \" (\" + v.job + \")\"; }'><option>should be deleted</option></select>";
ko.applyBindings({ myValues: modelValues }, testNode);
var values = ko.utils.arrayMap(testNode.childNodes[0].childNodes, function (node) { return node.value; });
expect(values).toEqual(["bob (manager)", "frank (coder & tester)"]);
expect(testNode.childNodes[0]).toHaveValues(["bob (manager)", "frank (coder & tester)"]);
var displayedText = ko.utils.arrayMap(testNode.childNodes[0].childNodes, function (node) { return node.innerText || node.textContent; });
expect(displayedText).toEqual(["bob (manager)", "frank (coder & tester)"]);
});
Expand All @@ -63,8 +59,7 @@ describe('Binding: Options', function() {
]);
testNode.innerHTML = "<select data-bind='options: myValues, optionsValue: \"name\"'></select>";
ko.applyBindings({ myValues: modelValues }, testNode);
var values = ko.utils.arrayMap(testNode.childNodes[0].childNodes, function (node) { return node.value; });
expect(values).toEqual(["frank"]);
expect(testNode.childNodes[0]).toHaveValues(["frank"]);
});

it('Should include items marked as destroyed if optionsIncludeDestroyed is set', function() {
Expand All @@ -74,17 +69,15 @@ describe('Binding: Options', function() {
]);
testNode.innerHTML = "<select data-bind='options: myValues, optionsValue: \"name\", optionsIncludeDestroyed: true'></select>";
ko.applyBindings({ myValues: modelValues }, testNode);
var values = ko.utils.arrayMap(testNode.childNodes[0].childNodes, function (node) { return node.value; });
expect(values).toEqual(["bob", "frank"]);
expect(testNode.childNodes[0]).toHaveValues(["bob", "frank"]);
});

it('Should update the SELECT node\'s options if the model changes', function () {
var observable = new ko.observableArray(["A", "B", "C"]);
testNode.innerHTML = "<select data-bind='options:myValues'><option>should be deleted</option></select>";
ko.applyBindings({ myValues: observable }, testNode);
observable.splice(1, 1);
var displayedOptions = ko.utils.arrayMap(testNode.childNodes[0].childNodes, function (node) { return node.innerHTML; });
expect(displayedOptions).toEqual(["A", "C"]);
expect(testNode.childNodes[0]).toHaveTexts(["A", "C"]);
});

it('Should retain as much selection as possible when changing the SELECT node\'s options', function () {
Expand All @@ -93,33 +86,28 @@ describe('Binding: Options', function() {
ko.applyBindings({ myValues: observable }, testNode);
testNode.childNodes[0].options[1].selected = true;
expect(testNode.childNodes[0]).toHaveSelectedValues(["B"]);
observable.valueHasMutated();
observable(["B", "C", "A"]);
expect(testNode.childNodes[0]).toHaveSelectedValues(["B"]);
});

it('Should place a caption at the top of the options list and display it when the model value is undefined', function() {
testNode.innerHTML = "<select data-bind='options:[\"A\", \"B\"], optionsCaption: \"Select one...\"'></select>";
ko.applyBindings({}, testNode);
var displayedOptions = ko.utils.arrayMap(testNode.childNodes[0].childNodes, function (node) { return node.innerHTML; });
expect(displayedOptions).toEqual(["Select one...", "A", "B"]);
expect(testNode.childNodes[0]).toHaveTexts(["Select one...", "A", "B"]);
});

it('Should allow the caption to be given by an observable, and update it when the model value changes (without affecting selection)', function() {
var myCaption = ko.observable("Initial caption"),
mySelectedValue = ko.observable("B");
testNode.innerHTML = "<select data-bind='options:[\"A\", \"B\"], optionsCaption: myCaption, value: mySelectedValue'></select>";
ko.applyBindings({ myCaption: myCaption, mySelectedValue: mySelectedValue }, testNode);
var myCaption = ko.observable("Initial caption");
testNode.innerHTML = "<select data-bind='options:[\"A\", \"B\"], optionsCaption: myCaption'></select>";
ko.applyBindings({ myCaption: myCaption }, testNode);
testNode.childNodes[0].options[2].selected = true;

var displayedOptions = ko.utils.arrayMap(testNode.childNodes[0].childNodes, function (node) { return node.innerHTML; });
expect(testNode.childNodes[0].selectedIndex).toEqual(2);
expect(mySelectedValue()).toEqual("B");
expect(displayedOptions).toEqual(["Initial caption", "A", "B"]);
expect(testNode.childNodes[0]).toHaveTexts(["Initial caption", "A", "B"]);

// Also show we can update the caption without affecting selection
myCaption("New caption");
var displayedOptions2 = ko.utils.arrayMap(testNode.childNodes[0].childNodes, function (node) { return node.innerHTML; });
expect(testNode.childNodes[0].selectedIndex).toEqual(2);
expect(mySelectedValue()).toEqual("B");
expect(displayedOptions2).toEqual(["New caption", "A", "B"]);
expect(testNode.childNodes[0]).toHaveTexts(["New caption", "A", "B"]);
});
});
12 changes: 12 additions & 0 deletions spec/lib/jasmine.extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ jasmine.Matchers.prototype.toHaveOwnProperties = function (expectedProperties) {
return this.env.equals_(ownProperties, expectedProperties);
};

jasmine.Matchers.prototype.toHaveTexts = function (expectedTexts) {
var texts = ko.utils.arrayMap(this.actual.childNodes, function (node) { return node.innerText || node.textContent; });
this.actual = texts; // Fix explanatory message
return this.env.equals_(texts, expectedTexts);
};

jasmine.Matchers.prototype.toHaveValues = function (expectedValues) {
var values = ko.utils.arrayMap(this.actual.childNodes, function (node) { return node.value; });
this.actual = values; // Fix explanatory message
return this.env.equals_(values, expectedValues);
};

jasmine.Matchers.prototype.toHaveSelectedValues = function (expectedValues) {
var selectedNodes = ko.utils.arrayFilter(this.actual.childNodes, function (node) { return node.selected; }),
selectedValues = ko.utils.arrayMap(selectedNodes, function (node) { return ko.selectExtensions.readValue(node); });
Expand Down

0 comments on commit 2a4cfa8

Please sign in to comment.