Skip to content

Commit 5fd21bb

Browse files
authored
Merge pull request #4 from WebFuzzing/ci-fix
fault counts fix
2 parents 64776a6 + bc1d933 commit 5fd21bb

14 files changed

Lines changed: 445 additions & 319 deletions

web-report/src-e2e/App.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ describe('App test', () => {
140140

141141
await waitFor(() => {
142142
expect(screen.getByTestId('faults-component-total-faults')).toContainHTML(`${total_faults}`);
143-
expect(screen.getByTestId('faults-component-fault-counts')).toContainHTML(faultCounts.size.toString());
143+
expect(screen.getByTestId('faults-component-fault-counts')).toContainHTML(faultCounts.length.toString());
144144
});
145145
});
146146
});

web-report/src/App.tsx

Lines changed: 6 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,12 @@
11
import './App.css'
2-
import {Dashboard} from "@/components/Dashboard.tsx";
3-
import {useEffect, useState} from "react";
4-
import {WebFuzzingReport} from "@/types/GeneratedTypes.tsx";
5-
import {LoadingScreen} from "@/components/LoadingScreen.tsx";
6-
import {fetchFileContent} from "@/lib/utils";
7-
import {ITestFiles} from "@/types/General.tsx";
2+
import {AppProvider} from "@/AppProvider.tsx";
3+
import {AppContent} from "@/AppContent.tsx";
84

