ui5-test-runner 1.1.5 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -188
- package/index.js +47 -16
- package/package.json +28 -10
- package/src/add-test-pages.js +35 -0
- package/src/add-test-pages.spec.js +95 -0
- package/src/browser.spec.js +724 -0
- package/src/browsers.js +220 -59
- package/src/capabilities/index.js +194 -0
- package/src/capabilities/tests/basic/iframe.html +8 -0
- package/src/capabilities/tests/basic/index.html +12 -0
- package/src/capabilities/tests/basic/index.js +20 -0
- package/src/capabilities/tests/basic/ui5.html +24 -0
- package/src/capabilities/tests/dynamic-include/index.js +21 -0
- package/src/capabilities/tests/dynamic-include/mix.html +11 -0
- package/src/capabilities/tests/dynamic-include/one.html +11 -0
- package/src/capabilities/tests/dynamic-include/post.js +3 -0
- package/src/capabilities/tests/dynamic-include/test.js +1 -0
- package/src/capabilities/tests/dynamic-include/two.html +11 -0
- package/src/capabilities/tests/index.js +16 -0
- package/src/capabilities/tests/local-storage/index.html +16 -0
- package/src/capabilities/tests/local-storage/index.js +21 -0
- package/src/capabilities/tests/screenshot/index.html +13 -0
- package/src/capabilities/tests/screenshot/index.js +18 -0
- package/src/capabilities/tests/scripts/index.js +50 -0
- package/src/capabilities/tests/scripts/qunit.html +22 -0
- package/src/capabilities/tests/scripts/testsuite.html +10 -0
- package/src/capabilities/tests/scripts/testsuite.js +8 -0
- package/src/capabilities/tests/timeout/index.html +21 -0
- package/src/capabilities/tests/timeout/index.js +19 -0
- package/src/capabilities/tests/traces/index.html +18 -0
- package/src/capabilities/tests/traces/index.js +81 -0
- package/src/cors.js +1 -1
- package/src/cors.spec.js +41 -0
- package/src/coverage.js +30 -18
- package/src/coverage.spec.js +79 -0
- package/src/csv-reader.js +36 -0
- package/src/csv-reader.spec.js +42 -0
- package/src/csv-writer.js +52 -0
- package/src/csv-writer.spec.js +77 -0
- package/src/defaults/browser.js +144 -0
- package/src/defaults/jsdom/compatibility.js +95 -0
- package/src/defaults/jsdom/debug.js +23 -0
- package/src/defaults/jsdom/resource-loader.js +43 -0
- package/src/defaults/jsdom/sap.ui.test.matchers.visible.js +39 -0
- package/src/defaults/jsdom.js +64 -0
- package/src/defaults/junit-xml-report.js +64 -0
- package/src/defaults/puppeteer.js +111 -0
- package/src/defaults/report/common.js +38 -0
- package/src/defaults/report/default.html +84 -0
- package/src/defaults/report/main.js +44 -0
- package/src/defaults/report/progress.js +49 -0
- package/src/defaults/report/styles.css +66 -0
- package/src/defaults/report.js +69 -0
- package/src/defaults/selenium-webdriver/chrome.js +38 -0
- package/src/defaults/selenium-webdriver/edge.js +25 -0
- package/src/defaults/selenium-webdriver/firefox.js +31 -0
- package/src/defaults/selenium-webdriver.js +138 -0
- package/src/endpoints.js +70 -124
- package/src/error.js +52 -0
- package/src/error.spec.js +17 -0
- package/src/get-job-progress.js +69 -0
- package/src/get-job-progress.spec.js +175 -0
- package/src/inject/post.js +96 -0
- package/src/inject/post.spec.js +147 -0
- package/src/inject/qunit-hooks.js +6 -21
- package/src/inject/qunit-intercept.js +30 -0
- package/src/inject/qunit-redirect.js +15 -7
- package/src/job-mode.js +45 -0
- package/src/job.js +254 -108
- package/src/job.spec.js +413 -0
- package/src/npm.js +73 -0
- package/src/npm.spec.js +98 -0
- package/src/options.js +73 -0
- package/src/options.spec.js +125 -0
- package/src/output.js +450 -131
- package/src/qunit-hooks.js +116 -0
- package/src/qunit-hooks.spec.js +687 -0
- package/src/report.js +42 -0
- package/src/reserve.js +3 -4
- package/src/simulate.spec.js +437 -0
- package/src/symbols.js +8 -0
- package/src/tests.js +127 -84
- package/src/timeout.spec.js +39 -0
- package/src/tools.js +111 -4
- package/src/tools.spec.js +90 -0
- package/src/ui5.js +3 -3
- package/src/unhandled.js +6 -6
- package/src/unhandled.spec.js +63 -0
- package/defaults/chromium.js +0 -62
- package/src/progress.html +0 -71
- package/src/proxies.js +0 -8
- package/src/report.html +0 -202
- /package/{defaults → src/defaults}/nyc.json +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<title>ui5-test-runner</title>
|
|
4
|
+
<link rel="stylesheet" href="/_/report/styles.css">
|
|
5
|
+
<script src="/_/punyexpr.js"></script>
|
|
6
|
+
<script src="/_/punybind.js"></script>
|
|
7
|
+
<script src="/_/report/common.js"></script>
|
|
8
|
+
<script src="/_/report/main.js"></script>
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div {{if}}="!(qunitPage || qunitTest)">
|
|
12
|
+
<h1>{{ status || 'Test report' }}</h1>
|
|
13
|
+
<div {{if}}="end === undefined" class="elapsed">In progress since {{ elapsed(start) }}</div>
|
|
14
|
+
<div {{else}} class="elapsed">Duration : {{ elapsed(start, end) }}</div>
|
|
15
|
+
<table style="visibility: {{ testPageUrls.length > 0 ? 'visible' : 'hidden' }};">
|
|
16
|
+
<tr>
|
|
17
|
+
<th> </th>
|
|
18
|
+
<th class="status" style="width: 10rem;"><div><span>Status</span></div></th>
|
|
19
|
+
<th class="count">Tests</th>
|
|
20
|
+
<th class="count">Passed</th>
|
|
21
|
+
<th class="count">Failed</th>
|
|
22
|
+
<th class="elapsed">Elapsed</th>
|
|
23
|
+
</tr>
|
|
24
|
+
<tr {{for}}="url of testPageUrls">
|
|
25
|
+
<td class="truncated">
|
|
26
|
+
<span {{if}}="qunitPages === undefined || !qunitPages[url]">{{ url }}</span>
|
|
27
|
+
<a {{else}} href="#{{ qunitPages[url].id }}">{{ url }}</a>
|
|
28
|
+
</td>
|
|
29
|
+
<td>
|
|
30
|
+
<span {{if}}="!qunitPages[url]">-</span>
|
|
31
|
+
<span {{elseif}}="qunitPages[url].failed">❌</span>
|
|
32
|
+
<span {{elseif}}="qunitPages[url].end">✔️</span>
|
|
33
|
+
<span {{if}}="!qunitPages[url].end">
|
|
34
|
+
<progress max="{{ qunitPages[url].count }}" value="{{ qunitPages[url].failed + qunitPages[url].passed }}"></progress>
|
|
35
|
+
</span>
|
|
36
|
+
</td>
|
|
37
|
+
<td>{{ qunitPages[url] ? qunitPages[url].count : '-' }}</td>
|
|
38
|
+
<td>{{ qunitPages[url] ? qunitPages[url].passed : '-' }}</td>
|
|
39
|
+
<td>{{ qunitPages[url] ? qunitPages[url].failed : '-' }}</td>
|
|
40
|
+
<td>
|
|
41
|
+
<span {{if}}="!qunitPages[url]">-</span>
|
|
42
|
+
<span {{elseif}}="qunitPages[url].end === undefined">{{ elapsed(qunitPages[url].start) }}</span>
|
|
43
|
+
<span {{else}}>{{ elapsed(qunitPages[url].start, qunitPages[url].end) }}</span>
|
|
44
|
+
</td>
|
|
45
|
+
</tr>
|
|
46
|
+
</table>
|
|
47
|
+
</div>
|
|
48
|
+
<div {{if}}="qunitPage">
|
|
49
|
+
<h1 class="truncated">{{ qunitPage.url }}</h1>
|
|
50
|
+
<a href="#">⏴ back to report</a>
|
|
51
|
+
<div {{if}}="qunitPage.end === undefined" class="elapsed">In progress since {{ elapsed(qunitPage.start) }}</div>
|
|
52
|
+
<div {{else}} class="elapsed">Duration : {{ elapsed(qunitPage.start, qunitPage.end) }}</div>
|
|
53
|
+
<div {{for}}="module of qunitPage.modules">
|
|
54
|
+
<h2>{{ module.name }}</h2>
|
|
55
|
+
<div {{for}}="test of module.tests">
|
|
56
|
+
<a {{if}}="!test.skip" href="#{{ qunitPage.id }}-{{ test.testId }}">{{ test.name }}</a>
|
|
57
|
+
<span {{else}}>{{ test.name }}</span>
|
|
58
|
+
<span {{if}}="test.skip">⏸️</span>
|
|
59
|
+
<span {{elseif}}="!test.end" class="elapsed">{{ elapsed(test.start) }}</span>
|
|
60
|
+
<span {{elseif}}="test.report && !test.report.failed">✔️ {{ elapsed(test.start, test.end) }}</span>
|
|
61
|
+
<span {{elseif}}="test.report">❌ {{ elapsed(test.start, test.end) }}</span>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
<div {{elseif}}="qunitTest">
|
|
66
|
+
<h1 class="truncated">{{ qunitTest.url }}</h1>
|
|
67
|
+
<a href="#">⏴ back to report</a>
|
|
68
|
+
<h2>{{ qunitTest.module }}</h2>
|
|
69
|
+
<a href="#{{ qunitTest.pageId }}">⏴ back to page</a>
|
|
70
|
+
<h3>{{ qunitTest.name }}
|
|
71
|
+
<span {{if}}="qunitTest.report && qunitTest.report.passed">✔️</span>
|
|
72
|
+
<span {{elseif}}="qunitTest.report">❌</span>
|
|
73
|
+
</h3>
|
|
74
|
+
<div {{if}}="qunitTest.end === undefined" class="elapsed">In progress since {{ elapsed(qunitTest.start) }}</div>
|
|
75
|
+
<div {{else}} class="elapsed">Duration : {{ elapsed(qunitTest.start, qunitTest.end) }}</div>
|
|
76
|
+
<div {{for}}="log of qunitTest.logs">
|
|
77
|
+
<pre {{if}}="log.result">✔️ {{ log.message }}</pre>
|
|
78
|
+
<pre {{else}}>❌ {{ log.message }}</pre>
|
|
79
|
+
<img {{if}}="log.screenshot" loading="lazy" class="log" src="{{ qunitTest.pageId }}/{{ log.screenshot }}" alt="Copy folder '{{ qunitTest.pageId }}' from the job report">
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
<div style="display: {{ disconnected ? 'block' : 'none' }};">❌ Disconnected</div>
|
|
83
|
+
</body>
|
|
84
|
+
</html>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* global report, job */
|
|
2
|
+
report.ready.then(update => {
|
|
3
|
+
const hashChange = () => {
|
|
4
|
+
const [, pageId, testId] = location.hash.match(/#?([^-]*)(?:-(.*))?/)
|
|
5
|
+
let [qunitPage, qunitTest] = [null, null]
|
|
6
|
+
if (pageId) {
|
|
7
|
+
const url = Object.keys(job.qunitPages).find(pageUrl => job.qunitPages[pageUrl].id === pageId)
|
|
8
|
+
if (!url) {
|
|
9
|
+
return
|
|
10
|
+
}
|
|
11
|
+
qunitPage = { url, ...job.qunitPages[url] }
|
|
12
|
+
if (testId) {
|
|
13
|
+
let test
|
|
14
|
+
let moduleName
|
|
15
|
+
qunitPage.modules.every(module => module.tests.every(candidate => {
|
|
16
|
+
if (candidate.testId === testId) {
|
|
17
|
+
moduleName = module.name
|
|
18
|
+
test = candidate
|
|
19
|
+
return false
|
|
20
|
+
}
|
|
21
|
+
return true
|
|
22
|
+
}))
|
|
23
|
+
qunitPage = null
|
|
24
|
+
if (test) {
|
|
25
|
+
qunitTest = {
|
|
26
|
+
url,
|
|
27
|
+
pageId,
|
|
28
|
+
module: moduleName,
|
|
29
|
+
...test
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
update({
|
|
35
|
+
...job,
|
|
36
|
+
qunitPage,
|
|
37
|
+
qunitTest,
|
|
38
|
+
elapsed: report.elapsed
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
window.addEventListener('hashchange', hashChange)
|
|
43
|
+
hashChange()
|
|
44
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
/* global report */
|
|
3
|
+
|
|
4
|
+
report.ready.then(update => {
|
|
5
|
+
let lastState = {}
|
|
6
|
+
|
|
7
|
+
async function refresh () {
|
|
8
|
+
const [, page, test] = location.hash.match(/#?([^-]*)(?:-(.*))?/)
|
|
9
|
+
let url = '/_/progress'
|
|
10
|
+
if (page) {
|
|
11
|
+
url += `?page=${page}`
|
|
12
|
+
if (test) {
|
|
13
|
+
url += `&test=${test}`
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
let json
|
|
17
|
+
try {
|
|
18
|
+
const response = await fetch(url)
|
|
19
|
+
json = await response.json()
|
|
20
|
+
} catch (e) {
|
|
21
|
+
update({
|
|
22
|
+
...lastState,
|
|
23
|
+
disconnected: true
|
|
24
|
+
})
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
if (test) {
|
|
28
|
+
lastState = {
|
|
29
|
+
qunitTest: json
|
|
30
|
+
}
|
|
31
|
+
} else if (page) {
|
|
32
|
+
lastState = {
|
|
33
|
+
qunitPage: json
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
lastState = {
|
|
37
|
+
...json
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
update({
|
|
41
|
+
...lastState,
|
|
42
|
+
disconnected: false,
|
|
43
|
+
elapsed: report.elapsed
|
|
44
|
+
})
|
|
45
|
+
setTimeout(refresh, 250)
|
|
46
|
+
}
|
|
47
|
+
refresh()
|
|
48
|
+
})
|
|
49
|
+
}())
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
body {
|
|
2
|
+
font-family: "Segoe UI", Arial, sans-serif;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
h1 {
|
|
6
|
+
margin-bottom: 0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
h2 {
|
|
10
|
+
margin-bottom: 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
h3 {
|
|
14
|
+
margin-bottom: 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
progress {
|
|
18
|
+
width: 5rem;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
th {
|
|
22
|
+
text-align: left;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
th.count {
|
|
26
|
+
width: 5rem;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
th.elapsed {
|
|
30
|
+
width: 6rem;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
th.status {
|
|
34
|
+
width: 10rem;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
a, a:hover {
|
|
38
|
+
color: black;
|
|
39
|
+
text-decoration: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
a:hover {
|
|
43
|
+
text-decoration: underline;
|
|
44
|
+
text-decoration-style: dotted;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
table {
|
|
48
|
+
table-layout: fixed;
|
|
49
|
+
width: 100%;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.truncated {
|
|
53
|
+
overflow: hidden;
|
|
54
|
+
text-overflow: ellipsis;
|
|
55
|
+
white-space: nowrap;
|
|
56
|
+
direction: rtl;
|
|
57
|
+
text-align: left;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
img.log {
|
|
61
|
+
width: 50%;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
img.log:hover {
|
|
65
|
+
width: unset;
|
|
66
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { join } = require('path')
|
|
4
|
+
const { readFile, writeFile } = require('fs').promises
|
|
5
|
+
const [,, reportDir] = process.argv
|
|
6
|
+
|
|
7
|
+
const defaultDir = join(__dirname, 'report')
|
|
8
|
+
|
|
9
|
+
async function readDefault (name) {
|
|
10
|
+
return (await readFile(join(defaultDir, name))).toString()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function readDependency (name) {
|
|
14
|
+
return (await readFile(join(__dirname, '../../node_modules', name, 'dist', `${name}.js`))).toString()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function minifyJs (src) {
|
|
18
|
+
return src
|
|
19
|
+
.replace(/\/\*.*\*\//g, '')
|
|
20
|
+
.replace(/\{\r?\n\s*/g, '{')
|
|
21
|
+
.replace(/\r?\n\s*\}/g, '}')
|
|
22
|
+
.replace(/,?\r?\n\s*\.?/g, match => {
|
|
23
|
+
let result = ''
|
|
24
|
+
if (match.startsWith(',')) {
|
|
25
|
+
result = ','
|
|
26
|
+
}
|
|
27
|
+
if (match.endsWith('.')) {
|
|
28
|
+
result += '.'
|
|
29
|
+
}
|
|
30
|
+
return result || ';'
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function main () {
|
|
35
|
+
const html = await readDefault('default.html')
|
|
36
|
+
const styles = (await readDefault('styles.css'))
|
|
37
|
+
.replace(/\{\r?\n\s+/g, '{')
|
|
38
|
+
.replace(/\}(\r?\n)+/g, '} ')
|
|
39
|
+
.replace(/;\r?\n\s*/g, ';')
|
|
40
|
+
.replace(/(:|,)\s*/g, (_, c) => c)
|
|
41
|
+
|
|
42
|
+
const punyexpr = await readDependency('punyexpr')
|
|
43
|
+
const punybind = await readDependency('punybind')
|
|
44
|
+
const common = minifyJs(await readDefault('common.js'))
|
|
45
|
+
const main = minifyJs(await readDefault('main.js'))
|
|
46
|
+
|
|
47
|
+
const job = (await readFile(join(reportDir, 'job.js'))).toString()
|
|
48
|
+
.replace(/(\{|,|\[)\r?\n\s*/g, (_, c) => c)
|
|
49
|
+
.replace(/\r?\n\s*(\}|\])/g, (_, c) => c)
|
|
50
|
+
.replace(/": "/g, '":"')
|
|
51
|
+
|
|
52
|
+
return await writeFile(join(reportDir, 'report.html'), html
|
|
53
|
+
.replace(/(>|\}\})\r?\n\s*</g, (_, c) => `${c}<`)
|
|
54
|
+
.replace('<link rel="stylesheet" href="/_/report/styles.css">', `<style>${styles}</style>`)
|
|
55
|
+
.replace('<script src="/_/punyexpr.js"></script>', `<script>${punyexpr}</script>`)
|
|
56
|
+
.replace('<script src="/_/punybind.js"></script>', `<script>${punybind}</script>`)
|
|
57
|
+
.replace('<script src="/_/report/common.js"></script>', `<script>${common}</script>`)
|
|
58
|
+
.replace('<script src="/_/report/main.js"></script>', `<script>const module={};${job};const job=module.exports;${main}</script>`)
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
main()
|
|
63
|
+
.catch(reason => {
|
|
64
|
+
console.error(reason)
|
|
65
|
+
return -1
|
|
66
|
+
})
|
|
67
|
+
.then((code = 0) => {
|
|
68
|
+
process.exit(code)
|
|
69
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const { join } = require('path')
|
|
2
|
+
|
|
3
|
+
module.exports = async ({
|
|
4
|
+
seleniumWebdriver,
|
|
5
|
+
settings,
|
|
6
|
+
options,
|
|
7
|
+
loggingPreferences
|
|
8
|
+
}) => {
|
|
9
|
+
const { Browser, Builder } = seleniumWebdriver
|
|
10
|
+
const chrome = require(join(settings.modules['selenium-webdriver'], 'chrome'))
|
|
11
|
+
|
|
12
|
+
const chromeOptions = new chrome.Options()
|
|
13
|
+
chromeOptions.excludeSwitches('enable-logging')
|
|
14
|
+
if (!options.visible) {
|
|
15
|
+
chromeOptions.addArguments('headless')
|
|
16
|
+
}
|
|
17
|
+
chromeOptions.addArguments('start-maximized')
|
|
18
|
+
chromeOptions.addArguments('disable-extensions')
|
|
19
|
+
chromeOptions.setLoggingPrefs(loggingPreferences)
|
|
20
|
+
if (options.binary) {
|
|
21
|
+
chromeOptions.setBinary(options.binary)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const builder = new Builder()
|
|
25
|
+
.forBrowser(Browser.CHROME)
|
|
26
|
+
.setChromeOptions(chromeOptions)
|
|
27
|
+
|
|
28
|
+
if (options.server) {
|
|
29
|
+
builder.usingServer(options.server)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const driver = await builder.build()
|
|
33
|
+
driver.__console__ = true
|
|
34
|
+
driver.__addScript__ = async function (source) {
|
|
35
|
+
return await driver.sendDevToolsCommand('Page.addScriptToEvaluateOnNewDocument', { source })
|
|
36
|
+
}
|
|
37
|
+
return driver
|
|
38
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const { join } = require('path')
|
|
2
|
+
|
|
3
|
+
module.exports = async ({
|
|
4
|
+
seleniumWebdriver,
|
|
5
|
+
settings,
|
|
6
|
+
options,
|
|
7
|
+
loggingPreferences,
|
|
8
|
+
$capabilities
|
|
9
|
+
}) => {
|
|
10
|
+
const { Browser, Builder } = seleniumWebdriver
|
|
11
|
+
const edge = require(join(settings.modules['selenium-webdriver'], 'edge'))
|
|
12
|
+
|
|
13
|
+
const edgeOptions = new edge.Options()
|
|
14
|
+
edgeOptions.setLoggingPrefs(loggingPreferences)
|
|
15
|
+
|
|
16
|
+
const builder = new Builder()
|
|
17
|
+
.forBrowser(Browser.EDGE)
|
|
18
|
+
.setEdgeOptions(edgeOptions)
|
|
19
|
+
|
|
20
|
+
if (options.server) {
|
|
21
|
+
builder.usingServer(options.server)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return await builder.build()
|
|
25
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const { join } = require('path')
|
|
2
|
+
|
|
3
|
+
module.exports = async ({
|
|
4
|
+
seleniumWebdriver,
|
|
5
|
+
settings,
|
|
6
|
+
options,
|
|
7
|
+
loggingPreferences,
|
|
8
|
+
$capabilities
|
|
9
|
+
}) => {
|
|
10
|
+
const { Browser, Builder } = seleniumWebdriver
|
|
11
|
+
const firefox = require(join(settings.modules['selenium-webdriver'], 'firefox'))
|
|
12
|
+
|
|
13
|
+
const firefoxOptions = new firefox.Options()
|
|
14
|
+
if (!options.visible) {
|
|
15
|
+
firefoxOptions.headless = true
|
|
16
|
+
}
|
|
17
|
+
firefoxOptions.setLoggingPrefs(loggingPreferences)
|
|
18
|
+
if (options.binary) {
|
|
19
|
+
firefoxOptions.setBinary(options.binary)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const builder = new Builder()
|
|
23
|
+
.forBrowser(Browser.FIREFOX)
|
|
24
|
+
.setFirefoxOptions(firefoxOptions)
|
|
25
|
+
|
|
26
|
+
if (options.server) {
|
|
27
|
+
builder.usingServer(options.server)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return await builder.build()
|
|
31
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { InvalidArgumentError } = require('commander')
|
|
4
|
+
const { url } = require('../options')
|
|
5
|
+
const { writeFile } = require('fs/promises')
|
|
6
|
+
|
|
7
|
+
let logging
|
|
8
|
+
let driver
|
|
9
|
+
|
|
10
|
+
function browser (value, defaultValue) {
|
|
11
|
+
if (value === undefined) {
|
|
12
|
+
return 'chrome'
|
|
13
|
+
}
|
|
14
|
+
if (!['chrome', 'firefox', 'edge'].includes(value)) {
|
|
15
|
+
throw new InvalidArgumentError('Browser name')
|
|
16
|
+
}
|
|
17
|
+
return value
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function buildDriver (settings, options) {
|
|
21
|
+
const seleniumWebdriver = require(settings.modules['selenium-webdriver'])
|
|
22
|
+
|
|
23
|
+
logging = seleniumWebdriver.logging
|
|
24
|
+
logging.getLogger(logging.Type.BROWSER).setLevel(logging.Level.ALL)
|
|
25
|
+
|
|
26
|
+
const loggingPreferences = new logging.Preferences()
|
|
27
|
+
loggingPreferences.setLevel(logging.Type.BROWSER, logging.Level.ALL)
|
|
28
|
+
|
|
29
|
+
driver = await require('./selenium-webdriver/' + options.browser)({
|
|
30
|
+
seleniumWebdriver,
|
|
31
|
+
settings,
|
|
32
|
+
options,
|
|
33
|
+
loggingPreferences
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
require('./browser')({
|
|
38
|
+
metadata: {
|
|
39
|
+
name: 'selenium-webdriver',
|
|
40
|
+
options: [
|
|
41
|
+
['-b, --browser <name>', 'Browser driver', browser, 'chrome'],
|
|
42
|
+
['--visible [flag]', 'Show the browser', false],
|
|
43
|
+
['-s, --server <server>', 'Selenium server URL', url],
|
|
44
|
+
['--binary <binary>', 'Binary path']
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
async capabilities ({ settings, options }) {
|
|
49
|
+
const capabilities = {
|
|
50
|
+
modules: ['selenium-webdriver'],
|
|
51
|
+
screenshot: '.png',
|
|
52
|
+
scripts: false,
|
|
53
|
+
traces: []
|
|
54
|
+
}
|
|
55
|
+
if (!settings.modules) {
|
|
56
|
+
return {
|
|
57
|
+
...capabilities,
|
|
58
|
+
'probe-with-modules': true
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
await buildDriver(settings, options)
|
|
62
|
+
if (driver.__console__) {
|
|
63
|
+
capabilities.traces.push('console')
|
|
64
|
+
}
|
|
65
|
+
if (driver.__network__) {
|
|
66
|
+
capabilities.traces.push('network')
|
|
67
|
+
}
|
|
68
|
+
if (driver.__addScript__) {
|
|
69
|
+
capabilities.scripts = true
|
|
70
|
+
}
|
|
71
|
+
return capabilities
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
async screenshot ({ filename }) {
|
|
75
|
+
if (driver) {
|
|
76
|
+
const data = await driver.takeScreenshot()
|
|
77
|
+
await writeFile(filename, data.replace(/^data:image\/png;base64,/, ''), {
|
|
78
|
+
encoding: 'base64'
|
|
79
|
+
})
|
|
80
|
+
return true
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
async flush ({
|
|
85
|
+
settings,
|
|
86
|
+
consoleWriter
|
|
87
|
+
}) {
|
|
88
|
+
if (driver && settings.capabilities.traces.includes('console')) {
|
|
89
|
+
const logs = await driver.manage().logs().get(logging.Type.BROWSER)
|
|
90
|
+
const logLevelMapping = {
|
|
91
|
+
INFO: 'log',
|
|
92
|
+
WARNING: 'warning',
|
|
93
|
+
SEVERE: 'error'
|
|
94
|
+
}
|
|
95
|
+
if (logs.length) {
|
|
96
|
+
consoleWriter.append(logs.map(({ timestamp, message, level }) => {
|
|
97
|
+
return {
|
|
98
|
+
timestamp,
|
|
99
|
+
type: logLevelMapping[level.toString()],
|
|
100
|
+
text: message
|
|
101
|
+
}
|
|
102
|
+
}))
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
async beforeExit () {
|
|
108
|
+
if (driver) {
|
|
109
|
+
await driver.quit()
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
async run ({
|
|
114
|
+
settings,
|
|
115
|
+
options
|
|
116
|
+
}) {
|
|
117
|
+
await buildDriver(settings, options)
|
|
118
|
+
|
|
119
|
+
const { url, scripts } = settings
|
|
120
|
+
|
|
121
|
+
if (scripts && scripts.length) {
|
|
122
|
+
for await (const script of scripts) {
|
|
123
|
+
await driver.__addScript__(script)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
await driver.get(url)
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
async error ({ error: e }) {
|
|
131
|
+
if (e.name === 'SessionNotCreatedError') {
|
|
132
|
+
console.error(e.message)
|
|
133
|
+
} else {
|
|
134
|
+
console.error(e)
|
|
135
|
+
}
|
|
136
|
+
console.error('Please check https://www.npmjs.com/package/selenium-webdriver#installation for browser driver')
|
|
137
|
+
}
|
|
138
|
+
})
|