Morgan Cheng
Morgan Cheng

Reputation: 75998

How to avoid "TypeError: Cannot set property" error with jest and babel v7?

I have a project to be upgraded from babel v6 to babel v7. To make it work is not hard, but I met some problems in unit testing code.

For working code foo.js like below.

import foo from './bar';
export {foo};

When I try to mock it in unit testing code.

import * as Foo 'path/to/foo.js';
Foo.foo = jest.fn().mockReturnValue('whatever');

It fails with error:

TypeError: Cannot set property foo of #<Object> which has only a getter

It turns out that babel v7 do transpilation different from v6. It compiles foo.js into:

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
Object.defineProperty(exports, "foo", {
  enumerable: true,
  get: function get() {
    return _bar.default;
  }
});

Since foo is defined as a getter-only property of exports, it cannot manipulate the exported foo any more.

For the time being, I just change foo.js to avoid such transpilation. I'm wondering whether this is any babel config to disable such transpilation. Any ideas?

Upvotes: 10

Views: 6773

Answers (2)

noahnu
noahnu

Reputation: 3574

In Babel 7, you can disable this behaviour by enabling "loose" mode in @babel/preset-env. If you only want this behaviour for your test environment, you can further scope the configuration in your babelrc/babel.config.js.

babel.config.js

module.exports = {
    env: {
        production: {
            presets: [
                [
                    '@babel/preset-env',
                    { loose: false },
                ],
            ],
        },
        test: {
            presets: [
                [
                    '@babel/preset-env',
                    { loose: true },
                ],
            ],
        },
    },
}

See loose transformation.

Upvotes: 3

roydukkey
roydukkey

Reputation: 3288

My suspicion that Babel use to transpile properties differently than it does now. Properties that only define a getter are expected to throw a TypeError when using "use strict", otherwise no error is given.

Example Class

class TestClass
{
  constructor ()
  {
    this._propOne = "JUMP";
  }

  get propOne ()
  {
    return this._propOne;
  }

  set propOne (value)
  {
    this._propOne = value;
  }

  get propTwo ()
  {
    return "HOW HIGH";
  }
}

const testClass = new TestClass();

console.log(customer.propOne);
customer.propOne = "10 Feet!";
console.log(customer.propOne);
customer.propTwo = "20 Feet!";

Babel 6.x Log

> JUMP
> 10 Feet!
> HOW HIGH
> HOW HIGH

Babel 7.x Log

> JUMP
> 10 Feet!
> HOW HIGH
> Uncaught TypeError: Cannot set property propTwo of #<TestCustomer> which has only a getter

Upvotes: 0

Related Questions