Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 35 additions & 17 deletions src/lib/components/coverage/Coverage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,21 @@ test.describe('loading example file', () => {
let size_column = header.getByRole('columnheader').nth(1)
await expect.soft(size_column).toHaveAccessibleName('Total size')
await expect.soft(size_column).not.toHaveAttribute('aria-sort')
let coverage_column = header.getByRole('columnheader').nth(2)
let line_count_column = header.getByRole('columnheader').nth(2)
await expect.soft(line_count_column).toHaveAccessibleName('Lines')
await expect.soft(line_count_column).not.toHaveAttribute('aria-sort')
let coverage_column = header.getByRole('columnheader').nth(3)
await expect.soft(coverage_column).toHaveAccessibleName('Coverage')
await expect.soft(coverage_column).not.toHaveAttribute('aria-sort')

// Row contents:
let first_row = table.getByRole('row').nth(1)
await expect.soft(first_row.getByRole('cell').nth(0)).toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/0.BBE7cspC.css')
await expect
.soft(first_row.getByRole('cell').nth(0))
.toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/0.BBE7cspC.css')
await expect.soft(first_row.getByRole('cell').nth(1)).toHaveAccessibleName('38 kB')
await expect.soft(first_row.getByRole('cell').nth(2)).toHaveAccessibleName('72.16%')
await expect.soft(first_row.getByRole('cell').nth(2)).toHaveAccessibleName('2,619')
await expect.soft(first_row.getByRole('cell').nth(3)).toHaveAccessibleName('72.16%')

// Elements in correct state:
await expect.soft(table.getByRole('row').nth(1)).toHaveAttribute('aria-selected', 'true')
Expand Down Expand Up @@ -87,19 +93,23 @@ test.describe('loading example file', () => {
await expect.soft(url_header).toHaveAttribute('aria-sort', 'descending')
let first_row = table.getByRole('row').nth(1)
await expect.soft(first_row).toHaveAttribute('aria-selected', 'true')
await expect.soft(first_row.getByRole('cell').nth(0)).toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/Textarea.D3Oc5lUl.css')
await expect
.soft(first_row.getByRole('cell').nth(0))
.toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/Textarea.D3Oc5lUl.css')
await expect.soft(first_row.getByRole('cell').nth(1)).toHaveAccessibleName('238 B')
await expect.soft(first_row.getByRole('cell').nth(2)).toHaveAccessibleName('100%')
await expect.soft(first_row.getByRole('cell').nth(3)).toHaveAccessibleName('100%')
let css_content = await page.getByTestId('pre-css').textContent()
expect.soft(css_content).toContain('textarea.svelte-g7hyhb {')

// Click the same column again to reverse the sort
await url_header.click()
await expect.soft(url_header).toHaveAttribute('aria-sort', 'ascending')
await expect.soft(first_row).toHaveAttribute('aria-selected', 'true')
await expect.soft(first_row.getByRole('cell').nth(0)).toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/0.BBE7cspC.css')
await expect
.soft(first_row.getByRole('cell').nth(0))
.toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/0.BBE7cspC.css')
await expect.soft(first_row.getByRole('cell').nth(1)).toHaveAccessibleName('38 kB')
await expect.soft(first_row.getByRole('cell').nth(2)).toHaveAccessibleName('72.16%')
await expect.soft(first_row.getByRole('cell').nth(3)).toHaveAccessibleName('72.16%')
})

test('sorting by total size', async ({ page }) => {
Expand All @@ -109,44 +119,52 @@ test.describe('loading example file', () => {
await expect.soft(size_header).toHaveAttribute('aria-sort', 'descending')
let first_row = table.getByRole('row').nth(1)
await expect.soft(first_row).toHaveAttribute('aria-selected', 'true')
await expect.soft(first_row.getByRole('cell').nth(0)).toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/0.BBE7cspC.css')
await expect
.soft(first_row.getByRole('cell').nth(0))
.toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/0.BBE7cspC.css')
await expect.soft(first_row.getByRole('cell').nth(1)).toHaveAccessibleName('38 kB')
await expect.soft(first_row.getByRole('cell').nth(2)).toHaveAccessibleName('72.16%')
await expect.soft(first_row.getByRole('cell').nth(3)).toHaveAccessibleName('72.16%')
let css_content = await page.getByTestId('pre-css').textContent()
expect.soft(css_content).toContain('.logo.svelte-1jiwtxp {')

// Click the same column again to reverse the sort
await size_header.click()
await expect.soft(size_header).toHaveAttribute('aria-sort', 'ascending')
await expect.soft(first_row).toHaveAttribute('aria-selected', 'true')
await expect.soft(first_row.getByRole('cell').nth(0)).toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/FormattedDate.JHv9Zh3p.css')
await expect
.soft(first_row.getByRole('cell').nth(0))
.toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/FormattedDate.JHv9Zh3p.css')
await expect.soft(first_row.getByRole('cell').nth(1)).toHaveAccessibleName('69 B')
await expect.soft(first_row.getByRole('cell').nth(2)).toHaveAccessibleName('100%')
await expect.soft(first_row.getByRole('cell').nth(3)).toHaveAccessibleName('100%')
css_content = await page.getByTestId('pre-css').textContent()
expect.soft(css_content).toContain('time.svelte-60ldmz {')
})

test('sorting by coverage', async ({ page }) => {
let header = table.getByRole('row').first()
let coverage_header = header.getByRole('columnheader').nth(2)
let coverage_header = header.getByRole('columnheader').nth(3)
await coverage_header.click()
await expect.soft(coverage_header).toHaveAttribute('aria-sort', 'descending')
let first_row = table.getByRole('row').nth(1)
await expect.soft(first_row).toHaveAttribute('aria-selected', 'true')
await expect.soft(first_row.getByRole('cell').nth(0)).toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/23.lTvFD_l9.css')
await expect
.soft(first_row.getByRole('cell').nth(0))
.toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/23.lTvFD_l9.css')
await expect.soft(first_row.getByRole('cell').nth(1)).toHaveAccessibleName('405 B')
await expect.soft(first_row.getByRole('cell').nth(2)).toHaveAccessibleName('100%')
await expect.soft(first_row.getByRole('cell').nth(3)).toHaveAccessibleName('100%')
let css_content = await page.getByTestId('pre-css').textContent()
expect.soft(css_content).toContain('.form.svelte-148ca8f {')

// Click the same column again to reverse the sort
await coverage_header.click()
await expect.soft(coverage_header).toHaveAttribute('aria-sort', 'ascending')
await expect.soft(first_row).toHaveAttribute('aria-selected', 'true')
await expect.soft(first_row.getByRole('cell').nth(0)).toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/25.C4edrrKC.css')
await expect
.soft(first_row.getByRole('cell').nth(0))
.toHaveAccessibleName('https://www.projectwallace.com/_app/immutable/assets/25.C4edrrKC.css')
await expect.soft(first_row.getByRole('cell').nth(1)).toHaveAccessibleName('780 B')
await expect.soft(first_row.getByRole('cell').nth(2)).toHaveAccessibleName('0%')
await expect.soft(first_row.getByRole('cell').nth(3)).toHaveAccessibleName('0%')
css_content = await page.getByTestId('pre-css').textContent()
expect.soft(css_content).toContain('.page.svelte-1b1m7j9 {')
})
})
})
50 changes: 38 additions & 12 deletions src/lib/components/coverage/Coverage.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { PaneGroup, Pane, PaneResizer } from 'paneforge'
import { format_filesize } from '$lib/format-filesize'
import { format_percentage } from '$lib/format-number'
import { format_number, format_percentage } from '$lib/format-number'
import { create_keyboard_list } from '$components/use-keyboard-list.svelte'
import Panel from '$components/Panel.svelte'
import Meter from '$components/Meter.svelte'
Expand All @@ -23,7 +23,12 @@
} = create_keyboard_list()
let selected_index = $state(0)

