| // Copyright 2007 The Closure Library Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS-IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| goog.provide('goog.net.XhrIoTest'); |
| goog.setTestOnly('goog.net.XhrIoTest'); |
| |
| goog.require('goog.Uri'); |
| goog.require('goog.debug.EntryPointMonitor'); |
| goog.require('goog.debug.ErrorHandler'); |
| goog.require('goog.debug.entryPointRegistry'); |
| goog.require('goog.events'); |
| goog.require('goog.functions'); |
| goog.require('goog.net.EventType'); |
| goog.require('goog.net.WrapperXmlHttpFactory'); |
| goog.require('goog.net.XhrIo'); |
| goog.require('goog.net.XmlHttp'); |
| goog.require('goog.object'); |
| goog.require('goog.string'); |
| goog.require('goog.testing.MockClock'); |
| goog.require('goog.testing.PropertyReplacer'); |
| goog.require('goog.testing.jsunit'); |
| goog.require('goog.testing.net.XhrIo'); |
| goog.require('goog.testing.recordFunction'); |
| |
| function MockXmlHttp() { |
| /** |
| * The headers for this XmlHttpRequest. |
| * @type {!Object<string>} |
| */ |
| this.headers = {}; |
| } |
| |
| MockXmlHttp.prototype.readyState = goog.net.XmlHttp.ReadyState.UNINITIALIZED; |
| |
| MockXmlHttp.prototype.status = 200; |
| |
| MockXmlHttp.syncSend = false; |
| |
| MockXmlHttp.prototype.send = function(opt_data) { |
| this.readyState = goog.net.XmlHttp.ReadyState.UNINITIALIZED; |
| |
| if (MockXmlHttp.syncSend) { |
| this.complete(); |
| } |
| |
| }; |
| |
| MockXmlHttp.prototype.complete = function() { |
| this.readyState = goog.net.XmlHttp.ReadyState.LOADING; |
| this.onreadystatechange(); |
| |
| this.readyState = goog.net.XmlHttp.ReadyState.LOADED; |
| this.onreadystatechange(); |
| |
| this.readyState = goog.net.XmlHttp.ReadyState.INTERACTIVE; |
| this.onreadystatechange(); |
| |
| this.readyState = goog.net.XmlHttp.ReadyState.COMPLETE; |
| this.onreadystatechange(); |
| }; |
| |
| |
| MockXmlHttp.prototype.open = function(verb, uri, async) { |
| }; |
| |
| MockXmlHttp.prototype.abort = function() {}; |
| |
| MockXmlHttp.prototype.setRequestHeader = function(key, value) { |
| this.headers[key] = value; |
| }; |
| |
| var lastMockXmlHttp; |
| goog.net.XmlHttp.setGlobalFactory(new goog.net.WrapperXmlHttpFactory( |
| function() { |
| lastMockXmlHttp = new MockXmlHttp(); |
| return lastMockXmlHttp; |
| }, |
| function() { |
| return {}; |
| })); |
| |
| |
| var propertyReplacer = new goog.testing.PropertyReplacer(); |
| var clock; |
| var originalEntryPoint = |
| goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_; |
| |
| function setUp() { |
| lastMockXmlHttp = null; |
| clock = new goog.testing.MockClock(true); |
| } |
| |
| function tearDown() { |
| propertyReplacer.reset(); |
| clock.dispose(); |
| goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = originalEntryPoint; |
| } |
| |
| |
| function testSyncSend() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertTrue('Should be succesful', e.target.isSuccess()); |
| count++; |
| |
| }); |
| |
| var inSend = true; |
| x.send('url'); |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| function testSyncSendFailure() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertFalse('Should not be succesful', e.target.isSuccess()); |
| count++; |
| }); |
| |
| var inSend = true; |
| x.send('url'); |
| lastMockXmlHttp.status = 404; |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testSendRelativeZeroStatus() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertEquals('Should be the same as ', e.target.isSuccess(), |
| window.location.href.toLowerCase().indexOf('file:') == 0); |
| count++; |
| }); |
| |
| var inSend = true; |
| x.send('relative'); |
| lastMockXmlHttp.status = 0; |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testSendRelativeUriZeroStatus() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertEquals('Should be the same as ', e.target.isSuccess(), |
| window.location.href.toLowerCase().indexOf('file:') == 0); |
| count++; |
| }); |
| |
| var inSend = true; |
| x.send(goog.Uri.parse('relative')); |
| lastMockXmlHttp.status = 0; |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testSendHttpZeroStatusFailure() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertFalse('Should not be succesful', e.target.isSuccess()); |
| count++; |
| }); |
| |
| var inSend = true; |
| x.send('http://foo'); |
| lastMockXmlHttp.status = 0; |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testSendHttpUpperZeroStatusFailure() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertFalse('Should not be succesful', e.target.isSuccess()); |
| count++; |
| }); |
| |
| var inSend = true; |
| x.send('HTTP://foo'); |
| lastMockXmlHttp.status = 0; |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testSendHttpUpperUriZeroStatusFailure() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertFalse('Should not be succesful', e.target.isSuccess()); |
| count++; |
| }); |
| |
| var inSend = true; |
| x.send(goog.Uri.parse('HTTP://foo')); |
| lastMockXmlHttp.status = 0; |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testSendHttpUriZeroStatusFailure() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertFalse('Should not be succesful', e.target.isSuccess()); |
| count++; |
| }); |
| |
| var inSend = true; |
| x.send(goog.Uri.parse('http://foo')); |
| lastMockXmlHttp.status = 0; |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testSendHttpUriZeroStatusFailure() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertFalse('Should not be succesful', e.target.isSuccess()); |
| count++; |
| }); |
| |
| var inSend = true; |
| x.send(goog.Uri.parse('HTTP://foo')); |
| lastMockXmlHttp.status = 0; |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testSendHttpsZeroStatusFailure() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertFalse('Should not be succesful', e.target.isSuccess()); |
| count++; |
| }); |
| |
| var inSend = true; |
| x.send('https://foo'); |
| lastMockXmlHttp.status = 0; |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testSendFileUpperZeroStatusSuccess() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertTrue('Should not be succesful', e.target.isSuccess()); |
| count++; |
| }); |
| |
| var inSend = true; |
| x.send('FILE:///foo'); |
| lastMockXmlHttp.status = 0; |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testSendFileUriZeroStatusSuccess() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertTrue('Should not be succesful', e.target.isSuccess()); |
| count++; |
| }); |
| |
| var inSend = true; |
| x.send(goog.Uri.parse('file:///foo')); |
| lastMockXmlHttp.status = 0; |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testSendDummyUriZeroStatusSuccess() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertTrue('Should not be succesful', e.target.isSuccess()); |
| count++; |
| }); |
| |
| var inSend = true; |
| x.send(goog.Uri.parse('dummy:///foo')); |
| lastMockXmlHttp.status = 0; |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testSendFileUpperUriZeroStatusSuccess() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertFalse('Should not fire complete from inside send', inSend); |
| assertTrue('Should not be succesful', e.target.isSuccess()); |
| count++; |
| }); |
| |
| var inSend = true; |
| x.send(goog.Uri.parse('FILE:///foo')); |
| lastMockXmlHttp.status = 0; |
| inSend = false; |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testSendFromListener() { |
| MockXmlHttp.syncSend = true; |
| var count = 0; |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| count++; |
| |
| var e = assertThrows(function() { |
| x.send('url2'); |
| }); |
| assertEquals('[goog.net.XhrIo] Object is active with another request=url' + |
| '; newUri=url2', e.message); |
| }); |
| |
| x.send('url'); |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| |
| assertEquals('Complete should have been called once', 1, count); |
| } |
| |
| |
| function testStatesDuringEvents() { |
| MockXmlHttp.syncSend = true; |
| |
| var x = new goog.net.XhrIo; |
| var readyState = goog.net.XmlHttp.ReadyState.UNINITIALIZED; |
| goog.events.listen(x, goog.net.EventType.READY_STATE_CHANGE, function(e) { |
| readyState++; |
| assertObjectEquals(e.target, x); |
| assertEquals(x.getReadyState(), readyState); |
| assertTrue(x.isActive()); |
| }); |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| assertObjectEquals(e.target, x); |
| assertTrue(x.isActive()); |
| }); |
| goog.events.listen(x, goog.net.EventType.SUCCESS, function(e) { |
| assertObjectEquals(e.target, x); |
| assertTrue(x.isActive()); |
| }); |
| goog.events.listen(x, goog.net.EventType.READY, function(e) { |
| assertObjectEquals(e.target, x); |
| assertFalse(x.isActive()); |
| }); |
| |
| x.send('url'); |
| |
| clock.tick(1); // callOnce(f, 0, ...) |
| } |
| |
| |
| function testProtectEntryPointCalledOnAsyncSend() { |
| MockXmlHttp.syncSend = false; |
| |
| var errorHandlerCallbackCalled = false; |
| var errorHandler = new goog.debug.ErrorHandler(function() { |
| errorHandlerCallbackCalled = true; |
| }); |
| |
| goog.net.XhrIo.protectEntryPoints(errorHandler); |
| |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.READY_STATE_CHANGE, function(e) { |
| throw Error(); |
| }); |
| |
| x.send('url'); |
| assertThrows(function() { |
| lastMockXmlHttp.complete(); |
| }); |
| |
| assertTrue('Error handler callback should be called on async send.', |
| errorHandlerCallbackCalled); |
| } |
| |
| function testXHRIsDiposedEvenIfAListenerThrowsAnExceptionOnComplete() { |
| MockXmlHttp.syncSend = false; |
| |
| var x = new goog.net.XhrIo; |
| |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| throw Error(); |
| }, false, x); |
| |
| x.send('url'); |
| assertThrows(function() { |
| lastMockXmlHttp.complete(); |
| }); |
| |
| // The XHR should have been disposed, even though the listener threw an |
| // exception. |
| assertNull(x.xhr_); |
| } |
| |
| function testDisposeInternalDoesNotAbortXhrRequestObjectWhenActiveIsFalse() { |
| MockXmlHttp.syncSend = false; |
| |
| var xmlHttp = goog.net.XmlHttp; |
| var abortCalled = false; |
| var x = new goog.net.XhrIo; |
| |
| goog.net.XmlHttp.prototype.abort = function() { abortCalled = true; }; |
| |
| goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { |
| this.active_ = false; |
| this.dispose(); |
| }, false, x); |
| |
| x.send('url'); |
| lastMockXmlHttp.complete(); |
| |
| goog.net.XmlHttp = xmlHttp; |
| assertFalse(abortCalled); |
| } |
| |
| function testCallingAbortFromWithinAbortCallbackDoesntLoop() { |
| var x = new goog.net.XhrIo; |
| goog.events.listen(x, goog.net.EventType.ABORT, function(e) { |
| x.abort(); // Shouldn't get a stack overflow |
| }); |
| x.send('url'); |
| x.abort(); |
| } |
| |
| function testPostSetsContentTypeHeader() { |
| var x = new goog.net.XhrIo; |
| |
| x.send('url', 'POST', 'content'); |
| var headers = lastMockXmlHttp.headers; |
| assertEquals(1, goog.object.getCount(headers)); |
| assertEquals( |
| headers[goog.net.XhrIo.CONTENT_TYPE_HEADER], |
| goog.net.XhrIo.FORM_CONTENT_TYPE); |
| } |
| |
| function testNonPostSetsContentTypeHeader() { |
| var x = new goog.net.XhrIo; |
| |
| x.send('url', 'PUT', 'content'); |
| headers = lastMockXmlHttp.headers; |
| assertEquals(1, goog.object.getCount(headers)); |
| assertEquals( |
| headers[goog.net.XhrIo.CONTENT_TYPE_HEADER], |
| goog.net.XhrIo.FORM_CONTENT_TYPE); |
| } |
| |
| function testContentTypeIsTreatedCaseInsensitively() { |
| var x = new goog.net.XhrIo; |
| |
| x.send('url', 'POST', 'content', {'content-type': 'testing'}); |
| |
| assertObjectEquals( |
| 'Headers should not be modified since they already contain a ' + |
| 'content type definition', |
| {'content-type': 'testing'}, |
| lastMockXmlHttp.headers); |
| } |
| |
| function testIsContentTypeHeader_() { |
| assertTrue(goog.net.XhrIo.isContentTypeHeader_('content-type')); |
| assertTrue(goog.net.XhrIo.isContentTypeHeader_('Content-type')); |
| assertTrue(goog.net.XhrIo.isContentTypeHeader_('CONTENT-TYPE')); |
| assertTrue(goog.net.XhrIo.isContentTypeHeader_('Content-Type')); |
| assertFalse(goog.net.XhrIo.isContentTypeHeader_('Content Type')); |
| } |
| |
| function testPostFormDataDoesNotSetContentTypeHeader() { |
| function FakeFormData() {} |
| |
| propertyReplacer.set(goog.global, 'FormData', FakeFormData); |
| |
| var x = new goog.net.XhrIo; |
| x.send('url', 'POST', new FakeFormData()); |
| var headers = lastMockXmlHttp.headers; |
| assertTrue(goog.object.isEmpty(headers)); |
| } |
| |
| function testNonPostFormDataDoesNotSetContentTypeHeader() { |
| function FakeFormData() {} |
| |
| propertyReplacer.set(goog.global, 'FormData', FakeFormData); |
| |
| var x = new goog.net.XhrIo; |
| x.send('url', 'PUT', new FakeFormData()); |
| headers = lastMockXmlHttp.headers; |
| assertTrue(goog.object.isEmpty(headers)); |
| } |
| |
| function testFactoryInjection() { |
| var xhr = new MockXmlHttp(); |
| var optionsFactoryCalled = 0; |
| var xhrFactoryCalled = 0; |
| var wrapperFactory = new goog.net.WrapperXmlHttpFactory( |
| function() { |
| xhrFactoryCalled++; |
| return xhr; |
| }, |
| function() { |
| optionsFactoryCalled++; |
| return {}; |
| }); |
| var xhrIo = new goog.net.XhrIo(wrapperFactory); |
| |
| xhrIo.send('url'); |
| |
| assertEquals('XHR factory should have been called', 1, xhrFactoryCalled); |
| assertEquals('Options factory should have been called', 1, |
| optionsFactoryCalled); |
| } |
| |
| function testGoogTestingNetXhrIoIsInSync() { |
| var xhrIo = new goog.net.XhrIo(); |
| var testingXhrIo = new goog.testing.net.XhrIo(); |
| |
| var propertyComparator = function(value, key, obj) { |
| if (goog.string.endsWith(key, '_')) { |
| // Ignore private properties/methods |
| return true; |
| } else if (typeof value == 'function' && typeof this[key] != 'function') { |
| // Only type check is sufficient for functions |
| fail('Mismatched property:' + key + ': gooo.net.XhrIo has:<' + |
| value + '>; while goog.testing.net.XhrIo has:<' + this[key] + '>'); |
| return true; |
| } else { |
| // Ignore all other type of properties. |
| return true; |
| } |
| }; |
| |
| goog.object.every(xhrIo, propertyComparator, testingXhrIo); |
| } |
| |
| function testEntryPointRegistry() { |
| var monitor = new goog.debug.EntryPointMonitor(); |
| var replacement = function() {}; |
| monitor.wrap = goog.testing.recordFunction( |
| goog.functions.constant(replacement)); |
| |
| goog.debug.entryPointRegistry.monitorAll(monitor); |
| assertTrue(monitor.wrap.getCallCount() >= 1); |
| assertEquals( |
| replacement, |
| goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_); |
| } |
| |
| function testSetWithCredentials() { |
| // Test on XHR objects that don't have the withCredentials property (older |
| // browsers). |
| var x = new goog.net.XhrIo; |
| x.setWithCredentials(true); |
| x.send('url'); |
| assertFalse( |
| 'withCredentials should not be set on an XHR object if the property ' + |
| 'does not exist.', |
| goog.object.containsKey(lastMockXmlHttp, 'withCredentials')); |
| |
| // Test on XHR objects that have the withCredentials property. |
| MockXmlHttp.prototype.withCredentials = false; |
| x = new goog.net.XhrIo; |
| x.setWithCredentials(true); |
| x.send('url'); |
| assertTrue( |
| 'withCredentials should be set on an XHR object if the property exists', |
| goog.object.containsKey(lastMockXmlHttp, 'withCredentials')); |
| |
| assertTrue( |
| 'withCredentials value not set on XHR object', |
| lastMockXmlHttp.withCredentials); |
| |
| // Reset the prototype so it does not effect other tests. |
| delete MockXmlHttp.prototype.withCredentials; |
| } |
| |
| function testGetResponse() { |
| var x = new goog.net.XhrIo; |
| |
| // No XHR yet |
| assertEquals(null, x.getResponse()); |
| |
| // XHR with no .response and no response type, gets text. |
| x.xhr_ = {}; |
| x.xhr_.responseText = 'text'; |
| assertEquals('text', x.getResponse()); |
| |
| // Response type of text gets text as well. |
| x.setResponseType(goog.net.XhrIo.ResponseType.TEXT); |
| x.xhr_.responseText = ''; |
| assertEquals('', x.getResponse()); |
| |
| // Response type of array buffer gets the array buffer. |
| x.xhr_.mozResponseArrayBuffer = 'ab'; |
| x.setResponseType(goog.net.XhrIo.ResponseType.ARRAY_BUFFER); |
| assertEquals('ab', x.getResponse()); |
| |
| // With a response field, it is returned no matter what value it has. |
| x.xhr_.response = undefined; |
| assertEquals(undefined, x.getResponse()); |
| |
| x.xhr_.response = null; |
| assertEquals(null, x.getResponse()); |
| |
| x.xhr_.response = ''; |
| assertEquals('', x.getResponse()); |
| |
| x.xhr_.response = 'resp'; |
| assertEquals('resp', x.getResponse()); |
| } |
| |
| function testGetResponseHeaders() { |
| var x = new goog.net.XhrIo(); |
| |
| // No XHR yet |
| assertEquals(0, goog.object.getCount(x.getResponseHeaders())); |
| |
| // Simulate an XHR with 2 headers. |
| var headersRaw = 'test1: foo\r\ntest2: bar'; |
| |
| propertyReplacer.set(x, 'getAllResponseHeaders', |
| goog.functions.constant(headersRaw)); |
| |
| var headers = x.getResponseHeaders(); |
| assertEquals(2, goog.object.getCount(headers)); |
| assertEquals('foo', headers['test1']); |
| assertEquals('bar', headers['test2']); |
| } |
| |
| function testGetResponseHeadersWithColonInValue() { |
| var x = new goog.net.XhrIo(); |
| |
| // Simulate an XHR with a colon in the http header value. |
| var headersRaw = 'test1: f:o:o'; |
| |
| propertyReplacer.set(x, 'getAllResponseHeaders', |
| goog.functions.constant(headersRaw)); |
| |
| var headers = x.getResponseHeaders(); |
| assertEquals(1, goog.object.getCount(headers)); |
| assertEquals('f:o:o', headers['test1']); |
| } |
| |
| function testGetResponseHeadersMultipleValuesForOneKey() { |
| var x = new goog.net.XhrIo(); |
| |
| // No XHR yet |
| assertEquals(0, goog.object.getCount(x.getResponseHeaders())); |
| |
| // Simulate an XHR with 2 headers. |
| var headersRaw = 'test1: foo\r\ntest1: bar'; |
| |
| propertyReplacer.set(x, 'getAllResponseHeaders', |
| goog.functions.constant(headersRaw)); |
| |
| var headers = x.getResponseHeaders(); |
| assertEquals(1, goog.object.getCount(headers)); |
| assertEquals('foo, bar', headers['test1']); |
| } |
| |
| function testGetResponseHeadersEmptyHeader() { |
| var x = new goog.net.XhrIo(); |
| |
| // No XHR yet |
| assertEquals(0, goog.object.getCount(x.getResponseHeaders())); |
| |
| // Simulate an XHR with 2 headers, the last of which is empty. |
| var headersRaw = 'test2: bar\r\n'; |
| |
| propertyReplacer.set(x, 'getAllResponseHeaders', |
| goog.functions.constant(headersRaw)); |
| |
| var headers = x.getResponseHeaders(); |
| assertEquals(1, goog.object.getCount(headers)); |
| assertEquals('bar', headers['test2']); |
| } |