Migrate //scouting:scouting_test to Protractor
This framework automatically takes care of the webdriver/selenium
setup. It just lets us focus on writing tests.
This patch migrates the scouting test to use Protractor. It validates
that the application loads correctly and displays the only message
that exists so far.
I can confirm that that test uses a sandboxed version of the chromium
browser:
$ bazel cquery 'somepath(//scouting:scouting_test, @org_chromium_chromium_linux_x64//:metadata)' 2>/dev/null
//scouting:scouting_test (cdf6808)
//scouting:scouting_test_chromium-local (cdf6808)
@io_bazel_rules_webtesting//browsers:chromium-local (3ee7ec9)
@io_bazel_rules_webtesting//third_party/chromium:chromium (3ee7ec9)
@org_chromium_chromium_linux_x64//:metadata (3ee7ec9)
I based the test itself on the upstream example code:
https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular/e2e/src
Signed-off-by: Philipp Schrader <philipp.schrader@gmail.com>
Change-Id: I8d24e82077af3c104d676168e52ecec89fda8004
diff --git a/scouting/BUILD b/scouting/BUILD
index 9b8adee..0ed540b 100644
--- a/scouting/BUILD
+++ b/scouting/BUILD
@@ -1,5 +1,5 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-load("//tools/build_rules:js.bzl", "turn_files_into_runfiles")
+load("//tools/build_rules:js.bzl", "protractor_ts_test", "turn_files_into_runfiles")
go_binary(
name = "sql_demo",
@@ -35,12 +35,11 @@
],
)
-py_test(
+protractor_ts_test(
name = "scouting_test",
srcs = [
- "scouting_test.py",
+ ":scouting_test.ts",
],
- data = [
- ":scouting",
- ],
+ on_prepare = ":scouting_test.protractor.on-prepare.js",
+ server = ":scouting",
)
diff --git a/scouting/scouting_test.protractor.on-prepare.js b/scouting/scouting_test.protractor.on-prepare.js
new file mode 100644
index 0000000..7919fe7
--- /dev/null
+++ b/scouting/scouting_test.protractor.on-prepare.js
@@ -0,0 +1,22 @@
+// The function exported from this file is used by the protractor_web_test_suite.
+// It is passed to the `onPrepare` configuration setting in protractor and executed
+// before running tests.
+//
+// If the function returns a promise, as it does here, protractor will wait
+// for the promise to resolve before running tests.
+
+const protractorUtils = require('@bazel/protractor/protractor-utils');
+const protractor = require('protractor');
+
+module.exports = function(config) {
+ // In this example, `@bazel/protractor/protractor-utils` is used to run
+ // the server. protractorUtils.runServer() runs the server on a randomly
+ // selected port (given a port flag to pass to the server as an argument).
+ // The port used is returned in serverSpec and the protractor serverUrl
+ // is the configured.
+ return protractorUtils
+ .runServer(config.workspace, config.server, '--port', [])
+ .then(serverSpec => {
+ protractor.browser.baseUrl = `http://localhost:${serverSpec.port}`;
+ });
+};
diff --git a/scouting/scouting_test.py b/scouting/scouting_test.py
deleted file mode 100644
index 3b62224..0000000
--- a/scouting/scouting_test.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# TODO(phil): Delete this and replace it with a selenium test. Preferably
-# written in either Javascript or Go.
-
-import socket
-import subprocess
-import time
-import unittest
-import urllib.request
-
-class TestDebugCli(unittest.TestCase):
-
- def setUp(self):
- self.webserver = subprocess.Popen(["scouting/scouting"])
-
- # Wait for the server to respond to requests.
- while True:
- try:
- connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- connection.connect(("localhost", 8080))
- connection.close()
- break
- except ConnectionRefusedError:
- connection.close()
- time.sleep(0.01)
-
- def tearDown(self):
- self.webserver.terminate()
- self.webserver.wait()
-
- def test_index_html(self):
- """Makes sure that we the scouting server is serving our main index.html file."""
- with urllib.request.urlopen("http://localhost:8080/") as file:
- html = file.read().decode("utf-8")
- self.assertIn("<my-app></my-app>", html)
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/scouting/scouting_test.ts b/scouting/scouting_test.ts
new file mode 100644
index 0000000..bb1c075
--- /dev/null
+++ b/scouting/scouting_test.ts
@@ -0,0 +1,32 @@
+import {browser, by, element} from 'protractor';
+
+class AppPage {
+ async navigateTo() {
+ await browser.get(browser.baseUrl);
+ }
+
+ // Wait for basically forever for these elements to appear.
+ // Bazel will manage the timeouts.
+ async waitForElement(el, timeout = 1000000) {
+ await browser.wait(() => el.isPresent(), timeout);
+ await browser.wait(() => el.isDisplayed(), timeout);
+ return el;
+ }
+
+ async getParagraphText() {
+ return (await this.waitForElement(element(by.css('h1')))).getText();
+ }
+}
+
+describe('The scouting web page', () => {
+ let page: AppPage;
+
+ beforeEach(() => {
+ page = new AppPage();
+ });
+
+ it('should display: This is an app.', async () => {
+ await page.navigateTo();
+ expect(await page.getParagraphText()).toEqual('This is an app.');
+ });
+});