Open orendin opened 7 years ago
Hi @orendin how are you importing "reflect-metadata" ? from the command line or form the app?
The problem seems to be caused because the metadata is stored in the Reflect
object which is created as a global by reflect-metadata
.
My guess is that the mocha watch mode is not cleaning the globals with each run. Can you please check if mocha has some setting force cleaning the globals?
Hey @remojansen, super quick response time, thanks!
It is imported inside the inversify.config.ts
at the top (as outlined in the code in the issue, sorry for the long post...).
Hmmm... the globals in mocha. I have already done some research into this and could not find anything useful. But your hint helps to refine the search.
Here we have a 'manual' way of trying to store and reset a global after tests are run in a global hook. https://github.com/mochajs/mocha/wiki/Mess-with-globals
This would mean trying to store a reference to the original Reflect and then resetting it back after the tests ran... I'll give this a shot, thanks!
No peoblem @orendin, I'm quite sure that that is the problem. If you manage to reset the Reflect global it should work :wink:
I can't seem to get a proper snapshot of the Reflect "Instance" to reset back to.
import "reflect-metadata";
let refl: any = Reflect;
Then in the global after hook, I'm trying to resets the global Reflect back to the original:
after(() => {
(<any>global).Reflect = refl;
});
But this doesn't do the trick. I don't have time to fiddle around with this any more at the moment and will keep the work-around for now. I'll come back to this later. Thanks!
No problem, maybe the mocha guys can help.
I have the same issue with jest
. Wondering if anyone finds a way.
I believe I have the same issue with parcel, which watches my React App and performs hot module reloading when source changes. 😞
FYI, I've created a PR to address this issue.
The PR exposes a function to disable throwing an error on duplicate injectable
decorators. This allows keeping the default functionality while letting devs suffering from this error ignore them.
That said, I don't believe there's actually any benefit from throwing the error at all. Even if the developer has mistakenly applied an injectable
decorator twice somehow, there's not really any harm in simply ignoring the "mistake". I don't see a benefit in breaking hard and fast in this particular scenario given it breaks tools which watch like mocha, jest, parcel, etc.
I have the same problem with nextJS in combination with a custom server watched bei nodemon. When i switch pages in nextJS or change anything in my sourcecode, i will receive this error.
Has anyone found a solution to this?
I had a PR which fixed the issue but I decided to close it since no one would merge it or give feedback even after I reached out to devs.
Side: I’ve given up on using IOC libraries with JavaScript. I’ve found I rarely if ever need to swap out one implementation of some abstraction with another, other than when mocking services in tests, and because Jest makes mocking anything very simple I’ve found it makes IOC libraries for JS largely redundant, for my uses at least.
Thanks for your feedback :) I am developing a large scale business application, so it is kind of a must-have :( I will check out typescript-ioc later today, maybe it will work better in combination with watch modes :)
Hi all I have a problem with my unit tests when I am trying to use Inversify with mocha on node. To be honest, I am not sure if it is an underlying mocha issue or if this could somehow be better handled by either my unit test setup or Inversify.
Expected Behavior
When I run my unit tests using mocha in watch mode
mocha --opts ./test/mocha.opts -w
, they should always result in the tests passing.Current Behavior
When I run my unit tests using mocha in watch mode
mocha --opts ./test/mocha.opts -w
, the first time they work ok, any subsequent time Inversify throws the following exception: Cannot apply @injectable decorator multiple times.Possible Solution
So I looked into the code in the annotation/injectable.js and spotted this:
Which, in turn, let me come up with this fugly work around:
This is obviously far from ideal since it's using magic strings taken out of your library.
Steps to Reproduce (for bugs)
I'll let the code speak in the context section. As described above, I am using mocha in watch mode to continuously run my tests when I change something, which I find a requirement to be productive:
mocha -w
,Context
As suggested in the documentation, I have created a inversify.config.ts file where I configure the container:
Here is a sample version of my test class:
In case it is relevant, I am creating es6 code, and using babel to execute mocha. Mocha options file:
./src/**/*.spec.js --compilers js:babel-core/register --recursive
tsconfig.json:
It makes sense to only add the decorator once for the lifetime of the process, which works fine for the actual app. But in the case of unit tests with mocha in watch mode, I have no control over this (at least not that I can see). It seems, the decorator is kept in memory between the executions of the tests. Is there a way in Inversify to officially check if the decorator has been registered before? Or do you know of a way how I can "reset" the state in mocha with watch mode (I couldn't find one)? Or is there something else I can do with my test setup to ensure that the external class is only decorated once (I mean other than my glorious work around)?
Your Environment
Versions used: "inversify": "^4.1.0", "reflect-metadata": "^0.1.10",
"babel-cli": "^6.24.1", "babel-core": "^6.24.1", "babel-loader": "^6.4.1", "babel-preset-es2015": "^6.24.1", "jasmine-core": "^2.6.2", "mocha": "^3.4.2", "mocha-junit-reporter": "^1.12.2",
Stack trace