How to reset knockout bindings in Jasmine test

2019-05-21 05:11发布

问题:

I'm trying to write test for knockout feature with jasmine as below and I'm getting following error:

Error: You cannot apply bindings multiple times to the same element.

describe("ThreeStepNavigationView", ()=> {
    var testSubject;
    var SmallNavigationStates = ['ribbon','expanded'];
    var ExtraSmallNavigationStates = ['collapsed','ribbon','expanded'];
    beforeEach(()=> {
        loadFixtures('SidebarAndSiteHeader.html');
        testSubject = new Mobile.Navigation.ThreeStepNavigation.View();
        ko.applyBindings(testSubject);
    });
    describe('When user clicks on navigation toggle button', ()=>{

    it('Should update state class name to the next state', ()=>{
        var button = $('#MobileMainNavLink');
        var currentScreenSize = Mobile.Helpers.getScreenSize();

        button.click();

        var classValue = $("#sidebar-wrapper").attr('class');
        if (currentScreenSize == 'ExtraSmall') {
            expect(classValue).toBe(ExtraSmallNavigationStates[1]);
        }
        if (currentScreenSize == 'Small') {
            expect(classValue).toBe(SmallNavigationStates[1]);
        }

    });

});

I did try resetting ko as but the result is the same.

 afterEach(()=>{
        ko.cleanNode($('#MobileMainNavLink')[0]);
        ko.cleanNode($('#sidebar-wrapper')[0]);
    });

Based on ko documentation cleanNode is an internal function and is not part of the API.

I'm using ko 3.2 and jasmine 1.5

回答1:

Your not explicitly applying your bindings to a node. I believe this will therefore apply to your document.body. Which explains your error as your not cleaning the body.

ko.applyBindings(testSubject);

Ref: http://knockoutjs.com/documentation/observables.html

In case you’re wondering what the parameters to ko.applyBindings do,

The first parameter says what view model object you want to use with the declarative bindings it activates

Optionally, you can pass a second parameter to define which part of the document you want to search for data-bind attributes. For example, ko.applyBindings(myViewModel, document.getElementById('someElementId')). This restricts the activation to the element with ID someElementId and its descendants, which is useful if you want to have multiple view models and associate each with a different region of the page.

Useful Function:

// Checks if Element has Already been Bound (Stops Errors Occuring if already bound as element can't be bound multiple times)
var isBound = function (id) {
    if (document.getElementById(id) != null)
        return !!ko.dataFor(document.getElementById(id));
    else
        return false;
};

Answer:

testSubject = new Mobile.Navigation.ThreeStepNavigation.View();
if (isBound("parent-container"))
    ko.cleanNode(document.getElementById('parent-container'));
ko.applyBindings(testSubject, document.getElementById("parent-container"));