Injecting lodash in Karma - karma-jasmine

I have injected lodash in ionic angular app. i have created a factory to register it as '_' and it's working fine while i run the app.
While i am writing unit test for that using Karma + jasmine and one of the service dependency injects '_' in it. It gives Uncaught Error: [$injector:unpr] Unknown provider: _Provider <- _ <- Dispatcher <- UserService. As i dig more into it, i found provider as a string has been appended to '_' when it tries to inject the dependency.
Changed the order of loading lodash factory dependency in karma.conf but no luck.
Any help is appreciated.

You need to make sure that the reference to Lodash in your node_modules directory is in the files[] property of your karma.conf.js file:
...
files: [
'node_modules/lodash/lodash.min.js',
// Other files listed here...
],
...

Try importing it as import * as _ from 'lodash' instead of import _ from 'lodash' in the file that is being tested. No changes elsewhere. I think that Karma is not happy with the default exports.
That worked for me.

Related

SyntaxError: Cannot use import statement outside a module { AXIOS }

Hello I changed my code from fetch to axios and when I run my tests I get this problem... Can anyone help me with that ?
SyntaxError: Cannot use import statement outside a module
> 1 | import axios from "axios";
Jest encountered an unexpected token
This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
This issue occurred after axios update from 0.27.2 to 1.0.0. There is an opened issue, so probably this is going to be fixed soon. Meanwhile they're working on that, you can temporary fix it by setting up transformIgnorePatterns in jest config:
transformIgnorePatterns = ["node_modules/(?!axios)/"]
For me helped the following jest.config.js setup:
transformIgnorePattern: [
'<rootDir>/node_modules/(?!axios)/'
]
alongside with
moduleNameMapper: {
'^axios$': require.resolve('axios'),
}

Liberary dotenv-webpack doesn't work with vue 3 and webpack-cli

I'm using Vue 3 and Webpack 5 and wanted to install dotenv-webpack, but I can't get it to work.
Here's full code: https://github.com/golebiewska-n/webpack5-vue3
Setup:
package.json script I'm using to launch the app
webpack-cli serve
webpack.config.js
const Dotenv = require('dotenv-webpack')
...
module.exports = (env) => {
return {
...
plugins: [
...
new Dotenv()
]
}
}
.env (added in the root folder of my app)
VUE_APP_VAR=123
main.js
console.log(process.env)
and output in console is: "MISSING_ENV_VAR"
I tried removing new webpack.DefinePlugin({...}) from plugins in webpack config, but it didn't help.
In fact you successfully loaded the .env file with dotenv-webpack and the VUE_APP_VAR is accessible. It is just you cannot use the entire process.env object as dotenv-webpack does not allow it showing you MISSING_ENV_VAR instead.
If you chnange line 12 in your src\Layout.vue as follows:
- return process.env
+ return process.env.VUE_APP_VAR
you get your 123 value of the variable in your Vue app.
The reason is at the time of building your application with webpack dotenv-webpack replaces the explicit string process.env.SOME_EXPLICIT_VARIABLE_NAME_HERE existing in your code with the actual value of SOME_EXPLICIT_VARIABLE_NAME_HERE if that exist in the Webpack JS environment's actual process.env object.
This means you never get the entire process.env object accessible in your webpack bundle, and the bundle does not comprise the variable names like VUE_APP_VAR=123. This is the goal of dotenv-webpack.
You can get some more details in my answer here.
PS: DefinePlugin, being returned in the build config, could override process.env. It does so in Vue CLI (which is hardly justifiable). So its effect there sould be neutralized manually for dotenv-webpack to work within Vue CLI (v4 and v5) applications as expected.

vitetest: Failed to resolve import "$lib/stores/store"

