Additional tests for tree component and tree node component.

Fixes: 359126036
Test: npm run test:unit:ci
Change-Id: I3db8ef81770ebeab792ff9a0e0501e78adc4ecc3
diff --git a/tools/winscope/src/viewers/components/tree_component_test.ts b/tools/winscope/src/viewers/components/tree_component_test.ts
index 447ed8b..80728c7 100644
--- a/tools/winscope/src/viewers/components/tree_component_test.ts
+++ b/tools/winscope/src/viewers/components/tree_component_test.ts
@@ -76,29 +76,33 @@
     expect(treeComponent.hasSelectedChild()).toBeTrue();
   });
 
-  it('highlights node upon click', () => {
+  it('highlights node and inner node upon click', () => {
     fixture.detectChanges();
-    const treeNode = assertDefined(htmlElement.querySelector('tree-node'));
+    const treeNodes = assertDefined(
+      htmlElement.querySelectorAll<HTMLElement>('tree-node'),
+    );
+
     const spy = spyOn(
       assertDefined(component.treeComponent).highlightedChange,
       'emit',
     );
-    (treeNode as HTMLButtonElement).dispatchEvent(
-      new MouseEvent('click', {detail: 1}),
-    );
+    treeNodes.item(0).dispatchEvent(new MouseEvent('click', {detail: 1}));
     fixture.detectChanges();
-    expect(spy).toHaveBeenCalled();
+    expect(spy).toHaveBeenCalledTimes(1);
+
+    treeNodes.item(1).click();
+    fixture.detectChanges();
+    expect(spy).toHaveBeenCalledTimes(2);
   });
 
   it('toggles tree upon node double click', () => {
     fixture.detectChanges();
     const treeComponent = assertDefined(component.treeComponent);
-    const treeNode = assertDefined(htmlElement.querySelector('tree-node'));
-
-    const currLocalExpandedState = treeComponent.localExpandedState;
-    (treeNode as HTMLButtonElement).dispatchEvent(
-      new MouseEvent('click', {detail: 2}),
+    const treeNode = assertDefined(
+      htmlElement.querySelector<HTMLElement>('tree-node'),
     );
+    const currLocalExpandedState = treeComponent.localExpandedState;
+    treeNode.dispatchEvent(new MouseEvent('click', {detail: 2}));
     fixture.detectChanges();
     expect(!currLocalExpandedState).toEqual(treeComponent.localExpandedState);
   });
@@ -108,16 +112,45 @@
     const treeComponent = assertDefined(component.treeComponent);
     component.isFlattened = true;
     fixture.detectChanges();
-    const treeNode = assertDefined(htmlElement.querySelector('tree-node'));
+    const treeNode = assertDefined(
+      htmlElement.querySelector<HTMLElement>('tree-node'),
+    );
 
     const currLocalExpandedState = treeComponent.localExpandedState;
-    (treeNode as HTMLButtonElement).dispatchEvent(
-      new MouseEvent('click', {detail: 2}),
-    );
+    treeNode.dispatchEvent(new MouseEvent('click', {detail: 2}));
     fixture.detectChanges();
     expect(currLocalExpandedState).toEqual(treeComponent.localExpandedState);
   });
 
+  it('pins node on click', () => {
+    fixture.detectChanges();
+    const pinNodeButton = assertDefined(
+      htmlElement.querySelector<HTMLElement>('.pin-node-btn'),
+    );
+    const spy = spyOn(
+      assertDefined(component.treeComponent).pinnedItemChange,
+      'emit',
+    );
+    pinNodeButton.click();
+    fixture.detectChanges();
+    expect(spy).toHaveBeenCalled();
+  });
+
+  it('expands tree on expand tree button click', () => {
+    fixture.detectChanges();
+    const treeNode = assertDefined(
+      htmlElement.querySelector<HTMLElement>('tree-node'),
+    );
+    treeNode.dispatchEvent(new MouseEvent('click', {detail: 2}));
+    fixture.detectChanges();
+    expect(component.treeComponent?.localExpandedState).toEqual(false);
+    assertDefined(
+      htmlElement.querySelector<HTMLElement>('.expand-tree-btn'),
+    ).click();
+    fixture.detectChanges();
+    expect(component.treeComponent?.localExpandedState).toEqual(true);
+  });
+
   it('scrolls selected node only if not in view', () => {
     fixture.detectChanges();
     const treeComponent = assertDefined(component.treeComponent);
@@ -138,7 +171,13 @@
     expect(spy).toHaveBeenCalledTimes(1);
   });
 
-  it('sets initial expanded state to true by default', () => {
+  it('sets initial expanded state to true by default for leaf', () => {
+    fixture.detectChanges();
+    expect(assertDefined(component.treeComponent).isExpanded()).toBeTrue();
+  });
+
+  it('sets initial expanded state to true by default for non root', () => {
+    component.tree = component.tree.getAllChildren()[0];
     fixture.detectChanges();
     expect(assertDefined(component.treeComponent).isExpanded()).toBeTrue();
   });
@@ -190,20 +229,23 @@
     ]);
     fixture.detectChanges();
     const button = assertDefined(
-      htmlElement.querySelector('.toggle-rect-show-state-btn'),
-    ) as HTMLElement;
+      htmlElement.querySelector<HTMLElement>('.toggle-rect-show-state-btn'),
+    );
     expect(button.textContent).toContain('visibility_off');
 
