RequireJS and Karma - javascript

I am trying to set my project up to use karma/jasmine. This project also uses knockoutjs (shouldn't really matter) and requirejs (really matters). The project structure is a little different from the norm and that's what is giving me issues. I am running this using karma start from the command line.
I tried to follow the karma requirejs setup instructions which I feel got me most of the way there. I can set it up to load the test/spec files correctly or the src files correctly but not both. In its current state, I get the following message:
Failed to load resource: the server responded with a status of 404 (Not Found) http://localhost:9876/base/app/test/components/home-pageSpec.js
If I change the baseUrl in test-main.js (generated by karma init) from '/base/app' to '/base'it works just fine until I have a relatively address require.
home.js working (no relative require):
define(['jquery'], function ($) {
function HomeViewModel()
{
this.name = 'myName';
}
return {viewModel: HomeViewModel};
});
home.js not working (relative require):
define(['jquery', 'js/services/someService'], function ($, someService) {
function HomeViewModel()
{
this.name = 'myName';
}
return {viewModel: HomeViewModel};
});
Which gives the following error GET http://localhost:9876/base/js/services/programService.js. This is because the resource is really at (or should be at) http://localhost:9876/base/app/js/services/programService.js
.
├── app
│   ├── bower_modules ...
│   ├── components
│   │   ├── home
│   │   │   └── home.js
│   ├── index.html
│   ├── js
│   │   ├── lib ...
│   │   ├── services
│   │   │   └── someService.js
│   │   ├── require.config.js
│   │   ├── router.js
│   │   └── startup.js
├── bower.json
├── gulpfile.js
├── karma.conf.js
├── node_modules ...
├── package.json
├── test
│   └── components
│   └── home-pageSpec.js
└── test-main.js
Please tell me how to fix the relative path stuff please.
karma.conf.js:
// Karma configuration
// Generated on Wed Apr 15 2015 10:07:13 GMT-0400 (Eastern Daylight 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-main.js',
//{pattern: 'app/bower_modules/jquery/dist/jquery.js', included: false},
{pattern: 'app/bower_modules/**/*.js', included: false},
{pattern: 'app/js/lib/**/*.js', included: false},
{pattern: 'test/**/*Spec.js', included: false},
{pattern: 'app/components/**/*.js', included: false},
{pattern: 'app/js/services/**/*.js', included: false}
],
// list of files to exclude
exclude: [
'app/bower_modules/**/tests/*',
'app/bower_modules/**/spec/*',
'app/bower_modules/**/meteor/test.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_DEBUG,
// 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) {
console.log(path + "********");
var p = path.replace(/^\/base\//, '').replace(/\.js$/, '');
console.log(p + "********");
return p;
};
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',
paths: {
"jquery": "app/bower_modules/jquery/dist/jquery",
},
// dynamically load all test files
deps: allTestFiles,
// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
});
home-pageSpec.js:
define(['app/components/home/home'], function(homePage) {
var HomePageViewModel = homePage.viewModel;
describe('Home page view model', function() {
it('should supply a friendly message which changes when acted upon', function() {
expect(1).toEqual(1);
});
});
});

Related

Grunt cssmin and timestamp filename

