Fix black viewport with testing filtering demo on webgl renderer. Introduce managed mock getters for tests.

This commit is contained in:
Aiosa 2024-03-05 10:48:07 +01:00
parent e2c633a23b
commit e0f442209b
9 changed files with 171 additions and 149 deletions

View File

@ -2707,7 +2707,7 @@ function OpenSeadragon( options ){
if (newCache) {
newCache._updateStamp = tStamp;
} else {
$.console.error("After an update, the tile %s has not cache data! Check handlers on 'tile-needs-update' evemt!", tile);
$.console.error("After an update, the tile %s has not cache data! Check handlers on 'tile-needs-update' event!", tile);
}
});
}

View File

@ -598,8 +598,8 @@ $.Tile.prototype = {
ref.destroyInternalCache();
}
this._cKey = value;
// when key changes the image probably needs re-render
this.tiledImage.redraw();
// we do not trigger redraw, this is handled within cache
// as drawers request data for drawing
},
/**

View File

@ -180,7 +180,8 @@
let internalCache = this[DRAWER_INTERNAL_CACHE];
if (keepInternalCopy && !internalCache) {
this.prepareForRendering(supportedTypes, keepInternalCopy).then(() => this._triggerNeedsDraw);
this.prepareForRendering(supportedTypes, keepInternalCopy)
.then(() => this._triggerNeedsDraw());
return undefined;
}
@ -198,7 +199,7 @@
if (!supportedTypes.includes(internalCache.type)) {
internalCache.transformTo(supportedTypes.length > 1 ? supportedTypes : supportedTypes[0])
.then(() => this._triggerNeedsDraw);
.then(() => this._triggerNeedsDraw());
return undefined; // type is NOT compatible
}

View File

@ -58,6 +58,7 @@
<!-- Helpers -->
<script src="/test/helpers/legacy.mouse.shim.js"></script>
<script src="/test/helpers/mocks.js"></script>
<script src="/test/helpers/test.js"></script>
<script src="/test/helpers/touch.js"></script>

95
test/helpers/mocks.js Normal file
View File

@ -0,0 +1,95 @@
// Test-wide mocks for more test stability: tests might require calling functions that expect
// presence of certain mock properties. It is better to include maintened mock props than to copy
// over all the place
window.MockSeadragon = {
/**
* Get mocked tile: loaded state, cutoff such that it is not kept in cache by force,
* level: 1, x: 0, y: 0, all coords: [x0 y0 w0 h0]
*
* Requires TiledImage referece (mock or real)
* @return {OpenSeadragon.Tile}
*/
getTile(url, tiledImage, props={}) {
const dummyRect = new OpenSeadragon.Rect(0, 0, 0, 0, 0);
//default cutoof = 0 --> use level 1 to not to keep caches from unloading (cutoff = navigator data, kept in cache)
const dummyTile = new OpenSeadragon.Tile(1, 0, 0, dummyRect, true, url,
undefined, true, null, dummyRect, null, url);
dummyTile.tiledImage = tiledImage;
//by default set as ready
dummyTile.loaded = true;
dummyTile.loading = false;
//override anything we need
OpenSeadragon.extend(tiledImage, props);
return dummyTile;
},
/**
* Get mocked viewer: it has not all props that might be required. If your
* tests fails because they do not find some props on a viewer, add them here.
*
* Requires a drawer reference (mock or real). Automatically created if not provided.
* @return {OpenSeadragon.Viewer}
*/
getViewer(drawer=null, props={}) {
drawer = drawer || this.getDrawer();
return OpenSeadragon.extend(new class extends OpenSeadragon.EventSource {
forceRedraw () {}
drawer = drawer
tileCache = new OpenSeadragon.TileCache()
}, props);
},
/**
* Get mocked viewer: it has not all props that might be required. If your
* tests fails because they do not find some props on a viewer, add them here.
* @return {OpenSeadragon.Viewer}
*/
getDrawer(props={}) {
return OpenSeadragon.extend({
getType: function () {
return "mock";
}
}, props);
},
/**
* Get mocked tiled image: it has not all props that might be required. If your
* tests fails because they do not find some props on a tiled image, add them here.
*
* Requires viewer reference (mock or real). Automatically created if not provided.
* @return {OpenSeadragon.TiledImage}
*/
getTiledImage(viewer=null, props={}) {
viewer = viewer || this.getViewer();
return OpenSeadragon.extend({
viewer: viewer,
source: OpenSeadragon.TileSource.prototype,
redraw: function() {},
_tileCache: viewer.tileCache
}, props);
},
/**
* Get mocked tile source
* @return {OpenSeadragon.TileSource}
*/
getTileSource(props={}) {
return new OpenSeadragon.TileSource(OpenSeadragon.extend({
width: 1500,
height: 1000,
tileWidth: 200,
tileHeight: 150,
tileOverlap: 0
}, props));
},
/**
* Get mocked cache record
* @return {OpenSeadragon.CacheRecord}
*/
getCacheRecord(props={}) {
return OpenSeadragon.extend(new OpenSeadragon.CacheRecord(), props);
}
};

