aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/test/jest.zig73
1 files changed, 69 insertions, 4 deletions
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig
index 9f96fc1ce..f84106085 100644
--- a/src/bun.js/test/jest.zig
+++ b/src/bun.js/test/jest.zig
@@ -469,6 +469,7 @@ pub const TestRunner = struct {
onTestPass: OnTestUpdate,
onTestFail: OnTestUpdate,
onTestSkip: OnTestUpdate,
+ onTestTodo: OnTestUpdate,
};
pub fn reportPass(this: *TestRunner, test_id: Test.ID, file: string, label: string, expectations: u32, elapsed_ns: u64, parent: ?*DescribeScope) void {
@@ -485,6 +486,11 @@ pub const TestRunner = struct {
this.callback.onTestSkip(this.callback, test_id, file, label, 0, 0, parent);
}
+ pub fn reportTodo(this: *TestRunner, test_id: Test.ID, file: string, label: string, parent: ?*DescribeScope) void {
+ this.tests.items(.status)[test_id] = .todo;
+ this.callback.onTestTodo(this.callback, test_id, file, label, 0, 0, parent);
+ }
+
pub fn addTestCount(this: *TestRunner, count: u32) u32 {
this.tests.ensureUnusedCapacity(this.allocator, count) catch unreachable;
const start = @truncate(Test.ID, this.tests.len);
@@ -532,6 +538,7 @@ pub const TestRunner = struct {
pass,
fail,
skip,
+ todo,
};
};
};
@@ -3159,6 +3166,7 @@ pub const TestScope = struct {
ran: bool = false,
task: ?*TestRunnerTask = null,
skipped: bool = false,
+ is_todo: bool = false,
snapshot_count: usize = 0,
timeout_millis: u32 = default_timeout,
@@ -3169,6 +3177,7 @@ pub const TestScope = struct {
.call = call,
.only = only,
.skip = skip,
+ .todo = todo,
},
.{},
);
@@ -3214,6 +3223,17 @@ pub const TestScope = struct {
return prepare(this, ctx, arguments, exception, .call);
}
+ pub fn todo(
+ _: void,
+ ctx: js.JSContextRef,
+ this: js.JSObjectRef,
+ _: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSObjectRef {
+ return prepare(this, ctx, arguments, exception, .todo);
+ }
+
fn prepare(
this: js.JSObjectRef,
ctx: js.JSContextRef,
@@ -3240,16 +3260,36 @@ pub const TestScope = struct {
label = (label_value.toSlice(ctx, allocator).cloneIfNeeded(allocator) catch unreachable).slice();
}
+ if (tag == .todo and label_value == .zero) {
+ JSError(getAllocator(ctx), "test.todo() requires a description", .{}, ctx, exception);
+ return this;
+ }
+
const function = function_value;
if (function.isEmptyOrUndefinedOrNull() or !function.isCell() or !function.isCallable(ctx.vm())) {
- JSError(getAllocator(ctx), "test() expects a function", .{}, ctx, exception);
- return this;
+ // a callback is not required for .todo
+ if (tag != .todo) {
+ JSError(getAllocator(ctx), "test() expects a function", .{}, ctx, exception);
+ return this;
+ }
}
if (tag == .only) {
Jest.runner.?.setOnly();
}
+ if (tag == .todo) {
+ DescribeScope.active.todo_counter += 1;
+ DescribeScope.active.tests.append(getAllocator(ctx), TestScope{
+ .label = label,
+ .parent = DescribeScope.active,
+ .is_todo = true,
+ .callback = if (function == .zero) null else function.asObjectRef(),
+ }) catch unreachable;
+
+ return this;
+ }
+
if (tag == .skip or (tag != .only and Jest.runner.?.only)) {
DescribeScope.active.skipped_counter += 1;
DescribeScope.active.tests.append(getAllocator(ctx), TestScope{
@@ -3369,10 +3409,15 @@ pub const TestScope = struct {
if (initial_value.isAnyError()) {
if (!Jest.runner.?.did_pending_test_fail) {
- Jest.runner.?.did_pending_test_fail = true;
+ // test failed unless it's a todo
+ Jest.runner.?.did_pending_test_fail = !this.is_todo;
vm.runErrorHandler(initial_value, null);
}
+ if (this.is_todo) {
+ return .{ .todo = {} };
+ }
+
return .{ .fail = active_test_expectation_counter.actual };
}
@@ -3391,10 +3436,15 @@ pub const TestScope = struct {
switch (promise.status(vm.global.vm())) {
.Rejected => {
if (!Jest.runner.?.did_pending_test_fail) {
- Jest.runner.?.did_pending_test_fail = true;
+ // test failed unless it's a todo
+ Jest.runner.?.did_pending_test_fail = !this.is_todo;
vm.runErrorHandler(promise.result(vm.global.vm()), null);
}
+ if (this.is_todo) {
+ return .{ .todo = {} };
+ }
+
return .{ .fail = active_test_expectation_counter.actual };
},
.Pending => {
@@ -3427,6 +3477,11 @@ pub const TestScope = struct {
return .{ .fail = active_test_expectation_counter.actual };
}
+ if (this.is_todo) {
+ Output.prettyErrorln(" <d>^<r> <red>this test is marked as todo but passes.<r> <d>Remove `.todo` or check that test is correct.<r>", .{});
+ return .{ .fail = active_test_expectation_counter.actual };
+ }
+
return .{ .pass = active_test_expectation_counter.actual };
}
@@ -3465,6 +3520,7 @@ pub const DescribeScope = struct {
done: bool = false,
skipped: bool = false,
skipped_counter: u32 = 0,
+ todo_counter: u32 = 0,
pub fn isAllSkipped(this: *const DescribeScope) bool {
return this.skipped or @as(usize, this.skipped_counter) >= this.tests.items.len;
@@ -3940,6 +3996,13 @@ pub const TestRunnerTask = struct {
var test_: TestScope = this.describe.tests.items[test_id];
describe.current_test_id = test_id;
var globalThis = this.globalThis;
+
+ if (!describe.skipped and test_.is_todo and test_.callback == null) {
+ this.processTestResult(globalThis, .{ .todo = {} }, test_, test_id, describe);
+ this.deinit();
+ return false;
+ }
+
if (test_.skipped or describe.skipped) {
this.processTestResult(globalThis, .{ .skip = {} }, test_, test_id, describe);
this.deinit();
@@ -4067,6 +4130,7 @@ pub const TestRunnerTask = struct {
describe,
),
.skip => Jest.runner.?.reportSkip(test_id, this.source_file_path, test_.label, describe),
+ .todo => Jest.runner.?.reportTodo(test_id, this.source_file_path, test_.label, describe),
.pending => @panic("Unexpected pending test"),
}
describe.onTestComplete(globalThis, test_id, result == .skip);
@@ -4101,4 +4165,5 @@ pub const Result = union(TestRunner.Test.Status) {
pass: u32, // assertion count
pending: void,
skip: void,
+ todo: void,
};