Struct goose_eggs::ValidateBuilder
source · pub struct ValidateBuilder<'a> { /* private fields */ }
Expand description
Used to build a Validate
object, necessary to invoke the
validate_page
or validate_and_load_static_assets
functions.
Example
use goose::prelude::*;
use goose_eggs::{validate_and_load_static_assets, Validate};
transaction!(load_and_validate_page);
async fn load_and_validate_page(user: &mut GooseUser) -> TransactionResult {
// Make a GET request.
let mut goose = user.get("example/path").await?;
// Build a [`Validate`] object to confirm the response is valid.
let validate = &Validate::builder()
// Validate that the page has `Example` in the title.
.title("Example")
// Validate that the page has `foo` in the returned html body.
.text("foo")
// Validate that the page also has `<a href="bar">` in the returned
// html body.
.text(r#"<a href="bar">"#)
.build();
// Perform the actual validation, using `?` to pass up the error if any
// validation fails.
validate_and_load_static_assets(
user,
goose,
&validate,
).await?;
Ok(())
}
Implementations§
source§impl<'a> ValidateBuilder<'a>
impl<'a> ValidateBuilder<'a>
sourcepub fn status(self, status: u16) -> Self
pub fn status(self, status: u16) -> Self
Define the HTTP status expected to be returned when loading the page.
This structure is passed to validate_page
or validate_and_load_static_assets
.
Example
use goose_eggs::Validate;
let _validate = Validate::builder()
.status(200)
.build();
sourcepub fn title(self, title: impl Into<&'a str>) -> Self
pub fn title(self, title: impl Into<&'a str>) -> Self
Create a Validate
object to validate that response title contains the specified
text.
This structure is passed to validate_page
or validate_and_load_static_assets
.
Example
use goose_eggs::Validate;
let _validate = Validate::builder()
.title("Home page")
.build();
Examples found in repository?
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
pub async fn front_page_en(user: &mut GooseUser) -> TransactionResult {
let goose = user.get("").await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder().title("Home").build(),
)
.await?;
Ok(())
}
/// Load recipe listing in English and all static assets found on the page.
pub async fn recipe_listing_en(user: &mut GooseUser) -> TransactionResult {
let goose = user.get("en/recipes/").await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder().title("Recipes").build(),
)
.await?;
Ok(())
}
/// Load a random recipe in English and all static assets found on the page.
pub async fn recipe_en(user: &mut GooseUser) -> TransactionResult {
let nodes = common::get_nodes(&common::ContentType::Recipe);
let recipe = nodes.choose(&mut rand::thread_rng());
let goose = user.get(recipe.unwrap().url_en).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(recipe.unwrap().title_en)
.build(),
)
.await?;
Ok(())
}
/// Load article listing in English and all static assets found on the page.
pub async fn article_listing_en(user: &mut GooseUser) -> TransactionResult {
let goose = user.get("en/articles/").await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder().title("Articles").build(),
)
.await?;
Ok(())
}
/// Load a random article in English and all static assets found on the page.
pub async fn article_en(user: &mut GooseUser) -> TransactionResult {
let nodes = common::get_nodes(&common::ContentType::Article);
let article = nodes.choose(&mut rand::thread_rng());
let goose = user.get(article.unwrap().url_en).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(article.unwrap().title_en)
.build(),
)
.await?;
Ok(())
}
/// Load a random basic page in English and all static assets found on the page.
pub async fn basic_page_en(user: &mut GooseUser) -> TransactionResult {
let nodes = common::get_nodes(&common::ContentType::BasicPage);
let page = nodes.choose(&mut rand::thread_rng());
let goose = user.get(page.unwrap().url_en).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(page.unwrap().title_en)
.build(),
)
.await?;
Ok(())
}
/// Load a random node by nid in English and all static assets found on the page.
pub async fn page_by_nid(user: &mut GooseUser) -> TransactionResult {
// Randomly select a content type.
let content_types = vec![
common::ContentType::Article,
common::ContentType::BasicPage,
common::ContentType::Recipe,
];
let content_type = content_types.choose(&mut rand::thread_rng());
// Then randomly select a node of this content type.
let nodes = common::get_nodes(content_type.unwrap());
let page = nodes.choose(&mut rand::thread_rng());
// Load the page by nid instead of by URL.
let goose = user
.get(&("node/".to_string() + &page.unwrap().nid.to_string()))
.await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(page.unwrap().title_en)
.build(),
)
.await?;
Ok(())
}
/// Anonymously load the contact form in English and POST feedback.
pub async fn anonymous_contact_form_en(user: &mut GooseUser) -> TransactionResult {
common::anonymous_contact_form(user, true).await?;
Ok(())
}
// Pick a random word from the title of a random node and perform a search in English.
pub async fn search_en(user: &mut GooseUser) -> TransactionResult {
// Build a random three-word phrase taken from english words on the Umami website.
let search_words = common::random_words(3, true);
let search_phrase = search_words.join(" ");
// The search page should have "Search" in the title.
let validate_search_page = &goose_eggs::Validate::builder().title("Search").build();
// The results page should have the search_phrase in the title.
let validate_results_page = &goose_eggs::Validate::builder()
.title(&*search_phrase)
.build();
let search_params = goose_eggs::drupal::SearchParams::builder()
.keys(&*search_phrase)
.url("en/search/node")
.search_page_validation(validate_search_page)
.results_page_validation(validate_results_page)
.build();
goose_eggs::drupal::search(user, &search_params).await?;
Ok(())
}
/// Load category listing by a random term in English and all static assets found on the page.
pub async fn term_listing_en(user: &mut GooseUser) -> TransactionResult {
let terms = common::get_terms();
let term = terms.choose(&mut rand::thread_rng());
let goose = user.get(term.unwrap().url_en).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(term.unwrap().title_en)
.build(),
)
.await?;
Ok(())
}
More examples
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
pub async fn front_page_es(user: &mut GooseUser) -> TransactionResult {
let goose = user.get("es").await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder().title("Inicio").build(),
)
.await?;
Ok(())
}
/// Load article listing in Spanish and all static assets found on the page.
pub async fn recipe_listing_es(user: &mut GooseUser) -> TransactionResult {
let goose = user.get("es/recipes/").await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder().title("Recetas").build(),
)
.await?;
Ok(())
}
/// Load a random recipe in Spanish and all static assets found on the page.
pub async fn recipe_es(user: &mut GooseUser) -> TransactionResult {
let nodes = common::get_nodes(&common::ContentType::Recipe);
let recipe = nodes.choose(&mut rand::thread_rng());
let goose = user.get(recipe.unwrap().url_es).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(recipe.unwrap().title_es)
.build(),
)
.await?;
Ok(())
}
/// Load article listing in Spanish and all static assets found on the page.
pub async fn article_listing_es(user: &mut GooseUser) -> TransactionResult {
let goose = user.get("es/articles/").await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder().title("Artículos").build(),
)
.await?;
Ok(())
}
/// Load a random article in Spanish and all static assets found on the page.
pub async fn article_es(user: &mut GooseUser) -> TransactionResult {
let nodes = common::get_nodes(&common::ContentType::Article);
let article = nodes.choose(&mut rand::thread_rng());
let goose = user.get(article.unwrap().url_es).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(article.unwrap().title_es)
.build(),
)
.await?;
Ok(())
}
/// Load a basic page in Spanish and all static assets found on the page.
pub async fn basic_page_es(user: &mut GooseUser) -> TransactionResult {
let nodes = common::get_nodes(&common::ContentType::BasicPage);
let page = nodes.choose(&mut rand::thread_rng());
let goose = user.get(page.unwrap().url_es).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(page.unwrap().title_es)
.build(),
)
.await?;
Ok(())
}
/// Anonymously load the contact form in Spanish and POST feedback.
pub async fn anonymous_contact_form_es(user: &mut GooseUser) -> TransactionResult {
common::anonymous_contact_form(user, false).await?;
Ok(())
}
// Pick a random word from the title of a random node and perform a search in Spanish.
pub async fn search_es(user: &mut GooseUser) -> TransactionResult {
// Build a random three-word phrase taken from Spanish words on the Umami website.
let search_words = common::random_words(3, false);
let search_phrase = search_words.join(" ");
// The search page should have "Buscar" in the title.
let validate_search_page = &goose_eggs::Validate::builder().title("Buscar").build();
// The results page should have the search_phrase in the title.
let validate_results_page = &goose_eggs::Validate::builder()
.title(&*search_phrase)
.build();
let search_params = goose_eggs::drupal::SearchParams::builder()
.keys(&*search_phrase)
.url("es/search/node")
.search_page_validation(validate_search_page)
.results_page_validation(validate_results_page)
.build();
goose_eggs::drupal::search(user, &search_params).await?;
Ok(())
}
/// Load category listing by a random term in Spanish and all static assets found on the page.
pub async fn term_listing_es(user: &mut GooseUser) -> TransactionResult {
let terms = common::get_terms();
let term = terms.choose(&mut rand::thread_rng());
let goose = user.get(term.unwrap().url_es).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(term.unwrap().title_es)
.build(),
)
.await?;
Ok(())
}
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
pub async fn edit_article(user: &mut GooseUser) -> TransactionResult {
// First, load a random article.
let nodes = common::get_nodes(&common::ContentType::Article);
let article = nodes.choose(&mut rand::thread_rng());
let goose = user.get(article.unwrap().url_en).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(article.unwrap().title_en)
.text(&format!("en/node/{}/edit", article.unwrap().nid))
.build(),
)
.await?;
// Next, load the edit link for the chosen article.
let goose = user
.get(&format!("en/node/{}/edit", article.unwrap().nid))
.await?;
let edit_page = goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title("Edit Article")
.build(),
)
.await?;
let edit_form = goose_eggs::drupal::get_form(&edit_page, "node-article-edit-form");
let form_build_id = goose_eggs::drupal::get_form_value(&edit_form, "form_build_id");
let form_token = goose_eggs::drupal::get_form_value(&edit_form, "form_token");
let form_id = goose_eggs::drupal::get_form_value(&edit_form, "form_id");
// Build node form with random word from title.
let params = [
("form_build_id", &form_build_id),
("form_token", &form_token),
("form_id", &form_id),
("op", &"Save (this translation)".to_string()),
];
let mut saved_article = user
.post_form(&format!("en/node/{}/edit", article.unwrap().nid), ¶ms)
.await?;
// A successful node save is redirected.
if !saved_article.request.redirected {
return user.set_failure(
&format!("{}: saving article failed", saved_article.request.final_url),
&mut saved_article.request,
None,
None,
);
}
// Be sure we're viewing the same article after editing it.
goose_eggs::validate_and_load_static_assets(
user,
saved_article,
&goose_eggs::Validate::builder()
.title(article.unwrap().title_en)
.build(),
)
.await?;
Ok(())
}
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
pub async fn anonymous_contact_form(user: &mut GooseUser, english: bool) -> TransactionResult {
let contact_form_url = if english { "en/contact" } else { "es/contact" };
let goose = user.get(contact_form_url).await?;
let contact_page = goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(if english {
"Website feedback"
} else {
"Comentarios sobre el sitio web"
})
.build(),
)
.await?;
let form = goose_eggs::drupal::get_form(&contact_page, "contact-message-feedback-form");
let form_build_id = goose_eggs::drupal::get_form_value(&form, "form_build_id");
let form_id = goose_eggs::drupal::get_form_value(&form, "form_id");
// Build contact form parameters.
let name = random_words(2, english).join(" ");
let email = format!("{}@example.com", random_words(1, english).pop().unwrap());
let subject = random_words(8, english).join(" ");
let message = random_words(12, english).join(" ");
let params = [
("name", name.as_str()),
("mail", email.as_str()),
("subject[0][value]", subject.as_str()),
("message[0][value]", message.as_str()),
("form_build_id", &form_build_id),
("form_id", &form_id),
("op", "Send+message"),
];
let mut goose = user.post_form(contact_form_url, ¶ms).await?;
// Drupal 9 throttles how many times an IP address can submit the contact form, so we
// need special handling.
match goose.response {
Ok(response) => {
// Copy the headers so we have them for logging if there are errors.
let headers = &response.headers().clone();
match response.text().await {
Ok(html) => {
// Drupal 9 will throttle how many times our IP address can actually
// submit the contact form. We can detect this, but it happens a lot
// so there's nothing useful to do.
let error_text = if english {
"You cannot send more than"
} else {
"No le está permitido enviar más"
};
if html.contains(error_text) {
// The contact form was throttled, safely ignore this.
}
// Either way, a "real" user would still load all static elements on
// the returned page.
goose_eggs::load_static_elements(user, &html).await;
}
Err(e) => {
return user.set_failure(
&format!("{}: failed to parse page: {}", goose.request.raw.url, e),
&mut goose.request,
Some(headers),
None,
);
}
}
}
Err(e) => {
return user.set_failure(
&format!("{}: no response from server: {}", goose.request.raw.url, e),
&mut goose.request,
None,
None,
);
}
}
Ok(())
}
sourcepub fn text(self, text: &'a str) -> Self
pub fn text(self, text: &'a str) -> Self
Create a Validate
object to validate that the response page contains the specified
text.
This structure is passed to validate_page
or validate_and_load_static_assets
.
Example
use goose_eggs::Validate;
let _validate = Validate::builder()
.text("example")
.build();
It’s possible to call this function multiple times to validate that multiple texts
appear on the page. Alternatively you can call ValidateBuilder::texts
.
Multiple Example
use goose_eggs::Validate;
let _validate = Validate::builder()
.text("example")
.text("another")
.build();
Examples found in repository?
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
pub async fn edit_article(user: &mut GooseUser) -> TransactionResult {
// First, load a random article.
let nodes = common::get_nodes(&common::ContentType::Article);
let article = nodes.choose(&mut rand::thread_rng());
let goose = user.get(article.unwrap().url_en).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(article.unwrap().title_en)
.text(&format!("en/node/{}/edit", article.unwrap().nid))
.build(),
)
.await?;
// Next, load the edit link for the chosen article.
let goose = user
.get(&format!("en/node/{}/edit", article.unwrap().nid))
.await?;
let edit_page = goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title("Edit Article")
.build(),
)
.await?;
let edit_form = goose_eggs::drupal::get_form(&edit_page, "node-article-edit-form");
let form_build_id = goose_eggs::drupal::get_form_value(&edit_form, "form_build_id");
let form_token = goose_eggs::drupal::get_form_value(&edit_form, "form_token");
let form_id = goose_eggs::drupal::get_form_value(&edit_form, "form_id");
// Build node form with random word from title.
let params = [
("form_build_id", &form_build_id),
("form_token", &form_token),
("form_id", &form_id),
("op", &"Save (this translation)".to_string()),
];
let mut saved_article = user
.post_form(&format!("en/node/{}/edit", article.unwrap().nid), ¶ms)
.await?;
// A successful node save is redirected.
if !saved_article.request.redirected {
return user.set_failure(
&format!("{}: saving article failed", saved_article.request.final_url),
&mut saved_article.request,
None,
None,
);
}
// Be sure we're viewing the same article after editing it.
goose_eggs::validate_and_load_static_assets(
user,
saved_article,
&goose_eggs::Validate::builder()
.title(article.unwrap().title_en)
.build(),
)
.await?;
Ok(())
}
sourcepub fn texts(self, texts: Vec<&'a str>) -> Self
pub fn texts(self, texts: Vec<&'a str>) -> Self
Create a Validate
object to validate that the response page contains the specified
texts.
This structure is passed to validate_page
or validate_and_load_static_assets
.
Example
use goose_eggs::Validate;
let _validate = Validate::builder()
.texts(vec!["example", "another"])
.build();
Alternatively you can call ValidateBuilder::text
.
sourcepub fn header(self, header: impl Into<&'a str>) -> Self
pub fn header(self, header: impl Into<&'a str>) -> Self
Create a Validate
object to validate that the response includes the specified
header.
To validate that a header contains a specific value (instead of just validating
that it exists), use ValidateBuilder::header_value
.
This structure is passed to validate_page
or validate_and_load_static_assets
.
Example
use goose_eggs::Validate;
let _validate = Validate::builder()
.header("x-cache")
.build();
It’s possible to call this function multiple times to validate that multiple headers are set.
Multiple Example
use goose_eggs::Validate;
let _validate = Validate::builder()
.header("x-cache")
.header("x-generator")
.build();
sourcepub fn header_value(
self,
header: impl Into<&'a str>,
value: impl Into<&'a str>
) -> Self
pub fn header_value(
self,
header: impl Into<&'a str>,
value: impl Into<&'a str>
) -> Self
Create a Validate
object to validate that the response includes the specified
header which contains the specified value.
To validate that a header simply exists without confirming that it contains a
specific value, use ValidateBuilder::header
.
This structure is passed to validate_page
or validate_and_load_static_assets
.
Example
use goose_eggs::Validate;
let _validate = Validate::builder()
.header_value("x-generator", "Drupal 7")
.build();
It’s possible to call this function multiple times, and/or together with
ValidateBuilder::header
to validate that multiple headers are set and their
values.
Multiple Example
use goose_eggs::Validate;
let _validate = Validate::builder()
// Validate that the "x-cache" header is set.
.header("x-cache")
// Validate that the "x-generator" header is set and contains "Drupal 7".
.header_value("x-generator", "Drupal-7")
// Validate that the "x-drupal-cache" header is set and contains "HIT".
.header_value("x-drupal-cache", "HIT")
.build();
sourcepub fn redirect(self, redirect: impl Into<bool>) -> Self
pub fn redirect(self, redirect: impl Into<bool>) -> Self
Create a Validate
object to validate whether or not the response page redirected.
This structure is passed to validate_page
or validate_and_load_static_assets
.
Example
use goose_eggs::Validate;
// Verify the response redirected.
let _validate = Validate::builder().redirect(true).build();
// Verify the response did not redirect.
let _validate = Validate::builder().redirect(false).build();
sourcepub fn build(self) -> Validate<'a>
pub fn build(self) -> Validate<'a>
Build the Validate
object which is then passed to the
validate_page
or validate_and_load_static_assets
functions.
Example
use goose_eggs::Validate;
// Use the default search form to search for `example keys`.
let _validate = Validate::builder()
.text("example text")
.build();
Examples found in repository?
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
pub async fn front_page_en(user: &mut GooseUser) -> TransactionResult {
let goose = user.get("").await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder().title("Home").build(),
)
.await?;
Ok(())
}
/// Load recipe listing in English and all static assets found on the page.
pub async fn recipe_listing_en(user: &mut GooseUser) -> TransactionResult {
let goose = user.get("en/recipes/").await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder().title("Recipes").build(),
)
.await?;
Ok(())
}
/// Load a random recipe in English and all static assets found on the page.
pub async fn recipe_en(user: &mut GooseUser) -> TransactionResult {
let nodes = common::get_nodes(&common::ContentType::Recipe);
let recipe = nodes.choose(&mut rand::thread_rng());
let goose = user.get(recipe.unwrap().url_en).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(recipe.unwrap().title_en)
.build(),
)
.await?;
Ok(())
}
/// Load article listing in English and all static assets found on the page.
pub async fn article_listing_en(user: &mut GooseUser) -> TransactionResult {
let goose = user.get("en/articles/").await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder().title("Articles").build(),
)
.await?;
Ok(())
}
/// Load a random article in English and all static assets found on the page.
pub async fn article_en(user: &mut GooseUser) -> TransactionResult {
let nodes = common::get_nodes(&common::ContentType::Article);
let article = nodes.choose(&mut rand::thread_rng());
let goose = user.get(article.unwrap().url_en).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(article.unwrap().title_en)
.build(),
)
.await?;
Ok(())
}
/// Load a random basic page in English and all static assets found on the page.
pub async fn basic_page_en(user: &mut GooseUser) -> TransactionResult {
let nodes = common::get_nodes(&common::ContentType::BasicPage);
let page = nodes.choose(&mut rand::thread_rng());
let goose = user.get(page.unwrap().url_en).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(page.unwrap().title_en)
.build(),
)
.await?;
Ok(())
}
/// Load a random node by nid in English and all static assets found on the page.
pub async fn page_by_nid(user: &mut GooseUser) -> TransactionResult {
// Randomly select a content type.
let content_types = vec![
common::ContentType::Article,
common::ContentType::BasicPage,
common::ContentType::Recipe,
];
let content_type = content_types.choose(&mut rand::thread_rng());
// Then randomly select a node of this content type.
let nodes = common::get_nodes(content_type.unwrap());
let page = nodes.choose(&mut rand::thread_rng());
// Load the page by nid instead of by URL.
let goose = user
.get(&("node/".to_string() + &page.unwrap().nid.to_string()))
.await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(page.unwrap().title_en)
.build(),
)
.await?;
Ok(())
}
/// Anonymously load the contact form in English and POST feedback.
pub async fn anonymous_contact_form_en(user: &mut GooseUser) -> TransactionResult {
common::anonymous_contact_form(user, true).await?;
Ok(())
}
// Pick a random word from the title of a random node and perform a search in English.
pub async fn search_en(user: &mut GooseUser) -> TransactionResult {
// Build a random three-word phrase taken from english words on the Umami website.
let search_words = common::random_words(3, true);
let search_phrase = search_words.join(" ");
// The search page should have "Search" in the title.
let validate_search_page = &goose_eggs::Validate::builder().title("Search").build();
// The results page should have the search_phrase in the title.
let validate_results_page = &goose_eggs::Validate::builder()
.title(&*search_phrase)
.build();
let search_params = goose_eggs::drupal::SearchParams::builder()
.keys(&*search_phrase)
.url("en/search/node")
.search_page_validation(validate_search_page)
.results_page_validation(validate_results_page)
.build();
goose_eggs::drupal::search(user, &search_params).await?;
Ok(())
}
/// Load category listing by a random term in English and all static assets found on the page.
pub async fn term_listing_en(user: &mut GooseUser) -> TransactionResult {
let terms = common::get_terms();
let term = terms.choose(&mut rand::thread_rng());
let goose = user.get(term.unwrap().url_en).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(term.unwrap().title_en)
.build(),
)
.await?;
Ok(())
}
More examples
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
pub async fn front_page_es(user: &mut GooseUser) -> TransactionResult {
let goose = user.get("es").await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder().title("Inicio").build(),
)
.await?;
Ok(())
}
/// Load article listing in Spanish and all static assets found on the page.
pub async fn recipe_listing_es(user: &mut GooseUser) -> TransactionResult {
let goose = user.get("es/recipes/").await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder().title("Recetas").build(),
)
.await?;
Ok(())
}
/// Load a random recipe in Spanish and all static assets found on the page.
pub async fn recipe_es(user: &mut GooseUser) -> TransactionResult {
let nodes = common::get_nodes(&common::ContentType::Recipe);
let recipe = nodes.choose(&mut rand::thread_rng());
let goose = user.get(recipe.unwrap().url_es).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(recipe.unwrap().title_es)
.build(),
)
.await?;
Ok(())
}
/// Load article listing in Spanish and all static assets found on the page.
pub async fn article_listing_es(user: &mut GooseUser) -> TransactionResult {
let goose = user.get("es/articles/").await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder().title("Artículos").build(),
)
.await?;
Ok(())
}
/// Load a random article in Spanish and all static assets found on the page.
pub async fn article_es(user: &mut GooseUser) -> TransactionResult {
let nodes = common::get_nodes(&common::ContentType::Article);
let article = nodes.choose(&mut rand::thread_rng());
let goose = user.get(article.unwrap().url_es).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(article.unwrap().title_es)
.build(),
)
.await?;
Ok(())
}
/// Load a basic page in Spanish and all static assets found on the page.
pub async fn basic_page_es(user: &mut GooseUser) -> TransactionResult {
let nodes = common::get_nodes(&common::ContentType::BasicPage);
let page = nodes.choose(&mut rand::thread_rng());
let goose = user.get(page.unwrap().url_es).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(page.unwrap().title_es)
.build(),
)
.await?;
Ok(())
}
/// Anonymously load the contact form in Spanish and POST feedback.
pub async fn anonymous_contact_form_es(user: &mut GooseUser) -> TransactionResult {
common::anonymous_contact_form(user, false).await?;
Ok(())
}
// Pick a random word from the title of a random node and perform a search in Spanish.
pub async fn search_es(user: &mut GooseUser) -> TransactionResult {
// Build a random three-word phrase taken from Spanish words on the Umami website.
let search_words = common::random_words(3, false);
let search_phrase = search_words.join(" ");
// The search page should have "Buscar" in the title.
let validate_search_page = &goose_eggs::Validate::builder().title("Buscar").build();
// The results page should have the search_phrase in the title.
let validate_results_page = &goose_eggs::Validate::builder()
.title(&*search_phrase)
.build();
let search_params = goose_eggs::drupal::SearchParams::builder()
.keys(&*search_phrase)
.url("es/search/node")
.search_page_validation(validate_search_page)
.results_page_validation(validate_results_page)
.build();
goose_eggs::drupal::search(user, &search_params).await?;
Ok(())
}
/// Load category listing by a random term in Spanish and all static assets found on the page.
pub async fn term_listing_es(user: &mut GooseUser) -> TransactionResult {
let terms = common::get_terms();
let term = terms.choose(&mut rand::thread_rng());
let goose = user.get(term.unwrap().url_es).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(term.unwrap().title_es)
.build(),
)
.await?;
Ok(())
}
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
pub async fn edit_article(user: &mut GooseUser) -> TransactionResult {
// First, load a random article.
let nodes = common::get_nodes(&common::ContentType::Article);
let article = nodes.choose(&mut rand::thread_rng());
let goose = user.get(article.unwrap().url_en).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(article.unwrap().title_en)
.text(&format!("en/node/{}/edit", article.unwrap().nid))
.build(),
)
.await?;
// Next, load the edit link for the chosen article.
let goose = user
.get(&format!("en/node/{}/edit", article.unwrap().nid))
.await?;
let edit_page = goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title("Edit Article")
.build(),
)
.await?;
let edit_form = goose_eggs::drupal::get_form(&edit_page, "node-article-edit-form");
let form_build_id = goose_eggs::drupal::get_form_value(&edit_form, "form_build_id");
let form_token = goose_eggs::drupal::get_form_value(&edit_form, "form_token");
let form_id = goose_eggs::drupal::get_form_value(&edit_form, "form_id");
// Build node form with random word from title.
let params = [
("form_build_id", &form_build_id),
("form_token", &form_token),
("form_id", &form_id),
("op", &"Save (this translation)".to_string()),
];
let mut saved_article = user
.post_form(&format!("en/node/{}/edit", article.unwrap().nid), ¶ms)
.await?;
// A successful node save is redirected.
if !saved_article.request.redirected {
return user.set_failure(
&format!("{}: saving article failed", saved_article.request.final_url),
&mut saved_article.request,
None,
None,
);
}
// Be sure we're viewing the same article after editing it.
goose_eggs::validate_and_load_static_assets(
user,
saved_article,
&goose_eggs::Validate::builder()
.title(article.unwrap().title_en)
.build(),
)
.await?;
Ok(())
}
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
pub async fn anonymous_contact_form(user: &mut GooseUser, english: bool) -> TransactionResult {
let contact_form_url = if english { "en/contact" } else { "es/contact" };
let goose = user.get(contact_form_url).await?;
let contact_page = goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title(if english {
"Website feedback"
} else {
"Comentarios sobre el sitio web"
})
.build(),
)
.await?;
let form = goose_eggs::drupal::get_form(&contact_page, "contact-message-feedback-form");
let form_build_id = goose_eggs::drupal::get_form_value(&form, "form_build_id");
let form_id = goose_eggs::drupal::get_form_value(&form, "form_id");
// Build contact form parameters.
let name = random_words(2, english).join(" ");
let email = format!("{}@example.com", random_words(1, english).pop().unwrap());
let subject = random_words(8, english).join(" ");
let message = random_words(12, english).join(" ");
let params = [
("name", name.as_str()),
("mail", email.as_str()),
("subject[0][value]", subject.as_str()),
("message[0][value]", message.as_str()),
("form_build_id", &form_build_id),
("form_id", &form_id),
("op", "Send+message"),
];
let mut goose = user.post_form(contact_form_url, ¶ms).await?;
// Drupal 9 throttles how many times an IP address can submit the contact form, so we
// need special handling.
match goose.response {
Ok(response) => {
// Copy the headers so we have them for logging if there are errors.
let headers = &response.headers().clone();
match response.text().await {
Ok(html) => {
// Drupal 9 will throttle how many times our IP address can actually
// submit the contact form. We can detect this, but it happens a lot
// so there's nothing useful to do.
let error_text = if english {
"You cannot send more than"
} else {
"No le está permitido enviar más"
};
if html.contains(error_text) {
// The contact form was throttled, safely ignore this.
}
// Either way, a "real" user would still load all static elements on
// the returned page.
goose_eggs::load_static_elements(user, &html).await;
}
Err(e) => {
return user.set_failure(
&format!("{}: failed to parse page: {}", goose.request.raw.url, e),
&mut goose.request,
Some(headers),
None,
);
}
}
}
Err(e) => {
return user.set_failure(
&format!("{}: no response from server: {}", goose.request.raw.url, e),
&mut goose.request,
None,
None,
);
}
}
Ok(())
}
Trait Implementations§
source§impl<'a> Clone for ValidateBuilder<'a>
impl<'a> Clone for ValidateBuilder<'a>
source§fn clone(&self) -> ValidateBuilder<'a>
fn clone(&self) -> ValidateBuilder<'a>
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moreAuto Trait Implementations§
impl<'a> RefUnwindSafe for ValidateBuilder<'a>
impl<'a> Send for ValidateBuilder<'a>
impl<'a> Sync for ValidateBuilder<'a>
impl<'a> Unpin for ValidateBuilder<'a>
impl<'a> UnwindSafe for ValidateBuilder<'a>
Blanket Implementations§
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T, Global>) -> Box<dyn Any + 'static, Global>
fn into_any(self: Box<T, Global>) -> Box<dyn Any + 'static, Global>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any + 'static>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any + 'static>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.