test(app): remove useless frontend tests (#2819)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-17 15:05:36 +02:00
1 parent ed9528834d
commit deac653a9e
341 files changed
-62758

No files matched your search

@@ -1,50 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {
cssColorStringToHex,
cssColorStringToNumber,
numberToHex,
updateCssForVariable,
} from '@app/features/user/components/modals/tabs/appearance_tab/theme/ThemeUtils';
import {describe, expect, it} from 'vitest';
describe('updateCssForVariable', () => {
it('adds a token override when the CSS is empty', () => {
expect(updateCssForVariable('', '--background-primary', '#ff00ff')).toBe(
':root { --background-primary: #ff00ff; }\n',
);
});
it('updates an existing token override', () => {
expect(updateCssForVariable(':root { --background-primary: #ffffff; }\n', '--background-primary', '#111111')).toBe(
':root { --background-primary: #111111; }\n',
);
});
it('removes the empty root block after the last token override is cleared', () => {
expect(updateCssForVariable(':root { --background-primary: #ffffff; }\n', '--background-primary', null)).toBe('');
});
it('keeps unrelated CSS when clearing a token override', () => {
expect(
updateCssForVariable(
'body { color: red; }\n:root { --background-primary: #ffffff; }\n',
'--background-primary',
null,
),
).toBe('body { color: red; }');
});
});
describe('cssColorStringToNumber', () => {
it('parses black as a real color', () => {
expect(numberToHex(cssColorStringToNumber('#000000') ?? -1)).toBe('#000000');
expect(numberToHex(cssColorStringToNumber('rgb(0, 0, 0)') ?? -1)).toBe('#000000');
expect(numberToHex(cssColorStringToNumber('#000000 !important') ?? -1)).toBe('#000000');
});
it('does not turn invalid CSS values into black', () => {
expect(cssColorStringToNumber('1px solid hsl(0, 0%, 0%)')).toBeNull();
expect(cssColorStringToNumber('not-a-color')).toBeNull();
});
it('normalizes equivalent CSS colors to the same hex value', () => {
expect(cssColorStringToHex('rgb(0, 0, 0)')).toBe('#000000');
expect(cssColorStringToHex('#000000 !important')).toBe('#000000');
});
});
@@ -1,178 +0,0 @@
// @vitest-environment happy-dom
// SPDX-License-Identifier: AGPL-3.0-or-later
import type {
EnsureVoiceDevicesOptions,
VoiceDeviceState,
VoiceMediaPermissionType,
} from '@app/features/voice/utils/VoiceDeviceManager';
import {act, createElement, useEffect} from 'react';
import {createRoot, type Root} from 'react-dom/client';
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
const deviceManagerMock = vi.hoisted(() => {
const idleState = (): VoiceDeviceState => ({
inputDevices: [],
outputDevices: [],
videoDevices: [],
permissionStatus: {audio: 'idle', video: 'idle'},
});
const listeners = new Set<(state: VoiceDeviceState) => void>();
const mock = {
state: idleState(),
permissionRequests: [] as Array<ReadonlyArray<VoiceMediaPermissionType>>,
pending: [] as Array<(state: VoiceDeviceState) => void>,
reset(): void {
mock.state = idleState();
mock.permissionRequests = [];
mock.pending = [];
listeners.clear();
},
settlePendingWith(next: VoiceDeviceState): void {
const pending = mock.pending;
mock.pending = [];
mock.state = next;
for (const listener of listeners) listener(next);
for (const resolve of pending) resolve(next);
},
manager: {
getState: (): VoiceDeviceState => mock.state,
subscribe: (listener: (state: VoiceDeviceState) => void): (() => void) => {
listeners.add(listener);
listener(mock.state);
return () => listeners.delete(listener);
},
ensureDevices: (options: EnsureVoiceDevicesOptions = {}): Promise<VoiceDeviceState> => {
const requestPermissionTypes =
options.requestPermissionTypes ?? (options.requestPermissions === true ? ['audio', 'video'] : []);
if (requestPermissionTypes.length === 0) return Promise.resolve(mock.state);
mock.permissionRequests.push([...requestPermissionTypes]);
return new Promise<VoiceDeviceState>((resolve) => {
mock.pending.push(resolve);
});
},
},
};
return mock;
});
const mediaPermissionMock = vi.hoisted(() => ({
microphoneExplicitlyDenied: false,
cameraExplicitlyDenied: false,
microphonePermissionState: null as PermissionState | null,
cameraPermissionState: null as PermissionState | null,
isMicrophoneGranted: vi.fn(() => false),
isCameraGranted: vi.fn(() => false),
updateMicrophonePermissionGranted: vi.fn(),
updateCameraPermissionGranted: vi.fn(),
markMicrophoneExplicitlyDenied: vi.fn(),
markCameraExplicitlyDenied: vi.fn(),
}));
const handleMediaPermissionBlocked = vi.hoisted(() => vi.fn());
vi.mock('@app/features/voice/utils/VoiceDeviceManager', () => ({voiceDeviceManager: deviceManagerMock.manager}));
vi.mock('@app/features/permissions/system/state/MediaPermission', () => ({default: mediaPermissionMock}));
vi.mock('@app/features/permissions/system/commands/MacPermissionsModalCommands', () => ({
handleMediaPermissionBlocked,
}));
const {useMediaPermission} = await import('@app/features/user/components/modals/tabs/hooks/useMediaPermission');
(globalThis as {IS_REACT_ACT_ENVIRONMENT?: boolean}).IS_REACT_ACT_ENVIRONMENT = true;
const MICROPHONE: MediaDeviceInfo = {
deviceId: 'mic-1',
groupId: 'group-1',
kind: 'audioinput',
label: 'Microphone',
toJSON: () => ({}),
};
const grantedState = (): VoiceDeviceState => ({
inputDevices: [MICROPHONE],
outputDevices: [],
videoDevices: [],
permissionStatus: {audio: 'granted', video: 'idle'},
});
const deniedState = (): VoiceDeviceState => ({
inputDevices: [],
outputDevices: [],
videoDevices: [],
permissionStatus: {audio: 'denied', video: 'idle'},
});
let host: HTMLDivElement;
let root: Root;
const requesters: Array<() => Promise<boolean>> = [];
function Consumer(): null {
const {requestPermission} = useMediaPermission('audio');
useEffect(() => {
requesters.push(requestPermission);
return () => {
const index = requesters.indexOf(requestPermission);
if (index !== -1) requesters.splice(index, 1);
};
}, [requestPermission]);
return null;
}
function renderConsumers(count: number): void {
act(() => {
root.render(Array.from({length: count}, (_, index) => createElement(Consumer, {key: index})));
});
}
beforeEach(() => {
deviceManagerMock.reset();
requesters.length = 0;
mediaPermissionMock.microphoneExplicitlyDenied = false;
mediaPermissionMock.microphonePermissionState = null;
mediaPermissionMock.isMicrophoneGranted.mockReturnValue(false);
host = document.createElement('div');
document.body.append(host);
root = createRoot(host);
});
afterEach(() => {
act(() => {
root.unmount();
});
document.body.replaceChildren();
vi.clearAllMocks();
});
describe('useMediaPermission', () => {
it('raises a single device permission request when two consumers ask at once', async () => {
renderConsumers(2);
expect(requesters).toHaveLength(2);
const results = await act(async () => {
const pending = Promise.all([requesters[0](), requesters[1]()]);
await Promise.resolve();
deviceManagerMock.settlePendingWith(grantedState());
return pending;
});
expect(deviceManagerMock.permissionRequests).toEqual([['audio']]);
expect(results).toEqual([true, true]);
expect(mediaPermissionMock.updateMicrophonePermissionGranted).toHaveBeenCalledTimes(1);
});
it('reports a denied request through the shared permission state', async () => {
renderConsumers(1);
const granted = await act(async () => {
const pending = requesters[0]();
await Promise.resolve();
deviceManagerMock.settlePendingWith(deniedState());
return pending;
});
expect(granted).toBe(false);
expect(mediaPermissionMock.markMicrophoneExplicitlyDenied).toHaveBeenCalledTimes(1);
expect(handleMediaPermissionBlocked).toHaveBeenCalledWith('microphone');
});
});
@@ -1,189 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {
assignProfileAssetUploadPatch,
createGlobalProfileAssetRemoteState,
createProfileAssetCustomizationSnapshot,
createProfileAssetRemoteStateFromFlags,
getProfileAssetUploadPatch,
type ProfileAssetCustomizationEvent,
type ProfileAssetCustomizationSnapshot,
type ProfileAssetMode,
type ProfileAssetRemoteState,
selectProfileAssetCustomizationState,
transitionProfileAssetCustomizationSnapshot,
} from '@app/features/user/components/modals/tabs/my_profile_tab/ProfileAssetCustomizationStateMachine';
import {describe, expect, it} from 'vitest';
const IDENTITY = 'user-1:guild-1';
const OTHER_IDENTITY = 'user-1:guild-2';
const DATA_URL = 'data:image/png;base64,AAA';
function remote(mode: ProfileAssetMode, hasCustomAsset: boolean, identityKey = IDENTITY): ProfileAssetRemoteState {
return {identityKey, mode, hasCustomAsset};
}
function transition(
snapshot: ProfileAssetCustomizationSnapshot,
event: ProfileAssetCustomizationEvent,
): ProfileAssetCustomizationSnapshot {
return transitionProfileAssetCustomizationSnapshot(snapshot, event);
}
function hydrate(remoteState: ProfileAssetRemoteState): ProfileAssetCustomizationSnapshot {
return transition(createProfileAssetCustomizationSnapshot(), {type: 'asset.remoteApplied', remoteState});
}
describe('ProfileAssetCustomizationStateMachine', () => {
it('derives per-community asset modes from custom hashes and unset flags', () => {
expect(
createProfileAssetRemoteStateFromFlags({
identityKey: IDENTITY,
hasCustomAsset: false,
isUnset: false,
}),
).toEqual(remote('inherit', false));
expect(
createProfileAssetRemoteStateFromFlags({
identityKey: IDENTITY,
hasCustomAsset: true,
isUnset: false,
}),
).toEqual(remote('custom', true));
expect(
createProfileAssetRemoteStateFromFlags({
identityKey: IDENTITY,
hasCustomAsset: true,
isUnset: true,
}),
).toEqual(remote('unset', false));
});
it('tracks an accepted upload as a dirty custom asset patch', () => {
let snapshot = hydrate(remote('inherit', false));
snapshot = transition(snapshot, {type: 'asset.uploaded', previewUrl: DATA_URL});
const state = selectProfileAssetCustomizationState(snapshot);
expect(state).toMatchObject({
state: 'dirty',
mode: 'custom',
initialMode: 'inherit',
hasCustomAsset: true,
previewUrl: DATA_URL,
hasCleared: false,
hasAsset: true,
isDirty: true,
});
expect(getProfileAssetUploadPatch(state)).toEqual({value: DATA_URL});
});
it('sends null when a custom asset is changed back to inherit or unset', () => {
let snapshot = hydrate(remote('custom', true));
snapshot = transition(snapshot, {type: 'asset.modeSelected', mode: 'inherit'});
let state = selectProfileAssetCustomizationState(snapshot);
expect(state).toMatchObject({state: 'dirty', mode: 'inherit', hasCleared: false});
expect(getProfileAssetUploadPatch(state)).toEqual({value: null});
snapshot = hydrate(remote('custom', true));
snapshot = transition(snapshot, {type: 'asset.modeSelected', mode: 'unset'});
state = selectProfileAssetCustomizationState(snapshot);
expect(state).toMatchObject({state: 'dirty', mode: 'unset', hasCleared: true});
expect(getProfileAssetUploadPatch(state)).toEqual({value: null});
});
it('does not revert an accepted custom upload when a stale same-identity remote snapshot says inherit', () => {
let snapshot = hydrate(remote('inherit', false));
snapshot = transition(snapshot, {type: 'asset.uploaded', previewUrl: DATA_URL});
snapshot = transition(snapshot, {type: 'asset.committed', remoteState: remote('custom', true)});
let state = selectProfileAssetCustomizationState(snapshot);
expect(state).toMatchObject({
state: 'committed',
mode: 'custom',
initialMode: 'custom',
hasCustomAsset: true,
previewUrl: null,
isDirty: false,
});
snapshot = transition(snapshot, {type: 'asset.remoteApplied', remoteState: remote('inherit', false)});
state = selectProfileAssetCustomizationState(snapshot);
expect(state).toMatchObject({
state: 'committed',
mode: 'custom',
hasCustomAsset: true,
isDirty: false,
});
expect(getProfileAssetUploadPatch(state)).toEqual({value: undefined});
snapshot = transition(snapshot, {type: 'asset.remoteApplied', remoteState: remote('custom', true)});
state = selectProfileAssetCustomizationState(snapshot);
expect(state).toMatchObject({state: 'clean', mode: 'custom', hasCustomAsset: true});
});
it('protects dirty local edits from same-identity remote refreshes but accepts identity changes', () => {
let snapshot = hydrate(remote('inherit', false));
snapshot = transition(snapshot, {type: 'asset.uploaded', previewUrl: DATA_URL});
snapshot = transition(snapshot, {type: 'asset.remoteApplied', remoteState: remote('inherit', false)});
let state = selectProfileAssetCustomizationState(snapshot);
expect(state).toMatchObject({state: 'dirty', mode: 'custom', previewUrl: DATA_URL});
snapshot = transition(snapshot, {
type: 'asset.remoteApplied',
remoteState: remote('inherit', false, OTHER_IDENTITY),
});
state = selectProfileAssetCustomizationState(snapshot);
expect(state).toMatchObject({
state: 'clean',
identityKey: OTHER_IDENTITY,
mode: 'inherit',
previewUrl: null,
isDirty: false,
});
});
it('allows explicit same-identity resets to discard dirty local edits', () => {
let snapshot = hydrate(remote('inherit', false));
snapshot = transition(snapshot, {type: 'asset.uploaded', previewUrl: DATA_URL});
snapshot = transition(snapshot, {
type: 'asset.remoteApplied',
remoteState: remote('inherit', false),
force: true,
});
const state = selectProfileAssetCustomizationState(snapshot);
expect(state).toMatchObject({
state: 'clean',
mode: 'inherit',
previewUrl: null,
hasCleared: false,
isDirty: false,
});
});
it('assigns upload patches without writing undefined fields', () => {
const cleanState = selectProfileAssetCustomizationState(hydrate(remote('inherit', false)));
const dirtyState = selectProfileAssetCustomizationState(
transition(hydrate(remote('inherit', false)), {type: 'asset.uploaded', previewUrl: DATA_URL}),
);
const payload: {avatar?: string | null} = {};
assignProfileAssetUploadPatch(payload, 'avatar', cleanState);
expect(payload).toEqual({});
assignProfileAssetUploadPatch(payload, 'avatar', dirtyState);
expect(payload).toEqual({avatar: DATA_URL});
});
it('models global profile assets as custom or unset instead of inherit', () => {
expect(createGlobalProfileAssetRemoteState({identityKey: 'user-1:global', hasCustomAsset: true})).toEqual({
identityKey: 'user-1:global',
mode: 'custom',
hasCustomAsset: true,
});
expect(createGlobalProfileAssetRemoteState({identityKey: 'user-1:global', hasCustomAsset: false})).toEqual({
identityKey: 'user-1:global',
mode: 'unset',
hasCustomAsset: false,
});
});
});
@@ -1,30 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {isSettingsItemNew} from '@app/features/user/components/settings_utils/SettingsMetadata';
import {describe, expect, it} from 'vitest';
const NOW = new Date('2026-06-04T12:00:00.000Z');
describe('SettingsMetadata new badges', () => {
it('does not mark settings without an addedAt timestamp as new', () => {
expect(isSettingsItemNew({}, NOW)).toBe(false);
});
it('marks settings added within the freshness window as new', () => {
expect(isSettingsItemNew({addedAt: '2026-06-03T00:00:00.000Z'}, NOW)).toBe(true);
});
it('stops marking settings as new after 30 days', () => {
expect(isSettingsItemNew({addedAt: '2026-05-01T00:00:00.000Z'}, NOW)).toBe(false);
});
it('does not mark settings as new for accounts created after the setting was added', () => {
expect(isSettingsItemNew({addedAt: '2026-06-03T00:00:00.000Z'}, NOW, new Date('2026-06-04T00:00:00.000Z'))).toBe(
false,
);
});
it('does not mark future timestamps as new', () => {
expect(isSettingsItemNew({addedAt: '2026-06-05T00:00:00.000Z'}, NOW)).toBe(false);
});
});