Fix flaky //scouting:scouting_test

The test occasionally fails because of the alerts that pop up when
navigating away from the page. I've failed to make protractor deal
with the alerts in a reliable way. So this patch turns them off.
There's a special hidden checkbox that the test checks. When it's
checked, the scouting application does not display alerts. It's hacky,
but it seems to work. Rather than failing ~10 out of 1000 times, the
test now fails 0 out of 1000 times.

Signed-off-by: Philipp Schrader <philipp.schrader@gmail.com>
Change-Id: I2e920771c1605464994d7877da2bbb62a2e69d1f
diff --git a/scouting/scouting_test.ts b/scouting/scouting_test.ts
index db0c9fd..c63251b 100644
--- a/scouting/scouting_test.ts
+++ b/scouting/scouting_test.ts
@@ -3,14 +3,21 @@
 // Loads the page (or reloads it) and deals with the "Are you sure you want to
 // leave this page" popup.
 async function loadPage() {
-  await browser.get(browser.baseUrl).catch(function () {
-    return browser.switchTo().alert().then(function (alert) {
-      alert.accept();
-      return browser.get(browser.baseUrl);
-    });
-  });
+  await disableAlerts();
+  await browser.navigate().refresh();
+  expect((await browser.getTitle())).toEqual('FRC971 Scouting Application');
 }
 
+// Disables alert popups. They are extremely tedious to deal with in
+// Protractor since they're not angular elements. We achieve this by checking
+// an invisible checkbox that's off-screen.
+async function disableAlerts() {
+  await browser.executeAsyncScript(function (callback) {
+    const block_alerts = document.getElementById('block_alerts') as HTMLInputElement;
+    block_alerts.checked = true;
+    callback();
+  });
+}
 // Returns the contents of the header that displays the "Auto", "TeleOp", and
 // "Climb" labels etc.
 function getHeadingText() {
@@ -37,6 +44,12 @@
 }
 
 describe('The scouting web page', () => {
+  beforeAll(async () => {
+    await browser.get(browser.baseUrl);
+    expect((await browser.getTitle())).toEqual('FRC971 Scouting Application');
+    await disableAlerts();
+  });
+
   it('should: review and submit correct data.', async () => {
     await loadPage();
 
diff --git a/scouting/www/app.ng.html b/scouting/www/app.ng.html
index 2fafceb..d4ee5f4 100644
--- a/scouting/www/app.ng.html
+++ b/scouting/www/app.ng.html
@@ -1,3 +1,8 @@
+<!-- Hidden element for protractor to disable alerts. -->
+<form class="visually-hidden">
+  <input type="checkbox" name="block_alerts" value="1" id="block_alerts" #block_alerts>
+</form>
+
 <ul class="nav nav-tabs">
   <li class="nav-item">
     <a class="nav-link" [class.active]="tabIs('Entry')" (click)="switchTabTo('Entry')">Data Entry</a>
diff --git a/scouting/www/app.ts b/scouting/www/app.ts
index 79c1094..18f08d4 100644
--- a/scouting/www/app.ts
+++ b/scouting/www/app.ts
@@ -1,4 +1,4 @@
-import {Component} from '@angular/core';
+import {Component, ElementRef, ViewChild} from '@angular/core';
 
 type Tab = 'Entry'|'ImportMatchList';
 
@@ -10,12 +10,16 @@
 export class App {
   tab: Tab = 'Entry';
 
+  @ViewChild("block_alerts") block_alerts: ElementRef;
+
   constructor() {
     window.addEventListener('beforeunload', (e) => {
-      // Based on https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload#example
-      // This combination ensures a dialog will be shown on most browsers.
-      e.preventDefault();
-      e.returnValue = '';
+      if (!this.block_alerts.nativeElement.checked) {
+        // Based on https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload#example
+        // This combination ensures a dialog will be shown on most browsers.
+        e.preventDefault();
+        e.returnValue = '';
+      }
     });
   }
 
diff --git a/scouting/www/common.css b/scouting/www/common.css
index 35e943f..43f117e 100644
--- a/scouting/www/common.css
+++ b/scouting/www/common.css
@@ -8,3 +8,10 @@
    * I.e. It would be nice to keep the error message and the progress message
    * aligned when they are non-empty. */
 }
+
+/* Hidden from the user, but interactable from protractor. */
+.visually-hidden {
+  position: absolute !important;
+  top: -9999px !important;
+  left: -9999px !important;
+}
diff --git a/scouting/www/index.html b/scouting/www/index.html
index 3a09dfd..b5c33e6 100644
--- a/scouting/www/index.html
+++ b/scouting/www/index.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
   <head>
+    <title>FRC971 Scouting Application</title>
     <meta name="viewport" content="width=device-width, initial-scale=1">
     <base href="/">
     <script src="./npm/node_modules/zone.js/dist/zone.min.js"></script>