config/__tests__/reset-password.spec.js
Rama main · réplica de lectura del repositorio original.
const mockCalls = [];
const mockUserId = 'user-1';
const mockFailures = new Set();
const mockStep = (name, value) =>
jest.fn(async () => {
mockCalls.push(name);
if (mockFailures.has(name)) {
throw new Error(`${name} failed`);
}
return value;
});
const mockStampedAt = new Date('2026-01-01T00:00:00.000Z');
const mockMethods = {
updateUser: jest.fn(async (_id, update) => {
const name = update.password ? 'writePassword' : 'restamp';
mockCalls.push(name);
if (mockFailures.has(name)) {
throw new Error(`${name} failed`);
}
return { _id: mockUserId };
}),
awaitAuthUserDocEviction: mockStep('evict'),
};
jest.mock('../connect', () => jest.fn(async () => undefined));
jest.mock('../helpers', () => ({
askSilentQuestion: jest.fn(async () => 'a-new-password'),
}));
jest.mock('~/cache/getLogStores', () => jest.fn());
jest.mock('readline', () => ({
createInterface: () => ({
question: (_query, answer) => answer('user@example.com'),
close: () => undefined,
}),
}));
jest.mock('@librechat/api', () => ({
createPasswordResetUpdate: (password) => ({ password, credentialsChangedAt: mockStampedAt }),
restampRetirementCutoff: (field, _userId, stampedAt, write) =>
write({ [field]: new Date() }, { [field]: stampedAt }),
}));
jest.mock('@librechat/data-schemas', () => ({
createModels: () => ({
User: { findOne: async () => ({ _id: mockUserId }) },
Passkey: { deleteMany: mockStep('deletePasskeys', { deletedCount: 1 }) },
Session: { deleteMany: mockStep('deleteSessions') },
}),
createMethods: () => mockMethods,
}));
/** The script runs on load and ends in process.exit, so the exit code is its result. */
const runScript = () =>
new Promise((resolve) => {
jest.spyOn(process, 'exit').mockImplementation((code) => {
resolve(code);
/** Ends the script's flow the way a real exit would, without tripping its own catch. */
return new Promise(() => undefined);
});
jest.isolateModules(() => require('../reset-password'));
});
describe('Reset password CLI', () => {
beforeEach(() => {
mockCalls.length = 0;
mockFailures.clear();
jest.spyOn(console, 'log').mockImplementation(() => undefined);
jest.spyOn(console, 'error').mockImplementation(() => undefined);
});
afterEach(() => {
jest.restoreAllMocks();
});
it('settles the auth cache after the final cutoff write', async () => {
await expect(runScript()).resolves.toBe(0);
expect(mockCalls).toEqual([
'writePassword',
'deletePasskeys',
'deleteSessions',
'restamp',
'evict',
]);
});
it.each(['deletePasskeys', 'deleteSessions', 'restamp', 'evict'])(
'runs every other step and exits non-zero when %s fails',
async (failing) => {
mockFailures.add(failing);
await expect(runScript()).resolves.toBe(1);
expect(mockCalls).toEqual([
'writePassword',
'deletePasskeys',
'deleteSessions',
'restamp',
'evict',
]);
},
);
});