From 2b23e5bc0b452b3f9c50c3ccbf90293653803c18 Mon Sep 17 00:00:00 2001 From: Gregory Eric Sanderson <202192+gelendir@users.noreply.github.com> Date: Wed, 14 Feb 2024 15:29:16 -0500 Subject: [PATCH 1/4] Support wasm32-unknown-unknown architecture --- .github/workflows/ci.yml | 27 ++ Cargo.toml | 17 +- rspotify-http/src/common.rs | 3 +- rspotify-http/src/reqwest.rs | 17 +- src/auth_code.rs | 6 +- src/auth_code_pkce.rs | 6 +- src/client_creds.rs | 3 +- src/clients/base.rs | 3 +- src/clients/oauth.rs | 3 +- src/clients/pagination/mod.rs | 12 +- src/clients/pagination/wasm_stream.rs | 62 ++++ src/lib.rs | 5 +- tests/test_enums.rs | 13 + tests/test_models.rs | 23 ++ tests/test_oauth2.rs | 4 + tests/test_with_credential.rs | 239 +++++++++++++-- tests/test_with_oauth.rs | 424 +++++++++++++++++++++++--- tests/util.rs | 37 +++ 18 files changed, 810 insertions(+), 94 deletions(-) create mode 100644 src/clients/pagination/wasm_stream.rs create mode 100644 tests/util.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7fb1696..64545de4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,3 +91,30 @@ jobs: with: command: test args: -p rspotify -p rspotify-http -p rspotify-model -p rspotify-macros --no-default-features --features=${{ matrix.features }} + + test-wasm: + name: Test WASM client + runs-on: ubuntu-latest + env: + RUST_BACKTRACE: 1 + + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: clippy + + - name: Install node + uses: actions/setup-node@v4 + + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + + - name: Run wasm-pack test + run: wasm-pack test --node \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 7d8ff1b1..b617ca53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ base64 = "0.21.2" chrono = { version = "0.4.19", features = ["serde"] } dotenvy = { version = "0.15.0", optional = true } futures = { version = "0.3.17", optional = true } -getrandom = "0.2.3" + log = "0.4.14" maybe-async = "0.2.6" serde = { version = "1.0.130", default-features = false } @@ -46,10 +46,23 @@ thiserror = "1.0.29" url = "2.2.2" webbrowser = { version = "0.8.0", optional = true } +[target.'cfg(target_arch = "wasm32")'.dependencies] +getrandom = { version = "0.2.3", features = ["js"] } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +getrandom = "0.2.3" + [dev-dependencies] env_logger = { version = "0.11.0", default-features = false } -tokio = { version = "1.11.0", features = ["rt-multi-thread", "macros"] } futures-util = "0.3.17" +wasm-bindgen-test = "0.3.34" + +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +tokio = { version = "1.11.0", features = ["rt-multi-thread", "macros"] } + +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +tokio = { version = "1.11.0", features = ["rt", "macros"] } +dotenvy_macro = { version = "0.15.7" } [features] default = ["client-reqwest", "reqwest-default-tls"] diff --git a/rspotify-http/src/common.rs b/rspotify-http/src/common.rs index 596286a5..2e611d0c 100644 --- a/rspotify-http/src/common.rs +++ b/rspotify-http/src/common.rs @@ -18,7 +18,8 @@ pub type Form<'a> = HashMap<&'a str, &'a str>; /// different ways (`Value::Null`, an empty `Value::Object`...), so this removes /// redundancy and edge cases (a `Some(Value::Null), for example, doesn't make /// much sense). -#[maybe_async] +#[cfg_attr(target_arch = "wasm32", maybe_async(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), maybe_async)] pub trait BaseHttpClient: Send + Default + Clone + fmt::Debug { type Error; diff --git a/rspotify-http/src/reqwest.rs b/rspotify-http/src/reqwest.rs index 3498b37a..238f0a79 100644 --- a/rspotify-http/src/reqwest.rs +++ b/rspotify-http/src/reqwest.rs @@ -4,6 +4,8 @@ use super::{BaseHttpClient, Form, Headers, Query}; use std::convert::TryInto; + +#[cfg(not(target_arch = "wasm32"))] use std::time::Duration; use maybe_async::async_impl; @@ -56,6 +58,7 @@ pub struct ReqwestClient { client: reqwest::Client, } +#[cfg(not(target_arch = "wasm32"))] impl Default for ReqwestClient { fn default() -> Self { let client = reqwest::ClientBuilder::new() @@ -67,6 +70,17 @@ impl Default for ReqwestClient { } } +#[cfg(target_arch = "wasm32")] +impl Default for ReqwestClient { + fn default() -> Self { + let client = reqwest::ClientBuilder::new() + .build() + // building with these options cannot fail + .unwrap(); + Self { client } + } +} + impl ReqwestClient { async fn request( &self, @@ -109,7 +123,8 @@ impl ReqwestClient { } } -#[async_impl] +#[cfg_attr(target_arch = "wasm32", async_impl(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_impl)] impl BaseHttpClient for ReqwestClient { type Error = ReqwestError; diff --git a/src/auth_code.rs b/src/auth_code.rs index 7b5f7ce2..d11f1ac0 100644 --- a/src/auth_code.rs +++ b/src/auth_code.rs @@ -72,7 +72,8 @@ pub struct AuthCodeSpotify { } /// This client has access to the base methods. -#[maybe_async] +#[cfg_attr(target_arch = "wasm32", maybe_async(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), maybe_async)] impl BaseClient for AuthCodeSpotify { fn get_http(&self) -> &HttpClient { &self.http @@ -126,7 +127,8 @@ impl BaseClient for AuthCodeSpotify { /// This client includes user authorization, so it has access to the user /// private endpoints in [`OAuthClient`]. -#[maybe_async] +#[cfg_attr(target_arch = "wasm32", maybe_async(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), maybe_async)] impl OAuthClient for AuthCodeSpotify { fn get_oauth(&self) -> &OAuth { &self.oauth diff --git a/src/auth_code_pkce.rs b/src/auth_code_pkce.rs index e87d8ced..367f3340 100644 --- a/src/auth_code_pkce.rs +++ b/src/auth_code_pkce.rs @@ -44,7 +44,8 @@ pub struct AuthCodePkceSpotify { } /// This client has access to the base methods. -#[maybe_async] +#[cfg_attr(target_arch = "wasm32", maybe_async(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), maybe_async)] impl BaseClient for AuthCodePkceSpotify { fn get_http(&self) -> &HttpClient { &self.http @@ -88,7 +89,8 @@ impl BaseClient for AuthCodePkceSpotify { /// This client includes user authorization, so it has access to the user /// private endpoints in [`OAuthClient`]. -#[maybe_async] +#[cfg_attr(target_arch = "wasm32", maybe_async(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), maybe_async)] impl OAuthClient for AuthCodePkceSpotify { fn get_oauth(&self) -> &OAuth { &self.oauth diff --git a/src/client_creds.rs b/src/client_creds.rs index ffdde5e2..f4364282 100644 --- a/src/client_creds.rs +++ b/src/client_creds.rs @@ -30,7 +30,8 @@ pub struct ClientCredsSpotify { } /// This client has access to the base methods. -#[maybe_async] +#[cfg_attr(target_arch = "wasm32", maybe_async(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), maybe_async)] impl BaseClient for ClientCredsSpotify { fn get_http(&self) -> &HttpClient { &self.http diff --git a/src/clients/base.rs b/src/clients/base.rs index 0298c9c8..ae1b81c0 100644 --- a/src/clients/base.rs +++ b/src/clients/base.rs @@ -21,7 +21,8 @@ use serde_json::Value; /// This trait implements the basic endpoints from the Spotify API that may be /// accessed without user authorization, including parts of the authentication /// flow that are shared, and the endpoints. -#[maybe_async] +#[cfg_attr(target_arch = "wasm32", maybe_async(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), maybe_async)] pub trait BaseClient where Self: Send + Sync + Default + Clone + fmt::Debug, diff --git a/src/clients/oauth.rs b/src/clients/oauth.rs index 222c1161..e9154b63 100644 --- a/src/clients/oauth.rs +++ b/src/clients/oauth.rs @@ -27,7 +27,8 @@ use url::Url; /// [`user_playlist`](crate::clients::BaseClient::user_playlist). This trait /// only separates endpoints that *always* need authorization from the base /// ones. -#[maybe_async] +#[cfg_attr(target_arch = "wasm32", maybe_async(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), maybe_async)] pub trait OAuthClient: BaseClient { fn get_oauth(&self) -> &OAuth; diff --git a/src/clients/pagination/mod.rs b/src/clients/pagination/mod.rs index ac6fcab7..1bf57d8a 100644 --- a/src/clients/pagination/mod.rs +++ b/src/clients/pagination/mod.rs @@ -25,10 +25,18 @@ #[cfg(feature = "__sync")] mod iter; -#[cfg(feature = "__async")] + +#[cfg(all(feature = "__async", not(target_arch = "wasm32")))] mod stream; +#[cfg(all(feature = "__async", target_arch = "wasm32"))] +mod wasm_stream; + #[cfg(feature = "__sync")] pub use iter::{paginate, paginate_with_ctx, Paginator}; -#[cfg(feature = "__async")] + +#[cfg(all(feature = "__async", not(target_arch = "wasm32")))] pub use stream::{paginate, paginate_with_ctx, Paginator}; + +#[cfg(all(feature = "__async", target_arch = "wasm32"))] +pub use wasm_stream::{paginate, paginate_with_ctx, Paginator}; diff --git a/src/clients/pagination/wasm_stream.rs b/src/clients/pagination/wasm_stream.rs new file mode 100644 index 00000000..700fd4b2 --- /dev/null +++ b/src/clients/pagination/wasm_stream.rs @@ -0,0 +1,62 @@ +//! Asynchronous implementation of automatic pagination requests. + +use crate::{model::Page, ClientResult}; + +use std::pin::Pin; + +use futures::{future::Future, stream::Stream}; + +/// Alias for `futures::stream::Stream`, since async mode is enabled. +pub type Paginator<'a, T> = Pin + 'a>>; + +pub type RequestFuture<'a, T> = Pin>>>>; + +/// This is used to handle paginated requests automatically. +pub fn paginate_with_ctx<'a, Ctx: 'a, T, Request>( + ctx: Ctx, + req: Request, + page_size: u32, +) -> Paginator<'a, ClientResult> +where + T: 'a + Unpin, + Request: 'a + for<'ctx> Fn(&'ctx Ctx, u32, u32) -> RequestFuture<'ctx, T>, +{ + use async_stream::stream; + let mut offset = 0; + Box::pin(stream! { + loop { + let request = req(&ctx, page_size, offset); + let page = request.await?; + offset += page.items.len() as u32; + for item in page.items { + yield Ok(item); + } + if page.next.is_none() { + break; + } + } + }) +} + +pub fn paginate<'a, T, Fut, Request>(req: Request, page_size: u32) -> Paginator<'a, ClientResult> +where + T: 'a + Unpin, + Fut: Future>>, + Request: 'a + Fn(u32, u32) -> Fut, +{ + use async_stream::stream; + let mut offset = 0; + Box::pin(stream! { + loop { + let request = req(page_size, offset); + let page = request.await?; + offset += page.items.len() as u32; + for item in page.items { + yield Ok(item); + } + if page.next.is_none() { + break; + } + } + }) +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 67ea075e..b97ebd2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -442,11 +442,13 @@ impl OAuth { } #[cfg(test)] -mod test { +pub mod test { use crate::{alphabets, generate_random_string, Credentials}; use std::collections::HashSet; + use wasm_bindgen_test::*; #[test] + #[wasm_bindgen_test] fn test_generate_random_string() { let mut containers = HashSet::new(); for _ in 1..101 { @@ -456,6 +458,7 @@ mod test { } #[test] + #[wasm_bindgen_test] fn test_basic_auth() { let creds = Credentials::new_pkce("ramsay"); let headers = creds.auth_headers(); diff --git a/tests/test_enums.rs b/tests/test_enums.rs index 546f68a4..5141a315 100644 --- a/tests/test_enums.rs +++ b/tests/test_enums.rs @@ -1,72 +1,85 @@ use rspotify::model::*; +use wasm_bindgen_test::*; #[test] +#[wasm_bindgen_test] fn test_include_external() { let audio = IncludeExternal::Audio; assert_eq!("audio", <&str>::from(audio)); } #[test] +#[wasm_bindgen_test] fn test_repeat_state() { let context = RepeatState::Context; assert_eq!(<&str>::from(context), "context"); } #[test] +#[wasm_bindgen_test] fn test_disallow_key() { let toggling_shuffle = DisallowKey::TogglingShuffle; assert_eq!(<&str>::from(toggling_shuffle), "toggling_shuffle"); } #[test] +#[wasm_bindgen_test] fn test_time_range() { let medium_range = TimeRange::MediumTerm; assert_eq!(<&str>::from(medium_range), "medium_term"); } #[test] +#[wasm_bindgen_test] fn test_date_precision() { let month = DatePrecision::Month; assert_eq!(<&str>::from(month), "month"); } #[test] +#[wasm_bindgen_test] fn test_album_type_convert_from_str() { let appears_on = AlbumType::AppearsOn; assert_eq!("appears_on", <&str>::from(appears_on)); } #[test] +#[wasm_bindgen_test] fn test_convert_search_type_from_str() { let search_type = SearchType::Artist; assert_eq!("artist", <&str>::from(search_type)); } #[test] +#[wasm_bindgen_test] fn test_type_convert_from_str() { let artist = Type::Artist; assert_eq!(<&str>::from(artist), "artist"); } #[test] +#[wasm_bindgen_test] fn test_additional_type() { let episode = AdditionalType::Episode; assert_eq!(<&str>::from(episode), "episode"); } #[test] +#[wasm_bindgen_test] fn test_current_playing_type() { let ad = CurrentlyPlayingType::Advertisement; assert_eq!(<&str>::from(ad), "ad"); } #[test] +#[wasm_bindgen_test] fn test_search_type() { let episode = SearchType::Episode; assert_eq!(<&str>::from(episode), "episode"); } #[test] +#[wasm_bindgen_test] fn test_convert_country_from_str() { let zimbabwe = Country::Zimbabwe; assert_eq!(<&str>::from(zimbabwe), "ZW"); diff --git a/tests/test_models.rs b/tests/test_models.rs index b08340d7..c7b92325 100644 --- a/tests/test_models.rs +++ b/tests/test_models.rs @@ -1,6 +1,7 @@ use chrono::{DateTime, Duration, NaiveDateTime, Utc}; use rspotify::model::*; use serde::de::DeserializeOwned; +use wasm_bindgen_test::*; #[track_caller] fn deserialize(data: impl AsRef) -> T @@ -18,6 +19,7 @@ where } #[test] +#[wasm_bindgen_test] fn test_simplified_track() { let json_str = r#" { @@ -55,6 +57,7 @@ fn test_simplified_track() { } #[test] +#[wasm_bindgen_test] fn test_public_user() { let json_str = r#" { @@ -89,6 +92,7 @@ fn test_public_user() { } #[test] +#[wasm_bindgen_test] fn test_private_user() { let json_str = r#" { @@ -119,6 +123,7 @@ fn test_private_user() { } #[test] +#[wasm_bindgen_test] fn test_full_artist() { let json_str = r#" { @@ -153,6 +158,7 @@ fn test_full_artist() { } #[test] +#[wasm_bindgen_test] fn test_simplified_episode() { let json_str = r#" { @@ -199,6 +205,7 @@ fn test_simplified_episode() { } #[test] +#[wasm_bindgen_test] fn test_full_episode() { let json_str = r#" { @@ -267,6 +274,7 @@ fn test_full_episode() { } #[test] +#[wasm_bindgen_test] fn test_copyright() { let json_str = r#" [ { @@ -280,6 +288,7 @@ fn test_copyright() { } #[test] +#[wasm_bindgen_test] fn test_audio_analysis_section() { let json_str = r#" { @@ -303,6 +312,7 @@ fn test_audio_analysis_section() { } #[test] +#[wasm_bindgen_test] fn test_audio_analysis_segments() { let json_str = r#" { @@ -327,6 +337,7 @@ fn test_audio_analysis_segments() { } #[test] +#[wasm_bindgen_test] fn test_actions() { let json_str = r#" { @@ -340,6 +351,7 @@ fn test_actions() { } #[test] +#[wasm_bindgen_test] fn test_recommendations_seed() { let json_str = r#" { @@ -356,6 +368,7 @@ fn test_recommendations_seed() { } #[test] +#[wasm_bindgen_test] fn test_full_playlist() { let json_str_images = r#" [ @@ -493,6 +506,7 @@ fn test_full_playlist() { } #[test] +#[wasm_bindgen_test] fn test_audio_features() { let json = r#" { @@ -522,6 +536,7 @@ fn test_audio_features() { } #[test] +#[wasm_bindgen_test] fn test_full_track() { let json = r#" { @@ -601,6 +616,7 @@ fn test_full_track() { } #[test] +#[wasm_bindgen_test] fn test_resume_point() { let json = r#" { @@ -614,6 +630,7 @@ fn test_resume_point() { } #[test] +#[wasm_bindgen_test] fn test_resume_point_negative() { let json = r#" { @@ -627,6 +644,7 @@ fn test_resume_point_negative() { } #[test] +#[wasm_bindgen_test] fn test_currently_playing_context() { let json = r#" { @@ -741,6 +759,7 @@ fn test_currently_playing_context() { } #[test] +#[wasm_bindgen_test] fn test_current_playback_context() { let json = r#" { @@ -854,6 +873,7 @@ fn test_current_playback_context() { } #[test] +#[wasm_bindgen_test] fn test_current_user_queue() { let json = r#" { @@ -1045,6 +1065,7 @@ fn test_current_user_queue() { } #[test] +#[wasm_bindgen_test] fn test_audio_analysis_track() { let json = r#" { @@ -1081,6 +1102,7 @@ fn test_audio_analysis_track() { } #[test] +#[wasm_bindgen_test] fn test_simplified_playlist() { let json = r#" { @@ -1129,6 +1151,7 @@ fn test_simplified_playlist() { } #[test] +#[wasm_bindgen_test] fn test_collectionyourepisodes_type() { let json = r#" { diff --git a/tests/test_oauth2.rs b/tests/test_oauth2.rs index 34378e70..dcec1b73 100644 --- a/tests/test_oauth2.rs +++ b/tests/test_oauth2.rs @@ -5,8 +5,10 @@ use rspotify::{ }; use std::{collections::HashMap, fs, io::Read, path::PathBuf}; use url::Url; +use wasm_bindgen_test::*; #[test] +#[wasm_bindgen_test] fn test_get_authorize_url() { let oauth = OAuth { state: "fdsafdsfa".to_owned(), @@ -111,6 +113,7 @@ async fn test_write_token() { } #[test] +#[wasm_bindgen_test] fn test_token_is_expired() { let expires_in = Duration::seconds(20); let tok = Token { @@ -134,6 +137,7 @@ fn test_token_is_expired() { } #[test] +#[wasm_bindgen_test] fn test_parse_response_code() { // A random state is generated by default let spotify = AuthCodeSpotify::default(); diff --git a/tests/test_with_credential.rs b/tests/test_with_credential.rs index 15e33c39..f7f6f8d7 100644 --- a/tests/test_with_credential.rs +++ b/tests/test_with_credential.rs @@ -1,35 +1,52 @@ +mod util; + use rspotify::{ model::{AlbumId, AlbumType, ArtistId, Country, Market, PlaylistId, TrackId, UserId}, prelude::*, - ClientCredsSpotify, Credentials, + ClientCredsSpotify, }; use maybe_async::maybe_async; +#[cfg(target_arch="wasm32")] +use wasm_bindgen_test::*; + /// Generating a new basic client for the requests. #[maybe_async] pub async fn creds_client() -> ClientCredsSpotify { - // The credentials must be available in the environment. - let creds = Credentials::from_env().unwrap_or_else(|| { - panic!( - "No credentials configured. Make sure that either the `env-file` \ - feature is enabled, or that the required environment variables are \ - exported (`RSPOTIFY_CLIENT_ID`, `RSPOTIFY_CLIENT_SECRET`)" - ) - }); - + let creds = util::get_credentials(); let spotify = ClientCredsSpotify::new(creds); spotify.request_token().await.unwrap(); spotify } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_album() { let birdy_uri = AlbumId::from_uri("spotify:album:0sNOF9WDwhWunNAHPD3Baj").unwrap(); creds_client().await.album(birdy_uri, None).await.unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_albums() { let track_uris = [ AlbumId::from_uri("spotify:album:41MnTivkwTO3UUJ8DrqEJJ").unwrap(), @@ -39,7 +56,17 @@ async fn test_albums() { creds_client().await.albums(track_uris, None).await.unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_album_tracks() { let birdy_uri = AlbumId::from_uri("spotify:album:6akEvsycLGftJxYudPjmqK").unwrap(); creds_client() @@ -49,7 +76,17 @@ async fn test_album_tracks() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_artist_related_artists() { let birdy_uri = ArtistId::from_uri("spotify:artist:43ZHCT0cAZBISjO8DG9PnE").unwrap(); creds_client() @@ -59,13 +96,33 @@ async fn test_artist_related_artists() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_artist() { let birdy_uri = ArtistId::from_uri("spotify:artist:2WX2uTcsvV5OnS0inACecP").unwrap(); creds_client().await.artist(birdy_uri).await.unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_artists_albums() { let birdy_uri = ArtistId::from_uri("spotify:artist:2WX2uTcsvV5OnS0inACecP").unwrap(); creds_client() @@ -81,7 +138,17 @@ async fn test_artists_albums() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_artists_albums_with_multiple_album_types() { let birdy_uri = ArtistId::from_uri("spotify:artist:2WX2uTcsvV5OnS0inACecP").unwrap(); let include_groups = [ @@ -103,7 +170,17 @@ async fn test_artists_albums_with_multiple_album_types() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_artists_albums_with_zero_album_type() { let birdy_uri = ArtistId::from_uri("spotify:artist:2WX2uTcsvV5OnS0inACecP").unwrap(); creds_client() @@ -119,7 +196,17 @@ async fn test_artists_albums_with_zero_album_type() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_artists() { let artist_uris = [ ArtistId::from_uri("spotify:artist:0oSGxfWSnnOXhD2fKuz2Gy").unwrap(), @@ -128,7 +215,17 @@ async fn test_artists() { creds_client().await.artists(artist_uris).await.unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_artist_top_tracks() { let birdy_uri = ArtistId::from_uri("spotify:artist:2WX2uTcsvV5OnS0inACecP").unwrap(); creds_client() @@ -138,19 +235,49 @@ async fn test_artist_top_tracks() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_audio_analysis() { let track = TrackId::from_id("06AKEBrKUckW0KREUWRnvT").unwrap(); creds_client().await.track_analysis(track).await.unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_audio_features() { let track = TrackId::from_uri("spotify:track:06AKEBrKUckW0KREUWRnvT").unwrap(); creds_client().await.track_features(track).await.unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_audios_features() { let mut tracks_ids = vec![]; let track_id1 = TrackId::from_uri("spotify:track:4JpKVNYnVcJ8tuMKjAj50A").unwrap(); @@ -166,19 +293,49 @@ async fn test_audios_features() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_user() { let birdy_uri = UserId::from_id("tuggareutangranser").unwrap(); creds_client().await.user(birdy_uri).await.unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_track() { let birdy_uri = TrackId::from_uri("spotify:track:6rqhFgbbKwnb9MLmUQDhG6").unwrap(); creds_client().await.track(birdy_uri, None).await.unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_tracks() { let track_uris = [ TrackId::from_uri("spotify:track:3n3Ppam7vgaVa1iaRUc9Lp").unwrap(), @@ -187,7 +344,17 @@ async fn test_tracks() { creds_client().await.tracks(track_uris, None).await.unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_existing_playlist() { let playlist_id = PlaylistId::from_id("37i9dQZF1DZ06evO45P0Eo").unwrap(); creds_client() @@ -197,14 +364,24 @@ async fn test_existing_playlist() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] async fn test_fake_playlist() { let playlist_id = PlaylistId::from_id("fakeid").unwrap(); let playlist = creds_client().await.playlist(playlist_id, None, None).await; assert!(playlist.is_err()); } -mod test_pagination { +pub mod test_pagination { use super::*; static ALBUM: &str = "spotify:album:2T7DdrOvsqOqU9bGTkjBYu"; @@ -238,8 +415,8 @@ mod test_pagination { } /// This test iterates a request of 10 items, with 5 requests of 2 items. - #[cfg(feature = "__async")] - #[tokio::test] + #[cfg_attr(all(feature = "__async", not(target_arch="wasm32")), tokio::test)] + #[cfg_attr(all(feature = "__async", target_arch="wasm32"), wasm_bindgen_test)] async fn test_pagination_async() { use futures_util::StreamExt; diff --git a/tests/test_with_oauth.rs b/tests/test_with_oauth.rs index 18a2f0d8..c5549069 100644 --- a/tests/test_with_oauth.rs +++ b/tests/test_with_oauth.rs @@ -14,6 +14,8 @@ //! with the `oauth_tokens` example: //! //! cargo run --example oauth_tokens --features=env-file,cli +//! +mod util; use rspotify::{ clients::pagination::Paginator, @@ -23,36 +25,30 @@ use rspotify::{ SearchType, ShowId, TimeLimits, TimeRange, TrackId, UserId, }, prelude::*, - scopes, AuthCodeSpotify, ClientResult, Credentials, OAuth, Token, + scopes, AuthCodeSpotify, ClientResult, OAuth, Token, }; -use std::env; - use chrono::{prelude::*, Duration}; use maybe_async::maybe_async; +#[cfg(target_arch="wasm32")] +use wasm_bindgen_test::*; + + /// Generating a new OAuth client for the requests. #[maybe_async] pub async fn oauth_client() -> AuthCodeSpotify { - if let Ok(access_token) = env::var("RSPOTIFY_ACCESS_TOKEN") { + let (access_token, refresh_token) = util::get_access_tokens(); + + if let Some(access_token) = access_token { let tok = Token { access_token, ..Default::default() }; AuthCodeSpotify::from_token(tok) - } else if let Ok(refresh_token) = env::var("RSPOTIFY_REFRESH_TOKEN") { - // The credentials must be available in the environment. Enable - // `env-file` in order to read them from an `.env` file. - let creds = Credentials::from_env().unwrap_or_else(|| { - panic!( - "No credentials configured. Make sure that either the \ - `env-file` feature is enabled, or that the required \ - environment variables are exported (`RSPOTIFY_CLIENT_ID`, \ - `RSPOTIFY_CLIENT_SECRET`)." - ) - }); - + } else if let Some(refresh_token) = refresh_token { + let creds = util::get_credentials(); let scopes = scopes!( "playlist-modify-private", "playlist-modify-public", @@ -110,7 +106,17 @@ async fn fetch_all(paginator: Paginator<'_, ClientResult>) -> Vec { } } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_categories() { oauth_client() @@ -125,7 +131,17 @@ async fn test_categories() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_category_playlists() { oauth_client() @@ -140,7 +156,17 @@ async fn test_category_playlists() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_current_playback() { oauth_client() @@ -150,7 +176,17 @@ async fn test_current_playback() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_current_playing() { oauth_client() @@ -160,7 +196,17 @@ async fn test_current_playing() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_current_user_followed_artists() { oauth_client() @@ -170,7 +216,17 @@ async fn test_current_user_followed_artists() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_current_user_playing_track() { oauth_client() @@ -180,7 +236,17 @@ async fn test_current_user_playing_track() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_current_user_recently_played() { let limit = TimeLimits::After(Utc::now() - Duration::days(2)); @@ -191,7 +257,17 @@ async fn test_current_user_recently_played() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_current_user_saved_albums() { let album_ids = [ @@ -228,7 +304,17 @@ async fn test_current_user_saved_albums() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_current_user_saved_tracks_add() { let client = oauth_client().await; @@ -262,7 +348,17 @@ async fn test_current_user_saved_tracks_add() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_current_user_top_artists() { oauth_client() @@ -272,7 +368,17 @@ async fn test_current_user_top_artists() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_current_user_top_tracks() { oauth_client() @@ -282,7 +388,17 @@ async fn test_current_user_top_tracks() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_featured_playlists() { let now: DateTime = Utc::now(); @@ -293,13 +409,33 @@ async fn test_featured_playlists() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_me() { oauth_client().await.me().await.unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_new_releases() { oauth_client() @@ -309,7 +445,17 @@ async fn test_new_releases() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_new_releases_with_from_token() { oauth_client() @@ -319,7 +465,17 @@ async fn test_new_releases_with_from_token() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_playback() { let client = oauth_client().await; @@ -402,7 +558,17 @@ async fn test_playback() { } } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_recommendations() { let seed_artists = [ArtistId::from_id("4NHQUGzhtTLFvgF5SZesLK").unwrap()]; @@ -426,7 +592,17 @@ async fn test_recommendations() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_repeat() { let client = oauth_client().await; @@ -441,7 +617,17 @@ async fn test_repeat() { } } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_search_album() { let query = "album:arrival artist:abba"; @@ -452,7 +638,17 @@ async fn test_search_album() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_search_artist() { let query = "tania bowra"; @@ -470,7 +666,17 @@ async fn test_search_artist() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_search_playlist() { let query = "\"doom metal\""; @@ -488,7 +694,17 @@ async fn test_search_playlist() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_search_track() { let query = "abba"; @@ -508,7 +724,17 @@ async fn test_search_track() { // This also tests percentage signs in search queries to avoid regressions of // https://github.com/ramsayleung/rspotify/issues/141 -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_search_show() { let query = "99% invisible"; @@ -519,7 +745,17 @@ async fn test_search_show() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_seek_track() { let client = oauth_client().await; @@ -541,7 +777,17 @@ async fn test_seek_track() { } } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_shuffle() { let client = oauth_client().await; @@ -556,7 +802,17 @@ async fn test_shuffle() { } } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_user_follow_artist() { let client = oauth_client().await; @@ -572,7 +828,17 @@ async fn test_user_follow_artist() { client.user_unfollow_artists(artists).await.unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_user_follow_users() { let client = oauth_client().await; @@ -588,7 +854,17 @@ async fn test_user_follow_users() { client.user_unfollow_users(users).await.unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_user_follow_playlist() { let client = oauth_client().await; @@ -761,7 +1037,17 @@ async fn check_playlist_follow(client: &AuthCodeSpotify, playlist: &FullPlaylist .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_playlist() { let client = oauth_client().await; @@ -771,7 +1057,17 @@ async fn test_playlist() { check_playlist_follow(&client, &playlist).await; } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_volume() { let client = oauth_client().await; @@ -793,7 +1089,17 @@ async fn test_volume() { } } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_add_queue() { // NOTE: unfortunately it's impossible to revert this test @@ -807,7 +1113,17 @@ async fn test_add_queue() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_get_several_shows() { let shows = [ @@ -822,7 +1138,17 @@ async fn test_get_several_shows() { .unwrap(); } -#[maybe_async::test(feature = "__sync", async(feature = "__async", tokio::test))] +#[maybe_async::test( + feature = "__sync", + async( + all(feature = "__async", not(target_arch="wasm32")), + tokio::test + ), + async( + all(feature = "__async", target_arch="wasm32"), + wasm_bindgen_test + ) +)] #[ignore] async fn test_get_several_episodes() { let episodes = [ diff --git a/tests/util.rs b/tests/util.rs new file mode 100644 index 00000000..6cb873de --- /dev/null +++ b/tests/util.rs @@ -0,0 +1,37 @@ +use rspotify::Credentials; + +#[cfg(not(target_arch="wasm32"))] +pub fn get_credentials() -> Credentials { + // The credentials must be available in the environment. + Credentials::from_env().unwrap_or_else(|| { + panic!( + "No credentials configured. Make sure that either the `env-file` \ + feature is enabled, or that the required environment variables are \ + exported (`RSPOTIFY_CLIENT_ID`, `RSPOTIFY_CLIENT_SECRET`)" + ) + }) +} + +#[cfg(target_arch="wasm32")] +pub fn get_credentials() -> Credentials { + // The credentials must be available in the environment. Panics if they are not available + let id = dotenvy_macro::dotenv!("RSPOTIFY_CLIENT_ID"); + let secret = dotenvy_macro::dotenv!("RSPOTIFY_CLIENT_SECRET"); + Credentials::new(&id, &secret) +} + +#[cfg(not(target_arch="wasm32"))] +pub fn get_access_tokens() -> (Option, Option) { + use std::env; + ( + env::var("RSPOTIFY_ACCESS_TOKEN").ok(), + env::var("RSPOTIFY_REFRESH_TOKEN").ok() + ) +} + +#[cfg(target_arch="wasm32")] +pub fn get_access_tokens() -> (Option, Option) { + let access_token = option_env!("RSPOTIFY_ACCESS_TOKEN").map(|s| s.to_string()); + let refresh_token = option_env!("RSPOTIFY_REFRESH_TOKEN").map(|s| s.to_string()); + (access_token, refresh_token) +} \ No newline at end of file From 64be77d461383b207490f926b524b489a1c34aa2 Mon Sep 17 00:00:00 2001 From: Gregory Eric Sanderson <202192+gelendir@users.noreply.github.com> Date: Mon, 19 Feb 2024 21:50:33 -0500 Subject: [PATCH 2/4] code formatting --- src/clients/pagination/wasm_stream.rs | 2 +- tests/test_with_credential.rs | 222 ++++---------- tests/test_with_oauth.rs | 401 +++++++------------------- tests/util.rs | 12 +- 4 files changed, 165 insertions(+), 472 deletions(-) diff --git a/src/clients/pagination/wasm_stream.rs b/src/clients/pagination/wasm_stream.rs index 700fd4b2..58df6dbd 100644 --- a/src/clients/pagination/wasm_stream.rs +++ b/src/clients/pagination/wasm_stream.rs @@ -59,4 +59,4 @@ where } } }) -} \ No newline at end of file +} diff --git a/tests/test_with_credential.rs b/tests/test_with_credential.rs index f7f6f8d7..98e89a4b 100644 --- a/tests/test_with_credential.rs +++ b/tests/test_with_credential.rs @@ -8,7 +8,7 @@ use rspotify::{ use maybe_async::maybe_async; -#[cfg(target_arch="wasm32")] +#[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; /// Generating a new basic client for the requests. @@ -21,15 +21,9 @@ pub async fn creds_client() -> ClientCredsSpotify { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_album() { let birdy_uri = AlbumId::from_uri("spotify:album:0sNOF9WDwhWunNAHPD3Baj").unwrap(); @@ -37,15 +31,9 @@ async fn test_album() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_albums() { let track_uris = [ @@ -57,15 +45,9 @@ async fn test_albums() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_album_tracks() { let birdy_uri = AlbumId::from_uri("spotify:album:6akEvsycLGftJxYudPjmqK").unwrap(); @@ -77,15 +59,9 @@ async fn test_album_tracks() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_artist_related_artists() { let birdy_uri = ArtistId::from_uri("spotify:artist:43ZHCT0cAZBISjO8DG9PnE").unwrap(); @@ -97,15 +73,9 @@ async fn test_artist_related_artists() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_artist() { let birdy_uri = ArtistId::from_uri("spotify:artist:2WX2uTcsvV5OnS0inACecP").unwrap(); @@ -113,15 +83,9 @@ async fn test_artist() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_artists_albums() { let birdy_uri = ArtistId::from_uri("spotify:artist:2WX2uTcsvV5OnS0inACecP").unwrap(); @@ -139,15 +103,9 @@ async fn test_artists_albums() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_artists_albums_with_multiple_album_types() { let birdy_uri = ArtistId::from_uri("spotify:artist:2WX2uTcsvV5OnS0inACecP").unwrap(); @@ -171,15 +129,9 @@ async fn test_artists_albums_with_multiple_album_types() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_artists_albums_with_zero_album_type() { let birdy_uri = ArtistId::from_uri("spotify:artist:2WX2uTcsvV5OnS0inACecP").unwrap(); @@ -197,15 +149,9 @@ async fn test_artists_albums_with_zero_album_type() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_artists() { let artist_uris = [ @@ -216,15 +162,9 @@ async fn test_artists() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_artist_top_tracks() { let birdy_uri = ArtistId::from_uri("spotify:artist:2WX2uTcsvV5OnS0inACecP").unwrap(); @@ -236,15 +176,9 @@ async fn test_artist_top_tracks() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_audio_analysis() { let track = TrackId::from_id("06AKEBrKUckW0KREUWRnvT").unwrap(); @@ -252,15 +186,9 @@ async fn test_audio_analysis() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_audio_features() { let track = TrackId::from_uri("spotify:track:06AKEBrKUckW0KREUWRnvT").unwrap(); @@ -268,15 +196,9 @@ async fn test_audio_features() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_audios_features() { let mut tracks_ids = vec![]; @@ -294,15 +216,9 @@ async fn test_audios_features() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_user() { let birdy_uri = UserId::from_id("tuggareutangranser").unwrap(); @@ -310,15 +226,9 @@ async fn test_user() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_track() { let birdy_uri = TrackId::from_uri("spotify:track:6rqhFgbbKwnb9MLmUQDhG6").unwrap(); @@ -326,15 +236,9 @@ async fn test_track() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_tracks() { let track_uris = [ @@ -345,15 +249,9 @@ async fn test_tracks() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_existing_playlist() { let playlist_id = PlaylistId::from_id("37i9dQZF1DZ06evO45P0Eo").unwrap(); @@ -365,15 +263,9 @@ async fn test_existing_playlist() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] async fn test_fake_playlist() { let playlist_id = PlaylistId::from_id("fakeid").unwrap(); @@ -415,8 +307,8 @@ pub mod test_pagination { } /// This test iterates a request of 10 items, with 5 requests of 2 items. - #[cfg_attr(all(feature = "__async", not(target_arch="wasm32")), tokio::test)] - #[cfg_attr(all(feature = "__async", target_arch="wasm32"), wasm_bindgen_test)] + #[cfg_attr(all(feature = "__async", not(target_arch = "wasm32")), tokio::test)] + #[cfg_attr(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)] async fn test_pagination_async() { use futures_util::StreamExt; diff --git a/tests/test_with_oauth.rs b/tests/test_with_oauth.rs index c5549069..48941f31 100644 --- a/tests/test_with_oauth.rs +++ b/tests/test_with_oauth.rs @@ -14,7 +14,7 @@ //! with the `oauth_tokens` example: //! //! cargo run --example oauth_tokens --features=env-file,cli -//! +//! mod util; use rspotify::{ @@ -31,10 +31,9 @@ use rspotify::{ use chrono::{prelude::*, Duration}; use maybe_async::maybe_async; -#[cfg(target_arch="wasm32")] +#[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; - /// Generating a new OAuth client for the requests. #[maybe_async] pub async fn oauth_client() -> AuthCodeSpotify { @@ -107,15 +106,9 @@ async fn fetch_all(paginator: Paginator<'_, ClientResult>) -> Vec { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_categories() { @@ -132,15 +125,9 @@ async fn test_categories() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_category_playlists() { @@ -157,15 +144,9 @@ async fn test_category_playlists() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_current_playback() { @@ -177,15 +158,9 @@ async fn test_current_playback() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_current_playing() { @@ -197,15 +172,9 @@ async fn test_current_playing() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_current_user_followed_artists() { @@ -217,15 +186,9 @@ async fn test_current_user_followed_artists() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_current_user_playing_track() { @@ -237,15 +200,9 @@ async fn test_current_user_playing_track() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_current_user_recently_played() { @@ -258,15 +215,9 @@ async fn test_current_user_recently_played() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_current_user_saved_albums() { @@ -305,15 +256,9 @@ async fn test_current_user_saved_albums() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_current_user_saved_tracks_add() { @@ -349,15 +294,9 @@ async fn test_current_user_saved_tracks_add() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_current_user_top_artists() { @@ -369,15 +308,9 @@ async fn test_current_user_top_artists() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_current_user_top_tracks() { @@ -389,15 +322,9 @@ async fn test_current_user_top_tracks() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_featured_playlists() { @@ -410,15 +337,9 @@ async fn test_featured_playlists() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_me() { @@ -426,15 +347,9 @@ async fn test_me() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_new_releases() { @@ -446,15 +361,9 @@ async fn test_new_releases() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_new_releases_with_from_token() { @@ -466,15 +375,9 @@ async fn test_new_releases_with_from_token() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_playback() { @@ -559,15 +462,9 @@ async fn test_playback() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_recommendations() { @@ -593,15 +490,9 @@ async fn test_recommendations() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_repeat() { @@ -618,15 +509,9 @@ async fn test_repeat() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_search_album() { @@ -639,15 +524,9 @@ async fn test_search_album() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_search_artist() { @@ -667,15 +546,9 @@ async fn test_search_artist() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_search_playlist() { @@ -695,15 +568,9 @@ async fn test_search_playlist() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_search_track() { @@ -725,15 +592,9 @@ async fn test_search_track() { // This also tests percentage signs in search queries to avoid regressions of // https://github.com/ramsayleung/rspotify/issues/141 #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_search_show() { @@ -746,15 +607,9 @@ async fn test_search_show() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_seek_track() { @@ -778,15 +633,9 @@ async fn test_seek_track() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_shuffle() { @@ -803,15 +652,9 @@ async fn test_shuffle() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_user_follow_artist() { @@ -829,15 +672,9 @@ async fn test_user_follow_artist() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_user_follow_users() { @@ -855,15 +692,9 @@ async fn test_user_follow_users() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_user_follow_playlist() { @@ -1038,15 +869,9 @@ async fn check_playlist_follow(client: &AuthCodeSpotify, playlist: &FullPlaylist } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_playlist() { @@ -1058,15 +883,9 @@ async fn test_playlist() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_volume() { @@ -1090,15 +909,9 @@ async fn test_volume() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_add_queue() { @@ -1114,15 +927,9 @@ async fn test_add_queue() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_get_several_shows() { @@ -1139,15 +946,9 @@ async fn test_get_several_shows() { } #[maybe_async::test( - feature = "__sync", - async( - all(feature = "__async", not(target_arch="wasm32")), - tokio::test - ), - async( - all(feature = "__async", target_arch="wasm32"), - wasm_bindgen_test - ) + feature = "__sync", + async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test), + async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test) )] #[ignore] async fn test_get_several_episodes() { diff --git a/tests/util.rs b/tests/util.rs index 6cb873de..ac6bac04 100644 --- a/tests/util.rs +++ b/tests/util.rs @@ -1,6 +1,6 @@ use rspotify::Credentials; -#[cfg(not(target_arch="wasm32"))] +#[cfg(not(target_arch = "wasm32"))] pub fn get_credentials() -> Credentials { // The credentials must be available in the environment. Credentials::from_env().unwrap_or_else(|| { @@ -12,7 +12,7 @@ pub fn get_credentials() -> Credentials { }) } -#[cfg(target_arch="wasm32")] +#[cfg(target_arch = "wasm32")] pub fn get_credentials() -> Credentials { // The credentials must be available in the environment. Panics if they are not available let id = dotenvy_macro::dotenv!("RSPOTIFY_CLIENT_ID"); @@ -20,18 +20,18 @@ pub fn get_credentials() -> Credentials { Credentials::new(&id, &secret) } -#[cfg(not(target_arch="wasm32"))] +#[cfg(not(target_arch = "wasm32"))] pub fn get_access_tokens() -> (Option, Option) { use std::env; ( env::var("RSPOTIFY_ACCESS_TOKEN").ok(), - env::var("RSPOTIFY_REFRESH_TOKEN").ok() + env::var("RSPOTIFY_REFRESH_TOKEN").ok(), ) } -#[cfg(target_arch="wasm32")] +#[cfg(target_arch = "wasm32")] pub fn get_access_tokens() -> (Option, Option) { let access_token = option_env!("RSPOTIFY_ACCESS_TOKEN").map(|s| s.to_string()); let refresh_token = option_env!("RSPOTIFY_REFRESH_TOKEN").map(|s| s.to_string()); (access_token, refresh_token) -} \ No newline at end of file +} From 70d50265031bc8b2e37b718f5e77db6ba926d374 Mon Sep 17 00:00:00 2001 From: Gregory Eric Sanderson <202192+gelendir@users.noreply.github.com> Date: Mon, 19 Feb 2024 22:02:44 -0500 Subject: [PATCH 3/4] fix clippy errors --- tests/test_with_credential.rs | 5 +++-- tests/test_with_oauth.rs | 18 +++++++++++++++++- tests/util.rs | 16 ---------------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/tests/test_with_credential.rs b/tests/test_with_credential.rs index 98e89a4b..dd76a8e3 100644 --- a/tests/test_with_credential.rs +++ b/tests/test_with_credential.rs @@ -307,8 +307,9 @@ pub mod test_pagination { } /// This test iterates a request of 10 items, with 5 requests of 2 items. - #[cfg_attr(all(feature = "__async", not(target_arch = "wasm32")), tokio::test)] - #[cfg_attr(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)] + #[cfg(feature = "__async")] + #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] async fn test_pagination_async() { use futures_util::StreamExt; diff --git a/tests/test_with_oauth.rs b/tests/test_with_oauth.rs index 48941f31..ac20f11b 100644 --- a/tests/test_with_oauth.rs +++ b/tests/test_with_oauth.rs @@ -34,10 +34,26 @@ use maybe_async::maybe_async; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; +#[cfg(not(target_arch = "wasm32"))] +fn get_access_tokens() -> (Option, Option) { + use std::env; + ( + env::var("RSPOTIFY_ACCESS_TOKEN").ok(), + env::var("RSPOTIFY_REFRESH_TOKEN").ok(), + ) +} + +#[cfg(target_arch = "wasm32")] +fn get_access_tokens() -> (Option, Option) { + let access_token = option_env!("RSPOTIFY_ACCESS_TOKEN").map(|s| s.to_string()); + let refresh_token = option_env!("RSPOTIFY_REFRESH_TOKEN").map(|s| s.to_string()); + (access_token, refresh_token) +} + /// Generating a new OAuth client for the requests. #[maybe_async] pub async fn oauth_client() -> AuthCodeSpotify { - let (access_token, refresh_token) = util::get_access_tokens(); + let (access_token, refresh_token) = get_access_tokens(); if let Some(access_token) = access_token { let tok = Token { diff --git a/tests/util.rs b/tests/util.rs index ac6bac04..2698fd70 100644 --- a/tests/util.rs +++ b/tests/util.rs @@ -19,19 +19,3 @@ pub fn get_credentials() -> Credentials { let secret = dotenvy_macro::dotenv!("RSPOTIFY_CLIENT_SECRET"); Credentials::new(&id, &secret) } - -#[cfg(not(target_arch = "wasm32"))] -pub fn get_access_tokens() -> (Option, Option) { - use std::env; - ( - env::var("RSPOTIFY_ACCESS_TOKEN").ok(), - env::var("RSPOTIFY_REFRESH_TOKEN").ok(), - ) -} - -#[cfg(target_arch = "wasm32")] -pub fn get_access_tokens() -> (Option, Option) { - let access_token = option_env!("RSPOTIFY_ACCESS_TOKEN").map(|s| s.to_string()); - let refresh_token = option_env!("RSPOTIFY_REFRESH_TOKEN").map(|s| s.to_string()); - (access_token, refresh_token) -} From 9bf39b44019cb8519a0d067a254abfc9ddc52fe7 Mon Sep 17 00:00:00 2001 From: Gregory Eric Sanderson <202192+gelendir@users.noreply.github.com> Date: Wed, 28 Feb 2024 14:26:14 -0500 Subject: [PATCH 4/4] document wasm support --- CHANGELOG.md | 5 +++++ README.md | 10 ++++++++++ src/lib.rs | 15 +++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 470e31fe..f2b0e161 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.13.0 (2024.02.28) + +**New features** +- ([#458](https://github.com/ramsayleung/rspotify/pull/458)) Support for the `wasm32-unknown-unknown` build target + ## 0.12.1 (Unreleased) **Bugfixes** - ([#440](https://github.com/ramsayleung/rspotify/issues/440)) Add Smartwatch device type, fix for json parse error: unknown variant Smartwatch. diff --git a/README.md b/README.md index d208de72..fd0ec1f1 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,16 @@ $ cargo build --all-features Because in order to switch between clients, the different clients have to implement the same base trait in [src/http/mod.rs](https://github.com/ramsayleung/rspotify/blob/master/src/http/mod.rs), so if you build with all features, you'll get `duplicate definitions` error. As every coin has two sides, you can only have one side at a time, not all sides of it. +## WASM support + +RSpotify supports building for the `wasm32-unknown-unknown` target. It should be as easy as: + +```sh +$ cargo build --target wasm32-unknown-unknown +``` + +Refer to the [documentation](https://docs.rs/rspotify/latest/rspotify/#webassembly) for more details + ## License [MIT](./LICENSE) diff --git a/src/lib.rs b/src/lib.rs index b97ebd2a..2947fb10 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,6 +108,21 @@ //! the [`.env` file](https://github.com/ramsayleung/rspotify/blob/master/.env) //! for more details. //! +//! ### WebAssembly +//! +//! RSpotify supports the `wasm32-unknown-unknown` target in combination +//! with the `client-reqwest` feature. HTTP requests must be processed async. +//! Other HTTP client configurations are not supported. +//! +//! [Spotify recommends][spotify-auth-flows] using [`AuthCodePkceSpotify`] for +//! authorization flows on the web. +//! +//! Importing the Client ID via `RSPOTIFY_CLIENT_ID` is not possible since WASM +//! web runtimes are isolated from the host environment. The client ID must be +//! passed explicitly to [`Credentials::new_pkce`]. Alternatively, it can be +//! embedded at compile time with the [`std::env!`] or +//! [`dotenv!`](https://crates.io/crates/dotenvy) macros. +//! //! ### Examples //! //! There are some [available examples on the GitHub