Skip to content

Commit 768276c

Browse files
authored
test: implement screen-shooter integration tests (#1241)
* fix: exclude certain dependencies from prebundling * test: specify concrete browser version in standalone integration tests * test: implement screen-shooter integration tests
1 parent 9afdc37 commit 768276c

17 files changed

Lines changed: 857 additions & 0 deletions

src/runner/browser-env/vite/server.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,16 @@ export class ViteServer {
5454
"rgb2hex",
5555
"ws",
5656
],
57+
exclude: [
58+
// These packages must not be pre-bundled: esbuild would inline Node.js-only
59+
// deps (puppeteer-core, node:events, etc.) before Vite's resolveId stubs/
60+
// polyfills can intercept them, causing "extends undefined" crashes.
61+
"@testplane/webdriverio",
62+
"@testplane/webdriver",
63+
"@testplane/wdio-utils",
64+
"@testplane/wdio-protocols",
65+
"puppeteer-core",
66+
],
5767
esbuildOptions: {
5868
logLevel: "silent",
5969
},
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Deterministic geometry changes</title>
7+
<style>
8+
html,
9+
body {
10+
margin: 0;
11+
width: 100%;
12+
height: 100%;
13+
overflow: hidden;
14+
background: #f3f5f7;
15+
font-family: Arial, sans-serif;
16+
}
17+
18+
.Modal {
19+
position: fixed;
20+
inset: 0;
21+
background: rgba(0, 0, 0, 0.3);
22+
}
23+
24+
.Modal-Wrapper {
25+
position: absolute;
26+
left: 80px;
27+
top: 40px;
28+
width: 640px;
29+
height: 520px;
30+
overflow-y: auto;
31+
background: #fff;
32+
border-radius: 12px;
33+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
34+
}
35+
36+
.Modal-Content {
37+
width: 560px;
38+
height: 2200px;
39+
margin: 24px auto;
40+
border: 1px solid red;
41+
background: linear-gradient(180deg, #eff8ff 0%, #b8ddff 100%);
42+
border-radius: 8px;
43+
transform: translateY(0px);
44+
will-change: transform, height;
45+
}
46+
47+
.Modal-Content::before {
48+
content: "";
49+
display: block;
50+
height: 100%;
51+
background: repeating-linear-gradient(
52+
180deg,
53+
rgba(255, 255, 255, 0.2) 0px,
54+
rgba(255, 255, 255, 0.2) 24px,
55+
rgba(0, 0, 0, 0.03) 24px,
56+
rgba(0, 0, 0, 0.03) 48px
57+
);
58+
border-radius: 8px;
59+
}
60+
</style>
61+
</head>
62+
<body>
63+
<div class="Modal">
64+
<div class="Modal-Wrapper">
65+
<div class="Modal-Content"></div>
66+
</div>
67+
</div>
68+
<script>
69+
const wrapper = document.querySelector(".Modal-Wrapper");
70+
const content = document.querySelector(".Modal-Content");
71+
let updateToken = 0;
72+
73+
wrapper.addEventListener("scroll", () => {
74+
updateToken += 1;
75+
const token = updateToken;
76+
const phase = Math.floor(wrapper.scrollTop / 200) % 4;
77+
const yOffsets = [0, 2, 1, 3];
78+
const heightOffsets = [0, 4, 2, 6];
79+
80+
setTimeout(() => {
81+
if (token !== updateToken) {
82+
return;
83+
}
84+
85+
content.style.transform = `translateY(${yOffsets[phase]}px)`;
86+
content.style.height = `${2200 + heightOffsets[phase]}px`;
87+
}, 0);
88+
});
89+
</script>
90+
</body>
91+
</html>
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Dynamic sticky menu safe-area fixture</title>
7+
<style>
8+
* {
9+
box-sizing: border-box;
10+
margin: 0;
11+
padding: 0;
12+
}
13+
14+
body {
15+
font-family: Arial, sans-serif;
16+
color: #1f2937;
17+
background: #f3f5f7;
18+
}
19+
20+
.Hero {
21+
height: 300px;
22+
padding: 36px 28px;
23+
background: linear-gradient(180deg, #f9fbff 0%, #e7eef8 100%);
24+
border-bottom: 1px solid #d6dfeb;
25+
}
26+
27+
.Hero h1 {
28+
font-size: 30px;
29+
line-height: 1.2;
30+
margin-bottom: 12px;
31+
}
32+
33+
.Hero p {
34+
max-width: 760px;
35+
line-height: 1.5;
36+
color: #4b5563;
37+
}
38+
39+
#menu-slot {
40+
min-height: 66px;
41+
}
42+
43+
.TopMenu {
44+
min-height: 66px;
45+
padding: 12px 18px;
46+
border-bottom: 1px solid #c8d2df;
47+
background: #fff;
48+
display: flex;
49+
align-items: center;
50+
gap: 10px;
51+
flex-wrap: nowrap;
52+
overflow-x: auto;
53+
z-index: 30;
54+
}
55+
56+
body.is-fixed .TopMenu {
57+
position: fixed;
58+
top: 0;
59+
left: 0;
60+
right: 0;
61+
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.14);
62+
}
63+
64+
.TopMenu-Item {
65+
height: 34px;
66+
padding: 0 12px;
67+
border-radius: 17px;
68+
border: 1px solid #b8c3d1;
69+
background: #eef2f8;
70+
display: inline-flex;
71+
align-items: center;
72+
font-size: 14px;
73+
white-space: nowrap;
74+
}
75+
76+
.Layout {
77+
width: min(1100px, calc(100% - 32px));
78+
margin: 22px auto 0;
79+
display: flex;
80+
gap: 18px;
81+
}
82+
83+
.Sidebar {
84+
width: 240px;
85+
min-height: 900px;
86+
padding: 16px;
87+
border: 1px solid #d7dde7;
88+
border-radius: 12px;
89+
background: #fff;
90+
color: #6b7280;
91+
line-height: 1.5;
92+
}
93+
94+
.Feed {
95+
flex: 1;
96+
min-height: 1700px;
97+
padding: 16px;
98+
border: 1px solid #d7dde7;
99+
border-radius: 12px;
100+
background: #fff;
101+
}
102+
103+
.Feed-LongBlock {
104+
width: 100%;
105+
min-height: 1300px;
106+
padding: 20px;
107+
border-radius: 10px;
108+
border: 2px solid #5b8ec7;
109+
background: repeating-linear-gradient(to bottom, #eaf3ff 0px, #eaf3ff 26px, #dbe9fa 26px, #dbe9fa 52px);
110+
}
111+
112+
.Feed-LongBlock h2 {
113+
margin-bottom: 12px;
114+
font-size: 26px;
115+
}
116+
117+
.Feed-LongBlock p {
118+
max-width: 720px;
119+
margin-bottom: 16px;
120+
line-height: 1.5;
121+
color: #374151;
122+
}
123+
</style>
124+
</head>
125+
<body>
126+
<section class="Hero">
127+
<h1>Product feed with sticky top menu</h1>
128+
<p>
129+
The top menu is static at first, then switches to fixed right when it reaches viewport top. This fixture
130+
is intended to surface dynamic safe-area behavior while compositing long screenshots.
131+
</p>
132+
</section>
133+
134+
<div id="menu-slot">
135+
<nav id="top-menu" class="TopMenu">
136+
<span class="TopMenu-Item">All</span>
137+
<span class="TopMenu-Item">News</span>
138+
<span class="TopMenu-Item">Videos</span>
139+
<span class="TopMenu-Item">Docs</span>
140+
<span class="TopMenu-Item">Guides</span>
141+
<span class="TopMenu-Item">Community</span>
142+
</nav>
143+
</div>
144+
145+
<main class="Layout">
146+
<aside class="Sidebar">
147+
<strong>Left panel</strong><br /><br />
148+
Filters, stats and helper cards imitate a realistic layout around the main feed block.
149+
</aside>
150+
<section class="Feed">
151+
<article class="Feed-LongBlock">
152+
<h2>Long capture target</h2>
153+
<p>
154+
This block is intentionally tall and should be captured as a composite image. As scrolling
155+
progresses, the menu above turns fixed and starts occupying the top viewport area.
156+
</p>
157+
</article>
158+
</section>
159+
</main>
160+
161+
<script>
162+
(function () {
163+
var menu = document.getElementById("top-menu");
164+
var slot = document.getElementById("menu-slot");
165+
166+
function syncSlotHeight() {
167+
var isFixed = document.body.classList.contains("is-fixed");
168+
if (isFixed) {
169+
document.body.classList.remove("is-fixed");
170+
}
171+
slot.style.height = menu.offsetHeight + "px";
172+
if (isFixed) {
173+
document.body.classList.add("is-fixed");
174+
}
175+
}
176+
177+
function updateMenuMode() {
178+
var shouldFix = slot.getBoundingClientRect().top <= 0;
179+
180+
if (shouldFix) {
181+
if (!document.body.classList.contains("is-fixed")) {
182+
document.body.classList.add("is-fixed");
183+
}
184+
return;
185+
}
186+
187+
if (document.body.classList.contains("is-fixed")) {
188+
document.body.classList.remove("is-fixed");
189+
}
190+
}
191+
192+
window.addEventListener("scroll", updateMenuMode, { passive: true });
193+
window.addEventListener("resize", function () {
194+
syncSlotHeight();
195+
updateMenuMode();
196+
});
197+
syncSlotHeight();
198+
updateMenuMode();
199+
})();
200+
</script>
201+
</body>
202+
</html>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Screen shooter horizontal overflow fixture</title>
7+
<style>
8+
html,
9+
body {
10+
margin: 0;
11+
padding: 0;
12+
}
13+
14+
.content {
15+
height: 2000px;
16+
}
17+
18+
#partially-offscreen {
19+
position: fixed;
20+
bottom: -20px;
21+
left: 100px;
22+
padding: 40px;
23+
/* width: 40px; */
24+
/* height: 40px; */
25+
background: rgba(0, 0, 0, 0.5);
26+
border: 1px solid red;
27+
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.5);
28+
}
29+
</style>
30+
</head>
31+
<body>
32+
<div id="partially-offscreen">Hello, this is a partially off-screen element</div>
33+
<div class="content">Some long content...</div>
34+
</body>
35+
</html>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Fractional scroll checkpoint stability</title>
7+
<style>
8+
html,
9+
body {
10+
margin: 0;
11+
}
12+
13+
html {
14+
height: 2300.6px;
15+
}
16+
17+
.Content {
18+
width: 320px;
19+
height: 2200.4px;
20+
margin: 12.5px auto;
21+
background: linear-gradient(180deg, #edf7ff 0%, #c7e4ff 100%);
22+
border-radius: 8px;
23+
}
24+
25+
.Content::before {
26+
content: "";
27+
display: block;
28+
height: 100%;
29+
background: repeating-linear-gradient(
30+
180deg,
31+
rgba(255, 255, 255, 0.2) 0px,
32+
rgba(255, 255, 255, 0.2) 24px,
33+
rgba(0, 0, 0, 0.03) 24px,
34+
rgba(0, 0, 0, 0.03) 48px
35+
);
36+
border-radius: 8px;
37+
}
38+
</style>
39+
</head>
40+
<body>
41+
<div class="Content"></div>
42+
</body>
43+
<script>
44+
window.scrollTo(0, 0.5);
45+
</script>
46+
</html>

0 commit comments

Comments
 (0)