jestSnapshotSerializer.js•5.09 kB
'use strict'
const path = require('node:path')
const { stripVTControlCharacters } = require('node:util')
const { binaryTargetRegex } = require('./binaryTargetRegex')
// Pipe utility
const pipe =
  (...fns) =>
  (x) =>
    fns.reduce((v, f) => f(v), x)
function normalizePrismaPaths(str) {
  return str
    .replace(/prisma\\([\w-]+)\.prisma/g, 'prisma/$1.prisma')
    .replace(/prisma\\seed\.ts/g, 'prisma/seed.ts')
    .replace(/custom-folder\\seed\.js/g, 'custom-folder/seed.js')
}
function normalizeLogs(str) {
  return str
    .replace(
      /Started query engine http server on http:\/\/127\.0\.0\.1:\d{1,5}/g,
      'Started query engine http server on http://127.0.0.1:00000',
    )
    .replace(/Starting a postgresql pool with \d+ connections./g, 'Starting a postgresql pool with XX connections.')
}
function normalizeTmpDir(str) {
  return str.replace(/\/tmp\/([a-z0-9]+)\//g, '/tmp/dir/')
}
function trimErrorPaths(str) {
  const parentDir = path.dirname(path.dirname(path.dirname(__dirname)))
  return str.replaceAll(parentDir, '')
}
function normalizeToUnixPaths(str) {
  // TODO: Windows: this breaks some tests by replacing backslashes outside of file names.
  return str.replaceAll(path.sep, '/')
}
function normalizeGitHubLinks(str) {
  return str.replace(/https:\/\/github.com\/prisma\/prisma(-client-js)?\/issues\/new\S+/, 'TEST_GITHUB_LINK')
}
function normalizeTsClientStackTrace(str) {
  return str
    .replace(/([/\\]client[/\\]src[/\\]__tests__[/\\].*test\.ts)(:\d*:\d*)/, '$1:0:0')
    .replace(/([/\\]client[/\\]tests[/\\]functional[/\\].*\.ts)(:\d*:\d*)/, '$1:0:0')
}
function removePlatforms(str) {
  return str.replace(binaryTargetRegex, 'TEST_PLATFORM')
}
// When updating snapshots this is sensitive to OS
// macOS will update extension to .dylib.node, but CI uses .so.node for example
// Note that on Windows the file name doesn't start with "lib".
function normalizeNodeApiLibFilePath(str) {
  return str.replace(
    /((lib)?query_engine-TEST_PLATFORM\.)(.*)(\.node)/g,
    'libquery_engine-TEST_PLATFORM.LIBRARY_TYPE.node',
  )
}
function normalizeBinaryFilePath(str) {
  // write a regex expression that matches strings ending with ".exe" followed by any number of space characters with an empty string:
  return str.replace(/\.exe(\s+)?(\W.*)/g, '$1$2').replace(/\.exe$/g, '')
}
function normalizeMigrateTimestamps(str) {
  return str.replace(/(?<!\d)\d{14}(?!\d)/g, '20201231000000')
}
function normalizeDbUrl(str) {
  return str.replace(/(localhost|postgres|mysql|mssql|mongodb_migrate|cockroachdb):(\d+)/g, 'localhost:$2')
}
function normalizeRustError(str) {
  return str.replace(/\/rustc\/(.+)\//g, '/rustc/hash/').replace(/(\[.*)(:\d*:\d*)(\])/g, '[/some/rust/path:0:0$3')
}
function normalizeRustCodeLocation(str) {
  // replaces strings like 'prisma-fmt/src/get_dmmf.rs:17:13' to 'prisma-fmt/src/get_dmmf.rs:0:0'
  return str.replace(/(\w+\.rs):(\d+):(\d+)/g, '$1:0:0')
}
function normalizeArtificialPanic(str) {
  return str.replace(/(Command failed with exit code 101:) (.+) /g, '$1 prisma-engines-path ')
}
function normalizeTime(str) {
  // sometimes something can take a few seconds when usually it's less than 1s or a few ms
  return str.replace(/ \d+ms/g, ' XXXms').replace(/ \d+(\.\d+)?s/g, ' XXXms')
}
/**
 * Replace dynamic variable bits of Prisma schema with static strings.
 * Only for integration-tests
 */
function prepareSchemaForSnapshot(str) {
  if (!str.includes('tmp/prisma-tests/integration-test')) return str
  const urlRegex = /url\s*=\s*.+/
  const outputRegex = /output\s*=\s*.+/
  return str
    .split('\n')
    .map((line) => {
      const urlMatch = urlRegex.exec(line)
      if (urlMatch) {
        return `${line.slice(0, urlMatch.index)}url = "***"`
      }
      const outputMatch = outputRegex.exec(line)
      if (outputMatch) {
        return `${line.slice(0, outputMatch.index)}output = "***"`
      }
      return line
    })
    .join('\n')
}
// needed for jest to correctly handle indentation on multiline snapshot updates
function wrapWithQuotes(str) {
  return `"${str}"`
}
module.exports = {
  // Expected by Jest
  test(value) {
    return typeof value === 'string' || value instanceof Error
  },
  serialize(value) {
    const message = typeof value === 'string' ? value : value instanceof Error ? value.message : ''
    // order is important
    return pipe(
      stripVTControlCharacters,
      // integration-tests pkg
      prepareSchemaForSnapshot,
      // Generic
      normalizeTmpDir,
      normalizeTime,
      // From Client package
      normalizeGitHubLinks,
      removePlatforms,
      normalizeNodeApiLibFilePath,
      normalizeBinaryFilePath,
      normalizeTsClientStackTrace,
      trimErrorPaths,
      normalizePrismaPaths,
      normalizeLogs,
      // remove windows \\
      normalizeToUnixPaths,
      // From Migrate/CLI package
      normalizeDbUrl,
      normalizeRustError,
      normalizeRustCodeLocation,
      normalizeMigrateTimestamps,
      // artificial panic
      normalizeArtificialPanic,
      wrapWithQuotes,
    )(message)
  },
}