mirror of
https://github.com/logto-io/logto.git
synced 2025-01-06 20:40:08 -05:00
test(core): add api response guard and error case tests to dashboard api (#3789)
* test(core): add dashboard api response guard add dashboard api response guard * test(core): add dashboard integration tests add dashboard integration tests
This commit is contained in:
parent
f4f8224ff9
commit
5c0ed8e79e
4 changed files with 94 additions and 40 deletions
|
@ -1,6 +1,7 @@
|
||||||
import { dateRegex } from '@logto/core-kit';
|
import { dateRegex } from '@logto/core-kit';
|
||||||
|
import { getNewUsersResponseGuard, getActiveUsersResponseGuard } from '@logto/schemas';
|
||||||
import { endOfDay, format, subDays } from 'date-fns';
|
import { endOfDay, format, subDays } from 'date-fns';
|
||||||
import { object, string } from 'zod';
|
import { number, object, string } from 'zod';
|
||||||
|
|
||||||
import koaGuard from '#src/middleware/koa-guard.js';
|
import koaGuard from '#src/middleware/koa-guard.js';
|
||||||
|
|
||||||
|
@ -20,56 +21,74 @@ export default function dashboardRoutes<T extends AuthedRouter>(
|
||||||
users: { countUsers, getDailyNewUserCountsByTimeInterval },
|
users: { countUsers, getDailyNewUserCountsByTimeInterval },
|
||||||
} = queries;
|
} = queries;
|
||||||
|
|
||||||
router.get('/dashboard/users/total', async (ctx, next) => {
|
router.get(
|
||||||
const { count: totalUserCount } = await countUsers();
|
'/dashboard/users/total',
|
||||||
ctx.body = { totalUserCount };
|
koaGuard({
|
||||||
|
response: object({
|
||||||
|
totalUserCount: number(),
|
||||||
|
}),
|
||||||
|
status: [200, 401, 403],
|
||||||
|
}),
|
||||||
|
async (ctx, next) => {
|
||||||
|
const { count: totalUserCount } = await countUsers();
|
||||||
|
ctx.body = { totalUserCount };
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
router.get('/dashboard/users/new', async (ctx, next) => {
|
router.get(
|
||||||
const today = Date.now();
|
'/dashboard/users/new',
|
||||||
const dailyNewUserCounts = await getDailyNewUserCountsByTimeInterval(
|
koaGuard({
|
||||||
// (14 days ago 23:59:59.999, today 23:59:59.999]
|
response: getNewUsersResponseGuard,
|
||||||
getEndOfDayTimestamp(subDays(today, 14)),
|
status: [200, 401, 403],
|
||||||
getEndOfDayTimestamp(today)
|
}),
|
||||||
);
|
async (ctx, next) => {
|
||||||
|
const today = Date.now();
|
||||||
|
const dailyNewUserCounts = await getDailyNewUserCountsByTimeInterval(
|
||||||
|
// (14 days ago 23:59:59.999, today 23:59:59.999]
|
||||||
|
getEndOfDayTimestamp(subDays(today, 14)),
|
||||||
|
getEndOfDayTimestamp(today)
|
||||||
|
);
|
||||||
|
|
||||||
const last14DaysNewUserCounts = new Map(
|
const last14DaysNewUserCounts = new Map(
|
||||||
dailyNewUserCounts.map(({ date, count }) => [date, count])
|
dailyNewUserCounts.map(({ date, count }) => [date, count])
|
||||||
);
|
);
|
||||||
|
|
||||||
const todayNewUserCount = last14DaysNewUserCounts.get(getDateString(today)) ?? 0;
|
const todayNewUserCount = last14DaysNewUserCounts.get(getDateString(today)) ?? 0;
|
||||||
const yesterday = subDays(today, 1);
|
const yesterday = subDays(today, 1);
|
||||||
const yesterdayNewUserCount = last14DaysNewUserCounts.get(getDateString(yesterday)) ?? 0;
|
const yesterdayNewUserCount = last14DaysNewUserCounts.get(getDateString(yesterday)) ?? 0;
|
||||||
const todayDelta = todayNewUserCount - yesterdayNewUserCount;
|
const todayDelta = todayNewUserCount - yesterdayNewUserCount;
|
||||||
|
|
||||||
const last7DaysNewUserCount = indices(7)
|
const last7DaysNewUserCount = indices(7)
|
||||||
.map((index) => getDateString(subDays(today, index)))
|
.map((index) => getDateString(subDays(today, index)))
|
||||||
.reduce((sum, date) => sum + (last14DaysNewUserCounts.get(date) ?? 0), 0);
|
.reduce((sum, date) => sum + (last14DaysNewUserCounts.get(date) ?? 0), 0);
|
||||||
const newUserCountFrom13DaysAgoTo7DaysAgo = indices(7)
|
const newUserCountFrom13DaysAgoTo7DaysAgo = indices(7)
|
||||||
.map((index) => getDateString(subDays(today, index + 7)))
|
.map((index) => getDateString(subDays(today, index + 7)))
|
||||||
.reduce((sum, date) => sum + (last14DaysNewUserCounts.get(date) ?? 0), 0);
|
.reduce((sum, date) => sum + (last14DaysNewUserCounts.get(date) ?? 0), 0);
|
||||||
const last7DaysDelta = last7DaysNewUserCount - newUserCountFrom13DaysAgoTo7DaysAgo;
|
const last7DaysDelta = last7DaysNewUserCount - newUserCountFrom13DaysAgoTo7DaysAgo;
|
||||||
|
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
today: {
|
today: {
|
||||||
count: todayNewUserCount,
|
count: todayNewUserCount,
|
||||||
delta: todayDelta,
|
delta: todayDelta,
|
||||||
},
|
},
|
||||||
last7Days: {
|
last7Days: {
|
||||||
count: last7DaysNewUserCount,
|
count: last7DaysNewUserCount,
|
||||||
delta: last7DaysDelta,
|
delta: last7DaysDelta,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
'/dashboard/users/active',
|
'/dashboard/users/active',
|
||||||
koaGuard({
|
koaGuard({
|
||||||
query: object({ date: string().regex(dateRegex).optional() }),
|
query: object({ date: string().regex(dateRegex).optional() }),
|
||||||
|
response: getActiveUsersResponseGuard,
|
||||||
|
status: [200, 401, 403],
|
||||||
}),
|
}),
|
||||||
async (ctx, next) => {
|
async (ctx, next) => {
|
||||||
const {
|
const {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { SignInIdentifier } from '@logto/schemas';
|
import { SignInIdentifier } from '@logto/schemas';
|
||||||
|
|
||||||
import type { StatisticsData } from '#src/api/index.js';
|
import type { StatisticsData } from '#src/api/index.js';
|
||||||
import { getTotalUsersCount, getNewUsersData, getActiveUsersData } from '#src/api/index.js';
|
import { api, getTotalUsersCount, getNewUsersData, getActiveUsersData } from '#src/api/index.js';
|
||||||
|
import { createResponseWithCode } from '#src/helpers/admin-tenant.js';
|
||||||
import { createUserByAdmin } from '#src/helpers/index.js';
|
import { createUserByAdmin } from '#src/helpers/index.js';
|
||||||
import { registerNewUser, signInWithPassword } from '#src/helpers/interactions.js';
|
import { registerNewUser, signInWithPassword } from '#src/helpers/interactions.js';
|
||||||
import { enableAllPasswordSignInMethods } from '#src/helpers/sign-in-experience.js';
|
import { enableAllPasswordSignInMethods } from '#src/helpers/sign-in-experience.js';
|
||||||
|
@ -16,6 +17,16 @@ describe('admin console dashboard', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('non authorized request should return 401', async () => {
|
||||||
|
await expect(api.get('dashboard/users/total')).rejects.toMatchObject(
|
||||||
|
createResponseWithCode(401)
|
||||||
|
);
|
||||||
|
await expect(api.get('dashboard/users/new')).rejects.toMatchObject(createResponseWithCode(401));
|
||||||
|
await expect(api.get('dashboard/users/active')).rejects.toMatchObject(
|
||||||
|
createResponseWithCode(401)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('should get total user count successfully', async () => {
|
it('should get total user count successfully', async () => {
|
||||||
const { totalUserCount: originTotalUserCount } = await getTotalUsersCount();
|
const { totalUserCount: originTotalUserCount } = await getTotalUsersCount();
|
||||||
|
|
||||||
|
|
23
packages/schemas/src/types/dashboard.ts
Normal file
23
packages/schemas/src/types/dashboard.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { number, object, array, string } from 'zod';
|
||||||
|
|
||||||
|
const dashboardUsersDataGuard = object({
|
||||||
|
count: number(),
|
||||||
|
delta: number(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getNewUsersResponseGuard = object({
|
||||||
|
today: dashboardUsersDataGuard,
|
||||||
|
last7Days: dashboardUsersDataGuard,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getActiveUsersResponseGuard = object({
|
||||||
|
dauCurve: array(
|
||||||
|
object({
|
||||||
|
date: string(),
|
||||||
|
count: number(),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
dau: dashboardUsersDataGuard,
|
||||||
|
wau: dashboardUsersDataGuard,
|
||||||
|
mau: dashboardUsersDataGuard,
|
||||||
|
});
|
|
@ -17,3 +17,4 @@ export * from './hook.js';
|
||||||
export * from './service-log.js';
|
export * from './service-log.js';
|
||||||
export * from './theme.js';
|
export * from './theme.js';
|
||||||
export * from './cookie.js';
|
export * from './cookie.js';
|
||||||
|
export * from './dashboard.js';
|
||||||
|
|
Loading…
Reference in a new issue