I'm trying to set up a grunt task that outputs a minified css file and changes the file name with a timestamp.
My Gruntfile looks like this:
module.exports = function (grunt) {
//project configurations
grunt.initConfig({
cssmin: {
target: {
src: ["css/aw2018.css", ],
dest: "dist/aw2018.min.css"
}
}
replace: {
foo: {
options: {
variables: {
'timestamp': '<%= new Date().getTime() %>'
},
force: true
},
files: [{
expand: true,
cwd: 'css/',
src: ['*.css/*.js'],
dest: 'dist/',
ext: '.<%= new Date().getTime() %>.js'
}]
}
}
});
//load cssmin plugin
grunt.loadNpmTasks('grunt-contrib-cssmin');
//create default task
grunt.registerTask("default", ["cssmin"]);
grunt.registerTask('default', 'replace');
};
But I get an error of
Loading "Gruntfile.js" tasks...ERROR
SyntaxError: Unexpected identifier
Warning: Task "default" not found. Use --force to continue.
EDIT:
This is what I'm ultimately trying to achieve:
Minify a css file
Add a timestamp to the end of the file name.
I would like to have it work for any css file in a folder but keep them separate. For instance, lets say I have aw2018.css and aw2017.css. I would like both of them to run through the task and then be output to their own individual minified css file with the timestamp of YYYY-MM-DD-HH-MM-SS at the end of the filename.
This can be achieved by utilizing grunt's rename function when building the files object dynamically, instead of using another task.
The documentation describes grunts rename function as follows:
rename Embeds a customized function, which returns a string containing the new destination and filename. This function is called for each matched src file (after extension renaming and flattening).
Inside the body of the rename function is where you add your custom logic to append a timestamp to each filename.
The following Gruntfile.js configuration shows how to achieve this:
Gruntfile.js
module.exports = function (grunt) {
var path = require('path'); // Load nodes built-in `path` module.
// Obtain local timestamp formatted as: YYYY-MM-DD-HH-MM-SS
var tzOffset = (new Date()).getTimezoneOffset() * 60000;
var timeStamp = (new Date(Date.now() - tzOffset)).toISOString().slice(0, -1)
.replace(/\.[\w\W]+?$/, '') // Delete from dot to end.
.replace(/\:|\s|T/g, '-'); // Replace colons, spaces, and T with hyphen.
grunt.initConfig({
cssmin: {
timestamp: {
files: [{
expand: true,
cwd: 'css/',
src: ['aw2017.css', 'aw2018.css'],
dest: 'dist/',
/**
* Grunt rename function generates new destination filepath,
# adds timestamp, and new min.css extension to the file name.
# (https://gruntjs.com/configuring-tasks#the-rename-property)
#
* #param {String} dest - The path to the desination directory.
* #param {String} src - The path to the source directory.
* #returns {String} New dest path with time-stamped filename.
*/
rename: function(dest, src) {
var fileExt = path.extname(src),
fileName = path.basename(src, fileExt),
dirName = path.dirname(src),
newFileExt = ['.min', fileExt].join(''),
newFileName = [fileName, '-', timeStamp, newFileExt].join(''),
newDestPath = path.join(dest, dirName, newFileName);
return newDestPath;
}
}]
}
}
});
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.registerTask('default', ['cssmin:timestamp']);
};
Additional info:
Firstly, in the Gruntfile.js above, we load the nodejs built-in path module via the line reading.
var path = require('path');
This module is used later in the rename function to help create the new time-stamped filename, and ascertain the destination filepath to be return'ed:
We then create a local timestamp formatted as YYYY-MM-DD-HH-MM-SS via the lines reading:
var tzOffset = (new Date()).getTimezoneOffset() * 60000;
var timeStamp = (new Date(Date.now() - tzOffset)).toISOString().slice(0, -1)
.replace(/\.[\w\W]+?$/, '') // Delete from dot to end.
.replace(/\:|\s|T/g, '-'); // Replace colons, spaces, and T with hyphen.
Note: We assign the generated timestamp to the timeStamp variable outside of any grunt task(s) to ensure all resultant filenames get the same timestamp.
The date/time format will be based on your local timezone and not UTC (Coordinated Universal Time).
We then reconfigure your cssmin task to build the files object dynamically instead of utilizing the compact format. By configuring the task this way we get access to the rename function.
Further usage and modifications to the current config:
The Gruntfile.js configuration provided above takes a two source CSS files, named aw2017.css and aw2018.css from the following directory structure:
.
└── css
├── aw2017.css
└── aw2018.css
After running the grunt command via your CLI, it outputs both minified (time-stamped) .css files to the new dist directory. Resulting as this:
.
├── css
│ ├── aw2017.css
│ └── aw2018.css
└── dist
├── aw2017-2018-05-09-08-35-57.min.css
└── aw2018-2018-05-09-08-35-57.min.css
However, if you want to also include the source css folder in the dist directory like this:
.
├── css
│ ├── aw2017.css
│ └── aw2018.css
└── dist
└── css
├── aw2017-2018-05-09-08-35-57.min.css
└── aw2018-2018-05-09-08-35-57.min.css
then you need to change the values of the cwd and src properties in the cssmin task to this:
// ...
cwd: '.',
src: ['css/aw2017.css', 'css/aw2018.css'],
// ...
Minifying and time-stamping multiple .css files using a glob pattern
Currently, in your question, you seem to only want to minify two .css file, namely aw2017.css and aw2018.css.
However, if you wanted to minify (and time-stamp) many .css files found in the css directory, however many levels deep, you can utilize a globbing pattern. For example, lets say your source css directory looks like this:
.
└── css
├── a.css
├── b.css
├── foo
│ ├── bar
│ │ └── c.css
│ └── d.css
└── quux
└── e.css
...and if you change the values of the cwd and src properties in your cssmin task to this:
// ...
cwd: '.',
src: ['css/**/*.css'],
// ...
Your resultant output will be something like this:
.
├── css
│ └── ...
└── dist
└── css
├── a-2018-05-09-08-35-57.min.css
├── b-2018-05-09-08-35-57.min.css
├── foo
│ ├── bar
│ │ └── c-2018-05-09-08-35-57.min.css
│ └── d-2018-05-09-08-35-57.min.css
└── quux
└── e-2018-05-09-08-35-57.min.css

