mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 09:17:35 +00:00
LibJS: Implement ShadowRealm.prototype.evaluate()
This commit is contained in:
parent
b0ee7f38d0
commit
c70784bb82
9 changed files with 260 additions and 1 deletions
|
@ -0,0 +1,96 @@
|
|||
describe("normal behavior", () => {
|
||||
test("length is 1", () => {
|
||||
expect(ShadowRealm.prototype.evaluate).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
expect(shadowRealm.evaluate("globalThis.foo = 'bar';")).toBe("bar");
|
||||
expect(shadowRealm.foo).toBeUndefined();
|
||||
expect(shadowRealm.evaluate("foo;")).toBe("bar");
|
||||
expect(shadowRealm.evaluate("foo;")).toBe("bar");
|
||||
});
|
||||
|
||||
test("global object initialization", () => {
|
||||
// Currently uses a plain JS::GlobalObject, i.e. no TestRunnerGlobalObject functions are available on the
|
||||
// shadow realm's global object. This may change in the future, update the test accordingly.
|
||||
const shadowRealm = new ShadowRealm();
|
||||
expect(shadowRealm.evaluate("globalThis.isStrictMode")).toBeUndefined();
|
||||
});
|
||||
|
||||
test("strict mode behavior", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
// NOTE: We don't have access to the isStrictMode() test helper inside the shadow realm, see the comment in the test above.
|
||||
|
||||
// sloppy mode
|
||||
expect(shadowRealm.evaluate("(function() { return !this; })()")).toBe(false);
|
||||
// strict mode
|
||||
expect(shadowRealm.evaluate("'use strict'; (function() { return !this; })()")).toBe(true);
|
||||
// Only the parsed script's strict mode changes the strictEval value used for EvalDeclarationInstantiation
|
||||
expect(
|
||||
(function () {
|
||||
"use strict";
|
||||
return shadowRealm.evaluate("(function() { return !this; })()");
|
||||
})()
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test("wrapped function object", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
|
||||
const string = shadowRealm.evaluate("(function () { return 'foo'; })")();
|
||||
expect(string).toBe("foo");
|
||||
|
||||
const wrappedFunction = shadowRealm.evaluate("(function () { return 'foo'; })");
|
||||
expect(wrappedFunction()).toBe("foo");
|
||||
expect(typeof wrappedFunction).toBe("function");
|
||||
expect(Object.getPrototypeOf(wrappedFunction)).toBe(Function.prototype);
|
||||
|
||||
expect(() => {
|
||||
shadowRealm.evaluate("(function () { throw Error(); })")();
|
||||
}).toThrowWithMessage(
|
||||
TypeError,
|
||||
"Call of wrapped target function did not complete normally"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("throws for non-string input", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
const values = [
|
||||
[undefined, "undefined"],
|
||||
[42, "42"],
|
||||
[new String(), "[object StringObject]"],
|
||||
];
|
||||
for (const [value, errorString] of values) {
|
||||
expect(() => {
|
||||
shadowRealm.evaluate(value);
|
||||
}).toThrowWithMessage(TypeError, `${errorString} is not a string`);
|
||||
}
|
||||
});
|
||||
|
||||
test("throws if non-function object is returned from evaluation", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
const values = [
|
||||
["[]", "[object Array]"],
|
||||
["({})", "[object Object]"],
|
||||
["new String()", "[object StringObject]"],
|
||||
];
|
||||
for (const [value, errorString] of values) {
|
||||
expect(() => {
|
||||
shadowRealm.evaluate(value);
|
||||
}).toThrowWithMessage(
|
||||
TypeError,
|
||||
`Wrapped value must be primitive or a function object, got ${errorString}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("any exception is changed to a TypeError", () => {
|
||||
const shadowRealm = new ShadowRealm();
|
||||
expect(() => {
|
||||
shadowRealm.evaluate("(() => { throw 42; })()");
|
||||
}).toThrowWithMessage(TypeError, "The evaluated script did not complete normally");
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue