blob: 96ab046f5137c98c9a9c7cd6eb2a3449d1fa6e14 [file] [log] [blame]
// Copyright 2022 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 chai from 'chai'; // not esm
import chaiDom from 'chai-dom'; // not esm
import * as constant from '../src/constants';
import { FakeWebviewAPi, ffxEventForTest, logDataForTest, malformedLogForTest }
from './util';
import { Filter } from '../src/filter';
import { LogList, WRAP_LOG_TEXT_ATTR } from '../components/log_list';
import { State } from '../src/state';
import {LitElement} from 'lit';
import {ffxLogToLogRowData} from '../src/ffxLogToLogRow';
before(function () {
chai.should();
chai.use(chaiDom);
});
describe('LogList', () => {
let root: HTMLElement;
let state: State;
beforeEach(() => {
root = document.createElement('div');
document.body.appendChild(root);
state = new State(new FakeWebviewAPi());
});
afterEach(() => {
root.remove();
});
describe('#constructor', () => {
it('crates a new empty view', async () => {
const logsList = new LogList(state);
root.appendChild(logsList);
await logsList.updateComplete;
logsList.shadowRoot!.children.length.should.equal(1);
await (logsList.shadowRoot!.children[0] as LitElement).updateComplete;
logsList.shadowRoot!.children[0].nodeName.should.equal('LOG-HEADER');
logsList.should.have.attr('aria-colcount');
const expectedColumns = Object.keys(state.currentFields).length;
logsList.getAttribute('aria-colcount')?.should.equal(`${expectedColumns}`);
});
it('sets the log wrapping from the state', async () => {
state.shouldWrapLogs = true;
let logList = new LogList(state);
root.appendChild(logList);
await logList.updateComplete;
logList.hasAttribute(WRAP_LOG_TEXT_ATTR).should.be.true;
state.shouldWrapLogs = false;
logList = new LogList(state);
logList.hasAttribute(WRAP_LOG_TEXT_ATTR).should.be.false;
});
});
describe('#addLog', () => {
it('appends a log', async () => {
const logsList = new LogList(state);
document.body.appendChild(logsList);
await logsList.updateComplete;
logsList.shadowRoot!.children.length.should.equal(1);
await (logsList.shadowRoot!.children[0] as LitElement).updateComplete;
logsList.shadowRoot!.children[0].nodeName.should.equal('LOG-HEADER');
logsList.addLog(ffxLogToLogRowData(logDataForTest('core/foo'))!);
await logsList.updateComplete;
logsList.shadowRoot!.children.length.should.equal(2);
const logLine = logsList.shadowRoot!.children[1] as LitElement;
logLine.children[0].should.have.class('log-entry');
logLine.children[0].should.have.attr('data-moniker', 'core/foo');
logLine.children[0].should.have.attr('data-pid', '123');
logLine.children[0].should.have.attr('data-tid', '456');
(logLine.children[0] as HTMLElement).hidden.should.be.false;
const testFields = ['000000.12', '123', '456', 'core/foo', 'my_tag', 'Info', 'msg'];
let field: keyof typeof testFields;
for (field in testFields) {
const logField = logLine.children[0].children[field] as HTMLElement;
logField.innerText.should.equal(testFields[field]);
}
logsList.remove();
});
it('hides the log if the filters require so', async () => {
const logsList = new LogList(state);
root.appendChild(logsList);
state.registerFilter(new Filter({
category: 'moniker',
subCategory: undefined,
operator: 'contains',
value: 'core/bar',
}), 'moniker:core/bar');
logsList.addLog(ffxLogToLogRowData(logDataForTest('core/foo'))!);
logsList.addLog(ffxLogToLogRowData(logDataForTest('core/bar'))!);
await logsList.updateComplete;
// sleep a bit and wait for rerender
await new Promise((resolve) => {setTimeout(resolve, 10 /* 10ms */);});
logsList.shadowRoot!.children.length.should.equal(3);
const logLine1 = logsList.shadowRoot!.children[1] as HTMLElement;
logLine1.hidden.should.be.true;
const logLine2 = logsList.shadowRoot!.children[2] as HTMLElement;
logLine2.hidden.should.be.false;
});
it('handles ffx events', async () => {
const logsList = new LogList(state);
let moniker = constant.FFX_MONIKER;
const msg = 'Logger lost connection to target. Retrying...';
logsList.addLog(ffxLogToLogRowData(ffxEventForTest('TargetDisconnected'))!);
document.body.appendChild(logsList);
await logsList.updateComplete;
logsList.shadowRoot!.children.length.should.equal(2);
logsList.shadowRoot!.children[0].nodeName.should.equal('LOG-HEADER');
const logLine = logsList.shadowRoot!.children[1] as LitElement;
logLine.children[0].children.length.should.equal(7);
logLine.children[0].should.have.class('log-entry');
logLine.children[0].should.have.attr('data-moniker', '<ffx>');
(logLine.children[0] as HTMLElement).hidden.should.be.false;
let monikerEl = logLine.children[0].children[3] as HTMLElement;
let msgEl = logLine.children[0].children[6] as HTMLElement;
monikerEl.innerText.should.equal(moniker);
msgEl.innerText.should.equal(msg);
logsList.remove();
});
it('handles malformed logs', async () => {
const logsList = new LogList(state);
const msg = 'Malformed target log: oh no something went wrong';
logsList.addLog(ffxLogToLogRowData(malformedLogForTest('oh no something went wrong'))!);
document.body.appendChild(logsList);
await logsList.updateComplete;
logsList.shadowRoot!.children.length.should.equal(2);
logsList.shadowRoot!.children[0].nodeName.should.equal('LOG-HEADER');
const logLine = logsList.shadowRoot!.children[1] as LitElement;
await logLine.updateComplete;
logLine.children[0].children.length.should.equal(7);
logLine.children[0].should.have.class('log-entry');
(logLine.children[0] as HTMLElement).hidden.should.be.false;
let msgEl = logLine.children[0].children[6] as HTMLElement;
msgEl.innerText.should.equal(msg);
logsList.remove();
});
it('detects user hovering logs', () => {
const view = new LogList(state);
view.addLog(ffxLogToLogRowData(logDataForTest('core/foo'))!);
const scrollArea = view.parentElement;
scrollArea?.matches(':hover').should.equal(false);
scrollArea?.dispatchEvent(new MouseEvent('onmouseenter'));
scrollArea?.matches(':hover').should.equal(true);
});
});
describe('#reset', () => {
it('resets the log list', async () => {
const logsList = new LogList(state);
root.appendChild(logsList);
logsList.addLog(ffxLogToLogRowData(logDataForTest('core/foo'))!);
await logsList.updateComplete;
logsList.shadowRoot!.children.length.should.equal(2);
logsList.reset();
await logsList.updateComplete;
logsList.shadowRoot!.children.length.should.equal(1);
});
});
});