feat(PageController): make sure page is indexed before calling actions on elements

This commit is contained in:
Simon
2026-01-21 18:54:17 +08:00
parent 23ec4602c2
commit 34ce56b446

View File

@@ -80,6 +80,9 @@ export class PageController extends EventTarget {
/** last time the tree was updated */ /** last time the tree was updated */
private lastTimeUpdate = 0 private lastTimeUpdate = 0
/** Whether the tree has been indexed at least once */
private isIndexed = false
/** Visual mask overlay for blocking user interaction during automation */ /** Visual mask overlay for blocking user interaction during automation */
private mask: InstanceType<typeof import('./mask/SimulatorMask').SimulatorMask> | null = null private mask: InstanceType<typeof import('./mask/SimulatorMask').SimulatorMask> | null = null
private maskReady: Promise<void> | null = null private maskReady: Promise<void> | null = null
@@ -196,6 +199,9 @@ export class PageController extends EventTarget {
this.elementTextMap.clear() this.elementTextMap.clear()
this.elementTextMap = dom.getElementTextMap(this.simplifiedHTML) this.elementTextMap = dom.getElementTextMap(this.simplifiedHTML)
// Mark as indexed - now element actions are allowed
this.isIndexed = true
// Restore mask blocking // Restore mask blocking
if (this.mask) { if (this.mask) {
this.mask.wrapper.style.pointerEvents = 'auto' this.mask.wrapper.style.pointerEvents = 'auto'
@@ -215,11 +221,22 @@ export class PageController extends EventTarget {
// ======= Element Actions ======= // ======= Element Actions =======
/**
* Ensure the tree has been indexed before any index-based operation.
* Throws if updateTree() hasn't been called yet.
*/
private assertIndexed(): void {
if (!this.isIndexed) {
throw new Error('DOM tree not indexed. Can not perform actions on elements.')
}
}
/** /**
* Click element by index * Click element by index
*/ */
async clickElement(index: number): Promise<ActionResult> { async clickElement(index: number): Promise<ActionResult> {
try { try {
this.assertIndexed()
const element = getElementByIndex(this.selectorMap, index) const element = getElementByIndex(this.selectorMap, index)
const elemText = this.elementTextMap.get(index) const elemText = this.elementTextMap.get(index)
await clickElement(element) await clickElement(element)
@@ -249,6 +266,7 @@ export class PageController extends EventTarget {
*/ */
async inputText(index: number, text: string): Promise<ActionResult> { async inputText(index: number, text: string): Promise<ActionResult> {
try { try {
this.assertIndexed()
const element = getElementByIndex(this.selectorMap, index) const element = getElementByIndex(this.selectorMap, index)
const elemText = this.elementTextMap.get(index) const elemText = this.elementTextMap.get(index)
await inputTextElement(element, text) await inputTextElement(element, text)
@@ -270,6 +288,7 @@ export class PageController extends EventTarget {
*/ */
async selectOption(index: number, optionText: string): Promise<ActionResult> { async selectOption(index: number, optionText: string): Promise<ActionResult> {
try { try {
this.assertIndexed()
const element = getElementByIndex(this.selectorMap, index) const element = getElementByIndex(this.selectorMap, index)
const elemText = this.elementTextMap.get(index) const elemText = this.elementTextMap.get(index)
await selectOptionElement(element as HTMLSelectElement, optionText) await selectOptionElement(element as HTMLSelectElement, optionText)
@@ -298,6 +317,8 @@ export class PageController extends EventTarget {
try { try {
const { down, numPages, pixels, index } = options const { down, numPages, pixels, index } = options
this.assertIndexed()
const scrollAmount = pixels ?? numPages * (down ? 1 : -1) * window.innerHeight const scrollAmount = pixels ?? numPages * (down ? 1 : -1) * window.innerHeight
const element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null const element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null
@@ -327,6 +348,8 @@ export class PageController extends EventTarget {
try { try {
const { right, pixels, index } = options const { right, pixels, index } = options
this.assertIndexed()
const scrollAmount = pixels * (right ? 1 : -1) const scrollAmount = pixels * (right ? 1 : -1)
const element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null const element = index !== undefined ? getElementByIndex(this.selectorMap, index) : null
@@ -394,6 +417,7 @@ export class PageController extends EventTarget {
this.selectorMap.clear() this.selectorMap.clear()
this.elementTextMap.clear() this.elementTextMap.clear()
this.simplifiedHTML = '<EMPTY>' this.simplifiedHTML = '<EMPTY>'
this.isIndexed = false
this.mask?.dispose() this.mask?.dispose()
this.mask = null this.mask = null
} }