34 lines
2.5 KiB
JavaScript
34 lines
2.5 KiB
JavaScript
const test=require('node:test'),assert=require('node:assert/strict'),crypto=require('node:crypto'),fs=require('node:fs');
|
|
const hash=require('./web/file-hash.js');
|
|
test('upload MD5 matches RFC vectors and a multi-block file',()=>{
|
|
for(const text of ['', 'a', 'abc', 'message digest', 'abcdefghijklmnopqrstuvwxyz', '照片与语音', 'x'.repeat(4194304)]){
|
|
const bytes=Buffer.from(text);assert.equal(hash.md5(bytes),crypto.createHash('md5').update(bytes).digest('hex'));
|
|
}
|
|
});
|
|
test('browser hashes in 4 MiB slices rather than loading the entire video',async()=>{
|
|
const file=new Blob([Buffer.alloc(4194304,1),Buffer.from('tail')]);const values=await hash.blocks(file);
|
|
assert.equal(values.length,2);assert.equal(values[1],crypto.createHash('md5').update('tail').digest('hex'));
|
|
await assert.rejects(hash.blocks(file,()=>{},()=>false),/取消/);
|
|
});
|
|
test('journals default to private and encode content before rendering',()=>{
|
|
const html=fs.readFileSync('web/index.html','utf8'),js=fs.readFileSync('web/journal.js','utf8');
|
|
assert.match(html,/<select name="visibility"><option value="private">/);assert.match(js,/esc\(e.text\)/);assert.match(js,/esc\(c.text\)/);
|
|
assert.doesNotMatch(js,/localStorage|indexedDB|caches\.open|access_token|secretKey.*localStorage/);
|
|
});
|
|
test('leave clears media URLs, live microphone tracks, and pending requests',()=>{
|
|
const js=fs.readFileSync('web/journal.js','utf8');assert.match(js,/journalRequest\?\.abort\(\)/);assert.match(js,/URL.revokeObjectURL/);assert.match(js,/getTracks\(\).forEach\(t=>t.stop\(\)\)/);
|
|
});
|
|
test('new entry clears hidden edit identifiers even when form.reset preserves them',()=>{
|
|
const vm=require('node:vm'),js=fs.readFileSync('web/journal.js','utf8');
|
|
const form={elements:{id:{value:'old-entry'},revision:{value:'9'},clientId:{value:'old-request'}},reset(){}};
|
|
const context={$:()=>form};vm.createContext(context);
|
|
vm.runInContext(js.match(/function clearJournalForm\(\)\{[^\n]+/)[0]+'\nclearJournalForm();',context);
|
|
for(const field of Object.values(form.elements))assert.equal(field.value,'');
|
|
assert.match(js,/function newJournal\(\)\{clearJournalForm\(\)/);
|
|
assert.match(js,/function resetJournal\(\).*clearJournalForm\(\)/);
|
|
});
|
|
test('initial composer setup happens before asynchronous loading and never clears a typed draft',()=>{
|
|
const js=fs.readFileSync('web/journal.js','utf8');const fn=js.slice(js.indexOf('async function loadJournal'),js.indexOf('function renderJournalUploads'));
|
|
assert.ok(fn.indexOf('newJournal()')<fn.indexOf('await api('));assert.equal(fn.match(/newJournal\(\)/g).length,1);
|
|
});
|