diff --git a/.changeset/pretty-countries-look.md b/.changeset/pretty-countries-look.md new file mode 100644 index 0000000..323f480 --- /dev/null +++ b/.changeset/pretty-countries-look.md @@ -0,0 +1,5 @@ +--- +'@chainlink/functions-toolkit': patch +--- + +Added support for 3rd party imports in the simulator diff --git a/README.md b/README.md index be4f995..beef234 100644 --- a/README.md +++ b/README.md @@ -572,6 +572,17 @@ const result = await simulateScript({ } ``` +Any 3rd party imports used in the JavaScript source code are loaded asynchronously at runtime. Therefore, to use 3rd party imports in the source code that is executed by the `simulateScript` function, you must use the async `import` function as shown in the examples below. + +``` +const { format } = await import("npm:date-fns"); +return Functions.encodeString(format(new Date(), "yyyy-MM-dd")); +``` +``` +const { escape } = await import("https://deno.land/std/regexp/mod.ts"); +return Functions.encodeString(escape("$hello*world?")); +``` + **_NOTE:_** When running `simulateScript`, depending on your security settings, you may get a popup asking if you would like to accept incoming network connections. You can safely accept or ignore this popup and it should disappear when the simulation is complete. **_NOTE:_** The `simulateScript` function is a debugging tool and hence is not a perfect representation of the actual Chainlink oracle execution environment. Therefore, it is important to make a Functions request on a supported testnet blockchain before mainnet usage. diff --git a/src/simulateScript/simulateScript.ts b/src/simulateScript/simulateScript.ts index c5e5473..b8c7aba 100644 --- a/src/simulateScript/simulateScript.ts +++ b/src/simulateScript/simulateScript.ts @@ -86,8 +86,6 @@ export const simulateScript = async ({ const simulation = spawn('deno', [ 'run', '--no-prompt', - '--no-npm', - '--no-remote', `--v8-flags=--max-old-space-size=${maxMemoryUsageMb}`, '--allow-net', scriptPath, diff --git a/test/unit/simulateScript.test.ts b/test/unit/simulateScript.test.ts index 97d409f..13ca43c 100644 --- a/test/unit/simulateScript.test.ts +++ b/test/unit/simulateScript.test.ts @@ -207,21 +207,6 @@ describe('simulateScript', () => { expect(result).toEqual(expected) }) - it('should capture import error', async () => { - const result = await simulateScript({ - source: 'const http = await import("https://deno.land/std/http/mod.ts");', - maxExecutionTimeMs: 100, - }) - - const expected = { - capturedTerminalOutput: '', - errorString: - 'A remote specifier was requested: "https://deno.land/std/http/mod.ts", but --no-remote is specified.', - } - - expect(result).toEqual(expected) - }) - it('should capture permissions error', async () => { const result = await simulateScript({ source: "Deno.openSync('test.txt')", @@ -296,6 +281,28 @@ describe('simulateScript', () => { await expect(result).rejects.toThrow('bytesArgs param contains invalid hex string') }) + + it('should allow 3rd party imports', async () => { + const result = await simulateScript({ + source: + 'const { escape } = await import("https://deno.land/std/regexp/mod.ts"); return Functions.encodeString(escape("$hello*world?"));', + }) + + expect(result.responseBytesHexstring).toEqual( + `0x${Buffer.from('\\$hello\\*world\\?').toString('hex')}`, + ) + }) + + it('should allow NPM imports', async () => { + const result = await simulateScript({ + source: + 'const { format } = await import("npm:date-fns"); return Functions.encodeString(format(new Date(), "yyyy-MM-dd"));', + }) + + expect(Buffer.from(result.responseBytesHexstring?.slice(2) as string, 'hex').length).toEqual( + 10, + ) + }) }) })