added error to failing line number in script unit test w/ burnettk

This commit is contained in:
jasquat 2022-09-28 15:18:44 -04:00
parent 270708b2b8
commit c521e0f7fe

View File

@ -1,4 +1,4 @@
import { useContext, useEffect, useState } from 'react'; import { useContext, useEffect, useRef, useState } from 'react';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import { Button, Modal, Stack } from 'react-bootstrap'; import { Button, Modal, Stack } from 'react-bootstrap';
import Container from 'react-bootstrap/Container'; import Container from 'react-bootstrap/Container';
@ -11,6 +11,7 @@ import ReactDiagramEditor from '../components/ReactDiagramEditor';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import HttpService from '../services/HttpService'; import HttpService from '../services/HttpService';
import ErrorContext from '../contexts/ErrorContext'; import ErrorContext from '../contexts/ErrorContext';
import { makeid } from '../helpers';
export default function ProcessModelEditDiagram() { export default function ProcessModelEditDiagram() {
const [showFileNameEditor, setShowFileNameEditor] = useState(false); const [showFileNameEditor, setShowFileNameEditor] = useState(false);
@ -22,25 +23,38 @@ export default function ProcessModelEditDiagram() {
const [showScriptEditor, setShowScriptEditor] = useState(false); const [showScriptEditor, setShowScriptEditor] = useState(false);
const handleShowScriptEditor = () => setShowScriptEditor(true); const handleShowScriptEditor = () => setShowScriptEditor(true);
const editorRef = useRef(null);
const monacoRef = useRef(null);
const failingScriptLineClassNamePrefix = 'failingScriptLineError';
function handleEditorDidMount(editor: any, monaco: any) {
// here is the editor instance
// you can store it in `useRef` for further usage
editorRef.current = editor;
monacoRef.current = monaco;
}
interface ScriptUnitTest { interface ScriptUnitTest {
id: string; id: string;
inputJson: any; inputJson: any;
expectedOutputJson: any; expectedOutputJson: any;
} }
interface ScriptUnitTestResult {
result: boolean;
context: object;
error: string;
line_number: number;
offset: number;
}
const [currentScriptUnitTest, setCurrentScriptUnitTest] = const [currentScriptUnitTest, setCurrentScriptUnitTest] =
useState<ScriptUnitTest | null>(null); useState<ScriptUnitTest | null>(null);
const [currentScriptUnitTestIndex, setCurrentScriptUnitTestIndex] = const [currentScriptUnitTestIndex, setCurrentScriptUnitTestIndex] =
useState<number>(-1); useState<number>(-1);
const [unitTestResultBool, setUnitTestResultBool] = useState<boolean | null>( const [scriptUnitTestResult, setScriptUnitTestResult] =
null useState<ScriptUnitTestResult | null>(null);
);
const [unitTestResultContext, setUnitTestResultContext] = useState<
object | null
>(null);
const [unitTestResultErrorString, setUnitTestResultErrorString] = useState<
string | null
>(null);
const params = useParams(); const params = useParams();
const navigate = useNavigate(); const navigate = useNavigate();
@ -174,9 +188,17 @@ export default function ProcessModelEditDiagram() {
}; };
const resetUnitTextResult = () => { const resetUnitTextResult = () => {
setUnitTestResultBool(null); setScriptUnitTestResult(null);
setUnitTestResultContext(null); const styleSheet = document.styleSheets[0];
setUnitTestResultErrorString(null); const ruleList = styleSheet.cssRules;
for (let ii = ruleList.length - 1; ii >= 0; ii -= 1) {
const regexp = new RegExp(
`^.${failingScriptLineClassNamePrefix}_.*::after `
);
if (ruleList[ii].cssText.match(regexp)) {
styleSheet.deleteRule(ii);
}
}
}; };
const makeApiHandler = (event: any) => { const makeApiHandler = (event: any) => {
@ -281,17 +303,49 @@ export default function ProcessModelEditDiagram() {
}; };
const processScriptUnitTestRunResult = (result: any) => { const processScriptUnitTestRunResult = (result: any) => {
if (result.result === true) { if ('result' in result) {
setUnitTestResultBool(true); setScriptUnitTestResult(result);
} else { if (
setUnitTestResultContext(result.context); result.line_number &&
setUnitTestResultErrorString(result.error); result.error &&
setUnitTestResultBool(false); editorRef.current &&
monacoRef.current
) {
const currentClassName = `${failingScriptLineClassNamePrefix}_${makeid(
7
)}`;
// document.documentElement.style.setProperty causes the content property to go away
// so add the rule dynamically instead of changing a property variable
document.styleSheets[0].addRule(
`.${currentClassName}::after`,
`content: " # ${result.error}"; color: red`
);
const lineLength =
scriptText.split('\n')[result.line_number - 1].length + 1;
const editorRefToUse = editorRef.current as any;
editorRefToUse.deltaDecorations(
[],
[
{
// Range(lineStart, column, lineEnd, column)
range: new (monacoRef.current as any).Range(
result.line_number,
lineLength
),
options: { afterContentClassName: currentClassName },
},
]
);
}
} }
}; };
const runCurrentUnitTest = () => { const runCurrentUnitTest = () => {
if (currentScriptUnitTest && scriptElement) { if (currentScriptUnitTest && scriptElement) {
resetUnitTextResult();
HttpService.makeCallToBackend({ HttpService.makeCallToBackend({
path: `/process-models/${params.process_group_id}/${params.process_model_id}/script-unit-tests/run`, path: `/process-models/${params.process_group_id}/${params.process_model_id}/script-unit-tests/run`,
httpMethod: 'POST', httpMethod: 'POST',
@ -305,20 +359,30 @@ export default function ProcessModelEditDiagram() {
}; };
const unitTestFailureElement = () => { const unitTestFailureElement = () => {
if (scriptUnitTestResult && scriptUnitTestResult.result === false) {
let errorStringElement = null; let errorStringElement = null;
if (unitTestResultErrorString) { if (scriptUnitTestResult.error) {
errorStringElement = ( errorStringElement = (
<span> <span>
Received error when running script:{' '} Received error when running script:{' '}
{JSON.stringify(unitTestResultErrorString)} {JSON.stringify(scriptUnitTestResult.error)}
</span> </span>
); );
} }
let errorContextElement = null; let errorContextElement = null;
if (unitTestResultContext) { if (scriptUnitTestResult.context) {
errorContextElement = ( errorContextElement = (
<span> <span>
Received unexpected output: {JSON.stringify(unitTestResultContext)} Received unexpected output:{' '}
{JSON.stringify(scriptUnitTestResult.context)}
</span>
);
}
const lineNumberElement = null;
if (scriptUnitTestResult.line_number) {
errorContextElement = (
<span>
At line: {JSON.stringify(scriptUnitTestResult.line_number)}
</span> </span>
); );
} }
@ -326,8 +390,11 @@ export default function ProcessModelEditDiagram() {
<span style={{ color: 'red', fontSize: '1em' }}> <span style={{ color: 'red', fontSize: '1em' }}>
{errorStringElement} {errorStringElement}
{errorContextElement} {errorContextElement}
{lineNumberElement}
</span> </span>
); );
}
return null;
}; };
const scriptUnitTestEditorElement = () => { const scriptUnitTestEditorElement = () => {
@ -347,6 +414,20 @@ export default function ProcessModelEditDiagram() {
setCurrentScriptUnitTest(null); setCurrentScriptUnitTest(null);
setCurrentScriptUnitTestIndex(-1); setCurrentScriptUnitTestIndex(-1);
} }
let scriptUnitTestResultBoolElement = null;
if (scriptUnitTestResult) {
scriptUnitTestResultBoolElement = (
<Col xs={1}>
{scriptUnitTestResult.result === true && (
<span style={{ color: 'green', fontSize: '3em' }}></span>
)}
{scriptUnitTestResult.result === false && (
<span style={{ color: 'red', fontSize: '3em' }}></span>
)}
</Col>
);
}
return ( return (
<main> <main>
<Container> <Container>
@ -378,14 +459,7 @@ export default function ProcessModelEditDiagram() {
Run Run
</Button> </Button>
</Col> </Col>
<Col xs={1}> {scriptUnitTestResultBoolElement}
{unitTestResultBool === true && (
<span style={{ color: 'green', fontSize: '3em' }}></span>
)}
{unitTestResultBool === false && (
<span style={{ color: 'red', fontSize: '3em' }}></span>
)}
</Col>
<Col className="d-flex justify-content-end"> <Col className="d-flex justify-content-end">
<Button <Button
data-qa="unit-test-next-button" data-qa="unit-test-next-button"
@ -456,6 +530,7 @@ export default function ProcessModelEditDiagram() {
defaultLanguage="python" defaultLanguage="python"
defaultValue={scriptText} defaultValue={scriptText}
onChange={handleEditorScriptChange} onChange={handleEditorScriptChange}
onMount={handleEditorDidMount}
/> />
{scriptUnitTestEditorElement()} {scriptUnitTestEditorElement()}
</Modal.Body> </Modal.Body>