[results feed] Update tests to work with current staging database

Change-Id: I965792b0b4494c68e21c7719dd261a1ae6c9fd4d
Reviewed-on: https://dart-review.googlesource.com/c/dart_ci/+/156917
Reviewed-by: Alexander Thomas <athom@google.com>
diff --git a/results_feed/lib/src/services/firestore_service.dart b/results_feed/lib/src/services/firestore_service.dart
index 8fa8c4b..d0da50b 100644
--- a/results_feed/lib/src/services/firestore_service.dart
+++ b/results_feed/lib/src/services/firestore_service.dart
@@ -218,21 +218,25 @@
     // Firebase api key is public, and must be sent to client for use.
     // It is invalid over any connection except https to the app URL.
     // It is not used for security, only usage accounting.
-    app = firebase.initializeApp(
+    app = initializeApp();
+    await app.auth().setPersistence(firebase.Persistence.LOCAL);
+  }
+
+  static firebase.App initializeApp({String name}) {
+    return firebase.initializeApp(
         apiKey: 'AIzaSyBky7KGq1dbVn_J48iAI6oVyKRcMrRanns',
         authDomain: 'dart-ci-staging.firebaseapp.com',
         databaseURL: 'https://dart-ci-staging.firebaseio.com',
         messagingSenderId: '287461583823',
         projectId: 'dart-ci-staging',
-        storageBucket: 'dart-ci-staging.appspot.com');
-    await app.auth().setPersistence(firebase.Persistence.LOCAL);
+        storageBucket: 'dart-ci-staging.appspot.com',
+        name: name);
   }
 }
 
 class TestingFirestoreService extends StagingFirestoreService {
   // TestingFirestoreService uses the Firestore database at
   // dart-ci-staging.
-  // It adds additional methods used by integration tests.
   // It includes local password-based authentication for
   // tests that write to staging.
   @override
@@ -242,7 +246,9 @@
   }
 
   @override
-  Future logIn() async {
+  Future logIn() => logInWithPassword(app);
+
+  static Future<void> logInWithPassword(firebase.App app) async {
     try {
       await app.auth().signInWithEmailAndPassword(
           'dartresultsfeedtestaccount2@example.com', r'');
@@ -253,7 +259,15 @@
     } catch (e) {
       print(e.toString());
     }
-    return;
+  }
+}
+
+class FirestoreTestSetup {
+  firebase.App app;
+
+  Future<void> initialize() async {
+    app = StagingFirestoreService.initializeApp(name: 'testing');
+    await TestingFirestoreService.logInWithPassword(app);
   }
 
   Future<void> writeDocumentsFrom(Map<String, dynamic> documents,
@@ -281,4 +295,13 @@
       await document.ref.delete();
     }
   }
+
+  Future<int> lastIndex() async {
+    final commits = app.firestore().collection('commits');
+    var snapshot = await commits.orderBy('index', 'desc').limit(3).get();
+    if (snapshot.docs.length < 3) {
+      throw Exception('Staging database does not contain 3 commits');
+    }
+    return snapshot.docs.first.data()['index'];
+  }
 }
diff --git a/results_feed/test/comments_sample_data.dart b/results_feed/test/comments_sample_data.dart
index 18e4b60..4fce2ef 100644
--- a/results_feed/test/comments_sample_data.dart
+++ b/results_feed/test/comments_sample_data.dart
@@ -8,54 +8,53 @@
 // the comments apply to.
 
 final commentId1 = 'sampleId00001';
-final commentThreadId = 'sampleId00002';
-final commentId2 = 'sampleId00003';
-final commentId3 = 'sampleId00004';
+final commentId2 = 'sampleId00002';
+final commentId3 = 'sampleId00003';
 
-final result1 = '1d91eLOxn3mWjJY9qsEO';
-final result2 = 'RyMWa5iGfYCjUms0FBU7';
-final result3 = 'FkCKOa7uZQdtEpidTYbe';
-final result4 = 'JCXiPwG5O7td1X5wjSzA';
-final result5 = 'rjDBqGpGiIDOJgimyIid';
-final result6 = '';
+final result1 = 'sample_result_1';
 
 // These documents are added to the sample database for testing, then removed.
