Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit284b082

Browse files
authored
Tests: share queue/browser handling for all worker types
- one queue to rule them all: browserstack, selenium, and jsdom- retries and hard retries are now supported in selenium- selenium tests now re-use browsers in the same way as browserstackClosegh-5460
1 parent691c0ae commit284b082

File tree

13 files changed

+336
-446
lines changed

13 files changed

+336
-446
lines changed

‎test/runner/browsers.js

Lines changed: 247 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,248 @@
1-
// This list is static, so no requests are required
2-
// in the command help menu.
3-
4-
import{getBrowsers}from"./browserstack/api.js";
5-
6-
exportconstbrowsers=[
7-
"chrome",
8-
"ie",
9-
"firefox",
10-
"edge",
11-
"safari",
12-
"opera",
13-
"yandex",
14-
"IE Mobile",
15-
"Android Browser",
16-
"Mobile Safari",
17-
"jsdom"
18-
];
19-
20-
// A function that can be used to update the above list.
21-
exportasyncfunctiongetAvailableBrowsers(){
22-
constbrowsers=awaitgetBrowsers({flat:true});
23-
constavailable=[ ...newSet(browsers.map(({ browser})=>browser))];
24-
returnavailable.concat("jsdom");
1+
importchalkfrom"chalk";
2+
import{getBrowserString}from"./lib/getBrowserString.js";
3+
import{
4+
createWorker,
5+
deleteWorker,
6+
getAvailableSessions
7+
}from"./browserstack/api.js";
8+
importcreateDriverfrom"./selenium/createDriver.js";
9+
importcreateWindowfrom"./jsdom/createWindow.js";
10+
11+
constworkers=Object.create(null);
12+
13+
/**
14+
* Keys are browser strings
15+
* Structure of a worker:
16+
* {
17+
* browser: object // The browser object
18+
* debug: boolean // Stops the worker from being cleaned up when finished
19+
* lastTouch: number // The last time a request was received
20+
* restarts: number // The number of times the worker has been restarted
21+
* options: object // The options to create the worker
22+
* url: string // The URL the worker is on
23+
* quit: function // A function to stop the worker
24+
* }
25+
*/
26+
27+
// Acknowledge the worker within the time limit.
28+
// BrowserStack can take much longer spinning up
29+
// some browsers, such as iOS 15 Safari.
30+
constACKNOWLEDGE_INTERVAL=1000;
31+
constACKNOWLEDGE_TIMEOUT=60*1000*5;
32+
33+
constMAX_WORKER_RESTARTS=5;
34+
35+
// No report after the time limit
36+
// should refresh the worker
37+
constRUN_WORKER_TIMEOUT=60*1000*2;
38+
39+
constWORKER_WAIT_TIME=30000;
40+
41+
// Limit concurrency to 8 by default in selenium
42+
constMAX_SELENIUM_CONCURRENCY=8;
43+
44+
exportasyncfunctioncreateBrowserWorker(url,browser,options,restarts=0){
45+
if(restarts>MAX_WORKER_RESTARTS){
46+
thrownewError(
47+
`Reached the maximum number of restarts for${chalk.yellow(
48+
getBrowserString(browser)
49+
)}`
50+
);
51+
}
52+
const{ browserstack, debug, headless, reportId, runId, tunnelId, verbose}=options;
53+
while(awaitmaxWorkersReached(options)){
54+
if(verbose){
55+
console.log("\nWaiting for available sessions...");
56+
}
57+
awaitnewPromise((resolve)=>setTimeout(resolve,WORKER_WAIT_TIME));
58+
}
59+
60+
constfullBrowser=getBrowserString(browser);
61+
62+
letworker;
63+
64+
if(browserstack){
65+
worker=awaitcreateWorker({
66+
...browser,
67+
url:encodeURI(url),
68+
project:"jquery",
69+
build:`Run${runId}`,
70+
71+
// This is the maximum timeout allowed
72+
// by BrowserStack. We do this because
73+
// we control the timeout in the runner.
74+
// See https://github.com/browserstack/api/blob/b324a6a5bc1b6052510d74e286b8e1c758c308a7/README.md#timeout300
75+
timeout:1800,
76+
77+
// Not documented in the API docs,
78+
// but required to make local testing work.
79+
// See https://www.browserstack.com/docs/automate/selenium/manage-multiple-connections#nodejs
80+
"browserstack.local":true,
81+
"browserstack.localIdentifier":tunnelId
82+
});
83+
worker.quit=()=>deleteWorker(worker.id);
84+
}elseif(browser.browser==="jsdom"){
85+
constwindow=awaitcreateWindow({ reportId, url, verbose});
86+
worker={
87+
quit:()=>window.close()
88+
};
89+
}else{
90+
constdriver=awaitcreateDriver({
91+
browserName:browser.browser,
92+
headless,
93+
url,
94+
verbose
95+
});
96+
worker={
97+
quit:()=>driver.quit()
98+
};
99+
}
100+
101+
worker.debug=!!debug;
102+
worker.url=url;
103+
worker.browser=browser;
104+
worker.restarts=restarts;
105+
worker.options=options;
106+
touchBrowser(browser);
107+
workers[fullBrowser]=worker;
108+
109+
// Wait for the worker to show up in the list
110+
// before returning it.
111+
returnensureAcknowledged(worker);
112+
}
113+
114+
exportfunctiontouchBrowser(browser){
115+
constfullBrowser=getBrowserString(browser);
116+
constworker=workers[fullBrowser];
117+
if(worker){
118+
worker.lastTouch=Date.now();
119+
}
120+
}
121+
122+
exportasyncfunctionsetBrowserWorkerUrl(browser,url){
123+
constfullBrowser=getBrowserString(browser);
124+
constworker=workers[fullBrowser];
125+
if(worker){
126+
worker.url=url;
127+
}
128+
}
129+
130+
exportasyncfunctionrestartBrowser(browser){
131+
constfullBrowser=getBrowserString(browser);
132+
constworker=workers[fullBrowser];
133+
if(worker){
134+
awaitrestartWorker(worker);
135+
}
136+
}
137+
138+
/**
139+
* Checks that all browsers have received
140+
* a response in the given amount of time.
141+
* If not, the worker is restarted.
142+
*/
143+
exportasyncfunctioncheckLastTouches(){
144+
for(const[fullBrowser,worker]ofObject.entries(workers)){
145+
if(Date.now()-worker.lastTouch>RUN_WORKER_TIMEOUT){
146+
constoptions=worker.options;
147+
if(options.verbose){
148+
console.log(
149+
`\nNo response from${chalk.yellow(fullBrowser)} in${
150+
RUN_WORKER_TIMEOUT/1000/60
151+
}min.`
152+
);
153+
}
154+
awaitrestartWorker(worker);
155+
}
156+
}
157+
}
158+
159+
exportasyncfunctioncleanupAllBrowsers({ verbose}){
160+
constworkersRemaining=Object.values(workers);
161+
constnumRemaining=workersRemaining.length;
162+
if(numRemaining){
163+
try{
164+
awaitPromise.all(workersRemaining.map((worker)=>worker.quit()));
165+
if(verbose){
166+
console.log(
167+
`Stopped${numRemaining} browser${numRemaining>1 ?"s" :""}.`
168+
);
169+
}
170+
}catch(error){
171+
172+
// Log the error, but do not consider the test run failed
173+
console.error(error);
174+
}
175+
}
176+
}
177+
178+
asyncfunctionmaxWorkersReached({
179+
browserstack,
180+
concurrency=MAX_SELENIUM_CONCURRENCY
181+
}){
182+
if(browserstack){
183+
return(awaitgetAvailableSessions())<=0;
184+
}
185+
returnworkers.length>=concurrency;
186+
}
187+
188+
asyncfunctionwaitForAck(worker,{ fullBrowser, verbose}){
189+
deleteworker.lastTouch;
190+
returnnewPromise((resolve,reject)=>{
191+
constinterval=setInterval(()=>{
192+
if(worker.lastTouch){
193+
if(verbose){
194+
console.log(`\n${fullBrowser} acknowledged.`);
195+
}
196+
clearTimeout(timeout);
197+
clearInterval(interval);
198+
resolve();
199+
}
200+
},ACKNOWLEDGE_INTERVAL);
201+
202+
consttimeout=setTimeout(()=>{
203+
clearInterval(interval);
204+
reject(
205+
newError(
206+
`${fullBrowser} not acknowledged after${
207+
ACKNOWLEDGE_TIMEOUT/1000/60
208+
}min.`
209+
)
210+
);
211+
},ACKNOWLEDGE_TIMEOUT);
212+
});
213+
}
214+
215+
asyncfunctionensureAcknowledged(worker){
216+
constfullBrowser=getBrowserString(worker.browser);
217+
constverbose=worker.options.verbose;
218+
try{
219+
awaitwaitForAck(worker,{ fullBrowser, verbose});
220+
returnworker;
221+
}catch(error){
222+
console.error(error.message);
223+
awaitrestartWorker(worker);
224+
}
225+
}
226+
227+
asyncfunctioncleanupWorker(worker,{ verbose}){
228+
for(const[fullBrowser,w]ofObject.entries(workers)){
229+
if(w===worker){
230+
deleteworkers[fullBrowser];
231+
awaitworker.quit();
232+
if(verbose){
233+
console.log(`\nStopped${fullBrowser}.`);
234+
}
235+
return;
236+
}
237+
}
238+
}
239+
240+
asyncfunctionrestartWorker(worker){
241+
awaitcleanupWorker(worker,worker.options);
242+
awaitcreateBrowserWorker(
243+
worker.url,
244+
worker.browser,
245+
worker.options,
246+
worker.restarts+1
247+
);
25248
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp