@@ -1623,4 +1623,179 @@ describe("WorkerExecutor", () => {
16231623 const result = JSON . parse ( resultStr ) ;
16241624 expect ( result . result ) . toEqual ( { temp : 72 , city : "NYC" } ) ;
16251625 } ) ;
1626+
1627+ test ( "handles non-Error rejection (raw string throw)" , async ( ) => {
1628+ const executor = new WorkerExecutor ( ) ;
1629+ const fns = {
1630+ bad : async ( ) => {
1631+ throw "raw string rejection" ;
1632+ } ,
1633+ } ;
1634+ const result = await executor . execute (
1635+ "async () => { return await codemode.bad(); }" ,
1636+ fns ,
1637+ ) ;
1638+ expect ( result . error ) . toBe ( "raw string rejection" ) ;
1639+ } ) ;
1640+
1641+ test ( "handles large return values across worker boundary" , async ( ) => {
1642+ const executor = new WorkerExecutor ( ) ;
1643+ const result = await executor . execute (
1644+ "async () => { return Array.from({ length: 10000 }, (_, i) => i); }" ,
1645+ { } ,
1646+ ) ;
1647+ expect ( result . error ) . toBeUndefined ( ) ;
1648+ expect ( ( result . result as number [ ] ) . length ) . toBe ( 10000 ) ;
1649+ } ) ;
1650+
1651+ test ( "handles undefined return" , async ( ) => {
1652+ const executor = new WorkerExecutor ( ) ;
1653+ const result = await executor . execute ( "async () => { /* no return */ }" , { } ) ;
1654+ expect ( result . error ) . toBeUndefined ( ) ;
1655+ // undefined doesn't survive structured clone, becomes null or undefined
1656+ expect ( result . result == null ) . toBe ( true ) ;
1657+ } ) ;
1658+
1659+ test ( "handles null return" , async ( ) => {
1660+ const executor = new WorkerExecutor ( ) ;
1661+ const result = await executor . execute ( "async () => { return null; }" , { } ) ;
1662+ expect ( result . error ) . toBeUndefined ( ) ;
1663+ expect ( result . result ) . toBeNull ( ) ;
1664+ } ) ;
1665+
1666+ test ( "handles syntax error in code" , async ( ) => {
1667+ const executor = new WorkerExecutor ( ) ;
1668+ const result = await executor . execute ( "async () => { if ( }" , { } ) ;
1669+ expect ( result . error ) . toBeDefined ( ) ;
1670+ } ) ;
1671+
1672+ test ( "times out on infinite loop" , async ( ) => {
1673+ const executor = new WorkerExecutor ( { timeout : 300 } ) ;
1674+ const result = await executor . execute (
1675+ "async () => { while (true) {} }" ,
1676+ { } ,
1677+ ) ;
1678+ expect ( result . error ) . toBe ( "Execution timed out" ) ;
1679+ } ) ;
1680+
1681+ test ( "multiple sequential executions each get a fresh worker" , async ( ) => {
1682+ const executor = new WorkerExecutor ( ) ;
1683+ const results : number [ ] = [ ] ;
1684+ for ( let i = 0 ; i < 5 ; i ++ ) {
1685+ const result = await executor . execute ( `async () => { return ${ i } ; }` , { } ) ;
1686+ results . push ( result . result as number ) ;
1687+ }
1688+ expect ( results ) . toEqual ( [ 0 , 1 , 2 , 3 , 4 ] ) ;
1689+ } ) ;
1690+
1691+ test ( "handles tool that returns slowly (worker waits on host)" , async ( ) => {
1692+ const executor = new WorkerExecutor ( { timeout : 10_000 } ) ;
1693+ const fns = {
1694+ slow : async ( ) => {
1695+ await new Promise ( ( r ) => setTimeout ( r , 200 ) ) ;
1696+ return "slow result" ;
1697+ } ,
1698+ } ;
1699+ const result = await executor . execute (
1700+ "async () => { return await codemode.slow(); }" ,
1701+ fns ,
1702+ ) ;
1703+ expect ( result . result ) . toBe ( "slow result" ) ;
1704+ } ) ;
1705+
1706+ test ( "code without tool calls works with empty fns map" , async ( ) => {
1707+ const executor = new WorkerExecutor ( ) ;
1708+ const result = await executor . execute (
1709+ "async () => { const x = [1,2,3]; return x.map(n => n * 2); }" ,
1710+ { } ,
1711+ ) ;
1712+ expect ( result . result ) . toEqual ( [ 2 , 4 , 6 ] ) ;
1713+ } ) ;
1714+
1715+ test ( "returning nested objects survives structured clone" , async ( ) => {
1716+ const executor = new WorkerExecutor ( ) ;
1717+ const result = await executor . execute (
1718+ `async () => {
1719+ return {
1720+ users: [
1721+ { name: "Alice", scores: [10, 20] },
1722+ { name: "Bob", scores: [30, 40] },
1723+ ],
1724+ meta: { total: 2, nested: { deep: true } },
1725+ };
1726+ }` ,
1727+ { } ,
1728+ ) ;
1729+ expect ( result . error ) . toBeUndefined ( ) ;
1730+ const r = result . result as any ;
1731+ expect ( r . users ) . toHaveLength ( 2 ) ;
1732+ expect ( r . users [ 0 ] . scores ) . toEqual ( [ 10 , 20 ] ) ;
1733+ expect ( r . meta . nested . deep ) . toBe ( true ) ;
1734+ } ) ;
1735+
1736+ test ( "tool call that returns undefined" , async ( ) => {
1737+ const executor = new WorkerExecutor ( ) ;
1738+ const fns = {
1739+ noop : async ( ) => undefined ,
1740+ } ;
1741+ const result = await executor . execute (
1742+ "async () => { const r = await codemode.noop(); return { got: r }; }" ,
1743+ fns ,
1744+ ) ;
1745+ expect ( result . error ) . toBeUndefined ( ) ;
1746+ // undefined doesn't survive structured clone in postMessage
1747+ expect ( ( result . result as any ) . got == null ) . toBe ( true ) ;
1748+ } ) ;
1749+
1750+ test ( "concurrent executions on same WorkerExecutor instance" , async ( ) => {
1751+ const executor = new WorkerExecutor ( ) ;
1752+ const promises = Array . from ( { length : 5 } , ( _ , i ) =>
1753+ executor . execute ( `async () => { return ${ i } * 10; }` , { } ) ,
1754+ ) ;
1755+ const results = await Promise . all ( promises ) ;
1756+ expect ( results . map ( ( r ) => r . result ) ) . toEqual ( [ 0 , 10 , 20 , 30 , 40 ] ) ;
1757+ expect ( results . every ( ( r ) => ! r . error ) ) . toBe ( true ) ;
1758+ } ) ;
1759+
1760+ test ( "error in tool preserves logs captured before the error" , async ( ) => {
1761+ const executor = new WorkerExecutor ( ) ;
1762+ const fns = {
1763+ explode : async ( ) => {
1764+ throw new Error ( "kaboom" ) ;
1765+ } ,
1766+ } ;
1767+ const result = await executor . execute (
1768+ `async () => {
1769+ console.log("step 1");
1770+ console.log("step 2");
1771+ await codemode.explode();
1772+ console.log("step 3");
1773+ }` ,
1774+ fns ,
1775+ ) ;
1776+ expect ( result . error ) . toBe ( "kaboom" ) ;
1777+ expect ( result . logs ) . toContain ( "step 1" ) ;
1778+ expect ( result . logs ) . toContain ( "step 2" ) ;
1779+ expect ( result . logs ) . not . toContain ( "step 3" ) ;
1780+ } ) ;
1781+
1782+ test ( "code that accesses globalThis still works in worker" , async ( ) => {
1783+ const executor = new WorkerExecutor ( ) ;
1784+ const result = await executor . execute (
1785+ "async () => { return typeof globalThis === 'object'; }" ,
1786+ { } ,
1787+ ) ;
1788+ expect ( result . error ) . toBeUndefined ( ) ;
1789+ expect ( result . result ) . toBe ( true ) ;
1790+ } ) ;
1791+
1792+ test ( "handles boolean and string return types" , async ( ) => {
1793+ const executor = new WorkerExecutor ( ) ;
1794+ const r1 = await executor . execute ( "async () => { return true; }" , { } ) ;
1795+ expect ( r1 . result ) . toBe ( true ) ;
1796+ const r2 = await executor . execute ( "async () => { return 'hello'; }" , { } ) ;
1797+ expect ( r2 . result ) . toBe ( "hello" ) ;
1798+ const r3 = await executor . execute ( "async () => { return 0; }" , { } ) ;
1799+ expect ( r3 . result ) . toBe ( 0 ) ;
1800+ } ) ;
16261801} ) ;
0 commit comments