-Map<String, dynamic> commentsSampleData = {
-  'comments/$commentId1': {
-    'author': 'user@example.com',
-    'created': DateTime.parse('2019-11-20 20:18:00Z'),
-    'comment': 'Sample comment approving a test',
-    'approved': true,
-    'results': [result1],
-    'blamelist_start_index': 66142,
-    'blamelist_end_index': 66142
-  },
-  'comments/$commentThreadId': {
-    'author': 'user@example.com',
-    'created': DateTime.parse('2019-11-21 20:19:00Z'),
-    'comment': 'Sample comment approving 2 tests',
-    'approved': true,
-    'results': [result2, result3],
-    'blamelist_start_index': 66235,
-    'blamelist_end_index': 66235
-  },
-  'comments/$commentId2': {
-    'author': 'user@example.com',
-    'created': DateTime.parse('2019-11-22 22:19:00Z'),
-    'comment': 'Sample comment disapproving 1 of 2 approved tests',
-    'approved': false,
-    'results': [result3],
-    'base_comment': commentThreadId,
-    'blamelist_start_index': 66235,
-    'blamelist_end_index': 66235
-  },
-  'comments/$commentId3': {
-    'author': 'user2@example.com',
-    'created': DateTime.parse('2019-10-31 23:19:00Z'),
-    'comment': 'Sample comment on a non-trivial blamelist',
-    'approved': true,
-    'results': [result4, result5],
-    'blamelist_start_index': 66148,
-    'blamelist_end_index': 66151
-  },
-};
+Map<String, Map<String, dynamic>> createCommentsSampleData(int lastIndex) {
+  final startIndex = lastIndex - 2;
+  final endIndex = lastIndex;
+  final commentTime = DateTime.now().subtract(Duration(days: 2));
+  return {
+    'results/$result1': {
+      'approved': false,
+      'configurations': ['analyzer-asserts-win', 'analyzer-asserts-linux'],
+      'name': 'sample_suite/sample_test',
+      'result': 'RuntimeError',
+      'expected': 'Pass',
+      'previous_result': 'Pass',
+      'blamelist_start_index': startIndex,
+      'blamelist_end_index': endIndex,
+    },
+    'comments/$commentId1': {
+      'author': 'user@example.com',
+      'created': commentTime,
+      'comment': 'Sample comment approving a test',
+      'approved': true,
+      'results': [result1],
+      'blamelist_start_index': startIndex,
+      'blamelist_end_index': endIndex,
+    },
+    'comments/$commentId2': {
+      'author': 'user@example.com',
+      'created': commentTime,
+      'comment': 'Sample comment approving 2 tests',
+      'approved': true,
+      'results': [result1],
+      'blamelist_start_index': startIndex,
+      'blamelist_end_index': endIndex,
+    },
+    'comments/$commentId3': {
+      'author': 'user@example.com',
+      'created': commentTime,
+      'comment': 'Sample comment disapproving 1 of 2 approved tests',
+      'approved': false,
+      'results': [result1],
+      'blamelist_start_index': startIndex,
+      'blamelist_end_index': endIndex,
+    },
+  };
+}
diff --git a/results_feed/test/comments_test.dart b/results_feed/test/comments_test.dart
index 5898523..5d3ed50 100644
--- a/results_feed/test/comments_test.dart
+++ b/results_feed/test/comments_test.dart
@@ -17,35 +17,39 @@
 import 'comments_test.template.dart' as self;
 import 'page_objects/app_po.dart';
 import 'page_objects/blamelist_po.dart';
+import 'page_objects/commit_po.dart';
 
 // pub run build_runner test --fail-on-severe -- -p chrome comments_test.dart
 
