Skip to content

Commit

Permalink
Merge branch 'master' into ws-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
jayphelps authored Oct 24, 2016
2 parents cf27fa0 + 76a9abb commit fc4a816
Show file tree
Hide file tree
Showing 11 changed files with 288 additions and 41 deletions.
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"clean_spec": "Clean up existing test spec build output",
"clean_dist_cjs": "Clean up existing CJS package output",
"clean_dist_es6": "Clean up existing ES6 package output",
"clean_dist_global": "Clean up existing Global package output",
"commit": "Run git commit wizard",
"compile_dist_cjs": "Compile codebase into CJS module",
"compile_dist_es6": "Compile codebase into ES6",
Expand All @@ -56,7 +57,7 @@
"build_es6": "npm-run-all clean_dist_es6 copy_src_es6 compile_dist_es6",
"build_es6_for_docs": "npm-run-all clean_dist_es6 copy_src_es6 compile_dist_es6_for_docs",
"build_closure_core": "node ./tools/make-closure-core.js",
"build_global": "shx rm -rf ./dist/global && mkdirp ./dist/global && node tools/make-umd-bundle.js && npm-run-all build_closure_core",
"build_global": "npm-run-all clean_dist_global build_es6 && mkdirp ./dist/global && node tools/make-umd-bundle.js && npm-run-all build_closure_core",
"build_perf": "webdriver-manager update && npm-run-all build_cjs build_global perf",
"build_test": "shx rm -rf ./dist/ && npm-run-all build_cjs clean_spec build_spec test_mocha",
"build_cover": "shx rm -rf ./dist/ && npm-run-all build_cjs build_spec cover",
Expand All @@ -67,6 +68,7 @@
"clean_spec": "shx rm -rf spec-js",
"clean_dist_cjs": "shx rm -rf ./dist/cjs",
"clean_dist_es6": "shx rm -rf ./dist/es6",
"clean_dist_global": "shx rm -rf ./dist/global",
"copy_src_cjs": "mkdirp ./dist/cjs/src && shx cp -r ./src/* ./dist/cjs/src",
"copy_src_es6": "mkdirp ./dist/es6/src && shx cp -r ./src/* ./dist/es6/src",
"commit": "git-cz",
Expand Down Expand Up @@ -142,17 +144,19 @@
},
"homepage": "https://github.com/ReactiveX/RxJS",
"devDependencies": {
"babel-polyfill": "6.9.1",
"babel-core": "6.17.0",
"babel-polyfill": "6.16.0",
"babel-preset-es2015": "6.16.0",
"benchmark": "^2.1.0",
"benchpress": "2.0.0-beta.1",
"browserify": "13.0.1",
"chai": "^3.5.0",
"color": "^0.11.1",
"colors": "1.1.2",
"commitizen": "^2.8.6",
"coveralls": "^2.11.13",
"cz-conventional-changelog": "^1.2.0",
"doctoc": "^1.0.0",
"escape-string-regexp": "^1.0.5 ",
"esdoc": "^0.4.7",
"eslint": "^2.12.0",
"fs-extra": "^0.30.0",
Expand All @@ -177,6 +181,7 @@
"platform": "^1.3.1",
"promise": "^7.1.1",
"protractor": "^3.1.1",
"rollup": "0.36.3",
"rx": "latest",
"shx": "^0.1.4",
"sinon": "^2.0.0-pre",
Expand All @@ -187,7 +192,6 @@
"typings": "^1.3.3",
"validate-commit-msg": "^2.3.1",
"watch": "^0.18.0",
"watchify": "3.7.0",
"webpack": "^1.13.1",
"xmlhttprequest": "1.8.0"
},
Expand Down
11 changes: 10 additions & 1 deletion publish_docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,13 @@
# Generates documentation and pushes it up to the site
# WARNING: Do NOT run this script unless you have remote `upstream` set properly
#
rm -rf tmp/docs && npm run build_docs && git checkout gh-pages && git fetch upstream && git rebase upstream/gh-pages && cp -r ./tmp/docs/ ./ && rm -rf tmp/ && git add . && git commit -am "chore(docs): docs generated automatically" && git push upstream gh-pages
rm -rf tmp/docs && \
npm run build_docs && \
git checkout gh-pages && \
git fetch upstream && \
git rebase upstream/gh-pages && \
cp -r ./tmp/docs/ ./ && \
rm -rf tmp/ && \
git add . && \
git commit -am "chore(docs): docs generated automatically" && \
git push upstream gh-pages
6 changes: 6 additions & 0 deletions spec/helpers/ajax-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ export class MockXMLHttpRequest {
requestHeaders: any = {};
withCredentials: boolean = false;

onreadystatechange: (e: ProgressEvent) => any;
onerror: (e: ErrorEvent) => any;
onprogress: (e: ProgressEvent) => any;
ontimeout: (e: ProgressEvent) => any;
upload: XMLHttpRequestUpload;

constructor() {
this.previousRequest = MockXMLHttpRequest.recentRequest;
MockXMLHttpRequest.recentRequest = this;
Expand Down
162 changes: 162 additions & 0 deletions spec/observables/dom/ajax-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -598,4 +598,166 @@ describe('Observable.ajax', () => {
});

});

