A Python-based interactive dashboard that reads daily test execution CSV reports and displays live charts, KPI cards, and filterable tables.
Built with Python ยท Dash ยท Plotly ยท Pandas
qa-python-dashboard/
โ
โโโ app.py โ ๐ Start here โ runs the dashboard server
โโโ config.py โ โ๏ธ All settings (colors, port, paths)
โโโ data_loader.py โ ๐ Reads and cleans CSV files
โโโ charts.py โ ๐ Builds every chart / graph
โโโ layout.py โ ๐ผ๏ธ Defines the page structure
โโโ callbacks.py โ ๐ Handles user interactions
โ
โโโ reports/ โ ๐ DROP YOUR CSV FILES HERE
โ โโโ test-summary-2026-06-08.csv
โ โโโ test-summary-2026-06-09.csv
โ โโโ test-summary-2026-06-10.csv
โ
โโโ README.md
For interns: Each file has one job.
- To change a color โ edit
config.py- To change how CSV data is read โ edit
data_loader.py- To change a chart โ edit
charts.py- To change the page layout โ edit
layout.py- To change what happens on a button click โ edit
callbacks.py
The dashboard auto-discovers all *.csv files inside the reports/ folder.
You do not need to edit any code when adding a new report:
- Export your test summary as a CSV from your test runner
- Save it into the
reports/folder - Restart the app (or wait for the 60-second auto-refresh)
The file name does not matter โ any .csv file in reports/ will be picked up.
The dashboard expects these columns (column names are case-insensitive):
| Column | Required? | Description |
|---|---|---|
Test ID |
Optional | Unique test identifier |
Test Name |
โ Yes | Human-readable test name |
Status |
โ Yes | Passed, Failed, Skipped, Broken |
Start Time |
โ Yes | When the test began |
Stop Time |
Optional | When the test ended |
Duration (s) |
Optional | Runtime in seconds |
Monitor Status |
Optional | High, Critical, Normal, etc. |
Failure Root Cause |
Optional | Why the test failed |
Updated At |
Optional | When the test was last updated |
Created At |
Optional | When the test was created |
Note: If a column is missing from an older CSV, the dashboard fills in a safe default โ it will not crash.
Why a virtual environment?
Modern Linux/Ubuntu systems block installing Python packages system-wide
(externally-managed-environmenterror). A virtual environment creates
an isolated Python sandbox just for this project โ safe and clean.
Open a terminal inside the project folder and run:
# Navigate to the project folder
cd qa-python-dashboard
# Create the virtual environment (creates a .venv folder)
python3 -m venv .venv.venv/bin/pip install -r requirements.txtYou should see packages being downloaded and installed.
This only needs to be done once.
reports/
โโโ test-summary-2026-06-08.csv
โโโ test-summary-2026-06-09.csv
โโโ test-summary-2026-06-10.csv
# Always use the venv Python to run the app
.venv/bin/python3 app.pyWindows users: use
.venv\Scripts\python app.pyinstead
Expected output:
[app] Starting QA Analytics Dashboard...
[data_loader] Found 3 CSV file(s):
โข test-summary-2026-06-08.csv
โข test-summary-2026-06-09.csv
โข test-summary-2026-06-10.csv
[data_loader] Total rows after merge: 1,532
[app] Dashboard running at โ http://127.0.0.1:8052
http://127.0.0.1:8052
| Filter | What it does |
|---|---|
| FROM DATE | Show only tests run on or after this date |
| TO DATE | Show only tests run on or before this date |
All charts update instantly when you change a filter.
Five summary cards show at a glance:
| Card | Color | Meaning |
|---|---|---|
| ๐งช TOTAL | Grey | All test runs in the selected range |
| โ PASS | Green | Tests that passed |
| โ FAIL | Red | Tests that failed |
| โญ๏ธ SKIPPED | Yellow | Tests that were skipped |
| Purple | Tests marked as broken |
| Chart | Description |
|---|---|
| Test Status Distribution | Donut chart โ proportion of each status |
| Test Execution Duration | Bar chart โ how long tests take (grouped into 10 s buckets) |
| Failed Tests Per Day | Bar chart โ failure count per date |
| Daily Test Trend | Line chart โ daily total, daily new, and daily updated |
| Monitor Status Breakdown | Stacked bar โ HIGH / CRITICAL / MONITOR CLOSELY priority tests |
| Failure Root Cause Analysis | Donut chart โ distribution of why tests failed |
| Button | Shows |
|---|---|
| ๐ View New Tests | Date, Test ID, Test Name, Status, Duration |
| โ๏ธ View Updated Tests | Date, Updated At, Test ID, Test Name, Status |
| ๐ Full Dataset | Every column in the combined CSV data |
The table supports:
- Column sorting โ click any column header
- Row filtering โ type in the filter row below headers
- Pagination โ 15 rows per page by default
The dashboard automatically reloads data every 60 seconds.
If you update a CSV while the dashboard is running, the new data will appear within the next refresh cycle โ no restart needed.
To force an immediate reload: change a filter value and change it back.
Open config.py to change dashboard settings without touching any other file:
PORT = 8052 # Change the server port
REFRESH_INTERVAL_MS = 60000 # Auto-refresh interval (milliseconds)
TABLE_PAGE_SIZE = 15 # Rows shown per page in the data table
PLOTLY_TEMPLATE = "plotly_white" # Chart visual themeInstall dependencies:
pip install dash plotly pandas numpyCreate the reports/ folder next to app.py and drop your CSV files in it:
mkdir reportsMake sure the folder contains at least one .csv file.
The dashboard expects columns to be named exactly as listed in the Required CSV Columns table above. Check the actual column names in your CSV:
head -1 reports/your-file.csvCheck that:
- The
DATEcolumn is being parsed correctly (checkStart Timecolumn format) - Your CSV uses one of the supported status values:
Passed,Failed,Skipped,Broken
Change the port in config.py:
PORT = 8053 # or any free porthttp://127.0.0.1:8052
- Write a
build_my_chart(df)function incharts.py - Add a
dcc.Graph(id="my_chart")tolayout.py - Add it to the
Outputlist and return value incallbacks.py โ update_dashboard()
- Add the Dash component to
layout.py - Add an
Input("my_filter", "value")to the callback incallbacks.py - Apply the filter to
dfinsideupdate_dashboard()
Edit STATUS_COLORS and KPI_CARD_COLORS in config.py.
Changes automatically apply to all charts and KPI cards.
Press Ctrl + C in the terminal where the app is running.