diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index aeeab684..41a11110 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -674,7 +674,7 @@ extern "C" { /// /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply #[wasm_bindgen(method)] - pub fn apply(this: &Function, context: &JsValue, args: &Array) -> Function; + pub fn apply(this: &Function, context: &JsValue, args: &Array) -> JsValue; /// The bind() method creates a new function that, when called, has its this keyword set to the provided value, /// with a given sequence of arguments preceding any provided when the new function is called. diff --git a/crates/js-sys/tests/all/Function.rs b/crates/js-sys/tests/all/Function.rs deleted file mode 100644 index 23755f48..00000000 --- a/crates/js-sys/tests/all/Function.rs +++ /dev/null @@ -1,208 +0,0 @@ -#![allow(non_snake_case)] - -use project; - -#[test] -fn apply() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - extern crate js_sys; - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub fn apply(this: &js_sys::Function, context: &JsValue, args: &js_sys::Array) -> js_sys::Function { - this.apply(context, args) - } - "#, - ) - .file( - "test.js", - r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - assert.equal(wasm.apply(Math.max, {}, [1, 2, 3]), 3); - - const arr = [1, 2]; - wasm.apply(Array.prototype.push, arr, [3]); - assert.equal(arr[2], 3); - } - "#, - ) - .test() -} - -#[test] -fn bind() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - extern crate js_sys; - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub fn bind(this: &js_sys::Function, context: &JsValue) -> js_sys::Function { - this.bind(context) - } - "#, - ) - .file( - "test.js", - r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - const obj = { - a: 0, - fn: function () { - return this.a + 1; - } - } - - const boundFn = wasm.bind(obj.fn, { a: 41 }); - assert.equal(boundFn(), 42); - } - "#, - ) - .test() -} - -#[test] -fn length() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - extern crate js_sys; - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub fn fn_length(this: &js_sys::Function) -> u32 { - this.length() - } - "#, - ) - .file( - "test.js", - r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - assert.equal(wasm.fn_length(() => {}), 0); - assert.equal(wasm.fn_length(a => console.log(a)), 1); - assert.equal(wasm.fn_length((a, b) => console.log({ a, b })), 2); - - function fn0() {} - function fn1(a) { - console.log(a); - } - function fn2(a, b) { - console.log({ a, b }); - } - - assert.equal(wasm.fn_length(fn0), 0); - assert.equal(wasm.fn_length(fn1), 1); - assert.equal(wasm.fn_length(fn2), 2); - } - "#, - ) - .test() -} - -#[test] -fn name() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - extern crate js_sys; - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub fn fn_name(this: &js_sys::Function) -> js_sys::JsString { - this.name() - } - "#, - ) - .file( - "test.js", - r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - function namedFn() {} - assert.equal(wasm.fn_name(namedFn), 'namedFn'); - - assert.equal(wasm.fn_name(namedFn.bind({})), 'bound namedFn'); - - const obj = { - method: () => {} - } - assert.equal(wasm.fn_name(obj.method), 'method'); - - assert.equal(wasm.fn_name(new Function()), 'anonymous'); - - assert.equal(wasm.fn_name(() => {}), ''); - - const closure = () => {}; - assert.equal(wasm.fn_name(closure), 'closure'); - } - "#, - ) - .test() -} - -#[test] -fn to_string() { - project() - .file( - "src/lib.rs", - r#" - #![feature(use_extern_macros)] - - extern crate wasm_bindgen; - extern crate js_sys; - use wasm_bindgen::prelude::*; - - #[wasm_bindgen] - pub fn get_source_code(this: &js_sys::Function) -> js_sys::JsString { - this.to_string() - } - "#, - ) - .file( - "test.js", - r#" - import * as assert from "assert"; - import * as wasm from "./out"; - - export function test() { - function fn1(a, b) { return a + b; } - const fn2 = a => console.log(a); - - assert.equal(wasm.get_source_code(fn1), 'function fn1(a, b) { return a + b; }'); - assert.equal(wasm.get_source_code(fn2), 'a => console.log(a)'); - } - "#, - ) - .test() -} diff --git a/crates/js-sys/tests/all/main.rs b/crates/js-sys/tests/all/main.rs index 69010cac..ddfe145f 100644 --- a/crates/js-sys/tests/all/main.rs +++ b/crates/js-sys/tests/all/main.rs @@ -11,7 +11,6 @@ fn project() -> project_builder::Project { // Keep these tests in alphabetical order, just like the imports in `src/js.rs`. mod ArrayIterator; -mod Function; mod Generator; mod Intl; mod JsString; diff --git a/crates/js-sys/tests/wasm/Function.js b/crates/js-sys/tests/wasm/Function.js new file mode 100644 index 00000000..f445792d --- /dev/null +++ b/crates/js-sys/tests/wasm/Function.js @@ -0,0 +1,10 @@ +// Used for `Function.rs` tests +exports.get_function_to_bind = function() { + return function() { return this.x || 1; } +}; +exports.get_value_to_bind_to = function() { + return { x: 2 }; +}; +exports.call_function = function(f) { + return f(); +}; diff --git a/crates/js-sys/tests/wasm/Function.rs b/crates/js-sys/tests/wasm/Function.rs new file mode 100644 index 00000000..258e153b --- /dev/null +++ b/crates/js-sys/tests/wasm/Function.rs @@ -0,0 +1,62 @@ +use wasm_bindgen::prelude::*; +use wasm_bindgen_test::*; +use js_sys::*; + +#[wasm_bindgen] +extern { + #[wasm_bindgen(js_name = max, js_namespace = Math)] + static MAX: Function; + + type ArrayPrototype; + #[wasm_bindgen(method, getter, structural)] + pub fn push(this: &ArrayPrototype) -> Function; + #[wasm_bindgen(js_name = prototype, js_namespace = Array)] + static ARRAY_PROTOTYPE: ArrayPrototype; +} + +#[wasm_bindgen_test] +fn apply() { + let args = Array::new(); + args.push(1.into()); + args.push(2.into()); + args.push(3.into()); + assert_eq!(MAX.apply(&JsValue::undefined(), &args), 3); + + let arr = JsValue::from(Array::new()); + let args = Array::new(); + args.push(1.into()); + ARRAY_PROTOTYPE.push().apply(&arr, &args); + assert_eq!(Array::from(arr).length(), 1); +} + +#[wasm_bindgen(module = "tests/wasm/Function.js", version = "*")] +extern { + fn get_function_to_bind() -> Function; + fn get_value_to_bind_to() -> JsValue; + fn call_function(f: Function) -> JsValue; +} + +#[wasm_bindgen_test] +fn bind() { + let f = get_function_to_bind(); + let new_f = f.bind(&get_value_to_bind_to()); + assert_eq!(call_function(f), 1); + assert_eq!(call_function(new_f), 2); +} + +#[wasm_bindgen_test] +fn length() { + assert_eq!(MAX.length(), 2); + assert_eq!(ARRAY_PROTOTYPE.push().length(), 1); +} + +#[wasm_bindgen_test] +fn name() { + assert_eq!(JsValue::from(MAX.name()), "max"); + assert_eq!(JsValue::from(ARRAY_PROTOTYPE.push().name()), "push"); +} + +#[wasm_bindgen_test] +fn to_string() { + assert!(MAX.to_string().length() > 0); +} diff --git a/crates/js-sys/tests/wasm/main.rs b/crates/js-sys/tests/wasm/main.rs index a24c8c8a..a09f523a 100644 --- a/crates/js-sys/tests/wasm/main.rs +++ b/crates/js-sys/tests/wasm/main.rs @@ -13,3 +13,4 @@ pub mod Boolean; pub mod DataView; pub mod Date; pub mod Error; +pub mod Function;