+const int neededCommits = 3;
+
 @GenerateInjector([
   ClassProvider(FirestoreService, useClass: TestingFirestoreService),
 ])
 final InjectorFactory rootInjector = self.rootInjector$Injector;
 
 void main() {
+  final testSetup = FirestoreTestSetup();
   final testBed = NgTestBed.forComponent<AppComponent>(ng.AppComponentNgFactory,
       rootInjector: rootInjector);
   NgTestFixture<AppComponent> fixture;
+  Map<String, Map<String, dynamic>> commentsSampleData;
 
   setUpAll(() async {
     // Because the FirestoreService can only be initialized once, set up the
     // testBed (and component, and root injectors, and injected FirestoreService
     // instance, in a setupAll function that is created once.
+    await testSetup.initialize();
+    final lastIndex = await testSetup.lastIndex();
+    commentsSampleData = createCommentsSampleData(lastIndex);
+    await testSetup.writeDocumentsFrom(commentsSampleData);
     fixture = await testBed.create();
-    final firestore =
-        AppComponentTest(fixture.assertOnlyInstance).firestoreService;
-    await firestore.logIn();
-    await firestore.writeDocumentsFrom(commentsSampleData);
+    await fixture.assertOnlyInstance.fetching;
   });
 
   tearDownAll(() async {
     await disposeAnyRunningTest();
-    final firestore =
-        AppComponentTest(fixture.assertOnlyInstance).firestoreService;
-    await firestore.writeDocumentsFrom(commentsSampleData, delete: true);
+    await testSetup.writeDocumentsFrom(commentsSampleData, delete: true);
   });
 
   void testEqual(Comment comment, Map<String, dynamic> original, String id) {
@@ -90,83 +94,48 @@
     testEqual(comment, original, commentId1);
   });
 
-  test('load comment threads', () async {
-    final firestore =
-        AppComponentTest(fixture.assertOnlyInstance).firestoreService;
-    final documents = await firestore.fetchCommentThread(commentThreadId);
-    expect(documents, hasLength(2));
-    final baseComment = Comment.fromDocument(documents[0]);
-    final baseOriginal = commentsSampleData['comments/$commentThreadId'];
-    testEqual(baseComment, baseOriginal, commentThreadId);
-    final threadComment = Comment.fromDocument(documents[1]);
-    final threadOriginal = commentsSampleData['comments/$commentId2'];
-    testEqual(threadComment, threadOriginal, commentId2);
-  });
-
   test('check comment ui', () async {
-    Future fetcher;
+    // TODO(whesse): The app fetches when initialized, with the old filter.
+    // Because our new result is an active failure, it is fetched.
+    // The fetch here fetches some earlier commits, does not really help.
+    await fixture.update((app) => app.filterService.filter = app
+        .filterService.filter
+        .copy(showLatestFailures: false, showUnapprovedOnly: false));
+    await fixture.update((app) => app.fetchData());
+    await fixture.assertOnlyInstance.fetching;
     final context =
         HtmlPageLoaderElement.createFromElement(fixture.rootElement);
-    void fetchMoreCommits(AppComponent app) {
-      fetcher = app.fetchData();
-    }
-
-    while (fixture.assertOnlyInstance.commits.length < 100) {
-      await fixture.update(fetchMoreCommits);
-      await fetcher;
-    }
-
     var app = AppPO.create(context);
+    // Take our sample commit with a non-trival buildlist, press button on it.
+    bool isSampleCommit(CommitPO commit) =>
+        commit.isNotEmpty &&
+        commit.blamelist.commentBodies.isNotEmpty &&
+        commit.blamelist.numCommits == neededCommits;
 
-    // Take commit with a non-trival buildlist, press button on it.
-    final unpinned = app.commits
-        .where((commit) =>
-            commit.isNotEmpty &&
-            commit.blamelist.commentBodies.isNotEmpty &&
-            commit.blamelist.firstCommit != commit.blamelist.lastCommit)
-        .single;
+    final unpinned = app.commits.firstWhere(isSampleCommit);
     await fixture.update((AppComponent app) => unpinned.pressPickerButton());
 
     // Create a new AppPO because AppPO fields are final and cached, and the
     // DOM has changed.
     app = AppPO.create(context);
-    final commits = app.commits
-        .where((commit) =>
-            commit.isNotEmpty && commit.blamelist.commentBodies.isNotEmpty)
-        .toList();
+    final commit = app.commits.firstWhere(isSampleCommit);
 
     final data = commentsSampleData;
     var expected = {
       'comments': [
-        data['comments/$commentThreadId']['comment'],
-        data['comments/$commentId2']['comment']
-      ],
-      'author': data['comments/$commentThreadId']['author'],
-      'date': '21:19 Thu Nov 21',
-      'first_commit': '80fc4d',
-      'last_commit': '80fc4d'
-    };
-
-    checkComments(commits[0].blamelist, expected);
-    expected = {
-      'comments': [
+        data['comments/$commentId1']['comment'],
+        data['comments/$commentId2']['comment'],
         data['comments/$commentId3']['comment'],
       ],
-      'author': data['comments/$commentId3']['author'],
-      'date': '0:19 Fri Nov 1',
-      'first_commit': '8a09d7',
-      'last_commit': '924ec3',
-      'is_blamelist_picker': true
+      'author': data['comments/$commentId1']['author'],
+      'is_blamelist_picker': true,
     };
-    checkComments(commits[1].blamelist, expected);
+    checkComments(commit.blamelist, expected);
   });
 }
 
 void checkComments(BlamelistPO blamelist, Map<String, dynamic> data) {
   expect(blamelist.commentBodies, equals(data['comments']));
   expect(blamelist.comments.first, matches(data['author']));
-  expect(blamelist.comments.first, matches(data['date']));
-  expect(blamelist.firstCommit, data['first_commit']);
-  expect(blamelist.lastCommit, data['last_commit']);
   expect(blamelist.hasRadioButtons, data['is_blamelist_picker'] ?? false);
 }
