|
1 | 1 | import electron from "electron"; |
| 2 | +import type { Application } from "express"; |
| 3 | +import type { ParamsDictionary, Request, Response } from "express-serve-static-core"; |
| 4 | +import type QueryString from "qs"; |
| 5 | +import { Session, SessionData } from "express-session"; |
| 6 | +import { parse as parseQuery } from "qs"; |
| 7 | +import EventEmitter from "events"; |
2 | 8 |
|
3 | | -interface Response { |
4 | | - statusCode: number; |
5 | | - getHeader: (name: string) => string; |
6 | | - setHeader: (name: string, value: string) => Response; |
7 | | - header: (name: string, value: string) => Response; |
8 | | - status: (statusCode: number) => Response; |
9 | | - send: (obj: {}) => void; // eslint-disable-line @typescript-eslint/no-empty-object-type |
10 | | -} |
| 9 | +type MockedResponse = Response<any, Record<string, any>, number>; |
11 | 10 |
|
12 | | -function init(app: Express.Application) { |
| 11 | +function init(app: Application) { |
13 | 12 | electron.ipcMain.on("server-request", (event, arg) => { |
14 | | - const req = { |
15 | | - url: arg.url, |
16 | | - method: arg.method, |
17 | | - body: arg.data, |
18 | | - headers: arg.headers, |
19 | | - session: { |
20 | | - loggedIn: true |
21 | | - } |
22 | | - }; |
23 | | - |
24 | | - const respHeaders: Record<string, string> = {}; |
25 | | - |
26 | | - const res: Response = { |
27 | | - statusCode: 200, |
28 | | - getHeader: (name) => respHeaders[name], |
29 | | - setHeader: (name, value) => { |
30 | | - respHeaders[name] = value.toString(); |
31 | | - return res; |
32 | | - }, |
33 | | - header: (name, value) => { |
34 | | - respHeaders[name] = value.toString(); |
35 | | - return res; |
36 | | - }, |
37 | | - status: (statusCode) => { |
38 | | - res.statusCode = statusCode; |
39 | | - return res; |
40 | | - }, |
41 | | - send: (obj) => { |
42 | | - event.sender.send("server-response", { |
43 | | - url: arg.url, |
44 | | - method: arg.method, |
45 | | - requestId: arg.requestId, |
46 | | - statusCode: res.statusCode, |
47 | | - headers: respHeaders, |
48 | | - body: obj |
49 | | - }); |
50 | | - } |
51 | | - }; |
52 | | - |
53 | | - return (app as any)._router.handle(req, res, () => {}); |
| 13 | + const req = new FakeRequest(arg); |
| 14 | + const res = new FakeResponse(event, arg); |
| 15 | + |
| 16 | + return app.router(req as any, res as any, () => {}); |
54 | 17 | }); |
55 | 18 | } |
56 | 19 |
|
| 20 | +const fakeSession: Session & Partial<SessionData> = { |
| 21 | + id: "session-id", // Placeholder for session ID |
| 22 | + cookie: { |
| 23 | + originalMaxAge: 3600000, // 1 hour |
| 24 | + }, |
| 25 | + loggedIn: true, |
| 26 | + regenerate(callback) { |
| 27 | + callback?.(null); |
| 28 | + return fakeSession; |
| 29 | + }, |
| 30 | + destroy(callback) { |
| 31 | + callback?.(null); |
| 32 | + return fakeSession; |
| 33 | + }, |
| 34 | + reload(callback) { |
| 35 | + callback?.(null); |
| 36 | + return fakeSession; |
| 37 | + }, |
| 38 | + save(callback) { |
| 39 | + callback?.(null); |
| 40 | + return fakeSession; |
| 41 | + }, |
| 42 | + resetMaxAge: () => fakeSession, |
| 43 | + touch: () => fakeSession |
| 44 | +}; |
| 45 | + |
| 46 | +interface Arg { |
| 47 | + url: string; |
| 48 | + method: string; |
| 49 | + data: any; |
| 50 | + headers: Record<string, string> |
| 51 | +} |
| 52 | + |
| 53 | +class FakeRequest extends EventEmitter implements Pick<Request<ParamsDictionary, any, any, QueryString.ParsedQs, Record<string, any>>, "url" | "method" | "body" | "headers" | "session" | "query"> { |
| 54 | + url: string; |
| 55 | + method: string; |
| 56 | + body: any; |
| 57 | + headers: Record<string, string>; |
| 58 | + session: Session & Partial<SessionData>; |
| 59 | + query: Record<string, any>; |
| 60 | + |
| 61 | + constructor(arg: Arg) { |
| 62 | + super(); |
| 63 | + this.url = arg.url; |
| 64 | + this.method = arg.method; |
| 65 | + this.body = arg.data; |
| 66 | + this.headers = arg.headers; |
| 67 | + this.session = fakeSession; |
| 68 | + this.query = parseQuery(arg.url.split("?")[1] || "", { ignoreQueryPrefix: true }); |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | +class FakeResponse extends EventEmitter implements Pick<Response<any, Record<string, any>, number>, "status" | "send" | "json" | "setHeader"> { |
| 73 | + private respHeaders: Record<string, string | string[]> = {}; |
| 74 | + private event: Electron.IpcMainEvent; |
| 75 | + private arg: Arg & { requestId: string; }; |
| 76 | + statusCode: number = 200; |
| 77 | + headers: Record<string, string> = {}; |
| 78 | + locals: Record<string, any> = {}; |
| 79 | + |
| 80 | + constructor(event: Electron.IpcMainEvent, arg: Arg & { requestId: string; }) { |
| 81 | + super(); |
| 82 | + this.event = event; |
| 83 | + this.arg = arg; |
| 84 | + } |
| 85 | + |
| 86 | + getHeader(name) { |
| 87 | + return this.respHeaders[name]; |
| 88 | + } |
| 89 | + |
| 90 | + setHeader(name, value) { |
| 91 | + this.respHeaders[name] = value.toString(); |
| 92 | + return this as unknown as MockedResponse; |
| 93 | + } |
| 94 | + |
| 95 | + header(name: string, value?: string | string[]) { |
| 96 | + this.respHeaders[name] = value ?? ""; |
| 97 | + return this as unknown as MockedResponse; |
| 98 | + } |
| 99 | + |
| 100 | + status(statusCode) { |
| 101 | + this.statusCode = statusCode; |
| 102 | + return this as unknown as MockedResponse; |
| 103 | + } |
| 104 | + |
| 105 | + send(obj) { |
| 106 | + this.event.sender.send("server-response", { |
| 107 | + url: this.arg.url, |
| 108 | + method: this.arg.method, |
| 109 | + requestId: this.arg.requestId, |
| 110 | + statusCode: this.statusCode, |
| 111 | + headers: this.respHeaders, |
| 112 | + body: obj |
| 113 | + }); |
| 114 | + return this as unknown as MockedResponse; |
| 115 | + } |
| 116 | + |
| 117 | + json(obj) { |
| 118 | + this.send(JSON.stringify(obj)); |
| 119 | + return this as unknown as MockedResponse; |
| 120 | + } |
| 121 | +} |
| 122 | + |
57 | 123 | export default init; |
0 commit comments