Intern path error in browser client

I have a conventional recommended Intern directory structure:
MyProject
├── node_modules
│ ├── intern-geezer
│ │ ├── client.html
├── src
│ ├── myFunction.js
├── tests
│ ├── intern.js
│ ├── unit
│ │ ├── ps.js
with a very simple config:
useLoader: {
'host-node': 'dojo/dojo',
'host-browser': 'node_modules/dojo/dojo.js'
},
loader: {
packages: []
},
suites: [ 'tests/unit/ps' ]
and tests:
define(function (require) {
var tdd = require('intern!tdd');
var assert = require('intern/chai!assert');
// Global function to test, not an AMD module
var parseF = require('src/myFunction.js');
var he = require('tests/he');
tdd.suite('My tests', function() {
//etc
});
});
````
but when I open the browser client the loader is looking for the test suite inside the intern-geezer directory:
I am not setting a baseUrl in the config (or in the browser URL). I didn't have this trouble going through the regular (non-geezer) intern tutorial. Since the baseUrl defaults to two directories up from client.html I don't see what I'm doing wrong. Thanks for any help. (Yes, I will need geezer for ancient IE. No, I do not want to rewrite the function I'm testing as an AMD module.)
The Intern loader doesn't know how to get to your tests because they haven't been registered as a package. When using the recommended directory structure, you'll want to also set up the recommended loader configuration so that Intern knows where to find your code and tests.
loader: {
packages: [
{ name: 'app', location: 'src/' },
{ name: 'tests', location: 'tests/' }
]
}
Then, update your tests to correctly find the code you need to test.
// Global function to test, not an AMD module
var parseF = require('app/myFunction.js');
Now, Intern should be able to correctly find the code and tests.

Gulp with browserify: Cannot find module src/js/main.js

I'm trying to get a basic build set up using Gulp and browserify, but keep seeing this error when trying to run the default task:
Error: Cannot find module 'src/js/main.js' from '/Users/ben/dev/git/myapp/'
gulpfile.js
var gulp = require('gulp');
var browserify = require('browserify');
var del = require('del');
var source = require('vinyl-source-stream');
var paths = {
main_js: ['src/js/main.js'],
js: ['src/js/*.js']
};
gulp.task('clean', function(done) {
del(['build'], done);
});
gulp.task('js', ['clean'], function() {
browserify(paths.main_js)
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest('./build/'));
});
gulp.task('watch', function() {
gulp.watch(paths.js, ['js']);
});
gulp.task('default', ['watch', 'js']);
main.js
console.log("Hello!")
myapp/
.
├── gulpfile.js
├── node_modules
│   ├── browserify
│   ├── del
│   ├── gulp
│   └── vinyl-source-stream
├── npm-debug.log
├── package.json
└── src
├── css
├── index.html
└── js
└── main.js
I can't understand why it's failing to find main.js. When I run this command from myapp/, it works fine:
$ browserify src/js/main.js > build/bundle.js
Try using "./src/js/main.js" instead of "src/js/main.js" i.e:
var paths = {
main_js: ['./src/js/main.js'],
js: ['src/js/*.js']
};

Gulp watch, incremental build

