feat: Support thumbnails in ImageryView and ImageryTimeView (#6132)

* fix: get image thumbnail formatter

* refactor: ImageryView cleanup

* docs: add comment

* feat: Support thumbnails in ImageryView

- Prefer an image's thumbnail URL if its available

* feat: Support thumbnails in ImageryTimeView

* refactor: rename variable

* test(WIP): add thumbnail unit test, not working yet

* test: temp disable test

* feat: imagery thumbnail urls for example imagery

* test: add unit test for imagery thumbnails

* test(e2e): check for thumbnail urls

- Update imagery view tests to check for use of thumbnail urls
This commit is contained in:
Jesse Mazzella 2023-01-21 11:25:35 -08:00 committed by GitHub
parent 986c596d90
commit 5e530aa625
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 166 additions and 73 deletions

View File

@ -25,13 +25,13 @@ This test suite is dedicated to tests which verify the basic operations surround
but only assume that example imagery is present. but only assume that example imagery is present.
*/ */
/* globals process */ /* globals process */
const { v4: uuid } = require('uuid');
const { waitForAnimations } = require('../../../../baseFixtures'); const { waitForAnimations } = require('../../../../baseFixtures');
const { test, expect } = require('../../../../pluginFixtures'); const { test, expect } = require('../../../../pluginFixtures');
const { createDomainObjectWithDefaults } = require('../../../../appActions'); const { createDomainObjectWithDefaults } = require('../../../../appActions');
const backgroundImageSelector = '.c-imagery__main-image__background-image'; const backgroundImageSelector = '.c-imagery__main-image__background-image';
const panHotkey = process.platform === 'linux' ? ['Control', 'Alt'] : ['Alt']; const panHotkey = process.platform === 'linux' ? ['Control', 'Alt'] : ['Alt'];
const expectedAltText = process.platform === 'linux' ? 'Ctrl+Alt drag to pan' : 'Alt drag to pan'; const expectedAltText = process.platform === 'linux' ? 'Ctrl+Alt drag to pan' : 'Alt drag to pan';
const thumbnailUrlParamsRegexp = /\?w=100&h=100/;
//The following block of tests verifies the basic functionality of example imagery and serves as a template for Imagery objects embedded in other objects. //The following block of tests verifies the basic functionality of example imagery and serves as a template for Imagery objects embedded in other objects.
test.describe('Example Imagery Object', () => { test.describe('Example Imagery Object', () => {
@ -397,13 +397,11 @@ test.describe('Example Imagery in Time Strip', () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto('./', { waitUntil: 'networkidle' }); await page.goto('./', { waitUntil: 'networkidle' });
timeStripObject = await createDomainObjectWithDefaults(page, { timeStripObject = await createDomainObjectWithDefaults(page, {
type: 'Time Strip', type: 'Time Strip'
name: 'Time Strip'.concat(' ', uuid())
}); });
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'Example Imagery', type: 'Example Imagery',
name: 'Example Imagery'.concat(' ', uuid()),
parent: timeStripObject.uuid parent: timeStripObject.uuid
}); });
// Navigate to timestrip // Navigate to timestrip
@ -414,17 +412,28 @@ test.describe('Example Imagery in Time Strip', () => {
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/5632' description: 'https://github.com/nasa/openmct/issues/5632'
}); });
// Hover over the timestrip to reveal a thumbnail image
await page.locator('.c-imagery-tsv-container').hover(); await page.locator('.c-imagery-tsv-container').hover();
// get url of the hovered image
const hoveredImg = page.locator('.c-imagery-tsv div.c-imagery-tsv__image-wrapper:hover img'); // Get the img src of the hovered image thumbnail
const hoveredImgSrc = await hoveredImg.getAttribute('src'); const hoveredThumbnailImg = page.locator('.c-imagery-tsv div.c-imagery-tsv__image-wrapper:hover img');
expect(hoveredImgSrc).toBeTruthy(); const hoveredThumbnailImgSrc = await hoveredThumbnailImg.getAttribute('src');
// Verify that imagery timestrip view uses the thumbnailUrl as img src for thumbnails
expect(hoveredThumbnailImgSrc).toBeTruthy();
expect(hoveredThumbnailImgSrc).toMatch(thumbnailUrlParamsRegexp);
// Click on the hovered thumbnail to open "View Large" view
await page.locator('.c-imagery-tsv-container').click(); await page.locator('.c-imagery-tsv-container').click();
// get image of view large container
// Get the img src of the large view image
const viewLargeImg = page.locator('img.c-imagery__main-image__image'); const viewLargeImg = page.locator('img.c-imagery__main-image__image');
const viewLargeImgSrc = await viewLargeImg.getAttribute('src'); const viewLargeImgSrc = await viewLargeImg.getAttribute('src');
expect(viewLargeImgSrc).toBeTruthy(); expect(viewLargeImgSrc).toBeTruthy();
expect(viewLargeImgSrc).toEqual(hoveredImgSrc);
// Verify that the image in the large view is the same as the hovered thumbnail
expect(viewLargeImgSrc).toEqual(hoveredThumbnailImgSrc.split('?')[0]);
}); });
}); });
@ -441,6 +450,12 @@ test.describe('Example Imagery in Time Strip', () => {
* @param {import('@playwright/test').Page} page * @param {import('@playwright/test').Page} page
*/ */
async function performImageryViewOperationsAndAssert(page) { async function performImageryViewOperationsAndAssert(page) {
// Verify that imagery thumbnails use a thumbnail url
const thumbnailImages = page.locator('.c-thumb__image');
const mainImage = page.locator('.c-imagery__main-image__image');
await expect(thumbnailImages.first()).toHaveAttribute('src', thumbnailUrlParamsRegexp);
await expect(mainImage).not.toHaveAttribute('src', thumbnailUrlParamsRegexp);
// Click previous image button // Click previous image button
const previousImageButton = page.locator('.c-nav--prev'); const previousImageButton = page.locator('.c-nav--prev');
await previousImageButton.click(); await previousImageButton.click();

View File

@ -107,6 +107,15 @@ export default function () {
} }
] ]
}, },
{
name: 'Image Thumbnail',
key: 'thumbnail-url',
format: 'thumbnail',
hints: {
thumbnail: 1
},
source: 'url'
},
{ {
name: 'Image Download Name', name: 'Image Download Name',
key: 'imageDownloadName', key: 'imageDownloadName',
@ -143,6 +152,16 @@ export default function () {
] ]
}); });
const formatThumbnail = {
format: function (url) {
return `${url}?w=100&h=100`;
}
};
openmct.telemetry.addFormat({
key: 'thumbnail',
...formatThumbnail
});
openmct.telemetry.addProvider(getRealtimeProvider()); openmct.telemetry.addProvider(getRealtimeProvider());
openmct.telemetry.addProvider(getHistoricalProvider()); openmct.telemetry.addProvider(getHistoricalProvider());
openmct.telemetry.addProvider(getLadProvider()); openmct.telemetry.addProvider(getLadProvider());

