Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override read only object within a jasmine unit test

Anyone know how to override properties and functions in a read only objects like window or [htmlelement].style?

Example function to need to test:

public static getCSSTransitionEvent(element: HTMLElement): string {
    let transitions = {
        'transition': 'transitionend',
        'OTransition': 'oTransitionEnd',
        'MozTransition': 'transitionend',
        'WebkitTransition': 'webkitTransitionEnd'
    };

    for (let transition in transitions) {
        if (element.style[transition] !== undefined ) {
            return transitions[transition];
        }
    }
    return;
}

How can I override the transition property in element.style to tests that the function returns undefined at the bottom?

Another example, how do I test this if statement

function isCryptoAvailable() {
    if (typeof (window.crypto) !== 'undefined' && typeof (window.crypto.getRandomValues) !== 'undefined') {
        return true
    }
    else {
        return false
    }
}
like image 841
bjorkblom Avatar asked Oct 25 '25 05:10

bjorkblom


1 Answers

This is done with property descriptors. Read-only properties have writable descriptor property set to false. As long as they are configurable, they can be redefined with Object.defineProperty like:

 const cryptoDescriptor = Object.getOwnPropertyDescriptor(window, 'crypto');

 afterEach(() => {
   if (origCryptoDescriptor) {
     delete window.crypto;
     Object.defineProperty(window, 'crypto', cryptoDescriptor);
   }
 });

 it('...', () => {
   expect(origCryptoDescriptor).toBeTruthy();
   expect(origCryptoDescriptor.configurable).toBeTruthy();

   const cryptoMock = ...;
   delete window.crypto;
   window.crypto = cryptoMock;
   ...
 });

The descriptor should be restored in afterEach because it will be executed even if test fails. And test will fail if a property is non-configurable. This is possible in some browsers, so a test should be excluded from suite in browsers that are known to fail it.

The same concerns a function that involves non-globals like HTMLElement object, but if it is possible to mock this object entirely instead of mocking its properties, this is the preferable strategy.

like image 112
Estus Flask Avatar answered Oct 26 '25 19:10

Estus Flask