tried running tests with vitest and it can seem to resolve dependencies from $lib/* and $app/* this is the error, Failed to resolve import "$lib/stores/store" from "src/lib/components/Hello.svelte". Does the file exist? here is the link to the playground https://gitlab.com/paulwvnjohi/hello-vitest
It seems Vitest is NOT automatically picking up your Vite config, since it's "hidden" in svelte.config.js and I'm sure there's tons of magic stuff SvelteKit adds, such as the resolve.alias paths for things like the $lib and $app imports to work.
I don't know if Vitest core would do something automatically in the future, but now there's the vitest-svelte-kit package you can use: https://github.com/nickbreaton/vitest-svelte-kit
Install the package:
npm i -D vitest-svelte-kit
Create a file vitest.config.js and put inside the method that magically extracts the correct vite config for you, according to your settings in svelte.config.js:
// vitest.config.js
import { extractFromSvelteConfig } from "vitest-svelte-kit"
export default extractFromSvelteConfig()
Worked for me!

Npm workspaces: Different "main" property for development and publishing?

I've created an npm workspace with two packages "foo" and "bar".
Furthermore, I'm using typescript so both packages contain a src/index.ts.
During development, I want to have the "main" property of both packages to be src/index.ts.
But after building and publishing the packages the "main" entry has to point to the built dist/index.js.
How can I accomplish that or is my assumption wrong, that I can point to the typescript file during development?
But then I would have to rebuild the packages during development all the time.
I hope that's not necessary.
Thank you for your help in advance
UPDATE
To be more precise, I need to have "main" point to the Typescript file src/index.ts because otherwise, I can't reference "foo" inside of "foo" itself:
// foo/src/index.ts
import { something } from 'foo';
This error is thrown:
[vite:resolve] Failed to resolve entry for package "foo". The package may have incorrect main/module/exports specified in its package.json.
The above import only works, If "main" points to src/index.ts.
Otherwise I would have to use relative paths to the imported file of the same project, for example
// foo/src/index.ts
import { something } from './someotherfile.ts';
I found out, that vite needs the plugin vite-tsconfig-paths to find my main tsconfig.json to properly resolve the project:
// vite.config.ts
import tsconfigPaths from "vite-tsconfig-paths";
plugins: [
tsconfigPaths({
root: "../../",
}),
],

Bundling a plugin with Rollup but having duplicate Vue.js package imported in the client app's bundle (Nuxt)

Dear Stack Overflow / Vue.js / Rollup community
This could be a noob question for the master plugin developers working with Vue and Rollup. I will write the question very explicitly hoping that it could help other noobs like me in the future.
I have simple plugin that helps with form validation. One of the components in this plugin imports Vue in order to programatically create a component and append to DOM on mount like below:
import Vue from 'vue'
import Notification from './Notification.vue' /* a very simple Vue component */
...
mounted() {
const NotificationClass = Vue.extend(Notification)
const notificationInstance = new NotificationClass({ propsData: { name: 'ABC' } })
notificationInstance.$mount('#something')
}
This works as expected, and this plugin is bundled using Rollup with a config like this:
import vue from 'rollup-plugin-vue'
import babel from 'rollup-plugin-babel'
import { terser } from 'rollup-plugin-terser'
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
export default {
input: 'src/index.js',
output: {
name: 'forms',
globals: {
vue: 'Vue'
}
},
plugins: [
vue(),
babel(),
resolve(),
commonjs(),
terser()
],
external: ['vue']
}
As you can see, Vue.js is getting externalised in this bundle. The aim (and the assumption) is that the client app that imports this plugin will be running on Vue, therefore there's no need to bundle it here (assumption).
The very simple src/index.js that the bundler uses is below:
import Form from './Form.vue'
export default {
install(Vue, _) {
Vue.component('bs-form', Form)
}
}
Rollup creates 2 files (one esm and one umd) and references them in in the plugins package.json file like below:
"name": "bs-forms",
"main": "./dist/umd.js",
"module": "./dist/esm.js",
"files": [
"dist/*"
],
"scripts": {
"build": "npm run build:umd & npm run build:es",
"build:es": "rollup --config rollup.config.js --format es --file dist/esm.js",
"build:umd": "rollup --config rollup.config.js --format umd --file dist/umd.js"
}
Everything works as expected up to this point and the bundles are generated nicely.
The client app (Nuxt SSR) imports this plugin (using npm-link since it's in development) with a very simple import in a plugin file:
/* main.js*/
import Vue from 'vue'
import bsForms from 'bs-forms'
Vue.use(bsForms)
This plugin file (main.js) is added to nuxt.config.js as a plugin:
// Nuxt Plugins
...
plugins: [{src: '~/plugins/main'}]
...
Everything still works as expected but here comes the problem:
Since the clients is a Nuxt app, the Vue is imported by default of course but the externalised Vue module (by the forms plugin) is also imported in the client. Therefore there is a duplication of this package in the client bundle.
I guess the client app can configure its webpack config in order to remove this duplicated module. Perhaps by using something like a Dedupe plugin or something? Can someone suggests how to best handle situation like these?
But what I really want to learn, is the best practice of bundling the plugin at the first place, so that the client doesn't have to change anything in its config and simply imports this plugin and move on.
I know that importing the Vue.js in the plugin may not be a great thing to do at the first place. But there could be other reasons for an import like this as well, for example imagine that the plugin could be written in Typescript and Vue.js / Typescript is written by using Vue.extend statements (see below) which also imports Vue (in order to enable type interface):
import Vue from 'vue'
const Component = Vue.extend({
// type inference enabled
})
So here's the long question. Please masters of Rollup, help me and the community out by suggesting best practice approaches (or your approaches) to handle situations like these.
Thank you!!!!
I had the same problem and I found this answer of #vatson very helpful
Your problem is the combination of "npm link", the nature of nodejs module loading and the vue intolerance to multiple instances from different places.
Short introduction how import in nodejs works. If your script has some kind of library import, then nodejs initially looks in the local node_modules folder, if local node_modules doesn't contain required dependency then nodejs goes to the folder above to find node_modules and your imported dependency there.
You do not need to publish your package on NPM. It is enough if you generate your package locally using npm pack and then install it in your other project npm install /absolute_path_to_your_local_package/your_package_name.tgz. If you update something in your package, you can reinstall it in your other project and everything should work.
Here is the source about the difference between npm pack and npm link https://stackoverflow.com/a/50689049/6072503.
I have sorted this problem with an interesting caveat:
The duplicate Vue package doesn't get imported when the plugin is used via an NPM package (installed by npm install -save <plugin-name> )
However, during development, if you use the package vie npm link (like npm link <plugin-name>) then Vue gets imported twice, like shown in that image in the original question.
People who encounter similar problems in the future, please try to publish and import your package and see if it makes any difference.
Thank you!