Skip to content

RS-21803: Banded Rows test - #69

Merged
SurreyHughesDisplayr merged 7 commits into
masterfrom
RS-21803-bandedrows
Aug 25, 2026
Merged

RS-21803: Banded Rows test#69
SurreyHughesDisplayr merged 7 commits into
masterfrom
RS-21803-bandedrows

Conversation

@SurreyHughesDisplayr

@SurreyHughesDisplayr SurreyHughesDisplayr commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds unit test coverage for the banded.rows and banded.cols arguments of CreateCustomTable (R/createcustomtable.R).

  • Pins each banding rule as one contiguous exact string — both the odd and even clauses and both fill values — so inserting anything between the clauses, or swapping banded.odd.fill with banded.even.fill, fails the test.
  • Asserts no nth-child rule is emitted at all when banding is off.
  • Pins the column rule verbatim, including the td:nth-child(2n+3) / td:nth-child(even) pair as coded.
  • Asserts banded.odd.fill / banded.even.fill reach both emitted rules. These are separate cata() calls that interpolate the arguments independently, so the row branch, the column branch, and both-at-once are each exercised with non-default values.
  • Asserts that enabling banding removes the configured cell.fill from the celldefault declaration, so the banded background is what shows. Banding wins over cell.fill, not the other way round (createcustomtable.R:397-400 blanks the cell-fill matrix whenever either banding argument is set). Pinned as a single-variable contrast against the unbanded case, where the same cell.fill value does reach the declaration.
  • Asserts the banding rule is emitted once regardless of row count.
  • Extracts the generated container id and asserts the first clause is scoped to it, guarded by expect_length(containerSel, 1).

Pinned production defects

Two tests deliberately pin current buggy behaviour and will fail loudly when fixed. Both are ticketed.

1. The second clause of each banding rule is unscoped — RS-23594. Every other rule this function emits is namespaced under the generated container class. The banding rules are the exception: only the first clause carries the prefix, so tr:nth-child(even) / td:nth-child(even) is emitted bare and applies to every table on the page. Affected tables need neither banding enabled nor to be CreateCustomTable output. Because the odd clause is scoped, the two halves split — unrelated tables pick up the banded fill on even rows only, which reads as inconsistent striping rather than an obvious fault.

2. banded.cols leaves the first column unbanded when row headers are hidden — RS-23595. The selectors assume a row-header cell at nth-child(1). With show.row.headers = FALSE the data columns start at position 1, which matches neither 2n+3 ({3,5,…}) nor even ({2,4,…}). Verified: the emitted rule is byte-identical with and without row headers, so the selectors are not header-aware. The test asserts that equality, which is what trips if anyone makes them adapt.

Plan corrections

Two of the plan's expectations did not survive checking and were corrected rather than encoded:

  • The plan's example CSS strings have no space before ;. cata() writes via cat(..., sep = " "), so real output is background-color: rgb(250,250,250) ; — the plan's string never occurs. Tests pin the real text.
  • The plan records the 2n+3 / even column selectors as overlapping and asks for that to be logged as a defect. They are provably disjoint: 2n+3 = {3, 5, 7, …} and even = {2, 4, …}. With row headers shown the header cell occupies nth-child(1), so data columns land on 2, 3, 4 and alternate correctly. Not a defect — the real defect in that rule is the header-hidden case above, which the plan did not raise.

No production code is changed in this PR.

Jira: https://numbers.atlassian.net/browse/RS-21803

Stacked PR

