mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-08-28 22:08:25 +00:00
## Summary Fixes the move-panel corner-cycle button silently no-op'ing after a panel is dragged on `/live`. Two coexisting positioning systems were mutating disjoint state: - `public/drag-manager.js` sets inline `top/left/right/bottom/transform/position`, stamps `data-dragged="true"`, and persists `localStorage['panel-drag-<id>']`. - `public/live.js` `applyPanelPosition()` only flips the `data-position` attribute (selecting a `.live-overlay[data-position="…"]` rule with `top/left/right/bottom`). Inline styles win the cascade, so after any drag the corner button updated the glyph but the panel never moved. The fix has `onCornerClick` clear drag state (attribute, inline coords, localStorage) before calling `applyPanelPosition`. ## Commits - Red: `ea2f8009` — `test(live): failing E2E for corner-cycle button after drag (#1567)` — Playwright test injects DragManager-shaped drag state on `#liveFeed`, clicks `.panel-corner-btn`, asserts `data-dragged`/inline styles/`localStorage` are cleared AND `getBoundingClientRect()` matches the CSS corner anchor (not the dragged coords). Fails on master at the post-click assertion. - Green: `abb5a21f` — `fix(live): corner-cycle button clears drag state (#1567)` — 11-line change in `onCornerClick`, plus new E2E wired into the workflow. ## Files - `public/live.js` — `onCornerClick` clears `data-dragged`, inline `top/left/right/bottom/transform/position`, and `localStorage['panel-drag-<id>']` before `applyPanelPosition`. - `test-issue-1567-corner-clears-drag-e2e.js` — new Playwright E2E (drag-state injection + post-click rect assertion). - `.github/workflows/deploy.yml` — runs the new E2E next to `test-drag-manager-e2e.js`. ## E2E E2E assertion added: `test-issue-1567-corner-clears-drag-e2e.js:108` (post-click drag-state + anchor-match assertions). Browser verified: red-on-master gated by assertion (`'data-dragged must be cleared after corner click'`) — green commit makes it pass. ## Scope - No changes to `drag-manager.js` (out of scope per triage fix path). - No config / API surface changes. - Desktop drag path only; mobile / coarse-pointer path unchanged (drag is gated off there at `live.js:1941`, so the button was always the only repositioning affordance on touch — preserved). Partial fix for #1567 — addresses the corner-button-no-op symptom called out in triage; leaves the issue open for the user to verify in the browser and close. --------- Co-authored-by: Kpa-clawbot <bot@openclaw.local> Co-authored-by: mc-bot <bot@meshcore.local>
This commit is contained in:
co-authored by
Kpa-clawbot
mc-bot
parent
5fa6568835
commit
2b45f7872c
@@ -406,6 +406,7 @@ jobs:
|
||||
BASE_URL=http://localhost:13581 node test-customize-display-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
BASE_URL=http://localhost:13581 node test-customize-export-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-drag-manager-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-issue-1567-corner-clears-drag-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-issue-1306-collisions-terminology-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-issue-1374-route-map-a11y-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
CHROMIUM_REQUIRE=1 BASE_URL=http://localhost:13581 node test-channels-list-render-e2e.js 2>&1 | tee -a e2e-output.txt
|
||||
|
||||
+34
-13
@@ -10,6 +10,29 @@
|
||||
var SNAP_THRESHOLD = 20; // px — snap to edge on release
|
||||
var SNAP_MARGIN = 12; // px — margin when snapped
|
||||
|
||||
// Shared drag-state cleaner (#1568 round-1 MAJOR 2).
|
||||
// Removes every side-effect _detachFromCorner/_finalizePosition/_persist
|
||||
// can leave on a panel element so subsequent corner CSS rules win the
|
||||
// cascade. Call sites: Escape revert, responsive gate, panel corner-
|
||||
// click, reset-to-defaults. Keep this list in sync with _detachFromCorner.
|
||||
// - removes `data-dragged` attribute
|
||||
// - removes `is-dragging` class (defensive: normally cleared on
|
||||
// pointerup, but cheap symmetry for races)
|
||||
// - clears inline top/left/right/bottom/transform/position/zIndex
|
||||
// (zIndex is bumped on every DRAGGING transition; must reset)
|
||||
// - removes `panel-drag-<id>` from localStorage when clearStorage !== false
|
||||
function clearPanel(el, panelId, opts) {
|
||||
if (!el) return;
|
||||
el.removeAttribute('data-dragged');
|
||||
el.classList.remove('is-dragging');
|
||||
['top', 'left', 'right', 'bottom', 'transform', 'position', 'zIndex'].forEach(function (p) {
|
||||
el.style[p] = '';
|
||||
});
|
||||
if (!opts || opts.clearStorage !== false) {
|
||||
try { localStorage.removeItem('panel-drag-' + panelId); } catch (_) { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
function DragManager() {
|
||||
this.state = 'IDLE';
|
||||
this.activePanel = null;
|
||||
@@ -89,24 +112,21 @@
|
||||
|
||||
DragManager.prototype._handleKeyDown = function (e) {
|
||||
if (e.key === 'Escape' && this.state === 'DRAGGING' && this.activePanel) {
|
||||
this.activePanel.classList.remove('is-dragging');
|
||||
this.activePanel.style.transform = this.preTransform;
|
||||
var panel = this.activePanel;
|
||||
panel.style.transform = this.preTransform;
|
||||
// Revert: re-attach to corner if it was cornered before
|
||||
var saved = localStorage.getItem('panel-drag-' + this.activePanel.id);
|
||||
var saved = localStorage.getItem('panel-drag-' + panel.id);
|
||||
if (!saved) {
|
||||
// Was in corner mode — restore corner CSS
|
||||
delete this.activePanel.dataset.dragged;
|
||||
this.activePanel.style.top = '';
|
||||
this.activePanel.style.left = '';
|
||||
this.activePanel.style.right = '';
|
||||
this.activePanel.style.bottom = '';
|
||||
this.activePanel.style.transform = '';
|
||||
// Was in corner mode — restore corner CSS via shared helper.
|
||||
// No storage key existed, so clearStorage is a no-op.
|
||||
DragManager.clearPanel(panel, panel.id);
|
||||
// Re-apply corner position from M0
|
||||
var corner = localStorage.getItem('panel-corner-' + this.activePanel.id);
|
||||
if (corner) this.activePanel.setAttribute('data-position', corner);
|
||||
var corner = localStorage.getItem('panel-corner-' + panel.id);
|
||||
if (corner) panel.setAttribute('data-position', corner);
|
||||
} else {
|
||||
// Was already dragged — revert to pre-drag position
|
||||
this.activePanel.style.transform = 'none';
|
||||
panel.classList.remove('is-dragging');
|
||||
panel.style.transform = 'none';
|
||||
}
|
||||
this._reset();
|
||||
}
|
||||
@@ -213,4 +233,5 @@
|
||||
|
||||
// Export
|
||||
window.DragManager = DragManager;
|
||||
DragManager.clearPanel = clearPanel;
|
||||
})();
|
||||
|
||||
+24
-7
@@ -215,6 +215,14 @@
|
||||
var nextIdx = (CORNER_CYCLE.indexOf(current) + 1) % 4;
|
||||
var next = nextAvailableCorner(panelId, CORNER_CYCLE[nextIdx], positions);
|
||||
try { localStorage.setItem('panel-corner-' + panelId, next); } catch (_) { /* quota */ }
|
||||
// #1567: corner button must clear any prior free-form drag state, or
|
||||
// the inline top/left from drag-manager.js wins the cascade over the
|
||||
// corner anchors and the panel silently no-ops on click.
|
||||
// #1568 round-1 MAJOR 2: shared cleaner — keeps Escape revert,
|
||||
// responsive gate, corner-click, and reset paths in sync.
|
||||
if (window.DragManager && DragManager.clearPanel) {
|
||||
DragManager.clearPanel(document.getElementById(panelId), panelId);
|
||||
}
|
||||
applyPanelPosition(panelId, next);
|
||||
// Announce for screen readers
|
||||
var announce = document.getElementById('panelPositionAnnounce');
|
||||
@@ -224,6 +232,11 @@
|
||||
function resetPanelPositions() {
|
||||
for (var id in PANEL_DEFAULTS) {
|
||||
try { localStorage.removeItem('panel-corner-' + id); } catch (_) { /* ignore */ }
|
||||
// #1568 round-1 MAJOR 1: clear drag state before applying defaults,
|
||||
// otherwise a dragged panel's inline coords win the cascade.
|
||||
if (window.DragManager && DragManager.clearPanel) {
|
||||
DragManager.clearPanel(document.getElementById(id), id);
|
||||
}
|
||||
applyPanelPosition(id, PANEL_DEFAULTS[id]);
|
||||
}
|
||||
}
|
||||
@@ -326,6 +339,12 @@
|
||||
function publish() {
|
||||
var h = Math.ceil(bar.getBoundingClientRect().height) || 58;
|
||||
page.style.setProperty('--vcr-bar-height', h + 'px');
|
||||
// #1568 round-2: also publish on :root so JS reading
|
||||
// getComputedStyle(document.documentElement).getPropertyValue(
|
||||
// '--vcr-bar-height') sees the measured value (E2E assertions,
|
||||
// future global consumers). CSS resolution unchanged — the
|
||||
// .live-page-scoped var still wins for live-overlay rules.
|
||||
try { document.documentElement.style.setProperty('--vcr-bar-height', h + 'px'); } catch (_) {}
|
||||
}
|
||||
publish();
|
||||
var ro = null;
|
||||
@@ -1941,14 +1960,12 @@
|
||||
var dragMql = window.matchMedia('(pointer: fine) and (min-width: 768px)');
|
||||
function onDragMediaChange(e) {
|
||||
if (!e.matches) {
|
||||
// Revert dragged panels to corner positions
|
||||
// Revert dragged panels to corner positions. Preserve the
|
||||
// localStorage drag key so widening the viewport restores
|
||||
// the dragged position via dragMgr.restorePositions().
|
||||
// #1568 round-1 MAJOR 2: shared cleaner with clearStorage:false.
|
||||
document.querySelectorAll('.live-overlay[data-dragged="true"]').forEach(function (p) {
|
||||
delete p.dataset.dragged;
|
||||
p.style.transform = '';
|
||||
p.style.top = '';
|
||||
p.style.left = '';
|
||||
p.style.right = '';
|
||||
p.style.bottom = '';
|
||||
DragManager.clearPanel(p, p.id, { clearStorage: false });
|
||||
});
|
||||
initPanelPositions();
|
||||
dragMgr.disable();
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* E2E for #1567 — Move-panel corner-cycle button silently no-ops after the
|
||||
* panel has been dragged.
|
||||
*
|
||||
* Root cause (see triage on #1567): two coexisting positioning systems
|
||||
* mutate disjoint state. `drag-manager.js` sets `data-dragged="true"` and
|
||||
* inline `position:fixed; top/left/right:auto; bottom:auto; transform:none`
|
||||
* and persists to `localStorage['panel-drag-<id>']`. `live.js` →
|
||||
* `applyPanelPosition()` only flips the `data-position` attribute (which
|
||||
* selects a `.live-overlay[data-position="…"]` CSS rule with `top/left/right/
|
||||
* bottom`). The inline styles win cascade-wise, so the panel does not move.
|
||||
*
|
||||
* Fix path under test: `onCornerClick` must clear drag state (attribute,
|
||||
* inline coords, localStorage) BEFORE calling `applyPanelPosition`.
|
||||
*
|
||||
* Assertions:
|
||||
* (a) After programmatic drag, the panel sits at the dragged coords
|
||||
* (sanity; if false the harness is broken).
|
||||
* (b) After clicking the panel-corner-btn, `data-dragged` is gone,
|
||||
* inline `top/left/right/bottom/transform/position` are cleared,
|
||||
* `localStorage['panel-drag-<id>']` is gone, and the panel's
|
||||
* bounding rect matches the CSS corner-anchor for the new
|
||||
* `data-position` value (NOT the dragged coords).
|
||||
*
|
||||
* Red-on-master: assertion (b) fails on master — panel stays at the
|
||||
* dragged coords after the click because inline styles are not cleared.
|
||||
*
|
||||
* Run: BASE_URL=http://localhost:13581 node test-issue-1567-corner-clears-drag-e2e.js
|
||||
*/
|
||||
'use strict';
|
||||
const { chromium } = require('playwright');
|
||||
|
||||
const BASE = process.env.BASE_URL || 'http://localhost:3000';
|
||||
|
||||
let passed = 0, failed = 0;
|
||||
async function step(name, fn) {
|
||||
try { await fn(); passed++; console.log(' \u2713 ' + name); }
|
||||
catch (e) { failed++; console.error(' \u2717 ' + name + ': ' + e.message); }
|
||||
}
|
||||
function assert(c, m) { if (!c) throw new Error(m || 'assertion failed'); }
|
||||
|
||||
(async () => {
|
||||
const browser = await chromium.launch({
|
||||
headless: true,
|
||||
executablePath: process.env.CHROMIUM_PATH || undefined,
|
||||
args: ['--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage'],
|
||||
});
|
||||
// Desktop viewport — drag is gated off on coarse pointer / narrow widths.
|
||||
const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
|
||||
const page = await ctx.newPage();
|
||||
page.setDefaultTimeout(10000);
|
||||
page.on('pageerror', (e) => console.error('[pageerror]', e.message));
|
||||
|
||||
console.log(`\n=== #1567 corner-button clears drag state E2E against ${BASE} ===`);
|
||||
|
||||
await step('navigate to /live with a clean slate', async () => {
|
||||
await page.goto(BASE + '/#/live', { waitUntil: 'domcontentloaded' });
|
||||
await page.evaluate(() => {
|
||||
['liveFeed', 'liveLegend', 'liveNodeDetail'].forEach((id) => {
|
||||
try { localStorage.removeItem('panel-drag-' + id); } catch (_) {}
|
||||
try { localStorage.removeItem('panel-corner-' + id); } catch (_) {}
|
||||
});
|
||||
});
|
||||
await page.reload({ waitUntil: 'load' });
|
||||
await page.waitForSelector('#liveFeed .panel-corner-btn', { timeout: 8000 });
|
||||
await page.waitForTimeout(200);
|
||||
});
|
||||
|
||||
// (a) Programmatically push #liveFeed into "dragged" state via the same
|
||||
// DOM shape DragManager produces. Using direct attribute/style writes
|
||||
// keeps the test deterministic across viewports / pointer types and
|
||||
// avoids racing the real drag handlers.
|
||||
await step('inject drag state on #liveFeed (mirrors DragManager output)', async () => {
|
||||
const got = await page.evaluate(() => {
|
||||
const el = document.getElementById('liveFeed');
|
||||
if (!el) return null;
|
||||
el.removeAttribute('data-position');
|
||||
el.dataset.dragged = 'true';
|
||||
el.style.position = 'fixed';
|
||||
el.style.top = '300px';
|
||||
el.style.left = '500px';
|
||||
el.style.right = 'auto';
|
||||
el.style.bottom = 'auto';
|
||||
el.style.transform = 'none';
|
||||
localStorage.setItem('panel-drag-liveFeed', JSON.stringify({
|
||||
xPct: 500 / window.innerWidth, yPct: 300 / window.innerHeight,
|
||||
}));
|
||||
const r = el.getBoundingClientRect();
|
||||
return { top: r.top, left: r.left, dragged: el.dataset.dragged };
|
||||
});
|
||||
assert(got, '#liveFeed missing');
|
||||
assert(got.dragged === 'true', 'data-dragged should be "true"');
|
||||
// Tolerate a few px (panel chrome/scrollbar). Bug repro requires the
|
||||
// panel to actually be at the dragged coords before the click.
|
||||
assert(Math.abs(got.top - 300) < 8, 'pre-click panel top ~300, got ' + got.top);
|
||||
assert(Math.abs(got.left - 500) < 8, 'pre-click panel left ~500, got ' + got.left);
|
||||
});
|
||||
|
||||
// (b) Click the corner button and assert drag state is FULLY cleared
|
||||
// and the panel actually sits at the CSS corner anchor for the new
|
||||
// data-position.
|
||||
await step('clicking .panel-corner-btn clears drag state and snaps to the corner anchor', async () => {
|
||||
await page.click('#liveFeed .panel-corner-btn');
|
||||
await page.waitForTimeout(150);
|
||||
|
||||
const after = await page.evaluate(() => {
|
||||
const el = document.getElementById('liveFeed');
|
||||
const pos = el.getAttribute('data-position');
|
||||
const rect = el.getBoundingClientRect();
|
||||
// Compute the CSS-rule anchor for this corner. Mirrors live.css
|
||||
// .live-overlay[data-position="…"] rules (see public/live.css ~1200).
|
||||
const VCR = parseInt(getComputedStyle(document.documentElement)
|
||||
.getPropertyValue('--vcr-bar-height')) || 58;
|
||||
const anchors = {
|
||||
tl: { top: 64, left: 12 },
|
||||
tr: { top: 64, right: 12 },
|
||||
bl: { bottom: VCR + 10, left: 12 },
|
||||
br: { bottom: VCR + 10, right: 12 },
|
||||
};
|
||||
return {
|
||||
dragged: el.dataset.dragged,
|
||||
inlineTop: el.style.top,
|
||||
inlineLeft: el.style.left,
|
||||
inlineRight: el.style.right,
|
||||
inlineBottom: el.style.bottom,
|
||||
inlineTransform: el.style.transform,
|
||||
inlinePosition: el.style.position,
|
||||
ls: localStorage.getItem('panel-drag-liveFeed'),
|
||||
pos: pos,
|
||||
rect: { top: rect.top, left: rect.left, right: rect.right, bottom: rect.bottom },
|
||||
vw: window.innerWidth, vh: window.innerHeight,
|
||||
anchor: anchors[pos],
|
||||
};
|
||||
});
|
||||
|
||||
assert(after.pos && /^(tl|tr|bl|br)$/.test(after.pos),
|
||||
'data-position must be a corner code, got: ' + after.pos);
|
||||
assert(!after.dragged,
|
||||
'data-dragged must be cleared after corner click, got: ' + after.dragged);
|
||||
assert(!after.ls,
|
||||
'localStorage panel-drag-liveFeed must be removed, got: ' + after.ls);
|
||||
['inlineTop', 'inlineLeft', 'inlineRight', 'inlineBottom', 'inlineTransform', 'inlinePosition'].forEach((k) => {
|
||||
assert(after[k] === '',
|
||||
'inline style ' + k + ' must be cleared after corner click, got: ' + JSON.stringify(after[k]));
|
||||
});
|
||||
|
||||
// Now the panel must actually be at the corner anchor — not at the
|
||||
// dragged coords. Tolerate a few px (border/scrollbar).
|
||||
var TOL = 12;
|
||||
if ('top' in after.anchor) {
|
||||
assert(Math.abs(after.rect.top - after.anchor.top) < TOL,
|
||||
'panel top must match CSS anchor (' + after.anchor.top + ') for ' + after.pos +
|
||||
', got rect.top=' + after.rect.top);
|
||||
}
|
||||
if ('left' in after.anchor) {
|
||||
assert(Math.abs(after.rect.left - after.anchor.left) < TOL,
|
||||
'panel left must match CSS anchor (' + after.anchor.left + ') for ' + after.pos +
|
||||
', got rect.left=' + after.rect.left);
|
||||
}
|
||||
if ('right' in after.anchor) {
|
||||
var rightGap = after.vw - after.rect.right;
|
||||
assert(Math.abs(rightGap - after.anchor.right) < TOL,
|
||||
'panel right-gap must match CSS anchor (' + after.anchor.right + ') for ' + after.pos +
|
||||
', got vw-rect.right=' + rightGap);
|
||||
}
|
||||
if ('bottom' in after.anchor) {
|
||||
var bottomGap = after.vh - after.rect.bottom;
|
||||
assert(Math.abs(bottomGap - after.anchor.bottom) < TOL,
|
||||
'panel bottom-gap must match CSS anchor (' + after.anchor.bottom + ') for ' + after.pos +
|
||||
', got vh-rect.bottom=' + bottomGap);
|
||||
}
|
||||
// Sanity: the panel must have actually moved away from the dragged coords.
|
||||
assert(Math.abs(after.rect.top - 300) > TOL || Math.abs(after.rect.left - 500) > TOL,
|
||||
'panel must move away from dragged coords (300,500); rect=' + JSON.stringify(after.rect));
|
||||
});
|
||||
|
||||
// (c) Same bug applies to `resetPanelPositions` — it calls
|
||||
// applyPanelPosition without clearing drag state, so a dragged panel
|
||||
// won't return to its default corner. Re-inject drag state, invoke
|
||||
// window._panelCorner.resetPanelPositions(), assert full reset.
|
||||
await step('resetPanelPositions clears drag state and snaps to default corner', async () => {
|
||||
const after = await page.evaluate(() => {
|
||||
const el = document.getElementById('liveFeed');
|
||||
// Re-inject drag state (mirrors DragManager output).
|
||||
el.removeAttribute('data-position');
|
||||
el.dataset.dragged = 'true';
|
||||
el.classList.add('is-dragging');
|
||||
el.style.position = 'fixed';
|
||||
el.style.top = '320px';
|
||||
el.style.left = '520px';
|
||||
el.style.right = 'auto';
|
||||
el.style.bottom = 'auto';
|
||||
el.style.transform = 'translate(5px,5px)';
|
||||
el.style.zIndex = '1500';
|
||||
localStorage.setItem('panel-drag-liveFeed', JSON.stringify({
|
||||
xPct: 520 / window.innerWidth, yPct: 320 / window.innerHeight,
|
||||
}));
|
||||
// Now reset.
|
||||
window._panelCorner.resetPanelPositions();
|
||||
const r = el.getBoundingClientRect();
|
||||
const VCR = parseInt(getComputedStyle(document.documentElement)
|
||||
.getPropertyValue('--vcr-bar-height')) || 58;
|
||||
// PANEL_DEFAULTS.liveFeed = 'bl' → anchor bottom: VCR+10, left: 12
|
||||
return {
|
||||
pos: el.getAttribute('data-position'),
|
||||
dragged: el.dataset.dragged,
|
||||
isDragging: el.classList.contains('is-dragging'),
|
||||
inlineTop: el.style.top, inlineLeft: el.style.left,
|
||||
inlineRight: el.style.right, inlineBottom: el.style.bottom,
|
||||
inlineTransform: el.style.transform, inlinePosition: el.style.position,
|
||||
inlineZIndex: el.style.zIndex,
|
||||
ls: localStorage.getItem('panel-drag-liveFeed'),
|
||||
rect: { top: r.top, left: r.left, right: r.right, bottom: r.bottom },
|
||||
vw: window.innerWidth, vh: window.innerHeight,
|
||||
anchor: { bottom: VCR + 10, left: 12 },
|
||||
};
|
||||
});
|
||||
|
||||
assert(after.pos === 'bl',
|
||||
'data-position must reset to default "bl" for liveFeed, got: ' + after.pos);
|
||||
assert(!after.dragged,
|
||||
'data-dragged must be cleared after reset, got: ' + after.dragged);
|
||||
assert(!after.isDragging,
|
||||
'is-dragging class must be cleared after reset');
|
||||
assert(!after.ls,
|
||||
'localStorage panel-drag-liveFeed must be removed after reset, got: ' + after.ls);
|
||||
assert(after.inlineZIndex === '',
|
||||
'inline zIndex must be cleared after reset, got: ' + JSON.stringify(after.inlineZIndex));
|
||||
['inlineTop', 'inlineLeft', 'inlineRight', 'inlineBottom', 'inlineTransform', 'inlinePosition'].forEach(function (k) {
|
||||
assert(after[k] === '',
|
||||
'inline style ' + k + ' must be cleared after reset, got: ' + JSON.stringify(after[k]));
|
||||
});
|
||||
var TOL = 12;
|
||||
var bottomGap = after.vh - after.rect.bottom;
|
||||
assert(Math.abs(bottomGap - after.anchor.bottom) < TOL,
|
||||
'panel bottom-gap must match default-corner anchor (' + after.anchor.bottom +
|
||||
'), got vh-rect.bottom=' + bottomGap);
|
||||
assert(Math.abs(after.rect.left - after.anchor.left) < TOL,
|
||||
'panel left must match default-corner anchor (' + after.anchor.left +
|
||||
'), got rect.left=' + after.rect.left);
|
||||
// Sanity: panel must have moved off the injected dragged coords.
|
||||
assert(Math.abs(after.rect.top - 320) > TOL || Math.abs(after.rect.left - 520) > TOL,
|
||||
'panel must move away from injected dragged coords (320,520); rect=' + JSON.stringify(after.rect));
|
||||
});
|
||||
|
||||
await ctx.close();
|
||||
await browser.close();
|
||||
console.log(`\n=== Results: ${passed} passed, ${failed} failed ===`);
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
})().catch(e => { console.error(e); process.exit(1); });
|
||||
Reference in New Issue
Block a user