Skip to content

Commit

Permalink
feat: Test Queue v2 (#1124)
Browse files Browse the repository at this point in the history
Addresses #791 (comment)

---------

Co-authored-by: Paul Clue <[email protected]>
Co-authored-by: alflennik <[email protected]>
  • Loading branch information
3 people authored Jun 20, 2024
1 parent d9374ca commit 0f42b1d
Show file tree
Hide file tree
Showing 44 changed files with 2,916 additions and 1,095 deletions.
92 changes: 66 additions & 26 deletions client/components/AddTestToQueueWithConfirmation/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import {
SCHEDULE_COLLECTION_JOB_MUTATION,
EXISTING_TEST_PLAN_REPORTS
} from './queries';
import { TEST_QUEUE_PAGE_QUERY } from '../TestQueue2/queries';
import { TEST_PLAN_REPORT_STATUS_DIALOG_QUERY } from '../TestPlanReportStatusDialog/queries';
import { ME_QUERY } from '../App/queries';

function AddTestToQueueWithConfirmation({
testPlanVersion,
Expand All @@ -29,8 +32,27 @@ function AddTestToQueueWithConfirmation({
useState(false);
const [showConfirmation, setShowConfirmation] = useState(false);
const [canUseOldResults, setCanUseOldResults] = useState(false);
const [addTestPlanReport] = useMutation(ADD_TEST_QUEUE_MUTATION);
const [scheduleCollection] = useMutation(SCHEDULE_COLLECTION_JOB_MUTATION);

const [addTestPlanReport] = useMutation(ADD_TEST_QUEUE_MUTATION, {
refetchQueries: [
ME_QUERY,
EXISTING_TEST_PLAN_REPORTS,
TEST_QUEUE_PAGE_QUERY,
TEST_PLAN_REPORT_STATUS_DIALOG_QUERY
],
awaitRefetchQueries: true
});

const [scheduleCollection] = useMutation(SCHEDULE_COLLECTION_JOB_MUTATION, {
refetchQueries: [
ME_QUERY,
EXISTING_TEST_PLAN_REPORTS,
TEST_QUEUE_PAGE_QUERY,
TEST_PLAN_REPORT_STATUS_DIALOG_QUERY
],
awaitRefetchQueries: true
});

const { data: existingTestPlanReportsData } = useQuery(
EXISTING_TEST_PLAN_REPORTS,
{
Expand All @@ -49,13 +71,23 @@ function AddTestToQueueWithConfirmation({
let latestOldVersion;
let oldReportToCopyResultsFrom;

// Check if any results data available from a previous result
if (existingTestPlanReportsData?.oldTestPlanVersions?.length) {
latestOldVersion =
existingTestPlanReportsData?.oldTestPlanVersions?.reduce((a, b) =>
new Date(a.updatedAt) > new Date(b.updatedAt) ? a : b
);
// Check if any results data available from a previous result using the
// same testFormatVersion
const oldTestPlanVersions =
existingTestPlanReportsData?.oldTestPlanVersions?.filter(
({ metadata }) => {
return (
metadata.testFormatVersion ===
existingTestPlanReportsData?.existingTestPlanVersion
?.metadata.testFormatVersion
);
}
) || [];

if (oldTestPlanVersions?.length) {
latestOldVersion = oldTestPlanVersions?.reduce((a, b) =>
new Date(a.updatedAt) > new Date(b.updatedAt) ? a : b
);
if (
new Date(latestOldVersion?.updatedAt) <
new Date(testPlanVersion?.updatedAt)
Expand Down Expand Up @@ -122,32 +154,40 @@ function AddTestToQueueWithConfirmation({
actions.push({
label: 'Add and run later',
onClick: async () => {
await addTestToQueue(
canUseOldResults
? {
copyResultsFromTestPlanVersionId:
latestOldVersion.id
}
: {}
);
await closeWithUpdate();
}
});

if (!alreadyHasBotInTestPlanReport) {
actions.push({
label: 'Add and run with bot',
onClick: async () => {
const testPlanReport = await addTestToQueue(
try {
await addTestToQueue(
canUseOldResults
? {
copyResultsFromTestPlanVersionId:
latestOldVersion.id
}
: {}
);
await scheduleCollectionJob(testPlanReport);
await closeWithUpdate();
} catch (e) {
console.error(e);
}
}
});

if (!alreadyHasBotInTestPlanReport) {
actions.push({
label: 'Add and run with bot',
onClick: async () => {
try {
const testPlanReport = await addTestToQueue(
canUseOldResults
? {
copyResultsFromTestPlanVersionId:
latestOldVersion.id
}
: {}
);
await scheduleCollectionJob(testPlanReport);
await closeWithUpdate();
} catch (e) {
console.error(e);
}
}
});
}
Expand Down
2 changes: 2 additions & 0 deletions client/components/AddTestToQueueWithConfirmation/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const EXISTING_TEST_PLAN_REPORTS = gql`
id
}
}
metadata
}
oldTestPlanVersions: testPlanVersions(
phases: [CANDIDATE, RECOMMENDED]
Expand All @@ -46,6 +47,7 @@ export const EXISTING_TEST_PLAN_REPORTS = gql`
id
}
}
metadata
}
}
`;
115 changes: 86 additions & 29 deletions client/components/BotRunTestStatusList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useQuery } from '@apollo/client';
import styled from '@emotion/styled';
import ReportStatusDot from '../common/ReportStatusDot';

// TODO: Remove when Test Queue v1 is removed
const BotRunTestStatusUnorderedList = styled.ul`
list-style-type: none;
background-color: #f6f8fa;
Expand All @@ -14,6 +15,21 @@ const BotRunTestStatusUnorderedList = styled.ul`
white-space: nowrap;
`;

const BotRunTestContainer = styled.div`
font-size: 0.875rem !important;
padding: 0.5rem 0;
margin: 0.5rem 0;
background: #f5f5f5;
border-radius: 0.25rem;
white-space: nowrap;
`;

const BotRunTestStatusUnorderedListV2 = styled.ul`
list-style-type: none;
`;

/**
* Generate a string describing the status of some number of "Tests" where the
* word "Test" is pluralized appropriately and qualified with the provided
Expand All @@ -33,7 +49,10 @@ const testCountString = (count, status) =>

const pollInterval = 2000;

const BotRunTestStatusList = ({ testPlanReportId }) => {
const BotRunTestStatusList = ({
testPlanReportId,
fromTestQueueV2 = false // TODO: Remove when Test Queue v1 is removed
}) => {
const {
data: testPlanRunsQueryResult,
startPolling,
Expand Down Expand Up @@ -84,40 +103,78 @@ const BotRunTestStatusList = ({ testPlanReportId }) => {
) {
return null;
}

return (
<BotRunTestStatusUnorderedList className="text-secondary fs-6">
{RUNNING > 0 && (
<li className="m-2">
<ReportStatusDot className="tests-running" />
{testCountString(RUNNING, 'Running')}
</li>
)}
{ERROR > 0 && (
<li className="m-2">
<ReportStatusDot className="tests-error" />
{testCountString(ERROR, 'Error')}
</li>
)}
<li className="m-2">
<ReportStatusDot className="tests-complete" />
{testCountString(COMPLETED, 'Completed')}
</li>
<li className="m-2">
<ReportStatusDot className="tests-queued" />
{testCountString(QUEUED, 'Queued')}
</li>
{CANCELLED > 0 && (
<li className="m-2">
<ReportStatusDot className="tests-cancelled" />
{testCountString(CANCELLED, 'Cancelled')}
</li>
<>
{fromTestQueueV2 ? (
<BotRunTestContainer>
Bot Status:
<BotRunTestStatusUnorderedListV2 className="text-secondary">
{RUNNING > 0 && (
<li>
<ReportStatusDot className="tests-running" />
{testCountString(RUNNING, 'Running')}
</li>
)}
{ERROR > 0 && (
<li>
<ReportStatusDot className="tests-error" />
{testCountString(ERROR, 'Error')}
</li>
)}
<li>
<ReportStatusDot className="tests-complete" />
{testCountString(COMPLETED, 'Completed')}
</li>
<li>
<ReportStatusDot className="tests-queued" />
{testCountString(QUEUED, 'Queued')}
</li>
{CANCELLED > 0 && (
<li>
<ReportStatusDot className="tests-cancelled" />
{testCountString(CANCELLED, 'Cancelled')}
</li>
)}
</BotRunTestStatusUnorderedListV2>
</BotRunTestContainer>
) : (
<BotRunTestStatusUnorderedList className="text-secondary fs-6">
{RUNNING > 0 && (
<li className="m-2">
<ReportStatusDot className="tests-running" />
{testCountString(RUNNING, 'Running')}
</li>
)}
{ERROR > 0 && (
<li className="m-2">
<ReportStatusDot className="tests-error" />
{testCountString(ERROR, 'Error')}
</li>
)}
<li className="m-2">
<ReportStatusDot className="tests-complete" />
{testCountString(COMPLETED, 'Completed')}
</li>
<li className="m-2">
<ReportStatusDot className="tests-queued" />
{testCountString(QUEUED, 'Queued')}
</li>
{CANCELLED > 0 && (
<li className="m-2">
<ReportStatusDot className="tests-cancelled" />
{testCountString(CANCELLED, 'Cancelled')}
</li>
)}
</BotRunTestStatusUnorderedList>
)}
</BotRunTestStatusUnorderedList>
</>
);
};

BotRunTestStatusList.propTypes = {
testPlanReportId: PropTypes.string.isRequired
testPlanReportId: PropTypes.string.isRequired,
fromTestQueueV2: PropTypes.bool
};

export default BotRunTestStatusList;
1 change: 1 addition & 0 deletions client/components/GraphQLProvider/GraphQLProvider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const client = new ApolloClient({
typePolicies: {
Query: {
fields: {
me: { merge: true },
testPlanVersion: { merge: true },
testPlanVersions: { merge: false },
testPlanReport: { merge: true },
Expand Down
33 changes: 20 additions & 13 deletions client/components/ManageBotRunDialog/WithButton.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { Button } from 'react-bootstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faRobot } from '@fortawesome/free-solid-svg-icons';
import ManageBotRunDialog from '.';
import { useTestPlanRunIsFinished } from '../../hooks/useTestPlanRunIsFinished';

Expand All @@ -9,6 +11,7 @@ const ManageBotRunDialogWithButton = ({
testPlanReportId,
runnableTestsLength,
testers,
includeIcon = false,
onChange
}) => {
const { runIsFinished } = useTestPlanRunIsFinished(testPlanRun.id);
Expand All @@ -24,22 +27,25 @@ const ManageBotRunDialogWithButton = ({
onClick={async () => {
setShowDialog(true);
}}
className="mb-2"
>
{/* TODO: Include by default after removing Test Queue v1 content */}
{includeIcon ? <FontAwesomeIcon icon={faRobot} /> : null}
Manage {testPlanRun?.tester?.username} Run
</Button>
<ManageBotRunDialog
testPlanRun={testPlanRun}
show={showDialog}
setShow={setShowDialog}
testers={testers}
testPlanReportId={testPlanReportId}
runnableTestsLength={runnableTestsLength}
onChange={async () => {
await onChange();
setShowDialog(false);
}}
/>
{showDialog ? (
<ManageBotRunDialog
testPlanRun={testPlanRun}
show={showDialog}
setShow={setShowDialog}
testers={testers}
testPlanReportId={testPlanReportId}
runnableTestsLength={runnableTestsLength}
onChange={async () => {
await onChange();
setShowDialog(false);
}}
/>
) : null}
</>
);
};
Expand All @@ -49,6 +55,7 @@ ManageBotRunDialogWithButton.propTypes = {
testPlanReportId: PropTypes.string.isRequired,
runnableTestsLength: PropTypes.number.isRequired,
testers: PropTypes.array.isRequired,
includeIcon: PropTypes.bool,
onChange: PropTypes.func.isRequired
};

Expand Down
Loading

0 comments on commit 0f42b1d

Please sign in to comment.