Jesse Mazzella 43338f3980
chore: remove vue/compat and complete Vue 3 migration (#7133)
* chore: remove custom `compatConfig` settings

* chore: remove `vue-compat` and adjust webpack config

* chore: explicitly define Vue feature flags

* fix: `_data` property moved to `_.data`

* fix(e2e): revert to original test procedures

* refactor: replace final instances of `$set`

* refactor: remove `Vue` imports from tests

* refactor: `Vue.ref()` -> `ref()`

* refactor: actually push the changes...

* test: replace unit test with e2e test

* test: remove test as it's already covered by e2e

* fix(test): use `$ref`s instead of `$children`

* test(fix): more `$refs`

* fix(test): more `$refs`

* fix(test): use `$refs` in InspectorStyles tests

* fix(SearchComponent): use `$attrs` correctly

---------

Co-authored-by: Scott Bell <scott@traclabs.com>
2023-10-19 09:08:39 -07:00

484 lines
15 KiB
JavaScript

/*****************************************************************************
* Open MCT, Copyright (c) 2014-2023, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import {
createMouseEvent,
createOpenMct,
resetApplicationState,
spyOnBuiltins
} from 'utils/testing';
import { nextTick } from 'vue';
import TablePlugin from './plugin.js';
class MockDataTransfer {
constructor() {
this.data = {};
}
get types() {
return Object.keys(this.data);
}
setData(format, data) {
this.data[format] = data;
}
getData(format) {
return this.data[format];
}
}
describe('the plugin', () => {
let openmct;
let tablePlugin;
let element;
let child;
let historicalProvider;
let originalRouterPath;
let unlistenConfigMutation;
beforeEach((done) => {
openmct = createOpenMct();
// Table Plugin is actually installed by default, but because installing it
// again is harmless it is left here as an example for non-default plugins.
tablePlugin = new TablePlugin();
openmct.install(tablePlugin);
historicalProvider = {
request: () => {
return Promise.resolve([]);
}
};
spyOn(openmct.telemetry, 'findRequestProvider').and.returnValue(historicalProvider);
element = document.createElement('div');
child = document.createElement('div');
element.appendChild(child);
openmct.time.timeSystem('utc', {
start: 0,
end: 4
});
openmct.types.addType('test-object', {
creatable: true
});
spyOnBuiltins(['requestAnimationFrame']);
window.requestAnimationFrame.and.callFake((callBack) => {
callBack();
});
originalRouterPath = openmct.router.path;
openmct.on('start', done);
openmct.startHeadless();
});
afterEach(() => {
openmct.time.timeSystem('utc', {
start: 0,
end: 1
});
if (unlistenConfigMutation) {
unlistenConfigMutation();
}
return resetApplicationState(openmct);
});
describe('defines a table object', function () {
it('that is creatable', () => {
let tableType = openmct.types.get('table');
expect(tableType.definition.creatable).toBe(true);
});
});
it('provides a table view for objects with telemetry', () => {
const testTelemetryObject = {
id: 'test-object',
type: 'test-object',
telemetry: {
values: [
{
key: 'some-key'
}
]
}
};
const applicableViews = openmct.objectViews.get(testTelemetryObject, []);
let tableView = applicableViews.find((viewProvider) => viewProvider.key === 'table');
expect(tableView).toBeDefined();
});
describe('The table view', () => {
let testTelemetryObject;
let applicableViews;
let tableViewProvider;
let tableView;
let tableInstance;
let mockClock;
beforeEach(async () => {
openmct.time.timeSystem('utc', {
start: 0,
end: 4
});
mockClock = jasmine.createSpyObj('clock', ['on', 'off', 'currentValue']);
mockClock.key = 'mockClock';
mockClock.currentValue.and.returnValue(1);
openmct.time.addClock(mockClock);
openmct.time.clock('mockClock', {
start: 0,
end: 4
});
testTelemetryObject = {
identifier: {
namespace: '',
key: 'test-object'
},
type: 'test-object',
name: 'Test Object',
telemetry: {
values: [
{
key: 'utc',
format: 'utc',
name: 'Time',
hints: {
domain: 1
}
},
{
key: 'some-key',
name: 'Some attribute',
hints: {
range: 1
}
},
{
key: 'some-other-key',
name: 'Another attribute',
hints: {
range: 2
}
}
]
},
configuration: {
hiddenColumns: {
name: false,
utc: false,
'some-key': false,
'some-other-key': false
}
}
};
const testTelemetry = [
{
utc: 1,
'some-key': 'some-value 1',
'some-other-key': 'some-other-value 1'
},
{
utc: 2,
'some-key': 'some-value 2',
'some-other-key': 'some-other-value 2'
},
{
utc: 3,
'some-key': 'some-value 3',
'some-other-key': 'some-other-value 3'
}
];
historicalProvider.request = () => Promise.resolve(testTelemetry);
openmct.router.path = [testTelemetryObject];
applicableViews = openmct.objectViews.get(testTelemetryObject, []);
tableViewProvider = applicableViews.find((viewProvider) => viewProvider.key === 'table');
tableView = tableViewProvider.view(testTelemetryObject, [testTelemetryObject]);
tableView.show(child, true);
tableInstance = tableView.getTable();
await nextTick();
});
afterEach(() => {
openmct.router.path = originalRouterPath;
openmct.time.setClock('local');
});
it('Shows no progress bar initially', () => {
let progressBar = element.querySelector('.c-progress-bar');
expect(tableInstance.outstandingRequests).toBe(0);
expect(progressBar).toBeNull();
});
it('Shows a progress bar while making requests', async () => {
tableInstance.incrementOutstandingRequests();
await nextTick();
let progressBar = element.querySelector('.c-progress-bar');
expect(tableInstance.outstandingRequests).toBe(1);
expect(progressBar).not.toBeNull();
});
it('Renders a row for every telemetry datum returned', async () => {
let rows = element.querySelectorAll('table.c-telemetry-table__body tr');
await nextTick();
expect(rows.length).toBe(3);
});
it('Renders a column for every item in telemetry metadata', () => {
let headers = element.querySelectorAll('span.c-telemetry-table__headers__label');
expect(headers.length).toBe(4);
expect(headers[0].innerText).toBe('Name');
expect(headers[1].innerText).toBe('Time');
expect(headers[2].innerText).toBe('Some attribute');
expect(headers[3].innerText).toBe('Another attribute');
});
it('Supports column reordering via drag and drop', async () => {
let columns = element.querySelectorAll('tr.c-telemetry-table__headers__labels th');
let fromColumn = columns[0];
let toColumn = columns[1];
let fromColumnText = fromColumn.querySelector(
'span.c-telemetry-table__headers__label'
).innerText;
let toColumnText = toColumn.querySelector('span.c-telemetry-table__headers__label').innerText;
let dragStartEvent = createMouseEvent('dragstart');
let dragOverEvent = createMouseEvent('dragover');
let dropEvent = createMouseEvent('drop');
dragStartEvent.dataTransfer =
dragOverEvent.dataTransfer =
dropEvent.dataTransfer =
new MockDataTransfer();
fromColumn.dispatchEvent(dragStartEvent);
toColumn.dispatchEvent(dragOverEvent);
toColumn.dispatchEvent(dropEvent);
await nextTick();
columns = element.querySelectorAll('tr.c-telemetry-table__headers__labels th');
let firstColumn = columns[0];
let secondColumn = columns[1];
let firstColumnText = firstColumn.querySelector(
'span.c-telemetry-table__headers__label'
).innerText;
let secondColumnText = secondColumn.querySelector(
'span.c-telemetry-table__headers__label'
).innerText;
expect(fromColumnText).not.toEqual(firstColumnText);
expect(fromColumnText).toEqual(secondColumnText);
expect(toColumnText).not.toEqual(secondColumnText);
expect(toColumnText).toEqual(firstColumnText);
});
it('Supports filtering telemetry by regular text search', async () => {
tableInstance.tableRows.setColumnFilter('some-key', '1');
await nextTick();
let filteredRowElements = element.querySelectorAll('table.c-telemetry-table__body tr');
expect(filteredRowElements.length).toEqual(1);
tableInstance.tableRows.setColumnFilter('some-key', '');
await nextTick();
let allRowElements = element.querySelectorAll('table.c-telemetry-table__body tr');
expect(allRowElements.length).toEqual(3);
});
it('Supports filtering using Regex', async () => {
tableInstance.tableRows.setColumnRegexFilter('some-key', '^some-value$');
await nextTick();
let filteredRowElements = element.querySelectorAll('table.c-telemetry-table__body tr');
expect(filteredRowElements.length).toEqual(0);
tableInstance.tableRows.setColumnRegexFilter('some-key', '^some-value');
await nextTick();
let allRowElements = element.querySelectorAll('table.c-telemetry-table__body tr');
expect(allRowElements.length).toEqual(3);
});
it('displays the correct number of column headers when the configuration is mutated', async () => {
const tableInstanceConfiguration = tableInstance.domainObject.configuration;
tableInstanceConfiguration.hiddenColumns['some-key'] = true;
unlistenConfigMutation = tableInstance.openmct.objects.mutate(
tableInstance.domainObject,
'configuration',
tableInstanceConfiguration
);
await nextTick();
let tableHeaderElements = element.querySelectorAll('.c-telemetry-table__headers__label');
expect(tableHeaderElements.length).toEqual(3);
tableInstanceConfiguration.hiddenColumns['some-key'] = false;
unlistenConfigMutation = tableInstance.openmct.objects.mutate(
tableInstance.domainObject,
'configuration',
tableInstanceConfiguration
);
await nextTick();
tableHeaderElements = element.querySelectorAll('.c-telemetry-table__headers__label');
expect(tableHeaderElements.length).toEqual(4);
});
it('displays the correct number of table cells in a row when the configuration is mutated', async () => {
const tableInstanceConfiguration = tableInstance.domainObject.configuration;
tableInstanceConfiguration.hiddenColumns['some-key'] = true;
unlistenConfigMutation = tableInstance.openmct.objects.mutate(
tableInstance.domainObject,
'configuration',
tableInstanceConfiguration
);
await nextTick();
let tableRowCells = element.querySelectorAll(
'table.c-telemetry-table__body > tbody > tr:first-child td'
);
expect(tableRowCells.length).toEqual(3);
tableInstanceConfiguration.hiddenColumns['some-key'] = false;
unlistenConfigMutation = tableInstance.openmct.objects.mutate(
tableInstance.domainObject,
'configuration',
tableInstanceConfiguration
);
await nextTick();
tableRowCells = element.querySelectorAll(
'table.c-telemetry-table__body > tbody > tr:first-child td'
);
expect(tableRowCells.length).toEqual(4);
});
it('Pauses the table when a row is marked', async () => {
let firstRow = element.querySelector('table.c-telemetry-table__body > tbody > tr');
let clickEvent = createMouseEvent('click');
// Mark a row
firstRow.dispatchEvent(clickEvent);
await nextTick();
// Verify table is paused
expect(element.querySelector('div.c-table.is-paused')).not.toBeNull();
});
it('Unpauses the table on user bounds change', async () => {
let firstRow = element.querySelector('table.c-telemetry-table__body > tbody > tr');
let clickEvent = createMouseEvent('click');
// Mark a row
firstRow.dispatchEvent(clickEvent);
await nextTick();
// Verify table is paused
expect(element.querySelector('div.c-table.is-paused')).not.toBeNull();
const currentBounds = openmct.time.bounds();
await nextTick();
const newBounds = {
start: currentBounds.start,
end: currentBounds.end - 3
};
// Manually change the time bounds
openmct.time.bounds(newBounds);
await nextTick();
// Verify table is no longer paused
expect(element.querySelector('div.c-table.is-paused')).toBeNull();
});
it('Unpauses the table on user bounds change if paused by button', async () => {
const viewContext = tableView.getViewContext();
// Pause by button
viewContext.togglePauseByButton();
await nextTick();
// Verify table is paused
expect(element.querySelector('div.c-table.is-paused')).not.toBeNull();
const currentBounds = openmct.time.bounds();
await nextTick();
const newBounds = {
start: currentBounds.start,
end: currentBounds.end - 1
};
// Manually change the time bounds
openmct.time.bounds(newBounds);
await nextTick();
// Verify table is no longer paused
expect(element.querySelector('div.c-table.is-paused')).toBeNull();
});
it('Does not unpause the table on tick', async () => {
const viewContext = tableView.getViewContext();
// Pause by button
viewContext.togglePauseByButton();
await nextTick();
// Verify table displays the correct number of rows
let tableRows = element.querySelectorAll('table.c-telemetry-table__body > tbody > tr');
expect(tableRows.length).toEqual(3);
// Verify table is paused
expect(element.querySelector('div.c-table.is-paused')).not.toBeNull();
// Tick the clock
openmct.time.tick(1);
await nextTick();
// Verify table is still paused
expect(element.querySelector('div.c-table.is-paused')).not.toBeNull();
await nextTick();
// Verify table displays the correct number of rows
tableRows = element.querySelectorAll('table.c-telemetry-table__body > tbody > tr');
expect(tableRows.length).toEqual(3);
});
});
});