Xóa scene con mà không xóa scene cha
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
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'));
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user