Skip to content

Commit 0acb86a

Browse files
committed
Test network errors
1 parent ab12bc3 commit 0acb86a

File tree

3 files changed

+62
-17
lines changed

3 files changed

+62
-17
lines changed

graphql_client_web/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ log = "0.4.5"
1515
serde_json = "1.0.32"
1616
wasm-bindgen = "0.2.25"
1717
wasm-bindgen-futures = "0.3.2"
18+
js-sys = "0.3.5"
1819

1920
[dependencies.web-sys]
2021
version = "0.3.2"

graphql_client_web/src/lib.rs

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@
88

99
#[macro_use]
1010
pub extern crate graphql_client;
11+
extern crate js_sys;
1112
#[macro_use]
1213
extern crate wasm_bindgen;
1314

14-
pub use graphql_client::GraphQLQuery;
1515
use failure::*;
1616
use futures::{Future, IntoFuture};
17+
pub use graphql_client::GraphQLQuery;
1718
use log::*;
1819
use std::collections::HashMap;
19-
use wasm_bindgen_futures::JsFuture;
2020
use wasm_bindgen::{JsCast, JsValue};
21+
use wasm_bindgen_futures::JsFuture;
2122

2223
/// The main interface to the library.
2324
///
@@ -34,15 +35,15 @@ pub struct Client {
3435
/// All the ways a request can go wrong.
3536
///
3637
/// not exhaustive
37-
#[derive(Debug, Fail)]
38+
#[derive(Debug, Fail, PartialEq)]
3839
#[non_exhaustive]
3940
pub enum ClientError {
4041
/// The body couldn't be built
4142
#[fail(display = "Request body is not a valid string")]
4243
Body,
4344
/// An error caused by window.fetch
4445
#[fail(display = "Network error")]
45-
Network,
46+
Network(String),
4647
/// Error in a dynamic JS cast that should have worked
4748
#[fail(display = "JS casting error")]
4849
Cast,
@@ -52,13 +53,13 @@ pub enum ClientError {
5253
)]
5354
NoWindow,
5455
/// Response shape does not match the generated code
55-
#[fail(display = "Response shape error",)]
56+
#[fail(display = "Response shape error")]
5657
ResponseShape,
5758
/// Response could not be converted to text
5859
#[fail(display = "Response conversion to text failed (Response.text threw)")]
5960
ResponseText,
6061
/// Exception thrown when building the request
61-
#[fail(display = "Error building the request",)]
62+
#[fail(display = "Error building the request")]
6263
RequestError,
6364
/// Other JS exception
6465
#[fail(display = "Unexpected JS exception")]
@@ -73,9 +74,15 @@ impl Client {
7374
{
7475
Client {
7576
endpoint: endpoint.into(),
77+
headers: HashMap::new(),
7678
}
7779
}
7880

81+
/// Add a header to those sent with the requests. Can be used for things like authorization.
82+
pub fn add_header(&mut self, name: &str, value: &str) {
83+
self.headers.insert(name.into(), value.into());
84+
}
85+
7986
/// Perform a query.
8087
pub fn call<Q: GraphQLQuery + 'static>(
8188
&self,
@@ -93,7 +100,8 @@ impl Client {
93100
serde_json::to_string(&Q::build_query(variables))
94101
.map_err(|_| ClientError::Body)
95102
.map(move |body| (window, body))
96-
}).and_then(move |(window, body)| {
103+
})
104+
.and_then(move |(window, body)| {
97105
let mut request_init = web_sys::RequestInit::new();
98106
request_init
99107
.method("POST")
@@ -103,7 +111,8 @@ impl Client {
103111
.map_err(|_| ClientError::JsException)
104112
.map(|request| (window, request))
105113
// "Request constructor threw");
106-
}).and_then(move |(window, request)| {
114+
})
115+
.and_then(move |(window, request)| {
107116
let request: Result<web_sys::Request, _> = request
108117
.headers()
109118
.set("Content-Type", "application/json")
@@ -118,18 +127,23 @@ impl Client {
118127
});
119128

120129
request.map(move |request| (window, request))
121-
}).and_then(move |(window, request)| {
130+
})
131+
.and_then(move |(window, request)| {
122132
JsFuture::from(window.fetch_with_request(&request))
123-
.map_err(|_| ClientError::Network)
124-
}).and_then(move |res| {
133+
.map_err(|err| ClientError::Network(js_sys::Error::from(err).message().into()))
134+
})
135+
.and_then(move |res| {
125136
debug!("response: {:?}", res);
126137
res.dyn_into::<web_sys::Response>()
127138
.map_err(|_| ClientError::Cast)
128-
}).and_then(move |cast_response| {
139+
})
140+
.and_then(move |cast_response| {
129141
cast_response.text().map_err(|_| ClientError::ResponseText)
130-
}).and_then(move |text_promise| {
142+
})
143+
.and_then(move |text_promise| {
131144
JsFuture::from(text_promise).map_err(|_| ClientError::ResponseText)
132-
}).and_then(|text| {
145+
})
146+
.and_then(|text| {
133147
let response_text = text.as_string().unwrap_or_else(|| String::new());
134148
debug!("response text as string: {:?}", response_text);
135149
serde_json::from_str(&response_text).map_err(|_| ClientError::ResponseShape)

graphql_client_web/tests/web.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ fn test_germany() -> impl Future<Item = (), Error = JsValue> {
4242
.expect("germany is on a continent");
4343

4444
assert_eq!(continent_name, "Europe");
45-
}).map_err(|err| {
45+
})
46+
.map_err(|err| {
4647
panic!("{:?}", err);
4748
JsValue::NULL
4849
})
@@ -63,7 +64,8 @@ fn test_country() -> impl Future<Item = (), Error = JsValue> {
6364
country::Variables {
6465
country_code: "CN".to_owned(),
6566
},
66-
).map(|response| {
67+
)
68+
.map(|response| {
6769
let continent_name = response
6870
.data
6971
.expect("response data is not null")
@@ -75,8 +77,36 @@ fn test_country() -> impl Future<Item = (), Error = JsValue> {
7577
.expect("country is on a continent");
7678

7779
assert_eq!(continent_name, "Asia");
78-
}).map_err(|err| {
80+
})
81+
.map_err(|err| {
7982
panic!("{:?}", err);
8083
JsValue::NULL
8184
})
8285
}
86+
87+
#[wasm_bindgen_test(async)]
88+
fn test_bad_url() -> impl Future<Item = (), Error = JsValue> {
89+
Client::new("https://example.com/non-existent/graphql/endpoint")
90+
.call(
91+
Country,
92+
country::Variables {
93+
country_code: "CN".to_owned(),
94+
},
95+
)
96+
.map(|_response| panic!("The API endpoint does not exist, this should not be called."))
97+
.map_err(|err| {
98+
assert_eq!(
99+
err,
100+
graphql_client_web::ClientError::Network(
101+
"NetworkError when attempting to fetch resource.".into()
102+
)
103+
);
104+
JsValue::NULL
105+
})
106+
.then(|_| Ok(()))
107+
}
108+
109+
#[wasm_bindgen_test]
110+
fn test_404() {
111+
unimplemented!()
112+
}

0 commit comments

Comments
 (0)