Home / Function/ test() — tailwindcss Function Reference

test() — tailwindcss Function Reference

Architecture documentation for the test() function in utils.ts from the tailwindcss codebase.

Entity Profile

Dependency Diagram

graph TD
  323920ab_ae9d_fcbf_30d4_edccd93f84b9["test()"]
  c86c847a_8130_6f75_8a62_c27d00e8e252["overwriteVersionsInPackageJson()"]
  323920ab_ae9d_fcbf_30d4_edccd93f84b9 -->|calls| c86c847a_8130_6f75_8a62_c27d00e8e252
  dc20bda5_e334_9ff7_d816_63cc049e6e0b["retryAssertion()"]
  323920ab_ae9d_fcbf_30d4_edccd93f84b9 -->|calls| dc20bda5_e334_9ff7_d816_63cc049e6e0b
  4e38a30e_dedd_1ec9_f7cb_f8f0d30d2961["gracefullyRemove()"]
  323920ab_ae9d_fcbf_30d4_edccd93f84b9 -->|calls| 4e38a30e_dedd_1ec9_f7cb_f8f0d30d2961
  style 323920ab_ae9d_fcbf_30d4_edccd93f84b9 fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

integrations/utils.ts lines 81–456

export function test(
  name: string,
  config: TestConfig,
  testCallback: TestCallback,
  { only = false, skip = false, debug = false }: TestFlags = {},
) {
  return defaultTest(
    name,
    {
      timeout: config.timeout ?? TEST_TIMEOUT,
      retry: process.env.CI ? 2 : 0,
      only: only || (!process.env.CI && debug),
      skip,
      concurrent: true,
    },
    async (options) => {
      let rootDir = debug ? path.join(REPO_ROOT, '.debug') : TMP_ROOT
      await fs.mkdir(rootDir, { recursive: true })

      let root = await fs.mkdtemp(path.join(rootDir, 'tailwind-integrations'))

      if (debug) {
        console.log('Running test in debug mode. File system will be written to:')
        console.log(root)
        console.log()
      }

      let context = {
        root,
        expect: options.expect,
        parseSourceMap,
        async exec(
          command: string,
          childProcessOptions: ChildProcessOptions = {},
          execOptions: ExecOptions = {},
        ) {
          let cwd = childProcessOptions.cwd ?? root
          if (debug && cwd !== root) {
            let relative = path.relative(root, cwd)
            if (relative[0] !== '.') relative = `./${relative}`
            console.log(`> cd ${relative}`)
          }
          if (debug) console.log(`> ${command}`)
          return new Promise((resolve, reject) => {
            let child = exec(
              command,
              {
                cwd,
                ...childProcessOptions,
                env: {
                  ...process.env,
                  ...childProcessOptions.env,
                },
              },
              (error, stdout, stderr) => {
                if (error) {
                  if (execOptions.ignoreStdErr !== true) console.error(stderr)
                  if (only || debug) {
                    console.error(stdout)
                  }
                  reject(error)
                } else {
                  if (only || debug) {
                    console.log(stdout.toString() + '\n\n' + stderr.toString())
                  }
                  resolve(stdout.toString() + '\n\n' + stderr.toString())
                }
              },
            )
            if (execOptions.stdin) {
              child.stdin?.write(execOptions.stdin)
              child.stdin?.end()
            }
          })
        },
        async spawn(command: string, childProcessOptions: ChildProcessOptions = {}) {
          let resolveDisposal: (() => void) | undefined
          let rejectDisposal: ((error: Error) => void) | undefined
          let disposePromise = new Promise<void>((resolve, reject) => {
            resolveDisposal = resolve
            rejectDisposal = reject
          })

          let cwd = childProcessOptions.cwd ?? root
          if (debug && cwd !== root) {
            let relative = path.relative(root, cwd)
            if (relative[0] !== '.') relative = `./${relative}`
            console.log(`> cd ${relative}`)
          }
          if (debug) console.log(`>& ${command}`)
          let child = spawn(command, {
            cwd,
            shell: true,
            ...childProcessOptions,
            env: {
              ...process.env,
              ...childProcessOptions.env,
            },
          })

          function dispose() {
            if (!child.kill()) {
              child.kill('SIGKILL')
            }

            let timer = setTimeout(
              () =>
                rejectDisposal?.(new Error(`spawned process (${command}) did not exit in time`)),
              ASSERTION_TIMEOUT,
            )
            disposePromise.finally(() => {
              clearTimeout(timer)
            })
            return disposePromise
          }
          disposables.push(dispose)
          function onExit() {
            resolveDisposal?.()
          }

          let stdoutMessages: string[] = []
          let stderrMessages: string[] = []

          let stdoutActors: SpawnActor[] = []
          let stderrActors: SpawnActor[] = []

          function notifyNext(actors: SpawnActor[], messages: string[]) {
            if (actors.length <= 0) return
            let [next] = actors

            for (let [idx, message] of messages.entries()) {
              if (next.predicate(message)) {
                messages.splice(0, idx + 1)
                let actorIdx = actors.indexOf(next)
                actors.splice(actorIdx, 1)
                next.resolve()
                break
              }
            }
          }

          let combined: ['stdout' | 'stderr', string][] = []

          child.stdout.on('data', (result) => {
            let content = result.toString()
            if (debug || only) console.log(content)
            combined.push(['stdout', content])
            for (let line of content.split('\n')) {
              stdoutMessages.push(stripVTControlCharacters(line))
            }
            notifyNext(stdoutActors, stdoutMessages)
          })
          child.stderr.on('data', (result) => {
            let content = result.toString()
            if (debug || only) console.error(content)
            combined.push(['stderr', content])
            for (let line of content.split('\n')) {
              stderrMessages.push(stripVTControlCharacters(line))
            }
            notifyNext(stderrActors, stderrMessages)
          })
          child.on('exit', onExit)
          child.on('error', (error) => {
            if (error.name !== 'AbortError') {
              throw error
            }
          })

          options.onTestFailed(() => {
            // In only or debug mode, messages are logged to the console
            // immediately.
            if (only || debug) return

            for (let [type, message] of combined) {
              if (type === 'stdout') {
                console.log(message)
              } else {
                console.error(message)
              }
            }
          })

          return {
            dispose,
            flush() {
              stdoutActors.splice(0)
              stderrActors.splice(0)

              stdoutMessages.splice(0)
              stderrMessages.splice(0)
            },
            onStdout(predicate: (message: string) => boolean) {
              return new Promise<void>((resolve) => {
                stdoutActors.push({ predicate, resolve })
                notifyNext(stdoutActors, stdoutMessages)
              })
            },
            onStderr(predicate: (message: string) => boolean) {
              return new Promise<void>((resolve) => {
                stderrActors.push({ predicate, resolve })
                notifyNext(stderrActors, stderrMessages)
              })
            },
          }
        },
        fs: {
          async write(
            filename: string,
            content: string | Uint8Array,
            encoding: BufferEncoding = 'utf8',
          ): Promise<void> {
            let full = path.join(root, filename)
            let dir = path.dirname(full)
            await fs.mkdir(dir, { recursive: true })

            if (typeof content !== 'string') {
              return await fs.writeFile(full, content)
            }

            if (filename.endsWith('package.json')) {
              content = await overwriteVersionsInPackageJson(content)
            }

            // Ensure that files written on Windows use \r\n line ending
            if (IS_WINDOWS) {
              content = content.replace(/\n/g, '\r\n')
            }

            await fs.writeFile(full, content, encoding)
          },

          async create(filenames: string[]): Promise<void> {
            for (let filename of filenames) {
              let full = path.join(root, filename)

              let dir = path.dirname(full)
              await fs.mkdir(dir, { recursive: true })
              await fs.writeFile(full, '')
            }
          },

          async read(filePath: string) {
            let content = await fs.readFile(path.resolve(root, filePath), 'utf8')

            // Ensure that files read on Windows have \r\n line endings removed
            if (IS_WINDOWS) {
              content = content.replace(/\r\n/g, '\n')
            }

            return content
          },
          async glob(pattern: string) {
            let files = await fastGlob(pattern, { cwd: root })
            return Promise.all(
              files.map(async (file) => {
                let content = await fs.readFile(path.join(root, file), 'utf8')
                return [
                  file,
                  // Drop license comment
                  content.replace(/[\s\n]*\/\*![\s\S]*?\*\/[\s\n]*/g, ''),
                ]
              }),
            )
          },
          async dumpFiles(pattern: string) {
            let files = await context.fs.glob(pattern)
            return `\n${files
              .slice()
              .sort((a: [string], z: [string]) => {
                let aParts = a[0].split('/')
                let zParts = z[0].split('/')

                let aFile = aParts.at(-1)
                let zFile = zParts.at(-1)

                // Sort by depth, shallow first
                if (aParts.length < zParts.length) return -1
                if (aParts.length > zParts.length) return 1

                // Sort by folder names, alphabetically
                for (let i = 0; i < aParts.length - 1; i++) {
                  let diff = aParts[i].localeCompare(zParts[i])
                  if (diff !== 0) return diff
                }

                // Sort by filename, sort files named `index` before others
                if (aFile?.startsWith('index') && !zFile?.startsWith('index')) return -1
                if (zFile?.startsWith('index') && !aFile?.startsWith('index')) return 1

                // Sort by filename, alphabetically
                return a[0].localeCompare(z[0])
              })
              .map(([file, content]) => `--- ${file} ---\n${content || '<EMPTY>'}`)
              .join('\n\n')
              .trim()}\n`
          },
          async expectFileToContain(filePath, contents) {
            return retryAssertion(async () => {
              let fileContent = await this.read(filePath)
              for (let content of Array.isArray(contents) ? contents : [contents]) {
                if (content instanceof RegExp) {
                  options.expect(fileContent).toMatch(content)
                } else {
                  options.expect(fileContent).toContain(content)
                }
              }
            })
          },
          async expectFileNotToContain(filePath, contents) {
            return retryAssertion(async () => {
              let fileContent = await this.read(filePath)
              for (let content of contents) {
                options.expect(fileContent).not.toContain(content)
              }
            })
          },
        },
      } satisfies TestContext

      config.fs['.gitignore'] ??= txt`
        node_modules/
      `

      for (let [filename, content] of Object.entries(config.fs)) {
        await context.fs.write(filename, content)
      }

      let shouldInstallDependencies = config.installDependencies ?? true

      try {
        // In debug mode, the directory is going to be inside the pnpm workspace
        // of the tailwindcss package. This means that `pnpm install` will run
        // pnpm install on the workspace instead (expect if the root dir defines
        // a separate workspace). We work around this by using the
        // `--ignore-workspace` flag.
        if (shouldInstallDependencies) {
          let ignoreWorkspace = debug && !config.fs['pnpm-workspace.yaml']
          await context.exec(`pnpm install${ignoreWorkspace ? ' --ignore-workspace' : ''}`)
        }
      } catch (error: any) {
        console.error(error)
        console.error(error.stdout?.toString())
        console.error(error.stderr?.toString())
        throw error
      }

      let disposables: (() => Promise<void>)[] = []

      async function dispose() {
        await Promise.all(disposables.map((dispose) => dispose()))

        if (!debug) {
          await gracefullyRemove(root)
        }
      }

      options.onTestFinished(dispose)

      // Make it a git repository, and commit all files
      if (only || debug) {
        try {
          await context.exec('git init', { cwd: root })
          await context.exec('git add --all', { cwd: root })
          await context.exec('git commit -m "before migration"', { cwd: root })
        } catch (error: any) {
          console.error(error)
          console.error(error.stdout?.toString())
          console.error(error.stderr?.toString())
          throw error
        }
      }

      return await testCallback(context)
    },
  )
}

Domain

Subdomains

Frequently Asked Questions

What does test() do?
test() is a function in the tailwindcss codebase.
What does test() call?
test() calls 3 function(s): gracefullyRemove, overwriteVersionsInPackageJson, retryAssertion.

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free