How to setup grunt task for requirejs and qunit - javascript

I am trying to setup a QUnit environment using requirejs and grunt-contrib-qunit.
Here is what I have.
gruntfile:
qunit: {
all: {
options: {
urls: [
'http://localhost:8000/qunit/qunit-test-suite.html'
]
}
}
},
connect: {
server: {
options: {
port: 8000,
base: '.'
}
}
},
qunit-test-suite.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>QUnit Tests Suite: travis CI Test</title>
<link rel="stylesheet" href="../components/libs/qunit/qunit/qunit.css">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="../components/libs/qunit/qunit/qunit.js"></script>
<script>
QUnit.config.autoload = false;
QUnit.config.autostart = false;
</script>
<script data-main="qunit" src="../components/libs/requirejs/require.js"></script>
</body>
</html>
qunit.js:
require.config({
baseUrl: "../",
paths: {
'jquery': 'components/libs/jquery/dist/jquery.min',
// Test for Foo
'foo': 'components/app/foo/foo',
'test-Foo': 'components/app/foo/test-Foo'
},
shim: {
'QUnit': {
exports: 'QUnit',
init: function() {
QUnit.config.autoload = false;
QUnit.config.autostart = false;
}
}
}
});
require(['test-Foo'], function (Foo) {
QUnit.load();
QUnit.start();
});
test-Foo.js:
define(['foo'], function(Foo) {
'use strict';
module("Foo");
test("Foo return Test", function() {
equal(Foo.foo(), "foo", "Function should return 'foo'");
equal(Foo.oof(), "oof", "Function should return 'oof'");
});
test("Bar return Test", function() {
equal(Foo.bar(), "barz", "Function should return 'bar'");
});
});
Problem is that it all works fine when I open up the test-suite.html in my browser. Once sent to PhantomJS I get the following error:
Running "connect:server" (connect) task
Started connect web server on http://localhost:8000
Running "qunit:all" (qunit) task
Testing http://localhost:8000/qunit/qunit-test-suite.html
>> PhantomJS timed out, possibly due to a missing QUnit start() call.
Warning: 1/1 assertions failed (0ms) Use --force to continue.
Aborted due to warnings.
Full setup: https://github.com/markusfalk/test-travis
Test Run: https://travis-ci.org/markusfalk/test-travis
Thanks for any help :)

With the help of Jörn I came up with a working setup. Trick is to setup requireJS before QUnit loads (moved requireJS config to config.js and load it first).
Requirements:
grunt-contrib-qunit v0.7.0
qunit v1.18.0
HTML test suite:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>QUnit Tests Suite: asdf</title>
<link rel="stylesheet" href="../components/libs/qunit/qunit/qunit.css">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="config.js"></script>
<script data-main="unit" src="../components/libs/requirejs/require.js"></script>
</body>
</html>
config.js
var requirejs = {
baseUrl: "../",
paths: {
//{{app}}
'foo': 'components/app/foo/foo',
'test-foo': 'components/app/foo/test-foo',
//{{libs}}
'unit': 'qunit/unit',
'qunit': 'components/libs/qunit/qunit/qunit',
'jquery.exists': 'libs/jquery.exists/jquery.exists',
'jquery': 'components/libs/jquery/dist/jquery.min'
},
'shim': {
'jquery.exists': ['jquery']
}
};
unit.js
require([
'qunit',
'test-foo'
],
function(qunit, TestFoo) {
TestFoo();
qunit.start();
});
test-foo.js:
define(['jquery', 'qunit', 'foo'], function($, qunit, Foo) {
'use strict';
return function() {
qunit.module("Foo");
qunit.test("Foo Test", function() {
equal(Foo.saySomething(), "Hello", "returns 'Hello'");
});
};
});
And finally the module I want to test:
define(['jquery'], function($) {
'use strict';
var Foo = {
saySomething: function() {
return "Hello";
}
};
return {
saySomething: Foo.saySomething
};
});

