Skip to content

Commit

Permalink
make Page.WaitStable more stable
Browse files Browse the repository at this point in the history
  • Loading branch information
ysmood committed Jul 12, 2023
1 parent cc4f51f commit 6b2bbc6
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 99 deletions.
90 changes: 10 additions & 80 deletions fixtures/page-wait-stable.html
Original file line number Diff line number Diff line change
@@ -1,89 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<title>PageWaitStable</title>
<style>
/* 进度条的样式 */
progress[value] {
display: block;
width: 100%;
margin-top: 20px;
-webkit-appearance: none;
appearance: none;
height: 10px;
background-color: #ddd;
}

progress[value]::-webkit-progress-bar {
background-color: #ddd;
}

progress[value]::-webkit-progress-value {
background-color: #0078ff;
}

/* loading 动画的样式 */
.loading {
display: block;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 9999;
}
</style>
</head>

<body>
<!-- 进度条 -->
<progress id="progressBar" value="0" max="100"></progress>

<!-- loading 动画 -->
<div id="loading" class="loading">
<img src="path-to-loading-gif" alt="loading" />
</div>

<!-- Your other HTML content here -->

<!-- 页面加载完成时的弹窗 -->
<div
id="popup"
style="
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
padding: 20px;
border-radius: 10px;
box-shadow: 2px 2px 10px #888;
"
>
<h1 style="text-align: center">Page loading and rendering complete</h1>
</div>
<div id="progress"></div>

<script>
/* 页面加载时触发的函数 */
window.onload = function () {
/* 获取进度条和 loading 动画元素 */
var progressBar = document.getElementById('progressBar')
var loading = document.getElementById('loading')
var popup = document.getElementById('popup')
var progress = 0
/* 定时器,每 50ms 触发一次 */
var timer = setInterval(function () {
/* 如果进度条已满,则隐藏 loading 动画,并显示弹窗 */
if (progress === 100) {
clearInterval(timer)
loading.style.display = 'none'
popup.style.display = 'block'
} else {
/* 否则,增加进度,更新进度条 */
progress += 1
progressBar.value = progress
}
}, 50)
var pg = document.getElementById('progress')
var count = 0
function tick() {
count += 1
pg.textContent = count + '%'

if (count < 100) setTimeout(tick, 10)
}
tick()
}
</script>
</body>
Expand Down
8 changes: 6 additions & 2 deletions must.go
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,11 @@ func (p *Page) MustWaitNavigation() func() {

// MustWaitRequestIdle is similar to Page.WaitRequestIdle
func (p *Page) MustWaitRequestIdle(excludes ...string) (wait func()) {
return p.WaitRequestIdle(300*time.Millisecond, nil, excludes)
return p.WaitRequestIdle(300*time.Millisecond, nil, excludes, []proto.NetworkResourceType{
proto.NetworkResourceTypeWebSocket,
proto.NetworkResourceTypeEventSource,
proto.NetworkResourceTypeMedia,
})
}

// MustWaitIdle is similar to Page.WaitIdle
Expand All @@ -427,7 +431,7 @@ func (p *Page) MustWaitIdle() *Page {

// MustWaitStable is similar to Page.WaitStable
func (p *Page) MustWaitStable() *Page {
p.e(p.WaitStable(800*time.Millisecond, 1))
p.e(p.WaitStable(500*time.Millisecond, 0))
return p
}

Expand Down
33 changes: 23 additions & 10 deletions page.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,9 @@ func (p *Page) WaitNavigation(name proto.PageLifecycleEventName) func() {
// Be careful, d is not the max wait timeout, it's the least idle time.
// If you want to set a timeout you can use the "Page.Timeout" function.
// Use the includes and excludes regexp list to filter the requests by their url.
func (p *Page) WaitRequestIdle(d time.Duration, includes, excludes []string) func() {
func (p *Page) WaitRequestIdle(d time.Duration, includes, excludes []string, excludeTypes []proto.NetworkResourceType) func() {
defer p.tryTrace(TraceTypeWait, "request-idle")()

if len(includes) == 0 {
includes = []string{""}
}
Expand All @@ -605,6 +607,12 @@ func (p *Page) WaitRequestIdle(d time.Duration, includes, excludes []string) fun
}

wait := p.EachEvent(func(sent *proto.NetworkRequestWillBeSent) {
for _, t := range excludeTypes {
if sent.Type == t {
return
}
}

if match(sent.Request.URL) {
// Redirect will send multiple NetworkRequestWillBeSent events with the same RequestID,
// we should filter them out.
Expand All @@ -629,13 +637,18 @@ func (p *Page) WaitRequestIdle(d time.Duration, includes, excludes []string) fun
}
}

// WaitStable like "Element.WaitStable". WaitStable polling the changes
// of the DOM tree in `d` duration,until the similarity equal or more than simThreshold.
// `simThreshold` is the similarity threshold,it's scope in [0,1].
// Be careful,d is not the max wait timeout, it's the least stable time.
// WaitStable waits until the change of the DOM tree is less or equal than diff percent for d duration.
// Be careful, d is not the max wait timeout, it's the least stable time.
// If you want to set a timeout you can use the "Page.Timeout" function.
func (p *Page) WaitStable(d time.Duration, similarity float32) error {
defer p.tryTrace(TraceTypeWait, "stable")
func (p *Page) WaitStable(d time.Duration, diff float64) error {
defer p.tryTrace(TraceTypeWait, "stable")()

err := p.WaitLoad()
if err != nil {
return err
}

p.MustWaitRequestIdle()()

domSnapshot, err := p.CaptureDOMSnapshot()
if err != nil {
Expand All @@ -659,10 +672,10 @@ func (p *Page) WaitStable(d time.Duration, similarity float32) error {

xs := lcs.NewWords(domSnapshot.Strings)
ys := lcs.NewWords(currentDomSnapshot.Strings)
diff := xs.YadLCS(p.ctx, ys)
lcs := xs.YadLCS(p.ctx, ys)

sim := float32(len(diff)) / float32(len(ys))
if sim >= similarity {
df := 1 - float64(len(lcs))/float64(len(ys))
if df <= diff {
break
}

Expand Down
24 changes: 17 additions & 7 deletions page_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -525,14 +525,24 @@ func TestPageCaptureDOMSnapshot(t *testing.T) {
func TestPageWaitStable(t *testing.T) {
g := setup(t)

p := g.page.MustNavigate(g.srcFile("fixtures/page-wait-stable.html"))
// wait for p loading and rending complete
p.MustWaitStable()
{
p := g.page.MustNavigate(g.srcFile("fixtures/page-wait-stable.html"))
p.MustWaitStable()
}

// for waitStable timeout
timeOutPage := p.Timeout(1 * time.Second)
err := timeOutPage.WaitStable(2*time.Second, 1)
g.Is(err, context.DeadlineExceeded)
{
p := g.page.MustNavigate(g.srcFile("fixtures/page-wait-stable.html"))
err := p.Timeout(time.Second).WaitStable(time.Second, 0)
g.Is(err, context.DeadlineExceeded)
}

{
g.Panic(func() {
p := g.page.MustWaitStable()
g.mc.stubErr(1, proto.RuntimeCallFunctionOn{})
p.MustWaitStable()
})
}

{
g.Panic(func() {
Expand Down

0 comments on commit 6b2bbc6

Please sign in to comment.