-
Notifications
You must be signed in to change notification settings - Fork 236
/
Copy pathPauseSpec.groovy
136 lines (111 loc) · 4.38 KB
/
PauseSpec.groovy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package geb
import geb.js.JavascriptInterface
import geb.test.GebSpecWithCallbackServer
import geb.test.GebTestManager
import geb.waiting.Wait
import groovy.transform.InheritConstructors
import org.openqa.selenium.JavascriptExecutor
import org.openqa.selenium.WebDriver
class PauseSpec extends GebSpecWithCallbackServer {
private static final GebTestManager TEST_MANAGER = managerBuilder()
.withBrowserCreator(configToBrowserSupplier { new ThreadSafeScriptExecutionDriverConfigurationLoader().conf })
.build()
@Override
GebTestManager getTestManager() {
TEST_MANAGER
}
def 'pausing triggered using pause() can be cancelled by setting geb.unpause js variable to true'() {
given:
html {}
and:
def browserPausingThread = new BrowserPausingThread(browser)
browserPausingThread.start()
when:
js.exec 'geb.unpause = true;'
then:
browserPausingThread.awaitCompletion()
!browserPausingThread.error
}
@InheritConstructors
private static class ThreadSafeScriptExecutionDriverConfiguration extends Configuration {
@Override
WebDriver createDriver() {
def driver = super.createDriver()
driver.javascriptEnabled = true
ThreadSafeScriptExecutionDriver.of(driver)
}
}
@InheritConstructors
private static class ThreadSafeScriptExecutionDriverConfigurationLoader extends ConfigurationLoader {
@Override
protected createConf(ConfigObject rawConfig, GroovyClassLoader classLoader) {
new ThreadSafeScriptExecutionDriverConfiguration(rawConfig, properties, createBuildAdapter(classLoader), classLoader)
}
}
/**
* The surrounding specification is using a WebDriver instance from multiple threads which is not safe.
* This class synchronises access to the executeScript() method which is the only method used concurrently.
*/
private static class ThreadSafeScriptExecutionDriver implements WebDriver, JavascriptExecutor {
private final Object executeScriptMutex = new Object()
@Delegate
private WebDriver driver
@Delegate
private JavascriptExecutor javascriptExecutor
private ThreadSafeScriptExecutionDriver(WebDriver driver, JavascriptExecutor javascriptExecutor) {
this.driver = driver
this.javascriptExecutor = javascriptExecutor
}
static <T extends WebDriver & JavascriptExecutor> ThreadSafeScriptExecutionDriver of(T driver) {
new ThreadSafeScriptExecutionDriver(driver, driver)
}
@Override
Object executeScript(String script, Object... args) {
synchronized (executeScriptMutex) {
javascriptExecutor.executeScript(script, args)
}
}
}
private static class BrowserPausingThread {
private final Wait waiting = new Wait()
private final JavascriptInterface js
private final Thread thread
private Throwable error
BrowserPausingThread(Browser browser) {
this.js = browser.js
this.thread = new Thread({ browser.pause() })
this.thread.uncaughtExceptionHandler = { Thread t, Throwable e ->
error = e
}
}
void start() {
thread.start()
waiting.waitFor {
js.exec 'return geb.unpause !== undefined;'
}
}
void awaitCompletion() {
waiting.waitFor {
!thread.alive
}
}
}
}