it('should work fine when XMLHttpRequest onreadystatechange property is monkey patched', function() {
Object.defineProperty(root.XMLHttpRequest.prototype, 'onreadystatechange', {
set: function (fn: (e: ProgressEvent) => any) {
const wrapFn = (ev: ProgressEvent) => {
const result = fn.call(this, ev);
if (result === false) {
ev.preventDefault();
}
};
this['_onreadystatechange'] = wrapFn;
},
get() {
return this['_onreadystatechange'];
},
configurable: true
});

Rx.Observable.ajax({
url: '/flibbertyJibbet'
})
.subscribe();

const request = MockXMLHttpRequest.mostRecent;
expect(() => {
request.onreadystatechange((<any>'onreadystatechange'));
}).not.throw();

delete root.XMLHttpRequest.prototype.onreadystatechange;
});

it('should work fine when XMLHttpRequest ontimeout property is monkey patched', function() {
Object.defineProperty(root.XMLHttpRequest.prototype, 'ontimeout', {
set: function (fn: (e: ProgressEvent) => any) {
const wrapFn = (ev: ProgressEvent) => {
const result = fn.call(this, ev);
if (result === false) {
ev.preventDefault();
}
};
this['_ontimeout'] = wrapFn;
},
get() {
return this['_ontimeout'];
},
configurable: true
});

const ajaxRequest = {
url: '/flibbertyJibbet'
};

Rx.Observable.ajax(ajaxRequest)
.subscribe();

const request = MockXMLHttpRequest.mostRecent;
try {
request.ontimeout((<any>'ontimeout'));
} catch (e) {
expect(e.message).to.equal(new Rx.AjaxTimeoutError((<any>request), ajaxRequest).message);
}
delete root.XMLHttpRequest.prototype.ontimeout;
});

it('should work fine when XMLHttpRequest onprogress property is monkey patched', function() {
Object.defineProperty(root.XMLHttpRequest.prototype, 'onprogress', {
set: function (fn: (e: ProgressEvent) => any) {
const wrapFn = (ev: ProgressEvent) => {
const result = fn.call(this, ev);
if (result === false) {
ev.preventDefault();
}
};
this['_onprogress'] = wrapFn;
},
get() {
return this['_onprogress'];
},
configurable: true
});

Object.defineProperty(root.XMLHttpRequest.prototype, 'upload', {
get() {
return true;
},
configurable: true
});

// mock for onprogress
root.XDomainRequest = true;

Rx.Observable.ajax({
url: '/flibbertyJibbet',
progressSubscriber: (<any>{
next: () => {
// noop
},
error: () => {
// noop
},
complete: () => {
// noop
}
})
})
.subscribe();

const request = MockXMLHttpRequest.mostRecent;

expect(() => {
request.onprogress((<any>'onprogress'));
}).not.throw();

delete root.XMLHttpRequest.prototype.onprogress;
delete root.XMLHttpRequest.prototype.upload;
delete root.XDomainRequest;
});

