mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
clean up for CI
This commit is contained in:
parent
2092c40bc7
commit
b4a1d90327
27 changed files with 49 additions and 525 deletions
|
@ -21,7 +21,7 @@ async fn main() {
|
|||
|
||||
// run our app with hyper
|
||||
// `axum::Server` is a re-export of `hyper::Server`
|
||||
logging::log!("listening on {}", addr);
|
||||
println!("listening on {}", addr);
|
||||
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
|
||||
axum::serve(listener, app.into_make_service())
|
||||
.await
|
||||
|
|
|
@ -13,10 +13,14 @@ lto = true
|
|||
[dependencies]
|
||||
console_log = "1.0"
|
||||
console_error_panic_hook = "0.1"
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos_axum = { path = "../../integrations/axum", default-features = false, optional = true }
|
||||
leptos_meta = { path = "../../meta", features = ["nightly"] }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
#leptos = { version = "0.5",/leptos", features = ["nightly"] }
|
||||
#leptos_axum = { version = "0.5",/integrations/axum", default-features = false, optional = true }
|
||||
#leptos_meta = { version = "0.5",/meta", features = ["nightly"] }
|
||||
#leptos_router = { version = "0.5",/router", features = ["nightly"] }
|
||||
leptos = { version = "0.5", features = ["nightly"] }
|
||||
leptos_axum = { version = "0.5", default-features = false, optional = true }
|
||||
leptos_meta = { version = "0.5", features = ["nightly"] }
|
||||
leptos_router = { version = "0.5", features = ["nightly"] }
|
||||
log = "0.4"
|
||||
simple_logger = "4.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
This example uses the basic Hacker News example as its basis, but shows how to run the server side as WASM running in a JS environment. In this example, Deno is used as the runtime.
|
||||
|
||||
**NOTE**: This example is slightly out of date pending an update to [`axum-js-fetch`](https://github.com/seanaye/axum-js-fetch/), which was waiting on a version of `gloo-net` that uses `http` 1.0. It still works with Leptos 0.5 and Axum 0.6, but not with the versions of Leptos (0.6 and later) that support Axum 1.0.
|
||||
|
||||
## Server Side Rendering with Deno
|
||||
|
||||
To run the Deno version, run
|
||||
|
|
|
@ -45,7 +45,6 @@ ssr = [
|
|||
"dep:leptos_axum",
|
||||
"dep:notify"
|
||||
]
|
||||
notify = ["dep:notify"]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["axum", "tower", "tower-http", "tokio", "leptos_axum"]
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
extend = [
|
||||
{ path = "../cargo-make/main.toml" },
|
||||
{ path = "../cargo-make/cargo-leptos-webdriver-test.toml" },
|
||||
{ path = "../cargo-make/cargo-leptos.toml" },
|
||||
]
|
||||
|
||||
[env]
|
||||
CLIENT_PROCESS_NAME = "todo_app_sqlite_axum"
|
||||
|
||||
[tasks.test-ui]
|
||||
cwd = "./e2e"
|
||||
command = "cargo"
|
||||
args = ["make", "test-ui", "${@}"]
|
||||
CLIENT_PROCESS_NAME = "server_fns_axum"
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
[package]
|
||||
name = "todo_app_sqlite_axum_e2e"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0.72"
|
||||
async-trait = "0.1.72"
|
||||
cucumber = "0.19.1"
|
||||
fantoccini = "0.19.3"
|
||||
pretty_assertions = "1.4.0"
|
||||
serde_json = "1.0.104"
|
||||
tokio = { version = "1.29.1", features = ["macros", "rt-multi-thread", "time"] }
|
||||
url = "2.4.0"
|
||||
|
||||
[[test]]
|
||||
name = "app_suite"
|
||||
harness = false # Allow Cucumber to print output instead of libtest
|
|
@ -1,20 +0,0 @@
|
|||
extend = { path = "../../cargo-make/main.toml" }
|
||||
|
||||
[tasks.test]
|
||||
env = { RUN_AUTOMATICALLY = false }
|
||||
condition = { env_true = ["RUN_AUTOMATICALLY"] }
|
||||
|
||||
[tasks.ci]
|
||||
|
||||
[tasks.test-ui]
|
||||
command = "cargo"
|
||||
args = [
|
||||
"test",
|
||||
"--test",
|
||||
"app_suite",
|
||||
"--",
|
||||
"--retry",
|
||||
"2",
|
||||
"--fail-fast",
|
||||
"${@}",
|
||||
]
|
|
@ -1,34 +0,0 @@
|
|||
# E2E Testing
|
||||
|
||||
This example demonstrates e2e testing with Rust using executable requirements.
|
||||
|
||||
## Testing Stack
|
||||
|
||||
| | Role | Description |
|
||||
|---|---|---|
|
||||
| [Cucumber](https://github.com/cucumber-rs/cucumber/tree/main) | Test Runner | Run [Gherkin](https://cucumber.io/docs/gherkin/reference/) specifications as Rust tests |
|
||||
| [Fantoccini](https://github.com/jonhoo/fantoccini/tree/main) | Browser Client | Interact with web pages through WebDriver |
|
||||
| [Cargo Leptos ](https://github.com/leptos-rs/cargo-leptos) | Build Tool | Compile example and start the server and end-2-end tests |
|
||||
| [chromedriver](https://chromedriver.chromium.org/downloads) | WebDriver | Provide WebDriver for Chrome
|
||||
|
||||
## Testing Organization
|
||||
|
||||
Testing is organized around what a user can do and see/not see. Test scenarios are grouped by the **user action** and the **object** of that action. This makes it easier to locate and reason about requirements.
|
||||
|
||||
Here is a brief overview of how things fit together.
|
||||
|
||||
```bash
|
||||
features
|
||||
└── {action}_{object}.feature # Specify test scenarios
|
||||
tests
|
||||
├── fixtures
|
||||
│ ├── action.rs # Perform a user action (click, type, etc.)
|
||||
│ ├── check.rs # Assert what a user can see/not see
|
||||
│ ├── find.rs # Query page elements
|
||||
│ ├── mod.rs
|
||||
│ └── world
|
||||
│ ├── action_steps.rs # Map Gherkin steps to user actions
|
||||
│ ├── check_steps.rs # Map Gherkin steps to user expectations
|
||||
│ └── mod.rs
|
||||
└── app_suite.rs # Test main
|
||||
```
|
|
@ -1,16 +0,0 @@
|
|||
@add_todo
|
||||
Feature: Add Todo
|
||||
|
||||
Background:
|
||||
Given I see the app
|
||||
|
||||
@add_todo-see
|
||||
Scenario: Should see the todo
|
||||
Given I set the todo as Buy Bread
|
||||
When I click the Add button
|
||||
Then I see the todo named Buy Bread
|
||||
|
||||
@add_todo-style
|
||||
Scenario: Should see the pending todo
|
||||
When I add a todo as Buy Oranges
|
||||
Then I see the pending todo
|
|
@ -1,18 +0,0 @@
|
|||
@delete_todo
|
||||
Feature: Delete Todo
|
||||
|
||||
Background:
|
||||
Given I see the app
|
||||
|
||||
@serial
|
||||
@delete_todo-remove
|
||||
Scenario: Should not see the deleted todo
|
||||
Given I add a todo as Buy Yogurt
|
||||
When I delete the todo named Buy Yogurt
|
||||
Then I do not see the todo named Buy Yogurt
|
||||
|
||||
@serial
|
||||
@delete_todo-message
|
||||
Scenario: Should see the empty list message
|
||||
When I empty the todo list
|
||||
Then I see the empty list message is No tasks were found.
|
|
@ -1,12 +0,0 @@
|
|||
@open_app
|
||||
Feature: Open App
|
||||
|
||||
@open_app-title
|
||||
Scenario: Should see the home page title
|
||||
When I open the app
|
||||
Then I see the page title is My Tasks
|
||||
|
||||
@open_app-label
|
||||
Scenario: Should see the input label
|
||||
When I open the app
|
||||
Then I see the label of the input is Add a Todo
|
|
@ -1,14 +0,0 @@
|
|||
mod fixtures;
|
||||
|
||||
use anyhow::Result;
|
||||
use cucumber::World;
|
||||
use fixtures::world::AppWorld;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
AppWorld::cucumber()
|
||||
.fail_on_skipped()
|
||||
.run_and_exit("./features")
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
use super::{find, world::HOST};
|
||||
use anyhow::Result;
|
||||
use fantoccini::Client;
|
||||
use std::result::Result::Ok;
|
||||
use tokio::{self, time};
|
||||
|
||||
pub async fn goto_path(client: &Client, path: &str) -> Result<()> {
|
||||
let url = format!("{}{}", HOST, path);
|
||||
client.goto(&url).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn add_todo(client: &Client, text: &str) -> Result<()> {
|
||||
fill_todo(client, text).await?;
|
||||
click_add_button(client).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn fill_todo(client: &Client, text: &str) -> Result<()> {
|
||||
let textbox = find::todo_input(client).await;
|
||||
textbox.send_keys(text).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn click_add_button(client: &Client) -> Result<()> {
|
||||
let add_button = find::add_button(client).await;
|
||||
add_button.click().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn empty_todo_list(client: &Client) -> Result<()> {
|
||||
let todos = find::todos(client).await;
|
||||
|
||||
for _todo in todos {
|
||||
let _ = delete_first_todo(client).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_first_todo(client: &Client) -> Result<()> {
|
||||
if let Some(element) = find::first_delete_button(client).await {
|
||||
element.click().await.expect("Failed to delete todo");
|
||||
time::sleep(time::Duration::from_millis(250)).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_todo(client: &Client, text: &str) -> Result<()> {
|
||||
if let Some(element) = find::delete_button(client, text).await {
|
||||
element.click().await?;
|
||||
time::sleep(time::Duration::from_millis(250)).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
use super::find;
|
||||
use anyhow::{Ok, Result};
|
||||
use fantoccini::{Client, Locator};
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
pub async fn text_on_element(
|
||||
client: &Client,
|
||||
selector: &str,
|
||||
expected_text: &str,
|
||||
) -> Result<()> {
|
||||
let element = client
|
||||
.wait()
|
||||
.for_element(Locator::Css(selector))
|
||||
.await
|
||||
.expect(
|
||||
format!("Element not found by Css selector `{}`", selector)
|
||||
.as_str(),
|
||||
);
|
||||
|
||||
let actual = element.text().await?;
|
||||
assert_eq!(&actual, expected_text);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn todo_present(
|
||||
client: &Client,
|
||||
text: &str,
|
||||
expected: bool,
|
||||
) -> Result<()> {
|
||||
let todo_present = is_todo_present(client, text).await;
|
||||
|
||||
assert_eq!(todo_present, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn is_todo_present(client: &Client, text: &str) -> bool {
|
||||
let todos = find::todos(client).await;
|
||||
|
||||
for todo in todos {
|
||||
let todo_title = todo.text().await.expect("Todo title not found");
|
||||
if todo_title == text {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub async fn todo_is_pending(client: &Client) -> Result<()> {
|
||||
if let None = find::pending_todo(client).await {
|
||||
assert!(false, "Pending todo not found");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
use fantoccini::{elements::Element, Client, Locator};
|
||||
|
||||
pub async fn todo_input(client: &Client) -> Element {
|
||||
let textbox = client
|
||||
.wait()
|
||||
.for_element(Locator::Css("input[name='title"))
|
||||
.await
|
||||
.expect("Todo textbox not found");
|
||||
|
||||
textbox
|
||||
}
|
||||
|
||||
pub async fn add_button(client: &Client) -> Element {
|
||||
let button = client
|
||||
.wait()
|
||||
.for_element(Locator::Css("input[value='Add']"))
|
||||
.await
|
||||
.expect("");
|
||||
|
||||
button
|
||||
}
|
||||
|
||||
pub async fn first_delete_button(client: &Client) -> Option<Element> {
|
||||
if let Ok(element) = client
|
||||
.wait()
|
||||
.for_element(Locator::Css("li:first-child input[value='X']"))
|
||||
.await
|
||||
{
|
||||
return Some(element);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub async fn delete_button(client: &Client, text: &str) -> Option<Element> {
|
||||
let selector = format!("//*[text()='{text}']//input[@value='X']");
|
||||
if let Ok(element) =
|
||||
client.wait().for_element(Locator::XPath(&selector)).await
|
||||
{
|
||||
return Some(element);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub async fn pending_todo(client: &Client) -> Option<Element> {
|
||||
if let Ok(element) =
|
||||
client.wait().for_element(Locator::Css(".pending")).await
|
||||
{
|
||||
return Some(element);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub async fn todos(client: &Client) -> Vec<Element> {
|
||||
let todos = client
|
||||
.find_all(Locator::Css("li"))
|
||||
.await
|
||||
.expect("Todo List not found");
|
||||
|
||||
todos
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
pub mod action;
|
||||
pub mod check;
|
||||
pub mod find;
|
||||
pub mod world;
|
|
@ -1,57 +0,0 @@
|
|||
use crate::fixtures::{action, world::AppWorld};
|
||||
use anyhow::{Ok, Result};
|
||||
use cucumber::{given, when};
|
||||
|
||||
#[given("I see the app")]
|
||||
#[when("I open the app")]
|
||||
async fn i_open_the_app(world: &mut AppWorld) -> Result<()> {
|
||||
let client = &world.client;
|
||||
action::goto_path(client, "").await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[given(regex = "^I add a todo as (.*)$")]
|
||||
#[when(regex = "^I add a todo as (.*)$")]
|
||||
async fn i_add_a_todo_titled(world: &mut AppWorld, text: String) -> Result<()> {
|
||||
let client = &world.client;
|
||||
action::add_todo(client, text.as_str()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[given(regex = "^I set the todo as (.*)$")]
|
||||
async fn i_set_the_todo_as(world: &mut AppWorld, text: String) -> Result<()> {
|
||||
let client = &world.client;
|
||||
action::fill_todo(client, &text).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[when(regex = "I click the Add button$")]
|
||||
async fn i_click_the_button(world: &mut AppWorld) -> Result<()> {
|
||||
let client = &world.client;
|
||||
action::click_add_button(client).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[when(regex = "^I delete the todo named (.*)$")]
|
||||
async fn i_delete_the_todo_named(
|
||||
world: &mut AppWorld,
|
||||
text: String,
|
||||
) -> Result<()> {
|
||||
let client = &world.client;
|
||||
action::delete_todo(client, text.as_str()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[given("the todo list is empty")]
|
||||
#[when("I empty the todo list")]
|
||||
async fn i_empty_the_todo_list(world: &mut AppWorld) -> Result<()> {
|
||||
let client = &world.client;
|
||||
action::empty_todo_list(client).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
use crate::fixtures::{check, world::AppWorld};
|
||||
use anyhow::{Ok, Result};
|
||||
use cucumber::then;
|
||||
|
||||
#[then(regex = "^I see the page title is (.*)$")]
|
||||
async fn i_see_the_page_title_is(
|
||||
world: &mut AppWorld,
|
||||
text: String,
|
||||
) -> Result<()> {
|
||||
let client = &world.client;
|
||||
check::text_on_element(client, "h1", &text).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(regex = "^I see the label of the input is (.*)$")]
|
||||
async fn i_see_the_label_of_the_input_is(
|
||||
world: &mut AppWorld,
|
||||
text: String,
|
||||
) -> Result<()> {
|
||||
let client = &world.client;
|
||||
check::text_on_element(client, "label", &text).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(regex = "^I see the todo named (.*)$")]
|
||||
async fn i_see_the_todo_is_present(
|
||||
world: &mut AppWorld,
|
||||
text: String,
|
||||
) -> Result<()> {
|
||||
let client = &world.client;
|
||||
check::todo_present(client, text.as_str(), true).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then("I see the pending todo")]
|
||||
async fn i_see_the_pending_todo(world: &mut AppWorld) -> Result<()> {
|
||||
let client = &world.client;
|
||||
|
||||
check::todo_is_pending(client).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(regex = "^I see the empty list message is (.*)$")]
|
||||
async fn i_see_the_empty_list_message_is(
|
||||
world: &mut AppWorld,
|
||||
text: String,
|
||||
) -> Result<()> {
|
||||
let client = &world.client;
|
||||
check::text_on_element(client, "ul p", &text).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(regex = "^I do not see the todo named (.*)$")]
|
||||
async fn i_do_not_see_the_todo_is_present(
|
||||
world: &mut AppWorld,
|
||||
text: String,
|
||||
) -> Result<()> {
|
||||
let client = &world.client;
|
||||
check::todo_present(client, text.as_str(), false).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
pub mod action_steps;
|
||||
pub mod check_steps;
|
||||
|
||||
use anyhow::Result;
|
||||
use cucumber::World;
|
||||
use fantoccini::{
|
||||
error::NewSessionError, wd::Capabilities, Client, ClientBuilder,
|
||||
};
|
||||
|
||||
pub const HOST: &str = "http://127.0.0.1:3000";
|
||||
|
||||
#[derive(Debug, World)]
|
||||
#[world(init = Self::new)]
|
||||
pub struct AppWorld {
|
||||
pub client: Client,
|
||||
}
|
||||
|
||||
impl AppWorld {
|
||||
async fn new() -> Result<Self, anyhow::Error> {
|
||||
let webdriver_client = build_client().await?;
|
||||
|
||||
Ok(Self {
|
||||
client: webdriver_client,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async fn build_client() -> Result<Client, NewSessionError> {
|
||||
let mut cap = Capabilities::new();
|
||||
let arg = serde_json::from_str("{\"args\": [\"-headless\"]}").unwrap();
|
||||
cap.insert("goog:chromeOptions".to_string(), arg);
|
||||
|
||||
let client = ClientBuilder::native()
|
||||
.capabilities(cap)
|
||||
.connect("http://localhost:4444")
|
||||
.await?;
|
||||
|
||||
Ok(client)
|
||||
}
|
|
@ -168,15 +168,12 @@ pub fn WithAnAction() -> impl IntoView {
|
|||
<button
|
||||
on:click=move |_| {
|
||||
let text = input_ref.get().unwrap().value();
|
||||
action.dispatch(text);
|
||||
action.dispatch(text.into());
|
||||
// note: technically, this `action` takes `AddRow` (the server fn type) as its
|
||||
// argument
|
||||
//
|
||||
// however, `.dispatch()` takes `impl Into<I>`, and for any one-argument server
|
||||
// functions, `From<_>` is implemented between the server function type and the
|
||||
// type of this single argument
|
||||
//
|
||||
// so `action.dispatch(text)` means `action.dispatch(AddRow { text })`
|
||||
// however, for any one-argument server functions, `From<_>` is implemented between
|
||||
// the server function type and the type of this single argument
|
||||
}
|
||||
>
|
||||
Submit
|
||||
|
|
|
@ -62,6 +62,9 @@ ssr = [
|
|||
"dep:leptos_axum",
|
||||
]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["axum", "tower", "tower-http", "tokio", "sqlx", "leptos_axum"]
|
||||
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
|
||||
|
||||
[package.metadata.leptos]
|
||||
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
extend = { path = "../cargo-make/main.toml" }
|
||||
extend = [
|
||||
{ path = "../cargo-make/main.toml" },
|
||||
{ path = "../cargo-make/cargo-leptos.toml" },
|
||||
]
|
||||
|
||||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
[env]
|
||||
|
||||
[tasks.check]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "check-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
CLIENT_PROCESS_NAME = "sso_auth_axum"
|
||||
|
|
|
@ -93,8 +93,8 @@ where
|
|||
any(debug_assertions, feature = "ssr"),
|
||||
tracing::instrument(level = "trace", skip_all,)
|
||||
)]
|
||||
pub fn dispatch(&self, input: impl Into<I>) {
|
||||
self.0.with_value(|a| a.dispatch(input.into()))
|
||||
pub fn dispatch(&self, input: I) {
|
||||
self.0.with_value(|a| a.dispatch(input))
|
||||
}
|
||||
|
||||
/// Create an [Action].
|
||||
|
|
|
@ -321,7 +321,7 @@ where
|
|||
|
||||
/// Creates an [MultiAction] that can be used to call a server function.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```rust,ignore
|
||||
/// # use leptos::*;
|
||||
///
|
||||
/// #[server(MyServerFn)]
|
||||
|
|
|
@ -105,3 +105,8 @@ ssr = ["inventory"]
|
|||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
# disables some feature combos for testing in CI
|
||||
[package.metadata.cargo-all-features]
|
||||
denylist = ["rustls", "default-tls"]
|
||||
skip_feature_sets = [["actix", "axum"], ["browser", "actix"], ["browser", "axum"]]
|
||||
|
|
|
@ -60,7 +60,7 @@ pub use stream::*;
|
|||
///
|
||||
/// For example, here’s the implementation for [`Json`].
|
||||
///
|
||||
/// ```rust
|
||||
/// ```rust,ignore
|
||||
/// impl<CustErr, T, Request> IntoReq<Json, Request, CustErr> for T
|
||||
/// where
|
||||
/// Request: ClientReq<CustErr>,
|
||||
|
@ -98,7 +98,7 @@ pub trait IntoReq<Encoding, Request, CustErr> {
|
|||
///
|
||||
/// For example, here’s the implementation for [`Json`].
|
||||
///
|
||||
/// ```rust
|
||||
/// ```rust,ignore
|
||||
/// impl<CustErr, T, Request> FromReq<Json, Request, CustErr> for T
|
||||
/// where
|
||||
/// // require the Request implement `Req`
|
||||
|
@ -137,7 +137,7 @@ where
|
|||
///
|
||||
/// For example, here’s the implementation for [`Json`].
|
||||
///
|
||||
/// ```rust
|
||||
/// ```rust,ignore
|
||||
/// impl<CustErr, T, Response> IntoRes<Json, Response, CustErr> for T
|
||||
/// where
|
||||
/// Response: Res<CustErr>,
|
||||
|
@ -170,7 +170,7 @@ pub trait IntoRes<Encoding, Response, CustErr> {
|
|||
///
|
||||
/// For example, here’s the implementation for [`Json`].
|
||||
///
|
||||
/// ```rust
|
||||
/// ```rust,ignore
|
||||
/// impl<CustErr, T, Response> FromRes<Json, Response, CustErr> for T
|
||||
/// where
|
||||
/// Response: ClientRes<CustErr> + Send,
|
||||
|
|
|
@ -416,12 +416,12 @@ pub fn server_macro_impl(
|
|||
} else if let Some(req_ty) = preset_req {
|
||||
req_ty.to_token_stream()
|
||||
} else {
|
||||
return Err(syn::Error::new(
|
||||
Span::call_site(),
|
||||
"If the `ssr` feature is enabled, either the `actix` or `axum` \
|
||||
features should also be enabled, or the `req = ` argument should \
|
||||
be provided to specify the request type.",
|
||||
));
|
||||
// fall back to the browser version, to avoid erroring out
|
||||
// in things like doctests
|
||||
// in reality, one of the above needs to be set
|
||||
quote! {
|
||||
#server_fn_path::request::BrowserMockReq
|
||||
}
|
||||
};
|
||||
let res = if !cfg!(feature = "ssr") {
|
||||
quote! {
|
||||
|
@ -440,12 +440,12 @@ pub fn server_macro_impl(
|
|||
} else if let Some(res_ty) = preset_res {
|
||||
res_ty.to_token_stream()
|
||||
} else {
|
||||
return Err(syn::Error::new(
|
||||
Span::call_site(),
|
||||
"If the `ssr` feature is enabled, either the `actix` or `axum` \
|
||||
features should also be enabled, or the `res = ` argument should \
|
||||
be provided to specify the response type.",
|
||||
));
|
||||
// fall back to the browser version, to avoid erroring out
|
||||
// in things like doctests
|
||||
// in reality, one of the above needs to be set
|
||||
quote! {
|
||||
#server_fn_path::response::BrowserMockRes
|
||||
}
|
||||
};
|
||||
|
||||
// Remove any leading slashes, even if they exist (we'll add them below)
|
||||
|
|
Loading…
Reference in a new issue