@rpcbase/test 0.308.0 → 0.310.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/clearDatabase.d.ts +2 -0
  2. package/dist/clearDatabase.d.ts.map +1 -0
  3. package/dist/clearDatabase.js +12 -0
  4. package/dist/clearDatabase.js.map +1 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +785 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/coverage/collect.d.ts +5 -0
  10. package/dist/coverage/collect.d.ts.map +1 -0
  11. package/dist/coverage/collect.js +113 -0
  12. package/dist/coverage/collect.js.map +1 -0
  13. package/dist/coverage/config-loader.d.ts +11 -0
  14. package/dist/coverage/config-loader.d.ts.map +1 -0
  15. package/dist/coverage/config-loader.js +292 -0
  16. package/dist/coverage/config-loader.js.map +1 -0
  17. package/dist/coverage/config.d.ts +3 -0
  18. package/dist/coverage/config.d.ts.map +1 -0
  19. package/dist/coverage/config.js +110 -0
  20. package/dist/coverage/config.js.map +1 -0
  21. package/dist/coverage/files.d.ts +4 -0
  22. package/dist/coverage/files.d.ts.map +1 -0
  23. package/dist/coverage/files.js +52 -0
  24. package/dist/coverage/files.js.map +1 -0
  25. package/dist/coverage/fixtures.d.ts +5 -0
  26. package/dist/coverage/fixtures.d.ts.map +1 -0
  27. package/dist/coverage/fixtures.js +42 -0
  28. package/dist/coverage/fixtures.js.map +1 -0
  29. package/dist/coverage/global-setup.d.ts +3 -0
  30. package/dist/coverage/global-setup.d.ts.map +1 -0
  31. package/dist/coverage/global-setup.js +18 -0
  32. package/dist/coverage/global-setup.js.map +1 -0
  33. package/dist/coverage/index.d.ts +10 -0
  34. package/dist/coverage/index.d.ts.map +1 -0
  35. package/dist/coverage/index.js +62 -0
  36. package/dist/coverage/index.js.map +1 -0
  37. package/dist/coverage/report.d.ts +7 -0
  38. package/dist/coverage/report.d.ts.map +1 -0
  39. package/{src → dist}/coverage/report.js +262 -362
  40. package/dist/coverage/report.js.map +1 -0
  41. package/dist/coverage/reporter.d.ts +16 -0
  42. package/dist/coverage/reporter.d.ts.map +1 -0
  43. package/dist/coverage/reporter.js +57 -0
  44. package/dist/coverage/reporter.js.map +1 -0
  45. package/dist/coverage/types.d.ts +47 -0
  46. package/dist/coverage/types.d.ts.map +1 -0
  47. package/dist/coverage/v8-tracker.d.ts +6 -0
  48. package/dist/coverage/v8-tracker.d.ts.map +1 -0
  49. package/dist/coverage/v8-tracker.js +166 -0
  50. package/dist/coverage/v8-tracker.js.map +1 -0
  51. package/dist/defineConfig.d.ts +3 -0
  52. package/dist/defineConfig.d.ts.map +1 -0
  53. package/dist/index.d.ts +11 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +61 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/serverCoverage.d.ts +8 -0
  58. package/dist/serverCoverage.d.ts.map +1 -0
  59. package/dist/serverCoverage.js +42 -0
  60. package/dist/serverCoverage.js.map +1 -0
  61. package/dist/vitest.config.d.ts +3 -0
  62. package/dist/vitest.config.d.ts.map +1 -0
  63. package/dist/vitest.config.js +83 -0
  64. package/dist/vitest.config.js.map +1 -0
  65. package/package.json +25 -14
  66. package/index.d.ts +0 -64
  67. package/src/clearDatabase.js +0 -19
  68. package/src/cli.js +0 -948
  69. package/src/coverage/collect.js +0 -134
  70. package/src/coverage/config-loader.js +0 -202
  71. package/src/coverage/config.js +0 -134
  72. package/src/coverage/files.js +0 -55
  73. package/src/coverage/fixtures.js +0 -37
  74. package/src/coverage/global-setup.js +0 -19
  75. package/src/coverage/index.js +0 -30
  76. package/src/coverage/reporter.js +0 -65
  77. package/src/coverage/v8-tracker.js +0 -205
  78. package/src/defineConfig.js +0 -129
  79. package/src/index.js +0 -49
  80. package/src/vitest.config.mjs +0 -107
  81. /package/{src → dist}/register-tty.cjs +0 -0
