mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-22 01:42:13 +02:00
test(auth): add 68 unit tests for auth-ui, shared-auth, and shared-branding
- userAgent utils: parseUserAgent, getDeviceType, formatUserAgent (17 tests) - guestWelcome utils: shouldShow, markSeen, reset (8 tests) - jwtUtils: decodeToken, isTokenValid, getUserFromToken, B2B (27 tests) - mana-apps: hasAppAccess, getTierLevel, getAccessibleManaApps (16 tests) Also fixes iOS detection bug in userAgent parser (iPhone UA contains "Mac OS X" — mobile check must come before desktop OS check). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ed9672ef2b
commit
4fb851947e
9 changed files with 555 additions and 5 deletions
92
packages/shared-auth-ui/src/utils/guestWelcome.spec.ts
Normal file
92
packages/shared-auth-ui/src/utils/guestWelcome.spec.ts
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import {
|
||||
shouldShowGuestWelcome,
|
||||
markGuestWelcomeSeen,
|
||||
resetGuestWelcome,
|
||||
resetAllGuestWelcome,
|
||||
} from './guestWelcome';
|
||||
|
||||
// Mock localStorage
|
||||
const store: Record<string, string> = {};
|
||||
const localStorageMock = {
|
||||
getItem: vi.fn((key: string) => store[key] ?? null),
|
||||
setItem: vi.fn((key: string, value: string) => {
|
||||
store[key] = value;
|
||||
}),
|
||||
removeItem: vi.fn((key: string) => {
|
||||
delete store[key];
|
||||
}),
|
||||
get length() {
|
||||
return Object.keys(store).length;
|
||||
},
|
||||
key: vi.fn((i: number) => Object.keys(store)[i] ?? null),
|
||||
clear: vi.fn(() => {
|
||||
for (const key of Object.keys(store)) delete store[key];
|
||||
}),
|
||||
};
|
||||
|
||||
Object.defineProperty(globalThis, 'localStorage', { value: localStorageMock });
|
||||
|
||||
beforeEach(() => {
|
||||
for (const key of Object.keys(store)) delete store[key];
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('shouldShowGuestWelcome', () => {
|
||||
it('returns true when not seen before', () => {
|
||||
expect(shouldShowGuestWelcome('todo')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false after marking as seen', () => {
|
||||
markGuestWelcomeSeen('todo');
|
||||
expect(shouldShowGuestWelcome('todo')).toBe(false);
|
||||
});
|
||||
|
||||
it('scopes to app ID', () => {
|
||||
markGuestWelcomeSeen('todo');
|
||||
expect(shouldShowGuestWelcome('todo')).toBe(false);
|
||||
expect(shouldShowGuestWelcome('chat')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('markGuestWelcomeSeen', () => {
|
||||
it('writes to localStorage with correct key', () => {
|
||||
markGuestWelcomeSeen('contacts');
|
||||
expect(localStorageMock.setItem).toHaveBeenCalledWith('guest-welcome-seen-contacts', 'true');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resetGuestWelcome', () => {
|
||||
it('removes the key for a specific app', () => {
|
||||
markGuestWelcomeSeen('todo');
|
||||
expect(shouldShowGuestWelcome('todo')).toBe(false);
|
||||
resetGuestWelcome('todo');
|
||||
expect(shouldShowGuestWelcome('todo')).toBe(true);
|
||||
});
|
||||
|
||||
it('does not affect other apps', () => {
|
||||
markGuestWelcomeSeen('todo');
|
||||
markGuestWelcomeSeen('chat');
|
||||
resetGuestWelcome('todo');
|
||||
expect(shouldShowGuestWelcome('chat')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resetAllGuestWelcome', () => {
|
||||
it('removes all guest-welcome keys', () => {
|
||||
markGuestWelcomeSeen('todo');
|
||||
markGuestWelcomeSeen('chat');
|
||||
markGuestWelcomeSeen('calendar');
|
||||
resetAllGuestWelcome();
|
||||
expect(shouldShowGuestWelcome('todo')).toBe(true);
|
||||
expect(shouldShowGuestWelcome('chat')).toBe(true);
|
||||
expect(shouldShowGuestWelcome('calendar')).toBe(true);
|
||||
});
|
||||
|
||||
it('does not remove unrelated keys', () => {
|
||||
store['other-key'] = 'value';
|
||||
markGuestWelcomeSeen('todo');
|
||||
resetAllGuestWelcome();
|
||||
expect(store['other-key']).toBe('value');
|
||||
});
|
||||
});
|
||||
97
packages/shared-auth-ui/src/utils/userAgent.spec.ts
Normal file
97
packages/shared-auth-ui/src/utils/userAgent.spec.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { parseUserAgent, getDeviceType, formatUserAgent } from './userAgent';
|
||||
|
||||
describe('parseUserAgent', () => {
|
||||
it('returns empty strings for null', () => {
|
||||
expect(parseUserAgent(null)).toEqual({ browser: '', os: '' });
|
||||
});
|
||||
|
||||
it('returns empty strings for empty string', () => {
|
||||
expect(parseUserAgent('')).toEqual({ browser: '', os: '' });
|
||||
});
|
||||
|
||||
it('detects Chrome on macOS', () => {
|
||||
const ua =
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
|
||||
expect(parseUserAgent(ua)).toEqual({ browser: 'Chrome', os: 'macOS' });
|
||||
});
|
||||
|
||||
it('detects Firefox on Windows', () => {
|
||||
const ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0';
|
||||
expect(parseUserAgent(ua)).toEqual({ browser: 'Firefox', os: 'Windows' });
|
||||
});
|
||||
|
||||
it('detects Safari on macOS', () => {
|
||||
const ua =
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15';
|
||||
expect(parseUserAgent(ua)).toEqual({ browser: 'Safari', os: 'macOS' });
|
||||
});
|
||||
|
||||
it('detects Edge on Windows', () => {
|
||||
const ua =
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0';
|
||||
expect(parseUserAgent(ua)).toEqual({ browser: 'Edge', os: 'Windows' });
|
||||
});
|
||||
|
||||
it('detects Chrome on Android', () => {
|
||||
const ua =
|
||||
'Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36';
|
||||
expect(parseUserAgent(ua)).toEqual({ browser: 'Chrome', os: 'Android' });
|
||||
});
|
||||
|
||||
it('detects Safari on iOS', () => {
|
||||
const ua =
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1';
|
||||
expect(parseUserAgent(ua)).toEqual({ browser: 'Safari', os: 'iOS' });
|
||||
});
|
||||
|
||||
it('detects Chrome on Linux', () => {
|
||||
const ua =
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
|
||||
expect(parseUserAgent(ua)).toEqual({ browser: 'Chrome', os: 'Linux' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDeviceType', () => {
|
||||
it('returns desktop for null', () => {
|
||||
expect(getDeviceType(null)).toBe('desktop');
|
||||
});
|
||||
|
||||
it('returns mobile for iPhone', () => {
|
||||
const ua = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)';
|
||||
expect(getDeviceType(ua)).toBe('mobile');
|
||||
});
|
||||
|
||||
it('returns mobile for Android phone', () => {
|
||||
const ua = 'Mozilla/5.0 (Linux; Android 14; Pixel 8) Mobile Safari/537.36';
|
||||
expect(getDeviceType(ua)).toBe('mobile');
|
||||
});
|
||||
|
||||
it('returns tablet for iPad', () => {
|
||||
const ua = 'Mozilla/5.0 (iPad; CPU OS 17_0 like Mac OS X)';
|
||||
expect(getDeviceType(ua)).toBe('tablet');
|
||||
});
|
||||
|
||||
it('returns desktop for macOS Chrome', () => {
|
||||
const ua =
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/120.0.0.0';
|
||||
expect(getDeviceType(ua)).toBe('desktop');
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatUserAgent', () => {
|
||||
it('returns empty string for null', () => {
|
||||
expect(formatUserAgent(null)).toBe('');
|
||||
});
|
||||
|
||||
it('formats browser and OS with separator', () => {
|
||||
const ua =
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36';
|
||||
expect(formatUserAgent(ua)).toBe('Chrome \u00b7 macOS');
|
||||
});
|
||||
|
||||
it('formats browser only if OS unknown', () => {
|
||||
const ua = 'Mozilla/5.0 Chrome/120.0.0.0';
|
||||
expect(formatUserAgent(ua)).toBe('Chrome');
|
||||
});
|
||||
});
|
||||
|
|
@ -13,11 +13,11 @@ export function parseUserAgent(ua: string | null): { browser: string; os: string
|
|||
else if (ua.includes('Safari/') && !ua.includes('Chrome/')) browser = 'Safari';
|
||||
else if (ua.includes('Opera/') || ua.includes('OPR/')) browser = 'Opera';
|
||||
|
||||
if (ua.includes('Windows')) os = 'Windows';
|
||||
else if (ua.includes('Mac OS X') || ua.includes('Macintosh')) os = 'macOS';
|
||||
else if (ua.includes('Linux') && !ua.includes('Android')) os = 'Linux';
|
||||
if (ua.includes('iPhone') || ua.includes('iPad')) os = 'iOS';
|
||||
else if (ua.includes('Android')) os = 'Android';
|
||||
else if (ua.includes('iPhone') || ua.includes('iPad')) os = 'iOS';
|
||||
else if (ua.includes('Windows')) os = 'Windows';
|
||||
else if (ua.includes('Mac OS X') || ua.includes('Macintosh')) os = 'macOS';
|
||||
else if (ua.includes('Linux')) os = 'Linux';
|
||||
|
||||
return { browser, os };
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue