I have the following abstract class which uses the "fs-extra" library:
import { ClassConstructor, instanceToPlain, plainToClass } from 'class-transformer';
import { validateOrReject } from 'class-validator';
import fs from 'fs-extra';
import getLog from '../../helpers/logger';
export default abstract class AppConfigService<T extends object> {
public async setConfig(config: T) {
const logger = getLog(`${AppConfigService.name}/${this.setConfig.name}`);
logger.info(`About to set app-config file with configuration:\n${JSON.stringify(config, null, 2)}`);
const currentFileObject = instanceToPlain(this.fileObject);
logger.info(`Current app-config configuration is:\n${JSON.stringify(currentFileObject, null, 2)}`);
const validatedConfig = await this.validatedConfig({ ...currentFileObject, ...config });
logger.info('Provided app-config configuration is valid');
const filePath = await this.getFilePath();
logger.info(`Got app-config file path: "${filePath}""`);
await fs.outputJson(filePath, validatedConfig);
this.fileObject = validatedConfig;
logger.info('Successfully set app-config provided configuration');
}
}
This is only snippet as I don't find the rest of the class relevant.
Then I have the following class:
import path from 'path';
import AppConfigService from '../../services/app-config';
import ConstantsModule from '../constants';
import { UserAppConfigDto } from './classes/user-app-config.dto';
import { APP_CONFIG_FILE_NAME } from './models/user-app-config';
export default class UserAppConfigService extends AppConfigService<UserAppConfigDto> {
protected classConstructorRef = UserAppConfigDto;
protected async getFilePath() {
const userConfigFolderPath = await ConstantsModule.service.getUserConfigFolder();
const appConfigFilePath = path.join(userConfigFolderPath, APP_CONFIG_FILE_NAME);
return appConfigFilePath;
}
}
And then I try to test the last class:
import { doesNotReject, rejects } from 'assert';
import sinon from 'sinon';
import { expect } from 'chai';
import fs from 'fs-extra';
import UserAppConfigModule from '../../app/modules/user-app-config';
import UserAppConfigService from '../../app/modules/user-app-config/user-app-config.service';
describe('[modules/user-app-config.module.ts]', () => {
const sandbox = sinon.createSandbox();
afterEach(sandbox.restore);
describe('setConfig()', () => {
it('should throws when "fs-extra/outputJson" rejects', async () => {
sandbox.stub(fs, 'outputJson').rejects();
await rejects(UserAppConfigModule.service.setConfig({}));
});
it('should succeed when "fs-extra/outputJson" resolves', async () => {
sandbox.stub(fs, 'outputJson').resolves();
await doesNotReject(UserAppConfigModule.service.setConfig({}));
});
});
});
But for some reason sinon does not stub fs-extra, the function outputJson. Why is that? I suspect the fs-extra/outputJson is not stubbed because of any context issues?
My first test fails because the function wasn't stubbed