include RunCases on testCase property
This commit is contained in:
@@ -63,11 +63,13 @@ app.use('/folders', foldersDeleteRoute);
|
|||||||
|
|
||||||
// "/cases"
|
// "/cases"
|
||||||
const casesIndexRoute = require('./routes/cases/index')(sequelize);
|
const casesIndexRoute = require('./routes/cases/index')(sequelize);
|
||||||
|
const casesIndexByProjectIdRoute = require('./routes/cases/indexByProjectId')(sequelize);
|
||||||
const casesShowRoute = require('./routes/cases/show')(sequelize);
|
const casesShowRoute = require('./routes/cases/show')(sequelize);
|
||||||
const casesNewRoute = require('./routes/cases/new')(sequelize);
|
const casesNewRoute = require('./routes/cases/new')(sequelize);
|
||||||
const casesEditRoute = require('./routes/cases/edit')(sequelize);
|
const casesEditRoute = require('./routes/cases/edit')(sequelize);
|
||||||
const casesDeleteRoute = require('./routes/cases/delete')(sequelize);
|
const casesDeleteRoute = require('./routes/cases/delete')(sequelize);
|
||||||
app.use('/cases', casesIndexRoute);
|
app.use('/cases', casesIndexRoute);
|
||||||
|
app.use('/cases', casesIndexByProjectIdRoute);
|
||||||
app.use('/cases', casesShowRoute);
|
app.use('/cases', casesShowRoute);
|
||||||
app.use('/cases', casesNewRoute);
|
app.use('/cases', casesNewRoute);
|
||||||
app.use('/cases', casesEditRoute);
|
app.use('/cases', casesEditRoute);
|
||||||
|
|||||||
54
backend/routes/cases/indexByProjectId.js
Normal file
54
backend/routes/cases/indexByProjectId.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const defineProject = require('../../models/projects');
|
||||||
|
const defineFolder = require('../../models/folders');
|
||||||
|
const defineCase = require('../../models/cases');
|
||||||
|
const defineRunCase = require('../../models/runCases');
|
||||||
|
const { DataTypes } = require('sequelize');
|
||||||
|
|
||||||
|
module.exports = function (sequelize) {
|
||||||
|
const Project = defineProject(sequelize, DataTypes);
|
||||||
|
const Folder = defineFolder(sequelize, DataTypes);
|
||||||
|
const Case = defineCase(sequelize, DataTypes);
|
||||||
|
const RunCase = defineRunCase(sequelize, DataTypes);
|
||||||
|
Project.hasMany(Folder, { foreignKey: 'projectId' });
|
||||||
|
Folder.hasMany(Case, { foreignKey: 'folderId' });
|
||||||
|
Folder.belongsTo(Project, { foreignKey: 'projectId' });
|
||||||
|
Case.belongsTo(Folder, { foreignKey: 'folderId' });
|
||||||
|
Case.hasMany(RunCase, { foreignKey: 'caseId' });
|
||||||
|
RunCase.belongsTo(Case, { foreignKey: 'caseId' });
|
||||||
|
const { verifySignedIn } = require('../../middleware/auth')(sequelize);
|
||||||
|
const { verifyProjectVisibleFromProjectId } = require('../../middleware/verifyVisible')(sequelize);
|
||||||
|
|
||||||
|
router.get('/byproject', verifySignedIn, verifyProjectVisibleFromProjectId, async (req, res) => {
|
||||||
|
const { projectId } = req.query;
|
||||||
|
|
||||||
|
if (!projectId) {
|
||||||
|
return res.status(400).json({ error: 'projectId is required' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const cases = await Case.findAll({
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Folder,
|
||||||
|
where: {
|
||||||
|
projectId: projectId,
|
||||||
|
},
|
||||||
|
attributes: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: RunCase,
|
||||||
|
attributes: ['runId', 'status'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
res.json(cases);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
res.status(500).send('Internal Server Error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return router;
|
||||||
|
};
|
||||||
@@ -4,7 +4,7 @@ const apiServer = Config.apiServer;
|
|||||||
/**
|
/**
|
||||||
* fetch folder records
|
* fetch folder records
|
||||||
*/
|
*/
|
||||||
async function fetchFolders(jwt: string, projectId: string) {
|
async function fetchFolders(jwt: string, projectId: number) {
|
||||||
try {
|
try {
|
||||||
const url = `${apiServer}/folders?projectId=${projectId}`;
|
const url = `${apiServer}/folders?projectId=${projectId}`;
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
|
|||||||
@@ -22,12 +22,18 @@ import { Save, ArrowLeft, Folder, ChevronDown, CopyPlus, CopyMinus, RotateCw } f
|
|||||||
import RunProgressChart from './RunPregressDonutChart';
|
import RunProgressChart from './RunPregressDonutChart';
|
||||||
import TestCaseSelector from './TestCaseSelector';
|
import TestCaseSelector from './TestCaseSelector';
|
||||||
import { testRunStatus } from '@/config/selection';
|
import { testRunStatus } from '@/config/selection';
|
||||||
import { RunType, RunCaseType, RunStatusCountType, RunMessages } from '@/types/run';
|
import { RunType, RunStatusCountType, RunMessages } from '@/types/run';
|
||||||
import { CaseType } from '@/types/case';
|
import { CaseType } from '@/types/case';
|
||||||
import { FolderType } from '@/types/folder';
|
import { FolderType } from '@/types/folder';
|
||||||
import { fetchRun, updateRun, fetchRunCases, updateRunCases, processRunCases } from '../runsControl';
|
import {
|
||||||
|
fetchRun,
|
||||||
|
updateRun,
|
||||||
|
updateRunCases,
|
||||||
|
processRunCases,
|
||||||
|
fetchProjectCases,
|
||||||
|
processTestCases,
|
||||||
|
} from '../runsControl';
|
||||||
import { fetchFolders } from '../../folders/foldersControl';
|
import { fetchFolders } from '../../folders/foldersControl';
|
||||||
import { fetchCases } from '@/utils/caseControl';
|
|
||||||
import { TokenContext } from '@/utils/TokenProvider';
|
import { TokenContext } from '@/utils/TokenProvider';
|
||||||
import { useTheme } from 'next-themes';
|
import { useTheme } from 'next-themes';
|
||||||
import { useFormGuard } from '@/utils/formGuard';
|
import { useFormGuard } from '@/utils/formGuard';
|
||||||
@@ -55,11 +61,11 @@ export default function RunEditor({ projectId, runId, messages, locale }: Props)
|
|||||||
const { theme, setTheme } = useTheme();
|
const { theme, setTheme } = useTheme();
|
||||||
const [testRun, setTestRun] = useState<RunType>(defaultTestRun);
|
const [testRun, setTestRun] = useState<RunType>(defaultTestRun);
|
||||||
const [folders, setFolders] = useState<FolderType[]>([]);
|
const [folders, setFolders] = useState<FolderType[]>([]);
|
||||||
const [runCases, setRunCases] = useState<RunCaseType[]>([]);
|
|
||||||
const [runStatusCounts, setRunStatusCounts] = useState<RunStatusCountType[]>();
|
const [runStatusCounts, setRunStatusCounts] = useState<RunStatusCountType[]>();
|
||||||
const [selectedKeys, setSelectedKeys] = useState<Selection>(new Set([]));
|
const [selectedKeys, setSelectedKeys] = useState<Selection>(new Set([]));
|
||||||
const [selectedFolder, setSelectedFolder] = useState<FolderType | null>(null);
|
const [selectedFolder, setSelectedFolder] = useState<FolderType | null>(null);
|
||||||
const [testcases, setTestCases] = useState<CaseType[]>([]);
|
const [testCases, setTestCases] = useState<CaseType[]>([]);
|
||||||
|
const [filteredTestCases, setFilteredTestCases] = useState<CaseType[]>([]);
|
||||||
const [isNameInvalid, setIsNameInvalid] = useState<boolean>(false);
|
const [isNameInvalid, setIsNameInvalid] = useState<boolean>(false);
|
||||||
const [isUpdating, setIsUpdating] = useState<boolean>(false);
|
const [isUpdating, setIsUpdating] = useState<boolean>(false);
|
||||||
const [isDirty, setIsDirty] = useState(false);
|
const [isDirty, setIsDirty] = useState(false);
|
||||||
@@ -80,9 +86,17 @@ export default function RunEditor({ projectId, runId, messages, locale }: Props)
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await fetchRunAndStatusCount();
|
await fetchRunAndStatusCount();
|
||||||
const foldersData = await fetchFolders(context.token.access_token, projectId);
|
const foldersData = await fetchFolders(context.token.access_token, Number(projectId));
|
||||||
setFolders(foldersData);
|
setFolders(foldersData);
|
||||||
setSelectedFolder(foldersData[0]);
|
setSelectedFolder(foldersData[0]);
|
||||||
|
|
||||||
|
const casesData = await fetchProjectCases(context.token.access_token, Number(projectId));
|
||||||
|
casesData.forEach((testCase: CaseType) => {
|
||||||
|
if (testCase.RunCases && testCase.RunCases.length > 0) {
|
||||||
|
testCase.RunCases[0].editState = 'notChanged';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setTestCases(casesData);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('Error in effect:', error.message);
|
console.error('Error in effect:', error.message);
|
||||||
}
|
}
|
||||||
@@ -92,39 +106,19 @@ export default function RunEditor({ projectId, runId, messages, locale }: Props)
|
|||||||
}, [context]);
|
}, [context]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchCasesData() {
|
function onFilter() {
|
||||||
if (selectedFolder && selectedFolder.id) {
|
if (selectedFolder && selectedFolder.id) {
|
||||||
try {
|
try {
|
||||||
const latestRunCases: RunCaseType[] = await fetchRunCases(context.token.access_token, Number(runId));
|
const filteredData = testCases.filter((testCase) => testCase.folderId === selectedFolder.id);
|
||||||
latestRunCases.forEach((runCase: RunCaseType) => {
|
setFilteredTestCases(filteredData);
|
||||||
runCase.editState = 'notChanged';
|
|
||||||
});
|
|
||||||
setRunCases(latestRunCases);
|
|
||||||
|
|
||||||
const testCasesData: CaseType[] = await fetchCases(context.token.access_token, selectedFolder.id);
|
|
||||||
// Check if each testCase has an association with testRun
|
|
||||||
// and add "isIncluded" property
|
|
||||||
const updatedTestCasesData = testCasesData.map((testCase) => {
|
|
||||||
const runCase = latestRunCases.find((runCase) => runCase.caseId === testCase.id);
|
|
||||||
|
|
||||||
const isIncluded = runCase ? true : false;
|
|
||||||
const runStatus = runCase ? runCase.status : 0;
|
|
||||||
return {
|
|
||||||
...testCase,
|
|
||||||
isIncluded,
|
|
||||||
runStatus,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
setTestCases(updatedTestCasesData);
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('Error fetching cases data:', error.message);
|
console.error('Error fetching cases data:', error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchCasesData();
|
onFilter();
|
||||||
}, [selectedFolder]);
|
}, [selectedFolder, testCases]);
|
||||||
|
|
||||||
const handleChangeStatus = async (changeCaseId: number, status: number) => {
|
const handleChangeStatus = async (changeCaseId: number, status: number) => {
|
||||||
setIsDirty(true);
|
setIsDirty(true);
|
||||||
@@ -141,38 +135,21 @@ export default function RunEditor({ projectId, runId, messages, locale }: Props)
|
|||||||
const handleIncludeExcludeCase = async (isInclude: boolean, clickedTestCaseId: number) => {
|
const handleIncludeExcludeCase = async (isInclude: boolean, clickedTestCaseId: number) => {
|
||||||
setIsDirty(true);
|
setIsDirty(true);
|
||||||
const keys = [clickedTestCaseId];
|
const keys = [clickedTestCaseId];
|
||||||
const newRunCases = processRunCases(isInclude, keys, Number(runId), runCases);
|
const newTestCases = processTestCases(isInclude, keys, Number(runId), testCases);
|
||||||
setRunCases(newRunCases);
|
setTestCases(newTestCases);
|
||||||
|
|
||||||
const updatedTestCases = testcases.map((testcase) => {
|
|
||||||
if (testcase.id === clickedTestCaseId) {
|
|
||||||
return { ...testcase, isIncluded: isInclude };
|
|
||||||
}
|
|
||||||
return testcase;
|
|
||||||
});
|
|
||||||
setTestCases(updatedTestCases);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBulkIncludeExcludeCases = async (isInclude: boolean) => {
|
const handleBulkIncludeExcludeCases = async (isInclude: boolean) => {
|
||||||
setIsDirty(true);
|
setIsDirty(true);
|
||||||
let keys: number[] = [];
|
let keys: number[] = [];
|
||||||
if (selectedKeys === 'all') {
|
if (selectedKeys === 'all') {
|
||||||
keys = testcases.map((item) => item.id);
|
keys = testCases.map((item) => item.id);
|
||||||
} else {
|
} else {
|
||||||
keys = Array.from(selectedKeys).map(Number);
|
keys = Array.from(selectedKeys).map(Number);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newRunCases = processRunCases(isInclude, keys, Number(runId), runCases);
|
const newTestCases = processTestCases(isInclude, keys, Number(runId), testCases);
|
||||||
setRunCases(newRunCases);
|
setTestCases(newTestCases);
|
||||||
|
|
||||||
const updatedTestCases = testcases.map((testcase) => {
|
|
||||||
if (keys.includes(testcase.id)) {
|
|
||||||
return { ...testcase, isIncluded: isInclude };
|
|
||||||
}
|
|
||||||
return testcase;
|
|
||||||
});
|
|
||||||
setTestCases(updatedTestCases);
|
|
||||||
|
|
||||||
setSelectedKeys(new Set([]));
|
setSelectedKeys(new Set([]));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -204,7 +181,7 @@ export default function RunEditor({ projectId, runId, messages, locale }: Props)
|
|||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
setIsUpdating(true);
|
setIsUpdating(true);
|
||||||
await updateRun(context.token.access_token, testRun);
|
await updateRun(context.token.access_token, testRun);
|
||||||
await updateRunCases(context.token.access_token, Number(runId), runCases);
|
await updateRunCases(context.token.access_token, Number(runId), testCases);
|
||||||
setIsUpdating(false);
|
setIsUpdating(false);
|
||||||
setIsDirty(false);
|
setIsDirty(false);
|
||||||
}}
|
}}
|
||||||
@@ -335,7 +312,7 @@ export default function RunEditor({ projectId, runId, messages, locale }: Props)
|
|||||||
</div>
|
</div>
|
||||||
<div className="w-9/12">
|
<div className="w-9/12">
|
||||||
<TestCaseSelector
|
<TestCaseSelector
|
||||||
cases={testcases}
|
cases={filteredTestCases}
|
||||||
isDisabled={!context.isProjectReporter(Number(projectId))}
|
isDisabled={!context.isProjectReporter(Number(projectId))}
|
||||||
selectedKeys={selectedKeys}
|
selectedKeys={selectedKeys}
|
||||||
onSelectionChange={setSelectedKeys}
|
onSelectionChange={setSelectedKeys}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import {
|
|||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { priorities, testRunCaseStatus } from '@/config/selection';
|
import { priorities, testRunCaseStatus } from '@/config/selection';
|
||||||
import { CaseType } from '@/types/case';
|
import { CaseType } from '@/types/case';
|
||||||
import { RunsMessages } from '@/types/run';
|
import { RunMessages } from '@/types/run';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
cases: CaseType[];
|
cases: CaseType[];
|
||||||
@@ -37,7 +37,7 @@ type Props = {
|
|||||||
onStatusChange: (changeCaseId: number, status: number) => {};
|
onStatusChange: (changeCaseId: number, status: number) => {};
|
||||||
onIncludeCase: (includeCaseId: number) => {};
|
onIncludeCase: (includeCaseId: number) => {};
|
||||||
onExcludeCase: (excludeCaseId: number) => {};
|
onExcludeCase: (excludeCaseId: number) => {};
|
||||||
messages: RunsMessages;
|
messages: RunMessages;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function TestCaseSelector({
|
export default function TestCaseSelector({
|
||||||
@@ -106,9 +106,22 @@ export default function TestCaseSelector({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isCaseIncluded = (testCase: CaseType) => {
|
||||||
|
let isIncluded = false;
|
||||||
|
if (testCase.RunCases && testCase.RunCases.length > 0) {
|
||||||
|
if (testCase.RunCases[0].editState !== 'deleted') {
|
||||||
|
// Even if RunCase[0] exists, if 'deleted' it will be as not included.
|
||||||
|
isIncluded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isIncluded;
|
||||||
|
};
|
||||||
|
|
||||||
const renderCell = (testCase: CaseType, columnKey: Key) => {
|
const renderCell = (testCase: CaseType, columnKey: Key) => {
|
||||||
const cellValue = testCase[columnKey as keyof CaseType];
|
const cellValue = testCase[columnKey as keyof CaseType];
|
||||||
const isIncluded = testCase.isIncluded;
|
const isIncluded = isCaseIncluded(testCase);
|
||||||
|
const runStatus = testCase.RunCases && testCase.RunCases.length > 0 ? testCase.RunCases[0].status : 0;
|
||||||
|
|
||||||
switch (columnKey) {
|
switch (columnKey) {
|
||||||
case 'priority':
|
case 'priority':
|
||||||
@@ -130,10 +143,10 @@ export default function TestCaseSelector({
|
|||||||
size="sm"
|
size="sm"
|
||||||
variant="light"
|
variant="light"
|
||||||
isDisabled={!isIncluded}
|
isDisabled={!isIncluded}
|
||||||
startContent={isIncluded && renderStatusIcon(testRunCaseStatus[cellValue].uid)}
|
startContent={isIncluded && renderStatusIcon(testRunCaseStatus[runStatus].uid)}
|
||||||
endContent={isIncluded && <ChevronDown size={16} />}
|
endContent={isIncluded && <ChevronDown size={16} />}
|
||||||
>
|
>
|
||||||
<span className="w-12">{isIncluded && messages[testRunCaseStatus[cellValue].uid]}</span>
|
<span className="w-12">{isIncluded && messages[testRunCaseStatus[runStatus].uid]}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownTrigger>
|
</DropdownTrigger>
|
||||||
<DropdownMenu disabledKeys={disabledStatusKeys} aria-label="test case actions">
|
<DropdownMenu disabledKeys={disabledStatusKeys} aria-label="test case actions">
|
||||||
@@ -143,7 +156,7 @@ export default function TestCaseSelector({
|
|||||||
startContent={renderStatusIcon(runCaseStatus.uid)}
|
startContent={renderStatusIcon(runCaseStatus.uid)}
|
||||||
onPress={() => onStatusChange(testCase.id, index)}
|
onPress={() => onStatusChange(testCase.id, index)}
|
||||||
>
|
>
|
||||||
{messages[runCaseStatus.uid]}
|
{messages[runStatus.uid]}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
))}
|
))}
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
@@ -162,7 +175,7 @@ export default function TestCaseSelector({
|
|||||||
key="include"
|
key="include"
|
||||||
startContent={<CopyPlus size={16} />}
|
startContent={<CopyPlus size={16} />}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (testCase.isIncluded) {
|
if (isIncluded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onIncludeCase(testCase.id);
|
onIncludeCase(testCase.id);
|
||||||
@@ -174,7 +187,7 @@ export default function TestCaseSelector({
|
|||||||
key="exclude"
|
key="exclude"
|
||||||
startContent={<CopyMinus size={16} />}
|
startContent={<CopyMinus size={16} />}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (!testCase.isIncluded) {
|
if (!isIncluded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onExcludeCase(testCase.id);
|
onExcludeCase(testCase.id);
|
||||||
@@ -239,8 +252,8 @@ export default function TestCaseSelector({
|
|||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody emptyContent={messages.noCasesFound} items={sortedItems}>
|
<TableBody emptyContent={messages.noCasesFound} items={sortedItems}>
|
||||||
{(item) => (
|
{(item) => (
|
||||||
<TableRow key={item.id} className={!item.isIncluded ? notIncludedCaseClass : ''}>
|
<TableRow key={item.id} className={isCaseIncluded(item) ? '' : notIncludedCaseClass}>
|
||||||
{(columnKey) => <TableCell>{renderCell(item, columnKey)}</TableCell>}
|
{(columnKey) => <TableCell key={`${item.id} + ${columnKey}`}>{renderCell(item, columnKey)}</TableCell>}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import { CaseType } from '@/types/case';
|
||||||
|
import { RunType, RunCaseType } from '@/types/run';
|
||||||
import Config from '@/config/config';
|
import Config from '@/config/config';
|
||||||
const apiServer = Config.apiServer;
|
const apiServer = Config.apiServer;
|
||||||
import { RunType, RunCaseType } from '@/types/run';
|
|
||||||
|
|
||||||
async function fetchRun(jwt: string, runId: number) {
|
async function fetchRun(jwt: string, runId: number) {
|
||||||
const url = `${apiServer}/runs/${runId}`;
|
const url = `${apiServer}/runs/${runId}`;
|
||||||
@@ -150,61 +151,134 @@ async function fetchRunCases(jwt: string, runId: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function processRunCases(
|
function processTestCases(isInclude: boolean, keys: number[], runId: number, currentTestCases: CaseType[]): CaseType[] {
|
||||||
isInclude: boolean,
|
const updatedTestCases = [...currentTestCases];
|
||||||
keys: number[],
|
|
||||||
runId: number,
|
|
||||||
currentRunCases: RunCaseType[]
|
|
||||||
): RunCaseType[] {
|
|
||||||
const updatedRunCases = [...currentRunCases];
|
|
||||||
|
|
||||||
if (isInclude) {
|
if (isInclude) {
|
||||||
keys.forEach((caseId) => {
|
keys.forEach((caseId) => {
|
||||||
const existingRunCase = currentRunCases.find((runCase) => runCase.caseId === caseId);
|
const targetCase = updatedTestCases.find((testCase) => testCase.id === caseId);
|
||||||
if (existingRunCase) {
|
if (!targetCase) {
|
||||||
|
console.error('failed to find target case');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetCase.RunCases && targetCase.RunCases.length > 0) {
|
||||||
// already included
|
// already included
|
||||||
if (existingRunCase.editState === 'notChanged') {
|
if (targetCase.RunCases[0].editState === 'notChanged') {
|
||||||
// do nothing
|
// do nothing
|
||||||
} else if (existingRunCase.editState === 'changed') {
|
} else if (targetCase.RunCases[0].editState === 'changed') {
|
||||||
// do nothing
|
// do nothing
|
||||||
} else if (existingRunCase.editState === 'new') {
|
} else if (targetCase.RunCases[0].editState === 'new') {
|
||||||
// do nothing
|
// do nothing
|
||||||
} else if (existingRunCase.editState === 'deleted') {
|
} else if (targetCase.RunCases[0].editState === 'deleted') {
|
||||||
existingRunCase.editState = 'changed';
|
targetCase.RunCases[0].editState = 'changed';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
updatedRunCases.push({
|
const newRunCase = {
|
||||||
id: -1,
|
|
||||||
runId: runId,
|
runId: runId,
|
||||||
caseId: caseId,
|
status: 0,
|
||||||
status: -1,
|
|
||||||
editState: 'new',
|
editState: 'new',
|
||||||
});
|
} as RunCaseType;
|
||||||
|
targetCase.RunCases = [newRunCase];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
keys.forEach((caseId) => {
|
keys.forEach((caseId) => {
|
||||||
const existingRunCase = currentRunCases.find((runCase) => runCase.caseId === caseId);
|
const targetCase = updatedTestCases.find((testCase) => testCase.id === caseId);
|
||||||
if (!existingRunCase) {
|
if (!targetCase) {
|
||||||
|
console.error('failed to find target case');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!targetCase.RunCases || targetCase.RunCases.length == 0) {
|
||||||
// already excluded
|
// already excluded
|
||||||
} else {
|
} else {
|
||||||
if (existingRunCase.editState === 'notChanged') {
|
if (targetCase.RunCases[0].editState === 'notChanged') {
|
||||||
existingRunCase.editState = 'deleted';
|
targetCase.RunCases[0].editState = 'deleted';
|
||||||
} else if (existingRunCase.editState === 'changed') {
|
} else if (targetCase.RunCases[0].editState === 'changed') {
|
||||||
existingRunCase.editState = 'deleted';
|
targetCase.RunCases[0].editState = 'deleted';
|
||||||
} else if (existingRunCase.editState === 'new') {
|
} else if (targetCase.RunCases[0].editState === 'new') {
|
||||||
existingRunCase.editState = 'deleted';
|
targetCase.RunCases[0].editState = 'deleted';
|
||||||
} else if (existingRunCase.editState === 'deleted') {
|
} else if (targetCase.RunCases[0].editState === 'deleted') {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return updatedRunCases;
|
return updatedTestCases;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateRunCases(jwt: string, runId: number, runCases: RunCaseType[]) {
|
// function processRunCases(
|
||||||
|
// isInclude: boolean,
|
||||||
|
// keys: number[],
|
||||||
|
// runId: number,
|
||||||
|
// currentRunCases: RunCaseType[]
|
||||||
|
// ): RunCaseType[] {
|
||||||
|
// const updatedRunCases = [...currentRunCases];
|
||||||
|
|
||||||
|
// if (isInclude) {
|
||||||
|
// keys.forEach((caseId) => {
|
||||||
|
// const existingRunCase = currentRunCases.find((runCase) => runCase.caseId === caseId);
|
||||||
|
// if (existingRunCase) {
|
||||||
|
// // already included
|
||||||
|
// if (existingRunCase.editState === 'notChanged') {
|
||||||
|
// // do nothing
|
||||||
|
// } else if (existingRunCase.editState === 'changed') {
|
||||||
|
// // do nothing
|
||||||
|
// } else if (existingRunCase.editState === 'new') {
|
||||||
|
// // do nothing
|
||||||
|
// } else if (existingRunCase.editState === 'deleted') {
|
||||||
|
// existingRunCase.editState = 'changed';
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// updatedRunCases.push({
|
||||||
|
// id: -1,
|
||||||
|
// runId: runId,
|
||||||
|
// caseId: caseId,
|
||||||
|
// status: 0,
|
||||||
|
// editState: 'new',
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// keys.forEach((caseId) => {
|
||||||
|
// const existingRunCase = currentRunCases.find((runCase) => runCase.caseId === caseId);
|
||||||
|
// if (!existingRunCase) {
|
||||||
|
// // already excluded
|
||||||
|
// } else {
|
||||||
|
// if (existingRunCase.editState === 'notChanged') {
|
||||||
|
// existingRunCase.editState = 'deleted';
|
||||||
|
// } else if (existingRunCase.editState === 'changed') {
|
||||||
|
// existingRunCase.editState = 'deleted';
|
||||||
|
// } else if (existingRunCase.editState === 'new') {
|
||||||
|
// existingRunCase.editState = 'deleted';
|
||||||
|
// } else if (existingRunCase.editState === 'deleted') {
|
||||||
|
// // do nothing
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return updatedRunCases;
|
||||||
|
// }
|
||||||
|
|
||||||
|
async function updateRunCases(jwt: string, runId: number, testCases: CaseType[]) {
|
||||||
|
const runCases: RunCaseType[] = [];
|
||||||
|
testCases.forEach((itr) => {
|
||||||
|
if (itr.RunCases && itr.RunCases.length > 0) {
|
||||||
|
runCases.push({
|
||||||
|
id: -1,
|
||||||
|
caseId: itr.id,
|
||||||
|
runId: runId,
|
||||||
|
status: itr.RunCases[0].status,
|
||||||
|
editState: itr.RunCases[0].editState,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(testCases, runCases);
|
||||||
|
|
||||||
const fetchOptions = {
|
const fetchOptions = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@@ -227,4 +301,37 @@ async function updateRunCases(jwt: string, runId: number, runCases: RunCaseType[
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { fetchRun, fetchRuns, createRun, updateRun, deleteRun, fetchRunCases, processRunCases, updateRunCases };
|
async function fetchProjectCases(jwt: string, projectId: number) {
|
||||||
|
const url = `${apiServer}/cases/byproject?projectId=${projectId}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${jwt}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
return data;
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Error fetching data:', error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
fetchRun,
|
||||||
|
fetchRuns,
|
||||||
|
createRun,
|
||||||
|
updateRun,
|
||||||
|
deleteRun,
|
||||||
|
fetchRunCases,
|
||||||
|
processTestCases,
|
||||||
|
updateRunCases,
|
||||||
|
fetchProjectCases,
|
||||||
|
};
|
||||||
|
|||||||
@@ -11,9 +11,8 @@ type CaseType = {
|
|||||||
expectedResults: string;
|
expectedResults: string;
|
||||||
folderId: number;
|
folderId: number;
|
||||||
Steps?: StepType[];
|
Steps?: StepType[];
|
||||||
|
RunCases?: RunCaseType[];
|
||||||
Attachments?: AttachmentType[];
|
Attachments?: AttachmentType[];
|
||||||
isIncluded?: boolean;
|
|
||||||
runStatus?: number;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type CaseStepType = {
|
type CaseStepType = {
|
||||||
@@ -35,6 +34,12 @@ type StepType = {
|
|||||||
editState: 'notChanged' | 'changed' | 'new' | 'deleted';
|
editState: 'notChanged' | 'changed' | 'new' | 'deleted';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type RunCaseType = {
|
||||||
|
runId: number;
|
||||||
|
status: number;
|
||||||
|
editState: 'notChanged' | 'changed' | 'new' | 'deleted';
|
||||||
|
};
|
||||||
|
|
||||||
type CaseAttachmentType = {
|
type CaseAttachmentType = {
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
|
|||||||
Reference in New Issue
Block a user