KarmaJS, Jasmine, RequireJS, etc: Como usar o Require para testar módulos
Atualmente, tenho um projeto de exercícios para me sentir confortável com o KarmaJS - e o Unit Testing, em geral. A questão geral é que realmente não tenho uma visão transparente do que o Karma está fazendo nos bastidores e não consigo encontrar documentação adequada em áreas relevantes. Sem mais delongas...
Aqui está o meuestrutura de pastas:
root
|-/lib
|-/[dependencies] (/angular, /angular-mocks, /bootstrap, /etc) # from bower
|-/src
|-/[unreferenced directories] (/js, /css, /views) # not referenced anywhere
|-app.js # sets up angular.module('app', ...)
|-globals.js # may be referenced in RequireJS main file; not used.
|-index.html # loads bootstrap.css and RequireJS main file
|-main.js # .config + require(['app', 'etc'])
|-routeMap.js # sets up a single route
|-test-file.js # *** simple define(function(){ return {...}; })
|-/test
|-/spec
|-test-test-file.js # *** require || define(['test-file'])
|-.bowerrc # { "directory": "lib" }
|-bower.json # standard format
|-karma.conf.js # *** HELP!
|-test-main.js # *** Save Our Souls!!!
karma.conf.js
// Karma configuration
// Generated on Wed Nov 19 2014 15:16:56 GMT-0700 (Mountain Standard Time)
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: [
//'test/spec/test-test-file.js',
//'lib/**/*.js',
//'src/**/*.js',
//'test/spec/**/*.js',
'test-main.js',
{pattern: 'lib/**/*.js', included: false},
{pattern: 'src/**/*.js', included: false},
{pattern: 'test/spec/*.js', included: true}
],
// list of files to exclude
exclude: [
'lib/**/!(angular|angular-mocks|angular-resource|angular-route|require|text).js',
'lib/**/**/!(jquery|bootstrap).js',
'src/app.js'
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false
});
};
test-main.js
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/src',
paths: {
angular: '../lib/angular/angular',
ngRoute: '../lib/angular-route/angular-route',
jquery: '../lib/jQuery/dist/jquery',
bootstrap: '../lib/bootstrap/dist/js/bootstrap',
models: 'models',
controllers: 'controllers',
globals: 'globals',
routeMap: 'routeMap'
},
shim: {
angular: {
exports: 'angular'
},
ngRoute: {
deps: ['angular']
},
jquery: {
exports: 'test-test-file.js
console.log('....................');
define(function(){
//console.log('testing test-file', testFile);
describe('Testing testing', function(){
it('should work', function(){
expect(true).toEqual(true);
});
});
});
test-file.js
define('testFile', [], function(){
return function init(sandbox){
var app, application = app = sandbox.app
, globals = sandbox.globals;
return {
some: 'module'
};
};
});
Perguntas e descrições
Os pontos-chave para os quais gostaria de ouvir respostas são:
o que {pattern: '...',incluem: verdadeiro | falso } Faz?melhor maneira de excluir todo o material extra dentro dos diretórios da bower.quais arquivos eu preciso incluir no arquivo test-main.js?quais arquivos eu preciso incluir no arquivo karma.conf.js?o que o test-main.js realmente faz; para que serve isto?Os horários em que recebo erros e problemas são assim que agrupo minhas especificações em umdefine(...)
call - event quando dou ao módulo um ID -define('someId', function(){ ... })
-preciso retornar algo deste módulo, pois é umdefine
ligar?
Outras vezes, recebo o 'olERRO: 'Não há registro de data e hora para /base/src/app.js!'. "Carimbo de data e hora, é claro! Que bobagem minha ..." - o que isso significa no mundo ?! Às vezes eu recebo o infame "Executado 0 de 0 ERRO"- Eu também poderia usar um pouco de clareza aqui, por favor. Realmente, tenho bastanteERRO: '... sem registro de data e hora ...' erros - e até404
s quandoparece Eu deveria estar puxando essa biblioteca com o karma.conf.jsfiles
config ... ???
Parece até que, geralmente, quando digo explicitamente o karma para excluirsrc/app.js
Eu ainda entendo404
se erros.
tl; dr
Obviamente, eu sou um pouco um novato confuso sobre Karma e * DD em geral ...
eu posso corrertest-test-file.js
bem quando meu karma.conf.jsfiles
matriz parece[ 'test-main.js', 'test/spec/test-test-file.js' ]
- mas, ainda assim, se envolver meu teste em uma chamada de definição RequireJS, recebo o "Incompatibilidade anonymous define ()"erro mencionado acima.
Parece que quando eu adiciono{pattern: '...', inclui:falso } então o karma simplesmente não adiciona nenhum dos meus arquivos para o padrão especificado (???).
Se alguém puder simplesmente me orientar sobre como usar o RequireJS com o Karma - ou seja, para que eu possa finalizar meus testes em umdefinir / exigir ligar e puxar o módulo que eu quero testar ... Isso seria muito apreciado.
Como é um pouco difícil manter esses tipos de perguntas curtos e ainda fornecer informações adequadas, espero não ter demorado muito.
EDITARDepois de ler a resposta de glepretre e algumas brincadeiras por conta própria, reconfigurei meu projeto da seguinte maneira:
Mudou-setest-main.js
paratest/test-main.js
,renomeadotest-test-file.js paratestFileSpec.js - mudou detest/spec
paratest/
,karma.conf.js:
...
// list of files / patterns to load in the browser
files: [
{pattern: 'lib/**/*.js', included: false},
{pattern: 'src/**/*.js', included: false},
{pattern: 'test/**/*Spec.js', included: false},
'test/test-main.js'
],
....
test / test-main.js:
/* **************** HOW COME THE DEFAULT (Karma-generated) CONFIGURATION DOES ***NOT WORK???
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));
}
});
*/
var tests = [];
for (var file in window.__karma__.files) {
if (/Spec\.js$/.test(file)) {
tests.push(file);
}
}
require.config({
// Karma serves files under /base, which is the basePath from your config file
baseUrl: '/base/src',
paths: {},
shim: {},
// dynamically load all test files
//deps: allTestFiles,
//
deps: tests,
// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
});
Agora estou executando testes de unidade com sucesso!Agradecimentos especiais a glepretre e todos os outros colaboradores.
Obrigado por qualquer insight :)
},
bootstrap: {
deps: ['jquery']
}
},
// dynamically load all test files
deps: allTestFiles,
// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
});
test-test-file.js
console.log('....................');
define(function(){
//console.log('testing test-file', testFile);
describe('Testing testing', function(){
it('should work', function(){
expect(true).toEqual(true);
});
});
});
test-file.js
define('testFile', [], function(){
return function init(sandbox){
var app, application = app = sandbox.app
, globals = sandbox.globals;
return {
some: 'module'
};
};
});
Perguntas e descrições
Os pontos-chave para os quais gostaria de ouvir respostas são:
o que {pattern: '...',incluem: verdadeiro | falso } Faz?melhor maneira de excluir todo o material extra dentro dos diretórios da bower.quais arquivos eu preciso incluir no arquivo test-main.js?quais arquivos eu preciso incluir no arquivo karma.conf.js?o que o test-main.js realmente faz; para que serve isto?Os horários em que recebo erros e problemas são assim que agrupo minhas especificações em umdefine(...)
call - event quando dou ao módulo um ID -define('someId', function(){ ... })
-preciso retornar algo deste módulo, pois é umdefine
ligar?
Outras vezes, recebo o 'olERRO: 'Não há registro de data e hora para /base/src/app.js!'. "Carimbo de data e hora, é claro! Que bobagem minha ..." - o que isso significa no mundo ?! Às vezes eu recebo o infame "Executado 0 de 0 ERRO"- Eu também poderia usar um pouco de clareza aqui, por favor. Realmente, tenho bastanteERRO: '... sem registro de data e hora ...' erros - e até404
s quandoparece Eu deveria estar puxando essa biblioteca com o karma.conf.jsfiles
config ... ???
Parece até que, geralmente, quando digo explicitamente o karma para excluirsrc/app.js
Eu ainda entendo404
se erros.
tl; dr
Obviamente, eu sou um pouco um novato confuso sobre Karma e * DD em geral ...
eu posso corrertest-test-file.js
bem quando meu karma.conf.jsfiles
matriz parece[ 'test-main.js', 'test/spec/test-test-file.js' ]
- mas, ainda assim, se envolver meu teste em uma chamada de definição RequireJS, recebo o "Incompatibilidade anonymous define ()"erro mencionado acima.
Parece que quando eu adiciono{pattern: '...', inclui:falso } então o karma simplesmente não adiciona nenhum dos meus arquivos para o padrão especificado (???).
Se alguém puder simplesmente me orientar sobre como usar o RequireJS com o Karma - ou seja, para que eu possa finalizar meus testes em umdefinir / exigir ligar e puxar o módulo que eu quero testar ... Isso seria muito apreciado.
Como é um pouco difícil manter esses tipos de perguntas curtos e ainda fornecer informações adequadas, espero não ter demorado muito.
EDITARDepois de ler a resposta de glepretre e algumas brincadeiras por conta própria, reconfigurei meu projeto da seguinte maneira:
Mudou-setest-main.js
paratest/test-main.js
,renomeadotest-test-file.js paratestFileSpec.js - mudou detest/spec
paratest/
,karma.conf.js:
...
// list of files / patterns to load in the browser
files: [
{pattern: 'lib/**/*.js', included: false},
{pattern: 'src/**/*.js', included: false},
{pattern: 'test/**/*Spec.js', included: false},
'test/test-main.js'
],
....
test / test-main.js:
/* **************** HOW COME THE DEFAULT (Karma-generated) CONFIGURATION DOES ***NOT WORK???
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));
}
});
*/
var tests = [];
for (var file in window.__karma__.files) {
if (/Spec\.js$/.test(file)) {
tests.push(file);
}
}
require.config({
// Karma serves files under /base, which is the basePath from your config file
baseUrl: '/base/src',
paths: {},
shim: {},
// dynamically load all test files
//deps: allTestFiles,
//
deps: tests,
// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
});
Agora estou executando testes de unidade com sucesso!Agradecimentos especiais a glepretre e todos os outros colaboradores.
Obrigado por qualquer insight :)