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.
Files changed (97) hide show
  1. package/GoogleChromeDevTools.js +98 -10
  2. package/{internal/GoogleChromeForTesting.js → GoogleChromeForTesting.js} +99 -19
  3. package/README.md +44 -14
  4. package/index.js +1 -0
  5. package/package.json +3 -2
  6. package/internal/GoogleChromeForTesting.test.js +0 -50
  7. package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69977DD3-9B6F.pma +0 -0
  8. package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69977DD4-9B86.pma +0 -0
  9. package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69978250-A191.pma +0 -0
  10. package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69978251-A1AD.pma +0 -0
  11. package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69978277-A1FA.pma +0 -0
  12. package/internal/tmp/chrome/BrowserMetrics/BrowserMetrics-69978278-A209.pma +0 -0
  13. package/internal/tmp/chrome/ChromeFeatureState +0 -1
  14. package/internal/tmp/chrome/Default/Affiliation Database +0 -0
  15. package/internal/tmp/chrome/Default/Affiliation Database-journal +0 -0
  16. package/internal/tmp/chrome/Default/ClientCertificates/LOCK +0 -0
  17. package/internal/tmp/chrome/Default/ClientCertificates/LOG +0 -0
  18. package/internal/tmp/chrome/Default/ClientCertificates/LOG.old +0 -0
  19. package/internal/tmp/chrome/Default/Extension Rules/000003.log +0 -0
  20. package/internal/tmp/chrome/Default/Extension Rules/CURRENT +0 -1
  21. package/internal/tmp/chrome/Default/Extension Rules/LOCK +0 -0
  22. package/internal/tmp/chrome/Default/Extension Rules/LOG +0 -3
  23. package/internal/tmp/chrome/Default/Extension Rules/LOG.old +0 -3
  24. package/internal/tmp/chrome/Default/Extension Rules/MANIFEST-000001 +0 -0
  25. package/internal/tmp/chrome/Default/Extension Scripts/000003.log +0 -0
  26. package/internal/tmp/chrome/Default/Extension Scripts/CURRENT +0 -1
  27. package/internal/tmp/chrome/Default/Extension Scripts/LOCK +0 -0
  28. package/internal/tmp/chrome/Default/Extension Scripts/LOG +0 -3
  29. package/internal/tmp/chrome/Default/Extension Scripts/LOG.old +0 -3
  30. package/internal/tmp/chrome/Default/Extension Scripts/MANIFEST-000001 +0 -0
  31. package/internal/tmp/chrome/Default/Favicons +0 -0
  32. package/internal/tmp/chrome/Default/Favicons-journal +0 -0
  33. package/internal/tmp/chrome/Default/History +0 -0
  34. package/internal/tmp/chrome/Default/History-journal +0 -0
  35. package/internal/tmp/chrome/Default/LOCK +0 -0
  36. package/internal/tmp/chrome/Default/LOG +0 -0
  37. package/internal/tmp/chrome/Default/LOG.old +0 -0
  38. package/internal/tmp/chrome/Default/Local Storage/leveldb/000003.log +0 -0
  39. package/internal/tmp/chrome/Default/Local Storage/leveldb/CURRENT +0 -1
  40. package/internal/tmp/chrome/Default/Local Storage/leveldb/LOCK +0 -0
  41. package/internal/tmp/chrome/Default/Local Storage/leveldb/LOG +0 -2
  42. package/internal/tmp/chrome/Default/Local Storage/leveldb/MANIFEST-000001 +0 -0
  43. package/internal/tmp/chrome/Default/PersistentOriginTrials/LOCK +0 -0
  44. package/internal/tmp/chrome/Default/PersistentOriginTrials/LOG +0 -0
  45. package/internal/tmp/chrome/Default/PersistentOriginTrials/LOG.old +0 -0
  46. package/internal/tmp/chrome/Default/README +0 -1
  47. package/internal/tmp/chrome/Default/Segmentation Platform/SegmentInfoDB/LOCK +0 -0
  48. package/internal/tmp/chrome/Default/Segmentation Platform/SegmentInfoDB/LOG +0 -0
  49. package/internal/tmp/chrome/Default/Segmentation Platform/SegmentInfoDB/LOG.old +0 -0
  50. package/internal/tmp/chrome/Default/Segmentation Platform/SignalDB/LOCK +0 -0
  51. package/internal/tmp/chrome/Default/Segmentation Platform/SignalDB/LOG +0 -0
  52. package/internal/tmp/chrome/Default/Segmentation Platform/SignalDB/LOG.old +0 -0
  53. package/internal/tmp/chrome/Default/Segmentation Platform/SignalStorageConfigDB/LOCK +0 -0
  54. package/internal/tmp/chrome/Default/Segmentation Platform/SignalStorageConfigDB/LOG +0 -0
  55. package/internal/tmp/chrome/Default/Segmentation Platform/SignalStorageConfigDB/LOG.old +0 -0
  56. package/internal/tmp/chrome/Default/ServerCertificate +0 -0
  57. package/internal/tmp/chrome/Default/ServerCertificate-journal +0 -0
  58. package/internal/tmp/chrome/Default/Site Characteristics Database/000003.log +0 -0
  59. package/internal/tmp/chrome/Default/Site Characteristics Database/CURRENT +0 -1
  60. package/internal/tmp/chrome/Default/Site Characteristics Database/LOCK +0 -0
  61. package/internal/tmp/chrome/Default/Site Characteristics Database/LOG +0 -3
  62. package/internal/tmp/chrome/Default/Site Characteristics Database/LOG.old +0 -3
  63. package/internal/tmp/chrome/Default/Site Characteristics Database/MANIFEST-000001 +0 -0
  64. package/internal/tmp/chrome/Default/Sync Data/LevelDB/000003.log +0 -0
  65. package/internal/tmp/chrome/Default/Sync Data/LevelDB/CURRENT +0 -1
  66. package/internal/tmp/chrome/Default/Sync Data/LevelDB/LOCK +0 -0
  67. package/internal/tmp/chrome/Default/Sync Data/LevelDB/LOG +0 -3
  68. package/internal/tmp/chrome/Default/Sync Data/LevelDB/LOG.old +0 -3
  69. package/internal/tmp/chrome/Default/Sync Data/LevelDB/MANIFEST-000001 +0 -0
  70. package/internal/tmp/chrome/Default/chrome_cart_db/LOCK +0 -0
  71. package/internal/tmp/chrome/Default/chrome_cart_db/LOG +0 -0
  72. package/internal/tmp/chrome/Default/chrome_cart_db/LOG.old +0 -0
  73. package/internal/tmp/chrome/Default/commerce_subscription_db/LOCK +0 -0
  74. package/internal/tmp/chrome/Default/commerce_subscription_db/LOG +0 -0
  75. package/internal/tmp/chrome/Default/commerce_subscription_db/LOG.old +0 -0
  76. package/internal/tmp/chrome/Default/discount_infos_db/LOCK +0 -0
  77. package/internal/tmp/chrome/Default/discount_infos_db/LOG +0 -0
  78. package/internal/tmp/chrome/Default/discount_infos_db/LOG.old +0 -0
  79. package/internal/tmp/chrome/Default/discounts_db/LOCK +0 -0
  80. package/internal/tmp/chrome/Default/discounts_db/LOG +0 -0
  81. package/internal/tmp/chrome/Default/discounts_db/LOG.old +0 -0
  82. package/internal/tmp/chrome/Default/parcel_tracking_db/LOCK +0 -0
  83. package/internal/tmp/chrome/Default/parcel_tracking_db/LOG +0 -0
  84. package/internal/tmp/chrome/Default/parcel_tracking_db/LOG.old +0 -0
  85. package/internal/tmp/chrome/Default/power_bookmarks/PowerBookmarks.db +0 -0
  86. package/internal/tmp/chrome/Default/power_bookmarks/PowerBookmarks.db-journal +0 -0
  87. package/internal/tmp/chrome/First Run +0 -0
  88. package/internal/tmp/chrome/Last Version +0 -1
  89. package/internal/tmp/chrome/Local State +0 -1
  90. package/internal/tmp/chrome/ShaderCache/data_0 +0 -0
  91. package/internal/tmp/chrome/ShaderCache/data_1 +0 -0
  92. package/internal/tmp/chrome/ShaderCache/data_2 +0 -0
  93. package/internal/tmp/chrome/ShaderCache/data_3 +0 -0
  94. package/internal/tmp/chrome/ShaderCache/index +0 -0
  95. package/internal/tmp/chrome/Variations +0 -1
  96. package/internal/tmp/chrome/segmentation_platform/ukm_db +0 -0
  97. package/internal/tmp/chrome/segmentation_platform/ukm_db-wal +0 -0
