"Maximum call stack size exceeded" when running cyclic ES6 imports in Jest - ecmascript-6

While writing some test suites for some ES6 modules, I discovered that Jest v26.6 runs into errors when trying to do some cyclic imports.
The problem can be reduced to the following:
ClassA.mjs
import {B} from './ClassB.mjs';
class A {
constructor()
{
//...
}
}
ClassB.mjs
import {A} from './ClassA.mjs';
class B extends A {
constructor()
{
super();
// ...
}
}
Cyclic.test.js
import {B} from "./ClassB.mjs";
describe('Cyclic', () => {
test('Cyclic', () => {
// ...
});
});
Jest exits with a "Maximum call stack size exceeded" error message, at different places of its source, depending on the imports of the test.
Are there any solutions to this, any known workarounds?
Thanks in advance.

I was also seeing this with Jest version 26 using NODE_OPTIONS='--experimental-vm-modules'. When I updated to Jest version 27 (27.5.1), the errors went away.
With Jest version 26, my errors looked like:
RangeError: Maximum call stack size exceeded
Exception in PromiseRejectCallback:
internal/vm/module.js:321
const module = await linker(identifier, this);

Related

Infinite retries when using RpcFilter in NestJS microservice setup with Kafka

I am new to Kafka and I am experiencing a mixed behaviour when trying to setup proper error handling on my consumer when there is an error. In few instances I am observing retry policy in action - kafka retries my message 5 times(as what I configured) then consumer crashes, then recovers and my group rebalanaces. However, in other instances that's not happens - consumer crashes, then recovers and my group rebalances and consumer attempts to consume the message again and again, inifinitely.
Let's say I have a controller method that's subscribed to a Kafka topic
#EventPattern("cat-topic")
public async createCat(
#Payload()
message: CatRequestDto,
#Ctx() context: IKafkaContext
): Promise<void> {
try {
await this.catService.createCat(message);
} catch (ex) {
this.logger.error(ex);
throw new RpcException(
`Couldn't create a cat`
);
}
}
Using RpcFilter on this method, like this one - https://docs.nestjs.com/microservices/exception-filters
:
import { Catch, RpcExceptionFilter, ArgumentsHost } from '#nestjs/common';
import { Observable, throwError } from 'rxjs';
import { RpcException } from '#nestjs/microservices';
#Catch(RpcException)
export class ExceptionFilter implements RpcExceptionFilter<RpcException> {
catch(exception: RpcException, host: ArgumentsHost): Observable<any> {
return throwError(() => exception.getError());
}
}
I feel like it might be something funky happening with properly committing offsets or something else. Can't pinpoint it.
Any comments are suggestions are greatly appreciated.

What is the correct type of Exception to throw in a Nestjs service?

So, by reading the NestJS documentation, I get the main idea behind how the filters work with exceptions.
But from all the code I have seen, it seems like all services always throw HttpExceptions.
My question is: Should the services really be throwing HttpExceptions? I mean, shouldn't they be more generic? And, if so, what kind of Error/Exception should I throw and how should I implement the filter to catch it, so I won't need to change it later when my service is not invoked by a Http controller?
Thanks :)
No they should not. An HttpException should be thrown from within a controller. So yes, your services should expose their own errors in a more generic way.
But "exposing errors" doesn't have to mean "throwing exceptions".
Let's say you have the following project structure :
📁 sample
|_ 📄 sample.controller.ts
|_ 📄 sample.service.ts
When calling one of your SampleService methods, you want your SampleController to know whether or not it should throw an HttpException.
This is where your SampleService comes into play. It is not going to throw anything but it's rather going to return a specific object that will tell your controller what to do.
Consider the two following classes :
export class Error {
constructor(
readonly code: number,
readonly message: string,
) {}
}
export class Result<T> {
constructor(readonly data: T) {}
}
Now take a look at this random SampleService class and how it makes use of them :
#Injectable()
export class SampleService {
isOddCheck(numberToCheck: number): Error | Result<boolean> {
const isOdd = numberToCheck%2 === 0;
if (isOdd) {
return new Result(isOdd);
}
return new Error(
400,
`Number ${numberToCheck} is even.`
);
}
}
Finally this is how your SampleController should look like :
#Controller()
export class SampleController {
constructor(
private readonly sampleService: SampleService
) {}
#Get()
sampleGetResponse(): boolean {
const result = this.sampleService.isOddCheck(13);
if (result instanceof Result) {
return result.data;
}
throw new HttpException(
result.message,
result.code,
);
}
}
As you can see nothing gets thrown from your service. It only exposes whether or not an error has occurred. Only your controller gets the responsibility to throw an HttpException when it needs to.
Also notice that I didn't use any exception filter. I didn't have to. But I hope this helps.

WebUSB API protected interface class error

