-
-
Notifications
You must be signed in to change notification settings - Fork 17
Add dolt_tests to workbench #630
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good so far, started with the graphql server code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few higher level comments before I get into the details
web/renderer/components/pageComponents/DatabasePage/ForTests/TestList/useTestList.ts
Outdated
Show resolved
Hide resolved
web/renderer/components/pageComponents/DatabasePage/ForTests/TestList/TestItemRenderer.tsx
Outdated
Show resolved
Hide resolved
web/renderer/components/pageComponents/DatabasePage/ForTests/TestList/index.tsx
Outdated
Show resolved
Hide resolved
web/renderer/components/pageComponents/DatabasePage/ForTests/TestList/useTestList.ts
Outdated
Show resolved
Hide resolved
web/renderer/components/pageComponents/DatabasePage/ForTests/TestGroup/index.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking much better
I know you have your blog today and most of these comments are best practice related and non blocking. If needed they can be addressed after you get this all in
The one blocking one is making sure that if runTests
results in an error at any point that that error is displayed on the page
Also, have you tested this with doltgres? If it doesn't work you should hide this tab for doltgres databases
web/renderer/components/pageComponents/DatabasePage/ForPulls/PullActions/Merge/index.tsx
Show resolved
Hide resolved
expandedItems: Set<string>; | ||
expandedGroups: Set<string>; | ||
emptyGroups: Set<string>; | ||
editingTestNames: Record<string, string>; | ||
tests: Test[]; | ||
groupedTests: Record<string, Test[]>; | ||
sortedGroupEntries: Array<[string, Test[]]>; | ||
testResults: Record< | ||
string, | ||
{ status: "passed" | "failed"; error?: string } | undefined | ||
>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you return state: TestState
from the context so you don't need to list all these types out twice?
flex: 1 1 auto; | ||
min-width: 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should use tailwind classes for all these in this file too
@apply w-full !important; | ||
width: 100% !important; | ||
min-width: 100% !important; | ||
max-width: 100% !important; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should avoid using !important
whenever possible. It gets messy quickly. There are usually other ways to make it work
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); | ||
const [localAssertionValue, setLocalAssertionValue] = useState( | ||
test.assertionValue, | ||
); | ||
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null); | ||
|
||
const updateTest = useCallback( | ||
(name: string, field: keyof Test, value: string) => { | ||
setState({ | ||
tests: tests.map((test: Test) => | ||
test.testName === name ? { ...test, [field]: value } : test, | ||
), | ||
hasUnsavedChanges: true, | ||
}); | ||
}, | ||
[tests, setState], | ||
); | ||
|
||
const handleDeleteTest = (testName: string) => { | ||
const newExpandedItems = new Set(expandedItems); | ||
newExpandedItems.delete(testName); | ||
setState({ | ||
tests: tests.filter(test => test.testName !== testName), | ||
expandedItems: newExpandedItems, | ||
hasUnsavedChanges: true, | ||
}); | ||
}; | ||
|
||
const handleTestNameEdit = (testId: string, name: string) => { | ||
setState({ | ||
editingTestNames: { | ||
...editingTestNames, | ||
[testId]: name, | ||
}, | ||
}); | ||
}; | ||
|
||
const handleTestNameBlur = (testName: string) => { | ||
const newName = editingTestNames[testName]; | ||
const test = tests.find(t => t.testName === testName); | ||
if (newName.trim() && newName !== test?.testName) { | ||
updateTest(testName, "testName", newName.trim()); | ||
} | ||
const newEditingTestNames = { ...editingTestNames }; | ||
delete newEditingTestNames[testName]; | ||
setState({ editingTestNames: newEditingTestNames }); | ||
}; | ||
|
||
const groupOptions = sortedGroupEntries | ||
.map(entry => entry[0]) | ||
.filter(group => group !== ""); | ||
const isExpanded = expandedItems.has(test.testName); | ||
const editingName = editingTestNames[test.testName]; | ||
const testResult = testResults[test.testName]; | ||
|
||
const debouncedOnUpdateTest = (field: keyof Test, value: string) => { | ||
if (debounceRef.current) { | ||
clearTimeout(debounceRef.current); | ||
} | ||
debounceRef.current = setTimeout(() => { | ||
updateTest(test.testName, field, value); | ||
}, 500); // 500ms debounce | ||
}; | ||
|
||
useEffect( | ||
() => () => { | ||
if (debounceRef.current) { | ||
clearTimeout(debounceRef.current); | ||
} | ||
}, | ||
[], | ||
); | ||
|
||
useEffect(() => { | ||
setLocalAssertionValue(test.assertionValue); | ||
}, [test.assertionValue]); | ||
|
||
const handleDeleteClick = (e: MouseEvent) => { | ||
e.stopPropagation(); | ||
setShowDeleteConfirm(true); | ||
}; | ||
|
||
const handleConfirmDelete = () => { | ||
setShowDeleteConfirm(false); | ||
handleDeleteTest(test.testName); | ||
}; | ||
|
||
const handleCancelDelete = () => { | ||
setShowDeleteConfirm(false); | ||
}; | ||
|
||
const handleAssertionValueBlur = () => { | ||
if (localAssertionValue !== test.assertionValue) { | ||
updateTest(test.testName, "assertionValue", localAssertionValue); | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the group item comment, this could be moved into a useEditTestItem
hook in this dir
<div className={css.expandedContent}> | ||
{testResult?.status === "failed" && testResult.error && ( | ||
<div className={css.errorMessage}> | ||
<strong>Error:</strong> {testResult.error} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would prefer using a span
with a className here over strong
…ontext/index.tsx Co-authored-by: Taylor Bantle <[email protected]>
Co-authored-by: Taylor Bantle <[email protected]>
…estGroup/index.tsx Co-authored-by: Taylor Bantle <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some error handling related comments, but none of them are blocking
<span style={{ color: "red" }}> | ||
Failed to load tests: {error.message} | ||
</span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should use ErrorMsg
for styling
<div style={{ color: "red", padding: "8px" }}> | ||
Error running tests: {runTestError || runTestsError?.message} | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here too. And should generally avoid using inline styling like this and use classes instead
}); | ||
|
||
if (result.error) { | ||
console.error("Error running tests:", result.error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need to console the error if you're displaying the error
const [testResults, setTestResults] = useState<TestResult[]>([]); | ||
const [runTests] = useRunTestsLazyQuery(); | ||
const { data } = useTestListQuery({ | ||
const [runTestError, setRunTestError] = useState<string | null>(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useApolloError
might simplify some of the type casting below
if (runTestsError) { | ||
console.error("Run Tests query error:", runTestsError); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need this
useEffect(() => { | ||
if (testsError) { | ||
console.error("Error loading tests:", testsError); | ||
} | ||
}, [testsError]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need this
result.data && | ||
result.data.runTests.list.length > 0 && | ||
result.data.runTests.list[0].status === "PASS"; | ||
{} as Record<string, { status: "passed" | "failed"; error?: string }>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could make { status: "passed" | "failed"; error?: string }
a named type since it's repeated a few times
result.data?.runTests.list.map(test => | ||
test.status === "PASS" | ||
? { | ||
status: "passed", | ||
} | ||
: { | ||
status: "failed", | ||
error: test.message, | ||
}, | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be assigned to something?
<Button>Commit</Button> | ||
</Link> | ||
</div> | ||
{!testsLoading && !testsError && ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should put all of this in an Inner
component and use this pattern that we use in other components:
if (loading) return <Loader />
if (error) return <ErrorMsg />
return <div>{...inner test stuff that relies on query results}</div>
There's also a QueryHandler
util component that does this for you
This PR adds functionality to support the
dolt_tests
system table anddolt_test_run()
table function. This includes the new "Tests" tab, which allows you to view, edit, and run tests, as well as a test runner component that allows you to run tests and view test results before merging a branch.