Skip to content

Commit

Permalink
ensure snapshots are written when not using types
Browse files Browse the repository at this point in the history
  • Loading branch information
ssalbdivad committed Apr 30, 2023
1 parent accfd3b commit ee7a264
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 55 deletions.
9 changes: 3 additions & 6 deletions dev/attest/src/assertions/assertions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@ import { assertEquals } from "../assertions.js"
import type { AssertionContext } from "../attest.js"
import { caller } from "../main.js"
import type { SnapshotArgs } from "../snapshot.js"
import { getSnapshotByName } from "../snapshot.js"
import { getSnapshotByName, queueSnapshotUpdate } from "../snapshot.js"
import { getTypeDataAtPos } from "../type/getAssertionAtPos.js"
import {
updateExternalSnapshot,
writeInlineSnapshotUpdateToCacheDir
} from "../writeSnapshot.js"
import { updateExternalSnapshot } from "../writeSnapshot.js"
import type { ExternalSnapshotArgs, RootAssertions } from "./types.js"
import {
assertEqualOrMatching,
Expand Down Expand Up @@ -87,7 +84,7 @@ export class Assertions implements AssertionRecord {
position: caller(),
serializedValue: this.serializedActual
}
writeInlineSnapshotUpdateToCacheDir(snapshotArgs)
queueSnapshotUpdate(snapshotArgs)
}
} else {
// compare as strings, but if match fails, compare again as objects
Expand Down
25 changes: 7 additions & 18 deletions dev/attest/src/bench/baseline.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import process from "node:process"
import { snapshot } from "arktype/internal/utils/serialize.js"
import type { QueuedUpdate } from "../snapshot.js"
import { createQueuedSnapshotUpdate } from "../snapshot.js"
import { writeUpdates } from "../writeSnapshot.js"
import { queueSnapshotUpdate } from "../snapshot.js"
import type { BenchAssertionContext, BenchContext } from "./bench.js"
import type {
MarkMeasure,
Expand All @@ -11,8 +9,6 @@ import type {
} from "./measure/measure.js"
import { stringifyMeasure } from "./measure/measure.js"

const queuedUpdates: QueuedUpdate[] = []

export const queueBaselineUpdateIfNeeded = (
updated: Measure | MarkMeasure,
baseline: Measure | MarkMeasure | undefined,
Expand All @@ -28,19 +24,12 @@ export const queueBaselineUpdateIfNeeded = (
`Unable to update baseline for ${ctx.qualifiedName} ('lastSnapCallPosition' was unset).`
)
}
if (queuedUpdates.length === 0) {
process.addListener("exit", () => {
writeUpdates(queuedUpdates)
})
}
queuedUpdates.push(
createQueuedSnapshotUpdate({
position: ctx.lastSnapCallPosition,
serializedValue,
snapFunctionName: ctx.kind,
baselinePath: ctx.qualifiedPath
})
)
queueSnapshotUpdate({
position: ctx.lastSnapCallPosition,
serializedValue,
snapFunctionName: ctx.kind,
baselinePath: ctx.qualifiedPath
})
}

/** Pretty print comparison and set the process.exitCode to 1 if delta threshold is exceeded */
Expand Down
42 changes: 21 additions & 21 deletions dev/attest/src/snapshot.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { randomUUID } from "node:crypto"
import { basename, dirname, isAbsolute, join } from "node:path"
import type { CallExpression, Project, ts } from "ts-morph"
import { SyntaxKind } from "ts-morph"
import { readJson } from "./main.js"
import { getTsMorphProject } from "./type/cacheAssertions.js"
import { getConfig } from "./config.js"
import { readJson, writeJson } from "./main.js"
import { getTsNodeAtPosition } from "./type/getTsNodeAtPos.js"
import type { SourcePosition } from "./utils.js"
import { positionToString } from "./utils.js"
import { writeCachedInlineSnapshotUpdates } from "./writeSnapshot.js"

export type SnapshotArgs = {
position: SourcePosition
Expand All @@ -28,7 +30,7 @@ export const findCallExpressionAncestor = (
const name =
// If the call is made directly, e.g. snap(...), the expression will be an identifier, so can use its whole text
expression.asKind(SyntaxKind.Identifier)?.getText() ??
// If the call is made from a prop, e.g. snap in assert(...).snap(), check the name of the prop accessed
// If the call is made from a prop, e.g. snap in attest(...).snap(), check the name of the prop accessed
expression
.asKind(SyntaxKind.PropertyAccessExpression)
?.getName()
Expand Down Expand Up @@ -64,24 +66,22 @@ export const getSnapshotByName = (
return readJson(snapshotPath)?.[basename(file)]?.[name]
}

export const createQueuedSnapshotUpdate = ({
position,
serializedValue,
snapFunctionName = "snap",
baselinePath
}: SnapshotArgs): QueuedUpdate => {
const snapCall = findCallExpressionAncestor(
getTsMorphProject(),
position,
snapFunctionName
)
const newArgText = JSON.stringify(serializedValue)
return {
position,
snapCall,
snapFunctionName,
newArgText,
baselinePath
let writeCachedUpdatesOnExit = false
process.addListener("exit", () => {
if (writeCachedUpdatesOnExit) {
writeCachedInlineSnapshotUpdates()
}
})

/**
* Writes the update and position to cacheDir, which will eventually be read and copied to the source
* file by a cleanup process after all tests have completed.
*/
export const queueSnapshotUpdate = (args: SnapshotArgs) => {
const config = getConfig()
writeJson(join(config.snapCacheDir, `snap-${randomUUID()}.json`), args)
if (args.baselinePath || config.skipTypes) {
writeCachedUpdatesOnExit = true
}
}

Expand Down
31 changes: 22 additions & 9 deletions dev/attest/src/writeSnapshot.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { randomUUID } from "node:crypto"
import { existsSync, readdirSync } from "node:fs"
import { basename, join } from "node:path"
import type { Node, ts } from "ts-morph"
import { getConfig } from "./config.js"
import { readJson, shell, writeJson } from "./main.js"
import type { QueuedUpdate, SnapshotArgs } from "./snapshot.js"
import { createQueuedSnapshotUpdate, resolveSnapshotPath } from "./snapshot.js"
import { findCallExpressionAncestor, resolveSnapshotPath } from "./snapshot.js"
import { getTsMorphProject } from "./type/cacheAssertions.js"
import { getFileKey } from "./utils.js"

export type ExternalSnapshotArgs = SnapshotArgs & {
Expand Down Expand Up @@ -50,7 +50,7 @@ export const writeCachedInlineSnapshotUpdates = () => {
}
if (snapshotData) {
try {
queuedUpdates.push(createQueuedSnapshotUpdate(snapshotData))
queuedUpdates.push(snapshotArgsToQueuedUpdate(snapshotData))
} catch (error) {
// If writeInlineSnapshotToFile throws an error, log it and move on to the next update
console.error(String(error))
Expand All @@ -61,12 +61,25 @@ export const writeCachedInlineSnapshotUpdates = () => {
writeUpdates(queuedUpdates)
}

/**
* Writes the update and position to cacheDir, which will eventually be read and copied to the source
* file by a cleanup process after all tests have completed.
*/
export const writeInlineSnapshotUpdateToCacheDir = (args: SnapshotArgs) => {
writeJson(join(getConfig().snapCacheDir, `snap-${randomUUID()}.json`), args)
const snapshotArgsToQueuedUpdate = ({
position,
serializedValue,
snapFunctionName = "snap",
baselinePath
}: SnapshotArgs): QueuedUpdate => {
const snapCall = findCallExpressionAncestor(
getTsMorphProject(),
position,
snapFunctionName
)
const newArgText = JSON.stringify(serializedValue)
return {
position,
snapCall,
snapFunctionName,
newArgText,
baselinePath
}
}

// Waiting until process exit to write snapshots avoids invalidating existing source positions
Expand Down
2 changes: 1 addition & 1 deletion dev/attest/test/snapshots.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ describe("bench", () => {
it("populates file", async () => {
const actual = await runThenGetContents(benchActual, benchTemplate)
equal(actual, expectedOutput)
}).timeout(30000)
}).timeout(60000)
})

0 comments on commit ee7a264

Please sign in to comment.