Running Karma tests with VueJS single file component using Vueify - browserify

I am trying to run my unit tests with Karma. I have calendar.tests.js file that looks a lot like this:
import { handleSelectDay } from '../components/Calendar/index.vue'
describe('Calendar', () => {
describe('handleSelectDay', () => {
const data = {};
describe('updates data', () => {
it('should set the selectedDay to a new id', () => {
handleSelectDay('id');
expect(data.daySelected).to.equal('id');
});
});
});
});
When I run this test with Karma I get the following: TypeError: (0 , _index.handleSelectDay) is not a function is not a function
My karma.conf.js looks like:
module.exports = function (config) {
config.set({
frameworks: ['browserify', 'mocha'],
files: ['static/js/apps/FutureHours/test/calender.tests.js'],
preprocessors: {
'static/js/apps/**/test/*.js': ['browserify']
},
browsers: ['Chrome'],
logLevel: 'LOG_DEBUG',
plugins: [
'karma-mocha',
'karma-browserify',
'karma-chrome-launcher',
'karma-spec-reporter'
],
browserify: {
debug: true,
transform: [['babelify', { presets: ['env'] }], 'vueify']
}
})
}
How can I get Karma to play nice with VueJS single file components?

The problem with this is you can't have a named export from a .vue component. Instead, any methods used in the component will have to accessed via the component object in a unit test. Any functions used outside the component's methods, should probably live in their own ES module to make unit testing them much easier.

Related

Testing Angular 14 Standalone Components with Spectator

Our test runner is Jest.
Our component is marked as standalone: true,
If try to set up spectator like this:
describe('OurComponent', () => {
let spectator: Spectator<OurComponent>;
const fakeActivatedRoute: ActivatedRoute = {
snapshot: {data: {}},
} as ActivatedRoute;
const componentFactory: SpectatorFactory<OurComponent> = createComponentFactory({
component: OurComponent,
imports: [
// some imports
],
providers: [
// some providers
],
detectChanges: false,
shallow: true,
});
beforeEach(async () => {
spectator = componentFactory();
});
it('should be created', () => {
expect(spectator).toBeDefined();
});
});
Then we run into the following error:
"Error: Unexpected "OurComponent" found in the "declarations" array of the "TestBed.configureTestingModule" call, "OurComponent" is marked as standalone and can't be declared in any NgModule - did you intend to import it instead (by adding it to the "imports" array)?"
Using the Angular-CLI in order to generate resulted in a component with a test file which is built upon ComponentFixture.
How can we make it possible to test a standalone component using Spectator?
Depends on your spectator version (mine is 10.0.0) but you can use the declareComponent property :
const componentFactory: SpectatorFactory<OurComponent> = createComponentFactory({
component: OurComponent,
declareComponent: false,
});

How to I access my .env variables from a vitest test?

I am trying to migrate my tests from jest to vitest. I have a test suite that uses the dotenv package to pull in my .env variables.
I have this in my test suite
beforeAll(async () => {
vi.clearAllMocks();
cleanUpMetadata();
dotenv.config();
controller = new UserController(container.get<UserServiceLocator>(Symbol.for("UserServiceLocator")),
container.get<EmailServiceLocator>(Symbol.for("EmailServiceLocator")));
});
and this is the code in the test that has the undefined variable
let requestObj = httpMocks.createRequest({
cookies: {
token: jwt.sign({ username: "testusername" }, process.env.JWT_SECRET_KEY!)
}
});
Is there something special to vitest that i have to do in order to get my .env variables to be accessible?
You can include the dotenv package(if thats what you are using) into the vitest.config.ts file, it will look something like this below:
import { defineConfig } from 'vitest/config';
import { resolve } from 'path';
export default defineConfig({
root: '.',
esbuild: {
tsconfigRaw: '{}',
},
test: {
clearMocks: true,
globals: true,
setupFiles: ['dotenv/config'] //this line,
},
resolve: {
alias: [{ find: '~', replacement: resolve(__dirname, 'src') }],
},
});
import.meta.env.%VARIABLE_NAME%
Got it from here: https://stackoverflow.com/a/70711231

