From e0ae997501c56bea76bfe7c62439023ffdbfa3be Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 9 Jun 2021 00:33:04 -0400 Subject: [PATCH] tests: Don't auto-scroll Mocha results if user scrolls up --- src/tests/frontend/runner.css | 4 ++-- src/tests/frontend/runner.js | 45 +++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/tests/frontend/runner.css b/src/tests/frontend/runner.css index 04a15016..aac044c1 100644 --- a/src/tests/frontend/runner.css +++ b/src/tests/frontend/runner.css @@ -57,7 +57,7 @@ body { } #mocha h1 { - margin-top: 15px; + padding-top: 15px; /* margin-top breaks autoscrolling */ font-size: 1em; font-weight: 200; } @@ -68,7 +68,7 @@ body { } #mocha .suite .suite h1 { - margin-top: 0; + padding-top: 0; font-size: .8em; } diff --git a/src/tests/frontend/runner.js b/src/tests/frontend/runner.js index 620f5069..e3394269 100644 --- a/src/tests/frontend/runner.js +++ b/src/tests/frontend/runner.js @@ -29,13 +29,49 @@ $(() => (async () => { if (!runner) return; + // AUTO-SCROLLING: + + // Mocha can start multiple suites before the first 'suite' event is emitted. This can break the + // logic used to determine if the div is already scrolled to the bottom. If this is false, + // auto-scrolling unconditionally scrolls to the bottom no matter how far up the div is + // currently scrolled. If true, auto-scrolling only happens if the div is scrolled close to the + // bottom. + let manuallyScrolled = false; + // The 'scroll' event is fired for manual scrolling as well as JavaScript-initiated scrolling. + // This is incremented while auto-scrolling and decremented when done auto-scrolling. This is + // used to ensure that auto-scrolling never sets manuallyScrolled to true. + let autoScrolling = 0; + + // Auto-scroll the #mocha-report div to show the newly added test entry if it was previously + // scrolled to the bottom. + const autoscroll = (newElement) => { + const mr = $('#mocha-report')[0]; + const scroll = !manuallyScrolled || (() => { + const offsetTopAbs = newElement.getBoundingClientRect().top; + const mrOffsetTopAbs = mr.getBoundingClientRect().top - mr.scrollTop; + const offsetTop = offsetTopAbs - mrOffsetTopAbs; + // Add some margin to cover rounding error and to make it easier to engage the auto-scroll. + return offsetTop <= mr.clientHeight + mr.scrollTop + 5; + })(); + if (!scroll) return; + ++autoScrolling; + mr.scrollTop = mr.scrollHeight; + manuallyScrolled = false; + }; + + $('#mocha-report').on('scroll', () => { + if (!autoScrolling) manuallyScrolled = true; + else --autoScrolling; + }); + runner.on('start', () => { stats.start = new Date(); }); runner.on('suite', (suite) => { - suite.root || stats.suites++; if (suite.root) return; + autoscroll($('#mocha-report .suite').last()[0]); + stats.suites++; append(suite.title); level++; }); @@ -49,16 +85,11 @@ $(() => (async () => { } }); - // Scroll down test display after each test - const mochaEl = $('#mocha-report')[0]; - runner.on('test', () => { - mochaEl.scrollTop = mochaEl.scrollHeight; - }); - // max time a test is allowed to run // TODO this should be lowered once timeslider_revision.js is faster let killTimeout; runner.on('test end', () => { + autoscroll($('#mocha-report .test').last()[0]); stats.tests++; });