it('should work fine when XMLHttpRequest onerror property is monkey patched', function() {
Object.defineProperty(root.XMLHttpRequest.prototype, 'onerror', {
set: function (fn: (e: ProgressEvent) => any) {
const wrapFn = (ev: ProgressEvent) => {
const result = fn.call(this, ev);
if (result === false) {
ev.preventDefault();
}
};
this['_onerror'] = wrapFn;
},
get() {
return this['_onerror'];
},
configurable: true
});

Object.defineProperty(root.XMLHttpRequest.prototype, 'upload', {
get() {
return true;
},
configurable: true
});

// mock for onprogress
root.XDomainRequest = true;

Rx.Observable.ajax({
url: '/flibbertyJibbet'
})
.subscribe();

const request = MockXMLHttpRequest.mostRecent;

try {
request.onerror((<any>'onerror'));
} catch (e) {
expect(e.message).to.equal('ajax error');
}

delete root.XMLHttpRequest.prototype.onerror;
delete root.XMLHttpRequest.prototype.upload;
delete root.XDomainRequest;
});
});
22 changes: 22 additions & 0 deletions spec/operators/groupBy-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ declare const {hot, cold, asDiagram, expectObservable, expectSubscriptions};

declare const rxTestScheduler: Rx.TestScheduler;
const Observable = Rx.Observable;
const ReplaySubject = Rx.ReplaySubject;

