From 3ef35d746a343b3f885d96fd6c3cf9f0742d335a Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Mon, 18 Nov 2024 20:50:42 -0800 Subject: [PATCH] Implement junit test reporter (#15205) Co-authored-by: Jarred-Sumner Co-authored-by: Dylan Conway Co-authored-by: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> --- docs/cli/test.md | 43 +++ src/bunfig.zig | 11 + src/cli.zig | 22 ++ src/cli/test_command.zig | 488 ++++++++++++++++++++++++++- test/bun.lockb | Bin 373314 -> 374338 bytes test/js/junit-reporter/junit.test.js | 234 +++++++++++++ test/package.json | 1 + 7 files changed, 790 insertions(+), 9 deletions(-) create mode 100644 test/js/junit-reporter/junit.test.js diff --git a/docs/cli/test.md b/docs/cli/test.md index 3a9ec639a5d930..8ff796f5b02d05 100644 --- a/docs/cli/test.md +++ b/docs/cli/test.md @@ -55,6 +55,49 @@ $ bun test ./test/specific-file.test.ts The test runner runs all tests in a single process. It loads all `--preload` scripts (see [Lifecycle](https://bun.sh/docs/test/lifecycle) for details), then runs all tests. If a test fails, the test runner will exit with a non-zero exit code. +## CI/CD integration + +`bun test` supports a variety of CI/CD integrations. + +### GitHub Actions + +`bun test` automatically detects if it's running inside GitHub Actions and will emit GitHub Actions annotations to the console directly. + +No configuration is needed, other than installing `bun` in the workflow and running `bun test`. + +#### How to install `bun` in a GitHub Actions workflow + +To use `bun test` in a GitHub Actions workflow, add the following step: + +```yaml +jobs: + build: + name: build-app + runs-on: ubuntu-latest + steps: + - name: Install bun + uses: oven-sh/setup-bun + - name: Install dependencies # (assuming your project has dependencies) + run: bun install # You can use npm/yarn/pnpm instead if you prefer + - name: Run tests + run: bun test +``` + +From there, you'll get GitHub Actions annotations. + +### JUnit XML reports (GitLab, etc.) + +To use `bun test` with a JUnit XML reporter, you can use the `--reporter=junit` in combination with `--reporter-outfile`. + +```sh +$ bun test --reporter=junit --reporter-outfile=./bun.xml +``` + +This will continue to output to stdout/stderr as usual, and also write a JUnit +XML report to the given path at the very end of the test run. + +JUnit XML is a popular format for reporting test results in CI/CD pipelines. + ## Timeouts Use the `--timeout` flag to specify a _per-test_ timeout in milliseconds. If a test times out, it will be marked as failed. The default value is `5000`. diff --git a/src/bunfig.zig b/src/bunfig.zig index 4f1d73d68c3162..f5e41c434deb0e 100644 --- a/src/bunfig.zig +++ b/src/bunfig.zig @@ -266,6 +266,17 @@ pub const Bunfig = struct { this.ctx.test_options.coverage.enabled = expr.data.e_boolean.value; } + if (test_.get("reporter")) |expr| { + try this.expect(expr, .e_object); + if (expr.get("junit")) |junit_expr| { + try this.expectString(junit_expr); + if (junit_expr.data.e_string.len() > 0) { + this.ctx.test_options.file_reporter = .junit; + this.ctx.test_options.reporter_outfile = try junit_expr.data.e_string.string(allocator); + } + } + } + if (test_.get("coverageReporter")) |expr| brk: { this.ctx.test_options.coverage.reporters = .{ .text = false, .lcov = false }; if (expr.data == .e_string) { diff --git a/src/cli.zig b/src/cli.zig index f76416230c74ee..a28b799b5e36ce 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -306,6 +306,8 @@ pub const Arguments = struct { clap.parseParam("--coverage-dir Directory for coverage files. Defaults to 'coverage'.") catch unreachable, clap.parseParam("--bail ? Exit the test suite after failures. If you do not specify a number, it defaults to 1.") catch unreachable, clap.parseParam("-t, --test-name-pattern Run only tests with a name that matches the given regex.") catch unreachable, + clap.parseParam("--reporter Specify the test reporter. Currently --reporter=junit is the only supported format.") catch unreachable, + clap.parseParam("--reporter-outfile The output file used for the format from --reporter.") catch unreachable, }; pub const test_params = test_only_params ++ runtime_params_ ++ transpiler_params_ ++ base_params_; @@ -524,6 +526,23 @@ pub const Arguments = struct { } } + if (args.option("--reporter-outfile")) |reporter_outfile| { + ctx.test_options.reporter_outfile = reporter_outfile; + } + + if (args.option("--reporter")) |reporter| { + if (strings.eqlComptime(reporter, "junit")) { + if (ctx.test_options.reporter_outfile == null) { + Output.errGeneric("--reporter=junit expects an output file from --reporter-outfile", .{}); + Global.crash(); + } + ctx.test_options.file_reporter = .junit; + } else { + Output.errGeneric("unrecognized reporter format: '{s}'. Currently, only 'junit' is supported", .{reporter}); + Global.crash(); + } + } + if (args.option("--coverage-dir")) |dir| { ctx.test_options.coverage.reports_directory = dir; } @@ -1354,6 +1373,9 @@ pub const Command = struct { bail: u32 = 0, coverage: TestCommand.CodeCoverageOptions = .{}, test_filter_regex: ?*RegularExpression = null, + + file_reporter: ?TestCommand.FileReporter = null, + reporter_outfile: ?[]const u8 = null, }; pub const Debugger = union(enum) { diff --git a/src/cli/test_command.zig b/src/cli/test_command.zig index 451f1e2a529269..cfe25b04792c56 100644 --- a/src/cli/test_command.zig +++ b/src/cli/test_command.zig @@ -9,6 +9,7 @@ const stringZ = bun.stringZ; const default_allocator = bun.default_allocator; const C = bun.C; const std = @import("std"); +const OOM = bun.OOM; const lex = bun.js_lexer; const logger = bun.logger; @@ -45,6 +46,44 @@ const Test = TestRunner.Test; const CodeCoverageReport = bun.sourcemap.CodeCoverageReport; const uws = bun.uws; +fn escapeXml(str: string, writer: anytype) !void { + var last: usize = 0; + var i: usize = 0; + const len = str.len; + while (i < len) : (i += 1) { + const c = str[i]; + switch (c) { + '&', + '<', + '>', + '"', + '\'', + => { + if (i > last) { + try writer.writeAll(str[last..i]); + } + const escaped = switch (c) { + '&' => "&", + '<' => "<", + '>' => ">", + '"' => """, + '\'' => "'", + else => unreachable, + }; + try writer.writeAll(escaped); + last = i + 1; + }, + 0...0x1f => { + // Escape all control characters + try writer.print("&#{d};", .{c}); + }, + else => {}, + } + } + if (len > last) { + try writer.writeAll(str[last..]); + } +} fn fmtStatusTextLine(comptime status: @Type(.EnumLiteral), comptime emoji_or_color: bool) []const u8 { comptime { // emoji and color might be split into two different options in the future @@ -76,6 +115,357 @@ fn writeTestStatusLine(comptime status: @Type(.EnumLiteral), writer: anytype) vo writer.print(fmtStatusTextLine(status, false), .{}) catch unreachable; } +// Remaining TODOs: +// - Add stdout/stderr to the JUnit report +// - Add timestamp field to the JUnit report +pub const JunitReporter = struct { + contents: std.ArrayListUnmanaged(u8) = .{}, + total_metrics: Metrics = .{}, + testcases_metrics: Metrics = .{}, + offset_of_testsuites_value: usize = 0, + offset_of_testsuite_value: usize = 0, + current_file: string = "", + properties_list_to_repeat_in_every_test_suite: ?[]const u8 = null, + + hostname_value: ?string = null, + + pub fn getHostname(this: *JunitReporter) ?string { + if (this.hostname_value == null) { + if (Environment.isWindows) { + return null; + } + + var name_buffer: [bun.HOST_NAME_MAX]u8 = undefined; + const hostname = std.posix.gethostname(&name_buffer) catch { + this.hostname_value = ""; + return null; + }; + + var arraylist_writer = std.ArrayList(u8).init(bun.default_allocator); + escapeXml(hostname, arraylist_writer.writer()) catch { + this.hostname_value = ""; + return null; + }; + this.hostname_value = arraylist_writer.items; + } + + if (this.hostname_value) |hostname| { + if (hostname.len > 0) { + return hostname; + } + } + return null; + } + + const Metrics = struct { + test_cases: u32 = 0, + assertions: u32 = 0, + failures: u32 = 0, + skipped: u32 = 0, + elapsed_time: u64 = 0, + + pub fn add(this: *Metrics, other: *const Metrics) void { + this.test_cases += other.test_cases; + this.assertions += other.assertions; + this.failures += other.failures; + this.skipped += other.skipped; + } + }; + pub fn init() *JunitReporter { + return JunitReporter.new( + .{ .contents = .{}, .total_metrics = .{} }, + ); + } + + pub usingnamespace bun.New(JunitReporter); + + fn generatePropertiesList(this: *JunitReporter) !void { + const PropertiesList = struct { + ci: string, + commit: string, + }; + var arena = std.heap.ArenaAllocator.init(bun.default_allocator); + defer arena.deinit(); + var stack = std.heap.stackFallback(1024, arena.allocator()); + const allocator = stack.get(); + + const properties: PropertiesList = .{ + .ci = brk: { + if (bun.getenvZ("GITHUB_RUN_ID")) |github_run_id| { + if (bun.getenvZ("GITHUB_SERVER_URL")) |github_server_url| { + if (bun.getenvZ("GITHUB_REPOSITORY")) |github_repository| { + if (github_run_id.len > 0 and github_server_url.len > 0 and github_repository.len > 0) { + break :brk try std.fmt.allocPrint(allocator, "{s}/{s}/actions/runs/{s}", .{ github_server_url, github_repository, github_run_id }); + } + } + } + } + + if (bun.getenvZ("CI_JOB_URL")) |ci_job_url| { + if (ci_job_url.len > 0) { + break :brk ci_job_url; + } + } + + break :brk ""; + }, + .commit = brk: { + if (bun.getenvZ("GITHUB_SHA")) |github_sha| { + if (github_sha.len > 0) { + break :brk github_sha; + } + } + + if (bun.getenvZ("CI_COMMIT_SHA")) |sha| { + if (sha.len > 0) { + break :brk sha; + } + } + + if (bun.getenvZ("GIT_SHA")) |git_sha| { + if (git_sha.len > 0) { + break :brk git_sha; + } + } + + break :brk ""; + }, + }; + + if (properties.ci.len == 0 and properties.commit.len == 0) { + this.properties_list_to_repeat_in_every_test_suite = ""; + return; + } + + var buffer = std.ArrayList(u8).init(bun.default_allocator); + var writer = buffer.writer(); + + try writer.writeAll( + \\ + \\ + ); + + if (properties.ci.len > 0) { + try writer.writeAll( + \\ \n"); + } + if (properties.commit.len > 0) { + try writer.writeAll( + \\ \n"); + } + + try writer.writeAll(" \n"); + + this.properties_list_to_repeat_in_every_test_suite = buffer.items; + } + + pub fn beginTestSuite(this: *JunitReporter, name: string) !void { + if (this.contents.items.len == 0) { + try this.contents.appendSlice(bun.default_allocator, + \\ + \\ + ); + + try this.contents.appendSlice(bun.default_allocator, + \\\n"); + } + + try this.contents.appendSlice(bun.default_allocator, + \\ \n"); + + if (this.properties_list_to_repeat_in_every_test_suite == null) { + try this.generatePropertiesList(); + } + + if (this.properties_list_to_repeat_in_every_test_suite) |properties_list| { + if (properties_list.len > 0) { + try this.contents.appendSlice(bun.default_allocator, properties_list); + } + } + + this.current_file = name; + } + + pub fn endTestSuite(this: *JunitReporter) !void { + var arena = std.heap.ArenaAllocator.init(bun.default_allocator); + defer arena.deinit(); + var stack_fallback_allocator = std.heap.stackFallback(4096, arena.allocator()); + const allocator = stack_fallback_allocator.get(); + + const metrics = &this.testcases_metrics; + this.total_metrics.add(metrics); + + const elapsed_time_ms = metrics.elapsed_time; + const elapsed_time_ms_f64: f64 = @floatFromInt(elapsed_time_ms); + const elapsed_time_seconds = elapsed_time_ms_f64 / std.time.ms_per_s; + + // Insert the summary attributes + const summary = try std.fmt.allocPrint(allocator, + \\tests="{d}" assertions="{d}" failures="{d}" skipped="{d}" time="{d}" hostname="{s}" + , .{ + metrics.test_cases, + metrics.assertions, + metrics.failures, + metrics.skipped, + elapsed_time_seconds, + this.getHostname() orelse "", + }); + this.testcases_metrics = .{}; + this.contents.insertSlice(bun.default_allocator, this.offset_of_testsuite_value, summary) catch bun.outOfMemory(); + + try this.contents.appendSlice(bun.default_allocator, " \n"); + } + + pub fn writeTestCase( + this: *JunitReporter, + status: TestRunner.Test.Status, + file: string, + name: string, + class_name: string, + assertions: u32, + elapsed_ns: u64, + ) !void { + const elapsed_ns_f64: f64 = @floatFromInt(elapsed_ns); + const elapsed_ms = elapsed_ns_f64 / std.time.ns_per_ms; + this.testcases_metrics.elapsed_time +|= @as(u64, @intFromFloat(elapsed_ms)); + this.testcases_metrics.test_cases += 1; + + try this.contents.appendSlice(bun.default_allocator, " { + try this.contents.appendSlice(bun.default_allocator, " />\n"); + }, + .fail => { + this.testcases_metrics.failures += 1; + try this.contents.appendSlice(bun.default_allocator, ">\n \n \n"); + // TODO: add the failure message + // if (failure_message) |msg| { + // try this.contents.appendSlice(bun.default_allocator, " message=\""); + // try escapeXml(msg, this.contents.writer(bun.default_allocator)); + // try this.contents.appendSlice(bun.default_allocator, "\""); + // } + }, + .fail_because_expected_assertion_count => { + this.testcases_metrics.failures += 1; + // TODO: add the failure message + try this.contents.writer(bun.default_allocator).print( + \\> + \\ + \\ + , .{assertions}); + }, + .fail_because_todo_passed => { + this.testcases_metrics.failures += 1; + // TODO: add the failure message + try this.contents.writer(bun.default_allocator).print( + \\> + \\ + \\ + , .{}); + }, + .fail_because_expected_has_assertions => { + this.testcases_metrics.failures += 1; + try this.contents.writer(bun.default_allocator).print( + \\> + \\ + \\ + , .{}); + }, + .skip => { + this.testcases_metrics.skipped += 1; + try this.contents.appendSlice(bun.default_allocator, ">\n \n \n"); + }, + .todo => { + this.testcases_metrics.skipped += 1; + try this.contents.appendSlice(bun.default_allocator, ">\n \n \n"); + }, + .pending => unreachable, + } + } + + pub fn writeToFile(this: *JunitReporter, path: string) !void { + if (this.contents.items.len == 0) return; + { + var arena = std.heap.ArenaAllocator.init(bun.default_allocator); + defer arena.deinit(); + var stack_fallback_allocator = std.heap.stackFallback(4096, arena.allocator()); + const allocator = stack_fallback_allocator.get(); + const metrics = this.total_metrics; + const elapsed_time = @as(f64, @floatFromInt(std.time.nanoTimestamp() - bun.start_time)) / std.time.ns_per_s; + const summary = try std.fmt.allocPrint(allocator, + \\tests="{d}" assertions="{d}" failures="{d}" skipped="{d}" time="{d}" + , .{ + metrics.test_cases, + metrics.assertions, + metrics.failures, + metrics.skipped, + elapsed_time, + }); + this.contents.insertSlice(bun.default_allocator, this.offset_of_testsuites_value, summary) catch bun.outOfMemory(); + this.contents.appendSlice(bun.default_allocator, "\n") catch bun.outOfMemory(); + } + + var junit_path_buf: bun.PathBuffer = undefined; + + @memcpy(junit_path_buf[0..path.len], path); + junit_path_buf[path.len] = 0; + + switch (bun.sys.File.openat(std.fs.cwd(), junit_path_buf[0..path.len :0], bun.O.WRONLY | bun.O.CREAT | bun.O.TRUNC, 0o664)) { + .err => |err| { + Output.err(error.JUnitReportFailed, "Failed to write JUnit report to {s}\n{}", .{ path, err }); + }, + .result => |fd| { + defer _ = fd.close(); + switch (bun.sys.File.writeAll(fd, this.contents.items)) { + .result => {}, + .err => |err| { + Output.err(error.JUnitReportFailed, "Failed to write JUnit report to {s}\n{}", .{ path, err }); + }, + } + }, + } + } + + pub fn deinit(this: *JunitReporter) void { + this.contents.deinit(bun.default_allocator); + } +}; + pub const CommandLineReporter = struct { jest: TestRunner, callback: TestRunner.Callback, @@ -88,6 +478,12 @@ pub const CommandLineReporter = struct { skips_to_repeat_buf: std.ArrayListUnmanaged(u8) = .{}, todos_to_repeat_buf: std.ArrayListUnmanaged(u8) = .{}, + file_reporter: ?FileReporter = null, + + pub const FileReporter = union(enum) { + junit: *JunitReporter, + }; + pub const Summary = struct { pass: u32 = 0, expectations: u32 = 0, @@ -110,7 +506,17 @@ pub const CommandLineReporter = struct { pub fn handleTestStart(_: *TestRunner.Callback, _: Test.ID) void {} - fn printTestLine(label: string, elapsed_ns: u64, parent: ?*jest.DescribeScope, comptime skip: bool, writer: anytype) void { + fn printTestLine( + status: TestRunner.Test.Status, + label: string, + elapsed_ns: u64, + parent: ?*jest.DescribeScope, + assertions: u32, + comptime skip: bool, + writer: anytype, + file: string, + file_reporter: ?FileReporter, + ) void { var scopes_stack = std.BoundedArray(*jest.DescribeScope, 64).init(0) catch unreachable; var parent_ = parent; @@ -165,9 +571,51 @@ pub const CommandLineReporter = struct { } writer.writeAll("\n") catch unreachable; + + if (file_reporter) |reporter| { + switch (reporter) { + .junit => |junit| { + const filename = brk: { + if (strings.hasPrefix(file, bun.fs.FileSystem.instance.top_level_dir)) { + break :brk strings.withoutLeadingPathSeparator(file[bun.fs.FileSystem.instance.top_level_dir.len..]); + } else { + break :brk file; + } + }; + if (!strings.eql(junit.current_file, filename)) { + if (junit.current_file.len > 0) { + junit.endTestSuite() catch bun.outOfMemory(); + } + + junit.beginTestSuite(filename) catch bun.outOfMemory(); + } + + var arena = std.heap.ArenaAllocator.init(bun.default_allocator); + defer arena.deinit(); + var stack_fallback = std.heap.stackFallback(4096, arena.allocator()); + const allocator = stack_fallback.get(); + var concatenated_describe_scopes = std.ArrayList(u8).init(allocator); + + { + const initial_length = concatenated_describe_scopes.items.len; + for (scopes) |scope| { + if (scope.label.len > 0) { + if (initial_length != concatenated_describe_scopes.items.len) { + concatenated_describe_scopes.appendSlice(" > ") catch bun.outOfMemory(); + } + + escapeXml(scope.label, concatenated_describe_scopes.writer()) catch bun.outOfMemory(); + } + } + } + + junit.writeTestCase(status, filename, display_label, concatenated_describe_scopes.items, assertions, elapsed_ns) catch bun.outOfMemory(); + }, + } + } } - pub fn handleTestPass(cb: *TestRunner.Callback, id: Test.ID, _: string, label: string, expectations: u32, elapsed_ns: u64, parent: ?*jest.DescribeScope) void { + pub fn handleTestPass(cb: *TestRunner.Callback, id: Test.ID, file: string, label: string, expectations: u32, elapsed_ns: u64, parent: ?*jest.DescribeScope) void { const writer_ = Output.errorWriter(); var buffered_writer = std.io.bufferedWriter(writer_); var writer = buffered_writer.writer(); @@ -177,14 +625,14 @@ pub const CommandLineReporter = struct { writeTestStatusLine(.pass, &writer); - printTestLine(label, elapsed_ns, parent, false, writer); + printTestLine(.pass, label, elapsed_ns, parent, expectations, false, writer, file, this.file_reporter); this.jest.tests.items(.status)[id] = TestRunner.Test.Status.pass; this.summary.pass += 1; this.summary.expectations += expectations; } - pub fn handleTestFail(cb: *TestRunner.Callback, id: Test.ID, _: string, label: string, expectations: u32, elapsed_ns: u64, parent: ?*jest.DescribeScope) void { + pub fn handleTestFail(cb: *TestRunner.Callback, id: Test.ID, file: string, label: string, expectations: u32, elapsed_ns: u64, parent: ?*jest.DescribeScope) void { var writer_ = Output.errorWriter(); var this: *CommandLineReporter = @fieldParentPtr("callback", cb); @@ -194,7 +642,7 @@ pub const CommandLineReporter = struct { var writer = this.failures_to_repeat_buf.writer(bun.default_allocator); writeTestStatusLine(.fail, &writer); - printTestLine(label, elapsed_ns, parent, false, writer); + printTestLine(.fail, label, elapsed_ns, parent, expectations, false, writer, file, this.file_reporter); // We must always reset the colors because (skip) will have set them to if (Output.enable_ansi_colors_stderr) { @@ -217,7 +665,7 @@ pub const CommandLineReporter = struct { } } - pub fn handleTestSkip(cb: *TestRunner.Callback, id: Test.ID, _: string, label: string, expectations: u32, elapsed_ns: u64, parent: ?*jest.DescribeScope) void { + pub fn handleTestSkip(cb: *TestRunner.Callback, id: Test.ID, file: string, label: string, expectations: u32, elapsed_ns: u64, parent: ?*jest.DescribeScope) void { var writer_ = Output.errorWriter(); var this: *CommandLineReporter = @fieldParentPtr("callback", cb); @@ -229,7 +677,7 @@ pub const CommandLineReporter = struct { var writer = this.skips_to_repeat_buf.writer(bun.default_allocator); writeTestStatusLine(.skip, &writer); - printTestLine(label, elapsed_ns, parent, true, writer); + printTestLine(.skip, label, elapsed_ns, parent, expectations, true, writer, file, this.file_reporter); writer_.writeAll(this.skips_to_repeat_buf.items[initial_length..]) catch unreachable; Output.flush(); @@ -241,7 +689,7 @@ pub const CommandLineReporter = struct { this.jest.tests.items(.status)[id] = TestRunner.Test.Status.skip; } - pub fn handleTestTodo(cb: *TestRunner.Callback, id: Test.ID, _: string, label: string, expectations: u32, elapsed_ns: u64, parent: ?*jest.DescribeScope) void { + pub fn handleTestTodo(cb: *TestRunner.Callback, id: Test.ID, file: string, label: string, expectations: u32, elapsed_ns: u64, parent: ?*jest.DescribeScope) void { var writer_ = Output.errorWriter(); var this: *CommandLineReporter = @fieldParentPtr("callback", cb); @@ -252,7 +700,7 @@ pub const CommandLineReporter = struct { var writer = this.todos_to_repeat_buf.writer(bun.default_allocator); writeTestStatusLine(.todo, &writer); - printTestLine(label, elapsed_ns, parent, true, writer); + printTestLine(.todo, label, elapsed_ns, parent, expectations, true, writer, file, this.file_reporter); writer_.writeAll(this.todos_to_repeat_buf.items[initial_length..]) catch unreachable; Output.flush(); @@ -723,6 +1171,10 @@ pub const TestCommand = struct { lcov: bool, }; + pub const FileReporter = enum { + junit, + }; + pub fn exec(ctx: Command.Context) !void { if (comptime is_bindgen) unreachable; @@ -782,6 +1234,13 @@ pub const TestCommand = struct { reporter.jest.callback = &reporter.callback; jest.Jest.runner = &reporter.jest; reporter.jest.test_options = &ctx.test_options; + + if (ctx.test_options.file_reporter) |file_reporter| { + reporter.file_reporter = switch (file_reporter) { + .junit => .{ .junit = JunitReporter.init() }, + }; + } + js_ast.Expr.Data.Store.create(); js_ast.Stmt.Data.Store.create(); var vm = try JSC.VirtualMachine.init( @@ -1089,6 +1548,17 @@ pub const TestCommand = struct { Output.prettyError("\n", .{}); Output.flush(); + if (reporter.file_reporter) |file_reporter| { + switch (file_reporter) { + .junit => |junit| { + if (junit.current_file.len > 0) { + junit.endTestSuite() catch {}; + } + junit.writeToFile(ctx.test_options.reporter_outfile.?) catch {}; + }, + } + } + if (vm.hot_reload == .watch) { vm.eventLoop().tickPossiblyForever(); diff --git a/test/bun.lockb b/test/bun.lockb index b025efa7b6e56282a7d06294365885b65abaf58a..13caab649147e2c3f097ca8a0534289c5b204c98 100755 GIT binary patch delta 69501 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

>2LP#vTyWe%x}DOFt`vz}>}XNgEUP%~%> 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 CoT9G) diff --git a/test/js/junit-reporter/junit.test.js b/test/js/junit-reporter/junit.test.js new file mode 100644 index 00000000000000..fdbc19196ba94c --- /dev/null +++ b/test/js/junit-reporter/junit.test.js @@ -0,0 +1,234 @@ +import { it, describe, expect } from "bun:test"; +import { file, spawn } from "bun"; +import { tempDirWithFiles, bunEnv, bunExe } from "harness"; + +const xml2js = require("xml2js"); + +describe("junit reporter", () => { + for (let withCIEnvironmentVariables of [false, true]) { + it(`should generate valid junit xml for passing tests ${withCIEnvironmentVariables ? "with CI environment variables" : ""}`, async () => { + const tmpDir = tempDirWithFiles("junit", { + "package.json": "{}", + "passing.test.js": ` + + it("should pass", () => { + expect(1 + 1).toBe(2); + }); + + it("second test", () => { + expect(1 + 1).toBe(2); + }); + + it("failing test", () => { + expect(1 + 1).toBe(3); + }); + + it.skip("skipped test", () => { + expect(1 + 1).toBe(2); + }); + + it.todo("todo test"); + + describe("nested describe", () => { + it("should pass inside nested describe", () => { + expect(1 + 1).toBe(2); + }); + + it("should fail inside nested describe", () => { + expect(1 + 1).toBe(3); + }); + }); + `, + + "test-2.test.js": ` + + it("should pass", () => { + expect(1 + 1).toBe(2); + }); + + it("failing test", () => { + expect(1 + 1).toBe(3); + }); + + describe("nested describe", () => { + it("should pass inside nested describe", () => { + expect(1 + 1).toBe(2); + }); + + it("should fail inside nested describe", () => { + expect(1 + 1).toBe(3); + }); + }); + `, + }); + + let env = bunEnv; + + if (withCIEnvironmentVariables) { + env = { + ...env, + CI_JOB_URL: "https://ci.example.com/123", + CI_COMMIT_SHA: "1234567890", + }; + } + + const junitPath = `${tmpDir}/junit.xml`; + const proc = spawn([bunExe(), "test", "--reporter=junit", "--reporter-outfile", junitPath], { + cwd: tmpDir, + env, + stdout: "inherit", + "stderr": "inherit", + }); + await proc.exited; + console.log(junitPath); + + expect(proc.exitCode).toBe(1); + const xmlContent = await file(junitPath).text(); + + // Parse XML to verify structure + const result = await new Promise((resolve, reject) => { + xml2js.parseString(xmlContent, (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }); + + /** + * ------ Vitest ------ + * + * + * + * + * + * + * + * + * + * AssertionError: expected 2 to be 3 // Object.is equality + * + * - Expected + * + Received + * + * - 3 + * + 2 + * + * ❯ passing.test.js:12:25 + * + * + + * + * + * + * + * + * + * + * + * + * AssertionError: expected 2 to be 3 // Object.is equality + * + * - Expected + * + Received + * + * - 3 + * + 2 + * + * ❯ passing.test.js:27:27 + * + * + + * + * + * + * + * + * AssertionError: expected 2 to be 3 // Object.is equality + * + * - Expected + * + Received + * + * - 3 + * + 2 + * + * ❯ test-2.test.js:8:25 + * + * + * + * + * + * + * AssertionError: expected 2 to be 3 // Object.is equality + * + * - Expected + * + Received + * + * - 3 + * + 2 + * + * ❯ test-2.test.js:17:27 + * + * + * + * + */ + + expect(result.testsuites).toBeDefined(); + expect(result.testsuites.testsuite).toBeDefined(); + + let firstSuite = result.testsuites.testsuite[0]; + let secondSuite = result.testsuites.testsuite[1]; + + if (firstSuite.$.name === "passing.test.js") { + [firstSuite, secondSuite] = [secondSuite, firstSuite]; + } + + expect(firstSuite.testcase).toHaveLength(4); + expect(firstSuite.testcase[0].$.name).toBe("should pass inside nested describe"); + expect(firstSuite.$.name).toBe("test-2.test.js"); + expect(firstSuite.$.tests).toBe("4"); + expect(firstSuite.$.failures).toBe("2"); + expect(firstSuite.$.skipped).toBe("0"); + expect(parseFloat(firstSuite.$.time)).toBeGreaterThanOrEqual(0.0); + + expect(secondSuite.testcase).toHaveLength(7); + expect(secondSuite.testcase[0].$.name).toBe("should pass inside nested describe"); + expect(secondSuite.$.name).toBe("passing.test.js"); + expect(secondSuite.$.tests).toBe("7"); + expect(secondSuite.$.failures).toBe("2"); + expect(secondSuite.$.skipped).toBe("2"); + expect(parseFloat(secondSuite.$.time)).toBeGreaterThanOrEqual(0.0); + + expect(result.testsuites.$.tests).toBe("11"); + expect(result.testsuites.$.failures).toBe("4"); + expect(result.testsuites.$.skipped).toBe("2"); + expect(parseFloat(result.testsuites.$.time)).toBeGreaterThanOrEqual(0.0); + + if (withCIEnvironmentVariables) { + // "properties": [ + // { + // "property": [ + // { + // "$": { + // "name": "ci", + // "value": "https://ci.example.com/123" + // } + // }, + // { + // "$": { + // "name": "commit", + // "value": "1234567890" + // } + // } + // ] + // } + // ], + expect(firstSuite.properties).toHaveLength(1); + expect(firstSuite.properties[0].property).toHaveLength(2); + expect(firstSuite.properties[0].property[0].$.name).toBe("ci"); + expect(firstSuite.properties[0].property[0].$.value).toBe("https://ci.example.com/123"); + expect(firstSuite.properties[0].property[1].$.name).toBe("commit"); + expect(firstSuite.properties[0].property[1].$.value).toBe("1234567890"); + } + }); + } +}); diff --git a/test/package.json b/test/package.json index 3f75a236a42d80..b360be82bbb2e8 100644 --- a/test/package.json +++ b/test/package.json @@ -65,6 +65,7 @@ "vitest": "0.32.2", "webpack": "5.88.0", "webpack-cli": "4.7.2", + "xml2js": "0.6.2", "yargs": "17.7.2" }, "private": true,