Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion tests/Motus.Tests/Browser/FirefoxIntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,20 @@ await page.SetContentAsync(
Assert.IsTrue(await page.EvaluateAsync<bool>(Run("b")), "The script did not scroll to an element below the fold.");
Assert.IsTrue(await page.EvaluateAsync<bool>(InView), "The element is still outside the viewport.");

var scrollY = await page.EvaluateAsync<double>("window.scrollY");
// Centering lands on a half pixel whenever the viewport's height is odd, and Firefox can
// round a half-pixel scroll position to a whole one after the scroll has finished, so a
// position read straight after centering can move by a pixel with nothing scrolling it.
// The element is put at a whole-pixel position off center instead: still in view, so the
// script must leave it alone, and far enough from center that a script that scrolled
// anyway would visibly move it, which re-centering an already centered element would not.
var scrollY = await page.EvaluateAsync<double>("""
(() => {
const top = document.getElementById('b').getBoundingClientRect().top + window.scrollY;
window.scrollTo({ top: Math.round(top) - 100, behavior: 'instant' });
return window.scrollY;
})()
""");
Assert.IsTrue(await page.EvaluateAsync<bool>(InView), "The element left the viewport when it was moved off center.");
Assert.IsFalse(await page.EvaluateAsync<bool>(Run("b")), "The script scrolled an element that was already in view.");
Assert.AreEqual(scrollY, await page.EvaluateAsync<double>("window.scrollY"));

Expand Down
15 changes: 13 additions & 2 deletions tests/Motus.Tests/Context/TracingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -296,16 +296,27 @@ public async Task StartAsync_ConcurrentOnSameBrowser_SerializesViaGate()
await Task.Delay(50);
Assert.IsFalse(secondStartTask.IsCompleted, "Second StartAsync should be gated until the first stops.");

// Now stop the first and let the second proceed.
// Now stop the first and let the second proceed. The second start's answer is queued
// here, before the stop, because the stop releases the gate on its way out and the
// second start sends Tracing.start from that moment on another thread. Queued after
// awaiting the stop, the answer could arrive after the command it was meant for, which
// then waits out the transport's command timeout. The gate is what keeps the two
// answers in order: nothing can send Tracing.start until Tracing.end has been answered.
_socket.QueueResponse("""{"id":2,"result":{}}"""); // first end
_socket.QueueResponse("""{"id":3,"result":{}}"""); // second start, once the gate opens
var firstStopTask = first.StopAsync();
await Task.Delay(50);
_socket.Enqueue("""{"method":"Tracing.tracingComplete","params":{"dataLossOccurred":false}}""");
await firstStopTask;

_socket.QueueResponse("""{"id":3,"result":{}}"""); // second start (now unblocked)
await secondStartTask;

var sent = _socket.SentMessages.Select(bytes => System.Text.Encoding.UTF8.GetString(bytes)).ToList();
var firstEnd = sent.FindIndex(json => json.Contains("\"Tracing.end\""));
var secondStart = sent.FindLastIndex(json => json.Contains("\"Tracing.start\""));
Assert.IsTrue(firstEnd >= 0 && secondStart > firstEnd,
"The second Tracing.start went out before the first trace had ended.");

// Cleanly stop the second so the gate is released for any teardown.
_socket.QueueResponse("""{"id":4,"result":{}}""");
var secondStopTask = second.StopAsync();
Expand Down
Loading