I'm struggling to make gulp-watch behave as I desire. This small project is tooling to build HTML5 emails templates from Jade+SASS, in a repeatable way. The directory structure is as such:
.
├── Gulpfile.coffee
├── Gulpfile.js
├── build
│   ├── hello-world.html
│   └── styles
│   └── ink.css
├── node_modules
│   ├── ...snip...
├── package.json
└── source
├── hello-world.jade
├── layouts
│   └── default.jade
└── styles
└── ink.scss
My wish list is thus:
Build all templates when styles or templates change. This is what I can't do
Don't have a seaerate "cold" start, always use the gulp incremental build. (This seems to work)
Live reload would reload the browser, that'd be cool. (This too)
The Gulpfile, in CoffeeScript notation for brevity is included below, it's predominantly based on the documentation Incremental rebuilding, including operating on full file sets.
gulp = require 'gulp'
inlineCss = require 'gulp-inline-css'
jade = require 'gulp-jade'
marked = require 'gulp-marked'
plumber = require 'gulp-plumber'
rename = require 'gulp-rename'
sass = require 'gulp-sass'
cached = require 'gulp-cached'
util = require 'gulp-util'
watch = require 'gulp-watch'
webserver = require 'gulp-webserver'
styleGlob = "source/styles/*.scss"
templateAndLayouysGlob = "source/**/*.jade"
templateGlob = "source/*.jade"
styleChangeHandler = (event) ->
if event.type is "deleted"
delete cached.caches.scripts[event.path]
templateChangeHandler = (event) ->
if event.type is "deleted"
delete cached.caches.templates[event.path]
gulp.task "styleWatcher", ->
gulp.src(styleGlob)
.pipe(cached('styles'))
.pipe(watch(styleGlob))
.pipe(sass())
.pipe(gulp.dest("build/styles"))
.on('error', util.log)
gulp.task "templateWatcher", ->
gulp.src(templateGlob)
.pipe(cached('templates'))
.pipe(watch(templateGlob))
.pipe(jade(pretty: true))
.pipe(inlineCss())
.pipe(gulp.dest("build/"))
.on('error', util.log)
gulp.task 'webserver', ->
buildPath = 'build/'
gulp.src(buildPath)
.pipe(webserver({
livereload: true,
directoryListing: {
enable: true,
path: buildPath
},
open: true
}))
gulp.task "watch", ->
styleWatcher = gulp.watch(styleGlob, ["styleWatcher"])
styleWatcher.on 'change', styleChangeHandler
templateWatcher = gulp.watch(templateGlob, ["templateWatcher"])
templateWatcher.on 'change', templateChangeHandler
# I would expect this to fire when something in build/styles/*.css
# is updated by the style watcher?
templateStyleWatcher = gulp.watch('build/styles/*.css', ["templateWatcher"])
templateStyleWatcher.on 'change', templateChangeHandler
gulp.task "default", ["styleWatcher", "templateWatcher", "watch", "webserver"]
If it were possible, and I'd written this watcher in GNU Make or similar, I would have had the option to express that build/, and rely on the tooling to rebuild those files if the ones upon which they depend are out of date.
I've seen that there are a number of gulp-<something about inlining> plugins, but none of them make clear whether they support this conditional recompilation by watching paths that were imported for changes (I doubt it).
Given my background in systems programming, I may well be approaching Javascript build tooling in a completely incorrect way.

CSSLint : How to config tasks just print error not warning

I'm new with Grunt - csslint plugin, after I run and cssLint task complete, there are many and many errors and warnings that I can't follow. So how to config task just print out the errors, not warning??
If you use grunt-contrib-csslint you can specify the options in a .csslintrc file.
From the grunt-contrib-csslint Readme:
Options
Any specified option will be passed through directly to csslint, thus
you can specify any option that csslint supports. The csslint API is a
bit awkward: For each rule, a value of false ignores the rule, a value
of 2 will set it to become an error. Otherwise all rules are
considered warnings.
Assuming you have a structure like this:
├── .csslintrc
├── Gruntfile.js
├── css
│   └── foo.css
├── node_modules
└── package.json
.csslintrc
{
"ignore": [
"adjoining-classes",
"box-model",
"box-sizing",
"bulletproof-font-face",
"compatible-vendor-prefixes",
"display-property-grouping",
"duplicate-background-images",
"duplicate-properties",
"empty-rules",
"fallback-colors",
"floats",
"font-faces",
"font-sizes",
"gradients",
"ids",
"import",
"import-ie-limit",
"important",
"known-properties",
"non-link-hover",
"order-alphabetical",
"outline-none",
"overqualified-elements",
"qualified-headings",
"regex-selectors",
"rules-count",
"selector-max",
"selector-max-approaching",
"selector-newline",
"shorthand",
"star-property-hack",
"text-indent",
"underscore-property-hack",
"unique-headings",
"universal-selector",
"unqualified-attributes",
"vendor-prefix",
"zero-units"
]
}
reference: https://github.com/CSSLint/csslint/wiki/Command-line-interface
Gruntfile
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
csslint: {
strict: {
src: ['css/*.css']
},
lax: {
options: {
csslintrc: '.csslintrc'
},
src: ['css/*.css']
}
}
});
grunt.loadNpmTasks('grunt-contrib-csslint');
grunt.registerTask('default', ['csslint:lax']);
};
Then grunt will report only errors and grunt csslint:strict will report warnings and errors.

Categories

Resources