-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
[WIP] Add initial setup for BrowserStack CLI #14456
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[WIP] Add initial setup for BrowserStack CLI #14456
Conversation
eslint-plugin-wdio
@wdio/allure-reporter
@wdio/browser-runner
@wdio/browserstack-service
@wdio/appium-service
@wdio/cli
@wdio/concise-reporter
@wdio/config
@wdio/cucumber-framework
@wdio/dot-reporter
@wdio/firefox-profile-service
@wdio/globals
@wdio/jasmine-framework
@wdio/json-reporter
@wdio/junit-reporter
@wdio/lighthouse-service
@wdio/local-runner
@wdio/logger
@wdio/mocha-framework
@wdio/protocols
@wdio/repl
@wdio/reporter
@wdio/runner
@wdio/sauce-service
@wdio/shared-store-service
@wdio/smoke-test-cjs-service
@wdio/smoke-test-reporter
@wdio/smoke-test-service
@wdio/spec-reporter
@wdio/static-server-service
@wdio/sumologic-reporter
@wdio/testingbot-service
@wdio/types
@wdio/utils
@wdio/webdriver-mock-service
webdriver
webdriverio
commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we update the BrowserStack service docs to include this type of feature? I think we got a bit behind of documenting what this service does. See https://webdriver.io/docs/browserstack-service. I recommend to either update the docs, or remove them completely with a link to the BrowserStack docs.
packages/wdio-browserstack-service/src/cli/modules/BaseModule.ts
Outdated
Show resolved
Hide resolved
packages/wdio-browserstack-service/src/cli/modules/TestHubModule.ts
Outdated
Show resolved
Hide resolved
packages/wdio-browserstack-service/src/cli/modules/TestHubModule.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One last comment, the rest is ok to me. I would love to see more test coverage for all this added code. Also please address the comment above about documenting this feature. It is unclear at the moment what this is about.
return new Promise<string|null>((resolve, reject) => { | ||
fetch(binDownloadUrl, { | ||
redirect: 'follow' | ||
}).then((response) => { | ||
if (response.ok && response.body) { | ||
const binaryName = null | ||
Readable.fromWeb(response.body).pipe(downloadedFileStream) | ||
|
||
downloadedFileStream.on('error', function (err: Error) { | ||
logger.error('Got Error while downloading percy binary file' + err) | ||
PerformanceTester.end(PerformanceEvents.SDK_CLI_DOWNLOAD, false, util.format(err)) | ||
reject(err) | ||
}) | ||
CLIUtils.downloadFileStream(downloadedFileStream, binaryName, zipFilePath, cliDir, resolve, reject) | ||
} else { | ||
const err = 'Got Error in cli binary download response' + response.status | ||
logger.error(err) | ||
PerformanceTester.end(PerformanceEvents.SDK_CLI_DOWNLOAD, false, err) | ||
reject(err) | ||
} | ||
}).catch((err) => { | ||
logger.error(`Got Error in cli binary downloading request ${util.format(err)}`) | ||
PerformanceTester.end(PerformanceEvents.SDK_CLI_DOWNLOAD, false, util.format(err)) | ||
reject(err) | ||
}) | ||
PerformanceTester.end(PerformanceEvents.SDK_CLI_DOWNLOAD) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return new Promise<string|null>((resolve, reject) => { | |
fetch(binDownloadUrl, { | |
redirect: 'follow' | |
}).then((response) => { | |
if (response.ok && response.body) { | |
const binaryName = null | |
Readable.fromWeb(response.body).pipe(downloadedFileStream) | |
downloadedFileStream.on('error', function (err: Error) { | |
logger.error('Got Error while downloading percy binary file' + err) | |
PerformanceTester.end(PerformanceEvents.SDK_CLI_DOWNLOAD, false, util.format(err)) | |
reject(err) | |
}) | |
CLIUtils.downloadFileStream(downloadedFileStream, binaryName, zipFilePath, cliDir, resolve, reject) | |
} else { | |
const err = 'Got Error in cli binary download response' + response.status | |
logger.error(err) | |
PerformanceTester.end(PerformanceEvents.SDK_CLI_DOWNLOAD, false, err) | |
reject(err) | |
} | |
}).catch((err) => { | |
logger.error(`Got Error in cli binary downloading request ${util.format(err)}`) | |
PerformanceTester.end(PerformanceEvents.SDK_CLI_DOWNLOAD, false, util.format(err)) | |
reject(err) | |
}) | |
PerformanceTester.end(PerformanceEvents.SDK_CLI_DOWNLOAD) | |
}) | |
const response = await fetch(binDownloadUrl, { | |
redirect: 'follow' | |
}) | |
if (response.ok && response.body) { | |
const binaryName = null | |
Readable.fromWeb(response.body).pipe(downloadedFileStream) | |
downloadedFileStream.on('error', function (err: Error) { | |
logger.error('Got Error while downloading percy binary file' + err) | |
PerformanceTester.end(PerformanceEvents.SDK_CLI_DOWNLOAD, false, util.format(err)) | |
reject(err) | |
}) | |
CLIUtils.downloadFileStream(downloadedFileStream, binaryName, zipFilePath, cliDir, resolve, reject) | |
} else { | |
const err = 'Got Error in cli binary download response' + response.status | |
logger.error(err) | |
PerformanceTester.end(PerformanceEvents.SDK_CLI_DOWNLOAD, false, err) | |
reject(err) | |
} | |
PerformanceTester.end(PerformanceEvents.SDK_CLI_DOWNLOAD) | |
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I am working on adding unit tests here. Will commit with the above requested changes.
@christian-bromann We are building a new CLI binary to handle Browserstack product setup flows centrally, and move I understand the concern regarding documentation as well, which I have raised with our product team, and we have decided to redirect our documentation to BrowserStack pages. Currently, we don't have any public docs of binary internals, I'll discuss if we can publish that too. Although, for users this implementation doesn't change how they use browserstack service. So, there is no additional feature doc needed for this. |
This makes sense to me. I am happy if the service docs just reference to BrowserStack docs too. |
@AdityaHirapara please see #14527, I think the current integration is very unclear. We should come up with a plan to provide users better documentation also on the WebdriverIO side. I am curious about your team suggestions. |
As per feedback received from christian-bromann on the PR: webdriverio#14456 (review), we updated the existing BrowserStack service documentation with a link to the BrowserStack documentation.
@christian-bromann Yes, for documentation, our product team is actively looking into this on revamping the docs. To quickly address query raised
|
@christian-bromann Following this implementation, we need to implement major changes across browserstack service, which will result into Big PR. So,
To give you an idea on upcoming PRs (PRs are currently in internal testing, where mostly unit tests and bug fixes are pending)
In addition, regarding this v9 PR, we have prioritised v8 over v9. This was in consideration of the usage split and customer requests in Q1, we had to prioritise releasing support for additional support for V8. This decision was made to address the more immediate needs of the majority of our users. That said, we will be working on supporting v9 by the next quarter.
|
@AdityaHirapara this makes me wonder whether it makes sense to have the service live under a different umbrella. I mentioned it before that the current service implementation goes way over what we as WebdriverIO can maintain given we have no expertise with the BrowserStack ecosystem. With these large changes, I wonder if it would be a better decision for the BrowserStack team to maintain a custom WDIO SDK and only have a very small glue layer within the service. At this point there is no value in me reviewing these types of code changes anymore. Please let me know how you want to proceed. |
@christian-bromann we understand the concern here. Actually, this is the step towards that direction, where we move browserstack product logic out of WDIO service. So, the binary will handle communication with our products. Based on the user's configuration, the service will be responsible for running sessions on the remote BStack hub, and calling the CLI binary to perform product-specific actions based on a test config. So, going forward, fewer and fewer changes will be required on the service, which is related to Bstack products. Mostly integration changes will be required on the service. Currently, you will see code only being added, as we will need to keep old modules for fallback, in case the CLI flow fails. We can remove old code, once we verify the stability of the CLI flow. |
@christian-bromann did you get a chance to check above? Does that address your concerns? |
@AdityaHirapara can you help me understand what the protobuffer files are meant for? Shouldn't this life in a BS maintained package and consumed by the service? |
@christian-bromann protobuffer files are for GRPC contract between CLI binary and browserstack service. Service will now connect with CLI binary over GRPC call, to perform browserstack product-related actions |
@@ -25,6 +25,7 @@ | |||
"compile:all:all": "pnpm -r --filter=@wdio/compiler run build", | |||
"generate": "run-s generate:*", | |||
"generate:bidi": "tsx ./scripts/bidi/index.ts && pnpm eslint --fix packages/webdriver/src/bidi/", | |||
"generate:browserstack-proto": "npx grpc_tools_node_protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=./packages/wdio-browserstack-service/src/proto --ts_proto_opt=outputServices=grpc-js --proto_path=./packages/wdio-browserstack-service/src/proto/browserstack/sdk/v1/ --ts_proto_opt=importSuffix=.js ./packages/wdio-browserstack-service/src/proto/browserstack/sdk/v1/*.proto", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not quite sure about this. Adding complexity to our build is not ideal. Wouldn't it make more sense for BS to create an external client that contains all these proto files and build steps, publish that one to NPM and just import it here?
static logToFile(logMessage: string, logLevel: string) { | ||
try { | ||
if (!this.logFileStream) { | ||
this.ensureLogsFolder() | ||
this.logFileStream = fs.createWriteStream(this.logFilePath, { flags: 'a' }) | ||
} | ||
if (this.logFileStream && this.logFileStream.writable) { | ||
this.logFileStream.write(this.formatLog(logMessage, logLevel)) | ||
} | ||
} catch (error) { | ||
log.debug(`Failed to log to file. Error ${error}`) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This log message would pollute the wdio files every time you log something to the file which may be less desirable. I suggest:
static logToFile(logMessage: string, logLevel: string) { | |
try { | |
if (!this.logFileStream) { | |
this.ensureLogsFolder() | |
this.logFileStream = fs.createWriteStream(this.logFilePath, { flags: 'a' }) | |
} | |
if (this.logFileStream && this.logFileStream.writable) { | |
this.logFileStream.write(this.formatLog(logMessage, logLevel)) | |
} | |
} catch (error) { | |
log.debug(`Failed to log to file. Error ${error}`) | |
} | |
} | |
static logToFile(logMessage: string, logLevel: string) { | |
if (!this.logFileStream) { | |
try { | |
this.ensureLogsFolder() | |
this.logFileStream = fs.createWriteStream(this.logFilePath, { flags: 'a' }) | |
} catch (error) { | |
log.debug(`Failed to log to file. Error ${error}`) | |
this.logFileStream = { writable: false } | |
} | |
} | |
if (this.logFileStream && this.logFileStream.writable) { | |
this.logFileStream.write(this.formatLog(logMessage, logLevel)) | |
} | |
} |
import { exec } from 'node:child_process' | ||
import type { ZipFile, Options as yauzlOptions } from 'yauzl' | ||
import yauzl from 'yauzl' | ||
import { fetch } from 'undici' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason we can't just use Node.js native fetch?
import { Readable } from 'node:stream' | ||
const logger = BStackLogger | ||
|
||
export class CLIUtils { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no point IMHO to create a class when all methods are static, just export the functions directly
/** | ||
* GrpcClient - Singleton class for managing gRPC client connections | ||
* | ||
* This class uses the singleton pattern to ensure only one gRPC client instance exists | ||
* throughout the application lifecycle. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am sure this is something that should live in its own NPM package as you may want to use it in other environments other than just WDIO
Proposed changes
Types of changes
Checklist
Backport Request
//: # (The current
main
branch is the development branch for WebdriverIO v9. If your change should be released to the current major version of WebdriverIO (v8), please raise another PR with the same changes against thev8
branch.)v9
and doesn't need to be back-ported#XXXXX
Further comments
Reviewers: @webdriverio/project-committers