diff --git a/src/openseadragon.js b/src/openseadragon.js index 4f4e9752..d5688aed 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -882,47 +882,49 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){ /** * Wraps the given element in a nest of divs so that the element can - * be easily centered. + * be easily centered using CSS tables * @function * @name OpenSeadragon.makeCenteredNode * @param {Element|String} element - * @returns {Element} + * @returns {Element} outermost wrapper element */ makeCenteredNode: function( element ) { - - var div = $.makeNeutralElement( "div" ), - html = [], - innerDiv, - innerDivs; - + // Convert a possible ID to an actual HTMLElement element = $.getElement( element ); - //TODO: I dont understand the use of # inside the style attributes - // below. Invetigate the results of the constructed html in - // the browser and clean up the mark-up to make this clearer. - html.push('
'); - html.push('
'); - html.push('
'); + /* + CSS tables require you to have a display:table/row/cell hierarchy so we need to create + three nested wrapper divs: + */ - div.innerHTML = html.join( '' ); - div = div.firstChild; + var wrappers = [ + $.makeNeutralElement( 'div' ), + $.makeNeutralElement( 'div' ), + $.makeNeutralElement( 'div' ) + ]; - innerDiv = div; - innerDivs = div.getElementsByTagName( "div" ); - while ( innerDivs.length > 0 ) { - innerDiv = innerDivs[ 0 ]; - innerDivs = innerDiv.getElementsByTagName( "div" ); - } + // It feels like we should be able to pass style dicts to makeNeutralElement: + $.extend(wrappers[0].style, { + display: "table", + height: "100%", + width: "100%" + }); - innerDiv.appendChild( element ); + $.extend(wrappers[1].style, { + display: "table-row" + }); - return div; + $.extend(wrappers[2].style, { + display: "table-cell", + verticalAlign: "middle", + textAlign: "center" + }); + + wrappers[0].appendChild(wrappers[1]); + wrappers[1].appendChild(wrappers[2]); + wrappers[2].appendChild(element); + + return wrappers[0]; }, @@ -1313,7 +1315,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){ makeAjaxRequest: function( url, onSuccess, onError ) { var request = $.createAjaxRequest(); - if (!$.isFunction(onSuccess)) { + if ( !$.isFunction( onSuccess ) ) { throw new Error( "makeAjaxRequest requires a success callback" ); } @@ -1325,9 +1327,9 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){ if ( request.status == 200 ) { onSuccess( request ); } else { - $.console.log("AJAX request returned %s: %s", request.status, url); + $.console.log( "AJAX request returned %s: %s", request.status, url ); - if ($.isFunction(onError)) { + if ( $.isFunction( onError ) ) { onError( request ); } } @@ -1338,11 +1340,11 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){ request.open( "GET", url, true ); request.send( null ); } catch (e) { - $.console.log("%s while making AJAX request: %s", e.name, e.message); + $.console.log( "%s while making AJAX request: %s", e.name, e.message ); request.onreadystatechange = function(){}; - if ($.isFunction(onError)) { + if ( $.isFunction( onError ) ) { onError( request, e ); } } diff --git a/src/strings.js b/src/strings.js index 2b1f0c79..9616850a 100644 --- a/src/strings.js +++ b/src/strings.js @@ -45,7 +45,8 @@ var I18N = { ImageFormat: "Sorry, we don't support {0}-based Deep Zoom Images.", Security: "It looks like a security restriction stopped us from " + "loading this Deep Zoom Image.", - Status: "This space unintentionally left blank ({0} {1})." + Status: "This space unintentionally left blank ({0} {1}).", + "Open-Failed": "Unable to open {0}: {1}" }, Tooltips: { @@ -80,7 +81,8 @@ $.extend( $, { string = container[ props[ i ] ]; if ( typeof( string ) != "string" ) { - string = ""; + $.console.debug( "Untranslated source string:", prop ); + string = ""; // FIXME: this breaks gettext()-style convention, which would return source } return string.replace(/\{\d+\}/g, function(capture) { diff --git a/src/tilesource.js b/src/tilesource.js index 3168606e..fb22b21c 100644 --- a/src/tilesource.js +++ b/src/tilesource.js @@ -293,6 +293,11 @@ $.TileSource.prototype = { callback = function( data ){ var $TileSource = $.TileSource.determineType( _this, data, url ); + if ( !$TileSource ) { + _this.raiseEvent( 'open-failed', { message: "Unable to load TileSource", source: url } ); + return; + } + options = $TileSource.prototype.configure.apply( _this, [ data, url ]); readySource = new $TileSource( options ); _this.ready = true; @@ -315,6 +320,11 @@ $.TileSource.prototype = { $.makeAjaxRequest( url, function( xhr ) { var data = processResponse( xhr ); callback( data ); + }, function ( xhr ) { + _this.raiseEvent( 'open-failed', { + message: "HTTP " + xhr.status + " attempting to load TileSource", + source: url + }); }); } @@ -458,6 +468,8 @@ $.TileSource.determineType = function( tileSource, data, url ){ return OpenSeadragon[ property ]; } } + + $.console.error( "No TileSource was able to open %s %s", url, data ); }; diff --git a/src/viewer.js b/src/viewer.js index cf5c9aa1..8ebbd2b3 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -171,6 +171,12 @@ $.Viewer = function( options ) { //Inherit some behaviors and properties $.EventHandler.call( this ); + + this.addHandler( 'open-failed', function (source, args) { + var msg = $.getString( "Errors.Open-Failed", args.source, args.message); + _this._showMessage( msg ); + }); + $.ControlDock.call( this, options ); //Deal with tile sources @@ -417,6 +423,8 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, $TileSource, options; + _this._hideMessage(); + //allow plain xml strings or json strings to be parsed here if( $.type( tileSource ) == 'string' ){ if( tileSource.match(/\s*<.*/) ){ @@ -433,6 +441,9 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, tileSource = new $.TileSource( tileSource, function( readySource ){ openTileSource( _this, readySource ); }); + tileSource.addHandler( 'open-failed', function ( name, args ) { + _this.raiseEvent( 'open-failed', args ); + }); } else if ( $.isPlainObject( tileSource ) || tileSource.nodeType ){ if( $.isFunction( tileSource.getTileUrl ) ){ @@ -443,6 +454,13 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, } else { //inline configuration $TileSource = $.TileSource.determineType( _this, tileSource ); + if ( !$TileSource ) { + _this.raiseEvent( 'open-failed', { + message: "Unable to load TileSource", + source: tileSource + }); + return; + } options = $TileSource.prototype.configure.apply( _this, [ tileSource ]); readySource = new $TileSource( options ); openTileSource( _this, readySource ); @@ -1054,8 +1072,39 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype, this.referenceStrip.setFocus( page ); } return this; - } + }, + /** + * Display a message in the viewport + * @function + * @private + * @param {String} text message + */ + _showMessage: function ( message ) { + this._hideMessage(); + + var div = $.makeNeutralElement( "div" ); + div.appendChild( document.createTextNode( message ) ); + + this.messageDiv = $.makeCenteredNode( div ); + + $.addClass(this.messageDiv, "openseadragon-message"); + + this.container.appendChild( this.messageDiv ); + }, + + /** + * Hide any currently displayed viewport message + * @function + * @private + */ + _hideMessage: function () { + var div = this.messageDiv; + if (div) { + div.parentNode.removeChild(div); + delete this.messageDiv; + } + } }); /** diff --git a/test/basic.js b/test/basic.js index bd8b731f..61f36673 100644 --- a/test/basic.js +++ b/test/basic.js @@ -1,144 +1,211 @@ -/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util */ +/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */ (function() { + var viewer; - module('Basic'); + module('Basic', { + setup: function () { + var example = $('
').appendTo("#qunit-fixture"); - // TODO: Test drag + testLog.reset(); - var viewer = null; - - // ---------- - asyncTest('Open', function() { - $(document).ready(function() { viewer = OpenSeadragon({ id: 'example', prefixUrl: '/build/openseadragon/images/', - tileSources: '/test/data/testpattern.dzi', springStiffness: 100 // Faster animation = faster tests }); + }, + teardown: function () { + if (viewer && viewer.close) { + viewer.close(); + } - ok(viewer, 'Viewer exists'); + viewer = null; + } + }); - var openHandler = function(eventSender, eventData) { - viewer.removeHandler('open', openHandler); - ok(true, 'Open event was sent'); - equal(eventSender, viewer, 'Sender of open event was viewer'); - ok(eventData, 'Handler also received event data'); - ok(viewer.viewport, 'Viewport exists'); - ok(viewer.source, 'source exists'); - ok(viewer._updateRequestId, 'timer is on'); - start(); - }; + // ---------- + asyncTest('Open', function() { + ok(viewer, 'Viewer exists'); - viewer.addHandler('open', openHandler); + var openHandler = function(eventSender, eventData) { + viewer.removeHandler('open', openHandler); + ok(true, 'Open event was sent'); + equal(eventSender, viewer, 'Sender of open event was viewer'); + ok(eventData, 'Handler also received event data'); + ok(viewer.viewport, 'Viewport exists'); + ok(viewer.source, 'source exists'); + ok(viewer._updateRequestId, 'timer is on'); + start(); + }; + + viewer.addHandler('open', openHandler); + viewer.open('/test/data/testpattern.dzi'); + }); + + asyncTest('Open Error Handling', function() { + ok(viewer, 'Viewer exists'); + + viewer.addHandler('open', function(eventSender, eventData) { + ok(false, "The open event should not fire for failed opens"); + start(); }); + + viewer.addHandler('open-failed', function(eventSender, eventData) { + ok(true, "The open-failed event should be fired when the source 404s"); + + equal($(".openseadragon-message").length, 1, "Open failures should display a message"); + + ok(testLog.log.contains('["AJAX request returned %s: %s",404,"/test/data/not-a-real-file"]'), + "AJAX failures should be logged to the console"); + + start(); + }); + + viewer.open('/test/data/not-a-real-file'); }); // ---------- asyncTest('Zoom', function() { - var viewport = viewer.viewport; - equal(viewport.getZoom(), 1, 'We start out unzoomed'); + viewer.addHandler("open", function () { + var viewport = viewer.viewport; - var zoomHandler = function() { - viewer.removeHandler('animationfinish', zoomHandler); - equal(viewport.getZoom(), 2, 'Zoomed correctly'); - start(); - }; + equal(viewport.getZoom(), 1, 'We start out unzoomed'); - viewer.addHandler('animationfinish', zoomHandler); - viewport.zoomTo(2); + var zoomHandler = function() { + viewer.removeHandler('animationfinish', zoomHandler); + equal(viewport.getZoom(), 2, 'Zoomed correctly'); + start(); + }; + + viewer.addHandler('animationfinish', zoomHandler); + viewport.zoomTo(2); + }); + viewer.open('/test/data/testpattern.dzi'); }); // ---------- asyncTest('Pan', function() { - var viewport = viewer.viewport; - var center = viewport.getCenter(); - ok(center.x === 0.5 && center.y === 0.5, 'We start out unpanned'); + viewer.addHandler("open", function () { + var viewport = viewer.viewport, + center = viewport.getCenter(); - var panHandler = function() { - viewer.removeHandler('animationfinish', panHandler); - center = viewport.getCenter(); - ok(center.x === 0.1 && center.y === 0.1, 'Panned correctly'); - start(); - }; + ok(center.x === 0.5 && center.y === 0.5, 'We start out unpanned'); - viewer.addHandler('animationfinish', panHandler); - viewport.panTo(new OpenSeadragon.Point(0.1, 0.1)); + var panHandler = function() { + viewer.removeHandler('animationfinish', panHandler); + center = viewport.getCenter(); + ok(center.x === 0.1 && center.y === 0.1, 'Panned correctly'); + start(); + }; + + viewer.addHandler('animationfinish', panHandler); + viewport.panTo(new OpenSeadragon.Point(0.1, 0.1)); + }); + + viewer.open('/test/data/testpattern.dzi'); }); // ---------- asyncTest('Home', function() { - var viewport = viewer.viewport; - var center = viewport.getCenter(); - ok(center.x !== 0.5 && center.y !== 0.5, 'We start out panned'); - notEqual(viewport.getZoom(), 1, 'We start out zoomed'); + // Test setup: + function opener() { + var viewport = viewer.viewport; + viewport.panTo(new OpenSeadragon.Point(0.1, 0.1)); + viewport.zoomTo(2); + } - var homeHandler = function() { - viewer.removeHandler('animationfinish', homeHandler); - center = viewport.getCenter(); - ok(center.x === 0.5 && center.y === 0.5, 'We end up unpanned'); - equal(viewport.getZoom(), 1, 'We end up unzoomed'); - start(); - }; + function stage1() { + var viewport = viewer.viewport, + center = viewport.getCenter(); - viewer.addHandler('animationfinish', homeHandler); - viewport.goHome(true); + viewer.removeHandler('animationfinish', stage1); + + ok(center.x !== 0.5 && center.y !== 0.5, 'We start out panned'); + notEqual(viewport.getZoom(), 1, 'We start out zoomed'); + + var homeHandler = function() { + viewer.removeHandler('animationfinish', homeHandler); + center = viewport.getCenter(); + ok(center.x === 0.5 && center.y === 0.5, 'We end up unpanned'); + equal(viewport.getZoom(), 1, 'We end up unzoomed'); + start(); + }; + + viewer.addHandler('animationfinish', homeHandler); + viewport.goHome(true); + } + + viewer.addHandler("open", opener); + viewer.addHandler("animationfinish", stage1); + + viewer.open('/test/data/testpattern.dzi'); }); // ---------- asyncTest('Click', function() { - var viewport = viewer.viewport, + viewer.addHandler("open", function () { + var viewport = viewer.viewport, center = viewport.getCenter(); - ok(center.x === 0.5 && center.y === 0.5, 'We start out unpanned'); - equal(viewport.getZoom(), 1, 'We start out unzoomed'); + ok(center.x === 0.5 && center.y === 0.5, 'We start out unpanned'); + equal(viewport.getZoom(), 1, 'We start out unzoomed'); - var clickHandler = function() { - viewer.removeHandler('animationfinish', clickHandler); - center = viewport.getCenter(); - ok(center.x > 0.37 && center.x < 0.38 && center.y > 0.37 && center.y < 0.38, 'Panned correctly'); - equal(viewport.getZoom(), 2, 'Zoomed correctly'); - start(); - }; + var clickHandler = function() { + viewer.removeHandler('animationfinish', clickHandler); + center = viewport.getCenter(); + ok(center.x > 0.37 && center.x < 0.38 && center.y > 0.37 && center.y < 0.38, 'Panned correctly'); + equal(viewport.getZoom(), 2, 'Zoomed correctly'); + start(); + }; - viewer.addHandler('animationfinish', clickHandler); - Util.simulateViewerClick(viewer, 0.25, 0.25); + viewer.addHandler('animationfinish', clickHandler); + Util.simulateViewerClick(viewer, 0.25, 0.25); + }); + + viewer.open('/test/data/testpattern.dzi'); }); // ---------- - test('Fullscreen', function() { - ok(!viewer.isFullPage(), 'Started out not fullpage'); - ok(!$(viewer.element).hasClass('fullpage'), - 'No fullpage class on div'); + asyncTest('Fullscreen', function() { + viewer.addHandler("open", function () { + ok(!viewer.isFullPage(), 'Started out not fullpage'); + ok(!$(viewer.element).hasClass('fullpage'), + 'No fullpage class on div'); - viewer.setFullPage(true); - ok(viewer.isFullPage(), 'Enabled fullpage'); - ok($(viewer.element).hasClass('fullpage'), - 'Fullpage class added to div'); + viewer.setFullPage(true); + ok(viewer.isFullPage(), 'Enabled fullpage'); + ok($(viewer.element).hasClass('fullpage'), + 'Fullpage class added to div'); - viewer.setFullPage(false); - ok(!viewer.isFullPage(), 'Disabled fullpage'); - ok(!$(viewer.element).hasClass('fullpage'), - 'Fullpage class removed from div'); + viewer.setFullPage(false); + ok(!viewer.isFullPage(), 'Disabled fullpage'); + ok(!$(viewer.element).hasClass('fullpage'), + 'Fullpage class removed from div'); + start(); + }); + + viewer.open('/test/data/testpattern.dzi'); }); // ---------- asyncTest('Close', function() { - var closeHandler = function() { - viewer.removeHandler('close', closeHandler); - ok(!viewer.source, 'no source'); - $('#example').empty(); - ok(true, 'Close event was sent'); - ok(!viewer._updateRequestId, 'timer is off'); - setTimeout(function() { - ok(!viewer._updateRequestId, 'timer is still off'); - start(); - }, 100); - }; + viewer.addHandler("open", function () { + var closeHandler = function() { + viewer.removeHandler('close', closeHandler); + ok(!viewer.source, 'no source'); + ok(true, 'Close event was sent'); + ok(!viewer._updateRequestId, 'timer is off'); + setTimeout(function() { + ok(!viewer._updateRequestId, 'timer is still off'); + start(); + }, 100); + }; - viewer.addHandler('close', closeHandler); - viewer.close(); + viewer.addHandler('close', closeHandler); + viewer.close(); + }); + viewer.open('/test/data/testpattern.dzi'); }); })(); diff --git a/test/demo/basic.html b/test/demo/basic.html index b9a02aef..19572b86 100644 --- a/test/demo/basic.html +++ b/test/demo/basic.html @@ -1,3 +1,4 @@ + OpenSeadragon Basic Demo diff --git a/test/formats.js b/test/formats.js index aeaae6c9..0c673bcf 100644 --- a/test/formats.js +++ b/test/formats.js @@ -3,7 +3,13 @@ // This module tests whether our various file formats can be opened. // TODO: Add more file formats (with corresponding test data). - module('Formats'); + module('Formats', { + setup: function () { + var example = document.createElement("div"); + example.id = "example"; + document.getElementById("qunit-fixture").appendChild(example); + } + }); var viewer = null; diff --git a/test/navigator.js b/test/navigator.js index 547e39a3..62899328 100644 --- a/test/navigator.js +++ b/test/navigator.js @@ -1,3 +1,5 @@ +/* global QUnit, module, Util, $, console, test, asyncTest, start, ok, equal */ + QUnit.config.autostart = false; (function () { @@ -14,14 +16,18 @@ QUnit.config.autostart = false; topNavigatorClickAdjustment; module("navigator", { - setup:function () { - Util.resetDom(); + setup: function () { + Util.initializeTestDOM(); resetTestVariables(); $(document).scrollTop(0); $(document).scrollLeft(0); }, - teardown:function () { - Util.resetDom(); + teardown: function () { + // jQuery UI creates its controls outside the normal DOM hierarchy which QUnit cleans up: + if ($('#exampleNavigator').is(':ui-dialog')) { + $('#exampleNavigator').dialog('destroy'); + } + resetTestVariables(); } }); @@ -31,7 +37,7 @@ QUnit.config.autostart = false; }); var resetTestVariables = function () { - if (viewer != null) { + if (viewer) { viewer.close(); } displayRegion = null; @@ -125,11 +131,11 @@ QUnit.config.autostart = false; viewerAndNavigatorDisplayReady = viewer.drawer !== null && !viewer.drawer.needsUpdate() && currentDisplayWidth > 0 && - Util.equalsWithVariance(lastDisplayRegionLeft, currentDisplayRegionLeft, .0001) && - Util.equalsWithVariance(lastDisplayWidth, currentDisplayWidth, .0001) && - Util.equalsWithVariance(viewer.viewport.getBounds(true).x, viewer.viewport.getBounds().x, .0001) && - Util.equalsWithVariance(viewer.viewport.getBounds(true).y, viewer.viewport.getBounds().y, .0001) && - Util.equalsWithVariance(viewer.viewport.getBounds(true).width, viewer.viewport.getBounds().width, .0001); + Util.equalsWithVariance(lastDisplayRegionLeft, currentDisplayRegionLeft, 0.0001) && + Util.equalsWithVariance(lastDisplayWidth, currentDisplayWidth, 0.0001) && + Util.equalsWithVariance(viewer.viewport.getBounds(true).x, viewer.viewport.getBounds().x, 0.0001) && + Util.equalsWithVariance(viewer.viewport.getBounds(true).y, viewer.viewport.getBounds().y, 0.0001) && + Util.equalsWithVariance(viewer.viewport.getBounds(true).width, viewer.viewport.getBounds().width, 0.0001); } catch (err) { //Ignore. Subsequent code will try again shortly @@ -138,7 +144,7 @@ QUnit.config.autostart = false; count++; setTimeout(function () { waitForViewer(handler, count, currentDisplayRegionLeft, currentDisplayWidth); - }, 100) + }, 100); } else { if (count === 40) { @@ -201,21 +207,21 @@ QUnit.config.autostart = false; expecteYCoordinate = 1 / viewer.source.aspectRatio - viewer.viewport.getBounds().height; } if (viewer.viewport.getBounds().width < 1) { - Util.assessNumericValue(expectedXCoordinate, viewer.viewport.getBounds().x, .04, ' Viewer at ' + theContentCorner + ', x coord'); + Util.assessNumericValue(expectedXCoordinate, viewer.viewport.getBounds().x, 0.04, ' Viewer at ' + theContentCorner + ', x coord'); } if (viewer.viewport.getBounds().height < 1 / viewer.source.aspectRatio) { - Util.assessNumericValue(expecteYCoordinate, viewer.viewport.getBounds().y, .04, ' Viewer at ' + theContentCorner + ', y coord'); + Util.assessNumericValue(expecteYCoordinate, viewer.viewport.getBounds().y, 0.04, ' Viewer at ' + theContentCorner + ', y coord'); } - } + }; }; var assessViewerInCenter = function () { - var yPositionVariance = .04; + var yPositionVariance = 0.04; if (viewer.source.aspectRatio < 1) { yPositionVariance = yPositionVariance / viewer.source.aspectRatio; } Util.assessNumericValue(1 / viewer.source.aspectRatio / 2, viewer.viewport.getCenter().y, yPositionVariance, ' Viewer at center, y coord'); - Util.assessNumericValue(.5, viewer.viewport.getCenter().x, .4, ' Viewer at center, x coord'); + Util.assessNumericValue(0.5, viewer.viewport.getCenter().x, 0.4, ' Viewer at center, x coord'); }; var clickOnNavigator = function (theContentCorner) { @@ -239,7 +245,7 @@ QUnit.config.autostart = false; yPos = contentStartFromTop + displayRegionHeight; } simulateNavigatorClick(viewer.navigator, xPos, yPos); - } + }; }; var dragNavigatorBackToCenter = function () { @@ -354,11 +360,12 @@ QUnit.config.autostart = false; clientX:1, clientY:1 }; - mainViewerElement.simulate('blur', event); + + $("#" + seadragonProperties.id).simulate('blur', event); + if (testProperties.expectedAutoFade) { setTimeout(assessAutoFadeTriggered,autoFadeWaitTime); - } - else { + } else { setTimeout(assessAutoFadeDisabled,autoFadeWaitTime); } } diff --git a/test/strings.js b/test/strings.js index 61a12d93..1c740a8a 100644 --- a/test/strings.js +++ b/test/strings.js @@ -1,17 +1,33 @@ +/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */ + (function() { - module("strings"); + module("strings", { + setup: function () { + testLog.reset(); + } + }); + test("getSubString", function() { equal(OpenSeadragon.getString("Errors.Dzi"), "Hmm, this doesn't appear to be a valid Deep Zoom Image.", "Read sub-string"); }); + test("getStringWithPlaceholders", function() { + equal(OpenSeadragon.getString("Errors.Open-Failed", "foo", "bar"), + "Unable to open foo: bar", + "String placeholder replacement"); + }); + test("getInvalidString", function() { - equal(OpenSeadragon.getString("Greeting"), "", - "Handled unset string key"); - equal(OpenSeadragon.getString("Errors"), "", - "Handled requesting parent key"); + equal(OpenSeadragon.getString("Greeting"), "", "Handled unset string key"); + ok(testLog.debug.contains('["Untranslated source string:","Greeting"]'), + 'Invalid string keys are logged'); + + equal(OpenSeadragon.getString("Errors"), "", "Handled requesting parent key"); + ok(testLog.debug.contains('["Untranslated source string:","Errors"]'), + 'Invalid string parent keys are logged'); }); test("setString", function() { diff --git a/test/test.html b/test/test.html index 76d9cc2e..c41abe84 100644 --- a/test/test.html +++ b/test/test.html @@ -10,12 +10,6 @@
-
-
-
-
-
-
diff --git a/test/test.js b/test/test.js index 0e763fef..37b7a075 100644 --- a/test/test.js +++ b/test/test.js @@ -1,3 +1,5 @@ +/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util */ + (function() { // ---------- @@ -30,16 +32,11 @@ .simulate('mouseup', event); }, - resetDom: function () { - if ($('#exampleNavigator').is(':ui-dialog')) { - $('#exampleNavigator').dialog('destroy'); - } - $("#exampleNavigator").remove(); - $(".navigator").remove(); - $("#example").empty(); - $("#tallexample").empty(); - $("#wideexample").empty(); - $("#example").parent().append('
'); + initializeTestDOM: function () { + $("#qunit-fixture") + .append('
') + .append('
') + .append('
'); }, equalsWithVariance: function (value1, value2, variance) { @@ -74,5 +71,51 @@ }; + /* + Test console log capture + + 1. Only the OpenSeadragon.console logger is touched + 2. All log messages are stored in window.testLog in arrays keyed on the logger name (e.g. log, + warning, error, etc.) as JSON-serialized strings to simplify comparisons + 3. The captured log arrays have a custom contains() method for ease of testing + 4. testLog.reset() will clear all of the message arrays, intended for use in test setup routines + */ + var testConsole = window.testConsole = {}, + testLog = window.testLog = { + log: [], + debug: [], + info: [], + warn: [], + error: [], + reset: function () { + for (var i in testLog) { + if (testLog.hasOwnProperty(i) && 'length' in testLog[i] && 'push' in testLog[i]) { + testLog[i].length = 0; + } + } + } + }; + + for (var i in testLog) { + if (testLog.hasOwnProperty(i) && testLog[i].push) { + testConsole[i] = (function (arr) { + return function () { + var args = Array.prototype.slice.call(arguments, 0); // Coerce to true Array + arr.push(JSON.stringify(args)); // Store as JSON to avoid tedious array-equality tests + }; + })(testLog[i]); + + testLog[i].contains = function (needle) { + for (var i = 0; i < this.length; i++) { + if (this[i] == needle) { + return true; + } + } + return false; + }; + } + } + + OpenSeadragon.console = testConsole; })(); diff --git a/test/utils.js b/test/utils.js index 7489f03b..f46f9a84 100644 --- a/test/utils.js +++ b/test/utils.js @@ -1,3 +1,5 @@ +/* global module, asyncTest, $, ok, equal, strictEqual, notEqual, start, test, Util, testLog */ + (function() { module("utils"); @@ -56,10 +58,33 @@ asyncTest("makeAjaxRequest", function() { var timeWatcher = Util.timeWatcher(); - OpenSeadragon.makeAjaxRequest('data/testpattern.dzi', function(xhr) { - ok(/deepzoom/.test(xhr.response), 'file loaded'); - timeWatcher.done(); - }); + OpenSeadragon.makeAjaxRequest('data/testpattern.dzi', + function(xhr) { + equal(xhr.status, 200, 'Success callback called for HTTP 200'); + ok(/deepzoom/.test(xhr.responseText), 'Success function called'); + timeWatcher.done(); + }, + function(xhr) { + ok(false, 'Error callback should not be called'); + timeWatcher.done(); + } + ); + }); + + asyncTest("makeAjaxRequest for invalid file", function() { + var timeWatcher = Util.timeWatcher(); + + OpenSeadragon.makeAjaxRequest('not-a-real-dzi-file', + function(xhr) { + ok(false, 'Success function should not be called for errors'); + timeWatcher.done(); + }, + function(xhr) { + equal(xhr.status, 404, 'Error callback called for HTTP 404'); + ok(true, 'Error function should be called for errors'); + timeWatcher.done(); + } + ); }); // ----------