Unit tests and parsing
Code makes many decisions before and after the model. These tests check that code. The results are from the build of
this site.
168 of 168 unit tests pass.
Tables the extension skips
Before any question goes to the model, code drops tables that are not data. The model never sees these tables, thus no
check above covers them. The browser tests check each rule on a synthetic page.
- Tables marked
role="presentation", and tables that contain other tables: page layout. - Tables in an editable region, because an editor would save the shading with the document.
- App lists, such as a mail inbox. Such a table is marked
role="grid", has a checkbox or button in every
row, and has no header row. All three must be true. A data grid with a header row is still shaded, even with a
checkbox in every row. - Tables with fewer than two rows or two columns.
Parsing
The parser changes cell text into numbers and dates. Each row below is the output of parseNumber and parseDate during the build. Text that is not clear becomes no value, thus it cannot change a scale.
Test files
admit.test.ts 3 of 3
| Pass | rate-limits an IPv6 address by its /64 prefix | 1 ms |
| Pass | rate-limits an IPv4 address by the whole address | <1 ms |
| Pass | compares a bearer token with the secret | 13 ms |
allow.test.ts 8 of 8
The free endpoint accepts each request that the extension sends on the test pages. It refuses all other requests.
| Pass | accepts every request the extension sends for the fixture pages | 388 ms |
| Pass | accepts the extension's wording with any header | <1 ms |
| Pass | refuses questions the extension doesn't ask | <1 ms |
| Pass | clips long table data instead of refusing it | <1 ms |
| Pass | refuses table data with a shape that the extension's builders don't produce | <1 ms |
| Pass | refuses a state with a shape that the extension's builders don't produce | <1 ms |
| Pass | clips harder when the table data is too large in total | 15 ms |
| Pass | reads a JSON body up to the byte limit | 3 ms |
allowance.test.ts 4 of 4
The free daily allowance as the reader sees it: the requests that remain, the reset time, and the text.
| Pass | the reset is the next UTC midnight, shown in local time | 14 ms |
| Pass | the lowest count reported today wins; a new day starts over | <1 ms |
| Pass | a note appears only when under a fifth of today's allowance is left | <1 ms |
| Pass | used-up messages say whose allowance it was and when it resets | <1 ms |
cache.test.ts 2 of 2
| Pass | a stored answer reads back | 7 ms |
| Pass | concurrent writes stay within the cap | 4022 ms |
concurrency.test.ts 5 of 5
| Pass | results come back in item order, with at most `limit` calls running | 37 ms |
| Pass | an empty list resolves at once | 1 ms |
| Pass | the first failure rejects, aborts the running calls, and starts no more | 7 ms |
| Pass | an abort of the outer signal reaches the calls | <1 ms |
| Pass | sleep rejects with the signal's reason when it aborts | <1 ms |
dates.test.ts 16 of 16
Cell text to dates: calendar dates, months, times with offsets, and relative times such as 3 days ago. Day and month order for numeric dates. The text that must not become a date.
| Pass | parses calendar dates in common formats | 4 ms |
| Pass | parses months without a day | <1 ms |
| Pass | parses times of day, offsets, and two-digit years | <1 ms |
| Pass | relative times count back from now | <1 ms |
| Pass | rejects strings that are not dates | <1 ms |
| Pass | numeric dates need a column to tell day from month | <1 ms |
| Pass | a column of dates: missing cells, units, and the share needed | <1 ms |
| Pass | formats legend text at the column's precision | 14 ms |
| Pass | dates without a year take one from their column | <1 ms |
| Pass | a sorted column of dates without years crosses New Year once | <1 ms |
| Pass | ignores notes in parentheses and reads ranges of days as their midpoint | 3 ms |
| Pass | words that name Object.prototype members are not dates | <1 ms |
| Pass | cells far longer than any date return null | 1 ms |
| Pass | a date with a long trailing note still parses | <1 ms |
| Pass | a weekday and a clock time without a date is a time in a week | <1 ms |
| Pass | a column of weekday times starts its week after its longest gap | <1 ms |
flags.test.ts 5 of 5
Flags from the dev build: the issue that a flag files, and the order of the calls to GitHub. The store build has no flags.
| Pass | a flag's issue names the host and lists the judged columns | 1 ms |
| Pass | a skipped table without a screenshot says so and has no image | <1 ms |
| Pass | flag ids sort by time | <1 ms |
| Pass | filing writes the context and screenshot, then opens the issue | 30 ms |
| Pass | a GitHub error stops the flag | 1 ms |
judge.test.ts 16 of 16
The judge, with answers supplied by code. Code ignores identifiers and two-level labels. Shared scales. Rows that sum the other rows are totals. One failed table does not stop the other tables.
| Pass | judges price and category columns, sharing scales across tables | 35 ms |
| Pass | declines numeric columns the model calls identifiers | 1 ms |
| Pass | drops two-level ordinals unless a shared scale widens them | 4 ms |
| Pass | a failed share request keeps per-table scales instead of failing the page | 2 ms |
| Pass | one table's failure leaves the other tables judged | 2 ms |
| Pass | unordered label columns never send pairwise order questions | 1 ms |
| Pass | never offers a share for same-named columns of different magnitude | 2 ms |
| Pass | columns on one shared scale share one direction | <1 ms |
| Pass | brackets that name the rows are ignored; brackets that are values are shaded | 6 ms |
| Pass | ranks that count the rows, and ranks that don't | <1 ms |
| Pass | ranks in row order are ignored; ranks out of row order are shaded, on a linear scale | 2 ms |
| Pass | date columns are shaded by code, never asked about, and never shared | 1 ms |
| Pass | a shared ordinal scale too wide to reorder leaves each table its own order | 2 ms |
| Pass | a row whose numbers add up to the other rows is a total | <1 ms |
| Pass | a row labeled Total needs only one column to add up | <1 ms |
| Pass | a total found by code is left out of the domain even when the model calls it an entry | <1 ms |
legend.test.ts 6 of 6
The card that shows when you put the pointer on a header: ranges and units for shared, log, ranked, and duration columns, and the totals that are not on the scale.
| Pass | a shared, log-scaled price column | 15 ms |
| Pass | a linear column that excludes a totals row | <1 ms |
| Pass | ranked categories show their first and last level as extents | <1 ms |
| Pass | duration extents read back as clock values | <1 ms |
| Pass | a date column reads as dates, earliest to latest | 5 ms |
| Pass | a column of times without dates reads as times | <1 ms |
model.test.ts 7 of 7
Validation of answers, and the quota and allowance values from the free endpoint.
| Pass | accepts answers that match the questions asked | 1 ms |
| Pass | rejects missing answers, wrong types, unknown options and out-of-range probabilities | <1 ms |
| Pass | a spent hosted allowance fails at once as quota, without waiting or retrying | 40 ms |
| Pass | a spent allowance for everyone is told apart from this install's own | 2 ms |
| Pass | hosted responses report what's left of the allowance; cache hits report nothing | 4 ms |
| Pass | the hosted endpoint retries a 503 only once, because each attempt spends from the allowance | 279 ms |
| Pass | Jev retries a 503 four times | 3770 ms |
order.test.ts 4 of 4
The label order from pair answers, also when some answers disagree.
| Pass | recovers the true order from consistent pairs | 1 ms |
| Pass | a contradictory non-adjacent comparison does not flip the order | <1 ms |
| Pass | places are ordered by their numbers, worst first | <1 ms |
| Pass | labels that are not all places get no code order | <1 ms |
orient.test.ts 1 of 1
Row-based tables, read one row at a time.
| Pass | transposes a benchmark table so each benchmark becomes a column | 1 ms |
pace.test.ts 3 of 3
| Pass | one change sends one request after the first wait | 2 ms |
| Pass | a cell that changes every second for an hour sends at most 25 requests | 3 ms |
| Pass | after a quiet period, a change waits only the first delay again | <1 ms |
parse.test.ts 59 of 59
Cell text to numbers: currencies, percentages, suffixes, durations, ranges, and bounds. Also the text that must not become a number.
| Pass | parseNumber("$0.25") | 3 ms |
| Pass | parseNumber("6½") | <1 ms |
| Pass | parseNumber("½") | <1 ms |
| Pass | parseNumber("51½") | <1 ms |
| Pass | parseNumber("8 1⁄2") | 1 ms |
| Pass | parseNumber("1⁄2") | <1 ms |
| Pass | parseNumber("22 3⁄4") | <1 ms |
| Pass | parseNumber("81⁄2") | <1 ms |
| Pass | parseNumber("$14.00") | <1 ms |
| Pass | parseNumber("€1,200.50") | <1 ms |
| Pass | parseNumber("-$3") | <1 ms |
| Pass | parseNumber("($3.00)") | <1 ms |
| Pass | parseNumber("45%") | <1 ms |
| Pass | parseNumber("45.2 %") | <1 ms |
| Pass | parseNumber("0.33x") | <1 ms |
| Pass | parseNumber(".312") | <1 ms |
| Pass | parseNumber("−0.5") | <1 ms |
| Pass | parseNumber("1,425,671,352") | <1 ms |
| Pass | parseNumber("1,234[12]") | <1 ms |
| Pass | parseNumber("≤ 272K") | <1 ms |
| Pass | parseNumber("$1.5B") | <1 ms |
| Pass | parseNumber("12 GB") | <1 ms |
| Pass | parseNumber("3.2 GHz") | <1 ms |
| Pass | parseNumber("2024") | <1 ms |
| Pass | parseNumber("42*") | <1 ms |
| Pass | parseNumber("6' 6\\"") | <1 ms |
| Pass | parseNumber("6'0\\"") | <1 ms |
| Pass | parseNumber("5′ 11″") | <1 ms |
| Pass | parseNumber("6 ft 2 in") | <1 ms |
| Pass | parseNumber("20-25") | <1 ms |
| Pass | parseNumber("26–30") | <1 ms |
| Pass | parseNumber("$10 to $20") | <1 ms |
| Pass | parseNumber("1.5-2.5 GB") | <1 ms |
| Pass | parseNumber("65+") | <1 ms |
| Pass | parseNumber("1M+") | <1 ms |
| Pass | parseNumber("$500K+") | <1 ms |
| Pass | parseNumber("35-10") | <1 ms |
| Pass | parseNumber("6-6") | <1 ms |
| Pass | parseNumber("2024-01") | <1 ms |
| Pass | parseNumber("2:59") | <1 ms |
| Pass | parseNumber("3:00") | <1 ms |
| Pass | parseNumber("0:57") | <1 ms |
| Pass | parseNumber("1:02:03") | <1 ms |
| Pass | parseNumber("1544:10") | <1 ms |
| Pass | parseNumber("12345:00") | <1 ms |
| Pass | parseNumber("1200:1") | <1 ms |
| Pass | parseNumber("2:61") | <1 ms |
| Pass | parseNumber("7:05 PM") | <1 ms |
| Pass | parseNumber("1st") | <1 ms |
| Pass | parseNumber("3–4") | <1 ms |
| Pass | parseNumber("2024-01-02") | <1 ms |
| Pass | parseNumber("1:23.45") | <1 ms |
| Pass | parseNumber("GPT-5 mini") | <1 ms |
| Pass | parseNumber("Not applicable") | <1 ms |
| Pass | a value followed by the condition it holds under parses to the value | <1 ms |
| Pass | isMissing recognizes placeholders | <1 ms |
| Pass | clock-like durations are numbers; times of day stay dates | <1 ms |
| Pass | a unit that names an Object.prototype member is a unit, not a magnitude | <1 ms |
| Pass | a value followed by a signed change parses as the value | <1 ms |
profile.test.ts 7 of 7
Column profiles: kind, spread, unit, ranks, years, and label order. Dates do not go to the model.
| Pass | profiles each column by kind | 8 ms |
| Pass | numeric profile reports spread, unit, rank and year hints | 19 ms |
| Pass | categorical profile keeps first-seen level order and display text | 1 ms |
| Pass | timestamps and dates are not offered as categories or numbers | <1 ms |
| Pass | labels that name Object.prototype members are levels like any other | <1 ms |
| Pass | a win/loss streak column reads as wins minus losses | <1 ms |
| Pass | a value with its rank in parentheses reads as the value when the ranks follow the values | <1 ms |
quota.test.ts 4 of 4
| Pass | counts requests per install up to the daily limit | 2 ms |
| Pass | gives back a request that failed upstream, with its estimated tokens | <1 ms |
| Pass | refuses every install once the token budget is spent | <1 ms |
| Pass | counts estimated tokens for requests in flight against the budget | <1 ms |
scale.test.ts 7 of 7
Values to positions to colors, for each palette.
| Pass | lower-is-better puts the cheapest row at t=1 (the good end) | 1 ms |
| Pass | log transform centers the geometric midpoint | <1 ms |
| Pass | excluded aggregate rows get no position | <1 ms |
| Pass | ordinal levels spread evenly from 0 to 1 | <1 ms |
| Pass | every palette has full-strength ends, and fading ramps leave the middle plain | 1 ms |
| Pass | on dark pages, single-hue scales ramp up from the background | <1 ms |
| Pass | isPaletteId accepts palette names only | <1 ms |
settings.test.ts 5 of 5
| Pass | local and private-network hosts are private | 1 ms |
| Pass | public hosts are not private | <1 ms |
| Pass | in every-site mode, a private host is off until the user turns it on | <1 ms |
| Pass | turning a public host off and on again in every-site mode | <1 ms |
| Pass | in chosen-sites mode, private and public hosts are off until the user turns them on | <1 ms |
tint.test.ts 1 of 1
Colors on the page background. For each palette, step, and page, the text contrast stays at 5:1 or more. If not, the cell is not shaded.
| Pass | text keeps 5:1 contrast on every palette, step, and page, or the cell is left plain | 18 ms |
usage.test.ts 5 of 5
| Pass | a model answer records its tokens and the install's count today | 35 ms |
| Pass | a cache hit records no tokens and no count | <1 ms |
| Pass | a refusal records its error code | <1 ms |
| Pass | an upstream refusal records the provider's status | <1 ms |
| Pass | other routes and unreadable bodies | 3 ms |