Global node-config variable undefined when testing with Jest - vue.js

I am implementing Option 2 from the node-config docs.
This runs fine, and my global config variable is defined when running outside of a test environment.
However, when I run this with vue-cli and Jest unit testing (e.g. vue-cli-service test:unit), I get this error:
● Test suite failed to run
ReferenceError: APP_CONFIG is not defined
// vue.config.js
...
configureWebpack: {
plugins: [
new ConfigWebpackPlugin('APP_CONFIG')
]
},
...
What is a good way around this? Is it because Jest starts executing the JS files before the node-config can finish switching out all global variables with their values?

Jest does not run Webpack, so you would have to manually setup the config for your tests. As a workaround, you could declare the config as a Jest global.
To declare the global, add the globals property to the exported object in jest.config.js. The sub-property key would be the config-webpack's namespace (APP_CONFIG in your case), and the value would be the required config JSON files from config/:
// jest.config.js
module.exports = {
globals: {
APP_CONFIG: require('./config/default.json')
}
}

Related

How to compile Cypress e2e tests/files using Vite?

By default, Cypress compiles e2e tests with a built-in webpack config, which used to be fine because Vue-CLI also used Webpack; however, now that I've upgraded to Vue 3 and Vite, no webpack.
I have two options:
Revive the old webpack config for my Vue 2 project and update it for Vue 3 just to run Cypress' e2e tests.
Figure out how to tell Cypress to compile the app with Vite and not Webpack
I can't figure out #2, and I don't want to do #1 because having two different compilation methods sounds like a really bad future headache.
So far, I have this for my Cypress config:
import { devServer } from '#cypress/vite-dev-server'
import { defineConfig } from 'cypress'
import * as path from 'path'
export default defineConfig({
chromeWebSecurity: false,
projectId: '5kusbh',
requestTimeout: 10000,
responseTimeout: 60000,
viewportHeight: 1080,
viewportWidth: 1920,
e2e: {
baseUrl: 'http://localhost:8080',
setupNodeEvents (on, config) {
on('dev-server:start', (options) => {
return devServer({
...options,
viteConfig: {
configFile: path.resolve(__dirname, 'vite.config.ts'),
},
})
})
return config
},
specPattern: 'cypress/e2e/**/**.spec.js',
},
})
However, when I run Cypress, I get a webpack compilation error, which is telling me Vite is not compiling the application for Cypress.
Note Otherwise, my application is working great - I just can't run Cypress, and we have hundreds of unit, integration, and e2e tests written in Cypress.
TL;DR; I need help configuring Cypress to use my app's Vite config to compile its e2e tests and run it's dev server.
EDIT:
I removed my config to see how it'd run just hitting localhost, but Cypress must be trying to compile my code, because it's struggling with the Vite env variable syntax, import.meta.env.[insert key name here] in non-Cypress JavaScript files because it's not process.env...
For e2e tests, the execution of tests is separate from running the app and you access the app using cy.visit(). #cypress/vite-dev-server was for running component tests prior to cypress 10. But with cypress-vite you can also compile e2e tests using vite and use the same configuration as your app, so you don't need to config the webpack anymore.

Vue.js 3 extension breaks while using "vue-cli-service build" due to unsafe-eval

I am developing a chrome extension using vue 3, vue-router and vuex based on Kocal's project which uses vue-cli under the hood. I used whenever possible Single File Components with extensive use of vue bindings.
Everything works perfect on development mode but I recently tried to build the application for production and I encountered this error with partial rendering:
chunk-vendors.f6de00a6.js:11 EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".
After a few days of digging, my understanding is that either webpack or vue compiling system is messing with CSP by referring/injecting code through eval scripts. As I am fairly new to this, it's hard for me to read to distinguish what I can do.
I tried different approaches:
defining $vue alias to a runtime only build in vue.config.js (supposedly removing unsafe eval by having code compiled before runtime but ending with a new error: Uncaught TypeError: Object(...) is not a function for o=Object(n["withScopeId"])("data-v-21ae70c6");)
using render() function at root
adding "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'", to manifest.json
switching a component to render() to see if I have better chance with the partial rendering, but ending up with nothing being displayed although having console.log from render being executed.
Adding a config to chainWebpack splitting manifest and inline manifest on vue.config
What puzzles me is that I can't shake off the unsafe-eval, with at best a partial display, at worst a blank page. Bindings seem to be shaken off regardless and using a router-link to change page will give a blank page.
Edit: After digging through compiled code from webpack and setting minimize opt to false, it seems the error comes from a vendor: vue-i18n
The eval is likely coming from Webpack, due to an issue with global scoping.
see link for more detail https://mathiasbynens.be/notes/globalthis
Could you try adding this configuration to vue.config.js
module.exports = {
configureWebpack: {
node: {
global: false
},
plugins: [
new webpack.DefinePlugin({
global: "window"
})
]
}
};
tl;dr: Check your dependencies/packages, including those you wouldn't think they use unsafe-eval.
After digging into webpack internals and components building for vue3, here are the takeaways:
using Single File Components and default vue-cli config is ok as it will indeed just need vue runtime, so no unsolicited unsafe-eval
webpack config as below works:
module.exports = {
configureWebpack: {
plugins: [
new webpack.DefinePlugin({
global: "window" // Placeholder for global used in any node_modules
})
]
},
...
};
// Note that this plugin definition would break if you are using "unit-mocha" module for vue-cli
In the end, the issue was a dependency I was using for i18n vue-i18n#next, after removing it and switching to chrome's i18n way, it's now working.

