| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- import { createServer, type Server } from 'node:http';
- import { renderHook, waitFor } from '@testing-library/react';
- import axios from 'axios';
- import express from 'express';
- import {
- afterAll,
- beforeAll,
- beforeEach,
- describe,
- expect,
- it,
- vi,
- } from 'vitest';
- import { useSWRxRef, useSWRxRefs } from '../src/client/stores/refs';
- import { routesFactory } from '../src/server/routes/refs';
- // Test server setup
- let testServer: Server;
- let baseURL: string;
- // Mock data for testing
- const mockUser = {
- _id: 'user123',
- username: 'testuser',
- email: 'test@example.com',
- };
- const mockPage = {
- _id: 'page123',
- path: '/test/page',
- };
- const mockAttachment = {
- _id: 'attachment123',
- originalName: 'test-file.pdf',
- fileName: 'test-file.pdf',
- fileFormat: 'pdf',
- filePath: '/uploads/test-file.pdf',
- filePathProxied: '/api/attachments/attachment123',
- downloadPathProxied: '/api/attachments/attachment123/download',
- fileSize: 1024,
- attachmentType: 'file',
- page: 'page123',
- creator: 'user123',
- createdAt: '2023-01-01T00:00:00.000Z', // Use string format to match JSON serialization
- };
- const mockAttachments = [
- {
- _id: 'attachment1',
- originalName: 'file1.pdf',
- fileName: 'file1.pdf',
- filePath: '/uploads/file1.pdf',
- creator: mockUser._id,
- page: mockPage._id, // This should match the page ID returned by the page query
- createdAt: '2023-01-01T00:00:00.000Z', // JSON serialized format
- fileFormat: 'pdf',
- fileSize: 1024,
- attachmentType: 'file',
- filePathProxied: '/api/attachments/attachment1',
- downloadPathProxied: '/api/attachments/attachment1/download',
- },
- {
- _id: 'attachment2',
- originalName: 'file2.jpg',
- fileName: 'file2.jpg',
- filePath: '/uploads/file2.jpg',
- creator: mockUser._id,
- page: mockPage._id, // This should match the page ID returned by the page query
- createdAt: '2023-01-01T00:00:00.000Z', // JSON serialized format
- fileFormat: 'image',
- fileSize: 2048,
- attachmentType: 'image',
- filePathProxied: '/api/attachments/attachment2',
- downloadPathProxied: '/api/attachments/attachment2/download',
- },
- ];
- // Mock the Growi dependencies that the routes need
- const mockCrowi = {
- require: vi.fn((path) => {
- if (path === '../middlewares/login-required') {
- return () => (_req, _res, next) => {
- // Mock authentication - add user to request
- _req.user = mockUser;
- next();
- };
- }
- return vi.fn();
- }),
- accessTokenParser: (_req, _res, next) => next(),
- };
- // Mock mongoose models
- const mockPageModel = {
- findByPathAndViewer: vi.fn(),
- isAccessiblePageByViewer: vi.fn().mockResolvedValue(true),
- find: vi.fn().mockImplementation(() => {
- // Return a mock query that has chaining methods
- const mockQuery = {
- select: vi.fn().mockReturnThis(),
- exec: vi.fn().mockResolvedValue([
- { id: mockPage._id }, // Return our mock page ID
- ]),
- };
- return mockQuery;
- }),
- addConditionToFilteringByViewerForList: vi.fn(),
- PageQueryBuilder: vi.fn().mockImplementation((query) => ({
- query: query || mockPageModel.find(), // Use the actual query or fall back to find()
- addConditionToListWithDescendants: vi.fn().mockReturnThis(),
- addConditionToExcludeTrashed: vi.fn().mockReturnThis(),
- })),
- };
- const mockAttachmentModel = {
- findOne: vi.fn(),
- find: vi.fn().mockImplementation(() => {
- // Return a mock query that supports chaining
- const mockQuery = {
- and: vi.fn().mockReturnThis(),
- populate: vi.fn().mockReturnThis(),
- exec: vi.fn().mockResolvedValue(mockAttachments), // Return our mock attachments
- };
- return mockQuery;
- }),
- and: vi.fn().mockReturnThis(),
- populate: vi.fn().mockReturnThis(),
- exec: vi.fn().mockResolvedValue(mockAttachments),
- };
- // Mock mongoose
- vi.mock('mongoose', () => ({
- default: {
- model: vi.fn((modelName) => {
- if (modelName === 'Page') return mockPageModel;
- if (modelName === 'Attachment') return mockAttachmentModel;
- return {};
- }),
- },
- model: vi.fn((modelName) => {
- if (modelName === 'Attachment') return mockAttachmentModel;
- return {};
- }),
- Types: {
- ObjectId: class MockObjectId {
- private id: string;
- constructor(id: string) {
- this.id = id;
- }
- static isValid(_id: unknown): boolean {
- return true; // Accept any ID as valid for testing
- }
- toString(): string {
- return this.id;
- }
- },
- },
- }));
- // Mock the serializer
- vi.mock('@growi/core/dist/models/serializers', () => ({
- serializeAttachmentSecurely: vi.fn((attachment) => attachment),
- }));
- describe('refs hooks - Integration Tests with Actual Routes', () => {
- beforeAll(async () => {
- // Create a real Express app with the actual routes
- const app = express();
- app.use(express.json());
- app.use(express.urlencoded({ extended: true }));
- // Create the routes using the real routesFactory with our mocks
- const router = routesFactory(mockCrowi);
- app.use('/_api/attachment-refs', router);
- // Start the test server on a dynamic port
- testServer = createServer(app);
- await new Promise<void>((resolve) => {
- testServer.listen(0, () => {
- const address = testServer.address();
- if (address && typeof address === 'object') {
- const port = address.port;
- baseURL = `http://localhost:${port}`;
- console.log(`Test server started on ${baseURL}`);
- }
- resolve();
- });
- });
- });
- afterAll(async () => {
- // Clean up the test server
- if (testServer) {
- await new Promise<void>((resolve) => {
- testServer.close(() => resolve());
- });
- }
- });
- beforeEach(() => {
- // Reset all mocks before each test
- vi.clearAllMocks();
- // Setup default mock behaviors
- mockPageModel.findByPathAndViewer.mockResolvedValue(mockPage);
- mockPageModel.isAccessiblePageByViewer.mockResolvedValue(true);
- mockAttachmentModel.findOne.mockImplementation(() => ({
- populate: vi.fn().mockResolvedValue(mockAttachment),
- }));
- mockAttachmentModel.find.mockReturnValue({
- and: vi.fn().mockReturnThis(),
- populate: vi.fn().mockReturnThis(),
- exec: vi.fn().mockResolvedValue(mockAttachments),
- });
- });
- describe('SWR Hook Integration Tests', () => {
- it('should test useSWRxRef hook with real server requests', async () => {
- // Arrange
- const pagePath = '/test/page';
- const fileNameOrId = 'test-file.pdf';
- // Configure axios to use our test server
- const originalDefaults = axios.defaults.baseURL;
- axios.defaults.baseURL = baseURL;
- try {
- console.log(`Testing with baseURL: ${baseURL}`);
- // Act - Test the hook with real server
- const { result } = renderHook(() =>
- useSWRxRef(pagePath, fileNameOrId, false),
- );
- // Wait for the hook to complete the request
- await waitFor(
- () => {
- console.log('Hook result:', result.current);
- expect(result.current.data).toBeDefined();
- },
- { timeout: 5000 },
- );
- // Assert - Hook should return attachment data from real server
- expect(result.current.data).toEqual(mockAttachment);
- expect(result.current.error).toBeUndefined();
- } finally {
- // Restore original axios defaults
- axios.defaults.baseURL = originalDefaults;
- }
- });
- it('should test useSWRxRefs hook with real server requests', async () => {
- // Arrange
- const pagePath = '/test/page';
- const prefix = '/test';
- const options = { depth: '1', regexp: '.*\\.pdf$' };
- // Configure axios to use our test server
- const originalDefaults = axios.defaults.baseURL;
- axios.defaults.baseURL = baseURL;
- try {
- console.log(`Testing with baseURL: ${baseURL}`);
- // Act - Test the hook with real server
- const { result } = renderHook(() =>
- useSWRxRefs(pagePath, prefix, options, false),
- );
- // Wait for the hook to complete the request
- await waitFor(
- () => {
- console.log('Hook result:', result.current);
- expect(result.current.data).toBeDefined();
- },
- { timeout: 5000 },
- );
- // Assert - Hook should return attachments data from real server
- expect(result.current.data).toEqual(mockAttachments);
- expect(result.current.error).toBeUndefined();
- } finally {
- // Restore original axios defaults
- axios.defaults.baseURL = originalDefaults;
- }
- });
- });
- });
|