chore(client): migrate TestSuite component to TypeScript (#43794)
* chore: rename Test-Suite.js to test-suite.tsx * feat: migrate test-suite to ts * feat: use type guard to narrow down tests prop * revert: text prop from Test type I added when rebasing * remove optionality from props Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com> Co-authored-by: moT01 <20648924+moT01@users.noreply.github.com> Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@ -1,17 +1,18 @@
|
|||||||
import React, { useEffect, ReactElement } from 'react';
|
import React, { useEffect, ReactElement } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
import { Test } from '../../../redux/prop-types';
|
||||||
|
|
||||||
import { mathJaxScriptLoader } from '../../../utils/script-loaders';
|
import { mathJaxScriptLoader } from '../../../utils/script-loaders';
|
||||||
import { challengeTestsSelector } from '../redux';
|
import { challengeTestsSelector } from '../redux';
|
||||||
import TestSuite from './Test-Suite';
|
import TestSuite from './test-suite';
|
||||||
import ToolPanel from './tool-panel';
|
import ToolPanel from './tool-panel';
|
||||||
|
|
||||||
import './side-panel.css';
|
import './side-panel.css';
|
||||||
|
|
||||||
const mapStateToProps = createSelector(
|
const mapStateToProps = createSelector(
|
||||||
challengeTestsSelector,
|
challengeTestsSelector,
|
||||||
(tests: Record<string, unknown>[]) => ({
|
(tests: Test[]) => ({
|
||||||
tests
|
tests
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -22,7 +23,7 @@ interface SidePanelProps {
|
|||||||
guideUrl: string;
|
guideUrl: string;
|
||||||
instructionsPanelRef: React.RefObject<HTMLDivElement>;
|
instructionsPanelRef: React.RefObject<HTMLDivElement>;
|
||||||
showToolPanel: boolean;
|
showToolPanel: boolean;
|
||||||
tests?: Record<string, unknown>[];
|
tests: Test[];
|
||||||
videoUrl: string;
|
videoUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import Fail from '../../../assets/icons/fail';
|
import Fail from '../../../assets/icons/fail';
|
||||||
@ -6,12 +5,22 @@ import GreenPass from '../../../assets/icons/green-pass';
|
|||||||
import Initial from '../../../assets/icons/initial';
|
import Initial from '../../../assets/icons/initial';
|
||||||
|
|
||||||
import './test-suite.css';
|
import './test-suite.css';
|
||||||
|
import { ChallengeTest, Test } from '../../../redux/prop-types';
|
||||||
|
|
||||||
const propTypes = {
|
type TestSuiteTest = {
|
||||||
tests: PropTypes.arrayOf(PropTypes.object)
|
err?: string;
|
||||||
};
|
pass?: boolean;
|
||||||
|
} & ChallengeTest;
|
||||||
|
|
||||||
function getAccessibleText(err, pass, text) {
|
function isTestSuiteTest(test: Test): test is TestSuiteTest {
|
||||||
|
return 'text' in test;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TestSuiteProps {
|
||||||
|
tests: Test[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAccessibleText(text: string, err?: string, pass?: boolean) {
|
||||||
let accessibleText = 'Waiting';
|
let accessibleText = 'Waiting';
|
||||||
const cleanText = text.replace(/<\/?code>/g, '');
|
const cleanText = text.replace(/<\/?code>/g, '');
|
||||||
|
|
||||||
@ -26,17 +35,19 @@ function getAccessibleText(err, pass, text) {
|
|||||||
return accessibleText + ' - ' + cleanText;
|
return accessibleText + ' - ' + cleanText;
|
||||||
}
|
}
|
||||||
|
|
||||||
function TestSuite({ tests }) {
|
function TestSuite({ tests }: TestSuiteProps): JSX.Element {
|
||||||
|
const testSuiteTests = tests.filter(isTestSuiteTest);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='challenge-test-suite'>
|
<div className='challenge-test-suite'>
|
||||||
{tests.map(({ err, pass = false, text = '' }, index) => {
|
{testSuiteTests.map(({ err, pass = false, text = '' }, index) => {
|
||||||
const isInitial = !pass && !err;
|
const isInitial = !pass && !err;
|
||||||
const statusIcon = pass && !err ? <GreenPass /> : <Fail />;
|
const statusIcon = pass && !err ? <GreenPass /> : <Fail />;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
aria-label={getAccessibleText(err, pass, text)}
|
aria-label={getAccessibleText(text, err, pass)}
|
||||||
className='test-result'
|
className='test-result'
|
||||||
key={text.slice(-6) + index}
|
key={text.slice(-6) + String(index)}
|
||||||
>
|
>
|
||||||
<div className='test-status-icon'>
|
<div className='test-status-icon'>
|
||||||
{isInitial ? <Initial /> : statusIcon}
|
{isInitial ? <Initial /> : statusIcon}
|
||||||
@ -45,7 +56,6 @@ function TestSuite({ tests }) {
|
|||||||
aria-hidden='true'
|
aria-hidden='true'
|
||||||
className='test-output'
|
className='test-output'
|
||||||
dangerouslySetInnerHTML={{ __html: text }}
|
dangerouslySetInnerHTML={{ __html: text }}
|
||||||
xs={10}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -55,6 +65,5 @@ function TestSuite({ tests }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TestSuite.displayName = 'TestSuite';
|
TestSuite.displayName = 'TestSuite';
|
||||||
TestSuite.propTypes = propTypes;
|
|
||||||
|
|
||||||
export default TestSuite;
|
export default TestSuite;
|
@ -20,11 +20,11 @@ import {
|
|||||||
} from '../../../../redux/prop-types';
|
} from '../../../../redux/prop-types';
|
||||||
import ChallengeDescription from '../../components/Challenge-Description';
|
import ChallengeDescription from '../../components/Challenge-Description';
|
||||||
import Hotkeys from '../../components/Hotkeys';
|
import Hotkeys from '../../components/Hotkeys';
|
||||||
import TestSuite from '../../components/Test-Suite';
|
|
||||||
import ChallengeTitle from '../../components/challenge-title';
|
import ChallengeTitle from '../../components/challenge-title';
|
||||||
import CompletionModal from '../../components/completion-modal';
|
import CompletionModal from '../../components/completion-modal';
|
||||||
import HelpModal from '../../components/help-modal';
|
import HelpModal from '../../components/help-modal';
|
||||||
import Output from '../../components/output';
|
import Output from '../../components/output';
|
||||||
|
import TestSuite from '../../components/test-suite';
|
||||||
import {
|
import {
|
||||||
challengeMounted,
|
challengeMounted,
|
||||||
challengeTestsSelector,
|
challengeTestsSelector,
|
||||||
|
Reference in New Issue
Block a user