Have you tried running grunt with the -v and/or -d flags to get some more verbose output? I did notice that there was something skipped regarding PhantomJS in your travis-ci build.
Writing location.js file
PhantomJS is already installed at /usr/local/phantomjs/bin/phantomjs.
npm WARN excluding symbolic link lib/socket.io-client.js -> io.js
If it's dependant on io.js and the link isn't there, it will fail.
UPDATE:
I found the issue using the verbose output. Your test is 404ing because of a filename issue.
["phantomjs","onResourceReceived",{"contentType":"text/html; charset=utf-8","headers":[{"name":"X-Content-Type-Options","value":"nosniff"},{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Content-Length","value":"43"},{"name":"Date","value":"Fri, 10 Apr 2015 06:45:47 GMT"},{"name":"Connection","value":"keep-alive"}],"id":6,"redirectURL":null,"stage":"end","status":404,"statusText":"Not Found","time":"2015-04-10T06:45:47.747Z","url":"http://localhost:10000/components/app/foo/test-Foo.js"}]
You're trying to use the file test-Foo.js. The file is named test-foo.js in your repository. Changing the case should fix the test.

Apologies in advance if I'm stating the obvious but do you have PhantomJS installed? I can't see it in your packages.json file. You can install it using npm install phantomjs --save-dev in your project root. The save-dev will add it to your packages.json so when you run npm install it will automatically get installed.

Related

Configuring gulp with Angular & system.js

I have been searching through the web and found various tutorials covering this subject. However, most of the ones i have come across i cannot understand well enough, have been outdated, or do not cover the subject in enough detail.
I am simply trying to set up a gulpfile that will:
Compile a Typescript project
Copy required modules (Angular)
So that the result is a working Angular app. At this point, i am able to compile TS to JS, however, when i load main.js into index.html, i get the following error:
Uncaught ReferenceError: System is not defined
at main.js:1
With the code i have so far, i expected to receive the output of the aMethod function. If i remove "module": "system" from tsconfig, i am able to get the ouput in the node console, however.
I have added angular and its dependencies, together with system.js as npm packages.
My questions are:
What am i doing wrong at this point, since i cannot get any output from my transpiled TS app?
How do i utilize system.js with gulp, to create a task that will copy the #angular modules (core etc.) to my build dir, so my app can make us of Angular?
What are the advantages, when transpiling, to transpile the various typescript files into a single javascript file?
Thank you in advance. Any help is, as always, much appreciated.
Project files
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "system",
"moduleResolution": "node",
"experimentalDecorators": true,
"removeComments": false
},
"include": [
"src/app/**/*"
],
"exclude": [
"gulpfile.js",
"node_modules"
]
}
gulpfile.js
const gulp = require("gulp");
const del = require("del");
const ts = require("gulp-typescript");
const tsProject = ts.createProject("tsconfig.json");
const appDir = "build/js";
// Tasks
gulp.task("clean", function() {
del([appDir]);
});
gulp.task("compile", function() {
return tsProject.src()
.pipe(tsProject())
.js
.pipe(gulp.dest(appDir));
});
gulp.task("build", ['clean', 'compile'], function() {
});
main.ts
import { Test } from "./class";
let t1 = new Test();
t1.aMethod("test");
class.ts
export class Test
{
aMethod(s: string)
{
console.log(s);
}
}
index.html
<DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Angular & Python App</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script src="js/main.js"></script>
</body>
</html>
Try this:
Copy all required dependencies to build directory and then build.
Create your gulp compile like this:
var typeScriptsPath = "src/**/*.ts";
const sourcemaps = require('gulp-sourcemaps');
const tsc = require("gulp-typescript");
/**
* Compile TypeScript sources and create sourcemaps in build directory.
*/
gulp.task("compile", () => {
let tsResult = gulp.src(typeScriptsPath)
.pipe(sourcemaps.init())
.pipe(tsc(tsProject));
return tsResult.js
.pipe(sourcemaps.write(".", {
sourceRoot: '/src'
}))
.pipe(gulp.dest("build"));
});
/**
* copy all dependencies to build directory
*/
gulp.task("libs", () => {
return gulp.src([
'core-js/client/shim.min.js',
'systemjs/dist/system-polyfills.js',
'systemjs/dist/system.src.js',
'systemjs/dist/system.js',
'reflect-metadata/Reflect.js',
'rxjs/**/*.js',
'rxjs/**/*.js.map',
'zone.js/dist/*.min.js',
'#angular/*/bundles/**',
'jquery/dist/*min.js',
'lodash/lodash.min.js',
'bootstrap/dist/js/*min.js',
'bootstrap/dist/css/*min.css',
'moment/min/*min.js',
'underscore/underscore-min*',
'angular2-cookie/**',
'moment/**'
], {
cwd: "node_modules/**"
}) /* Glob required here. */
.pipe(gulp.dest("build/lib"));
});
gulp.task("build", ['compile', 'libs'], () => {
console.log("Building the project ...");
});
You should use systemjs-builder to build main.ts file as same as systemjs file build it. So, your gulp file should be something like this:
var Builder = require('systemjs-builder');
var builder = new Builder('', 'systemjs.config.js');
gulp.task('dist',['compile', 'bundle']);
gulp.task('compile', shell.task([
'tsc'
]));
gulp.task('bundle', ['bundle:vendor', 'bundle:app'], function(){
return gulp.src(['./dist/*.js'], {base:"."})
.pipe(uglify({
compress: true,
mangle: true
}))
.pipe(gulp.dest('./'));
});
gulp.task('bundle:app', function () {
return builder
.buildStatic('app/main.js', './dist/main.bundle.js')
.catch(function (err) {
console.log('App bundle error');
console.log(err);
});
});
gulp.task('bundle:vendor', function () {
return builder
.buildStatic('app/vendor.js', './dist/vendor.bundle.js')
.catch(function (err) {
console.log('Vendor bundle error');
console.log(err);
});
});
where vendor.js file contains all angular vendors libraries like: 'zone', 'reflect' and 'core-js-shim'.
Now you can call gulp dist task to compile all your file.

Run mochajs asynchronously (AMD-like)

Can I load mocha module asynchronously in browser? I can do it for sure with chai. Is there any workaround to make mocha work in amd-like style ?
require.config({
baseUrl: "/scripts",
paths: {
"mocha": "framework/mocha",
"chai": "framework/chai",
"first": "custom/first"
}
});
require(['first', 'mocha', 'chai'], function (first, mocha, chai) {
first.echo();
console.log('something');
console.log('something');
mocha.ui('tdd');
var assert = chai.assert;
suite('"Home" Page Tests', function () {
test('page should contain link to contact page', function () {
assert($('a[href="/contact"]').length);
});
});
mocha.run();
console.log('whatever');
});
in the code sample above first and chai work fine, while mocha is undefined.
Mocha is not AMD-aware so if you are going to load Mocha using RequireJS, you need a shim for it. Here is an index.html file that contains a minimal example:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8"/>
<link href="node_modules/mocha/mocha.css" type="text/css" media="screen" rel="stylesheet" />
<script type="text/javascript" src="node_modules/requirejs/require.js"></script>
</head>
<body>
<div id="mocha"></div>
<script>
require.config({
paths: {
mocha: 'node_modules/mocha/mocha',
},
shim: {
mocha: {
exports: "mocha",
}
},
});
require(["mocha"], function (mocha) {
mocha.setup("bdd");
it("foo", function () {});
mocha.run();
});
</script>
</body>
</html>
You need to have run npm install requirejs mocha in the same directory where index.html is located.
In cases where I want to be able to use the Mocha constructor I use this shim instead:
shim: {
mocha: {
exports: "mocha",
init: function () { return {mocha: mocha, Mocha: Mocha }; }
}
},

Using require.js and mocha.js for a browser (front-end) Javascript unit testing [duplicate]

Can I load mocha module asynchronously in browser? I can do it for sure with chai. Is there any workaround to make mocha work in amd-like style ?
require.config({
baseUrl: "/scripts",
paths: {
"mocha": "framework/mocha",
"chai": "framework/chai",
"first": "custom/first"
}
});
require(['first', 'mocha', 'chai'], function (first, mocha, chai) {
first.echo();
console.log('something');
console.log('something');
mocha.ui('tdd');
var assert = chai.assert;
suite('"Home" Page Tests', function () {
test('page should contain link to contact page', function () {
assert($('a[href="/contact"]').length);
});
});
mocha.run();
console.log('whatever');
});
in the code sample above first and chai work fine, while mocha is undefined.
Mocha is not AMD-aware so if you are going to load Mocha using RequireJS, you need a shim for it. Here is an index.html file that contains a minimal example:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8"/>
<link href="node_modules/mocha/mocha.css" type="text/css" media="screen" rel="stylesheet" />
<script type="text/javascript" src="node_modules/requirejs/require.js"></script>
</head>
<body>
<div id="mocha"></div>
<script>
require.config({
paths: {
mocha: 'node_modules/mocha/mocha',
},
shim: {
mocha: {
exports: "mocha",
}
},
});
require(["mocha"], function (mocha) {
mocha.setup("bdd");
it("foo", function () {});
mocha.run();
});
</script>
</body>
</html>
You need to have run npm install requirejs mocha in the same directory where index.html is located.
In cases where I want to be able to use the Mocha constructor I use this shim instead:
shim: {
mocha: {
exports: "mocha",
init: function () { return {mocha: mocha, Mocha: Mocha }; }
}
},

PhantomJS not playing nice with RequireJS+Jasmine

I have some tests running with RequireJS and Jasmine. I have a Jasmine test harness file that looks like this:
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="./Scripts/jasmine/jasmine.css" />
<script type="text/javascript" src="./Scripts/jasmine/jasmine.js"></script>
<script type="text/javascript" src="./Scripts/jasmine/jasmine-html.js"></script>
<script type="text/javascript" src="./Scripts/jasmine/boot.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js"></script>
<script type="text/javascript">
require(["fakeTest"], function () {
window.onload();
});
</script>
</head>
<body>
</body>
</html>
My fakeTest file is very simple:
define(["require", "exports"], function (require, exports) {
describe("fake test", function () {
it("test nothing", function () {
expect(1).toEqual(1);
});
});
});
If I run this in FireFox/Chrome then everything works fine; I see one test and that it passed. If I run this with PhantomJS though, I start getting problems. Running it with the remote debugger flag I get the error:
Error: Cannot find module 'fakeTest'
phantomjs://bootstrap.js:299 in require
phantomjs://bootstrap.js:263 in require
If I try changing my harness file so that it says requirejs[("fakeTest"...... instead of just require, I get this error:
Error: Script error for "fakeTest"
http://requirejs.org/docs/errors.html#scripterror
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:140
in defaultOnError
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:544
in onError
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:1732
in onScriptError :0 in appendChild
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:1952
in load
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:1679
in load
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:829
in load
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:819
in fetch
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:851
in check
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:1177
in enable
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:1550
in enable
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:1162
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:131
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:56
in each
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:1114
in enable
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:783
in init
https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js:1453
If I put in a completely invalid module name, I get the same errors in both cases.
I'm totally lost as to why this is happening. I've played around with changing the path for fakeTest in the harness file but nothing changes. I've simplified the harness file as much as I could, but since I'm still seeing this i'm not sure what else to try. Anyone have any ideas?
edit
I've removed everything to do with Jasmine and just have fakeTest do an alert. Now I get errors saying
<html>
<head>
<meta charset="utf-8" />
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.20/require.js"></script>
<script type="text/javascript">
require(["fakeTest"], function () {});
</script>
</head>
<body>
</body>
</html>
and
define(["require", "exports"], function (require, exports) {
alert('foo');
});
"ReferenceError: Can't find variable: requirejs"
Instead of write html use karma with requirejs plugin.
karma.conf.js
module.exports = function(config) {
config.set({
frameworks: ['jasmine', 'requirejs'],
files: [
{pattern: 'Scripts/**/*.js', included: false},
{pattern: 'test/*.js', included: false},
'test/test-main.js'
],
// list of files to exclude
exclude: [],
browsers: ['PhantomJS']
});
};
test/test-main.js
var TEST_REGEXP = /(spec|test)\.js$/i;
var allTestFiles = [];
// Get a list of all the test files to include
Object.keys(window.__karma__.files).forEach(function(file) {
if (TEST_REGEXP.test(file)) {
// Normalize paths to RequireJS module names.
// If you require sub-dependencies of test files to be loaded as-is (requiring file extension)
// then do not normalize the paths
var normalizedTestModule = file.replace(/^\/base\/|\.js$/g, '');
allTestFiles.push(normalizedTestModule);
}
});
require.config({
// Karma serves files under /base, which is the basePath from your config file
baseUrl: '/base',
// example of using a couple path translations (paths), to allow us to refer to different library dependencies, without using relative paths
paths: {
// Put Your requirejs config here
},
// example of using a shim, to load non AMD libraries (such as underscore)
shim: {
},
// dynamically load all test files
deps: allTestFiles,
// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
});
This is example files. Fix it and run
karma run
Instead of
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js"></script>
use
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js"
data-main="Tests/main"></script>
Move test files to Tests directory.
In Tests/main.js use Your requirejs config and run main tests file.
var deps = ['Tests/fakeTest'];
require.config({
baseUrl: '..',
paths: {
'jasmine': ['Scripts/jasmine//jasmine'],
'jasmine-html': ['Scripts/jasmine/jasmine-html'],
'jasmine-boot': ['Scripts/jasmine/boot']
},
// shim: makes external libraries compatible with requirejs (AMD)
shim: {
'jasmine-html': {
deps : ['jasmine']
},
'jasmine-boot': {
deps : ['jasmine', 'jasmine-html']
}
}
});
require(['jasmine-boot'], function () {
require(deps, function(){
//trigger Jasmine
window.onload();
})
});
In index.html run only Tests/main.js file:
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="./Scripts/jasmine/jasmine.css" />
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js" data-main="Tests/main"></script>
</head>
<body>
</body>
</html>

How to use "import" in a polymer element

I'm trying something like the following:
<dom-module id="my-app">
<template> <div>{{data.name}}</div> </template>
<script>
import data from 'data';
class MyApp {
constructor() { ... }
beforeRegister() {
this.is = 'my-app';
this.properties = {
data: {
type: Object,
value: function () {
return data;
},
}
};
}
ready() {}
...
}
</script>
</dom-module>
So, I have here ES6 too, so I constructed the following gulp task:
gulp.task('js', function () {
return gulp.src(['app/**/*.{js,html}'])
.pipe($.sourcemaps.init())
.pipe($.if('*.html', $.crisper())) // Extract JS from .html files
.pipe($.if('*.js', $.babel()))
.pipe($.sourcemaps.write('.'))
.pipe(gulp.dest('.tmp/'))
.pipe(gulp.dest('dist/'));
});
});
This works as long as I don't have the import data from 'data' line. Now I get the following error in the browser:
require is not defined
So, I decided to add browserify to the process just below babel
.pipe($.if('*.js', $.browserify({ debug: true, extensions: ['.js', '.html'] })))
Now I get a transpile error
ParseError: 'import' and 'export' may appear only with 'sourceType: module'
I think I'm close, but I'm now stuck here unfortunately. To reproduce this I've created a github repo here
You can check it out and do:
$> cd polymer-es6
$> npm install
$> bower install
$> gulp js
A bonus question: Why is the constructor not called ? It seems that ready is called instead.

Categories