How do I mock global scss variables in my jest test - vue.js

I am setting up tests for an already existent vue project. The project uses certain scss variables that are injected in the vue config via scss-loader from the env.
Excerpt of my vue config file
module.exports = {
outputDir: path.resolve(__dirname, output),
css: {
loaderOptions: {
sass: {
additionalData: `$tabletbreakpoint: ${process.env.TABLET_BREAKPOINT}; $mobilebreakpoint: ${process.env.MOBILE_BREAKPOINT}; $mobpreview: ${process.env.VUE_APP_ADMIN_PREVIEW_MOB};`
},
scss: {
additionalData: `$tabletbreakpoint: ${process.env.TABLET_BREAKPOINT}; $mobilebreakpoint: ${process.env.MOBILE_BREAKPOINT}; $mobpreview: ${process.env.VUE_APP_ADMIN_PREVIEW_MOB};`
}
}
},
...
}
However when I try to run my component tests setup using #vue/test-utils it fails with the following error
Error: Undefined variable.
╷
92 │ #if $mobpreview {
│ ^^^^^^^^^^^
╵
stdin 92:7 root stylesheet
FAIL tests/unit/Banner.spec.js
● Test suite failed to run
[vue-jest] Error: Vue template compilation failed
8 | export { default as OverflowWatcher } from "./OverflowWatcher.vue";
9 | export { default as SimpleRadioButton } from "./SimpleRadioButton.vue";
> 10 | export { default as DropdownSetup } from "./DropdownSetup.vue";
| ^
11 | export { default as FitText } from "./FitText.vue";
12 | export { default as ProgressLevel } from "./ProgressLevel.vue";
13 | export { default as Banner } from "./Banner.vue";
at error (node_modules/#vue/vue2-jest/lib/utils.js:122:9)
at logResultErrors (node_modules/#vue/vue2-jest/lib/utils.js:134:5)
at processStyle (node_modules/#vue/vue2-jest/lib/process-style.js:104:5)
at node_modules/#vue/vue2-jest/lib/process.js:87:13
at Array.map (<anonymous>)
at processStyle (node_modules/#vue/vue2-jest/lib/process.js:86:6)
at Object.module.exports [as process] (node_modules/#vue/vue2-jest/lib/process.js:103:24)
at ScriptTransformer.transformSource (node_modules/#jest/transform/build/ScriptTransformer.js:619:31)
at ScriptTransformer._transformAndBuildScript (node_modules/#jest/transform/build/ScriptTransformer.js:765:40)
at ScriptTransformer.transform (node_modules/#jest/transform/build/ScriptTransformer.js:822:19)
at Object.<anonymous> (src/atoms/index.js:10:1)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 2.435 s
I am looking for a way to make these variables available to all components I am going to be testing.

I found out the best way to get these variables is to put them into an scss file and require them globally for the tests using vue-jest's config.
My jest-config file
module.exports = {
preset: "#vue/cli-plugin-unit-jest",
globals: {
"vue-jest": {
resources: {
scss: ["./tests/css-mocks.scss"]
}
}
}
};
My mock file
$mobpreview:false
Hope this helps someone.

Related

How to enable reactivityTransform in Nuxt 3?

I want to enable Vue 3 experimental feature reactivityTransform in Nuxt 3 (3.0.0-rc.3). I've tried the solution provided here, but it did not work and I did get the following error:
Type '{ vue: { reactivityTransform: true; }; }' is not assignable to type 'UserConfig'.
Here is my nuxt.config.ts file:
import { defineNuxtConfig } from "nuxt";
export default defineNuxtConfig({
vite: {
vue: {
reactivityTransform: true
}
},
});
Any idea about what am I doing wrong? How can I enable reactivityTransform in Nuxt 3?
Apparently in the current version of Nuxt 3 (3.0.0-rc.3), instead of modifing the vite config in the nuxt.config file, we should add an experimental proprety; The following code enabled reactivityTransform in Nuxt 3:
// nuxt.config.ts
import { defineNuxtConfig } from "nuxt";
export default defineNuxtConfig({
experimental: {
reactivityTransform: true
},
});
Here is the related link.

can't import the named export 'computed' from non ecmascript module pinia and Vue 2

After installing Pinia on my Vue 2 project, and imported it in the main.js file
I got this error
Failed to compile.
./node_modules/pinia/dist/pinia.mjs 1147:44-52
Can't import the named export 'computed' from non EcmaScript module (only default export is available)
This Vue configuration should do the trick
// vue.config.js
module.exports = {
configureWebpack: {
module: {
rules: [
{
test: /\.mjs$/,
include: /node_modules/,
type: "javascript/auto"
}
]
}
}
}
As mentioned in this Github issue.

Jest with Vue 3 - ReferenceError: define is not defined

I would like to test my component with Jest and inside component, I imported #vue/apollo-composable library and when I run test I get the error:
ReferenceError: define is not defined
2 | // libraries
3 | import { defineComponent, ref, watch } from '#vue/composition-api'
> 4 | import { useLazyQuery, useResult } from '#vue/apollo-composable'
| ^
5 | import gql from 'graphql-tag'
In the jest test I don't use apollo-composable and I don't plan to. Code:
import '#/plugins/composition-api'
import App from '#/components/App.vue'
import Vue from 'vue'
import { Wrapper, createLocalVue, mount } from '#vue/test-utils'
Vue.use(Vuetify)
describe('SelectMediaProcess.vue', () => {
let wrapper: Wrapper<Vue>
const localVue = createLocalVue()
beforeEach(() => {
wrapper = mount(SelectMediaProcess, { localVue })
})
it('render', () => {
expect(wrapper.exists()).toBe(true)
})
})
I read on the internet what I can use:
jest.mock('#vue/apollo-composable', () => {
// mock implementation
})
But when I use this piece of code in my test. I get error: (useLazyQuery is a function from #vue/apollo-composable library)
TypeError: Cannot read property 'useLazyQuery' of undefined
19 |
20 | // get default media process
> 21 | const { onResult, load: loadDefaultMP } = useLazyQuery<
| ^
22 | getDefaultMediaProcess,
23 | getDefaultMediaProcessVariables
24 | >(
Does anyone know what can I do please?
EDIT
I added these lines to my jest.config.js. It helped others but not me.
transformIgnorePatterns: ['<rootDir>/node_modules/(?!#vue/apollo-composable).+\\.js$']
moduleNameMapper: { '#vue/apollo-composable': '#vue/apollo-composable/dist/index.js' }
Full jest.config.js:
module.exports = {
preset: '#vue/cli-plugin-unit-jest/presets/typescript-and-babel',
moduleFileExtensions: ['js', 'ts', 'json', 'vue'],
moduleNameMapper: {
'^#/(.*)$': '<rootDir>/src/$1',
'vuetify/lib(.*)': '<rootDir>/node_modules/vuetify/es5$1',
'#vue/apollo-composable': '#vue/apollo-composable/dist/index.js'
},
modulePaths: ['<rootDir>/src', '<rootDir>/node_modules'],
transform: {
'.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$':
'jest-transform-stub',
'^.+\\.ts?$': 'ts-jest',
'.*\\.(vue)$': 'vue-jest'
},
transformIgnorePatterns: [
'<rootDir>/node_modules/(?!(vuetify)/)',
'<rootDir>/node_modules/(?!#vue/apollo-composable).+\\.js$'
]
}
and I get these new errors:
FAIL tests/unit/selectMediaProcess.spec.ts
● Test suite failed to run
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:
• 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:
https://jestjs.io/docs/en/configuration.html
Details:
C:\Users\u112200\Documents\deposit-frontend\node_modules\#vue\apollo-composable\dist\index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){export { useQuery, } from './useQuery';
^^^^^^
SyntaxError: Unexpected token 'export'
2 | // libraries
3 | import { defineComponent, ref, watch } from '#vue/composition-api'
> 4 | import { useLazyQuery, useResult } from '#vue/apollo-composable'
| ^
5 | import gql from 'graphql-tag'
6 | // models
7 | import { allMediaProcesses } from '../models/__generated__/allMediaProcesses'
at ScriptTransformer._transformAndBuildScript (node_modules/#jest/transform/build/ScriptTransformer.js:537:17)
at ScriptTransformer.transform (node_modules/#jest/transform/build/ScriptTransformer.js:579:25)
at src/components/SelectMediaProcess.vue:4:1
at Object.<anonymous> (src/components/SelectMediaProcess.vue:89:3)
Does anyone know what can I do next please?
You'll need to define the functions inside the mock statement.
Currently, you've said that rather than using the real thing a mock should be used. The reason you're then getting undefine is because the mock is empty (you've not defined any functions in it).
So, the next thing to do is to specify how that mocked library should interact. You're importing two functions, so you'll need to define those functions inside the mock statement:
jest.mock('#vue/apollo-composable', () => {
return {
__esModule: true,
useLazyQuery: jest.fn(() => 42), // Replace 42 with whatever result you'd expect
useResult: jest.fn(() => 43), // Replace 43 with whatever result you'd expect
};
})
There's some more detail about this in the jest documentation.
Do you have a .babelrc file in your project? If so, you will need to change it to a babel.config.js (don't ask me why, only worked for me this way).
Also, you will need to add the following line to your jest.config.js
transformIgnorePatterns: ['node_modules/(?!#vue/apollo-composable)/']
In your case, you are already using a jest.config.js file, but in case you were using the package.json to define your testing config, you would need to create the jest config file.
This issue on GitHub helped me a lot on solving this issue:
https://github.com/facebook/jest/issues/9395
If you wanna mock using jest, you use the following approach
jest.mock("apollo-client", () => ({
__esModule: true,
useQuery: (query: any) => {
//other mocks if needed
},
useLazyQuery: jest.fn().mockReturnValue([
jest.fn(),
{
data: {
yourProperties: "Add Here",
},
loading: false,
},
]),
}));
As you see, this approach even returns the mock function that is called in the code to be tested.

Vue.js with mocha and styles-resources-loader can't load dependency sass

I have the problem that mochapack does not seem to work together with the style resources loader.
packages that seem to produce the problem:
"#vue/cli-plugin-unit-mocha": "~4.2.0",
"vue-cli-plugin-style-resources-loader": "~0.1.4"
My vue.config.js file:
const path = require("path");
module.exports = {
...
pluginOptions: {
"style-resources-loader": {
preProcessor: "scss",
patterns: [path.resolve(__dirname, "./src/assets/styles/*.scss")]
}
}
};
The single sass file that is included through the above config:
#import "~vue-select/src/scss/vue-select.scss";
It seems to load the vue-select.scss correctly but then when interpreting this file it seems to loose its current directory and does not find the imported style.
Error log excerpt:
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Can't find stylesheet to import.
╷
1 │ #import "global/variables";
│ ^^^^^^^^^^^^^^^^^^
╵
/node_modules/vue-select/src/scss/vue-select.scss 1:9 #import
/src/components/HelloWorld.vue 1:9
See full detail error message and code:
https://github.com/petritz/food-calculator-web/runs/560575367
I'm using Mocha for my Unit Tests. After having the same issue, I noticed that I had to change my vue.config.js from:
module.exports = {
publicPath: "/",
css: {
sourceMap: true,
loaderOptions: {
sass: {
prependData: `#import "#/scss/main.scss";`
}
}
}
};
to:
module.exports = {
publicPath: "/",
css: {
sourceMap: true,
loaderOptions: {
scss: {
additionalData: `#import "#/scss/main.scss";`
}
}
},
chainWebpack: config => {
if (
process.env.NODE_ENV === "test" ||
process.env.NODE_ENV === "production"
) {
const scssRule = config.module.rule("scss");
scssRule.uses.clear();
scssRule.use("null-loader").loader("null-loader");
}
}
};
EDIT: This might have some issues with local dev and production, so I had to change a couple of things:
I upgraded the sass-loader to at least 10.1.0
I had to install the null-loader to work around with CSS Preprocessor modules
I had to use chainWebpack in the vue.config.js to use the null-loader in my test and production environments
I found the answer in this open issue on the Vue CLI GitHub repo: https://github.com/vuejs/vue-cli/issues/4053#issuecomment-544641072

Globally load Sass/Scss into a Vue Project

So, when I was using Vue-cli 3.X I used a method similar to This Thread to load my many style files globally.
However, I have upgraded to Vue-cli 4.X and since then, have been unable to use this technique. I just get this error:
./src/App.vue?vue&type=style&index=0&lang=scss& (./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=style&index=0&lang=scss&)
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Undefined variable: "$grey-700".
on line 8 of src/styles/global.scss
from line 12 of /Users/kieranparker/Desktop/Personal/Side Projects/Dev/landingpages/src/App.vue
>> color: $grey-700;
---------------^
Essentially, anything outside of the main screens (such as components) just will not grab anything in my "_variables.scss". (Even if I import them all into one file and use that)
Any suggestions?
(Quick update)
I am using node-sass and my config looks like so;
module.exports = {
css: {
loaderOptions: {
sass: {
data: `
#import "#/scss/_variables.scss";
#import "#/scss/_mixins.scss";
`
}
}
}
};
Ok so, previously it was a case of just using "data:"
But, since Vue 4, it seems it now has to be "prependData:"
module.exports = {
css: {
loaderOptions: {
sass: {
prependData: `#import "~#/styles/_variables.scss";`
}
}
}
}
it's changed to additionalData
module.exports = {
css: {
loaderOptions: {
sass: {
additionalData: `#import "~#/styles/_variables.scss";`
}
}
}
}