File tree

5 files changed

+259
-13
lines changed

5 files changed

+259
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ module.exports = function(config) {
2020
'bower_components/jquery-1/index.js',
2121
'bower_components/jquery/dist/jquery.js',
2222
'node_modules/es6-promise/dist/es6-promise.auto.js',
23+
'node_modules/abortcontroller-polyfill/dist/abortcontroller-polyfill-only.js',
24+
'node_modules/yetch/dist/yetch-ponyfill.js',
2325
'pretender.js',
2426
'test/**/*.js'
2527
],
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@
3737
"sinon": "^3.2.1"
3838
},
3939
"dependencies": {
40+
"abortcontroller-polyfill": "^1.1.9",
4041
"fake-xml-http-request": "^2.0.0",
41-
"route-recognizer": "^0.3.3"
42+
"route-recognizer": "^0.3.3",
43+
"yetch": "^0.0.1"
4244
},
4345
"jspm": {
4446
"shim": {
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ var RouteRecognizer = appearsBrowserified ? getModuleDefault(require('route-reco
1313
var FakeXMLHttpRequest = appearsBrowserified ? getModuleDefault(require('fake-xml-http-request')) :
1414
self.FakeXMLHttpRequest;
1515

16+
// fetch related ponyfills
17+
var Yetch = appearsBrowserified ? getModuleDefault(require('yetch/dist/yetch-polyfill')) : self.Yetch;
18+
1619
/**
1720
* parseURL - decompose a URL into its parts
1821
* @param {String} url a URL
@@ -139,6 +142,14 @@ function Pretender(/* routeMap1, routeMap2, ..., options*/) {
139142
// the route map.
140143
self.XMLHttpRequest = interceptor(ctx);
141144

145+
// polyfill fetch when xhr is ready
146+
// AbortController doesn't need restore
147+
this._fetchProps = ['fetch', 'Headers', 'Request', 'Response'];
148+
this._fetchProps.forEach(function(name) {
149+
this['_native' + name] = self[name];
150+
self[name] = Yetch[name];
151+
}, this);
152+
142153
// 'start' the server
143154
this.running = true;
144155

@@ -471,6 +482,9 @@ Pretender. = {
471482
},
472483
shutdown: function shutdown() {
473484
self.XMLHttpRequest = this._nativeXMLHttpRequest;
485+
this._fetchProps.forEach(function(name) {
486+
self[name] = this['_native' + name];
487+
}, this);
474488
this.ctx.pretender = undefined;
475489
// 'stop' the server
476490
this.running = false;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
var describe = QUnit.module;
2+
var it = QUnit.test;
3+
var clock;
4+
5+
describe('pretender invoking by fetch', function(config) {
6+
config.beforeEach(function() {
7+
this.pretender = new Pretender();
8+
});
9+
10+
config.afterEach(function() {
11+
if (clock) {
12+
clock.restore();
13+
}
14+
this.pretender.shutdown();
15+
});
16+
17+
it('fetch triggers pretender', function(assert) {
18+
var wasCalled;
19+
20+
this.pretender.get('/some/path', function() {
21+
wasCalled = true;
22+
});
23+
24+
fetch('/some/path');
25+
assert.ok(wasCalled);
26+
});
27+
28+
it('is resolved asynchronously', function(assert) {
29+
assert.expect(2);
30+
var done = assert.async();
31+
var val = 'unset';
32+
33+
this.pretender.get('/some/path', function(request) {
34+
return [200, {}, ''];
35+
});
36+
37+
fetch('/some/path').then(function() {
38+
assert.equal(val, 'set');
39+
done();
40+
});
41+
42+
assert.equal(val, 'unset');
43+
val = 'set';
44+
});
45+
46+
it('can NOT be resolved synchronously', function(assert) {
47+
assert.expect(1);
48+
var val = 0;
49+
50+
this.pretender.get(
51+
'/some/path',
52+
function(request) {
53+
return [200, {}, ''];
54+
},
55+
false
56+
);
57+
58+
fetch('/some/path').then(function() {
59+
// This won't be called
60+
assert.equal(val, 0);
61+
val++;
62+
});
63+
assert.equal(val, 0);
64+
});
65+
66+
it('has NO Abortable fetch', function(assert) {
67+
assert.expect(1);
68+
var done = assert.async();
69+
var wasCalled = false;
70+
this.pretender.get(
71+
'/downloads',
72+
function(request) {
73+
return [200, {}, 'FAIL'];
74+
},
75+
200
76+
);
77+
78+
var controller = new AbortController();
79+
var signal = controller.signal;
80+
setTimeout(function() {
81+
controller.abort();
82+
}, 10);
83+
fetch('/downloads', { signal: signal })
84+
.then(function(data) {
85+
assert.ok(data, 'AbortError was not rejected');
86+
done();
87+
})
88+
.catch(function(err) {
89+
// it should execute to here but won't due to FakeXmlHttpRequest limitation
90+
//
91+
// ### why it's not working for fetch
92+
// For `fake_xml_http_request` impl, the request is resolved once its state
93+
// is changed to `DONE` so the `reject` is not cathed.
94+
// So the senario happens in pretender is:
95+
// 1. state chagne to `DONE`, trigger resolve request
96+
// 2. abort, trigger reject
97+
// 3. xhr.onerror, trigger reject
98+
// The first resolve wins, error thus not rejected but an empty request is resolved.
99+
done();
100+
});
101+
});
102+
});

0 commit comments

Comments
 (0)