@finos/legend-studio
Version:
129 lines • 12.4 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/**
* Copyright (c) 2020-present, Goldman Sachs
*
* 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.
*/
import { EDITOR_LANGUAGE } from '@finos/legend-application';
import { clsx, PanelLoadingIndicator, PlayIcon, TreeView, ChevronDownIcon, ChevronRightIcon, RefreshIcon, TimesCircleIcon, CheckCircleIcon, ContextMenu, MenuContent, MenuContentItem, Dialog, WarningIcon, CircleNotchIcon, EmptyCircleIcon, } from '@finos/legend-art';
import { AssertFail, EqualToJsonAssertFail, TestError, } from '@finos/legend-graph';
import { isNonNullable } from '@finos/legend-shared';
import { observer } from 'mobx-react-lite';
import { forwardRef, useEffect } from 'react';
import { TESTABLE_RESULT, AtomicTestTreeNodeData, AssertionTestTreeNodeData, TestableTreeNodeData, TestSuiteTreeNodeData, getNodeTestableResult, getAtomicTest_TestResult, getAssertionStatus, } from '../../../../stores/sidebar-state/testable/GlobalTestRunnerState.js';
import { LEGEND_STUDIO_TEST_ID } from '../../../LegendStudioTestID.js';
import { TextDiffView } from '../../../shared/DiffView.js';
import { StudioTextInputEditor } from '../../../shared/StudioTextInputEditor.js';
import { useEditorStore } from '../../EditorStoreProvider.js';
export const getTestableResultIcon = (testableResult) => {
switch (testableResult) {
case TESTABLE_RESULT.PASSED:
return (_jsx("div", { title: "Test passed", className: "global-test-runner__item__link__content__status__indicator global-test-runner__item__link__content__status__indicator--succeeded", children: _jsx(CheckCircleIcon, {}) }));
case TESTABLE_RESULT.IN_PROGRESS:
return (_jsx("div", { title: "Test is running", className: "global-test-runner__item__link__content__status__indicator workflow-manager__item__link__content__status__indicator--in-progress", children: _jsx(CircleNotchIcon, {}) }));
case TESTABLE_RESULT.FAILED:
return (_jsx("div", { title: "Test Failed", className: "global-test-runner__item__link__content__status__indicator global-test-runner__item__link__content__status__indicator--failed", children: _jsx(TimesCircleIcon, {}) }));
case TESTABLE_RESULT.ERROR:
return (_jsx("div", { title: "Test has an error", className: "global-test-runner__item__link__content__status__indicator global-test-runner__item__link__content__status__indicator--failed", children: _jsx(WarningIcon, {}) }));
default:
return (_jsx("div", { title: "Test did not run", className: "global-test-runner__item__link__content__status__indicator global-test-runner__item__link__content__status__indicator--unknown", children: _jsx(EmptyCircleIcon, {}) }));
}
};
const getOptionalError = (node, testableState) => {
if (node instanceof AtomicTestTreeNodeData) {
const result = getAtomicTest_TestResult(node.atomicTest, testableState.results);
if (result instanceof TestError) {
return result;
}
}
else if (node instanceof AssertionTestTreeNodeData) {
const status = getAssertionStatus(node.assertion, testableState.results);
if (status instanceof AssertFail) {
return status;
}
}
return undefined;
};
const TestFailViewer = observer((props) => {
const { globalTestRunnerState, failure } = props;
const id = failure instanceof TestError
? failure.atomicTestId.atomicTest.id
: failure.assertion.id;
const closeLogViewer = () => globalTestRunnerState.setFailureViewing(undefined);
return (_jsx(Dialog, { open: Boolean(failure), onClose: closeLogViewer, classes: {
root: 'editor-modal__root-container',
container: 'editor-modal__container',
paper: 'editor-modal__content',
}, children: _jsxs("div", { className: "modal modal--dark editor-modal", children: [_jsx(PanelLoadingIndicator, { isLoading: globalTestRunnerState.isDispatchingAction }), _jsx("div", { className: "modal__header", children: _jsx("div", { className: "modal__title", children: id }) }), _jsxs("div", { className: "modal__body", children: [failure instanceof TestError && (_jsx(StudioTextInputEditor, { inputValue: failure.error, isReadOnly: true, language: EDITOR_LANGUAGE.TEXT, showMiniMap: true })), failure instanceof EqualToJsonAssertFail && (_jsx(TextDiffView, { language: EDITOR_LANGUAGE.JSON, from: failure.expected, to: failure.actual })), failure instanceof AssertFail &&
!(failure instanceof EqualToJsonAssertFail) && (_jsx(StudioTextInputEditor, { inputValue: failure.message ?? '', isReadOnly: true, language: EDITOR_LANGUAGE.TEXT }))] }), _jsx("div", { className: "modal__footer", children: _jsx("button", { className: "btn modal__footer__close-btn", onClick: closeLogViewer, children: "Close" }) })] }) }));
});
const TestableExplorerContextMenu = observer(forwardRef(function TestableExplorerContextMenu(props, ref) {
const { node, error, globalTestRunnerState, testableState } = props;
const runTest = () => {
testableState.run(node);
};
const viewError = () => globalTestRunnerState.setFailureViewing(error);
return (_jsxs(MenuContent, { "data-testid": LEGEND_STUDIO_TEST_ID.EXPLORER_CONTEXT_MENU, children: [_jsx(MenuContentItem, { disabled: globalTestRunnerState.isDispatchingAction, onClick: runTest, children: "Run" }), error && (_jsx(MenuContentItem, { onClick: viewError, children: error instanceof TestError ? 'View Error' : 'View assert fail' }))] }));
}));
const TestableTreeNodeContainer = (props) => {
const { node, level, stepPaddingInRem, onNodeSelect } = props;
const { treeData, testableState, globalTestRunnerState } = props.innerProps;
const results = testableState.results;
const expandIcon = node instanceof AssertionTestTreeNodeData ? (_jsx("div", {})) : node.isOpen ? (_jsx(ChevronDownIcon, {})) : (_jsx(ChevronRightIcon, {}));
const nodeIcon = node instanceof TestableTreeNodeData ? node.testableMetadata.icon : null;
const resultIcon = getTestableResultIcon(getNodeTestableResult(node, testableState.globalTestRunnerState.isRunningTests.isInProgress, results));
const optionalError = getOptionalError(node, testableState);
// );
const selectNode = (event) => onNodeSelect?.(node);
return (_jsx(ContextMenu, { content: _jsx(TestableExplorerContextMenu, { globalTestRunnerState: globalTestRunnerState, testableState: testableState, treeData: treeData, node: node, error: optionalError }), menuProps: { elevation: 7 }, children: _jsxs("div", { className: clsx('tree-view__node__container global-test-runner__explorer__testable-tree__node__container'), onClick: selectNode, style: {
paddingLeft: `${level * (stepPaddingInRem ?? 1)}rem`,
display: 'flex',
}, children: [_jsxs("div", { className: "tree-view__node__icon global-test-runner__explorer__testable-tree__node__icon", children: [_jsx("div", { className: "global-test-runner__explorer__testable-tree__node__icon__expand", children: expandIcon }), _jsx("div", { className: "global-test-runner__explorer__testable-tree__node__icon__type", children: resultIcon }), nodeIcon && (_jsx("div", { className: "global-test-runner__explorer__testable-tree__node__result__icon__type", children: nodeIcon }))] }), node instanceof TestableTreeNodeData && (_jsx("div", { className: "global-test-runner__item__link__content", children: _jsx("span", { className: "global-test-runner__item__link__content__id", children: node.testableMetadata.name }) })), node instanceof TestSuiteTreeNodeData && (_jsx("div", { className: "global-test-runner__item__link__content", children: _jsx("span", { className: "global-test-runner__item__link__content__id", children: node.label }) })), node instanceof AtomicTestTreeNodeData && (_jsx("div", { className: "global-test-runner__item__link__content", children: _jsx("span", { className: "global-test-runner__item__link__content__id", children: node.label }) })), node instanceof AssertionTestTreeNodeData && (_jsx("div", { className: "global-test-runner__item__link__content", children: _jsx("span", { className: "global-test-runner__item__link__content__id", children: node.label }) }))] }) }));
};
// TODO:
// - Handle Multi Execution Test Results
// - Add `Visit Test` to open test editors when Testable Editors are complete
export const GlobalTestRunner = observer((props) => {
const editorStore = useEditorStore();
const globalTestRunnerState = props.globalTestRunnerState;
const isDispatchingAction = globalTestRunnerState.isDispatchingAction;
const renderTestables = () => (_jsx(_Fragment, { children: (globalTestRunnerState.testableStates ?? []).map((testableState) => {
const onNodeSelect = (node) => {
testableState.onTreeNodeSelect(node, testableState.treeData);
};
const getChildNodes = (node) => {
if (node.childrenIds) {
return node.childrenIds
.map((id) => testableState.treeData.nodes.get(id))
.filter(isNonNullable);
}
return [];
};
return (_jsx(TreeView, { components: {
TreeNodeContainer: TestableTreeNodeContainer,
}, treeData: testableState.treeData, onNodeSelect: onNodeSelect, getChildNodes: getChildNodes, innerProps: {
globalTestRunnerState,
testableState,
treeData: testableState.treeData,
} }, testableState.uuid));
}) }));
useEffect(() => {
editorStore.globalTestRunnerState.init();
}, [editorStore.globalTestRunnerState]);
const runAllTests = () => globalTestRunnerState.runAllTests(undefined);
const reset = () => globalTestRunnerState.init(true);
return (_jsxs("div", { "data-testid": LEGEND_STUDIO_TEST_ID.GLOBAL_TEST_RUNNER, className: "panel global-test-runner", children: [_jsxs("div", { className: "panel__header side-bar__header", children: [_jsx("div", { className: "panel__header__title global-test-runner__header__title", children: _jsx("div", { className: "panel__header__title__content side-bar__header__title__content", children: "GLOBAL TEST RUNNER" }) }), _jsxs("div", { className: "panel__header__actions side-bar__header__actions", children: [_jsx("button", { className: clsx('panel__header__action side-bar__header__action global-test-runner__refresh-btn', {
'global-test-runner__refresh-btn--loading': isDispatchingAction,
}), disabled: isDispatchingAction, onClick: reset, tabIndex: -1, title: "Run All Tests", children: _jsx(RefreshIcon, {}) }), _jsx("button", { className: "panel__header__action side-bar__header__action global-test-runner__refresh-btn", disabled: isDispatchingAction, onClick: runAllTests, tabIndex: -1, title: "Run All Tests", children: _jsx(PlayIcon, {}) })] })] }), _jsxs("div", { className: "panel__content side-bar__content", children: [_jsx(PanelLoadingIndicator, { isLoading: isDispatchingAction }), _jsxs("div", { className: "panel side-bar__panel", children: [_jsxs("div", { className: "panel__header", children: [_jsx("div", { className: "panel__header__title", children: _jsx("div", { className: "panel__header__title__content", children: "TESTABLES" }) }), _jsx("div", { className: "side-bar__panel__header__changes-count", "data-testid": LEGEND_STUDIO_TEST_ID.SIDEBAR_PANEL_HEADER__CHANGES_COUNT })] }), _jsx("div", { className: "panel__content", children: renderTestables() }), globalTestRunnerState.failureViewing && (_jsx(TestFailViewer, { globalTestRunnerState: globalTestRunnerState, failure: globalTestRunnerState.failureViewing }))] })] })] }));
});
//# sourceMappingURL=GlobalTestRunner.js.map