From 4e93769dc954255c4b576fa3341b2b07ac8df590 Mon Sep 17 00:00:00 2001 From: Carla Severe Date: Thu, 23 Jul 2026 17:24:32 -0700 Subject: [PATCH 1/6] created toggle for customizing col: simple vs power view --- src/common/constants.ts | 4 +- src/common/store.ts | 2 + src/common/testVersions/index.ts | 15 +- src/common/testVersions/mannWhitney.tsx | 512 ++++++++++-------- src/common/testVersions/studentT.tsx | 17 +- .../CompareResults/AdvancedColumnsToggle.tsx | 38 ++ .../CompareResults/ResultsControls.tsx | 39 +- .../CompareResults/ResultsTable.tsx | 18 +- src/components/CompareResults/RevisionRow.tsx | 6 +- .../SubtestsResults/SubtestsResultsMain.tsx | 4 + .../SubtestsResults/SubtestsResultsTable.tsx | 11 +- .../SubtestsResults/SubtestsRevisionRow.tsx | 6 +- src/components/CompareResults/TableHeader.tsx | 6 + src/reducers/ColumnPrefsSlice.ts | 21 + src/utils/rowTemplateColumns.ts | 4 +- 15 files changed, 451 insertions(+), 252 deletions(-) create mode 100644 src/components/CompareResults/AdvancedColumnsToggle.tsx create mode 100644 src/reducers/ColumnPrefsSlice.ts diff --git a/src/common/constants.ts b/src/common/constants.ts index cdafa0247..8137c73c2 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -338,4 +338,6 @@ export const tooltipConfidence = export const tooltipDelta = 'The percentage difference between the Base and New values'; export const tooltipMedianDiff = - 'Median Diff %: The percentage change in median from Base to New: ((New − Base) / Base) × 100.'; + 'Shows how much the middle result changed from Base to New. We line up all the runs from smallest to biggest and pick the middle one for each side, then show the change as a percent. A postive sign means New is higher; a negative sign means New is lower.'; +export const tooltipDifferenceSize = + 'Shows how big the difference between Base and New is, in plain words: negligible (barely any), small, medium, or large. It comes from how much the Base and New results overlap — the less they overlap, the bigger the difference.'; diff --git a/src/common/store.ts b/src/common/store.ts index 0e46ee60d..dc1a9ed09 100644 --- a/src/common/store.ts +++ b/src/common/store.ts @@ -1,5 +1,6 @@ import { configureStore } from '@reduxjs/toolkit'; +import columnPrefs from '../reducers/ColumnPrefsSlice'; import comparison from '../reducers/ComparisonSlice'; import selectedRevisions from '../reducers/SelectedRevisionsSlice'; import theme from '../reducers/ThemeSlice'; @@ -10,6 +11,7 @@ export const createStore = () => theme, selectedRevisions, comparison, + columnPrefs, }, }); diff --git a/src/common/testVersions/index.ts b/src/common/testVersions/index.ts index bf0e1ecb3..7e6962ce8 100644 --- a/src/common/testVersions/index.ts +++ b/src/common/testVersions/index.ts @@ -6,15 +6,23 @@ import { CombinedResultsItemType } from '../../types/state'; import { TableConfig, TestVersion } from '../../types/types'; export interface TestVersionStrategy { - getColumns(isSubtestTable: boolean): TableConfig; + // showAdvancedColumns toggles the power-user columns (CD, CLES, Sig). + getColumns( + isSubtestTable: boolean, + showAdvancedColumns: boolean, + ): TableConfig; getAvgValues(result: CombinedResultsItemType): { baseAvg: number | null; newAvg: number | null; }; - renderColumns(result: CombinedResultsItemType): ReactNode; + renderColumns( + result: CombinedResultsItemType, + showAdvancedColumns: boolean, + ): ReactNode; renderSubtestColumns( result: CombinedResultsItemType, expanded: boolean, + showAdvancedColumns: boolean, ): ReactNode; renderExpandedLeft(result: CombinedResultsItemType): ReactNode; getComparisonResult(result: CombinedResultsItemType): string; @@ -54,6 +62,7 @@ export function getStrategy(testVersion: TestVersion): TestVersionStrategy { export function getColumnsForVersion( testVersion: TestVersion, isSubtestTable: boolean, + showAdvancedColumns: boolean, ): TableConfig { - return registry[testVersion].getColumns(isSubtestTable); + return registry[testVersion].getColumns(isSubtestTable, showAdvancedColumns); } diff --git a/src/common/testVersions/mannWhitney.tsx b/src/common/testVersions/mannWhitney.tsx index 742855fd4..ae964acbc 100644 --- a/src/common/testVersions/mannWhitney.tsx +++ b/src/common/testVersions/mannWhitney.tsx @@ -26,6 +26,7 @@ import { shapiroWilkTest } from '../../utils/shapiroWilk'; import { defaultSortFunction } from '../../utils/sortFunctions'; import { tooltipBaseMean, + tooltipDifferenceSize, tooltipMedianDiff, tooltipNewMean, tooltipSignificance, @@ -79,26 +80,155 @@ const SW_NORMALITY_THRESHOLD = 0.2; type NormalityResult = 'both' | 'one' | 'neither'; +// Shapiro-Wilk is run twice (base + new) per call and cell renderers invoke +// this for every row on every render. Cache by the (stable) result object so +// the test runs once per result rather than once per render. +// +// A WeakMap is a lookup table whose keys are objects (here, the result object). +// "Weak" means it does not keep those objects alive: once a result is no longer +// used anywhere else (e.g. the user loads new data), it gets garbage-collected +// and its cache entry disappears on its own — so this cache never leaks memory +// and needs no manual cleanup. +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap +const normalityCache = new WeakMap(); + export function checkDistributionNormality( result: MannWhitneyResultsItem, ): NormalityResult { + const cached = normalityCache.get(result); + if (cached !== undefined) return cached; + const baseResult = shapiroWilkTest(result.base_runs); const newResult = shapiroWilkTest(result.new_runs); const baseNormal = baseResult !== null && baseResult.pvalue > SW_NORMALITY_THRESHOLD; const newNormal = newResult !== null && newResult.pvalue > SW_NORMALITY_THRESHOLD; - if (baseNormal && newNormal) return 'both'; - if (baseNormal || newNormal) return 'one'; - return 'neither'; + const value: NormalityResult = + baseNormal && newNormal + ? 'both' + : baseNormal || newNormal + ? 'one' + : 'neither'; + + normalityCache.set(result, value); + return value; } export function isDistributionNormal(result: MannWhitneyResultsItem): boolean { return checkDistributionNormality(result) !== 'neither'; } +function medianOf(values: number[]): number | null { + if (!values.length) return null; + const sorted = [...values].sort((a, b) => a - b); + const mid = Math.floor(sorted.length / 2); + return sorted.length % 2 === 0 + ? (sorted[mid - 1] + sorted[mid]) / 2 + : sorted[mid]; +} + +// Δ median as a signed percentage of the base median, computed from the raw +// runs. This is the same basis as the expanded panel's "Δ median" blurb +// (bootstrapMedianDiffCI's point estimate is median(new) - median(base) over +// the same runs), so the column and the panel always agree. +// +// Cached by the (stable) result object (see the WeakMap note on normalityCache +// above): this is called per row on every render and, in the Δ Median % sort +// comparator, on every comparison — recomputing the median (which sorts both +// run arrays) each time would be wasteful. +const medianDiffPctCache = new WeakMap(); + +export function medianDiffPct(result: MannWhitneyResultsItem): number | null { + const cached = medianDiffPctCache.get(result); + if (cached !== undefined) return cached; + + const baseMedian = medianOf(result.base_runs ?? []); + const newMedian = medianOf(result.new_runs ?? []); + const value = + baseMedian === null || newMedian === null || baseMedian === 0 + ? null + : ((newMedian - baseMedian) / baseMedian) * 100; + + medianDiffPctCache.set(result, value); + return value; +} + +export function formatMedianDiffPct(pct: number): string { + return `${pct >= 0 ? '+' : ''}${pct.toFixed(2)}%`; +} + +// Plain-language "Difference Size" cell — the Cliff's Delta interpretation +// (negligible/small/medium/large). Shared by the main and subtests rows so +// they render identically. +function renderDifferenceSizeCell(interpretation: string) { + return ( +
+ {interpretation ? capitalize(interpretation) : '-'} +
+ ); +} + +function renderStatusCell( + directionOfChange: MannWhitneyResultsItem['direction_of_change'], +) { + const isImprovement = directionOfChange === 'improvement'; + const isRegression = directionOfChange === 'regression'; + return ( +
+ + {isImprovement ? : null} + {isRegression ? : null} + {capitalize(directionOfChange ?? '')} + +
+ ); +} + +// Δ Median % cell, shared by the main and subtests rows. Shows the run-based +// median difference; a warning icon flags non-normal distributions, and "-" +// when the value can't be computed. +function renderMedianDiffCell(result: MannWhitneyResultsItem) { + const pct = medianDiffPct(result); + const normality = checkDistributionNormality(result); + return ( +
+ {pct === null ? ( + '-' + ) : ( + + {formatMedianDiffPct(pct)} + {normality !== 'both' && ( + + )} + + )} +
+ ); +} + export const mannWhitneyStrategy = { - getColumns(isSubtestTable: boolean): TableConfig { + getColumns( + isSubtestTable: boolean, + showAdvancedColumns: boolean, + ): TableConfig { const platformConfig = isSubtestTable ? { name: 'Subtests', @@ -133,20 +263,19 @@ export const mannWhitneyStrategy = { { key: 'comparisonSign', gridWidth: '0.25fr' }, { name: 'New', key: 'new', gridWidth: '1fr', tooltip: tooltipNewMean }, { - name: 'MD (%)', + name: 'Δ Median %', key: 'median-diff', - gridWidth: '1fr', + gridWidth: showAdvancedColumns ? '1.5fr' : '1fr', sortFunction( resultA: MannWhitneyResultsItem, resultB: MannWhitneyResultsItem, ) { - // Compute a normalized median diff percentage where positive - // means "improved" regardless of whether lower or higher is better. + // Normalize so positive means "improved" regardless of whether lower + // or higher is better. Uses the same run-based Δ median % the cell + // displays, so sort order matches the shown values. const normalizedDiffPct = (r: MannWhitneyResultsItem) => { - const base = r.base_standard_stats?.median ?? 0; - const newVal = r.new_standard_stats?.median ?? 0; - const rawPct = base !== 0 ? ((newVal - base) / base) * 100 : 0; - return r.lower_is_better ? -rawPct : rawPct; + const pct = medianDiffPct(r) ?? 0; + return r.lower_is_better ? -pct : pct; }; return normalizedDiffPct(resultB) - normalizedDiffPct(resultA); @@ -178,66 +307,100 @@ export const mannWhitneyStrategy = { }, tooltip: tooltipStatusMannWhitney, }, - { - name: 'CD', - key: 'delta', - gridWidth: '1fr', - sortFunction( - resultA: MannWhitneyResultsItem, - resultB: MannWhitneyResultsItem, - ) { - return ( - Math.abs(resultA.cliffs_delta) - Math.abs(resultB.cliffs_delta) - ); - }, - tooltip: tooltipCliffsDelta, - }, - { - name: 'CLES (%)', - key: 'effects', - gridWidth: '1.25fr', - sortFunction( - resultA: MannWhitneyResultsItem, - resultB: MannWhitneyResultsItem, - ) { - return ( - Math.abs((resultA.cles?.cles ?? 0.5) - 0.5) - - Math.abs((resultB.cles?.cles ?? 0.5) - 0.5) - ); - }, - tooltip: tooltipEffectSize, - }, - { - name: 'Sig', - key: 'significance', - filter: true, - gridWidth: '1.25fr', - tooltip: tooltipSignificance, - possibleValues: [ - { - label: 'Significant', - key: 'significant', - icon: , - }, - { - label: 'Not Significant', - key: 'not significant', - icon:
-
, - }, - ], - matchesFunction(result: MannWhitneyResultsItem, valueKey: string) { - return result.mann_whitney_test?.interpretation === valueKey; - }, - sortFunction( - resultA: MannWhitneyResultsItem, - resultB: MannWhitneyResultsItem, - ) { - return ( - Math.abs(resultA.mann_whitney_test?.pvalue ?? 0) - - Math.abs(resultB.mann_whitney_test?.pvalue ?? 0) - ); - }, - }, + // Plain-language size of the difference (the Cliff's Delta + // interpretation: negligible/small/medium/large). Simplified view only. + // Sorted by the magnitude of Cliff's Delta, which is what the buckets + // derive from, so the order matches the labels. + ...(!showAdvancedColumns + ? [ + { + name: 'Difference Size', + key: 'difference-size', + gridWidth: '1fr', + sortFunction( + resultA: MannWhitneyResultsItem, + resultB: MannWhitneyResultsItem, + ) { + return ( + Math.abs(resultA.cliffs_delta) - + Math.abs(resultB.cliffs_delta) + ); + }, + tooltip: tooltipDifferenceSize, + }, + ] + : []), + // Advanced (power-user) columns — hidden in the simplified view. Kept in + // sync with the matching cells in renderColumns/renderSubtestColumns, + // which gate on the same showAdvancedColumns flag. + ...(showAdvancedColumns + ? [ + { + name: 'CD', + key: 'delta', + gridWidth: '1fr', + sortFunction( + resultA: MannWhitneyResultsItem, + resultB: MannWhitneyResultsItem, + ) { + return ( + Math.abs(resultA.cliffs_delta) - + Math.abs(resultB.cliffs_delta) + ); + }, + tooltip: tooltipCliffsDelta, + }, + { + name: 'CLES %', + key: 'effects', + gridWidth: '1.25fr', + sortFunction( + resultA: MannWhitneyResultsItem, + resultB: MannWhitneyResultsItem, + ) { + return ( + Math.abs((resultA.cles?.cles ?? 0.5) - 0.5) - + Math.abs((resultB.cles?.cles ?? 0.5) - 0.5) + ); + }, + tooltip: tooltipEffectSize, + }, + { + name: 'Sig', + key: 'significance', + filter: true, + gridWidth: '1.25fr', + tooltip: tooltipSignificance, + possibleValues: [ + { + label: 'Significant', + key: 'significant', + icon: , + }, + { + label: 'Not Significant', + key: 'not significant', + icon:
-
, + }, + ], + matchesFunction( + result: MannWhitneyResultsItem, + valueKey: string, + ) { + return result.mann_whitney_test?.interpretation === valueKey; + }, + sortFunction( + resultA: MannWhitneyResultsItem, + resultB: MannWhitneyResultsItem, + ) { + return ( + Math.abs(resultA.mann_whitney_test?.pvalue ?? 0) - + Math.abs(resultB.mann_whitney_test?.pvalue ?? 0) + ); + }, + }, + ] + : []), { name: 'Total Trials', @@ -258,10 +421,15 @@ export const mannWhitneyStrategy = { }; }, - renderSubtestColumns(result: CombinedResultsItemType, expanded: boolean) { + renderSubtestColumns( + result: CombinedResultsItemType, + expanded: boolean, + showAdvancedColumns: boolean, + ) { const { test, cliffs_delta, + cliffs_interpretation, mann_whitney_test, cles, direction_of_change, @@ -295,75 +463,29 @@ export const mannWhitneyStrategy = { ({newApp}) )} -
- {(() => { - const mwResult = result as MannWhitneyResultsItem; - const normality = checkDistributionNormality(mwResult); - if (normality === 'neither') return '-'; - const baseMedian = mwResult.base_standard_stats?.median ?? 0; - const newMedian = mwResult.new_standard_stats?.median ?? 0; - const pct = - baseMedian !== 0 - ? ((newMedian - baseMedian) / baseMedian) * 100 - : 0; - return ( - - {`${formatNumber(pct)} %`} - {normality === 'one' && ( - - )} - - ); - })()} -
-
- - {direction_of_change === 'improvement' ? ( - - ) : null} - {direction_of_change === 'regression' ? ( - - ) : null} - {capitalize(direction_of_change ?? '')} - -
-
- {' '} - {cliffs_delta || '-'} -
+ {renderMedianDiffCell(result as MannWhitneyResultsItem)} + {renderStatusCell(direction_of_change)} + {!showAdvancedColumns && + renderDifferenceSizeCell(cliffs_interpretation)} + {showAdvancedColumns && ( + <> +
+ {' '} + {cliffs_delta || '-'} +
-
- {clesVal ? `${clesVal}% ` : '-'} -
-
- {mann_whitney_test?.interpretation === 'significant' ? ( - - ) : ( - '-' - )} -
+
+ {clesVal ? `${clesVal}% ` : '-'} +
+
+ {mann_whitney_test?.interpretation === 'significant' ? ( + + ) : ( + '-' + )} +
+ + )} ); }, @@ -415,21 +537,13 @@ export const mannWhitneyStrategy = { ? adaptUnit([ci.medianDiff, ci.ciLow, ci.ciHigh], rawUnit) : adaptUnit([], rawUnit); const ciCrossesZero = ci && ci.ciLow < 0 && ci.ciHigh > 0; - const baseMedian = (() => { - if (!baseRuns.length) return null; - const s = [...baseRuns].sort((a, b) => a - b); - const m = Math.floor(s.length / 2); - return s.length % 2 === 0 ? (s[m - 1] + s[m]) / 2 : s[m]; - })(); - const pctDiff = - baseMedian && ci ? ((ci.medianDiff / baseMedian) * 100).toFixed(1) : null; + // Same run-based Δ median % the column shows, formatted identically. + const pctDiff = medianDiffPct(mwResult); const summary = ci ? ( Δ median = {fmt(ci.medianDiff)} {displayUnit} - {pctDiff !== null - ? ` (${Number(pctDiff) >= 0 ? '+' : ''}${pctDiff}%)` - : ''}{' '} - 95% CI [{fmt(ci.ciLow)}, {fmt(ci.ciHigh)}] + {pctDiff !== null ? ` (${formatMedianDiffPct(pctDiff)})` : ''} 95% CI [ + {fmt(ci.ciLow)}, {fmt(ci.ciHigh)}] {ciCrossesZero ? ' ⚠ interval includes zero — effect direction uncertain' : ''} @@ -474,84 +588,40 @@ export const mannWhitneyStrategy = { ); }, - renderColumns(result: CombinedResultsItemType) { + renderColumns(result: CombinedResultsItemType, showAdvancedColumns: boolean) { + const mwResult = result as MannWhitneyResultsItem; const { cliffs_delta, + cliffs_interpretation, direction_of_change, mann_whitney_test, cles, - base_standard_stats, - new_standard_stats, - } = result as MannWhitneyResultsItem; + } = mwResult; const clesValue = cles?.cles ? `${(cles.cles * 100).toFixed(2)} %` : '-'; - const baseMedian = base_standard_stats?.median ?? 0; - const newMedian = new_standard_stats?.median ?? 0; - const medianDiffPct = - baseMedian !== 0 ? ((newMedian - baseMedian) / baseMedian) * 100 : 0; - const normality = checkDistributionNormality( - result as MannWhitneyResultsItem, - ); return ( <> -
- {normality === 'neither' ? ( - '-' - ) : ( - - {`${formatNumber(medianDiffPct)} %`} - {normality === 'one' && ( - + {renderMedianDiffCell(mwResult)} + {renderStatusCell(direction_of_change)} + {!showAdvancedColumns && + renderDifferenceSizeCell(cliffs_interpretation)} + {showAdvancedColumns && ( + <> +
+ {cliffs_delta || '-'} +
+
+ {clesValue} +
+
+ {mann_whitney_test?.interpretation === 'significant' ? ( + + ) : ( + '-' )} - - )} -
-
- - {direction_of_change === 'improvement' ? ( - - ) : null} - {direction_of_change === 'regression' ? ( - - ) : null} - {capitalize(direction_of_change ?? '')} - -
-
- {cliffs_delta || '-'} -
-
- {clesValue} -
-
- {mann_whitney_test?.interpretation === 'significant' ? ( - - ) : ( - '-' - )} -
+
+ + )} ); }, diff --git a/src/common/testVersions/studentT.tsx b/src/common/testVersions/studentT.tsx index 89c138cc9..266280ee5 100644 --- a/src/common/testVersions/studentT.tsx +++ b/src/common/testVersions/studentT.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ import DragHandleIcon from '@mui/icons-material/DragHandle'; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; @@ -41,7 +42,10 @@ const confidenceIcons: Record<'Low' | 'Medium' | 'High', React.ReactNode> = { }; export const studentTStrategy = { - getColumns(isSubtestTable: boolean): TableConfig { + getColumns( + isSubtestTable: boolean, + _showAdvancedColumns: boolean, + ): TableConfig { const platformConfig = isSubtestTable ? { name: 'Subtests', @@ -159,7 +163,11 @@ export const studentTStrategy = { }; }, - renderSubtestColumns(result: CombinedResultsItemType, expanded: boolean) { + renderSubtestColumns( + result: CombinedResultsItemType, + expanded: boolean, + _showAdvancedColumns: boolean, + ) { const { test, delta_percentage: deltaPercent, @@ -308,7 +316,10 @@ export const studentTStrategy = { return null; }, - renderColumns(result: CombinedResultsItemType) { + renderColumns( + result: CombinedResultsItemType, + _showAdvancedColumns: boolean, + ) { const { is_improvement: improvement, is_regression: regression, diff --git a/src/components/CompareResults/AdvancedColumnsToggle.tsx b/src/components/CompareResults/AdvancedColumnsToggle.tsx new file mode 100644 index 000000000..72728b856 --- /dev/null +++ b/src/components/CompareResults/AdvancedColumnsToggle.tsx @@ -0,0 +1,38 @@ +import Checkbox from '@mui/material/Checkbox'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import Tooltip from '@mui/material/Tooltip'; + +import { useAppDispatch, useAppSelector } from '../../hooks/app'; +import { updateShowAdvancedColumns } from '../../reducers/ColumnPrefsSlice'; + +// Checkbox that toggles the advanced statistics columns (Cliff's Delta, CLES, +// Significance) in the results tables. Self-contained: reads/writes the +// columnPrefs Redux slice and mirrors the choice to localStorage so it +// persists across reloads. Shared by the main results controls and the +// subtests controls so the two stay in sync. +function AdvancedColumnsToggle() { + const dispatch = useAppDispatch(); + const showAdvancedColumns = useAppSelector( + (state) => state.columnPrefs.showAdvancedColumns, + ); + const onChange = (checked: boolean) => { + dispatch(updateShowAdvancedColumns(checked)); + localStorage.setItem('showAdvancedColumns', String(checked)); + }; + return ( + + onChange(e.target.checked)} + size='small' + /> + } + label='Advanced columns' + /> + + ); +} + +export default AdvancedColumnsToggle; diff --git a/src/components/CompareResults/ResultsControls.tsx b/src/components/CompareResults/ResultsControls.tsx index 103ec22cf..0d27c29e4 100644 --- a/src/components/CompareResults/ResultsControls.tsx +++ b/src/components/CompareResults/ResultsControls.tsx @@ -1,3 +1,4 @@ +import Box from '@mui/material/Box'; import Checkbox from '@mui/material/Checkbox'; import FormControl from '@mui/material/FormControl'; import FormControlLabel from '@mui/material/FormControlLabel'; @@ -5,6 +6,7 @@ import Grid from '@mui/material/Grid'; import Tooltip from '@mui/material/Tooltip'; import { style } from 'typestyle'; +import AdvancedColumnsToggle from './AdvancedColumnsToggle'; import { DownloadButton } from './DownloadButton'; import RevisionSelect from './RevisionSelect'; import SearchInput from './SearchInput'; @@ -90,25 +92,34 @@ export default function ResultsControls({ /> - + - + - - onExpandAllChange(e.target.checked)} - size='small' - /> - } - label='Expand all' - /> - + + + + onExpandAllChange(e.target.checked)} + size='small' + /> + } + label='Expand all' + /> + + ); diff --git a/src/components/CompareResults/ResultsTable.tsx b/src/components/CompareResults/ResultsTable.tsx index 3205fb5fe..8ca6a81e8 100644 --- a/src/components/CompareResults/ResultsTable.tsx +++ b/src/components/CompareResults/ResultsTable.tsx @@ -1,4 +1,4 @@ -import { Suspense, useState } from 'react'; +import { Suspense, useMemo, useState } from 'react'; import Box from '@mui/material/Box'; import CircularProgress from '@mui/material/CircularProgress'; @@ -10,6 +10,7 @@ import ResultsControls from './ResultsControls'; import TableContent from './TableContent'; import TableHeader from './TableHeader'; import { MANN_WHITNEY_U } from '../../common/constants'; +import { useAppSelector } from '../../hooks/app'; import useRawSearchParams from '../../hooks/useRawSearchParams'; import useTableFilters from '../../hooks/useTableFilters'; import useTableSort from '../../hooks/useTableSort'; @@ -35,9 +36,18 @@ export default function ResultsTable() { // This is our custom hook that updates the search params without a rerender. const [rawSearchParams, updateRawSearchParams] = useRawSearchParams(); - const columnsConfig = getColumnsConfiguration( - false, - testVersion ?? MANN_WHITNEY_U, + const showAdvancedColumns = useAppSelector( + (state) => state.columnPrefs.showAdvancedColumns, + ); + + const columnsConfig = useMemo( + () => + getColumnsConfiguration( + false, + testVersion ?? MANN_WHITNEY_U, + showAdvancedColumns, + ), + [testVersion, showAdvancedColumns], ); // This is our custom hook that manages table filters diff --git a/src/components/CompareResults/RevisionRow.tsx b/src/components/CompareResults/RevisionRow.tsx index 5a4a18f22..569107c59 100644 --- a/src/components/CompareResults/RevisionRow.tsx +++ b/src/components/CompareResults/RevisionRow.tsx @@ -12,6 +12,7 @@ import { RetriggerButton } from './Retrigger/RetriggerButton'; import RevisionRowExpandable from './RevisionRowExpandable'; import { compareView, compareOverTimeView } from '../../common/constants'; import { getStrategy } from '../../common/testVersions'; +import { useAppSelector } from '../../hooks/app'; import { useSubtestRegressionCount } from '../../hooks/useSubtestRegressionCount'; import { Strings } from '../../resources/Strings'; import { FontSize, Spacing } from '../../styles'; @@ -246,6 +247,9 @@ function RevisionRow(props: RevisionRowProps) { : baseRuns.length; const newRunsCount = replicates ? newRunsReplicates.length : newRuns.length; const strategy = getStrategy(testVersion); + const showAdvancedColumns = useAppSelector( + (state) => state.columnPrefs.showAdvancedColumns, + ); const { baseAvg: baseAvgValue, newAvg: newAvgValue } = strategy.getAvgValues(result); const [expanded, setExpanded] = useState(false); @@ -312,7 +316,7 @@ function RevisionRow(props: RevisionRowProps) { ({newApp}) )} - {strategy.renderColumns(result)} + {strategy.renderColumns(result, showAdvancedColumns)}
+ + + ); diff --git a/src/components/CompareResults/SubtestsResults/SubtestsResultsTable.tsx b/src/components/CompareResults/SubtestsResults/SubtestsResultsTable.tsx index 138c795d6..67db241ea 100644 --- a/src/components/CompareResults/SubtestsResults/SubtestsResultsTable.tsx +++ b/src/components/CompareResults/SubtestsResults/SubtestsResultsTable.tsx @@ -8,6 +8,7 @@ import SubtestsTableContent from './SubtestsTableContent'; import NoResultsFound from '.././NoResultsFound'; import TableHeader from '.././TableHeader'; import { STUDENT_T } from '../../../common/constants'; +import { useAppSelector } from '../../../hooks/app'; import useTableFilters, { filterResults } from '../../../hooks/useTableFilters'; import useTableSort, { sortResults } from '../../../hooks/useTableSort'; import type { CombinedResultsItemType } from '../../../types/state'; @@ -79,9 +80,13 @@ function SubtestsResultsTable({ replicates, testVersion, }: ResultsTableProps) { - const columnsConfiguration = getColumnsConfiguration( - true, - testVersion ?? STUDENT_T, + const showAdvancedColumns = useAppSelector( + (state) => state.columnPrefs.showAdvancedColumns, + ); + const columnsConfiguration = useMemo( + () => + getColumnsConfiguration(true, testVersion ?? STUDENT_T, showAdvancedColumns), + [testVersion, showAdvancedColumns], ); // This is our custom hook that manages table filters // and provides methods for clearing and toggling them. diff --git a/src/components/CompareResults/SubtestsResults/SubtestsRevisionRow.tsx b/src/components/CompareResults/SubtestsResults/SubtestsRevisionRow.tsx index 0529f5495..668ee17b6 100644 --- a/src/components/CompareResults/SubtestsResults/SubtestsRevisionRow.tsx +++ b/src/components/CompareResults/SubtestsResults/SubtestsRevisionRow.tsx @@ -9,6 +9,7 @@ import { style } from 'typestyle'; import RevisionRowExpandable from '.././RevisionRowExpandable'; import { MANN_WHITNEY_U } from '../../../common/constants'; import { getStrategy } from '../../../common/testVersions'; +import { useAppSelector } from '../../../hooks/app'; import { Strings } from '../../../resources/Strings'; import { Spacing } from '../../../styles'; import type { CombinedResultsItemType } from '../../../types/state'; @@ -119,6 +120,9 @@ function SubtestsRevisionRow(props: RevisionRowProps) { }; const strategy = getStrategy(testVersion ?? MANN_WHITNEY_U); + const showAdvancedColumns = useAppSelector( + (state) => state.columnPrefs.showAdvancedColumns, + ); return ( <> @@ -127,7 +131,7 @@ function SubtestsRevisionRow(props: RevisionRowProps) { sx={{ gridTemplateColumns, backgroundColor: 'revisionRow.background' }} role='row' > - {strategy.renderSubtestColumns(result, expanded)} + {strategy.renderSubtestColumns(result, expanded, showAdvancedColumns)}
) { + state.showAdvancedColumns = action.payload; + }, + }, +}); + +export const { updateShowAdvancedColumns } = columnPrefs.actions; +export default columnPrefs.reducer; diff --git a/src/utils/rowTemplateColumns.ts b/src/utils/rowTemplateColumns.ts index 1caa4d4a1..cc29f3140 100644 --- a/src/utils/rowTemplateColumns.ts +++ b/src/utils/rowTemplateColumns.ts @@ -11,6 +11,8 @@ export { export const getColumnsConfiguration = ( isSubtestTable: boolean, testVersion: TestVersion, -): TableConfig => getColumnsForVersion(testVersion, isSubtestTable); + showAdvancedColumns: boolean, +): TableConfig => + getColumnsForVersion(testVersion, isSubtestTable, showAdvancedColumns); export { toGridTemplateColumns } from './gridTemplateColumns'; From c9e027f0e8e476157f435e299013dae50304d218 Mon Sep 17 00:00:00 2001 From: Carla Severe Date: Thu, 23 Jul 2026 18:06:53 -0700 Subject: [PATCH 2/6] update tests to reflect new UI/UX --- .claude/settings.local.json | 3 +- src/__tests__/App.test.tsx | 11 +- .../CompareResults/ResultsTable.test.tsx | 370 +++-- .../CompareResults/RevisionRow.test.tsx | 18 +- .../SubtestsResultsView.test.tsx | 148 +- .../SubtestsRevisionRow.test.tsx | 18 +- .../OverTimeResultsView.test.tsx.snap | 282 +--- .../__snapshots__/ResultsTable.test.tsx.snap | 500 +++--- .../__snapshots__/ResultsView.test.tsx.snap | 296 ++-- .../SubtestsResultsView.test.tsx.snap | 1426 ++++------------- .../CompareOverTime.test.tsx.snap | 8 +- .../CompareWithBase.test.tsx.snap | 30 +- src/__tests__/utils/test-utils.tsx | 9 + .../SubtestsResults/SubtestsResultsTable.tsx | 6 +- 14 files changed, 1115 insertions(+), 2010 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index f3cdb7021..668c033d2 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -7,7 +7,8 @@ "Bash(node:*)", "Bash(tail:*)", "Bash(git add src/components/CompareResults/SubtestsResults/SubtestsRevisionRow.tsx && git rebase --continue 2>&1)", - "Bash(grep:*)" + "Bash(grep:*)", + "Bash(npx jest *)" ] } } diff --git a/src/__tests__/App.test.tsx b/src/__tests__/App.test.tsx index a418178d9..1a2bc9587 100644 --- a/src/__tests__/App.test.tsx +++ b/src/__tests__/App.test.tsx @@ -396,11 +396,12 @@ describe('App', () => { // Wait for the page to load await screen.findByText('a11yr'); - // Verify that Mann-Whitney-U specific columns are rendered - // (this indicates the testVersion defaulted to mann-whitney-u) - expect(screen.getByText('CD')).toBeInTheDocument(); - expect(screen.getByText('Sig')).toBeInTheDocument(); - expect(screen.getByText('CLES (%)')).toBeInTheDocument(); + // Verify that Mann-Whitney-U specific columns are rendered in the + // default (simplified) view — "Difference Size" and "Δ Median %" are + // unique to the Mann-Whitney strategy, so their presence indicates the + // testVersion defaulted to mann-whitney-u. + expect(screen.getByText('Difference Size')).toBeInTheDocument(); + expect(screen.getByText('Δ Median %')).toBeInTheDocument(); // Verify the Stats Test Version dropdown shows Mann-Whitney-U as selected const testVersionDropdown = screen.getByRole('combobox', { diff --git a/src/__tests__/CompareResults/ResultsTable.test.tsx b/src/__tests__/CompareResults/ResultsTable.test.tsx index c663ada1d..dae55f633 100644 --- a/src/__tests__/CompareResults/ResultsTable.test.tsx +++ b/src/__tests__/CompareResults/ResultsTable.test.tsx @@ -14,7 +14,13 @@ import getTestData, { augmentCompareMannWhitneyDataWithSeveralRevisions, augmentCompareMannWhitneyDataWithSeveralTests, } from '../utils/fixtures'; -import { renderWithRouter, screen, waitFor, within } from '../utils/test-utils'; +import { + renderWithRouter, + screen, + waitFor, + within, + enableAdvancedColumns, +} from '../utils/test-utils'; function renderWithRoute(component: ReactElement, extraParameters?: string) { return renderWithRouter(component, { @@ -48,7 +54,7 @@ function setupAndRender( // This handy function parses the results page and returns an array of visible // rows. It makes it easy to assert visible rows when filtering them in a // user-friendly way without using snapshots. -function summarizeVisibleRows(testVersion?: TestVersion) { +function summarizeVisibleRows(testVersion?: TestVersion, advanced = false) { const rowGroups = screen.getAllByRole('rowgroup'); const result = []; @@ -83,17 +89,33 @@ function summarizeVisibleRows(testVersion?: TestVersion) { for (const row of rows) { const rowClasses = testVersion === 'mann-whitney-u' - ? [ - '.platform span', - '.median-diff', - '.status', - '.delta', - '.significance', - '.effects', - ] + ? advanced + ? [ + '.platform span', + '.median-diff', + '.status', + '.delta', + '.significance', + '.effects', + ] + : [ + '.platform span', + '.median-diff', + '.status', + '.difference-size', + ] : ['.platform span', '.status', '.delta', '.confidence']; const rowString = rowClasses - .map((selector) => row.querySelector(selector)?.textContent?.trim()) + .map((selector) => { + const cell = row.querySelector(selector); + if (!cell) return undefined; + // Strip icon text (e.g. the median-diff normality warning) + // so the data-focused expectations stay stable; icon presence is + // asserted separately. + const clone = cell.cloneNode(true) as HTMLElement; + clone.querySelectorAll('svg').forEach((svg) => svg.remove()); + return clone.textContent?.trim(); + }) .join(', '); result.push(' - ' + rowString); @@ -690,6 +712,13 @@ describe('Results Table', () => { }); describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion', () => { + // These tests exercise the full (advanced) table — CD, CLES, Sig columns and + // their sort/filter behavior. The simplified default view (which hides those + // and shows Difference Size) is covered separately below. + beforeEach(() => { + enableAdvancedColumns(); + }); + it('Should match snapshot', async () => { const { testCompareMannWhitneyData } = getTestData(); @@ -719,12 +748,12 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio setupAndRender(simplerTestCompareData, 'test_version=mann-whitney-u'); await screen.findByText('a11yr'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: spam', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ' rev: devilrabbit', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ]); expect(screen.getByRole('rowgroup')).toMatchSnapshot(); }); @@ -746,25 +775,25 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); await screen.findByText('a11yr'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - inexistant, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Android, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - inexistant, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({}); const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); await clickMenuItem(user, 'Platform', /Windows/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Android, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ platform: ['osx', 'linux', 'android', 'ios'], @@ -773,78 +802,78 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio // Clicking Windows again should remove the search param and make the // "inexitant" platform visible again. await clickMenuItem(user, 'Platform', /Windows/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - inexistant, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Android, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - inexistant, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({}); await clickMenuItem(user, 'Platform', /Windows/); await clickMenuItem(user, 'Platform', /Linux/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Android, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ platform: ['osx', 'android', 'ios'], }); await clickMenuItem(user, 'Platform', /Linux/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Android, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ platform: ['osx', 'android', 'ios', 'linux'], }); await clickMenuItem(user, 'Platform', 'Select all values'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - inexistant, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Android, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - inexistant, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({}); await clickMenuItem(user, 'Platform', /macOS/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', + ' - Android, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ platform: ['windows', 'linux', 'android', 'ios'], }); await clickMenuItem(user, 'Platform', /Android/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ platform: ['windows', 'linux', 'ios'], }); await clickMenuItem(user, 'Platform', /Select only.*Android/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Android, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Android, +1.08%, Improvement, 0.1, -, 25.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ platform: ['android'], @@ -881,30 +910,30 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); await screen.findByText('a11yr'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({}); const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); await clickMenuItem(user, 'Status', /No changes/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ status: ['improvement', 'regression'], }); await clickMenuItem(user, 'Status', /Improvement/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ status: ['regression'], @@ -912,39 +941,39 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio await clickMenuItem(user, 'Status', /Select all values/); await clickMenuItem(user, 'Status', /Regression/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ status: ['none', 'improvement'], }); await clickMenuItem(user, 'Status', /Regression/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({}); await clickMenuItem(user, 'Status', /Select only.*Regression/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ status: ['regression'], }); await clickMenuItem(user, 'Status', /Select only.*Improvement/); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ]); expect(summarizeTableFiltersFromUrl()).toEqual({ status: ['improvement'], @@ -959,9 +988,9 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio ); await screen.findByText('dhtml.html'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html spam opt e10s fission stylo webrender', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ]); const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); expect(await summarizeTableFiltersFromCheckboxes(user)).toEqual({ @@ -994,29 +1023,29 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio expect(deltaButton).toMatchSnapshot(); // // Sort descending - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr aria.html opt e10s fission stylo webrender', ' rev: spam', - ' - Linux 18.04, 1.849 %, Regression, 1.2, -, 44.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 1.3, -, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 1.2, -, 44.00 %', + ' - macOS 10.15, +1.08%, Improvement, 1.3, -, 24.00 %', ' - Windows 10, -, , 1.2, , 99.00 %', - ' - Windows 10, -2.401 %, , 1.2, , 49.00 %', + ' - Windows 10, -2.40%, , 1.2, , 49.00 %', ' rev: tictactoe', - ' - Linux 18.04, 1.849 %, Regression, 2, -, 43.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 2.1, -, 23.00 %', + ' - Linux 18.04, +1.85%, Regression, 2, -, 43.00 %', + ' - macOS 10.15, +1.08%, Improvement, 2.1, -, 23.00 %', ' - Windows 10, -, , 2, , 98.00 %', - ' - Windows 10, -2.401 %, , 2, , 48.00 %', + ' - Windows 10, -2.40%, , 2, , 48.00 %', 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: spam', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', ' rev: tictactoe', - ' - Linux 18.04, 1.849 %, Regression, 0.8, -, 44.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.9, -, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 0.8, -, 44.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.9, -, 24.00 %', ' - Windows 10, -, , 0.8, , 99.00 %', - ' - Windows 10, -2.401 %, , 0.8, , 49.00 %', + ' - Windows 10, -2.40%, , 0.8, , 49.00 %', ]); // It should have the "descending" SVG. expect(deltaButton).toMatchSnapshot(); @@ -1025,28 +1054,28 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio // sort ascending await user.click(deltaButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr aria.html opt e10s fission stylo webrender', ' rev: tictactoe', - ' - macOS 10.15, 1.078 %, Improvement, 2.1, -, 23.00 %', - ' - Linux 18.04, 1.849 %, Regression, 2, -, 43.00 %', - ' - Windows 10, -2.401 %, , 2, , 48.00 %', + ' - macOS 10.15, +1.08%, Improvement, 2.1, -, 23.00 %', + ' - Linux 18.04, +1.85%, Regression, 2, -, 43.00 %', + ' - Windows 10, -2.40%, , 2, , 48.00 %', ' - Windows 10, -, , 2, , 98.00 %', ' rev: spam', - ' - macOS 10.15, 1.078 %, Improvement, 1.3, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 1.2, -, 44.00 %', - ' - Windows 10, -2.401 %, , 1.2, , 49.00 %', + ' - macOS 10.15, +1.08%, Improvement, 1.3, -, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 1.2, -, 44.00 %', + ' - Windows 10, -2.40%, , 1.2, , 49.00 %', ' - Windows 10, -, , 1.2, , 99.00 %', 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: tictactoe', - ' - macOS 10.15, 1.078 %, Improvement, 0.9, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 0.8, -, 44.00 %', - ' - Windows 10, -2.401 %, , 0.8, , 49.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.9, -, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 0.8, -, 44.00 %', + ' - Windows 10, -2.40%, , 0.8, , 49.00 %', ' - Windows 10, -, , 0.8, , 99.00 %', ' rev: spam', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', ' - Windows 10, -, , -, , 100.00 %', ]); // It should have the "ascending" SVG. @@ -1059,29 +1088,29 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio name: /Sig.*sort/, }); await user.click(significanceButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr aria.html opt e10s fission stylo webrender', ' rev: tictactoe', - ' - macOS 10.15, 1.078 %, Improvement, 2.1, -, 23.00 %', - ' - Linux 18.04, 1.849 %, Regression, 2, -, 43.00 %', + ' - macOS 10.15, +1.08%, Improvement, 2.1, -, 23.00 %', + ' - Linux 18.04, +1.85%, Regression, 2, -, 43.00 %', ' - Windows 10, -, , 2, , 98.00 %', - ' - Windows 10, -2.401 %, , 2, , 48.00 %', + ' - Windows 10, -2.40%, , 2, , 48.00 %', ' rev: spam', - ' - macOS 10.15, 1.078 %, Improvement, 1.3, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 1.2, -, 44.00 %', + ' - macOS 10.15, +1.08%, Improvement, 1.3, -, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 1.2, -, 44.00 %', ' - Windows 10, -, , 1.2, , 99.00 %', - ' - Windows 10, -2.401 %, , 1.2, , 49.00 %', + ' - Windows 10, -2.40%, , 1.2, , 49.00 %', 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: tictactoe', - ' - macOS 10.15, 1.078 %, Improvement, 0.9, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 0.8, -, 44.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.9, -, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 0.8, -, 44.00 %', ' - Windows 10, -, , 0.8, , 99.00 %', - ' - Windows 10, -2.401 %, , 0.8, , 49.00 %', + ' - Windows 10, -2.40%, , 0.8, , 49.00 %', ' rev: spam', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', ' - Windows 10, -, , -, , 100.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', ]); // It should have the "descending" SVG. expect(significanceButton).toMatchSnapshot(); @@ -1090,29 +1119,29 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio // Sort by Significance ascending await user.click(significanceButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: spam', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', ' - Windows 10, -, , -, , 100.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', ' rev: tictactoe', - ' - Windows 10, -2.401 %, , 0.8, , 49.00 %', + ' - Windows 10, -2.40%, , 0.8, , 49.00 %', ' - Windows 10, -, , 0.8, , 99.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.9, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 0.8, -, 44.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.9, -, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 0.8, -, 44.00 %', 'a11yr aria.html opt e10s fission stylo webrender', ' rev: spam', - ' - Windows 10, -2.401 %, , 1.2, , 49.00 %', + ' - Windows 10, -2.40%, , 1.2, , 49.00 %', ' - Windows 10, -, , 1.2, , 99.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 1.3, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 1.2, -, 44.00 %', + ' - macOS 10.15, +1.08%, Improvement, 1.3, -, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 1.2, -, 44.00 %', ' rev: tictactoe', - ' - Windows 10, -2.401 %, , 2, , 48.00 %', + ' - Windows 10, -2.40%, , 2, , 48.00 %', ' - Windows 10, -, , 2, , 98.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 2.1, -, 23.00 %', - ' - Linux 18.04, 1.849 %, Regression, 2, -, 43.00 %', + ' - macOS 10.15, +1.08%, Improvement, 2.1, -, 23.00 %', + ' - Linux 18.04, +1.85%, Regression, 2, -, 43.00 %', ]); // It should have the "descending" SVG. expect(significanceButton).toMatchSnapshot(); @@ -1121,32 +1150,32 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio // Sort by Effect Size (%) descending const effectSizeButton = screen.getByRole('button', { - name: /CLES \(%\).*sort/, + name: /CLES %.*sort/, }); await user.click(effectSizeButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: spam', ' - Windows 10, -, , -, , 100.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - Windows 10, -2.401 %, , -, , 50.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', ' rev: tictactoe', ' - Windows 10, -, , 0.8, , 99.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.9, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 0.8, -, 44.00 %', - ' - Windows 10, -2.401 %, , 0.8, , 49.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.9, -, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 0.8, -, 44.00 %', + ' - Windows 10, -2.40%, , 0.8, , 49.00 %', 'a11yr aria.html opt e10s fission stylo webrender', ' rev: spam', ' - Windows 10, -, , 1.2, , 99.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 1.3, -, 24.00 %', - ' - Linux 18.04, 1.849 %, Regression, 1.2, -, 44.00 %', - ' - Windows 10, -2.401 %, , 1.2, , 49.00 %', + ' - macOS 10.15, +1.08%, Improvement, 1.3, -, 24.00 %', + ' - Linux 18.04, +1.85%, Regression, 1.2, -, 44.00 %', + ' - Windows 10, -2.40%, , 1.2, , 49.00 %', ' rev: tictactoe', ' - Windows 10, -, , 2, , 98.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 2.1, -, 23.00 %', - ' - Linux 18.04, 1.849 %, Regression, 2, -, 43.00 %', - ' - Windows 10, -2.401 %, , 2, , 48.00 %', + ' - macOS 10.15, +1.08%, Improvement, 2.1, -, 23.00 %', + ' - Linux 18.04, +1.85%, Regression, 2, -, 43.00 %', + ' - Windows 10, -2.40%, , 2, , 48.00 %', ]); expect(effectSizeButton).toMatchSnapshot(); @@ -1155,46 +1184,46 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio // Sort by Effect Size (%) ascending await user.click(effectSizeButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ 'a11yr dhtml.html opt e10s fission stylo webrender', ' rev: spam', - ' - Windows 10, -2.401 %, , -, , 50.00 %', - ' - Linux 18.04, 1.849 %, Regression, -, -, 45.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.1, -, 25.00 %', + ' - Windows 10, -2.40%, , -, , 50.00 %', + ' - Linux 18.04, +1.85%, Regression, -, -, 45.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.1, -, 25.00 %', ' - Windows 10, -, , -, , 100.00 %', ' rev: tictactoe', - ' - Windows 10, -2.401 %, , 0.8, , 49.00 %', - ' - Linux 18.04, 1.849 %, Regression, 0.8, -, 44.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 0.9, -, 24.00 %', + ' - Windows 10, -2.40%, , 0.8, , 49.00 %', + ' - Linux 18.04, +1.85%, Regression, 0.8, -, 44.00 %', + ' - macOS 10.15, +1.08%, Improvement, 0.9, -, 24.00 %', ' - Windows 10, -, , 0.8, , 99.00 %', 'a11yr aria.html opt e10s fission stylo webrender', ' rev: spam', - ' - Windows 10, -2.401 %, , 1.2, , 49.00 %', - ' - Linux 18.04, 1.849 %, Regression, 1.2, -, 44.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 1.3, -, 24.00 %', + ' - Windows 10, -2.40%, , 1.2, , 49.00 %', + ' - Linux 18.04, +1.85%, Regression, 1.2, -, 44.00 %', + ' - macOS 10.15, +1.08%, Improvement, 1.3, -, 24.00 %', ' - Windows 10, -, , 1.2, , 99.00 %', ' rev: tictactoe', - ' - Windows 10, -2.401 %, , 2, , 48.00 %', - ' - Linux 18.04, 1.849 %, Regression, 2, -, 43.00 %', - ' - macOS 10.15, 1.078 %, Improvement, 2.1, -, 23.00 %', + ' - Windows 10, -2.40%, , 2, , 48.00 %', + ' - Linux 18.04, +1.85%, Regression, 2, -, 43.00 %', + ' - macOS 10.15, +1.08%, Improvement, 2.1, -, 23.00 %', ' - Windows 10, -, , 2, , 98.00 %', ]); expect(effectSizeButton).toMatchSnapshot(); // It should be persisted in the URL expectParameterToHaveValue('sort', 'effects|asc'); - // Sort by MD(%) descending + // Sort by Δ Median % descending const medianDiffButton = screen.getByRole('button', { - name: /MD \(%\).*sort/, + name: /Δ Median %.*sort/, }); await user.click(medianDiffButton); - expect(summarizeVisibleRows('mann-whitney-u')).toMatchSnapshot(); + expect(summarizeVisibleRows('mann-whitney-u', true)).toMatchSnapshot(); expect(medianDiffButton).toMatchSnapshot(); expectParameterToHaveValue('sort', 'median-diff|desc'); // Sort by MD(%) ascending await user.click(medianDiffButton); - expect(summarizeVisibleRows('mann-whitney-u')).toMatchSnapshot(); + expect(summarizeVisibleRows('mann-whitney-u', true)).toMatchSnapshot(); expect(medianDiffButton).toMatchSnapshot(); expectParameterToHaveValue('sort', 'median-diff|asc'); }); @@ -1248,3 +1277,30 @@ describe('Results Table for MannWhitneyResultsItem for mann-whitney-u testVersio }); }); }); + +describe('Advanced-columns toggle for mann-whitney-u testVersion', () => { + it('shows Difference Size and hides CD/CLES/Sig in the simplified (default) view', async () => { + const { testCompareMannWhitneyData } = getTestData(); + setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); + await screen.findByText('a11yr'); + + const header = screen.getByTestId('table-header'); + expect(header.querySelector('.difference-size-header')).toBeTruthy(); + expect(header.querySelector('.delta-header')).toBeFalsy(); + expect(header.querySelector('.effects-header')).toBeFalsy(); + expect(header.querySelector('.significance-header')).toBeFalsy(); + }); + + it('shows CD/CLES/Sig and hides Difference Size when advanced columns are enabled', async () => { + enableAdvancedColumns(); + const { testCompareMannWhitneyData } = getTestData(); + setupAndRender(testCompareMannWhitneyData, 'test_version=mann-whitney-u'); + await screen.findByText('a11yr'); + + const header = screen.getByTestId('table-header'); + expect(header.querySelector('.delta-header')).toBeTruthy(); + expect(header.querySelector('.effects-header')).toBeTruthy(); + expect(header.querySelector('.significance-header')).toBeTruthy(); + expect(header.querySelector('.difference-size-header')).toBeFalsy(); + }); +}); diff --git a/src/__tests__/CompareResults/RevisionRow.test.tsx b/src/__tests__/CompareResults/RevisionRow.test.tsx index ae86e4950..6f542eab5 100644 --- a/src/__tests__/CompareResults/RevisionRow.test.tsx +++ b/src/__tests__/CompareResults/RevisionRow.test.tsx @@ -11,7 +11,11 @@ import { useSubtestRegressionCount } from '../../hooks/useSubtestRegressionCount import { CompareResultsItem, MannWhitneyResultsItem } from '../../types/state'; import { Platform } from '../../types/types'; import getTestData from '../utils/fixtures'; -import { screen, renderWithRouter } from '../utils/test-utils'; +import { + screen, + renderWithRouter, + enableAdvancedColumns, +} from '../utils/test-utils'; jest.mock('../../hooks/useSubtestRegressionCount'); const mockUseSubtestRegressionCount = useSubtestRegressionCount as jest.Mock; @@ -427,6 +431,7 @@ describe('Expanded row', () => { }); it('should display mean for base or new in row headers for mann-whitney-u testVersion', async () => { + enableAdvancedColumns(); const { testCompareMannWhitneyData: rowData } = getTestData(); renderWithRoute( <RevisionRow @@ -541,7 +546,7 @@ describe('Expanded row', () => { }; } - it('shows dash when neither distribution is normal', async () => { + it('shows value with warning icon when neither distribution is normal', async () => { const result = makeResult(tooFewRuns, tooFewRuns); expect(isDistributionNormal(result)).toBe(false); renderWithRoute( @@ -555,7 +560,10 @@ describe('Expanded row', () => { />, ); const roles = await screen.findAllByRole('cell'); - expect(roles[4]).toHaveTextContent('-'); + // The median difference is rank-based, so it's shown even for non-normal + // data; only a warning icon flags the shape. + expect(roles[4]).toHaveTextContent('%'); + expect(roles[4].querySelector('svg[role="img"]')).toBeTruthy(); }); it('shows value with warning icon when only one distribution is normal', async () => { @@ -572,7 +580,7 @@ describe('Expanded row', () => { />, ); const roles = await screen.findAllByRole('cell'); - expect(roles[4]).not.toHaveTextContent('-'); + expect(roles[4]).toHaveTextContent('%'); expect(roles[4].querySelector('svg[role="img"]')).toBeTruthy(); }); @@ -590,7 +598,7 @@ describe('Expanded row', () => { />, ); const roles = await screen.findAllByRole('cell'); - expect(roles[4]).not.toHaveTextContent('-'); + expect(roles[4]).toHaveTextContent('%'); expect(roles[4].querySelector('svg[role="img"]')).toBeFalsy(); }); }); diff --git a/src/__tests__/CompareResults/SubtestsResultsView.test.tsx b/src/__tests__/CompareResults/SubtestsResultsView.test.tsx index 87e1b9081..522c3b35c 100644 --- a/src/__tests__/CompareResults/SubtestsResultsView.test.tsx +++ b/src/__tests__/CompareResults/SubtestsResultsView.test.tsx @@ -10,7 +10,11 @@ import type { CombinedResultsItemType } from '../../types/state'; import { TestVersion } from '../../types/types'; import { getLocationOrigin } from '../../utils/location'; import getTestData from '../utils/fixtures'; -import { renderWithRouter, screen } from '../utils/test-utils'; +import { + renderWithRouter, + screen, + enableAdvancedColumns, +} from '../utils/test-utils'; jest.mock('../../utils/location'); const mockedGetLocationOrigin = getLocationOrigin as jest.Mock; @@ -48,7 +52,7 @@ const setup = ({ // This handy function parses the results page and returns an array of visible // rows. It makes it easy to assert visible rows when filtering them in a // user-friendly way without using snapshots. -function summarizeVisibleRows(testVersion?: TestVersion) { +function summarizeVisibleRows(testVersion?: TestVersion, advanced = false) { const rows = screen.getAllByRole('row'); const result = []; for (const row of rows) { @@ -59,10 +63,19 @@ function summarizeVisibleRows(testVersion?: TestVersion) { } const rowClasses = testVersion === 'mann-whitney-u' - ? ['.median-diff', '.delta', '.significance', '.effects'] + ? advanced + ? ['.median-diff', '.delta', '.significance', '.effects'] + : ['.median-diff', '.status', '.difference-size'] : ['.delta', '.confidence']; const rowString = rowClasses - .map((selector) => row.querySelector(selector)?.textContent.trim()) + .map((selector) => { + const cell = row.querySelector(selector); + if (!cell) return undefined; + // Strip icon <title> text (e.g. the median-diff normality warning). + const clone = cell.cloneNode(true) as HTMLElement; + clone.querySelectorAll('svg').forEach((svg) => svg.remove()); + return clone.textContent?.trim(); + }) .join(', '); result.push(`${subtest}: ${rowString}`); } @@ -499,6 +512,11 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( }); describe('table sorting', () => { + // These sort by CD and Significance, which are advanced-only columns. + beforeEach(() => { + enableAdvancedColumns(); + }); + async function setupForSorting({ extraParameters, }: Partial<{ @@ -526,12 +544,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( it('can sort the table and persist the information to the URL of mann-whitney-u values', async () => { await setupForSorting(); // Initial view (alphabetical ordered, even if "sort by subtests" isn't specified - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'browser.html: +1.14%, -0.04, -, 15.00%', + 'dhtml.html: +1.14%, 0.02, , 60.00%', + 'improvement.html: +1.14%, -0.05, , 50.00%', + 'regression.html: +1.14%, 0.12, , 25.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', ]); // Sort by Delta @@ -541,12 +559,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( expect(window.location.search).not.toContain('sort='); // Sort descending await user.click(deltaButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'regression.html: +1.14%, 0.12, , 25.00%', + 'improvement.html: +1.14%, -0.05, , 50.00%', + 'browser.html: +1.14%, -0.04, -, 15.00%', + 'dhtml.html: +1.14%, 0.02, , 60.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', ]); // It should have the "descending" SVG. @@ -556,12 +574,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( // Sort ascending await user.click(deltaButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', + 'dhtml.html: +1.14%, 0.02, , 60.00%', + 'browser.html: +1.14%, -0.04, -, 15.00%', + 'improvement.html: +1.14%, -0.05, , 50.00%', + 'regression.html: +1.14%, 0.12, , 25.00%', ]); // It should have the "ascending" SVG. expect(deltaButton).toMatchSnapshot(); @@ -573,12 +591,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( name: /Sig.*sort/, }); await user.click(significanceButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'browser.html: +1.14%, -0.04, -, 15.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', + 'dhtml.html: +1.14%, 0.02, , 60.00%', + 'regression.html: +1.14%, 0.12, , 25.00%', + 'improvement.html: +1.14%, -0.05, , 50.00%', ]); // It should have the "no sort" SVG. expect(deltaButton).toMatchSnapshot(); @@ -589,26 +607,26 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( // Sort by Significance ascending await user.click(significanceButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'improvement.html: +1.14%, -0.05, , 50.00%', + 'regression.html: +1.14%, 0.12, , 25.00%', + 'dhtml.html: +1.14%, 0.02, , 60.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', + 'browser.html: +1.14%, -0.04, -, 15.00%', ]); expectParameterToHaveValue('sort', 'significance|asc'); // Sort by Effect Size descending const effectButton = screen.getByRole('button', { - name: /CLES \(%\).*sort/, + name: /CLES %.*sort/, }); await user.click(effectButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'browser.html: +1.14%, -0.04, -, 15.00%', + 'regression.html: +1.14%, 0.12, , 25.00%', + 'dhtml.html: +1.14%, 0.02, , 60.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', + 'improvement.html: +1.14%, -0.05, , 50.00%', ]); // It should have the "descending" SVG. @@ -618,12 +636,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( // Sort by Effect Size ascending await user.click(effectButton); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'improvement.html: +1.14%, -0.05, , 50.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', + 'dhtml.html: +1.14%, 0.02, , 60.00%', + 'regression.html: +1.14%, 0.12, , 25.00%', + 'browser.html: +1.14%, -0.04, -, 15.00%', ]); expectParameterToHaveValue('sort', 'effects|asc'); }); @@ -631,12 +649,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( it('initializes the sort from the URL at load time for an ascending sort', async () => { await setupForSorting({ extraParameters: 'sort=delta|asc' }); await screen.findByText('dhtml.html'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'regression.html: 1.135 %, 0.12, , 25.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', + 'dhtml.html: +1.14%, 0.02, , 60.00%', + 'browser.html: +1.14%, -0.04, -, 15.00%', + 'improvement.html: +1.14%, -0.05, , 50.00%', + 'regression.html: +1.14%, 0.12, , 25.00%', ]); // It should have the "ascending" SVG. expect(screen.getByRole('button', { name: /CD/ })).toMatchSnapshot(); @@ -645,12 +663,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( it('initializes the sort from the URL at load time for an implicit descending sort', async () => { await setupForSorting({ extraParameters: 'sort=delta' }); await screen.findByText('dhtml.html'); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'regression.html: +1.14%, 0.12, , 25.00%', + 'improvement.html: +1.14%, -0.05, , 50.00%', + 'browser.html: +1.14%, -0.04, -, 15.00%', + 'dhtml.html: +1.14%, 0.02, , 60.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', ]); // It should have the "descending" SVG. expect(screen.getByRole('button', { name: /CD/ })).toMatchSnapshot(); @@ -658,12 +676,12 @@ describe('SubtestsResultsView Component Tests for mann-whitney-u testVersion', ( it('initializes the sort from the URL at load time for a descending sort', async () => { await setupForSorting({ extraParameters: 'sort=delta|desc' }); - expect(summarizeVisibleRows('mann-whitney-u')).toEqual([ - 'regression.html: 1.135 %, 0.12, , 25.00%', - 'improvement.html: 0.963 %, -0.05, , 50.00%', - 'browser.html: 0.963 %, -0.04, -, 15.00%', - 'dhtml.html: 1.135 %, 0.02, , 60.00%', - 'tablemutation.html: 0.98 %, 0.01, -, 45.00%', + expect(summarizeVisibleRows('mann-whitney-u', true)).toEqual([ + 'regression.html: +1.14%, 0.12, , 25.00%', + 'improvement.html: +1.14%, -0.05, , 50.00%', + 'browser.html: +1.14%, -0.04, -, 15.00%', + 'dhtml.html: +1.14%, 0.02, , 60.00%', + 'tablemutation.html: +0.98%, 0.01, -, 45.00%', ]); // It should have the "descending" SVG. expect(screen.getByRole('button', { name: /CD/ })).toMatchSnapshot(); diff --git a/src/__tests__/CompareResults/SubtestsRevisionRow.test.tsx b/src/__tests__/CompareResults/SubtestsRevisionRow.test.tsx index d8941e030..f3f3fe330 100644 --- a/src/__tests__/CompareResults/SubtestsRevisionRow.test.tsx +++ b/src/__tests__/CompareResults/SubtestsRevisionRow.test.tsx @@ -7,7 +7,11 @@ import { loader } from '../../components/CompareResults/loader'; import SubtestsRevisionRow from '../../components/CompareResults/SubtestsResults/SubtestsRevisionRow'; import { MannWhitneyResultsItem } from '../../types/state'; import getTestData from '../utils/fixtures'; -import { screen, renderWithRouter } from '../utils/test-utils'; +import { + screen, + renderWithRouter, + enableAdvancedColumns, +} from '../utils/test-utils'; function renderWithRoute(component: ReactElement) { fetchMock @@ -178,6 +182,7 @@ describe('SubtestsRevisionRow Component', () => { }); it('should display cliffs delta, significance, and effects size in subtests for mann-whitney-u testVersion', async () => { + enableAdvancedColumns(); const { subtestsMannWhitneyResult } = getTestData(); const mockGridTemplateColumns = '1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr'; renderWithRoute( @@ -253,7 +258,7 @@ describe('SubtestsRevisionRow Component', () => { }; } - it('shows dash when neither distribution is normal', async () => { + it('shows value with warning icon when neither distribution is normal', async () => { renderWithRoute( <SubtestsRevisionRow result={makeResult(tooFewRuns, tooFewRuns)} @@ -263,7 +268,10 @@ describe('SubtestsRevisionRow Component', () => { />, ); const roles = await screen.findAllByRole('cell'); - expect(roles[4]).toHaveTextContent('-'); + // The median difference is rank-based, so it's shown even for non-normal + // data; only a warning icon flags the shape. + expect(roles[4]).toHaveTextContent('%'); + expect(roles[4].querySelector('svg[role="img"]')).toBeTruthy(); }); it('shows value with warning icon when only one distribution is normal', async () => { @@ -276,7 +284,7 @@ describe('SubtestsRevisionRow Component', () => { />, ); const roles = await screen.findAllByRole('cell'); - expect(roles[4]).not.toHaveTextContent('-'); + expect(roles[4]).toHaveTextContent('%'); expect(roles[4].querySelector('svg[role="img"]')).toBeTruthy(); }); @@ -290,7 +298,7 @@ describe('SubtestsRevisionRow Component', () => { />, ); const roles = await screen.findAllByRole('cell'); - expect(roles[4]).not.toHaveTextContent('-'); + expect(roles[4]).toHaveTextContent('%'); expect(roles[4].querySelector('svg[role="img"]')).toBeFalsy(); }); }); diff --git a/src/__tests__/CompareResults/__snapshots__/OverTimeResultsView.test.tsx.snap b/src/__tests__/CompareResults/__snapshots__/OverTimeResultsView.test.tsx.snap index dbd059e14..0d1a7f550 100644 --- a/src/__tests__/CompareResults/__snapshots__/OverTimeResultsView.test.tsx.snap +++ b/src/__tests__/CompareResults/__snapshots__/OverTimeResultsView.test.tsx.snap @@ -217,7 +217,7 @@ exports[`Results View The table should match snapshot and other elements should </div> </div> <div - class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-grow css-t3of1j-MuiGrid-root" + class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-grow css-vvfr7q-MuiGrid-root" > <div class="MuiBox-root css-0" @@ -295,7 +295,7 @@ exports[`Results View The table should match snapshot and other elements should </div> </div> <div - class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-grow css-t3of1j-MuiGrid-root" + class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-grow css-wautn6-MuiGrid-root" > <div class="f6hg2jo" @@ -312,41 +312,76 @@ exports[`Results View The table should match snapshot and other elements should <div class="MuiGrid-root MuiGrid-direction-xs-row MuiGrid-grid-xs-auto css-zh2j38-MuiGrid-root" > - <label - aria-label="Expand all rows" - class="MuiFormControlLabel-root MuiFormControlLabel-labelPlacementEnd css-1bsjtco-MuiFormControlLabel-root" - data-mui-internal-clone-element="true" + <div + class="MuiBox-root css-p2w42" > - <span - class="MuiButtonBase-root MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall PrivateSwitchBase-root MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall css-1nff2up-MuiButtonBase-root-MuiSwitchBase-root-MuiCheckbox-root" + <label + aria-label="Show the advanced statistics columns (Cliff’s Delta, CLES, Significance)" + class="MuiFormControlLabel-root MuiFormControlLabel-labelPlacementEnd css-1bsjtco-MuiFormControlLabel-root" + data-mui-internal-clone-element="true" > - <input - class="PrivateSwitchBase-input css-12xagqm-MuiSwitchBase-root" - data-indeterminate="false" - type="checkbox" - /> - <svg - aria-hidden="true" - class="MuiSvgIcon-root MuiSvgIcon-fontSizeSmall css-54rgmy-MuiSvgIcon-root" - data-testid="CheckBoxOutlineBlankIcon" - focusable="false" - viewBox="0 0 24 24" + <span + class="MuiButtonBase-root MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall PrivateSwitchBase-root MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall css-1nff2up-MuiButtonBase-root-MuiSwitchBase-root-MuiCheckbox-root" > - <path - d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z" + <input + class="PrivateSwitchBase-input css-12xagqm-MuiSwitchBase-root" + data-indeterminate="false" + type="checkbox" /> - </svg> - </span> - <span - class="MuiTypography-root MuiTypography-body1 MuiFormControlLabel-label css-n290n7-MuiTypography-root" + <svg + aria-hidden="true" + class="MuiSvgIcon-root MuiSvgIcon-fontSizeSmall css-54rgmy-MuiSvgIcon-root" + data-testid="CheckBoxOutlineBlankIcon" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z" + /> + </svg> + </span> + <span + class="MuiTypography-root MuiTypography-body1 MuiFormControlLabel-label css-n290n7-MuiTypography-root" + > + Advanced columns + </span> + </label> + <label + aria-label="Expand all rows" + class="MuiFormControlLabel-root MuiFormControlLabel-labelPlacementEnd css-1bsjtco-MuiFormControlLabel-root" + data-mui-internal-clone-element="true" > - Expand all - </span> - </label> + <span + class="MuiButtonBase-root MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall PrivateSwitchBase-root MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall MuiCheckbox-root MuiCheckbox-colorPrimary MuiCheckbox-sizeSmall css-1nff2up-MuiButtonBase-root-MuiSwitchBase-root-MuiCheckbox-root" + > + <input + class="PrivateSwitchBase-input css-12xagqm-MuiSwitchBase-root" + data-indeterminate="false" + type="checkbox" + /> + <svg + aria-hidden="true" + class="MuiSvgIcon-root MuiSvgIcon-fontSizeSmall css-54rgmy-MuiSvgIcon-root" + data-testid="CheckBoxOutlineBlankIcon" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z" + /> + </svg> + </span> + <span + class="MuiTypography-root MuiTypography-body1 MuiFormControlLabel-label css-n290n7-MuiTypography-root" + > + Expand all + </span> + </label> + </div> </div> </div> <div - class="fdtnfac f1l733lh" + class="f11g8g7n f1l733lh" data-testid="table-header" role="row" > @@ -417,12 +452,12 @@ exports[`Results View The table should match snapshot and other elements should role="columnheader" > <span - aria-label="Median Diff %: The percentage change in median from Base to New: ((New − Base) / Base) × 100." + aria-label="Shows how much the middle result changed from Base to New. We line up all the runs from smallest to biggest and pick the middle one for each side, then show the change as a percent. A postive sign means New is higher; a negative sign means New is lower." class="MuiBox-root css-1tkq7a4" data-mui-internal-clone-element="true" > <button - aria-label="MD (%) (Click to sort by this column)" + aria-label="Δ Median % (Click to sort by this column)" class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedTableHeaderButton MuiButton-sizeSmall MuiButton-containedSizeSmall MuiButton-colorTableHeaderButton MuiButton-disableElevation css-7upxw3-MuiButtonBase-root-MuiButton-root" tabindex="0" type="button" @@ -438,10 +473,10 @@ exports[`Results View The table should match snapshot and other elements should d="M16 17.01V10h-2v7.01h-3L15 21l4-3.99zM9 3 5 6.99h3V14h2V6.99h3z" /> <title> - Not sorted by MD (%) + Not sorted by Δ Median % - MD (%) + Δ Median %
@@ -480,47 +515,16 @@ exports[`Results View The table should match snapshot and other elements should
- - - -
-
-
-
- - -
-
- 0 % + +1.85%
- - -
-
- - -
-
- @@ -917,7 +849,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
- 0 % + +1.08%
- - -
-
- - -
-
- @@ -1116,7 +1036,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
- 0 % + -2.40%
- - -
-
- - -
-
- @@ -1315,7 +1223,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
- 0 % + -2.40%
- - -
-
- - -
-
- @@ -1514,7 +1410,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
- + + + + + + + Expand all + + +
@@ -1390,12 +1425,12 @@ exports[`Results Table Should match snapshot 1`] = ` role="columnheader" >
@@ -1453,15 +1488,16 @@ exports[`Results Table Should match snapshot 1`] = `
-
- - - -
-
-
- - -
-
- 0 % + +1.85%
- - -
-
- - -
-
- @@ -1890,7 +1822,7 @@ exports[`Results Table Should match snapshot 1`] = ` data-testid="expand-revision-button" >
- 0 % + +1.08%
- - -
-
- - -
-
- @@ -2089,7 +2009,7 @@ exports[`Results Table Should match snapshot 1`] = ` data-testid="expand-revision-button" >
- 0 % + -2.40%
- - -
-
- - -
-
- @@ -2288,7 +2196,7 @@ exports[`Results Table Should match snapshot 1`] = ` data-testid="expand-revision-button" >
- + + + + + + + Expand all + + +
@@ -4273,12 +4205,12 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion role="columnheader" >
@@ -4376,7 +4308,7 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion data-mui-internal-clone-element="true" >
@@ -4598,7 +4530,7 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion class="revision-block fw0pvlu" >
- 1.849 % + +1.85%
- 1.078 % + +1.08%
- -2.401 % + -2.40%
- 1.078 % + +1.08%
- 1.078 % + +1.08%
@@ -1635,47 +1668,16 @@ exports[`Results View The table should match snapshot and other elements should
- - - -
-
-
-
- - -
-
- 0 % + +1.85%
- - -
-
- - -
-
- @@ -2072,7 +2002,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
- 0 % + +1.08%
- - -
-
- - -
-
- @@ -2271,7 +2189,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
- 0 % + -2.40%
- - -
-
- - -
-
- @@ -2470,7 +2376,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
- 0 % + -2.40%
- - -
-
- - -
-
- @@ -2669,7 +2563,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
+
+ +
@@ -904,12 +939,12 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="columnheader" >
@@ -967,47 +1002,16 @@ exports[`SubtestsResultsView Component Tests should render the subtests results
- - - -
-
-
-
- - -
-
- 0 % + +1.14%
- - - -
-
- 0.00% -
-
- @@ -1252,7 +1183,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
- 0 % + +1.14%
- - - -
-
- 0.00% -
-
- @@ -1400,7 +1318,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
- 0 % + +1.14%
- - - -
-
- 0.00% -
-
- @@ -1548,7 +1453,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
- 0 % + +1.14%
- - - -
-
- 0.00% -
-
- @@ -1696,7 +1588,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
- 0 % + +0.98%
- - - -
-
- 0.00% -
-
- @@ -1844,7 +1723,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
+
+ +
@@ -2815,12 +2729,12 @@ exports[`SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVersi role="columnheader" >
@@ -2878,47 +2792,16 @@ exports[`SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVersi
- - - -
-
-
-
- - -
-
- 0.963 % + +1.14%
- - -0.04 -
-
- 15.00% -
-
- - + Negligible
- 1.135 % + +1.14%
- - 0.02 -
-
- 60.00% + Negligible
- -
-
@@ -3341,7 +3125,7 @@ exports[`SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVersi role="cell" >
- 0.963 % + +1.14%
- - -0.05 -
-
- 50.00% -
-
- + Negligible
- 1.135 % + +1.14%
- - 0.12 -
-
- 25.00% -
-
- + Small
- 0.98 % + +0.98%
- - 0.01 -
-
- 45.00% -
-
- - + Negligible
+
+ +
@@ -4417,12 +4171,12 @@ exports[`SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVersi role="columnheader" >
@@ -4480,47 +4234,16 @@ exports[`SubtestsViewCompareOverTime Component Tests in mann-whitney-u testVersi
- - - -
-
-
-
- - -
-
- 0.963 % + +1.14%
- - -0.04 -
-
- 15.00% -
-
- - + Negligible
- 1.135 % + +1.14%
- - 0.02 -
-
- 60.00% -
-
- + Negligible
- 0.963 % + +1.14%
- - -0.05 -
-
- 50.00% -
-
- + Negligible
- 1.135 % + +1.14%
- - 0.12 -
-
- 25.00% -
-
- + Small
- 0.98 % + +0.98%
- - 0.01 -
-
- 45.00% -
-
- - + Negligible
+
+ +
@@ -6019,12 +5613,12 @@ exports[`SubtestsViewCompareOverTime Component Tests renders over-time view when role="columnheader" >
@@ -6082,15 +5676,16 @@ exports[`SubtestsViewCompareOverTime Component Tests renders over-time view when
- - -
-
-
- - -
-
-
- @@ -6227,7 +5730,7 @@ exports[`SubtestsViewCompareOverTime Component Tests renders over-time view when />
- 0.963 % + +1.14%
- - -0.04 -
-
- 15.00% -
-
- - + Negligible
- 1.135 % + +1.14%
- - 0.02 -
-
- 60.00% -
-
- + Negligible
- 0.963 % + +1.14%
- - -0.05 -
-
- 50.00% -
-
- + Negligible
- 1.135 % + +1.14%
- - 0.12 -
-
- 25.00% -
-
- + Small
- 0.98 % + +0.98%
- - 0.01 -
-
- 45.00% -
-
- - + Negligible
+
+ +
@@ -7621,12 +7055,12 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="columnheader" >
@@ -7684,47 +7118,16 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests
- - - -
-
-
-
- - -
-
- 0 % + +1.14%
- - - -
-
- 0.00% -
-
- @@ -7969,7 +7299,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
- 0 % + +1.14%
- - - -
-
- 0.00% -
-
- @@ -8117,7 +7434,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
- 0 % + +1.14%
- - - -
-
- 0.00% -
-
- @@ -8265,7 +7569,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
- 0 % + +1.14%
- - - -
-
- 0.00% -
-
- @@ -8413,7 +7704,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
- 0 % + +0.98%
- - - -
-
- 0.00% -
-
- @@ -8561,7 +7839,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
+
+
+
+
@@ -547,22 +547,21 @@ exports[`Results View The table should match snapshot and other elements should
- - + +
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -881,7 +912,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -1068,7 +1103,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -1255,7 +1294,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -1442,7 +1485,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
@@ -1508,7 +1508,7 @@ exports[`Results Table Should match snapshot 1`] = `
@@ -1642,22 +1642,21 @@ exports[`Results Table Should match snapshot 1`] = `
- - + +
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -1976,7 +2007,7 @@ exports[`Results Table Should match snapshot 1`] = ` data-testid="expand-revision-button" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -2163,7 +2198,7 @@ exports[`Results Table Should match snapshot 1`] = ` data-testid="expand-revision-button" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -2350,7 +2389,7 @@ exports[`Results Table Should match snapshot 1`] = ` data-testid="expand-revision-button" >
@@ -4080,7 +4123,7 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion aria-invalid="false" aria-label="Search by title, platform, revision or options" class="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputSizeSmall MuiInputBase-inputAdornedStart MuiInputBase-inputAdornedEnd css-3v3un6-MuiInputBase-input-MuiOutlinedInput-input" - id="_r_rg_" + id="_r_ri_" placeholder="Filter results" type="search" value="" @@ -4901,20 +4944,29 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion role="cell" >
- - Regression + + Regression +
+ + Negligible +
- - + Noise
- - + Noise
- - + Noise
- - + Noise
- - + +
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -2034,7 +2065,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -2221,7 +2256,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -2408,7 +2447,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -2595,7 +2638,7 @@ exports[`Results View The table should match snapshot and other elements should data-testid="expand-revision-button" >
- - + +
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -1183,7 +1214,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -1318,7 +1353,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -1453,7 +1492,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -1588,7 +1631,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -1723,7 +1770,7 @@ exports[`SubtestsResultsView Component Tests should render the subtests results role="cell" >
- - + +
+ class="MuiBox-root css-j0pheo" + > +
+ + Negligible + +
- Negligible + Noise
- - Regression + + Regression +
+ + Negligible +
- Negligible + Real
+ class="MuiBox-root css-j0pheo" + > +
+ + Negligible + +
- Negligible + Real
+ class="MuiBox-root css-j0pheo" + > +
+ + Small + +
- Small + Real
- - Improvement + + Improvement +
+ + Negligible +
- Negligible + -
- - + +
+ class="MuiBox-root css-j0pheo" + > +
+ + Negligible + +
- Negligible + Noise
- - Regression + + Regression +
+ + Negligible +
- Negligible + Real
+ class="MuiBox-root css-j0pheo" + > +
+ + Negligible + +
- Negligible + Real
+ class="MuiBox-root css-j0pheo" + > +
+ + Small + +
- Small + Real
- - Improvement + + Improvement +
+ + Negligible +
- Negligible + -
- - + +
+ class="MuiBox-root css-j0pheo" + > +
+ + Negligible + +
- Negligible + Noise
- - Regression + + Regression +
+ + Negligible +
- Negligible + Real
+ class="MuiBox-root css-j0pheo" + > +
+ + Negligible + +
- Negligible + Real
+ class="MuiBox-root css-j0pheo" + > +
+ + Small + +
- Small + Real
- - Improvement + + Improvement +
+ + Negligible +
- Negligible + -
- - + +
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -7299,7 +7593,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -7434,7 +7732,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -7569,7 +7871,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -7704,7 +8010,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
+ class="MuiBox-root css-j0pheo" + > +
+
- @@ -7839,7 +8149,7 @@ exports[`SubtestsViewCompareOverTime Component Tests should render the subtests role="cell" >
{renderMedianDiffCell(result as MannWhitneyResultsItem)} - {renderStatusCell(direction_of_change)} - {!showAdvancedColumns && - renderDifferenceSizeCell(cliffs_interpretation)} + {renderStatusCell(direction_of_change, cliffs_interpretation)} {showAdvancedColumns && ( <>
@@ -483,15 +463,15 @@ export const mannWhitneyStrategy = {
{clesVal ? `${clesVal}% ` : '-'}
-
- {mann_whitney_test?.interpretation === 'significant' ? ( - - ) : ( - '-' - )} -
)} +
+ {mann_whitney_test?.interpretation === 'significant' + ? 'Real' + : mann_whitney_test?.interpretation === 'not significant' + ? 'Noise' + : '-'} +
); }, @@ -608,9 +588,7 @@ export const mannWhitneyStrategy = { return ( <> {renderMedianDiffCell(mwResult)} - {renderStatusCell(direction_of_change)} - {!showAdvancedColumns && - renderDifferenceSizeCell(cliffs_interpretation)} + {renderStatusCell(direction_of_change, cliffs_interpretation)} {showAdvancedColumns && ( <>
@@ -619,15 +597,15 @@ export const mannWhitneyStrategy = {
{clesValue}
-
- {mann_whitney_test?.interpretation === 'significant' ? ( - - ) : ( - '-' - )} -
)} +
+ {mann_whitney_test?.interpretation === 'significant' + ? 'Real' + : mann_whitney_test?.interpretation === 'not significant' + ? 'Noise' + : '-'} +
); }, diff --git a/src/components/CompareResults/HowToReadResults.tsx b/src/components/CompareResults/HowToReadResults.tsx index fc8b98a80..c97fe6391 100644 --- a/src/components/CompareResults/HowToReadResults.tsx +++ b/src/components/CompareResults/HowToReadResults.tsx @@ -47,15 +47,16 @@ function HowToReadResults() {
  • Status says whether the change is an{' '} Improvement, a Regression, or{' '} - No change. + No change — with the size of the difference + (negligible, small, medium, or large) shown beneath it.
  • - Difference Size says how big the difference is: - negligible, small, medium, or large. + Sig shows whether the difference is statistically + significant (an arrow) or not (a dash).
  • Tick Advanced columns to add the expert stats - (Cliff's Delta, CLES, Significance). + (Cliff's Delta and CLES).
  • From 0ee7631cb7090d8c81137d2d7315d26663dc9c56 Mon Sep 17 00:00:00 2001 From: Carla Severe Date: Fri, 24 Jul 2026 16:54:33 -0700 Subject: [PATCH 6/6] update how to read the results --- .../__snapshots__/ResultsTable.test.tsx.snap | 24 +++++++++++++++---- .../CompareResults/HowToReadResults.tsx | 5 ++-- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/__tests__/CompareResults/__snapshots__/ResultsTable.test.tsx.snap b/src/__tests__/CompareResults/__snapshots__/ResultsTable.test.tsx.snap index 21132c962..3cc7f4df5 100644 --- a/src/__tests__/CompareResults/__snapshots__/ResultsTable.test.tsx.snap +++ b/src/__tests__/CompareResults/__snapshots__/ResultsTable.test.tsx.snap @@ -1059,9 +1059,17 @@ exports[`Results Table Should match snapshot 1`] = `
  • - Sig + Significance - shows whether the difference is statistically significant (an arrow) or not (a dash). + tells you whether the difference is likely a + + Real + + change or just + + Noise + + (random run-to-run variation).
  • Tick @@ -4035,9 +4043,17 @@ exports[`Results Table for MannWhitneyResultsItem for mann-whitney-u testVersion
  • - Sig + Significance + + tells you whether the difference is likely a + + Real + + change or just + + Noise - shows whether the difference is statistically significant (an arrow) or not (a dash). + (random run-to-run variation).
  • Tick diff --git a/src/components/CompareResults/HowToReadResults.tsx b/src/components/CompareResults/HowToReadResults.tsx index c97fe6391..7a79914b7 100644 --- a/src/components/CompareResults/HowToReadResults.tsx +++ b/src/components/CompareResults/HowToReadResults.tsx @@ -51,8 +51,9 @@ function HowToReadResults() { (negligible, small, medium, or large) shown beneath it.
  • - Sig shows whether the difference is statistically - significant (an arrow) or not (a dash). + Significance tells you whether the difference is + likely a Real change or just Noise + (random run-to-run variation).
  • Tick Advanced columns to add the expert stats