Repository navigation
Theme: Add tests for ThemeProvider and useThemeProviderStyles #79126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
8e680fb
Theme: Add tests for ThemeProvider and useThemeProviderStyles
ciampo 845cdc1
Theme: Strengthen ThemeProvider scoping assertions in tests
ciampo 41baa72
Theme: Fix package-lock.json sync for new test devDependencies
ciampo a8bcb48
Theme: Add CHANGELOG entry for ThemeProvider tests
ciampo 4a38b6c
Theme: Assert computed custom properties in ThemeProvider tests
ciampo 1a4a177
Theme: Assert the semantic brand token instead of the legacy one
ciampo 9b6eacf
Theme: Assert token equals the primary seed for in-gamut brand colors
ciampo b86c4d0
Theme: Cover the background color prop and partial overrides
ciampo 4110a90
Theme: Refocus useThemeProviderStyles tests on its resolution contract
ciampo d0ca318
Theme: Consolidate ThemeProvider color and nesting tests
ciampo 6b0eb0e
Theme: Use CSSProperties type in useThemeProviderStyles tests
ciampo dc8ee05
Theme: Add cornerRadius coverage to ThemeProvider tests
ciampo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| // These tests read the resolved CSS custom properties produced by the provider. | ||
| // jsdom does not cascade custom properties to descendant elements, so the value | ||
| // is asserted on the provider's own scoping element (where the property is | ||
| // defined and from which real children would inherit) and on the document root. | ||
|
|
||
| import { render, screen } from '@testing-library/react'; | ||
| import { ThemeProvider } from '../theme-provider'; | ||
|
|
||
| // Mock the CSS module so the provider's scoping class is a real, stable class | ||
| // name. Without this the global Jest CSS mock leaves the class `undefined`, and | ||
| // jsdom cannot match the generated rules to compute the custom properties. | ||
| jest.mock( '../style.module.css', () => ( { | ||
| root: 'theme-provider-root', | ||
| } ) ); | ||
|
|
||
| // The "strong" brand background resolves to the `color.primary` seed itself, and | ||
| // the neutral surface resolves to the `color.background` seed itself, which makes | ||
| // the expected values predictable. (Extreme seeds get snapped into the accessible | ||
| // ramp, so the seeds below are deliberately mid-range/light hex values that | ||
| // round-trip. Ramp generation itself is covered by the color-ramps tests.) | ||
| const BRAND_BG = '--wpds-color-background-interactive-brand-strong'; | ||
| const SURFACE_BG = '--wpds-color-background-surface-neutral'; | ||
| const CURSOR_CONTROL = '--wpds-cursor-control'; | ||
| const PRIMARY = '#1e90ff'; | ||
| const OTHER_PRIMARY = '#8e44ad'; | ||
| const BACKGROUND = '#f8f8f8'; | ||
|
|
||
| function readProp( element: Element, property: string ) { | ||
| return getComputedStyle( element ).getPropertyValue( property ).trim(); | ||
| } | ||
|
|
||
| // The `ThemeProvider` wrapper element that scopes the given descendant. | ||
| function getScopingProvider( element: Element ) { | ||
| return element.closest< HTMLElement >( '[data-wpds-theme-provider-id]' )!; | ||
| } | ||
|
|
||
| describe( 'ThemeProvider', () => { | ||
| it( 'renders its children', () => { | ||
| render( <ThemeProvider>content</ThemeProvider> ); | ||
|
|
||
| expect( screen.getByText( 'content' ) ).toBeInTheDocument(); | ||
| } ); | ||
|
|
||
| it( 'defines the color tokens from the seeds within its subtree', () => { | ||
| render( | ||
| <ThemeProvider | ||
| color={ { primary: PRIMARY, background: BACKGROUND } } | ||
| > | ||
| <div data-testid="child">x</div> | ||
| </ThemeProvider> | ||
| ); | ||
|
|
||
| const provider = getScopingProvider( screen.getByTestId( 'child' ) ); | ||
| expect( readProp( provider, BRAND_BG ) ).toBe( PRIMARY ); | ||
| expect( readProp( provider, SURFACE_BG ) ).toBe( BACKGROUND ); | ||
| } ); | ||
|
|
||
| it( 'does not define the custom property outside of the provider', () => { | ||
| render( | ||
| <ThemeProvider color={ { primary: PRIMARY } }> | ||
| <div data-testid="child">x</div> | ||
| </ThemeProvider> | ||
| ); | ||
|
|
||
| const outside = document.createElement( 'div' ); | ||
| document.body.appendChild( outside ); | ||
|
|
||
| expect( readProp( outside, BRAND_BG ) ).toBe( '' ); | ||
| } ); | ||
|
|
||
| it( 'applies the cursor custom property when set', () => { | ||
| render( | ||
| <ThemeProvider cursor={ { control: 'pointer' } }> | ||
| <div data-testid="child">x</div> | ||
| </ThemeProvider> | ||
| ); | ||
|
|
||
| const provider = getScopingProvider( screen.getByTestId( 'child' ) ); | ||
| expect( readProp( provider, CURSOR_CONTROL ) ).toBe( 'pointer' ); | ||
| } ); | ||
|
|
||
| describe( 'cornerRadius', () => { | ||
| it( 'reflects the preset as a data attribute', () => { | ||
| render( | ||
| <ThemeProvider cornerRadius="pronounced"> | ||
| <div data-testid="child">x</div> | ||
| </ThemeProvider> | ||
| ); | ||
|
|
||
| expect( | ||
| getScopingProvider( screen.getByTestId( 'child' ) ) | ||
| ).toHaveAttribute( 'data-wpds-corner-radius', 'pronounced' ); | ||
| } ); | ||
|
|
||
| it( 'defaults to the subtle preset', () => { | ||
| render( | ||
| <ThemeProvider> | ||
| <div data-testid="child">x</div> | ||
| </ThemeProvider> | ||
| ); | ||
|
|
||
| expect( | ||
| getScopingProvider( screen.getByTestId( 'child' ) ) | ||
| ).toHaveAttribute( 'data-wpds-corner-radius', 'subtle' ); | ||
| } ); | ||
| } ); | ||
|
|
||
| describe( 'isRoot', () => { | ||
| it( 'defines the token on the document root', () => { | ||
| render( | ||
| <ThemeProvider isRoot color={ { primary: PRIMARY } }> | ||
| <div>x</div> | ||
| </ThemeProvider> | ||
| ); | ||
|
|
||
| expect( readProp( document.documentElement, BRAND_BG ) ).toBe( | ||
| PRIMARY | ||
| ); | ||
| } ); | ||
|
|
||
| it( 'does not affect the document root by default', () => { | ||
| render( | ||
| <ThemeProvider color={ { primary: PRIMARY } }> | ||
| <div>x</div> | ||
| </ThemeProvider> | ||
| ); | ||
|
|
||
| expect( readProp( document.documentElement, BRAND_BG ) ).toBe( '' ); | ||
| } ); | ||
| } ); | ||
|
|
||
| describe( 'nested providers', () => { | ||
|
ciampo marked this conversation as resolved.
|
||
| it( 'overrides the settings it defines and inherits the rest', () => { | ||
| render( | ||
| <ThemeProvider | ||
| color={ { primary: PRIMARY, background: BACKGROUND } } | ||
| cursor={ { control: 'pointer' } } | ||
| cornerRadius="pronounced" | ||
| > | ||
| <ThemeProvider> | ||
| <div data-testid="inheriting">a</div> | ||
| </ThemeProvider> | ||
| <ThemeProvider color={ { primary: OTHER_PRIMARY } }> | ||
| <div data-testid="overriding">b</div> | ||
| </ThemeProvider> | ||
| </ThemeProvider> | ||
| ); | ||
|
|
||
| const inheriting = getScopingProvider( | ||
| screen.getByTestId( 'inheriting' ) | ||
| ); | ||
| const overriding = getScopingProvider( | ||
| screen.getByTestId( 'overriding' ) | ||
| ); | ||
|
|
||
| // A nested provider with no settings of its own inherits everything. | ||
| expect( readProp( inheriting, BRAND_BG ) ).toBe( PRIMARY ); | ||
| expect( readProp( inheriting, SURFACE_BG ) ).toBe( BACKGROUND ); | ||
| expect( readProp( inheriting, CURSOR_CONTROL ) ).toBe( 'pointer' ); | ||
| expect( inheriting ).toHaveAttribute( | ||
| 'data-wpds-corner-radius', | ||
| 'pronounced' | ||
| ); | ||
|
|
||
| // A nested provider overrides only what it defines (`primary`), | ||
| // inheriting the rest (`background`, `cursor`, `cornerRadius`). | ||
| expect( readProp( overriding, BRAND_BG ) ).toBe( OTHER_PRIMARY ); | ||
| expect( readProp( overriding, SURFACE_BG ) ).toBe( BACKGROUND ); | ||
| expect( readProp( overriding, CURSOR_CONTROL ) ).toBe( 'pointer' ); | ||
| expect( overriding ).toHaveAttribute( | ||
| 'data-wpds-corner-radius', | ||
| 'pronounced' | ||
| ); | ||
| } ); | ||
| } ); | ||
| } ); | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this dependency? I don't see that we're using it? Or is it used indirectly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need it because it's a mandatory peer dependency of
@testing-library/react@16, every other Gutenberg package usingreact-testing-librarydeclares it