mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-09-25 06:01:40 +08:00
test(server): ensure session info exists
This commit is contained in:
parent
2ceab66b98
commit
e003ec3b6f
@ -2,14 +2,19 @@ import { beforeAll, describe, expect, it } from "vitest";
|
|||||||
import supertest from "supertest";
|
import supertest from "supertest";
|
||||||
import type { Application } from "express";
|
import type { Application } from "express";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import type { SQLiteSessionStore } from "./session_parser.js";
|
||||||
|
import { promisify } from "util";
|
||||||
|
import { SessionData } from "express-session";
|
||||||
|
|
||||||
let app: Application;
|
let app: Application;
|
||||||
|
let sessionStore: SQLiteSessionStore;
|
||||||
|
|
||||||
describe("Login Route test", () => {
|
describe("Login Route test", () => {
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const buildApp = (await import("../app.js")).default;
|
const buildApp = (await import("../app.js")).default;
|
||||||
app = await buildApp();
|
app = await buildApp();
|
||||||
|
sessionStore = (await import("./session_parser.js")).sessionStore;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return the login page, when using a GET request", async () => {
|
it("should return the login page, when using a GET request", async () => {
|
||||||
@ -52,7 +57,7 @@ describe("Login Route test", () => {
|
|||||||
// match for e.g. "Expires=Wed, 07 May 2025 07:02:59 GMT;"
|
// match for e.g. "Expires=Wed, 07 May 2025 07:02:59 GMT;"
|
||||||
const expiresCookieRegExp = /Expires=(?<date>[\w\s,:]+)/;
|
const expiresCookieRegExp = /Expires=(?<date>[\w\s,:]+)/;
|
||||||
const expiresCookieMatch = setCookieHeader.match(expiresCookieRegExp);
|
const expiresCookieMatch = setCookieHeader.match(expiresCookieRegExp);
|
||||||
const actualExpiresDate = new Date(expiresCookieMatch?.groups?.date || "").toUTCString()
|
const actualExpiresDate = new Date(expiresCookieMatch?.groups?.date || "").toUTCString();
|
||||||
|
|
||||||
expect(actualExpiresDate).to.not.eql("Invalid Date");
|
expect(actualExpiresDate).to.not.eql("Invalid Date");
|
||||||
|
|
||||||
@ -60,6 +65,13 @@ describe("Login Route test", () => {
|
|||||||
// if for some reason execution is slow between calculation of expected and actual
|
// if for some reason execution is slow between calculation of expected and actual
|
||||||
expect(actualExpiresDate.slice(0,23)).toBe(expectedExpiresDate.slice(0,23))
|
expect(actualExpiresDate.slice(0,23)).toBe(expectedExpiresDate.slice(0,23))
|
||||||
|
|
||||||
|
// Check the session is stored in the database.
|
||||||
|
const session = await getSessionFromCookie(setCookieHeader);
|
||||||
|
expect(session!).toBeTruthy();
|
||||||
|
expect(session!.cookie.expires).toBeTruthy();
|
||||||
|
expect(new Date(session!.cookie.expires!).toUTCString().substring(0, 23))
|
||||||
|
.toBe(expectedExpiresDate.substring(0, 23));
|
||||||
|
expect(session!.loggedIn).toBe(true);
|
||||||
}, 10_000);
|
}, 10_000);
|
||||||
// use 10 sec (10_000 ms) timeout for now, instead of default 5 sec to work around
|
// use 10 sec (10_000 ms) timeout for now, instead of default 5 sec to work around
|
||||||
// failing CI, because for some reason it currently takes approx. 6 secs to run
|
// failing CI, because for some reason it currently takes approx. 6 secs to run
|
||||||
@ -67,7 +79,6 @@ describe("Login Route test", () => {
|
|||||||
|
|
||||||
|
|
||||||
it("does not set Expires, when 'Remember Me' is not ticked", async () => {
|
it("does not set Expires, when 'Remember Me' is not ticked", async () => {
|
||||||
|
|
||||||
const res = await supertest(app)
|
const res = await supertest(app)
|
||||||
.post("/login")
|
.post("/login")
|
||||||
.send({ password: "demo1234" })
|
.send({ password: "demo1234" })
|
||||||
@ -76,14 +87,38 @@ describe("Login Route test", () => {
|
|||||||
const setCookieHeader = res.headers["set-cookie"][0];
|
const setCookieHeader = res.headers["set-cookie"][0];
|
||||||
|
|
||||||
// match for e.g. "Expires=Wed, 07 May 2025 07:02:59 GMT;"
|
// match for e.g. "Expires=Wed, 07 May 2025 07:02:59 GMT;"
|
||||||
const expiresCookieRegExp = /Expires=(?<date>[\w\s,:]+)/;
|
expect(setCookieHeader).not.toMatch(/Expires=(?<date>[\w\s,:]+)/)
|
||||||
const expiresCookieMatch = setCookieHeader.match(expiresCookieRegExp);
|
|
||||||
expect(expiresCookieMatch).toBeNull();
|
|
||||||
|
|
||||||
|
// Check the session is stored in the database.
|
||||||
|
const session = await getSessionFromCookie(setCookieHeader);
|
||||||
|
expect(session!).toBeTruthy();
|
||||||
|
expect(session!.cookie.expires).toBeUndefined();
|
||||||
|
expect(session!.loggedIn).toBe(true);
|
||||||
}, 10_000);
|
}, 10_000);
|
||||||
// use 10 sec (10_000 ms) timeout for now, instead of default 5 sec to work around
|
// use 10 sec (10_000 ms) timeout for now, instead of default 5 sec to work around
|
||||||
// failing CI, because for some reason it currently takes approx. 6 secs to run
|
// failing CI, because for some reason it currently takes approx. 6 secs to run
|
||||||
// TODO: actually identify what is causing this and fix the flakiness
|
// TODO: actually identify what is causing this and fix the flakiness
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function getSessionFromCookie(setCookieHeader: string) {
|
||||||
|
// Extract the session ID from the cookie.
|
||||||
|
const sessionIdMatch = setCookieHeader.match(/trilium.sid=(?<sessionId>[^;]+)/)?.[1];
|
||||||
|
expect(sessionIdMatch).toBeTruthy();
|
||||||
|
|
||||||
|
// Check the session is stored in the database.
|
||||||
|
const sessionId = decodeURIComponent(sessionIdMatch!).slice(2).split(".")[0];
|
||||||
|
return await getSessionFromStore(sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSessionFromStore(sessionId: string) {
|
||||||
|
return new Promise<SessionData | null | undefined>((resolve, reject) => {
|
||||||
|
sessionStore.get(sessionId, (err, session) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(session);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
14
apps/server/src/routes/session_parser.spec.ts
Normal file
14
apps/server/src/routes/session_parser.spec.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { beforeAll, describe, expect, it } from "vitest";
|
||||||
|
import supertest from "supertest";
|
||||||
|
import type { Application } from "express";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
let app: Application;
|
||||||
|
|
||||||
|
describe("Session parser", () => {
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const buildApp = (await import("../app.js")).default;
|
||||||
|
app = await buildApp();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -5,7 +5,7 @@ import config from "../services/config.js";
|
|||||||
import log from "../services/log.js";
|
import log from "../services/log.js";
|
||||||
import type express from "express";
|
import type express from "express";
|
||||||
|
|
||||||
class SQLiteSessionStore extends Store {
|
export class SQLiteSessionStore extends Store {
|
||||||
|
|
||||||
get(sid: string, callback: (err: any, session?: session.SessionData | null) => void): void {
|
get(sid: string, callback: (err: any, session?: session.SessionData | null) => void): void {
|
||||||
try {
|
try {
|
||||||
@ -52,6 +52,8 @@ class SQLiteSessionStore extends Store {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const sessionStore = new SQLiteSessionStore();
|
||||||
|
|
||||||
const sessionParser: express.RequestHandler = session({
|
const sessionParser: express.RequestHandler = session({
|
||||||
secret: sessionSecret,
|
secret: sessionSecret,
|
||||||
resave: false, // true forces the session to be saved back to the session store, even if the session was never modified during the request.
|
resave: false, // true forces the session to be saved back to the session store, even if the session was never modified during the request.
|
||||||
@ -62,7 +64,7 @@ const sessionParser: express.RequestHandler = session({
|
|||||||
maxAge: config.Session.cookieMaxAge * 1000 // needs value in milliseconds
|
maxAge: config.Session.cookieMaxAge * 1000 // needs value in milliseconds
|
||||||
},
|
},
|
||||||
name: "trilium.sid",
|
name: "trilium.sid",
|
||||||
store: new SQLiteSessionStore()
|
store: sessionStore
|
||||||
});
|
});
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user