forked from knockout/knockout
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split default bindings specs into separate files
- Loading branch information
1 parent
48c911b
commit 8664530
Showing
24 changed files
with
1,904 additions
and
1,897 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,3 +11,5 @@ desktop.ini | |
.eprj | ||
perf/* | ||
*.orig | ||
|
||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
describe('Binding: Attr', { | ||
before_each: JSSpec.prepareTestNode, | ||
|
||
'Should be able to set arbitrary attribute values': function() { | ||
var model = { myValue: "first value" }; | ||
testNode.innerHTML = "<div data-bind='attr: {firstAttribute: myValue, \"second-attribute\": true}'></div>"; | ||
ko.applyBindings(model, testNode); | ||
value_of(testNode.childNodes[0].getAttribute("firstAttribute")).should_be("first value"); | ||
value_of(testNode.childNodes[0].getAttribute("second-attribute")).should_be("true"); | ||
}, | ||
|
||
'Should be able to set \"name\" attribute, even on IE6-7': function() { | ||
var myValue = ko.observable("myName"); | ||
testNode.innerHTML = "<input data-bind='attr: { name: myValue }' />"; | ||
ko.applyBindings({ myValue: myValue }, testNode); | ||
value_of(testNode.childNodes[0].name).should_be("myName"); | ||
value_of(testNode.childNodes[0].outerHTML).should_match('name="?myName"?'); | ||
|
||
// Also check we can remove it (which, for a name attribute, means setting it to an empty string) | ||
myValue(false); | ||
value_of(testNode.childNodes[0].name).should_be(""); | ||
value_of(testNode.childNodes[0].outerHTML).should_not_match('name="?([^">]+)'); | ||
}, | ||
|
||
'Should respond to changes in an observable value': function() { | ||
var model = { myprop : ko.observable("initial value") }; | ||
testNode.innerHTML = "<div data-bind='attr: { someAttrib: myprop }'></div>"; | ||
ko.applyBindings(model, testNode); | ||
value_of(testNode.childNodes[0].getAttribute("someAttrib")).should_be("initial value"); | ||
|
||
// Change the observable; observe it reflected in the DOM | ||
model.myprop("new value"); | ||
value_of(testNode.childNodes[0].getAttribute("someAttrib")).should_be("new value"); | ||
}, | ||
|
||
'Should remove the attribute if the value is strictly false, null, or undefined': function() { | ||
var model = { myprop : ko.observable() }; | ||
testNode.innerHTML = "<div data-bind='attr: { someAttrib: myprop }'></div>"; | ||
ko.applyBindings(model, testNode); | ||
ko.utils.arrayForEach([false, null, undefined], function(testValue) { | ||
model.myprop("nonempty value"); | ||
value_of(testNode.childNodes[0].getAttribute("someAttrib")).should_be("nonempty value"); | ||
model.myprop(testValue); | ||
value_of(testNode.childNodes[0].getAttribute("someAttrib")).should_be(null); | ||
}); | ||
}, | ||
|
||
'Should be able to set class attribute and access it using className property': function() { | ||
var model = { myprop : ko.observable("newClass") }; | ||
testNode.innerHTML = "<div class='oldClass' data-bind=\"attr: {'class': myprop}\"></div>"; | ||
value_of(testNode.childNodes[0].className).should_be("oldClass"); | ||
ko.applyBindings(model, testNode); | ||
value_of(testNode.childNodes[0].className).should_be("newClass"); | ||
// Should be able to clear class also | ||
model.myprop(undefined); | ||
value_of(testNode.childNodes[0].className).should_be(""); | ||
value_of(testNode.childNodes[0].getAttribute("class")).should_be(null); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
describe('Binding: Checked', { | ||
before_each: JSSpec.prepareTestNode, | ||
|
||
'Triggering a click should toggle a checkbox\'s checked state before the event handler fires': function() { | ||
// This isn't strictly to do with the checked binding, but if this doesn't work, the rest of the specs aren't meaningful | ||
testNode.innerHTML = "<input type='checkbox' />"; | ||
var clickHandlerFireCount = 0, expectedCheckedStateInHandler; | ||
ko.utils.registerEventHandler(testNode.childNodes[0], "click", function() { | ||
clickHandlerFireCount++; | ||
value_of(testNode.childNodes[0].checked).should_be(expectedCheckedStateInHandler); | ||
}) | ||
value_of(testNode.childNodes[0].checked).should_be(false); | ||
expectedCheckedStateInHandler = true; | ||
ko.utils.triggerEvent(testNode.childNodes[0], "click"); | ||
value_of(testNode.childNodes[0].checked).should_be(true); | ||
value_of(clickHandlerFireCount).should_be(1); | ||
|
||
expectedCheckedStateInHandler = false; | ||
ko.utils.triggerEvent(testNode.childNodes[0], "click"); | ||
value_of(testNode.childNodes[0].checked).should_be(false); | ||
value_of(clickHandlerFireCount).should_be(2); | ||
}, | ||
|
||
'Should be able to control a checkbox\'s checked state': function () { | ||
var myobservable = new ko.observable(true); | ||
testNode.innerHTML = "<input type='checkbox' data-bind='checked:someProp' />"; | ||
|
||
ko.applyBindings({ someProp: myobservable }, testNode); | ||
value_of(testNode.childNodes[0].checked).should_be(true); | ||
|
||
myobservable(false); | ||
value_of(testNode.childNodes[0].checked).should_be(false); | ||
}, | ||
|
||
'Should update observable properties on the underlying model when the checkbox click event fires': function () { | ||
var myobservable = new ko.observable(false); | ||
testNode.innerHTML = "<input type='checkbox' data-bind='checked:someProp' />"; | ||
ko.applyBindings({ someProp: myobservable }, testNode); | ||
|
||
ko.utils.triggerEvent(testNode.childNodes[0], "click"); | ||
value_of(myobservable()).should_be(true); | ||
}, | ||
|
||
'Should only notify observable properties on the underlying model *once* even if the checkbox change events fire multiple times': function () { | ||
var myobservable = new ko.observable(); | ||
var timesNotified = 0; | ||
myobservable.subscribe(function() { timesNotified++ }); | ||
testNode.innerHTML = "<input type='checkbox' data-bind='checked:someProp' />"; | ||
ko.applyBindings({ someProp: myobservable }, testNode); | ||
|
||
// Multiple events only cause one notification... | ||
ko.utils.triggerEvent(testNode.childNodes[0], "click"); | ||
ko.utils.triggerEvent(testNode.childNodes[0], "change"); | ||
ko.utils.triggerEvent(testNode.childNodes[0], "change"); | ||
value_of(timesNotified).should_be(1); | ||
|
||
// ... until the checkbox value actually changes | ||
ko.utils.triggerEvent(testNode.childNodes[0], "click"); | ||
ko.utils.triggerEvent(testNode.childNodes[0], "change"); | ||
value_of(timesNotified).should_be(2); | ||
}, | ||
|
||
'Should update non-observable properties on the underlying model when the checkbox click event fires': function () { | ||
var model = { someProp: false }; | ||
testNode.innerHTML = "<input type='checkbox' data-bind='checked:someProp' />"; | ||
ko.applyBindings(model, testNode); | ||
|
||
ko.utils.triggerEvent(testNode.childNodes[0], "click"); | ||
value_of(model.someProp).should_be(true); | ||
}, | ||
|
||
'Should update observable properties on the underlying model when the checkbox is clicked': function () { | ||
var myobservable = new ko.observable(false); | ||
testNode.innerHTML = "<input type='checkbox' data-bind='checked:someProp' />"; | ||
ko.applyBindings({ someProp: myobservable }, testNode); | ||
|
||
ko.utils.triggerEvent(testNode.childNodes[0], "click"); | ||
value_of(myobservable()).should_be(true); | ||
}, | ||
|
||
'Should update non-observable properties on the underlying model when the checkbox is clicked': function () { | ||
var model = { someProp: false }; | ||
testNode.innerHTML = "<input type='checkbox' data-bind='checked:someProp' />"; | ||
ko.applyBindings(model, testNode); | ||
|
||
ko.utils.triggerEvent(testNode.childNodes[0], "click"); | ||
value_of(model.someProp).should_be(true); | ||
}, | ||
|
||
'Should make a radio button checked if and only if its value matches the bound model property': function () { | ||
var myobservable = new ko.observable("another value"); | ||
testNode.innerHTML = "<input type='radio' value='This Radio Button Value' data-bind='checked:someProp' />"; | ||
|
||
ko.applyBindings({ someProp: myobservable }, testNode); | ||
value_of(testNode.childNodes[0].checked).should_be(false); | ||
|
||
myobservable("This Radio Button Value"); | ||
value_of(testNode.childNodes[0].checked).should_be(true); | ||
}, | ||
|
||
'Should set an observable model property to this radio button\'s value when checked': function () { | ||
var myobservable = new ko.observable("another value"); | ||
testNode.innerHTML = "<input type='radio' value='this radio button value' data-bind='checked:someProp' />"; | ||
ko.applyBindings({ someProp: myobservable }, testNode); | ||
|
||
value_of(myobservable()).should_be("another value"); | ||
testNode.childNodes[0].click(); | ||
value_of(myobservable()).should_be("this radio button value"); | ||
}, | ||
|
||
'Should only notify observable properties on the underlying model *once* even if the radio button change/click events fire multiple times': function () { | ||
var myobservable = new ko.observable("original value"); | ||
var timesNotified = 0; | ||
myobservable.subscribe(function() { timesNotified++ }); | ||
testNode.innerHTML = "<input type='radio' value='this radio button value' data-bind='checked:someProp' /><input type='radio' value='different value' data-bind='checked:someProp' />"; | ||
ko.applyBindings({ someProp: myobservable }, testNode); | ||
|
||
// Multiple events only cause one notification... | ||
ko.utils.triggerEvent(testNode.childNodes[0], "click"); | ||
ko.utils.triggerEvent(testNode.childNodes[0], "change"); | ||
ko.utils.triggerEvent(testNode.childNodes[0], "click"); | ||
ko.utils.triggerEvent(testNode.childNodes[0], "change"); | ||
value_of(timesNotified).should_be(1); | ||
|
||
// ... until you click something with a different value | ||
ko.utils.triggerEvent(testNode.childNodes[1], "click"); | ||
ko.utils.triggerEvent(testNode.childNodes[1], "change"); | ||
value_of(timesNotified).should_be(2); | ||
}, | ||
|
||
'Should set a non-observable model property to this radio button\'s value when checked': function () { | ||
var model = { someProp: "another value" }; | ||
testNode.innerHTML = "<input type='radio' value='this radio button value' data-bind='checked:someProp' />"; | ||
ko.applyBindings(model, testNode); | ||
|
||
ko.utils.triggerEvent(testNode.childNodes[0], "click"); | ||
value_of(model.someProp).should_be("this radio button value"); | ||
}, | ||
|
||
'When a checkbox is bound to an array, the checkbox should control whether its value is in that array': function() { | ||
var model = { myArray: ["Existing value", "Unrelated value"] }; | ||
testNode.innerHTML = "<input type='checkbox' value='Existing value' data-bind='checked:myArray' />" | ||
+ "<input type='checkbox' value='New value' data-bind='checked:myArray' />"; | ||
ko.applyBindings(model, testNode); | ||
|
||
value_of(model.myArray).should_be(["Existing value", "Unrelated value"]); | ||
|
||
// Checkbox initial state is determined by whether the value is in the array | ||
value_of(testNode.childNodes[0].checked).should_be(true); | ||
value_of(testNode.childNodes[1].checked).should_be(false); | ||
// Checking the checkbox puts it in the array | ||
ko.utils.triggerEvent(testNode.childNodes[1], "click"); | ||
value_of(testNode.childNodes[1].checked).should_be(true); | ||
value_of(model.myArray).should_be(["Existing value", "Unrelated value", "New value"]); | ||
// Unchecking the checkbox removes it from the array | ||
ko.utils.triggerEvent(testNode.childNodes[1], "click"); | ||
value_of(testNode.childNodes[1].checked).should_be(false); | ||
value_of(model.myArray).should_be(["Existing value", "Unrelated value"]); | ||
}, | ||
|
||
'When a checkbox is bound to an observable array, the checkbox checked state responds to changes in the array': function() { | ||
var model = { myObservableArray: ko.observableArray(["Unrelated value"]) }; | ||
testNode.innerHTML = "<input type='checkbox' value='My value' data-bind='checked:myObservableArray' />"; | ||
ko.applyBindings(model, testNode); | ||
|
||
value_of(testNode.childNodes[0].checked).should_be(false); | ||
|
||
// Put the value in the array; observe the checkbox reflect this | ||
model.myObservableArray.push("My value"); | ||
value_of(testNode.childNodes[0].checked).should_be(true); | ||
|
||
// Remove the value from the array; observe the checkbox reflect this | ||
model.myObservableArray.remove("My value"); | ||
value_of(testNode.childNodes[0].checked).should_be(false); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
describe('Binding: Click', { | ||
// This is just a special case of the "event" binding, so not necessary to respecify all its behaviours | ||
before_each: JSSpec.prepareTestNode, | ||
|
||
'Should invoke the supplied function on click, using model as \'this\' param and first arg, and event as second arg': function () { | ||
var model = { | ||
wasCalled: false, | ||
doCall: function (arg1, arg2) { | ||
this.wasCalled = true; | ||
value_of(arg1).should_be(model); | ||
value_of(arg2.type).should_be("click"); | ||
} | ||
}; | ||
testNode.innerHTML = "<button data-bind='click:doCall'>hey</button>"; | ||
ko.applyBindings(model, testNode); | ||
ko.utils.triggerEvent(testNode.childNodes[0], "click"); | ||
value_of(model.wasCalled).should_be(true); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
describe('Binding: CSS class name', { | ||
before_each: JSSpec.prepareTestNode, | ||
|
||
'Should give the element the specific CSS class only when the specified value is true': function () { | ||
var observable1 = new ko.observable(); | ||
var observable2 = new ko.observable(true); | ||
testNode.innerHTML = "<div class='unrelatedClass1 unrelatedClass2' data-bind='css: { myRule: someModelProperty, anotherRule: anotherModelProperty }'>Hallo</div>"; | ||
ko.applyBindings({ someModelProperty: observable1, anotherModelProperty: observable2 }, testNode); | ||
|
||
value_of(testNode.childNodes[0].className).should_be("unrelatedClass1 unrelatedClass2 anotherRule"); | ||
observable1(true); | ||
value_of(testNode.childNodes[0].className).should_be("unrelatedClass1 unrelatedClass2 anotherRule myRule"); | ||
observable2(false); | ||
value_of(testNode.childNodes[0].className).should_be("unrelatedClass1 unrelatedClass2 myRule"); | ||
}, | ||
|
||
'Should give the element a single CSS class without a leading space when the specified value is true': function() { | ||
var observable1 = new ko.observable(); | ||
testNode.innerHTML = "<div data-bind='css: { myRule: someModelProperty }'>Hallo</div>"; | ||
ko.applyBindings({ someModelProperty: observable1 }, testNode); | ||
|
||
value_of(testNode.childNodes[0].className).should_be(""); | ||
observable1(true); | ||
value_of(testNode.childNodes[0].className).should_be("myRule"); | ||
}, | ||
|
||
'Should toggle multiple CSS classes if specified as a single string separated by spaces': function() { | ||
var observable1 = new ko.observable(); | ||
testNode.innerHTML = "<div class='unrelatedClass1' data-bind='css: { \"myRule _another-Rule123\": someModelProperty }'>Hallo</div>"; | ||
ko.applyBindings({ someModelProperty: observable1 }, testNode); | ||
|
||
value_of(testNode.childNodes[0].className).should_be("unrelatedClass1"); | ||
observable1(true); | ||
value_of(testNode.childNodes[0].className).should_be("unrelatedClass1 myRule _another-Rule123"); | ||
observable1(false); | ||
value_of(testNode.childNodes[0].className).should_be("unrelatedClass1"); | ||
}, | ||
|
||
'Should set/change dynamic CSS class(es) if string is specified': function() { | ||
var observable1 = new ko.observable(""); | ||
testNode.innerHTML = "<div class='unrelatedClass1' data-bind='css: someModelProperty'>Hallo</div>"; | ||
ko.applyBindings({ someModelProperty: observable1 }, testNode); | ||
|
||
value_of(testNode.childNodes[0].className).should_be("unrelatedClass1"); | ||
observable1("my-Rule"); | ||
value_of(testNode.childNodes[0].className).should_be("unrelatedClass1 my-Rule"); | ||
observable1("another_Rule my-Rule"); | ||
value_of(testNode.childNodes[0].className).should_be("unrelatedClass1 another_Rule my-Rule"); | ||
observable1(undefined); | ||
value_of(testNode.childNodes[0].className).should_be("unrelatedClass1"); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
describe('Binding: Enable/Disable', { | ||
before_each: JSSpec.prepareTestNode, | ||
|
||
'Enable means the node is enabled only when the value is true': function () { | ||
var observable = new ko.observable(); | ||
testNode.innerHTML = "<input data-bind='enable:myModelProperty()' />"; | ||
ko.applyBindings({ myModelProperty: observable }, testNode); | ||
|
||
value_of(testNode.childNodes[0].disabled).should_be(true); | ||
observable(1); | ||
value_of(testNode.childNodes[0].disabled).should_be(false); | ||
}, | ||
|
||
'Disable means the node is enabled only when the value is false': function () { | ||
var observable = new ko.observable(); | ||
testNode.innerHTML = "<input data-bind='disable:myModelProperty()' />"; | ||
ko.applyBindings({ myModelProperty: observable }, testNode); | ||
|
||
value_of(testNode.childNodes[0].disabled).should_be(false); | ||
observable(1); | ||
value_of(testNode.childNodes[0].disabled).should_be(true); | ||
}, | ||
|
||
'Enable should unwrap observables implicitly': function () { | ||
var observable = new ko.observable(false); | ||
testNode.innerHTML = "<input data-bind='enable:myModelProperty' />"; | ||
ko.applyBindings({ myModelProperty: observable }, testNode); | ||
value_of(testNode.childNodes[0].disabled).should_be(true); | ||
}, | ||
|
||
'Disable should unwrap observables implicitly': function () { | ||
var observable = new ko.observable(false); | ||
testNode.innerHTML = "<input data-bind='disable:myModelProperty' />"; | ||
ko.applyBindings({ myModelProperty: observable }, testNode); | ||
value_of(testNode.childNodes[0].disabled).should_be(false); | ||
} | ||
}); |
Oops, something went wrong.