typescript 笑话模拟:xx.default不是构造函数:无法示例化模拟

wgx48brx  于 2023-02-10  发布在  TypeScript
关注(0)|答案(2)|浏览(113)

我在尝试模拟类和构造函数时遇到了麻烦。
我想测试一个App.ts类:

class App {
  public server: Express;

  constructor() {
    this.server = new Express();
    this.server.init();
  }
}

export default App;

对于测试场景-〉示例化App类后,它应该:- 确保创建Express类的新示例-确保调用init函数
所以我有我的App.test文件:

import App from '../App';

let mockedExp: jest.Mock;
jest.mock('../Express', () => {
  return {
    default: jest.fn().mockImplementation(() => {
      return {
        init: mockedExp,
      };
    }),
  };
});

describe('App', () => {
  beforeEach(() => {
    mockedExp = jest.fn().mockImplementation();
    mockedExp.mockClear();
  });

  it('Should call init from express with initialize', () => {
    new App();
    expect(mockedExp).toBeCalled();
  });
});

当我运行测试时,我得到了以下结果:

TypeError: Express_1.default is not a constructor

       8 | 
       9 |   constructor() {
    > 10 |     this.server = new Express();
         |                   ^
      11 |     this.server.init();
      12 |   }

特快舱位:

import express from 'express';
import Boom from 'express-boom';
import morgan from 'morgan';

import Locals from './Locals';
import Middleware from './Middleware';
import Logger from './Logger';

export default class Express {
  public app: express.Application;

  constructor() {
    this.app = express();

    // disable the x-powered-by header
    this.app.disable('x-powered-by');

    this.app.locals = Locals.getConfig();
    // add boom
    this.app.use(Boom());

    this.app.set('logger', Logger);

    // morgan logger
    /* instanbul ignore next */
    if (this.app.locals.env === 'production') this.app.use(morgan('combined'));
    else {
      this.app.use(morgan('dev'));
    }
  }

  public init(): void {
    const mid = new Middleware(this.app);
    mid.addLogRoutes();
  }

  public start(): void {
    const server = this.app.listen(this.app.locals.PORT, (error: Error) => {
      if (error) {
        throw new Error(`Unable to start server ${error}`);
      }
      /* istanbul ignore next */
      console.log(`Server starting on ${server.address().port}`);
    });
  }
}

我使用以下打字规则:

"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"noUnusedLocals": true /* Report errors on unused locals. */,
"noUnusedParameters": true /* Report errors on unused parameters. */,
"noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,
"strict": true /* Enable all strict type-checking options. */,
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
"strictNullChecks": true,
"strictFunctionTypes": true /* Enable strict checking of function types. */,
"strictBindCallApply": true /* Enable strict 'bind', 'call', and 'apply' methods on functions. */,
"noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */,
"alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */

我做错什么了?

klr1opcd

klr1opcd1#

必须在返回的对象中指定__esModule: true

jest.mock('../Express', () => {
  return {
    __esModule: true,
    default: jest.fn().mockImplementation(() => {
      return {
        init: mockedExp,
      };
    }),
  };
});

或者,如果默认导出是唯一导出,则可以直接从工厂返回:

jest.mock('../Express', () => function() { // arrow function cannot be invoked with `new`
  return { init: mockedExp };
});

// or, if you want to spy on the constructor

jest.mock('../Express', () => jest.fn().mockImplementation(() => ({
  init: mockedExp
})));
vsdwdz23

vsdwdz232#

对我来说,只要将"esModuleInterop": true添加到我的规范的ts配置中就可以解决这个问题。
但是在我的用例中,我甚至没有尝试去模仿一个外部库,我希望我的测试可以运行它。下面是我编写的代码的一个例子:

import { default as AutoNumeric } from 'autonumeric';

// was failing here
const options = (AutoNumeric as any).options;

class A {
  instance: AutoNumeric;
  defaultCurrencySymbol = options.currencySymbol.none;

  constructor() {
    // failing here as well
    this.instance = new AutoNumeric(...)
  }
}

相关问题