Skip to content

Commit 130f97f

Browse files
authored
Apply viewport emulation to prerender targets (#2444)
* Apply viewport emulation to prerender targets * Remove extra assigment
1 parent 9f464b2 commit 130f97f

File tree

3 files changed

+105
-23
lines changed

3 files changed

+105
-23
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System.Diagnostics;
2+
using System.Threading.Tasks;
3+
using NUnit.Framework;
4+
using PuppeteerSharp.Nunit;
5+
using PuppeteerSharp.Tests.Attributes;
6+
7+
namespace PuppeteerSharp.Tests.PrerenderTests;
8+
9+
public class WithEmulationTests : PuppeteerPageBaseTest
10+
{
11+
[PuppeteerTest("prerender.spec.ts", "Prerender with emulation", "can configure viewport for prerendered pages")]
12+
[Skip(SkipAttribute.Targets.Firefox)]
13+
public async Task CanConfigureViewportForPrerenderedPages()
14+
{
15+
await Page.SetViewportAsync(new ViewPortOptions()
16+
{
17+
Width = 300,
18+
Height = 400,
19+
});
20+
21+
await Page.GoToAsync(TestConstants.ServerUrl + "/prerender/index.html");
22+
23+
var button = await Page.WaitForSelectorAsync("button");
24+
await button.ClickAsync();
25+
26+
var mainFrame = Page.MainFrame;
27+
var link = await mainFrame.WaitForSelectorAsync("a");
28+
await Task.WhenAll(
29+
mainFrame.WaitForNavigationAsync(),
30+
link.ClickAsync()
31+
);
32+
33+
var result = await Page.EvaluateFunctionAsync<decimal[]>(@"() => {
34+
return [
35+
document.documentElement.clientWidth,
36+
document.documentElement.clientHeight,
37+
window.devicePixelRatio,
38+
];
39+
}");
40+
41+
Assert.AreEqual(300 * result[2], result[0]);
42+
Assert.AreEqual(400 * result[2], result[1]);
43+
}
44+
}

lib/PuppeteerSharp/EmulationManager.cs

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using System.Threading.Tasks;
5+
using PuppeteerSharp.Helpers;
46
using PuppeteerSharp.Media;
57
using PuppeteerSharp.Messaging;
68

79
namespace PuppeteerSharp
810
{
911
internal class EmulationManager
1012
{
13+
private readonly ConcurrentSet<CDPSession> _secondaryClients = [];
1114
private CDPSession _client;
1215
private bool _emulatingMobile;
1316
private bool _hasTouch;
17+
private ViewPortOptions _viewport;
1418

1519
public EmulationManager(CDPSession client)
1620
{
@@ -19,7 +23,18 @@ public EmulationManager(CDPSession client)
1923

2024
public bool JavascriptEnabled { get; private set; } = true;
2125

22-
internal void UpdateClient(CDPSession client) => _client = client;
26+
internal void UpdateClient(CDPSession client)
27+
{
28+
_client = client;
29+
_secondaryClients.Remove(client);
30+
}
31+
32+
internal async Task RegisterSecondaryPageAsync(CDPSession client)
33+
{
34+
_secondaryClients.Add(client);
35+
await ApplyViewportAsync(client).ConfigureAwait(false);
36+
client.Disconnected += (sender, e) => _secondaryClients.Remove(client);
37+
}
2338

2439
internal async Task EmulateTimezoneAsync(string timezoneId)
2540
{
@@ -72,33 +87,22 @@ await _client.SendAsync(
7287

7388
internal async Task<bool> EmulateViewportAsync(ViewPortOptions viewport)
7489
{
75-
var mobile = viewport.IsMobile;
76-
var width = viewport.Width;
77-
var height = viewport.Height;
78-
var deviceScaleFactor = viewport.DeviceScaleFactor;
79-
var screenOrientation = viewport.IsLandscape
80-
? new ScreenOrientation { Angle = 90, Type = ScreenOrientationType.LandscapePrimary, }
81-
: new ScreenOrientation { Angle = 0, Type = ScreenOrientationType.PortraitPrimary, };
82-
var hasTouch = viewport.HasTouch;
90+
_viewport = viewport;
8391

84-
await Task.WhenAll(
85-
[
86-
_client.SendAsync("Emulation.setDeviceMetricsOverride", new EmulationSetDeviceMetricsOverrideRequest
87-
{
88-
Mobile = mobile,
89-
Width = width,
90-
Height = height,
91-
DeviceScaleFactor = deviceScaleFactor,
92-
ScreenOrientation = screenOrientation,
93-
}),
94-
_client.SendAsync(
95-
"Emulation.setTouchEmulationEnabled",
96-
new EmulationSetTouchEmulationEnabledRequest { Enabled = hasTouch, }),
97-
]).ConfigureAwait(false);
92+
await ApplyViewportAsync(_client).ConfigureAwait(false);
9893

94+
var mobile = viewport.IsMobile;
95+
var hasTouch = viewport.HasTouch;
9996
var reloadNeeded = _emulatingMobile != mobile || _hasTouch != hasTouch;
10097
_emulatingMobile = mobile;
10198
_hasTouch = hasTouch;
99+
100+
if (!reloadNeeded)
101+
{
102+
// If the page will be reloaded, no need to adjust secondary clients.
103+
await Task.WhenAll(_secondaryClients.Select(ApplyViewportAsync)).ConfigureAwait(false);
104+
}
105+
102106
return reloadNeeded;
103107
}
104108

@@ -165,5 +169,38 @@ internal Task SetJavaScriptEnabledAsync(bool enabled)
165169
Value = !enabled,
166170
});
167171
}
172+
173+
private async Task ApplyViewportAsync(CDPSession client)
174+
{
175+
var viewport = _viewport;
176+
if (viewport == null)
177+
{
178+
return;
179+
}
180+
181+
var mobile = viewport.IsMobile;
182+
var width = viewport.Width;
183+
var height = viewport.Height;
184+
var deviceScaleFactor = viewport.DeviceScaleFactor;
185+
var screenOrientation = viewport.IsLandscape
186+
? new ScreenOrientation { Angle = 90, Type = ScreenOrientationType.LandscapePrimary, }
187+
: new ScreenOrientation { Angle = 0, Type = ScreenOrientationType.PortraitPrimary, };
188+
var hasTouch = viewport.HasTouch;
189+
190+
await Task.WhenAll(
191+
[
192+
client.SendAsync("Emulation.setDeviceMetricsOverride", new EmulationSetDeviceMetricsOverrideRequest
193+
{
194+
Mobile = mobile,
195+
Width = width,
196+
Height = height,
197+
DeviceScaleFactor = deviceScaleFactor,
198+
ScreenOrientation = screenOrientation,
199+
}),
200+
client.SendAsync(
201+
"Emulation.setTouchEmulationEnabled",
202+
new EmulationSetTouchEmulationEnabledRequest { Enabled = hasTouch, }),
203+
]).ConfigureAwait(false);
204+
}
168205
}
169206
}

lib/PuppeteerSharp/Page.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ private Page(
124124
}
125125

126126
await FrameManager.RegisterSpeculativeSessionAsync(session).ConfigureAwait(false);
127+
await _emulationManager.RegisterSecondaryPageAsync(session).ConfigureAwait(false);
127128
}
128129
catch (Exception ex)
129130
{

0 commit comments

Comments
 (0)