Fonctionnalités implémentées : ✅ Authentification locale (email/password) + Azure AD + Manus OAuth ✅ Upload drag-and-drop de fichiers PDF avec suivi en temps réel ✅ Extraction automatique avec Mistral AI (OCR + LLM) ✅ Détection de doublons (fournisseur, numéro, date) ✅ Score de qualité d'extraction (0-100) ✅ Tableau de bord avec statistiques ✅ Liste des factures avec recherche et filtres ✅ Paramètres utilisateur (LLM, keywords, SFTP) ✅ Historique des imports avec logs détaillés ✅ Gestion des utilisateurs (admin) ✅ Export SFTP manuel/automatique ✅ Stockage local avec organisation YYYY-MM ✅ Tests unitaires d'authentification Architecture : - Frontend : React 19 + Vite + TailwindCSS + Radix UI - Backend : Express + tRPC + Drizzle ORM - Base de données : MySQL (6 tables) - IA : Mistral AI pour extraction - Stockage : Local filesystem - Export : SFTP Pages : - Login (choix local/Azure/Manus) - Dashboard (statistiques) - Upload (drag-and-drop) - Invoices (liste avec recherche) - Settings (LLM, keywords, SFTP) - History (logs d'import) - Users (gestion admin)
69 lines
2.0 KiB
TypeScript
69 lines
2.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { hashPassword, verifyPassword, generateToken, verifyToken } from "./auth";
|
|
|
|
describe("Authentication", () => {
|
|
describe("Password hashing", () => {
|
|
it("should hash a password", async () => {
|
|
const password = "testpassword123";
|
|
const hash = await hashPassword(password);
|
|
|
|
expect(hash).toBeDefined();
|
|
expect(hash).not.toBe(password);
|
|
expect(hash.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("should verify a correct password", async () => {
|
|
const password = "testpassword123";
|
|
const hash = await hashPassword(password);
|
|
|
|
const isValid = await verifyPassword(password, hash);
|
|
expect(isValid).toBe(true);
|
|
});
|
|
|
|
it("should reject an incorrect password", async () => {
|
|
const password = "testpassword123";
|
|
const hash = await hashPassword(password);
|
|
|
|
const isValid = await verifyPassword("wrongpassword", hash);
|
|
expect(isValid).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("JWT tokens", () => {
|
|
it("should generate a valid JWT token", () => {
|
|
const user = {
|
|
id: 1,
|
|
email: "test@example.com",
|
|
role: "user",
|
|
};
|
|
|
|
const token = generateToken(user);
|
|
|
|
expect(token).toBeDefined();
|
|
expect(typeof token).toBe("string");
|
|
expect(token.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("should verify and decode a valid token", () => {
|
|
const user = {
|
|
id: 1,
|
|
email: "test@example.com",
|
|
role: "user",
|
|
};
|
|
|
|
const token = generateToken(user);
|
|
const decoded = verifyToken(token);
|
|
|
|
expect(decoded).toBeDefined();
|
|
expect(decoded?.userId).toBe(user.id);
|
|
expect(decoded?.email).toBe(user.email);
|
|
expect(decoded?.role).toBe(user.role);
|
|
});
|
|
|
|
it("should reject an invalid token", () => {
|
|
const decoded = verifyToken("invalid-token");
|
|
expect(decoded).toBeNull();
|
|
});
|
|
});
|
|
});
|