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,176 +0,0 @@
// @vitest-environment happy-dom
// SPDX-License-Identifier: AGPL-3.0-or-later
import {setupI18n} from '@lingui/core';
import {describe, expect, it, vi} from 'vitest';
vi.mock('@lingui/core/macro', () => {
const descriptor = (value: unknown): unknown => (typeof value === 'string' ? {message: value} : value);
return {msg: descriptor, t: descriptor, plural: () => '', select: () => '', selectOrdinal: () => ''};
});
vi.mock('@app/features/app/config/Config', () => ({
default: {
PUBLIC_BUILD_VERSION: 'test',
PUBLIC_RELEASE_CHANNEL: 'canary',
PUBLIC_BOOTSTRAP_API_ENDPOINT: 'https://example.invalid',
PUBLIC_BOOTSTRAP_API_PUBLIC_ENDPOINT: 'https://example.invalid',
},
}));
vi.mock('@lingui/react/macro', () => ({
Trans: () => null,
useLingui: () => ({i18n: {_: (descriptor: {message?: string}) => descriptor.message ?? '', locale: 'en'}}),
}));
vi.mock('@app/features/app/components/alerts/GenericErrorModalCommands', () => ({showGenericErrorModal: vi.fn()}));
vi.mock('@app/features/app/components/dialogs/Modal', () => ({}));
vi.mock('@app/features/app/components/shared/ExternalLink', () => ({ExternalLink: () => null}));
vi.mock('@app/features/ui/button/Button', () => ({Button: () => null}));
vi.mock('@app/features/ui/commands/ToastCommands', () => ({showToast: vi.fn()}));
vi.mock('@app/features/ui/components/form/Form', () => ({Form: () => null}));
vi.mock('@app/features/ui/components/form/FormInput', () => ({Input: () => null}));
vi.mock('@app/features/auth/state/SudoPrompt', () => ({isAbortError: () => false}));
const {APIErrorCodes} = await import('@fluxer/constants/src/ApiErrorCodes');
const {HttpError} = await import('@app/features/platform/types/EndpointError');
const {resolveRequiredActionErrorMessage} = await import(
'@app/features/auth/components/modals/required_action/RequiredActionShared'
);
const {
ENTER_VALID_PHONE_DESCRIPTOR,
PHONE_CANNOT_BE_USED_DESCRIPTOR,
PHONE_COUNTRY_NOT_SUPPORTED_DESCRIPTOR,
PHONE_INBOUND_REQUIRED_DESCRIPTOR,
PHONE_LOOKUP_UNAVAILABLE_DESCRIPTOR,
PHONE_NEEDS_REVIEW_DESCRIPTOR,
PHONE_NOT_IN_SERVICE_DESCRIPTOR,
PHONE_NOT_MOBILE_DESCRIPTOR,
SOMETHING_WENT_WRONG_TRY_AGAIN_DESCRIPTOR,
TOO_MANY_ATTEMPTS_DESCRIPTOR,
} = await import('@app/features/auth/components/modals/required_action/RequiredActionDescriptors');
const i18n = setupI18n({locale: 'en', messages: {en: {}}});
function apiError(code: string, body: Record<string, unknown> = {}) {
return new HttpError({
method: 'POST',
path: '/auth/verify-phone',
status: 400,
body: {code, message: 'server message', ...body},
responseHeaders: {},
});
}
const PHONE_REJECTION_CASES = [
[APIErrorCodes.PHONE_COUNTRY_NOT_SUPPORTED, PHONE_COUNTRY_NOT_SUPPORTED_DESCRIPTOR],
[APIErrorCodes.PHONE_NUMBER_NOT_IN_SERVICE, PHONE_NOT_IN_SERVICE_DESCRIPTOR],
[APIErrorCodes.PHONE_NUMBER_NOT_MOBILE, PHONE_NOT_MOBILE_DESCRIPTOR],
[APIErrorCodes.PHONE_LOOKUP_UNAVAILABLE, PHONE_LOOKUP_UNAVAILABLE_DESCRIPTOR],
[APIErrorCodes.PHONE_INBOUND_VERIFICATION_REQUIRED, PHONE_INBOUND_REQUIRED_DESCRIPTOR],
[APIErrorCodes.PHONE_VERIFICATION_NEEDS_REVIEW, PHONE_NEEDS_REVIEW_DESCRIPTOR],
] as const;
describe('resolveRequiredActionErrorMessage', () => {
for (const [code, descriptor] of PHONE_REJECTION_CASES) {
for (const context of ['phone-number', 'phone-code'] as const) {
it(`explains ${code} on the ${context} step`, () => {
const message = resolveRequiredActionErrorMessage(i18n, apiError(code), context);
expect(message).toBe(i18n._(descriptor));
expect(message).not.toBe(i18n._(SOMETHING_WENT_WRONG_TRY_AGAIN_DESCRIPTOR));
});
}
}
it('never blames the number when our own lookup is down', () => {
const message = resolveRequiredActionErrorMessage(
i18n,
apiError(APIErrorCodes.PHONE_LOOKUP_UNAVAILABLE),
'phone-number',
);
expect(message).not.toContain('invalid');
expect(message).toContain('try the same number again');
});
it('keeps the fraud message free of any distinguishing detail', () => {
const message = resolveRequiredActionErrorMessage(
i18n,
apiError(APIErrorCodes.PHONE_VERIFICATION_NEEDS_REVIEW),
'phone-number',
);
expect(message).toBe(i18n._(PHONE_NEEDS_REVIEW_DESCRIPTOR));
expect(message).toContain('Contact support');
});
it('keeps the existing invalid-number copy per step', () => {
expect(resolveRequiredActionErrorMessage(i18n, apiError(APIErrorCodes.INVALID_PHONE_NUMBER), 'phone-number')).toBe(
i18n._(ENTER_VALID_PHONE_DESCRIPTOR),
);
expect(resolveRequiredActionErrorMessage(i18n, apiError(APIErrorCodes.INVALID_PHONE_NUMBER), 'phone-code')).toBe(
i18n._(PHONE_CANNOT_BE_USED_DESCRIPTOR),
);
});
it('still falls back to the generic message for a code nothing maps', () => {
expect(resolveRequiredActionErrorMessage(i18n, apiError('SOME_UNMAPPED_CODE'), 'phone-number')).toBe(
i18n._(SOMETHING_WENT_WRONG_TRY_AGAIN_DESCRIPTOR),
);
});
it('lets a rate limit win over a new phone rejection code', () => {
const message = resolveRequiredActionErrorMessage(
i18n,
apiError(APIErrorCodes.PHONE_VERIFICATION_NEEDS_REVIEW, {retry_after: 86400}),
'phone-number',
);
expect(message).toBe(i18n._(TOO_MANY_ATTEMPTS_DESCRIPTOR));
});
});
const PHONE_GATE_CODES = [
APIErrorCodes.INVALID_PHONE_NUMBER,
APIErrorCodes.PHONE_COUNTRY_NOT_SUPPORTED,
APIErrorCodes.PHONE_INBOUND_VERIFICATION_REQUIRED,
APIErrorCodes.PHONE_LOOKUP_UNAVAILABLE,
APIErrorCodes.PHONE_NUMBER_NOT_IN_SERVICE,
APIErrorCodes.PHONE_NUMBER_NOT_MOBILE,
APIErrorCodes.PHONE_VERIFICATION_NEEDS_REVIEW,
] as const;
describe('phone gate code coverage', () => {
for (const context of ['phone-number', 'phone-code'] as const) {
it(`no phone gate code falls through to the generic message on the ${context} step`, () => {
const generic = i18n._(SOMETHING_WENT_WRONG_TRY_AGAIN_DESCRIPTOR);
for (const code of PHONE_GATE_CODES) {
expect(resolveRequiredActionErrorMessage(i18n, apiError(code), context)).not.toBe(generic);
}
});
}
it('gives each of the six new codes its own message', () => {
const messages = PHONE_REJECTION_CASES.map(([code]) =>
resolveRequiredActionErrorMessage(i18n, apiError(code), 'phone-number'),
);
expect(new Set(messages).size).toBe(PHONE_REJECTION_CASES.length);
});
it('never tells a user their working number is invalid for a benign rejection', () => {
const benign = [
APIErrorCodes.PHONE_COUNTRY_NOT_SUPPORTED,
APIErrorCodes.PHONE_LOOKUP_UNAVAILABLE,
APIErrorCodes.PHONE_INBOUND_VERIFICATION_REQUIRED,
];
for (const code of benign) {
const message = resolveRequiredActionErrorMessage(i18n, apiError(code), 'phone-number');
expect(message).not.toBe(i18n._(ENTER_VALID_PHONE_DESCRIPTOR));
expect(message).not.toBe(i18n._(PHONE_CANNOT_BE_USED_DESCRIPTOR));
}
});
it('routes every dead-end rejection somewhere a person can act', () => {
const routed = [
APIErrorCodes.PHONE_COUNTRY_NOT_SUPPORTED,
APIErrorCodes.PHONE_NUMBER_NOT_IN_SERVICE,
APIErrorCodes.PHONE_NUMBER_NOT_MOBILE,
APIErrorCodes.PHONE_VERIFICATION_NEEDS_REVIEW,
];
for (const code of routed) {
expect(resolveRequiredActionErrorMessage(i18n, apiError(code), 'phone-number')).toContain('support');
}
});
});
@@ -1,98 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {setupI18n} from '@lingui/core';
import {describe, expect, it, vi} from 'vitest';
vi.mock('@lingui/core/macro', () => {
const descriptor = (value: unknown): unknown => (typeof value === 'string' ? {message: value} : value);
return {msg: descriptor, t: descriptor, plural: () => '', select: () => '', selectOrdinal: () => ''};
});
vi.mock('@app/features/app/config/Config', () => ({
default: {
PUBLIC_BUILD_VERSION: 'test',
PUBLIC_RELEASE_CHANNEL: 'canary',
PUBLIC_BOOTSTRAP_API_ENDPOINT: 'https://example.invalid',
PUBLIC_BOOTSTRAP_API_PUBLIC_ENDPOINT: 'https://example.invalid',
},
}));
const {buildPhoneGateEscapeConfirmCopy, buildPhoneGateEscapeHint} = await import(
'@app/features/auth/components/modals/required_action/RequiredActionEscapeCopy'
);
const i18n = setupI18n({locale: 'en', messages: {en: {}}});
function confirmCopy(overrides: Partial<Parameters<typeof buildPhoneGateEscapeConfirmCopy>[1]> = {}) {
return buildPhoneGateEscapeConfirmCopy(i18n, {
guildNames: [],
ownedGuildNames: [],
emailStepRemains: false,
...overrides,
});
}
describe('buildPhoneGateEscapeHint', () => {
it('promises no removal when the user is in no community the check applies to', () => {
const hint = buildPhoneGateEscapeHint(i18n, 0);
expect(hint).toContain('nothing is removed');
expect(hint).not.toContain('leave');
});
it('counts the communities that will be left', () => {
expect(buildPhoneGateEscapeHint(i18n, 1)).toContain('1 community');
expect(buildPhoneGateEscapeHint(i18n, 4)).toContain('4 communities');
});
});
describe('buildPhoneGateEscapeConfirmCopy', () => {
it('never mentions leaving when nothing will be left', () => {
const copy = confirmCopy();
expect(copy.title).toBe('Set this check aside?');
expect(copy.primaryText).toBe('Set this check aside');
expect(copy.primaryVariant).toBe('primary');
expect(copy.bodyLines).toHaveLength(2);
for (const line of copy.bodyLines) {
expect(line).not.toContain('leave');
expect(line).not.toContain('join');
}
});
it('uses the singular form and the destructive style for a single community', () => {
const copy = confirmCopy({guildNames: ['Cat Fans']});
expect(copy.title).toBe('Leave 1 community and set this check aside?');
expect(copy.primaryText).toBe('Leave and set aside');
expect(copy.primaryVariant).toBe('danger');
expect(copy.bodyLines[1]).toContain('You will leave Cat Fans.');
});
it('names every community that will be left', () => {
const copy = confirmCopy({guildNames: ['Cat Fans', 'Dog Fans', 'Bird Fans']});
expect(copy.title).toBe('Leave 3 communities and set this check aside?');
expect(copy.bodyLines[1]).toContain('You will leave Cat Fans, Dog Fans, and Bird Fans.');
});
it('explains kept communities without claiming anything is left', () => {
const copy = confirmCopy({ownedGuildNames: ['My Server']});
expect(copy.title).toBe('Set this check aside?');
expect(copy.primaryVariant).toBe('primary');
expect(copy.bodyLines[1]).toBe('You stay in My Server. Owners cannot leave their own community.');
});
it('states the leave line before the ownership line', () => {
const copy = confirmCopy({guildNames: ['Cat Fans'], ownedGuildNames: ['My Server', 'My Other Server']});
expect(copy.bodyLines[1]).toContain('You will leave Cat Fans.');
expect(copy.bodyLines[2]).toBe(
'You stay in My Server and My Other Server. Owners cannot leave their own community.',
);
});
it('warns about the remaining email step before the support line, which is always last', () => {
const copy = confirmCopy({emailStepRemains: true});
expect(copy.bodyLines.at(-2)).toBe('You will still need to finish the email step.');
expect(copy.bodyLines.at(-1)).toBe('You can still email [email protected] for a human review at any time.');
expect(confirmCopy().bodyLines.at(-1)).toBe(
'You can still email [email protected] for a human review at any time.',
);
});
});
@@ -1,51 +0,0 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {
createAuthorizeSnapshot,
getAuthorizeStateValue,
selectAuthorizePhase,
transitionAuthorizeSnapshot,
} from '@app/features/auth/components/pages/oauth_authorize_page/state/authorizeMachine';
import {describe, expect, it} from 'vitest';
describe('authorizeMachine', () => {
it('moves from loading into review and through bot invite success', () => {
let snapshot = createAuthorizeSnapshot();
expect(getAuthorizeStateValue(snapshot)).toBe('loading');
expect(selectAuthorizePhase(snapshot)).toEqual({kind: 'loading'});
snapshot = transitionAuthorizeSnapshot(snapshot, {type: 'INIT_OK', step: 'scopes'});
expect(selectAuthorizePhase(snapshot)).toEqual({kind: 'review', step: 'scopes'});
snapshot = transitionAuthorizeSnapshot(snapshot, {type: 'SET_REVIEW_STEP', step: 'permissions'});
expect(selectAuthorizePhase(snapshot)).toEqual({kind: 'review', step: 'permissions'});
snapshot = transitionAuthorizeSnapshot(snapshot, {
type: 'SUBMIT_BOT_INVITE_DONE',
destinationName: 'Engineering',
});
expect(selectAuthorizePhase(snapshot)).toEqual({kind: 'success', destinationName: 'Engineering'});
});
it('ignores review-only events outside the review state', () => {
let snapshot = createAuthorizeSnapshot();
snapshot = transitionAuthorizeSnapshot(snapshot, {type: 'SET_REVIEW_STEP', step: 'community'});
expect(selectAuthorizePhase(snapshot)).toEqual({kind: 'loading'});
snapshot = transitionAuthorizeSnapshot(snapshot, {
type: 'SUBMIT_BOT_INVITE_DONE',
destinationName: 'Engineering',
});
expect(selectAuthorizePhase(snapshot)).toEqual({kind: 'loading'});
});
it('allows invalid request and session-expired terminal states from any phase', () => {
let snapshot = createAuthorizeSnapshot();
snapshot = transitionAuthorizeSnapshot(snapshot, {type: 'INIT_OK'});
snapshot = transitionAuthorizeSnapshot(snapshot, {type: 'INIT_INVALID', message: 'Bad redirect_uri'});
expect(selectAuthorizePhase(snapshot)).toEqual({kind: 'invalid_request', message: 'Bad redirect_uri'});
snapshot = transitionAuthorizeSnapshot(snapshot, {type: 'INIT_SESSION_EXPIRED'});
expect(selectAuthorizePhase(snapshot)).toEqual({kind: 'session_expired'});
});
});