From 07f322b652a94c0d11a055e5c2a276e4514f2ebc Mon Sep 17 00:00:00 2001 From: LiZhenhai-MBP14 <5935568+jackhai9@users.noreply.github.com> Date: Fri, 28 Aug 2026 12:18:14 +0800 Subject: [PATCH] fix: hide chart order setup UI promptly --- .../fixtures/binance-futures.js | 2 + .../scenarios/cancel-current-symbol.js | 6 +++ .../specs/cancel-current-symbol.pw.js | 43 +++++++++++++++++++ scripts/binance-orderbook-trade.user.js | 20 +++++++-- src/binance-orderbook-trade/index.user.js | 25 +++++++++-- 5 files changed, 90 insertions(+), 6 deletions(-) diff --git a/e2e/binance-orderbook/fixtures/binance-futures.js b/e2e/binance-orderbook/fixtures/binance-futures.js index 43ecd8d..a4c2fad 100644 --- a/e2e/binance-orderbook/fixtures/binance-futures.js +++ b/e2e/binance-orderbook/fixtures/binance-futures.js @@ -400,6 +400,8 @@ export function renderBinanceFuturesFixture(scenario) { function closeChartOrdersPopover() { if (!chartOrdersPopover.classList.contains('active')) return; + record('chart-orders-popover-close-requested'); + if (scenario.host.chartOrdersPopoverCloseMode === 'stuck') return; chartOrdersPopover.classList.remove('active'); record('chart-orders-popover-closed'); } diff --git a/e2e/binance-orderbook/scenarios/cancel-current-symbol.js b/e2e/binance-orderbook/scenarios/cancel-current-symbol.js index 631dc3e..75da223 100644 --- a/e2e/binance-orderbook/scenarios/cancel-current-symbol.js +++ b/e2e/binance-orderbook/scenarios/cancel-current-symbol.js @@ -55,6 +55,7 @@ export function createCancelScenario(overrides = {}) { dialogMode: 'normal', dialogReplacementDelayMs: null, clearMode: 'currentSymbol', + chartOrdersPopoverCloseMode: 'normal', precisionOptions: ['0.001', '0.01', '0.1', '1'], ...overrides.host, }, @@ -84,6 +85,11 @@ export function createCancelScenario(overrides = {}) { if (!['currentSymbol', 'none'].includes(scenario.host.clearMode)) { throw new Error(`Unsupported clear mode: ${scenario.host.clearMode}`); } + if (!['normal', 'stuck'].includes(scenario.host.chartOrdersPopoverCloseMode)) { + throw new Error( + `Unsupported chart-orders popover close mode: ${scenario.host.chartOrdersPopoverCloseMode}`, + ); + } if ( scenario.host.dialogReplacementDelayMs !== null && (!Number.isInteger(scenario.host.dialogReplacementDelayMs) diff --git a/e2e/binance-orderbook/specs/cancel-current-symbol.pw.js b/e2e/binance-orderbook/specs/cancel-current-symbol.pw.js index 3fc292e..3fa1172 100644 --- a/e2e/binance-orderbook/specs/cancel-current-symbol.pw.js +++ b/e2e/binance-orderbook/specs/cancel-current-symbol.pw.js @@ -138,6 +138,25 @@ test('a 70-order drawing burst split across tasks performs one full save per tog .filter((event) => event.type === 'chart-orders-checked') .map((event) => event.value), ).toEqual([false, true]); + for (const checked of [false, true]) { + const checkedIndex = state.events.findIndex( + (event) => event.type === 'chart-orders-checked' && event.value === checked, + ); + const popoverClosedIndex = state.events.findIndex( + (event, index) => index > checkedIndex && event.type === 'chart-orders-popover-closed', + ); + const finalSaveRequestIndex = state.events.findLastIndex( + (event) => event.type === 'chart-save-requested' && event.checked === checked, + ); + const fullSaveIndex = state.events.findIndex( + (event, index) => index > finalSaveRequestIndex + && event.type === 'chart-saved' + && event.snapshot.checked === checked, + ); + expect(popoverClosedIndex).toBeGreaterThan(checkedIndex); + expect(popoverClosedIndex).toBeLessThan(finalSaveRequestIndex); + expect(popoverClosedIndex).toBeLessThan(fullSaveIndex); + } await expectRestoredState(page, scenario); const probe = await finishInteractionProbe(page); assertResponsiveInteraction(expect, probe); @@ -145,6 +164,30 @@ test('a 70-order drawing burst split across tasks performs one full save per tog expect(errors).toEqual([]); }); +test('a popover close failure does not discard coalesced chart saves', async ({ page }) => { + const scenario = createCancelScenario({ + positions: POSITION_SETS.current, + orders: ORDER_SETS.current, + ui: { hideOtherSymbols: false, accountTab: 'positions', showOrders: true }, + host: { chartOrdersPopoverCloseMode: 'stuck' }, + }); + const { errors } = await openUserscriptScenario(page, scenario); + + await page.getByRole('button', { name: '撤单' }).click(); + await expect(page.getByText('未能恢复图表当前委托显示')).toBeVisible({ timeout: 6_000 }); + + const state = await readFixtureState(page); + expect(state.dialogOpen).toBe(false); + expect(state.orders).toEqual(ORDER_SETS.current); + expect(state.showOrders).toBe(true); + expect(state.events.filter((event) => event.type === 'chart-save-requested')).toHaveLength(2); + expect(state.events.filter((event) => event.type === 'chart-saved')).toHaveLength(2); + expect( + state.events.filter((event) => event.type === 'chart-orders-popover-close-requested'), + ).toHaveLength(2); + expect(errors).toEqual([]); +}); + test('confirming with mixed-symbol orders clears only the current symbol', async ({ page }) => { const scenario = createCancelScenario({ positions: POSITION_SETS.both, diff --git a/scripts/binance-orderbook-trade.user.js b/scripts/binance-orderbook-trade.user.js index 55ded5b..70ac178 100644 --- a/scripts/binance-orderbook-trade.user.js +++ b/scripts/binance-orderbook-trade.user.js @@ -3,7 +3,7 @@ // @namespace binance.orderbook.trade // @icon data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2064%2064%22%3E%3Crect%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2214%22%20fill%3D%22%23f0b90b%22%2F%3E%3Ctext%20x%3D%2232%22%20y%3D%2249%22%20text-anchor%3D%22middle%22%20font-family%3D%22Arial%2C%20sans-serif%22%20font-size%3D%2242%22%20font-weight%3D%22800%22%20fill%3D%22%23111827%22%3EJ%3C%2Ftext%3E%3C%2Fsvg%3E // @icon64 data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2064%2064%22%3E%3Crect%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2214%22%20fill%3D%22%23f0b90b%22%2F%3E%3Ctext%20x%3D%2232%22%20y%3D%2249%22%20text-anchor%3D%22middle%22%20font-family%3D%22Arial%2C%20sans-serif%22%20font-size%3D%2242%22%20font-weight%3D%22800%22%20fill%3D%22%23111827%22%3EJ%3C%2Ftext%3E%3C%2Fsvg%3E -// @version 2.7.146 +// @version 2.7.147 // @author jackhai9 // @description 单击订单簿价格,按当前开仓/平仓 tab 自动填数量并执行下单,内置数量倍率面板 // @match https://www.binance.com/*/futures/* @@ -5268,14 +5268,26 @@ if (typeof expectDrawingEvents !== "boolean") { throw new Error("Chart orders drawing-event expectation is invalid"); } - const result = await coalesceTradingViewDrawingSaves( + let popoverCloseOutcomePromise = null; + const coalescingOutcome = await coalesceTradingViewDrawingSaves( target.tradingViewApi, async () => { checkbox.click(); await waitForBinanceChartOrdersPopover(target, expectedChecked); + popoverCloseOutcomePromise = closeBinanceChartOrdersPopover(target).then( + () => null, + (error) => error + ); }, expectDrawingEvents ? {} : { eventDiscoveryTimeoutMs: 0 } + ).then( + (result2) => ({ result: result2, error: null }), + (error) => ({ result: null, error }) ); + const popoverCloseError = popoverCloseOutcomePromise ? await popoverCloseOutcomePromise : null; + if (coalescingOutcome.error) throw coalescingOutcome.error; + if (popoverCloseError) throw popoverCloseError; + const { result } = coalescingOutcome; log("图表当前委托保存已合并", { drawingEvents: result.drawingEventCount, saveRequests: result.saveRequestCount, @@ -5294,6 +5306,7 @@ false, true ); + return; } await closeBinanceChartOrdersPopover(target); } @@ -5310,8 +5323,9 @@ state.originalChecked, expectDrawingEvents ); + } else { + await closeBinanceChartOrdersPopover(target); } - await closeBinanceChartOrdersPopover(target); clearChartOrdersRecoveryRecord(); } async function recoverChartOrdersStateAfterReload() { diff --git a/src/binance-orderbook-trade/index.user.js b/src/binance-orderbook-trade/index.user.js index c1a50e8..51fbc1e 100644 --- a/src/binance-orderbook-trade/index.user.js +++ b/src/binance-orderbook-trade/index.user.js @@ -3,7 +3,7 @@ // @namespace binance.orderbook.trade // @icon data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2064%2064%22%3E%3Crect%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2214%22%20fill%3D%22%23f0b90b%22%2F%3E%3Ctext%20x%3D%2232%22%20y%3D%2249%22%20text-anchor%3D%22middle%22%20font-family%3D%22Arial%2C%20sans-serif%22%20font-size%3D%2242%22%20font-weight%3D%22800%22%20fill%3D%22%23111827%22%3EJ%3C%2Ftext%3E%3C%2Fsvg%3E // @icon64 data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2064%2064%22%3E%3Crect%20width%3D%2264%22%20height%3D%2264%22%20rx%3D%2214%22%20fill%3D%22%23f0b90b%22%2F%3E%3Ctext%20x%3D%2232%22%20y%3D%2249%22%20text-anchor%3D%22middle%22%20font-family%3D%22Arial%2C%20sans-serif%22%20font-size%3D%2242%22%20font-weight%3D%22800%22%20fill%3D%22%23111827%22%3EJ%3C%2Ftext%3E%3C%2Fsvg%3E -// @version 2.7.146 +// @version 2.7.147 // @author jackhai9 // @description 单击订单簿价格,按当前开仓/平仓 tab 自动填数量并执行下单,内置数量倍率面板 // @match https://www.binance.com/*/futures/* @@ -3765,14 +3765,31 @@ import { if (typeof expectDrawingEvents !== 'boolean') { throw new Error('Chart orders drawing-event expectation is invalid'); } - const result = await coalesceTradingViewDrawingSaves( + let popoverCloseOutcomePromise = null; + const coalescingOutcome = await coalesceTradingViewDrawingSaves( target.tradingViewApi, async () => { checkbox.click(); await waitForBinanceChartOrdersPopover(target, expectedChecked); + // Start hiding native setup UI immediately, but keep its failure outside + // the action so the coalescer can still replay the final chart snapshot. + popoverCloseOutcomePromise = closeBinanceChartOrdersPopover(target).then( + () => null, + (error) => error, + ); }, expectDrawingEvents ? {} : { eventDiscoveryTimeoutMs: 0 }, + ).then( + (result) => ({ result, error: null }), + (error) => ({ result: null, error }), ); + const popoverCloseError = popoverCloseOutcomePromise + ? await popoverCloseOutcomePromise + : null; + if (coalescingOutcome.error) throw coalescingOutcome.error; + if (popoverCloseError) throw popoverCloseError; + + const { result } = coalescingOutcome; log('图表当前委托保存已合并', { drawingEvents: result.drawingEventCount, saveRequests: result.saveRequestCount, @@ -3792,6 +3809,7 @@ import { false, true, ); + return; } await closeBinanceChartOrdersPopover(target); } @@ -3813,8 +3831,9 @@ import { state.originalChecked, expectDrawingEvents, ); + } else { + await closeBinanceChartOrdersPopover(target); } - await closeBinanceChartOrdersPopover(target); clearChartOrdersRecoveryRecord(); }