I'm using: NestJS and I have a class exported using namespace. Right after the export namespace I have the NestJS #Injectable decorator and I get the following error when I try to run the test: × Expected '{', got 'namespace'
Without #Injectable the test runs without problems, but I need Injectable.
Class with Injectable
export namespace SearchCase {
#Injectable()
export class SearchCase {
constructor(private casesRepository: InterfaceRepository<Case.Case>) { }
async execute(request: RequestSearchCase): Promise<ResponseSearchCase> {
const searchResult = await this.casesRepository.search(request.search);
return {
searchResult,
};
}
}
}
Test
describe('Search Case', () => {
it('should be able return a case with substring', async () => {
const casesRepository = new InMemoryCaseRepository();
const searchCase = new SearchCase.SearchCase(casesRepository);
const createCase = new Case.Case({
utente: 'utente test',
caseOrigin: 'case origin test',
reportingDate: new Date(),
reporterName: 'Emanuela Xavier',
disease: 'disease test',
})
await casesRepository.create(createCase);
const response = await searchCase.execute({
search: 'Ema'
});
expect(response.searchResult.length).toBe(1);
expect(response.searchResult[0].reporterName).toContain('Ema');
});
});
ERROR
Error shown when I run the test
Removing #Injectable the test works without problem, but I need to use it.
I was using SWC/Jest instead of ts-jest, when I switched to ts-jest in my jest.config.ts the tests came back working even though I was using #Injectable.
I still don't understand why with #swc/jest it's failing, but for now it's working, when I have time I'll research more to find out the error.
Configuration with #swc/jest not working
Archive: jest.config.ts
"transform": {
"^.+\\.(t|j)s$": ["#swc/jest"]
}
Configuration with #SW/jest that work
Archive: jest.config.ts
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
}
Related
I am trying to inject a dependency to an exception filter.
Here is my dependency:
#Injectable()
export class SmsService {
constructor() {}
async create() {
console.log('sms created');
}
}
And its module:
#Module({
providers: [SmsService],
exports: [SmsService],
})
export class SmsModule {}
And my exception filter is here:
#Catch(InternalServerErrorException)
export class InternalServerErrorFilter implements ExceptionFilter {
#Inject(SmsService)
private readonly smsService: SmsService;
async catch(exception: InternalServerErrorException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
// smsService is undefined so create property is undefined
await this.smsService.create();
response.status(exception.getStatus()).send({
message: 'Something went wrong our side.',
statusCode: exception.getStatus(),
});
}
}
My app module :
#Module({
imports: [SmsModule, MailsModule],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_FILTER,
useClass: InternalServerErrorFilter,
},
],
})
export class AppModule {}
My main.ts file :
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new InternalServerErrorFilter());
await app.listen(3000);
}
bootstrap();
Finally my app service is here.
#Injectable()
export class AppService {
getHello(): string {
throw new InternalServerErrorException();
}
}
It just throws internal server error exception for executing internal server error filter.
When I send a request to http://localhost:3000 it throws an error like below:
/* await this.smsService.create();
^
TypeError: Cannot read properties of undefined (reading 'create')
*/
My application starts successfully so it seems like no dependency error.
If I recall, enhancers bound by useGlobal*() have precedence over APP_* providers (need to double check that). By using new you are in charge of setting everything that that class instance will need, regardless if it has #Inject() decorators on properties or in the constructor or not. The #Inject() just sets metadata that Nest can read so it knows what to set during class instantiation. So, when you pass new InternalServerErrorFilter() and don't ever set smsService, you get an error at runtime because that service is never defined, only declared.
If you're going to use global enhancers, I'd highly suggest keeping just one global enhancer binding type, and would even more highly suggest just using the APP_* bindings because they're easier to keep inline with your application and your e2e tests, plus Nest can do DI on enahncers bound via APP_*
Hey I am playing around with web3 inside react as a client application (using vite react-ts) and trying to call web3.eth.net.getId() but this will throw me an error that callbackify is not a function I digged a little and found an old issue on the github which states that older versions of Nodejs.util (prior version 0.11) didn't have this function. So I checked the package.json where the error occurs (web3-core-requestmanager) it has "util":"^0.12.0", so callbackify should be available.
In fact when I am looking at their imports, they seem to be able to import it:
(following code is ./node_modules\web3-core-requestmanager\src\index.js
const { callbackify } = require('util');
but when they want to use it, callbackify is undefined
//RequestManager.prototype.send function
const callbackRequest = callbackify(this.provider.request.bind(this.provider));
I tried to play around with the dependencies and tried different versions of web3.js (1.7.3; 1.6.0; 1.5.1) all of them had the same util dependency (0.12.0).
My code in all this matter looks like this:
class Blockchain {
public blockchainBaseUrl: string;
public web3;
public provider;
public account: string = '';
public contract: any;
constructor() {
if (process.env.REACT_APP_BLOCKCHAIN_BASE_URL === undefined) {
throw new Error('REACT_APP_BLOCKCHAIN_BASE_URL is not defined');
}
this.provider = window.ethereum;
if (this.provider === undefined) {
throw new Error('MetaMask is not installed');
}
this.setUpInitialAccount();
this.addEthereumEventListener();
this.blockchainBaseUrl = process.env.REACT_APP_BLOCKCHAIN_BASE_URL;
this.web3 = new Web3(Web3.givenProvider || this.blockchainBaseUrl);
this.setContract();
}
async setContract() {
// error comes from the next line
const networkId = await this.web3.eth.net.getId();
this.contract = new this.web3.eth.Contract(
// #ts-ignore
Token.abi,
// #ts-ignore
Token.networks[networkId].address
);
}
}
I also was told that I should simply add a .catch() to web3.eth.net.getId() but this did nothing. Am I doing something wrong or is this a dependency problem? If anyone could point me in the right direction I would really appreciate it. Do I need to expose the util API to the browser somehow? To me, it seems that the API is simply not available.
This is should be the relevant part of my vite.config.ts:
import GlobalsPolyfills from '#esbuild-plugins/node-globals-polyfill';
import NodeModulesPolyfills from '#esbuild-plugins/node-modules-polyfill';
import { defineConfig } from 'vite';
import react from '#vitejs/plugin-react';
export default defineConfig({
plugins: [
react(),
],
optimizeDeps: {
esbuildOptions: {
plugins: [
NodeModulesPolyfills(),
GlobalsPolyfills({
process: true,
buffer: true,
}),
],
define: {
global: 'globalThis',
},
},
},
});
Here is my complete vite config
https://pastebin.com/zvgbNbhQ
Update
By now I think that I understand the issue - it seems that it is a VIte-specific problem and I need to polyfill the NodeJs.util API. I am already doing this (at least I thought). Perhaps someone can provide some guidance on what I am doing wrong with my config?
Update 2
I actually have now the util API inside the browser, but it is still giving me the same error. This is my new config:
https://pastebin.com/mreVbzUW I can even log it out:
Update 3
SO I am still facing this issue - I tried a different approach to polyfill I posted the update to the github issue https://github.com/ChainSafe/web3.js/issues/4992#issuecomment-1117894830
Had similar problem with vue3 + vite + we3
It's started from errors: process in not defined than Buffer is not defined and finally after I configure polyfill I came to callbackify is not defined
Did a lot of researches and finally solved this issue with next trick:
Rollback all polyfill configurations
Add to the head html file
<script>window.global = window;</script>
<script type="module">
import process from "process";
import { Buffer } from "buffer";
import EventEmitter from "events";
window.Buffer = Buffer;
window.process = process;
window.EventEmitter = EventEmitter;
</script>
vite.config.ts
import vue from '#vitejs/plugin-vue'
export default {
resolve: {
alias: {
process: "process/browser",
stream: "stream-browserify",
zlib: "browserify-zlib",
util: 'util'
}
},
plugins: [
vue(),
]
}
add these dependencies browserify-zlib, events, process, stream-browserify, util
Source https://github.com/vitejs/vite/issues/3817#issuecomment-864450199
Hope it will helps you
I'm trying to write unit tests for some private methods in my class using Typescript for my Node.js module.
I tried using rewire, but it's unable to access any methods (even public ones).
Here is my setup:
myclass.ts
class MyClass{
private somePrivateMethod() {
// do something
console.log(42);
}
public somePublicMethod() {
// do something
this.somePrivateMethod();
// do something
}
}
export default MyClass;
test.ts
import { expect } from 'chai';
import rewire from 'rewire';
describe('Test', function () {
describe('#somePrivateMethod()', function () {
const rewired = rewire('../src/myclass.ts');
//const rewired = rewire('../dist/myclass.js');
const method = rewired.__get__('somePrivateMethod');
});
});
I tried using rewire on the Typescript file and on the compiled JS file as well, but I get the same error:
ReferenceError: somePrivateMethod is not defined
I'm using Mocha with the following config:
'use strict';
module.exports = {
extension: ["ts"],
package: "./package.json",
reporter: "spec",
slow: 75,
timeout: 2000,
ui: "bdd",
"watch-files": ["test/**/*.ts"],
require: "ts-node/register",
};
Is there any solution for this problem?
I know is a pretty old question but if someone else find themself in the situation I've managed to find a solutions:
export class YourClass {
constructor( ) { }
private thisIsPrivate() {
//private stuff
}
otherPublicMethod() {
//public stuff
}
}
inside your test file you can import the class as usual to test public methods
import YourClass from '../src/classes/YourClass'
const testClass = new YourClass();
...
to test private methods import the class using rewire
import rewire from 'rewire'
const rewiredModule = rewire('../src/classes/YourClass')
const rewiredClass = rewiredModule.__get__('YourClass')
then inside your test
it('Test your private method', function () {
const myRewiredClassInstance = new rewiredClass()
myRewiredClassInstance.thisIsPrivate()
//do your expect here
}
The only downside is that the object returned is "any" and so no help from typescript.
you can even debug inside it if you have setup your debugger correctly
Enjoy everyone
I have a problem with unit tests in a javascript (react) project.
Wanted to test the ApiClient class. For this I will have to isolate settingsApi, HttpClient and resources.
I using tools: mocha, chai, sinon
I also tried using rewire and I could not. I already read that it could be because of babel.
I've tried stubs like this:
sinon.stub(ApiClient.prototype, 'constructor');
Has anyone had this problem, can you give me a hand?
Below is part of the code:
File ApiClient.js
import settingsApi from '../../settings/api.json';
import HttpClient from './HttpClient';
import resources from './resources';
class ApiClient {
constructor() {
this.httpClient = new HttpClient(settingsApi);
}
get flux() {
return new resources.resourceOne(this.httpClient);
}
}
export default ApiClient;
FileHttpClient.js
class HttpClient {
/**
*
* #param {*} config
*/
constructor(config) {
this.basePath = `${config.protocol}://${config.host}:${config.port}`;
}
post(resource, options = {}, formatResponse) {
return this.request({
method: 'POST',
resource,
options,
formatResponse
});
}
export default HttpClient;
I could already solve my problem, I used the babel-plugin-rewire (https://github.com/speedskater/babel-plugin-rewire):
Installation:
yarn add babel-core babel-plugin-rewire --dev
Add to .babelrc
"plugins": [
"rewire"
]
Mock the dependencies example:
ApiClient.__Rewire__('settingsApi', {
paramConfig: 'config',
});
ApiClient.__Rewire__('HttpClient', class HttpClient {
constructor(config) {
}
});
ApiClient.__Rewire__('resources', {
resourceOne: class {
constructor(httpClient) {
}
});
Now instead of calling the dependencies calls the above functions.
I use ts-jest and jest to write my testing files with typescript.
I am confused how to typing the mock function of a module.
Here is my code:
./module.ts:
import {IObj} from '../interfaces';
const obj: IObj = {
getMessage() {
return `Her name is ${this.genName()}, age is ${this.getAge()}`;
},
genName() {
return 'novaline';
},
getAge() {
return 26;
}
};
export default obj;
./module.test.ts:
import * as m from './module';
describe('mock function test suites', () => {
it('t-1', () => {
// I think the jest.Mock<string> type here is not correct.
m.genName: jest.Mock<string> = jest.fn(() => 'emilie');
expect(jest.isMockFunction(m.genName)).toBeTruthy();
expect(m.genName()).toBe('emilie');
expect(m.getMessage()).toEqual('Her name is emilie, age is 26');
expect(m.genName).toHaveBeenCalled();
});
});
how to type the mock function genName of module m?
typescript give me an error here:
Error:(8, 7) TS2540:Cannot assign to 'genName' because it is a constant or a read-only property.
This is how I have solved the same problem and how I do all of my mocking and spying now.
import * as m from './module';
describe('your test', () => {
let mockGenName;
beforeEach(() => {
mockGenName = jest.spyOn(m,
'genName').mockImplemetation(() => 'franc');
})
afterEach(() => {
mockGenName.mockRestore();
})
test('your test description', () => {
// do something that calls the genName function
expect(mockGenName).toHaveBeenCalledTimes(1);
})
})
With this setup, you can programmatically change the implementation of the mock for different tests, and then assert that the function was called and what it was called with, all while clearing your mock in between tests and after all tests.
Try this one - https://jestjs.io/docs/mock-function-api#typescript
In short there are only three strategies possible
Mock the entire module being imported and get handler to the mocked function to manipulate it (jest.Mock(), jest.MockedFunction)
Mock the module partially being imported and get handler to the mocked function to manipulate it (jest.Mock() with factory, jest.MockedFunction)
Import the module as is and then spy on the function which needs to be mocked (jest.spy())
You want to mock the module and then alter the exported function within it. This should replace your import statement.
jest.mock('./module', () => ({
genName: jest.fn().mockImplementation(() => 'emilie')
}))
import * as m from './module'
jest.mock('./module', () => ({
genName: jest.fn().mockImplementation(() => 'emilie')
// will return "enilie" for all tests
}))
it('returns franc', () => {
m.genName.mockImplementationOnce(() => 'franc')
// will return "franc" for this particular test
})
The reason why I got the error is:
The properties of a module object foo (import * as foo from 'foo') are like the properties of a frozen object.
For more info, see In ES6, imports are live read-only views on exported values
When I changed import * as m from './module' to import m from './module';, The error is gone.
Package versions:
"typescript": "^3.6.4"
"ts-jest": "^24.1.0"
"jest": "^24.9.0",
jest.config.js:
module.exports = {
preset: 'ts-jest/presets/js-with-ts',
//...
}
tsconfig.json:
"compilerOptions": {
"target": "es6",
"module": "commonjs",
//...
}
I'm mocking it a follow :
jest.mock('./module')
const {genName} = require('./module')
and in my test :
genName.mockImplementationOnce(() => 'franc')
works great for me and no typescript errors