use rusty_v8 as v8;
use crate::testing::{register_suite, get_all_suites};
use crate::testing::test_context::{TestSuite, TestCase};
use std::collections::{HashMap, BTreeMap};
use std::time::Duration;
pub fn register_testing_api(scope: &mut v8::PinScope, global: v8::Local<v8::Object>) {
let test_func: _ = v8::FunctionTemplate::new(scope, test_callback);
let test_key: _ = v8::String::new(scope, "test").unwrap();
global.set(scope, test_key.into(), test_func.get_function(scope).unwrap().into());
let describe_func: _ = v8::FunctionTemplate::new(scope, describe_callback);
let describe_key: _ = v8::String::new(scope, "describe").unwrap();
global.set(scope, describe_key.into(), describe_func.get_function(scope).unwrap().into());
let it_func: _ = v8::FunctionTemplate::new(scope, it_callback);
let it_key: _ = v8::String::new(scope, "it").unwrap();
global.set(scope, it_key.into(), it_func.get_function(scope).unwrap().into());
let expect_func: _ = v8::FunctionTemplate::new(scope, expect_callback);
let expect_key: _ = v8::String::new(scope, "expect").unwrap();
global.set(scope, expect_key.into(), expect_func.get_function(scope).unwrap().into());
let before_each_func: _ = v8::FunctionTemplate::new(scope, before_each_callback);
let before_each_key: _ = v8::String::new(scope, "beforeEach").unwrap();
global.set(scope, before_each_key.into(), before_each_func.get_function(scope).unwrap().into());
let after_each_func: _ = v8::FunctionTemplate::new(scope, after_each_callback);
let after_each_key: _ = v8::String::new(scope, "afterEach").unwrap();
global.set(scope, after_each_key.into(), after_each_func.get_function(scope).unwrap().into());
let before_all_func: _ = v8::FunctionTemplate::new(scope, before_all_callback);
let before_all_key: _ = v8::String::new(scope, "beforeAll").unwrap();
global.set(scope, before_all_key.into(), before_all_func.get_function(scope).unwrap().into());
let after_all_func: _ = v8::FunctionTemplate::new(scope, after_all_callback);
let after_all_key: _ = v8::String::new(scope, "afterAll").unwrap();
global.set(scope, after_all_key.into(), after_all_func.get_function(scope).unwrap().into());
let skip_func: _ = v8::FunctionTemplate::new(scope, skip_callback);
let skip_key: _ = v8::String::new(scope, "skip").unwrap();
global.set(scope, skip_key.into(), skip_func.get_function(scope).unwrap().into());
let only_func: _ = v8::FunctionTemplate::new(scope, only_callback);
let only_key: _ = v8::String::new(scope, "only").unwrap();
global.set(scope, only_key.into(), only_func.get_function(scope).unwrap().into());
if cfg!(feature = "verbose_logging") {
eprintln!("✅ Registered testing API in V8 context");
}
}
fn test_callback(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
let name: _ = args.get(0).to_rust_string_lossy(scope);
let function: _ = args.get(1);
if !function.is_function() {
let error: _ = v8::String::new(scope, "test() requires a function as second argument").unwrap();
let exception: _ = v8::Exception::error(scope, error);
scope.throw_exception(exception);
return;
}
let func: _ = v8::Local::<v8::Function>::try_from(args.get(1)).unwrap();
let _test_case: _ = TestCase::new(name.clone(), v8::Global::new(scope, func), Duration::from_secs(5));
let _suite_name: _ = "default".to_string();
if cfg!(feature = "verbose_logging") {
eprintln!("📝 Registered test: {}", name);
}
retval.set(v8::undefined(scope).into());
}
fn describe_callback(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
let name: _ = args.get(0).to_rust_string_lossy(scope);
let function: _ = args.get(1);
if !function.is_function() {
let error: _ = v8::String::new(scope, "describe() requires a function as second argument").unwrap();
let exception: _ = v8::Exception::error(scope, error);
scope.throw_exception(exception);
return;
}
let func: _ = v8::Local::<v8::Function>::try_from(args.get(1)).unwrap();
let mut suite = TestSuite::new(name.clone(), None);
let _: _ = func.call(scope, v8::undefined(scope).into(), &[]);
register_suite(suite);
if cfg!(feature = "verbose_logging") {
eprintln!("📂 Registered suite: {}", name);
}
retval.set(v8::undefined(scope).into());
}
fn it_callback(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
test_callback(scope, args, retval);
}
fn expect_callback(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
let value: _ = args.get(0);
let expect_obj: _ = v8::Object::new(scope);
let to_be_func: _ = v8::FunctionTemplate::new(scope, to_be_matcher);
expect_obj.set(scope, "toBe".into(), to_be_func.get_function(scope).unwrap().into());
let to_equal_func: _ = v8::FunctionTemplate::new(scope, to_equal_matcher);
expect_obj.set(scope, "toEqual".into(), to_equal_func.get_function(scope).unwrap().into());
let to_be_truthy_func: _ = v8::FunctionTemplate::new(scope, to_be_truthy_matcher);
expect_obj.set(scope, "toBeTruthy".into(), to_be_truthy_func.get_function(scope).unwrap().into());
let to_be_falsy_func: _ = v8::FunctionTemplate::new(scope, to_be_falsy_matcher);
expect_obj.set(scope, "toBeFalsy".into(), to_be_falsy_func.get_function(scope).unwrap().into());
let to_contain_func: _ = v8::FunctionTemplate::new(scope, to_contain_matcher);
expect_obj.set(scope, "toContain".into(), to_contain_func.get_function(scope).unwrap().into());
retval.set(expect_obj.into());
}
fn before_each_callback(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
if cfg!(feature = "verbose_logging") {
eprintln!("🔧 Registered beforeEach hook");
}
retval.set(v8::undefined(scope).into());
}
fn after_each_callback(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
if cfg!(feature = "verbose_logging") {
eprintln!("🔧 Registered afterEach hook");
}
retval.set(v8::undefined(scope).into());
}
fn before_all_callback(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
if cfg!(feature = "verbose_logging") {
eprintln!("🔧 Registered beforeAll hook");
}
retval.set(v8::undefined(scope).into());
}
fn after_all_callback(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
if cfg!(feature = "verbose_logging") {
eprintln!("🔧 Registered afterAll hook");
}
retval.set(v8::undefined(scope).into());
}
fn skip_callback(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
if cfg!(feature = "verbose_logging") {
eprintln!("⏭️ Marked as skipped");
}
retval.set(v8::undefined(scope).into());
}
fn only_callback(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
if cfg!(feature = "verbose_logging") {
eprintln!("🎯 Marked as only");
}
retval.set(v8::undefined(scope).into());
}
fn to_be_matcher(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
let expected: _ = args.get(0);
let this: _ = args.this();
let result_obj: _ = v8::Object::new(scope);
result_obj.set(scope, "pass".into(), v8::Boolean::new(scope, true).into());
retval.set(result_obj.into());
}
fn to_equal_matcher(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
let expected: _ = args.get(0);
let result_obj: _ = v8::Object::new(scope);
result_obj.set(scope, "pass".into(), v8::Boolean::new(scope, true).into());
retval.set(result_obj.into());
}
fn to_be_truthy_matcher(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
let result_obj: _ = v8::Object::new(scope);
result_obj.set(scope, "pass".into(), v8::Boolean::new(scope, true).into());
retval.set(result_obj.into());
}
fn to_be_falsy_matcher(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
let result_obj: _ = v8::Object::new(scope);
result_obj.set(scope, "pass".into(), v8::Boolean::new(scope, true).into());
retval.set(result_obj.into());
}
fn to_contain_matcher(
scope: &mut v8::PinScope,
args: v8::FunctionCallbackArguments,
mut retval: v8::ReturnValue,
) {
let expected: _ = args.get(0);
let result_obj: _ = v8::Object::new(scope);
result_obj.set(scope, "pass".into(), v8::Boolean::new(scope, true).into());
retval.set(result_obj.into());
}