mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
test(core): add unit tests for generateUserId()
(#113)
This commit is contained in:
parent
7ae7912642
commit
8e291b51bf
3 changed files with 73 additions and 20 deletions
50
packages/core/src/lib/user.test.ts
Normal file
50
packages/core/src/lib/user.test.ts
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import { hasUserWithId } from '@/queries/user';
|
||||||
|
|
||||||
|
import { generateUserId } from './user';
|
||||||
|
|
||||||
|
jest.mock('@/queries/user');
|
||||||
|
|
||||||
|
describe('generateUserId()', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
(hasUserWithId as jest.MockedFunction<typeof hasUserWithId>).mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('generates user ID with correct length when no conflict found', async () => {
|
||||||
|
const mockedHasUserWithId = (
|
||||||
|
hasUserWithId as jest.MockedFunction<typeof hasUserWithId>
|
||||||
|
).mockImplementationOnce(async () => false);
|
||||||
|
|
||||||
|
await expect(generateUserId()).resolves.toHaveLength(12);
|
||||||
|
expect(mockedHasUserWithId).toBeCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('generates user ID with correct length when retry limit is not reached', async () => {
|
||||||
|
// eslint-disable-next-line @silverhand/fp/no-let
|
||||||
|
let tried = 0;
|
||||||
|
const mockedHasUserWithId = (
|
||||||
|
hasUserWithId as jest.MockedFunction<typeof hasUserWithId>
|
||||||
|
).mockImplementation(async () => {
|
||||||
|
if (tried) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @silverhand/fp/no-mutation
|
||||||
|
tried++;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(generateUserId(2)).resolves.toHaveLength(12);
|
||||||
|
expect(mockedHasUserWithId).toBeCalledTimes(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects with correct error message when retry limit is reached', async () => {
|
||||||
|
const mockedHasUserWithId = (
|
||||||
|
hasUserWithId as jest.MockedFunction<typeof hasUserWithId>
|
||||||
|
).mockImplementation(async () => true);
|
||||||
|
|
||||||
|
await expect(generateUserId(10)).rejects.toThrow(
|
||||||
|
'Cannot generate user ID in reasonable retries'
|
||||||
|
);
|
||||||
|
expect(mockedHasUserWithId).toBeCalledTimes(11);
|
||||||
|
});
|
||||||
|
});
|
21
packages/core/src/lib/user.ts
Normal file
21
packages/core/src/lib/user.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import pRetry from 'p-retry';
|
||||||
|
|
||||||
|
import { hasUserWithId } from '@/queries/user';
|
||||||
|
import { buildIdGenerator } from '@/utils/id';
|
||||||
|
|
||||||
|
const userId = buildIdGenerator(12);
|
||||||
|
|
||||||
|
// LOG-89: Add unit tests
|
||||||
|
export const generateUserId = async (retries = 500) =>
|
||||||
|
pRetry(
|
||||||
|
async () => {
|
||||||
|
const id = userId();
|
||||||
|
|
||||||
|
if (!(await hasUserWithId(id))) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Cannot generate user ID in reasonable retries');
|
||||||
|
},
|
||||||
|
{ retries, factor: 0 } // No need for exponential backoff
|
||||||
|
);
|
|
@ -1,33 +1,15 @@
|
||||||
import { PasswordEncryptionMethod } from '@logto/schemas';
|
import { PasswordEncryptionMethod } from '@logto/schemas';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import pRetry from 'p-retry';
|
|
||||||
import { object, string } from 'zod';
|
import { object, string } from 'zod';
|
||||||
|
|
||||||
import RequestError from '@/errors/RequestError';
|
import RequestError from '@/errors/RequestError';
|
||||||
|
import { generateUserId } from '@/lib/user';
|
||||||
import koaGuard from '@/middleware/koa-guard';
|
import koaGuard from '@/middleware/koa-guard';
|
||||||
import { hasUser, hasUserWithId, insertUser } from '@/queries/user';
|
import { hasUser, insertUser } from '@/queries/user';
|
||||||
import { buildIdGenerator } from '@/utils/id';
|
|
||||||
import { encryptPassword } from '@/utils/password';
|
import { encryptPassword } from '@/utils/password';
|
||||||
|
|
||||||
import { AnonymousRouter } from './types';
|
import { AnonymousRouter } from './types';
|
||||||
|
|
||||||
const userId = buildIdGenerator(12);
|
|
||||||
|
|
||||||
// LOG-89: Add unit tests
|
|
||||||
const generateUserId = async (retries = 500) =>
|
|
||||||
pRetry(
|
|
||||||
async () => {
|
|
||||||
const id = userId();
|
|
||||||
|
|
||||||
if (!(await hasUserWithId(id))) {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error('Cannot generate user ID in reasonable retries');
|
|
||||||
},
|
|
||||||
{ retries }
|
|
||||||
);
|
|
||||||
|
|
||||||
export default function userRoutes<T extends AnonymousRouter>(router: T) {
|
export default function userRoutes<T extends AnonymousRouter>(router: T) {
|
||||||
router.post(
|
router.post(
|
||||||
'/user',
|
'/user',
|
||||||
|
|
Loading…
Reference in a new issue