diff --git a/testing/unstable_snapshot.ts b/testing/unstable_snapshot.ts index f2be5334e1b2..36c45e93d0b3 100644 --- a/testing/unstable_snapshot.ts +++ b/testing/unstable_snapshot.ts @@ -19,7 +19,15 @@ import { * @experimental **UNSTABLE**: New API, yet to be vetted. */ export interface InlineSnapshotOptions - extends Pick, "msg" | "serializer"> {} + extends Pick, "msg" | "serializer"> { + /** + * Function frame to start backtrace from. + * The source code location to modify will be decided from the stack that comes after this function. + * + * This is only relevant if you are wrapping the call to {@linkcode assertInlineSnapshot}. + */ + frame?: typeof assertInlineSnapshot; +} interface ErrorLocation { lineNumber: number; @@ -169,6 +177,10 @@ globalThis.addEventListener("unload", () => { * * Type parameter can be specified to ensure values under comparison have the same type. * + * This function discovers the caller's source location by doing a stacktrace. + * If you wraps this function, make sure to specifiy the correct frame location in + * {@linkcode InlineSnapshotOptions.frame}. + * * @experimental **UNSTABLE**: New API, yet to be vetted. * * @example Usage @@ -255,7 +267,11 @@ export function assertInlineSnapshot( }; }; // Capture the stack that comes after this function. - Error.captureStackTrace(stackCatcher, assertInlineSnapshot); + Error.captureStackTrace( + stackCatcher, + // Start backtrace from this frame, otherwise the call location will be wrong. + options.frame ?? assertInlineSnapshot, + ); // Forcibly access the stack, and note it down const request = stackCatcher.stack; if (request !== null) { @@ -303,12 +319,14 @@ export function createAssertInlineSnapshot( options: InlineSnapshotOptions, baseAssertSnapshot: typeof assertInlineSnapshot = assertInlineSnapshot, ): typeof assertInlineSnapshot { - return function ( + return function frame( actual: T, expectedSnapshot: string, messageOrOptions?: string | InlineSnapshotOptions, ) { const mergedOptions: InlineSnapshotOptions = { + // Ordering matters here to allow outer options overriding frame. + frame, ...options, ...(typeof messageOrOptions === "string" ? { msg: messageOrOptions } diff --git a/testing/unstable_snapshot_test.ts b/testing/unstable_snapshot_test.ts index ab3e6e0a1a2f..1f7cadcb3f80 100644 --- a/testing/unstable_snapshot_test.ts +++ b/testing/unstable_snapshot_test.ts @@ -151,7 +151,7 @@ Deno.test("assertInlineSnapshot() counts lines and columns like V8", async () => await Deno.writeTextFile( countTestFile, `import { assertInlineSnapshot } from "${SNAPSHOT_MODULE_URL}"; - \n \r \n\r \r\n \u2028 \u2029 + \n \r \n\r \r\n \u2028 \u2029\u0020 Deno.test("format", async () => { /* 🐈‍⬛🇦🇶 */ assertInlineSnapshot( "hello world", "" ); });`, @@ -174,7 +174,7 @@ Deno.test("format", async () => { assertEquals( await Deno.readTextFile(countTestFile), `import { assertInlineSnapshot } from "${SNAPSHOT_MODULE_URL}"; - \n \r \n\r \r\n \u2028 \u2029 + \n \r \n\r \r\n \u2028 \u2029\u0020 Deno.test("format", async () => { /* 🐈‍⬛🇦🇶 */ assertInlineSnapshot( "hello world", \`"hello world"\` ); });`, @@ -193,3 +193,49 @@ Deno.test("createAssertInlineSnapshot()", () => { `This green text has had its colors stripped`, ); }); + +Deno.test("createAssertInlineSnapshot() writes to the correct location", async () => { + if (!LINT_SUPPORTED) return; + + const tempDir = await Deno.makeTempDir(); + const testFile = join(tempDir, "create_test.ts"); + try { + await Deno.writeTextFile( + testFile, + `import { createAssertInlineSnapshot } from "${SNAPSHOT_MODULE_URL}"; + +const assertInlineSnapshot = createAssertInlineSnapshot({}); + +Deno.test("format", () => { + assertInlineSnapshot( "hello world", "" ); +});`, + ); + + const command = new Deno.Command(Deno.execPath(), { + args: [ + "test", + "--no-lock", + "--allow-read", + "--allow-write", + tempDir, + "--", + "--update", + "--no-format", + ], + }); + await command.output(); + + assertEquals( + await Deno.readTextFile(testFile), + `import { createAssertInlineSnapshot } from "${SNAPSHOT_MODULE_URL}"; + +const assertInlineSnapshot = createAssertInlineSnapshot({}); + +Deno.test("format", () => { + assertInlineSnapshot( "hello world", \`"hello world"\` ); +});`, + ); + } finally { + await Deno.remove(tempDir, { recursive: true }); + } +});