View File

@ -18,17 +18,6 @@
}, 20);
}
function createFakeTile(url, tiledImage, loading=false, loaded=true) {
const dummyRect = new OpenSeadragon.Rect(0, 0, 0, 0, 0);
//default cutoof = 0 --> use level 1 to not to keep caches from unloading (cutoff = navigator data, kept in cache)
const dummyTile = new OpenSeadragon.Tile(1, 0, 0, dummyRect, true, url,
undefined, true, null, dummyRect, null, url);
dummyTile.tiledImage = tiledImage;
dummyTile.loading = loading;
dummyTile.loaded = loaded;
return dummyTile;
}
// Replace conversion with our own system and test: __TEST__ prefix must be used, otherwise
// other tests will interfere
let typeAtoB = 0, typeBtoC = 0, typeCtoA = 0, typeDtoA = 0, typeCtoE = 0;
@ -122,28 +111,19 @@
// TODO: this used to be async
QUnit.test('basics', function(assert) {
const done = assert.async();
const fakeViewer = {
raiseEvent: function() {},
drawer: {
const fakeViewer = MockSeadragon.getViewer(
MockSeadragon.getDrawer({
// tile in safe mode inspects the supported formats upon cache set
getSupportedDataFormats() {
return [T_A, T_B, T_C, T_D, T_E];
}
}
};
const fakeTiledImage0 = {
viewer: fakeViewer,
source: OpenSeadragon.TileSource.prototype,
redraw: function() {}
};
const fakeTiledImage1 = {
viewer: fakeViewer,
source: OpenSeadragon.TileSource.prototype,
redraw: function() {}
};
})
);
const fakeTiledImage0 = MockSeadragon.getTiledImage(fakeViewer);
const fakeTiledImage1 = MockSeadragon.getTiledImage(fakeViewer);
const tile0 = createFakeTile('foo.jpg', fakeTiledImage0);
const tile1 = createFakeTile('foo.jpg', fakeTiledImage1);
const tile0 = MockSeadragon.getTile('foo.jpg', fakeTiledImage0);
const tile1 = MockSeadragon.getTile('foo.jpg', fakeTiledImage1);
const cache = new OpenSeadragon.TileCache();
assert.equal(cache.numTilesLoaded(), 0, 'no tiles to begin with');
@ -177,24 +157,18 @@
// ----------
QUnit.test('maxImageCacheCount', function(assert) {
const done = assert.async();
const fakeViewer = {
raiseEvent: function() {},
drawer: {
const fakeViewer = MockSeadragon.getViewer(
MockSeadragon.getDrawer({
// tile in safe mode inspects the supported formats upon cache set
getSupportedDataFormats() {
return [T_A, T_B, T_C, T_D, T_E];
}
}
};
const fakeTiledImage0 = {
viewer: fakeViewer,
source: OpenSeadragon.TileSource.prototype,
draw: function() {}
};
const tile0 = createFakeTile('different.jpg', fakeTiledImage0);
const tile1 = createFakeTile('same.jpg', fakeTiledImage0);
const tile2 = createFakeTile('same.jpg', fakeTiledImage0);
})
);
const fakeTiledImage0 = MockSeadragon.getTiledImage(fakeViewer);
const tile0 = MockSeadragon.getTile('different.jpg', fakeTiledImage0);
const tile1 = MockSeadragon.getTile('same.jpg', fakeTiledImage0);
const tile2 = MockSeadragon.getTile('same.jpg', fakeTiledImage0);
const cache = new OpenSeadragon.TileCache({
maxImageCacheCount: 1
@ -232,39 +206,28 @@
//Tile API and cache interaction
QUnit.test('Tile API: basic conversion', function(test) {
const done = test.async();
const fakeViewer = {
raiseEvent: function() {},
drawer: {
const fakeViewer = MockSeadragon.getViewer(
MockSeadragon.getDrawer({
// tile in safe mode inspects the supported formats upon cache set
getSupportedDataFormats() {
return [T_A, T_B, T_C, T_D, T_E];
}
}
};
const tileCache = new OpenSeadragon.TileCache();
const fakeTiledImage0 = {
viewer: fakeViewer,
source: OpenSeadragon.TileSource.prototype,
_tileCache: tileCache,
redraw: function() {}
};
const fakeTiledImage1 = {
viewer: fakeViewer,
source: OpenSeadragon.TileSource.prototype,
_tileCache: tileCache,
redraw: function() {}
};
})
);
const tileCache = fakeViewer.tileCache;
const fakeTiledImage0 = MockSeadragon.getTiledImage(fakeViewer);
const fakeTiledImage1 = MockSeadragon.getTiledImage(fakeViewer);
//load data
const tile00 = createFakeTile('foo.jpg', fakeTiledImage0);
const tile00 = MockSeadragon.getTile('foo.jpg', fakeTiledImage0);
tile00.addCache(tile00.cacheKey, 0, T_A, false, false);
const tile01 = createFakeTile('foo2.jpg', fakeTiledImage0);
const tile01 = MockSeadragon.getTile('foo2.jpg', fakeTiledImage0);
tile01.addCache(tile01.cacheKey, 0, T_B, false, false);
const tile10 = createFakeTile('foo3.jpg', fakeTiledImage1);
const tile10 = MockSeadragon.getTile('foo3.jpg', fakeTiledImage1);
tile10.addCache(tile10.cacheKey, 0, T_C, false, false);
const tile11 = createFakeTile('foo3.jpg', fakeTiledImage1);
const tile11 = MockSeadragon.getTile('foo3.jpg', fakeTiledImage1);
tile11.addCache(tile11.cacheKey, 0, T_C, false, false);
const tile12 = createFakeTile('foo.jpg', fakeTiledImage1);
const tile12 = MockSeadragon.getTile('foo.jpg', fakeTiledImage1);
tile12.addCache(tile12.cacheKey, 0, T_A, false, false);
const collideGetSet = async (tile, type) => {
@ -428,39 +391,28 @@
//Tile API and cache interaction
QUnit.test('Tile API Cache Interaction', function(test) {
const done = test.async();
const fakeViewer = {
raiseEvent: function() {},
drawer: {
const fakeViewer = MockSeadragon.getViewer(
MockSeadragon.getDrawer({
// tile in safe mode inspects the supported formats upon cache set
getSupportedDataFormats() {
return [T_A, T_B, T_C, T_D, T_E];
}
}
};
const tileCache = new OpenSeadragon.TileCache();
const fakeTiledImage0 = {
viewer: fakeViewer,
source: OpenSeadragon.TileSource.prototype,
_tileCache: tileCache,
redraw: function() {}
};
const fakeTiledImage1 = {
viewer: fakeViewer,
source: OpenSeadragon.TileSource.prototype,
_tileCache: tileCache,
redraw: function() {}
};
})
);
const tileCache = fakeViewer.tileCache;
const fakeTiledImage0 = MockSeadragon.getTiledImage(fakeViewer);
const fakeTiledImage1 = MockSeadragon.getTiledImage(fakeViewer);
//load data
const tile00 = createFakeTile('foo.jpg', fakeTiledImage0);
const tile00 = MockSeadragon.getTile('foo.jpg', fakeTiledImage0);
tile00.addCache(tile00.cacheKey, 0, T_A, false, false);
const tile01 = createFakeTile('foo2.jpg', fakeTiledImage0);
const tile01 = MockSeadragon.getTile('foo2.jpg', fakeTiledImage0);
tile01.addCache(tile01.cacheKey, 0, T_B, false, false);
const tile10 = createFakeTile('foo3.jpg', fakeTiledImage1);
const tile10 = MockSeadragon.getTile('foo3.jpg', fakeTiledImage1);
tile10.addCache(tile10.cacheKey, 0, T_C, false, false);
const tile11 = createFakeTile('foo3.jpg', fakeTiledImage1);
const tile11 = MockSeadragon.getTile('foo3.jpg', fakeTiledImage1);
tile11.addCache(tile11.cacheKey, 0, T_C, false, false);
const tile12 = createFakeTile('foo.jpg', fakeTiledImage1);
const tile12 = MockSeadragon.getTile('foo.jpg', fakeTiledImage1);
tile12.addCache(tile12.cacheKey, 0, T_A, false, false);
//test set/get data in async env

View File

@ -558,17 +558,17 @@
});
QUnit.test('_getCornerTiles without wrapping', function(assert) {
var tiledImageMock = {
var tiledImageMock = MockSeadragon.getTiledImage(null, {
wrapHorizontal: false,
wrapVertical: false,
source: new OpenSeadragon.TileSource({
source: MockSeadragon.getTileSource({
width: 1500,
height: 1000,
tileWidth: 200,
tileHeight: 150,
tileOverlap: 1,
}),
};
})
});
var _getCornerTiles = OpenSeadragon.TiledImage.prototype._getCornerTiles.bind(tiledImageMock);
function assertCornerTiles(topLeftBound, bottomRightBound,
@ -606,17 +606,13 @@
});
QUnit.test('_getCornerTiles with horizontal wrapping', function(assert) {
var tiledImageMock = {
var tiledImageMock = MockSeadragon.getTiledImage(null, {
wrapHorizontal: true,
wrapVertical: false,
source: new OpenSeadragon.TileSource({
width: 1500,
height: 1000,
tileWidth: 200,
tileHeight: 150,
tileOverlap: 1,
}),
};
source: MockSeadragon.getTileSource({
tileOverlap: 1
})
});
var _getCornerTiles = OpenSeadragon.TiledImage.prototype._getCornerTiles.bind(tiledImageMock);
function assertCornerTiles(topLeftBound, bottomRightBound,
@ -653,17 +649,13 @@
});
QUnit.test('_getCornerTiles with vertical wrapping', function(assert) {
var tiledImageMock = {
var tiledImageMock = MockSeadragon.getTiledImage(null, {
wrapHorizontal: false,
wrapVertical: true,
source: new OpenSeadragon.TileSource({
width: 1500,
height: 1000,
tileWidth: 200,
tileHeight: 150,
tileOverlap: 1,
}),
};
source: MockSeadragon.getTileSource({
tileOverlap: 1
})
});
var _getCornerTiles = OpenSeadragon.TiledImage.prototype._getCornerTiles.bind(tiledImageMock);
function assertCornerTiles(topLeftBound, bottomRightBound,

View File

@ -210,14 +210,8 @@
QUnit.test('Data Convertors via Cache object: testing conversion & destruction', function (test) {
const done = test.async();
const dummyRect = new OpenSeadragon.Rect(0, 0, 0, 0, 0);
const dummyTile = new OpenSeadragon.Tile(0, 0, 0, dummyRect, true, "",
undefined, true, null, dummyRect, "", "key");
dummyTile.tiledImage = {
redraw: function () {}
};
const cache = new OpenSeadragon.CacheRecord();
const dummyTile = MockSeadragon.getTile("", MockSeadragon.getTiledImage(), {cacheKey: "key"});
const cache = MockSeadragon.getCacheRecord();
cache.addTile(dummyTile, "/test/data/A.png", "__TEST__url");
//load image object: url -> image
@ -262,18 +256,14 @@
QUnit.test('Data Convertors via Cache object: testing set/get', function (test) {
const done = test.async();
const dummyRect = new OpenSeadragon.Rect(0, 0, 0, 0, 0);
const dummyTile = new OpenSeadragon.Tile(0, 0, 0, dummyRect, true, "",
undefined, true, null, dummyRect, "", "key");
dummyTile.tiledImage = {
redraw: function () {}
};
const cache = new OpenSeadragon.CacheRecord();
cache.testGetSet = async function(type) {
const value = await cache.getDataAs(type, false);
await cache.setDataAs(value, type);
return value;
}
const dummyTile = MockSeadragon.getTile("", MockSeadragon.getTiledImage(), {cacheKey: "key"});
const cache = MockSeadragon.getCacheRecord({
testGetSet: async function(type) {
const value = await cache.getDataAs(type, false);
await cache.setDataAs(value, type);
return value;
}
});
cache.addTile(dummyTile, "/test/data/A.png", "__TEST__url");
//load image object: url -> image
@ -332,13 +322,8 @@
longConversionDestroy++;
});
const dummyRect = new OpenSeadragon.Rect(0, 0, 0, 0, 0);
const dummyTile = new OpenSeadragon.Tile(0, 0, 0, dummyRect, true, "",
undefined, true, null, dummyRect, "", "key");
dummyTile.tiledImage = {
redraw: function () {}
};
const cache = new OpenSeadragon.CacheRecord();
const dummyTile = MockSeadragon.getTile("", MockSeadragon.getTiledImage(), {cacheKey: "key"});
const cache = MockSeadragon.getCacheRecord();
cache.addTile(dummyTile, "/test/data/A.png", "__TEST__url");
cache.getDataAs("__TEST__longConversionProcessForTesting").then(convertedData => {
test.equal(longConversionDestroy, 1, "Copy already destroyed.");
@ -377,13 +362,8 @@
destructionHappened = true;
});
const dummyRect = new OpenSeadragon.Rect(0, 0, 0, 0, 0);
const dummyTile = new OpenSeadragon.Tile(0, 0, 0, dummyRect, true, "",
undefined, true, null, dummyRect, "", "key");
dummyTile.tiledImage = {
redraw: function () {}
};
const cache = new OpenSeadragon.CacheRecord();
const dummyTile = MockSeadragon.getTile("", MockSeadragon.getTiledImage(), {cacheKey: "key"});
const cache = MockSeadragon.getCacheRecord();
cache.addTile(dummyTile, "/test/data/A.png", "__TEST__url");
cache.transformTo("__TEST__longConversionProcessForTesting").then(_ => {
test.ok(conversionHappened, "Interrupted conversion finished.");

View File

@ -24,6 +24,7 @@
<script src="/test/lib/jquery.simulate.js"></script>
<script src="/build/openseadragon/openseadragon.min.js"></script>
<script src="/test/helpers/legacy.mouse.shim.js"></script>
<script src="/test/helpers/mocks.js"></script>
<script src="/test/helpers/test.js"></script>
<script src="/test/helpers/touch.js"></script>