@@ -1,205 +0,0 @@
1
- import fs from "node:fs/promises"
2
- import path from "node:path"
3
-
4
- import { isInsideAnyRoot, resolveCollectCoverageRoots } from "./collect.js"
5
-
6
-
7
- const VITE_FS_PREFIX = "/@fs/"
8
-
9
- function sanitizePathSegment(input) {
10
- const value = String(input ?? "").trim()
11
- return value.replace(/[^a-zA-Z0-9._-]+/g, "_") || "unknown"
12
- }
13
-
14
- function urlPathLooksLikeFile(pathname) {
15
- const base = path.posix.basename(String(pathname ?? ""))
16
- return base.length > 0 && base.includes(".")
17
- }
18
-
19
- export async function createCoverageTracker(page, config) {
20
- const session = await page.context().newCDPSession(page)
21
- const scriptMeta = new Map()
22
- const sourceCache = new Map()
23
- const scriptRoots = resolveCollectCoverageRoots(config.collectCoverageFrom, config.rootDir)
24
-
25
- await session.send("Debugger.enable")
26
- session.on("Debugger.scriptParsed", (event) => {
27
- if (!event.url) {
28
- return
29
- }
30
-
31
- const normalized = normalizeScriptUrl(event.url, config)
32
- const trackable = normalized
33
- && !isNodeModulesPath(normalized.absolutePath)
34
- && isInsideAnyRoot(normalized.absolutePath, scriptRoots)
35
-
36
- scriptMeta.set(event.scriptId, {
37
- normalized: trackable ? normalized : null,
38
- url: event.url,
39
- })
40
- })
41
-
42
- await session.send("Profiler.enable")
43
- await session.send("Profiler.startPreciseCoverage", { callCount: false, detailed: true })
44
-
45
- return {
46
- async stop(testInfo) {
47
- try {
48
- const payload = await collectCoveragePayload(session, scriptMeta, sourceCache, testInfo, config)
49
-
50
- if (payload.scripts.length === 0) {
51
- return
52
- }
53
-
54
- const outputFile = resolveCoverageOutputFile(config, testInfo)
55
- await fs.mkdir(path.dirname(outputFile), { recursive: true })
56
- await fs.writeFile(outputFile, JSON.stringify(payload, null, 2), "utf8")
57
- } finally {
58
- await shutdownSession(session)
59
- }
60
- },
61
- }
62
- }
63
-
64
- function resolveCoverageOutputFile(config, testInfo) {
65
- const projectName = sanitizePathSegment(testInfo.project?.name)
66
- const testId = sanitizePathSegment(testInfo.testId)
67
- const outputDir = path.join(config.testResultsRoot, "playwright", projectName, testId)
68
- return path.join(outputDir, config.coverageFileName)
69
- }
70
-
71
- async function collectCoveragePayload(session, scriptMeta, sourceCache, testInfo, config) {
72
- const { result } = await session.send("Profiler.takePreciseCoverage")
73
- await session.send("Profiler.stopPreciseCoverage")
74
-
75
- const scripts = []
76
-
77
- for (const script of result) {
78
- const meta = scriptMeta.get(script.scriptId)
79
- if (!meta || !meta.normalized) {
80
- continue
81
- }
82
-
83
- const source = await resolveScriptSource(session, sourceCache, script.scriptId)
84
- scripts.push({
85
- absolutePath: meta.normalized.absolutePath,
86
- relativePath: meta.normalized.relativePath,
87
- source,
88
- functions: script.functions,
89
- url: meta.url,
90
- })
91
- }
92
-
93
- return {
94
- testId: testInfo.titlePath.join(" › "),
95
- scripts,
96
- }
97
- }
98
-
99
- async function resolveScriptSource(session, cache, scriptId) {
100
- const cached = cache.get(scriptId)
101
- if (cached) {
102
- return cached
103
- }
104
-
105
- const promise = fetchScriptSource(session, scriptId)
106
- cache.set(scriptId, promise)
107
- return promise
108
- }
109
-
110
- async function fetchScriptSource(session, scriptId) {
111
- try {
112
- const sourceResponse = await session.send("Debugger.getScriptSource", { scriptId })
113
- return sourceResponse?.scriptSource ?? ""
114
- } catch (error) {
115
- const message = String(error?.message ?? error)
116
- if (message.includes("Debugger agent is not enabled")) {
117
- try {
118
- await session.send("Debugger.enable")
119
- const sourceResponse = await session.send("Debugger.getScriptSource", { scriptId })
120
- return sourceResponse?.scriptSource ?? ""
121
- } catch {
122
- return ""
123
- }
124
- }
125
-
126
- return ""
127
- }
128
- }
129
-
130
- async function shutdownSession(session) {
131
- await Promise.allSettled([
132
- session.send("Profiler.stopPreciseCoverage").catch(() => undefined),
133
- session.send("Profiler.disable").catch(() => undefined),
134
- session.send("Debugger.disable").catch(() => undefined),
135
- ])
136
- await session.detach().catch(() => undefined)
137
- }
138
-
139
- function normalizeScriptUrl(rawUrl, config) {
140
- if (!rawUrl || rawUrl.startsWith("node:")) {
141
- return null
142
- }
143
-
144
- const cleaned = stripQuery(rawUrl)
145
- let pathname = cleaned
146
-
147
- try {
148
- const parsed = new URL(cleaned)
149
- pathname = parsed.pathname
150
- } catch {
151
- // keep as-is for relative paths
152
- }
153
-
154
- if (!pathname) {
155
- return null
156
- }
157
-
158
- let absolutePath
159
-
160
- const decoded = decodeURIComponent(pathname)
161
- if (decoded.startsWith(VITE_FS_PREFIX)) {
162
- absolutePath = path.normalize(decoded.slice(VITE_FS_PREFIX.length))
163
- } else if (decoded.startsWith("/")) {
164
- if (!urlPathLooksLikeFile(decoded)) {
165
- return null
166
- }
167
- absolutePath = path.resolve(process.cwd(), `.${decoded}`)
168
- } else {
169
- return null
170
- }
171
-
172
- return createNormalizedPath(absolutePath, config.rootDir)
173
- }
174
-
175
- function createNormalizedPath(absolutePath, rootDir) {
176
- const normalizedAbsolute = path.normalize(absolutePath)
177
- const relativePath = path.relative(rootDir, normalizedAbsolute)
178
- return {
179
- absolutePath: normalizedAbsolute,
180
- relativePath,
181
- }
182
- }
183
-
184
- function stripQuery(url) {
185
- const queryIndex = url.indexOf("?")
186
- const hashIndex = url.indexOf("#")
187
-
188
- const endIndex = Math.min(
189
- queryIndex === -1 ? Number.POSITIVE_INFINITY : queryIndex,
190
- hashIndex === -1 ? Number.POSITIVE_INFINITY : hashIndex,
191
- )
192
-
193
- if (!Number.isFinite(endIndex)) {
194
- return url
195
- }
196
-
197
- return url.slice(0, endIndex)
198
- }
199
-
200
- function isNodeModulesPath(filePath) {
201
- return path
202
- .normalize(String(filePath ?? ""))
203
- .split(path.sep)
204
- .includes("node_modules")
205
- }
@@ -1,129 +0,0 @@
1
- import fs from "fs"
2
- import path from "path"
3
- import { fileURLToPath } from "url"
4
- import { cpus } from "os"
5
-
6
- import _ from "lodash"
7
- import { defineConfig, devices } from "@playwright/test"
8
-
9
-
10
- function mergeConfig(base, override) {
11
- return _.merge({}, base, override)
12
- }
13
-
14
- function getCallerConfigDir() {
15
- const stack = new Error().stack?.split("\n") ?? []
16
- const frame = stack.find(line =>
17
- line.includes("playwright.config") &&
18
- !line.includes("defineConfig.js")
19
- )
20
- if (!frame) return null
21
- const match = frame.match(/(file:[^):]+|\/[^):]+):\d+:\d+/)
22
- if (!match) return null
23
- return path.dirname(fileURLToPath(match[1]))
24
- }
25
-
26
- const hasPassedAllPreviousTests = (data) => {
27
- function checkSuite(suite) {
28
- if (suite.specs && suite.specs.length > 0) {
29
- for (const spec of suite.specs) {
30
- if (!checkSpec(spec)) return false
31
- }
32
- }
33
- if (suite.suites && suite.suites.length > 0) {
34
- for (const innerSuite of suite.suites) {
35
- if (!checkSuite(innerSuite)) return false
36
- }
37
- }
38
- return true
39
- }
40
-
41
- function checkSpec(spec) {
42
- if (spec.tests && spec.tests.length > 0) {
43
- for (const test of spec.tests) {
44
- if (!checkTest(test)) return false
45
- }
46
- }
47
- return true
48
- }
49
-
50
- function checkTest(test) {
51
- if (test.results && test.results.length > 0) {
52
- for (const result of test.results) {
53
- if (!["passed", "skipped"].includes(result.status)) return false
54
- }
55
- }
56
- return true
57
- }
58
-
59
- if (data.suites && data.suites.length > 0) {
60
- for (const suite of data.suites) {
61
- if (!checkSuite(suite)) return false
62
- }
63
- }
64
-
65
- return true
66
- }
67
-
68
-
69
- const isHeadless = () => {
70
- if (process.env.CI) return true
71
- try {
72
- const lastResults = JSON.parse(fs.readFileSync("./build/playwright/results.json", "utf8"))
73
- const hasPassed = hasPassedAllPreviousTests(lastResults)
74
- return hasPassed
75
- } catch (_err) {
76
- // console.log("Error reading last results", err)
77
- // Default to show if no previous results or error reading file
78
- return false
79
- }
80
- }
81
-
82
-
83
- // https://playwright.dev/docs/test-configuration
84
- export default function(config) {
85
- const expected = getCallerConfigDir()
86
- if (expected && process.cwd() !== expected) {
87
- throw new Error(
88
- `Playwright must be run from ${expected}. Current cwd: ${process.cwd()}.`
89
- )
90
- }
91
-
92
- const baseConfig = {
93
- globalSetup: ["./spec/helpers/globalSetup.ts"],
94
- testDir: "./build/spec",
95
- fullyParallel: false,
96
- /* Fail the build on CI if you accidentally left test.only in the source code. */
97
- forbidOnly: !!process.env.CI,
98
- /* Retry on CI only */
99
- retries: process.env.CI ? 4 : 0,
100
- /* Opt out of parallel tests on CI. */
101
- workers: process.env.CI ? 1 : cpus().length,
102
- /* Reporter to use. See https://playwright.dev/docs/test-reporters */
103
- reporter: [
104
- ["html", {open: "never", outputFolder: "./build/playwright/report"}],
105
- ["blob", {outputFile: "./build/playwright/blob"}],
106
- ["list", {outputFile: "./build/playwright/results.txt"}],
107
- ["json", { outputFile: "./build/playwright/results.json" }]
108
- ],
109
- outputDir: "./build/playwright/test-results",
110
- /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
111
- use: {
112
- baseURL: "http://localhost:8080",
113
- /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
114
- trace: "on",
115
- video: "on",
116
- launchOptions: {
117
- headless: isHeadless(),
118
- },
119
- },
120
- projects: [
121
- {
122
- name: "chromium",
123
- use: { ...devices["Desktop Chrome"] },
124
- },
125
- ],
126
- }
127
-
128
- return defineConfig(mergeConfig(baseConfig, config))
129
- }
package/src/index.js DELETED
@@ -1,49 +0,0 @@
1
- import { test as baseTest, expect as baseExpect, defineConfig as playwrightDefineConfig, devices } from "@playwright/test"
2
-
3
- import { loadCoverageOptions } from "./coverage/config-loader.js"
4
- import { createCoverageHarness } from "./coverage/index.js"
5
-
6
-
7
- export { clearDatabase } from "./clearDatabase.js"
8
- export * from "./coverage/index.js"
9
-
10
- const coverageOptions = await loadCoverageOptions({ optional: true })
11
- const coverageHarness = coverageOptions ? createCoverageHarness(coverageOptions) : null
12
- export const test = coverageHarness ? coverageHarness.extendTest(baseTest) : baseTest
13
- export const expect = baseExpect
14
- export { devices }
15
-
16
- export function defineConfig(userConfig = {}) {
17
- const normalized = { ...userConfig }
18
- const reporters = ensureReporterArray(normalized.reporter)
19
-
20
- if (coverageHarness?.config.coverageEnabled && process.env.RB_TEST_COMBINED_COVERAGE !== "1") {
21
- const coverageReporter = coverageHarness.reporterEntry()
22
- if (!reporters.some(([name]) => name === coverageReporter[0])) {
23
- reporters.push(coverageReporter)
24
- }
25
- }
26
-
27
- normalized.reporter = reporters
28
-
29
- return playwrightDefineConfig(normalized)
30
- }
31
-
32
- function ensureReporterArray(reporter) {
33
- if (!reporter) {
34
- return [["list"]]
35
- }
36
-
37
- if (!Array.isArray(reporter)) {
38
- return [normalizeReporterEntry(reporter)]
39
- }
40
-
41
- return reporter.map((entry) => normalizeReporterEntry(entry))
42
- }
43
-
44
- function normalizeReporterEntry(entry) {
45
- if (Array.isArray(entry)) {
46
- return entry
47
- }
48
- return [entry]
49
- }
@@ -1,107 +0,0 @@
1
- import path from "node:path"
2
- import fs from "node:fs"
3
- import { createRequire } from "node:module"
4
-
5
- import { defineConfig } from "vitest/config"
6
-
7
-
8
- const require = createRequire(import.meta.url)
9
-
10
- function escapeRegex(str) {
11
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
12
- }
13
-
14
- function loadTsconfig() {
15
- let ts
16
- try {
17
- ts = require("typescript")
18
- } catch (_err) {
19
- throw new Error(
20
- "@rpcbase/test: TypeScript is required to resolve path aliases. Please add it as a devDependency.",
21
- )
22
- }
23
-
24
- const cwd = process.cwd()
25
- const configPath =
26
- ts.findConfigFile(cwd, ts.sys.fileExists, "tsconfig.json") ||
27
- ts.findConfigFile(cwd, ts.sys.fileExists, "tsconfig.base.json")
28
-
29
- if (!configPath) {
30
- throw new Error("@rpcbase/test: no tsconfig found for alias resolution")
31
- }
32
-
33
- const configFile = ts.readConfigFile(configPath, ts.sys.readFile)
34
- if (configFile.error) {
35
- throw new Error(`@rpcbase/test: unable to read tsconfig at ${configPath}`)
36
- }
37
-
38
- const parsed = ts.parseJsonConfigFileContent(
39
- configFile.config,
40
- ts.sys,
41
- path.dirname(configPath),
42
- )
43
-
44
- return {
45
- path: configPath,
46
- baseUrl: parsed.options?.baseUrl
47
- ? path.resolve(path.dirname(configPath), parsed.options.baseUrl)
48
- : path.dirname(configPath),
49
- paths: parsed.options?.paths,
50
- }
51
- }
52
-
53
- function pathsToAlias(tsconfig) {
54
- const paths = tsconfig?.paths
55
- if (!paths) return []
56
-
57
- const baseUrl = tsconfig.baseUrl || path.dirname(tsconfig.path)
58
- const alias = []
59
-
60
- for (const [key, targets] of Object.entries(paths)) {
61
- if (!Array.isArray(targets)) continue
62
-
63
- for (const target of targets) {
64
- if (key.includes("*") && target.includes("*")) {
65
- const wildcardPattern = target.endsWith("*") ? "(.+)" : "([^/]+)"
66
- const find = new RegExp(
67
- `^${escapeRegex(key).split("\\*").join(wildcardPattern)}$`,
68
- )
69
- let groupIndex = 0
70
- const replacedTarget = target.replace(/\*/g, () => `$${++groupIndex}`)
71
- const replacement = path.resolve(baseUrl, replacedTarget)
72
- const checkPath = replacement.replace(/\$\\d+/g, "")
73
- if (
74
- checkPath.includes(`${path.sep}node_modules${path.sep}`) &&
75
- !fs.existsSync(checkPath)
76
- ) {
77
- continue
78
- }
79
- alias.push({ find, replacement })
80
- continue
81
- }
82
-
83
- const find = key.replace(/\*$/, "")
84
- const cleanTarget = target.replace(/\*$/, "")
85
- const replacement = path.resolve(baseUrl, cleanTarget)
86
- if (
87
- replacement.includes(`${path.sep}node_modules${path.sep}`) &&
88
- !fs.existsSync(replacement)
89
- ) {
90
- continue
91
- }
92
- alias.push({ find, replacement })
93
- }
94
- }
95
-
96
- return alias
97
- }
98
-
99
- const tsconfig = loadTsconfig()
100
- const alias = pathsToAlias(tsconfig)
101
-
102
- export default defineConfig({
103
- test: {
104
- include: ["{src,lib}/**/*.test.{js,ts,tsx}"],
105
- },
106
- resolve: alias.length > 0 ? { alias } : undefined,
107
- })
File without changes