xref: /aosp_15_r20/external/pigweed/pw_web/log-viewer/test/log-view-controls.test.js (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1// Copyright 2024 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15import { MockLogSource } from '../src/custom/mock-log-source';
16import { createLogViewer } from '../src/createLogViewer';
17import { expect } from '@open-wc/testing';
18import { LocalStateStorage, StateService } from '../src/shared/state';
19import { NodeType, Orientation, ViewNode } from '../src/shared/view-node';
20
21function setUpLogViewer() {
22  const mockLogSource = new MockLogSource();
23  const destroyLogViewer = createLogViewer(mockLogSource, document.body);
24  const logViewer = document.querySelector('log-viewer');
25  return { mockLogSource, destroyLogViewer, logViewer };
26}
27
28// Handle benign ResizeObserver error caused by custom log viewer initialization
29// See: https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors
30function handleResizeObserverError() {
31  const e = window.onerror;
32  window.onerror = function (err) {
33    if (
34      err === 'ResizeObserver loop completed with undelivered notifications.'
35    ) {
36      console.warn(
37        'Ignored: ResizeObserver loop completed with undelivered notifications.',
38      );
39      return false;
40    } else {
41      return e(...arguments);
42    }
43  };
44}
45
46describe('log-view-controls', () => {
47  let mockLogSource;
48  let destroyLogViewer;
49  let logViewer;
50  let mockColumnData;
51  let mockState;
52  let stateService;
53
54  before(() => {
55    mockColumnData = [
56      {
57        fieldName: 'test',
58        characterLength: 0,
59        manualWidth: null,
60        isVisible: false,
61      },
62      {
63        fieldName: 'foo',
64        characterLength: 0,
65        manualWidth: null,
66        isVisible: true,
67      },
68      {
69        fieldName: 'bar',
70        characterLength: 0,
71        manualWidth: null,
72        isVisible: false,
73      },
74    ];
75    mockState = {
76      rootNode: new ViewNode({
77        type: NodeType.Split,
78        orientation: Orientation.Horizontal,
79        children: [
80          new ViewNode({
81            searchText: 'hello',
82            logViewId: 'child-node-1',
83            type: NodeType.View,
84            columnData: mockColumnData,
85          }),
86          new ViewNode({
87            searchText: 'world',
88            logViewId: 'child-node-2',
89            type: NodeType.View,
90            columnData: mockColumnData,
91          }),
92        ],
93      }),
94    };
95
96    stateService = new StateService(new LocalStateStorage());
97    stateService.saveState(mockState);
98    handleResizeObserverError();
99  });
100
101  after(() => {
102    window.localStorage.clear();
103    mockLogSource.stop();
104    destroyLogViewer();
105  });
106
107  describe('state', () => {
108    it('should populate search field value on component load', async () => {
109      ({ mockLogSource, destroyLogViewer, logViewer } = setUpLogViewer());
110      const logViews = await getLogViews();
111      const stateSearchString =
112        mockState.rootNode.children[0].logViewState.searchText;
113      const logControls =
114        logViews[0].shadowRoot.querySelector('log-view-controls');
115      logControls.requestUpdate();
116      const inputEl = logControls.shadowRoot.querySelector('.search-field');
117
118      await logViewer.updateComplete;
119      expect(inputEl.value).to.equal(stateSearchString);
120    });
121
122    it('should populate search field values for multiple log views on component load', async () => {
123      ({ mockLogSource, destroyLogViewer, logViewer } = setUpLogViewer());
124
125      const state = stateService.loadState();
126      const logViews = await getLogViews();
127      const searchInputs = [];
128
129      logViews.forEach((logView) => {
130        const logControls =
131          logView.shadowRoot.querySelector('log-view-controls');
132        const inputEl = logControls.shadowRoot.querySelector('.search-field');
133        searchInputs.push(inputEl.value);
134      });
135
136      state.rootNode.children.forEach((childNode, index) => {
137        expect(childNode.logViewState.searchText).to.equal(searchInputs[index]);
138      });
139    });
140
141    it('should recall table column visibility on component load', async () => {
142      ({ mockLogSource, destroyLogViewer, logViewer } = setUpLogViewer());
143
144      const state = stateService.loadState();
145      const logViews = await getLogViews();
146      const logControls =
147        logViews[0].shadowRoot.querySelector('log-view-controls');
148      const colToggleMenu = logControls.shadowRoot
149        .querySelector('#col-toggle-menu')
150        .querySelectorAll('.item-checkbox');
151
152      colToggleMenu.forEach((field, index) => {
153        const columnData = state.rootNode.children[0].logViewState.columnData;
154        expect(field.checked).to.equal(columnData[index].isVisible);
155      });
156
157      const colToggleSubMenu = logControls.shadowRoot
158        .querySelector('#col-toggle-sub-menu')
159        .querySelectorAll('.item-checkbox');
160
161      colToggleSubMenu.forEach((field, index) => {
162        const columnData = state.rootNode.children[0].logViewState.columnData;
163        expect(field.checked).to.equal(columnData[index].isVisible);
164      });
165    });
166
167    async function getLogViews() {
168      const logViewerEl = document.querySelector('log-viewer');
169      await logViewerEl.updateComplete;
170      await new Promise((resolve) => setTimeout(resolve, 100));
171      const logViews = logViewerEl.shadowRoot.querySelectorAll('log-view');
172      return logViews;
173    }
174  });
175});
176