@@ -1,5 +1,5 @@
1
1
  const EventEmitter = require('events')
2
- const GoogleChromeForTesting = require('./internal/GoogleChromeForTesting')
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(url string) -> googleChromeDevTools 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 googleChromeDevTools = new GoogleChromeDevTools()
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 googleChromeDevTools = new GoogleChromeDevTools()
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
- const googleChromeForTesting = new GoogleChromeForTesting({
910
+ this.googleChromeForTesting ??= new GoogleChromeForTesting({
850
911
  chromeVersion: this.chromeVersion,
851
- userDataDir: `${__dirname}/tmp/chrome`,
852
- useMockKeychain: true,
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('../HTTP')
9
- const XML = require('../XML')
10
- const Readable = require('../Readable')
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
- async function getChromeUrl() {
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
- await extract(filepath, { dir: parentDir })
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
- * References:
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 ?? './tmp/chrome'
146
- this.useMockKeychain = options.useMockKeychain ?? false
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
- const devtoolsUrlPromiseWithResolvers = Promise.withResolvers()
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
- devtoolsUrlPromiseWithResolvers.resolve(devtoolsUrl)
251
+ devtoolsUrlResolve(devtoolsUrl)
177
252
  }
178
253
  })
179
254
 
180
- const spawnPromiseWithResolvers = Promise.withResolvers()
255
+ let spawnResolve
256
+ const spawnPromise = new Promise(_resolve => {
257
+ spawnResolve = _resolve
258
+ })
181
259
  cmd.on('spawn', () => {
182
- spawnPromiseWithResolvers.resolve()
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 spawnPromiseWithResolvers.promise
201
- this.devtoolsUrl = await devtoolsUrlPromiseWithResolvers.promise
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
- ## Handle WebSocket
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
- ## CRUD and Query DynamoDB
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
- ## Upload to S3
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 Push Docker Images
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
- const pushStream = await docker.pushImage({
282
- image: myImage,
283
- repository: 'my-registry.io',
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
- pushStream.pipe(process.stdout)
286
+
286
287
  ```
287
288
 
288
- ## Run Docker Containers
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 Services
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",
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.1",
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