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: support installing a compatible version of ChromeDriver #548

Merged
merged 20 commits into from
May 26, 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
5 changes: 5 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,16 @@ jobs:
uses: ./
with:
chrome-version: ${{ matrix.version }}
install-chromedriver: true
id: setup-chrome
- if: runner.os == 'Linux' || runner.os == 'macOS'
run: |
"${{ steps.setup-chrome.outputs.chrome-path }}" --version
"${{ steps.setup-chrome.outputs.chromedriver-path }}" --version
- if: runner.os == 'Windows'
run: |
(Get-Item (Get-Command "${{ steps.setup-chrome.outputs.chrome-path }}").Source).VersionInfo.ProductVersion
(Get-Item (Get-Command "${{ steps.setup-chrome.outputs.chromedriver-path }}").Source).VersionInfo.ProductVersion

test-install-dependencies:
needs: [build]
Expand Down Expand Up @@ -82,7 +85,9 @@ jobs:
uses: ./
with:
chrome-version: 120
install-chromedriver: true
install-dependencies: true
id: setup-chrome
- run: |
"${{ steps.setup-chrome.outputs.chrome-path }}" --version
"${{ steps.setup-chrome.outputs.chromedriver-path }}" --version
2 changes: 2 additions & 0 deletions .github/workflows/manual-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ jobs:
- if: runner.os == 'Linux' || runner.os == 'macOS'
run: |
"${{ steps.setup-chrome.outputs.chrome-path }}" --version
"${{ steps.setup-chrome.outputs.chromedriver-path }}" --version
- if: runner.os == 'Windows'
run: |
(Get-Item (Get-Command "${{ steps.setup-chrome.outputs.chrome-path }}").Source).VersionInfo.ProductVersion
(Get-Item (Get-Command "${{ steps.setup-chrome.outputs.chromedriver-path }}").Source).VersionInfo.ProductVersion
25 changes: 20 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

# setup-chrome

This action sets by Google Chrome/Chromium for use in actions by:
This action sets-up Google Chrome/Chromium for GitHub Actions. This action supports the following features:

- [X] Install and setup latest Chromium
- [X] Cross platform runner (macOS, Linux, Windows)
- [X] Install Google Chrome by channel (stable, beta, dev, and canary)
- [X] Install by version number (88.0.4324, or 88.0)
- Install and setup the Google Chrome onto the runner.
- Install a specific version of Google Chrome/Chromium by the version number, commit position, and release channel.
- Cross-platform runner support (Windows, macOS, Linux) and self-hosted runner support.
- Install the compatible versions of ChromeDriver with the browser.

## Usage

