{"record":{"id":"208a7b5941434b5a","repo":"jackwener/OpenCLI","slug":"wechat-save-draft-button-was-not-found","errorCode":null,"errorMessage":"WeChat save-draft button was not found.","messagePattern":"WeChat save-draft button was not found\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/weixin/create-draft.js","lineNumber":263,"sourceCode":"            return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n        }).map(function(el) {\n            return (el.innerText || el.textContent || '').replace(/\\\\s+/g, ' ').trim();\n        }).find(function(value) { return /已保存|保存成功/.test(value); }) || '';\n        return { visible: !!text, text: text };\n    })()`);\n}\n\nasync function saveDraft(page) {\n    const before = await readSaveState(page);\n    const result = await evaluate(page, `(() => {\n        var button = Array.from(document.querySelectorAll('span, button, a')).find(function(el) {\n            return (el.textContent || '').trim() === '保存为草稿' && !el.disabled;\n        });\n        if (!button) return { ok: false };\n        button.click();\n        return { ok: true };\n    })()`);\n    if (!result?.ok) throw new CommandExecutionError('WeChat save-draft button was not found.');\n\n    for (let attempt = 0; attempt < 8; attempt++) {\n        await page.wait(1);\n        const state = await readSaveState(page);\n        if (state?.visible && (!before?.visible || state.text !== before.text)) return;\n    }\n    throw new CommandExecutionError('WeChat draft save was not confirmed by a fresh success status.');\n}\n\nexport const createDraftCommand = cli({\n    site: 'weixin',\n    name: 'create-draft',\n    access: 'write',\n    description: '创建微信公众号图文草稿',\n    domain: WEIXIN_DOMAIN,\n    strategy: Strategy.COOKIE,\n    browser: true,\n    navigateBefore: false,","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/weixin/create-draft.js#L245-L281","documentation":"Thrown by saveDraft when the in-page script cannot find an enabled button whose text is exactly 保存为草稿 (Save as draft). Without that button the library cannot trigger the draft save, so it throws before polling for confirmation.","triggerScenarios":"The article editor page is not fully loaded or the session expired so the toolbar/footer actions are missing, WeChat renamed or relabeled the save button, the button is disabled (e.g. empty title/content), the button exists but has extra whitespace or nested elements so textContent !== '保存为草稿', or a modal blocks rendering.","commonSituations":"WeChat UI updates changing the button label or structure; running against an unloaded/interstitial page; the editor disabled the save button because required fields are missing; rendering differences in headless mode.","solutions":["Confirm the editor loaded fully (title textarea present) and the article has valid title/content so the save button is enabled.","Open the live editor and inspect the save button's exact text/structure; update the matching logic if WeChat changed it (e.g. trim, includes, or query by class).","Re-login and retry if the page was a session-expiry interstitial rather than the editor.","Add a wait/poll for the button before the single click attempt to allow late rendering."],"exampleFix":"// before\nif (!result?.ok) throw new CommandExecutionError('WeChat save-draft button was not found.');\n// after (in-page matching)\nvar els = Array.from(document.querySelectorAll('button, a, span'));\nvar button = els.find(function(el) {\n    return (el.textContent || '').trim().includes('保存为草稿') && !el.disabled;\n});\nif (!button) return { ok: false };\nbutton.scrollIntoView();\nbutton.click();","handlingStrategy":"validation","validationCode":"await page.wait(4);\nconst canSave = await evaluate(page, 'Array.from(document.querySelectorAll(\"button, a, span\")).some(el => (el.textContent || \"\").trim() === \"保存为草稿\" && !el.disabled)');\nif (canSave !== true) throw new Error('save-draft button unavailable — check editor loaded and article has title/content');","typeGuard":"function isSaveClickResult(v) { return typeof v === 'object' && v !== null && typeof v.ok === 'boolean'; }","tryCatchPattern":"try {\n    await createDraftCommand(opts);\n} catch (e) {\n    if (/save-draft button was not found/i.test(e.message)) {\n        console.error('save button unavailable — verify session and editor state, then retry');\n    }\n    throw e;\n}","preventionTips":["Ensure title and content are non-empty so the save button is enabled.","Verify the editor fully loaded before the save step.","Re-check the 保存为草稿 label and button structure after WeChat UI updates.","Poll for the button instead of a single immediate lookup."],"tags":["wechat","dom-parsing","editor-ui","scraping"],"backgroundTag":"selector-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}