foundation: resolve platform in injection context for dot background teardown
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -100,6 +100,7 @@ German and English are written idiomatically per language, never machine-transla
|
|||||||
- Use the injected `DOCUMENT` token when the document element is required (it works on server and browser)
|
- Use the injected `DOCUMENT` token when the document element is required (it works on server and browser)
|
||||||
- No user-agent sniffing; use CSS media queries for device capability
|
- No user-agent sniffing; use CSS media queries for device capability
|
||||||
- Capability helpers live in `src/app/core/platform/browser.ts` and return conservative defaults on the server
|
- Capability helpers live in `src/app/core/platform/browser.ts` and return conservative defaults on the server
|
||||||
|
- Helpers that use `inject()` must be called from a field initializer or constructor, never from a lifecycle hook or callback, and the resolved value must be stored on the instance
|
||||||
- Every addressable route must remain prerenderable
|
- Every addressable route must remain prerenderable
|
||||||
|
|
||||||
## Accessibility checklist
|
## Accessibility checklist
|
||||||
|
|||||||
@@ -25,4 +25,29 @@ describe('DotBackground', () => {
|
|||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not throw when destroyed after browser initialization', async () => {
|
||||||
|
const gradient = { addColorStop: vi.fn() };
|
||||||
|
const context = {
|
||||||
|
clearRect: vi.fn(),
|
||||||
|
beginPath: vi.fn(),
|
||||||
|
arc: vi.fn(),
|
||||||
|
fill: vi.fn(),
|
||||||
|
createRadialGradient: vi.fn(() => gradient),
|
||||||
|
};
|
||||||
|
|
||||||
|
vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockReturnValue(
|
||||||
|
context as unknown as CanvasRenderingContext2D,
|
||||||
|
);
|
||||||
|
const animationFrameSpy = vi.spyOn(window, 'requestAnimationFrame').mockReturnValue(0);
|
||||||
|
|
||||||
|
const initializedFixture = TestBed.createComponent(DotBackground);
|
||||||
|
initializedFixture.detectChanges();
|
||||||
|
await initializedFixture.whenStable();
|
||||||
|
|
||||||
|
expect(() => initializedFixture.destroy()).not.toThrow();
|
||||||
|
|
||||||
|
animationFrameSpy.mockRestore();
|
||||||
|
vi.restoreAllMocks();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export class DotBackground implements OnDestroy {
|
|||||||
|
|
||||||
private readonly ngZone = inject(NgZone);
|
private readonly ngZone = inject(NgZone);
|
||||||
private readonly coarsePointer = prefersCoarsePointer();
|
private readonly coarsePointer = prefersCoarsePointer();
|
||||||
|
private readonly isBrowser = isBrowserPlatform();
|
||||||
|
|
||||||
private ctx: CanvasRenderingContext2D | undefined;
|
private ctx: CanvasRenderingContext2D | undefined;
|
||||||
private dots: Dot[] = [];
|
private dots: Dot[] = [];
|
||||||
@@ -50,7 +51,7 @@ export class DotBackground implements OnDestroy {
|
|||||||
|
|
||||||
cancelAnimationFrame(this.animationId);
|
cancelAnimationFrame(this.animationId);
|
||||||
|
|
||||||
if (isBrowserPlatform()) {
|
if (this.isBrowser) {
|
||||||
window.removeEventListener('resize', this.resize);
|
window.removeEventListener('resize', this.resize);
|
||||||
window.removeEventListener('mousemove', this.onMouseMove);
|
window.removeEventListener('mousemove', this.onMouseMove);
|
||||||
window.removeEventListener('click', this.onMouseClick);
|
window.removeEventListener('click', this.onMouseClick);
|
||||||
|
|||||||
Reference in New Issue
Block a user