I'm trying to use the WebUSB api with Chrome 67. The following code was working a month ago. I'm not sure if something is changed or if I missing something. The error I'm getting now is occurring when I'm trying to claim the interface.
The error messages are as follows: DOMException: The requested interface implements a protected class. and An attempt to claim a USB device interface has been blocked because it implements a protected interface class.
window.setInterval(function() {
navigator.usb.getDevices({ filters: [{ vendorId: 0x0b67 }]
}).then(function(devices) {
device = devices[0];
return device.open();
}).then(function() {
return device.selectConfiguration(1);
}).then(function() {
return device.claimInterface(0);
}).then(function() {
return device.transferIn(1, 6);
I can't find any information about the error, any information would be appreciated.
I announced this change here:
https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/LZXocaeCwDw/GLfAffGLAAAJ

Custom error classes not extending correctly [duplicate]

I'm trying to throw a custom error with my "CustomError" class name printed in the console instead of "Error", with no success:
class CustomError extends Error {
constructor(message: string) {
super(`Lorem "${message}" ipsum dolor.`);
this.name = 'CustomError';
}
}
throw new CustomError('foo');
The output is Uncaught Error: Lorem "foo" ipsum dolor.
What I expect: Uncaught CustomError: Lorem "foo" ipsum dolor.
I wonder if that can be done using TS only (without messing with JS prototypes)?
Are you using typescript version 2.1, and transpiling to ES5? Check this section of the breaking changes page for possible issues and workaround: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
The relevant bit:
As a recommendation, you can manually adjust the prototype immediately after any super(...) calls.
class FooError extends Error {
constructor(m: string) {
super(m);
// Set the prototype explicitly.
Object.setPrototypeOf(this, FooError.prototype);
}
sayHello() {
return "hello " + this.message;
}
}
However, any subclass of FooError will have to manually set the prototype as well. For runtimes that don't support Object.setPrototypeOf, you may instead be able to use __proto__.
Unfortunately, these workarounds will not work on Internet Explorer 10 and prior. One can manually copy methods from the prototype onto the instance itself (i.e. FooError.prototype onto this), but the prototype chain itself cannot be fixed.
The problem is that Javascript's built-in class Error breaks the prototype chain by switching the object to be constructed (i.e. this) to a new, different object, when you call super and that new object doesn't have the expected prototype chain, i.e. it's an instance of Error not of CustomError.
This problem can be elegantly solved using 'new.target', which is supported since Typescript 2.2, see here: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html
class CustomError extends Error {
constructor(message?: string) {
// 'Error' breaks prototype chain here
super(message);
// restore prototype chain
const actualProto = new.target.prototype;
if (Object.setPrototypeOf) { Object.setPrototypeOf(this, actualProto); }
else { this.__proto__ = actualProto; }
}
}
Using new.target has the advantage that you don't have to hardcode the prototype, like some other answers here proposed. That again has the advantage that classes inheriting from CustomError will automatically also get the correct prototype chain.
If you were to hardcode the prototype (e.g. Object.setPrototype(this, CustomError.prototype)), CustomError itself would have a working prototype chain, but any classes inheriting from CustomError would be broken, e.g. instances of a class VeryCustomError < CustomError would not be instanceof VeryCustomError as expected, but only instanceof CustomError.
See also: https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200
As of TypeScript 2.2 it can be done via new.target.prototype.
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#example
class CustomError extends Error {
constructor(message?: string) {
super(message); // 'Error' breaks prototype chain here
this.name = 'CustomError';
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
}
}
It works correctly in ES2015 (https://jsfiddle.net/x40n2gyr/). Most likely, the problem is that the TypeScript compiler is transpiling to ES5, and Error cannot be correctly subclassed using only ES5 features; it can only be correctly subclassed using ES2015 and above features (class or, more obscurely, Reflect.construct). This is because when you call Error as a function (rather than via new or, in ES2015, super or Reflect.construct), it ignores this and creates a new Error.
You'll probably have to live with the imperfect output until you can target ES2015 or higher...
I literally never post on SO, but my team is working on a TypeScript project, and we needed to create many custom error classes, while also targeting es5. It would have been incredibly tedious to do the suggested fix in every single error class. But we found that we were able to have a downstream effect on all subsequent error classes by creating a main custom error class, and having the rest of our errors extend that class. Inside of that main error class we did the following to have that downstream effect of updating the prototype:
class MainErrorClass extends Error {
constructor() {
super()
Object.setPrototypeOf(this, new.target.prototype)
}
}
class SomeNewError extends MainErrorClass {}
...
Using new.target.prototype was the key to getting all of the inheriting error classes to be updated without needing to update the constructor of each one.
Just hoping this saves someone else a headache in the future!
I ran into the same problem in my typescript project a few days ago. To make it work, I use the implementation from MDN using only vanilla js. So your error would look something like the following:
function CustomError(message) {
this.name = 'CustomError';
this.message = message || 'Default Message';
this.stack = (new Error()).stack;
}
CustomError.prototype = Object.create(Error.prototype);
CustomError.prototype.constructor = CustomError;
throw new CustomError('foo');
It doesn't seem to work in SO code snippet, but it does in the chrome console and in my typescript project:
I was having this problem in a nodejs server. what worked for me was to transpile down to es2017 in which these issues seems to be fixed.
Edit tsconfig to
"target": "es2017"
Try this...
class CustomError extends Error {
constructor(message: string) {
super(`Lorem "${message}" ipsum dolor.`)
}
get name() { return this.constructor.name }
}
throw new CustomError('foo')

ES6 Class, extending Ractive

I'm using ES6 (via Babel), and looking for the "proper" way to define a Class that extends Ractive (without calling Ractive.extend(...) if possible), since Ractive allows new (http://docs.ractivejs.org/latest/new-ractive).
Tried the following approach, which almost seems to work:
class Home extends Ractive {
constructor() {
super();
this.template = "<h1>{{message}}</h1>";
}
data() {
return {
message: 'This is sample data'
}
}
oninit() {
console.log('ok');
}
}
Ractive instance is initialized without error, and oninit is called, however the template seems undefined.
I would like to start using that syntax as well. :)
But I spent an hour a month ago trying to see if it was hackable, but concluded it's not currently possible due to how some of the component extension works. But it's on our radar and should land in a near-future version.