Skip to content

10.0.283: 97.1% line coverage, 3,592 tests, and the fixes they led to

Latest

Choose a tag to compare

@davidnmbond davidnmbond released this 29 Sep 22:35
· 272 commits to main since this release
cfc3f9f

Code coverage

10.0.236 (before) 10.0.283
Line coverage 19.3% (3,655 / 18,929) 97.1% (18,596 / 19,149)
Branch coverage 12.7% 89.5%
Tests 497 3,592
Components at 100% line coverage 61 of 113
Components at 95% or more 106 of 113
Components at 90% or more 111 of 113
Code units at 100% (components, models, services, extensions) 212 of 272

Measured on the release commit cfc3f9fe with Microsoft.Testing.Extensions.CodeCoverage (cobertura), for the PanoramicData.Blazor assembly only. The suite passes on Windows and on Linux (Ubuntu, TZ=Etc/UTC), with 0 build warnings.

The two components below 90% are PDFormFieldEditor (76%: its Monaco editor paths only run with a live BlazorMonaco editor model) and PDDateTime (85%: the remaining lines are catch blocks around TryParseExact, which cannot throw). Elsewhere, uncovered lines are mostly catch blocks around JS interop teardown and guards the UI makes unreachable.

What changed

  • bUnit tests for every component (#154, PR #196), written to test behaviour and to pass reliably under load: every bUnit event is awaited, and timer-driven waits have explicit timeouts.
  • Fixes for the defects those tests found, one PR per component group (#205, #207 to #210, #212 to #215, #217, #220), plus the refresh-selection work released in 10.0.236 (#151, #152). Each fix has a regression test that failed before it.

Compatibility

No breaking changes. No public or protected member was removed or had its signature changed (checked against 10.0.239 from the generated XML documentation). Public additions are optional: PDDropDown.ExceptionHandler, FileExplorerPreviewProvider's HttpClient constructor and property, PDCardDeckLoadingIcon.Clock, IAsyncDisposable on PDCardDeck and PDResizePane, and a protected PDComponentBase.HasDefaultId.

Where a correct fix would have changed what existing pages show, it was made opt-in or compatible, and each PR's "Compatibility" section lists what a consumer sees. The ones most worth knowing:

  • PDColorPicker: ColorPickerOptions.DefaultMode is honoured only when set explicitly; pickers that do not set it still open in RGB.
  • PDMixingDesk: MinHeight is applied only when set explicitly; existing desks keep their height.
  • PDToggleSwitch: the width no longer jumps backwards around the text-width threshold; a switch with very short text can be a few pixels narrower.
  • PDForm.GetField returns null for an unknown name, as its documentation always said, instead of throwing.
  • PDDropDown and PDContextMenu now log (and, for PDDropDown, pass to ExceptionHandler) errors they used to swallow; nothing new propagates.
  • PDTable: an empty SortCriteria key no longer silently sorts by the first empty-titled column (#211); a survey of Magic Suite's 129 tables found none whose order changes.
  • Date filters in DataProviderBase no longer shift by the server's UTC offset (#193), and US dates without a time zone now parse (#197).

Issues closed (56)

  • #151 PDTable: RefreshAsync clears the selection and raises SelectionChanged on every refresh
  • #152 PDTree: RefreshAsync collapses the selected path, re-raises SelectionChange, and does nothing when nothing is selected
  • #154 bUnit tests for every component, aiming for full coverage
  • #155 PDTiles: empty Logos throws, culture-dependent connector points, Tiles changes ignored, #FFF colour throws
  • #156 PDGlobalListener: DotNetObjectReference is never disposed
  • #157 PDStackedBar: tooltip throws IndexOutOfRangeException when there are more series than values
  • #158 PDSection: Id parameter overwritten, aria-expanded wrong, Collapse/Expand/Toggle do not re-render
  • #159 PDComponentBase: generated Ids race on the static Sequence (PDGraphViewer, PDGraphControls, PDGraphInfo)
  • #160 PDGraphControls: mutates the caller's AvailableDimensions list
  • #161 PDTimeline: SetSelection moves an early start to the end, PanTo(Start) ignores the date, disabled timeline still pans
  • #162 TimelineScale.IsMajorTick: Seconds and Milliseconds rules look swapped
  • #163 PDResizePane: resizing appears to do nothing (JS module never imported)
  • #164 PDMixingDesk ignores CssClass and MinHeight
  • #165 PDToolbarLinkButton ignores TextCssClass
  • #166 PDAudioPad: Linear decay never reports its final inactive event when throttled
  • #167 PDFormFieldEditor: a nullable numeric field cannot be cleared or set to null
  • #168 PDDashboard: dragging tiles does nothing when edit mode comes from the built-in edit button
  • #169 PDDateTime: custom DateFormat is displayed in the current culture but parsed in the invariant culture
  • #170 ShortcutKey.IsMatch: a shortcut with an empty Code matches any key event with an empty Code
  • #171 ReflectionExtensions.GetPropertyMemberInfo throws for non-member selectors, so a computed PDColumn Field crashes
  • #172 PDColumnConfig.Title never reaches the column header
  • #173 PDZoomBar: zooming out from a value that is not a step jumps to the smallest step
  • #174 PDFileExplorer: PreviewProvider ignored, table drops ignore CanAddItems, case-only tree rename refused, preview details and downloads wrong
  • #175 PDCardDeck: a standalone deck (outside a group) never shows its cards
  • #176 PDStudio: status stays "Cancelling..." after a cancel completes
  • #177 PDColorPicker: ColorPickerOptions.DefaultMode is ignored
  • #178 PDSplitter: GutterAlign is not passed to split.js
  • #179 PDRange: handles and ticks are drawn in the wrong place when Min is not 0
  • #180 PDToolbarDropdown: disabled menu items still fire their click
  • #181 PDList: a saved selection restores only its first item when there is no ItemKeyFunction
  • #182 PDForm: GetField throws for an unknown name instead of returning null
  • #183 PDTree: expanding a node from code does not re-render
  • #184 PDDropZone: CancelAsync, ClearAsync and dispose pass the bare Id, so the JS finds nothing
  • #185 PDFormMessage: a labelled scale reports the label instead of the chosen number
  • #186 PDContextMenu: first right-click opens no menu; missing popper.js error is swallowed
  • #187 PDGraph: an async data provider crashes the component; spinner never stops without a provider
  • #188 PDToggleSwitch: CalculatedWidth jumps backwards around the text-width threshold
  • #189 PDQuestVisualizer: cyclic prerequisites overflow the stack
  • #190 PDChat: adding a canvas tab throws; typing indicator marks unread; background tab unread marker lags
  • #191 PDFileModal: ShowOpenAsync(folderSelect: true) still lists files when already at the root
  • #192 PDTagInput: a null Values from the parent does not clear the tags
  • #193 DataProviderBase: date filters shift by the machine's UTC offset
  • #194 DefaultDescriptionProvider: Math.Truncate never gets its description (stray bracket in key)
  • #195 PDCardDeckLoadingIcon: disposed during its start-up delay, it starts a timer loop that never stops
  • #197 Filter: US dates without a time zone never parse (MM/yy/yyyy typo); year, month and hour precision can never be detected
  • #198 PDDropDown: exceptions thrown by the consumer's DropDownShown, DropDownHidden and KeyPress callbacks are silently swallowed
  • #199 ReflectionExtensions.GetFriendlyTypeName: arrays are not given friendly names; unreachable generic arm
  • #200 Dead code found by the coverage work
  • #201 PDDateTimeOffset: on Linux with Etc/UTC the time-zone dropdown selects nothing, so it shows the wrong zone
  • #202 PDTextArea with DebounceWait wipes the user's typing when the parent re-renders before the debounce fires
  • #204 Demo site: the PDCardDeck page never finishes loading (all four examples stuck on Loading Data...)
  • #206 PDTimeline JS: four event listeners leak on every dispose, disposed timelines stay in the map, setData calls a missing method
  • #211 PDTable: the default empty SortCriteria key matches any column with an empty title, so the table silently sorts by it
  • #216 PDCardDeck JS: document-level drop/drag/mouse listeners are never removed, so disposed decks keep handling every drop
  • #218 PDChatConversationSidebar: a superseded search whose debounce already elapsed still clears the list and queries the store
  • #219 PDAudioPad: a decay superseded by a new press can reset the value to the minimum and report inactive while the new decay runs
Line coverage by component (before, after)
Component Lines 10.0.236 10.0.283
PDAnimation 58 0% 100%
PDAudioButton 12 0% 91.7%
PDAudioChannel 48 0% 100%
PDAudioControl 78 0% 98.7%
PDAudioPad 106 0% 99.1%
PDBlockOverlay 20 0% 100%
PDBusyOverlay 6 0% 100%
PDButton 64 0% 100%
PDCanvas 4 0% 100%
PDCard 49 0% 100%
PDCardDeck 201 0% 95.5%
PDCardDeckGroup 105 0% 92.4%
PDCardDeckLoadingIcon 31 0% 96.8%
PDChat 606 21.1% 95.9%
PDChatContainer 16 0% 100%
PDChatConversationSidebar 96 64.5% 99%
PDCheckboxTree 29 0% 100%
PDClickableImage 7 0% 100%
PDClipboard 19 0% 100%
PDColorPicker 276 43.4% 97.5%
PDColumn 159 40.3% 100%
PDColumnConfig 1 0% 100%
PDColumnGroup 9 0% 100%
PDColumnGrouper 40 0% 100%
PDComboBox 184 0% 98.4%
PDComponentBase 44 0% 95.5%
PDConfirm 68 0% 95.6%
PDContextMenu 60 0% 95%
PDDashboard 452 0% 98.2%
PDDateTime 41 0% 85.4%
PDDateTimeOffset 136 0% 92.6%
PDDragContainer 7 0% 100%
PDDragContext 1 0% 100%
PDDragDropSeparator 8 0% 100%
PDDragPanel 44 0% 100%
PDDropDown 119 0% 96.6%
PDDropZone 132 0% 97%
PDFader 41 0% 100%
PDField 29 0% 100%
PDFileExplorer 1060 0% 98.3%
PDFileModal 193 0% 96.4%
PDFilePreview 23 0% 100%
PDFilter 186 0% 97.8%
PDFlag 2 0% 100%
PDForm 335 0% 95.2%
PDFormBody 159 0% 97.5%
PDFormCheckBox 15 0% 100%
PDFormFieldEditor 221 0% 76%
PDFormFooter 77 0% 100%
PDFormHeader 32 0% 100%
PDFormMessage 242 0% 98.3%
PDGlobalListener 33 0% 100%
PDGraph 389 0% 98.5%
PDGraphControls 46 0% 100%
PDGraphInfo 60 0% 100%
PDGraphSelectionInfo 29 0% 100%
PDGraphViewer 87 0% 100%
PDImage 7 0% 100%
PDKnob 104 0% 100%
PDLabel 32 0% 100%
PDLinkButton 56 0% 96.4%
PDList 177 0% 97.7%
PDLocalStorageStateManager 39 0% 100%
PDLog 88 0% 97.7%
PDMenuItem 7 0% 100%
PDMessage 329 0% 100%
PDMessages 78 69.2% 97.4%
PDMixingDesk 7 0% 100%
PDModal 128 0% 100%
PDModalBase 15 0% 100%
PDMonacoEditor 116 0% 98.3%
PDNavLink 69 0% 97.1%
PDPager 43 0% 100%
PDProgressBar 7 0% 100%
PDQuestVisualizer 67 0% 100%
PDRange 122 0% 95.9%
PDResizePane 31 0% 100%
PDSection 79 0% 100%
PDSplitPanel 7 0% 100%
PDSplitter 57 0% 100%
PDStackedBar 36 0% 100%
PDStatusCascade 82 0% 98.8%
PDStatusRollUp 100 56% 96%
PDStudio 335 0% 98.5%
PDStudioResults 131 0% 96.9%
PDTab 23 94.1% 100%
PDTable 1530 72% 99.2%
PDTableColumnSelector 48 0% 100%
PDTabSet 120 31.9% 100%
PDTagInput 156 0% 98.7%
PDTextArea 98 0% 98%
PDTextBox 92 0% 97.8%
PDTiles 1367 0% 99.8%
PDTilesJavaScript 142 0% 95.1%
PDTimeline 676 2.7% 98.1%
PDTimelineToolbar 39 0% 97.4%
PDToggleSwitch 106 0% 94.3%
PDToolbar 12 0% 100%
PDToolbarButton 28 0% 100%
PDToolbarDropdown 70 0% 100%
PDToolbarLinkButton 26 0% 100%
PDToolbarPlaceholder 4 0% 100%
PDToolbarSeparator 15 0% 100%
PDToolbarTextbox 33 0% 100%
PDTree 353 54.9% 98%
PDTreeMap 249 0% 93.2%
PDTreeNode 68 35.3% 95.6%
PDValidationSummary 4 0% 100%
PDVoiceListener 90 0% 96.7%
PDWidget 277 0% 99.3%
PDWizard 127 0% 98.4%
PDWizardStep 7 0% 100%
PDZoomBar 51 0% 100%