[i18n][e2e] e2e tests for Ermine L10N

Adds a simple basic test: switch locale with an external service, then
figure out whether the on-screen display has actually changed as result.

This is simplistic, but infinitely better than what we used to have
(manual spot checks).

Bug: 44741
Change-Id: I0b3a62f9681249667b57d7a40f4a3b9f7a83c019
diff --git a/tests/e2e/BUILD.gn b/tests/e2e/BUILD.gn
index 92f3d94..df43d54 100644
--- a/tests/e2e/BUILD.gn
+++ b/tests/e2e/BUILD.gn
@@ -13,6 +13,7 @@
     # "ermine_session_shell_ask_test.dart",
     # "ermine_session_shell_simple_browser_test.dart",
     # "ermine_session_shell_status_test.dart",
+    "ermine_intl_test.dart",
     "ermine_smoke_test.dart",
   ]
 
@@ -45,6 +46,11 @@
 
   if (is_debug) {
     # Ermine tests use Flutter Driver, which only works in debug builds.
-    deps += [ ":experiences_ermine_session_shell_e2e_test($host_toolchain)" ]
+    deps += [
+      ":experiences_ermine_session_shell_e2e_test($host_toolchain)",
+
+      # Used for intl tests.
+      "//garnet/bin/setui_client:setui_client",
+    ]
   }
 }
diff --git a/tests/e2e/test/ermine_intl_test.dart b/tests/e2e/test/ermine_intl_test.dart
new file mode 100644
index 0000000..308ec7b
--- /dev/null
+++ b/tests/e2e/test/ermine_intl_test.dart
@@ -0,0 +1,65 @@
+// Copyright 2020 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter_driver/flutter_driver.dart';
+import 'package:flutter_driver_sl4f/flutter_driver_sl4f.dart';
+import 'package:sl4f/sl4f.dart';
+import 'package:test/test.dart';
+
+/// Tests that the DUT running ermine can do the following:
+///   - Change locale via setui_client and that change takes effect
+void main() {
+  Sl4f sl4f;
+  FlutterDriverConnector connector;
+  FlutterDriver driver;
+
+  void setLocale(String localeId) async {
+    expect(
+        (await sl4f.ssh.run('run setui_client.cm intl -l $localeId')).exitCode,
+        0);
+  }
+
+  void findTextOnScreen(String text) {
+    expect(find.text(text).serialize()['text'], text);
+  }
+
+  setUpAll(() async {
+    sl4f = Sl4f.fromEnvironment();
+    await sl4f.startServer();
+
+    connector = FlutterDriverConnector(sl4f);
+    await connector.initialize();
+
+    // Check if ermine is running.
+    final isolate = await connector.isolate('ermine');
+    if (isolate == null) {
+      fail('could not find ermine.');
+    }
+
+    // Now connect to ermine.
+    driver = await connector.driverForIsolate('ermine');
+    if (driver == null) {
+      fail('unable to connect to ermine.');
+    }
+  });
+
+  tearDownAll(() async {
+    setLocale('en-US');
+
+    // Any of these may end up being null if the test fails in setup.
+    await driver?.close();
+    await connector?.tearDown();
+    await sl4f?.stopServer();
+    sl4f?.close();
+  });
+
+  test('Locale can be switched and takes effect', () async {
+    setLocale('en-US');
+    findTextOnScreen('MEMORY');
+
+    // The text on screen is equivalent to US English "MEMORY".
+    setLocale('sr');
+    findTextOnScreen('МЕМОРИЈА');
+  });
+}
diff --git a/tests/e2e/test/ermine_smoke_test.dart b/tests/e2e/test/ermine_smoke_test.dart
index 92e7b43..02bef75 100644
--- a/tests/e2e/test/ermine_smoke_test.dart
+++ b/tests/e2e/test/ermine_smoke_test.dart
@@ -38,10 +38,11 @@
   });
 
   tearDownAll(() async {
+    // Any of these may end up being null if the test fails in setup.
     await driver?.close();
-    await connector.tearDown();
-    await sl4f.stopServer();
-    sl4f.close();
+    await connector?.tearDown();
+    await sl4f?.stopServer();
+    sl4f?.close();
   });
 
   test('Screen should not be black', () async {