mirror of
https://github.com/Wan-Video/Wan2.1.git
synced 2025-06-08 08:14:57 +00:00
655 lines
21 KiB
JavaScript
655 lines
21 KiB
JavaScript
|
|
(function(Platform) {
|
|
|
|
describe("oboe integration (real http)", function() {
|
|
|
|
var oboe = Platform.isNode
|
|
? require('../../dist/oboe-node.js')
|
|
: (window.oboe)
|
|
;
|
|
|
|
var ASYNC_TEST_TIMEOUT = 15 * 1000; // 15 seconds
|
|
|
|
function url( path ){
|
|
if( Platform.isNode ) {
|
|
return 'localhost:4567/' + path;
|
|
} else {
|
|
return '/testServer/' + path;
|
|
}
|
|
}
|
|
|
|
Platform.isNode && describe('running under node', function(){
|
|
|
|
var http = require('http'),
|
|
fs = require('fs');
|
|
|
|
it('can read from a stream that is passed in', function() {
|
|
|
|
http.request( 'http://localhost:4567/tenSlowNumbers' )
|
|
.on('response', function( res ) {
|
|
|
|
oboe(res)
|
|
.node('![*]', callbackSpy)
|
|
.done(whenDoneFn);
|
|
|
|
}).on('error', function(e) {
|
|
|
|
console.log(e);
|
|
}).end();
|
|
|
|
|
|
waitsFor(doneCalled, 'the request to have called done', ASYNC_TEST_TIMEOUT);
|
|
|
|
runs(function () {
|
|
|
|
expect( callbackSpy.calls.length ).toBe(10);
|
|
});
|
|
})
|
|
|
|
it('can read from a local file', function() {
|
|
|
|
oboe(fs.createReadStream( 'test/json/firstTenNaturalNumbers.json' ))
|
|
.node('![*]', callbackSpy)
|
|
.done(whenDoneFn);
|
|
|
|
waitsFor(doneCalled, 'the request to have called done', ASYNC_TEST_TIMEOUT);
|
|
|
|
runs(function () {
|
|
|
|
expect( callbackSpy.calls.length ).toBe(10);
|
|
});
|
|
})
|
|
|
|
});
|
|
|
|
it('gets all expected callbacks by time request finishes', function () {
|
|
|
|
oboe(url('tenSlowNumbers'))
|
|
.node('![*]', callbackSpy)
|
|
.done(whenDoneFn);
|
|
|
|
waitsFor(doneCalled, 'the request to have called done', ASYNC_TEST_TIMEOUT);
|
|
|
|
runs(function () {
|
|
|
|
expect(callbackSpy).toHaveBeenCalledWith(0, [0], [fullResponse, 0]);
|
|
expect(callbackSpy).toHaveBeenCalledWith(1, [1], [fullResponse, 1]);
|
|
expect(callbackSpy).toHaveBeenCalledWith(2, [2], [fullResponse, 2]);
|
|
expect(callbackSpy).toHaveBeenCalledWith(3, [3], [fullResponse, 3]);
|
|
expect(callbackSpy).toHaveBeenCalledWith(4, [4], [fullResponse, 4]);
|
|
expect(callbackSpy).toHaveBeenCalledWith(5, [5], [fullResponse, 5]);
|
|
expect(callbackSpy).toHaveBeenCalledWith(6, [6], [fullResponse, 6]);
|
|
expect(callbackSpy).toHaveBeenCalledWith(7, [7], [fullResponse, 7]);
|
|
expect(callbackSpy).toHaveBeenCalledWith(8, [8], [fullResponse, 8]);
|
|
expect(callbackSpy).toHaveBeenCalledWith(9, [9], [fullResponse, 9]);
|
|
|
|
});
|
|
})
|
|
|
|
|
|
it('can make nested requests from arrays', function () {
|
|
|
|
oboe(url('tenSlowNumbers'))
|
|
.node('![*]', function(outerNumber){
|
|
|
|
oboe(url('tenSlowNumbers'))
|
|
.node('![*]', function(innerNumber){
|
|
callbackSpy();
|
|
});
|
|
})
|
|
.done(whenDoneFn);
|
|
|
|
waitsFor(
|
|
function () {
|
|
return !!(callbackSpy.calls.length == 100);
|
|
},
|
|
'100 callbacks',
|
|
30 * 1000 // makes a lot of requests so give it a while to complete
|
|
);
|
|
})
|
|
|
|
|
|
it('continues to parse after a callback throws an exception', function () {
|
|
|
|
oboe(url('static/json/tenRecords.json'))
|
|
.node('{id name}', function(){
|
|
|
|
callbackSpy()
|
|
throw new Error('uh oh!');
|
|
})
|
|
.done(whenDoneFn);
|
|
|
|
waitsFor(
|
|
function () {
|
|
return !!(callbackSpy.calls.length == 10);
|
|
},
|
|
'100 callbacks'
|
|
);
|
|
})
|
|
|
|
it('can abort once some data has been found in streamed response', function () {
|
|
|
|
var req = oboe(url('tenSlowNumbers'))
|
|
.node('![5]', abortCallback);
|
|
|
|
waitsFor(theRequestToBeAborted, 'the request to be aborted', ASYNC_TEST_TIMEOUT);
|
|
|
|
// in case we didn't abort, wait a little longer. If we didn't really abort we'd get the
|
|
// rest of the data now and the test would fail:
|
|
waitsFor(someSecondsToPass(2), ASYNC_TEST_TIMEOUT);
|
|
|
|
runs(function () {
|
|
// because the request was aborted on index array 5, we got 6 numbers (inc zero)
|
|
// not the whole ten.
|
|
|
|
expect(req.root()).toEqual([0, 1, 2, 3, 4, 5]);
|
|
|
|
});
|
|
})
|
|
|
|
it('can deregister from inside the callback', function () {
|
|
|
|
var nodeCallback = jasmine.createSpy().andCallFake(function(){
|
|
if( nodeCallback.calls.length == 5 ) {
|
|
this.forget();
|
|
}
|
|
});
|
|
|
|
oboe(url('tenSlowNumbers'))
|
|
.node('![*]', nodeCallback)
|
|
.done(whenDoneFn);
|
|
|
|
// in case we didn't abort, wait a little longer. If we didn't really abort we'd get the
|
|
// rest of the data now and the test would fail:
|
|
waitsFor(doneCalled, ASYNC_TEST_TIMEOUT);
|
|
|
|
runs(function () {
|
|
// because the request was aborted on index array 5, we got 6 numbers (inc zero)
|
|
// not the whole ten.
|
|
|
|
expect(nodeCallback.calls.length).toBe(5);
|
|
|
|
});
|
|
})
|
|
|
|
it('can still gets the whole resource after deregistering the callback', function () {
|
|
|
|
var callback = jasmine.createSpy().andCallFake(function(){
|
|
if( callback.calls.length == 5 ) {
|
|
this.forget();
|
|
}
|
|
});
|
|
|
|
oboe(url('tenSlowNumbers'))
|
|
.node('![*]', callback)
|
|
.done(whenDoneFn);
|
|
|
|
// in case we didn't abort, wait a little longer. If we didn't really abort we'd get the
|
|
// rest of the data now and the test would fail:
|
|
waitsFor(doneCalled, ASYNC_TEST_TIMEOUT);
|
|
|
|
runs(function () {
|
|
// because the request was aborted on index array 5, we got 6 numbers (inc zero)
|
|
// not the whole ten.
|
|
|
|
expect(fullResponse).toEqual([0,1,2,3,4,5,6,7,8,9]);
|
|
});
|
|
})
|
|
|
|
it('can abort once some data has been found in not very streamed response', function () {
|
|
|
|
// like above but we're getting a static file not the streamed numbers. This means
|
|
// we'll almost certainly read in the whole response as one onprogress it is on localhost
|
|
// and the json is very small
|
|
|
|
var req = oboe(url('static/json/firstTenNaturalNumbers.json'))
|
|
.node('![5]', abortCallback);
|
|
|
|
waitsFor(theRequestToBeAborted, 'the request to be aborted', ASYNC_TEST_TIMEOUT);
|
|
|
|
// in case we didn't abort, wait a little longer. If we didn't really abort we'd get the
|
|
// rest of the data now and the test would fail:
|
|
waitsFor(someSecondsToPass(2), ASYNC_TEST_TIMEOUT);
|
|
|
|
runs(function () {
|
|
// because the request was aborted on index array 5, we got 6 numbers (inc zero)
|
|
// not the whole ten.
|
|
|
|
expect(req.root()).toEqual([0, 1, 2, 3, 4, 5]);
|
|
});
|
|
})
|
|
|
|
it('gives full json to callback when request finishes', function () {
|
|
|
|
oboe(url('static/json/firstTenNaturalNumbers.json'))
|
|
.done(whenDoneFn);
|
|
|
|
waitsFor(doneCalled, 'the request to give full response', ASYNC_TEST_TIMEOUT)
|
|
|
|
runs(function () {
|
|
expect(fullResponse).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
|
|
});
|
|
})
|
|
|
|
it('gives content type as JSON when provided with an Object body', function () {
|
|
|
|
var done;
|
|
|
|
oboe({
|
|
method:'PUT',
|
|
url:url('echoBackHeadersAsBodyJson'),
|
|
body:{'potatoes':3, 'cabbages':4}
|
|
|
|
}).done(function(json){
|
|
done = true;
|
|
var contentType = contextTypeFrom(json['content-type']);
|
|
expect(contentType).toBe('application/json');
|
|
});
|
|
|
|
waitsFor(function (){ return !!done; }, 'the request to complete', ASYNC_TEST_TIMEOUT)
|
|
})
|
|
|
|
it('gives allows content type to be overridden when provided with an Object body', function () {
|
|
|
|
var done;
|
|
|
|
oboe({
|
|
method:'PUT',
|
|
url:url('echoBackHeadersAsBodyJson'),
|
|
body:{'potatoes':3, 'cabbages':4},
|
|
headers:{'Content-Type':'application/vegetableDiffThing'}
|
|
|
|
}).done(function(json){
|
|
done = true;
|
|
var contentType = contextTypeFrom(json['content-type']);
|
|
expect(contentType).toBe('application/vegetableDiffThing');
|
|
});
|
|
|
|
waitsFor(function (){ return !!done; }, 'the request to complete', ASYNC_TEST_TIMEOUT)
|
|
})
|
|
|
|
it('gives header to server side', function () {
|
|
|
|
var countGotBack = 0;
|
|
|
|
oboe(
|
|
{ url:url('echoBackHeadersAsBodyJson'),
|
|
headers:{'x-snarfu':'SNARF', 'x-foo':'BAR'}
|
|
}
|
|
|
|
).node('x-snarfu', function (headerValue) {
|
|
|
|
expect(headerValue).toBe('SNARF')
|
|
countGotBack++;
|
|
|
|
}).node('x-foo', function (headerValue) {
|
|
|
|
expect(headerValue).toBe('BAR')
|
|
countGotBack++;
|
|
})
|
|
|
|
waitsFor(function () {
|
|
return countGotBack == 2
|
|
}, 'all headers to have been detected back here', ASYNC_TEST_TIMEOUT)
|
|
})
|
|
|
|
it('can read response headers', function () {
|
|
|
|
var done = false;
|
|
|
|
oboe(
|
|
{ url:url('echoBackHeadersAsHeaders'),
|
|
headers:{'x-sso':'sso', 'x-sso2':'sso2'}
|
|
}
|
|
|
|
).done(function(){
|
|
|
|
expect(this.header('x-sso')).toEqual('sso');
|
|
expect(this.header('x-sso2')).toEqual('sso2');
|
|
|
|
expect(this.header()['x-sso']).toEqual('sso');
|
|
expect(this.header()['x-sso2']).toEqual('sso2');
|
|
expect(this.header()['x-sso3']).toBeUndefined();
|
|
|
|
done = true;
|
|
})
|
|
|
|
waitsFor(function () {
|
|
return done;
|
|
}, 'the response to complete', ASYNC_TEST_TIMEOUT)
|
|
})
|
|
|
|
it('gives undefined for headers before they are ready', function () {
|
|
|
|
var o = oboe(
|
|
{ url:url('echoBackHeadersAsHeaders'),
|
|
headers:{'x-sso':'sso', 'x-sso2':'sso2'}
|
|
}
|
|
)
|
|
|
|
expect(o.header()).toBeUndefined();
|
|
expect(o.header('x-sso')).toBeUndefined();
|
|
expect(o.header('x-sso2')).toBeUndefined();
|
|
})
|
|
|
|
it('notifies of response starting by giving status code and headers to callback', function () {
|
|
var called = 0;
|
|
|
|
oboe(
|
|
{ url:url('echoBackHeadersAsHeaders'),
|
|
headers:{'x-a':'A', 'x-b':'B'}
|
|
}
|
|
).start(function(statusCode, headers){
|
|
|
|
expect(statusCode).toBe(200);
|
|
expect(headers['x-a']).toBe('A');
|
|
called++;
|
|
|
|
}).on('start', function(statusCode, headers){
|
|
|
|
expect(statusCode).toBe(200);
|
|
expect(headers['x-b']).toBe('B');
|
|
called++;
|
|
});
|
|
|
|
waitsFor(function () {
|
|
return called == 2;
|
|
}, 'the response to call both start callbacks', ASYNC_TEST_TIMEOUT)
|
|
});
|
|
|
|
it('can listen for nodes nodejs style', function () {
|
|
|
|
var countGotBack = 0;
|
|
|
|
oboe(url('static/json/firstTenNaturalNumbers.json'))
|
|
.on('node', '!.*', function () {
|
|
countGotBack++;
|
|
});
|
|
|
|
waitsFor(function () {
|
|
return countGotBack == 10
|
|
}, 'ten callbacks', ASYNC_TEST_TIMEOUT)
|
|
})
|
|
|
|
it('can listen for paths nodejs style', function () {
|
|
|
|
var countGotBack = 0;
|
|
|
|
oboe(url('static/json/firstTenNaturalNumbers.json'))
|
|
|
|
.on('path', '!.*', function (number) {
|
|
countGotBack++;
|
|
});
|
|
|
|
waitsFor(function () {
|
|
return countGotBack == 10
|
|
}, 'ten callbacks', ASYNC_TEST_TIMEOUT)
|
|
})
|
|
|
|
it('can listen for done nodejs style', function () {
|
|
|
|
oboe(url('static/json/firstTenNaturalNumbers.json'))
|
|
|
|
.on('done', whenDoneFn);
|
|
|
|
waitsFor(doneCalled, 'the request to finish', ASYNC_TEST_TIMEOUT)
|
|
})
|
|
|
|
it('gets all callbacks and they are in correct order', function () {
|
|
var order = [];
|
|
|
|
oboe({
|
|
method:'POST',
|
|
url: url('echoBackBody')
|
|
, body: {a:'A', b:'B', c:'C'}
|
|
})
|
|
.path('!', function(){ order.push(1) })
|
|
.path('a', function(){ order.push(2) })
|
|
.node('a', function(){ order.push(3) })
|
|
.path('b', function(){ order.push(4) })
|
|
.node('b', function(){ order.push(5) })
|
|
.path('c', function(){ order.push(6) })
|
|
.node('c', function(){ order.push(7) })
|
|
.done(function(){ order.push(8) })
|
|
|
|
waitsFor(function(){ return order.length == 8 },
|
|
'all 8 callbacks', ASYNC_TEST_TIMEOUT);
|
|
|
|
runs(function(){
|
|
expect(order).toEqual([1,2,3,4,5,6,7,8]);
|
|
});
|
|
|
|
});
|
|
|
|
it('emits error on 404', function () {
|
|
|
|
var stubCallback = jasmine.createSpy('error callback');
|
|
|
|
oboe(url('404json'))
|
|
.fail(stubCallback);
|
|
|
|
waitsFor(function () {
|
|
return !!stubCallback.calls.length;
|
|
}, 'the request to fail', ASYNC_TEST_TIMEOUT)
|
|
|
|
runs( function() {
|
|
expect( stubCallback ).toHaveBeenGivenErrorStatusCode( 404 );
|
|
expect( stubCallback ).toHaveBeenGivenBodyJson(
|
|
{ "found":"false",
|
|
"errorMessage":"was not found"
|
|
}
|
|
);
|
|
});
|
|
})
|
|
|
|
it('emits error on 404 in nodejs style too', function () {
|
|
|
|
var stubCallback = jasmine.createSpy('error callback');
|
|
|
|
oboe(url('doesNotExist'))
|
|
.on('fail', stubCallback);
|
|
|
|
waitsFor(function () {
|
|
return !!stubCallback.calls.length;
|
|
}, 'the request to fail', ASYNC_TEST_TIMEOUT)
|
|
})
|
|
|
|
/*
|
|
This isn't reliable enough, too many false negatives for a ci
|
|
it('emits error on unreachable url', function () {
|
|
|
|
var stubCallback = jasmine.createSpy('error callback');
|
|
|
|
oboe('nowhere.ox.ac.uk:754196/fooz/barz')
|
|
.fail(stubCallback);
|
|
|
|
waitsFor(function () {
|
|
return !!stubCallback.calls.length;
|
|
}, 'the request to fail', 30*1000)
|
|
|
|
runs( function() {
|
|
expect(stubCallback).toHaveBeenGivenAnyError();
|
|
});
|
|
})
|
|
*/
|
|
|
|
it('emits error if callback throws a string', function () {
|
|
|
|
var stubCallback = jasmine.createSpy('error callback');
|
|
|
|
oboe(url('static/json/firstTenNaturalNumbers.json'))
|
|
.node('!.*', jasmine.createSpy().andThrow('I am a bad callback') )
|
|
.fail(stubCallback);
|
|
|
|
waitsFor(function () {
|
|
return !!stubCallback.calls.length;
|
|
}, 'the request to fail', ASYNC_TEST_TIMEOUT)
|
|
|
|
runs( function() {
|
|
expect( stubCallback ).toHaveBeenGivenThrowee('I am a bad callback')
|
|
});
|
|
})
|
|
|
|
it('emits error if callback throws an error', function () {
|
|
|
|
var stubCallback = jasmine.createSpy('error callback'),
|
|
callbackError = new Error('I am a bad callback');
|
|
|
|
oboe(url('static/json/firstTenNaturalNumbers.json'))
|
|
.node('!.*', jasmine.createSpy().andThrow(callbackError) )
|
|
.fail(stubCallback);
|
|
|
|
waitsFor(function () {
|
|
return !!stubCallback.calls.length;
|
|
}, 'the request to fail', ASYNC_TEST_TIMEOUT)
|
|
|
|
|
|
runs( function() {
|
|
expect( stubCallback ).toHaveBeenGivenThrowee(callbackError)
|
|
})
|
|
})
|
|
|
|
it('emits error if done callback throws an error', function () {
|
|
|
|
var stubCallback = jasmine.createSpy('error callback'),
|
|
callbackError = new Error('I am a bad callback');
|
|
|
|
oboe(url('static/json/firstTenNaturalNumbers.json'))
|
|
.done(jasmine.createSpy().andThrow(callbackError) )
|
|
.fail(stubCallback);
|
|
|
|
waitsFor(function () {
|
|
return !!stubCallback.calls.length;
|
|
}, 'the request to fail', ASYNC_TEST_TIMEOUT)
|
|
|
|
|
|
runs( function() {
|
|
expect( stubCallback ).toHaveBeenGivenThrowee(callbackError)
|
|
})
|
|
})
|
|
|
|
it('emits error with incomplete json', function () {
|
|
|
|
var stubCallback = jasmine.createSpy('error callback');
|
|
|
|
oboe(url('static/json/incomplete.json'))
|
|
.fail(stubCallback);
|
|
|
|
waitsFor(function () {
|
|
return !!stubCallback.calls.length;
|
|
}, 'the request to fail', ASYNC_TEST_TIMEOUT);
|
|
})
|
|
|
|
if( !Platform.isNode ) {
|
|
// only worry about this in the browser
|
|
|
|
it( 'hasn\'t put clarinet in the global namespace', function(){
|
|
|
|
expect( window.clarinet ).toBeUndefined();
|
|
});
|
|
}
|
|
|
|
function someSecondsToPass(waitSecs) {
|
|
|
|
function now() {
|
|
// IE8 doesn't have Date.now()
|
|
return new Date().getTime();
|
|
}
|
|
|
|
var waitStart = now(),
|
|
waitMs = waitSecs * 1000;
|
|
|
|
return function () {
|
|
return now() > (waitStart + waitMs);
|
|
}
|
|
}
|
|
|
|
var callbackSpy,
|
|
fullResponse,
|
|
aborted;
|
|
|
|
function abortCallback() {
|
|
this.abort();
|
|
aborted = true;
|
|
}
|
|
|
|
function theRequestToBeAborted() {
|
|
return aborted
|
|
}
|
|
|
|
function whenDoneFn(obj) {
|
|
fullResponse = obj;
|
|
}
|
|
|
|
function doneCalled(){
|
|
return !!fullResponse
|
|
}
|
|
|
|
/**
|
|
* A context-type header can come back like:
|
|
* 'application/json'
|
|
*
|
|
* or like:
|
|
* 'application/json; charset=UTF-8'
|
|
*/
|
|
function contextTypeFrom(header){
|
|
return header.split(';')[0];
|
|
}
|
|
|
|
beforeEach(function () {
|
|
aborted = false;
|
|
fullResponse = null;
|
|
callbackSpy = jasmine.createSpy('callbackSpy');
|
|
|
|
this.addMatchers({
|
|
toHaveBeenGivenAnyError:function(){
|
|
var errorReport = this.actual.mostRecentCall.args[0],
|
|
maybeErr = errorReport.thrown;
|
|
|
|
if( typeof maybeErr != 'object' ) {
|
|
return false;
|
|
}
|
|
|
|
if( maybeErr instanceof Error ) {
|
|
return true;
|
|
}
|
|
|
|
// instanceof Error doesn't always work in Safari (tested v6.0.5)
|
|
// because:
|
|
//
|
|
// ((new XMLHttpRequestException()) instanceof Error) == false
|
|
if( window && window.XMLHttpRequestException &&
|
|
maybeErr instanceof XMLHttpRequestException ) {
|
|
return true;
|
|
}
|
|
|
|
// if that didn't work fallback to some duck typing:
|
|
return( (typeof maybeErr.message != 'undefined') &&
|
|
(typeof maybeErr.lineNumber != 'undefined') );
|
|
},
|
|
toHaveBeenGivenThrowee:function(expectedError){
|
|
var errorReport = this.actual.mostRecentCall.args[0];
|
|
|
|
return errorReport.thrown === expectedError;
|
|
},
|
|
toHaveBeenGivenErrorStatusCode:function(expectedCode){
|
|
var errorReport = this.actual.mostRecentCall.args[0];
|
|
|
|
return errorReport.statusCode === expectedCode;
|
|
},
|
|
toHaveBeenGivenBodyJson:function(expectedBodyJson){
|
|
var errorReport = this.actual.mostRecentCall.args[0];
|
|
|
|
return JSON.stringify(expectedBodyJson)
|
|
===
|
|
JSON.stringify(errorReport.jsonBody);
|
|
}
|
|
});
|
|
});
|
|
|
|
});
|
|
})(typeof Platform == 'undefined'? require('../libs/platform.js') : Platform)
|
|
|
|
|
|
|