@furystack/shades
Version:
A lightweight UI framework for FuryStack with JSX support
110 lines • 5.32 kB
JavaScript
import { createInjector } from '@furystack/inject';
import { usingAsync } from '@furystack/utils';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { ScreenService, ScreenSizes } from './screen-service.js';
describe('ScreenService', () => {
beforeEach(() => {
document.body.innerHTML = '<div id="root"></div>';
});
afterEach(() => {
document.body.innerHTML = '';
vi.restoreAllMocks();
});
it('Should be constructed', async () => {
await usingAsync(createInjector(), async (i) => {
const s = i.get(ScreenService);
expect(s).toBeDefined();
expect(s.breakpoints).toBeDefined();
});
});
describe('breakpoints', () => {
it('Should have correct breakpoint definitions', async () => {
await usingAsync(createInjector(), async (i) => {
const s = i.get(ScreenService);
expect(s.breakpoints.xs.minSize).toBe(0);
expect(s.breakpoints.sm.minSize).toBe(600);
expect(s.breakpoints.md.minSize).toBe(960);
expect(s.breakpoints.lg.minSize).toBe(1280);
expect(s.breakpoints.xl.minSize).toBe(1920);
});
});
});
describe('screenSize.atLeast', () => {
it('Should have observable for each screen size', async () => {
await usingAsync(createInjector(), async (i) => {
const s = i.get(ScreenService);
for (const size of ScreenSizes) {
expect(s.screenSize.atLeast[size]).toBeDefined();
expect(typeof s.screenSize.atLeast[size].getValue()).toBe('boolean');
}
});
});
it('Should return true for xs on any screen size', async () => {
await usingAsync(createInjector(), async (i) => {
const s = i.get(ScreenService);
// xs has minSize 0, so it should always be true
expect(s.screenSize.atLeast.xs.getValue()).toBe(true);
});
});
it('Should update screenSize observables on window resize', async () => {
await usingAsync(createInjector(), async (i) => {
const s = i.get(ScreenService);
// Mock window.innerWidth to simulate a large screen
vi.spyOn(window, 'innerWidth', 'get').mockReturnValue(1920);
// Trigger resize event
window.dispatchEvent(new Event('resize'));
// All breakpoints should be true for 1920px width
expect(s.screenSize.atLeast.xs.getValue()).toBe(true);
expect(s.screenSize.atLeast.sm.getValue()).toBe(true);
expect(s.screenSize.atLeast.md.getValue()).toBe(true);
expect(s.screenSize.atLeast.lg.getValue()).toBe(true);
expect(s.screenSize.atLeast.xl.getValue()).toBe(true);
// Mock a small screen
vi.spyOn(window, 'innerWidth', 'get').mockReturnValue(500);
window.dispatchEvent(new Event('resize'));
// Only xs should be true for 500px width
expect(s.screenSize.atLeast.xs.getValue()).toBe(true);
expect(s.screenSize.atLeast.sm.getValue()).toBe(false);
expect(s.screenSize.atLeast.md.getValue()).toBe(false);
expect(s.screenSize.atLeast.lg.getValue()).toBe(false);
expect(s.screenSize.atLeast.xl.getValue()).toBe(false);
});
});
});
describe('orientation', () => {
it('Should have an orientation observable', async () => {
await usingAsync(createInjector(), async (i) => {
const s = i.get(ScreenService);
const orientation = s.orientation.getValue();
expect(['landscape', 'portrait']).toContain(orientation);
});
});
it('Should update orientation on resize', async () => {
// Mock matchMedia before creating the service
const matchMediaMock = vi.fn();
window.matchMedia = matchMediaMock;
await usingAsync(createInjector(), async (i) => {
// Set initial orientation to landscape
matchMediaMock.mockReturnValue({ matches: true });
const s = i.get(ScreenService);
// Verify initial landscape
window.dispatchEvent(new Event('resize'));
expect(s.orientation.getValue()).toBe('landscape');
// Change to portrait
matchMediaMock.mockReturnValue({ matches: false });
window.dispatchEvent(new Event('resize'));
expect(s.orientation.getValue()).toBe('portrait');
});
});
});
describe('disposal', () => {
it('Should remove resize event listener on dispose', async () => {
const removeEventListenerSpy = vi.spyOn(window, 'removeEventListener');
await usingAsync(createInjector(), async (i) => {
i.get(ScreenService);
});
expect(removeEventListenerSpy).toHaveBeenCalledWith('resize', expect.any(Function));
});
});
});
//# sourceMappingURL=screen-service.spec.js.map