提交 4e00ced5 编写于 作者: M Mislav Marohnić

Merge pull request #258 from mislav/exercise-polyfill

Exercise both polyfill and native `fetch` in test suite
...@@ -17,5 +17,8 @@ ...@@ -17,5 +17,8 @@
"esnext": true, "esnext": true,
"eqnull": true, "eqnull": true,
"browser": true, "browser": true,
"worker": true "worker": true,
"globals": {
"JSON": false
}
} }
...@@ -13,10 +13,10 @@ ...@@ -13,10 +13,10 @@
"devDependencies": { "devDependencies": {
"bower": "1.3.8", "bower": "1.3.8",
"chai": "1.10.0", "chai": "1.10.0",
"jshint": "2.5.2", "jshint": "2.8.0",
"mocha-phantomjs": "3.5.2", "mocha-phantomjs": "3.5.2",
"mocha": "2.1.0", "mocha": "2.1.0",
"phantomjs": "1.9.13" "phantomjs": "1.9.19"
}, },
"files" : [ "files" : [
"LICENSE", "LICENSE",
......
...@@ -12,5 +12,16 @@ node ./script/server $port &>/dev/null & ...@@ -12,5 +12,16 @@ node ./script/server $port &>/dev/null &
server_pid=$! server_pid=$!
trap "kill $server_pid" INT EXIT trap "kill $server_pid" INT EXIT
node ./node_modules/.bin/mocha-phantomjs -s localToRemoteUrlAccessEnabled=true -s webSecurityEnabled=false "http://localhost:$port/test/test.html" STATUS=0
node ./node_modules/.bin/mocha-phantomjs -s localToRemoteUrlAccessEnabled=true -s webSecurityEnabled=false "http://localhost:$port/test/test-worker.html"
run() {
node ./node_modules/.bin/mocha-phantomjs \
-s localToRemoteUrlAccessEnabled=true \
-s webSecurityEnabled=false \
"$@" || STATUS=$?
}
run "http://localhost:$port/"
run "http://localhost:$port/test/test-worker.html"
exit $STATUS
...@@ -25,7 +25,7 @@ job="$(./script/saucelabs-api --raw "js-tests" <<JSON ...@@ -25,7 +25,7 @@ job="$(./script/saucelabs-api --raw "js-tests" <<JSON
"tags": ["$TRAVIS_PULL_REQUEST", "$TRAVIS_BRANCH"], "tags": ["$TRAVIS_PULL_REQUEST", "$TRAVIS_BRANCH"],
"tunnel-identifier": "$TRAVIS_JOB_NUMBER", "tunnel-identifier": "$TRAVIS_JOB_NUMBER",
"platforms": [["$SAUCE_PLATFORM", "$SAUCE_BROWSER", "$SAUCE_VERSION"]], "platforms": [["$SAUCE_PLATFORM", "$SAUCE_BROWSER", "$SAUCE_VERSION"]],
"url": "http://localhost:$port/test/test.html", "url": "http://localhost:$port/",
"framework": "mocha" "framework": "mocha"
} }
JSON JSON
......
...@@ -123,12 +123,13 @@ var types = { ...@@ -123,12 +123,13 @@ var types = {
txt: 'text/plain' txt: 'text/plain'
}; };
http.createServer(function(req, res) { server = http.createServer(function(req, res) {
var pathname = url.parse(req.url).pathname; var pathname = url.parse(req.url).pathname;
var route = routes[pathname]; var route = routes[pathname];
if (route) { if (route) {
route(res, req); route(res, req);
} else { } else {
if (pathname == '/') pathname = '/test/test.html'
fs.readFile(__dirname + '/..' + pathname, function(err, data) { fs.readFile(__dirname + '/..' + pathname, function(err, data) {
if (err) { if (err) {
res.writeHead(404, {'Content-Type': types.txt}); res.writeHead(404, {'Content-Type': types.txt});
...@@ -140,4 +141,8 @@ http.createServer(function(req, res) { ...@@ -140,4 +141,8 @@ http.createServer(function(req, res) {
} }
}); });
} }
}).listen(port); });
console.warn("Started test server on localhost:" + port);
server.listen(port);
{ {
"curly": true, "extends": "../.jshintrc",
"eqeqeq": true, "es3": false,
"immed": true, "strict": false,
"indent": 2,
"latedef": true,
"newcap": true,
"noarg": true,
"quotmark": true,
"undef": true,
"unused": true,
"trailing": true,
"asi": true,
"boss": true,
"esnext": true,
"sub": true, "sub": true,
"eqnull": true,
"browser": true,
"worker": true,
"globals": { "globals": {
"fetch": false, "fetch": false,
"Headers": false, "Headers": false,
...@@ -26,6 +12,7 @@ ...@@ -26,6 +12,7 @@
"chai": false, "chai": false,
"suite": false, "suite": false,
"setup": false, "setup": false,
"suiteSetup": false,
"test": false, "test": false,
"assert": false "assert": false
} }
......
...@@ -3,16 +3,16 @@ ...@@ -3,16 +3,16 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Fetch Worker Tests</title> <title>Fetch Worker Tests</title>
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" /> <link rel="stylesheet" href="/node_modules/mocha/mocha.css" />
</head> </head>
<body> <body>
<div id="mocha"></div> <div id="mocha"></div>
<script src="../node_modules/mocha/mocha.js"></script> <script src="/node_modules/mocha/mocha.js"></script>
<script> <script>
mocha.setup('tdd') mocha.setup('tdd')
var worker = new Worker('worker.js') var worker = new Worker('/test/worker.js')
worker.addEventListener('message', function(e) { worker.addEventListener('message', function(e) {
switch (e.data.name) { switch (e.data.name) {
......
...@@ -3,21 +3,24 @@ ...@@ -3,21 +3,24 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Fetch Tests</title> <title>Fetch Tests</title>
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" /> <link rel="stylesheet" href="/node_modules/mocha/mocha.css" />
</head> </head>
<body> <body>
<div id="mocha"></div> <div id="mocha"></div>
<script src="../node_modules/chai/chai.js"></script> <script src="/node_modules/chai/chai.js"></script>
<script src="../node_modules/mocha/mocha.js"></script> <script src="/node_modules/mocha/mocha.js"></script>
<script> <script>
mocha.setup('tdd') if (self.mocha && mocha.setup) {
self.assert = chai.assert mocha.setup('tdd')
self.assert = chai.assert
} else {
document.write('<p>Error: please run <code>make</code> to install dependencies and try again.</p>')
}
</script> </script>
<script src="../bower_components/es6-promise/promise.js"></script> <script src="/bower_components/es6-promise/promise.js"></script>
<script src="../fetch.js"></script> <script src="/test/test.js"></script>
<script src="/fetch.js"></script>
<script src="test.js"></script>
<script> <script>
if (self.mochaPhantomJS) { if (self.mochaPhantomJS) {
......
var support = {
blob: 'FileReader' in self && 'Blob' in self && (function() {
try {
new Blob()
return true
} catch(e) {
return false
}
})(),
formData: 'FormData' in self,
arrayBuffer: 'ArrayBuffer' in self,
patch: !/PhantomJS/.test(navigator.userAgent),
permanentRedirect: !/PhantomJS|Trident/.test(navigator.userAgent)
}
function readBlobAsText(blob) { function readBlobAsText(blob) {
if ('FileReader' in self) { if ('FileReader' in self) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
...@@ -37,6 +52,40 @@ function readBlobAsBytes(blob) { ...@@ -37,6 +52,40 @@ function readBlobAsBytes(blob) {
} }
} }
var native = {}
var keepGlobals = ['fetch', 'Headers', 'Request', 'Response']
var exercise = ['polyfill']
// If native fetch implementation exists, save it and allow it to be replaced
// by the polyfill. Native implementation will be exercised additionally.
if (self.fetch) {
keepGlobals.forEach(function(name) {
native[name] = self[name]
})
self.fetch = undefined
exercise.push('native')
}
var slice = Array.prototype.slice
function featureDependent(testOrSuite, condition) {
(condition ? testOrSuite : testOrSuite.skip).apply(this, slice.call(arguments, 2))
}
exercise.forEach(function(exerciseMode) {
suite(exerciseMode, function() {
if (exerciseMode === 'native') {
suiteSetup(function() {
keepGlobals.forEach(function(name) {
self[name] = native[name]
})
})
}
var nativeChrome = /Chrome\//.test(navigator.userAgent) && exerciseMode === 'native'
var nativeFirefox = /Firefox\//.test(navigator.userAgent) && exerciseMode === 'native'
var polyfillFirefox = /Firefox\//.test(navigator.userAgent) && exerciseMode === 'polyfill'
test('resolves promise on 500 error', function() { test('resolves promise on 500 error', function() {
return fetch('/boom').then(function(response) { return fetch('/boom').then(function(response) {
assert.equal(response.status, 500) assert.equal(response.status, 500)
...@@ -148,7 +197,7 @@ suite('Headers', function() { ...@@ -148,7 +197,7 @@ suite('Headers', function() {
headers.set({field: 'value'}, 'application/json'); headers.set({field: 'value'}, 'application/json');
}, TypeError) }, TypeError)
}) })
test('is iterable with forEach', function() { featureDependent(test, !nativeFirefox, 'is iterable with forEach', function() {
var headers = new Headers() var headers = new Headers()
headers.append('Accept', 'application/json') headers.append('Accept', 'application/json')
headers.append('Accept', 'text/plain') headers.append('Accept', 'text/plain')
...@@ -164,7 +213,7 @@ suite('Headers', function() { ...@@ -164,7 +213,7 @@ suite('Headers', function() {
assert.deepEqual({key: 'accept', value: 'text/plain', object: headers}, results[1]) assert.deepEqual({key: 'accept', value: 'text/plain', object: headers}, results[1])
assert.deepEqual({key: 'content-type', value: 'text/html', object: headers}, results[2]) assert.deepEqual({key: 'content-type', value: 'text/html', object: headers}, results[2])
}) })
test('forEach accepts second thisArg argument', function() { featureDependent(test, !nativeFirefox, 'forEach accepts second thisArg argument', function() {
var headers = new Headers({'Accept': 'application/json'}) var headers = new Headers({'Accept': 'application/json'})
var thisArg = 42 var thisArg = 42
headers.forEach(function() { headers.forEach(function() {
...@@ -205,7 +254,7 @@ suite('Request', function() { ...@@ -205,7 +254,7 @@ suite('Request', function() {
}) })
}) })
;(ArrayBuffer in self ? test : test.skip)('sends ArrayBuffer body', function() { featureDependent(test, support.arrayBuffer, 'sends ArrayBuffer body', function() {
var text = 'name=Hubot' var text = 'name=Hubot'
var buf = new ArrayBuffer(text.length) var buf = new ArrayBuffer(text.length)
...@@ -294,7 +343,7 @@ suite('Request', function() { ...@@ -294,7 +343,7 @@ suite('Request', function() {
}) })
}) })
;(/Chrome\//.test(navigator.userAgent) && !fetch.polyfill ? test.skip : test)('construct with used Request body', function() { featureDependent(test, !nativeChrome, 'construct with used Request body', function() {
var request1 = new Request('https://fetch.spec.whatwg.org/', { var request1 = new Request('https://fetch.spec.whatwg.org/', {
method: 'post', method: 'post',
body: 'I work out' body: 'I work out'
...@@ -324,7 +373,7 @@ suite('Request', function() { ...@@ -324,7 +373,7 @@ suite('Request', function() {
}) })
}) })
;(/Chrome\//.test(navigator.userAgent) && !fetch.polyfill ? test.skip : test)('clone with used Request body', function() { featureDependent(test, !nativeChrome, 'clone with used Request body', function() {
var req = new Request('https://fetch.spec.whatwg.org/', { var req = new Request('https://fetch.spec.whatwg.org/', {
method: 'post', method: 'post',
body: 'I work out' body: 'I work out'
...@@ -339,7 +388,7 @@ suite('Request', function() { ...@@ -339,7 +388,7 @@ suite('Request', function() {
// https://fetch.spec.whatwg.org/#concept-bodyinit-extract // https://fetch.spec.whatwg.org/#concept-bodyinit-extract
suite('BodyInit extract', function() { suite('BodyInit extract', function() {
;(Request.prototype.blob ? suite : suite.skip)('type Blob', function() { featureDependent(suite, support.blob, 'type Blob', function() {
test('consume as blob', function() { test('consume as blob', function() {
var request = new Request(null, {method: 'POST', body: new Blob(['hello'])}) var request = new Request(null, {method: 'POST', body: new Blob(['hello'])})
return request.blob().then(readBlobAsText).then(function(text) { return request.blob().then(readBlobAsText).then(function(text) {
...@@ -363,7 +412,7 @@ suite('Request', function() { ...@@ -363,7 +412,7 @@ suite('Request', function() {
}) })
}) })
;(Request.prototype.blob ? test : test.skip)('consume as blob', function() { featureDependent(test, support.blob, 'consume as blob', function() {
var request = new Request(null, {method: 'POST', body: 'hello'}) var request = new Request(null, {method: 'POST', body: 'hello'})
return request.blob().then(readBlobAsText).then(function(text) { return request.blob().then(readBlobAsText).then(function(text) {
assert.equal(text, 'hello') assert.equal(text, 'hello')
...@@ -377,7 +426,7 @@ suite('Request', function() { ...@@ -377,7 +426,7 @@ suite('Request', function() {
suite('Response', function() { suite('Response', function() {
// https://fetch.spec.whatwg.org/#concept-bodyinit-extract // https://fetch.spec.whatwg.org/#concept-bodyinit-extract
suite('BodyInit extract', function() { suite('BodyInit extract', function() {
;(Response.prototype.blob ? suite : suite.skip)('type Blob', function() { featureDependent(suite, support.blob, 'type Blob', function() {
test('consume as blob', function() { test('consume as blob', function() {
var response = new Response(new Blob(['hello'])) var response = new Response(new Blob(['hello']))
return response.blob().then(readBlobAsText).then(function(text) { return response.blob().then(readBlobAsText).then(function(text) {
...@@ -401,7 +450,7 @@ suite('Response', function() { ...@@ -401,7 +450,7 @@ suite('Response', function() {
}) })
}) })
;(Response.prototype.blob ? test : test.skip)('consume as blob', function() { featureDependent(test, support.blob, 'consume as blob', function() {
var response = new Response('hello') var response = new Response('hello')
return response.blob().then(readBlobAsText).then(function(text) { return response.blob().then(readBlobAsText).then(function(text) {
assert.equal(text, 'hello') assert.equal(text, 'hello')
...@@ -450,7 +499,7 @@ suite('Response', function() { ...@@ -450,7 +499,7 @@ suite('Response', function() {
}) })
}) })
;(Response.prototype.arrayBuffer ? test : test.skip)('clone blob response', function() { featureDependent(test, support.blob, 'clone blob response', function() {
return fetch('/binary').then(function(response) { return fetch('/binary').then(function(response) {
return Promise.all([response.clone().arrayBuffer(), response.arrayBuffer()]).then(function(bufs){ return Promise.all([response.clone().arrayBuffer(), response.arrayBuffer()]).then(function(bufs){
bufs.forEach(function(buf){ bufs.forEach(function(buf){
...@@ -483,7 +532,7 @@ suite('Response', function() { ...@@ -483,7 +532,7 @@ suite('Response', function() {
// https://fetch.spec.whatwg.org/#body-mixin // https://fetch.spec.whatwg.org/#body-mixin
suite('Body mixin', function() { suite('Body mixin', function() {
;(Response.prototype.arrayBuffer ? suite : suite.skip)('arrayBuffer', function() { featureDependent(suite, support.blob, 'arrayBuffer', function() {
test('resolves arrayBuffer promise', function() { test('resolves arrayBuffer promise', function() {
return fetch('/hello').then(function(response) { return fetch('/hello').then(function(response) {
return response.arrayBuffer() return response.arrayBuffer()
...@@ -530,7 +579,6 @@ suite('Body mixin', function() { ...@@ -530,7 +579,6 @@ suite('Body mixin', function() {
test('rejects arrayBuffer promise after body is consumed', function() { test('rejects arrayBuffer promise after body is consumed', function() {
return fetch('/hello').then(function(response) { return fetch('/hello').then(function(response) {
assert(response.arrayBuffer, 'Body does not implement arrayBuffer')
assert.equal(response.bodyUsed, false) assert.equal(response.bodyUsed, false)
response.blob() response.blob()
assert.equal(response.bodyUsed, true) assert.equal(response.bodyUsed, true)
...@@ -541,7 +589,7 @@ suite('Body mixin', function() { ...@@ -541,7 +589,7 @@ suite('Body mixin', function() {
}) })
}) })
;(Response.prototype.blob ? suite : suite.skip)('blob', function() { featureDependent(suite, support.blob, 'blob', function() {
test('resolves blob promise', function() { test('resolves blob promise', function() {
return fetch('/hello').then(function(response) { return fetch('/hello').then(function(response) {
return response.blob() return response.blob()
...@@ -591,7 +639,7 @@ suite('Body mixin', function() { ...@@ -591,7 +639,7 @@ suite('Body mixin', function() {
}) })
}) })
;(Response.prototype.formData ? suite : suite.skip)('formData', function() { featureDependent(suite, support.formData, 'formData', function() {
test('post sets content-type header', function() { test('post sets content-type header', function() {
return fetch('/request', { return fetch('/request', {
method: 'post', method: 'post',
...@@ -604,7 +652,7 @@ suite('Body mixin', function() { ...@@ -604,7 +652,7 @@ suite('Body mixin', function() {
}) })
}) })
test('rejects formData promise after body is consumed', function() { featureDependent(test, !nativeChrome, 'rejects formData promise after body is consumed', function() {
return fetch('/json').then(function(response) { return fetch('/json').then(function(response) {
assert(response.formData, 'Body does not implement formData') assert(response.formData, 'Body does not implement formData')
response.formData() response.formData()
...@@ -618,7 +666,7 @@ suite('Body mixin', function() { ...@@ -618,7 +666,7 @@ suite('Body mixin', function() {
}) })
}) })
test('parses form encoded response', function() { featureDependent(test, !nativeChrome, 'parses form encoded response', function() {
return fetch('/form').then(function(response) { return fetch('/form').then(function(response) {
return response.formData() return response.formData()
}).then(function(form) { }).then(function(form) {
...@@ -649,7 +697,7 @@ suite('Body mixin', function() { ...@@ -649,7 +697,7 @@ suite('Body mixin', function() {
}) })
}) })
test('handles json parse error', function() { featureDependent(test, !polyfillFirefox, 'handles json parse error', function() {
return fetch('/json-error').then(function(response) { return fetch('/json-error').then(function(response) {
return response.json() return response.json()
}).catch(function(error) { }).catch(function(error) {
...@@ -746,9 +794,7 @@ suite('Methods', function() { ...@@ -746,9 +794,7 @@ suite('Methods', function() {
}) })
}) })
var patchSupported = !/PhantomJS/.test(navigator.userAgent) featureDependent(test, support.patch, 'supports HTTP PATCH', function() {
;(patchSupported ? test : test.skip)('supports HTTP PATCH', function() {
return fetch('/request', { return fetch('/request', {
method: 'PATCH', method: 'PATCH',
body: 'name=Hubot' body: 'name=Hubot'
...@@ -818,9 +864,7 @@ suite('Atomic HTTP redirect handling', function() { ...@@ -818,9 +864,7 @@ suite('Atomic HTTP redirect handling', function() {
}) })
}) })
var permanentRedirectSupported = !/PhantomJS|Trident/.test(navigator.userAgent) featureDependent(test, support.permanentRedirect, 'handles 308 redirect response', function() {
;(permanentRedirectSupported ? test : test.skip)('handles 308 redirect response', function() {
return fetch('/redirect/308').then(function(response) { return fetch('/redirect/308').then(function(response) {
assert.equal(response.status, 200) assert.equal(response.status, 200)
assert.equal(response.ok, true) assert.equal(response.ok, true)
...@@ -834,13 +878,11 @@ suite('Atomic HTTP redirect handling', function() { ...@@ -834,13 +878,11 @@ suite('Atomic HTTP redirect handling', function() {
// https://fetch.spec.whatwg.org/#concept-request-credentials-mode // https://fetch.spec.whatwg.org/#concept-request-credentials-mode
suite('credentials mode', function() { suite('credentials mode', function() {
var omitSupported = !self.fetch.polyfill
setup(function() { setup(function() {
return fetch('/cookie?name=foo&value=reset', {credentials: 'same-origin'}); return fetch('/cookie?name=foo&value=reset', {credentials: 'same-origin'});
}) })
;(omitSupported ? suite : suite.skip)('omit', function() { featureDependent(suite, exerciseMode === 'native', 'omit', function() {
test('request credentials defaults to omit', function() { test('request credentials defaults to omit', function() {
var request = new Request('') var request = new Request('')
assert.equal(request.credentials, 'omit') assert.equal(request.credentials, 'omit')
...@@ -916,3 +958,6 @@ suite('credentials mode', function() { ...@@ -916,3 +958,6 @@ suite('credentials mode', function() {
}) })
}) })
}) })
})
})
importScripts('../node_modules/chai/chai.js') importScripts('/node_modules/chai/chai.js')
importScripts('../node_modules/mocha/mocha.js') importScripts('/node_modules/mocha/mocha.js')
mocha.setup('tdd') mocha.setup('tdd')
self.assert = chai.assert self.assert = chai.assert
importScripts('../bower_components/es6-promise/promise.js') importScripts('/bower_components/es6-promise/promise.js')
importScripts('../fetch.js') importScripts('/test/test.js')
importScripts('/fetch.js')
importScripts('test.js')
function title(test) { function title(test) {
return test.fullTitle().replace(/#/g, ''); return test.fullTitle().replace(/#/g, '');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册