Based on RS-21803-rowspans (#68), not master — these plans all add tests to tests/testthat/test-createcustomtable.R and share its helpers. #66 has already merged to master, so the remaining merge order is #67, #68, then this. This branch is up to date with its base, and the diff against it is this plan's work only.

Test plan

Rscript -e "devtools::load_all('.'); testthat::test_file('tests/testthat/test-createcustomtable.R')"

188 passing, 0 failures, 0 warnings (48 test_that blocks; 8 added here). Also run under LANGUAGE=fr with identical results.

🤖 Generated with Claude Code

SurreyHughesDisplayr and others added 3 commits August 21, 2026 10:19
Adds unit tests for CreateCustomTable's banded.rows/banded.cols
behaviour: no CSS emitted by default, the odd/even row-banding rule
(pinning the confirmed unscoped tr:nth-child(even) clause), custom
fill colours, per-cell background suppression shared by both flags,
the verbatim td:nth-child(2n+3)/even column rule, both flags
together, and row-count independence of the emitted rule count.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…plan-mistake comment

Pins the whole banded.cols verbatim CSS rule (both the 2n+3 and even
clauses with their fill values) instead of only half of it, and adds a
scoping-leak check mirroring the existing banded.rows one, confirming
the unscoped `td:nth-child(even)` clause is a real, unticketed defect.
Removes the incorrect "defect"/"corrected odd/even split" framing for
the 2n+3/even selector pair, which is disjoint and correct as coded -
that was a plan-authoring mistake, not a production bug. Guards the
container-selector regex extraction with expect_length() so a failed
match can't pass vacuously. Pins the paired custom banded.odd.fill /
banded.even.fill values so swapping them would fail. Tightens two
cell-fill assertions to include the trailing " ;" for anchoring. Moves
the banded.rows/banded.cols section to after the last row.spans test
it had been accidentally inserted into the middle of.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Merge the odd/even grepl pairs for banded.rows (default and custom
fill cases) into single contiguous-string assertions, mirroring the
existing banded.cols test. As two independent greps, inserting
content between the odd and even clauses in production would not
have failed these assertions. Also drop "deliberately" from a
comment asserting unestablished author intent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds characterization tests for row and column banding in CreateCustomTable.

Changes:

  • Verifies generated banding CSS, fill behavior, selector scoping, and defaults.
  • Covers combined banding and row-count independence.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +629 to +633
res <- CreateCustomTable(x2, cell.fill = "rgb(3,3,3)", banded.cols = TRUE)
h <- normWs(tableHtml(res))
expect_true(grepl(paste0("tbody td:nth-child(2n+3){background-color: rgb(250,250,250) ;}",
" td:nth-child(even){background-color: rgb(245,245,245) ;}"),
h, fixed = TRUE))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed by mutation, and it was a real gap. banded.rows and banded.cols are separate cata() calls (createcustomtable.R:626-631) that each interpolate banded.odd.fill/banded.even.fill independently, and only the row branch was exercised with non-default values.

I hard-coded the defaults in the banded.cols call exactly as you describe:

cata(container.selector.name, 'tbody td:nth-child(2n+3){background-color:', 'rgb(250,250,250)',
     ';} td:nth-child(even){background-color:', 'rgb(245,245,245)', ';}')

The suite stayed fully green at 181 passing. Against the same mutant the extended test now fails on 6 assertions.

Added three cases rather than one: banded.cols alone with rgb(1,1,1)/rgb(2,2,2), and banded.rows + banded.cols together. The both-at-once case matters because the two branches take the same argument pair — a regression that forwarded them in only one of the two rules would otherwise still pass the single-branch tests.

188 passing, 0 failures. Production is unchanged; the mutation was reverted.

{
resBanded <- CreateCustomTable(x2, cell.fill = "rgb(3,3,3)", banded.rows = TRUE)
hBanded <- normWs(tableHtml(resBanded))
expect_false(grepl("background: rgb(3,3,3) ;", hBanded, fixed = TRUE))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, the summary had it backwards. The test pins that enabling banding removes the configured cell.fill, not that cell.fill suppresses the banding.

Confirmed in production (createcustomtable.R:397-400):

if (!banded.rows && !banded.cols)
    cell.fill <- matrix(rep(paste("background:", cell.fill, ";"), length = nrows * ncols), nrows, ncols)
else
    cell.fill <- matrix("", nrows, ncols)

Banding wins: the moment either banding argument is set, the cell-fill matrix is blanked, so the banded background is what shows. Summary corrected to say that, with the line reference and a note that the single-variable contrast against the unbanded case is what makes the assertion meaningful — with banded.rows = FALSE the same cell.fill value does reach the celldefault declaration.

The test names themselves already described the right direction ("banded.rows = TRUE drops the per-cell background from the celldefault CSS"), so only the PR body needed the fix.

SurreyHughesDisplayr and others added 3 commits August 25, 2026 15:08
…t column

From a review pass over this PR.

- The beforeEven/afterOddRule assertions in both banding scope tests could not
  fail for the reason they existed. If the even clause ever disappeared,
  regexpr(..., fixed = TRUE) returns -1L, substr(h, 1, -2) yields "", and
  expect_false(grepl(sel, "")) passes trivially. They were also strictly
  weaker than the exact-string pin above them, which asserts the odd selector
  through to the even one as one contiguous string and so already fails the
  moment a container prefix is inserted between the clauses. Removed, keeping
  the genuinely additive assertion that the first clause carries the prefix.

- The comment in the banded.cols test noted that show.row.headers = FALSE
  leaves column 1 matching neither nth-child(2n+3) nor nth-child(even), so the
  first column is never banded - but nothing asserted it, leaving the gap with
  no regression anchor. Added a test asserting the emitted rule is
  byte-identical with and without row headers, which pins the defect and trips
  if anyone makes the selectors header-aware.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both banding defects this file pins were previously marked as having no
ticket, which leaves whoever fixes them facing a red, deliberately-inverted
test with no trail back to why.

- RS-23594: the second clause of each banding rule is emitted without the
  container prefix, so it is not scoped to the table and applies to every
  table on the page.
- RS-23595: the column selectors assume a row-header cell at nth-child(1) and
  are not adjusted when row headers are hidden, so the first data column
  matches neither 2n+3 nor even and is never banded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@SurreyHughesDisplayr
SurreyHughesDisplayr changed the base branch from RS-21803-rowspans to master August 25, 2026 05:27
Responds to a review comment on PR #69.

banded.rows and banded.cols are separate cata() calls
(createcustomtable.R:626-631) that each interpolate banded.odd.fill and
banded.even.fill independently. Only the row branch was exercised with
non-default fills; the banded.cols test used the defaults, so the column
branch could have stopped forwarding those arguments and hard-coded
rgb(250,250,250)/rgb(245,245,245) without any test failing.

Confirmed by mutation: hard-coding the defaults in the banded.cols cata() call
left the suite fully green at 181 passing. The extended test now fails on 6
assertions against the same mutant.

Adds three cases to the custom-fills test: banded.cols alone, and both
banded.rows and banded.cols together, so a regression that forwarded the
arguments in only one of the two rules is caught as well.

188 passing, 0 failures, 0 warnings. R/createcustomtable.R is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chschan chschan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@SurreyHughesDisplayr
SurreyHughesDisplayr merged commit 95fd28e into master Aug 25, 2026
1 check was pending
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants