apify-test-tools 0.10.2-beta.13 → 0.10.2-beta.14
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.
- package/.github/cli/apify-test-tools.mjs +123 -128
- package/.github/workflows/public_platform-tests-claude-investigate-and-fix.yaml +1 -1
- package/.github/workflows/public_platform-tests.yaml +36 -22
- package/.github/workflows/public_pr-build-test.yaml +7 -6
- package/.github/workflows/public_push-build-latest.yaml +6 -4
- package/CHANGELOG.md +2 -0
- package/CONTRIBUTING.md +8 -6
- package/README.md +10 -11
- package/bin/actor-ids.ts +38 -0
- package/bin/build.ts +1 -1
- package/bin/git.ts +20 -92
- package/bin/main.ts +87 -73
- package/bin/notify.ts +198 -0
- package/bin/run-tests.ts +141 -0
- package/bin/slack.ts +16 -87
- package/bin/stdin-input.ts +98 -7
- package/bin/test-report.ts +141 -140
- package/bin/types.ts +0 -9
- package/dist/bin/actor-ids.d.ts +16 -0
- package/dist/bin/actor-ids.d.ts.map +1 -0
- package/dist/bin/actor-ids.js +24 -0
- package/dist/bin/actor-ids.js.map +1 -0
- package/dist/bin/build.js +1 -1
- package/dist/bin/build.js.map +1 -1
- package/dist/bin/git.d.ts +6 -16
- package/dist/bin/git.d.ts.map +1 -1
- package/dist/bin/git.js +15 -75
- package/dist/bin/git.js.map +1 -1
- package/dist/bin/main.js +80 -51
- package/dist/bin/main.js.map +1 -1
- package/dist/bin/notify.d.ts +35 -0
- package/dist/bin/notify.d.ts.map +1 -0
- package/dist/bin/notify.js +131 -0
- package/dist/bin/notify.js.map +1 -0
- package/dist/bin/run-tests.d.ts +21 -0
- package/dist/bin/run-tests.d.ts.map +1 -0
- package/dist/bin/run-tests.js +116 -0
- package/dist/bin/run-tests.js.map +1 -0
- package/dist/bin/slack.d.ts +2 -17
- package/dist/bin/slack.d.ts.map +1 -1
- package/dist/bin/slack.js +17 -58
- package/dist/bin/slack.js.map +1 -1
- package/dist/bin/stdin-input.d.ts +71 -9
- package/dist/bin/stdin-input.d.ts.map +1 -1
- package/dist/bin/stdin-input.js +76 -6
- package/dist/bin/stdin-input.js.map +1 -1
- package/dist/bin/test-report.d.ts +69 -8
- package/dist/bin/test-report.d.ts.map +1 -1
- package/dist/bin/test-report.js +76 -67
- package/dist/bin/test-report.js.map +1 -1
- package/dist/bin/types.d.ts +0 -8
- package/dist/bin/types.d.ts.map +1 -1
- package/dist/lib/lib.d.ts +0 -3
- package/dist/lib/lib.d.ts.map +1 -1
- package/dist/lib/lib.js +5 -10
- package/dist/lib/lib.js.map +1 -1
- package/dist/test/bundle/cli-bundle.test.js +40 -48
- package/dist/test/bundle/cli-bundle.test.js.map +1 -1
- package/dist/test/e2e/cli-bundle.e2e.test.js +15 -16
- package/dist/test/e2e/cli-bundle.e2e.test.js.map +1 -1
- package/dist/test/e2e/git-build-release.e2e.test.js +2 -2
- package/dist/test/e2e/git-build-release.e2e.test.js.map +1 -1
- package/dist/test/unit/bin/actor-ids.test.d.ts +2 -0
- package/dist/test/unit/bin/actor-ids.test.d.ts.map +1 -0
- package/dist/test/unit/bin/actor-ids.test.js +32 -0
- package/dist/test/unit/bin/actor-ids.test.js.map +1 -0
- package/dist/test/unit/bin/build-cli.test.js +8 -3
- package/dist/test/unit/bin/build-cli.test.js.map +1 -1
- package/dist/test/unit/bin/diff-changes.test.js +1 -1
- package/dist/test/unit/bin/diff-changes.test.js.map +1 -1
- package/dist/test/unit/bin/git.test.js +4 -142
- package/dist/test/unit/bin/git.test.js.map +1 -1
- package/dist/test/unit/bin/notify.test.d.ts +2 -0
- package/dist/test/unit/bin/notify.test.d.ts.map +1 -0
- package/dist/test/unit/bin/notify.test.js +222 -0
- package/dist/test/unit/bin/notify.test.js.map +1 -0
- package/dist/test/unit/bin/stdin-input.test.js +51 -9
- package/dist/test/unit/bin/stdin-input.test.js.map +1 -1
- package/dist/test/unit/bin/test-cli.test.d.ts +2 -0
- package/dist/test/unit/bin/test-cli.test.d.ts.map +1 -0
- package/dist/test/unit/bin/test-cli.test.js +115 -0
- package/dist/test/unit/bin/test-cli.test.js.map +1 -0
- package/dist/test/unit/bin/test-report.test.d.ts +2 -0
- package/dist/test/unit/bin/test-report.test.d.ts.map +1 -0
- package/dist/test/unit/bin/test-report.test.js +100 -0
- package/dist/test/unit/bin/test-report.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/cli.md +131 -53
- package/docs/lib.md +21 -16
- package/docs/workflows.md +24 -23
- package/lib/lib.ts +5 -10
- package/package.json +1 -1
- package/test/bundle/cli-bundle.test.ts +47 -60
- package/test/e2e/cli-bundle.e2e.test.ts +18 -25
- package/test/e2e/git-build-release.e2e.test.ts +2 -2
- package/test/unit/bin/actor-ids.test.ts +43 -0
- package/test/unit/bin/build-cli.test.ts +9 -3
- package/test/unit/bin/diff-changes.test.ts +1 -1
- package/test/unit/bin/git.test.ts +3 -197
- package/test/unit/bin/notify.test.ts +299 -0
- package/test/unit/bin/stdin-input.test.ts +68 -9
- package/test/unit/bin/test-cli.test.ts +137 -0
- package/test/unit/bin/test-report.test.ts +118 -0
- package/dist/test/unit/bin/logging.test.d.ts +0 -2
- package/dist/test/unit/bin/logging.test.d.ts.map +0 -1
- package/dist/test/unit/bin/logging.test.js +0 -37
- package/dist/test/unit/bin/logging.test.js.map +0 -1
- package/dist/test/unit/bin/slack.test.d.ts +0 -2
- package/dist/test/unit/bin/slack.test.d.ts.map +0 -1
- package/dist/test/unit/bin/slack.test.js +0 -71
- package/dist/test/unit/bin/slack.test.js.map +0 -1
- package/test/unit/bin/logging.test.ts +0 -48
- package/test/unit/bin/slack.test.ts +0 -84
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import process from 'node:process';
|
|
7
|
+
import { createInterface } from 'node:readline';
|
|
8
|
+
import { withActorIds } from './actor-ids.js';
|
|
9
|
+
import { logger } from './logger.js';
|
|
10
|
+
import { failedRunReport, logTestReport, toTestReport } from './test-report.js';
|
|
11
|
+
/**
|
|
12
|
+
* Finds the vitest the repository installed, the way Node would resolve it from `cwd`. The CLI ships as a bundle
|
|
13
|
+
* that runs outside the repository's `node_modules`, so the tests keep the vitest (and the lib) version the
|
|
14
|
+
* repository locked. Read from `package.json` because vitest's exports don't expose its bin.
|
|
15
|
+
*/
|
|
16
|
+
const resolveVitestBin = async (cwd) => {
|
|
17
|
+
for (let dir = path.resolve(cwd);; dir = path.dirname(dir)) {
|
|
18
|
+
const packageDir = path.join(dir, 'node_modules', 'vitest');
|
|
19
|
+
if (existsSync(path.join(packageDir, 'package.json'))) {
|
|
20
|
+
const { bin } = JSON.parse(await fs.readFile(path.join(packageDir, 'package.json'), 'utf8'));
|
|
21
|
+
return path.join(packageDir, typeof bin === 'string' ? bin : bin.vitest);
|
|
22
|
+
}
|
|
23
|
+
if (path.dirname(dir) === dir) {
|
|
24
|
+
throw new Error(`vitest is not installed in ${cwd}, install the repository's dependencies first`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Runs the repository's vitest on the given builds and returns what happened as a `TestReport`. Vitest's own output
|
|
30
|
+
* goes to stderr, so stdout stays free for the report. A failing test or a crashing vitest is a failed report, not
|
|
31
|
+
* an error: the report is how the failure gets to `notify`.
|
|
32
|
+
*/
|
|
33
|
+
export const runTests = async ({ filters, targets, vitestOutputFile, reporters = [], cwd = process.cwd(), }) => {
|
|
34
|
+
// Without it the lib skips every platform test, and a run that tested nothing would pass
|
|
35
|
+
if (!process.env.TESTER_APIFY_TOKEN) {
|
|
36
|
+
throw new Error('TESTER_APIFY_TOKEN is not set. The platform tests need it to run the Actors.');
|
|
37
|
+
}
|
|
38
|
+
const vitestBin = await resolveVitestBin(cwd);
|
|
39
|
+
// A test only runs when the ID it names its Actor by is listed, so each Actor gets both its full name and raw ID
|
|
40
|
+
const actorBuilds = await withActorIds(targets);
|
|
41
|
+
const tempDir = vitestOutputFile ? null : await fs.mkdtemp(path.join(os.tmpdir(), 'apify-test-tools-'));
|
|
42
|
+
const outputFile = path.resolve(cwd, vitestOutputFile ?? path.join(tempDir, 'vitest-report.json'));
|
|
43
|
+
// A report left over from an earlier run must not pass for this one's
|
|
44
|
+
await fs.rm(outputFile, { force: true });
|
|
45
|
+
// Stdin is the only source of what to test, so whatever the caller's environment holds doesn't leak into the tests
|
|
46
|
+
const env = { ...process.env };
|
|
47
|
+
// Vitest writes to a pipe, so it would drop colors that the terminal it ends up in shows
|
|
48
|
+
if (process.stderr.isTTY && env.FORCE_COLOR === undefined && env.NO_COLOR === undefined)
|
|
49
|
+
env.FORCE_COLOR = '1';
|
|
50
|
+
// The lib runs the tests of the Actors listed here, each on the build given, or on its default build without one
|
|
51
|
+
env.ACTOR_BUILDS = JSON.stringify(actorBuilds);
|
|
52
|
+
const described = actorBuilds.map(({ actorFullName, buildNumber }) => `${actorFullName} (${buildNumber ?? 'default build'})`);
|
|
53
|
+
logger.info(`Testing ${targets.length} Actor(s): ${described.join(', ') || 'none'}`);
|
|
54
|
+
const args = [
|
|
55
|
+
vitestBin,
|
|
56
|
+
'run',
|
|
57
|
+
...filters,
|
|
58
|
+
'--reporter=default',
|
|
59
|
+
'--reporter=json',
|
|
60
|
+
...reporters.map((reporter) => `--reporter=${reporter}`),
|
|
61
|
+
`--outputFile.json=${outputFile}`,
|
|
62
|
+
// Platform tests mostly wait on Actor runs, not on the CPU, so they run far more at once than vitest's defaults
|
|
63
|
+
'--maxConcurrency=20',
|
|
64
|
+
'--fileParallelism',
|
|
65
|
+
'--maxWorkers=100',
|
|
66
|
+
];
|
|
67
|
+
logger.debug(`Running vitest: ${args.join(' ')}`);
|
|
68
|
+
try {
|
|
69
|
+
const exitCode = await spawnVitest(args, { cwd, env });
|
|
70
|
+
let vitestReport;
|
|
71
|
+
try {
|
|
72
|
+
vitestReport = JSON.parse(await fs.readFile(outputFile, 'utf8'));
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
logger.debug(`Could not read the vitest report: ${error.message}`);
|
|
76
|
+
const report = failedRunReport(`Vitest exited with code ${exitCode} without a report, see its output above`);
|
|
77
|
+
logTestReport(report);
|
|
78
|
+
return report;
|
|
79
|
+
}
|
|
80
|
+
const report = toTestReport(vitestReport, { cwd, exitCode });
|
|
81
|
+
logTestReport(report);
|
|
82
|
+
return report;
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
if (tempDir)
|
|
86
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
/** Resolves with vitest's exit code. Signals we get (a cancelled CI job) are passed on, so vitest can clean up. */
|
|
90
|
+
const spawnVitest = async (args, { cwd, env }) => new Promise((resolve, reject) => {
|
|
91
|
+
// Vitest's stdout goes to our stderr: stdout is reserved for the report. It is piped through us rather than
|
|
92
|
+
// handed over, to leave out the JSON reporter's note about the temporary file it wrote.
|
|
93
|
+
const child = spawn(process.execPath, args, { cwd, env, stdio: ['ignore', 'pipe', 2] });
|
|
94
|
+
createInterface({ input: child.stdout, crlfDelay: Infinity }).on('line', (line) => {
|
|
95
|
+
if (!line.startsWith('JSON report written to '))
|
|
96
|
+
process.stderr.write(`${line}\n`);
|
|
97
|
+
});
|
|
98
|
+
const forward = (signal) => child.kill(signal);
|
|
99
|
+
process.on('SIGINT', forward);
|
|
100
|
+
process.on('SIGTERM', forward);
|
|
101
|
+
const cleanup = () => {
|
|
102
|
+
process.off('SIGINT', forward);
|
|
103
|
+
process.off('SIGTERM', forward);
|
|
104
|
+
};
|
|
105
|
+
child.on('error', (error) => {
|
|
106
|
+
cleanup();
|
|
107
|
+
reject(new Error(`Failed to start vitest: ${error.message}`));
|
|
108
|
+
});
|
|
109
|
+
child.on('close', (code, signal) => {
|
|
110
|
+
cleanup();
|
|
111
|
+
if (signal)
|
|
112
|
+
logger.warn(`Vitest was stopped by ${signal}`);
|
|
113
|
+
resolve(code ?? 1);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
//# sourceMappingURL=run-tests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-tests.js","sourceRoot":"","sources":["../../bin/run-tests.ts"],"names":[],"mappings":"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"}
|
package/dist/bin/slack.d.ts
CHANGED
|
@@ -1,25 +1,10 @@
|
|
|
1
1
|
import { WebClient } from '@slack/web-api';
|
|
2
|
-
import type { Commit } from './types.js';
|
|
3
|
-
type NotifyToSlackOptions = {
|
|
4
|
-
changedFiles: string[];
|
|
5
|
-
changelog: string | null;
|
|
6
|
-
commits: Commit[];
|
|
7
|
-
repoUrl?: string;
|
|
8
|
-
dryRun: boolean;
|
|
9
|
-
releaseSlackChannel?: string;
|
|
10
|
-
reportSlackChannel?: string;
|
|
11
|
-
};
|
|
12
2
|
/**
|
|
13
3
|
* Creates the client the real run posts with. A dry run posts nothing but still requires the token and checks
|
|
14
4
|
* Slack accepts it (`auth.test` is read-only), so it fails wherever the real run would.
|
|
15
5
|
*/
|
|
16
6
|
export declare const getSlackClient: (tokenEnvVar: string, dryRun: boolean) => Promise<WebClient>;
|
|
17
7
|
export declare const sendingLabel: (dryRun: boolean) => "[DRY RUN] Would send" | "Sending";
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
* Posts nothing when there are no commits, which means there is nothing new to release.
|
|
21
|
-
*/
|
|
22
|
-
export declare const notifyToSlack: ({ changedFiles, commits, changelog, repoUrl, dryRun, releaseSlackChannel, reportSlackChannel, }: NotifyToSlackOptions) => Promise<void>;
|
|
23
|
-
export declare const sendSlackMessage: (slack: WebClient, channel: string, text: string, blocks: string[]) => Promise<void>;
|
|
24
|
-
export {};
|
|
8
|
+
/** Posts `text`, with `details` as sections in its thread, as many replies as Slack's block limit needs. */
|
|
9
|
+
export declare const sendSlackMessage: (slack: WebClient, channel: string, text: string, details: string[]) => Promise<void>;
|
|
25
10
|
//# sourceMappingURL=slack.d.ts.map
|
package/dist/bin/slack.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../bin/slack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../bin/slack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAK3C;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAU,aAAa,MAAM,EAAE,QAAQ,OAAO,KAAG,OAAO,CAAC,SAAS,CAW5F,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,QAAQ,OAAO,uCAAkD,CAAC;AAM/F,4GAA4G;AAC5G,eAAO,MAAM,gBAAgB,GAAU,OAAO,SAAS,EAAE,SAAS,MAAM,EAAE,MAAM,MAAM,EAAE,SAAS,MAAM,EAAE,kBAkBxG,CAAC"}
|
package/dist/bin/slack.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { WebClient } from '@slack/web-api';
|
|
2
|
-
import { getRepoName, resolveRepoUrl } from './git.js';
|
|
3
2
|
import { logger } from './logger.js';
|
|
4
3
|
import { getEnvVar } from './utils.js';
|
|
5
4
|
/**
|
|
@@ -20,67 +19,27 @@ export const getSlackClient = async (tokenEnvVar, dryRun) => {
|
|
|
20
19
|
return slack;
|
|
21
20
|
};
|
|
22
21
|
export const sendingLabel = (dryRun) => (dryRun ? '[DRY RUN] Would send' : 'Sending');
|
|
23
|
-
//
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
*/
|
|
29
|
-
export const notifyToSlack = async ({ changedFiles, commits, changelog, repoUrl, dryRun, releaseSlackChannel, reportSlackChannel, }) => {
|
|
30
|
-
if (commits.length === 0) {
|
|
31
|
-
logger.info('No new commits, so there is no release to announce');
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
if (!changelog) {
|
|
35
|
-
logger.warn('No new changelog entries found, did you forget to update it?');
|
|
36
|
-
}
|
|
37
|
-
if (!releaseSlackChannel && !reportSlackChannel) {
|
|
38
|
-
logger.info('Skipping slack notification, no --release-slack-channel or --report-slack-channel passed');
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const slack = await getSlackClient('SLACK_TOKEN_RELEASES_BOT', dryRun);
|
|
42
|
-
const repository = getRepoName((await resolveRepoUrl(repoUrl)).repoUrl);
|
|
43
|
-
// The newest commit, same as the pushed head commit
|
|
44
|
-
const { author } = commits[commits.length - 1];
|
|
45
|
-
let shortMessage = `*${repository}* – New release (by ${displayName(author)}):\n\n`;
|
|
46
|
-
// This one is just for broader public that only cares about public facing changes
|
|
47
|
-
if (changelog && releaseSlackChannel) {
|
|
48
|
-
shortMessage += `*Additions to the changelog*:\n\n${changelog}\n`;
|
|
49
|
-
logger.info(`=========================================`);
|
|
50
|
-
logger.info(`**${sendingLabel(dryRun)} slack message to channel**: ${releaseSlackChannel}.\n\n${shortMessage}`);
|
|
51
|
-
logger.info(`=========================================`);
|
|
52
|
-
if (!dryRun) {
|
|
53
|
-
await slack.chat.postMessage({
|
|
54
|
-
channel: releaseSlackChannel,
|
|
55
|
-
text: shortMessage,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
const commitsMessage = `${commits
|
|
60
|
-
.map(({ author: commitAuthor, message }, index) => `${index + 1}. Commit message: ${message}\n\tAuthor: ${displayName(commitAuthor)}.`)
|
|
61
|
-
.join('\n')}`;
|
|
62
|
-
const changedFilesMessage = `*Files changed*: ${changedFiles.map((file) => `\`${file}\``).join(', ')}`;
|
|
63
|
-
const longMessage = `${shortMessage}\n*Commit list*:\n${commitsMessage}\n\n${changedFilesMessage}`;
|
|
64
|
-
// This one is for devs and project managers that need to know more details
|
|
65
|
-
if (reportSlackChannel) {
|
|
66
|
-
logger.info(`=========================================`);
|
|
67
|
-
logger.info(`${sendingLabel(dryRun)} slack message to channel: ${reportSlackChannel}.\n\n${longMessage}`);
|
|
68
|
-
logger.info(`=========================================`);
|
|
69
|
-
if (!dryRun) {
|
|
70
|
-
await slack.chat.postMessage({
|
|
71
|
-
text: longMessage,
|
|
72
|
-
channel: reportSlackChannel,
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
export const sendSlackMessage = async (slack, channel, text, blocks) => {
|
|
22
|
+
// Slack's limits: 50 blocks per message, 3000 characters per section
|
|
23
|
+
const MAX_BLOCKS_PER_MESSAGE = 50;
|
|
24
|
+
const MAX_SECTION_LENGTH = 3000;
|
|
25
|
+
/** Posts `text`, with `details` as sections in its thread, as many replies as Slack's block limit needs. */
|
|
26
|
+
export const sendSlackMessage = async (slack, channel, text, details) => {
|
|
78
27
|
const { ts } = await slack.chat.postMessage({ text, channel });
|
|
79
|
-
if (
|
|
28
|
+
if (!ts)
|
|
29
|
+
return;
|
|
30
|
+
for (let i = 0; i < details.length; i += MAX_BLOCKS_PER_MESSAGE) {
|
|
31
|
+
const sections = details.slice(i, i + MAX_BLOCKS_PER_MESSAGE);
|
|
80
32
|
await slack.chat.postMessage({
|
|
81
33
|
channel,
|
|
82
34
|
thread_ts: ts,
|
|
83
|
-
|
|
35
|
+
text: sections.join('\n').slice(0, MAX_SECTION_LENGTH),
|
|
36
|
+
blocks: sections.map((t) => ({
|
|
37
|
+
text: {
|
|
38
|
+
type: 'mrkdwn',
|
|
39
|
+
text: t.length > MAX_SECTION_LENGTH ? `${t.slice(0, MAX_SECTION_LENGTH - 1)}…` : t,
|
|
40
|
+
},
|
|
41
|
+
type: 'section',
|
|
42
|
+
})),
|
|
84
43
|
});
|
|
85
44
|
}
|
|
86
45
|
};
|
package/dist/bin/slack.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack.js","sourceRoot":"","sources":["../../bin/slack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"slack.js","sourceRoot":"","sources":["../../bin/slack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAAE,WAAmB,EAAE,MAAe,EAAsB,EAAE;IAC7F,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;IACpD,IAAI,MAAM,EAAE,CAAC;QACT,IAAI,CAAC;YACD,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,GAAG,WAAW,2BAA4B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACvF,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,aAAa,WAAW,WAAW,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAe,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAE/F,qEAAqE;AACrE,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAClC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC,4GAA4G;AAC5G,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAAE,KAAgB,EAAE,OAAe,EAAE,IAAY,EAAE,OAAiB,EAAE,EAAE;IACzG,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC/D,IAAI,CAAC,EAAE;QAAE,OAAO;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,sBAAsB,EAAE,CAAC;QAC9D,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,sBAAsB,CAAC,CAAC;QAC9D,MAAM,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC;YACzB,OAAO;YACP,SAAS,EAAE,EAAE;YACb,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,kBAAkB,CAAC;YACtD,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACzB,IAAI,EAAE;oBACF,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,kBAAkB,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;iBACrF;gBACD,IAAI,EAAE,SAAS;aAClB,CAAC,CAAC;SACN,CAAC,CAAC;IACP,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -1,17 +1,79 @@
|
|
|
1
|
+
import z from 'zod';
|
|
1
2
|
export declare const readStdin: () => Promise<string>;
|
|
2
3
|
export declare const parseBuildInput: (raw: string) => {
|
|
3
4
|
actors: {
|
|
4
5
|
actorFullName: string;
|
|
5
6
|
}[];
|
|
6
7
|
};
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
/**
|
|
9
|
+
* What `test` reads: the Actors to test, each with the build to test or, without one, its default build. The builds
|
|
10
|
+
* `build` and `build-from-local` print fit, and so does `get-actor-configs`, whose other fields are ignored. An Actor
|
|
11
|
+
* needs its full name or its raw ID, `test` looks up the other. A dry-run plan is an object on purpose, so it is
|
|
12
|
+
* rejected here rather than tested as if it were built.
|
|
13
|
+
*/
|
|
14
|
+
declare const testTargetsSchema: z.ZodArray<z.ZodObject<{
|
|
15
|
+
actorFullName: z.ZodOptional<z.ZodString>;
|
|
16
|
+
buildId: z.ZodOptional<z.ZodString>;
|
|
17
|
+
actorRawId: z.ZodOptional<z.ZodString>;
|
|
18
|
+
buildNumber: z.ZodOptional<z.ZodString>;
|
|
19
|
+
}, z.z.core.$strip>>;
|
|
20
|
+
export type TestTarget = z.infer<typeof testTargetsSchema>[number];
|
|
21
|
+
export declare const parseTestTargets: (raw: string) => {
|
|
22
|
+
actorFullName?: string | undefined;
|
|
23
|
+
buildId?: string | undefined;
|
|
24
|
+
actorRawId?: string | undefined;
|
|
25
|
+
buildNumber?: string | undefined;
|
|
26
|
+
}[];
|
|
27
|
+
declare const testReportSchema: z.ZodObject<{
|
|
28
|
+
kind: z.ZodLiteral<"test-report">;
|
|
29
|
+
version: z.ZodLiteral<1>;
|
|
30
|
+
success: z.ZodBoolean;
|
|
31
|
+
summary: z.ZodObject<{
|
|
32
|
+
total: z.ZodNumber;
|
|
33
|
+
passed: z.ZodNumber;
|
|
34
|
+
failed: z.ZodNumber;
|
|
35
|
+
skipped: z.ZodNumber;
|
|
36
|
+
}, z.z.core.$strip>;
|
|
37
|
+
tests: z.ZodArray<z.ZodObject<{
|
|
38
|
+
name: z.ZodString;
|
|
39
|
+
file: z.ZodString;
|
|
40
|
+
status: z.ZodEnum<{
|
|
41
|
+
passed: "passed";
|
|
42
|
+
failed: "failed";
|
|
43
|
+
skipped: "skipped";
|
|
44
|
+
}>;
|
|
45
|
+
durationMs: z.ZodNullable<z.ZodNumber>;
|
|
46
|
+
failureMessages: z.ZodArray<z.ZodString>;
|
|
47
|
+
run: z.ZodNullable<z.ZodObject<{
|
|
48
|
+
actorId: z.ZodString;
|
|
49
|
+
runId: z.ZodString;
|
|
50
|
+
runLink: z.ZodString;
|
|
51
|
+
}, z.z.core.$strip>>;
|
|
52
|
+
}, z.z.core.$strip>>;
|
|
53
|
+
errors: z.ZodArray<z.ZodString>;
|
|
54
|
+
}, z.z.core.$strip>;
|
|
55
|
+
/** The parts of a get-affected-actors document that describe what a release changed. Other fields are ignored. */
|
|
56
|
+
declare const releaseChangesSchema: z.ZodObject<{
|
|
57
|
+
commits: z.ZodArray<z.ZodObject<{
|
|
58
|
+
sha: z.ZodString;
|
|
59
|
+
author: z.ZodString;
|
|
60
|
+
date: z.ZodString;
|
|
61
|
+
message: z.ZodString;
|
|
62
|
+
}, z.z.core.$strip>>;
|
|
63
|
+
changelog: z.ZodNullable<z.ZodString>;
|
|
64
|
+
}, z.z.core.$strip>;
|
|
65
|
+
export type ReleaseChanges = z.infer<typeof releaseChangesSchema>;
|
|
66
|
+
export type NotifyInput = {
|
|
67
|
+
kind: 'tests';
|
|
68
|
+
report: z.infer<typeof testReportSchema>;
|
|
69
|
+
} | {
|
|
70
|
+
kind: 'release';
|
|
71
|
+
changes: ReleaseChanges;
|
|
16
72
|
};
|
|
73
|
+
/**
|
|
74
|
+
* What `notify` reads: a test run, as `test` reports it, or a release, as `get-affected-actors` reports it. The test
|
|
75
|
+
* report says so in its `kind`, a release is told by its `commits`, so either can be piped in as it is.
|
|
76
|
+
*/
|
|
77
|
+
export declare const parseNotifyInput: (raw: string) => NotifyInput;
|
|
78
|
+
export {};
|
|
17
79
|
//# sourceMappingURL=stdin-input.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdin-input.d.ts","sourceRoot":"","sources":["../../bin/stdin-input.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"stdin-input.d.ts","sourceRoot":"","sources":["../../bin/stdin-input.ts"],"names":[],"mappings":"AAEA,OAAO,CAAkC,MAAM,KAAK,CAAC;AAErD,eAAO,MAAM,SAAS,QAAa,OAAO,CAAC,MAAM,CAUhD,CAAC;AAyCF,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM;;;;CAIrC,CAAC;AAEP;;;;;GAKG;AACH,QAAA,MAAM,iBAAiB;;;;;oBAWtB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAWnE,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM;;;;;GAQ3C,CAAC;AAIF,QAAA,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAgBpB,CAAC;AAEH,kHAAkH;AAClH,QAAA,MAAM,oBAAoB;;;;;;;;mBAGxB,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,MAAM,MAAM,WAAW,GACjB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,WAkB9C,CAAC"}
|
package/dist/bin/stdin-input.js
CHANGED
|
@@ -23,6 +23,9 @@ const parseStdinJson = (raw, schema, { expected, example }) => {
|
|
|
23
23
|
catch (error) {
|
|
24
24
|
throw new Error(`The input on stdin is not valid JSON: ${error.message}`);
|
|
25
25
|
}
|
|
26
|
+
return validateStdinJson(json, schema, { expected, example });
|
|
27
|
+
};
|
|
28
|
+
const validateStdinJson = (json, schema, { expected, example }) => {
|
|
26
29
|
const result = schema.safeParse(json);
|
|
27
30
|
if (!result.success) {
|
|
28
31
|
throw new Error(`The input on stdin is not ${expected} (${example}):\n${prettifyError(result.error)}`);
|
|
@@ -41,14 +44,81 @@ export const parseBuildInput = (raw) => parseStdinJson(raw, buildInputSchema, {
|
|
|
41
44
|
expected: 'the Actors to build',
|
|
42
45
|
example: `e.g. echo '{"actors":[{"actorFullName":"owner/name"}]}' | apify-test-tools build --version-number 0.1`,
|
|
43
46
|
});
|
|
44
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* What `test` reads: the Actors to test, each with the build to test or, without one, its default build. The builds
|
|
49
|
+
* `build` and `build-from-local` print fit, and so does `get-actor-configs`, whose other fields are ignored. An Actor
|
|
50
|
+
* needs its full name or its raw ID, `test` looks up the other. A dry-run plan is an object on purpose, so it is
|
|
51
|
+
* rejected here rather than tested as if it were built.
|
|
52
|
+
*/
|
|
53
|
+
const testTargetsSchema = z.array(z
|
|
54
|
+
.object({
|
|
55
|
+
actorFullName: z.string().optional(),
|
|
56
|
+
buildId: z.string().optional(),
|
|
57
|
+
actorRawId: z.string().optional(),
|
|
58
|
+
buildNumber: z.string().optional(),
|
|
59
|
+
})
|
|
60
|
+
.refine(({ actorFullName, actorRawId }) => !!actorFullName || !!actorRawId, {
|
|
61
|
+
message: 'An Actor needs actorFullName or actorRawId',
|
|
62
|
+
}));
|
|
63
|
+
const isDryRunPlan = (raw) => {
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(raw)?.dryRun === true;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Not JSON at all, parseStdinJson says so
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
export const parseTestTargets = (raw) => {
|
|
73
|
+
const example = 'e.g. ... | apify-test-tools build --version-number 0.99 | apify-test-tools test, ' +
|
|
74
|
+
"or apify-test-tools get-actor-configs | apify-test-tools test for every Actor's default build";
|
|
75
|
+
if (isDryRunPlan(raw)) {
|
|
76
|
+
throw new Error(`The input on stdin is a dry-run plan, not builds, so there is nothing to test (${example}).`);
|
|
77
|
+
}
|
|
78
|
+
return parseStdinJson(raw, testTargetsSchema, { expected: 'the Actors to test', example });
|
|
79
|
+
};
|
|
80
|
+
/** The report `test` prints, see TestReport. */
|
|
81
|
+
const testRunSchema = z.object({ actorId: z.string(), runId: z.string(), runLink: z.string() });
|
|
82
|
+
const testReportSchema = z.object({
|
|
83
|
+
kind: z.literal('test-report'),
|
|
84
|
+
version: z.literal(1),
|
|
85
|
+
success: z.boolean(),
|
|
86
|
+
summary: z.object({ total: z.number(), passed: z.number(), failed: z.number(), skipped: z.number() }),
|
|
87
|
+
tests: z.array(z.object({
|
|
88
|
+
name: z.string(),
|
|
89
|
+
file: z.string(),
|
|
90
|
+
status: z.enum(['passed', 'failed', 'skipped']),
|
|
91
|
+
durationMs: z.number().nullable(),
|
|
92
|
+
failureMessages: z.array(z.string()),
|
|
93
|
+
run: testRunSchema.nullable(),
|
|
94
|
+
})),
|
|
95
|
+
errors: z.array(z.string()),
|
|
96
|
+
});
|
|
97
|
+
/** The parts of a get-affected-actors document that describe what a release changed. Other fields are ignored. */
|
|
45
98
|
const releaseChangesSchema = z.object({
|
|
46
99
|
commits: z.array(z.object({ sha: z.string(), author: z.string(), date: z.string(), message: z.string() })),
|
|
47
|
-
changedFiles: z.array(z.string()),
|
|
48
100
|
changelog: z.string().nullable(),
|
|
49
101
|
});
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
102
|
+
/**
|
|
103
|
+
* What `notify` reads: a test run, as `test` reports it, or a release, as `get-affected-actors` reports it. The test
|
|
104
|
+
* report says so in its `kind`, a release is told by its `commits`, so either can be piped in as it is.
|
|
105
|
+
*/
|
|
106
|
+
export const parseNotifyInput = (raw) => {
|
|
107
|
+
const example = 'e.g. ... | apify-test-tools test | apify-test-tools notify --slack-channel "#my-channel", ' +
|
|
108
|
+
'or apify-test-tools get-affected-actors --since <sha> | apify-test-tools notify --slack-channel "#my-channel"';
|
|
109
|
+
const expected = 'the output of test or get-affected-actors';
|
|
110
|
+
const json = parseStdinJson(raw, z.looseObject({}), { expected, example });
|
|
111
|
+
if (json.kind === 'test-report') {
|
|
112
|
+
const report = validateStdinJson(json, testReportSchema, { expected: 'the output of test', example });
|
|
113
|
+
return { kind: 'tests', report };
|
|
114
|
+
}
|
|
115
|
+
if ('commits' in json) {
|
|
116
|
+
const changes = validateStdinJson(json, releaseChangesSchema, {
|
|
117
|
+
expected: 'the output of get-affected-actors',
|
|
118
|
+
example,
|
|
119
|
+
});
|
|
120
|
+
return { kind: 'release', changes };
|
|
121
|
+
}
|
|
122
|
+
throw new Error(`The input on stdin is not ${expected} (${example}).`);
|
|
123
|
+
};
|
|
54
124
|
//# sourceMappingURL=stdin-input.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdin-input.js","sourceRoot":"","sources":["../../bin/stdin-input.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,CAAC,EAAE,EAAE,aAAa,EAAgB,MAAM,KAAK,CAAC;AAErD,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,IAAqB,EAAE;IACjD,2EAA2E;IAC3E,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACtC,GAAG,IAAI,KAAK,CAAC;IACjB,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CACnB,GAAW,EACX,MAAkB,EAClB,EAAE,QAAQ,EAAE,OAAO,EAAyC,EAC9D,EAAE;IACA,8GAA8G;IAC9G,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,YAAY,QAAQ,mCAAmC,OAAO,IAAI,CAAC,CAAC;IACxF,CAAC;IACD,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACD,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,yCAA0C,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,KAAK,OAAO,OAAO,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC3G,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACvB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;CAC3D,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAW,EAAE,EAAE,CAC3C,cAAc,CAAC,GAAG,EAAE,gBAAgB,EAAE;IAClC,QAAQ,EAAE,qBAAqB;IAC/B,OAAO,EAAE,uGAAuG;CACnH,CAAC,CAAC;AAEP
|
|
1
|
+
{"version":3,"file":"stdin-input.js","sourceRoot":"","sources":["../../bin/stdin-input.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,71 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
export
|
|
1
|
+
export type TestStatus = 'passed' | 'failed' | 'skipped';
|
|
2
|
+
/** The Actor run a test started, as the lib records it on the test's `meta`. */
|
|
3
|
+
export interface TestRun {
|
|
4
|
+
actorId: string;
|
|
5
|
+
runId: string;
|
|
6
|
+
runLink: string;
|
|
7
|
+
}
|
|
8
|
+
export interface TestCaseReport {
|
|
9
|
+
/** The full test name, including its `describe` blocks, e.g. `owner/name: finishes` */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Relative to the directory the tests ran in */
|
|
12
|
+
file: string;
|
|
13
|
+
status: TestStatus;
|
|
14
|
+
durationMs: number | null;
|
|
15
|
+
/** The first line of each failure, the rest (diffs, stack traces) is in the vitest output */
|
|
16
|
+
failureMessages: string[];
|
|
17
|
+
/** Null for tests that didn't start a run: skipped ones, standby tests, or ones that failed before the run */
|
|
18
|
+
run: TestRun | null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* What `test` writes to stdout and `notify` reads. A contract between the CLI and whoever reads it, so add fields
|
|
22
|
+
* freely, but renaming or removing one needs a new `version`.
|
|
23
|
+
*/
|
|
24
|
+
export interface TestReport {
|
|
25
|
+
/** What the document is, so `notify` and others can tell it from other outputs */
|
|
26
|
+
kind: 'test-report';
|
|
27
|
+
version: 1;
|
|
28
|
+
/** False if any test failed, or the run failed in a way no test accounts for (see `errors`) */
|
|
29
|
+
success: boolean;
|
|
30
|
+
summary: {
|
|
31
|
+
total: number;
|
|
32
|
+
passed: number;
|
|
33
|
+
failed: number;
|
|
34
|
+
skipped: number;
|
|
35
|
+
};
|
|
36
|
+
tests: TestCaseReport[];
|
|
37
|
+
/** Failures outside any test, e.g. a test file that failed to import, or vitest crashing without a report */
|
|
38
|
+
errors: string[];
|
|
39
|
+
}
|
|
40
|
+
type VitestStatus = 'passed' | 'failed' | 'skipped' | 'pending' | 'todo' | 'disabled';
|
|
41
|
+
interface VitestAssertionResult {
|
|
42
|
+
fullName: string;
|
|
43
|
+
status: VitestStatus;
|
|
44
|
+
duration?: number | null;
|
|
45
|
+
failureMessages: string[] | null;
|
|
46
|
+
meta?: Partial<TestRun>;
|
|
47
|
+
}
|
|
48
|
+
interface VitestFileResult {
|
|
49
|
+
name: string;
|
|
50
|
+
status: 'failed' | 'passed';
|
|
51
|
+
message: string;
|
|
52
|
+
assertionResults: VitestAssertionResult[];
|
|
53
|
+
}
|
|
54
|
+
export interface VitestJsonReport {
|
|
55
|
+
success: boolean;
|
|
56
|
+
testResults: VitestFileResult[];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Turns vitest's JSON report into a `TestReport`. `exitCode` is vitest's: a non-zero exit with every test passing
|
|
60
|
+
* still fails the report (e.g. an unhandled error between tests), so the report never reads greener than the run.
|
|
61
|
+
*/
|
|
62
|
+
export declare const toTestReport: (vitest: VitestJsonReport, { cwd, exitCode }: {
|
|
63
|
+
cwd: string;
|
|
64
|
+
exitCode: number;
|
|
65
|
+
}) => TestReport;
|
|
66
|
+
/** The report of a run that left no vitest report behind, e.g. because vitest crashed or was killed. */
|
|
67
|
+
export declare const failedRunReport: (error: string) => TestReport;
|
|
68
|
+
/** Logs the tests with their run links, which vitest's own output doesn't show. */
|
|
69
|
+
export declare const logTestReport: ({ summary, tests, errors }: TestReport) => void;
|
|
9
70
|
export {};
|
|
10
71
|
//# sourceMappingURL=test-report.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-report.d.ts","sourceRoot":"","sources":["../../bin/test-report.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"test-report.d.ts","sourceRoot":"","sources":["../../bin/test-report.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEzD,gFAAgF;AAChF,MAAM,WAAW,OAAO;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC3B,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,6FAA6F;IAC7F,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,8GAA8G;IAC9G,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACvB,kFAAkF;IAClF,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,CAAC,CAAC;IACX,+FAA+F;IAC/F,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,6GAA6G;IAC7G,MAAM,EAAE,MAAM,EAAE,CAAC;CACpB;AAGD,KAAK,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;AAEtF,UAAU,qBAAqB;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3B;AAED,UAAU,gBAAgB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,qBAAqB,EAAE,CAAC;CAC7C;AAED,MAAM,WAAW,gBAAgB;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,gBAAgB,EAAE,CAAC;CACnC;AASD;;;GAGG;AACH,eAAO,MAAM,YAAY,GACrB,QAAQ,gBAAgB,EACxB,mBAAmB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,KACrD,UA2CF,CAAC;AAEF,wGAAwG;AACxG,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,KAAG,UAO9C,CAAC;AAEH,mFAAmF;AACnF,eAAO,MAAM,aAAa,GAAI,4BAA4B,UAAU,SAuBnE,CAAC"}
|