138 lines
5.0 KiB
JavaScript
138 lines
5.0 KiB
JavaScript
const request = require('supertest');
|
|
const mongoose = require('mongoose');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const Scene = require('../models/Scene');
|
|
const Asset = require('../models/Asset');
|
|
const Hotspot = require('../models/Hotspot');
|
|
const User = require('../models/User');
|
|
|
|
// Mock fs để không xóa file thật trong quá trình test và kiểm tra số lần gọi hàm
|
|
jest.mock('fs', () => ({
|
|
...jest.requireActual('fs'),
|
|
promises: {
|
|
unlink: jest.fn().mockResolvedValue()
|
|
},
|
|
existsSync: jest.fn().mockReturnValue(true)
|
|
}));
|
|
|
|
// Import app - Giả định server.js của bạn export express app
|
|
// Nếu file khởi tạo app của bạn có tên khác, hãy điều chỉnh đường dẫn bên dưới
|
|
const app = require('../server');
|
|
|
|
describe('Integration Test: Cascade Scene Deletion (BFS)', () => {
|
|
let adminToken;
|
|
let adminUser;
|
|
let parentAsset, childAsset;
|
|
let parentScene, childScene;
|
|
|
|
beforeAll(async () => {
|
|
// Kết nối tới Database Test (Sử dụng biến môi trường hoặc mặc định)
|
|
if (mongoose.connection.readyState === 0) {
|
|
await mongoose.connect(process.env.MONGO_URI || 'mongodb://localhost:27017/3dtours_test');
|
|
}
|
|
|
|
// Thiết lập Admin User để thực hiện các request có quyền bảo mật
|
|
await User.deleteMany({});
|
|
adminUser = await User.create({
|
|
fullName: 'Admin Test',
|
|
username: 'admintest',
|
|
email: 'admin@test.com',
|
|
password: 'password123',
|
|
role: 'admin',
|
|
agreedToRules: true
|
|
});
|
|
|
|
// Đăng nhập để lấy JWT Token
|
|
const res = await request(app)
|
|
.post('/api/auth/login')
|
|
.send({ username: 'admintest', password: 'password123' });
|
|
adminToken = res.body.token;
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await User.deleteMany({});
|
|
await Scene.deleteMany({});
|
|
await Asset.deleteMany({});
|
|
await Hotspot.deleteMany({});
|
|
await mongoose.connection.close();
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
jest.clearAllMocks();
|
|
await Scene.deleteMany({});
|
|
await Asset.deleteMany({});
|
|
await Hotspot.deleteMany({});
|
|
|
|
// 1. Tạo dữ liệu Scene Cha và Asset tương ứng
|
|
parentAsset = await Asset.create({
|
|
filePath: path.join(__dirname, '../uploads/parent_room.jpg'),
|
|
fileSize: 1024 * 1024,
|
|
uploadedBy: adminUser._id
|
|
});
|
|
parentScene = await Scene.create({
|
|
name: 'Phòng Khách (Cha)',
|
|
assetId: parentAsset._id,
|
|
createdBy: adminUser._id,
|
|
status: 'completed'
|
|
});
|
|
|
|
// 2. Tạo dữ liệu Scene Con và Asset tương ứng
|
|
childAsset = await Asset.create({
|
|
filePath: path.join(__dirname, '../uploads/child_balcony.jpg'),
|
|
fileSize: 800 * 1024,
|
|
uploadedBy: adminUser._id
|
|
});
|
|
childScene = await Scene.create({
|
|
name: 'Ban Công (Con)',
|
|
assetId: childAsset._id,
|
|
createdBy: adminUser._id,
|
|
status: 'completed'
|
|
});
|
|
|
|
// 3. Tạo liên kết: Cha -> trỏ tới -> Con thông qua Hotspot
|
|
await Hotspot.create({
|
|
parent_scene_id: parentScene._id,
|
|
target_scene_id: childScene._id,
|
|
title: 'Đi ra Ban Công'
|
|
});
|
|
});
|
|
|
|
test('Khi xóa scene CHA, phải xóa dây chuyền sang scene CON và gỡ bỏ toàn bộ file vật lý', async () => {
|
|
const res = await request(app)
|
|
.delete(`/api/scenes/${parentScene._id}`)
|
|
.set('Authorization', `Bearer ${adminToken}`);
|
|
|
|
expect(res.status).toBe(200);
|
|
|
|
// Kiểm tra Database: Không còn bất kỳ scene nào
|
|
const scenesInDB = await Scene.find({});
|
|
expect(scenesInDB.length).toBe(0);
|
|
|
|
// Kiểm tra Assets: Các bản ghi asset cũng phải bị xóa sạch
|
|
const assetsInDB = await Asset.find({});
|
|
expect(assetsInDB.length).toBe(0);
|
|
|
|
// Kiểm tra Filesystem: Phải gọi lệnh xóa (unlink) cho cả 2 tệp tin (cha và con)
|
|
expect(fs.promises.unlink).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
test('Khi xóa scene CON, scene CHA vẫn phải tồn tại (Không được xóa ngược)', async () => {
|
|
const res = await request(app)
|
|
.delete(`/api/scenes/${childScene._id}`)
|
|
.set('Authorization', `Bearer ${adminToken}`);
|
|
|
|
expect(res.status).toBe(200);
|
|
|
|
// Scene Cha và Asset của nó phải còn nguyên trong Database
|
|
const parentInDB = await Scene.findById(parentScene._id);
|
|
expect(parentInDB).not.toBeNull();
|
|
|
|
const parentAssetInDB = await Asset.findById(parentAsset._id);
|
|
expect(parentAssetInDB).not.toBeNull();
|
|
|
|
// Chỉ có 1 tệp tin bị xóa (tệp của scene con)
|
|
expect(fs.promises.unlink).toHaveBeenCalledTimes(1);
|
|
expect(fs.promises.unlink).toHaveBeenCalledWith(expect.stringContaining('child_balcony.jpg'));
|
|
});
|
|
}); |