-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Ngo Iok Ui (Wu Yu Wei) <wusyong9104@gmail.com>
- Loading branch information
Showing
7 changed files
with
898 additions
and
12 deletions.
There are no files selected for viewing
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,100 @@ | ||
--- | ||
title: Continuous Integration | ||
--- | ||
|
||
Utilizing Linux and some programs to create a fake display, it is possible to run [WebDriver] tests with | ||
[`tauri-driver`] on your CI. The following example will use the [WebdriverIO] example we [previously built together] and | ||
GitHub Actions. | ||
|
||
This means the following assumptions: | ||
|
||
1. The Tauri application is in the repository root and the binary builds when running `cargo build --release`. | ||
2. The [WebDriverIO] test runner is in the `webdriver/webdriverio` directory and runs when `yarn test` is used in that | ||
directory. | ||
|
||
The following is a commented GitHub Actions workflow file at `.github/workflows/webdriver.yml` | ||
|
||
```yaml | ||
# run this action when the repository is pushed to | ||
on: [ push ] | ||
|
||
# the name of our workflow | ||
name: WebDriver | ||
|
||
jobs: | ||
# a single job named test | ||
test: | ||
# the display name the test job | ||
name: WebDriverIO Test Runner | ||
|
||
# we want to run on the latest linux environment | ||
runs-on: ubuntu-latest | ||
|
||
# the steps our job runs **in order** | ||
steps: | ||
# checkout the code on the workflow runner | ||
- uses: actions/checkout@v2 | ||
|
||
# install system dependencies that Tauri needs to compile on Linux. | ||
# note the extra dependencies for `tauri-driver` to run which are `webkit2gtk-driver` and `xvfb` | ||
- name: Tauri dependencies | ||
run: >- | ||
sudo apt-get update && | ||
sudo apt-get install -y | ||
libgtk-3-dev | ||
libgtksourceview-3.0-dev | ||
webkit2gtk-4.0 | ||
libappindicator3-dev | ||
webkit2gtk-driver | ||
xvfb | ||
# install the latest Rust stable | ||
- name: Rust stable | ||
uses: actions-rs/toolchain@v1 | ||
with: | ||
toolchain: stable | ||
|
||
# we run our rust tests before the webdriver tests to avoid testing a broken application | ||
- name: Cargo test | ||
uses: actions-rs/cargo@v1 | ||
with: | ||
command: test | ||
|
||
# build a release build of our application to be used during our WebdriverIO tests | ||
- name: Cargo build | ||
uses: actions-rs/cargo@v1 | ||
with: | ||
command: build | ||
args: --release | ||
|
||
# install the latest stable node version at the time of writing | ||
- name: Node v16 | ||
uses: actions/setup-node@v1 | ||
with: | ||
node-version: 16.x | ||
|
||
# install our Node.js dependencies with Yarn | ||
- name: Yarn install | ||
run: yarn install | ||
working-directory: webdriver/webdriverio | ||
|
||
# install the latest version of `tauri-driver`. | ||
# note: the tauri-driver version is independent of any other Tauri versions | ||
- name: Install tauri-driver | ||
uses: actions-rs/cargo@v1 | ||
with: | ||
command: install | ||
args: tauri-driver | ||
|
||
# run the WebdriverIO test suite. | ||
# we run it through `xvfb-run` (the dependency we installed earlier) to have a fake | ||
# display server which allows our application to run headless without any changes to the code | ||
- name: WebdriverIO | ||
run: xvfb-run yarn test | ||
working-directory: webdriver/webdriverio | ||
``` | ||
|
||
[WebDriver]: https://www.w3.org/TR/webdriver/ | ||
[`tauri-driver`]: https://crates.io/crates/tauri-driver | ||
[WebdriverIO]: https://webdriver.io/ | ||
[previously built together]: example/webdriverio |
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,256 @@ | ||
--- | ||
title: Selenium | ||
--- | ||
import Alert from '@theme/Alert' | ||
import Tabs from '@theme/Tabs' | ||
import TabItem from '@theme/TabItem' | ||
|
||
<Alert title="Example Application" type="info" icon="info-alt"> | ||
|
||
This [Selenium] guide expects you to have already gone through the [example Application setup] in order to follow | ||
step-by-step. The general information may still be useful otherwise. | ||
</Alert> | ||
|
||
This WebDriver testing example will use [Selenium] and a popular Node.js testing suite. It is expected to already have | ||
Node.js installed, along with `npm` or `yarn` although the [finished example project] uses `yarn`. | ||
|
||
## Create a Directory for the Tests | ||
|
||
Let's start off by creating a space in our project to write these tests. We are going to be using a nested directory for | ||
this example project as we will later also go over other frameworks, but typically you will only need to use one. Create | ||
the directory we will use with `mkdir -p webdriver/selenium`. The rest of this guide will assume you are inside the | ||
`webdriver/selenium` directory. | ||
|
||
## Initializing a Selenium Project | ||
|
||
We will be using a pre-existing `package.json` to bootstrap this test suite because we have already chosen specific | ||
dependencies to use and want to showcase a simple working solution. The bottom of this section has a collapsed | ||
guide on how to set it up from scratch. | ||
|
||
`package.json`: | ||
```json | ||
{ | ||
"name": "selenium", | ||
"version": "1.0.0", | ||
"private": true, | ||
"scripts": { | ||
"test": "mocha" | ||
}, | ||
"dependencies": { | ||
"chai": "^4.3.4", | ||
"mocha": "^9.0.3", | ||
"selenium-webdriver": "^4.0.0-beta.4" | ||
} | ||
} | ||
``` | ||
|
||
We have a script which runs [Mocha] as a test framework exposed as the `test` command. We also have various dependencies | ||
that we will be using to run the tests. [Mocha] as the testing framework, [Chai] as the assertion library, and | ||
[`selenium-webdriver`] which is the Node.js [Selenium] package. | ||
|
||
<details><summary>Click me if you want to see how to set a project up from scratch</summary> | ||
|
||
If you wanted to install the dependencies from scratch, just run the following command. | ||
|
||
<Tabs groupId="package-manager" | ||
defaultValue="yarn" | ||
values={[ | ||
{label: 'npm', value: 'npm'}, {label: 'Yarn', value: 'yarn'}, | ||
]}> | ||
<TabItem value="npm"> | ||
|
||
```sh | ||
npm install mocha chai selenium-webdriver | ||
``` | ||
|
||
</TabItem> | ||
|
||
<TabItem value="yarn"> | ||
|
||
```sh | ||
yarn add mocha chai selenium-webdriver | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
I suggest also adding a `"test": "mocha"` item in the `package.json` `"scripts"` key so that running mocha can be called | ||
simply with | ||
|
||
<Tabs groupId="package-manager" | ||
defaultValue="yarn" | ||
values={[ | ||
{label: 'npm', value: 'npm'}, {label: 'Yarn', value: 'yarn'}, | ||
]}> | ||
<TabItem value="npm"> | ||
|
||
```sh | ||
npm test | ||
``` | ||
|
||
</TabItem> | ||
|
||
<TabItem value="yarn"> | ||
|
||
```sh | ||
yarn test | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
</details> | ||
|
||
## Testing | ||
|
||
Unlike the [WebdriverIO Test Suite](webdriverio#config), Selenium does not come out of the box with a Test Suite and | ||
leaves it up to the developer to build those out. We chose [Mocha] which is pretty neutral, and not related to WebDrivers | ||
at all, so our script will need to do a bit of work to set up everything for us in the right order. [Mocha] expects a | ||
testing file at `test/test.js` by default, so let's create that file now. | ||
|
||
`test/test.js`: | ||
```js | ||
const os = require("os"); | ||
const path = require("path"); | ||
const { expect } = require("chai"); | ||
const { spawn, spawnSync } = require("child_process"); | ||
const { Builder, By, Capabilities } = require("selenium-webdriver"); | ||
|
||
// create the path to the expected application binary | ||
const application = path.resolve( | ||
__dirname, | ||
"..", | ||
"..", | ||
"..", | ||
"target", | ||
"release", | ||
"hello-tauri-webdriver" | ||
); | ||
|
||
// keep track of the webdriver instance we create | ||
let driver; | ||
|
||
// keep track of the tauri-driver process we start | ||
let tauriDriver; | ||
|
||
before(async function() { | ||
// set timeout to 2 minutes to allow the program to build if it needs to | ||
this.timeout(120000) | ||
|
||
// ensure the program has been built | ||
spawnSync("cargo", ["build", "--release"]); | ||
|
||
// start tauri-driver | ||
tauriDriver = spawn( | ||
path.resolve(os.homedir(), ".cargo", "bin", "tauri-driver"), | ||
[], | ||
{ stdio: [null, process.stdout, process.stderr] } | ||
); | ||
|
||
const capabilities = new Capabilities(); | ||
capabilities.set("tauri:options", { application }); | ||
capabilities.setBrowserName("wry"); | ||
|
||
// start the webdriver client | ||
driver = await new Builder() | ||
.withCapabilities(capabilities) | ||
.usingServer("http://localhost:4444/") | ||
.build(); | ||
}); | ||
|
||
after(async function() { | ||
// stop the webdriver session | ||
await driver.quit(); | ||
|
||
// kill the tauri-driver process | ||
tauriDriver.kill(); | ||
}); | ||
|
||
describe("Hello Tauri", () => { | ||
it("should be cordial", async () => { | ||
const text = await driver.findElement(By.css("body > h1")).getText(); | ||
expect(text).to.match(/^[hH]ello/); | ||
}); | ||
|
||
it("should be excited", async () => { | ||
const text = await driver.findElement(By.css("body > h1")).getText(); | ||
expect(text).to.match(/!$/); | ||
}); | ||
|
||
it("should be easy on the eyes", async () => { | ||
// selenium returns color css values as rgb(r, g, b) | ||
const text = await driver.findElement(By.css("body")).getCssValue("background-color"); | ||
|
||
const rgb = text.match(/^rgb\((?<r>\d+), (?<g>\d+), (?<b>\d+)\)$/).groups; | ||
expect(rgb).to.have.all.keys('r','g','b'); | ||
|
||
const luma = 0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b ; | ||
expect(luma).to.be.lessThan(100) | ||
}); | ||
}); | ||
``` | ||
|
||
If you are familiar with JS testing frameworks, `describe`, `it`, and `expect` should look familiar. We also have | ||
semi-complex `before()` and `after()` callbacks to setup and teardown mocha. Lines that are not the tests themselves | ||
have comments explaining what the setup and teardown code is doing. If you were familiar with the Spec file from the | ||
[WebdriverIO example](webdriverio#spec), you will notice a lot more code that isn't tests, as we have to set up a few | ||
more WebDriver related items. | ||
|
||
## Running the Test Suite | ||
|
||
Now that we are all set up with our dependencies and our test script, lets run it! | ||
|
||
<Tabs groupId="package-manager" | ||
defaultValue="yarn" | ||
values={[ | ||
{label: 'npm', value: 'npm'}, {label: 'Yarn', value: 'yarn'}, | ||
]}> | ||
<TabItem value="npm"> | ||
|
||
```sh | ||
npm test | ||
``` | ||
|
||
</TabItem> | ||
|
||
<TabItem value="yarn"> | ||
|
||
```sh | ||
yarn test | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
We should see output the following output: | ||
|
||
```text | ||
➜ selenium git:(main) ✗ yarn test | ||
yarn run v1.22.11 | ||
$ mocha | ||
Hello Tauri | ||
✔ should be cordial (120ms) | ||
✔ should be excited | ||
✔ should be easy on the eyes | ||
3 passing (588ms) | ||
Done in 0.93s. | ||
``` | ||
|
||
We can see that our `Hello Tauri` sweet we created with `decribe` had all 3 items we created with `it` pass their | ||
tests! | ||
|
||
With [Selenium] and some hooking up to a test suite, we just enabled e2e testing without modifying our Tauri | ||
application at all! | ||
|
||
|
||
[Selenium]: https://selenium.dev/ | ||
[finished example project]: https://github.com/chippers/hello_tauri | ||
[example Application setup]: setup | ||
[Mocha]: https://mochajs.org/ | ||
[Chai]: https://www.chaijs.com/ | ||
[`selenium-webdriver`]: https://www.npmjs.com/package/selenium-webdriver |
Oops, something went wrong.