generated from saucelabs/new-project
-
Notifications
You must be signed in to change notification settings - Fork 0
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
feat: implement minimum required plugin functions #3
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
d946391
feat: implement minimum required plugin functions
alexplischke 12c8422
grep shenanigans
alexplischke 588d073
better wording
alexplischke 4a6d125
add cautionary note
alexplischke 02018b4
fix: not closing browser at the end of the run
alexplischke 9c7f594
docs
alexplischke File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import WebDriver, { Client } from 'webdriver'; | ||
|
||
export class SauceDriver { | ||
private readonly username: string; | ||
private readonly accessKey: string; | ||
private readonly tunnelName: string; | ||
private sessions = new Map<string, Client>(); | ||
|
||
constructor(username: string, accessKey: string, tunnelName: string) { | ||
this.username = username; | ||
this.accessKey = accessKey; | ||
this.tunnelName = tunnelName; | ||
} | ||
|
||
async openBrowser(browserId: string, url: string, browserName: string) { | ||
const webDriver = await WebDriver.newSession({ | ||
protocol: 'https', | ||
hostname: `ondemand.saucelabs.com`, // TODO multi region support | ||
port: 443, | ||
user: this.username, | ||
key: this.accessKey, | ||
capabilities: { | ||
name: 'testcafe sauce provider job', // TODO make this configurable | ||
browserName: browserName, | ||
buildName: 'TCPRVDR', // TODO make this configurable | ||
tunnelIdentifier: this.tunnelName, | ||
idleTimeout: 3600, // 1 hour | ||
}, | ||
logLevel: 'error', | ||
connectionRetryTimeout: 9 * 60 * 1000, // 9 minutes | ||
connectionRetryCount: 3, | ||
path: '/wd/hub', | ||
}); | ||
this.sessions.set(browserId, webDriver); | ||
|
||
// TODO do we need a keep-alive? | ||
|
||
await webDriver.navigateTo(url); | ||
|
||
return { | ||
jobUrl: `https://app.saucelabs.com/tests/${webDriver.sessionId}`, | ||
webDriver: webDriver, | ||
}; | ||
} | ||
|
||
async closeBrowser(browserId: string) { | ||
await this.sessions.get(browserId)?.deleteSession(); | ||
this.sessions.delete(browserId); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
export class AuthError extends Error { | ||
constructor() { | ||
super( | ||
'Authentication failed. Please assign the correct username and access key ' + | ||
'to the SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables.', | ||
); | ||
this.name = 'AuthError'; | ||
} | ||
} | ||
|
||
export class TunnelNameError extends Error { | ||
constructor() { | ||
super( | ||
'The SAUCE_TUNNEL_NAME environment variable is not set. Please start a ' + | ||
'tunnel first and set the SAUCE_TUNNEL_NAME environment variable.', | ||
); | ||
this.name = 'TunnelNameError'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,140 @@ | ||
export default { | ||
import { SauceDriver } from './driver.js'; | ||
import { AuthError, TunnelNameError } from './errors'; | ||
|
||
let sauceDriver: SauceDriver; | ||
|
||
/** | ||
* The Sauce Labs browser provider plugin for TestCafe. | ||
* | ||
* CAUTION: Do not export the `default` keyword, as TestCafe will not be able to | ||
* load the plugin. Neither does it support the `exports =` syntax without | ||
* `module`. | ||
*/ | ||
module.exports = { | ||
/** | ||
* Inspected by TestCafe to check whether the browser provider supports | ||
* multiple browsers. | ||
* | ||
* https://github.com/DevExpress/testcafe/blob/4a30f1c3b8769ca68c9b7912911f1dd8aa91d62c/src/browser/provider/index.ts#L65 | ||
*/ | ||
isMultiBrowser: true, | ||
|
||
// Required - must be implemented | ||
// Browser control | ||
async openBrowser(/* id, pageUrl, browserName */) { | ||
throw new Error('Not implemented!'); | ||
}, | ||
/** | ||
* Called by TestCafe to initialize the browser provider. | ||
* | ||
* https://github.com/DevExpress/testcafe/blob/4a30f1c3b8769ca68c9b7912911f1dd8aa91d62c/src/browser/provider/plugin-host.js#L81 | ||
*/ | ||
async init(): Promise<void> { | ||
const username = process.env.SAUCE_USERNAME; | ||
const accessKey = process.env.SAUCE_ACCESS_KEY; | ||
const tunnelName = process.env.SAUCE_TUNNEL_NAME; | ||
|
||
if (!username || !accessKey) { | ||
throw new AuthError(); | ||
} | ||
if (!tunnelName) { | ||
throw new TunnelNameError(); | ||
} | ||
|
||
async closeBrowser(/* id */) { | ||
throw new Error('Not implemented!'); | ||
sauceDriver = new SauceDriver(username, accessKey, tunnelName); | ||
}, | ||
|
||
// Optional - implement methods you need, remove other methods | ||
// Initialization | ||
async init() { | ||
return; | ||
/** | ||
* Called by TestCafe to open a browser. | ||
* | ||
* https://github.com/DevExpress/testcafe/blob/4a30f1c3b8769ca68c9b7912911f1dd8aa91d62c/src/browser/provider/plugin-host.js#L72 | ||
* | ||
* @param browserId | ||
* @param url | ||
* @param browserName | ||
*/ | ||
async openBrowser( | ||
browserId: string, | ||
url: string, | ||
browserName: string, | ||
): Promise<void> { | ||
// TODO check available concurrency and wait if necessary | ||
|
||
// TODO check tunnel status and wait if necessary | ||
// See https://docs.saucelabs.com/secure-connections/sauce-connect-5/operation/readiness-checks/. | ||
|
||
console.log('Starting browser on Sauce Labs...'); | ||
const { jobUrl } = await sauceDriver.openBrowser( | ||
browserId, | ||
url, | ||
browserName, | ||
); | ||
console.log('Browser started.'); | ||
|
||
// Pass the job URL to TestCafe, which it will append to the test report. | ||
// Output: | ||
// Running tests in: | ||
// - Chrome 122.0.0.0 / Windows 10 (https://app.saucelabs.com/tests/8545f0fb12a24da290af1f6b87dcc530) | ||
this.setUserAgentMetaInfo(browserId, jobUrl); | ||
}, | ||
|
||
async dispose() { | ||
return; | ||
/** | ||
* Called by TestCafe to close a browser. | ||
* | ||
* https://github.com/DevExpress/testcafe/blob/4a30f1c3b8769ca68c9b7912911f1dd8aa91d62c/src/browser/provider/plugin-host.js#L76 | ||
* | ||
* @param browserId | ||
*/ | ||
async closeBrowser(browserId: string): Promise<void> { | ||
await sauceDriver.closeBrowser(browserId); | ||
}, | ||
|
||
// Browser names handling | ||
async getBrowserList() { | ||
throw new Error('Not implemented!'); | ||
/** | ||
* Called by TestCafe at the end of the test run. | ||
* Perform any cleanups necessary here. | ||
* | ||
* https://github.com/DevExpress/testcafe/blob/4a30f1c3b8769ca68c9b7912911f1dd8aa91d62c/src/browser/provider/plugin-host.js#L85 | ||
*/ | ||
async dispose(): Promise<void> {}, | ||
|
||
/** | ||
* Called by TestCafe to get the list of available browsers. | ||
* | ||
* E.g. `"testcafe -b sauce"` will call this method to print the available | ||
* browsers. | ||
* | ||
* https://github.com/DevExpress/testcafe/blob/4a30f1c3b8769ca68c9b7912911f1dd8aa91d62c/src/browser/provider/plugin-host.js#L91 | ||
*/ | ||
async getBrowserList(): Promise<string[]> { | ||
return ['chrome']; | ||
}, | ||
|
||
async isValidBrowserName(/* browserName */) { | ||
return true; | ||
/** | ||
* Called by TestCafe to verify if the user specified browser is valid. | ||
* | ||
* E.g. `"testcafe -b sauce:chrome@latest"` will call this method to verify. | ||
* | ||
* https://github.com/DevExpress/testcafe/blob/4a30f1c3b8769ca68c9b7912911f1dd8aa91d62c/src/browser/provider/plugin-host.js#L95 | ||
* @param browserName | ||
*/ | ||
async isValidBrowserName(browserName: string): Promise<boolean> { | ||
return (await this.getBrowserList()).includes(browserName); | ||
}, | ||
|
||
// Extra methods | ||
/** | ||
* Called by TestCafe to resize the browser window. | ||
* | ||
* https://github.com/DevExpress/testcafe/blob/master/src/browser/provider/plugin-host.js#L126 | ||
*/ | ||
async resizeWindow(/* id, width, height, currentWidth, currentHeight */) { | ||
// this.reportWarning( | ||
// 'The window resize functionality is not supported by the "saucelabs-official" browser provider.', | ||
// ); | ||
this.reportWarning( | ||
'The window resize functionality is not supported by the Sauce Labs browser provider plugin.', | ||
); | ||
}, | ||
|
||
/** | ||
* Called by TestCafe to take a screenshot. | ||
* | ||
* https://github.com/DevExpress/testcafe/blob/4a30f1c3b8769ca68c9b7912911f1dd8aa91d62c/src/browser/provider/plugin-host.js#L134 | ||
*/ | ||
async takeScreenshot(/* id, screenshotPath, pageWidth, pageHeight */) { | ||
// this.reportWarning( | ||
// 'The screenshot functionality is not supported by the "saucelabs-official" browser provider.', | ||
// ); | ||
this.reportWarning( | ||
'The screenshot functionality is not supported by the Sauce Labs browser provider plugin.', | ||
); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Note: Removed this on a whim. Seems to work so far.