How to setup environment files for dev, local and prod api urls, flag in NativeScript Vue?

The agenda is to use certain flags and a specific api base url for different modes say dev, local and prod in my NativeScript Vue app.
Just like NativeScript angular has environment.[mode].ts files?
I've tried using .env.[mode] files, by referring to VueJs docs
// https://cli.vuejs.org/guide/mode-and-env.html#environment-variables.com
But this did not favour the scenario.
// Something like this of a config,
module.exports = {
NODE_ENV: "production",
ROOT_API: "some api url"
}
The config should be accessible like this
process.env.ROOT_API throughout the app.
Refer the Pass Environment Variables section in the docs.
You can also provide environmental variables to the Webpack build:
$ tns build android --bundle --env.development --env.property=value
They can be accessed through the env object in the Webpack
configuration:
// webpack.config.js
module.exports = env => {
console.dir(env); // { development: true, property: 'value' }
}
You may update your DefinePlugin something like below,
new webpack.DefinePlugin({
"global.TNS_WEBPACK": "true",
"global.ENV_NAME": JSON.stringify(name),
"global.ENV_PROPERTY": JSON.stringify(env.property),
process: undefined,
}),
Now using global.ENV_PROPERTY anywhere in your project should be replaced by actual value you pass in command line at compile time.
If you are familar with webpack, you may also configure the CopyWebpackPlugin to copy right environment file to your app instead of having variable for each configuration.

vue-cli-service build: validationError for new workbox-webpack-plugin options

With the following vue.config.js:
module.exports = {
pwa: {
name: 'My App',
...
workboxPluginMode: 'InjectManifest',
workboxOptions: {
swSrc: 'src/sw.js', //and I use "sw.js" in my registerServiceWorker.js file
skipWaiting: true,
clientsClaim: true,
}
}
}
The validation errors during build are that 'skipWaiting' and 'clientsClaim' are not supported parameters. Why? swSrc is from the same list of options listed here and the build doesn't complain about that option. When I remove these two options, the build works.
So I guess my question is:
skipWaiting, clientsClaim are "not a supported parameter" of what? Of webpack? of the PWA plugin? Of the workbox-webpack plugin? Where can I find the correct set of options? Thanks.
UPDATE: I do not have a .env file setting the NODE-ENV. However npm run build which I guess builds production assets works only if I remove the 2 options. The removed options in dev (npm run serve) yields NO service worker file.
You are using workbox plugin in InjectManifest mode, but pass parameters for GenerateSW.
InjectManifest mode expects an existing service-worker file to be injected and it's path defined in swSrc, while GenerateSW will create service-worker file, thus accepts different set of options (e.g. swDest, etc)
All options for each of modes can be found on the same documentation page of workbox-webpack-plugin you've posted in corresponding sections.

How to disable webpack minification for classes names

I use jasmine, karma and webpack to test my module. The webpack preprocesses my tests files before initiating tests.
In my tests I have the class Name{...} to be tested. I create new Name instance and then, in my tests I expect(myInstance.constructor.name).toBe("Name")
class Name{}
const myInstance = new Name();
describe("The object",function(){
it("should be the instance of Name class",function(){
expect(myInstance.constructor.name).toBe("Name"); // Expected 't' to be 'Name'.
})
});
But it returns failed tests. I figured out that my Name class is parsed by webpack to the t class in the bundled file and myInstance.constructor.name equals "t".
Can I prevent webpack to change the names of classes/constructors?
Have a build setup for development and production separately, whenever in development mode(which you can mention in the webpack config object), don't apply minification plugin(might be there in your webpack config).
Help links:
Bundling Modes
Minification pluin
You can use 'keep_classnames' option provided by the minification plugin to keep the class names intact.
Install Terser Plugin to customize Webpack optimization > minimizer options running:
npm i -D terser-webpack-plugin
...or in the case you use yarn:
yarn add -D terser-webpack-plugin
Then add this optimization option inside webpack.config.js:
module.exports = {
mode: ...,
resolve: ...,
target: ...,
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
keep_classnames: true,
},
}),
],
},
};