diff --git a/src/editor/FilePicker.ts b/src/editor/FilePicker.ts index 80b0d173..3e776a15 100644 --- a/src/editor/FilePicker.ts +++ b/src/editor/FilePicker.ts @@ -272,6 +272,11 @@ export abstract class FilePicker extends Popup { }; } + /** The scrolled part of the dialog – what tells an entry in view from one past its edge (test hook). */ + get listView(): ScrollContainer { + return this.scroll; + } + override close(): void { super.close(); if (current === this) current = null; diff --git a/src/editor/debug/uiHooks.ts b/src/editor/debug/uiHooks.ts index c9c2b126..84babe86 100644 --- a/src/editor/debug/uiHooks.ts +++ b/src/editor/debug/uiHooks.ts @@ -283,6 +283,10 @@ export function uiHooks({ app, state, editor }: HookContext) { /** The open image picker: what it offers, what is picked, and where a tile sits. */ imagePicker: () => currentImagePicker()?.debugInfo() ?? null, imagePickerTile: (file: string) => currentImagePicker()?.tileGlobal(file) ?? null, + imagePickerRect: () => { + const picker = currentImagePicker(); + return picker ? rectOf(picker.listView) : null; + }, /** The same for the font picker, whose rows are the preview. */ fontPicker: () => currentFontPicker()?.debugInfo() ?? null, fontPickerRow: (file: string) => currentFontPicker()?.rowGlobal(file) ?? null, diff --git a/tools/e2e/12-textures.mjs b/tools/e2e/12-textures.mjs index d0fdb1e6..cb06c67a 100644 --- a/tools/e2e/12-textures.mjs +++ b/tools/e2e/12-textures.mjs @@ -1,4 +1,5 @@ import { colourDistance } from '../lib/harness.mjs'; +import { inView } from './lib/scaffold.mjs'; /** * Uploading a picture and wearing it. Runs last because it adds an asset and repaints the @@ -363,7 +364,11 @@ export async function textures(t) { ); check('building the tiles draws no complaint from Pixi', tileComplaints.length === 0, tileComplaints); - const tile = await json(`__gm.imagePickerTile(${JSON.stringify(spare)})`); + // Scrolled into view first: the server holds every picture ever uploaded, so on a long-lived + // one the spare's tile sits below the dialog's fold, where a click lands on nothing. + const tileOf = (file) => + inView(t, '__gm.imagePickerRect()', `__gm.imagePickerTile(${JSON.stringify(file)})`); + const tile = await tileOf(spare); await click(tile.x, tile.y); check( 'clicking a tile picks that image', @@ -424,7 +429,7 @@ export async function textures(t) { (reopened?.used ?? []).includes(spare), JSON.stringify(reopened?.used), ); - const sameTile = await json(`__gm.imagePickerTile(${JSON.stringify(spare)})`); + const sameTile = await tileOf(spare); await doubleClick(sameTile.x, sameTile.y); await sleep(600); const afterSecondPick = await json(