Module parse failed: Unexpected token in Storybook when working with pdfjs-dist

I am working with a package that uses the pdfjs-dist package, and when trying to load the component that uses it in my Storybook, I get the following error
ERROR in ./node_modules/pdfjs-dist/build/pdf.js 2267:39
Module parse failed: Unexpected token (2267:39)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|
| async getXfa() {
> return this._transport._htmlForXfa?.children[this._pageIndex] || null;
| }
|
My guess, it is about handling XFA files, which are PDF files.
This is my main.js file in .storybook
const path = require('path');
module.exports = {
stories: ['../components/**/*.stories.js', '../components/**/*.stories.mdx'],
addons: [
'#storybook/addon-links',
'#storybook/addon-essentials',
'storybook-dark-mode',
'storybook-addon-next-router',
],
webpackFinal: async (config, { isServer }) => {
config.resolve.modules = [path.resolve(__dirname, '..'), 'node_modules'];
config.resolve.alias = {
...config.resolve.alias,
'#': path.resolve(__dirname, '../components'),
store: path.resolve(__dirname, '../utils/stores'),
dummy: path.resolve(__dirname, '../utils/dummy'),
};
if (!isServer) {
config.node = {
fs: 'empty',
};
}
return config;
},
};
pdfjs-dist: https://github.com/mozilla/pdf.js
react-pdf-viewer: https://github.com/react-pdf-viewer/react-pdf-viewer
The component works swimmingly in my development server, the issue is only in Storybook. Because of that issue, it is unable to even start the storybook server. If I remove the component that uses the package, storybook loads.
The error tells me to use proper webpack configs, but I just cannot figure that one out. This is what I tried, and it didn't work. (in webpackFInal: async () => { ... )
config.module.entry['pdf.worker'] = 'pdfjs-dist/build/pdf.worker.entry';
and
config.module.rules.push({
test: /pdf\.worker\.js$/,
type: 'asset/inline',
generator: {
dataUrl: (content) => content.toString(),
},
});
Found them here: https://github.com/mozilla/pdf.js/issues/14172

How to enable dotenv variables for a file inside the /public folder in a Vue project?

I have very little experience with configuring Webpack, and I'am a bit overwhelmed by this issue.
I've been working on a Vue2 project built on top of this boilerplate. The project has a folder called public which contains the entry point file index.html. Inside that index.html file I can normally access .env environment variables (e.g. process.env.VUE_APP_PAGE_TITLE).
I've included an HTML fragment inside the public folder, navbar.html, because I want it to be available for other applications via https://example.com/public/navbar.html. However, I cannot seem to get my environment variables working inside ./public/navbar.html even though they work just fine in ./public/index.html. I assume this is a problem with my webpack config.
I know I can edit my Webpack config by editing a file in my project root called vue.config.js. This file contains a configureWebpack object, but I have no idea how to make it enable environment variables inside ./public/navbar.html. Any help would be appreciated.
EDIT:
Here's my vue.config.js:
const HtmlWebpackPlugin = require('html-webpack-plugin');
function resolveClientEnv() {
const env = {};
Object.keys(process.env).forEach((key) => {
env[key] = process.env[key];
});
env.BASE_URL = '/';
return env;
}
module.exports = {
configureWebpack: {
plugins: [
new HtmlWebpackPlugin({
// This is the generated file from the build, which ends up in public/navbar.html
filename: 'navbar.html',
// This is the source file you edit.
template: 'public/navbar.html',
templateParameters: (compilation, assets, pluginOptions) => {
let stats;
return Object.assign({
// make stats lazy as it is expensive
get webpack() {
return stats || (stats = compilation.getStats().toJson());
},
compilation,
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options: pluginOptions,
},
}, resolveClientEnv());
},
}),
],
},
};
This is what my custom HTMLWebpackPlugin adds to the configuration according to vue inspect:
{
options: {
template: 'public/navbar.html',
templateContent: false,
templateParameters: function () { /* omitted long function */ },
filename: 'navbar.html',
hash: false,
inject: true,
compile: true,
favicon: false,
minify: 'auto',
cache: true,
showErrors: true,
chunks: 'all',
excludeChunks: [],
chunksSortMode: 'auto',
meta: {},
base: false,
title: 'Webpack App',
xhtml: false
},
childCompilerHash: undefined,
childCompilationOutputName: undefined,
assetJson: undefined,
hash: undefined,
version: 4
}
Use this standard plugin to generate navbar.html. https://github.com/jantimon/html-webpack-plugin.
If you read the docs, the templateParameters option is what you pass env variables to. Those variables will be available in navbar.html.
This is the same plugin that vue-cli uses for index.html. If you run the vue inspect command, you can see what options they provide to the plugin. You'll need to read the source code for resolveClientEnv() to see how it works.
Example:
/* config.plugin('html-portal') */
new HtmlWebpackPlugin(
{
templateParameters: (compilation, assets, pluginOptions) => {
// enhance html-webpack-plugin's built in template params
let stats
return Object.assign({
// make stats lazy as it is expensive
get webpack () {
return stats || (stats = compilation.getStats().toJson())
},
compilation: compilation,
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options: pluginOptions
}
}, resolveClientEnv(options, true /* raw */))
},
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true,
collapseBooleanAttributes: true,
removeScriptTypeAttributes: true
},
chunks: [
'chunk-vendors',
'chunk-common',
'portal'
],
template: 'C:\\Users\\Eric\\workspace\\arc-core\\portal\\client\\templates\\portal.html',
filename: 'portal.html',
title: 'Arc Portal'
}
),
That's a bit much, a minimal example would be:
new HtmlWebpackPlugin({
// This is the generated file from the build, which ends up in public/navbar.html
filename: 'navbar.html',
// This is the source file you edit.
template: 'templates/navbar.html',
templateParameters: {
MY_VAR: 'myVar'
}
}),

