presidium 3.0.3 → 3.2.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/GoogleChromeDevTools.js +98 -10
- package/{internal/GoogleChromeForTesting.js → GoogleChromeForTesting.js} +99 -19
- package/README.md +44 -14
- package/index.js +1 -0
- package/package.json +3 -2
- package/internal/GoogleChromeForTesting.test.js +0 -50
- package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69977DD3-9B6F.pma +0 -0
- package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69977DD4-9B86.pma +0 -0
- package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69978250-A191.pma +0 -0
- package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69978251-A1AD.pma +0 -0
- package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69978277-A1FA.pma +0 -0
- package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69978278-A209.pma +0 -0
- package/internal/tmp/chrome/ChromeFeatureState +0 -1
- package/internal/tmp/chrome/Default/Affiliation Database +0 -0
- package/internal/tmp/chrome/Default/Affiliation Database-journal +0 -0
- package/internal/tmp/chrome/Default/ClientCertificates/LOCK +0 -0
- package/internal/tmp/chrome/Default/ClientCertificates/LOG +0 -0
- package/internal/tmp/chrome/Default/ClientCertificates/LOG.old +0 -0
- package/internal/tmp/chrome/Default/Extension Rules/000003.log +0 -0
- package/internal/tmp/chrome/Default/Extension Rules/CURRENT +0 -1
- package/internal/tmp/chrome/Default/Extension Rules/LOCK +0 -0
- package/internal/tmp/chrome/Default/Extension Rules/LOG +0 -3
- package/internal/tmp/chrome/Default/Extension Rules/LOG.old +0 -3
- package/internal/tmp/chrome/Default/Extension Rules/MANIFEST-000001 +0 -0
- package/internal/tmp/chrome/Default/Extension Scripts/000003.log +0 -0
- package/internal/tmp/chrome/Default/Extension Scripts/CURRENT +0 -1
- package/internal/tmp/chrome/Default/Extension Scripts/LOCK +0 -0
- package/internal/tmp/chrome/Default/Extension Scripts/LOG +0 -3
- package/internal/tmp/chrome/Default/Extension Scripts/LOG.old +0 -3
- package/internal/tmp/chrome/Default/Extension Scripts/MANIFEST-000001 +0 -0
- package/internal/tmp/chrome/Default/Favicons +0 -0
- package/internal/tmp/chrome/Default/Favicons-journal +0 -0
- package/internal/tmp/chrome/Default/History +0 -0
- package/internal/tmp/chrome/Default/History-journal +0 -0
- package/internal/tmp/chrome/Default/LOCK +0 -0
- package/internal/tmp/chrome/Default/LOG +0 -0
- package/internal/tmp/chrome/Default/LOG.old +0 -0
- package/internal/tmp/chrome/Default/Local Storage/leveldb/000003.log +0 -0
- package/internal/tmp/chrome/Default/Local Storage/leveldb/CURRENT +0 -1
- package/internal/tmp/chrome/Default/Local Storage/leveldb/LOCK +0 -0
- package/internal/tmp/chrome/Default/Local Storage/leveldb/LOG +0 -2
- package/internal/tmp/chrome/Default/Local Storage/leveldb/MANIFEST-000001 +0 -0
- package/internal/tmp/chrome/Default/PersistentOriginTrials/LOCK +0 -0
- package/internal/tmp/chrome/Default/PersistentOriginTrials/LOG +0 -0
- package/internal/tmp/chrome/Default/PersistentOriginTrials/LOG.old +0 -0
- package/internal/tmp/chrome/Default/README +0 -1
- package/internal/tmp/chrome/Default/Segmentation Platform/SegmentInfoDB/LOCK +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SegmentInfoDB/LOG +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SegmentInfoDB/LOG.old +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SignalDB/LOCK +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SignalDB/LOG +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SignalDB/LOG.old +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SignalStorageConfigDB/LOCK +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SignalStorageConfigDB/LOG +0 -0
- package/internal/tmp/chrome/Default/Segmentation Platform/SignalStorageConfigDB/LOG.old +0 -0
- package/internal/tmp/chrome/Default/ServerCertificate +0 -0
- package/internal/tmp/chrome/Default/ServerCertificate-journal +0 -0
- package/internal/tmp/chrome/Default/Site Characteristics Database/000003.log +0 -0
- package/internal/tmp/chrome/Default/Site Characteristics Database/CURRENT +0 -1
- package/internal/tmp/chrome/Default/Site Characteristics Database/LOCK +0 -0
- package/internal/tmp/chrome/Default/Site Characteristics Database/LOG +0 -3
- package/internal/tmp/chrome/Default/Site Characteristics Database/LOG.old +0 -3
- package/internal/tmp/chrome/Default/Site Characteristics Database/MANIFEST-000001 +0 -0
- package/internal/tmp/chrome/Default/Sync Data/LevelDB/000003.log +0 -0
- package/internal/tmp/chrome/Default/Sync Data/LevelDB/CURRENT +0 -1
- package/internal/tmp/chrome/Default/Sync Data/LevelDB/LOCK +0 -0
- package/internal/tmp/chrome/Default/Sync Data/LevelDB/LOG +0 -3
- package/internal/tmp/chrome/Default/Sync Data/LevelDB/LOG.old +0 -3
- package/internal/tmp/chrome/Default/Sync Data/LevelDB/MANIFEST-000001 +0 -0
- package/internal/tmp/chrome/Default/chrome_cart_db/LOCK +0 -0
- package/internal/tmp/chrome/Default/chrome_cart_db/LOG +0 -0
- package/internal/tmp/chrome/Default/chrome_cart_db/LOG.old +0 -0
- package/internal/tmp/chrome/Default/commerce_subscription_db/LOCK +0 -0
- package/internal/tmp/chrome/Default/commerce_subscription_db/LOG +0 -0
- package/internal/tmp/chrome/Default/commerce_subscription_db/LOG.old +0 -0
- package/internal/tmp/chrome/Default/discount_infos_db/LOCK +0 -0
- package/internal/tmp/chrome/Default/discount_infos_db/LOG +0 -0
- package/internal/tmp/chrome/Default/discount_infos_db/LOG.old +0 -0
- package/internal/tmp/chrome/Default/discounts_db/LOCK +0 -0
- package/internal/tmp/chrome/Default/discounts_db/LOG +0 -0
- package/internal/tmp/chrome/Default/discounts_db/LOG.old +0 -0
- package/internal/tmp/chrome/Default/parcel_tracking_db/LOCK +0 -0
- package/internal/tmp/chrome/Default/parcel_tracking_db/LOG +0 -0
- package/internal/tmp/chrome/Default/parcel_tracking_db/LOG.old +0 -0
- package/internal/tmp/chrome/Default/power_bookmarks/PowerBookmarks.db +0 -0
- package/internal/tmp/chrome/Default/power_bookmarks/PowerBookmarks.db-journal +0 -0
- package/internal/tmp/chrome/First Run +0 -0
- package/internal/tmp/chrome/Last Version +0 -1
- package/internal/tmp/chrome/Local State +0 -1
- package/internal/tmp/chrome/ShaderCache/data_0 +0 -0
- package/internal/tmp/chrome/ShaderCache/data_1 +0 -0
- package/internal/tmp/chrome/ShaderCache/data_2 +0 -0
- package/internal/tmp/chrome/ShaderCache/data_3 +0 -0
- package/internal/tmp/chrome/ShaderCache/index +0 -0
- package/internal/tmp/chrome/Variations +0 -1
- package/internal/tmp/chrome/segmentation_platform/ukm_db +0 -0
- package/internal/tmp/chrome/segmentation_platform/ukm_db-wal +0 -0
package/GoogleChromeDevTools.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const EventEmitter = require('events')
|
|
2
|
-
const GoogleChromeForTesting = require('./
|
|
2
|
+
const GoogleChromeForTesting = require('./GoogleChromeForTesting')
|
|
3
3
|
const WebSocket = require('./WebSocket')
|
|
4
4
|
|
|
5
5
|
let id = 0
|
|
@@ -743,13 +743,40 @@ class GoogleChromeDevToolsRuntime {
|
|
|
743
743
|
*
|
|
744
744
|
* @docs
|
|
745
745
|
* ```coffeescript [specscript]
|
|
746
|
-
* new GoogleChromeDevTools(
|
|
746
|
+
* new GoogleChromeDevTools(
|
|
747
|
+
* googleChromeForTesting GoogleChromeForTesting
|
|
748
|
+
* ) -> googleChromeDevTools GoogleChromeDevTools
|
|
749
|
+
*
|
|
750
|
+
* new GoogleChromeDevTools(options {
|
|
751
|
+
* chromeVersion: 'stable'|'beta'|'dev'|'canary'|string,
|
|
752
|
+
* chromeDir: string,
|
|
753
|
+
* remoteDebuggingPort: number,
|
|
754
|
+
* headless: boolean,
|
|
755
|
+
* userDataDir: string,
|
|
756
|
+
* useMockKeychain: boolean,
|
|
757
|
+
* }) -> googleChromeDevTools GoogleChromeDevTools
|
|
747
758
|
* ```
|
|
748
759
|
*
|
|
749
760
|
* Presidium GoogleChromeDevTools client for test automation.
|
|
750
761
|
*
|
|
762
|
+
* Arguments:
|
|
763
|
+
* * `googleChromeForTesting` - an instance of a Presidium [GoogleChromeForTesting](/docs/GoogleChromeForTesting) client.
|
|
764
|
+
* * `options`
|
|
765
|
+
* * `chromeVersion` - the version of Google Chrome for Testing to download. Defaults to `'stable'`.
|
|
766
|
+
* * `chromeDir` - the directory that Google Chrome for Testing will install to. Defaults to ``google-chrome-for-testing'`.
|
|
767
|
+
* * `remoteDebuggingPort` - the port that the Chrome DevTools Protocol server will listen on. Defaults to `9222`
|
|
768
|
+
* * `headless` - whether to run Google Chrome for Testing in headless mode. Defaults to `false`.
|
|
769
|
+
* * `userDataDir` - directory for storing user profile data such as history, bookmarks, cookies, and settings. Defaults to `tmp/chrome`.
|
|
770
|
+
* * `useMockKeychain` - whether to use a mock keychain instead of the system's real security keychain. Defaults to `true`.
|
|
771
|
+
*
|
|
772
|
+
* Returns:
|
|
773
|
+
* * `googleChromeDevTools` - an instance of the Presidium GoogleChromeDevTools client.
|
|
774
|
+
*
|
|
751
775
|
* ```javascript
|
|
752
|
-
* const
|
|
776
|
+
* const googleChromeForTesting = new GoogleChromeForTesting()
|
|
777
|
+
* await googleChromeForTesting.init()
|
|
778
|
+
*
|
|
779
|
+
* const googleChromeDevTools = new GoogleChromeDevTools(googleChromeForTesting)
|
|
753
780
|
* await googleChromeDevTools.init()
|
|
754
781
|
*
|
|
755
782
|
* const target = await googleChromeDevTools.Target.getTargets()
|
|
@@ -791,7 +818,10 @@ class GoogleChromeDevToolsRuntime {
|
|
|
791
818
|
* Every Chrome DevTools Protocol client needs to first attach to the target using the `Target.attachToTarget` command. The command will establish a protocol session with the given target and return a `sessionId`. The returned `sessionId` should be set on the `GoogleChromeDevTools` client using [`setSessionId`](#setSessionId) or included in every message to the DevTools server.
|
|
792
819
|
*
|
|
793
820
|
* ```javascript
|
|
794
|
-
* const
|
|
821
|
+
* const googleChromeForTesting = new GoogleChromeForTesting()
|
|
822
|
+
* await googleChromeForTesting.init()
|
|
823
|
+
*
|
|
824
|
+
* const googleChromeDevTools = new GoogleChromeDevTools(googleChromeForTesting)
|
|
795
825
|
* await googleChromeDevTools.init()
|
|
796
826
|
*
|
|
797
827
|
* // get targets
|
|
@@ -815,12 +845,43 @@ class GoogleChromeDevToolsRuntime {
|
|
|
815
845
|
* References:
|
|
816
846
|
* * [Getting Started with the Chrome Devtools Protocol](https://github.com/aslushnikov/getting-started-with-cdp/blob/master/README.md)
|
|
817
847
|
* * [Chrome Devtools Protocol](https://chromedevtools.github.io/devtools-protocol/)
|
|
848
|
+
*
|
|
849
|
+
* Supported platforms:
|
|
850
|
+
* * `mac-arm64`
|
|
851
|
+
* * `linux64`
|
|
852
|
+
*
|
|
853
|
+
* ## Further Installation
|
|
854
|
+
* Some further installation may be required for Linux platforms.
|
|
855
|
+
*
|
|
856
|
+
* ### Install headless dependencies for Amazon Linux 2023
|
|
857
|
+
* ```sh
|
|
858
|
+
* sudo dnf install -y cairo pango nss nspr atk at-spi2-atk cups-libs libdrm libxkbcommon libXcomposite libXdamage libXfixes libXrandr mesa-libgbm alsa-lib
|
|
859
|
+
* ```
|
|
860
|
+
*
|
|
861
|
+
* ### Install headless dependencies for Ubuntu
|
|
862
|
+
* ```sh
|
|
863
|
+
* sudo apt-get update && sudo apt-get install -y libcairo2 libpango-1.0-0 libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libatspi2.0-0 libcups2 libdrm-dev libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm-dev libasound2-dev
|
|
864
|
+
*
|
|
865
|
+
* # disable AppArmor unprivileged security restriction
|
|
866
|
+
* echo "kernel.apparmor_restrict_unprivileged_userns=0" | sudo tee /etc/sysctl.d/60-apparmor-namespace.conf
|
|
867
|
+
* sudo sysctl -p /etc/sysctl.d/60-apparmor-namespace.conf
|
|
868
|
+
* ```
|
|
869
|
+
*
|
|
818
870
|
*/
|
|
819
871
|
class GoogleChromeDevTools extends EventEmitter {
|
|
820
872
|
constructor(options = {}) {
|
|
821
873
|
super()
|
|
822
874
|
|
|
875
|
+
if (options.constructor == GoogleChromeForTesting) {
|
|
876
|
+
this.googleChromeForTesting = options
|
|
877
|
+
}
|
|
878
|
+
|
|
823
879
|
this.chromeVersion = options.chromeVersion ?? 'stable'
|
|
880
|
+
this.chromeDir = options.chromeDir ?? 'google-chrome-for-testing'
|
|
881
|
+
this.remoteDebuggingPort = options.remoteDebuggingPort ?? 9222
|
|
882
|
+
this.headless = options.headless ?? false
|
|
883
|
+
this.userDataDir = options.userDataDir ?? 'tmp/chrome'
|
|
884
|
+
this.useMockKeychain = options.useMockKeychain ?? true
|
|
824
885
|
}
|
|
825
886
|
|
|
826
887
|
/**
|
|
@@ -846,15 +907,17 @@ class GoogleChromeDevTools extends EventEmitter {
|
|
|
846
907
|
* ```
|
|
847
908
|
*/
|
|
848
909
|
async init() {
|
|
849
|
-
|
|
910
|
+
this.googleChromeForTesting ??= new GoogleChromeForTesting({
|
|
850
911
|
chromeVersion: this.chromeVersion,
|
|
851
|
-
|
|
852
|
-
|
|
912
|
+
chromeDir: this.chromeDir,
|
|
913
|
+
remoteDebuggingPort: this.remoteDebuggingPort,
|
|
914
|
+
headless: this.headless,
|
|
915
|
+
userDataDir: this.userDataDir,
|
|
916
|
+
useMockKeychain: this.useMockKeychain,
|
|
853
917
|
})
|
|
854
|
-
await googleChromeForTesting.init()
|
|
855
|
-
this.googleChromeForTesting = googleChromeForTesting
|
|
918
|
+
await this.googleChromeForTesting.init()
|
|
856
919
|
|
|
857
|
-
this.websocket = new WebSocket(googleChromeForTesting.devtoolsUrl, {
|
|
920
|
+
this.websocket = new WebSocket(this.googleChromeForTesting.devtoolsUrl, {
|
|
858
921
|
offerPerMessageDeflate: false,
|
|
859
922
|
})
|
|
860
923
|
this.websocket.on('error', error => {
|
|
@@ -911,6 +974,31 @@ class GoogleChromeDevTools extends EventEmitter {
|
|
|
911
974
|
this.Runtime.sessionId = sessionId
|
|
912
975
|
}
|
|
913
976
|
|
|
977
|
+
/**
|
|
978
|
+
* @name close
|
|
979
|
+
*
|
|
980
|
+
* @docs
|
|
981
|
+
* ```coffeescript [specscript]
|
|
982
|
+
* close() -> undefined
|
|
983
|
+
* ```
|
|
984
|
+
*
|
|
985
|
+
* Closes the websocket connection to the DevTools server and terminates the Google Chrome for Testing process.
|
|
986
|
+
*
|
|
987
|
+
* Arguments:
|
|
988
|
+
* * (none)
|
|
989
|
+
*
|
|
990
|
+
* Return:
|
|
991
|
+
* * `undefined`
|
|
992
|
+
*
|
|
993
|
+
* ```javascript
|
|
994
|
+
* googleChromeDevTools.close()
|
|
995
|
+
* ```
|
|
996
|
+
*/
|
|
997
|
+
close() {
|
|
998
|
+
this.websocket.sendClose()
|
|
999
|
+
this.websocket.close()
|
|
1000
|
+
this.googleChromeForTesting.close()
|
|
1001
|
+
}
|
|
914
1002
|
}
|
|
915
1003
|
|
|
916
1004
|
module.exports = GoogleChromeDevTools
|
|
@@ -5,10 +5,11 @@ const path = require('path')
|
|
|
5
5
|
const { spawn } = require('child_process')
|
|
6
6
|
const readline = require('readline')
|
|
7
7
|
const extract = require('extract-zip')
|
|
8
|
-
const HTTP = require('
|
|
9
|
-
const XML = require('
|
|
10
|
-
const Readable = require('
|
|
11
|
-
const walk = require('./walk')
|
|
8
|
+
const HTTP = require('./HTTP')
|
|
9
|
+
const XML = require('./XML')
|
|
10
|
+
const Readable = require('./Readable')
|
|
11
|
+
const walk = require('./internal/walk')
|
|
12
|
+
const sleep = require('./internal/sleep')
|
|
12
13
|
|
|
13
14
|
async function getChromeVersions() {
|
|
14
15
|
const http = new HTTP()
|
|
@@ -23,7 +24,7 @@ function updateConsoleLog(message) {
|
|
|
23
24
|
process.stdout.write(message);
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
function getPlatform() {
|
|
27
28
|
let platform = os.platform()
|
|
28
29
|
if (platform == 'darwin') {
|
|
29
30
|
platform = 'mac'
|
|
@@ -36,6 +37,12 @@ async function getChromeUrl() {
|
|
|
36
37
|
platform = `${platform}${arch.slice(1)}`
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
return platform
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function getChromeUrl() {
|
|
44
|
+
const platform = getPlatform()
|
|
45
|
+
|
|
39
46
|
let url
|
|
40
47
|
if (['stable', 'beta', 'dev', 'canary'].includes(this.chromeVersion)) {
|
|
41
48
|
const chromeVersions = await getChromeVersions()
|
|
@@ -91,19 +98,27 @@ async function installChrome() {
|
|
|
91
98
|
})
|
|
92
99
|
await promise
|
|
93
100
|
|
|
94
|
-
|
|
101
|
+
try {
|
|
102
|
+
await extract(filepath, { dir: parentDir })
|
|
103
|
+
} catch {
|
|
104
|
+
await sleep(100)
|
|
105
|
+
await extract(filepath, { dir: parentDir })
|
|
106
|
+
}
|
|
95
107
|
}
|
|
96
108
|
|
|
97
109
|
async function getChromeFilepath() {
|
|
110
|
+
const platform = getPlatform()
|
|
98
111
|
const url = await getChromeUrl.call(this)
|
|
99
112
|
const filepath = `${this.chromeDir}/${url.replace('https://storage.googleapis.com/chrome-for-testing-public/', '')}`
|
|
100
113
|
const parentDir = `${filepath.split('/').slice(0, -1).join('/')}`
|
|
101
114
|
|
|
102
|
-
const googleChromeForTestingFilepath = `${parentDir}`
|
|
103
115
|
try {
|
|
104
116
|
for await (const filepath of walk(parentDir)) {
|
|
105
117
|
console.log(filepath)
|
|
106
|
-
if (filepath.endsWith('Google Chrome for Testing')) {
|
|
118
|
+
if (platform.startsWith('mac') && filepath.endsWith('Google Chrome for Testing')) {
|
|
119
|
+
return filepath
|
|
120
|
+
}
|
|
121
|
+
if (platform.startsWith('linux') && filepath.endsWith('chrome')) {
|
|
107
122
|
return filepath
|
|
108
123
|
}
|
|
109
124
|
}
|
|
@@ -130,11 +145,51 @@ async function getChromeFilepath() {
|
|
|
130
145
|
* headless: boolean,
|
|
131
146
|
* userDataDir: string,
|
|
132
147
|
* useMockKeychain: boolean,
|
|
133
|
-
* }) -> GoogleChromeForTesting
|
|
148
|
+
* }) -> googleChromeForTesting GoogleChromeForTesting
|
|
149
|
+
* ```
|
|
150
|
+
*
|
|
151
|
+
* Presidium GoogleChromeForTesting client for test automation.
|
|
152
|
+
*
|
|
153
|
+
* Arguments:
|
|
154
|
+
* * `options`
|
|
155
|
+
* * `chromeVersion` - the version of Google Chrome for Testing to download. Defaults to `'stable'`.
|
|
156
|
+
* * `chromeDir` - the directory that Google Chrome for Testing will install to. Defaults to ``google-chrome-for-testing'`.
|
|
157
|
+
* * `remoteDebuggingPort` - the port that the Chrome DevTools Protocol server will listen on. Defaults to `9222`
|
|
158
|
+
* * `headless` - whether to run Google Chrome for Testing in headless mode. Defaults to `false`.
|
|
159
|
+
* * `userDataDir` - directory for storing user profile data such as history, bookmarks, cookies, and settings. Defaults to `tmp/chrome`.
|
|
160
|
+
* * `useMockKeychain` - whether to use a mock keychain instead of the system's real security keychain. Defaults to `true`.
|
|
161
|
+
*
|
|
162
|
+
* Returns:
|
|
163
|
+
* * `googleChromeForTesting` - an instance of the `GoogleChromeForTesting` client.
|
|
164
|
+
*
|
|
165
|
+
* ```javascript
|
|
166
|
+
* const googleChromeForTesting = new GoogleChromeForTesting({ chromeVersion: 'stable' })
|
|
167
|
+
* await googleChromeForTesting.init()
|
|
134
168
|
* ```
|
|
135
169
|
*
|
|
136
|
-
*
|
|
170
|
+
* Google Chrome for Testing versions:
|
|
137
171
|
* * [Chrome for Testing availability](https://googlechromelabs.github.io/chrome-for-testing/)
|
|
172
|
+
*
|
|
173
|
+
* Supported platforms:
|
|
174
|
+
* * `mac-arm64`
|
|
175
|
+
* * `linux64`
|
|
176
|
+
*
|
|
177
|
+
* ## Further Installation
|
|
178
|
+
* Some further installation may be required for Linux platforms.
|
|
179
|
+
*
|
|
180
|
+
* ### Install headless dependencies for Amazon Linux 2023 / Red Hat
|
|
181
|
+
* ```sh
|
|
182
|
+
* sudo dnf install -y cairo pango nss nspr atk at-spi2-atk cups-libs libdrm libxkbcommon libXcomposite libXdamage libXfixes libXrandr mesa-libgbm alsa-lib
|
|
183
|
+
* ```
|
|
184
|
+
*
|
|
185
|
+
* ### Install headless dependencies for Ubuntu / Debian
|
|
186
|
+
* ```sh
|
|
187
|
+
* sudo apt-get update && sudo apt-get install -y libcairo2 libpango-1.0-0 libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libatspi2.0-0 libcups2 libdrm-dev libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm-dev libasound2-dev
|
|
188
|
+
*
|
|
189
|
+
* # disable AppArmor unprivileged security restriction
|
|
190
|
+
* echo "kernel.apparmor_restrict_unprivileged_userns=0" | sudo tee /etc/sysctl.d/60-apparmor-namespace.conf
|
|
191
|
+
* sudo sysctl -p /etc/sysctl.d/60-apparmor-namespace.conf
|
|
192
|
+
* ```
|
|
138
193
|
*/
|
|
139
194
|
class GoogleChromeForTesting {
|
|
140
195
|
constructor(options = {}) {
|
|
@@ -142,8 +197,8 @@ class GoogleChromeForTesting {
|
|
|
142
197
|
this.chromeDir = options.chromeDir ?? 'google-chrome-for-testing'
|
|
143
198
|
this.remoteDebuggingPort = options.remoteDebuggingPort ?? 9222
|
|
144
199
|
this.headless = options.headless ?? false
|
|
145
|
-
this.userDataDir = options.userDataDir ?? '
|
|
146
|
-
this.useMockKeychain = options.useMockKeychain ??
|
|
200
|
+
this.userDataDir = options.userDataDir ?? 'tmp/chrome'
|
|
201
|
+
this.useMockKeychain = options.useMockKeychain ?? true
|
|
147
202
|
this.devtoolsUrl = undefined
|
|
148
203
|
}
|
|
149
204
|
|
|
@@ -154,10 +209,27 @@ class GoogleChromeForTesting {
|
|
|
154
209
|
* ```coffeescript [specscript]
|
|
155
210
|
* init() -> Promise<>
|
|
156
211
|
* ```
|
|
212
|
+
*
|
|
213
|
+
* Initializes the `GoogleChromeForTesting` client.
|
|
214
|
+
*
|
|
215
|
+
* Arguments:
|
|
216
|
+
* * (none)
|
|
217
|
+
*
|
|
218
|
+
* Returns:
|
|
219
|
+
* * `promise` - a promise that resolves when the initialization process is done.
|
|
220
|
+
*
|
|
221
|
+
* ```javascript
|
|
222
|
+
* const googleChromeForTesting = new GoogleChromeForTesting()
|
|
223
|
+
*
|
|
224
|
+
* await googleChromeForTesting.init()
|
|
225
|
+
* ```
|
|
157
226
|
*/
|
|
158
227
|
async init() {
|
|
228
|
+
if (this.devtoolsUrl) {
|
|
229
|
+
return undefined
|
|
230
|
+
}
|
|
231
|
+
|
|
159
232
|
const chromeFilepath = await getChromeFilepath.call(this)
|
|
160
|
-
console.log('spawn', chromeFilepath)
|
|
161
233
|
|
|
162
234
|
const cmd = spawn(chromeFilepath, [
|
|
163
235
|
`--remote-debugging-port=${this.remoteDebuggingPort}`,
|
|
@@ -168,18 +240,24 @@ class GoogleChromeForTesting {
|
|
|
168
240
|
cmd.stdout.pipe(process.stdout)
|
|
169
241
|
cmd.stderr.pipe(process.stderr)
|
|
170
242
|
|
|
171
|
-
|
|
243
|
+
let devtoolsUrlResolve
|
|
244
|
+
const devtoolsUrlPromise = new Promise(_resolve => {
|
|
245
|
+
devtoolsUrlResolve = _resolve
|
|
246
|
+
})
|
|
172
247
|
cmd.stderr.on('data', chunk => {
|
|
173
248
|
const line = chunk.toString('utf8').trim()
|
|
174
249
|
if (line.includes('DevTools listening on')) {
|
|
175
250
|
const devtoolsUrl = line.replace('DevTools listening on ', '')
|
|
176
|
-
|
|
251
|
+
devtoolsUrlResolve(devtoolsUrl)
|
|
177
252
|
}
|
|
178
253
|
})
|
|
179
254
|
|
|
180
|
-
|
|
255
|
+
let spawnResolve
|
|
256
|
+
const spawnPromise = new Promise(_resolve => {
|
|
257
|
+
spawnResolve = _resolve
|
|
258
|
+
})
|
|
181
259
|
cmd.on('spawn', () => {
|
|
182
|
-
|
|
260
|
+
spawnResolve()
|
|
183
261
|
})
|
|
184
262
|
|
|
185
263
|
cmd.on('error', error => {
|
|
@@ -197,8 +275,10 @@ class GoogleChromeForTesting {
|
|
|
197
275
|
|
|
198
276
|
this.cmd = cmd
|
|
199
277
|
|
|
200
|
-
await
|
|
201
|
-
this.devtoolsUrl = await
|
|
278
|
+
await spawnPromise
|
|
279
|
+
this.devtoolsUrl = await devtoolsUrlPromise
|
|
280
|
+
|
|
281
|
+
return undefined
|
|
202
282
|
}
|
|
203
283
|
|
|
204
284
|
/**
|
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ const WebSocket = require('presidium/WebSocket')
|
|
|
28
28
|
const Readable = require('presidium/Readable')
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
## Handle HTTP
|
|
31
|
+
## [Handle HTTP](https://presidium.services/docs/HTTP)
|
|
32
32
|
```javascript
|
|
33
33
|
const HTTP = require('presidium/HTTP')
|
|
34
34
|
|
|
@@ -47,7 +47,7 @@ http.get('/')
|
|
|
47
47
|
.then(console.log) // { greeting: 'Hello World' }
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
##
|
|
50
|
+
## [Send messages with WebSocket](https://presidium.services/docs/WebSocket)
|
|
51
51
|
```javascript
|
|
52
52
|
const WebSocket = require('presidium/WebSocket')
|
|
53
53
|
|
|
@@ -71,7 +71,7 @@ websocket.on('message', message => {
|
|
|
71
71
|
})
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
-
##
|
|
74
|
+
## [Create, read, update, delete, and query with AWS DynamoDB](https://presidium.services/docs/DynamoDBTable)
|
|
75
75
|
```javascript
|
|
76
76
|
const DynamoDBTable = require('presidium/DynamoDBTable')
|
|
77
77
|
const DynamoDBGlobalSecondaryIndex = require('presidium/DynamoDBGlobalSecondaryIndex')
|
|
@@ -175,7 +175,7 @@ await myTable.putItemJSON({ id: '3', name: 'Jane', age: 33, type: 'person' })
|
|
|
175
175
|
}
|
|
176
176
|
```
|
|
177
177
|
|
|
178
|
-
## Consume DynamoDB Streams
|
|
178
|
+
## [Consume AWS DynamoDB Streams](https://presidium.services/docs/DynamoDBStream)
|
|
179
179
|
```javascript
|
|
180
180
|
const DynamoDBTable = require('presidium/DynamoDBTable')
|
|
181
181
|
const DynamoDBStream = require('presidium/DynamoDBStream')
|
|
@@ -219,7 +219,7 @@ for await (const record of myStreamJSON) {
|
|
|
219
219
|
}
|
|
220
220
|
```
|
|
221
221
|
|
|
222
|
-
##
|
|
222
|
+
## [Download and upload with AWS S3](https://presidium.services/docs/S3Bucket)
|
|
223
223
|
```javascript
|
|
224
224
|
const S3Bucket = require('presidium/S3Bucket')
|
|
225
225
|
const AwsCredentials = require('presidium/AwsCredentials')
|
|
@@ -245,8 +245,7 @@ await myBucket.deleteAllObjects()
|
|
|
245
245
|
await myBucket.delete()
|
|
246
246
|
```
|
|
247
247
|
|
|
248
|
-
## Build and
|
|
249
|
-
> No more --build-arg for npm tokens!
|
|
248
|
+
## [Build and push Docker images](https://presidium.services/docs/Docker)
|
|
250
249
|
```javascript
|
|
251
250
|
const Docker = require('presidium/Docker')
|
|
252
251
|
const NpmToken = require('presidium/NpmToken')
|
|
@@ -276,16 +275,18 @@ CMD ["npm", "start"]
|
|
|
276
275
|
})
|
|
277
276
|
|
|
278
277
|
buildStream.pipe(process.stdout)
|
|
279
|
-
await new Promise(resolve => buildStream.on('end', resolve))
|
|
280
278
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
279
|
+
buildStream.on('end', () => {
|
|
280
|
+
const pushStream = await docker.pushImage({
|
|
281
|
+
image: myImage,
|
|
282
|
+
repository: 'my-registry.io',
|
|
283
|
+
})
|
|
284
|
+
pushStream.pipe(process.stdout)
|
|
284
285
|
})
|
|
285
|
-
|
|
286
|
+
|
|
286
287
|
```
|
|
287
288
|
|
|
288
|
-
## Run Docker
|
|
289
|
+
## [Run Docker containers](https://presidium.services/docs/Docker)
|
|
289
290
|
```javascript
|
|
290
291
|
const Docker = require('presidium/Docker')
|
|
291
292
|
|
|
@@ -301,7 +302,7 @@ const runStream = await docker.runContainer({
|
|
|
301
302
|
runStream.pipe(process.stdout) // Example
|
|
302
303
|
```
|
|
303
304
|
|
|
304
|
-
## Deploy Docker Swarm
|
|
305
|
+
## [Deploy Docker Swarm services](https://presidium.services/docs/Docker)
|
|
305
306
|
```javascript
|
|
306
307
|
const Docker = require('presidium/Docker')
|
|
307
308
|
|
|
@@ -320,5 +321,34 @@ await docker.createService({
|
|
|
320
321
|
// new nginx service is deploying to the docker swarm
|
|
321
322
|
```
|
|
322
323
|
|
|
324
|
+
## [Automate tests with Google Chrome for Testing](https://presidium.services/docs/GoogleChromeDevTools)
|
|
325
|
+
```javascript
|
|
326
|
+
const GoogleChromeForTesting = require('presidium/GoogleChromeForTesting')
|
|
327
|
+
const GoogleChromeDevTools = require('presidium/GoogleChromeDevTools')
|
|
328
|
+
|
|
329
|
+
const googleChromeForTesting = new GoogleChromeForTesting()
|
|
330
|
+
await googleChromeForTesting.init() // downloads Google Chrome for Testing
|
|
331
|
+
|
|
332
|
+
const googleChromeDevTools = new GoogleChromeDevTools(googleChromeForTesting)
|
|
333
|
+
await googleChromeDevTools.init() // connects to the DevTools server
|
|
334
|
+
|
|
335
|
+
// get targets
|
|
336
|
+
const targetsData = await googleChromeDevTools.Target.getTargets()
|
|
337
|
+
const pageTarget = targetsData.result.targetInfos.find(info => info.type == 'page')
|
|
338
|
+
|
|
339
|
+
// attach to target
|
|
340
|
+
const attachToTargetData = await googleChromeDevTools.Target.attachToTarget({
|
|
341
|
+
targetId: this.pageTarget.targetId,
|
|
342
|
+
flatten: true,
|
|
343
|
+
})
|
|
344
|
+
const sessionId = attachToTargetData.result.sessionId
|
|
345
|
+
|
|
346
|
+
// navigate to the home page
|
|
347
|
+
const data = await googleChromeDevTools.Page.navigate({
|
|
348
|
+
sessionId: this.sessionId,
|
|
349
|
+
url: `http://localhost:3000/`,
|
|
350
|
+
})
|
|
351
|
+
```
|
|
352
|
+
|
|
323
353
|
# Support
|
|
324
354
|
* minimum Node.js version: 16
|
package/index.js
CHANGED
|
@@ -6,6 +6,7 @@ module.exports = {
|
|
|
6
6
|
DynamoDBTable: require('./DynamoDBTable.js'),
|
|
7
7
|
ECR: require('./ECR.js'),
|
|
8
8
|
GoogleChromeDevTools: require('./GoogleChromeDevTools.js'),
|
|
9
|
+
GoogleChromeForTesting: require('./GoogleChromeForTesting.js'),
|
|
9
10
|
HTTP: require('./HTTP.js'),
|
|
10
11
|
NpmToken: require('./NpmToken.js'),
|
|
11
12
|
OptionalValidator: require('./OptionalValidator.js'),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "presidium",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "A library for creating web services",
|
|
5
5
|
"author": "Richard Tong",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"DynamoDBTable.js",
|
|
20
20
|
"ECR.js",
|
|
21
21
|
"GoogleChromeDevTools.js",
|
|
22
|
+
"GoogleChromeForTesting.js",
|
|
22
23
|
"HTTP.js",
|
|
23
24
|
"index.js",
|
|
24
25
|
"NpmToken.js",
|
|
@@ -75,7 +76,7 @@
|
|
|
75
76
|
"fast-crc32c": "^2.0.0",
|
|
76
77
|
"mocha": "^10.8.2",
|
|
77
78
|
"nyc": "^17.1.0",
|
|
78
|
-
"thunk-test": "^1.3.
|
|
79
|
+
"thunk-test": "^1.3.9",
|
|
79
80
|
"wavefile": "^11.0.0"
|
|
80
81
|
}
|
|
81
82
|
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
const Test = require('thunk-test')
|
|
2
|
-
const assert = require('assert')
|
|
3
|
-
const fs = require('fs')
|
|
4
|
-
const { exec } = require('child_process')
|
|
5
|
-
const Readable = require('../Readable')
|
|
6
|
-
const GoogleChromeForTesting = require('./GoogleChromeForTesting')
|
|
7
|
-
|
|
8
|
-
const test = new Test('GoogleChromeForTesting', async function integration() {
|
|
9
|
-
await fs.promises.rm('google-chrome-for-testing', { recursive: true, force: true })
|
|
10
|
-
|
|
11
|
-
const cmd = await exec('ps aux | grep "Google Chrome for Testing" | awk \'{print $2}\' | xargs kill', {
|
|
12
|
-
stdio: 'inherit',
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
{
|
|
16
|
-
const googleChromeForTesting = new GoogleChromeForTesting({
|
|
17
|
-
userDataDir: `${__dirname}/tmp/chrome`,
|
|
18
|
-
useMockKeychain: true,
|
|
19
|
-
})
|
|
20
|
-
await googleChromeForTesting.init()
|
|
21
|
-
|
|
22
|
-
assert.equal(typeof googleChromeForTesting.devtoolsUrl, 'string')
|
|
23
|
-
assert(googleChromeForTesting.devtoolsUrl.startsWith('ws://'))
|
|
24
|
-
|
|
25
|
-
googleChromeForTesting.close()
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
{
|
|
29
|
-
const googleChromeForTesting = new GoogleChromeForTesting({
|
|
30
|
-
userDataDir: `${__dirname}/tmp/chrome`,
|
|
31
|
-
useMockKeychain: true,
|
|
32
|
-
})
|
|
33
|
-
await googleChromeForTesting.init()
|
|
34
|
-
|
|
35
|
-
assert.equal(typeof googleChromeForTesting.devtoolsUrl, 'string')
|
|
36
|
-
assert(googleChromeForTesting.devtoolsUrl.startsWith('ws://'))
|
|
37
|
-
|
|
38
|
-
googleChromeForTesting.close()
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
await fs.promises.rm('google-chrome-for-testing', { recursive: true, force: true })
|
|
42
|
-
|
|
43
|
-
console.log('Success')
|
|
44
|
-
}).case()
|
|
45
|
-
|
|
46
|
-
if (process.argv[1] == __filename) {
|
|
47
|
-
test()
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
module.exports = test
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|