I'm having a hell of a time with Karma/Jasmine. I'm just trying to run the example specs from Jasmine's site.
When I run jasmine on command line, the tests run fine. However, if I try to run them using Karma test runner, I have a multitude of problems.
Here's My File Structure
Here's my karma.conf.js file:
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine', 'requirejs'],
// list of files / patterns to load in the browser
files: [
'node_modules/requirejs/require.js',
'**/test-main.js', {
pattern: 'spec/jasmine_examples/*.js',
included: false
}
],
// list of files to exclude
exclude: ['**/*conf.js'],
...port,browser etc.
Here's my test.main.js file
var allTestFiles = [];
var TEST_REGEXP = /(spec|test)\.js$/i;
var pathToModule = function(path) {
return path.replace(/^\/base\//, '').replace(/\.js$/, '');
};
Object.keys(window.__karma__.files).forEach(function(file) {
if (TEST_REGEXP.test(file)) {
// Normalize paths to RequireJS module names.
allTestFiles.push(pathToModule(file));
}
});
require.config({
// Karma serves files under /base, which is the basePath from your config file
baseUrl: '/base',
// dynamically load all test files
deps: allTestFiles,
// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
});
When I run karma start, I get a 404 that PlayerTest.js and SongTest.js are not under base/. However they are loaded and located in base/spec/jasmine_examples. In addition, PlayerTest.js throws an error "module not defined".
Honestly, what am I doing wrong?
I think you need to refer to the karma-requirejs and the karma-jasmine plugins in the karma.conf.js file -
config.set({
plugins: [
'karma-jasmine',
'karma-requirejs'
],
From karma doc, it states:
Please note just about all frameworks in Karma require an additional plugin/framework library to be installed (via NPM).
Additional information can be found in plugins.
You will not need to have require.js in the files section.
Related
I'm trying to do UI testing with jasmine-jquery. I'm using karma as my test runner and jasmine as my testing framework. I think I've loaded the fixture successfully and jasmine-jquery is listed as a testing framework inside my karma configuration.
However I'm unable to find an element in the DOM using jasmine-jquery. Why?
Directory structure
base
spec
javascripts
fixtures
myfixture.html
karma.conf.js
tests
settingUpHTMLFixtures.test.js
myfixture.html
<div id="my-fixture">foo bar</div>
settingUpHTMLFixtures.test.js
jasmine.getFixtures().fixturesPath = 'base/spec/javascripts/fixtures';
loadFixtures('myfixture.html');
describe('testing out jasmine-jquery', function(){
it('can find an element in the dom using jasmine-jquery', function(){
expect($j('#my-fixture')).toBeInDOM();
})
})
karma.conf.js
const webpackConfig = require('./webpack.config.js');
module.exports = function(config) {
config.set({
basePath: "",
files: ["tests/**/*.test.js", 'spec/javascripts/fixtures/*.html'],
frameworks: ['jasmine-jquery', 'jasmine', 'jasmine-matchers'],
preprocessors: {
"tests/**/*.test.js": ["webpack"]
},
webpack: webpackConfig,
plugins : [
'karma-chrome-launcher',
'karma-jasmine',
'karma-jasmine-jquery',
'karma-jasmine-matchers',
'karma-webpack',
'karma-jasmine-html-reporter'
],
logLevel: config.LOG_INFO,
reporters: ['kjhtml'],
port: 9876,
browsers: ["Chrome"],
//...
});
};
At the moment I'm just getting the message that the test failed, which is
testing out jasmine-jquery can find an element in the dom using jasmine-jquery FAILED
Expected jQuery({ context: HTMLNode, selector: '#my-fixture' }) to be in d o m.
at UserContext.<anonymous> (tests/settingUpHTMLFixtures.test.js:78:31)"
I had a path error. It was a mistake to create the base directory on my own. Karma simply serves everything from the base directory.
The only time I needed to use the word base was when setting the fixtures path (as shown in my settingUpHTMLFixtures.test.js code above)
TLDR: How to combine css-modules with normal sass, preferably in webpack.
The Setup:
I am working on the styling build process for an e-commerce website. The site's styles are currently done in sass along with the js through a gulp browserify build process.
I have recently added a single page app that is built using react with webpack and babel. Inside of that application I am taking advantage of css-modules provided by webpack to scope the class names to each react component.
The problem:
I would like to incorporate the styles from the webpack css-modules build in with the main styling bundle for the site. To do this, I was considering building a webpack configuration to build the styles for the whole site. The problem I have is how to get the styles which are currently built by the single page webpack configuration and inject just the style chunk into a global webpack configuration that handles styles for the whole site. I should mention that I would like to keep the two configurations as separate as possible
The Questions:
Is there a proper way of having decoupled webpack builds where one is still able to use chunks from the other?
If so, how do I do it so that the css-module setup stays in the single page configuration, and the extract-text-webpack part along with a boring sass build goes into a global configuarion?
If not, how should I go about having one section of sass go through the css-modules workflow, and still combine it with the bundle from the rest of the site.
Thanks in advance.
EDIT
based on #Alexandr Subbotin's answer, I have updated my webpack to look something like the code below. I did have to change names and paths because of the code belongs to my employer, so there may be slight errors.
var ExtractTextPlugin = require('extract-text-webpack-plugin');
const JSDIR = './build/js/';
const STYLES = './build/css/bundle.css';
module.exports = {
entry : {
'styles' : './src/styles.scss',
'app' : './src/index.js',
// a javascript file that includes the root of the single page app.
'single-page' : './src/single-page/styles-entry.js',
},
output : {
path : JSDIR,
filename : '[name].js', // normally compiles my
publicPath: 'http://localhost:8080/',
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader : 'babel-loader',
query : {
presets: [
'react','es2015','stage-0',
]
},
},
{
test : /\.scss$/,
loader: ExtractTextPlugin.extract('style?sourceMap', 'css?-url&sourceMap!sass?sourceMap'),
exclude : /\/single-page\//,
},
{
test : /\.scss$/,
loader: ExtractTextPlugin.extract(
'style?sourceMap',
'css?-url&modules&importLoaders=1&localIdentName=SinglePage__[name]__[local]!sass?sourceMap'
),
include : /\/single-page\//,
}
]
},
plugins : [
new ExtractTextPlugin(STYLES, {
allChunks : true,
}),
],
resolve : {
alias: {
"eventEmitter/EventEmitter": "wolfy87-eventemitter",
},
extensions: ['', '.js','.jsx'],
},
}
If I understood your question you want to apply css-modules only to one part of your application and leave simple sass building process in other parts.
To do this you can use exclude and include options in loaders. I.e. if you have your single page application inside single-page directory your webpack config can be:
module: {
entry: {
// it is your global sass styles
application_css: './css/application.scss',
// it is main file of your SPA bundle. Somewhere inside you will use require('./styles.scss') that should be processed by css-modules
spa_index: './single-page/index.js'
},
loaders: [
...,
{
// This loader will build all your sass that are not in `single-page` directory
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style', 'css!sass'),
exclude: /\/single-page\//
},
{
// This loader will handle all your css module in `single-page` directory
test: /\.scss$/,
loader: 'style!css?modules!sass',
include: /\/single-page\//
},
],
...
}
So, in this case all css from single-page/ will use css modules, and the rest won't.
EDIT:
If you take a look in API section of ExtractTextPlugin documentation you find
The ExtractTextPlugin generates an output file per entry, so you must use [name], [id] or [contenthash] when using multiple entries.
In your example you have have two chunks with css (styles and single-page), but only one output ./build/css/bundle.css. If you change your output to ./build/css/[name].css your will have two css files: styles.css with your global css and single-page.css with SPA styles.
I've got Babel 6 working nicely with Gulp and Webpack. I now need to polyfill it to get IE8 support.
I've installed the babel-polyfill, but can't get it working and the docs and Google haven't helped so far.
My Gulp task (inc. Webpack config):
gulp.task('webpack', function(callback) {
var webpackConfig = {
context: __dirname + '../../../js',
entry: {
homepage: [
'babel-polyfill',
'./public/homepage/homepage.js'
]
},
output: {
path: __dirname + '../../../dist/public/scripts/',
filename: '[name].bundle.js'
},
module: {
loaders: [
{
loader: 'babel-loader',
test: /\.js$/, // Only run .js files through Babel
include: /js/, // Only include the /js dir
query: {
//plugins: ['transform-runtime'], // Disabled pending fix to https://github.com/babel/babel/issues/2954
presets: ['es2015'],//, 'stage-0'
}
}
]
}
};
webpack(webpackConfig, function(err, stats) {
if (err) {
throw new gutil.PluginError('webpack', err);
}
gutil.log('[webpack]', stats.toString({
// output options
}));
callback();
});
});
From the docs (https://babeljs.io/docs/usage/polyfill/):
Usage in Node / Browserify / Webpack
To include the polyfill you need to require it at the top of the entry point to > your application.
require("babel-polyfill");
Usage in Browser
Available from the dist/polyfill.js file within a babel-polyfill npm release. This needs to be included before all your compiled Babel code. You can either prepend it to your compiled code or include it in a before it.
NOTE: Do not require this via browserify etc, use babel-polyfill.
I've tried simply adding the polyfill.js file to the top of the page, but IE8 still isn't happy with the compiled code's use of the default keyword.
I've also tried adding the polyfill to the webpack process, as per http://jamesknelson.com/using-es6-in-the-browser-with-babel-6-and-webpack/ and other suggestions from Google
What am I doing wrong?
I'm totally new to the concept of testing, and i need one solid example on how to do it in my project:
I have a gulp file goes like this (Not all of it, just the important portions)
gulp.task('bundle', function() {
gulp.src('public/angular-app/main.js')
.pipe(browserify({
debug: true
}))
.pipe(gulp.dest('public/min-js'));
});
This is a slight portion of my main.js:
'use strict';
angular.module('myApp', [
'ui.router',
'ui.bootstrap',
'ngSanitize',
'ngFx',
...
], ['$interpolateProvider',
function($interpolateProvider) {
$interpolateProvider.startSymbol('{{');
$interpolateProvider.endSymbol('}}');
}
])
.config(require('./config/routes'))
.config(require('./config/authInterceptor'))
.run(require('./config/runPhase'))
.run(require('./config/xeditable'))
.controller('homeController', require('./controllers/homeController'))
.controller('modalInstanceCtrl', require('./controllers/modalInstanceCtrl'))
.controller('modalparticipantCtrl',require('./controllers/modalParticipantCtrl'))
.controller('generatorController',require('./controllers/generatorController'))
.controller('navController', require('./controllers/navController'))
.controller('signInController', require('./controllers/signInController'))
.controller('pricingController', require('./controllers/pricingController'))
.controller('howItWorksController',require('./controllers/howItWorks'))
...
Now this is my config file for karma:
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'public/vendor/jquery/dist/jquery.js',
'public/vendor/angular/angular.js',
'public/vendor/angular-mocks/angular-mocks.js',
'public/angular-app/**/*.js',
'test/**/*Spec.js'
],
// list of files to exclude
exclude: [
],
When i run karma with karma start this is what i get:
Uncaught reference error:require is not defined
at root/public/angular-app/main.js
So my question is simple, how can i do tests, for example, on my homeController...
//update
So I updated my test file to this:
describe("An Angularjs test suite",function(){
var target, rootScope;
beforeEach(inject(function($rootScope) {
rootScope = $rootScope;
// Mock everything here
spyOn(rootScope, "$on")
}));
beforeEach(inject(function(homeController) {
target = homeController;
}));
it('should have called rootScope.$on', function(){
expect(rootScope.$on).toHaveBeenCalled();
});
});
and my config file to this:
// list of files / patterns to load in the browser
files: [
'public/vendor/jquery/dist/jquery.js',
'public/vendor/angular/angular.js',
'public/vendor/angular-mocks/angular-mocks.js',
'public/min-js/main.js',
'test/**/*Spec.js'
],
// list of files to exclude
exclude: [
],
browserify: {
watch: true,
debug: true
},
preprocessors: {
'test/*': ['browserify']
},
Still nothing works, first he says 'unknown provider homeControllerProvider',
Now if i delete them lines:
beforeEach(inject(function(homeController) {
target = homeController;
}));
it still gives me error, expected spy $on to be called, How do i fix this?
You need to inform Karma to run Browserify before running tests.
You can add this in your Karma config:
{
browserify: {
watch: true,
debug: true
},
preprocessors: {
'test/*': ['browserify']
}
}
Karma config file reference: http://karma-runner.github.io/0.12/config/configuration-file.html
Or have a look at one of of my projects that uses Karma for testing: smild.
I'm using Yeoman+Angular Generator for my application and I have been running around hard to get along with Jasmine! This is where I am stuck. I want to be able to use jQuery selectors with Jasmine tests. I have installed the karma-jasmine and karma-jasmine-jquery packages. Then I installed it for bower (I'm new and I have no idea what should be installed for what!). I have manually added the path in my karma.conf.js, but I still get the message that says this:
Running "karma:unit" (karma) task
Warning: No provider for "framework:jasmine-jquery"! (Resolving: framework:jasmine-jquery) Use --force to continue.
This is how my karma config looks like:
// Karma configuration
// http://karma-runner.github.io/0.12/config/configuration-file.html
// Generated on 2014-09-12 using
// generator-karma 0.8.3
module.exports = function(config) {
'use strict';
config.set({
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// base path, that will be used to resolve files and exclude
basePath: '../',
// testing framework to use (jasmine/mocha/qunit/...)
frameworks: ['jasmine-jquery', 'jasmine'],
// list of files / patterns to load in the browser
files: [
'bower_components/jasmine-jquery/lib/jasmine-jquery.js',
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
'bower_components/angular-animate/angular-animate.js',
'bower_components/angular-cookies/angular-cookies.js',
'bower_components/angular-resource/angular-resource.js',
'bower_components/angular-route/angular-route.js',
'bower_components/angular-sanitize/angular-sanitize.js',
'bower_components/angular-touch/angular-touch.js',
'bower_components/angular-bootstrap/ui-bootstrap.js',
'app/scripts/**/*.js',
//'test/mock/**/*.js',
'test/spec/**/*.js',
'app/views/*.html'
],
// list of files / patterns to exclude
exclude: [],
// web server port
port: 8080,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: [
'PhantomJS'
],
// Which plugins to enable
plugins: [
'karma-phantomjs-launcher',
'karma-jasmine',
'karma-ng-html2js-preprocessor'
],
preprocessors: {
'app/views/*.html': 'ng-html2js'
},
ngHtml2JsPreprocessor: {
stripPrefix: 'app/',
moduleName: 'views'
},
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false,
colors: true,
// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel: config.LOG_INFO,
// Uncomment the following lines if you are using grunt's server to run the tests
// proxies: {
// '/': 'http://localhost:9000/'
// },
// URL root prevent conflicts with the site root
// urlRoot: '_karma_'
});
};
I had the same problem as this. Fixed it by adding karma-jasmine-jquery to the plugins array in karma.conf.js. This is my karma.conf in full.
module.exports = function(config) {
'use strict';
config.set({
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// base path, that will be used to resolve files and exclude
basePath: '../',
// testing framework to use (jasmine/mocha/qunit/...)
frameworks: ['jasmine-jquery', 'jasmine'],
// list of files / patterns to load in the browser
files: [
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
'app/scripts/**/*.js',
'test/mock/**/*.js',
'test/spec/**/*.js'
],
// list of files / patterns to exclude
exclude: [],
// web server port
port: 8080,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: [
'PhantomJS'
],
// Which plugins to enable
plugins: [
'karma-phantomjs-launcher',
'karma-jasmine-jquery',
'karma-jasmine',
],
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false,
colors: true,
// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel: config.LOG_INFO,
// Uncomment the following lines if you are using grunt's server to run the tests
// proxies: {
// '/': 'http://localhost:9000/'
// },
// URL root prevent conflicts with the site root
// urlRoot: '_karma_'
});
};
The other change I made is that as per the jasmine-jquery docs it requires jasmine version of at least 0.2.0. The generator gives version of 0.1.5 (at least it did for me yesterday). So to fix this I ran 'npm install karma-jasmine#0.2.0 --save-dev'. The save dev should do this but make sure you have the correct packages listed in the devDependencies in the root package.json for me I have:
"karma-jasmine": "^0.2.0",
"karma-jasmine-jquery": "^0.1.1",
Obviously these should correspond with the actual packages in node-modules
Hope it helps
C