From e0f442209b2d86fc9043dc5457ca9fd3513f2822 Mon Sep 17 00:00:00 2001 From: Aiosa <469130@mail.muni.cz> Date: Tue, 5 Mar 2024 10:48:07 +0100 Subject: [PATCH] Fix black viewport with testing filtering demo on webgl renderer. Introduce managed mock getters for tests. --- src/openseadragon.js | 2 +- src/tile.js | 4 +- src/tilecache.js | 5 +- test/coverage.html | 1 + test/helpers/mocks.js | 95 ++++++++++++++++++++++++ test/modules/tilecache.js | 128 ++++++++++---------------------- test/modules/tiledimage.js | 36 ++++----- test/modules/type-conversion.js | 48 ++++-------- test/test.html | 1 + 9 files changed, 171 insertions(+), 149 deletions(-) create mode 100644 test/helpers/mocks.js diff --git a/src/openseadragon.js b/src/openseadragon.js index d13fcfc8..0326b28f 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -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); } }); } diff --git a/src/tile.js b/src/tile.js index ce22ead4..258c62d6 100644 --- a/src/tile.js +++ b/src/tile.js @@ -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 }, /** diff --git a/src/tilecache.js b/src/tilecache.js index 67aced6e..89bc4783 100644 --- a/src/tilecache.js +++ b/src/tilecache.js @@ -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 } diff --git a/test/coverage.html b/test/coverage.html index e4046459..30b27ab2 100644 --- a/test/coverage.html +++ b/test/coverage.html @@ -58,6 +58,7 @@ + diff --git a/test/helpers/mocks.js b/test/helpers/mocks.js new file mode 100644 index 00000000..2958fe19 --- /dev/null +++ b/test/helpers/mocks.js @@ -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); + } +}; + diff --git a/test/modules/tilecache.js b/test/modules/tilecache.js index f06bea84..e5ebe519 100644 --- a/test/modules/tilecache.js +++ b/test/modules/tilecache.js @@ -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 diff --git a/test/modules/tiledimage.js b/test/modules/tiledimage.js index 6c33b752..bbee01ce 100644 --- a/test/modules/tiledimage.js +++ b/test/modules/tiledimage.js @@ -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, diff --git a/test/modules/type-conversion.js b/test/modules/type-conversion.js index 4882eadd..07fa1213 100644 --- a/test/modules/type-conversion.js +++ b/test/modules/type-conversion.js @@ -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."); diff --git a/test/test.html b/test/test.html index 9baa6c1f..5da55417 100644 --- a/test/test.html +++ b/test/test.html @@ -24,6 +24,7 @@ +