-
Notifications
You must be signed in to change notification settings - Fork 23
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
feat(components/core): add SkyMediaQueryController
to interact with breakpoints in tests
#2802
base: main
Are you sure you want to change the base?
Conversation
☁️ Nx Cloud ReportCI is running/has finished running commands for commit 5529153. As they complete they will appear below. Click to see the status, the terminal output, and the build insights. 📂 See all runs for this CI Pipeline Execution ✅ Successfully ran 2 targetsSent with 💌 from NxCloud. |
libs/components/core/src/lib/modules/breakpoint-observer/provide-breakpoint-observer.ts
Show resolved
Hide resolved
libs/components/core/testing/src/media-query/media-query-testing-controller.ts
Show resolved
Hide resolved
libs/components/core/testing/src/media-query/provide-media-query-testing.ts
Show resolved
Hide resolved
libs/components/split-view/src/lib/modules/split-view/split-view-workspace.component.ts
Show resolved
Hide resolved
libs/components/core/src/lib/modules/breakpoint-observer/responsive-host.directive.ts
Show resolved
Hide resolved
libs/components/core/src/lib/modules/breakpoint-observer/container-breakpoint-observer.ts
Show resolved
Hide resolved
libs/components/core/src/lib/modules/breakpoint-observer/media-breakpoint-observer.ts
Show resolved
Hide resolved
it('should change the breakpoint', async () => { | ||
const { fixture, mediaController } = setupTest(); | ||
|
||
const containerWithHostDirective = fixture.debugElement.query( |
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.
Use nativeElement
instead of debugElement
here per Angular's guidance.
When you're filtering by CSS selector and only testing properties of a browser's native element, the By.css approach might be overkill.
It's often more straightforward and clear to filter with a standard HTMLElement method such as querySelector() or querySelectorAll().
const containerWithHostDirective = (fixture.nativeElement as HTMLElement).querySelector('[data-sky-id="container-w-host-directive"]');
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.
Interesting; that's new to me.
@@ -145,6 +164,7 @@ export class SkySummaryActionBarComponent implements AfterViewInit, OnDestroy { | |||
|
|||
public onDirectionChange(direction: string): void { | |||
this.slideDirection = direction; | |||
this.#changeDetector.markForCheck(); |
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.
This function is called as a result of an event handler, so in theory markForCheck()
should not be needed. Can you make slideDirection
a signal?
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.
Yes, definitely.
export function toSkyMediaBreakpoints( | ||
breakpoint: SkyBreakpoint, | ||
): SkyMediaBreakpoints { | ||
const breakpointsMap = new Map<SkyBreakpoint, SkyMediaBreakpoints>([ |
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.
These don't change between calls to toSkyMediaBreakpoints()
. Move to the top of this file so it can be reused.
export function toSkyBreakpoint( | ||
breakpoint: SkyMediaBreakpoints, | ||
): SkyBreakpoint { | ||
const breakpointsMap = new Map<SkyMediaBreakpoints, SkyBreakpoint>([ |
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.
These don't change between calls to toSkyBreakpoint()
. Move to the top of this file so it can be reused.
import { SkyBreakpointObserver } from './breakpoint-observer'; | ||
|
||
const QUERIES = new Map<SkyBreakpoint, (width: number) => boolean>([ | ||
['xs', (w): boolean => w > 0 && w <= 767], |
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 you need the : boolean
return type, or can it be inferred from the Map
declaration (or array declaration after the suggested refactor above)? Also, I'd make the parameter names match by using width
instead of w
for readability.
untracked(() => { | ||
if (this.#searchShouldCollapse()) { | ||
if (breakpoint === 'xs') { | ||
this.inputAnimate = INPUT_HIDDEN_STATE; |
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.
Setting properties in an effect()
seems like an anti-pattern to me. Can inputAnimate
and mobileSearchShown
be computed signals instead?
useExisting: SkySplitViewMediaQueryService, | ||
}, | ||
], | ||
templateUrl: 'split-view-drawer.component.html', |
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.
templateUrl
and styleUrls
are missing the ./
prefix. Didn't we hit issues a while back with this? I'm kind of surprised it works. Other split view files also have this problem.
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.
Yeah, strange. I updated all the paths.
protected layoutClassName = computed(() => { | ||
const breakpoint = this.#breakpoint(); | ||
|
||
return untracked(() => { |
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.
Why does this use untracked()
? it doesn't reference any signals.
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.
I misunderstood the use-case; I thought it marked code that doesn't include any signals. Reverted.
effect(() => { | ||
const breakpoint = this.#breakpoint(); | ||
|
||
untracked(() => { |
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.
Same issue with untracked()
as above.
breakpoint === 'xs' || breakpoint === 'sm' ? 'single' : 'multi'; | ||
|
||
if (mode !== this.#mode) { | ||
this.#mode = mode; |
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.
Another instance of setting a property in an effect. See if this can be a computed signal instead.
AB#2195494
Overview of API
Testing
Consumers can add the following to their tests to interact with breakpoints:
Creating responsive hosts
Consumers can apply a container breakpoint observer to an element in their template like this:
Or on their component's host element:
For embedded views, the responsive host can pass its injector: