// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. // /// /// /// /// /// module CorsicaTests { "use strict"; var S = WinJS.Utilities.Scheduler; var global: any = window; function schedulePromise(priority) { var s = new WinJS._Signal(); S.schedule(s.complete.bind(s), priority, null, "Scheduled Promise"); return s.promise; } interface IXHRRequest { type: string; url: string; async: boolean; user: string; password: string; headers: any; } class mockXMLHttpRequest { readyState = 0; _aborted = false; _readyStatePromise = WinJS.Promise.wrap(); _inheritedSchedulerPriority = S.currentPriority; _request: IXHRRequest; responseType: string; onreadystatechange; status: number; response; responseText: string; open(type: string, url: string, async: boolean, user: string, password: string) { this._readyStatePromise = this._readyStatePromise.then(() => { this._request = { type: type, url: url, async: async, user: user, password: password, headers: {} }; this.responseType = "text"; this.readyState = 1; return this._fireonreadystatechange(); }); } _fireonreadystatechange() { if (this._request.async == true) { return WinJS.Promise.timeout().then(() => { if (!this._aborted) { this.onreadystatechange(); } return schedulePromise(this._inheritedSchedulerPriority); }); } else { this.onreadystatechange(); return schedulePromise(this._inheritedSchedulerPriority); } } setRequestHeader(name, value) { this._request.headers[name] = value; } send(data) { this._readyStatePromise = this._readyStatePromise. then(() => { this.readyState = 2; return this._fireonreadystatechange(); }). then(() => { var nextState = () => { var response = this.mockResponse(this._request, data); this.status = response.status; if (this.responseType == "blob") { this.response = response.responseText; } else if (this.responseType == "text" || !this.responseType) { this.responseText = response.responseText; } this.readyState = 4; return this._fireonreadystatechange(); }; if (this._request.async) { return WinJS.Promise.timeout().then(nextState); } else { return nextState(); } }); } abort() { this.readyState = 0; this.onreadystatechange = null; this.status = 0; this._aborted = true; this._readyStatePromise.cancel(); var that = this; this._readyStatePromise = WinJS.Promise.wrap().then(function () { that.readyState = 0; return that._fireonreadystatechange(); }).then(function () { that.onreadystatechange = null; }); } //override me. mockResponse(request: IXHRRequest, data: any) { return { status: 400, responseText: "" }; } } export class XHR { testSimpleGet(complete) { var oldXHR = global.XMLHttpRequest; global.XMLHttpRequest = mockXMLHttpRequest; mockXMLHttpRequest.prototype.mockResponse = function (request) { LiveUnit.Assert.areEqual('GET', request.type); LiveUnit.Assert.areEqual('SimpleFile.txt', request.url); LiveUnit.Assert.areEqual(true, request.async); return { status: 200, responseText: "42" }; } try { var options = { url: 'SimpleFile.txt' }; var callback = function (success, response) { LiveUnit.Assert.areEqual(true, success, "File not successfully retrieved with XHR"); LiveUnit.Assert.areEqual("42", response.responseText); complete(); } WinJS.xhr(options). then( function (req) { callback(true, req); }, function (req) { callback(false, req); } ); } finally { global.XMLHttpRequest = oldXHR; } } testSimpleGetBlob(complete) { var oldXHR = global.XMLHttpRequest; global.XMLHttpRequest = mockXMLHttpRequest; mockXMLHttpRequest.prototype.mockResponse = function (request) { LiveUnit.Assert.areEqual('GET', request.type); LiveUnit.Assert.areEqual('SimpleFile.txt', request.url); LiveUnit.Assert.areEqual('blob', this.responseType); LiveUnit.Assert.areEqual(true, request.async); return { status: 200, responseText: "42" }; } try { var options = { url: 'SimpleFile.txt', responseType: 'blob' }; var callback = function (success, response) { LiveUnit.Assert.areEqual(true, success, "File not successfully retrieved with XHR"); LiveUnit.Assert.areEqual("42", response.response); complete(); } WinJS.xhr(options). then( function (req) { callback(true, req); }, function (req) { callback(false, req); } ); } finally { global.XMLHttpRequest = oldXHR; } } testSimpleGetError(complete) { var oldXHR = global.XMLHttpRequest; global.XMLHttpRequest = mockXMLHttpRequest; mockXMLHttpRequest.prototype.mockResponse = function (request) { LiveUnit.Assert.areEqual('GET', request.type); LiveUnit.Assert.areEqual('SimpleFile.txt', request.url); LiveUnit.Assert.areEqual(true, request.async); return { status: 404, responseText: "" }; } try { var options = { url: 'SimpleFile.txt' }; var callback = function (success, response) { LiveUnit.Assert.areEqual(false, success, "Expected file not to be retrieved."); complete(); } WinJS.xhr(options). then( function (req) { callback(true, req); }, function (req) { callback(false, req); } ); } finally { global.XMLHttpRequest = oldXHR; } } testPost(complete) { var oldXHR = global.XMLHttpRequest; global.XMLHttpRequest = mockXMLHttpRequest; mockXMLHttpRequest.prototype.mockResponse = function (request, data) { LiveUnit.Assert.areEqual('POST', request.type); LiveUnit.Assert.areEqual('posthandler.aspx', request.url); LiveUnit.Assert.areEqual(true, request.async); LiveUnit.Assert.areEqual("somedata", data); LiveUnit.Assert.areEqual("data1", request.headers["Foo"]); LiveUnit.Assert.areEqual("data2", request.headers["Bar"]); return { status: 200, responseText: "woot" }; } try { var options = { url: 'posthandler.aspx', type: 'POST', data: 'somedata', headers: { "Foo": "data1", "Bar": "data2" } } var callback = function (success, response) { LiveUnit.Assert.areEqual(true, success); complete(); } WinJS.xhr(options). then( function (req) { callback(true, req); }, function (req) { callback(false, req); } ); } finally { global.XMLHttpRequest = oldXHR; } } // Verifies that the complete and error handlers of the XHR promise // are executed in the priority context at which the XHR was created. // testPriorityInheritance(complete) { var Scheduler = WinJS.Utilities.Scheduler, Priority = Scheduler.Priority, oldXHR = global.XMLHttpRequest; global.XMLHttpRequest = mockXMLHttpRequest; function test(priority, expectSuccess) { mockXMLHttpRequest.prototype.mockResponse = function (request, data) { return expectSuccess ? { status: 200, responseText: "woot" } : { status: 404, responseText: "" }; } return new WinJS.Promise(function (subTestComplete) { Scheduler.schedule(function () { var async = false; var options = { url: 'posthandler.aspx', type: 'POST', data: 'somedata', headers: { "Foo": "data1", "Bar": "data2" } } var done = function (success) { LiveUnit.Assert.isTrue(async, "Request should have completed asynchronously relative to creation of XHR"); LiveUnit.Assert.areEqual(success, expectSuccess, "Request unexpectedly completed (un)successfully"); LiveUnit.Assert.areEqual(priority, Scheduler.currentPriority, "Request completed in wrong priority context"); subTestComplete(); }; WinJS.xhr(options). then( function (req) { done(true); }, function (req) { done(false); } ); async = true; }, priority); }); } var promise = WinJS.Promise.wrap(); [Priority.high, Priority.normal, Priority.idle].forEach(function (priority) { [true, false].forEach(function (success) { promise = promise.then(function () { return test(priority, success); }); }); }); promise.then(function () { global.XMLHttpRequest = oldXHR; complete(); }); } testAbort(complete) { var oldXHR = global.XMLHttpRequest; global.XMLHttpRequest = mockXMLHttpRequest; mockXMLHttpRequest.prototype.mockResponse = function (request) { return { status: 200, responseText: "42" }; } try { var options = { url: 'SimpleFile.txt' }; var hitCompleteCount = 0, hitErrorCount = 0; var request = WinJS.xhr(options); request.then( function () { hitCompleteCount++; }, function () { hitErrorCount++; } ); request.cancel(); global.setTimeout(function () { LiveUnit.Assert.areEqual(0, hitCompleteCount); LiveUnit.Assert.areEqual(1, hitErrorCount); complete(); }, 1); } finally { global.XMLHttpRequest = oldXHR; } } testReadyStateChange(complete) { var oldXHR = global.XMLHttpRequest; global.XMLHttpRequest = mockXMLHttpRequest; mockXMLHttpRequest.prototype.mockResponse = function (request) { return { status: 200, responseText: "42" }; } try { var options = { url: 'SimpleFile.txt', async: false }; var progress = [ { readyState: 1, status: undefined, responseText: undefined }, { readyState: 2, status: undefined, responseText: undefined } ]; var progressPos = -1; var callback = function (success) { LiveUnit.Assert.areEqual(true, success); LiveUnit.Assert.areEqual(1, progressPos); WinJS.Utilities._setImmediate(complete); } WinJS.xhr(options). then( function (req) { LiveUnit.Assert.areEqual(4, req.readyState); LiveUnit.Assert.areEqual(200, req.status); LiveUnit.Assert.areEqual("42", req.responseText); }, function (req) { LiveUnit.Assert.fail("Response should be successful"); }, function (req) { var expected = progress[++progressPos]; LiveUnit.Assert.areEqual(expected.readyState, req.readyState); LiveUnit.Assert.areEqual(expected.status, req.status); LiveUnit.Assert.areEqual(expected.responseText, req.responseText); } ).then( function () { callback(true); }, function () { callback(false); }); } finally { global.XMLHttpRequest = oldXHR; } } testXHR100(complete) { var fragmentFiles = ["FragmentBasic.html", "FragmentFindmeInternal.html", "FragmentWithExternalScriptAndStyles.html", "FragmentWithScriptAndStyles.html", "FragmentWithScriptAndStylesNoBody.html", "FragmentWithScriptAndStylesNoBodyNoLoad.html"]; var numFragments = 200; var href; var xhrPromises = []; for (var i = 0; i < numFragments; i++) { // get one of the fragment files from the array href = fragmentFiles[i % fragmentFiles.length]; xhrPromises.push(WinJS.xhr({ url: href })); } WinJS.Promise.join(xhrPromises). done(function (results) { complete(); }, function (error) { LiveUnit.Assert.fail("error from Promise.join: " + error); complete(); }); } testCustomRequestInitializer(complete) { var isCallbackCalled = false; function customRequestInitializerFunction(req) { isCallbackCalled = true; } var oldXHR = global.XMLHttpRequest; global.XMLHttpRequest = mockXMLHttpRequest; mockXMLHttpRequest.prototype.mockResponse = function (request, data) { return { status: 200, responseText: "" }; } try { var options = { url: 'SimpleFile.txt', customRequestInitializer: customRequestInitializerFunction }; // var callback = function (success) { LiveUnit.Assert.areEqual(true, isCallbackCalled, "customRequestInitializer is not called"); LiveUnit.Assert.areEqual(true, success, "File not successfully retrieved with XHR"); complete(); } WinJS.xhr(options). then( function () { callback(true); }, function () { callback(false); } ); } finally { global.XMLHttpRequest = oldXHR; } } // Cordova returns status of '0' when successfully retrieving local // file system resources with the file:// protocol. testCordovaXHR(complete) { var oldXHR = global.XMLHttpRequest; global.XMLHttpRequest = mockXMLHttpRequest; mockXMLHttpRequest.prototype.mockResponse = function (request) { LiveUnit.Assert.areEqual('GET', request.type); LiveUnit.Assert.areEqual('file://SimpleFile.txt', request.url); LiveUnit.Assert.areEqual(true, request.async); return { status: 0, responseText: "42" }; } try { var options = { url: 'file://SimpleFile.txt' }; var callback = function (success, response) { LiveUnit.Assert.areEqual(true, success, "File not successfully retrieved with XHR"); LiveUnit.Assert.areEqual("42", response.responseText); complete(); } WinJS.xhr(options). then( function (req) { callback(true, req); }, function (req) { callback(false, req); } ); } finally { global.XMLHttpRequest = oldXHR; } } }; } LiveUnit.registerTestClass("CorsicaTests.XHR");