a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
103 lines
4.2 KiB
Go
103 lines
4.2 KiB
Go
package languages
|
|
|
|
import (
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
// DetectJSTSTestRunner classifies the JavaScript / TypeScript test runner
|
|
// driving a file. It is meant to be called by the JS / TS extractors once
|
|
// per file, after imports and call names have been collected from the
|
|
// tree-sitter walk. Returned values:
|
|
//
|
|
// "bun-test" — Bun built-in runner; `import ... from "bun:test"`.
|
|
// "vitest" — Vitest; `import ... from "vitest"`.
|
|
// "playwright" — Playwright Test; `import ... from "@playwright/test"`.
|
|
// "cypress" — Cypress; `import ... from "cypress"`.
|
|
// "node-test" — node:test stdlib runner; `import ... from "node:test"`.
|
|
// "jest" — Jest; `import ... from "@jest/globals"` or
|
|
// `jest`, `jest-mock`, `ts-jest`, etc.
|
|
// "mocha" — Mocha; `import ... from "mocha"`, the TDD
|
|
// `suite()` / `test()` interface, or
|
|
// the BDD `describe` / `it` calls when
|
|
// no other runner imported.
|
|
// "" — No runner signal; caller should not stamp.
|
|
//
|
|
// Detection is import-first (deterministic, low false-positive) with a
|
|
// narrow byte-level fallback for Mocha TDD (`suite(` / `suiteSetup(`),
|
|
// since Mocha's TDD interface uses runner-provided globals with no module
|
|
// import. Plain BDD globals (`describe` / `it`) are claimed by Mocha only
|
|
// when no stronger signal is present and the file name looks like a test
|
|
// file — Jest, Vitest and Bun-test all also use these globals, so we
|
|
// can't disambiguate without a config file.
|
|
func DetectJSTSTestRunner(filePath string, src []byte, importPaths []string) string {
|
|
// Import-driven signals — each maps to a runner with no ambiguity.
|
|
for _, raw := range importPaths {
|
|
p := strings.Trim(raw, "\"'`")
|
|
// Strip any subpath: "vitest/config" → "vitest".
|
|
switch {
|
|
case p == "bun:test":
|
|
return "bun-test"
|
|
case p == "vitest" || strings.HasPrefix(p, "vitest/"):
|
|
return "vitest"
|
|
case p == "@playwright/test" || strings.HasPrefix(p, "@playwright/test/"):
|
|
return "playwright"
|
|
case p == "cypress" || strings.HasPrefix(p, "cypress/"):
|
|
return "cypress"
|
|
case p == "node:test" || strings.HasPrefix(p, "node:test/"):
|
|
return "node-test"
|
|
case p == "@jest/globals" || strings.HasPrefix(p, "@jest/globals/"),
|
|
p == "jest" || strings.HasPrefix(p, "jest/"),
|
|
p == "jest-mock", p == "ts-jest", p == "babel-jest",
|
|
p == "@types/jest":
|
|
return "jest"
|
|
case p == "mocha" || strings.HasPrefix(p, "mocha/"),
|
|
p == "@types/mocha", p == "mochawesome":
|
|
return "mocha"
|
|
}
|
|
}
|
|
|
|
// No explicit import. Fall back to Mocha-TDD byte detection: the TDD
|
|
// interface uses runner-injected globals `suite()` / `test()` /
|
|
// `suiteSetup()` and is not picked up by Jest/Vitest/Bun-test
|
|
// (which use describe/it/test). A top-level `suite(` is a strong
|
|
// Mocha-TDD signal.
|
|
if looksLikeJSTestFile(filePath) && reMochaTDD.Match(src) {
|
|
return "mocha"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// reMochaTDD matches a top-of-line `suite(` or `suiteSetup(` /
|
|
// `suiteTeardown(` call — the Mocha TDD interface entry points. Mocha
|
|
// BDD's `describe` is not used here because Jest/Vitest/Bun-test share
|
|
// it and the regex would produce false positives.
|
|
var reMochaTDD = regexp.MustCompile(`(?m)^\s*(suite|suiteSetup|suiteTeardown)\s*\(`)
|
|
|
|
// looksLikeJSTestFile is a small, dependency-free copy of the JS / TS
|
|
// branches of indexer.IsTestFile. Inlined to avoid the parser → indexer
|
|
// dependency cycle.
|
|
func looksLikeJSTestFile(p string) bool {
|
|
if p == "" {
|
|
return false
|
|
}
|
|
slash := filepath.ToSlash(p)
|
|
for _, marker := range []string{"/__tests__/", "/tests/", "/test/", "/spec/"} {
|
|
if strings.Contains(slash, marker) {
|
|
return true
|
|
}
|
|
}
|
|
if strings.HasPrefix(slash, "tests/") || strings.HasPrefix(slash, "test/") || strings.HasPrefix(slash, "spec/") {
|
|
return true
|
|
}
|
|
base := filepath.Base(slash)
|
|
ext := strings.ToLower(filepath.Ext(base))
|
|
switch ext {
|
|
case ".ts", ".tsx", ".js", ".jsx", ".mts", ".cts", ".mjs", ".cjs":
|
|
stem := strings.TrimSuffix(base, ext)
|
|
return strings.HasSuffix(stem, ".test") || strings.HasSuffix(stem, ".spec")
|
|
}
|
|
return false
|
|
}
|