konrado
konrado

Reputation: 235

Error: <spyOnProperty> : function is not declared configurable

I had working jasmine tests with webpack 3. Now I try to use it with webpack 4 but have some problem with it.

Firstly I had problem with spyOn function.

Error: : myFunction is not declared writable or has no setter

I found some articles about some workaround for this problem: spy-on-getter-and-setter

I changed spyOn to spyOnProperty but with no luck. Now I have problem with

> Error: : myFunction is not declared configurable

My code is written in js and looks like this:

import * as FocusServiceSpy from '../focus/FocusService';

describe('#onLinkClick', function() {
            it('should call myFunction', () => {
                spyOnProperty(FocusServiceSpy, 'myFunction', 'get');
                expect(FocusServiceSpy.myFunction).toHaveBeenCalled();
            });

        }

Do you know what could be a problem with this?

UPDATE 1:

I should be more descriptive. I would like to create spy on function of the FocusService. This service has only one method called myFunction. Only thing I want to achieve is to ensure that this method will be called.

Now I changed it to sth like this and have error:

>TypeError: Object is not a constructor (evaluating 'new FocusService()') (line 180)

describe('#onLinkClick', function() {
        const FocusService = require('../focus/FocusService');

        it('should call myFunction', () => {
            const service = new FocusService();
            spyOnProperty(service, 'myFunction').and.callThrough();
            ... (do some action)
            expect(service.myFunction).toHaveBeenCalled();
        });

    }

FocusService looks like this:

export function myFunction(arg) {
    ... (do some action)
}

Upvotes: 19

Views: 31172

Answers (4)

Steffen Kämmerer
Steffen Kämmerer

Reputation: 109

add configure({ safeDescriptors: false }); after the imports in Classdefinition file and it works with the properties

Upvotes: 0

uminder
uminder

Reputation: 26190

In your unit test, I can see several problems. First you need to understand that spyOnProperty installs a spy on a property onto an existing object but it does not invoke the getter itself.

  1. You don't create an object nor provide it to spyOnProperty.

  2. You invoke spyOnProperty with a function name instead of a property name.

Your test could be structured as follows:

it('should call myFunction', () => {

    // given
    const service = new FocusService(); 
    const spy = spyOnProperty(service , 'myProperty', 'get').and.callThrough();

    // when
    const myProperty = service.myProperty; 

    // then
    expect(myProperty).toBe(<expected value>);
    expect(spy).toHaveBeenCalled();
});

Upvotes: 7

Rudi Jansen van Vuuren
Rudi Jansen van Vuuren

Reputation: 455

With the newer version of Jasmine, the mutation of spies are not allowed and throws the above error for the member of the spy you are trying to modify.

Altering the definition of a spy's property isn't recommended as Jasmine explicitly disallows the members to be configurable.

Add the following code to your entry test file if you don't want this limitation to be forced upon you.

const defineProperty = Object.defineProperty;
Object.defineProperty = (o, p, c) => defineProperty(o, p, Object.assign({}, c ?? {}, { configurable: true }));

The code above forces every property, that is defined during the test run, to be marked as configurable.

Upvotes: 1

Thanh Nguyen
Thanh Nguyen

Reputation: 5352

I have experienced the same problem when I tried to upgrade project from Angular 8 to 9, there is no answer that I could find on Google, however I figured out a way how to solve it in my project.

In tsconfig.json, change target to es5.

Example:

{
  "compilerOptions": {
    ...
    "target": "es5",
    ...
  }
}

That's it! Hope this could help someone is trying to find the solution.

Upvotes: 1

Related Questions