mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 03:29:02 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			176 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import * as utils from "./utils.js";
 | |
| import { ContentDoesNotExistError } from "./ContentDoesNotExistError.js";
 | |
| import { createPartialContentHandler } from "./createPartialContentHandler.js";
 | |
| import type { ContentProvider } from "./ContentProvider.js";
 | |
| import type { Logger } from "./Logger.js";
 | |
| import type { Request, Response } from "express";
 | |
| import type { Content } from "./Content.js";
 | |
| import { Stream } from "stream";
 | |
| import type { Range } from "./Range.js";
 | |
| import type { MockInstance } from "vitest";
 | |
| 
 | |
| describe("createPartialContentHandler tests", () => {
 | |
|   let logger: Logger;
 | |
|   beforeEach(() => {
 | |
|     logger = {
 | |
|       debug: vi.fn() as (message: string, extra?: any) => void
 | |
|     };
 | |
|   });
 | |
|   afterEach(() => {
 | |
|     vi.restoreAllMocks();
 | |
|   });
 | |
|   it("returns a handler", () => {
 | |
|     const contentProvider = vi.fn().mockResolvedValue({}) as ContentProvider;
 | |
|     const handler = createPartialContentHandler(contentProvider, logger);
 | |
|     expect(typeof handler === "function");
 | |
|   });
 | |
| 
 | |
|   describe("handler tests", () => {
 | |
|     let req: Request;
 | |
|     let res: Response;
 | |
|     let statusSpy: MockInstance;
 | |
|     let sendSpy: MockInstance;
 | |
|     let sendStatusSpy: MockInstance;
 | |
|     beforeEach(() => {
 | |
|       req = {} as Request;
 | |
|       res = {
 | |
|         status: (code: number) => res,
 | |
|         send: (message: string) => res,
 | |
|         sendStatus: (code: number) => res,
 | |
|         setHeader: vi.fn() as (name: string, value: string) => void
 | |
|       } as Response;
 | |
|       statusSpy = vi.spyOn(res, "status");
 | |
|       sendSpy = vi.spyOn(res, "send");
 | |
|       sendStatusSpy = vi.spyOn(res, "sendStatus");
 | |
|     });
 | |
|     it("invokes contentProvider with the specified request", async () => {
 | |
|       const contentProvider = vi.fn().mockResolvedValue({}) as ContentProvider;
 | |
|       const handler = createPartialContentHandler(contentProvider, logger);
 | |
|       try {
 | |
|         await handler(req, res);
 | |
|       } catch {}
 | |
|       expect(contentProvider).toHaveBeenCalledExactlyOnceWith(req);
 | |
|     });
 | |
|     it("returns 404 if contentProvider throws ContentDoesNotExistError error", async () => {
 | |
|       const error = new ContentDoesNotExistError("404-File not found!");
 | |
|       const contentProvider = vi.fn().mockRejectedValue(error) as ContentProvider;
 | |
|       const handler = createPartialContentHandler(contentProvider, logger);
 | |
|       try {
 | |
|         await handler(req, res);
 | |
|         expect(statusSpy).toHaveBeenCalledExactlyOnceWith(404);
 | |
|         expect(sendSpy).toHaveBeenCalledExactlyOnceWith(error.message);
 | |
|       } catch {
 | |
|         expect(false);
 | |
|       }
 | |
|     });
 | |
|     it("returns 500 if contentProvider throws any other error", async () => {
 | |
|       const error = new Error("Something went wrong!");
 | |
|       const contentProvider = vi.fn().mockRejectedValue(error) as ContentProvider;
 | |
|       const handler = createPartialContentHandler(contentProvider, logger);
 | |
|       try {
 | |
|         await handler(req, res);
 | |
|         expect(sendStatusSpy).toHaveBeenCalledExactlyOnceWith(500);
 | |
|       } catch {
 | |
|         expect(false);
 | |
|       }
 | |
|     });
 | |
|     it("returns 416 if parseRangeHeader throws RangeParserError error", async () => {
 | |
|       const contentProvider = vi.fn().mockResolvedValue({}) as ContentProvider;
 | |
|       const handler = createPartialContentHandler(contentProvider, logger);
 | |
|       req.headers = { range: "bytes=30-10" };
 | |
|       try {
 | |
|         await handler(req, res);
 | |
|         expect(statusSpy).toHaveBeenCalledExactlyOnceWith(416);
 | |
|       } catch {
 | |
|         expect(false);
 | |
|       }
 | |
|     });
 | |
|     it("returns 500 if parseRangeHeader throws other errors", async () => {
 | |
|       const contentProvider = vi.fn().mockResolvedValue({}) as ContentProvider;
 | |
|       const handler = createPartialContentHandler(contentProvider, logger);
 | |
|       try {
 | |
|         await handler(req, res);
 | |
|         expect(sendStatusSpy).toHaveBeenCalledExactlyOnceWith(500);
 | |
|       } catch {
 | |
|         expect(false);
 | |
|       }
 | |
|     });
 | |
|     it("returns correct response if range is not specified", async () => {
 | |
|       const result = ({
 | |
|         pipe() {
 | |
|           return result;
 | |
|         }
 | |
|       } as any) as Stream;
 | |
|       const content: Content = {
 | |
|         fileName: "file.txt",
 | |
|         totalSize: 10,
 | |
|         mimeType: "text/plain",
 | |
|         getStream(range?: Range) {
 | |
|           return result;
 | |
|         }
 | |
|       };
 | |
|       const pipeSpy = vi.spyOn(result, "pipe");
 | |
|       const getStreamSpy = vi.spyOn(content, "getStream");
 | |
|       const contentProvider = vi.fn().mockResolvedValue(content) as ContentProvider;
 | |
|       const handler = createPartialContentHandler(contentProvider, logger);
 | |
|       const setContentTypeHeaderSpy = vi.spyOn(utils, "setContentTypeHeader");
 | |
|       const setContentDispositionHeaderSpy = vi.spyOn(utils, "setContentDispositionHeader");
 | |
|       const setAcceptRangesHeaderSpy = vi.spyOn(utils, "setAcceptRangesHeader");
 | |
|       const setContentLengthHeaderSpy = vi.spyOn(utils, "setContentLengthHeader");
 | |
|       const setContentRangeHeaderSpy = vi.spyOn(utils, "setContentRangeHeader");
 | |
|       try {
 | |
|         await handler(req, res);
 | |
|         expect(setContentTypeHeaderSpy).toHaveBeenCalledExactlyOnceWith(content.mimeType, res);
 | |
|         expect(setContentDispositionHeaderSpy).toHaveBeenCalledExactlyOnceWith(content.fileName, res);
 | |
|         expect(setAcceptRangesHeaderSpy).toHaveBeenCalledExactlyOnceWith(res);
 | |
|         expect(setContentLengthHeaderSpy).toHaveBeenCalledExactlyOnceWith(content.totalSize, res);
 | |
|         expect(getStreamSpy).toHaveBeenCalledExactlyOnceWith();
 | |
|         expect(pipeSpy).toHaveBeenCalledExactlyOnceWith(res);
 | |
|         expect(setContentRangeHeaderSpy).not.toHaveBeenCalled();
 | |
|       } catch {
 | |
|         expect(false);
 | |
|       }
 | |
|     });
 | |
|     it("returns correct partial response if range is specified", async () => {
 | |
|       req.headers = {
 | |
|         range: "bytes=0-5"
 | |
|       };
 | |
|       const result = ({
 | |
|         pipe() {
 | |
|           return result;
 | |
|         }
 | |
|       } as any) as Stream;
 | |
|       const content: Content = {
 | |
|         fileName: "file.txt",
 | |
|         totalSize: 10,
 | |
|         mimeType: "text/plain",
 | |
|         getStream(range?: Range) {
 | |
|           return result;
 | |
|         }
 | |
|       };
 | |
|       const range = { start: 0, end: 5 };
 | |
|       const pipeSpy = vi.spyOn(result, "pipe");
 | |
|       const getStreamSpy = vi.spyOn(content, "getStream");
 | |
|       const contentProvider = vi.fn().mockResolvedValue(content) as ContentProvider;
 | |
|       const handler = createPartialContentHandler(contentProvider, logger);
 | |
|       const setContentTypeHeaderSpy = vi.spyOn(utils, "setContentTypeHeader");
 | |
|       const setContentDispositionHeaderSpy = vi.spyOn(utils, "setContentDispositionHeader");
 | |
|       const setAcceptRangesHeaderSpy = vi.spyOn(utils, "setAcceptRangesHeader");
 | |
|       const setContentLengthHeaderSpy = vi.spyOn(utils, "setContentLengthHeader");
 | |
|       const setContentRangeHeaderSpy = vi.spyOn(utils, "setContentRangeHeader");
 | |
|       try {
 | |
|         await handler(req, res);
 | |
|         expect(setContentTypeHeaderSpy).toHaveBeenCalledExactlyOnceWith(content.mimeType, res);
 | |
|         expect(setContentDispositionHeaderSpy).toHaveBeenCalledExactlyOnceWith(content.fileName, res);
 | |
|         expect(setAcceptRangesHeaderSpy).toHaveBeenCalledExactlyOnceWith(res);
 | |
|         expect(setContentRangeHeaderSpy).toHaveBeenCalledExactlyOnceWith(range, content.totalSize, res);
 | |
|         expect(setContentLengthHeaderSpy).toHaveBeenCalledExactlyOnceWith(6, res);
 | |
|         expect(getStreamSpy).toHaveBeenCalledExactlyOnceWith(range);
 | |
|         expect(pipeSpy).toHaveBeenCalledExactlyOnceWith(res);
 | |
|       } catch {
 | |
|         expect(false);
 | |
|       }
 | |
|     });
 | |
|   });
 | |
| });
 | 
