Files
001code-html--cocos/scratch-vm/test/unit/tw_sandboxed_extensions.js
刘宇飞 6e0a1fbcbb Initial commit of 001code-html Scratch frontend project.
Includes scratch-gui, scratch-vm, scratch-blocks, scratch-render, scratch-l10n, and deployment config.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 15:37:45 +08:00

144 lines
4.2 KiB
JavaScript

const {test} = require('tap');
global.Request = class {
constructor (url) {
this.url = url;
}
};
global.fetch = (url, options = {}) => (
Promise.resolve(`[Response ${url instanceof Request ? url.url : url} options=${JSON.stringify(options)}]`)
);
// Remove navigator object from Node 21 and later
delete global.navigator;
// Need to trick the extension API to think it's running in a worker
// It will not actually use this object ever.
global.self = {};
// This will install extension worker APIs onto `global`
require('../../src/extension-support/extension-worker');
test('basic API', t => {
t.type(global.Scratch.extensions.register, 'function');
t.equal(global.Scratch.ArgumentType.BOOLEAN, 'Boolean');
t.equal(global.Scratch.BlockType.REPORTER, 'reporter');
t.end();
});
test('not unsandboxed', t => {
t.not(global.Scratch.extensions.unsandboxed, true);
t.end();
});
test('Cast', t => {
// Cast is thoroughly tested elsewhere
t.equal(global.Scratch.Cast.toString(5), '5');
t.equal(global.Scratch.Cast.toNumber(' 5'), 5);
t.equal(global.Scratch.Cast.toBoolean('true'), true);
t.end();
});
test('fetch', async t => {
t.equal(await global.Scratch.canFetch('https://untrusted.example/'), true);
t.equal(await global.Scratch.fetch('https://untrusted.example/'), '[Response https://untrusted.example/ options={}]');
t.equal(await global.Scratch.fetch('https://untrusted.example/', {
method: 'POST'
}), `[Response https://untrusted.example/ options={"method":"POST"}]`);
t.end();
});
test('openWindow', async t => {
t.equal(await global.Scratch.canOpenWindow('https://example.com/'), false);
await t.rejects(global.Scratch.openWindow('https://example.com/'), /^Scratch\.openWindow not supported in sandboxed extensions$/);
t.end();
});
test('redirect', async t => {
t.equal(await global.Scratch.canRedirect('https://example.com/'), false);
await t.rejects(global.Scratch.redirect('https://example.com/'), /^Scratch\.redirect not supported in sandboxed extensions$/);
t.end();
});
test('translate', t => {
t.equal(global.Scratch.translate({
id: 'test1',
default: 'Message 1: {var}',
description: 'Description'
}, {
var: 'test'
}), 'Message 1: test');
t.equal(global.Scratch.translate('test1'), 'test1');
t.equal(global.Scratch.translate('test1 {VAR}', {
VAR: '3'
}), 'test1 3');
t.equal(global.Scratch.translate.language, 'en');
const messages = {
en: {
test1: 'EN Message 1: {var}'
},
es: {
test1: 'ES Message 1: {var}'
}
};
// Should default to English when no navigator object
global.Scratch.translate.setup(messages);
t.equal(global.Scratch.translate({
id: 'test1',
default: 'Message 1',
description: 'Description'
}, {
var: 'ok'
}), 'EN Message 1: ok');
t.equal(global.Scratch.translate.language, 'en');
// But if there is a navigator object, it should use its language.
global.navigator = {
language: 'es'
};
// Note that real extensions will only generally call setup() once, but we need to do this
// again so that it realizes the language changed.
global.Scratch.translate.setup(messages);
t.equal(global.Scratch.translate({
id: 'test1',
default: 'Message 1',
description: 'Description'
}, {
var: 'ok'
}), 'ES Message 1: ok');
t.equal(global.Scratch.translate.language, 'es');
t.end();
});
test('canRecordAudio', async t => {
t.equal(await global.Scratch.canRecordAudio(), false);
t.end();
});
test('canRecordVideo', async t => {
t.equal(await global.Scratch.canRecordVideo(), false);
t.end();
});
test('canReadClipboard', async t => {
t.equal(await global.Scratch.canReadClipboard(), false);
t.end();
});
test('canNotify', async t => {
t.equal(await global.Scratch.canNotify(), false);
t.end();
});
test('canGeolocate', async t => {
t.equal(await global.Scratch.canGeolocate(), false);
t.end();
});
test('canEmbed', async t => {
t.equal(await global.Scratch.canEmbed('https://example.com/'), false);
t.end();
});