<?xml version="1.0" encoding="UTF-8"?>
<testsuites name="bun test" tests="358" assertions="3084" failures="0" skipped="0" time="14.376496097">
  <testsuite name="test/storage.test.ts" file="test/storage.test.ts" tests="7" assertions="8" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="readFilters / writeFilters" file="test/storage.test.ts" line="49" tests="7" assertions="8" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="round-trips whatever was last written" classname="readFilters / writeFilters" time="0.000241" file="test/storage.test.ts" line="50" assertions="1" />
      <testcase name="defaults the advanced fields to empty when reading a value stored before #8 added them" classname="readFilters / writeFilters" time="0.000047" file="test/storage.test.ts" line="63" assertions="1" />
      <testcase name="returns null when nothing has been stored yet" classname="readFilters / writeFilters" time="0.000023" file="test/storage.test.ts" line="75" assertions="1" />
      <testcase name="ignores a value that isn&apos;t valid JSON" classname="readFilters / writeFilters" time="0.000085" file="test/storage.test.ts" line="81" assertions="1" />
      <testcase name="ignores a value shaped wrong, such as an unknown cut" classname="readFilters / writeFilters" time="0.000033" file="test/storage.test.ts" line="89" assertions="1" />
      <testcase name="ignores a value whose pileQuery isn&apos;t a string" classname="readFilters / writeFilters" time="0.000028" file="test/storage.test.ts" line="97" assertions="1" />
      <testcase name="degrades to not remembering when storage itself throws" classname="readFilters / writeFilters" time="0.000135" file="test/storage.test.ts" line="105" assertions="2" />
    </testsuite>
  </testsuite>
  <testsuite name="test/config-source.test.ts" file="test/config-source.test.ts" tests="2" assertions="34" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="configSourceFor" file="test/config-source.test.ts" line="15" tests="2" assertions="34" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="returns the matching locale&apos;s own bundled source, not a shared fallback" classname="configSourceFor" time="0.00008" file="test/config-source.test.ts" line="16" assertions="11" />
      <testcase name="every locale&apos;s source is real, non-empty JSON, and distinct from at least one other locale" classname="configSourceFor" time="0.000676" file="test/config-source.test.ts" line="30" assertions="23" />
    </testsuite>
  </testsuite>
  <testsuite name="test/sheet-render.test.ts" file="test/sheet-render.test.ts" tests="19" assertions="31" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="Sheet" file="test/sheet-render.test.ts" line="26" tests="14" assertions="26" failures="0" skipped="0" time="0.024" hostname="runnervmtai0g">
      <testcase name="renders real markup for the full cut, not an embedded PDF" classname="Sheet" time="0.011284" file="test/sheet-render.test.ts" line="28" assertions="3" />
      <testcase name="renders one card per group of the full cut" classname="Sheet" time="0.00353" file="test/sheet-render.test.ts" line="36" assertions="1" />
      <testcase name="draws a dial for the legend and every card on the full cut" classname="Sheet" time="0.002537" file="test/sheet-render.test.ts" line="43" assertions="1" />
      <testcase name="renders real markup for the wash cut, not an embedded PDF" classname="Sheet" time="0.00143" file="test/sheet-render.test.ts" line="28" assertions="3" />
      <testcase name="renders one card per group of the wash cut" classname="Sheet" time="0.001179" file="test/sheet-render.test.ts" line="36" assertions="1" />
      <testcase name="draws a dial for the legend and every card on the wash cut" classname="Sheet" time="0.001163" file="test/sheet-render.test.ts" line="43" assertions="1" />
      <testcase name="renders real markup for the iron cut, not an embedded PDF" classname="Sheet" time="0.000805" file="test/sheet-render.test.ts" line="28" assertions="3" />
      <testcase name="renders one card per group of the iron cut" classname="Sheet" time="0.000471" file="test/sheet-render.test.ts" line="36" assertions="1" />
      <testcase name="draws a dial for the legend and every card on the iron cut" classname="Sheet" time="0.000362" file="test/sheet-render.test.ts" line="43" assertions="1" />
      <testcase name="the ironing cut has no softener badge — that&apos;s a washing-machine concern" classname="Sheet" time="0.000449" file="test/sheet-render.test.ts" line="55" assertions="1" />
      <testcase name="the washing cut drops the per-card iron section the full cut has" classname="Sheet" time="0.004064" file="test/sheet-render.test.ts" line="59" assertions="2" />
      <testcase name="a chart with nothing to iron still renders under the full cut" classname="Sheet" time="0.00168" file="test/sheet-render.test.ts" line="67" assertions="1" />
      <testcase name="a cited row shows its source as a safe off-site link" classname="Sheet" time="0.000395" file="test/sheet-render.test.ts" line="75" assertions="5" />
      <testcase name="no row citing a source means no SOURCE field at all" classname="Sheet" time="0.000285" file="test/sheet-render.test.ts" line="91" assertions="2" />
    </testsuite>
    <testsuite name="sheetGroups" file="test/sheet-render.test.ts" line="99" tests="3" assertions="3" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="full cut groups the same way cardGroups does" classname="sheetGroups" time="0.000207" file="test/sheet-render.test.ts" line="100" assertions="1" />
      <testcase name="wash cut groups the same way washGroups does" classname="sheetGroups" time="0.000154" file="test/sheet-render.test.ts" line="109" assertions="1" />
      <testcase name="iron cut groups the same way ironGroups does" classname="sheetGroups" time="0.000132" file="test/sheet-render.test.ts" line="118" assertions="1" />
    </testsuite>
    <testsuite name="ironCardKey" file="test/sheet-render.test.ts" line="131" tests="2" assertions="2" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="keys an ironed pile by its thermostat setting" classname="ironCardKey" time="0.000067" file="test/sheet-render.test.ts" line="132" assertions="1" />
      <testcase name="keys every never-ironed pile the same way, regardless of its own fields" classname="ironCardKey" time="0.000043" file="test/sheet-render.test.ts" line="139" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/section-heading-svelte.test.ts" file="test/section-heading-svelte.test.ts" tests="2" assertions="3" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="SectionHeading (Svelte)" file="test/section-heading-svelte.test.ts" line="5" tests="2" assertions="3" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="renders the exact markup a card&apos;s uppercase label needs" classname="SectionHeading (Svelte)" time="0.000153" file="test/section-heading-svelte.test.ts" line="6" assertions="1" />
      <testcase name="uppercases every character, not just the first" classname="SectionHeading (Svelte)" time="0.000122" file="test/section-heading-svelte.test.ts" line="20" assertions="2" />
    </testsuite>
  </testsuite>
  <testsuite name="test/sheet-actions.test.ts" file="test/sheet-actions.test.ts" tests="12" assertions="30" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="CardActions" file="test/sheet-actions.test.ts" line="159" tests="12" assertions="30" failures="0" skipped="0" time="2.303" hostname="runnervmtai0g">
      <testcase name="starts idle: no dropped-chars, error, or share-status message before any click" classname="CardActions" time="0.054969" file="test/sheet-actions.test.ts" line="160" assertions="5" />
      <testcase name="starting a new download immediately clears a previous one&apos;s dropped-chars message" classname="CardActions" time="0.023767" file="test/sheet-actions.test.ts" line="177" assertions="2" />
      <testcase name="copying the link swaps the label to Copied!, then reverts after the delay" classname="CardActions" time="2.117219" file="test/sheet-actions.test.ts" line="200" assertions="5" />
      <testcase name="a failed share shows the couldNotCopyLink message with the reason" classname="CardActions" time="0.015148" file="test/sheet-actions.test.ts" line="219" assertions="2" />
      <testcase name="a non-Error share rejection is stringified, not swallowed" classname="CardActions" time="0.01256" file="test/sheet-actions.test.ts" line="235" assertions="1" />
      <testcase name="downloading shows Preparing… and disables the button until the promise settles" classname="CardActions" time="0.017745" file="test/sheet-actions.test.ts" line="247" assertions="5" />
      <testcase name="reports characters the PDF renderer had to drop" classname="CardActions" time="0.011445" file="test/sheet-actions.test.ts" line="268" assertions="1" />
      <testcase name="a successful download after a previous failure clears the old error" classname="CardActions" time="0.01389" file="test/sheet-actions.test.ts" line="280" assertions="2" />
      <testcase name="a non-Error download rejection is stringified, not swallowed" classname="CardActions" time="0.011016" file="test/sheet-actions.test.ts" line="301" assertions="1" />
      <testcase name="no actions row at all when the card has no download/share callbacks" classname="CardActions" time="0.010366" file="test/sheet-actions.test.ts" line="313" assertions="2" />
      <testcase name="no actions row when only onDownloadCard is provided" classname="CardActions" time="0.010858" file="test/sheet-actions.test.ts" line="320" assertions="2" />
      <testcase name="no actions row when only onShareCard is provided" classname="CardActions" time="0.010937" file="test/sheet-actions.test.ts" line="326" assertions="2" />
    </testsuite>
  </testsuite>
  <testsuite name="test/sheet-fields.test.ts" file="test/sheet-fields.test.ts" tests="60" assertions="137" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="Masthead" file="test/sheet-fields.test.ts" line="313" tests="1" assertions="5" failures="0" skipped="0" time="0.008" hostname="runnervmtai0g">
      <testcase name="shows its own fixed heading, the right subtitle for each cut, and the machine&apos;s own names" classname="Masthead" time="0.008605" file="test/sheet-fields.test.ts" line="314" assertions="5" />
    </testsuite>
    <testsuite name="Loads" file="test/sheet-fields.test.ts" line="323" tests="3" assertions="17" failures="0" skipped="0" time="0.005" hostname="runnervmtai0g">
      <testcase name="explains what the TOGETHER badge means, and only shows it for a shared load" classname="Loads" time="0.002075" file="test/sheet-fields.test.ts" line="324" assertions="4" />
      <testcase name="each row shows its own programme, formatted temperature and total duration" classname="Loads" time="0.002044" file="test/sheet-fields.test.ts" line="341" assertions="2" />
      <testcase name="every load row but the last has a bottom border" classname="Loads" time="0.001565" file="test/sheet-fields.test.ts" line="353" assertions="11" />
    </testsuite>
    <testsuite name="Legend" file="test/sheet-fields.test.ts" line="370" tests="6" assertions="13" failures="0" skipped="0" time="0.007" hostname="runnervmtai0g">
      <testcase name="falls back to the only programme as its own example when there&apos;s just one" classname="Legend" time="0.001811" file="test/sheet-fields.test.ts" line="371" assertions="1" />
      <testcase name="the wash cut draws the second programme as the example, and the full cut&apos;s extra suffix" classname="Legend" time="0.003505" file="test/sheet-fields.test.ts" line="384" assertions="5" />
      <testcase name="the iron cut draws the hottest setting and its own caption/explain text" classname="Legend" time="0.000537" file="test/sheet-fields.test.ts" line="401" assertions="3" />
      <testcase name="draws the programme dial on the second programme specifically, not the first" classname="Legend" time="0.001703" file="test/sheet-fields.test.ts" line="409" assertions="1" />
      <testcase name="draws the thermostat dial on the machine&apos;s own hottest (last) setting" classname="Legend" time="0.000806" file="test/sheet-fields.test.ts" line="421" assertions="1" />
      <testcase name="falls back to empty strings rather than crashing on an empty programs/settings list" classname="Legend" time="0.002735" file="test/sheet-fields.test.ts" line="426" assertions="2" />
    </testsuite>
    <testsuite name="Card wash-together field" file="test/sheet-fields.test.ts" line="454" tests="5" assertions="5" failures="0" skipped="0" time="0.005" hostname="runnervmtai0g">
      <testcase name="two piles that can mix, with no one else invited" classname="Card wash-together field" time="0.001411" file="test/sheet-fields.test.ts" line="455" assertions="1" />
      <testcase name="two piles that can mix, plus who else could join them, joined by &apos;, &apos;" classname="Card wash-together field" time="0.00124" file="test/sheet-fields.test.ts" line="460" assertions="1" />
      <testcase name="two piles that share a card but can&apos;t actually mix" classname="Card wash-together field" time="0.001767" file="test/sheet-fields.test.ts" line="467" assertions="1" />
      <testcase name="a solo pile names who it could join, when it isn&apos;t alone in the chart" classname="Card wash-together field" time="0.001673" file="test/sheet-fields.test.ts" line="472" assertions="1" />
      <testcase name="a solo pile that can&apos;t mix with anything says so plainly" classname="Card wash-together field" time="0.001526" file="test/sheet-fields.test.ts" line="477" assertions="1" />
    </testsuite>
    <testsuite name="Card mixing — every pile, not just one" file="test/sheet-fields.test.ts" line="483" tests="2" assertions="5" failures="0" skipped="0" time="0.002" hostname="runnervmtai0g">
      <testcase name="`alsoWith` only names an outsider every member of the card can mix with" classname="Card mixing — every pile, not just one" time="0.001404" file="test/sheet-fields.test.ts" line="484" assertions="3" />
      <testcase name="`together` requires every pair to mix, not just one member mixing with the rest" classname="Card mixing — every pile, not just one" time="0.001814" file="test/sheet-fields.test.ts" line="497" assertions="2" />
    </testsuite>
    <testsuite name="Card temperature/spin display" file="test/sheet-fields.test.ts" line="510" tests="5" assertions="8" failures="0" skipped="0" time="0.005" hostname="runnervmtai0g">
      <testcase name="&apos;koud&apos; shows as-is, not &apos;°C&apos;, and the no-spin label replaces &apos;rpm&apos;" classname="Card temperature/spin display" time="0.001597" file="test/sheet-fields.test.ts" line="523" assertions="2" />
      <testcase name="a real temperature always shows °C" classname="Card temperature/spin display" time="0.001314" file="test/sheet-fields.test.ts" line="530" assertions="1" />
      <testcase name="a real spin speed shows rpm" classname="Card temperature/spin display" time="0.001195" file="test/sheet-fields.test.ts" line="534" assertions="1" />
      <testcase name="each readout is labelled, and the collapsed section has its summary" classname="Card temperature/spin display" time="0.001234" file="test/sheet-fields.test.ts" line="538" assertions="3" />
      <testcase name="the programme the dial is set to is named on the card" classname="Card temperature/spin display" time="0.001206" file="test/sheet-fields.test.ts" line="545" assertions="1" />
    </testsuite>
    <testsuite name="SoftenerBadge" file="test/sheet-fields.test.ts" line="550" tests="2" assertions="2" failures="0" skipped="0" time="0.002" hostname="runnervmtai0g">
      <testcase name="shows the softener-ok badge, styled bg-yes, only for a pile that gets one" classname="SoftenerBadge" time="0.001173" file="test/sheet-fields.test.ts" line="551" assertions="1" />
      <testcase name="shows the no-softener badge, styled bg-no, for a pile that doesn&apos;t" classname="SoftenerBadge" time="0.001538" file="test/sheet-fields.test.ts" line="558" assertions="1" />
    </testsuite>
    <testsuite name="SplitField / Prose" file="test/sheet-fields.test.ts" line="566" tests="7" assertions="19" failures="0" skipped="0" time="0.007" hostname="runnervmtai0g">
      <testcase name="shows one line per pile when the group disagrees" classname="SplitField / Prose" time="0.001328" file="test/sheet-fields.test.ts" line="567" assertions="6" />
      <testcase name="collapses to a single line when the whole group agrees" classname="SplitField / Prose" time="0.001198" file="test/sheet-fields.test.ts" line="579" assertions="3" />
      <testcase name="renders nothing at all when nobody in the group has anything to say" classname="SplitField / Prose" time="0.001212" file="test/sheet-fields.test.ts" line="586" assertions="1" />
      <testcase name="a per-pile line isn&apos;t emphasised — only Card&apos;s own wash-together Field is" classname="SplitField / Prose" time="0.001097" file="test/sheet-fields.test.ts" line="595" assertions="1" />
      <testcase name="Field&apos;s own label is uppercased, and its value bolded" classname="SplitField / Prose" time="0.001226" file="test/sheet-fields.test.ts" line="605" assertions="2" />
      <testcase name="SplitField&apos;s own label is uppercased too, and Prose&apos;s multi-line wrapper carries no class" classname="SplitField / Prose" time="0.00116" file="test/sheet-fields.test.ts" line="613" assertions="2" />
      <testcase name="only the piles with something to say show up when some, not all, of the group is silent" classname="SplitField / Prose" time="0.001202" file="test/sheet-fields.test.ts" line="627" assertions="4" />
    </testsuite>
    <testsuite name="ReferenceField" file="test/sheet-fields.test.ts" line="646" tests="5" assertions="11" failures="0" skipped="0" time="0.005" hostname="runnervmtai0g">
      <testcase name="a cited row with a link renders a real, safe off-site anchor" classname="ReferenceField" time="0.001133" file="test/sheet-fields.test.ts" line="647" assertions="4" />
      <testcase name="a cited row with no link renders the name as plain text" classname="ReferenceField" time="0.001258" file="test/sheet-fields.test.ts" line="655" assertions="2" />
      <testcase name="a multi-pile card labels each citation by clothing type, and only the second gets mt-0.5" classname="ReferenceField" time="0.001289" file="test/sheet-fields.test.ts" line="661" assertions="2" />
      <testcase name="a solo pile&apos;s own citation has no clothing-type prefix at all" classname="ReferenceField" time="0.001573" file="test/sheet-fields.test.ts" line="675" assertions="2" />
      <testcase name="a card with no citations at all has no SOURCE section" classname="ReferenceField" time="0.001634" file="test/sheet-fields.test.ts" line="684" assertions="1" />
    </testsuite>
    <testsuite name="IronPanel / IronCard" file="test/sheet-fields.test.ts" line="692" tests="13" assertions="26" failures="0" skipped="0" time="0.009" hostname="runnervmtai0g">
      <testcase name="an ironed pile inside the steam zone says so" classname="IronPanel / IronCard" time="0.001506" file="test/sheet-fields.test.ts" line="693" assertions="1" />
      <testcase name="an ironed pile below the steam zone says so instead" classname="IronPanel / IronCard" time="0.00118" file="test/sheet-fields.test.ts" line="698" assertions="1" />
      <testcase name="a never-ironed pile says do not iron, not a thermostat label" classname="IronPanel / IronCard" time="0.001112" file="test/sheet-fields.test.ts" line="703" assertions="1" />
      <testcase name="an ironed pile&apos;s own IronPanel names the exact setting, label and detail" classname="IronPanel / IronCard" time="0.003296" file="test/sheet-fields.test.ts" line="708" assertions="1" />
      <testcase name="IronPanel&apos;s own ironing notes are never bold — Field&apos;s own value is the only emphasised text" classname="IronPanel / IronCard" time="0.00135" file="test/sheet-fields.test.ts" line="713" assertions="1" />
      <testcase name="IronPanel&apos;s own Prose call renders nothing when the whole group has no ironing notes" classname="IronPanel / IronCard" time="0.00109" file="test/sheet-fields.test.ts" line="718" assertions="1" />
      <testcase name="only a never-ironed pile&apos;s own dial is drawn crossed out — an ironed one never is" classname="IronPanel / IronCard" time="0.001012" file="test/sheet-fields.test.ts" line="729" assertions="2" />
      <testcase name="the iron cut&apos;s own card names the thermostat setting and pile count" classname="IronPanel / IronCard" time="0.0005" file="test/sheet-fields.test.ts" line="741" assertions="5" />
      <testcase name="the iron cut&apos;s never-iron group gets its own heading and copy" classname="IronPanel / IronCard" time="0.000411" file="test/sheet-fields.test.ts" line="755" assertions="5" />
      <testcase name="the iron cut&apos;s own below-steam-zone copy shows for a setting that doesn&apos;t steam" classname="IronPanel / IronCard" time="0.000372" file="test/sheet-fields.test.ts" line="769" assertions="2" />
      <testcase name="a solo pile in the iron cut uses the singular pile count, not the plural" classname="IronPanel / IronCard" time="0.000395" file="test/sheet-fields.test.ts" line="776" assertions="2" />
      <testcase name="the iron cut&apos;s own crossed-out dial is only ever the never-iron card&apos;s" classname="IronPanel / IronCard" time="0.000377" file="test/sheet-fields.test.ts" line="785" assertions="2" />
      <testcase name="every member of a group is listed under it, by its own clothing type" classname="IronPanel / IronCard" time="0.000346" file="test/sheet-fields.test.ts" line="796" assertions="2" />
    </testsuite>
    <testsuite name="Sheet variant sections" file="test/sheet-fields.test.ts" line="810" tests="4" assertions="11" failures="0" skipped="0" time="0.002" hostname="runnervmtai0g">
      <testcase name="the wash cut hides the iron section entirely" classname="Sheet variant sections" time="0.000775" file="test/sheet-fields.test.ts" line="811" assertions="3" />
      <testcase name="the full and iron cuts both show an iron section or card" classname="Sheet variant sections" time="0.0014" file="test/sheet-fields.test.ts" line="821" assertions="2" />
      <testcase name="the iron cut has no Loads section and no durations disclaimer" classname="Sheet variant sections" time="0.000394" file="test/sheet-fields.test.ts" line="826" assertions="2" />
      <testcase name="the full and wash cuts both show the Loads section and the disclaimer" classname="Sheet variant sections" time="0.001597" file="test/sheet-fields.test.ts" line="832" assertions="4" />
    </testsuite>
    <testsuite name="ControlPanel / ChipRow" file="test/sheet-fields.test.ts" line="841" tests="3" assertions="9" failures="0" skipped="0" time="0.002" hostname="runnervmtai0g">
      <testcase name="names the programme&apos;s own position on the dial, clockwise from the first" classname="ControlPanel / ChipRow" time="0.000975" file="test/sheet-fields.test.ts" line="842" assertions="1" />
      <testcase name="highlights exactly the temperature/spin/options this pile actually uses" classname="ControlPanel / ChipRow" time="0.001084" file="test/sheet-fields.test.ts" line="847" assertions="7" />
      <testcase name="falls back to an empty &apos;off&apos; position when the washer has no programmes at all" classname="ControlPanel / ChipRow" time="0.001071" file="test/sheet-fields.test.ts" line="870" assertions="1" />
    </testsuite>
    <testsuite name="Card/IronCard numbering and heading" file="test/sheet-fields.test.ts" line="886" tests="4" assertions="6" failures="0" skipped="0" time="0.001" hostname="runnervmtai0g">
      <testcase name="cards are numbered from 1, not 0 or in reverse" classname="Card/IronCard numbering and heading" time="0.000981" file="test/sheet-fields.test.ts" line="887" assertions="1" />
      <testcase name="a multi-pile card&apos;s own heading joins clothing types with a single &apos; + &apos;" classname="Card/IronCard numbering and heading" time="0.000984" file="test/sheet-fields.test.ts" line="894" assertions="2" />
      <testcase name="the iron cut&apos;s own cards are numbered from 1 too, in order — not just &apos;1.&apos; somewhere" classname="Card/IronCard numbering and heading" time="0.000616" file="test/sheet-fields.test.ts" line="902" assertions="2" />
      <testcase name="the card header shows the group&apos;s own total duration, next to the numbered heading" classname="Card/IronCard numbering and heading" time="0.00103" file="test/sheet-fields.test.ts" line="911" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/rich-text.test.ts" file="test/rich-text.test.ts" tests="7" assertions="7" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="richText" file="test/rich-text.test.ts" line="4" tests="7" assertions="7" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="passes plain text through untouched" classname="richText" time="0.00021" file="test/rich-text.test.ts" line="5" assertions="1" />
      <testcase name="escapes HTML-significant characters in plain text" classname="richText" time="0.000039" file="test/rich-text.test.ts" line="9" assertions="1" />
      <testcase name="turns [label](url) into a link, keeping the url exact" classname="richText" time="0.000046" file="test/rich-text.test.ts" line="13" assertions="1" />
      <testcase name="turns `code` into a code span" classname="richText" time="0.000029" file="test/rich-text.test.ts" line="19" assertions="1" />
      <testcase name="turns *emphasis* into &lt;em&gt;" classname="richText" time="0.000057" file="test/rich-text.test.ts" line="25" assertions="1" />
      <testcase name="turns multi-character *emphasis* into &lt;em&gt;, not just a single character" classname="richText" time="0.000027" file="test/rich-text.test.ts" line="29" assertions="1" />
      <testcase name="handles a mix of markup and escapes surrounding text" classname="richText" time="0.000026" file="test/rich-text.test.ts" line="33" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/readme-shots.test.ts" file="test/readme-shots.test.ts" tests="3" assertions="7" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="README release screenshots" file="test/readme-shots.test.ts" line="13" tests="3" assertions="7" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="cover every non-footer English page, light and dark" classname="README release screenshots" time="0.000071" file="test/readme-shots.test.ts" line="14" assertions="3" />
      <testcase name="leave out every page the footer links to" classname="README release screenshots" time="0.000222" file="test/readme-shots.test.ts" line="30" assertions="3" />
      <testcase name="are all shown in the README, and the README shows nothing else" classname="README release screenshots" time="0.000145" file="test/readme-shots.test.ts" line="41" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/ui.test.ts" file="test/ui.test.ts" tests="25" assertions="2258" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="dictionaries" file="test/ui.test.ts" line="5" tests="21" assertions="2254" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="ja has exactly the same keys as English" classname="dictionaries" time="0.000135" file="test/ui.test.ts" line="9" assertions="1" />
      <testcase name="de has exactly the same keys as English" classname="dictionaries" time="0.000098" file="test/ui.test.ts" line="9" assertions="1" />
      <testcase name="es has exactly the same keys as English" classname="dictionaries" time="0.000099" file="test/ui.test.ts" line="9" assertions="1" />
      <testcase name="fr has exactly the same keys as English" classname="dictionaries" time="0.000095" file="test/ui.test.ts" line="9" assertions="1" />
      <testcase name="ar has exactly the same keys as English" classname="dictionaries" time="0.0001" file="test/ui.test.ts" line="9" assertions="1" />
      <testcase name="zh has exactly the same keys as English" classname="dictionaries" time="0.000099" file="test/ui.test.ts" line="9" assertions="1" />
      <testcase name="tr has exactly the same keys as English" classname="dictionaries" time="0.0001" file="test/ui.test.ts" line="9" assertions="1" />
      <testcase name="ru has exactly the same keys as English" classname="dictionaries" time="0.000112" file="test/ui.test.ts" line="9" assertions="1" />
      <testcase name="jive has exactly the same keys as English" classname="dictionaries" time="0.000097" file="test/ui.test.ts" line="9" assertions="1" />
      <testcase name="linkedin has exactly the same keys as English" classname="dictionaries" time="0.000096" file="test/ui.test.ts" line="9" assertions="1" />
      <testcase name="en has no empty string values" classname="dictionaries" time="0.000229" file="test/ui.test.ts" line="15" assertions="204" />
      <testcase name="ja has no empty string values" classname="dictionaries" time="0.000178" file="test/ui.test.ts" line="15" assertions="204" />
      <testcase name="de has no empty string values" classname="dictionaries" time="0.000229" file="test/ui.test.ts" line="15" assertions="204" />
      <testcase name="es has no empty string values" classname="dictionaries" time="0.000156" file="test/ui.test.ts" line="15" assertions="204" />
      <testcase name="fr has no empty string values" classname="dictionaries" time="0.000144" file="test/ui.test.ts" line="15" assertions="204" />
      <testcase name="ar has no empty string values" classname="dictionaries" time="0.000121" file="test/ui.test.ts" line="15" assertions="204" />
      <testcase name="zh has no empty string values" classname="dictionaries" time="0.000132" file="test/ui.test.ts" line="15" assertions="204" />
      <testcase name="tr has no empty string values" classname="dictionaries" time="0.000125" file="test/ui.test.ts" line="15" assertions="204" />
      <testcase name="ru has no empty string values" classname="dictionaries" time="0.00014" file="test/ui.test.ts" line="15" assertions="204" />
      <testcase name="jive has no empty string values" classname="dictionaries" time="0.000142" file="test/ui.test.ts" line="15" assertions="204" />
      <testcase name="linkedin has no empty string values" classname="dictionaries" time="0.000128" file="test/ui.test.ts" line="15" assertions="204" />
    </testsuite>
    <testsuite name="translator" file="test/ui.test.ts" line="23" tests="4" assertions="4" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="looks up a key in the requested locale" classname="translator" time="0.000058" file="test/ui.test.ts" line="24" assertions="1" />
      <testcase name="falls back to English for an unrecognised locale" classname="translator" time="0.000025" file="test/ui.test.ts" line="28" assertions="1" />
      <testcase name="interpolates {token} placeholders when params are given" classname="translator" time="0.000046" file="test/ui.test.ts" line="33" assertions="1" />
      <testcase name="returns the raw string untouched when no params are given, placeholders included" classname="translator" time="0.000027" file="test/ui.test.ts" line="39" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/keyboard-nav.test.ts" file="test/keyboard-nav.test.ts" tests="9" assertions="14" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="isTypingTarget" file="test/keyboard-nav.test.ts" line="4" tests="4" assertions="8" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="is false for no target" classname="isTypingTarget" time="0.000086" file="test/keyboard-nav.test.ts" line="5" assertions="2" />
      <testcase name="is false for a plain element" classname="isTypingTarget" time="0.000027" file="test/keyboard-nav.test.ts" line="10" assertions="2" />
      <testcase name="is true for an input, textarea or select" classname="isTypingTarget" time="0.000029" file="test/keyboard-nav.test.ts" line="15" assertions="3" />
      <testcase name="is true for a contenteditable element regardless of tag" classname="isTypingTarget" time="0.000016" file="test/keyboard-nav.test.ts" line="21" assertions="1" />
    </testsuite>
    <testsuite name="isSecondGPress" file="test/keyboard-nav.test.ts" line="26" tests="4" assertions="5" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="is false for a first g press (nothing recent behind it)" classname="isSecondGPress" time="0.000041" file="test/keyboard-nav.test.ts" line="27" assertions="1" />
      <testcase name="is true for a second g press within the threshold" classname="isSecondGPress" time="0.000023" file="test/keyboard-nav.test.ts" line="31" assertions="2" />
      <testcase name="is false once the threshold has passed" classname="isSecondGPress" time="0.000016" file="test/keyboard-nav.test.ts" line="37" assertions="1" />
      <testcase name="is false when lastGPressAt is 0 — &apos;no press yet&apos;, even if now is within the threshold of zero" classname="isSecondGPress" time="0.000015" file="test/keyboard-nav.test.ts" line="41" assertions="1" />
    </testsuite>
    <testsuite name="KEY_BINDINGS" file="test/keyboard-nav.test.ts" line="50" tests="1" assertions="1" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="lists every binding with its exact keys and description key" classname="KEY_BINDINGS" time="0.000045" file="test/keyboard-nav.test.ts" line="51" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/docs-images.test.ts" file="test/docs-images.test.ts" tests="1" assertions="1" failures="0" skipped="0" time="0.004" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testcase name="every docs screenshot declares its size" classname="" time="0.004334" file="test/docs-images.test.ts" line="7" assertions="1" />
  </testsuite>
  <testsuite name="test/config-share.test.ts" file="test/config-share.test.ts" tests="12" assertions="34" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="encodeConfigHash / decodeConfigHash" file="test/config-share.test.ts" line="11" tests="5" assertions="6" failures="0" skipped="0" time="0.023" hostname="runnervmtai0g">
      <testcase name="round-trips a real config unchanged" classname="encodeConfigHash / decodeConfigHash" time="0.015694" file="test/config-share.test.ts" line="12" assertions="1" />
      <testcase name="decodes without a leading # too, not just location.hash&apos;s own form" classname="encodeConfigHash / decodeConfigHash" time="0.005278" file="test/config-share.test.ts" line="21" assertions="1" />
      <testcase name="the hash starts with the expected prefix, ready to append to a URL" classname="encodeConfigHash / decodeConfigHash" time="0.002025" file="test/config-share.test.ts" line="30" assertions="1" />
      <testcase name="returns null for a hash that carries no config at all" classname="encodeConfigHash / decodeConfigHash" time="0.000162" file="test/config-share.test.ts" line="38" assertions="2" />
      <testcase name="throws the same row/column-scoped error configFromJson gives an invalid upload, for a corrupted hash" classname="encodeConfigHash / decodeConfigHash" time="0.001579" file="test/config-share.test.ts" line="43" assertions="1" />
    </testsuite>
    <testsuite name="toBase64Url / fromBase64Url" file="test/config-share.test.ts" line="48" tests="7" assertions="28" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="round-trips 0 byte(s) losslessly" classname="toBase64Url / fromBase64Url" time="0.00013" file="test/config-share.test.ts" line="53" assertions="4" />
      <testcase name="round-trips 1 byte(s) losslessly" classname="toBase64Url / fromBase64Url" time="0.000027" file="test/config-share.test.ts" line="53" assertions="4" />
      <testcase name="round-trips 2 byte(s) losslessly" classname="toBase64Url / fromBase64Url" time="0.000008" file="test/config-share.test.ts" line="53" assertions="4" />
      <testcase name="round-trips 3 byte(s) losslessly" classname="toBase64Url / fromBase64Url" time="0.000019" file="test/config-share.test.ts" line="53" assertions="4" />
      <testcase name="round-trips 4 byte(s) losslessly" classname="toBase64Url / fromBase64Url" time="0.000005" file="test/config-share.test.ts" line="53" assertions="4" />
      <testcase name="round-trips 5 byte(s) losslessly" classname="toBase64Url / fromBase64Url" time="0.000005" file="test/config-share.test.ts" line="53" assertions="4" />
      <testcase name="round-trips 6 byte(s) losslessly" classname="toBase64Url / fromBase64Url" time="0.000005" file="test/config-share.test.ts" line="53" assertions="4" />
    </testsuite>
  </testsuite>
  <testsuite name="test/assemble-reports.test.ts" file="test/assemble-reports.test.ts" tests="9" assertions="30" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="assembleReports" file="test/assemble-reports.test.ts" line="57" tests="6" assertions="22" failures="0" skipped="0" time="0.015" hostname="runnervmtai0g">
      <testcase name="lays the tests and coverage out as the site serves them" classname="assembleReports" time="0.006217" file="test/assemble-reports.test.ts" line="58" assertions="5" />
      <testcase name="keeps one Lighthouse pair per page, from the representative run" classname="assembleReports" time="0.00284" file="test/assemble-reports.test.ts" line="67" assertions="6" />
      <testcase name="writes a tests page and a top-level index with the commit and date" classname="assembleReports" time="0.003004" file="test/assemble-reports.test.ts" line="80" assertions="8" />
      <testcase name="refuses to run when an input is missing" classname="assembleReports" time="0.001735" file="test/assemble-reports.test.ts" line="94" assertions="1" />
      <testcase name="refuses to run when the e2e results are missing" classname="assembleReports" time="0.001741" file="test/assemble-reports.test.ts" line="101" assertions="1" />
      <testcase name="refuses to run when no Lighthouse run is representative" classname="assembleReports" time="0.002379" file="test/assemble-reports.test.ts" line="108" assertions="1" />
    </testsuite>
    <testsuite name="slugForUrl" file="test/assemble-reports.test.ts" line="116" tests="1" assertions="3" failures="0" skipped="0" time="0.001" hostname="runnervmtai0g">
      <testcase name="names a page after its path" classname="slugForUrl" time="0.001373" file="test/assemble-reports.test.ts" line="117" assertions="3" />
    </testsuite>
    <testsuite name="renderIndex" file="test/assemble-reports.test.ts" line="124" tests="2" assertions="5" failures="0" skipped="0" time="0.003" hostname="runnervmtai0g">
      <testcase name="escapes what it is given" classname="renderIndex" time="0.002503" file="test/assemble-reports.test.ts" line="125" assertions="3" />
      <testcase name="puts the note under the title when there is one" classname="renderIndex" time="0.001211" file="test/assemble-reports.test.ts" line="132" assertions="2" />
    </testsuite>
  </testsuite>
  <testsuite name="test/program-dial-render.test.ts" file="test/program-dial-render.test.ts" tests="9" assertions="75" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="ProgramDial (Svelte)" file="test/program-dial-render.test.ts" line="84" tests="9" assertions="75" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="draws one ring arc, one path for the unselected ticks, a selected tick, a knob and a pointer" classname="ProgramDial (Svelte)" time="0.00072" file="test/program-dial-render.test.ts" line="89" assertions="5" />
      <testcase name="defaults to a 76px square viewBox, honours an explicit size" classname="ProgramDial (Svelte)" time="0.000173" file="test/program-dial-render.test.ts" line="99" assertions="6" />
      <testcase name="draws the ring arc at exactly the geometry the maths predicts (2 programs)" classname="ProgramDial (Svelte)" time="0.00024" file="test/program-dial-render.test.ts" line="112" assertions="4" />
      <testcase name="draws the ring arc at exactly the geometry the maths predicts (4 programs)" classname="ProgramDial (Svelte)" time="0.000104" file="test/program-dial-render.test.ts" line="112" assertions="4" />
      <testcase name="draws every tick at its own angle, growing and recolouring only the selected one" classname="ProgramDial (Svelte)" time="0.000463" file="test/program-dial-render.test.ts" line="126" assertions="38" />
      <testcase name="the knob and centre dot are drawn at fixed radii regardless of the selection" classname="ProgramDial (Svelte)" time="0.000174" file="test/program-dial-render.test.ts" line="176" assertions="12" />
      <testcase name="an unrecognised program falls back to the first position, not a crash" classname="ProgramDial (Svelte)" time="0.000104" file="test/program-dial-render.test.ts" line="197" assertions="1" />
      <testcase name="a dial with no programs draws no ticks, only the pointer" classname="ProgramDial (Svelte)" time="0.000087" file="test/program-dial-render.test.ts" line="204" assertions="2" />
      <testcase name="a single program is the selected tick, with no unselected path" classname="ProgramDial (Svelte)" time="0.000101" file="test/program-dial-render.test.ts" line="211" assertions="3" />
    </testsuite>
  </testsuite>
  <testsuite name="test/config-progressive-cards.test.ts" file="test/config-progressive-cards.test.ts" tests="9" assertions="27" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="progressive chart cards" file="test/config-progressive-cards.test.ts" line="73" tests="9" assertions="27" failures="0" skipped="0" time="1.363" hostname="runnervmtai0g">
      <testcase name="the bundled chart is long enough to need two clicks" classname="progressive chart cards" time="0.008837" file="test/config-progressive-cards.test.ts" line="74" assertions="2" />
      <testcase name="renders only the first batch, with a button saying how many are shown" classname="progressive chart cards" time="0.149674" file="test/config-progressive-cards.test.ts" line="79" assertions="5" />
      <testcase name="each click reveals one more batch, the last one partial, then the button goes" classname="progressive chart cards" time="0.23343" file="test/config-progressive-cards.test.ts" line="89" assertions="4" />
      <testcase name="moves focus to the first revealed card so the button vanishing loses nothing" classname="progressive chart cards" time="0.1994" file="test/config-progressive-cards.test.ts" line="99" assertions="2" />
      <testcase name="a chart of exactly one batch has no button" classname="progressive chart cards" time="0.096246" file="test/config-progressive-cards.test.ts" line="109" assertions="2" />
      <testcase name="a chart one over a batch has a button that reveals the last card" classname="progressive chart cards" time="0.09456" file="test/config-progressive-cards.test.ts" line="115" assertions="4" />
      <testcase name="sorting keeps the visible count and shows the first of the sorted order" classname="progressive chart cards" time="0.290619" file="test/config-progressive-cards.test.ts" line="124" assertions="2" />
      <testcase name="an edit made to a card lands on that row, and Save keeps every row, hidden ones too" classname="progressive chart cards" time="0.129264" file="test/config-progressive-cards.test.ts" line="135" assertions="3" />
      <testcase name="going back to the bundled config starts over at the first batch" classname="progressive chart cards" time="0.165388" file="test/config-progressive-cards.test.ts" line="149" assertions="3" />
    </testsuite>
  </testsuite>
  <testsuite name="test/theme-preference.test.ts" file="test/theme-preference.test.ts" tests="9" assertions="12" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="readThemePreference / writeThemePreference" file="test/theme-preference.test.ts" line="49" tests="5" assertions="6" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="round-trips whatever was last written" classname="readThemePreference / writeThemePreference" time="0.000237" file="test/theme-preference.test.ts" line="50" assertions="1" />
      <testcase name="round-trips &apos;light&apos; too, not just &apos;dark&apos;" classname="readThemePreference / writeThemePreference" time="0.00004" file="test/theme-preference.test.ts" line="58" assertions="1" />
      <testcase name="returns null when nothing has been stored yet — &apos;follow the OS&apos;, not a default mode" classname="readThemePreference / writeThemePreference" time="0.000026" file="test/theme-preference.test.ts" line="66" assertions="1" />
      <testcase name="ignores a value that isn&apos;t a valid theme" classname="readThemePreference / writeThemePreference" time="0.000028" file="test/theme-preference.test.ts" line="72" assertions="1" />
      <testcase name="degrades to not remembering when storage itself throws" classname="readThemePreference / writeThemePreference" time="0.000152" file="test/theme-preference.test.ts" line="80" assertions="2" />
    </testsuite>
    <testsuite name="THEME_BOOTSTRAP_SCRIPT" file="test/theme-preference.test.ts" line="88" tests="2" assertions="3" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="reads the same key readThemePreference/writeThemePreference use" classname="THEME_BOOTSTRAP_SCRIPT" time="0.000024" file="test/theme-preference.test.ts" line="89" assertions="1" />
      <testcase name="only ever sets data-theme to a valid explicit value, never an arbitrary stored string" classname="THEME_BOOTSTRAP_SCRIPT" time="0.000022" file="test/theme-preference.test.ts" line="93" assertions="2" />
    </testsuite>
    <testsuite name="DOCS_THEME_BOOTSTRAP_SCRIPT" file="test/theme-preference.test.ts" line="99" tests="2" assertions="3" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="reads the same key as the other bootstrap script" classname="DOCS_THEME_BOOTSTRAP_SCRIPT" time="0.000017" file="test/theme-preference.test.ts" line="100" assertions="1" />
      <testcase name="falls back to prefers-color-scheme when nothing is stored, unlike THEME_BOOTSTRAP_SCRIPT" classname="DOCS_THEME_BOOTSTRAP_SCRIPT" time="0.000051" file="test/theme-preference.test.ts" line="104" assertions="2" />
    </testsuite>
  </testsuite>
  <testsuite name="test/headers.test.ts" file="test/headers.test.ts" tests="1" assertions="1" failures="0" skipped="0" time="0.001" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testcase name="fingerprinted assets are served immutable" classname="" time="0.001825" file="test/headers.test.ts" line="6" assertions="1" />
  </testsuite>
  <testsuite name="test/webmcp.test.ts" file="test/webmcp.test.ts" tests="12" assertions="26" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="createWebMcpTools" file="test/webmcp.test.ts" line="56" tests="2" assertions="3" failures="0" skipped="0" time="0.002" hostname="runnervmtai0g">
      <testcase name="declares the five documented tools" classname="createWebMcpTools" time="0.00281" file="test/webmcp.test.ts" line="57" assertions="1" />
      <testcase name="marks read-only tools and consequential tools distinctly" classname="createWebMcpTools" time="0.000183" file="test/webmcp.test.ts" line="69" assertions="2" />
    </testsuite>
    <testsuite name="washy_get_config" file="test/webmcp.test.ts" line="75" tests="2" assertions="4" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="returns the bundled example when no custom config is active" classname="washy_get_config" time="0.000431" file="test/webmcp.test.ts" line="76" assertions="3" />
      <testcase name="returns the saved config once one is active" classname="washy_get_config" time="0.000361" file="test/webmcp.test.ts" line="88" assertions="1" />
    </testsuite>
    <testsuite name="washy_validate_chart" file="test/webmcp.test.ts" line="98" tests="2" assertions="4" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="accepts rows that fit the active machine, without saving anything" classname="washy_validate_chart" time="0.000416" file="test/webmcp.test.ts" line="99" assertions="2" />
      <testcase name="reports the same row/column error the on-page editor would, for an unknown programme" classname="washy_validate_chart" time="0.000694" file="test/webmcp.test.ts" line="108" assertions="2" />
    </testsuite>
    <testsuite name="washy_set_chart" file="test/webmcp.test.ts" line="123" tests="2" assertions="5" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="persists a validated chart against the active machine" classname="washy_set_chart" time="0.000638" file="test/webmcp.test.ts" line="124" assertions="2" />
      <testcase name="saves nothing when a row doesn&apos;t fit the machine" classname="washy_set_chart" time="0.000571" file="test/webmcp.test.ts" line="133" assertions="3" />
    </testsuite>
    <testsuite name="washy_set_machine" file="test/webmcp.test.ts" line="149" tests="2" assertions="5" failures="0" skipped="0" time="0.001" hostname="runnervmtai0g">
      <testcase name="persists a new machine once the current chart still validates against it" classname="washy_set_machine" time="0.001019" file="test/webmcp.test.ts" line="150" assertions="2" />
      <testcase name="saves nothing when the new machine breaks the current chart" classname="washy_set_machine" time="0.00056" file="test/webmcp.test.ts" line="165" assertions="3" />
    </testsuite>
    <testsuite name="washy_export_pdf" file="test/webmcp.test.ts" line="192" tests="2" assertions="5" failures="0" skipped="0" time="4.523" hostname="runnervmtai0g">
      <testcase name="renders the phone layout for the active chart, base64-encoded" classname="washy_export_pdf" time="3.299594" file="test/webmcp.test.ts" line="193" assertions="3" />
      <testcase name="renders the print layout with the cut suffix in the filename" classname="washy_export_pdf" time="1.224235" file="test/webmcp.test.ts" line="209" assertions="2" />
    </testsuite>
  </testsuite>
  <testsuite name="test/banner-seen.test.ts" file="test/banner-seen.test.ts" tests="7" assertions="7" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="hasSeenBanner / markBannerSeen" file="test/banner-seen.test.ts" line="44" tests="7" assertions="7" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="is false before the banner has ever been marked seen" classname="hasSeenBanner / markBannerSeen" time="0.000186" file="test/banner-seen.test.ts" line="45" assertions="1" />
      <testcase name="is true after marking it seen for that locale" classname="hasSeenBanner / markBannerSeen" time="0.000085" file="test/banner-seen.test.ts" line="51" assertions="1" />
      <testcase name="is scoped per locale — marking one locale doesn&apos;t affect another" classname="hasSeenBanner / markBannerSeen" time="0.000029" file="test/banner-seen.test.ts" line="59" assertions="1" />
      <testcase name="uses the documented storage key literally, prefixed per locale" classname="hasSeenBanner / markBannerSeen" time="0.000283" file="test/banner-seen.test.ts" line="67" assertions="1" />
      <testcase name="treats any stored value other than the literal string &apos;true&apos; as not seen" classname="hasSeenBanner / markBannerSeen" time="0.000038" file="test/banner-seen.test.ts" line="75" assertions="1" />
      <testcase name="fails open — reads as &apos;not seen&apos; — when storage itself throws" classname="hasSeenBanner / markBannerSeen" time="0.000098" file="test/banner-seen.test.ts" line="83" assertions="1" />
      <testcase name="degrades silently when storage throws on write" classname="hasSeenBanner / markBannerSeen" time="0.000072" file="test/banner-seen.test.ts" line="89" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/iron-dial-render.test.ts" file="test/iron-dial-render.test.ts" tests="15" assertions="95" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="IronDial (Svelte)" file="test/iron-dial-render.test.ts" line="78" tests="15" assertions="95" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="draws the ring, one path for the unselected ticks, the selected tick, a knob and a pointer when not off" classname="IronDial (Svelte)" time="0.00072" file="test/iron-dial-render.test.ts" line="90" assertions="4" />
      <testcase name="defaults to a 76px square viewBox, honours an explicit size" classname="IronDial (Svelte)" time="0.000309" file="test/iron-dial-render.test.ts" line="105" assertions="4" />
      <testcase name="the ring always spans the same fixed 280 degree sweep, off or not" classname="IronDial (Svelte)" time="0.000573" file="test/iron-dial-render.test.ts" line="116" assertions="4" />
      <testcase name="a single setting doesn&apos;t divide by zero and still draws one tick at the ring&apos;s start" classname="IronDial (Svelte)" time="0.000331" file="test/iron-dial-render.test.ts" line="131" assertions="6" />
      <testcase name="draws every tick at its own angle, growing and recolouring only the selected one" classname="IronDial (Svelte)" time="0.000468" file="test/iron-dial-render.test.ts" line="148" assertions="36" />
      <testcase name="an unrecognised setting falls back to the first position" classname="IronDial (Svelte)" time="0.000165" file="test/iron-dial-render.test.ts" line="193" assertions="1" />
      <testcase name="draws no steam arc when nothing in the range steams" classname="IronDial (Svelte)" time="0.000111" file="test/iron-dial-render.test.ts" line="204" assertions="2" />
      <testcase name="still draws a steam arc when the very first setting is the one that steams" classname="IronDial (Svelte)" time="0.00016" file="test/iron-dial-render.test.ts" line="215" assertions="2" />
      <testcase name="draws a steam arc spanning the first through the last steaming setting" classname="IronDial (Svelte)" time="0.000272" file="test/iron-dial-render.test.ts" line="227" assertions="4" />
      <testcase name="a single steaming setting draws a steam arc from that setting to itself" classname="IronDial (Svelte)" time="0.000166" file="test/iron-dial-render.test.ts" line="243" assertions="2" />
      <testcase name="off renders a crossed-out ring instead of a pointer, and skips the steam arc" classname="IronDial (Svelte)" time="0.000236" file="test/iron-dial-render.test.ts" line="255" assertions="16" />
      <testcase name="off draws every tick in the hairline colour, none selected" classname="IronDial (Svelte)" time="0.000142" file="test/iron-dial-render.test.ts" line="289" assertions="2" />
      <testcase name="the knob face and radius switch between the on and off fills" classname="IronDial (Svelte)" time="0.000187" file="test/iron-dial-render.test.ts" line="301" assertions="8" />
      <testcase name="a dial with no settings draws no ticks, only the pointer" classname="IronDial (Svelte)" time="0.000109" file="test/iron-dial-render.test.ts" line="320" assertions="2" />
      <testcase name="off with a single setting still draws that one tick, in the hairline colour" classname="IronDial (Svelte)" time="0.000128" file="test/iron-dial-render.test.ts" line="327" assertions="2" />
    </testsuite>
  </testsuite>
  <testsuite name="test/duration.test.ts" file="test/duration.test.ts" tests="9" assertions="10" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="isValidDuration" file="test/duration.test.ts" line="4" tests="9" assertions="10" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="accepts empty — no duration set" classname="isValidDuration" time="0.00003" file="test/duration.test.ts" line="5" assertions="1" />
      <testcase name="accepts H:MM" classname="isValidDuration" time="0.000019" file="test/duration.test.ts" line="9" assertions="2" />
      <testcase name="accepts multi-digit hours" classname="isValidDuration" time="0.000012" file="test/duration.test.ts" line="14" assertions="1" />
      <testcase name="rejects non-numeric text" classname="isValidDuration" time="0.000017" file="test/duration.test.ts" line="18" assertions="1" />
      <testcase name="rejects a minutes value of 60 or more" classname="isValidDuration" time="0.000017" file="test/duration.test.ts" line="22" assertions="1" />
      <testcase name="rejects a missing colon" classname="isValidDuration" time="0.000016" file="test/duration.test.ts" line="26" assertions="1" />
      <testcase name="rejects a single-digit minutes part" classname="isValidDuration" time="0.000013" file="test/duration.test.ts" line="30" assertions="1" />
      <testcase name="rejects a leading ~ — callers strip it before validating" classname="isValidDuration" time="0.000016" file="test/duration.test.ts" line="34" assertions="1" />
      <testcase name="rejects trailing text after an otherwise-valid duration" classname="isValidDuration" time="0.000014" file="test/duration.test.ts" line="38" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/styles.test.ts" file="test/styles.test.ts" tests="10" assertions="10" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="shared style class strings" file="test/styles.test.ts" line="20" tests="10" assertions="10" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="TEXT_INPUT" classname="shared style class strings" time="0.000022" file="test/styles.test.ts" line="21" assertions="1" />
      <testcase name="FIELD_LABEL" classname="shared style class strings" time="0.000014" file="test/styles.test.ts" line="27" assertions="1" />
      <testcase name="BUTTON_PRIMARY" classname="shared style class strings" time="0.000013" file="test/styles.test.ts" line="31" assertions="1" />
      <testcase name="BUTTON_SECONDARY" classname="shared style class strings" time="0.000015" file="test/styles.test.ts" line="37" assertions="1" />
      <testcase name="ALERT" classname="shared style class strings" time="0.000014" file="test/styles.test.ts" line="43" assertions="1" />
      <testcase name="CARD" classname="shared style class strings" time="0.000012" file="test/styles.test.ts" line="47" assertions="1" />
      <testcase name="SECTION_HEADING" classname="shared style class strings" time="0.00003" file="test/styles.test.ts" line="51" assertions="1" />
      <testcase name="LINK" classname="shared style class strings" time="0.000013" file="test/styles.test.ts" line="55" assertions="1" />
      <testcase name="CHART_CARD" classname="shared style class strings" time="0.000052" file="test/styles.test.ts" line="61" assertions="1" />
      <testcase name="CHART_CARD_HEADER" classname="shared style class strings" time="0.000022" file="test/styles.test.ts" line="65" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/normalise-lcov.test.ts" file="test/normalise-lcov.test.ts" tests="3" assertions="6" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="normaliseLcov" file="test/normalise-lcov.test.ts" line="4" tests="3" assertions="6" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="leaves a plain record as it was" classname="normaliseLcov" time="0.000422" file="test/normalise-lcov.test.ts" line="5" assertions="1" />
      <testcase name="strips the ?client suffix from a file with only that record" classname="normaliseLcov" time="0.000076" file="test/normalise-lcov.test.ts" line="10" assertions="2" />
      <testcase name="merges the server and client records of a component, adding the hits" classname="normaliseLcov" time="0.000204" file="test/normalise-lcov.test.ts" line="16" assertions="3" />
    </testsuite>
  </testsuite>
  <testsuite name="test/sheet.test.ts" file="test/sheet.test.ts" tests="32" assertions="93" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="buildChart" file="test/sheet.test.ts" line="21" tests="1" assertions="2" failures="0" skipped="0" time="0.004" hostname="runnervmtai0g">
      <testcase name="parses the same items and machine the CLI draws the bundled examples from" classname="buildChart" time="0.004616" file="test/sheet.test.ts" line="22" assertions="2" />
    </testsuite>
    <testsuite name="filterByPile" file="test/sheet.test.ts" line="33" tests="3" assertions="9" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="keeps every pile when the query is empty or blank" classname="filterByPile" time="0.000743" file="test/sheet.test.ts" line="34" assertions="2" />
      <testcase name="matches by substring, case-insensitively" classname="filterByPile" time="0.000852" file="test/sheet.test.ts" line="41" assertions="6" />
      <testcase name="matches nothing rather than falling back to everything" classname="filterByPile" time="0.000682" file="test/sheet.test.ts" line="51" assertions="1" />
    </testsuite>
    <testsuite name="filterAdvanced" file="test/sheet.test.ts" line="58" tests="8" assertions="37" failures="0" skipped="0" time="0.001" hostname="runnervmtai0g">
      <testcase name="keeps every pile when every field is empty" classname="filterAdvanced" time="0.001889" file="test/sheet.test.ts" line="59" assertions="1" />
      <testcase name="matches by exact programme" classname="filterAdvanced" time="0.000618" file="test/sheet.test.ts" line="65" assertions="10" />
      <testcase name="matches by exact temperature" classname="filterAdvanced" time="0.00052" file="test/sheet.test.ts" line="75" assertions="4" />
      <testcase name="matches by exact spin" classname="filterAdvanced" time="0.000647" file="test/sheet.test.ts" line="85" assertions="7" />
      <testcase name="matches detergent by substring, case-insensitively" classname="filterAdvanced" time="0.000626" file="test/sheet.test.ts" line="95" assertions="5" />
      <testcase name="trims surrounding whitespace from the detergent query before matching" classname="filterAdvanced" time="0.000572" file="test/sheet.test.ts" line="105" assertions="2" />
      <testcase name="combines fields as AND, not OR" classname="filterAdvanced" time="0.000487" file="test/sheet.test.ts" line="115" assertions="1" />
      <testcase name="combines with filterByPile as AND" classname="filterAdvanced" time="0.000505" file="test/sheet.test.ts" line="135" assertions="7" />
    </testsuite>
    <testsuite name="hasActiveAdvancedFilters" file="test/sheet.test.ts" line="150" tests="5" assertions="6" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="is false when every field is empty, including whitespace-only detergent" classname="hasActiveAdvancedFilters" time="0.000098" file="test/sheet.test.ts" line="151" assertions="2" />
      <testcase name="is true when program alone is set" classname="hasActiveAdvancedFilters" time="0.000018" file="test/sheet.test.ts" line="158" assertions="1" />
      <testcase name="is true when temperature alone is set" classname="hasActiveAdvancedFilters" time="0.000036" file="test/sheet.test.ts" line="162" assertions="1" />
      <testcase name="is true when spin alone is set" classname="hasActiveAdvancedFilters" time="0.000019" file="test/sheet.test.ts" line="166" assertions="1" />
      <testcase name="is true when detergentQuery alone is set" classname="hasActiveAdvancedFilters" time="0.000018" file="test/sheet.test.ts" line="170" assertions="1" />
    </testsuite>
    <testsuite name="computeFacets" file="test/sheet.test.ts" line="177" tests="6" assertions="8" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="with no active filters, every field&apos;s facet is exactly the values piles actually use" classname="computeFacets" time="0.000807" file="test/sheet.test.ts" line="178" assertions="3" />
      <testcase name="a machine capability no pile actually uses never appears in its own facet" classname="computeFacets" time="0.000561" file="test/sheet.test.ts" line="188" assertions="1" />
      <testcase name="a field&apos;s own current selection doesn&apos;t narrow its own facet" classname="computeFacets" time="0.000503" file="test/sheet.test.ts" line="201" assertions="1" />
      <testcase name="another field&apos;s active filter narrows a field&apos;s facet live" classname="computeFacets" time="0.000735" file="test/sheet.test.ts" line="213" assertions="1" />
      <testcase name="a combination with no matches leaves the remaining field&apos;s facet empty" classname="computeFacets" time="0.000613" file="test/sheet.test.ts" line="231" assertions="1" />
      <testcase name="respects the pile search, the same as the chart itself" classname="computeFacets" time="0.000567" file="test/sheet.test.ts" line="253" assertions="1" />
    </testsuite>
    <testsuite name="facetOptions" file="test/sheet.test.ts" line="263" tests="4" assertions="4" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="keeps the machine&apos;s own declared order, narrowed to the facet" classname="facetOptions" time="0.000182" file="test/sheet.test.ts" line="264" assertions="1" />
      <testcase name="keeps the current selection visible even once it&apos;s fallen out of the facet" classname="facetOptions" time="0.000036" file="test/sheet.test.ts" line="270" assertions="1" />
      <testcase name="doesn&apos;t duplicate the current selection when it&apos;s already in the facet" classname="facetOptions" time="0.000024" file="test/sheet.test.ts" line="276" assertions="1" />
      <testcase name="is empty when nothing is selected and nothing in the facet matches" classname="facetOptions" time="0.000029" file="test/sheet.test.ts" line="282" assertions="1" />
    </testsuite>
    <testsuite name="every Filters option offered" file="test/sheet.test.ts" line="289" tests="2" assertions="24" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="picked alone, still matches at least one pile" classname="every Filters option offered" time="0.000894" file="test/sheet.test.ts" line="296" assertions="16" />
      <testcase name="after a Programme is picked, each Temperature and Spin still offered matches a pile" classname="every Filters option offered" time="0.000625" file="test/sheet.test.ts" line="316" assertions="8" />
    </testsuite>
    <testsuite name="renderPhone from the web chart" file="test/sheet.test.ts" line="342" tests="3" assertions="3" failures="0" skipped="0" time="4.831" hostname="runnervmtai0g">
      <testcase name="fits the full cut on one page, the same as the CLI" classname="renderPhone from the web chart" time="2.658426" file="test/sheet.test.ts" line="344" assertions="1" />
      <testcase name="fits the wash cut on one page, the same as the CLI" classname="renderPhone from the web chart" time="1.928391" file="test/sheet.test.ts" line="344" assertions="1" />
      <testcase name="fits the iron cut on one page, the same as the CLI" classname="renderPhone from the web chart" time="0.245281" file="test/sheet.test.ts" line="344" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/sheet-lazy-details.test.ts" file="test/sheet-lazy-details.test.ts" tests="5" assertions="10" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="closed card details (server render)" file="test/sheet-lazy-details.test.ts" line="28" tests="1" assertions="3" failures="0" skipped="0" time="0.014" hostname="runnervmtai0g">
      <testcase name="keep the summary but not the body" classname="closed card details (server render)" time="0.014295" file="test/sheet-lazy-details.test.ts" line="29" assertions="3" />
    </testsuite>
    <testsuite name="card details (mounted)" file="test/sheet-lazy-details.test.ts" line="77" tests="4" assertions="7" failures="0" skipped="0" time="0.077" hostname="runnervmtai0g">
      <testcase name="start without a body" classname="card details (mounted)" time="0.009771" file="test/sheet-lazy-details.test.ts" line="78" assertions="3" />
      <testcase name="opening one card renders only that card&apos;s body" classname="card details (mounted)" time="0.028188" file="test/sheet-lazy-details.test.ts" line="84" assertions="2" />
      <testcase name="a body stays rendered after its card is closed again" classname="card details (mounted)" time="0.03083" file="test/sheet-lazy-details.test.ts" line="90" assertions="1" />
      <testcase name="a toggle on a card that is still closed renders nothing" classname="card details (mounted)" time="0.010325" file="test/sheet-lazy-details.test.ts" line="96" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/url-history.test.ts" file="test/url-history.test.ts" tests="12" assertions="14" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="writeUrlFilters" file="test/url-history.test.ts" line="50" tests="12" assertions="14" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="writes a bare pathname, no &apos;?&apos; at all, when every filter is at its default" classname="writeUrlFilters" time="0.000213" file="test/url-history.test.ts" line="51" assertions="1" />
      <testcase name="writes cut only when it isn&apos;t the default &apos;full&apos; cut" classname="writeUrlFilters" time="0.000086" file="test/url-history.test.ts" line="59" assertions="1" />
      <testcase name="a &apos;full&apos; cut is never written to the query string" classname="writeUrlFilters" time="0.000044" file="test/url-history.test.ts" line="67" assertions="1" />
      <testcase name="writes a non-empty pile search" classname="writeUrlFilters" time="0.000036" file="test/url-history.test.ts" line="75" assertions="1" />
      <testcase name="writes a non-empty program filter" classname="writeUrlFilters" time="0.000032" file="test/url-history.test.ts" line="83" assertions="1" />
      <testcase name="writes a non-empty temperature filter" classname="writeUrlFilters" time="0.000034" file="test/url-history.test.ts" line="91" assertions="1" />
      <testcase name="writes a non-empty spin filter" classname="writeUrlFilters" time="0.000033" file="test/url-history.test.ts" line="99" assertions="1" />
      <testcase name="writes a non-empty detergent filter as &apos;detergent&apos;, not its own field name" classname="writeUrlFilters" time="0.000035" file="test/url-history.test.ts" line="107" assertions="1" />
      <testcase name="writes every filter together, in cut/pile/program/temperature/spin/detergent order" classname="writeUrlFilters" time="0.00006" file="test/url-history.test.ts" line="115" assertions="1" />
      <testcase name="URL-encodes a filter value that needs it" classname="writeUrlFilters" time="0.000029" file="test/url-history.test.ts" line="132" assertions="1" />
      <testcase name="preserves whatever pathname window.location currently has" classname="writeUrlFilters" time="0.000027" file="test/url-history.test.ts" line="140" assertions="1" />
      <testcase name="always calls replaceState, never pushState — a filter edit isn&apos;t a new history entry" classname="writeUrlFilters" time="0.000047" file="test/url-history.test.ts" line="148" assertions="3" />
    </testsuite>
  </testsuite>
  <testsuite name="test/custom-config.test.ts" file="test/custom-config.test.ts" tests="7" assertions="8" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="readCustomConfig / writeCustomConfig / clearCustomConfig" file="test/custom-config.test.ts" line="38" tests="6" assertions="6" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="round-trips what was written back to the same config" classname="readCustomConfig / writeCustomConfig / clearCustomConfig" time="0.00058" file="test/custom-config.test.ts" line="39" assertions="1" />
      <testcase name="returns null when nothing has been uploaded yet" classname="readCustomConfig / writeCustomConfig / clearCustomConfig" time="0.000033" file="test/custom-config.test.ts" line="45" assertions="1" />
      <testcase name="falls back to null for a chart that no longer fits the stored machine" classname="readCustomConfig / writeCustomConfig / clearCustomConfig" time="0.000534" file="test/custom-config.test.ts" line="49" assertions="1" />
      <testcase name="falls back to null for a value that isn&apos;t valid JSON" classname="readCustomConfig / writeCustomConfig / clearCustomConfig" time="0.000083" file="test/custom-config.test.ts" line="57" assertions="1" />
      <testcase name="clear removes a previously stored config" classname="readCustomConfig / writeCustomConfig / clearCustomConfig" time="0.000211" file="test/custom-config.test.ts" line="63" assertions="1" />
      <testcase name="reads back whatever is stored under the documented key literally" classname="readCustomConfig / writeCustomConfig / clearCustomConfig" time="0.000361" file="test/custom-config.test.ts" line="71" assertions="1" />
    </testsuite>
    <testsuite name="uploadConfigFile" file="test/custom-config.test.ts" line="78" tests="1" assertions="2" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="parses and stores an uploaded config file, returning the parsed config" classname="uploadConfigFile" time="0.000808" file="test/custom-config.test.ts" line="79" assertions="2" />
    </testsuite>
  </testsuite>
  <testsuite name="test/slug.test.ts" file="test/slug.test.ts" tests="6" assertions="6" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="slug" file="test/slug.test.ts" line="4" tests="6" assertions="6" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="lowercases the name" classname="slug" time="0.000112" file="test/slug.test.ts" line="5" assertions="1" />
      <testcase name="replaces runs of non-alphanumeric characters with a single dash" classname="slug" time="0.000027" file="test/slug.test.ts" line="9" assertions="1" />
      <testcase name="strips leading and trailing dashes rather than leaving them" classname="slug" time="0.000019" file="test/slug.test.ts" line="13" assertions="1" />
      <testcase name="strips diacritics via NFKD normalization, not just passes them through" classname="slug" time="0.000066" file="test/slug.test.ts" line="17" assertions="1" />
      <testcase name="keeps digits, doesn&apos;t treat them as separators" classname="slug" time="0.000018" file="test/slug.test.ts" line="21" assertions="1" />
      <testcase name="collapses a run of separators (spaces and punctuation together) into one dash" classname="slug" time="0.00002" file="test/slug.test.ts" line="25" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/code-split.test.ts" file="test/code-split.test.ts" tests="6" assertions="6" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="SheetViewer" file="test/code-split.test.ts" line="7" tests="2" assertions="2" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="does not statically import @washy-washy/pdf" classname="SheetViewer" time="0.000237" file="test/code-split.test.ts" line="8" assertions="1" />
      <testcase name="loads @washy-washy/pdf dynamically instead" classname="SheetViewer" time="0.000199" file="test/code-split.test.ts" line="18" assertions="1" />
    </testsuite>
    <testsuite name="webmcp" file="test/code-split.test.ts" line="25" tests="4" assertions="4" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="does not statically import @washy-washy/pdf" classname="webmcp" time="0.000148" file="test/code-split.test.ts" line="26" assertions="1" />
      <testcase name="loads @washy-washy/pdf dynamically instead" classname="webmcp" time="0.000135" file="test/code-split.test.ts" line="32" assertions="1" />
      <testcase name="does not statically import @mcp-b/webmcp-polyfill" classname="webmcp" time="0.000144" file="test/code-split.test.ts" line="38" assertions="1" />
      <testcase name="loads @mcp-b/webmcp-polyfill dynamically instead" classname="webmcp" time="0.000124" file="test/code-split.test.ts" line="47" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/analytics.test.ts" file="test/analytics.test.ts" tests="5" assertions="5" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="readUmamiConfig" file="test/analytics.test.ts" line="4" tests="5" assertions="5" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="returns null when neither env var is set — the default, opt-in-only state" classname="readUmamiConfig" time="0.00005" file="test/analytics.test.ts" line="5" assertions="1" />
      <testcase name="returns null when only the script URL is set" classname="readUmamiConfig" time="0.000034" file="test/analytics.test.ts" line="9" assertions="1" />
      <testcase name="returns null when only the website ID is set" classname="readUmamiConfig" time="0.000017" file="test/analytics.test.ts" line="15" assertions="1" />
      <testcase name="returns both values when both env vars are set — self-hosted or cloud, same shape either way" classname="readUmamiConfig" time="0.000027" file="test/analytics.test.ts" line="19" assertions="1" />
      <testcase name="treats an empty string the same as unset" classname="readUmamiConfig" time="0.000017" file="test/analytics.test.ts" line="31" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/locales.test.ts" file="test/locales.test.ts" tests="19" assertions="65" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="NON_DEFAULT_LOCALES" file="test/locales.test.ts" line="18" tests="1" assertions="3" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="is every locale except the default" classname="NON_DEFAULT_LOCALES" time="0.000086" file="test/locales.test.ts" line="19" assertions="3" />
    </testsuite>
    <testsuite name="LOCALE_META" file="test/locales.test.ts" line="28" tests="1" assertions="1" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="has the exact label, htmlLang and dir for every locale" classname="LOCALE_META" time="0.000075" file="test/locales.test.ts" line="29" assertions="1" />
    </testsuite>
    <testsuite name="localeFromPath" file="test/locales.test.ts" line="46" tests="3" assertions="8" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="defaults to English for the root and unprefixed pages" classname="localeFromPath" time="0.000126" file="test/locales.test.ts" line="47" assertions="3" />
      <testcase name="recognises a locale-prefixed path, with or without a trailing slash" classname="localeFromPath" time="0.000046" file="test/locales.test.ts" line="53" assertions="4" />
      <testcase name="doesn&apos;t false-match a page whose name happens to start with a locale code" classname="localeFromPath" time="0.000017" file="test/locales.test.ts" line="60" assertions="1" />
    </testsuite>
    <testsuite name="relativeLocaleUrl" file="test/locales.test.ts" line="66" tests="2" assertions="6" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="leaves English unprefixed" classname="relativeLocaleUrl" time="0.000028" file="test/locales.test.ts" line="67" assertions="2" />
      <testcase name="prefixes every other locale" classname="relativeLocaleUrl" time="0.000038" file="test/locales.test.ts" line="72" assertions="4" />
    </testsuite>
    <testsuite name="absoluteLocaleUrl" file="test/locales.test.ts" line="80" tests="1" assertions="2" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="resolves the relative URL against the given site" classname="absoluteLocaleUrl" time="0.000072" file="test/locales.test.ts" line="81" assertions="2" />
    </testsuite>
    <testsuite name="matchTranslatedPage" file="test/locales.test.ts" line="91" tests="3" assertions="13" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="matches the five translated pages regardless of locale prefix" classname="matchTranslatedPage" time="0.000335" file="test/locales.test.ts" line="92" assertions="11" />
      <testcase name="returns null for pages with no per-locale route" classname="matchTranslatedPage" time="0.000028" file="test/locales.test.ts" line="106" assertions="1" />
      <testcase name="strips every trailing slash, not just one" classname="matchTranslatedPage" time="0.000027" file="test/locales.test.ts" line="110" assertions="1" />
    </testsuite>
    <testsuite name="pagePath" file="test/locales.test.ts" line="115" tests="1" assertions="5" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="round-trips with matchTranslatedPage" classname="pagePath" time="0.00005" file="test/locales.test.ts" line="116" assertions="5" />
    </testsuite>
    <testsuite name="docsHref" file="test/locales.test.ts" line="125" tests="1" assertions="5" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="goes to that locale&apos;s own docs root, Starlight-routed or not" classname="docsHref" time="0.000073" file="test/locales.test.ts" line="126" assertions="5" />
    </testsuite>
    <testsuite name="matchDocsSlug" file="test/locales.test.ts" line="138" tests="4" assertions="13" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="extracts the slug after /docs, English, Starlight-locale-prefixed, or jive&apos;s/linkedin&apos;s own routes" classname="matchDocsSlug" time="0.000147" file="test/locales.test.ts" line="139" assertions="9" />
      <testcase name="returns null off a docs page entirely" classname="matchDocsSlug" time="0.000022" file="test/locales.test.ts" line="151" assertions="2" />
      <testcase name="doesn&apos;t match &apos;docs&apos; as a mere prefix of a longer, unrelated segment" classname="matchDocsSlug" time="0.000015" file="test/locales.test.ts" line="156" assertions="1" />
      <testcase name="doesn&apos;t match &apos;docs&apos; appearing after an unrecognised segment" classname="matchDocsSlug" time="0.000014" file="test/locales.test.ts" line="160" assertions="1" />
    </testsuite>
    <testsuite name="isLocale" file="test/locales.test.ts" line="167" tests="2" assertions="9" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="accepts every configured locale" classname="isLocale" time="0.000075" file="test/locales.test.ts" line="168" assertions="7" />
      <testcase name="rejects anything else" classname="isLocale" time="0.000024" file="test/locales.test.ts" line="174" assertions="2" />
    </testsuite>
  </testsuite>
  <testsuite name="test/changelog.test.ts" file="test/changelog.test.ts" tests="3" assertions="3" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="latestVersion" file="test/changelog.test.ts" line="17" tests="3" assertions="3" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="reads the newest version heading — semantic-release always writes newest-first" classname="latestVersion" time="0.000077" file="test/changelog.test.ts" line="18" assertions="1" />
      <testcase name="returns null when the changelog has no version heading yet" classname="latestVersion" time="0.000023" file="test/changelog.test.ts" line="22" assertions="1" />
      <testcase name="returns null for an empty changelog" classname="latestVersion" time="0.000016" file="test/changelog.test.ts" line="26" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/dial-geometry.test.ts" file="test/dial-geometry.test.ts" tests="3" assertions="3" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="segments" file="test/dial-geometry.test.ts" line="4" tests="3" assertions="3" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="joins each segment as its own M…L subpath" classname="segments" time="0.000098" file="test/dial-geometry.test.ts" line="5" assertions="1" />
      <testcase name="returns an empty path for no segments" classname="segments" time="0.00005" file="test/dial-geometry.test.ts" line="14" assertions="1" />
      <testcase name="rounds coordinates to three decimals, so float noise stays out of the markup" classname="segments" time="0.000033" file="test/dial-geometry.test.ts" line="18" assertions="1" />
    </testsuite>
  </testsuite>
  <testsuite name="test/url.test.ts" file="test/url.test.ts" tests="8" assertions="8" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
    <properties>
      <property name="ci" value="https://github.com/alrayyes/washy-washy-web/actions/runs/40674326052" />
      <property name="commit" value="58b2b6f3b9d8ba8bfcda5664f18d602839ef2c44" />
    </properties>
    <testsuite name="readUrlFilters" file="test/url.test.ts" line="4" tests="8" assertions="8" failures="0" skipped="0" time="0" hostname="runnervmtai0g">
      <testcase name="reads both params from a query string" classname="readUrlFilters" time="0.000114" file="test/url.test.ts" line="5" assertions="1" />
      <testcase name="reads a bare pile with no cut" classname="readUrlFilters" time="0.000055" file="test/url.test.ts" line="9" assertions="1" />
      <testcase name="reads a bare cut with no pile" classname="readUrlFilters" time="0.000024" file="test/url.test.ts" line="13" assertions="1" />
      <testcase name="returns an empty object for no query string at all" classname="readUrlFilters" time="0.000019" file="test/url.test.ts" line="17" assertions="1" />
      <testcase name="ignores a cut that isn&apos;t one of the known variants" classname="readUrlFilters" time="0.000025" file="test/url.test.ts" line="21" assertions="1" />
      <testcase name="decodes a URL-encoded pile search" classname="readUrlFilters" time="0.000019" file="test/url.test.ts" line="25" assertions="1" />
      <testcase name="reads the advanced fields alongside cut and pile" classname="readUrlFilters" time="0.000037" file="test/url.test.ts" line="29" assertions="1" />
      <testcase name="reads a bare advanced field with nothing else present" classname="readUrlFilters" time="0.000023" file="test/url.test.ts" line="44" assertions="1" />
    </testsuite>
  </testsuite>
</testsuites>