let calculated = $derived(calculate_coverage(browser_coverage))
function parse_html(html: string) {
let parser = new DOMParser()
return parser.parseFromString(html, 'text/html')
}

let calculated = $derived(calculate_coverage(browser_coverage, parse_html))

let max_lines = $derived.by(() => {
let max = 0
Expand All @@ -39,7 +44,7 @@
selected_index = active_index
}

let sort_by = $state<'bytes' | 'coverage' | 'name' | undefined>(undefined)
let sort_by = $state<'bytes' | 'coverage' | 'name' | 'lines' | undefined>(undefined)
let sort_direction = $state<'asc' | 'desc'>('asc')

let sorted_items = $derived.by(() => {
Expand All @@ -60,6 +65,9 @@
if (sort_by === 'name') {
return sort_direction === 'asc' ? string_sort(a.url, b.url) : string_sort(b.url, a.url)
}
if (sort_by === 'lines') {
return sort_direction === 'asc' ? a.covered_lines - b.covered_lines : b.covered_lines - a.covered_lines
}
return 0
})
})
Expand All @@ -76,7 +84,7 @@
})
</script>

{#snippet sorted_th(name: 'bytes' | 'coverage' | 'name', label: string)}
{#snippet sorted_th(name: 'bytes' | 'coverage' | 'name' | 'lines', label: string)}
{@const sort_by_attr = sort_by === name ? (sort_direction === 'asc' ? 'ascending' : 'descending') : undefined}
<th scope="col" aria-sort={sort_by_attr}>
<button
Expand All @@ -103,18 +111,22 @@
<div>
<dt>Coverage</dt>
<dd>{format_percentage(calculated.coverage_ratio)}</dd>
<dd>{format_percentage(calculated.line_coverage)} of lines</dd>
</div>
<div>
<dt>Total size</dt>
<dt>Total</dt>
<dd>{format_filesize(calculated.used_bytes + calculated.unused_bytes)}</dd>
<dd>{format_number(calculated.total_lines)} lines</dd>
</div>
<div>
<dt>Used</dt>
<dd>{format_filesize(calculated.used_bytes)}</dd>
<dd>{format_number(calculated.covered_lines)} lines</dd>
</div>
<div>
<dt>Unused</dt>
<dd>{format_filesize(calculated.unused_bytes)}</dd>
<dd>{format_number(calculated.uncovered_lines)} lines</dd>
</div>
</div>
</Panel>
Expand All @@ -123,14 +135,15 @@
<h2 class="sr-only">Coverage per stylesheet</h2>
<div class="devtools" data-empty={calculated.coverage_per_stylesheet.length === 0 ? 'true' : 'false'}>
{#if calculated.coverage_per_stylesheet.length > 0}
<PaneGroup direction="horizontal">
<PaneGroup direction="horizontal" autoSaveId="css-coverage">
<Pane defaultSize={50} minSize={20}>
<Table>
<caption class="sr-only">Coverage per origin</caption>
<thead>
<tr>
{@render sorted_th('name', 'URL')}
{@render sorted_th('bytes', 'Total size')}
{@render sorted_th('lines', 'Lines')}
{@render sorted_th('coverage', 'Coverage')}
<th scope="col">Coverage visualized</th>
</tr>
Expand All @@ -139,12 +152,13 @@
<tbody use:root={{ onchange }} style:--meter-height="0.5rem">
{#each sorted_items as item_index, index}
{@const stylesheet = calculated.coverage_per_stylesheet[item_index]}
{@const { url, total_bytes, coverage_ratio } = stylesheet}
<tr use:item={{ value: index.toString() }} aria-selected={selected_index === index ? 'true': 'false'}>
{@const { url, total_bytes, total_lines, coverage_ratio, covered_lines } = stylesheet}
<tr use:item={{ value: index.toString() }} aria-selected={selected_index === index ? 'true' : 'false'}>
<td class="url">
{url}
</td>
<td class="numeric">{format_filesize(total_bytes)}</td>
<td class="numeric">{format_number(total_lines)}</td>
<td class="numeric">{format_percentage(coverage_ratio)}</td>
<td>
<div style:width={(stylesheet.total_lines / max_lines) * 100 + '%'}>
Expand Down Expand Up @@ -223,6 +237,11 @@
flex-direction: row;
justify-content: space-between;
}

& > div {
display: grid;
row-gap: var(--space-2);
}
}

.css-slide {
Expand All @@ -231,15 +250,16 @@
border-inline-start: 1px solid var(--fg-450);
}

dt {
dt,
dd:last-of-type {
text-transform: uppercase;
color: var(--fg-300);
font-weight: var(--font-bold);
font-size: var(--size-sm);
}

dd {
font-size: var(--size-5xl);
dd:first-of-type {
font-size: var(--size-4xl);
line-height: var(--leading-none);
font-weight: var(--font-ultrabold);
color: var(--fg-0);
Expand All @@ -263,7 +283,13 @@
}

tr {
--meter-bg: var(--bg-500);
--meter-bg: repeating-linear-gradient(
-45deg,
var(--error-400),
var(--error-400) 3px,
var(--error-200) 3px,
var(--error-200) 6px
);
}

.sort-button {
Expand Down
Loading
Loading