Merge pull request #523 from openseadragon/ian2

More unit testing for collections
This commit is contained in:
Ian Gilman 2014-11-21 10:57:47 -08:00
commit 186e2f8f54
33 changed files with 780 additions and 133 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@
node_modules node_modules
build/ build/
sftp-config.json sftp-config.json
coverage/
temp/

View File

@ -1,3 +1,5 @@
/* global module */
module.exports = function(grunt) { module.exports = function(grunt) {
// ---------- // ----------
@ -5,7 +7,7 @@ module.exports = function(grunt) {
grunt.loadNpmTasks("grunt-contrib-concat"); grunt.loadNpmTasks("grunt-contrib-concat");
grunt.loadNpmTasks("grunt-contrib-jshint"); grunt.loadNpmTasks("grunt-contrib-jshint");
grunt.loadNpmTasks("grunt-contrib-uglify"); grunt.loadNpmTasks("grunt-contrib-uglify");
grunt.loadNpmTasks("grunt-contrib-qunit"); grunt.loadNpmTasks("grunt-qunit-istanbul");
grunt.loadNpmTasks("grunt-contrib-connect"); grunt.loadNpmTasks("grunt-contrib-connect");
grunt.loadNpmTasks("grunt-contrib-watch"); grunt.loadNpmTasks("grunt-contrib-watch");
grunt.loadNpmTasks("grunt-contrib-clean"); grunt.loadNpmTasks("grunt-contrib-clean");
@ -72,6 +74,7 @@ module.exports = function(grunt) {
clean: { clean: {
build: ["build"], build: ["build"],
package: [packageDir], package: [packageDir],
coverage: ["coverage"],
release: { release: {
src: [releaseRoot], src: [releaseRoot],
options: { options: {
@ -137,10 +140,26 @@ module.exports = function(grunt) {
} }
}, },
qunit: { qunit: {
normal: {
options: {
urls: [ "http://localhost:8000/test/test.html" ]
}
},
coverage: {
options: {
urls: [ "http://localhost:8000/test/coverage.html" ],
coverage: {
src: ['src/*.js'],
htmlReport: 'coverage/html/',
instrumentedFiles: 'temp/',
baseUrl: '.',
disposeCollector: true
}
}
},
all: { all: {
options: { options: {
timeout: 10000, timeout: 10000
urls: [ "http://localhost:8000/test/test.html" ]
} }
} }
}, },
@ -248,7 +267,12 @@ module.exports = function(grunt) {
// ---------- // ----------
// Test task. // Test task.
// Builds and runs unit tests. // Builds and runs unit tests.
grunt.registerTask("test", ["build", "connect", "qunit"]); grunt.registerTask("test", ["build", "connect", "qunit:normal"]);
// ----------
// Coverage task.
// Outputs unit test code coverage report.
grunt.registerTask("coverage", ["clean:coverage", "connect", "qunit:coverage"]);
// ---------- // ----------
// Package task. // Package task.

View File

@ -63,6 +63,12 @@ and open `http://localhost:8000/test/test.html` in your browser.
Another good page, if you want to interactively test out your changes, is `http://localhost:8000/test/demo/basic.html`. Another good page, if you want to interactively test out your changes, is `http://localhost:8000/test/demo/basic.html`.
You can also get a report of the tests' code coverage:
grunt coverage
The report shows up at `coverage/html/index.html` viewable in a browser.
### Contributing ### Contributing
OpenSeadragon is truly a community project; we welcome your involvement! OpenSeadragon is truly a community project; we welcome your involvement!

View File

@ -37,6 +37,7 @@ OPENSEADRAGON CHANGELOG
* Viewport.open supports positioning config properties * Viewport.open supports positioning config properties
* Margins option to push the home region in from the edges of the Viewer (#505) * Margins option to push the home region in from the edges of the Viewer (#505)
* Rect and Point toString() functions are now consistent: rounding values to nearest hundredth * Rect and Point toString() functions are now consistent: rounding values to nearest hundredth
* Overlays appear in the DOM immediately on open or addOverlay (#507)
1.2.0: (in progress) 1.2.0: (in progress)

View File

@ -10,11 +10,11 @@
"grunt-git-describe": "^2.3.2", "grunt-git-describe": "^2.3.2",
"grunt-contrib-uglify": "^0.4.0", "grunt-contrib-uglify": "^0.4.0",
"grunt-contrib-watch": "^0.6.1", "grunt-contrib-watch": "^0.6.1",
"grunt-contrib-qunit": "^0.5.1",
"grunt-contrib-jshint": "^0.10.0", "grunt-contrib-jshint": "^0.10.0",
"grunt-contrib-compress": "^0.9.1", "grunt-contrib-compress": "^0.9.1",
"grunt-contrib-connect": "^0.7.1", "grunt-contrib-connect": "^0.7.1",
"qunitjs": "^1.14.0" "qunitjs": "^1.14.0",
"grunt-qunit-istanbul": "^0.4.5"
}, },
"scripts": { "scripts": {
"test": "grunt test" "test": "grunt test"

View File

@ -129,8 +129,10 @@ $.Drawer = function( options ) {
* @memberof OpenSeadragon.Viewer * @memberof OpenSeadragon.Viewer
* @type {object} * @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {OpenSeadragon.Tile} tile * @property {OpenSeadragon.Tile} tile - The Tile being drawn.
* @property {?Object} userData - 'context', 'tile' and 'rendered'. * @property {OpenSeadragon.Tile} context - The HTML canvas context being drawn into.
* @property {OpenSeadragon.Tile} rendered - The HTML canvas context containing the tile imagery.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/ */
_this.viewer.raiseEvent('tile-drawing', args); _this.viewer.raiseEvent('tile-drawing', args);
} }
@ -187,25 +189,28 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
// deprecated // deprecated
needsUpdate: function() { needsUpdate: function() {
$.console.error( "[Drawer.needsUpdate] this function is deprecated." ); $.console.error( "[Drawer.needsUpdate] this function is deprecated. Use World.needsUpdate instead." );
return false; return this.viewer.world.needsUpdate();
}, },
// deprecated // deprecated
numTilesLoaded: function() { numTilesLoaded: function() {
$.console.error( "[Drawer.numTilesLoaded] this function is deprecated." ); $.console.error( "[Drawer.numTilesLoaded] this function is deprecated. Use TileCache.numTilesLoaded instead." );
return 0; return this.viewer.tileCache.numTilesLoaded();
}, },
// deprecated // deprecated
reset: function() { reset: function() {
$.console.error( "[Drawer.reset] this function is deprecated." ); $.console.error( "[Drawer.reset] this function is deprecated. Use World.resetItems instead." );
this.viewer.world.resetItems();
return this; return this;
}, },
// deprecated // deprecated
update: function() { update: function() {
$.console.error( "[Drawer.update] this function is deprecated." ); $.console.error( "[Drawer.update] this function is deprecated. Use Drawer.clear and World.update instead." );
this.clear();
this.viewer.world.update();
return this; return this;
}, },

View File

@ -155,7 +155,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
// Note that just because we're unloading a tile doesn't necessarily mean // Note that just because we're unloading a tile doesn't necessarily mean
// we're unloading an image. With repeated calls it should sort itself out, though. // we're unloading an image. With repeated calls it should sort itself out, though.
if ( this._imagesLoadedCount >= this._maxImageCacheCount ) { if ( this._imagesLoadedCount > this._maxImageCacheCount ) {
var worstTile = null; var worstTile = null;
var worstTileIndex = -1; var worstTileIndex = -1;
var prevTile, worstTime, worstLevel, prevTime, prevLevel, prevTileRecord; var prevTile, worstTime, worstLevel, prevTime, prevLevel, prevTileRecord;

View File

@ -438,6 +438,7 @@ function updateLevel( tiledImage, haveDrawn, drawLevel, level, levelOpacity, lev
* @memberof OpenSeadragon.Viewer * @memberof OpenSeadragon.Viewer
* @type {object} * @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.
* @property {Object} havedrawn * @property {Object} havedrawn
* @property {Object} level * @property {Object} level
* @property {Object} opacity * @property {Object} opacity
@ -449,6 +450,7 @@ function updateLevel( tiledImage, haveDrawn, drawLevel, level, levelOpacity, lev
* @property {?Object} userData - Arbitrary subscriber-defined object. * @property {?Object} userData - Arbitrary subscriber-defined object.
*/ */
tiledImage.viewer.raiseEvent( 'update-level', { tiledImage.viewer.raiseEvent( 'update-level', {
tiledImage: tiledImage,
havedrawn: haveDrawn, havedrawn: haveDrawn,
level: level, level: level,
opacity: levelOpacity, opacity: levelOpacity,
@ -519,10 +521,12 @@ function updateTile( tiledImage, drawLevel, haveDrawn, x, y, level, levelOpacity
* @memberof OpenSeadragon.Viewer * @memberof OpenSeadragon.Viewer
* @type {object} * @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.
* @property {OpenSeadragon.Tile} tile * @property {OpenSeadragon.Tile} tile
* @property {?Object} userData - Arbitrary subscriber-defined object. * @property {?Object} userData - Arbitrary subscriber-defined object.
*/ */
tiledImage.viewer.raiseEvent( 'update-tile', { tiledImage.viewer.raiseEvent( 'update-tile', {
tiledImage: tiledImage,
tile: tile tile: tile
}); });
} }
@ -868,25 +872,6 @@ function drawTiles( tiledImage, lastDrawn ){
position, position,
tileSource; tileSource;
// We need a callback to give image manipulation a chance to happen
var drawingHandler = function(args) {
if (tiledImage.viewer) {
/**
* This event is fired just before the tile is drawn giving the application a chance to alter the image.
*
* NOTE: This event is only fired when the tiledImage is using a <canvas>.
*
* @event tile-drawing
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {OpenSeadragon.Tile} tile
* @property {?Object} userData - 'context', 'tile' and 'rendered'.
*/
tiledImage.viewer.raiseEvent('tile-drawing', args);
}
};
for ( i = lastDrawn.length - 1; i >= 0; i-- ) { for ( i = lastDrawn.length - 1; i >= 0; i-- ) {
tile = lastDrawn[ i ]; tile = lastDrawn[ i ];
tiledImage._drawer.drawTile( tile ); tiledImage._drawer.drawTile( tile );
@ -908,10 +893,12 @@ function drawTiles( tiledImage, lastDrawn ){
* @memberof OpenSeadragon.Viewer * @memberof OpenSeadragon.Viewer
* @type {object} * @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn.
* @property {OpenSeadragon.Tile} tile * @property {OpenSeadragon.Tile} tile
* @property {?Object} userData - Arbitrary subscriber-defined object. * @property {?Object} userData - Arbitrary subscriber-defined object.
*/ */
tiledImage.viewer.raiseEvent( 'tile-drawn', { tiledImage.viewer.raiseEvent( 'tile-drawn', {
tiledImage: tiledImage,
tile: tile tile: tile
}); });
} }

View File

@ -207,6 +207,7 @@ $.Viewer = function( options ) {
this._sequenceIndex = 0; this._sequenceIndex = 0;
this._firstOpen = true; this._firstOpen = true;
this._updateRequestId = null; this._updateRequestId = null;
this._loadQueue = [];
this.currentOverlays = []; this.currentOverlays = [];
//Inherit some behaviors and properties //Inherit some behaviors and properties
@ -228,7 +229,6 @@ $.Viewer = function( options ) {
this.element = this.element || document.getElementById( this.id ); this.element = this.element || document.getElementById( this.id );
this.canvas = $.makeNeutralElement( "div" ); this.canvas = $.makeNeutralElement( "div" );
this.keyboardCommandArea = $.makeNeutralElement( "textarea" ); this.keyboardCommandArea = $.makeNeutralElement( "textarea" );
this.overlaysContainer = $.makeNeutralElement( "div" );
this.canvas.className = "openseadragon-canvas"; this.canvas.className = "openseadragon-canvas";
(function( style ){ (function( style ){
@ -267,7 +267,6 @@ $.Viewer = function( options ) {
this.container.insertBefore( this.canvas, this.container.firstChild ); this.container.insertBefore( this.canvas, this.container.firstChild );
this.container.insertBefore( this.keyboardCommandArea, this.container.firstChild ); this.container.insertBefore( this.keyboardCommandArea, this.container.firstChild );
this.element.appendChild( this.container ); this.element.appendChild( this.container );
this.canvas.appendChild( this.overlaysContainer );
//Used for toggling between fullscreen and default container size //Used for toggling between fullscreen and default container size
//TODO: these can be closure private and shared across Viewer //TODO: these can be closure private and shared across Viewer
@ -453,6 +452,10 @@ $.Viewer = function( options ) {
debugGridColor: this.debugGridColor debugGridColor: this.debugGridColor
}); });
// Overlay container
this.overlaysContainer = $.makeNeutralElement( "div" );
this.canvas.appendChild( this.overlaysContainer );
// Now that we have a drawer, see if it supports rotate. If not we need to remove the rotate buttons // Now that we have a drawer, see if it supports rotate. If not we need to remove the rotate buttons
if (!this.drawer.canRotate()) { if (!this.drawer.canRotate()) {
// Disable/remove the rotate left/right buttons since they aren't supported // Disable/remove the rotate left/right buttons since they aren't supported
@ -619,6 +622,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
_this.currentOverlays[ i ] = getOverlayObject( _this, _this.overlays[ i ] ); _this.currentOverlays[ i ] = getOverlayObject( _this, _this.overlays[ i ] );
} }
_this._drawOverlays();
/** /**
* Raised when the viewer has opened and loaded one or more TileSources. * Raised when the viewer has opened and loaded one or more TileSources.
* *
@ -688,7 +693,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
_this.addTiledImage(options); _this.addTiledImage(options);
// For backwards compatibility. TODO: deprecate. // TODO: now that options has other things besides tileSource, the overlays
// should probably be at the options level, not the tileSource level.
if (options.tileSource.overlays) { if (options.tileSource.overlays) {
for (var i = 0; i < options.tileSource.overlays.length; i++) { for (var i = 0; i < options.tileSource.overlays.length; i++) {
_this.addOverlay(options.tileSource.overlays[i]); _this.addOverlay(options.tileSource.overlays[i]);
@ -1260,12 +1266,22 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
$.console.assert(options, "[Viewer.addTiledImage] options is required"); $.console.assert(options, "[Viewer.addTiledImage] options is required");
$.console.assert(options.tileSource, "[Viewer.addTiledImage] options.tileSource is required"); $.console.assert(options.tileSource, "[Viewer.addTiledImage] options.tileSource is required");
var _this = this, var _this = this;
tileSource = options.tileSource;
this._hideMessage(); this._hideMessage();
var myQueueItem = {
options: options
};
function raiseAddItemFailed( event ) { function raiseAddItemFailed( event ) {
for (var i = 0; i < _this._loadQueue; i++) {
if (_this._loadQueue[i] === myQueueItem) {
_this._loadQueue.splice(i, 1);
break;
}
}
/** /**
* Raised when an error occurs while adding a item. * Raised when an error occurs while adding a item.
* @event add-item-failed * @event add-item-failed
@ -1284,7 +1300,9 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
} }
} }
getTileSourceImplementation( this, tileSource, function( tileSource ) { this._loadQueue.push(myQueueItem);
getTileSourceImplementation( this, options.tileSource, function( tileSource ) {
if ( tileSource instanceof Array ) { if ( tileSource instanceof Array ) {
raiseAddItemFailed({ raiseAddItemFailed({
@ -1295,17 +1313,29 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
return; return;
} }
var tiledImage = new $.TiledImage({ myQueueItem.tileSource = tileSource;
// add everybody at the front of the queue that's ready to go
var queueItem, tiledImage, optionsClone;
while (_this._loadQueue.length) {
queueItem = _this._loadQueue[0];
if (!queueItem.tileSource) {
break;
}
_this._loadQueue.splice(0, 1);
tiledImage = new $.TiledImage({
viewer: _this, viewer: _this,
source: tileSource, source: queueItem.tileSource,
viewport: _this.viewport, viewport: _this.viewport,
drawer: _this.drawer, drawer: _this.drawer,
tileCache: _this.tileCache, tileCache: _this.tileCache,
imageLoader: _this.imageLoader, imageLoader: _this.imageLoader,
x: options.x, x: queueItem.options.x,
y: options.y, y: queueItem.options.y,
width: options.width, width: queueItem.options.width,
height: options.height, height: queueItem.options.height,
imageLoaderLimit: _this.imageLoaderLimit, imageLoaderLimit: _this.imageLoaderLimit,
minZoomImageRatio: _this.minZoomImageRatio, minZoomImageRatio: _this.minZoomImageRatio,
wrapHorizontal: _this.wrapHorizontal, wrapHorizontal: _this.wrapHorizontal,
@ -1319,7 +1349,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
}); });
_this.world.addItem( tiledImage, { _this.world.addItem( tiledImage, {
index: options.index index: queueItem.options.index
}); });
if (_this.collectionMode) { if (_this.collectionMode) {
@ -1336,19 +1366,20 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
} }
if (_this.navigator) { if (_this.navigator) {
var optionsClone = $.extend({}, options, { optionsClone = $.extend({}, queueItem.options, {
originalTiledImage: tiledImage, originalTiledImage: tiledImage,
tileSource: tileSource tileSource: queueItem.tileSource
}); });
_this.navigator.addTiledImage(optionsClone); _this.navigator.addTiledImage(optionsClone);
} }
if (options.success) { if (queueItem.options.success) {
options.success({ queueItem.options.success({
item: tiledImage item: tiledImage
}); });
} }
}
}, function( event ) { }, function( event ) {
event.options = options; event.options = options;
raiseAddItemFailed(event); raiseAddItemFailed(event);
@ -1747,8 +1778,11 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
// they're trying to add a duplicate overlay // they're trying to add a duplicate overlay
return this; return this;
} }
this.currentOverlays.push( getOverlayObject( this, options ) );
THIS[ this.hash ].forceRedraw = true; var overlay = getOverlayObject( this, options);
this.currentOverlays.push(overlay);
overlay.drawHTML( this.overlaysContainer, this.viewport );
/** /**
* Raised when an overlay is added to the viewer (see {@link OpenSeadragon.Viewer#addOverlay}). * Raised when an overlay is added to the viewer (see {@link OpenSeadragon.Viewer#addOverlay}).
* *
@ -1955,8 +1989,16 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
default: default:
return this.gestureSettingsUnknown; return this.gestureSettingsUnknown;
} }
} },
// private
_drawOverlays: function() {
var i,
length = this.currentOverlays.length;
for ( i = 0; i < length; i++ ) {
this.currentOverlays[ i ].drawHTML( this.overlaysContainer, this.viewport );
}
}
}); });
@ -2114,14 +2156,6 @@ function getOverlayIndex( overlays, element ) {
return -1; return -1;
} }
function drawOverlays( viewport, overlays, container ) {
var i,
length = overlays.length;
for ( i = 0; i < length; i++ ) {
overlays[ i ].drawHTML( container, viewport );
}
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Schedulers provide the general engine for animation // Schedulers provide the general engine for animation
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -2645,7 +2679,7 @@ function updateOnce( viewer ) {
if ( animated || THIS[ viewer.hash ].forceRedraw || viewer.world.needsUpdate() ) { if ( animated || THIS[ viewer.hash ].forceRedraw || viewer.world.needsUpdate() ) {
updateWorld( viewer ); updateWorld( viewer );
drawOverlays( viewer.viewport, viewer.currentOverlays, viewer.overlaysContainer ); viewer._drawOverlays();
if( viewer.navigator ){ if( viewer.navigator ){
viewer.navigator.update( viewer.viewport ); viewer.navigator.update( viewer.viewport );
} }

79
test/coverage.html Normal file
View File

@ -0,0 +1,79 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OpenSeadragon QUnit</title>
<link rel="stylesheet" href="/node_modules/qunitjs/qunit/qunit.css">
<link rel="stylesheet" href="/test/lib/jquery-ui-1.10.2/css/smoothness/jquery-ui-1.10.2.min.css">
<link rel="stylesheet" href="/test/helpers/test.css">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="/node_modules/qunitjs/qunit/qunit.js"></script>
<script src="/test/lib/jquery-1.9.1.min.js"></script>
<script src="/test/lib/jquery-ui-1.10.2/js/jquery-ui-1.10.2.min.js"></script>
<script src="/test/lib/jquery.simulate.js"></script>
<!-- OpenSeadragon sources -->
<script src="/src/openseadragon.js"></script>
<script src="/src/fullscreen.js"></script>
<script src="/src/eventsource.js"></script>
<script src="/src/mousetracker.js"></script>
<script src="/src/control.js"></script>
<script src="/src/controldock.js"></script>
<script src="/src/viewer.js"></script>
<script src="/src/navigator.js"></script>
<script src="/src/strings.js"></script>
<script src="/src/point.js"></script>
<script src="/src/tilesource.js"></script>
<script src="/src/dzitilesource.js"></script>
<script src="/src/iiiftilesource.js"></script>
<script src="/src/osmtilesource.js"></script>
<script src="/src/tmstilesource.js"></script>
<script src="/src/legacytilesource.js"></script>
<script src="/src/tilesourcecollection.js"></script>
<script src="/src/button.js"></script>
<script src="/src/buttongroup.js"></script>
<script src="/src/rectangle.js"></script>
<script src="/src/referencestrip.js"></script>
<script src="/src/displayrectangle.js"></script>
<script src="/src/spring.js"></script>
<script src="/src/imageLoader.js"></script>
<script src="/src/tile.js"></script>
<script src="/src/overlay.js"></script>
<script src="/src/drawer.js"></script>
<script src="/src/viewport.js"></script>
<script src="/src/tiledimage.js"></script>
<script src="/src/tilecache.js"></script>
<script src="/src/world.js"></script>
<!-- Helpers -->
<script src="/test/helpers/legacy.mouse.shim.js"></script>
<script src="/test/helpers/test.js"></script>
<!-- Modules -->
<!-- Polyfill must be inserted first because it is testing functions
reassignments which could be done by other test. -->
<script src="/test/modules/polyfills.js"></script>
<script src="/test/modules/basic.js"></script>
<script src="/test/modules/strings.js"></script>
<script src="/test/modules/formats.js"></script>
<script src="/test/modules/utils.js"></script>
<script src="/test/modules/events.js"></script>
<script src="/test/modules/units.js"></script>
<script src="/test/modules/multi-image.js"></script>
<script src="/test/modules/overlays.js"></script>
<script src="/test/modules/controls.js"></script>
<script src="/test/viewport.js"></script>
<script src="/test/modules/world.js"></script>
<script src="/test/modules/drawer.js"></script>
<script src="/test/modules/tiledimage.js"></script>
<script src="/test/modules/tilecache.js"></script>
<script src="/test/modules/referencestrip.js"></script>
<script src="/test/modules/tilesourcecollection.js"></script>
<!-- The navigator tests are the slowest (for now; hopefully they can be sped up)
so we put them last. -->
<script src="/test/modules/navigator.js"></script>
</body>
</html>

View File

@ -19,10 +19,6 @@
background-color: rgba(255, 0, 0, 0.3); background-color: rgba(255, 0, 0, 0.3);
} }
#overlay1 {
z-index: 10;
}
</style> </style>
</head> </head>
<body> <body>

View File

@ -6,8 +6,8 @@
init: function() { init: function() {
var self = this; var self = this;
var testInitialOpen = false; var testInitialOpen = true;
var testOverlays = false; var testOverlays = true;
var testMargins = false; var testMargins = false;
var testNavigator = false; var testNavigator = false;
var margins; var margins;
@ -16,8 +16,8 @@
// debugMode: true, // debugMode: true,
zoomPerScroll: 1.02, zoomPerScroll: 1.02,
showNavigator: testNavigator, showNavigator: testNavigator,
sequenceMode: true, // sequenceMode: true,
showReferenceStrip: true, // showReferenceStrip: true,
// referenceStripScroll: 'vertical', // referenceStripScroll: 'vertical',
navPrevNextWrap: false, navPrevNextWrap: false,
preserveViewport: false, preserveViewport: false,
@ -54,7 +54,7 @@
config.overlays = [ config.overlays = [
{ {
id: "overlay1", id: "overlay1",
x: 0, x: 2,
y: 0, y: 0,
width: 0.25, width: 0.25,
height: 0.25 height: 0.25
@ -92,7 +92,6 @@
if (testInitialOpen) { if (testInitialOpen) {
this.viewer.addHandler( "open", function() { this.viewer.addHandler( "open", function() {
// console.log(self.viewer.viewport.contentSize);
}); });
} }

View File

@ -50,6 +50,7 @@
.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', event ); .simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', event );
}, },
// ----------
initializeTestDOM: function () { initializeTestDOM: function () {
$( "#qunit-fixture" ) $( "#qunit-fixture" )
.append( '<div><div id="example"></div><div id="exampleNavigator"></div></div>' ) .append( '<div><div id="example"></div><div id="exampleNavigator"></div></div>' )
@ -57,14 +58,17 @@
.append( '<div id="tallexample"></div>' ); .append( '<div id="tallexample"></div>' );
}, },
// ----------
equalsWithVariance: function ( value1, value2, variance ) { equalsWithVariance: function ( value1, value2, variance ) {
return Math.abs( value1 - value2 ) <= variance; return Math.abs( value1 - value2 ) <= variance;
}, },
// ----------
assessNumericValue: function ( value1, value2, variance, message ) { assessNumericValue: function ( value1, value2, variance, message ) {
ok( Util.equalsWithVariance( value1, value2, variance ), message + " Expected:" + value1 + " Found: " + value2 + " Variance: " + variance ); ok( Util.equalsWithVariance( value1, value2, variance ), message + " Expected:" + value1 + " Found: " + value2 + " Variance: " + variance );
}, },
// ----------
timeWatcher: function ( time ) { timeWatcher: function ( time ) {
time = time || 2000; time = time || 2000;
var finished = false; var finished = false;
@ -85,8 +89,46 @@
} }
} }
}; };
},
// ----------
spyOnce: function(obj, functionName, callback) {
var original = obj[functionName];
obj[functionName] = function() {
obj[functionName] = original;
var result = callback.apply(this, arguments);
if (result === undefined) {
result = original.apply(this, arguments);
} }
return result;
};
},
// ----------
testDeprecation: function(obj0, member0, obj1, member1) {
var called = false;
var errored = false;
if (obj1 && member1) {
this.spyOnce(obj1, member1, function() {
called = true;
return false;
});
} else {
called = true;
}
this.spyOnce(OpenSeadragon.console, 'error', function(message) {
if (/deprecated/.test(message)) {
errored = true;
}
});
obj0[member0]();
equal(called, true, 'called through for ' + member0);
equal(errored, true, 'errored for ' + member0);
}
}; };
/* /*

100
test/modules/drawer.js Normal file
View File

@ -0,0 +1,100 @@
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
(function() {
var viewer;
module('Drawer', {
setup: function () {
var example = $('<div id="example"></div>').appendTo("#qunit-fixture");
testLog.reset();
},
teardown: function () {
if (viewer && viewer.close) {
viewer.close();
}
viewer = null;
}
});
// ----------
var createViewer = function(options) {
options = options || {};
viewer = OpenSeadragon(OpenSeadragon.extend({
id: 'example',
prefixUrl: '/build/openseadragon/images/',
springStiffness: 100 // Faster animation = faster tests
}, options));
};
// ----------
asyncTest('basics', function() {
createViewer();
ok(viewer.drawer, 'Drawer exists');
equal(viewer.drawer.canRotate(), OpenSeadragon.supportsCanvas, 'we can rotate if we have canvas');
equal(viewer.drawer.getOpacity(), 1, 'starts with full opacity');
viewer.drawer.setOpacity(0.4);
equal(viewer.drawer.getOpacity(), 0.4, 'setting opacity works');
start();
});
// ----------
asyncTest('tile-drawing event', function() {
createViewer({
tileSources: '/test/data/testpattern.dzi'
});
viewer.addHandler('tile-drawing', function handler(event) {
viewer.removeHandler('tile-drawing', handler);
equal(event.eventSource, viewer, 'sender of tile-drawing event was viewer');
ok(event.tile, 'tile-drawing event includes a tile');
ok(event.context, 'tile-drawing event includes a context');
ok(event.rendered, 'tile-drawing event includes a rendered');
start();
});
});
// ----------
asyncTest('rotation', function() {
createViewer({
tileSources: '/test/data/testpattern.dzi'
});
viewer.addHandler('open', function handler(event) {
viewer.viewport.setRotation(30);
Util.spyOnce(viewer.drawer.context, 'rotate', function() {
ok(true, 'drawing with new rotation');
start();
});
});
});
// ----------
asyncTest('debug', function() {
createViewer({
tileSources: '/test/data/testpattern.dzi',
debugMode: true
});
Util.spyOnce(viewer.drawer, 'drawDebugInfo', function() {
ok(true, 'drawDebugInfo is called');
start();
});
});
// ----------
asyncTest('deprecations', function() {
createViewer();
Util.testDeprecation(viewer.drawer, 'addOverlay', viewer, 'addOverlay');
Util.testDeprecation(viewer.drawer, 'updateOverlay', viewer, 'updateOverlay');
Util.testDeprecation(viewer.drawer, 'removeOverlay', viewer, 'removeOverlay');
Util.testDeprecation(viewer.drawer, 'clearOverlays', viewer, 'clearOverlays');
Util.testDeprecation(viewer.drawer, 'needsUpdate', viewer.world, 'needsUpdate');
Util.testDeprecation(viewer.drawer, 'numTilesLoaded', viewer.tileCache, 'numTilesLoaded');
Util.testDeprecation(viewer.drawer, 'reset', viewer.world, 'resetItems');
Util.testDeprecation(viewer.drawer, 'update', viewer.world, 'update');
start();
});
})();

View File

@ -118,8 +118,8 @@
viewer.open( '/test/data/testpattern.dzi' ); viewer.open( '/test/data/testpattern.dzi' );
}); });
// ----------
asyncTest( 'Sequences as items', function() { asyncTest( 'Sequences as items', function() {
var options = { var options = {
tileSource: [{ tileSource: [{
type: 'legacy-image-pyramid', type: 'legacy-image-pyramid',
@ -154,4 +154,25 @@
viewer.open( '/test/data/testpattern.dzi' ); viewer.open( '/test/data/testpattern.dzi' );
}); });
// ----------
asyncTest('items are added in order', function() {
viewer.addHandler('open', function(event) {
equal(viewer.world.getItemAt(0).getContentSize().y, 2000, 'first image is tall');
equal(viewer.world.getItemAt(0).getBounds().width, 4, 'first image has 4 width');
equal(viewer.world.getItemAt(1).getContentSize().x, 2000, 'second image is wide');
equal(viewer.world.getItemAt(1).getBounds().width, 2, 'second image has 2 width');
start();
});
viewer.open([
{
tileSource: '/test/data/tall.dzi',
width: 4
}, {
tileSource: '/test/data/wide.dzi',
width: 2
}
]);
});
})(); })();

View File

@ -1,7 +1,5 @@
/* global QUnit, module, Util, $, console, test, asyncTest, start, ok, equal */ /* global QUnit, module, Util, $, console, test, asyncTest, start, ok, equal */
QUnit.config.autostart = false;
(function () { (function () {
var debug = false, var debug = false,
viewer, viewer,
@ -31,10 +29,6 @@ QUnit.config.autostart = false;
} }
}); });
$(document).ready(function () {
start();
});
var resetTestVariables = function () { var resetTestVariables = function () {
if (viewer) { if (viewer) {
viewer.close(); viewer.close();

View File

@ -1,4 +1,4 @@
/* global QUnit, module, Util, $, console, test, asyncTest, start, ok, equal */ /* global QUnit, module, Util, $, console, test, asyncTest, start, ok, equal, testLog */
( function() { ( function() {
var viewer; var viewer;
@ -532,4 +532,35 @@
} ); } );
// ----------
asyncTest('overlays appear immediately', function() {
equal($('#immediate-overlay0').length, 0, 'overlay 0 does not exist');
equal($('#immediate-overlay1').length, 0, 'overlay 1 does not exist');
viewer = OpenSeadragon( {
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
overlays: [ {
x: 0,
y: 0,
id: "immediate-overlay0"
} ]
} );
viewer.addHandler('open', function() {
equal($('#immediate-overlay0').length, 1, 'overlay 0 exists');
viewer.addOverlay( {
x: 0,
y: 0,
id: "immediate-overlay1"
} );
equal($('#immediate-overlay1').length, 1, 'overlay 1 exists');
start();
});
});
} )( ); } )( );

View File

@ -0,0 +1,46 @@
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
(function() {
var viewer;
module('ReferenceStrip', {
setup: function () {
var example = $('<div id="example"></div>').appendTo("#qunit-fixture");
testLog.reset();
},
teardown: function () {
if (viewer && viewer.close) {
viewer.close();
}
viewer = null;
}
});
// ----------
var createViewer = function(options) {
options = options || {};
viewer = OpenSeadragon(OpenSeadragon.extend({
id: 'example',
prefixUrl: '/build/openseadragon/images/',
springStiffness: 100 // Faster animation = faster tests
}, options));
};
// ----------
asyncTest('basics', function() {
createViewer({
sequenceMode: true,
showReferenceStrip: true,
tileSources: [
'/test/data/tall.dzi',
'/test/data/wide.dzi',
]
});
ok(viewer.referenceStrip, 'referenceStrip exists');
start();
});
})();

111
test/modules/tilecache.js Normal file
View File

@ -0,0 +1,111 @@
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
(function() {
// ----------
module('TileCache', {
setup: function () {
testLog.reset();
},
teardown: function () {
}
});
// ----------
asyncTest('basics', function() {
var fakeTiledImage0 = {};
var fakeTiledImage1 = {};
var fakeTile0 = {
url: 'foo.jpg',
image: {},
unload: function() {}
};
var fakeTile1 = {
url: 'foo.jpg',
image: {},
unload: function() {}
};
var cache = new OpenSeadragon.TileCache();
equal(cache.numTilesLoaded(), 0, 'no tiles to begin with');
cache.cacheTile({
tile: fakeTile0,
tiledImage: fakeTiledImage0
});
equal(cache.numTilesLoaded(), 1, 'tile count after cache');
cache.cacheTile({
tile: fakeTile1,
tiledImage: fakeTiledImage1
});
equal(cache.numTilesLoaded(), 2, 'tile count after second cache');
cache.clearTilesFor(fakeTiledImage0);
equal(cache.numTilesLoaded(), 1, 'tile count after first clear');
cache.clearTilesFor(fakeTiledImage1);
equal(cache.numTilesLoaded(), 0, 'tile count after second clear');
start();
});
// ----------
asyncTest('maxImageCacheCount', function() {
var fakeTiledImage0 = {};
var fakeTile0 = {
url: 'different.jpg',
image: {},
unload: function() {}
};
var fakeTile1 = {
url: 'same.jpg',
image: {},
unload: function() {}
};
var fakeTile2 = {
url: 'same.jpg',
image: {},
unload: function() {}
};
var cache = new OpenSeadragon.TileCache({
maxImageCacheCount: 1
});
equal(cache.numTilesLoaded(), 0, 'no tiles to begin with');
cache.cacheTile({
tile: fakeTile0,
tiledImage: fakeTiledImage0
});
equal(cache.numTilesLoaded(), 1, 'tile count after add');
cache.cacheTile({
tile: fakeTile1,
tiledImage: fakeTiledImage0
});
equal(cache.numTilesLoaded(), 1, 'tile count after add of second image');
cache.cacheTile({
tile: fakeTile2,
tiledImage: fakeTiledImage0
});
equal(cache.numTilesLoaded(), 2, 'tile count after additional same image');
start();
});
})();

144
test/modules/tiledimage.js Normal file
View File

@ -0,0 +1,144 @@
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
(function() {
var viewer;
module('TiledImage', {
setup: function () {
var example = $('<div id="example"></div>').appendTo("#qunit-fixture");
testLog.reset();
viewer = OpenSeadragon({
id: 'example',
prefixUrl: '/build/openseadragon/images/',
springStiffness: 100 // Faster animation = faster tests
});
},
teardown: function () {
if (viewer && viewer.close) {
viewer.close();
}
viewer = null;
}
});
// ----------
var checkBounds = function(image, expected, message) {
var bounds = image.getBounds();
equal(bounds.x, expected.x, message + ' x');
equal(bounds.y, expected.y, message + ' y');
equal(bounds.width, expected.width, message + ' width');
equal(bounds.height, expected.height, message + ' height');
};
// ----------
asyncTest('metrics', function() {
var handlerCount = 0;
viewer.addHandler('open', function(event) {
var image = viewer.world.getItemAt(0);
var contentSize = image.getContentSize();
equal(contentSize.x, 500, 'contentSize.x');
equal(contentSize.y, 2000, 'contentSize.y');
checkBounds(image, new OpenSeadragon.Rect(5, 6, 10, 40), 'initial bounds');
image.addHandler('bounds-change', function boundsChangeHandler(event) {
image.removeHandler('bounds-change', boundsChangeHandler);
handlerCount++;
});
image.setPosition(new OpenSeadragon.Point(7, 8));
checkBounds(image, new OpenSeadragon.Rect(7, 8, 10, 40), 'bounds after position');
image.setWidth(5);
checkBounds(image, new OpenSeadragon.Rect(7, 8, 5, 20), 'bounds after width');
image.setHeight(4);
checkBounds(image, new OpenSeadragon.Rect(7, 8, 1, 4), 'bounds after width');
equal(handlerCount, 1, 'correct number of handlers called');
start();
});
viewer.open({
tileSource: '/test/data/tall.dzi',
x: 5,
y: 6,
width: 10
});
});
// ----------
asyncTest('update', function() {
var handlerCount = 0;
viewer.addHandler('open', function(event) {
var image = viewer.world.getItemAt(0);
equal(image.needsUpdate(), true, 'needs update after open');
viewer.addHandler('update-level', function updateLevelHandler(event) {
viewer.removeHandler('update-level', updateLevelHandler);
handlerCount++;
equal(event.eventSource, viewer, 'sender of update-level event was viewer');
equal(event.tiledImage, image, 'tiledImage of update-level event is correct');
ok('havedrawn' in event, 'update-level event includes havedrawn');
ok('level' in event, 'update-level event includes level');
ok('opacity' in event, 'update-level event includes opacity');
ok('visibility' in event, 'update-level event includes visibility');
ok('topleft' in event, 'update-level event includes topleft');
ok('bottomright' in event, 'update-level event includes bottomright');
ok('currenttime' in event, 'update-level event includes currenttime');
ok('best' in event, 'update-level event includes best');
});
viewer.addHandler('update-tile', function updateTileHandler(event) {
viewer.removeHandler('update-tile', updateTileHandler);
handlerCount++;
equal(event.eventSource, viewer, 'sender of update-tile event was viewer');
equal(event.tiledImage, image, 'tiledImage of update-level event is correct');
ok(event.tile, 'update-tile event includes tile');
});
viewer.addHandler('tile-drawn', function tileDrawnHandler(event) {
viewer.removeHandler('tile-drawn', tileDrawnHandler);
handlerCount++;
equal(event.eventSource, viewer, 'sender of tile-drawn event was viewer');
equal(event.tiledImage, image, 'tiledImage of update-level event is correct');
ok(event.tile, 'tile-drawn event includes tile');
equal(handlerCount, 3, 'correct number of handlers called');
start();
});
image.update();
});
viewer.open('/test/data/testpattern.dzi');
});
// ----------
asyncTest('reset', function() {
viewer.addHandler('tile-drawn', function updateHandler() {
viewer.removeHandler('tile-drawn', updateHandler);
ok(viewer.tileCache.numTilesLoaded() > 0, 'we have tiles after tile-drawn');
viewer.world.getItemAt(0).reset();
equal(viewer.tileCache.numTilesLoaded(), 0, 'no tiles after reset');
viewer.addHandler('tile-drawn', function updateHandler2() {
viewer.removeHandler('tile-drawn', updateHandler2);
ok(viewer.tileCache.numTilesLoaded() > 0, 'more tiles load');
viewer.world.getItemAt(0).destroy();
equal(viewer.tileCache.numTilesLoaded(), 0, 'no tiles after destroy');
start();
});
});
equal(viewer.tileCache.numTilesLoaded(), 0, 'no tiles at start');
viewer.open('/test/data/testpattern.dzi');
});
})();

View File

@ -0,0 +1,20 @@
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
(function() {
var viewer;
module('TileSourceCollection', {
setup: function () {
testLog.reset();
},
teardown: function () {
}
});
// ----------
asyncTest('deprecation', function() {
Util.testDeprecation(OpenSeadragon, 'TileSourceCollection');
start();
});
})();

View File

@ -5,7 +5,7 @@
<title>OpenSeadragon QUnit</title> <title>OpenSeadragon QUnit</title>
<link rel="stylesheet" href="/node_modules/qunitjs/qunit/qunit.css"> <link rel="stylesheet" href="/node_modules/qunitjs/qunit/qunit.css">
<link rel="stylesheet" href="/test/lib/jquery-ui-1.10.2/css/smoothness/jquery-ui-1.10.2.min.css"> <link rel="stylesheet" href="/test/lib/jquery-ui-1.10.2/css/smoothness/jquery-ui-1.10.2.min.css">
<link rel="stylesheet" href="/test/test.css"> <link rel="stylesheet" href="/test/helpers/test.css">
</head> </head>
<body> <body>
<div id="qunit"></div> <div id="qunit"></div>
@ -15,25 +15,30 @@
<script src="/test/lib/jquery-ui-1.10.2/js/jquery-ui-1.10.2.min.js"></script> <script src="/test/lib/jquery-ui-1.10.2/js/jquery-ui-1.10.2.min.js"></script>
<script src="/test/lib/jquery.simulate.js"></script> <script src="/test/lib/jquery.simulate.js"></script>
<script src="/build/openseadragon/openseadragon.js"></script> <script src="/build/openseadragon/openseadragon.js"></script>
<script src="/test/legacy.mouse.shim.js"></script> <script src="/test/helpers/legacy.mouse.shim.js"></script>
<script src="/test/test.js"></script> <script src="/test/helpers/test.js"></script>
<!-- Polyfill must be inserted first because it is testing functions <!-- Polyfill must be inserted first because it is testing functions
reassignments which could be done by other test. --> reassignments which could be done by other test. -->
<script src="/test/polyfills.js"></script> <script src="/test/modules/polyfills.js"></script>
<script src="/test/basic.js"></script> <script src="/test/modules/basic.js"></script>
<script src="/test/strings.js"></script> <script src="/test/modules/strings.js"></script>
<script src="/test/formats.js"></script> <script src="/test/modules/formats.js"></script>
<script src="/test/utils.js"></script> <script src="/test/modules/utils.js"></script>
<script src="/test/events.js"></script> <script src="/test/modules/events.js"></script>
<script src="/test/units.js"></script> <script src="/test/modules/units.js"></script>
<script src="/test/multi-image.js"></script> <script src="/test/modules/multi-image.js"></script>
<script src="/test/overlays.js"></script> <script src="/test/modules/overlays.js"></script>
<script src="/test/controls.js"></script> <script src="/test/modules/controls.js"></script>
<script src="/test/viewport.js"></script> <script src="/test/viewport.js"></script>
<script src="/test/world.js"></script> <script src="/test/modules/world.js"></script>
<script src="/test/modules/drawer.js"></script>
<script src="/test/modules/tiledimage.js"></script>
<script src="/test/modules/tilecache.js"></script>
<script src="/test/modules/referencestrip.js"></script>
<script src="/test/modules/tilesourcecollection.js"></script>
<!-- The navigator tests are the slowest (for now; hopefully they can be sped up) <!-- The navigator tests are the slowest (for now; hopefully they can be sped up)
so we put them last. --> so we put them last. -->
<script src="/test/navigator.js"></script> <script src="/test/modules/navigator.js"></script>
</body> </body>
</html> </html>