1
1
---
2
- title : " 等待 "
2
+ title : " 等待策略 "
3
3
linkTitle : " 等待"
4
4
weight : 6
5
5
aliases : ["/documentation/zh-cn/webdriver/waits/"]
6
6
---
7
7
8
- Perhaps the most common challenge for browser automation is ensuring
9
- that the web application is in a state to execute a particular
10
- Selenium command as desired. The processes often end up in
11
- a _ race condition_ where sometimes the browser gets into the right
12
- state first (things work as intended) and sometimes the Selenium code
13
- executes first (things do not work as intended). This is one of the
14
- primary causes of _ flaky tests_ .
15
-
16
- All navigation commands wait for a specific ` readyState ` value
17
- based on the [ page load strategy] ({{< ref "drivers/options#pageloadstrategy" >}}) (the
18
- default value to wait for is ` "complete" ` ) before the driver returns control to the code.
19
- The ` readyState ` only concerns itself with loading assets defined in the HTML,
20
- but loaded JavaScript assets often result in changes to the site,
21
- and elements that need to be interacted with may not yet be on the page
22
- when the code is ready to execute the next Selenium command.
23
-
24
- Similarly, in a lot of single page applications, elements get dynamically
25
- added to a page or change visibility based on a click.
26
- An element must be both present and
27
- [ displayed] ({{< ref "elements/information/#is-displayed" >}}) on the page
28
- in order for Selenium to interact with it.
29
-
30
- Take this page for example: https://www.selenium.dev/selenium/web/dynamic.html
31
- When the "Add a box!" button is clicked, a "div" element that does not exist is created.
32
- When the "Reveal a new input" button is clicked, a hidden text field element is displayed.
33
- In both cases the transition takes a couple seconds.
34
- If the Selenium code is to click one of these buttons and interact with the resulting element,
35
- it will do so before that element is ready and fail.
36
-
37
- The first solution many people turn to is adding a sleep statement to
38
- pause the code execution for a set period of time.
39
- Because the code can't know exactly how long it needs to wait, this
40
- can fail when it doesn't sleep long enough. Alternately, if the value is set too high
41
- and a sleep statement is added in every place it is needed, the duration of
42
- the session can become prohibitive.
43
-
44
- Selenium provides two different mechanisms for synchronization that are better.
45
-
46
-
47
- ## Implicit waits
48
- Selenium has a built-in way to automatically wait for elements called an _ implicit wait_ .
49
- An implicit wait value can be set either with the [ timeouts] ({{< ref "drivers/options#timeouts" >}})
50
- capability in the browser options, or with a driver method (as shown below).
51
-
52
- This is a global setting that applies to every element location call for the entire session.
53
- The default value is ` 0 ` , which means that if the element is not found, it will
54
- immediately return an error. If an implicit wait is set, the driver will wait for the
55
- duration of the provided value before returning the error. Note that as soon as the
56
- element is located, the driver will return the element reference and the code will continue executing,
57
- so a larger implicit wait value won't necessarily increase the duration of the session.
58
-
59
- * Warning:*
60
- Do not mix implicit and explicit waits.
61
- Doing so can cause unpredictable wait times.
62
- For example, setting an implicit wait of 10 seconds
63
- and an explicit wait of 15 seconds
64
- could cause a timeout to occur after 20 seconds.
65
-
66
- Solving our example with an implicit wait looks like this:
8
+
9
+ 或许浏览器自动化面临的最常见挑战在于,
10
+ 确保网络应用程序处于能够按预期执行特定 Selenium 命令的状态.
11
+ 这些过程常常陷入一种 _ 竞态条件_ ,
12
+ 有时浏览器会先达到正确状态 (一切按预期运行) ,
13
+ 有时 Selenium 代码会先执行 (一切未按预期运行) .
14
+ 这是导致 _ 不稳定测试_ 的主要原因之一.
15
+
16
+
17
+ 所有导航命令都会等待特定基于 [ 页面加载策略] ({{< ref "drivers/options#pageloadstrategy">}}) 的值 ` readyState `
18
+ (默认等待的值为 ` "complete" ` ) ,
19
+ 然后驱动程序才会将控制权交还给代码.
20
+ ` readyState ` 仅关注 HTML 中定义的资源加载,
21
+ 但加载的 JavaScript 资源常常会导致网站发生变化,
22
+ 而当代码准备执行下一个 Selenium 命令时,
23
+ 需要交互的元素可能尚未出现在页面上.
24
+
25
+
26
+ 同样, 在许多单页应用程序中,
27
+ 元素会根据点击操作动态添加到页面上或改变可见性.
28
+ 对于 Selenium 能够与之交互,
29
+ 该元素必须既存在于页面上又处于[ displayed] ({{< ref "elements/information/#is-displayed">}}) 状态.
30
+
31
+
32
+ 以这个页面为例: https://www.selenium.dev/selenium/web/dynamic.html
33
+ 当点击 "Add a box!" 按钮时,
34
+ 会创建一个原本不存在的 "div" 元素.
35
+ 当点击 "Reveal a new input" 按钮时,
36
+ 一个隐藏的文本字段元素会被显示出来.
37
+ 在这两种情况下, 过渡都需要几秒钟.
38
+ 如果 Selenium 代码要点击其中一个按钮并与生成的元素进行交互,
39
+ 它会在该元素准备好之前就执行操作, 从而导致失败.
40
+
41
+
42
+ 许多人首先想到的解决办法是在代码中添加一个睡眠语句,
43
+ 让代码暂停执行一段设定的时间.
44
+ 由于代码无法确切知道需要等待多久,
45
+ 如果设置的睡眠时间不够长,
46
+ 这种方法可能会失败.
47
+ 相反, 如果睡眠时间设置得过高, 并且在每个需要的地方都添加睡眠语句,
48
+ 那么会话的持续时间可能会变得难以接受.
49
+
50
+ Selenium 提供了更好的两种不同的同步机制,
51
+
52
+
53
+ ## 隐式等待
54
+ Selenium 内置了一种自动等待元素出现的方式, 称为 _ 隐式等待_ .
55
+ 隐式等待的值可以通过浏览器选项中的 [ timeouts] ({{< ref "drivers/options#timeouts">}}) 设置来设定,
56
+ 也可以通过驱动程序的方法来设定 (如下所示) .
57
+
58
+ 这是一个全局设置, 适用于整个会话期间的每个元素定位调用.
59
+ 默认值为 ` 0 ` ,
60
+ 这意味着如果未找到元素,
61
+ 将立即返回错误.
62
+ 如果设置了隐式等待,
63
+ 驱动程序将在返回错误之前等待所提供的时长.
64
+ 请注意, 一旦定位到元素,
65
+ 驱动程序将返回元素引用,
66
+ 代码将继续执行,
67
+ 因此较大的隐式等待值不一定增加会话的持续时间.
68
+
69
+ * 警告:*
70
+ 请勿混合使用隐式等待和显式等待.
71
+ 这样做可能会导致等待时间不可预测.
72
+ 例如, 设置 10 秒的隐式等待和 15 秒的显式等待,
73
+ 可能会导致在 20 秒后发生超时.
74
+
75
+ 使用隐式等待解决我们的示例代码如下:
76
+
67
77
68
78
{{< tabpane text=true >}}
69
79
{{< tab header="Java" >}}
@@ -86,15 +96,20 @@ Solving our example with an implicit wait looks like this:
86
96
{{< /tab >}}
87
97
{{< /tabpane >}}
88
98
89
- ## Explicit waits
90
99
91
- _ Explicit waits_ are loops added to the code that poll the application
92
- for a specific condition to evaluate as true before it exits the loop and
93
- continues to the next command in the code. If the condition is not met before a designated timeout value,
94
- the code will give a timeout error. Since there are many ways for the application not to be in the desired state,
95
- explicit waits are a great choice to specify the exact condition to wait for
96
- in each place it is needed.
97
- Another nice feature is that, by default, the Selenium Wait class automatically waits for the designated element to exist.
100
+
101
+ ## 显式等待
102
+
103
+ _ 显式等待_ 是在代码中添加的, 用于轮询应用程序的循环,
104
+ 直到特定条件评估为真时, 才退出循环并继续执行代码中的下一个命令.
105
+ 如果在指定的超时值之前条件未满足,
106
+ 代码将给出超时错误.
107
+ 由于应用程序未处于所需状态的方式有很多,
108
+ 因此显式等待是为每个需要等待的地方指定确切等待条件的绝佳选择.
109
+ 另一个不错的特性是, 默认情况下,
110
+ Selenium 等待类会自动等待指定的元素存在.
111
+
112
+
98
113
99
114
{{< tabpane text=true >}}
100
115
{{% tab header="Java" %}}
@@ -122,23 +137,28 @@ JavaScript also supports [Expected Conditions]({{< ref "support_features/expecte
122
137
{{< /tab >}}
123
138
{{< /tabpane >}}
124
139
125
- ### Customization
126
140
127
- The Wait class can be instantiated with various parameters that will change how the conditions are evaluated.
128
141
129
- This can include:
130
- * Changing how often the code is evaluated (polling interval)
131
- * Specifying which exceptions should be handled automatically
132
- * Changing the total timeout length
133
- * Customizing the timeout message
142
+ ### 定制
143
+
144
+ Wait 类可以通过各种参数进行实例化,
145
+ 这些参数会改变条件的评估方式.
146
+
147
+ 这可以包括:
148
+ * 更改代码的评估频率 (轮询间隔)
149
+ * 指定哪些异常应自动处理
150
+ * 更改总超时时长
151
+ * 自定义超时消息
152
+
153
+ 例如, 如果默认情况下对 _ 元素不可交互_ 错误进行重试,
154
+ 那么我们可以在执行中的代码里的某个方法内添加一个操作
155
+ (我们只需要确保代码在成功时返回 ` true ` 即可):
156
+
134
157
135
- For instance, if the _ element not interactable_ error is retried by default, then we can
136
- add an action on a method inside the code getting executed (we just need to
137
- make sure that the code returns ` true ` when it is successful):
138
158
139
159
{{< tabpane text=true >}}
140
160
{{% tab header="Java" %}}
141
- The easiest way to customize Waits in Java is to use the ` FluentWait ` class:
161
+ The easiest way to customize Waits in Java is to use the ` FluentWait ` class:
142
162
{{< gh-codeblock path="examples/java/src/test/java/dev/selenium/waits/WaitsTest.java#L82-L92" >}}
143
163
{{% /tab %}}
144
164
{{< tab header="Python" >}}
@@ -157,3 +177,4 @@ The easiest way to customize Waits in Java is to use the `FluentWait` class:
157
177
{{< badge-code >}}
158
178
{{< /tab >}}
159
179
{{< /tabpane >}}
180
+
0 commit comments