View File

@ -39,7 +39,7 @@
<img <img
ref="img" ref="img"
class="c-thumb__image" class="c-thumb__image"
:src="image.url" :src="`${image.thumbnailUrl || image.url}`"
fetchpriority="low" fetchpriority="low"
@load="imageLoadCompleted" @load="imageLoadCompleted"
> >

View File

@ -186,17 +186,17 @@ export default {
item.remove(); item.remove();
}); });
let imagery = this.$el.querySelectorAll(`.${IMAGE_WRAPPER_CLASS}`); let imagery = this.$el.querySelectorAll(`.${IMAGE_WRAPPER_CLASS}`);
imagery.forEach(item => { imagery.forEach(imageElm => {
if (clearAllImagery) { if (clearAllImagery) {
item.remove(); imageElm.remove();
} else { } else {
const id = item.getAttributeNS(null, 'id'); const id = imageElm.getAttributeNS(null, 'id');
if (id) { if (id) {
const timestamp = id.replace(ID_PREFIX, ''); const timestamp = id.replace(ID_PREFIX, '');
if (!this.isImageryInBounds({ if (!this.isImageryInBounds({
time: timestamp time: timestamp
})) { })) {
item.remove(); imageElm.remove();
} }
} }
} }
@ -343,25 +343,25 @@ export default {
imageElement.style.display = 'block'; imageElement.style.display = 'block';
} }
}, },
updateExistingImageWrapper(existingImageWrapper, item, showImagePlaceholders) { updateExistingImageWrapper(existingImageWrapper, image, showImagePlaceholders) {
//Update the x co-ordinates of the image wrapper and the url of image //Update the x co-ordinates of the image wrapper and the url of image
//this is to avoid tearing down all elements completely and re-drawing them //this is to avoid tearing down all elements completely and re-drawing them
this.setNSAttributesForElement(existingImageWrapper, { this.setNSAttributesForElement(existingImageWrapper, {
'data-show-image-placeholders': showImagePlaceholders 'data-show-image-placeholders': showImagePlaceholders
}); });
existingImageWrapper.style.left = `${this.xScale(item.time)}px`; existingImageWrapper.style.left = `${this.xScale(image.time)}px`;
let imageElement = existingImageWrapper.querySelector('img'); let imageElement = existingImageWrapper.querySelector('img');
this.setNSAttributesForElement(imageElement, { this.setNSAttributesForElement(imageElement, {
src: item.url src: image.thumbnailUrl || image.url
}); });
this.setImageDisplay(imageElement, showImagePlaceholders); this.setImageDisplay(imageElement, showImagePlaceholders);
}, },
createImageWrapper(index, item, showImagePlaceholders) { createImageWrapper(index, image, showImagePlaceholders) {
const id = `${ID_PREFIX}${item.time}`; const id = `${ID_PREFIX}${image.time}`;
let imageWrapper = document.createElement('div'); let imageWrapper = document.createElement('div');
imageWrapper.classList.add(IMAGE_WRAPPER_CLASS); imageWrapper.classList.add(IMAGE_WRAPPER_CLASS);
imageWrapper.style.left = `${this.xScale(item.time)}px`; imageWrapper.style.left = `${this.xScale(image.time)}px`;
this.setNSAttributesForElement(imageWrapper, { this.setNSAttributesForElement(imageWrapper, {
id, id,
'data-show-image-placeholders': showImagePlaceholders 'data-show-image-placeholders': showImagePlaceholders
@ -383,7 +383,7 @@ export default {
//create image element //create image element
let imageElement = document.createElement('img'); let imageElement = document.createElement('img');
this.setNSAttributesForElement(imageElement, { this.setNSAttributesForElement(imageElement, {
src: item.url src: image.thumbnailUrl || image.url
}); });
imageElement.style.width = `${IMAGE_SIZE}px`; imageElement.style.width = `${IMAGE_SIZE}px`;
imageElement.style.height = `${IMAGE_SIZE}px`; imageElement.style.height = `${IMAGE_SIZE}px`;
@ -392,7 +392,7 @@ export default {
//handle mousedown event to show the image in a large view //handle mousedown event to show the image in a large view
imageWrapper.addEventListener('mousedown', (e) => { imageWrapper.addEventListener('mousedown', (e) => {
if (e.button === 0) { if (e.button === 0) {
this.expand(item.time); this.expand(image.time);
} }
}); });

View File

@ -171,7 +171,7 @@
> >
<ImageThumbnail <ImageThumbnail
v-for="(image, index) in imageHistory" v-for="(image, index) in imageHistory"
:key="image.url + image.time" :key="`${image.thumbnailUrl || image.url}${image.time}`"
:image="image" :image="image"
:active="focusedImageIndex === index" :active="focusedImageIndex === index"
:selected="focusedImageIndex === index && isPaused" :selected="focusedImageIndex === index && isPaused"
@ -225,6 +225,9 @@ const SHOW_THUMBS_FULLSIZE_THRESHOLD_HEIGHT = 600;
const IMAGE_CONTAINER_BORDER_WIDTH = 1; const IMAGE_CONTAINER_BORDER_WIDTH = 1;
const DEFAULT_IMAGE_PAN_ALT_TEXT = "Alt drag to pan";
const LINUX_IMAGE_PAN_ALT_TEXT = `Ctrl+${DEFAULT_IMAGE_PAN_ALT_TEXT}`;
export default { export default {
name: 'ImageryView', name: 'ImageryView',
components: { components: {
@ -308,8 +311,8 @@ export default {
}, },
focusImageStyles() { focusImageStyles() {
return { return {
'filter': `brightness(${this.filters.brightness}%) contrast(${this.filters.contrast}%)`, filter: `brightness(${this.filters.brightness}%) contrast(${this.filters.contrast}%)`,
'background-image': backgroundImage:
`${this.imageUrl ? ( `${this.imageUrl ? (
`url(${this.imageUrl}), `url(${this.imageUrl}),
repeating-linear-gradient( repeating-linear-gradient(
@ -320,10 +323,10 @@ export default {
rgba(125,125,125,.2) 8px rgba(125,125,125,.2) 8px
)` )`
) : ''}`, ) : ''}`,
'transform': `scale(${this.zoomFactor}) translate(${this.imageTranslateX}px, ${this.imageTranslateY}px)`, transform: `scale(${this.zoomFactor}) translate(${this.imageTranslateX}px, ${this.imageTranslateY}px)`,
'transition': `${!this.pan && this.animateZoom ? 'transform 250ms ease-in' : 'initial'}`, transition: `${!this.pan && this.animateZoom ? 'transform 250ms ease-in' : 'initial'}`,
'width': `${this.sizedImageWidth}px`, width: `${this.sizedImageWidth}px`,
'height': `${this.sizedImageHeight}px` height: `${this.sizedImageHeight}px`
}; };
}, },
time() { time() {
@ -334,11 +337,12 @@ export default {
}, },
imageWrapperStyle() { imageWrapperStyle() {
return { return {
'cursor-zoom-in': this.cursorStates.showCursorZoomIn, cursorZoomIn: this.cursorStates.showCursorZoomIn,
'cursor-zoom-out': this.cursorStates.showCursorZoomOut, cursorZoomOut: this.cursorStates.showCursorZoomOut,
'pannable': this.cursorStates.isPannable, pannable: this.cursorStates.isPannable,
'paused unnsynced': this.isPaused && !this.isFixed, paused: this.isPaused && !this.isFixed,
'stale': false unsynced: this.isPaused && !this.isFixed,
stale: false
}; };
}, },
isImageNew() { isImageNew() {
@ -515,10 +519,10 @@ export default {
const navigator = window.navigator.userAgent; const navigator = window.navigator.userAgent;
if (regexLinux.test(navigator)) { if (regexLinux.test(navigator)) {
return 'Ctrl+Alt drag to pan'; return LINUX_IMAGE_PAN_ALT_TEXT;
} }
return 'Alt drag to pan'; return DEFAULT_IMAGE_PAN_ALT_TEXT;
}, },
viewableArea() { viewableArea() {
if (this.zoomFactor === 1) { if (this.zoomFactor === 1) {
@ -679,9 +683,9 @@ export default {
}, },
getVisibleLayerStyles(layer) { getVisibleLayerStyles(layer) {
return { return {
'background-image': `url(${layer.source})`, backgroundImage: `url(${layer.source})`,
'transform': `scale(${this.zoomFactor}) translate(${this.imageTranslateX}px, ${this.imageTranslateY}px)`, transform: `scale(${this.zoomFactor}) translate(${this.imageTranslateX}px, ${this.imageTranslateY}px)`,
'transition': `${!this.pan && this.animateZoom ? 'transform 250ms ease-in' : 'initial'}` transition: `${!this.pan && this.animateZoom ? 'transform 250ms ease-in' : 'initial'}`
}; };
}, },
setTimeContext() { setTimeContext() {
@ -759,26 +763,26 @@ export default {
return mostRecent[valueKey]; return mostRecent[valueKey];
}, },
loadVisibleLayers() { loadVisibleLayers() {
const metaDataValues = this.metadata.valuesForHints(['image'])[0]; const layersMetadata = this.imageMetadataValue.layers;
this.imageFormat = this.openmct.telemetry.getValueFormatter(metaDataValues); if (!layersMetadata) {
let layersMetadata = metaDataValues.layers; return;
if (layersMetadata) { }
this.layers = layersMetadata;
if (this.domainObject.configuration) { this.layers = layersMetadata;
let persistedLayers = this.domainObject.configuration.layers; if (this.domainObject.configuration) {
layersMetadata.forEach((layer) => { const persistedLayers = this.domainObject.configuration.layers;
const persistedLayer = persistedLayers.find(object => object.name === layer.name); layersMetadata.forEach((layer) => {
if (persistedLayer) { const persistedLayer = persistedLayers.find(object => object.name === layer.name);
layer.visible = persistedLayer.visible === true; if (persistedLayer) {
} layer.visible = persistedLayer.visible === true;
}); }
this.visibleLayers = this.layers.filter(layer => layer.visible); });
} else { this.visibleLayers = this.layers.filter(layer => layer.visible);
this.visibleLayers = []; } else {
this.layers.forEach((layer) => { this.visibleLayers = [];
layer.visible = false; this.layers.forEach((layer) => {
}); layer.visible = false;
} });
} }
}, },
persistVisibleLayers() { persistVisibleLayers() {

View File

@ -29,7 +29,7 @@
flex-direction: column; flex-direction: column;
flex: 1 1 auto; flex: 1 1 auto;
&.unnsynced{ &.unsynced{
@include sUnsynced(); @include sUnsynced();
} }

View File

@ -21,6 +21,9 @@
*****************************************************************************/ *****************************************************************************/
const DEFAULT_DURATION_FORMATTER = 'duration'; const DEFAULT_DURATION_FORMATTER = 'duration';
const IMAGE_HINT_KEY = 'image';
const IMAGE_THUMBNAIL_HINT_KEY = 'thumbnail';
const IMAGE_DOWNLOAD_NAME_HINT_KEY = 'imageDownloadName';
export default { export default {
inject: ['openmct', 'domainObject', 'objectPath'], inject: ['openmct', 'domainObject', 'objectPath'],
@ -32,13 +35,20 @@ export default {
this.setDataTimeContext(); this.setDataTimeContext();
this.openmct.objectViews.on('clearData', this.dataCleared); this.openmct.objectViews.on('clearData', this.dataCleared);
// set // Get metadata and formatters
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier); this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject); this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
this.imageHints = { ...this.metadata.valuesForHints(['image'])[0] };
this.imageMetadataValue = { ...this.metadata.valuesForHints([IMAGE_HINT_KEY])[0] };
this.imageFormatter = this.getFormatter(this.imageMetadataValue.key);
this.imageThumbnailMetadataValue = { ...this.metadata.valuesForHints([IMAGE_THUMBNAIL_HINT_KEY])[0] };
this.imageThumbnailFormatter = this.imageThumbnailMetadataValue.key
? this.getFormatter(this.imageThumbnailMetadataValue.key)
: null;
this.durationFormatter = this.getFormatter(this.timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER); this.durationFormatter = this.getFormatter(this.timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
this.imageFormatter = this.openmct.telemetry.getValueFormatter(this.imageHints); this.imageDownloadNameMetadataValue = { ...this.metadata.valuesForHints([IMAGE_DOWNLOAD_NAME_HINT_KEY])[0]};
this.imageDownloadNameHints = { ...this.metadata.valuesForHints(['imageDownloadName'])[0]};
// initialize // initialize
this.timeKey = this.timeSystem.key; this.timeKey = this.timeSystem.key;
@ -105,12 +115,19 @@ export default {
return this.imageFormatter.format(datum); return this.imageFormatter.format(datum);
}, },
formatImageThumbnailUrl(datum) {
if (!datum || !this.imageThumbnailFormatter) {
return;
}
return this.imageThumbnailFormatter.format(datum);
},
formatTime(datum) { formatTime(datum) {
if (!datum) { if (!datum) {
return; return;
} }
let dateTimeStr = this.timeFormatter.format(datum); const dateTimeStr = this.timeFormatter.format(datum);
// Replace ISO "T" with a space to allow wrapping // Replace ISO "T" with a space to allow wrapping
return dateTimeStr.replace("T", " "); return dateTimeStr.replace("T", " ");
@ -118,7 +135,7 @@ export default {
getImageDownloadName(datum) { getImageDownloadName(datum) {
let imageDownloadName = ''; let imageDownloadName = '';
if (datum) { if (datum) {
const key = this.imageDownloadNameHints.key; const key = this.imageDownloadNameMetadataValue.key;
imageDownloadName = datum[key]; imageDownloadName = datum[key];
} }
@ -150,6 +167,7 @@ export default {
normalizeDatum(datum) { normalizeDatum(datum) {
const formattedTime = this.formatTime(datum); const formattedTime = this.formatTime(datum);
const url = this.formatImageUrl(datum); const url = this.formatImageUrl(datum);
const thumbnailUrl = this.formatImageThumbnailUrl(datum);
const time = this.parseTime(formattedTime); const time = this.parseTime(formattedTime);
const imageDownloadName = this.getImageDownloadName(datum); const imageDownloadName = this.getImageDownloadName(datum);
@ -157,13 +175,14 @@ export default {
...datum, ...datum,
formattedTime, formattedTime,
url, url,
thumbnailUrl,
time, time,
imageDownloadName imageDownloadName
}; };
}, },
getFormatter(key) { getFormatter(key) {
let metadataValue = this.metadata.value(key) || { format: key }; const metadataValue = this.metadata.value(key) || { format: key };
let valueFormatter = this.openmct.telemetry.getValueFormatter(metadataValue); const valueFormatter = this.openmct.telemetry.getValueFormatter(metadataValue);
return valueFormatter; return valueFormatter;
} }

View File

@ -35,6 +35,10 @@ const MAIN_IMAGE_CLASS = '.js-imageryView-image';
const NEW_IMAGE_CLASS = '.c-imagery__age.c-imagery--new'; const NEW_IMAGE_CLASS = '.c-imagery__age.c-imagery--new';
const REFRESH_CSS_MS = 500; const REFRESH_CSS_MS = 500;
function formatThumbnail(url) {
return url.replace('logo-openmct.svg', 'logo-nasa.svg');
}
function getImageInfo(doc) { function getImageInfo(doc) {
let imageElement = doc.querySelectorAll(MAIN_IMAGE_CLASS)[0]; let imageElement = doc.querySelectorAll(MAIN_IMAGE_CLASS)[0];
let timestamp = imageElement.dataset.openmctImageTimestamp; let timestamp = imageElement.dataset.openmctImageTimestamp;
@ -124,6 +128,16 @@ describe("The Imagery View Layouts", () => {
}, },
"source": "url" "source": "url"
}, },
{
"name": "Image Thumbnail",
"key": "thumbnail-url",
"format": "thumbnail",
"hints": {
"thumbnail": 1,
"priority": 3
},
"source": "url"
},
{ {
"name": "Name", "name": "Name",
"key": "name", "key": "name",
@ -200,6 +214,11 @@ describe("The Imagery View Layouts", () => {
originalRouterPath = openmct.router.path; originalRouterPath = openmct.router.path;
openmct.telemetry.addFormat({
key: 'thumbnail',
format: formatThumbnail
});
openmct.on('start', done); openmct.on('start', done);
openmct.startHeadless(); openmct.startHeadless();
}); });
@ -384,15 +403,32 @@ describe("The Imagery View Layouts", () => {
//Looks like we need Vue.nextTick here so that computed properties settle down //Looks like we need Vue.nextTick here so that computed properties settle down
await Vue.nextTick(); await Vue.nextTick();
const layerEls = parent.querySelectorAll('.js-layer-image'); const layerEls = parent.querySelectorAll('.js-layer-image');
console.log(layerEls);
expect(layerEls.length).toEqual(1); expect(layerEls.length).toEqual(1);
}); });
it("should use the image thumbnailUrl for thumbnails", async () => {
await Vue.nextTick();
const fullSizeImageUrl = imageTelemetry[5].url;
const thumbnailUrl = formatThumbnail(imageTelemetry[5].url);
// Ensure thumbnails are shown w/ thumbnail Urls
const thumbnails = parent.querySelectorAll(`img[src='${thumbnailUrl}']`);
expect(thumbnails.length).toBeGreaterThan(0);
// Click a thumbnail
parent.querySelectorAll(`img[src='${thumbnailUrl}']`)[0].click();
await Vue.nextTick();
// Ensure full size image is shown w/ full size url
const fullSizeImages = parent.querySelectorAll(`img[src='${fullSizeImageUrl}']`);
expect(fullSizeImages.length).toBeGreaterThan(0);
});
it("should show the clicked thumbnail as the main image", async () => { it("should show the clicked thumbnail as the main image", async () => {
//Looks like we need Vue.nextTick here so that computed properties settle down //Looks like we need Vue.nextTick here so that computed properties settle down
await Vue.nextTick(); await Vue.nextTick();
const target = imageTelemetry[5].url; const thumbnailUrl = formatThumbnail(imageTelemetry[5].url);
parent.querySelectorAll(`img[src='${target}']`)[0].click(); parent.querySelectorAll(`img[src='${thumbnailUrl}']`)[0].click();
await Vue.nextTick(); await Vue.nextTick();
const imageInfo = getImageInfo(parent); const imageInfo = getImageInfo(parent);
@ -417,7 +453,7 @@ describe("The Imagery View Layouts", () => {
it("should show that an image is not new", async () => { it("should show that an image is not new", async () => {
await Vue.nextTick(); await Vue.nextTick();
const target = imageTelemetry[4].url; const target = formatThumbnail(imageTelemetry[4].url);
parent.querySelectorAll(`img[src='${target}']`)[0].click(); parent.querySelectorAll(`img[src='${target}']`)[0].click();
await Vue.nextTick(); await Vue.nextTick();