diff --git a/results_feed/test/page_objects/blamelist_po.dart b/results_feed/test/page_objects/blamelist_po.dart
index ff04630..348740f 100644
--- a/results_feed/test/page_objects/blamelist_po.dart
+++ b/results_feed/test/page_objects/blamelist_po.dart
@@ -28,6 +28,8 @@
   @First(ByClass('commit'))
   PageLoaderElement get _firstCommit;
 
+  int get numCommits => _commits.length;
+
   String get firstCommit => _firstCommit.getElementsByCss('a').first.innerText;
 
   String get lastCommit => _commits.last.getElementsByCss('a').first.innerText;
diff --git a/results_feed/test/try_results_test.dart b/results_feed/test/try_results_test.dart
index 076f639..93a0458 100644
--- a/results_feed/test/try_results_test.dart
+++ b/results_feed/test/try_results_test.dart
@@ -27,23 +27,28 @@
 final InjectorFactory rootInjector = self.rootInjector$Injector;
 
 void main() {
+  final testSetup = FirestoreTestSetup();
   final testBed = NgTestBed.forComponent<TryResultsComponent>(
       ng.TryResultsComponentNgFactory,
       rootInjector: rootInjector);
 
+  setUpAll(() async {
+    await testSetup.initialize();
+    await testSetup.writeDocumentsFrom(tryResultsCreateComponentSampleData);
+  });
+
+  tearDownAll(() async {
+    await testSetup.writeDocumentsFrom(tryResultsCreateComponentSampleData,
+        delete: true);
+    await testSetup.deleteCommentsForReview(createComponentReview);
+  });
+
   tearDown(() async {
     await disposeAnyRunningTest();
   });
 
   test('create component', () async {
-    TestingFirestoreService firestore;
-    final fixture =
-        await testBed.create(beforeComponentCreated: (Injector injector) async {
-      firestore =
-          injector.provideType<TestingFirestoreService>(FirestoreService);
-      await firestore.getFirebaseClient();
-      await firestore.writeDocumentsFrom(tryResultsCreateComponentSampleData);
-    });
+    final fixture = await testBed.create();
     await fixture.update((TryResultsComponent tryResultsComponent) {
       tryResultsComponent.review = createComponentReview;
       tryResultsComponent.patchset = createComponentPatchset;
@@ -137,9 +142,5 @@
     ]);
     expect(tryResultsPO.comments.last.innerText,
         stringContainsInOrder(['approved', commentText]));
-
-    await firestore.writeDocumentsFrom(tryResultsCreateComponentSampleData,
-        delete: true);
-    await firestore.deleteCommentsForReview(createComponentReview);
   });
 }