-    let id: string | undefined;
-    let state: RectShowState | undefined;
+    let id = '';
     htmlElement.addEventListener(ViewerEvents.RectShowStateChange, (event) => {
-      id = (event as CustomEvent).detail.rectId;
-      state = (event as CustomEvent).detail.state;
+      const detail = (event as CustomEvent).detail;
+      id = detail.rectId;
+      component.rectIdToShowState?.set(detail.rectId, detail.state);
     });
     button.click();
     fixture.detectChanges();
-    expect(id).toEqual(component.tree.id);
-    expect(state).toEqual(RectShowState.SHOW);
+    expect(component.rectIdToShowState.get(id)).toEqual(RectShowState.SHOW);
+
+    button.click();
+    fixture.detectChanges();
+    expect(component.rectIdToShowState.get(id)).toEqual(RectShowState.HIDE);
   });
 
   it('shows node at full opacity when applicable', () => {
diff --git a/tools/winscope/src/viewers/components/tree_node_component_test.ts b/tools/winscope/src/viewers/components/tree_node_component_test.ts
index 5b67720..b5cf8ae 100644
--- a/tools/winscope/src/viewers/components/tree_node_component_test.ts
+++ b/tools/winscope/src/viewers/components/tree_node_component_test.ts
@@ -23,6 +23,7 @@
 import {HierarchyTreeBuilder} from 'test/unit/hierarchy_tree_builder';
 import {PropertyTreeBuilder} from 'test/unit/property_tree_builder';
 import {DEFAULT_PROPERTY_FORMATTER} from 'trace/tree_node/formatters';
+import {DiffType} from 'viewers/common/diff_type';
 import {UiHierarchyTreeNode} from 'viewers/common/ui_hierarchy_tree_node';
 import {UiPropertyTreeNode} from 'viewers/common/ui_property_tree_node';
 import {HierarchyTreeNodeDataViewComponent} from './hierarchy_tree_node_data_view_component';
@@ -69,15 +70,26 @@
     expect(component).toBeTruthy();
   });
 
-  it('can generate data view component', () => {
-    assertDefined(component.treeNodeComponent).isPropertyTreeNode = jasmine
-      .createSpy()
-      .and.returnValue(false);
-    fixture.detectChanges();
+  it('can generate hierarchy data view component', () => {
     const treeNodeDataView = htmlElement.querySelector(
       'hierarchy-tree-node-data-view',
     );
     expect(treeNodeDataView).toBeTruthy();
+    expect(
+      htmlElement.querySelector('property-tree-node-data-view'),
+    ).toBeNull();
+  });
+
+  it('can generate property data view component', () => {
+    component.node = propertiesTree;
+    fixture.detectChanges();
+    const treeNodeDataView = htmlElement.querySelector(
+      'property-tree-node-data-view',
+    );
+    expect(treeNodeDataView).toBeTruthy();
+    expect(
+      htmlElement.querySelector('hierarchy-tree-node-data-view'),
+    ).toBeNull();
   });
 
   it('can trigger tree toggle on click of chevron', () => {
@@ -105,6 +117,42 @@
     expect(spy).toHaveBeenCalled();
   });
 
+  it('assigns diff css classes to expand tree button', () => {
+    const expandButton = assertDefined(
+      htmlElement.querySelector<HTMLElement>('.expand-tree-btn'),
+    );
+    expect(expandButton.className).toEqual('icon-button expand-tree-btn');
+    component.node = UiHierarchyTreeNode.from(
+      new HierarchyTreeBuilder()
+        .setId('LayerTraceEntry')
+        .setName('Added Diff')
+        .setChildren([
+          {id: 1, name: 'Child 1', children: [{id: 2, name: 'Child 2'}]},
+        ])
+        .build(),
+    );
+    component.node.getChildByName('Child 1')?.setDiff(DiffType.ADDED);
+    fixture.detectChanges();
+    expect(expandButton.className).toEqual('icon-button expand-tree-btn added');
+
+    component.node = UiHierarchyTreeNode.from(
+      new HierarchyTreeBuilder()
+        .setId('LayerTraceEntry')
+        .setName('Added Diff')
+        .setChildren([
+          {id: 1, name: 'Child 1', children: [{id: 2, name: 'Child 2'}]},
+        ])
+        .build(),
+    );
+    const child1 = assertDefined(component.node.getChildByName('Child 1'));
+    child1.setDiff(DiffType.ADDED);
+    child1.getChildByName('Child 2')?.setDiff(DiffType.DELETED);
+    fixture.detectChanges();
+    expect(expandButton.className).toEqual(
+      'icon-button expand-tree-btn modified',
+    );
+  });
+
   it('pins node on click', () => {
     const treeNodeComponent = assertDefined(component.treeNodeComponent);
     treeNodeComponent.showPinNodeIcon = jasmine