/** @test {groupBy} */
describe('Observable.prototype.groupBy', () => {
Expand Down Expand Up @@ -98,6 +99,27 @@ describe('Observable.prototype.groupBy', () => {
expect(resultingGroups).to.deep.equal(expectedGroups);
});

it('should group values with a subject selector', (done: MochaDone) => {
const expectedGroups = [
{ key: 1, values: [3] },
{ key: 0, values: [2] }
];

Observable.of(1, 2, 3)
.groupBy((x: number) => x % 2, null, null, () => new ReplaySubject(1))
// Ensure each inner group reaches the destination after the first event
// has been next'd to the group
.delay(5)
.subscribe((g: any) => {
const expectedGroup = expectedGroups.shift();
expect(g.key).to.equal(expectedGroup.key);

g.subscribe((x: any) => {
expect(x).to.deep.equal(expectedGroup.values.shift());
});
}, null, done);
});

it('should handle an empty Observable', () => {
const e1 = cold('|');
const e1subs = '(^!)';
Expand Down
21 changes: 21 additions & 0 deletions spec/operators/multicast-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ declare const {hot, cold, asDiagram, expectObservable, expectSubscriptions, time

const Observable = Rx.Observable;
const Subject = Rx.Subject;
const ReplaySubject = Rx.ReplaySubject;

/** @test {multicast} */
describe('Observable.prototype.multicast', () => {
Expand Down Expand Up @@ -89,6 +90,26 @@ describe('Observable.prototype.multicast', () => {
expectSubscriptions(source.subscriptions).toBe(sourceSubs);
});

it('should accept a multicast selector and respect the subject\'s messaging semantics', () => {
const source = cold('-1-2-3----4-|');
const sourceSubs = ['^ !',
' ^ !',
' ^ !'];
const multicasted = source.multicast(() => new ReplaySubject(1),
x => x.concat(x.takeLast(1)));
const expected1 = '-1-2-3----4-(4|)';
const expected2 = ' -1-2-3----4-(4|)';
const expected3 = ' -1-2-3----4-(4|)';
const subscriber1 = hot('a| ').mergeMapTo(multicasted);
const subscriber2 = hot(' b| ').mergeMapTo(multicasted);
const subscriber3 = hot(' c| ').mergeMapTo(multicasted);

expectObservable(subscriber1).toBe(expected1);
expectObservable(subscriber2).toBe(expected2);
expectObservable(subscriber3).toBe(expected3);
expectSubscriptions(source.subscriptions).toBe(sourceSubs);
});

it('should do nothing if connect is not called, despite subscriptions', () => {
const source = cold('--1-2---3-4--5-|');
const sourceSubs = [];
Expand Down
36 changes: 20 additions & 16 deletions src/observable/dom/AjaxObservable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,39 +293,42 @@ export class AjaxSubscriber<T> extends Subscriber<Event> {
private setupEvents(xhr: XMLHttpRequest, request: AjaxRequest) {
const progressSubscriber = request.progressSubscriber;

xhr.ontimeout = function xhrTimeout(e) {
function xhrTimeout(e: ProgressEvent) {
const {subscriber, progressSubscriber, request } = (<any>xhrTimeout);
if (progressSubscriber) {
progressSubscriber.error(e);
}
subscriber.error(new AjaxTimeoutError(this, request)); //TODO: Make betterer.
};
(<any>xhr.ontimeout).request = request;
(<any>xhr.ontimeout).subscriber = this;
(<any>xhr.ontimeout).progressSubscriber = progressSubscriber;

xhr.ontimeout = xhrTimeout;
(<any>xhrTimeout).request = request;
(<any>xhrTimeout).subscriber = this;
(<any>xhrTimeout).progressSubscriber = progressSubscriber;
if (xhr.upload && 'withCredentials' in xhr && root.XDomainRequest) {
if (progressSubscriber) {
xhr.onprogress = function xhrProgress(e) {
let xhrProgress: (e: ProgressEvent) => void;
xhrProgress = function(e: ProgressEvent) {
const { progressSubscriber } = (<any>xhrProgress);
progressSubscriber.next(e);
};
(<any>xhr.onprogress).progressSubscriber = progressSubscriber;
xhr.onprogress = xhrProgress;
(<any>xhrProgress).progressSubscriber = progressSubscriber;
}

xhr.onerror = function xhrError(e) {
let xhrError: (e: ErrorEvent) => void;
xhrError = function(e: ErrorEvent) {
const { progressSubscriber, subscriber, request } = (<any>xhrError);
if (progressSubscriber) {
progressSubscriber.error(e);
}
subscriber.error(new AjaxError('ajax error', this, request));
};
(<any>xhr.onerror).request = request;
(<any>xhr.onerror).subscriber = this;
(<any>xhr.onerror).progressSubscriber = progressSubscriber;
xhr.onerror = xhrError;
(<any>xhrError).request = request;
(<any>xhrError).subscriber = this;
(<any>xhrError).progressSubscriber = progressSubscriber;
}

xhr.onreadystatechange = function xhrReadyStateChange(e) {
function xhrReadyStateChange(e: ProgressEvent) {
const { subscriber, progressSubscriber, request } = (<any>xhrReadyStateChange);
if (this.readyState === 4) {
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
Expand Down Expand Up @@ -354,9 +357,10 @@ export class AjaxSubscriber<T> extends Subscriber<Event> {
}
}
};
(<any>xhr.onreadystatechange).subscriber = this;
(<any>xhr.onreadystatechange).progressSubscriber = progressSubscriber;
(<any>xhr.onreadystatechange).request = request;
xhr.onreadystatechange = xhrReadyStateChange;
(<any>xhrReadyStateChange).subscriber = this;
(<any>xhrReadyStateChange).progressSubscriber = progressSubscriber;
(<any>xhrReadyStateChange).request = request;
}

unsubscribe() {
Expand Down
Loading

0 comments on commit fc4a816

Please sign in to comment.