Skip to content

Comments

Group scenarios by suites in the GUI#95

Open
atti92 wants to merge 4 commits intomainfrom
fb-92
Open

Group scenarios by suites in the GUI#95
atti92 wants to merge 4 commits intomainfrom
fb-92

Conversation

@atti92
Copy link
Contributor

@atti92 atti92 commented Feb 11, 2026

Implements #92

@atti92 atti92 marked this pull request as ready for review February 11, 2026 20:44
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements issue #92 by introducing “suite” groupings for pre-built scenarios in the web editor, backed by a new server endpoint that exposes suite→scenario mappings.

Changes:

  • Add /api/suites endpoint to return a suite-to-scenario mapping from server configuration.
  • Update ScenarioList UI to display scenarios grouped under collapsible suite headers (with an “Other Scenarios” bucket).
  • Add a root-level package-lock.json.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 6 comments.

File Description
web-editor/src/components/ScenarioEditor/ScenarioList.tsx Fetch suites and render scenarios grouped into collapsible suite sections.
src/openutm_verification/server/router.py Add /api/suites route that exposes configured suites and their scenario names.
package-lock.json Introduces a new root lockfile (currently empty) outside the existing web-editor Node project.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@atti92 atti92 self-assigned this Feb 12, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 25 to 31
Promise.all([
fetch('/api/scenarios').then(res => res.json()),
fetch('/api/suites').then(res => res.json()).catch(() => ({})),
]).then(([scenarioList, suiteMap]: [string[], SuiteMap]) => {
setScenarios(scenarioList.sort());
setSuites(suiteMap);
}).catch(err => console.error('Failed to load scenarios:', err));
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The /api/scenarios and /api/suites fetches assume a successful (2xx) response and the expected JSON shape. If either endpoint returns a non-OK status with an error payload (e.g., FastAPI {detail: ...}), scenarioList.sort() or suiteNames.flatMap(s => suites[s]) can throw at runtime. Consider checking res.ok before parsing, and validating/coercing the parsed JSON into string[] / Record<string, string[]>, falling back to [] / {} on mismatch.

Suggested change
Promise.all([
fetch('/api/scenarios').then(res => res.json()),
fetch('/api/suites').then(res => res.json()).catch(() => ({})),
]).then(([scenarioList, suiteMap]: [string[], SuiteMap]) => {
setScenarios(scenarioList.sort());
setSuites(suiteMap);
}).catch(err => console.error('Failed to load scenarios:', err));
const loadData = async () => {
try {
const [scenariosRes, suitesRes] = await Promise.all([
fetch('/api/scenarios'),
fetch('/api/suites'),
]);
let rawScenarios: unknown = [];
let rawSuites: unknown = {};
if (scenariosRes.ok) {
rawScenarios = await scenariosRes.json();
}
if (suitesRes.ok) {
rawSuites = await suitesRes.json();
}
// Coerce scenarios into string[]
const scenarioList: string[] = Array.isArray(rawScenarios)
? rawScenarios.filter((s): s is string => typeof s === 'string')
: [];
// Coerce suites into Record<string, string[]>
const suiteMap: SuiteMap = {};
if (rawSuites && typeof rawSuites === 'object' && !Array.isArray(rawSuites)) {
for (const [key, value] of Object.entries(rawSuites as Record<string, unknown>)) {
if (Array.isArray(value)) {
suiteMap[key] = value.filter((v): v is string => typeof v === 'string');
}
}
}
setScenarios(scenarioList.slice().sort());
setSuites(suiteMap);
} catch (err) {
console.error('Failed to load scenarios:', err);
setScenarios([]);
setSuites({});
}
};
void loadData();

Copilot uses AI. Check for mistakes.
Comment on lines 44 to 59
it('renders success status icon', () => {
render(<CustomNode {...defaultProps} />, { wrapper });
// Check for CheckCircle icon (or button containing it)
const button = screen.getByTitle('Success');
expect(button).toBeInTheDocument();
});

it('calls onShowResult when status icon is clicked', () => {
render(<CustomNode {...defaultProps} />, { wrapper });
const button = screen.getByTitle('Success');
fireEvent.click(button);
expect(mockData.onShowResult).toHaveBeenCalledWith(mockData.result);
const { container } = render(<CustomNode {...defaultProps} />, { wrapper });
// CheckCircle renders as an SVG with class containing 'circle-check-big'
const svg = container.querySelector('.lucide-circle-check-big');
expect(svg).toBeInTheDocument();
});

it('renders failure status', () => {
it('renders failure status icon', () => {
const failureProps = {
...defaultProps,
data: { ...mockData, status: 'failure' as const }
};
render(<CustomNode {...failureProps} />, { wrapper });
const button = screen.getByTitle('Failure');
expect(button).toBeInTheDocument();
// We could check for color or specific icon if we could query by icon
const { container } = render(<CustomNode {...failureProps} />, { wrapper });
// XCircle renders as an SVG with class containing 'circle-x'
const svg = container.querySelector('.lucide-circle-x');
expect(svg).toBeInTheDocument();
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These assertions rely on Lucide’s internal generated CSS class names (e.g. .lucide-circle-check-big, .lucide-circle-x). Those class names are not a stable public API and can change across Lucide releases, causing brittle tests. Prefer querying via accessible attributes (e.g., add an aria-label/title or data-testid on the status indicator in CustomNode) and use Testing Library queries instead of querySelector on framework-generated classes.

Copilot uses AI. Check for mistakes.
atti92 and others added 2 commits February 13, 2026 20:58
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant