feat: add weekly curriculum cover image upload and display
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const vm = require('node:vm');
|
||||
const ts = require('typescript');
|
||||
|
||||
// Exercise effect cleanup and asynchronous IPC responses without starting Electron.
|
||||
const slots = [];
|
||||
let cursor = 0;
|
||||
let effects = [];
|
||||
const react = {
|
||||
useRef(value) { const i = cursor++; return slots[i] ??= { current: value }; },
|
||||
useState(value) {
|
||||
const i = cursor++;
|
||||
if (!(i in slots)) slots[i] = value;
|
||||
return [slots[i], next => { slots[i] = typeof next === 'function' ? next(slots[i]) : next; }];
|
||||
},
|
||||
useEffect(fn, deps) {
|
||||
const i = cursor++;
|
||||
const previous = slots[i];
|
||||
if (previous && deps.every((dep, index) => Object.is(dep, previous.deps[index]))) return;
|
||||
effects.push(() => { previous?.cleanup?.(); slots[i] = { deps, cleanup: fn() }; });
|
||||
}
|
||||
};
|
||||
const requests = [];
|
||||
const context = { exports: {}, require: name => { assert.equal(name, 'react'); return react; }, window: {
|
||||
remoteWorkspace: { moduleFiles: { content: (...args) => new Promise((resolve, reject) => requests.push({ args, resolve, reject })) } }
|
||||
} };
|
||||
const source = fs.readFileSync(path.join(__dirname, '../src/renderer/src/features/workspace/useRemoteEditorFile.ts'), 'utf8');
|
||||
vm.runInNewContext(ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS } }).outputText, context);
|
||||
const options = {
|
||||
enabled: true, targetKey: 'platform', getTarget: () => ({}), module: { name: 'Test', folderName: 'test' },
|
||||
path: null, files: {}, dirty: {},
|
||||
setFiles(fn) { options.files = fn(options.files); },
|
||||
setSaved(fn) { options.saved = fn(options.saved ?? {}); }
|
||||
};
|
||||
function render() {
|
||||
cursor = 0;
|
||||
const result = context.exports.useRemoteEditorFile(options);
|
||||
const pending = effects; effects = []; pending.forEach(fn => fn());
|
||||
return result;
|
||||
}
|
||||
const tick = () => new Promise(resolve => setImmediate(resolve));
|
||||
(async () => {
|
||||
render(); assert.equal(requests.length, 0);
|
||||
options.path = 'modules/Test/first.py';
|
||||
assert.equal(render().loading, true); assert.equal(requests.length, 1);
|
||||
render(); assert.equal(requests.length, 1);
|
||||
options.path = 'modules/Test/second.py'; render();
|
||||
requests[0].resolve({ content: 'old response' }); await tick();
|
||||
assert.equal(options.files['modules/Test/first.py'], undefined);
|
||||
requests[1].resolve({ content: 'second' }); await tick();
|
||||
assert.equal(render().loading, false);
|
||||
assert.equal(options.files[options.path], 'second');
|
||||
options.path = null; render(); options.path = 'modules/Test/second.py'; render();
|
||||
assert.equal(requests.length, 2);
|
||||
options.path = 'modules/Test/fail.py'; render();
|
||||
requests[2].reject(new Error('offline')); await tick();
|
||||
assert.ok(render().error);
|
||||
render().retry(); render(); assert.equal(requests.length, 4);
|
||||
options.dirty[options.path] = true; options.files[options.path] = 'unsaved'; render();
|
||||
requests[3].resolve({ content: 'server copy' }); await tick();
|
||||
assert.equal(options.files[options.path], 'unsaved');
|
||||
options.path = 'modules/Test/image.png'; render(); assert.equal(requests.length, 4);
|
||||
options.enabled = false; options.path = 'modules/Test/local.py'; render(); assert.equal(requests.length, 4);
|
||||
console.log('Remote editor click loading, caching, cancellation, retry and dirty-file protection tests passed.');
|
||||
})().catch(error => { console.error(error); process.exitCode = 1; });
|
||||
Reference in New Issue
Block a user