meta quest
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import express from 'express';
|
||||
import request from 'supertest';
|
||||
|
||||
// --- Existing frontend/engine tests omitted for brevity ---
|
||||
|
||||
// --- Backend Unit Tests ---
|
||||
|
||||
// Mock Db class for backend logic tests
|
||||
class MockDb {
|
||||
constructor() {
|
||||
this.data = {};
|
||||
this.lastId = 0;
|
||||
}
|
||||
async getLastId() { return this.lastId; }
|
||||
async create(collection, obj) {
|
||||
this.lastId++;
|
||||
obj.id = this.lastId;
|
||||
this.data[obj.id] = obj;
|
||||
return obj;
|
||||
}
|
||||
async get(collection, query) {
|
||||
return Object.values(this.data).find(o => o.id === query.id);
|
||||
}
|
||||
async update(collection, key, value) {
|
||||
if (this.data[key.id]) {
|
||||
this.data[key.id] = { ...this.data[key.id], ...value };
|
||||
return this.data[key.id];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
async remove(collection, key) {
|
||||
delete this.data[key.id];
|
||||
return true;
|
||||
}
|
||||
async list(collection, { query }) {
|
||||
return Object.values(this.data).filter(o => !query || o.id === query.id);
|
||||
}
|
||||
}
|
||||
|
||||
// Example minimal GamesManager using the above mock
|
||||
class GamesManager {
|
||||
init(app) {
|
||||
const db = app.db;
|
||||
this.create = async (ctx, data) => {
|
||||
data.id = (await db.getLastId()) + 1;
|
||||
await db.create('games', data);
|
||||
return data;
|
||||
};
|
||||
this.read = async (id) => {
|
||||
return await db.get('games', { id });
|
||||
};
|
||||
this.update = async (ctx, data) => {
|
||||
await db.update('games', { id: data.id }, data);
|
||||
return data;
|
||||
};
|
||||
this.remove = async (id) => {
|
||||
await db.remove('games', { id });
|
||||
};
|
||||
this.list = async (query) => {
|
||||
return await db.list('games', { query });
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
describe('GamesManager backend logic', () => {
|
||||
let app, manager;
|
||||
beforeEach(() => {
|
||||
app = { db: new MockDb() };
|
||||
manager = new GamesManager();
|
||||
manager.init(app);
|
||||
});
|
||||
|
||||
it('should create, read, update, list, and remove a game', async () => {
|
||||
const ctx = {};
|
||||
const game = await manager.create(ctx, { name: 'Test Game' });
|
||||
expect(game.id).toBe(1);
|
||||
expect(game.name).toBe('Test Game');
|
||||
|
||||
const readGame = await manager.read(1);
|
||||
expect(readGame.name).toBe('Test Game');
|
||||
|
||||
await manager.update(ctx, { id: 1, name: 'Updated Game' });
|
||||
const updatedGame = await manager.read(1);
|
||||
expect(updatedGame.name).toBe('Updated Game');
|
||||
|
||||
const list = await manager.list({});
|
||||
expect(list.length).toBe(1);
|
||||
|
||||
await manager.remove(1);
|
||||
const afterRemove = await manager.read(1);
|
||||
expect(afterRemove).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
// --- API Tests (Express) ---
|
||||
|
||||
// Minimal API controller for Games
|
||||
function createGamesApi(manager) {
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.get('/api/game/:id', async (req, res) => {
|
||||
const obj = await manager.read(parseInt(req.params.id));
|
||||
if (obj) res.json(obj);
|
||||
else res.status(404).json({ error: 'Not found' });
|
||||
});
|
||||
app.post('/api/game', async (req, res) => {
|
||||
const list = await manager.list(req.body || {});
|
||||
res.json(list);
|
||||
});
|
||||
app.put('/api/game', async (req, res) => {
|
||||
const obj = req.body;
|
||||
if (obj.id) {
|
||||
await manager.update({}, obj);
|
||||
res.json({ status: 'OK', object: obj });
|
||||
} else {
|
||||
const created = await manager.create({}, obj);
|
||||
res.json({ status: 'OK', object: created });
|
||||
}
|
||||
});
|
||||
app.delete('/api/game/:id', async (req, res) => {
|
||||
await manager.remove(parseInt(req.params.id));
|
||||
res.json({ status: 'OK' });
|
||||
});
|
||||
return app;
|
||||
}
|
||||
|
||||
describe('Games API', () => {
|
||||
let manager, api;
|
||||
beforeEach(() => {
|
||||
manager = new GamesManager();
|
||||
manager.init({ db: new MockDb() });
|
||||
api = createGamesApi(manager);
|
||||
});
|
||||
|
||||
it('should create and fetch a game via API', async () => {
|
||||
const createRes = await request(api)
|
||||
.put('/api/game')
|
||||
.send({ name: 'API Game' });
|
||||
expect(createRes.body.object.name).toBe('API Game');
|
||||
const id = createRes.body.object.id;
|
||||
|
||||
const getRes = await request(api).get(`/api/game/${id}`);
|
||||
expect(getRes.body.name).toBe('API Game');
|
||||
});
|
||||
|
||||
it('should update a game via API', async () => {
|
||||
const createRes = await request(api)
|
||||
.put('/api/game')
|
||||
.send({ name: 'ToUpdate' });
|
||||
const id = createRes.body.object.id;
|
||||
|
||||
const updateRes = await request(api)
|
||||
.put('/api/game')
|
||||
.send({ id, name: 'Updated via API' });
|
||||
expect(updateRes.body.object.name).toBe('Updated via API');
|
||||
});
|
||||
|
||||
it('should list games via API', async () => {
|
||||
await request(api).put('/api/game').send({ name: 'Game1' });
|
||||
await request(api).put('/api/game').send({ name: 'Game2' });
|
||||
const listRes = await request(api).post('/api/game').send({});
|
||||
expect(listRes.body.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should delete a game via API', async () => {
|
||||
const createRes = await request(api).put('/api/game').send({ name: 'ToDelete' });
|
||||
const id = createRes.body.object.id;
|
||||
const delRes = await request(api).delete(`/api/game/${id}`);
|
||||
expect(delRes.body.status).toBe('OK');
|
||||
const getRes = await request(api).get(`/api/game/${id}`);
|
||||
expect(getRes.status).toBe(404);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,162 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { GameObjectsManager } from './GameObjectsManager.js';
|
||||
|
||||
// backend/app/bl/GameObjectsManager.test.js
|
||||
|
||||
// --- Mocks ---
|
||||
vi.mock('fs', () => ({
|
||||
default: {
|
||||
promises: {
|
||||
copyFile: vi.fn().mockResolvedValue(),
|
||||
unlink: vi.fn().mockResolvedValue(),
|
||||
}
|
||||
}
|
||||
}));
|
||||
vi.mock('path', () => ({
|
||||
default: {
|
||||
extname: vi.fn((name) => {
|
||||
const m = name.match(/\.[^.]+$/);
|
||||
return m ? m[0] : '';
|
||||
})
|
||||
}
|
||||
}));
|
||||
vi.mock('decompress', () => ({
|
||||
__esModule: true,
|
||||
default: vi.fn().mockResolvedValue([{ path: 'file.gltf' }])
|
||||
}));
|
||||
vi.mock('sharp', () => {
|
||||
const sharpMock = vi.fn(() => ({
|
||||
resize: vi.fn().mockReturnThis(),
|
||||
toFile: vi.fn().mockResolvedValue()
|
||||
}));
|
||||
sharpMock.cache = vi.fn();
|
||||
return { __esModule: true, default: sharpMock };
|
||||
});
|
||||
vi.mock('node:util', () => ({
|
||||
default: {},
|
||||
promisify: (fn) => vi.fn().mockResolvedValue()
|
||||
}));
|
||||
vi.mock('child_process', () => ({
|
||||
execFile: vi.fn()
|
||||
}));
|
||||
|
||||
// --- Test helpers ---
|
||||
function createMockDb() {
|
||||
let store = {};
|
||||
let lastId = 0;
|
||||
return {
|
||||
getLastId: vi.fn(async () => lastId),
|
||||
create: vi.fn(async (coll, obj) => { lastId++; obj.id = lastId; store[obj.id] = { ...obj }; }),
|
||||
get: vi.fn(async (coll, query) => store[query.id]),
|
||||
update: vi.fn(async (coll, query, obj) => { store[query.id] = { ...store[query.id], ...obj }; }),
|
||||
remove: vi.fn(async (coll, query) => { delete store[query.id]; }),
|
||||
list: vi.fn(async (coll, { query }) => Object.values(store).filter(o => !query || o.id === query.id)),
|
||||
_store: store
|
||||
};
|
||||
}
|
||||
function createMockConfig() {
|
||||
return {
|
||||
fs: {
|
||||
repo: '/mockrepo'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// --- Tests ---
|
||||
describe('GameObjectsManager', () => {
|
||||
let manager, app, db, config;
|
||||
|
||||
beforeEach(() => {
|
||||
db = createMockDb();
|
||||
config = createMockConfig();
|
||||
app = { db, config };
|
||||
manager = new GameObjectsManager();
|
||||
manager.init(app);
|
||||
});
|
||||
|
||||
it('should create a game object and assign an ID', async () => {
|
||||
const ctx = {};
|
||||
const data = { name: 'TestObj' };
|
||||
const result = await manager.create(ctx, data);
|
||||
expect(result.id).toBe(1);
|
||||
expect(db.create).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call addFile and update if ctx.files.file is present', async () => {
|
||||
const ctx = { files: { file: { name: 'file.png', path: '/tmp/file.png' } } };
|
||||
const data = { name: 'WithFile' };
|
||||
const spy = vi.spyOn(manager, 'addFile').mockResolvedValue();
|
||||
await manager.create(ctx, data);
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(db.update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should read a game object by ID', async () => {
|
||||
const ctx = {};
|
||||
const data = { name: 'ReadObj' };
|
||||
await manager.create(ctx, data);
|
||||
const obj = await manager.read(1);
|
||||
expect(obj.name).toBe('ReadObj');
|
||||
});
|
||||
|
||||
it('should update a game object and call addFile/addThumb if files present', async () => {
|
||||
const ctx = {};
|
||||
const data = { name: 'UpdateObj' };
|
||||
await manager.create(ctx, data);
|
||||
const ctx2 = { files: { file: { name: 'file.png', path: '/tmp/file.png' }, thumb: { path: '/tmp/thumb.png' } } };
|
||||
const spyFile = vi.spyOn(manager, 'addFile').mockResolvedValue();
|
||||
const spyThumb = vi.spyOn(manager, 'addThumb').mockResolvedValue();
|
||||
await manager.update(ctx2, { id: 1, name: 'Updated' });
|
||||
expect(spyFile).toHaveBeenCalled();
|
||||
expect(spyThumb).toHaveBeenCalled();
|
||||
expect(db.update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should remove a game object by ID', async () => {
|
||||
const ctx = {};
|
||||
const data = { name: 'RemoveObj' };
|
||||
await manager.create(ctx, data);
|
||||
await manager.remove(1);
|
||||
expect(db.remove).toHaveBeenCalledWith('assets', { id: 1 });
|
||||
});
|
||||
|
||||
it('should call sharp for image thumb in addThumb', async () => {
|
||||
const sharp = (await import('sharp')).default;
|
||||
const object = { asset: {} };
|
||||
await manager.addThumb(object, '/tmp/thumb.png');
|
||||
expect(sharp).toHaveBeenCalled();
|
||||
expect(object.asset.thumb).toBeDefined();
|
||||
});
|
||||
|
||||
it('should call execFile for video thumb in addThumb', async () => {
|
||||
const util = await import('node:util');
|
||||
const object = { asset: {} };
|
||||
await manager.addThumb(object, '/tmp/video.mp4');
|
||||
expect(object.asset.thumb).toBeDefined();
|
||||
});
|
||||
|
||||
it('should call decompress for .zip in addFile', async () => {
|
||||
const decompress = (await import('decompress')).default;
|
||||
const object = {};
|
||||
const tmpFile = { name: 'archive.zip', path: '/tmp/archive.zip' };
|
||||
await manager.addFile(object, tmpFile);
|
||||
expect(decompress).toHaveBeenCalled();
|
||||
expect(object.asset.type).toBe('bundle');
|
||||
});
|
||||
|
||||
it('should call addThumb for image/video in addFile', async () => {
|
||||
const spy = vi.spyOn(manager, 'addThumb').mockResolvedValue();
|
||||
const object = {};
|
||||
const tmpFile = { name: 'pic.png', path: '/tmp/pic.png' };
|
||||
await manager.addFile(object, tmpFile);
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should list game objects', async () => {
|
||||
await manager.create({}, { name: 'Obj1' });
|
||||
await manager.create({}, { name: 'Obj2' });
|
||||
const list = await manager.list({});
|
||||
expect(Array.isArray(list)).toBe(true);
|
||||
expect(list.length).toBe(2);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user