mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-18 13:21:55 +00:00
Merge commit '6e92d2345e8231a44556ce7d416451f5f3e6c398' as 'engine262'
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`preview evaluation > [] 1`] = `
|
||||
{
|
||||
"className": "Array",
|
||||
"description": "Array(0)",
|
||||
"objectId": "default:1",
|
||||
"preview": {
|
||||
"description": "Array(0)",
|
||||
"overflow": false,
|
||||
"properties": [],
|
||||
"subtype": "array",
|
||||
"type": "object",
|
||||
},
|
||||
"subtype": "array",
|
||||
"type": "object",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`preview evaluation > [1, 2, 3].map(x => x + 1) 1`] = `
|
||||
{
|
||||
"className": "Array",
|
||||
"description": "Array(3)",
|
||||
"objectId": "default:4",
|
||||
"preview": {
|
||||
"description": "Array(3)",
|
||||
"overflow": false,
|
||||
"properties": [
|
||||
{
|
||||
"name": "0",
|
||||
"type": "number",
|
||||
"value": "2",
|
||||
},
|
||||
{
|
||||
"name": "1",
|
||||
"type": "number",
|
||||
"value": "3",
|
||||
},
|
||||
{
|
||||
"name": "2",
|
||||
"type": "number",
|
||||
"value": "4",
|
||||
},
|
||||
],
|
||||
"subtype": "array",
|
||||
"type": "object",
|
||||
},
|
||||
"subtype": "array",
|
||||
"type": "object",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`preview evaluation > { let a = 1; a } 1`] = `
|
||||
{
|
||||
"description": "1",
|
||||
"type": "number",
|
||||
"value": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`preview evaluation > { var a = 1; a } 1`] = `"side effect"`;
|
||||
|
||||
exports[`preview evaluation > 1 1`] = `
|
||||
{
|
||||
"description": "1",
|
||||
"type": "number",
|
||||
"value": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`preview evaluation > globalThis.x = 1 1`] = `"side effect"`;
|
||||
@@ -0,0 +1,95 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`code in ShadowRealm 1`] = `
|
||||
[
|
||||
[
|
||||
{
|
||||
"columnNumber": 6,
|
||||
"functionName": "<anonymous>",
|
||||
"lineNumber": 0,
|
||||
"scriptId": "1",
|
||||
"url": "<anonymous>",
|
||||
},
|
||||
undefined,
|
||||
{
|
||||
"columnNumber": 15,
|
||||
"functionName": "<anonymous>",
|
||||
"lineNumber": 1,
|
||||
"scriptId": "0",
|
||||
"url": "<anonymous>",
|
||||
},
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`code in eval 1`] = `
|
||||
[
|
||||
[
|
||||
{
|
||||
"columnNumber": 6,
|
||||
"functionName": "<anonymous>",
|
||||
"lineNumber": 0,
|
||||
"scriptId": "1",
|
||||
"url": "<anonymous>",
|
||||
},
|
||||
{
|
||||
"columnNumber": 5,
|
||||
"functionName": "<anonymous>",
|
||||
"lineNumber": 0,
|
||||
"scriptId": "0",
|
||||
"url": "<anonymous>",
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
"columnNumber": 12,
|
||||
"functionName": "f",
|
||||
"lineNumber": 1,
|
||||
"scriptId": "2",
|
||||
"url": "<anonymous>",
|
||||
},
|
||||
{
|
||||
"columnNumber": 4,
|
||||
"functionName": "<anonymous>",
|
||||
"lineNumber": 3,
|
||||
"scriptId": "2",
|
||||
"url": "<anonymous>",
|
||||
},
|
||||
{
|
||||
"columnNumber": 5,
|
||||
"functionName": "<anonymous>",
|
||||
"lineNumber": 1,
|
||||
"scriptId": "0",
|
||||
"url": "<anonymous>",
|
||||
},
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`code in new Function 1`] = `
|
||||
[
|
||||
[
|
||||
{
|
||||
"columnNumber": 14,
|
||||
"functionName": "x",
|
||||
"lineNumber": 4,
|
||||
"scriptId": "1",
|
||||
"url": "<anonymous>",
|
||||
},
|
||||
{
|
||||
"columnNumber": 8,
|
||||
"functionName": "y",
|
||||
"lineNumber": 7,
|
||||
"scriptId": "1",
|
||||
"url": "<anonymous>",
|
||||
},
|
||||
{
|
||||
"columnNumber": 17,
|
||||
"functionName": "<anonymous>",
|
||||
"lineNumber": 1,
|
||||
"scriptId": "0",
|
||||
"url": "<anonymous>",
|
||||
},
|
||||
],
|
||||
]
|
||||
`;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,278 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
/* eslint-disable quotes */
|
||||
import { expect, test } from 'vitest';
|
||||
import { TestInspector } from './utils.mts';
|
||||
import { Agent, ManagedRealm, setSurroundingAgent } from '#self';
|
||||
|
||||
test('compile script (for invalid code break line)', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
const result = await inspector.runtime.compileScript({
|
||||
expression: 'function f() {',
|
||||
persistScript: false,
|
||||
sourceURL: '',
|
||||
executionContextId: 0,
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
{
|
||||
"exceptionDetails": {
|
||||
"columnNumber": 0,
|
||||
"exception": {
|
||||
"className": "SyntaxError",
|
||||
"description": "SyntaxError: Unexpected end of input",
|
||||
"objectId": "default:2",
|
||||
"preview": {
|
||||
"description": "
|
||||
function f() {
|
||||
^
|
||||
SyntaxError: Unexpected end of source",
|
||||
"entries": undefined,
|
||||
"overflow": false,
|
||||
"properties": [
|
||||
{
|
||||
"name": "message",
|
||||
"type": "string",
|
||||
"value": "Unexpected end of source",
|
||||
},
|
||||
{
|
||||
"name": "stack",
|
||||
"type": "string",
|
||||
"value": "
|
||||
function f() {
|
||||
^
|
||||
SyntaxError: Unexpected end of source",
|
||||
},
|
||||
],
|
||||
"subtype": "error",
|
||||
"type": "object",
|
||||
},
|
||||
"subtype": "error",
|
||||
"type": "object",
|
||||
},
|
||||
"exceptionId": 1,
|
||||
"lineNumber": 0,
|
||||
"scriptId": undefined,
|
||||
"stackTrace": {
|
||||
"callFrames": [],
|
||||
},
|
||||
"text": "Uncaught",
|
||||
"url": undefined,
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('preview evaluation', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const code of [
|
||||
`1`,
|
||||
`[]`,
|
||||
`{ var a = 1; a }`,
|
||||
`{ let a = 1; a }`,
|
||||
`[1, 2, 3].map(x => x + 1)`,
|
||||
`globalThis.x = 1`,
|
||||
]) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const result: any = await inspector.perview(code);
|
||||
if (result.exceptionDetails?.exception.preview.properties[0].value === 'Preview evaluator cannot evaluate side-effecting code') {
|
||||
expect('side effect').toMatchSnapshot(code);
|
||||
} else {
|
||||
expect(result).toMatchSnapshot(code);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('get local lexical names', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
expect(await inspector.runtime.globalLexicalScopeNames({
|
||||
executionContextId: 0,
|
||||
})).toMatchInlineSnapshot(`
|
||||
{
|
||||
"names": [
|
||||
"Infinity",
|
||||
"NaN",
|
||||
"undefined",
|
||||
"globalThis",
|
||||
"eval",
|
||||
"isFinite",
|
||||
"isNaN",
|
||||
"parseFloat",
|
||||
"parseInt",
|
||||
"decodeURI",
|
||||
"decodeURIComponent",
|
||||
"encodeURI",
|
||||
"encodeURIComponent",
|
||||
"AggregateError",
|
||||
"Array",
|
||||
"ArrayBuffer",
|
||||
"Boolean",
|
||||
"BigInt",
|
||||
"BigInt64Array",
|
||||
"BigUint64Array",
|
||||
"DataView",
|
||||
"Date",
|
||||
"Error",
|
||||
"EvalError",
|
||||
"FinalizationRegistry",
|
||||
"Float32Array",
|
||||
"Float64Array",
|
||||
"Function",
|
||||
"Int8Array",
|
||||
"Int16Array",
|
||||
"Int32Array",
|
||||
"Iterator",
|
||||
"Map",
|
||||
"Number",
|
||||
"Object",
|
||||
"Promise",
|
||||
"Proxy",
|
||||
"RangeError",
|
||||
"ReferenceError",
|
||||
"RegExp",
|
||||
"Set",
|
||||
"ShadowRealm",
|
||||
"String",
|
||||
"Symbol",
|
||||
"SyntaxError",
|
||||
"TypeError",
|
||||
"Uint8Array",
|
||||
"Uint8ClampedArray",
|
||||
"Uint16Array",
|
||||
"Uint32Array",
|
||||
"URIError",
|
||||
"WeakMap",
|
||||
"WeakRef",
|
||||
"WeakSet",
|
||||
"JSON",
|
||||
"Math",
|
||||
"Reflect",
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('call function on', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
inspector.flush();
|
||||
await inspector.eval('const a = { x: 1 }; a');
|
||||
expect(inspector.flush()).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"method": "Debugger.scriptParsed",
|
||||
"params": {
|
||||
"buildId": "",
|
||||
"endColumn": 21,
|
||||
"endLine": 1,
|
||||
"executionContextId": 0,
|
||||
"hash": "",
|
||||
"isModule": false,
|
||||
"scriptId": "0",
|
||||
"startColumn": 0,
|
||||
"startLine": 0,
|
||||
"url": "vm:///0",
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"method": "Runtime.evaluate",
|
||||
"params": {
|
||||
"expression": "const a = { x: 1 }; a",
|
||||
"uniqueContextId": "0",
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"result": {
|
||||
"exceptionDetails": undefined,
|
||||
"result": {
|
||||
"className": "Object",
|
||||
"description": "Object",
|
||||
"objectId": "default:1",
|
||||
"preview": {
|
||||
"description": "Object",
|
||||
"entries": undefined,
|
||||
"overflow": false,
|
||||
"properties": [
|
||||
{
|
||||
"name": "x",
|
||||
"type": "number",
|
||||
"value": "1",
|
||||
},
|
||||
],
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(await inspector.runtime.callFunctionOn({
|
||||
functionDeclaration: 'function (x) { return this.x + x }',
|
||||
arguments: [{ value: 1 }],
|
||||
executionContextId: 0,
|
||||
objectId: 'default:1',
|
||||
})).toMatchInlineSnapshot(`
|
||||
{
|
||||
"description": "2",
|
||||
"type": "number",
|
||||
"value": 2,
|
||||
}
|
||||
`);
|
||||
expect(await inspector.runtime.callFunctionOn({
|
||||
functionDeclaration: 'function (x) { return [this.x, x, 2, 3] }',
|
||||
arguments: [{ value: 1 }],
|
||||
executionContextId: 0,
|
||||
objectId: 'default:1',
|
||||
returnByValue: true,
|
||||
})).toMatchInlineSnapshot(`
|
||||
{
|
||||
"type": "object",
|
||||
"value": [
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('private field jailbreak', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
await inspector.eval('class A { #x = 1; }; globalThis.a = new A();');
|
||||
await inspector.debugger.engine262_setEvaluateMode({ mode: 'console' });
|
||||
expect(await inspector.runtime.evaluate({ expression: 'a.#x', uniqueContextId: '0' })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"description": "1",
|
||||
"type": "number",
|
||||
"value": 1,
|
||||
}
|
||||
`);
|
||||
});
|
||||
@@ -0,0 +1,489 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
/* eslint-disable quotes */
|
||||
import { expect, test } from 'vitest';
|
||||
import { TestInspector } from './utils.mts';
|
||||
import { Agent, ManagedRealm, setSurroundingAgent } from '#self';
|
||||
|
||||
test('evaluate on frame', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
const paused = inspector.eval(`
|
||||
'use strict';
|
||||
function f() {
|
||||
const a = 1;
|
||||
debugger;
|
||||
}
|
||||
function y() {
|
||||
const a = 0;
|
||||
f();
|
||||
}
|
||||
y();
|
||||
`);
|
||||
expect(inspector.flush()).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"method": "Runtime.executionContextCreated",
|
||||
"params": {
|
||||
"context": {
|
||||
"id": 0,
|
||||
"name": "engine262",
|
||||
"origin": "vm://repl",
|
||||
"uniqueId": "0",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"method": "Debugger.scriptParsed",
|
||||
"params": {
|
||||
"buildId": "",
|
||||
"endColumn": 2,
|
||||
"endLine": 12,
|
||||
"executionContextId": 0,
|
||||
"hash": "",
|
||||
"isModule": false,
|
||||
"scriptId": "0",
|
||||
"startColumn": 0,
|
||||
"startLine": 0,
|
||||
"url": "vm:///0",
|
||||
},
|
||||
},
|
||||
{
|
||||
"method": "Debugger.paused",
|
||||
"params": {
|
||||
"callFrames": [
|
||||
{
|
||||
"callFrameId": "3",
|
||||
"canBeRestarted": false,
|
||||
"functionLocation": {
|
||||
"columnNumber": 17,
|
||||
"lineNumber": 2,
|
||||
"scriptId": "0",
|
||||
},
|
||||
"functionName": "f",
|
||||
"location": {
|
||||
"columnNumber": 6,
|
||||
"lineNumber": 4,
|
||||
"scriptId": "0",
|
||||
},
|
||||
"scopeChain": [
|
||||
{
|
||||
"object": {
|
||||
"className": "Object",
|
||||
"description": "Object",
|
||||
"objectId": "default:1",
|
||||
"preview": {
|
||||
"description": "Object",
|
||||
"entries": undefined,
|
||||
"overflow": false,
|
||||
"properties": [
|
||||
{
|
||||
"name": "a",
|
||||
"type": "number",
|
||||
"value": "1",
|
||||
},
|
||||
],
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
"type": "local",
|
||||
},
|
||||
{
|
||||
"object": {
|
||||
"className": "Object",
|
||||
"description": "Object",
|
||||
"objectId": "default:2",
|
||||
"preview": {
|
||||
"description": "Object",
|
||||
"entries": undefined,
|
||||
"overflow": true,
|
||||
"properties": [
|
||||
{
|
||||
"name": "Infinity",
|
||||
"type": "number",
|
||||
"value": "Infinity",
|
||||
},
|
||||
{
|
||||
"name": "NaN",
|
||||
"type": "number",
|
||||
"value": "NaN",
|
||||
},
|
||||
{
|
||||
"name": "undefined",
|
||||
"type": "undefined",
|
||||
"value": "undefined",
|
||||
},
|
||||
{
|
||||
"name": "globalThis",
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
"value": "Object",
|
||||
},
|
||||
{
|
||||
"name": "eval",
|
||||
"type": "function",
|
||||
"value": "",
|
||||
},
|
||||
{
|
||||
"name": "isFinite",
|
||||
"type": "function",
|
||||
"value": "",
|
||||
},
|
||||
],
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
"type": "global",
|
||||
},
|
||||
],
|
||||
"this": {
|
||||
"type": "undefined",
|
||||
},
|
||||
"url": "",
|
||||
},
|
||||
{
|
||||
"callFrameId": "2",
|
||||
"canBeRestarted": false,
|
||||
"functionLocation": {
|
||||
"columnNumber": 17,
|
||||
"lineNumber": 6,
|
||||
"scriptId": "0",
|
||||
},
|
||||
"functionName": "y",
|
||||
"location": {
|
||||
"columnNumber": 6,
|
||||
"lineNumber": 8,
|
||||
"scriptId": "0",
|
||||
},
|
||||
"scopeChain": [
|
||||
{
|
||||
"object": {
|
||||
"className": "Object",
|
||||
"description": "Object",
|
||||
"objectId": "default:3",
|
||||
"preview": {
|
||||
"description": "Object",
|
||||
"entries": undefined,
|
||||
"overflow": false,
|
||||
"properties": [
|
||||
{
|
||||
"name": "a",
|
||||
"type": "number",
|
||||
"value": "0",
|
||||
},
|
||||
],
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
"type": "local",
|
||||
},
|
||||
{
|
||||
"object": {
|
||||
"className": "Object",
|
||||
"description": "Object",
|
||||
"objectId": "default:2",
|
||||
"preview": {
|
||||
"description": "Object",
|
||||
"entries": undefined,
|
||||
"overflow": true,
|
||||
"properties": [
|
||||
{
|
||||
"name": "Infinity",
|
||||
"type": "number",
|
||||
"value": "Infinity",
|
||||
},
|
||||
{
|
||||
"name": "NaN",
|
||||
"type": "number",
|
||||
"value": "NaN",
|
||||
},
|
||||
{
|
||||
"name": "undefined",
|
||||
"type": "undefined",
|
||||
"value": "undefined",
|
||||
},
|
||||
{
|
||||
"name": "globalThis",
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
"value": "Object",
|
||||
},
|
||||
{
|
||||
"name": "eval",
|
||||
"type": "function",
|
||||
"value": "",
|
||||
},
|
||||
{
|
||||
"name": "isFinite",
|
||||
"type": "function",
|
||||
"value": "",
|
||||
},
|
||||
],
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
"type": "global",
|
||||
},
|
||||
],
|
||||
"this": {
|
||||
"type": "undefined",
|
||||
},
|
||||
"url": "",
|
||||
},
|
||||
{
|
||||
"callFrameId": "1",
|
||||
"canBeRestarted": false,
|
||||
"functionLocation": undefined,
|
||||
"functionName": "<anonymous>",
|
||||
"location": {
|
||||
"columnNumber": 4,
|
||||
"lineNumber": 10,
|
||||
"scriptId": "0",
|
||||
},
|
||||
"scopeChain": [
|
||||
{
|
||||
"object": {
|
||||
"className": "Object",
|
||||
"description": "Object",
|
||||
"objectId": "default:2",
|
||||
"preview": {
|
||||
"description": "Object",
|
||||
"entries": undefined,
|
||||
"overflow": true,
|
||||
"properties": [
|
||||
{
|
||||
"name": "Infinity",
|
||||
"type": "number",
|
||||
"value": "Infinity",
|
||||
},
|
||||
{
|
||||
"name": "NaN",
|
||||
"type": "number",
|
||||
"value": "NaN",
|
||||
},
|
||||
{
|
||||
"name": "undefined",
|
||||
"type": "undefined",
|
||||
"value": "undefined",
|
||||
},
|
||||
{
|
||||
"name": "globalThis",
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
"value": "Object",
|
||||
},
|
||||
{
|
||||
"name": "eval",
|
||||
"type": "function",
|
||||
"value": "",
|
||||
},
|
||||
{
|
||||
"name": "isFinite",
|
||||
"type": "function",
|
||||
"value": "",
|
||||
},
|
||||
],
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
"type": "global",
|
||||
},
|
||||
],
|
||||
"this": {
|
||||
"className": "Object",
|
||||
"description": "Object",
|
||||
"objectId": "default:2",
|
||||
"preview": {
|
||||
"description": "Object",
|
||||
"entries": undefined,
|
||||
"overflow": true,
|
||||
"properties": [
|
||||
{
|
||||
"name": "Infinity",
|
||||
"type": "number",
|
||||
"value": "Infinity",
|
||||
},
|
||||
{
|
||||
"name": "NaN",
|
||||
"type": "number",
|
||||
"value": "NaN",
|
||||
},
|
||||
{
|
||||
"name": "undefined",
|
||||
"type": "undefined",
|
||||
"value": "undefined",
|
||||
},
|
||||
{
|
||||
"name": "globalThis",
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
"value": "Object",
|
||||
},
|
||||
{
|
||||
"name": "eval",
|
||||
"type": "function",
|
||||
"value": "",
|
||||
},
|
||||
{
|
||||
"name": "isFinite",
|
||||
"type": "function",
|
||||
"value": "",
|
||||
},
|
||||
],
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
"subtype": undefined,
|
||||
"type": "object",
|
||||
},
|
||||
"url": "",
|
||||
},
|
||||
],
|
||||
"reason": "debugCommand",
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"method": "Runtime.evaluate",
|
||||
"params": {
|
||||
"expression": "
|
||||
'use strict';
|
||||
function f() {
|
||||
const a = 1;
|
||||
debugger;
|
||||
}
|
||||
function y() {
|
||||
const a = 0;
|
||||
f();
|
||||
}
|
||||
y();
|
||||
",
|
||||
"uniqueContextId": "0",
|
||||
},
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(await inspector.debugger.evaluateOnCallFrame({
|
||||
callFrameId: "3",
|
||||
expression: 'a',
|
||||
})).toMatchInlineSnapshot(`
|
||||
{
|
||||
"description": "1",
|
||||
"type": "number",
|
||||
"value": 1,
|
||||
}
|
||||
`);
|
||||
expect(await inspector.debugger.evaluateOnCallFrame({
|
||||
callFrameId: "2",
|
||||
expression: 'a',
|
||||
})).toMatchInlineSnapshot(`
|
||||
{
|
||||
"description": "0",
|
||||
"type": "number",
|
||||
"value": 0,
|
||||
}
|
||||
`);
|
||||
expect(await inspector.debugger.evaluateOnCallFrame({
|
||||
callFrameId: "1",
|
||||
expression: 'a',
|
||||
})).toMatchInlineSnapshot(`
|
||||
{
|
||||
"exceptionDetails": {
|
||||
"columnNumber": 0,
|
||||
"exception": {
|
||||
"className": "SyntaxError",
|
||||
"description": "ReferenceError: 'a' is not defined
|
||||
at <anonymous>:1:1
|
||||
at <anonymous>:11:5",
|
||||
"objectId": "default:5",
|
||||
"preview": {
|
||||
"description": "ReferenceError: 'a' is not defined
|
||||
at <anonymous>:1:1
|
||||
at <anonymous>:11:5",
|
||||
"entries": undefined,
|
||||
"overflow": false,
|
||||
"properties": [
|
||||
{
|
||||
"name": "message",
|
||||
"type": "string",
|
||||
"value": "'a' is not defined",
|
||||
},
|
||||
],
|
||||
"subtype": "error",
|
||||
"type": "object",
|
||||
},
|
||||
"subtype": "error",
|
||||
"type": "object",
|
||||
},
|
||||
"exceptionId": 4,
|
||||
"lineNumber": 0,
|
||||
"scriptId": "0",
|
||||
"stackTrace": {
|
||||
"callFrames": [
|
||||
{
|
||||
"columnNumber": 0,
|
||||
"functionName": "<anonymous>",
|
||||
"lineNumber": 0,
|
||||
"scriptId": "0",
|
||||
"url": "<anonymous>",
|
||||
},
|
||||
{
|
||||
"columnNumber": 4,
|
||||
"functionName": "<anonymous>",
|
||||
"lineNumber": 10,
|
||||
"scriptId": "0",
|
||||
"url": "<anonymous>",
|
||||
},
|
||||
],
|
||||
},
|
||||
"text": "Uncaught",
|
||||
"url": "<anonymous>",
|
||||
},
|
||||
"result": {
|
||||
"className": "SyntaxError",
|
||||
"description": "ReferenceError: 'a' is not defined
|
||||
at <anonymous>:1:1
|
||||
at <anonymous>:11:5",
|
||||
"objectId": "default:5",
|
||||
"preview": {
|
||||
"description": "ReferenceError: 'a' is not defined
|
||||
at <anonymous>:1:1
|
||||
at <anonymous>:11:5",
|
||||
"entries": undefined,
|
||||
"overflow": false,
|
||||
"properties": [
|
||||
{
|
||||
"name": "message",
|
||||
"type": "string",
|
||||
"value": "'a' is not defined",
|
||||
},
|
||||
],
|
||||
"subtype": "error",
|
||||
"type": "object",
|
||||
},
|
||||
"subtype": "error",
|
||||
"type": "object",
|
||||
},
|
||||
}
|
||||
`);
|
||||
await inspector.debugger.resume();
|
||||
await paused;
|
||||
});
|
||||
@@ -0,0 +1,224 @@
|
||||
import { expect, test } from 'vitest';
|
||||
import { TestInspector } from './utils.mts';
|
||||
import {
|
||||
Agent, ManagedRealm, runJobQueue, setSurroundingAgent,
|
||||
} from '#self';
|
||||
import { createConsole } from '#self/inspector';
|
||||
|
||||
test('console', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
let count = 0;
|
||||
createConsole(realm, {
|
||||
log(args) {
|
||||
count += args.length;
|
||||
},
|
||||
});
|
||||
|
||||
inspector.flush();
|
||||
await inspector.eval('console.log("hello", "world")');
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const a: any = inspector.flush();
|
||||
a[1].params.timestamp = 0;
|
||||
expect(a).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"method": "Debugger.scriptParsed",
|
||||
"params": {
|
||||
"buildId": "",
|
||||
"endColumn": 29,
|
||||
"endLine": 1,
|
||||
"executionContextId": 0,
|
||||
"hash": "",
|
||||
"isModule": false,
|
||||
"scriptId": "0",
|
||||
"startColumn": 0,
|
||||
"startLine": 0,
|
||||
"url": "vm:///0",
|
||||
},
|
||||
},
|
||||
{
|
||||
"method": "Runtime.consoleAPICalled",
|
||||
"params": {
|
||||
"args": [
|
||||
{
|
||||
"type": "string",
|
||||
"value": "hello",
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"value": "world",
|
||||
},
|
||||
],
|
||||
"executionContextId": 0,
|
||||
"timestamp": 0,
|
||||
"type": "log",
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"method": "Runtime.evaluate",
|
||||
"params": {
|
||||
"expression": "console.log("hello", "world")",
|
||||
"uniqueContextId": "0",
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"result": {
|
||||
"exceptionDetails": undefined,
|
||||
"result": {
|
||||
"type": "undefined",
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(count).eq(2);
|
||||
|
||||
await inspector.perview('console.log("hello", "world")');
|
||||
expect(count).eq(2);
|
||||
});
|
||||
|
||||
test('unhandled promise rejection', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
inspector.flush();
|
||||
await inspector.eval('var a = Promise.reject(new Error())');
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const i: any = inspector.flush();
|
||||
i[1].params.timestamp = 0;
|
||||
expect(i).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"method": "Debugger.scriptParsed",
|
||||
"params": {
|
||||
"buildId": "",
|
||||
"endColumn": 35,
|
||||
"endLine": 1,
|
||||
"executionContextId": 0,
|
||||
"hash": "",
|
||||
"isModule": false,
|
||||
"scriptId": "0",
|
||||
"startColumn": 0,
|
||||
"startLine": 0,
|
||||
"url": "vm:///0",
|
||||
},
|
||||
},
|
||||
{
|
||||
"method": "Runtime.exceptionThrown",
|
||||
"params": {
|
||||
"exceptionDetails": {
|
||||
"columnNumber": 0,
|
||||
"exception": {
|
||||
"className": "Promise",
|
||||
"description": "Promise",
|
||||
"objectId": "default:2",
|
||||
"preview": {
|
||||
"description": "Promise",
|
||||
"entries": undefined,
|
||||
"overflow": false,
|
||||
"properties": [
|
||||
{
|
||||
"name": "[[PromiseState]]",
|
||||
"type": "string",
|
||||
"value": "rejected",
|
||||
},
|
||||
{
|
||||
"name": "[[PromiseResult]]",
|
||||
"subtype": "error",
|
||||
"type": "object",
|
||||
"value": "Error
|
||||
at <anonymous>:1:28",
|
||||
},
|
||||
],
|
||||
"subtype": "promise",
|
||||
"type": "object",
|
||||
},
|
||||
"subtype": "promise",
|
||||
"type": "object",
|
||||
},
|
||||
"exceptionId": 1,
|
||||
"lineNumber": 0,
|
||||
"scriptId": undefined,
|
||||
"stackTrace": undefined,
|
||||
"text": "Uncaught (in promise)",
|
||||
"url": undefined,
|
||||
},
|
||||
"timestamp": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"method": "Runtime.evaluate",
|
||||
"params": {
|
||||
"expression": "var a = Promise.reject(new Error())",
|
||||
"uniqueContextId": "0",
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"result": {
|
||||
"exceptionDetails": undefined,
|
||||
"result": {
|
||||
"type": "undefined",
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
||||
await inspector.eval('void a.catch(() => {});');
|
||||
runJobQueue();
|
||||
expect(inspector.flush()).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"method": "Debugger.scriptParsed",
|
||||
"params": {
|
||||
"buildId": "",
|
||||
"endColumn": 23,
|
||||
"endLine": 1,
|
||||
"executionContextId": 0,
|
||||
"hash": "",
|
||||
"isModule": false,
|
||||
"scriptId": "1",
|
||||
"startColumn": 0,
|
||||
"startLine": 0,
|
||||
"url": "vm:///1",
|
||||
},
|
||||
},
|
||||
{
|
||||
"method": "Runtime.exceptionRevoked",
|
||||
"params": {
|
||||
"exceptionId": 1,
|
||||
"reason": "Handler added to rejected promise",
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"method": "Runtime.evaluate",
|
||||
"params": {
|
||||
"expression": "void a.catch(() => {});",
|
||||
"uniqueContextId": "0",
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"result": {
|
||||
"exceptionDetails": undefined,
|
||||
"result": {
|
||||
"type": "undefined",
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
/* eslint-disable quotes */
|
||||
import { expect, test } from 'vitest';
|
||||
import { TestInspector } from './utils.mts';
|
||||
import {
|
||||
Agent, Construct, CreateBuiltinFunction, Descriptor, evalQ, getHostDefinedErrorStack, ManagedRealm, setSurroundingAgent,
|
||||
surroundingAgent,
|
||||
Value,
|
||||
type ShadowRealmObject,
|
||||
} from '#self';
|
||||
|
||||
test('code in eval', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
const messages: unknown[] = [];
|
||||
realm.scope(() => {
|
||||
realm.GlobalObject.properties.set('e', new Descriptor({
|
||||
Value: CreateBuiltinFunction.from(function* e(e = Value.undefined) {
|
||||
messages.push(getHostDefinedErrorStack(e)?.map((f) => f.toCallFrame()));
|
||||
}),
|
||||
}));
|
||||
});
|
||||
|
||||
await inspector.eval([
|
||||
`e(new Error());`,
|
||||
`function f() {
|
||||
e(new Error());
|
||||
};
|
||||
f();`,
|
||||
].map((code) => `eval(\`${code}\`)`).join('\n'));
|
||||
expect(messages).matchSnapshot();
|
||||
});
|
||||
|
||||
test('code in new Function', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
const messages: unknown[] = [];
|
||||
realm.scope(() => {
|
||||
realm.GlobalObject.properties.set('e', new Descriptor({
|
||||
Value: CreateBuiltinFunction.from(function* e(e = Value.undefined) {
|
||||
messages.push(getHostDefinedErrorStack(e)?.map((f) => f.toCallFrame()));
|
||||
}),
|
||||
}));
|
||||
});
|
||||
|
||||
await inspector.eval(`
|
||||
new Function(\`
|
||||
function x() {
|
||||
e(new Error());
|
||||
}
|
||||
function y() {
|
||||
x()
|
||||
}
|
||||
return y\`)()()
|
||||
`);
|
||||
expect(messages).matchSnapshot();
|
||||
});
|
||||
|
||||
test('code in ShadowRealm', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
const messages: unknown[] = [];
|
||||
realm.scope(() => {
|
||||
evalQ((_Q, X) => {
|
||||
const shadowRealm = X(Construct(surroundingAgent.intrinsic('%ShadowRealm%'))) as ShadowRealmObject;
|
||||
realm.GlobalObject.properties.set('r', new Descriptor({
|
||||
Value: shadowRealm,
|
||||
}));
|
||||
shadowRealm.ShadowRealm.GlobalObject.properties.set('e', new Descriptor({
|
||||
Value: CreateBuiltinFunction.from(function* e(e = Value.undefined) {
|
||||
messages.push(getHostDefinedErrorStack(e)?.map((f) => f.toCallFrame()));
|
||||
}),
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
await inspector.eval(`
|
||||
r.evaluate('e(new Error())');
|
||||
`);
|
||||
expect(messages).matchSnapshot();
|
||||
});
|
||||
@@ -0,0 +1,341 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable no-await-in-loop */
|
||||
import { expect, test } from 'vitest';
|
||||
import type Protocol from 'devtools-protocol';
|
||||
import { TestInspector } from './utils.mts';
|
||||
import { Agent, ManagedRealm, setSurroundingAgent } from '#self';
|
||||
|
||||
test('primitive values', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const value of [
|
||||
'undefined',
|
||||
'null',
|
||||
'false',
|
||||
'true',
|
||||
'42',
|
||||
'-42',
|
||||
'42n',
|
||||
'-42n',
|
||||
'0',
|
||||
'-0',
|
||||
'Infinity',
|
||||
'-Infinity',
|
||||
'NaN',
|
||||
'"engine262"',
|
||||
'Symbol()',
|
||||
'Symbol("desc")',
|
||||
'Symbol.for("symbol")',
|
||||
'Symbol.iterator',
|
||||
]) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
expect(await inspector.eval(value)).toMatchSnapshot(value);
|
||||
}
|
||||
});
|
||||
|
||||
test('functions', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const value of [
|
||||
// function declaration
|
||||
'function f() { /* comment */ }; f',
|
||||
'function* f() { /* comment */ }; f',
|
||||
'function *f() { /* comment */ }; f',
|
||||
'async function f() { /* comment */ }; f',
|
||||
'async function* f() { /* comment */ }; f',
|
||||
'async function *f() { /* comment */ }; f',
|
||||
// function expression
|
||||
'(function f() { /* comment */ })',
|
||||
'(function* f() { /* comment */ })',
|
||||
'(function *f() { /* comment */ })',
|
||||
'(async function f() { /* comment */ })',
|
||||
'(async function* f() { /* comment */ })',
|
||||
'(async function *f() { /* comment */ })',
|
||||
// arrow expression
|
||||
'(() => { /* comment */ })',
|
||||
'(() => 42)',
|
||||
'(async () => { /* comment */ })',
|
||||
'(async () => 42)',
|
||||
// computed function name
|
||||
'var a = 1; ({ [a]() {} })[a]',
|
||||
'({ *[Symbol.iterator]() {} })[Symbol.iterator]',
|
||||
// getter & setter
|
||||
'var o = { get f() { /* comment */ } }; Reflect.getOwnPropertyDescriptor(o, "f").get',
|
||||
'var o = { set f(v) { /* comment */ } }; Reflect.getOwnPropertyDescriptor(o, "f").set',
|
||||
// getter & setter with computed name
|
||||
'var o = { get [Symbol.iterator]() { /* comment */ } }; Reflect.getOwnPropertyDescriptor(o, Symbol.iterator).get',
|
||||
'var o = { set [Symbol.iterator](v) { /* comment */ } }; Reflect.getOwnPropertyDescriptor(o, Symbol.iterator).set',
|
||||
// built-in function
|
||||
'Array.prototype.map',
|
||||
// built-in getter
|
||||
'Reflect.getOwnPropertyDescriptor(Function.prototype, "caller").get',
|
||||
// method
|
||||
'class C { static method() {} }; C.method',
|
||||
'class C { constructor() {}; #f }; C.prototype.constructor',
|
||||
]) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
expect(await inspector.eval(value), value).toMatchSnapshot(value);
|
||||
}
|
||||
});
|
||||
|
||||
async function snapshotObject(inspector: TestInspector, value: string) {
|
||||
const result = await inspector.eval(value);
|
||||
expect(result).toMatchSnapshot(value);
|
||||
const properties = await inspector.runtime.getProperties({ objectId: (result as any).objectId!, ownProperties: true, generatePreview: true }) as Protocol.Protocol.Runtime.GetPropertiesResponse;
|
||||
properties.internalProperties = properties.internalProperties?.filter((prop) => prop.name !== '[[Prototype]]');
|
||||
expect(properties).toMatchSnapshot(`${value} properties`);
|
||||
}
|
||||
|
||||
test('array', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const value of [
|
||||
'[]',
|
||||
'[1]',
|
||||
'Array(10)',
|
||||
'[,,,]',
|
||||
'var a = [1,,2]; a.x = 1; a',
|
||||
]) {
|
||||
await snapshotObject(inspector, value);
|
||||
}
|
||||
});
|
||||
|
||||
test('regex', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const value of [
|
||||
'/cat/',
|
||||
'/cat/g',
|
||||
'/cat/i',
|
||||
'var a = /cat/; a.lastIndex = 1; a',
|
||||
]) {
|
||||
expect(await inspector.eval(value)).toMatchSnapshot(value);
|
||||
}
|
||||
});
|
||||
|
||||
test('date', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const value of [
|
||||
'new Date(0)',
|
||||
'new Date(NaN)',
|
||||
'new Date(-1)',
|
||||
'new Date(9999999999999)',
|
||||
]) {
|
||||
expect(await inspector.eval(value)).toMatchSnapshot(value);
|
||||
}
|
||||
});
|
||||
|
||||
test('map and set', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const value of [
|
||||
'new Map',
|
||||
'new Map([["a", 1], ["b", 2]])',
|
||||
'var x = new Map([["a", 1], ["b", 2]]); x.x = 1; x',
|
||||
'new Set',
|
||||
'new Set(["a", 1, "b", 2])',
|
||||
'var x = new Set(["a", 1, "b", 2]); x.x = 1; x',
|
||||
'new WeakMap',
|
||||
'new WeakMap([[{}, 1], [{}, 2]])',
|
||||
'var x = new WeakMap([[{}, 1], [{}, 2]]); x.x = 1; x',
|
||||
'new WeakSet',
|
||||
'new WeakSet([{}, {}])',
|
||||
'var x = new WeakSet([{}, {}]); x.x = 1; x',
|
||||
]) {
|
||||
await snapshotObject(inspector, value);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: generator
|
||||
|
||||
test('error', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const value of [
|
||||
'new Error()',
|
||||
'new Error("message")',
|
||||
'new Error("message", { cause: new Error("cause") })',
|
||||
'new RangeError()',
|
||||
'new (class MyError extends Error {})()',
|
||||
// TODO: className should not be syntaxError
|
||||
'new (class MyError extends Error { constructor() { super(); this.message = "hello" } })()',
|
||||
]) {
|
||||
expect(await inspector.eval(value)).toMatchSnapshot(value);
|
||||
}
|
||||
});
|
||||
|
||||
test('proxy', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const value of [
|
||||
'new Proxy({}, {})',
|
||||
'new Proxy({}, { get: () => {} })',
|
||||
'new Proxy({ a: 1 }, {})',
|
||||
'new Proxy(Function, {})',
|
||||
'new Proxy(() => {}, {})',
|
||||
'var a = Proxy.revocable({}, {}); a.revoke(); a.proxy',
|
||||
]) {
|
||||
await snapshotObject(inspector, value);
|
||||
}
|
||||
});
|
||||
|
||||
test('promise', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const value of [
|
||||
'new Promise(() => {})',
|
||||
'var a = new Promise(() => {}); a.x = 1; a',
|
||||
'Promise.resolve()',
|
||||
'Promise.resolve(42)',
|
||||
'Promise.reject()',
|
||||
'Promise.reject(42)',
|
||||
]) {
|
||||
await snapshotObject(inspector, value);
|
||||
}
|
||||
});
|
||||
|
||||
test('typed array', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const value of [
|
||||
'new Uint8Array()',
|
||||
'new Uint8Array(10)',
|
||||
'new Uint8Array([1, 2, 3])',
|
||||
'var x = new Uint8Array(10); x.a = 1; x',
|
||||
'new Int32Array()',
|
||||
'new Int32Array(10)',
|
||||
'new Int32Array([1, 2, 3])',
|
||||
// TODO: test with detached arraybuffer
|
||||
]) {
|
||||
await snapshotObject(inspector, value);
|
||||
}
|
||||
});
|
||||
|
||||
test('array buffer', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const value of [
|
||||
'new ArrayBuffer(0)',
|
||||
'new ArrayBuffer(10)',
|
||||
'var x = new ArrayBuffer(10); x.a = 1; x',
|
||||
// TODO: test with detached arraybuffer
|
||||
]) {
|
||||
await snapshotObject(inspector, value);
|
||||
}
|
||||
});
|
||||
|
||||
test('data view', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const value of [
|
||||
'new DataView(new ArrayBuffer(0))',
|
||||
'new DataView(new ArrayBuffer(10))',
|
||||
'var x = new DataView(new ArrayBuffer(10), 0); x.a = 1; x',
|
||||
]) {
|
||||
await snapshotObject(inspector, value);
|
||||
}
|
||||
});
|
||||
|
||||
test('module namespace', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
await inspector.debugger.engine262_setEvaluateMode({ mode: 'module' });
|
||||
|
||||
for (const value of [
|
||||
// Note: our inspector will return the module namespace object after evaluation
|
||||
'',
|
||||
'export const a = 1',
|
||||
'export const b = 2; export { b as c }',
|
||||
'export default 42',
|
||||
'export default function() {}',
|
||||
]) {
|
||||
await snapshotObject(inspector, value);
|
||||
}
|
||||
});
|
||||
|
||||
test('shadow realm', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
await snapshotObject(inspector, 'new ShadowRealm');
|
||||
expect(await inspector.eval('new ShadowRealm().evaluate("(() => {})")')).toMatchSnapshot('ShadowRealm function');
|
||||
});
|
||||
|
||||
test('normal object', async () => {
|
||||
const agent = new Agent();
|
||||
setSurroundingAgent(agent);
|
||||
const inspector = new TestInspector();
|
||||
const realm = new ManagedRealm();
|
||||
inspector.attachAgent(agent, [realm]);
|
||||
|
||||
for (const value of [
|
||||
'({})',
|
||||
'({ a: 1 })',
|
||||
'({ a: 1, b: 2 })',
|
||||
'({ __proto__: null })',
|
||||
'({ __proto__: { a: 1 } })',
|
||||
'({ [Symbol.iterator]: () => {} })',
|
||||
'({ f() {} })',
|
||||
'({ get f() {}, set f(v) {} })',
|
||||
'{ class T { #priv = 1 }; new T }',
|
||||
'{ class T { #priv = 1; normal = 2 }; new T }',
|
||||
'({ a: 1n, b: undefined, c: null, d: true, e: Symbol.iterator, f: [] })',
|
||||
]) {
|
||||
await snapshotObject(inspector, value);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
import type { DebuggerContext, DebuggerNamespace, RuntimeNamespace } from '../../lib/inspector/types.d.mts';
|
||||
import { Inspector } from '#self/inspector';
|
||||
|
||||
export class TestInspector extends Inspector {
|
||||
messages: object[] = [];
|
||||
|
||||
flush() {
|
||||
const old = this.messages;
|
||||
this.messages = [];
|
||||
return old;
|
||||
}
|
||||
|
||||
onInspectorMessage?: (message: object) => void;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
protected override send(data: any): void {
|
||||
this.messages.push(data);
|
||||
if ('id' in data) {
|
||||
let meaningfulData = data;
|
||||
if (data.result) {
|
||||
meaningfulData = data.result;
|
||||
if (!data.result.exceptionDetails) {
|
||||
if (data.result.result && Object.keys(data.result).length <= 2) {
|
||||
meaningfulData = data.result.result;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.#callbacks.at(data.id)?.resolve(meaningfulData);
|
||||
}
|
||||
this.onInspectorMessage?.(data);
|
||||
}
|
||||
|
||||
protected override onMessage(id: number, method: string, params: object | void): void {
|
||||
super.onMessage(id, method, params);
|
||||
this.messages.push({ id, method, params });
|
||||
}
|
||||
|
||||
debugger: {
|
||||
[T in keyof DebuggerNamespace]-?: (params: DebuggerNamespace[T] extends undefined | ((params: infer O, context: DebuggerContext) => unknown) ? O : void) => Promise<object>;
|
||||
};
|
||||
|
||||
runtime: {
|
||||
[T in keyof RuntimeNamespace]-?: (params: RuntimeNamespace[T] extends undefined | ((params: infer O, context: DebuggerContext) => unknown) ? O : void) => Promise<object>;
|
||||
};
|
||||
|
||||
#callbacks: PromiseWithResolvers<unknown>[] = [];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const object = (namespace: string) => Object.create(
|
||||
new Proxy({}, {
|
||||
get: (_, p, receiver) => {
|
||||
if (typeof p === 'symbol') {
|
||||
return undefined;
|
||||
}
|
||||
const f = (params: object) => {
|
||||
this.onMessage(this.#callbacks.length, `${namespace}.${p}`, params);
|
||||
const promise = Promise.withResolvers();
|
||||
this.#callbacks.push(promise);
|
||||
return promise.promise;
|
||||
};
|
||||
Reflect.defineProperty(receiver, p, { configurable: true, value: f });
|
||||
return f;
|
||||
},
|
||||
}),
|
||||
);
|
||||
this.runtime = object('Runtime');
|
||||
this.debugger = object('Debugger');
|
||||
}
|
||||
|
||||
// helpers
|
||||
eval(expression: string) {
|
||||
return this.runtime.evaluate({
|
||||
expression,
|
||||
uniqueContextId: '0',
|
||||
});
|
||||
}
|
||||
|
||||
perview(expression: string) {
|
||||
return this.runtime.evaluate({
|
||||
expression,
|
||||
uniqueContextId: '0',
|
||||
throwOnSideEffect: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user