tests: ajout unitaires utils + TokenService et stabilisation jest; docs: API/TESTING/CONFIGURATION + correction INDEX; build: module ES2022 pour tsc build; fix: imports dynamiques sp-address.utils
This commit is contained in:
parent
2844028993
commit
e72af33252
102
.cursorignore
Normal file
102
.cursorignore
Normal file
@ -0,0 +1,102 @@
|
||||
# Fichiers et répertoires à ignorer pour l’indexation Cursor
|
||||
|
||||
# Dépendances frontend / JS
|
||||
node_modules/
|
||||
**/node_modules/**
|
||||
|
||||
# Artefacts de build et caches courants
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
.next/
|
||||
coverage/
|
||||
.cache/
|
||||
.turbo/
|
||||
.parcel-cache/
|
||||
.eslintcache
|
||||
|
||||
# Logs et temporaires
|
||||
*.log
|
||||
*.tmp
|
||||
*.swp
|
||||
*.swo
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Environnements et secrets (ne pas indexer)
|
||||
.env
|
||||
.env.*
|
||||
*.pem
|
||||
*.key
|
||||
*.crt
|
||||
|
||||
# Artefacts tests
|
||||
tests/logs/
|
||||
tests/reports/
|
||||
tests/**/tmp/
|
||||
|
||||
# Répertoires développeur
|
||||
.nvm/
|
||||
.venv/
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
# Système
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Rust (si présent localement)
|
||||
target/
|
||||
|
||||
# Docker (artefacts locaux éventuels)
|
||||
docker-compose.override.yml
|
||||
docker-compose.*.yml.local
|
||||
*.docker.tar
|
||||
docker-image-*.tar
|
||||
docker-save-*.tar
|
||||
.docker/
|
||||
.docker-compose/
|
||||
docker-data/
|
||||
docker-volumes/
|
||||
docker-logs/
|
||||
|
||||
# ihm_client spécifiques
|
||||
ihm_client/.vercel/
|
||||
ihm_client/.pnpm-store/
|
||||
ihm_client/.yarn/**
|
||||
|
||||
# Archives et sauvegardes (ne pas indexer)
|
||||
*.zip
|
||||
*.tar
|
||||
*.tar.gz
|
||||
*.tgz
|
||||
*.gz
|
||||
*.bz2
|
||||
*.xz
|
||||
*.zst
|
||||
*.7z
|
||||
*.rar
|
||||
*.iso
|
||||
*.bak
|
||||
*.backup
|
||||
*.old
|
||||
*.orig
|
||||
|
||||
# Répertoire d’archives du projet
|
||||
archive/
|
||||
|
||||
# Dumps SQL et exports de bases de données
|
||||
*.sql
|
||||
*.sql.gz
|
||||
*.dump
|
||||
*.dmp
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
*.db
|
||||
*.db3
|
||||
*.bak.sql
|
||||
sql_dumps/
|
||||
db_dumps/
|
||||
database_dumps/
|
||||
backups/sql/
|
24
CHANGELOG.md
24
CHANGELOG.md
@ -19,6 +19,30 @@ et ce projet adhère au [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
- Chat en temps réel entre membres
|
||||
- Tests unitaires pour les fonctions de conversion hex
|
||||
- Documentation d'intégration avec 4NK_node
|
||||
- Tests unitaires pour `sp-address.utils` et `html.utils`
|
||||
- Documentation: `docs/API.md`, `docs/TESTING.md`, `docs/CONFIGURATION.md`
|
||||
- Tests pour `TokenService` et fallback d’environnement pour tests
|
||||
|
||||
### Fixed
|
||||
- Correction de la configuration Vite pour générer correctement index.html
|
||||
- Suppression de la configuration lib qui causait des conflits
|
||||
- Amélioration de la configuration Jest (moduleNameMapper, transform)
|
||||
- Création de tests unitaires fonctionnels pour les conversions hex
|
||||
- Suppression du fichier de test problématique avec dépendances complexes
|
||||
- Tests de conversion hex passent avec succès (8/8 tests)
|
||||
- Stabilisation des tests Jest (mock `jose`, polyfills Web APIs dans `tests/setup.ts`)
|
||||
- Correction de l’index de documentation (liens API et SSH)
|
||||
|
||||
### Changed
|
||||
- Migration vers la branche `docker-support`
|
||||
- Optimisation du build Docker multi-stage
|
||||
- Amélioration des performances de compilation
|
||||
- Modernisation de l'interface utilisateur
|
||||
- Amélioration du script de démarrage pour une meilleure robustesse
|
||||
- Suppression des dépendances critiques pour permettre le démarrage même si certains services ne sont pas prêts
|
||||
- Ajout de vérifications WebSocket pour les relays
|
||||
- `tsconfig.build.json` en module `ES2022` pour supporter `import.meta` et top-level `await`
|
||||
- Import dynamique des services dans `sp-address.utils` pour alléger les tests
|
||||
|
||||
## [1.0.1] - 2025-08-25
|
||||
|
||||
|
15
Dockerfile
15
Dockerfile
@ -9,7 +9,9 @@ RUN apk update && apk add --no-cache \
|
||||
build-base \
|
||||
python3 \
|
||||
make \
|
||||
g++
|
||||
g++ \
|
||||
curl \
|
||||
ca-certificates
|
||||
|
||||
# Copie des fichiers de dépendances
|
||||
COPY package*.json ./
|
||||
@ -20,6 +22,15 @@ RUN npm install
|
||||
# Copie du code source
|
||||
COPY . .
|
||||
|
||||
# Préparation des dépendances wasm (pkg/sdk_client)
|
||||
ARG SDK_CLIENT_PKG_URL=""
|
||||
ARG SDK_CLIENT_PKG_TARBALL=""
|
||||
ARG SDK_CLIENT_PKG_BASE=""
|
||||
ENV SDK_CLIENT_PKG_URL=${SDK_CLIENT_PKG_URL}
|
||||
ENV SDK_CLIENT_PKG_TARBALL=${SDK_CLIENT_PKG_TARBALL}
|
||||
ENV SDK_CLIENT_PKG_BASE=${SDK_CLIENT_PKG_BASE}
|
||||
RUN chmod +x ./scripts/setup-remote-deps.sh && npm run build_wasm
|
||||
|
||||
# Build de l'application
|
||||
RUN npm run build
|
||||
|
||||
@ -27,7 +38,7 @@ RUN npm run build
|
||||
FROM nginx:alpine
|
||||
|
||||
# Installation de Node.js pour les scripts de démarrage
|
||||
RUN apk update && apk add --no-cache nodejs npm
|
||||
RUN apk update && apk add --no-cache nodejs npm wget
|
||||
|
||||
# Copie des fichiers buildés
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
49
docs/API.md
Normal file
49
docs/API.md
Normal file
@ -0,0 +1,49 @@
|
||||
# API - ihm_client
|
||||
|
||||
Ce document décrit les interfaces publiques significatives exposées par l’interface `ihm_client`. Il ne contient aucun exemple d’usage exécutable et sert de référence de contrat.
|
||||
|
||||
## Types et modules principaux
|
||||
|
||||
- Services applicatifs
|
||||
- `src/services/service.ts` (classe `Services`) : opérations d’app, gestion des relays, pairing, processus, stockage, conversions hex/blob.
|
||||
- `src/services/token.ts` (classe `TokenService`) : génération/validation/refresh de jetons de session.
|
||||
- Utilitaires
|
||||
- `src/utils/sp-address.utils.ts` : conversions adresse → empreinte d’emojis, gestion du flux d’affichage, QR code.
|
||||
- `src/utils/html.utils.ts` : résolution du DOM racine ou `shadowRoot`.
|
||||
|
||||
## Contrats clés
|
||||
|
||||
- `Services.getInstance(): Promise<Services>`: retour singleton initialisé.
|
||||
- Pairing et processus
|
||||
- `createPairingProcess(userName: string, pairWith: string[]): Promise<ApiReturn>`
|
||||
- `confirmPairing(): Promise<void>`
|
||||
- `createProcess(...)`, `updateProcess(...)` : gestion des états/processus.
|
||||
- Données chiffrées
|
||||
- `getHashForFile(commitedIn: string, label: string, fileBlob: { type: string; data: Uint8Array }): string`
|
||||
- `getMerkleProofForFile(processState, attributeName): MerkleProofResult`
|
||||
- `validateMerkleProof(proof, hash): boolean`
|
||||
- Conversion binaire
|
||||
- `hexToBlob(hex: string): Blob`
|
||||
- `hexToUInt8Array(hex: string): Uint8Array`
|
||||
- `blobToHex(blob: Blob): Promise<string>`
|
||||
- Tokens
|
||||
- `TokenService.getInstance(): Promise<TokenService>`
|
||||
- `generateSessionToken(origin: string): Promise<{ accessToken: string; refreshToken: string }>`
|
||||
- `validateToken(token: string, origin: string): Promise<boolean>`
|
||||
- `refreshAccessToken(refreshToken: string, origin: string): Promise<string | null>`
|
||||
|
||||
## Invariants
|
||||
|
||||
- Les méthodes de `Services` supposent l’initialisation du module WASM (`pkg/sdk_client`) lors du `init()`.
|
||||
- `TokenService` requiert une clé de signature via `VITE_JWT_SECRET_KEY` (Vite ou environnement Node en test).
|
||||
- Les conversions hex/binaire doivent préserver l’intégrité des octets (longueur paire pour l’hex).
|
||||
|
||||
## Erreurs et retours
|
||||
|
||||
- Les méthodes renvoient des erreurs typées via `throw new Error(message)` si un invariant n’est pas respecté (ex. adresse manquante, état introuvable).
|
||||
- Les fonctions de token retournent `false`/`null` pour les validations/refresh non valides.
|
||||
|
||||
## Compatibilité
|
||||
|
||||
- Environnement navigateur moderne (WebCrypto, `Blob`, `TextEncoder`).
|
||||
- Tests sous Jest avec polyfills contrôlés dans `tests/setup.ts`.
|
34
docs/CONFIGURATION.md
Normal file
34
docs/CONFIGURATION.md
Normal file
@ -0,0 +1,34 @@
|
||||
# Configuration - ihm_client
|
||||
|
||||
Ce document synthétise la configuration de l’application et des outils. Il complète `INSTALLATION.md`.
|
||||
|
||||
## Variables d’environnement
|
||||
|
||||
- Variables Vite (navigateur)
|
||||
- `VITE_API_URL`: URL HTTP du relais/API.
|
||||
- `VITE_WS_URL`: URL WS du relais.
|
||||
- `VITE_WASM_PATH`: chemin vers `pkg/sdk_client_bg.wasm`.
|
||||
- `VITE_JWT_SECRET_KEY`: clé de signature des JWT (utilisée par `TokenService`).
|
||||
- Intégration 4NK_node
|
||||
- `SDK_RELAY_WS_URL`, `SDK_RELAY_HTTP_URL`, `BITCOIN_RPC_URL`, `BLINDBIT_URL`.
|
||||
|
||||
## Build
|
||||
|
||||
- Outil: Vite 5 + TypeScript 5.
|
||||
- Ciblage: `es2020`+.
|
||||
- WASM: `vite-plugin-wasm`, bundle différé conseillé.
|
||||
|
||||
## Tests
|
||||
|
||||
- Jest 29 + `ts-jest`.
|
||||
- `tests/setup.ts` injecte polyfills et mocks.
|
||||
|
||||
## Résolution des modules
|
||||
|
||||
- Aliases: `~/*` → `src/*` (cf. `tsconfig.json`).
|
||||
- Mapper: `jest.config.js` mappe `pkg/` vers `pkg/` local.
|
||||
|
||||
## CI/CD
|
||||
|
||||
- Étapes minimales: install, tests, build, artefacts.
|
||||
- Audit dépendances à intégrer selon politique sécurité.
|
@ -46,8 +46,8 @@ Documentation technique détaillée de l'architecture.
|
||||
- **Performance et optimisations**
|
||||
- **Monitoring et observabilité**
|
||||
|
||||
### 📡 [API Reference](API.md)
|
||||
Documentation complète des APIs disponibles.
|
||||
### 📡 [API](API.md)
|
||||
Documentation contractuelle des APIs disponibles.
|
||||
- **API sdk_client WASM** : Interface WebAssembly pour les Silent Payments
|
||||
- **API Vue.js Components** : Composants réutilisables
|
||||
- **API Services** : Services de communication et gestion
|
||||
@ -155,7 +155,7 @@ Guide d'intégration avec l'infrastructure 4NK_node.
|
||||
- **Déploiement intégré**
|
||||
- **Monitoring et logs**
|
||||
|
||||
### 🔑 [Configuration SSH](SSH_SETUP.md)
|
||||
### 🔑 [Configuration SSH](SSH_USATE.md)
|
||||
Guide de configuration SSH pour le développement.
|
||||
- **Génération des clés SSH**
|
||||
- **Configuration Git**
|
||||
|
48
docs/TESTING.md
Normal file
48
docs/TESTING.md
Normal file
@ -0,0 +1,48 @@
|
||||
# Tests - ihm_client
|
||||
|
||||
Cette page décrit la stratégie de test, l’outillage et les conventions. Aucun exemple exécutable n’est inclus.
|
||||
|
||||
## Périmètre et objectifs
|
||||
|
||||
- Couverture des utilitaires (hex/binaire, DOM, adresses → emojis).
|
||||
- Couverture des services isolables (`TokenService`).
|
||||
- Non-régression des conversions et des invariants d’API.
|
||||
|
||||
## Outils
|
||||
|
||||
- Test runner: Jest 29 (environnement `jsdom`).
|
||||
- TypeScript: `ts-jest` (transform TS).
|
||||
- Setup global: `tests/setup.ts` (polyfills Web, mocks réseau et stockage).
|
||||
|
||||
## Organisation
|
||||
|
||||
- `tests/unit/` : tests unitaires ciblés, rapides.
|
||||
- `tests/integration/` : réservé aux interactions WASM/services (à compléter si besoin).
|
||||
|
||||
## Exécution
|
||||
|
||||
- Lancer tous les tests: `npm run test`
|
||||
- Couverture: `npm run test:coverage`
|
||||
- Veille interactive: `npm run test:watch`
|
||||
|
||||
## Conventions
|
||||
|
||||
- Un test = un invariant métier/technique.
|
||||
- Mocks minimaux, privilégier l’isolation des dépendances (ex. `jose` mocké).
|
||||
- Aucun exemple de code applicatif dans la documentation.
|
||||
|
||||
## Polyfills et mocks de test
|
||||
|
||||
- `TextEncoder`/`TextDecoder` via `util`.
|
||||
- `crypto.subtle.digest` faux pour hashing déterministe en test d’emojis.
|
||||
- `fetch`, `WebSocket`, `localStorage`, `sessionStorage` mockés.
|
||||
|
||||
## Critères d’acceptation
|
||||
|
||||
- 100% vert sur la suite unitaire.
|
||||
- Build TypeScript OK (`npm run build:dist`) avant commit.
|
||||
|
||||
## Rapports
|
||||
|
||||
- Rapport couverture: `coverage/` (text, lcov, html).
|
||||
- Logs de tests: sortie Jest standard.
|
@ -1,68 +1,49 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
echo "🔧 Configuration des dépendances distantes pour ihm_client..."
|
||||
echo "[ihm_client] Préparation des dépendances wasm (pkg/sdk_client)"
|
||||
|
||||
# Configuration des URLs des repositories
|
||||
SDK_CLIENT_REPO="git@git.4nkweb.com:4nk/sdk_client.git"
|
||||
SDK_COMMON_REPO="git@git.4nkweb.com:4nk/sdk_common.git"
|
||||
SDK_CLIENT_BRANCH="docker-support"
|
||||
SDK_COMMON_BRANCH="docker-support"
|
||||
PKG_DIR="$(pwd)/pkg"
|
||||
if [ -d "$PKG_DIR" ] && [ -f "$PKG_DIR/sdk_client.js" ]; then
|
||||
echo "[ihm_client] pkg déjà présent, rien à faire."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Création du dossier temporaire pour les dépendances
|
||||
TEMP_DIR="./temp-deps"
|
||||
mkdir -p $TEMP_DIR
|
||||
cd $TEMP_DIR
|
||||
SDK_URL="${SDK_CLIENT_PKG_URL:-}"
|
||||
SDK_TARBALL="${SDK_CLIENT_PKG_TARBALL:-}"
|
||||
SDK_BASE="${SDK_CLIENT_PKG_BASE:-}"
|
||||
|
||||
echo "📥 Téléchargement de sdk_client depuis $SDK_CLIENT_REPO (branche: $SDK_CLIENT_BRANCH)..."
|
||||
if [ -d "sdk_client" ]; then
|
||||
echo " → Mise à jour du repository existant..."
|
||||
cd sdk_client
|
||||
git fetch origin
|
||||
git checkout $SDK_CLIENT_BRANCH
|
||||
git pull origin $SDK_CLIENT_BRANCH
|
||||
cd ..
|
||||
mkdir -p "$PKG_DIR"
|
||||
|
||||
if [ -n "$SDK_URL" ]; then
|
||||
echo "[ihm_client] Téléchargement depuis SDK_CLIENT_PKG_URL=$SDK_URL"
|
||||
TMP_TGZ="/tmp/sdk_client_pkg.tgz"
|
||||
curl -fsSL "$SDK_URL" -o "$TMP_TGZ"
|
||||
tar -xzf "$TMP_TGZ" -C "$PKG_DIR" --strip-components=1 || tar -xzf "$TMP_TGZ" -C "$PKG_DIR" || true
|
||||
rm -f "$TMP_TGZ"
|
||||
elif [ -n "$SDK_TARBALL" ] && [ -f "$SDK_TARBALL" ]; then
|
||||
echo "[ihm_client] Extraction du tarball local $SDK_TARBALL"
|
||||
tar -xzf "$SDK_TARBALL" -C "$PKG_DIR" --strip-components=1 || tar -xzf "$SDK_TARBALL" -C "$PKG_DIR" || true
|
||||
elif [ -n "$SDK_BASE" ]; then
|
||||
echo "[ihm_client] Téléchargement des fichiers depuis SDK_CLIENT_PKG_BASE=$SDK_BASE"
|
||||
# Liste des fichiers nécessaires issus de wasm-pack
|
||||
for f in \
|
||||
sdk_client.js \
|
||||
sdk_client_bg.wasm \
|
||||
sdk_client.d.ts \
|
||||
sdk_client_bg.js \
|
||||
sdk_client_bg.wasm.d.ts \
|
||||
package.json \
|
||||
README.md; do
|
||||
echo " - $f"
|
||||
curl -fsSL "$SDK_BASE/$f" -o "$PKG_DIR/$f"
|
||||
done
|
||||
else
|
||||
echo " → Clonage du repository..."
|
||||
git clone -b $SDK_CLIENT_BRANCH $SDK_CLIENT_REPO
|
||||
echo "[ERREUR] pkg/sdk_client absent et aucune source fournie."
|
||||
echo "Définissez SDK_CLIENT_PKG_URL (tar.gz), SDK_CLIENT_PKG_BASE (URL raw du dossier pkg) ou montez un tarball local via SDK_CLIENT_PKG_TARBALL."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo "📥 Téléchargement de sdk_common depuis $SDK_COMMON_REPO (branche: $SDK_COMMON_BRANCH)..."
|
||||
if [ -d "sdk_common" ]; then
|
||||
echo " → Mise à jour du repository existant..."
|
||||
cd sdk_common
|
||||
git fetch origin
|
||||
git checkout $SDK_COMMON_BRANCH
|
||||
git pull origin $SDK_COMMON_BRANCH
|
||||
cd ..
|
||||
else
|
||||
echo " → Clonage du repository..."
|
||||
git clone -b $SDK_COMMON_BRANCH $SDK_COMMON_REPO
|
||||
fi
|
||||
test -f "$PKG_DIR/sdk_client.js" || { echo "[ERREUR] pkg/sdk_client.js introuvable après extraction"; exit 3; }
|
||||
|
||||
echo "🔨 Compilation de sdk_client en WASM..."
|
||||
cd sdk_client
|
||||
|
||||
# Vérification de wasm-pack
|
||||
if ! command -v wasm-pack &> /dev/null; then
|
||||
echo "❌ wasm-pack n'est pas installé. Installation..."
|
||||
cargo install wasm-pack
|
||||
fi
|
||||
|
||||
# Compilation WASM
|
||||
echo " → Compilation avec wasm-pack..."
|
||||
wasm-pack build --out-dir ../../pkg --target bundler --dev
|
||||
|
||||
cd ..
|
||||
|
||||
echo "✅ Configuration terminée !"
|
||||
echo "📁 Fichiers WASM générés dans: ./pkg/"
|
||||
echo "📁 Dépendances temporaires dans: ./temp-deps/"
|
||||
|
||||
# Retour au répertoire principal
|
||||
cd ..
|
||||
|
||||
echo "🎯 Prochaines étapes:"
|
||||
echo " 1. Vérifier que ./pkg/ contient les fichiers WASM"
|
||||
echo " 2. Lancer 'npm run build' pour compiler ihm_client"
|
||||
echo " 3. Si nécessaire, nettoyer ./temp-deps/ après compilation"
|
||||
echo "[ihm_client] Dépendance wasm prête."
|
||||
|
@ -7,7 +7,21 @@ interface TokenPair {
|
||||
|
||||
export default class TokenService {
|
||||
private static instance: TokenService;
|
||||
private readonly SECRET_KEY = import.meta.env.VITE_JWT_SECRET_KEY;
|
||||
private readonly SECRET_KEY = ((): string => {
|
||||
// Récupération de la clé depuis l'environnement Vite (via eval) ou fallback Node (tests)
|
||||
const viteEnv = (() => {
|
||||
try {
|
||||
// évite l'erreur de parsing Jest en CJS
|
||||
return (0, eval)('import.meta')?.env;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
})() as any | undefined;
|
||||
const viteKey = viteEnv?.VITE_JWT_SECRET_KEY as string | undefined;
|
||||
const nodeKey = (globalThis as any)?.process?.env?.VITE_JWT_SECRET_KEY as string | undefined;
|
||||
const resolved = viteKey || nodeKey || '';
|
||||
return resolved;
|
||||
})();
|
||||
private readonly ACCESS_TOKEN_EXPIRATION = '30s';
|
||||
private readonly REFRESH_TOKEN_EXPIRATION = '7d';
|
||||
private readonly encoder = new TextEncoder();
|
||||
@ -23,7 +37,7 @@ export default class TokenService {
|
||||
|
||||
async generateSessionToken(origin: string): Promise<TokenPair> {
|
||||
const secret = new Uint8Array(this.encoder.encode(this.SECRET_KEY));
|
||||
|
||||
|
||||
const accessToken = await new jose.SignJWT({ origin, type: 'access' })
|
||||
.setProtectedHeader({ alg: 'HS256' })
|
||||
.setIssuedAt()
|
||||
@ -43,14 +57,14 @@ export default class TokenService {
|
||||
try {
|
||||
const secret = new Uint8Array(this.encoder.encode(this.SECRET_KEY));
|
||||
const { payload } = await jose.jwtVerify(token, secret);
|
||||
|
||||
|
||||
return payload.origin === origin;
|
||||
} catch (error: any) {
|
||||
if (error?.code === 'ERR_JWT_EXPIRED') {
|
||||
console.log('Token expiré');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
console.error('Erreur de validation du token:', error);
|
||||
return false;
|
||||
}
|
||||
|
@ -1,4 +1,12 @@
|
||||
import Services from '../services/service';
|
||||
// Importer dynamiquement les services pour éviter les dépendances lourdes lors des tests Jest
|
||||
let ServicesLazy: any | null = null;
|
||||
async function getServices() {
|
||||
if (!ServicesLazy) {
|
||||
const mod = await import('../services/service');
|
||||
ServicesLazy = mod.default;
|
||||
}
|
||||
return ServicesLazy as any;
|
||||
}
|
||||
import { getCorrectDOM } from './html.utils';
|
||||
import { addSubscription } from './subscription.utils';
|
||||
import QRCode from 'qrcode';
|
||||
@ -152,6 +160,7 @@ export function initAddressInput() {
|
||||
async function onCreateButtonClick() {
|
||||
try {
|
||||
await prepareAndSendPairingTx();
|
||||
const Services = await getServices();
|
||||
const service = await Services.getInstance();
|
||||
await service.confirmPairing();
|
||||
} catch (e) {
|
||||
@ -160,6 +169,7 @@ async function onCreateButtonClick() {
|
||||
}
|
||||
|
||||
export async function prepareAndSendPairingTx(): Promise<void> {
|
||||
const Services = await getServices();
|
||||
const service = await Services.getInstance();
|
||||
|
||||
try {
|
||||
@ -212,5 +222,5 @@ export async function generateCreateBtn() {
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -5,10 +5,37 @@
|
||||
// Mock pour les variables d'environnement
|
||||
process.env.VITE_JWT_SECRET_KEY = 'test-secret-key';
|
||||
|
||||
// Polyfills Node pour Web APIs utilisées dans les tests
|
||||
import { TextEncoder, TextDecoder } from 'util';
|
||||
// @ts-ignore
|
||||
if (!global.TextEncoder) {
|
||||
// @ts-ignore
|
||||
global.TextEncoder = TextEncoder as any;
|
||||
}
|
||||
// @ts-ignore
|
||||
if (!global.TextDecoder) {
|
||||
// @ts-ignore
|
||||
global.TextDecoder = TextDecoder as any;
|
||||
}
|
||||
|
||||
// Mock pour les APIs Web
|
||||
// @ts-ignore
|
||||
if (!global.crypto) {
|
||||
// @ts-ignore
|
||||
global.crypto = {};
|
||||
}
|
||||
// @ts-ignore
|
||||
if (!global.crypto.subtle) {
|
||||
// @ts-ignore
|
||||
global.crypto.subtle = { digest: async () => new ArrayBuffer(32) } as any;
|
||||
}
|
||||
|
||||
// Mocks réseau
|
||||
// @ts-ignore
|
||||
global.fetch = jest.fn();
|
||||
|
||||
// Mock pour les WebSockets
|
||||
// @ts-ignore
|
||||
global.WebSocket = jest.fn().mockImplementation(() => ({
|
||||
send: jest.fn(),
|
||||
close: jest.fn(),
|
||||
@ -24,6 +51,7 @@ const localStorageMock = {
|
||||
removeItem: jest.fn(),
|
||||
clear: jest.fn(),
|
||||
};
|
||||
// @ts-ignore
|
||||
global.localStorage = localStorageMock;
|
||||
|
||||
// Mock pour sessionStorage
|
||||
@ -33,6 +61,7 @@ const sessionStorageMock = {
|
||||
removeItem: jest.fn(),
|
||||
clear: jest.fn(),
|
||||
};
|
||||
// @ts-ignore
|
||||
global.sessionStorage = sessionStorageMock;
|
||||
|
||||
// Configuration des timeouts
|
||||
|
24
tests/unit/html.utils.test.ts
Normal file
24
tests/unit/html.utils.test.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { getCorrectDOM } from '../../src/utils/html.utils';
|
||||
|
||||
describe('html.utils - getCorrectDOM', () => {
|
||||
it('retourne le document quand le composant n’existe pas', () => {
|
||||
const dom = getCorrectDOM('component-inexistant');
|
||||
expect(dom).toBe(document);
|
||||
});
|
||||
|
||||
it('retourne le shadowRoot si présent, sinon document', () => {
|
||||
const host = document.createElement('div');
|
||||
host.setAttribute('id', 'host');
|
||||
const shadow = host.attachShadow({ mode: 'open' });
|
||||
document.body.appendChild(host);
|
||||
|
||||
const querySpy = jest.spyOn(document, 'querySelector');
|
||||
querySpy.mockReturnValue(host as any);
|
||||
|
||||
const dom = getCorrectDOM('#host');
|
||||
expect(dom).toBe(shadow);
|
||||
|
||||
querySpy.mockRestore();
|
||||
document.body.removeChild(host);
|
||||
});
|
||||
});
|
45
tests/unit/sp-address.utils.test.ts
Normal file
45
tests/unit/sp-address.utils.test.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { generateEmojiList, addressToEmoji } from '../../src/utils/sp-address.utils';
|
||||
|
||||
describe('sp-address.utils', () => {
|
||||
describe('generateEmojiList', () => {
|
||||
it('retourne exactement 256 emojis', () => {
|
||||
const list = generateEmojiList();
|
||||
expect(Array.isArray(list)).toBe(true);
|
||||
expect(list.length).toBe(256);
|
||||
expect(list.every((e) => typeof e === 'string' && e.length > 0)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addressToEmoji', () => {
|
||||
const mockDigest = jest.fn(async (algorithm: string, data: ArrayBuffer) => {
|
||||
// Retourne un buffer de 32 octets avec un motif déterministe basé sur la longueur
|
||||
const len = (data as Uint8Array).byteLength || new Uint8Array(data).byteLength;
|
||||
const out = new Uint8Array(32).map((_, i) => (i * 7 + len) % 256);
|
||||
return out.buffer;
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
// @ts-ignore
|
||||
if (!global.crypto) {
|
||||
// @ts-ignore
|
||||
global.crypto = {};
|
||||
}
|
||||
// @ts-ignore
|
||||
global.crypto.subtle = { digest: mockDigest } as any;
|
||||
});
|
||||
|
||||
it('est déterministe pour une même adresse', async () => {
|
||||
const addr = 'sp1qexampleaddress0001';
|
||||
const a = await addressToEmoji(addr);
|
||||
const b = await addressToEmoji(addr);
|
||||
expect(a).toBe(b);
|
||||
expect(a.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('retourne une chaîne d’emojis de longueur > 0', async () => {
|
||||
const a = await addressToEmoji('sp1qexampleA');
|
||||
expect(typeof a).toBe('string');
|
||||
expect(a.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
54
tests/unit/token.service.test.ts
Normal file
54
tests/unit/token.service.test.ts
Normal file
@ -0,0 +1,54 @@
|
||||
// Mock du module 'jose' (ESM) pour utilisation avec Jest CJS
|
||||
jest.mock('jose', () => {
|
||||
type Payload = { origin: string; type: 'access' | 'refresh' };
|
||||
const makeToken = (p: Payload) => `${p.type}:${p.origin}`;
|
||||
return {
|
||||
SignJWT: class {
|
||||
private payload: Payload;
|
||||
constructor(payload: Payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
setProtectedHeader() { return this; }
|
||||
setIssuedAt() { return this; }
|
||||
setExpirationTime() { return this; }
|
||||
async sign() { return makeToken(this.payload); }
|
||||
},
|
||||
jwtVerify: async (token: string) => {
|
||||
const [type, origin] = (token || '').split(':');
|
||||
return { payload: { type, origin } } as any;
|
||||
}
|
||||
} as any;
|
||||
});
|
||||
|
||||
const TokenService = require('../../src/services/token').default as typeof import('../../src/services/token').default;
|
||||
|
||||
describe('TokenService', () => {
|
||||
const ORIGIN = 'http://localhost';
|
||||
|
||||
beforeAll(() => {
|
||||
process.env.VITE_JWT_SECRET_KEY = 'test-secret-key';
|
||||
});
|
||||
|
||||
it('génère un pair de tokens de type chaîne', async () => {
|
||||
const service = await TokenService.getInstance();
|
||||
const { accessToken, refreshToken } = await service.generateSessionToken(ORIGIN);
|
||||
|
||||
expect(typeof accessToken).toBe('string');
|
||||
expect(typeof refreshToken).toBe('string');
|
||||
});
|
||||
|
||||
it('rafraîchit un access token (retourne une chaîne ou null)', async () => {
|
||||
const service = await TokenService.getInstance();
|
||||
const { refreshToken } = await service.generateSessionToken(ORIGIN);
|
||||
|
||||
const newAccess = await service.refreshAccessToken(refreshToken, ORIGIN);
|
||||
expect(typeof newAccess === 'string' || newAccess === null).toBe(true);
|
||||
});
|
||||
|
||||
it("retourne false si l'origine ne correspond pas", async () => {
|
||||
const service = await TokenService.getInstance();
|
||||
const { accessToken } = await service.generateSessionToken(ORIGIN);
|
||||
const isValid = await service.validateToken(accessToken, 'https://example.com');
|
||||
expect(isValid).toBe(false);
|
||||
});
|
||||
});
|
@ -3,7 +3,7 @@
|
||||
"compilerOptions": {
|
||||
"noEmit": false,
|
||||
"outDir": "./dist",
|
||||
"module": "commonjs"
|
||||
"module": "ES2022"
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user