В настоящее время я работаю над интеграцией модульного тестирования Jest в свое приложение Node.js, написанное на TypeScript. Однако я сталкиваюсь с ошибкой при попытке имитировать определенные элементы. Вот конкретная ошибка, с которой я столкнулся:
Вот упрощенная версия моего тестового файла (appcontroller.test.ts):
import 'reflect-metadata';
import AppController from '../controllers/AppController';
import { ResponseToolkit, Request } from '@hapi/hapi';
import Config from '../config/Config';
jest.mock('../controllers/AppController');
const mockToolkit = {} as ResponseToolkit;
describe('App Routes - V api', () => {
it('should return version details', async () => {
const mockedVersion = 'microservice-template';
const mockedName = '0.0.1';
const expectedResponse = {
"data": {
"version": "microservice-template",
"name": "0.0.1"
}
};
const mockRequest = {} as Request;
(Config.get as jest.Mock).mockReturnValueOnce(mockedVersion).mockReturnValueOnce(mockedName);
const mockController = jest.fn().mockResolvedValue(expectedResponse);
const mockAppController = new AppController();
mockAppController.getAppDetailsHandler = mockController;
const handler = mockAppController.getAppDetailsHandler.bind(mockAppController);
const response = await handler(mockRequest, mockToolkit);
expect(mockController).toHaveBeenCalled();
expect(response).toEqual(expectedResponse);
});
});
А вот соответствующая часть моего кода TypeScript (appcontroller.ts):
import Hapi from '@hapi/hapi';
import { injectable } from 'inversify';
import Config from '@app/config/Config';
import BaseController from './BaseController';
@injectable()
export default class AppController extends BaseController {
public async getAppDetailsHandler(request: Hapi.Request, h: Hapi.ResponseToolkit): Promise<Hapi.ResponseObject> {
try {
return this.buildResponse(h, {
version: Config.get('serviceName'),
name: Config.get('serviceVersion'),
});
} catch (error) {
return this.handleErrors(h, error);
}
}
}
Конфиг.ц
import convict from 'convict';
import dotenv from 'dotenv';
export const LOGGER_TYPE_FILE = 'file';
export const LOGGER_TYPE_CONSOLE = 'console';
/** Configure Dotenv to loads environment */
dotenv.config();
const configurationSchema = convict({
env: {
doc: 'The application environment.',
format: ['local', 'dev'],
default: 'local',
env: 'NODE_ENV',
},
serviceName: {
doc: 'Name of the service. It needs to be set in the package.json file.',
format: String,
default: process.env.npm_package_name ?? 'service_name_not_set',
env: 'npm_package_name',
},
serviceVersion: {
doc: 'Version of the service. It needs to be set in the package.json file.',
format: String,
default: process.env.npm_package_version ?? 'service_version_not_set',
env: 'npm_package_version',
},
});
const Config = configurationSchema.validate({ allowed: 'strict' });
export default Config;
Я пробовал устранить эту неполадку с помощью разных предложений, одно из которых добавляет код ниже в jest.config.js.
moduleNameMapper: {
"^~(.*)$": "<rootDir>/src/$1"
}
но я все еще застрял. Может ли кто-нибудь дать рекомендации по устранению этой ошибки?
Заранее благодарю за любую помощь!
@Jeremy Это решает проблему с конфигурацией, когда я меняю путь во всех файлах. Но это создает другую проблему: "env: должно быть одним из возможных значений: ["local","dev","qa","stage","prod"]: значение было "test" }); const Config = ConfigurationSchema .validate({ разрешено: 'strict' }); экспортировать конфигурацию по умолчанию;"
Итак, относительный путь работает, но приложение не настроено для шутки? Звучит как проблема с конфигурацией шутки, если вы заглянули в модульNameMapper и преобразовали настройки через Babel/любой транспилятор? Нужно больше места, чтобы разместить один из них, введу ответ с каким-нибудь примером.
У Jest иногда возникают подобные проблемы с импортом машинописных текстов. Однако в вашей конфигурации Jest json вы можете указать moduleNameMapper
, который может заменять части ваших путей.
{
"moduleFileExtensions": ["js", "json", "ts"],
"moduleNameMapper": {
"@app": "hello"
}
}
См. официальную документацию шутки.
Предполагая, что вы попробовали модульNameMapper согласно предложению Дэвида:
// jest.config.js
module.exports = {
// other Jest configuration options...
moduleNameMapper: {
// Regular expression mapping module names to paths
'^@/(.*)$': '<rootDir>/src/$1', // Example: Maps "@/components" to "<rootDir>/src/components"
// Specific mappings for individual modules
'^utils/(.*)$': '<rootDir>/src/utils/$1', // Example: Maps "utils/foo" to "<rootDir>/src/utils/foo"
// Mocking CSS files
'\\.(css|less|scss)$': 'identity-obj-proxy', // Example: Mock CSS imports using "identity-obj-proxy"
},
}; }
}
А как насчет трансформации, правильно ли вы транспилируете?
transform: {
'^.+\\.tsx?$': 'ts-jest', // Transform TypeScript files using ts-jest
},
transform: {
// Use babel-jest to transpile tests with the next/babel preset
// https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
'^.+\\.(js|jsx|ts|tsx)$': [
'babel-jest',
{
presets: [
[
'next/babel',
{
'preset-react': {
runtime: 'automatic',
importSource: '@emotion/react',
},
},
],
],
},
],
},
AppController.ts не может
import Config from '@app/config/Config';
, поэтому ваше @app, похоже, настроено неправильно - можете ли вы вместо этого использовать относительный путь?