123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- // Copyright 2006 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.ImageLoaderTest');
- goog.setTestOnly('goog.net.ImageLoaderTest');
- goog.require('goog.Promise');
- goog.require('goog.Timer');
- goog.require('goog.array');
- goog.require('goog.dispose');
- goog.require('goog.events');
- goog.require('goog.events.Event');
- goog.require('goog.events.EventType');
- goog.require('goog.net.EventType');
- goog.require('goog.net.ImageLoader');
- goog.require('goog.object');
- goog.require('goog.string');
- goog.require('goog.testing.TestCase');
- goog.require('goog.testing.jsunit');
- goog.require('goog.testing.recordFunction');
- var TEST_EVENT_TYPES = [
- goog.events.EventType.LOAD, goog.net.EventType.COMPLETE,
- goog.net.EventType.ERROR
- ];
- /**
- * Mapping from test image file name to:
- * [expected width, expected height, expected event to be fired].
- */
- var TEST_IMAGES = {
- 'imageloader_testimg1.gif': [20, 20, goog.events.EventType.LOAD],
- 'imageloader_testimg2.gif': [20, 20, goog.events.EventType.LOAD],
- 'imageloader_testimg3.gif': [32, 32, goog.events.EventType.LOAD],
- 'this-is-not-image-1.gif': [0, 0, goog.net.EventType.ERROR],
- 'this-is-not-image-2.gif': [0, 0, goog.net.EventType.ERROR]
- };
- var startTime;
- var loader;
- function setUpPage() {
- // Increase the timeout to 5 seconds to allow more time for images to load.
- goog.testing.TestCase.getActiveTestCase().promiseTimeout = 5 * 1000;
- }
- function setUp() {
- startTime = goog.now();
- loader = new goog.net.ImageLoader();
- // Adds test images to the loader.
- var i = 0;
- for (var key in TEST_IMAGES) {
- var imageId = 'img_' + i++;
- loader.addImage(imageId, key);
- }
- }
- function tearDown() {
- goog.dispose(loader);
- }
- /**
- * Tests loading image and disposing before loading completes.
- */
- function testDisposeInTheMiddleOfLoadingWorks() {
- var resolver = goog.Promise.withResolver();
- goog.events.listen(loader, TEST_EVENT_TYPES, function(e) {
- assertFalse(
- 'Handler is still invoked after loader is disposed.',
- loader.isDisposed());
- switch (e.type) {
- case goog.net.EventType.COMPLETE:
- resolver.reject('This test should never get COMPLETE event.');
- return;
- case goog.events.EventType.LOAD:
- case goog.net.EventType.ERROR:
- loader.dispose();
- break;
- }
- // Make sure that handler is never called again after disposal before
- // marking test as successful.
- goog.Timer.callOnce(function() { resolver.resolve(); }, 500);
- });
- loader.start();
- return resolver.promise;
- }
- /**
- * Tests loading of images until completion.
- */
- function testLoadingUntilCompletion() {
- var resolver = goog.Promise.withResolver();
- var results = {};
- goog.events.listen(loader, TEST_EVENT_TYPES, function(e) {
- switch (e.type) {
- case goog.events.EventType.LOAD:
- var image = e.target;
- results[image.src.substring(image.src.lastIndexOf('/') + 1)] =
- [image.naturalWidth, image.naturalHeight, e.type];
- return;
- case goog.net.EventType.ERROR:
- var image = e.target;
- results[image.src.substring(image.src.lastIndexOf('/') + 1)] =
- [image.naturalWidth, image.naturalHeight, e.type];
- return;
- case goog.net.EventType.COMPLETE:
- try {
- assertImagesAreCorrect(results);
- } catch (e) {
- resolver.reject(e);
- return;
- }
- resolver.resolve();
- return;
- }
- });
- loader.start();
- return resolver.promise;
- }
- function assertImagesAreCorrect(results) {
- assertEquals(
- goog.object.getCount(TEST_IMAGES), goog.object.getCount(results));
- goog.object.forEach(TEST_IMAGES, function(value, key) {
- // Check if fires the COMPLETE event.
- assertTrue('Image is not loaded completely.', key in results);
- var image = results[key];
- // Check image size.
- assertEquals('Image width is not correct', value[0], image[0]);
- assertEquals('Image length is not correct', value[1], image[1]);
- // Check if fired the correct event.
- assertEquals('Event *' + value[2] + '* must be fired', value[2], image[2]);
- });
- }
- /**
- * Overrides the loader's loadImage_ method so that it dispatches an image
- * loaded event immediately, causing any event listeners to receive them
- * synchronously. This allows tests to assume synchronous execution.
- */
- function makeLoaderSynchronous(loader) {
- var originalLoadImage = loader.loadImage_;
- loader.loadImage_ = function(request, id) {
- originalLoadImage.call(this, request, id);
- var event = new goog.events.Event(goog.events.EventType.LOAD);
- event.currentTarget = this.imageIdToImageMap_[id];
- loader.onNetworkEvent_(event);
- };
- // Make listen() a no-op.
- loader.handler_.listen = goog.nullFunction;
- }
- /**
- * Verifies that if an additional image is added after start() was called, but
- * before COMPLETE was dispatched, no COMPLETE event is sent. Verifies COMPLETE
- * is finally sent when .start() is called again and all images have now
- * completed loading.
- */
- function testImagesAddedAfterStart() {
- // Use synchronous image loading.
- makeLoaderSynchronous(loader);
- // Add another image once the first images finishes loading.
- goog.events.listenOnce(loader, goog.events.EventType.LOAD, function() {
- loader.addImage('extra_image', 'extra_image.gif');
- });
- // Keep track of the total # of image loads.
- var loadRecordFn = goog.testing.recordFunction();
- goog.events.listen(loader, goog.events.EventType.LOAD, loadRecordFn);
- // Keep track of how many times COMPLETE was dispatched.
- var completeRecordFn = goog.testing.recordFunction();
- goog.events.listen(loader, goog.net.EventType.COMPLETE, completeRecordFn);
- // Start testing.
- loader.start();
- assertEquals(
- 'COMPLETE event should not have been dispatched yet: An image was ' +
- 'added after the initial batch was started.',
- 0, completeRecordFn.getCallCount());
- assertEquals(
- 'Just the test images should have loaded',
- goog.object.getCount(TEST_IMAGES), loadRecordFn.getCallCount());
- loader.start();
- assertEquals(
- 'COMPLETE should have been dispatched once.', 1,
- completeRecordFn.getCallCount());
- assertEquals(
- 'All images should have been loaded',
- goog.object.getCount(TEST_IMAGES) + 1, loadRecordFn.getCallCount());
- }
- /**
- * Verifies that more images can be added after an upload starts, and start()
- * can be called for them, resulting in just one COMPLETE event once all the
- * images have completed.
- */
- function testImagesAddedAndStartedAfterStart() {
- // Use synchronous image loading.
- makeLoaderSynchronous(loader);
- // Keep track of the total # of image loads.
- var loadRecordFn = goog.testing.recordFunction();
- goog.events.listen(loader, goog.events.EventType.LOAD, loadRecordFn);
- // Add more images once the first images finishes loading, and call start()
- // to get them going.
- goog.events.listenOnce(loader, goog.events.EventType.LOAD, function(e) {
- loader.addImage('extra_image', 'extra_image.gif');
- loader.addImage('extra_image2', 'extra_image2.gif');
- loader.start();
- });
- // Keep track of how many times COMPLETE was dispatched.
- var completeRecordFn = goog.testing.recordFunction();
- goog.events.listen(loader, goog.net.EventType.COMPLETE, completeRecordFn);
- // Start testing. Make sure all 7 images loaded.
- loader.start();
- assertEquals(
- 'COMPLETE should have been dispatched once.', 1,
- completeRecordFn.getCallCount());
- assertEquals(
- 'All images should have been loaded',
- goog.object.getCount(TEST_IMAGES) + 2, loadRecordFn.getCallCount());
- }
- /**
- * Verifies that if images are removed after loading has started, COMPLETE
- * is dispatched once the remaining images have finished.
- */
- function testImagesRemovedAfterStart() {
- // Use synchronous image loading.
- makeLoaderSynchronous(loader);
- // Remove 2 images once the first image finishes loading.
- goog.events.listenOnce(loader, goog.events.EventType.LOAD, function(e) {
- loader.removeImage(
- goog.array.peek(goog.object.getKeys(this.imageIdToRequestMap_)));
- loader.removeImage(
- goog.array.peek(goog.object.getKeys(this.imageIdToRequestMap_)));
- });
- // Keep track of the total # of image loads.
- var loadRecordFn = goog.testing.recordFunction();
- goog.events.listen(loader, goog.events.EventType.LOAD, loadRecordFn);
- // Keep track of how many times COMPLETE was dispatched.
- var completeRecordFn = goog.testing.recordFunction();
- goog.events.listen(loader, goog.net.EventType.COMPLETE, completeRecordFn);
- // Start testing. Make sure only the 3 images remaining loaded.
- loader.start();
- assertEquals(
- 'COMPLETE should have been dispatched once.', 1,
- completeRecordFn.getCallCount());
- assertEquals(
- 'All images should have been loaded',
- goog.object.getCount(TEST_IMAGES) - 2, loadRecordFn.getCallCount());
- }
- /**
- * Verifies that the correct image attribute is set when using CORS requests.
- */
- function testSetsCorsAttribute() {
- // Use synchronous image loading.
- makeLoaderSynchronous(loader);
- // Verify the crossOrigin attribute of the requested images.
- goog.events.listen(loader, goog.events.EventType.LOAD, function(e) {
- var image = e.target;
- if (image.id == 'cors_request') {
- assertEquals(
- 'CORS requested image should have a crossOrigin attribute set',
- 'anonymous', image.crossOrigin);
- } else {
- assertTrue(
- 'Non-CORS requested images should not have a crossOrigin attribute',
- goog.string.isEmptyOrWhitespace(
- goog.string.makeSafe(image.crossOrigin)));
- }
- });
- // Make a new request for one of the images, this time using CORS.
- var srcs = goog.object.getKeys(TEST_IMAGES);
- loader.addImage(
- 'cors_request', srcs[0], goog.net.ImageLoader.CorsRequestType.ANONYMOUS);
- loader.start();
- }
|