Expand All @@ -31,6 +31,17 @@ steps:
chrome-version: 120
```

The action support installing the compatible ChromeDriver with the browser.
You can use the `install-chromedriver` to install the ChromeDriver.

```yaml
steps:
- uses: browser-actions/setup-chrome@v1
with:
chrome-version: 120
install-chromedriver: true
```

If you use the self-hosted runner, your runner may not have the required dependencies on the system.
You can install the dependencies by using the `install-dependencies` parameter.
It installs the required dependencies for the Google Chrome/Chromium to run automatically.
Expand Down Expand Up @@ -77,11 +88,15 @@ steps:
Default: `latest`
- `install-dependencies`: *(Optional)* Install the required dependencies for the Google Chrome/Chromium to run.
Default: `false`
- `install-chromedriver`: *(Optional)* Install the compatible ChromeDriver with the browser.
Default: `false`

### Outputs

- `chrome-path`: The installed Google Chrome/Chromium binary path.
- `chrome-version`: The installed Google Chrome/Chromium version.
- `chromedriver-path`: The installed ChromeDriver binary path.
- `chromedriver-version`: The installed ChromeDriver version.

[snapshots]: https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html

Expand Down
154 changes: 154 additions & 0 deletions __test__/channel_linux.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import * as fs from "node:fs";
import * as exec from "@actions/exec";
import * as tc from "@actions/tool-cache";
import { afterEach, describe, expect, test, vi } from "vitest";
import * as cache from "../src/cache";
import { LinuxChannelInstaller } from "../src/channel_linux";

const cacheFindSpy = vi.spyOn(cache, "find");
const cacheCacheDirSpy = vi.spyOn(cache, "cacheDir");
const tcDownloadToolSpy = vi.spyOn(tc, "downloadTool");
const tcExtractZipSpy = vi.spyOn(tc, "extractZip");
const execSpy = vi.spyOn(exec, "exec");
const fsMkdtempSpy = vi.spyOn(fs.promises, "mkdtemp");
const fsUnlinkSpy = vi.spyOn(fs.promises, "unlink");

afterEach(() => {
vi.resetAllMocks();
});

describe("LinuxChannelInstaller", () => {
const installer = new LinuxChannelInstaller({ os: "linux", arch: "amd64" });

describe("checkInstalledBrowser", () => {
test("return undefined if not installed", async () => {
cacheFindSpy.mockResolvedValue(undefined);

const result = await installer.checkInstalledBrowser("stable");

expect(result).toBeUndefined();
});

test("return install result if installed", async () => {
cacheFindSpy.mockResolvedValue("/path/to/chromium");

const result = await installer.checkInstalledBrowser("stable");

expect(result).toEqual({ root: "/path/to/chromium", bin: "chrome" });
});
});

describe("downloadBrowser", () => {
test("throw error if version is not release channel", async () => {
await expect(installer.downloadBrowser("foo")).rejects.toThrowError(
"Unexpected version: foo",
);
});

test("throw error if version is canary", async () => {
await expect(installer.downloadBrowser("canary")).rejects.toThrowError(
"Chrome canary not supported for platform linux amd64",
);
});

test("download stable version", async () => {
tcDownloadToolSpy.mockResolvedValue("/path/to/downloaded.deb");

const result = await installer.downloadBrowser("stable");

expect(result).toEqual({ archive: "/path/to/downloaded.deb" });
expect(tcDownloadToolSpy).toHaveBeenCalled();
});
});

describe("installBrowser", () => {
test("throw error if version is not release channel", async () => {
await expect(
installer.installBrowser("foo", "/path/to/downloaded.deb"),
).rejects.toThrowError("Unexpected version: foo");
});

test("throw error if version is canary", async () => {
await expect(
installer.installBrowser("canary", "/path/to/downloaded.deb"),
).rejects.toThrowError("Chrome canary not supported for Linux");
});

test("install stable version", async () => {
fsMkdtempSpy.mockResolvedValue("/deb-abcdef");
fsUnlinkSpy.mockResolvedValue(undefined);
execSpy.mockResolvedValue(0);
cacheCacheDirSpy.mockResolvedValue("/path/to/chromium");

const result = await installer.installBrowser(
"stable",
"/path/to/downloaded.deb",
);

expect(result).toEqual({ root: "/path/to/chromium", bin: "chrome" });
expect(cacheCacheDirSpy).toHaveBeenCalledWith(
"/deb-abcdef",
"chromium",
"stable",
);
});
});

describe("checkInstalledDriver", () => {
test("return undefined if not installed", async () => {
cacheFindSpy.mockResolvedValue(undefined);

const result = await installer.checkInstalledDriver("stable");
expect(result).toBeUndefined();
});

test("return install result if installed", async () => {
cacheFindSpy.mockResolvedValue("/path/to/chromedriver");

const result = await installer.checkInstalledDriver("stable");
expect(result).toEqual({
root: "/path/to/chromedriver",
bin: "chromedriver",
});
});
});

describe("downloadDriver", () => {
test("throw error if version is not release channel", async () => {
await expect(installer.downloadDriver("foo")).rejects.toThrowError(
"Invalid version: foo",
);
});

test("download stable version", async () => {
tcDownloadToolSpy.mockResolvedValue("/tmp/chromedirver.zip");

const result = await installer.downloadDriver("stable");

expect(result).toEqual({ archive: "/tmp/chromedirver.zip" });
expect(tcDownloadToolSpy).toHaveBeenCalled();
});
});

describe("installDriver", () => {
test("install stable version", async () => {
tcExtractZipSpy.mockResolvedValue("/tmp/chromedriver");
cacheCacheDirSpy.mockResolvedValue("/path/to/chromedriver");

const result = await installer.installDriver(
"stable",
"/path/to/downloaded.deb",
);

expect(result).toEqual({
root: "/path/to/chromedriver",
bin: "chromedriver",
});
expect(cacheCacheDirSpy).toHaveBeenCalledWith(
"/tmp/chromedriver/chromedriver-linux64",
"chromedriver",
"stable",
);
});
});
});
147 changes: 147 additions & 0 deletions __test__/channel_macos.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import * as fs from "node:fs";
import * as exec from "@actions/exec";
import * as tc from "@actions/tool-cache";
import { afterEach, describe, expect, test, vi } from "vitest";
import * as cache from "../src/cache";
import { MacOSChannelInstaller } from "../src/channel_macos";

const cacheFindSpy = vi.spyOn(cache, "find");
const cacheCacheDirSpy = vi.spyOn(cache, "cacheDir");
const tcDownloadToolSpy = vi.spyOn(tc, "downloadTool");
const tcExtractZipSpy = vi.spyOn(tc, "extractZip");
const fsSymlinkSpy = vi.spyOn(fs.promises, "symlink");
const execSpy = vi.spyOn(exec, "exec");

afterEach(() => {
vi.resetAllMocks();
});

describe("MacOSChannelInstaller", () => {
const installer = new MacOSChannelInstaller({
os: "darwin",
arch: "amd64",
});

describe("checkInstalledBrowser", () => {
test("return undefined if not installed", async () => {
cacheFindSpy.mockResolvedValue(undefined);

const result = await installer.checkInstalledBrowser("stable");

expect(result).toBeUndefined();
});

test("return install result if installed", async () => {
cacheFindSpy.mockResolvedValue("/path/to/Chromium.app");

const result = await installer.checkInstalledBrowser("stable");

expect(result).toEqual({
root: "/path/to/Chromium.app",
bin: "Contents/MacOS/chrome",
});
});
});

describe("downloadBrowser", () => {
test("throw error if version is not release channel", async () => {
await expect(installer.downloadBrowser("foo")).rejects.toThrowError(
"Unexpected version: foo",
);
});

test("download stable version", async () => {
tcDownloadToolSpy.mockResolvedValue("/path/to/downloaded.dmg");

const result = await installer.downloadBrowser("stable");

expect(result).toEqual({ archive: "/path/to/downloaded.dmg" });
});
});

describe("installBrowser", () => {
test("throw error if version is not release channel", async () => {
await expect(
installer.installBrowser("foo", "/path/to/downloaded.dmg"),
).rejects.toThrowError("Unexpected version: foo");
});

test("install stable version", async () => {
execSpy.mockResolvedValue(0);
fsSymlinkSpy.mockResolvedValue();
cacheCacheDirSpy.mockResolvedValue("/path/to/Chromium.app");

const result = await installer.installBrowser(
"stable",
"/path/to/downloaded.dmg",
);

expect(result).toEqual({
root: "/path/to/Chromium.app",
bin: "Contents/MacOS/chrome",
});
expect(cacheCacheDirSpy).toHaveBeenCalledWith(
"/Volumes/downloaded.dmg/Google Chrome.app",
"chromium",
"stable",
);
});
});

describe("checkInstalledDriver", () => {
test("return undefined if not installed", async () => {
cacheFindSpy.mockResolvedValue(undefined);

const result = await installer.checkInstalledDriver("stable");
expect(result).toBeUndefined();
});

test("return install result if installed", async () => {
cacheFindSpy.mockResolvedValue("/path/to/chromedriver");

const result = await installer.checkInstalledDriver("stable");
expect(result).toEqual({
root: "/path/to/chromedriver",
bin: "chromedriver",
});
});
});

describe("downloadDriver", () => {
test("throw error if version is not release channel", async () => {
await expect(installer.downloadDriver("foo")).rejects.toThrowError(
"Invalid version: foo",
);
});

test("download driver", async () => {
tcDownloadToolSpy.mockResolvedValue("/path/to/downloaded.zip");

const result = await installer.downloadDriver("stable");

expect(result).toEqual({ archive: "/path/to/downloaded.zip" });
});
});

describe("installDriver", () => {
test("install driver", async () => {
cacheCacheDirSpy.mockResolvedValue("/path/to/chromedriver");
tcExtractZipSpy.mockResolvedValue("/path/to/chromedriver");

const result = await installer.installDriver(
"stable",
"/path/to/chromedriver.zip",
);

expect(result).toEqual({
root: "/path/to/chromedriver",
bin: "chromedriver",
});
expect(cacheCacheDirSpy).toHaveBeenCalledWith(
"/path/to/chromedriver/chromedriver-mac-x64",
"chromedriver",
"stable",
);
});
});
});
Loading