File
Blob: src/workerd/api/tests/worker-test.js
| 1 | // Copyright (c) 2025 Cloudflare, Inc. |
| 2 | // Licensed under the Apache 2.0 license found in the LICENSE file or at: |
| 3 | // https://opensource.org/licenses/Apache-2.0 |
| 4 | import { throws, rejects, strictEqual } from 'node:assert'; |
| 5 | import { mock } from 'node:test'; |
| 6 | |
| 7 | // We allow eval and new Function() during startup (global scope evaluation). |
| 8 | strictEqual(eval('1+1'), 2); // should work |
| 9 | const StartupFunction = new Function('return 1+1'); |
| 10 | strictEqual(StartupFunction(), 2); // should work |
| 11 | await Promise.resolve(); |
| 12 | strictEqual(eval('1+1'), 2); // should still work |
| 13 | const StartupFunction2 = new Function('return 2+2'); |
| 14 | strictEqual(StartupFunction2(), 4); // should still work |
| 15 | strictEqual((await import('module-does-eval')).default, 2); // should work |
| 16 | |
| 17 | export const testStartupEval = { |
| 18 | async test() { |
| 19 | throws(() => eval('console.log("This should not work")'), { |
| 20 | message: /Code generation from strings disallowed for this context/, |
| 21 | }); |
| 22 | |
| 23 | throws(() => new Function('console.log("This should not work")'), { |
| 24 | message: /Code generation from strings disallowed for this context/, |
| 25 | }); |
| 26 | |
| 27 | await rejects(() => import('another-module-does-eval'), { |
| 28 | message: /Code generation from strings disallowed for this context/, |
| 29 | }); |
| 30 | |
| 31 | // eval() with no args or a non-string arg is allowed (V8 returns the value |
| 32 | // as-is per spec since there is no string to compile). |
| 33 | strictEqual(eval(), undefined); |
| 34 | strictEqual(eval(undefined), undefined); |
| 35 | |
| 36 | // new Function() with params and a string body is still blocked. |
| 37 | throws(() => new Function('a', 'b', 'return a + b'), { |
| 38 | message: /Code generation from strings disallowed for this context/, |
| 39 | }); |
| 40 | |
| 41 | // new Function() with params and undefined body is also blocked (the body |
| 42 | // becomes the string "undefined" via ToString). |
| 43 | throws(() => new Function('a', 'b', undefined), { |
| 44 | message: /Code generation from strings disallowed for this context/, |
| 45 | }); |
| 46 | |
| 47 | // new Function() with no arguments is allowed (the synthesized source |
| 48 | // matches the known empty-body, no-parameter pattern). |
| 49 | const emptyFn = new Function(); |
| 50 | strictEqual(typeof emptyFn, 'function'); |
| 51 | |
| 52 | // Extending Function with super() and no arguments is also allowed. |
| 53 | class Foo extends Function {} |
| 54 | const foo = new Foo(); |
| 55 | strictEqual(typeof foo, 'function'); |
| 56 | }, |
| 57 | }; |
| 58 | |
| 59 | // Test verifies that explicit resource management is, in fact, enabled. |
| 60 | export const disposeTest = { |
| 61 | test() { |
| 62 | const fn = mock.fn(); |
| 63 | { |
| 64 | using _ = { |
| 65 | [Symbol.dispose]() { |
| 66 | fn(); |
| 67 | }, |
| 68 | }; |
| 69 | } |
| 70 | strictEqual(fn.mock.callCount(), 1); |
| 71 | }, |
| 72 | }; |
| 73 | |
| 74 | export const asyncDisposeTest = { |
| 75 | async test() { |
| 76 | const fn = mock.fn(async () => {}); |
| 77 | { |
| 78 | await using _ = { |
| 79 | async [Symbol.asyncDispose]() { |
| 80 | await fn(); |
| 81 | }, |
| 82 | }; |
| 83 | } |
| 84 | strictEqual(fn.mock.callCount(), 1); |
| 85 | }, |
| 86 | }; |