Situation : I am currently using QUnit to test a project in TypeScript/Javascript and everything works fine when I'm running them in a browser.
Problem : I'm trying to use grunt to run the QUnit tests in a headless mode (I need it for continuous integration testing) and the tests don't run properly.
Configuration
Here's how I have things currently set up :
Gruntfile.js
package.json
src/
- Ts source files
test/
- config.js
- Test.ts
- Test.js
- test.html
Gruntfile.js
/*global module:false*/
module.exports = function(grunt) {
grunt.initConfig({
connect: {
server: {
options: {
port: 8000,
base: '.'
}
}
},
qunit: {
all: {
options: {
urls: [
'http://localhost:8000/test/test.html'
]
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.registerTask('test', ['connect', 'qunit']);
};
package.json
{
// Name, version, description, repo and author fields...
"engines": {
"node": ">= 0.10.0"
},
"devDependencies": {
"grunt": "~0.4.5",
"grunt-contrib-watch": "~0.6.1",
"grunt-contrib-connect": "~0.9.0",
"grunt-contrib-qunit": "~0.5.2"
}
}
And then I have a .travis.yml file to run all of this. I don't know if it's really important because the tests don't run either in travis or in my local environment, but here is it anyways :
language: node_js
node_js:
- "0.11"
- "0.10"
before_install:
- "npm install grunt --save-dev"
- "npm install -g grunt-cli"
install:
- "npm install"
- "npm install -g typescript"
script:
- "tsc --module amd --target ES5 ./src/*.ts"
- "grunt test --verbose --force"
And here's the part that errors in the travis build : http://puu.sh/eKpWj/35614680e1.png
(I currently have ~20 assertions that pass when I'm running them in a browser. Also, the typescript compilation runs ok.)
Edit : And as someone asked fot it, here's the content of the Test.html file : http://pastebin.com/LN3igmjc
Edit 2 : Here's also the content of config.js :
var require = {
baseUrl: "../src/"
};
Actually I managed to make it work.
I changed two things :
I wasn't compiling the tests, as tsc --module amd --target ES5 ./src/*.ts compiled the files in the src folder, and the test files were in the test folder. I'm bashing myself for this one...
So I simply added tsc --module amd --target ES5 ./test/*.ts in the .travis.yml file
The biggest problem was that the QUnit tests were trying to start before the work of require.js. The solution I used was to tell QUnit to not start tests automatically by using QUnit.config.autostart = false; and make them start when I want with QUnit.start(); I placed this start() at the end of my Test.js file so that the tests start only when QUnit is done loading.
Related
I am very new to TypeScript and I am trying out many things and got stuck with external modules after compilation.
I started with simple TypeScript project in Visual Studio Code set to target ES2015 and module to es2015 (because I want to use native stuff as much as possible) and I wanted to try Strongly Type Events (STE) which I installed using npm.
By changing module resolution to node and setting baseUrl in tsconfig.json, TypeScript has no problem in using STE with non-relative import:
import { SimpleEventDispatcher } from "ste-simple-events";
However, when I compile TypeScript, resulting JavaScript file has exact same import statement and when loading html which is including this module, I get an error that module cannot be found.
I can not figure out how to solve this.
Should TypeScript somehow change import statement to exact location of STE?
Perhaps, but TypeScript team says TypeScript compilation will never change code in import statements.
Or should I somehow compile external modules as well, so that they get included in output?
Or should default module resolution in ES2015 standard implemented in browsers do the job - for which I have no idea how it works and how should external ES2015 modules be imported in JavaScript?
Any help or a nudge in the right direction would be greatly appreciated.
Thanks,
Mario
For any TypeScript beginner scratching their head over this, the answer is called JavaScript bundlers.
Since I am using ES6, I opted for RollupJs bundler combined with following plugins (use them in this order):
rollup-plugin-resolve - required to resolve node_modules
rollup-plugin-commonjs - required to transpile CommonJS modules in node_modules to ES6
rollup-plugin-typescript2 - optional, you can have it in the process or you can use tsc manually before you run rollup - just make sure you use version 2 (first version is not maintained any more)
rollup-plugin-terser - minifier and obfuscator
You can install all of those with npm:
npm install rollup rollup-plugin-resolve rollup-plugin-commonjs rollup-plugin-typescript2 rollup-plugin-terser
Add rollup.config.js to the root of your project, mine looked like this:
import typescript from "rollup-plugin-typescript2"
import commonjs from "rollup-plugin-commonjs";
import resolve from "rollup-plugin-node-resolve";
import { terser } from "rollup-plugin-terser";
import pkg from "./package.json"
export default {
input: "./wwwroot/js/svgts.js",
output: [
{
file: pkg.module,
format: "esm",
},
],
external: [
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.peerDependencies || {}),
], plugins: [
resolve({
mainFields: ["module"], // Default: ["module", "main"]
}),
commonjs({
include: "node_modules/**"
}),
typescript({
typescript: require("typescript"),
tsconfig: "./tsconfig.json"
}),
(process.env.NODE_ENV === "production" && terser({
mangle: { reserved: ['svg'] }
}))
],
}
Rollup supports environment variables which I use here with line:
process.env.NODE_ENV === "production"
This allows you to create npm scripts in package.json to easily include minification or not, for example:
"scripts": {
"tsc": "tsc",
"tsc:w": "tsc -w",
"lite": "lite-server",
"rollup": "rollup -c",
"rollupw": "rollup -cw",
"start": "concurrently \"npm run rollupw\" \"npm run lite\"",
"startprod": "NODE_ENV=production concurrently \"npm run rollupw\" \"npm run lite\"",
"production": "NODE_ENV=production npm run rollup"
},
Then you can run in terminal npm run production for instance to build minified bundle.
You can find more details on GitHub of each project.
I have Jest installed on my machine and typing jest from terminal results in tests from parent folers also getting executed. I want to run tests only from the current folder.
For e.g. if I go to c:/dev/app in terminal and type some-jest-command, it should only run files with .test.js present in the app folder. Currently, running jest command from app folder runs tests in parent folders too, which is not my desired behaviour.
By default, Jest will try to recursively test everything from whatever folder package.json is located.
Let's say you're in c:/dev/app, and your package.json is in c:. If your basic command to invoke Jest is npm test, then try with run npm test dev/app.
If you want to run the tests from a specific folder user the --testPathPattern jest flag. When setting up the npm script add the path to the folder as well. In your package.json add the flag in you npm scripts. Check the bellow code for an example.
"scripts": {
....
"test:unit": "jest --testPathPattern=src/js/tests/unit-tests",
"test:integration": "jest --testPathPattern=src/js/tests/integration"
....
},
If you want to watch as well for changes, use the watch flag:
{
...
"test:unit": "jest --watch --testPathPattern=src/js/tests/unit-tests",
...
}
After that open, the command line, change the directory where your project is and run the unit test.
npm run test:unit
or integration tests.
npm run test:integration
To only run testing in a specific directory and to coerce Jest to read only certain type of files(my example: 'ExampleComponent.test.js' with new Jest version #24.9.0 you must write exact "testMatch" in jest.config.json || package.json in "jest" part next "testMatch": [ "<rootDir>/src/__tests__/**/*.test.js" ],
This testMatch in my case hits all files with the prefix .test.js in tests/subdirectories/ and skips all other files like 'setupTest.js' and other .js files in 'mocks' subdirectory which is placed inside of 'tests' directory,so,my 'jest.config.json' looks like this
{
"setupFiles": [
"raf/polyfill",
"<rootDir>/setupTests.js"
],
"snapshotSerializers": [
"enzyme-to-json/serializer"
],
"moduleNameMapper": {
"^.+\\.(css|less|scss|sass)$": "identity-obj-proxy"
},
"testMatch": [
"<rootDir>/src/__tests__/**/*.test.js"
]
}
Just adapt to your needs 'testMatch' regex.
A little note: This is for jest#24.9.0 && enzyme#3.10.0 if it matters to anyone.
I hope it will be useful to someone, cheers all.
--package.json
"scripts": {
"test": "jest"
}
--jest.config.js
module.exports = {
"testMatch": [
"<rootDir>/tests/unit/*.test.js"
]
}
From the root of your project, you can run jest <substring of files> and it will only run the test files which have the substring you added.
$ jest /libs/components
> [PASS] /libs/components/button.tsx
yarn:
yarn test nameoffolder
npm:
npm test nameoffolder
For example, if you have a folder named widget and you only want to run the tests in the widget folder you would run this command.
yarn:
yarn test widget
npm:
npm test widget
Details:
I have a directory structure like this.
myapp
root-one
-web
-app
-tests
root-two
-grunt
node_modules
.bin
intern-runner
selenium-standalone
intern
selenium-standalone
grunt-shell
Gruntfile.js
From my grunt file I am using shell npm to launch the selenium standalone server like so..
shell: {
intern : {
options: { stdout: true},
command: [
"cd node_modules/.bin",
"start selenium-standalone start",
"intern-runner config=tests/intern basePath=../../../../root-one/web"
].join('&&')
}
}
}
grunt.registerTask('intern', ['shell:intern']);
After running my grunt command grunt intern, selenium starts but I get the following error from intern-runner.
Error: Failed to load module tests/intern
from C:/myapp/root-two/grunt/node_modules/.bin/tests/intern.js
Now because I set the path (or so I thought) using basePath=../../../../root-one/web. I would have expected it to try to execute from C:/myapp/root-one/web/tests/intern.js instead of remaining in the .bin directory.
Question:
So really the question is. What is the proper way to set the basePath for intern-runner on the command line? Because this doesn't seem to work. And according to the docs...
You can also specify any valid configuration option as an argument on
the command-line.
Which leads me to believe I probably just have the syntax wrong.
Sounds like this doesn't quite work the way I was expecting it to. As discussed here: https://github.com/theintern/intern/issues/449
So for now the work around was to just install intern globally vs trying to run it locally out of my project. So instead I did..
npm install intern -g
With my project structure like so...
myapp
root-one
-web
-app
-tests
root-two
-grunt
node_modules
.bin
selenium-standalone
selenium-standalone
grunt-shell
Gruntfile.js
Basically just removed intern because it is installed globally now. Which is located at the following on windows..
C:\Users\user\AppData\Roaming\npm\node_modules\intern
And my Gruntfile has been changed too the following. After starting selenium I change directory back to the appropriate location to run the intern-runner command.
shell: {
intern : {
options: { stdout: true},
command: [
"cd node_modules/.bin",
"start selenium-standalone start",
"cd ../../../../root-one/web",
"intern-runner config=tests/intern
].join('&&')
}
}
}
grunt.registerTask('intern', ['shell:intern']);
I am trying to use the autoprefixer css post-processor. I am following a tutorial and have installed npm. Using a npm, I then installed grunt and autoprefixer inside my project root using that package.json file: https://github.com/nDmitry/grunt-autoprefixer/blob/master/package.json
Following the tutorial, I then created this Gruntfile.js inside my project root:
module.exports = function (grunt) {
grunt.initConfig({
autoprefixer: {
dist: {
files: {
'build/style.css': 'style.css'
}
}
},
watch: {
styles: {
files: ['style.css'],
tasks: ['autoprefixer']
}
}
});
grunt.loadNpmTasks('grunt-autoprefixer');
grunt.loadNpmTasks('grunt-contrib-watch');
};
After that the tutorial advises to use Grunt Watch using
./node_modules/.bin/grunt watch
Which results in
-bash: ./node_modules/.bin/grunt: No such file or directory
I also tried to navigate to the grunt folder inside my project, then it says
-bash: node_modules/grunt: is a directory
I also have a node_modules folder directly in my local user folder, but addressing that folder grunt also just tells me that its a folder.
Pleaser help me, why is this not working? I am willing to really learn grunt, but I am not even able to get started using the getting started guide...
Have you installed the grunt-cli? (npm install grunt-cli -g) What happens when you run grunt in your project root? The command you should be running is simply grunt watch, in your project root.
Edit: Your project root must also have a package.json file in which you define your development dependencies; e.g.
{
"name":"yourprojectname",
"version":"0.0.1",
"devDependencies":{
"grunt":"*",
"grunt-contrib-watch":"*",
"grunt-autoprefixer":"*"
}
}
if there is acutally a space in the executable name you need to put it in quotes
"./node_modules/.bin/grunt watch"
otherwise linux will run "./node_modules/.bin/grunt" with watch as a flag.
if that still doesn't work,
could be a few problems, either your ldconfig isn't updated, the files aren't set to executable, or the user you are trying to execute the command with doesn't have permission.
first try running "ldconfig" (just type and run it)
more info here
http://www.cyberciti.biz/tips/linux-shared-library-management.html
chmod -x the files to make them executable.
any luck?
I'm not sure to use Travis-CI for my client-side JavaScript library or not, because it compiles with NodeJs on Travis-CI servers.
I want to know is this a good approach to use some kind of continuous integration such as Travis-CI for client-side libraries or not?
Yes of course you should use continous integration with client side libraries.
I personally use PhantomJS (headless webkit browser) which is already installed in Travis-CI. I think this is the better option for client-side stuff than NodeJs.
If you use Grunt, it gets even easier to use, all you need is a simple Gruntfile.js file, your tests that run in browser (I use QUnit), and a simple .travis.yml
Gruntfile.js:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
qunit: {
files: ['test/index.html']
}
});
// Load plugin
grunt.loadNpmTasks('grunt-contrib-qunit');
// Task to run tests
grunt.registerTask('test', 'qunit');
};
.travis.yml:
before_script:
- sudo npm install -g grunt
script: grunt test --verbose --force
You can see it in action at one of my projects (source on GitHub).
I started with the answer from Odi and moved to gulp to get it working. If you specify node_js as your language in your travis file, travis will automatically run
npm install
followed by
npm test
The first will install any devDependencies specified in a package.json file, the second will run the script named "test" also from package.json. Below you'll find the three files I needed to have in the top level of my repo for travis to run a single qunit suite.
.travis.yml
language: node_js
node_js:
- "0.10"
gulpfile.js
var gulp = require('gulp'),
qunit = require('gulp-qunit');
gulp.task('default', function() {
return gulp.src('./tests/unit/unittests_nupic-js.html')
.pipe(qunit());
});
package.json
{
"name": "nupic-js",
"version": "0.0.1",
"description": "JavaScript port of NuPIC",
"license": "GPL-3.0",
"repository": "iandanforth/nupic-js",
"bugs": { "url" : "http://github.com/iandanforth/nupic-js/issues"
},
"author": {
"name": "Ian Danforth",
"email": "iandanforth#gmail.com"
},
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"test": "gulp"
},
"keywords": [
"numenta",
"nupic",
"machine learning"
],
"devDependencies": {
"gulp-qunit": "~0.2.1",
"gulp-util": "~2.2.14",
"gulp": "~3.5.1"
}
}
Odi's answer updated and using npm to resolve dependencies:
.travis.yml
language: node_js
node_js:
- "6"
.Gruntfile.js
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
qunit: {
files: ['./test/qunit.html']
}
});
// Load plugin
grunt.loadNpmTasks('grunt-contrib-qunit');
// Task to run tests
grunt.registerTask('test', 'qunit');
};
Package.json (relevant parts)
"devDependencies": {
"grunt": "^1.0.1",
"grunt-contrib-qunit": "^1.3.0"
},
"scripts": {
"test": "grunt test"
}
You can try the configuration locally by running npm install and then npm test.
I found this example. Quite comprehensive!
https://github.com/jonkemp/gulp-qunit
run:
npm install
gulp test
It also has tasks for lint watching files, coverage reports and more.