karma/jasmine to test an angular app, can't inject

I spent few hours on this issue and can't find what's wrong, I'm using karma/jasmine to create test in my angular app. I use, or at least try to use angular-mock to inject and test my controllers but I get this error :
Error: [$injector:unpr] Unknown provider: ENVProvider <- ENV
http://errors.angularjs.org/1.3.17/$injector/unpr?p0=ENVProvider%20%3C-%20ENV
in my test
describe('controllers', function(){
beforeEach(module('myModule'));
var $controller;
beforeEach(inject(function(_$controller_){
$controller = _$controller_;
}));
describe('$scope.testMessage', function() {
it('check the test message is ok', function() {
//TODO
});
});
});
So I suppose it's the inject call which cause the issue
here is my karma.conf.js
'use strict';
module.exports = function(config) {
var configuration = {
autoWatch : true,
frameworks: ['jasmine'],
ngHtml2JsPreprocessor: {
stripPrefix: 'src/',
moduleName: 'hematiteFront'
},
browsers : ['PhantomJS'],
plugins : [
'karma-phantomjs-launcher',
'karma-chrome-launcher',
'karma-jasmine',
'karma-ng-html2js-preprocessor'
],
files: [
'bower_components/jquery/dist/jquery.js',
'bower_components/angular/*.js',
'bower_components/angular-cookies/angular-cookies.js',
'bower_components/angular-touch/angular-touch.js',
'bower_components/angular-sanitize/angular-sanitize.js',
'bower_components/angular-resource/angular-resource.js',
'bower_components/angular-ui-router/release/angular-ui-router.js',
'bower_components/angular-materialize/js/*.js',
'bower_components/angular-materialize/src/*.js',
'bower_components/angular-translate/angular-translate.js',
'bower_components/angular-translate-loader-partial/angular-translate-loader-partial.js',
'bower_components/angular-translate-storage-cookie/angular-translate-storage-cookie.js',
'bower_components/angular-mocks/angular-mocks.js',
'src/**/*.js'
],
logLevel: 'LOG_ERROR',
exclude: [
'src/app/app.constants.js',
'bower_components/**/index.js',
'bower_components/**/*.min.js'
],
preprocessors: {
'src/**/*.html': ['ng-html2js']
}
};
config.set(configuration);
};
Any idea or piece of advice would be more than wellcome
thanks