From 98e7bf069fe23e92e09390301d19683f86ef2f62 Mon Sep 17 00:00:00 2001 From: Chris Pyles Date: Mon, 1 Jul 2024 23:19:18 -0700 Subject: [PATCH] show error if viewport is too small --- src/app/app.component.html | 9 +++- src/app/app.component.spec.ts | 80 ++++++++++++++++++++++++++++++----- src/app/app.component.ts | 14 ++++++ 3 files changed, 92 insertions(+), 11 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index f965570..990bd13 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -49,7 +49,14 @@ - +@if (viewportTooSmall()) { +
+ This browser's dimensions are too small for this application. Please view it + in a desktop browser. +
+} @else { + +}
{{ snackBarText() }} diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 4e995ce..0a65a14 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -12,6 +12,8 @@ describe('AppComponent', () => { let gameStateService: jasmine.SpyObj; let windowSpy: jasmine.SpyObj; let clipboardWriteSpy: jasmine.Spy; + let createComponent = true; + let testBed: TestBed; let fixture: ComponentFixture; const setInAnimation = () => { @@ -22,7 +24,6 @@ describe('AppComponent', () => { }; beforeAll(() => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 10_000; jasmine.clock().install(); }); @@ -46,18 +47,24 @@ describe('AppComponent', () => { 'http://example.com/?seed=321', ); - windowSpy = jasmine.createSpyObj('Window', ['matchMedia'], { - history: { pushState: jasmine.createSpy() }, - location: { - origin: 'http://example.com', - toString: () => 'http://example.com/?seed=123', + windowSpy = jasmine.createSpyObj( + 'Window', + ['addEventListener', 'matchMedia'], + { + history: { pushState: jasmine.createSpy() }, + innerHeight: 850, + innerWidth: 1000, + location: { + origin: 'http://example.com', + toString: () => 'http://example.com/?seed=123', + }, }, - }); + ); windowSpy.matchMedia.and.returnValue({ matches: false } as MediaQueryList); clipboardWriteSpy = spyOn(navigator.clipboard, 'writeText'); - await TestBed.configureTestingModule({ + testBed = TestBed.configureTestingModule({ imports: [AppComponent], providers: [ { provide: GameStateService, useValue: gameStateService }, @@ -66,9 +73,12 @@ describe('AppComponent', () => { useValue: windowSpy, }, ], - }).compileComponents(); + }); - fixture = TestBed.createComponent(AppComponent); + if (createComponent) { + await testBed.compileComponents(); + fixture = TestBed.createComponent(AppComponent); + } }); afterEach(() => { @@ -233,4 +243,54 @@ describe('AppComponent', () => { done(); }); }); + + describe('viewport size error', () => { + beforeAll(() => { + createComponent = false; + }); + + afterAll(() => { + createComponent = true; + }); + + it('should display a message if the viewport is too short', async () => { + ( + Object.getOwnPropertyDescriptor(windowSpy, 'innerHeight') + ?.get as jasmine.Spy + ).and.returnValue(849); + + await testBed.compileComponents(); + fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + + expect( + document + .querySelector('[data-test-id="viewport-size-error"]') + ?.textContent?.trim(), + ).toBe( + "This browser's dimensions are too small for this application. Please view it in a desktop browser.", + ); + expect(document.querySelector('amaze-maze')).toBeNull(); + }); + + it('should display a message if the viewport is too narrow', async () => { + ( + Object.getOwnPropertyDescriptor(windowSpy, 'innerWidth') + ?.get as jasmine.Spy + ).and.returnValue(999); + + await testBed.compileComponents(); + fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + + expect( + document + .querySelector('[data-test-id="viewport-size-error"]') + ?.textContent?.trim(), + ).toBe( + "This browser's dimensions are too small for this application. Please view it in a desktop browser.", + ); + expect(document.querySelector('amaze-maze')).toBeNull(); + }); + }); }); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index a3075a8..d34f6fd 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -42,6 +42,9 @@ export class AppComponent implements OnInit { /** Text to show in the snack bar. */ readonly snackBarText = signal(undefined); + /** Whether the viewport is too small to use the app. */ + viewportTooSmall = signal(false); + ngOnInit(): void { // Set dark mode if user's OS is using it. if ( @@ -58,6 +61,17 @@ export class AppComponent implements OnInit { this.window.history.pushState({}, '', this.window.location.origin); } this.generateNewMaze(seed); + + this.checkViewportSize(); + this.window.addEventListener('resize', () => this.checkViewportSize()); + } + + checkViewportSize(): void { + if (this.window.innerWidth < 1000 || this.window.innerHeight < 850) { + this.viewportTooSmall.set(true); + } else { + this.viewportTooSmall.set(false); + } } /** The color to use for the icons in the header. */