Skip to content
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: Add geckodriver download script #122

Merged
merged 8 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions .github/workflows/functional-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ jobs:
name: Start X virtual frame buffer
- run: sudo apt-get install firefox
name: Install Firefox
- run: |
latest_release="$(curl https://api.github.com/repos/mozilla/geckodriver/releases/latest | jq -r .name)"
curl -L "https://github.com/mozilla/geckodriver/releases/download/v${latest_release}/geckodriver-v${latest_release}-linux64.tar.gz" \
--output /tmp/geckodriver.tar.gz
tar -xzf /tmp/geckodriver.tar.gz
sudo mv geckodriver /usr/bin/
name: Deploy Gecko driver
- run: |
npm install -g appium
npm install
Expand All @@ -50,6 +43,8 @@ jobs:
pushd "$cwd"
cd ~
appium driver install --source=local "$cwd"
appium driver run gecko install-geckodriver
export PATH="$PATH:/usr/local/bin"
nohup appium server \
--port=$APPIUM_TEST_SERVER_PORT \
--address=$APPIUM_TEST_SERVER_HOST \
Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ Under the hood this driver is a wrapper/proxy over `geckodriver` binary. Check t

It is mandatory to have both Firefox browser installed and the geckodriver binary downloaded on the platform where automated tests are going to be executed. Firefox could be downloaded from the [official download site](https://www.mozilla.org/en-GB/firefox/all/) and the driver binary could be retrieved from the GitHub [releases page](https://github.com/mozilla/geckodriver/releases). The binary must be put into one of the folders included to PATH environment variable. On macOS it also might be necessary to run `xattr -cr "<binary_path>"` to avoid [notarization](https://firefox-source-docs.mozilla.org/testing/geckodriver/Notarization.html) issues.

Since driver version 1.4.0 the geckodriver binary deployment could be automated via the
[install-geckodriver](#install-geckodriver) driver script.

Then you need to decide where the automated test is going to be executed. Gecko driver supports the following target platforms:
- macOS
- Windows
Expand Down Expand Up @@ -56,6 +59,21 @@ setWindowRect | See https://www.w3.org/TR/webdriver/#capabilities
timeouts | See https://www.w3.org/TR/webdriver/#capabilities
unhandledPromptBehavior | See https://www.w3.org/TR/webdriver/#capabilities

## Scripts

### install-geckodriver

This script is used to install the given or latest stable version of Geckodriver server from
the [GitHub releases](https://github.com/mozilla/geckodriver/release) page.
Run `appium driver run gecko install-geckodriver <optional_version>`, where `optional_version`
must be either valid Geckodriver version number or should not be present (the latest stable version is used then).
By default, the script will download and unpack the binary into `/usr/local/bin/geckodriver`
on macOS and Linux or into `%LOCALAPPDATA%\Mozilla\geckodriver.exe` on Windows.
You must also make sure the `%LOCALAPPDATA%\Mozilla` (Windows) or `/usr/local/bin/` (Linux & macOS)
folder is present in the PATH environment variable before
starting an actual automation session. The deployment script should also show a warning message if
it is unable to find the parent folder in the PATH folders list.

## Example

```python
Expand Down
2 changes: 1 addition & 1 deletion lib/logger.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { logger } from 'appium/support';

const log = logger.getLogger('GeckoDriver');
export const log = logger.getLogger('GeckoDriver');

export default log;
100 changes: 98 additions & 2 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import _ from 'lodash';
import { fs, net, zip, tempDir } from 'appium/support';
import tar from 'tar-stream';
import zlib from 'node:zlib';
import B from 'bluebird';
import path from 'node:path';

const GECKO_CAP_PREFIXES = ['moz:'];
// https://www.w3.org/TR/webdriver/#capabilities
Expand All @@ -13,7 +18,7 @@ const STANDARD_CAPS = [
'unhandledPromptBehavior',
];

function formatCapsForServer (caps) {
export function formatCapsForServer (caps) {
const result = {};
if (caps.browserName) {
result.browserName = 'firefox';
Expand All @@ -30,4 +35,95 @@ function formatCapsForServer (caps) {
return result;
}

export { formatCapsForServer };
/**
*
* @param {string} srcUrl
* @param {string} dstPath
* @returns {Promise<void>}
*/
export async function downloadToFile(srcUrl, dstPath) {
await net.downloadFile(srcUrl, dstPath);
}

/**
*
* @param {string} p
* @returns {Promise<void>}
*/
export async function mkdirp(p) {
await fs.mkdirp(p);
}

/**
*
* @param {string} srcAcrhive
* @param {string} fileToExtract
* @param {string} dstPath
* @returns {Promise<void>}
*/
export async function extractFileFromTarGz(srcAcrhive, fileToExtract, dstPath) {
const chunks = [];
const extract = tar.extract();
const extractPromise = new B((resolve, reject) => {
extract.on('entry', (header, stream, next) => {
if (header.name === fileToExtract) {
stream.on('data', (chunk) => {
chunks.push(chunk);
});
}
stream.on('end', function() {
next();
});
stream.resume();
});
extract.once('error', reject);
extract.once('finish', async () => {
if (chunks.length) {
try {
await fs.writeFile(dstPath, Buffer.concat(chunks));
} catch (e) {
return reject(e);
}
} else {
return reject(
new Error(`The file '${fileToExtract}' could not be found in the '${srcAcrhive}' archive`)
);
}
resolve();
});
});

fs.createReadStream(srcAcrhive)
.pipe(zlib.createGunzip())
.pipe(extract);

await extractPromise;
}

/**
*
* @param {string} srcAcrhive
* @param {string} fileToExtract
* @param {string} dstPath
* @returns {Promise<void>}
*/
export async function extractFileFromZip(srcAcrhive, fileToExtract, dstPath) {
let didFindEntry = false;
await zip.readEntries(srcAcrhive, async ({entry, extractEntryTo}) => {
if (didFindEntry || entry.fileName !== fileToExtract) {
return;
}
didFindEntry = true;

const tmpRoot = await tempDir.openDir();
try {
await extractEntryTo(tmpRoot);
await fs.mv(path.resolve(tmpRoot, entry.fileName), dstPath);
} finally {
await fs.rimraf(tmpRoot);
}
});
if (!didFindEntry) {
throw new Error(`The file '${fileToExtract}' could not be found in the '${srcAcrhive}' archive`);
}
}
15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,38 @@
"Android",
"Windows"
],
"scripts": {
"install-geckodriver": "./scripts/install-geckodriver.mjs"
},
"mainClass": "GeckoDriver"
},
"main": "./build/index.js",
"bin": {},
"directories": {
"lib": "lib"
},
"files": [
"index.js",
"lib",
"build",
"CHANGELOG.md",
"LICENSE",
"npm-shrinkwrap.json",
"scripts/*.mjs"
],
"peerDependencies": {
"appium": "^2.4.1"
},
"dependencies": {
"appium-adb": "^12.0.3",
"asyncbox": "^3.0.0",
"axios": "^1.7.7",
"bluebird": "^3.5.1",
"lodash": "^4.17.4",
"portscanner": "2.2.0",
"semver": "^7.6.3",
"source-map-support": "^0.x",
"tar-stream": "^3.1.7",
"teen_process": "^2.0.0"
},
"scripts": {
Expand Down
Loading
Loading