feat: integrate learning module
This commit is contained in:
95
tests/unit/learning-player-server.test.ts
Normal file
95
tests/unit/learning-player-server.test.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
// @vitest-environment node
|
||||
import { createHash } from 'node:crypto';
|
||||
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { afterEach, describe, expect, it } from 'vitest';
|
||||
import AdmZip from 'adm-zip';
|
||||
import {
|
||||
createLearningPlayerServer,
|
||||
registerLearningCoursePackage,
|
||||
} from '@electron/services/learning-player-server';
|
||||
|
||||
async function writePlayerArtifact(root: string): Promise<void> {
|
||||
const html = '<!doctype html><main>player</main>';
|
||||
await mkdir(join(root, '_next', 'static', 'chunks'), { recursive: true });
|
||||
await mkdir(join(root, 'avatars'), { recursive: true });
|
||||
await mkdir(join(root, 'public'), { recursive: true });
|
||||
await writeFile(join(root, 'index.html'), html);
|
||||
await writeFile(join(root, 'artifact.json'), JSON.stringify({
|
||||
schemaVersion: 1,
|
||||
entrypoint: 'index.html',
|
||||
htmlSha256: createHash('sha256').update(html).digest('hex'),
|
||||
}));
|
||||
await writeFile(join(root, '_next', 'static', 'chunks', 'app.js'), 'window.player = true');
|
||||
await writeFile(join(root, 'avatars', 'teacher.png'), 'avatar');
|
||||
await writeFile(join(root, 'public', 'openmaic-mark.png'), 'mark');
|
||||
}
|
||||
|
||||
describe('Learning player static server', () => {
|
||||
let root: string | null = null;
|
||||
let close: (() => Promise<void>) | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
if (close) await close();
|
||||
if (root) await rm(root, { recursive: true, force: true });
|
||||
close = null;
|
||||
root = null;
|
||||
});
|
||||
|
||||
it('serves only the embedded OpenMAIC player and immutable static assets', async () => {
|
||||
root = await mkdtemp(join(tmpdir(), 'makelore-player-server-'));
|
||||
await writePlayerArtifact(root);
|
||||
const server = await createLearningPlayerServer({ artifactRoot: root });
|
||||
close = server.close;
|
||||
|
||||
const index = await fetch(server.url);
|
||||
expect(index.status).toBe(200);
|
||||
expect(await index.text()).toContain('player');
|
||||
expect(index.headers.get('content-security-policy')).toContain("object-src 'none'");
|
||||
|
||||
const asset = await fetch(new URL('/_next/static/chunks/app.js', server.url));
|
||||
expect(asset.headers.get('cache-control')).toContain('immutable');
|
||||
expect(await asset.text()).toContain('window.player');
|
||||
|
||||
const avatar = await fetch(new URL('/avatars/teacher.png', server.url));
|
||||
expect(avatar.status).toBe(200);
|
||||
expect(avatar.headers.get('content-type')).toBe('image/png');
|
||||
|
||||
const publicAsset = await fetch(new URL('/openmaic-mark.png', server.url));
|
||||
expect(publicAsset.status).toBe(200);
|
||||
expect(publicAsset.headers.get('cache-control')).toContain('immutable');
|
||||
expect(await publicAsset.text()).toBe('mark');
|
||||
|
||||
expect((await fetch(new URL('/package.json', server.url))).status).toBe(404);
|
||||
expect((await fetch(new URL('/%2e%2e/artifact.json', server.url))).status).toBe(404);
|
||||
});
|
||||
|
||||
it('serves only audio and media entries from a verified registered course package', async () => {
|
||||
root = await mkdtemp(join(tmpdir(), 'makelore-player-server-'));
|
||||
await writePlayerArtifact(root);
|
||||
const archivePath = join(root, 'course.zip');
|
||||
const archive = new AdmZip();
|
||||
archive.addFile('modules/module-1/audio/line.mp3', Buffer.from('audio-bytes'));
|
||||
archive.addFile('modules/module-1/media/diagram.png', Buffer.from('image-bytes'));
|
||||
archive.addFile('modules/module-1/bundle.json', Buffer.from('{}'));
|
||||
archive.writeZip(archivePath);
|
||||
const contentHash = 'a'.repeat(64);
|
||||
registerLearningCoursePackage('course-assets-test', contentHash, archivePath);
|
||||
const server = await createLearningPlayerServer({ artifactRoot: root });
|
||||
close = server.close;
|
||||
|
||||
const audio = await fetch(new URL(
|
||||
`/course-assets/course-assets-test/${contentHash}/modules/module-1/audio/line.mp3`,
|
||||
server.url,
|
||||
));
|
||||
expect(audio.status).toBe(200);
|
||||
expect(audio.headers.get('content-type')).toBe('audio/mpeg');
|
||||
expect(await audio.text()).toBe('audio-bytes');
|
||||
|
||||
expect((await fetch(new URL(
|
||||
`/course-assets/course-assets-test/${contentHash}/modules/module-1/bundle.json`,
|
||||
server.url,
|
||||
))).status).toBe(404);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user