{"record":{"id":"10abf21731f180f2","repo":"jackwener/OpenCLI","slug":"mercury-returned-malformed-review-click-result","errorCode":null,"errorMessage":"Mercury returned malformed Review click result","messagePattern":"Mercury returned malformed Review click result","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/mercury/reimbursement-draft.js","lineNumber":97,"sourceCode":"        const missing = expectedFields.filter((key) => !fields.touched[key]);\n        if (missing.length > 0) {\n            throw new CommandExecutionError(`Mercury reimbursement form fields were not all filled: ${missing.join(', ')}`);\n        }\n\n        const reviewClick = await page.evaluate(`(() => {\n            const norm = (s) => String(s || '').replace(/\\\\s+/g, ' ').trim().toLowerCase();\n            const candidates = Array.from(document.querySelectorAll('button, a, [role=\"button\"], [role=\"link\"]'))\n              .filter((node) => {\n                const style = window.getComputedStyle(node);\n                return style.visibility !== 'hidden' && style.display !== 'none' && node.offsetParent !== null;\n              });\n            const el = candidates.find((node) => norm(node.innerText || node.textContent || '') === 'review');\n            if (!el) return { clicked: false };\n            el.click();\n            return { clicked: true, text: el.innerText || el.textContent || '' };\n        })()`);\n        if (!reviewClick || typeof reviewClick !== 'object' || typeof reviewClick.clicked !== 'boolean') {\n            throw new CommandExecutionError('Mercury returned malformed Review click result');\n        }\n        if (!reviewClick.clicked) {\n            throw new CommandExecutionError('Mercury Review button was not clicked; inspect the page for validation errors');\n        }\n        await page.wait({ time: 2 });\n        const review = await reviewSnapshot(page);\n        if (!review.hasReview || !review.hasSubmitExpenseButton) {\n            throw new CommandExecutionError('Mercury did not reach the Review step with the final Submit expense button visible');\n        }\n\n        if (input.closeAfterReview) {\n            await page.evaluate(`(() => {\n                const norm = (s) => String(s || '').replace(/\\\\s+/g, ' ').trim().toLowerCase();\n                const el = Array.from(document.querySelectorAll('button, a, [role=\"button\"], [role=\"link\"]'))\n                  .find((node) => norm(node.innerText || node.textContent || '') === 'close');\n                el?.click();\n                return { clicked: Boolean(el) };\n            })()`);","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/mercury/reimbursement-draft.js#L79-L115","documentation":"This CLI drives the Mercury web UI via browser automation. After executing an in-page script that finds and clicks the 'Review' button, it validates the returned result object before proceeding. If the result is not an object with a boolean `clicked` field (e.g. the evaluate returned null/undefined because the script threw or the page context changed), this error is thrown because the automation cannot tell whether the click happened.","triggerScenarios":"The page.evaluate snippet returning the click result yields null, undefined, a non-object, or an object without a boolean `clicked` property — e.g. the script was interrupted by a navigation, the page context was destroyed, or the browser driver returned an unexpected serialization of the result.","commonSituations":"Slow Mercury SPA mid-render when the evaluate runs, page navigation triggered right as the script executes, browser session/driver issues returning undefined from evaluate, or a Mercury DOM change breaking the script so it never returns a value.","solutions":["Re-run the command; transient page-load races often resolve on a retry with the page fully loaded.","Increase the wait before the click step so the Mercury SPA is fully rendered before evaluating the script.","Verify the browser/driver session is healthy and the page has not navigated away from the expense form.","If persistent, inspect whether Mercury's DOM changed such that the in-page script throws (check the browser console); update the selector/script in reimbursement-draft.js."],"exampleFix":"// before\nconst reviewClick = await page.evaluate(`...`);\nif (!reviewClick || typeof reviewClick !== 'object' || typeof reviewClick.clicked !== 'boolean') {\n    throw new CommandExecutionError('Mercury returned malformed Review click result');\n}\n// after\nawait page.wait({ time: 2 }); // ensure SPA is settled before clicking\nconst reviewClick = await page.evaluate(`...`);\nif (!reviewClick || typeof reviewClick !== 'object' || typeof reviewClick.clicked !== 'boolean') {\n    throw new CommandExecutionError('Mercury returned malformed Review click result');\n}","handlingStrategy":"type-guard","validationCode":"const r = await page.evaluate(`...`);\nconst isClickResult = (v) => v !== null && typeof v === 'object' && typeof v.clicked === 'boolean';","typeGuard":"function isClickResult(v) { return v !== null && typeof v === 'object' && typeof v.clicked === 'boolean'; }","tryCatchPattern":"try {\n    const reviewClick = await page.evaluate(`...`);\n    if (!isClickResult(reviewClick)) throw new CommandExecutionError('Mercury returned malformed Review click result');\n} catch (err) {\n    if (err instanceof CommandExecutionError) throw err;\n    await page.wait({ time: 2 }); // retry once after settle, then rethrow\n    throw err;\n}","preventionTips":["Wait for the SPA to settle before running in-page click scripts.","Retry evaluate-based steps once on transient failures.","Assert the page URL/state before executing the click script.","Keep the in-page script defensive so it always returns an object, even on DOM changes."],"tags":["browser-automation","dom-scripting","validation"],"backgroundTag":"malformed-automation-result","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}