95
function App() {
10-
11-
const [data, setData] = useState<WebFuzzingReport | null>(null);
12-
const [loading, setLoading] = useState(true);
13-
const [error, setError] = useState<string | null>(null);
14-
const [testFiles, setTestFiles] = useState<ITestFiles[]>([]);
15-
16-
useEffect(() => {
17-
const fetchData = async () => {
18-
try {
19-
const jsonData = await fetchFileContent('./report.json') as WebFuzzingReport;
20-
setData(jsonData);
21-
} catch (error: Error | unknown) {
22-
if (error instanceof Error) {
23-
setError("Could not load the report file. Please check if the file exists and is accessible in /public folder.");
24-
} else {
25-
console.error(error);
26-
}
27-
} finally {
28-
setLoading(false);
29-
}
30-
};
31-
32-
fetchData();
33-
}, []);
34-
35-
useEffect(() => {
36-
if(data?.test_file_paths){
37-
data.test_file_paths.map(file => {
38-
fetchFileContent(file).then((content) => {
39-
if (typeof content === "string") {
40-
setTestFiles(prev => [...prev, {
41-
name: file,
42-
code: content
43-
}]);
44-
} else {
45-
setError("Could not load the test file. Please check if the file exists and is accessible.");
46-
}
47-
}).catch((error) => {
48-
console.error(error);
49-
setError("Could not load the test file. Please check if the file exists and is accessible.");
50-
})
51-
})
52-
}
53-
}, [data]);
54-
55-
if (error){
56-
return (
57-
<main className="min-h-screen p-4 bg-gray-100">
58-
<div className="flex items-center justify-center min-h-screen">
59-
<div className="bg-white p-4 rounded shadow-md">
60-
<h1 className="text-xl font-bold">Error</h1>
61-
<p>{error}</p>
62-
</div>
63-
</div>
64-
</main>
65-
)
66-
}
67-
68-
if (loading) {
69-
return (
70-
<main className="min-h-screen p-4 bg-gray-100">
71-
<LoadingScreen/>
72-
</main>
73-
)
74-
}
75-
return (
76-
<main className="min-h-screen p-4 bg-gray-100">
77-
{data && <Dashboard data={data} test_files={testFiles} />}
78-
</main>
6+
return(
7+
<AppProvider>
8+
<AppContent/>
9+
</AppProvider>
7910
)
8011
}
8112

web-report/src/AppContent.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {useAppContext} from "@/AppProvider.tsx";
2+
import {LoadingScreen} from "@/components/LoadingScreen.tsx";
3+
import {Dashboard} from "@/components/Dashboard.tsx";
4+
5+
export const AppContent: React.FC = () => {
6+
const {data, loading, error} = useAppContext();
7+
8+
if (error){
9+
return (
10+
<main className="min-h-screen p-4 bg-gray-100">
11+
<div className="flex items-center justify-center min-h-screen">
12+
<div className="bg-white p-4 rounded shadow-md">
13+
<h1 className="text-xl font-bold">Error</h1>
14+
<p>{error}</p>
15+
</div>
16+
</div>
17+
</main>
18+
)
19+
}
20+
21+
if (loading) {
22+
return (
23+
<main className="min-h-screen p-4 bg-gray-100">
24+
<LoadingScreen/>
25+
</main>
26+
)
27+
}
28+
29+
return (
30+
<main className="min-h-screen p-4 bg-gray-100">
31+
{data && <Dashboard/>}
32+
</main>
33+
)
34+
}

web-report/src/AppProvider.tsx

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import {createContext, useContext, useState, ReactNode, useEffect} from 'react';
2+
import {WebFuzzingCommonsReport} from "@/types/GeneratedTypes.tsx";
3+
import {ITestFiles} from "@/types/General.tsx";
4+
import {fetchFileContent, ITransformedReport, transformWebFuzzingReport} from "@/lib/utils.tsx";
5+
6+
type AppContextType = {
7+
data: WebFuzzingCommonsReport | null;
8+
loading: boolean;
9+
error: string | null;
10+
testFiles: ITestFiles[];
11+
transformedReport: ITransformedReport[];
12+
filterEndpoints: (activeFilters: Record<number, string>) => ITransformedReport[];
13+
filteredEndpoints: ITransformedReport[];
14+
};
15+
16+
const AppContext = createContext<AppContextType | undefined>(undefined);
17+
18+
type AppProviderProps = {
19+
children: ReactNode;
20+
};
21+
22+
export const AppProvider = ({ children }: AppProviderProps) => {
23+
24+
const [data, setData] = useState<WebFuzzingCommonsReport | null>(null);
25+
const [loading, setLoading] = useState(true);
26+
const [error, setError] = useState<string | null>(null);
27+
const [testFiles, setTestFiles] = useState<ITestFiles[]>([]);
28+
const transformedReport = transformWebFuzzingReport(data);
29+
30+
useEffect(() => {
31+
const fetchData = async () => {
32+
try {
33+
const jsonData = await fetchFileContent('./report.json') as WebFuzzingCommonsReport;
34+
setData(jsonData);
35+
} catch (error: Error | unknown) {
36+
if (error instanceof Error) {
37+
setError("Could not load the report file. Please check if the file exists and is accessible in /public folder.");
38+
} else {
39+
console.error(error);
40+
}
41+
} finally {
42+
setLoading(false);
43+
}
44+
};
45+
46+
fetchData();
47+
}, []);
48+
49+
useEffect(() => {
50+
if(data?.test_file_paths){
51+
data.test_file_paths.map(file => {
52+
fetchFileContent(file).then((content) => {
53+
if (typeof content === "string") {
54+
setTestFiles(prev => [...prev, {
55+
name: file,
56+
code: content
57+
}]);
58+
} else {
59+
setError("Could not load the test file. Please check if the file exists and is accessible.");
60+
}
61+
}).catch((error) => {
62+
console.error(error);
63+
setError("Could not load the test file. Please check if the file exists and is accessible.");
64+
})
65+
})
66+
}
67+
}, [data]);
68+
69+
const [filteredEndpoints, setFilteredEndpoints] = useState(transformedReport);
70+
71+
useEffect(() => {
72+
// Transform the report data into a format suitable for filtering
73+
if (data) {
74+
const transformed = transformWebFuzzingReport(data);
75+
setFilteredEndpoints(transformed);
76+
}
77+
}, [data]);
78+
79+
const filterEndpoints = (activeFilters: Record<number, string>) => {
80+
// Filter the endpoints based on the active filters
81+
const filtered = transformedReport.filter(endpoint => {
82+
// If no filters are active, show all endpoints
83+
if (Object.keys(activeFilters).length === 0) {
84+
return true;
85+
}
86+
87+
// Check if any status code or fault code is marked as "removed"
88+
const hasRemovedStatusCode = endpoint.http_status_codes.some(code =>
89+
activeFilters[code.code] === "removed"
90+
);
91+
const hasRemovedFaultCode = endpoint.faults.some(code =>
92+
activeFilters[-code.code] === "removed"
93+
);
94+
95+
// Check if any status code or fault code is marked as "active"
96+
const hasActiveStatusCode = endpoint.http_status_codes.some(code =>
97+
activeFilters[code.code] === "active"
98+
);
99+
const hasActiveFaultCode = endpoint.faults.some(code =>
100+
activeFilters[-code.code] === "active"
101+
);
102+
103+
const hasActiveFilter = activeFilters && Object.values(activeFilters).some((value) => value === "active");
104+
const hasRemovedFilter = activeFilters && Object.values(activeFilters).some((value) => value === "removed");
105+
106+
if (!hasActiveFilter && !hasRemovedFilter) {
107+
// If no filters are active, show all endpoints
108+
return true;
109+
}
110+
111+
if (hasActiveFilter) {
112+
if (hasRemovedFilter) {
113+
// If there are both active and removed filters, check if the endpoint matches any of them
114+
if(hasRemovedFaultCode || hasRemovedStatusCode) {
115+
return false;
116+
}
117+
118+
return !!(hasActiveStatusCode || hasActiveFaultCode);
119+
120+
} else {
121+
// If there are only active filters, check if the endpoint matches any of them
122+
return !!(hasActiveStatusCode || hasActiveFaultCode);
123+
124+
}
125+
} else if (hasRemovedFilter) {
126+
// If there are only removed filters, check if the endpoint matches any of them
127+
return !(hasRemovedStatusCode || hasRemovedFaultCode);
128+
129+
} else {
130+
// If there are no active or removed filters, show all endpoints
131+
return true;
132+
}
133+
});
134+
setFilteredEndpoints(filtered)
135+
return filtered;
136+
}
137+
138+
const value: AppContextType = { data, loading, error, testFiles, transformedReport, filterEndpoints, filteredEndpoints };
139+
140+
return (
141+
<AppContext.Provider value={value}>
142+
{children}
143+
</AppContext.Provider>
144+
);
145+
};
146+
147+
export const useAppContext = (): AppContextType => {
148+
const context = useContext(AppContext);
149+
if (!context) {
150+
throw new Error('useAppContext must be used within AppProvider');
151+
}
152+
return context;
153+
};

web-report/src/assets/info.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
"number_of_http_calls": "Total number of HTTP calls in the generated test suites.",
44
"code_number_identifiers": "Code number identifiers for detected fault types",
55
"identifier_name": "Identifier name for the fault type.",
6+
"test_files_located": "{number_of_test_cases} test cases are located in {file_name}",
7+
"http_endpoint_codes": "{number_of_endpoints} endpoints have {code} HTTP code out of {total_endpoints} endpoints.",
68
"number_of_faults_per_code": "Number of faults detected for each code.",
9+
"distribution_of_endpoints_per_code": "Distribution of endpoints per code (Affected/Total Endpoints).",
10+
"distribution_tooltip": "{operation_count} {endpoint_text} {code} error code out of {totalEndpointNumber} endpoints.",
711
"generated_test_files": "Number of generated test files.",
812
"generated_test_cases": "Number of generated test cases.",
913
"total_faults": "Total number of faults detected in the API.",
1014
"distinct_fault_types": "Total number of distinct fault types detected in the API.",
1115
"creation_date": "Date when the report was generated.",
1216
"tool_name_version": "Name and version of the tool that generated the report.",
1317
"schema_version": "Version of the schema used for the report.",
14-
"status_2xx": "Coverage of the 2xx status codes",
15-
"status_3xx": "Coverage of the 3xx status codes",
16-
"status_4xx": "Coverage of the 4xx status codes",
17-
"status_5xx": "Coverage of the 5xx status codes",
1818
"fault_codes": [
1919
{
2020
"short_definition": "HTTP_STATUS_500",

web-report/src/components/Dashboard.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,16 @@ import {Endpoints} from "@/pages/Endpoints.tsx";
88
import {TestResults} from "@/pages/TestResults.tsx";
99

1010
import {ScrollArea, ScrollBar} from "@/components/ui/scroll-area.tsx";
11-
import {WebFuzzingReport} from "@/types/GeneratedTypes.tsx";
12-
import {ITestFiles} from "@/types/General.tsx";
11+
import {useAppContext} from "@/AppProvider.tsx";
1312

1413

1514
export interface ITestTabs {
1615
value: string;
1716
}
1817

19-
export interface IDashboard {
20-
data: WebFuzzingReport;
21-
test_files: Array<ITestFiles>;
22-
}
18+
export const Dashboard: React.FC = () => {
19+
const {data} = useAppContext();
2320

24-
export const Dashboard: React.FC<IDashboard> = ({data, test_files}) => {
2521
const [activeTab, setActiveTab] = useState("overview")
2622

2723
const [testTabs, setTestTabs] = useState<Array<ITestTabs>>([]);
@@ -46,6 +42,14 @@ export const Dashboard: React.FC<IDashboard> = ({data, test_files}) => {
4642
}
4743
}
4844

45+
if(!data) {
46+
return (
47+
<div className="flex items-center justify-center h-screen">
48+
<p className="text-lg font-semibold">Loading...</p>
49+
</div>
50+
);
51+
}
52+
4953
const numberOfTestCaseOfFiles = data.test_file_paths.map((test_file) => {
5054
return {
5155
"file_name": test_file,
@@ -114,17 +118,13 @@ export const Dashboard: React.FC<IDashboard> = ({data, test_files}) => {
114118
</TabsContent>
115119

116120
<TabsContent value="endpoints">
117-
<Endpoints addTestTab={addTestTab} data={data}/>
121+
<Endpoints addTestTab={addTestTab}/>
118122
</TabsContent>
119123

120124
{
121125
testTabs.map((test, index) => (
122126
<TabsContent value={`${test.value}`} key={index}>
123-
<TestResults test_case_name={test.value}
124-
test_cases={data.test_cases}
125-
found_faults={data.faults.found_faults}
126-
problem_details={data.problem_details}
127-
test_files={test_files}/>
127+
<TestResults test_case_name={test.value} />
128128
</TabsContent>
129129
))
130130
}

0 commit comments

Comments
 (0)