Skip to content

Commit 01c127c

Browse files
authored
fix: clearTimeout illegal invocation with bundler (#187) (#283)
* fix: `clearTimeout` illegal invocation in browser (#187) * fix: return type of `Timeout/Interval` accepts both number and `NodeJS.Timeout` * chore: simplify clearTimeout/clearInterval binding refer #283 (comment) for background * CI: setup node tests
1 parent d6d00c3 commit 01c127c

File tree

5 files changed

+171
-13
lines changed

5 files changed

+171
-13
lines changed

.github/workflows/tests.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,43 @@ jobs:
7676
wasm-pack test --headless --firefox --chrome crates/$x --no-default-features
7777
done
7878
79+
node_tests:
80+
name: Node Tests
81+
runs-on: ubuntu-latest
82+
steps:
83+
- uses: actions/checkout@v3
84+
- uses: actions-rs/toolchain@v1
85+
with:
86+
toolchain: stable
87+
target: wasm32-unknown-unknown
88+
override: true
89+
profile: minimal
90+
91+
- name: Install wasm-pack
92+
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
93+
94+
- uses: actions/cache@v3
95+
with:
96+
path: |
97+
~/.cargo/registry
98+
~/.cargo/git
99+
target
100+
key: cargo-${{ runner.os }}-node-tests-${{ hashFiles('**/Cargo.toml') }}
101+
restore-keys: |
102+
cargo-${{ runner.os }}-node-tests-
103+
cargo-${{ runner.os }}-
104+
105+
- name: Run tests
106+
run: |
107+
for x in $(ls crates); do
108+
# gloo-net is tested separately
109+
if [[ "$x" == "net" ]]; then
110+
continue
111+
fi
112+
wasm-pack test --node crates/$x --all-features
113+
wasm-pack test --node crates/$x --no-default-features
114+
done
115+
79116
test-worker:
80117
name: Test gloo-worker
81118
runs-on: ubuntu-latest

CONTRIBUTING.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ yourself.
1717
- [Building](#building)
1818
- [Testing](#testing)
1919
- [Wasm Headless Browser Tests](#wasm-headless-browser-tests)
20+
- [Wasm Node Tests](#wasm-node-tests)
2021
- [Non-Wasm Tests](#non-wasm-tests)
2122
- [Formatting](#formatting)
2223
- [Updating `README.md`s](#updating-readmemds)
@@ -81,6 +82,14 @@ To run headless browser tests for a particular crate:
8182
wasm-pack test crates/my-particular-crate --headless --firefox # or --safari or --chrome
8283
```
8384

85+
#### Wasm Node Tests
86+
87+
To run tests in Node.js:
88+
89+
```shell
90+
wasm-pack test crates/my-particular-crate --node
91+
```
92+
8493
#### Non-Wasm Tests
8594

8695
You can run the non-Wasm tests (e.g. doc tests) for every Gloo crate with:

crates/timers/src/callback.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ use wasm_bindgen::{JsCast, JsValue};
77
#[wasm_bindgen]
88
extern "C" {
99
#[wasm_bindgen(js_name = "setTimeout", catch)]
10-
fn set_timeout(handler: &Function, timeout: i32) -> Result<i32, JsValue>;
10+
fn set_timeout(handler: &Function, timeout: i32) -> Result<JsValue, JsValue>;
1111

1212
#[wasm_bindgen(js_name = "setInterval", catch)]
13-
fn set_interval(handler: &Function, timeout: i32) -> Result<i32, JsValue>;
13+
fn set_interval(handler: &Function, timeout: i32) -> Result<JsValue, JsValue>;
1414

1515
#[wasm_bindgen(js_name = "clearTimeout")]
16-
fn clear_timeout(handle: i32);
16+
fn clear_timeout(handle: JsValue) -> JsValue;
1717

1818
#[wasm_bindgen(js_name = "clearInterval")]
19-
fn clear_interval(handle: i32);
19+
fn clear_interval(handle: JsValue) -> JsValue;
2020
}
2121

2222
/// A scheduled timeout.
@@ -28,15 +28,15 @@ extern "C" {
2828
#[derive(Debug)]
2929
#[must_use = "timeouts cancel on drop; either call `forget` or `drop` explicitly"]
3030
pub struct Timeout {
31-
id: Option<i32>,
31+
id: Option<JsValue>,
3232
closure: Option<Closure<dyn FnMut()>>,
3333
}
3434

3535
impl Drop for Timeout {
3636
/// Disposes of the timeout, dually cancelling this timeout by calling
3737
/// `clearTimeout` directly.
3838
fn drop(&mut self) {
39-
if let Some(id) = self.id {
39+
if let Some(id) = self.id.take() {
4040
clear_timeout(id);
4141
}
4242
}
@@ -90,7 +90,7 @@ impl Timeout {
9090
/// // Do stuff...
9191
/// }).forget();
9292
/// ```
93-
pub fn forget(mut self) -> i32 {
93+
pub fn forget(mut self) -> JsValue {
9494
let id = self.id.take().unwrap_throw();
9595
self.closure.take().unwrap_throw().forget();
9696
id
@@ -130,15 +130,15 @@ impl Timeout {
130130
#[derive(Debug)]
131131
#[must_use = "intervals cancel on drop; either call `forget` or `drop` explicitly"]
132132
pub struct Interval {
133-
id: Option<i32>,
133+
id: Option<JsValue>,
134134
closure: Option<Closure<dyn FnMut()>>,
135135
}
136136

137137
impl Drop for Interval {
138138
/// Disposes of the interval, dually cancelling this interval by calling
139139
/// `clearInterval` directly.
140140
fn drop(&mut self) {
141-
if let Some(id) = self.id {
141+
if let Some(id) = self.id.take() {
142142
clear_interval(id);
143143
}
144144
}
@@ -190,7 +190,7 @@ impl Interval {
190190
/// // Do stuff...
191191
/// }).forget();
192192
/// ```
193-
pub fn forget(mut self) -> i32 {
193+
pub fn forget(mut self) -> JsValue {
194194
let id = self.id.take().unwrap_throw();
195195
self.closure.take().unwrap_throw().forget();
196196
id

crates/timers/tests/node.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#![cfg(all(target_family = "wasm", feature = "futures"))]
2+
3+
use futures_channel::{mpsc, oneshot};
4+
use futures_util::{
5+
future::{select, Either, FutureExt},
6+
stream::StreamExt,
7+
};
8+
use gloo_timers::{
9+
callback::{Interval, Timeout},
10+
future::{sleep, IntervalStream, TimeoutFuture},
11+
};
12+
use std::cell::Cell;
13+
use std::rc::Rc;
14+
use std::time::Duration;
15+
use wasm_bindgen_test::*;
16+
17+
#[wasm_bindgen_test]
18+
async fn timeout() {
19+
let (sender, receiver) = oneshot::channel();
20+
Timeout::new(1, || sender.send(()).unwrap()).forget();
21+
receiver.await.unwrap();
22+
}
23+
24+
#[wasm_bindgen_test]
25+
async fn timeout_cancel() {
26+
let cell = Rc::new(Cell::new(false));
27+
28+
let t = Timeout::new(1, {
29+
let cell = cell.clone();
30+
move || {
31+
cell.set(true);
32+
panic!("should have been cancelled");
33+
}
34+
});
35+
t.cancel();
36+
37+
let (sender, receiver) = oneshot::channel();
38+
39+
Timeout::new(2, move || {
40+
sender.send(()).unwrap();
41+
assert_eq!(cell.get(), false);
42+
})
43+
.forget();
44+
45+
receiver.await.unwrap();
46+
}
47+
48+
#[wasm_bindgen_test]
49+
async fn timeout_future() {
50+
TimeoutFuture::new(1).await;
51+
}
52+
53+
#[wasm_bindgen_test]
54+
async fn timeout_future_cancel() {
55+
let cell = Rc::new(Cell::new(false));
56+
57+
let a = TimeoutFuture::new(1).map({
58+
let cell = cell.clone();
59+
move |_| {
60+
assert_eq!(cell.get(), false);
61+
1
62+
}
63+
});
64+
65+
let b = TimeoutFuture::new(2).map({
66+
let cell = cell.clone();
67+
move |_| {
68+
cell.set(true);
69+
2u32
70+
}
71+
});
72+
73+
let (who, other) = match select(a, b).await {
74+
Either::Left(x) => x,
75+
Either::Right(_) => panic!("Timer for 2 ms finished before timer for 1 ms"),
76+
};
77+
assert_eq!(who, 1);
78+
// Drop `b` so that its timer is canceled.
79+
drop(other);
80+
TimeoutFuture::new(3).await;
81+
// We should never have fired `b`'s timer.
82+
assert_eq!(cell.get(), false);
83+
}
84+
85+
#[wasm_bindgen_test]
86+
async fn interval() {
87+
let (mut sender, receiver) = mpsc::channel(1);
88+
let i = Interval::new(1, move || {
89+
if !sender.is_closed() {
90+
sender.try_send(()).unwrap()
91+
}
92+
});
93+
94+
let results: Vec<_> = receiver.take(5).collect().await;
95+
drop(i);
96+
assert_eq!(results.len(), 5);
97+
}
98+
99+
#[wasm_bindgen_test]
100+
async fn interval_cancel() {
101+
let i = Interval::new(10, move || {
102+
panic!("This should never be called");
103+
});
104+
i.cancel();
105+
106+
// This keeps us live for long enough that if any erroneous Interval callbacks fired, we'll have seen them.
107+
sleep(Duration::from_millis(100)).await;
108+
}
109+
110+
#[wasm_bindgen_test]
111+
async fn interval_stream() {
112+
let results: Vec<_> = IntervalStream::new(1).take(5).collect().await;
113+
assert_eq!(results.len(), 5);
114+
}

crates/timers/tests/web.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
//! Test suite for the Web and headless browsers.
2-
3-
#![cfg(all(target_arch = "wasm32", feature = "futures"))]
1+
#![cfg(all(target_family = "wasm", feature = "futures"))]
42

53
use futures_channel::{mpsc, oneshot};
64
use futures_util::{

0 commit comments

Comments
 (0)