Files
AirCardIOS/web/src/account/errors.test.ts
T

194 lines
8.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest';
import { errorMessage, errorType, isInvalidLinkError, isRowMissing, isUnauthorized, type ErrorContext } from './errors';
/** Fehler wie vom SDK (AppwriteException): Felder code, type, message. */
const fail = (code: number, type: string, message = '') => ({ code, type, message });
const LINK = 'Der Link ist ungültig oder abgelaufen.';
const WRONG = 'E-Mail oder Passwort ist falsch.';
const LENGTH = 'Das Passwort muss 8 bis 256 Zeichen lang sein.';
const COMMON = 'Dieses Passwort ist zu verbreitet. Bitte wähle ein anderes.';
const EMAIL = 'Bitte gib eine gültige E-Mail-Adresse ein.';
const GENERIC = 'Etwas ist schiefgelaufen. Bitte nochmal versuchen.';
const PW_LENGTH = 'Invalid `password` param: Password must be between 8 and 256 characters long.';
const PW_COMMON =
'Invalid `password` param: Password must be at least 8 characters and should not be one of the commonly used password.';
const EMAIL_INVALID = 'Invalid `email` param: Value must be a valid email address';
describe('errorMessage nach type', () => {
it('user_invalid_credentials', () => {
expect(errorMessage(fail(401, 'user_invalid_credentials', 'Invalid credentials.'), 'login')).toBe(WRONG);
});
it('user_already_exists', () => {
expect(errorMessage(fail(409, 'user_already_exists'), 'register')).toBe(
'Diese E-Mail ist schon registriert. Melde dich an.',
);
});
it('user_invalid_token', () => {
expect(errorMessage(fail(401, 'user_invalid_token'), 'reset')).toBe(LINK);
});
it('user_not_found hängt vom Kontext ab', () => {
expect(errorMessage(fail(404, 'user_not_found'), 'recover')).toBe('Zu dieser E-Mail gibt es kein Konto.');
expect(errorMessage(fail(404, 'user_not_found'), 'reset')).toBe(LINK);
});
it('user_not_found in anderen Kontexten fällt auf die allgemeine Meldung zurück', () => {
expect(errorMessage(fail(404, 'user_not_found'), 'save')).toBe(GENERIC);
});
it('row_not_found', () => {
expect(errorMessage(fail(404, 'row_not_found'), 'load')).toBe(
'Diese Karte gibt es nicht (mehr) oder sie gehört nicht zu deinem Konto.',
);
});
it('storage_file_not_found', () => {
expect(errorMessage(fail(404, 'storage_file_not_found'), 'load')).toBe('Das Bild dieser Karte fehlt.');
});
it('general_unknown_origin', () => {
expect(errorMessage(fail(403, 'general_unknown_origin'), 'login')).toBe(
'Diese Seite ist beim Server nicht freigeschaltet. Bitte melde dich beim Betreiber.',
);
});
it('user_session_already_exists: Hinweis mit Handlungsanweisung', () => {
expect(errorMessage(fail(401, 'user_session_already_exists'), 'login')).toBe(
'Du bist schon angemeldet. Bitte lade die Seite neu.',
);
expect(errorMessage(fail(401, 'user_session_already_exists'), 'register')).toBe(
'Du bist schon angemeldet. Bitte lade die Seite neu.',
);
});
it('user_count_exceeded', () => {
expect(errorMessage(fail(501, 'user_count_exceeded'), 'register')).toBe('Zurzeit sind keine neuen Konten möglich.');
});
});
describe('errorMessage bei general_argument_invalid', () => {
const invalid = (message: string) => fail(400, 'general_argument_invalid', message);
it('email', () => {
for (const ctx of ['login', 'register', 'recover'] as ErrorContext[]) {
expect(errorMessage(invalid(EMAIL_INVALID), ctx)).toBe(EMAIL);
}
});
it('password beim Login heißt: falsche Zugangsdaten', () => {
expect(errorMessage(invalid(PW_LENGTH), 'login')).toBe(WRONG);
});
it('password sonst: 8 bis 256 Zeichen', () => {
expect(errorMessage(invalid(PW_LENGTH), 'register')).toBe(LENGTH);
expect(errorMessage(invalid(PW_LENGTH), 'reset')).toBe(LENGTH);
});
it('password sonst: zu verbreitet', () => {
expect(errorMessage(invalid(PW_COMMON), 'register')).toBe(COMMON);
expect(errorMessage(invalid(PW_COMMON), 'reset')).toBe(COMMON);
});
it('userId und secret: Link ungültig', () => {
expect(errorMessage(invalid('Invalid `userId` param: Parameter must be a valid number'), 'reset')).toBe(LINK);
expect(errorMessage(invalid('Invalid `secret` param: Value must be a valid string'), 'reset')).toBe(LINK);
});
it('unbekannter oder fehlender Parameter: allgemeine Meldung', () => {
expect(errorMessage(invalid('Invalid `url` param: Invalid URI'), 'recover')).toBe(GENERIC);
expect(errorMessage(invalid('Something is wrong'), 'register')).toBe(GENERIC);
});
});
describe('errorMessage nach code und Fehlerart', () => {
it('429', () => {
expect(errorMessage(fail(429, 'general_rate_limit_exceeded'), 'login')).toBe('Zu viele Versuche – bitte kurz warten.');
expect(errorMessage(fail(429, ''), 'recover')).toBe('Zu viele Versuche – bitte kurz warten.');
});
it('type geht vor code', () => {
expect(errorMessage(fail(429, 'user_invalid_credentials'), 'login')).toBe(WRONG);
});
it('TypeError ist ein Netzfehler', () => {
expect(errorMessage(new TypeError('Failed to fetch'), 'save')).toBe('Keine Verbindung zum Server.');
});
it('alles andere ist die allgemeine Meldung', () => {
expect(errorMessage(fail(500, 'general_server_error', 'boom'), 'save')).toBe(GENERIC);
expect(errorMessage(new Error('x'), 'load')).toBe(GENERIC);
expect(errorMessage(undefined, 'load')).toBe(GENERIC);
expect(errorMessage('text', 'load')).toBe(GENERIC);
expect(errorMessage(null, 'load')).toBe(GENERIC);
});
});
describe('isUnauthorized', () => {
it('erkennt Code 401', () => {
expect(isUnauthorized({ code: 401 })).toBe(true);
});
it('andere Codes und Nicht-Fehler nicht', () => {
expect(isUnauthorized({ code: 404 })).toBe(false);
expect(isUnauthorized(new TypeError('Failed to fetch'))).toBe(false);
expect(isUnauthorized(null)).toBe(false);
expect(isUnauthorized(undefined)).toBe(false);
});
});
describe('errorType', () => {
it('liefert den type-String oder null', () => {
expect(errorType(fail(409, 'user_already_exists'))).toBe('user_already_exists');
expect(errorType(fail(500, ''))).toBeNull();
expect(errorType(new TypeError('x'))).toBeNull();
expect(errorType(undefined)).toBeNull();
});
});
describe('isRowMissing', () => {
it('404 mit row_not_found heißt: die Zeile gibt es nicht (oder nicht für mich)', () => {
expect(isRowMissing(fail(404, 'row_not_found'))).toBe(true);
});
it('404 ohne Typ (leer oder fehlend) zählt ebenso', () => {
expect(isRowMissing(fail(404, ''))).toBe(true);
expect(isRowMissing({ code: 404 })).toBe(true);
});
it('eine fehlende Tabelle, Datenbank oder Datei ist ein echter Fehler, kein „Zeile weg“', () => {
for (const type of ['table_not_found', 'database_not_found', 'storage_file_not_found']) {
expect(isRowMissing(fail(404, type)), type).toBe(false);
}
});
it('andere Status und Nicht-Fehler nicht', () => {
expect(isRowMissing(fail(401, 'row_not_found'))).toBe(false);
expect(isRowMissing(fail(500, 'row_not_found'))).toBe(false);
expect(isRowMissing({ code: '404', type: 'row_not_found' })).toBe(false);
expect(isRowMissing(new TypeError('Failed to fetch'))).toBe(false);
expect(isRowMissing('row_not_found')).toBe(false);
expect(isRowMissing(null)).toBe(false);
expect(isRowMissing(undefined)).toBe(false);
});
});
describe('isInvalidLinkError (Passwort-neu-Seite)', () => {
it('Link-Fehler', () => {
expect(isInvalidLinkError(fail(401, 'user_invalid_token'))).toBe(true);
expect(isInvalidLinkError(fail(404, 'user_not_found'))).toBe(true);
expect(isInvalidLinkError(fail(400, 'general_argument_invalid', 'Invalid `userId` param: x'))).toBe(true);
expect(isInvalidLinkError(fail(400, 'general_argument_invalid', 'Invalid `secret` param: x'))).toBe(true);
});
it('Passwort- und sonstige Fehler gehören zum Feld', () => {
expect(isInvalidLinkError(fail(400, 'general_argument_invalid', PW_LENGTH))).toBe(false);
expect(isInvalidLinkError(fail(429, 'general_rate_limit_exceeded'))).toBe(false);
expect(isInvalidLinkError(new TypeError('Failed to fetch'))).toBe(false);
expect(isInvalidLinkError(undefined)).toBe(false);
});
});