spire_core/testing/mod.rs
1//! Test handlers offline with [`MockSite`], [`MockPage`] and [`Visit`].
2//!
3//! A [`MockSite`] is a [`Backend`](crate::backend::Backend), so a whole crawl
4//! can run against it. To test what a handler does with one page, without
5//! crawling the links it queues, [`visit`](MockSite::visit) the page:
6//!
7//! ```
8//! use spire_core::dataset::InMemDataset;
9//! use spire_core::frontier::seed::Seed;
10//! use spire_core::testing::{MockPage, MockSite};
11//! use spire_core::worker::{Outcome, from_fn};
12//! use spire_core::{Context, Result};
13//!
14//! async fn page(cx: Context<impl spire_core::backend::Session>) -> Result<()> {
15//! let body = cx.body().await?;
16//! cx.dataset::<usize>()?.write(body.len()).await?;
17//! cx.queue().follow("/next").await?;
18//! Ok(())
19//! }
20//!
21//! # #[tokio::main(flavor = "current_thread")]
22//! # async fn main() -> Result<()> {
23//! let site = MockSite::new().page("https://example.com/", MockPage::html("<p>Hi</p>"));
24//! let visit = site
25//! .visit(Seed::get("https://example.com/")?)
26//! .with_dataset(InMemDataset::<usize>::new());
27//!
28//! assert!(matches!(visit.run(&from_fn(page)).await, Outcome::Continue));
29//! assert_eq!(visit.dataset::<usize>()?.read_all().await?, [9]);
30//! assert_eq!(visit.queued()[0].uri(), "https://example.com/next");
31//! assert_eq!(site.requests(), ["https://example.com/"]);
32//! # Ok(())
33//! # }
34//! ```
35
36mod page;
37mod site;
38mod visit;
39
40pub use page::MockPage;
41pub use site::{MockSession, MockSite, Sent};
42pub use visit::Visit;
43
44#[cfg(test)]
45mod tests;