0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -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:
simeng-li 2023-05-02 20:58:48 +08:00 committed by GitHub
parent f4f8224ff9
commit 5c0ed8e79e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 94 additions and 40 deletions

View file

@ -1,6 +1,7 @@
import { dateRegex } from '@logto/core-kit';
import { getNewUsersResponseGuard, getActiveUsersResponseGuard } from '@logto/schemas';
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';
@ -20,56 +21,74 @@ export default function dashboardRoutes<T extends AuthedRouter>(
users: { countUsers, getDailyNewUserCountsByTimeInterval },
} = queries;
router.get('/dashboard/users/total', async (ctx, next) => {
const { count: totalUserCount } = await countUsers();
ctx.body = { totalUserCount };
router.get(
'/dashboard/users/total',
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) => {
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)
);
router.get(
'/dashboard/users/new',
koaGuard({
response: getNewUsersResponseGuard,
status: [200, 401, 403],
}),
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(
dailyNewUserCounts.map(({ date, count }) => [date, count])
);
const last14DaysNewUserCounts = new Map(
dailyNewUserCounts.map(({ date, count }) => [date, count])
);
const todayNewUserCount = last14DaysNewUserCounts.get(getDateString(today)) ?? 0;
const yesterday = subDays(today, 1);
const yesterdayNewUserCount = last14DaysNewUserCounts.get(getDateString(yesterday)) ?? 0;
const todayDelta = todayNewUserCount - yesterdayNewUserCount;
const todayNewUserCount = last14DaysNewUserCounts.get(getDateString(today)) ?? 0;
const yesterday = subDays(today, 1);
const yesterdayNewUserCount = last14DaysNewUserCounts.get(getDateString(yesterday)) ?? 0;
const todayDelta = todayNewUserCount - yesterdayNewUserCount;
const last7DaysNewUserCount = indices(7)
.map((index) => getDateString(subDays(today, index)))
.reduce((sum, date) => sum + (last14DaysNewUserCounts.get(date) ?? 0), 0);
const newUserCountFrom13DaysAgoTo7DaysAgo = indices(7)
.map((index) => getDateString(subDays(today, index + 7)))
.reduce((sum, date) => sum + (last14DaysNewUserCounts.get(date) ?? 0), 0);
const last7DaysDelta = last7DaysNewUserCount - newUserCountFrom13DaysAgoTo7DaysAgo;
const last7DaysNewUserCount = indices(7)
.map((index) => getDateString(subDays(today, index)))
.reduce((sum, date) => sum + (last14DaysNewUserCounts.get(date) ?? 0), 0);
const newUserCountFrom13DaysAgoTo7DaysAgo = indices(7)
.map((index) => getDateString(subDays(today, index + 7)))
.reduce((sum, date) => sum + (last14DaysNewUserCounts.get(date) ?? 0), 0);
const last7DaysDelta = last7DaysNewUserCount - newUserCountFrom13DaysAgoTo7DaysAgo;
ctx.body = {
today: {
count: todayNewUserCount,
delta: todayDelta,
},
last7Days: {
count: last7DaysNewUserCount,
delta: last7DaysDelta,
},
};
ctx.body = {
today: {
count: todayNewUserCount,
delta: todayDelta,
},
last7Days: {
count: last7DaysNewUserCount,
delta: last7DaysDelta,
},
};
return next();
});
return next();
}
);
router.get(
'/dashboard/users/active',
koaGuard({
query: object({ date: string().regex(dateRegex).optional() }),
response: getActiveUsersResponseGuard,
status: [200, 401, 403],
}),
async (ctx, next) => {
const {

View file

@ -1,7 +1,8 @@
import { SignInIdentifier } from '@logto/schemas';
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 { registerNewUser, signInWithPassword } from '#src/helpers/interactions.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 () => {
const { totalUserCount: originTotalUserCount } = await getTotalUsersCount();

View 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,
});

View file

@ -17,3 +17,4 @@ export * from './hook.js';
export * from './service-log.js';
export * from './theme.js';
export * from './cookie.js';
export * from './dashboard.js';