Guide to testing and review¶
Because of River's structure — a core, plus four supported streams, each with a dark mode version — changes need to consider what other things might be impacted. The goal to ensure that River changes don't break Streams is a driving principle, so it's helpful to know the difference between:
- changes that impact one stream, no streams, all streams.
- changes that impact just one part of the user interface, vs potentially all of it.
This can make the difference between testing one layout in one stream, and doing a Comprehensive Test, which is when enough Core CSS, Primitive and/or Semantic Variables has been changed that the impact cannot be predicted and 'everything' needs re-checking.
Dress Code - an extension to help with UI testing¶
Rich Lott created the Dress Code extension to help with UI testing, and it was developed considerably during the build of River. It provides a series of user-interface snippets - e.g. alerts or buttons - that can be tested quickly with each Stream and light/dark mode.
Comprehensive Testing and Dress Code
Occasionally during the development of River the changes were so broad we would need to do Comprehensive Tests across the CiviCRM interface. While we're trying to stop doing more of these at a core level, it may be that your local changes are significant enough that this is needed. It means checking a range of layouts in each Stream, light and dark mode versions. Dress Code is a big help in this, but it alone isn't enough because it's the combination of different components that sometimes testing.
A comprehensive back-end only test would include in each Stream and light/dark mode every page of Dress Code, as well as the main Civi Dashboard, the Contact Layout (multiple tabs, edited fields and dialogs), Advanced Search, search results, SearchKit builder UX, Form Builder UX, API Explorer, Extensions listing, CiviMail interface, Contribution Dashboard with charts.
A public-facing test would include a Contribution page with all custom field types, an Event page, confirmation screens for both, Form Builder form with multiple field types and column types, and some SearchKit displays with multiple display types (table, list, grid, etc). If it's just for the a custom stream you've made for a specific context, then obviously you need to test only those layouts.
General principles¶
Changes to variables:¶
- Adding new Core variables has no negative impact, but it should be announced in the Changelog.
- Renaming variables in Core is only possible thru a process of deprecation, whereby the old variable name is added to the
/* Deprecated variables */section at the bottom ofcore/css/_variables.csswith a version number for when they were moved there, pointing to the new name. E.g.--crm-old-name: var(--crm-new-name) /* v6.11.0 */;. The change should be declared in the Changelog, and possibly also the User Interface channel. After 12-24 months they can be deleted from this section. - Deleting variables in Core uses a similar process – the variable should be moved to the deprecated variables section with a version number dating the move. The change should also be declared in the Changelog and in public channels.
- Changes to any Custom stream only impact that stream (
streams/[name]/_main.css) - Changes to the core default variables (
core/css/_variables.css) impacts every stream that doesn't override those specific variables. - Only colour variable changes impact dark mode and require dark mode(s) to be checked again.
- The main risk with colour changes is loss of contrast and legibility. This is why it's better to change Semantic colours (e.g.
--crm-info-color) and to check/change its contrast pair at the same time (e.g.--crm-info-text-color). When pairs change together and you're happy the contrast ratio is good enough, then you shouldn't need to test much more than a quick look in Dress Code. - Changes to Primitive Variables are much more impactful than changes to Semantic Variables, which in turn are much more impactful than changes to Component Variables.
- As you'd expect, mostly smaller changes have less consequence than big ones, e.g. changing
--crm-padding-smallfrom0.25remto0.3remwill probably be barely noticeable. A big change like making--crm-container-bg-colorbright green will have contrast issues on almost every screen, and while changing--crm-text-colorshould fix it, that will break other areas where that text-color is on a different background. In this situation it can be helpful to look at dark mode and other Streams to see how they handle large visual changes, then copy their patterns.
To recap, in terms of the amount of the testing potentially needed, at one end a big change to a Primitive colour variable in the Core file will impact most or all Streams, light and dark, in multiple places. At the other end a small change to a Component non-colour variable in a Custom stream should require a very limited amount of testing.
Changes to CSS:¶
- Thames is the only Stream with much custom CSS. Changes to Stream CSS impacts only the stream, and can be limited by tightly targeting the change to a specific selector. CSS is added to Streams at the Stream developer's own risk. The methodology for River is to work hard to avoid breaking variables and how they're used in Streams, but not to worry about local/Stream CSS overrides.
- Removing redundant CSS from River that's not called by CiviCRM is considered safe but should be checked by searching the Git repo of CiviCRM for related class names. However CSS not used by Civi core can still be used by extensions so it's also worth searching lab.civicrm.org/extensions for any CSS selectors that aren't being supported, and it they're used in a popular extension it may be worth either keeping or making a PR to the extension to update their CSS.
- The impact of adding new CSS to River
core/cssdepends on the scope of the changed element. If it's targeting core HTML elements, the changes can be vast. For example.crm-container p {line-height: 1.5};will have countless consequences that need looking at. But.crm-container .crm-some-new-section p {line-height: 1.5};can be quickly tested in that new section and shouldn't leak beyond that. Either change will impact all Streams so it's good practice to test multiple streams. - If new Core CSS is to support a new feature or function in CiviCRM - or add support for something missing in River, and that change is tightly scoped in the CSS selector, then the bar for testing is low. While it's good practice to check that it works in all Streams — the PR doesn't have to demonstrate it works in anything other than Minetta, because the change is going from zero support to default support. This is a decent enough first step, and future PRs can improve support across all Streams.
- The normal behaviour for PRs on core CSS edits: if the change impacts all streams but not in an obviously visible way to only screengrab the change on Minetta (if it's a large change you can always add a few other Stream screengrabs to prove everything is unchanged). If the change has a visible impact it's normal to PR with screengrabs of the changes in each Stream. If it's a colour change with visible impact, then it would be normal to include dark mode screengrabs too.
- If new Core CSS is to change or add to existing CSS in River, more testing is needed.
- If the change is to support a new markup pattern that replaces an old markup pattern which is becoming deprecated the safest approach is to keep backwards compatibility. This is done by moving the old pattern to the
_fixes.cssfile under the appropriate heading, and put the new pattern in the relevant css file. Normally 1-2 years after a markup pattern has been deprecated and doesn't appear in CiviCRM core it could be removed, but it's worth checking the impact on extensions. - When backwards compatibility isn't being kept, the change can be looked at as either 'clean' or 'impactful'. For example:
/* Old CSS */
.crm-classname {
height: 16px
padding: 0;
margin: 8px;
border: 1px dashed blue; /* never shows as is overwritten elsewhere */
}
/* New CSS - restructured impactfully */
.crm-classname {
height: var(--crm-l-reg);
padding: var(--crm-l-medium);
margin: 0;
}
/* New CSS - restructed cleanly */
.crm-classname {
height: var(--crm-l-reg);
padding: 0;
margin: var(--crm-l-medium);
}
In both changes the variables match the original sizes, and the removed declaration was never loading, so nothing obvious has changed. However in the first change swapping padding and margin will have an impact in some contexts, but not in others. As a result the first change would need testing wherever the classname is used. But it should only need testing with one stream and mode, because the change is to length, not colour.
The second change simply swaps hard values for variables with the same values and removes the unused declaration, so only needs basic testing to show that it's been written correctly (it's easy to mis-type variable names).
Cross CMS testing¶
Since the Github Jenkins jobs began to output demos as Standalone CiviCRM the expectation is that changes work in Standalone. There's no documented requirement that UI changes are checked on multiple CMSs, because most changes work the same across all CMS, and it would considerably slow the process down. However it can be useful to use a different local dev environment to Standalone to make sure you test on two different environments.
Things to look out for: - WordPress doesn't have dark mode, and has quite a lot of custom CSS for base HTML elements that interact with River. - Some admin CMS themes, e.g. Drupal's Claro, are quite opinionated and target base HTML elements, such as making table rows extra tall. There are overrides in place for these, but there might be contexts that haven't been spotted yet.
For new CSS, use Baseline: Widely Available
The CSS specification is being regularly updated with new features. To ensure a reliable level of browser support CiviCRM has adopted the Baseline standard: new River CSS should be Baseline: Widely Available which means 30 months have passed since the feature was first available in all browsers. This policy was decided after River's release, as a result it is only fully compliant with this policy from June 2026, because of the use of :has. Streams and Extensions are obviously free to use whatever period of time they wish, but a minimum of Baseline: Newly Available is suggested.