Add user profile panel with self-service password change and dark theme UserMenu
This commit is contained in:
48
backend/__tests__/auth-password-change.property.test.js
Normal file
48
backend/__tests__/auth-password-change.property.test.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Property-Based Test: Password Change Round-Trip
|
||||
*
|
||||
* Feature: user-profile, Property 3: Password change round-trip
|
||||
*
|
||||
* For any valid current password and any new password of 8+ characters,
|
||||
* after a successful change, bcrypt.compare(newPassword, storedHash) returns true.
|
||||
*
|
||||
* Validates: Requirements 2.2, 2.7
|
||||
*/
|
||||
|
||||
const fc = require('fast-check');
|
||||
const bcrypt = require('bcryptjs');
|
||||
|
||||
// bcrypt cost factor — production uses 10, but we use 4 (the minimum) here
|
||||
// to keep 100 iterations feasible within test timeouts. The round-trip property
|
||||
// holds regardless of cost factor.
|
||||
const BCRYPT_COST = 4;
|
||||
|
||||
describe('Feature: user-profile, Property 3: Password change round-trip', () => {
|
||||
it('after a password change, bcrypt.compare(newPassword, newHash) returns true', async () => {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
// Current password: any non-empty string (length >= 1)
|
||||
fc.string({ minLength: 1, maxLength: 72 }),
|
||||
// New password: any string of length >= 8 (bcrypt max input is 72 bytes)
|
||||
fc.string({ minLength: 8, maxLength: 72 }),
|
||||
async (currentPassword, newPassword) => {
|
||||
// Step 1: Hash the current password (simulates existing stored hash)
|
||||
const currentHash = await bcrypt.hash(currentPassword, BCRYPT_COST);
|
||||
|
||||
// Step 2: Verify the current password against the stored hash
|
||||
// (simulates the bcrypt.compare check in the change-password route)
|
||||
const currentPasswordValid = await bcrypt.compare(currentPassword, currentHash);
|
||||
expect(currentPasswordValid).toBe(true);
|
||||
|
||||
// Step 3: Hash the new password (simulates bcrypt.hash(newPassword, 10) in the route)
|
||||
const newHash = await bcrypt.hash(newPassword, BCRYPT_COST);
|
||||
|
||||
// Step 4: Verify the new password matches the new hash (round-trip property)
|
||||
const newPasswordValid = await bcrypt.compare(newPassword, newHash);
|
||||
expect(newPasswordValid).toBe(true);
|
||||
}
|
||||
),
|
||||
{ numRuns: 100 }
|
||||
);
|
||||
}, 120000); // 2-minute timeout for 100 bcrypt iterations
|
||||
});
|
||||
Reference in New Issue
Block a user