diff --git a/.travis.yml b/.travis.yml index ecc9a96f..72211b88 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,12 @@ sudo: false language: node_js node_js: - "node" +dist: trusty +addons: + chrome: stable +before_script: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start cache: directories: - phantomjs diff --git a/Makefile b/Makefile index 3d3f2e72..d532c4db 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,4 @@ test: lint dist/fetch.umd.js - ./script/test lint: node_modules/ ./node_modules/.bin/eslint --report-unused-disable-directives *.js test/*.js diff --git a/package.json b/package.json index 5153a7f4..94c31493 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,15 @@ "license": "MIT", "devDependencies": { "abortcontroller-polyfill": "^1.1.9", - "chai": "1.10.0", + "chai": "^4.1.2", "eslint": "^4.19.1", "eslint-plugin-github": "^1.0.0", - "mocha": "2.1.0", - "mocha-phantomjs-core": "2.0.1", + "karma": "^1.7.1", + "karma-chai": "^0.1.0", + "karma-chrome-launcher": "^2.2.0", + "karma-firefox-launcher": "^1.0.1", + "karma-mocha": "^1.3.0", + "mocha": "^4.0.1", "promise-polyfill": "6.0.2", "rollup": "^0.59.1", "url-search-params": "0.6.1" @@ -24,6 +28,7 @@ ], "scripts": { "prepublish": "make dist/fetch.umd.js", - "test": "make" + "pretest": "make", + "test": "karma start ./test/karma.config.js" } } diff --git a/script/server b/script/server deleted file mode 100755 index e89b9c91..00000000 --- a/script/server +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/env node - -var port = Number(process.argv[2] || 3000) - -var fs = require('fs') -var http = require('http'); -var url = require('url'); -var querystring = require('querystring'); - -var routes = { - '/request': function(res, req) { - res.writeHead(200, {'Content-Type': 'application/json'}); - var data = '' - req.on('data', function(c) { data += c }) - req.on('end', function() { - res.end(JSON.stringify({ - method: req.method, - url: req.url, - headers: req.headers, - data: data - })); - }) - }, - '/hello': function(res, req) { - res.writeHead(200, { - 'Content-Type': 'text/plain', - 'X-Request-URL': 'http://' + req.headers.host + req.url - }); - res.end('hi'); - }, - '/hello/utf8': function(res) { - res.writeHead(200, { - 'Content-Type': 'text/plain; charset=utf-8' - }); - // "hello" - var buf = new Buffer([104, 101, 108, 108, 111]); - res.end(buf); - }, - '/hello/utf16le': function(res) { - res.writeHead(200, { - 'Content-Type': 'text/plain; charset=utf-16le' - }); - // "hello" - var buf = new Buffer([104, 0, 101, 0, 108, 0, 108, 0, 111, 0]); - res.end(buf); - }, - '/binary': function(res) { - res.writeHead(200, {'Content-Type': 'application/octet-stream'}); - var buf = new Buffer(256); - for (var i = 0; i < 256; i++) { - buf[i] = i; - } - res.end(buf); - }, - '/redirect/301': function(res) { - res.writeHead(301, {'Location': '/hello'}); - res.end(); - }, - '/redirect/302': function(res) { - res.writeHead(302, {'Location': '/hello'}); - res.end(); - }, - '/redirect/303': function(res) { - res.writeHead(303, {'Location': '/hello'}); - res.end(); - }, - '/redirect/307': function(res) { - res.writeHead(307, {'Location': '/hello'}); - res.end(); - }, - '/redirect/308': function(res) { - res.writeHead(308, {'Location': '/hello'}); - res.end(); - }, - '/boom': function(res) { - res.writeHead(500, {'Content-Type': 'text/plain'}); - res.end('boom'); - }, - '/empty': function(res) { - res.writeHead(204); - res.end(); - }, - '/slow': function(res) { - setTimeout(function() { - res.writeHead(200); - res.end(); - }, 100); - }, - '/error': function(res) { - res.destroy(); - }, - '/form': function(res) { - res.writeHead(200, {'Content-Type': 'application/x-www-form-urlencoded'}); - res.end('number=1&space=one+two&empty=&encoded=a%2Bb&'); - }, - '/json': function(res) { - res.writeHead(200, {'Content-Type': 'application/json'}); - res.end(JSON.stringify({name: 'Hubot', login: 'hubot'})); - }, - '/json-error': function(res) { - res.writeHead(200, {'Content-Type': 'application/json'}); - res.end('not json {'); - }, - '/cookie': function(res, req) { - var setCookie, cookie - var params = querystring.parse(url.parse(req.url).query); - if (params.name && params.value) { - setCookie = [params.name, params.value].join('='); - } - if (params.name) { - cookie = querystring.parse(req.headers['cookie'], '; ')[params.name]; - } - res.writeHead(200, { - 'Content-Type': 'text/plain', - 'Set-Cookie': setCookie || '' - }); - res.end(cookie); - }, - '/headers': function(res) { - res.writeHead(200, { - 'Date': 'Mon, 13 Oct 2014 21:02:27 GMT', - 'Content-Type': 'text/html; charset=utf-8' - }); - res.end(); - } -}; - -var types = { - js: 'application/javascript', - css: 'text/css', - html: 'text/html', - txt: 'text/plain' -}; - -server = http.createServer(function(req, res) { - var pathname = url.parse(req.url).pathname; - var route = routes[pathname]; - if (route) { - route(res, req); - } else { - if (pathname == '/') pathname = '/test/test.html' - fs.readFile(__dirname + '/..' + pathname, function(err, data) { - if (err) { - res.writeHead(404, {'Content-Type': types.txt}); - res.end('Not Found'); - } else { - var ext = (pathname.match(/\.([^\/]+)$/) || [])[1] - res.writeHead(200, {'Content-Type': types[ext] || types.txt}); - res.end(data); - } - }); - } -}); - -console.warn("Started test server on localhost:" + port); -server.listen(port); - diff --git a/test/karma.config.js b/test/karma.config.js new file mode 100644 index 00000000..600cdcb4 --- /dev/null +++ b/test/karma.config.js @@ -0,0 +1,39 @@ +const serverEndpoints = require('./server') + +module.exports = function(config) { + config.set({ + frameworks: ['mocha', 'chai'], + client: { + mocha: { + ui: 'tdd' + } + }, + files: ['../dist/fetch.umd.js', 'test.js'], + reporters: ['progress'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + browsers: ['ChromeHeadlessNoSandbox', 'FirefoxHeadless'], + autoWatch: false, + singleRun: true, + concurrency: Infinity, + customLaunchers: { + ChromeHeadlessNoSandbox: { + base: 'ChromeHeadless', + flags: ['--no-sandbox'] + }, + FirefoxHeadless: { + base: 'Firefox', + flags: ['-headless'], + displayName: 'HeadlessFirefox' + } + }, + beforeMiddleware: ['custom'], + plugins: [ + 'karma-*', + { + 'middleware:custom': ['value', serverEndpoints] + } + ] + }) +} diff --git a/test/server.js b/test/server.js new file mode 100644 index 00000000..10036715 --- /dev/null +++ b/test/server.js @@ -0,0 +1,136 @@ +/* eslint-env node */ + +const url = require('url') +const querystring = require('querystring') + +const routes = { + '/request': function(res, req) { + res.writeHead(200, {'Content-Type': 'application/json'}) + var data = '' + req.on('data', function(c) { + data += c + }) + req.on('end', function() { + res.end( + JSON.stringify({ + method: req.method, + url: req.url, + headers: req.headers, + data: data + }) + ) + }) + }, + '/hello': function(res, req) { + res.writeHead(200, { + 'Content-Type': 'text/plain', + 'X-Request-URL': 'http://' + req.headers.host + req.url + }) + res.end('hi') + }, + '/hello/utf8': function(res) { + res.writeHead(200, { + 'Content-Type': 'text/plain; charset=utf-8' + }) + // "hello" + var buf = new Buffer([104, 101, 108, 108, 111]) + res.end(buf) + }, + '/hello/utf16le': function(res) { + res.writeHead(200, { + 'Content-Type': 'text/plain; charset=utf-16le' + }) + // "hello" + var buf = new Buffer([104, 0, 101, 0, 108, 0, 108, 0, 111, 0]) + res.end(buf) + }, + '/binary': function(res) { + res.writeHead(200, {'Content-Type': 'application/octet-stream'}) + var buf = new Buffer(256) + for (var i = 0; i < 256; i++) { + buf[i] = i + } + res.end(buf) + }, + '/redirect/301': function(res) { + res.writeHead(301, {Location: '/hello'}) + res.end() + }, + '/redirect/302': function(res) { + res.writeHead(302, {Location: '/hello'}) + res.end() + }, + '/redirect/303': function(res) { + res.writeHead(303, {Location: '/hello'}) + res.end() + }, + '/redirect/307': function(res) { + res.writeHead(307, {Location: '/hello'}) + res.end() + }, + '/redirect/308': function(res) { + res.writeHead(308, {Location: '/hello'}) + res.end() + }, + '/boom': function(res) { + res.writeHead(500, {'Content-Type': 'text/plain'}) + res.end('boom') + }, + '/empty': function(res) { + res.writeHead(204) + res.end() + }, + '/slow': function(res) { + setTimeout(function() { + res.writeHead(200) + res.end() + }, 100) + }, + '/error': function(res) { + res.destroy() + }, + '/form': function(res) { + res.writeHead(200, {'Content-Type': 'application/x-www-form-urlencoded'}) + res.end('number=1&space=one+two&empty=&encoded=a%2Bb&') + }, + '/json': function(res) { + res.writeHead(200, {'Content-Type': 'application/json'}) + res.end(JSON.stringify({name: 'Hubot', login: 'hubot'})) + }, + '/json-error': function(res) { + res.writeHead(200, {'Content-Type': 'application/json'}) + res.end('not json {') + }, + '/cookie': function(res, req) { + var setCookie, cookie + var params = querystring.parse(url.parse(req.url).query) + if (params.name && params.value) { + setCookie = [params.name, params.value].join('=') + } + if (params.name) { + cookie = querystring.parse(req.headers['cookie'], '; ')[params.name] + } + res.writeHead(200, { + 'Content-Type': 'text/plain', + 'Set-Cookie': setCookie || '' + }) + res.end(cookie) + }, + '/headers': function(res) { + res.writeHead(200, { + Date: 'Mon, 13 Oct 2014 21:02:27 GMT', + 'Content-Type': 'text/html; charset=utf-8' + }) + res.end() + } +} + +module.exports = function(req, res, next) { + const path = url.parse(req.url).pathname + const route = routes[path] + if (route) { + route(res, req) + } else { + next() + } +}