-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Open
Labels
enhancementA minor feature requestA minor feature requesthelp wantedContributions to this issue are neededContributions to this issue are needed
Milestone
Description
Testing forms in Rocket is currently an entirely manual process:
let client = Client::tracked(rocket).unwrap();
let response = client.post("/")
.header(ContentType::Form)
.body("field=value&is+it=a+cat%3F")
.dispatch();With the addition of multipart form support, form testing verbosity is even further exacerbated:
let client = Client::tracked(rocket).unwrap();
let ct = "multipart/form-data; boundary=X-BOUNDARY"
.parse::<ContentType>()
.unwrap();
let body = &[
"--X-BOUNDARY",
r#"Content-Disposition: form-data; name="names[]""#,
"",
"abcd",
"--X-BOUNDARY",
r#"Content-Disposition: form-data; name="names[]""#,
"",
"123",
"--X-BOUNDARY",
r#"Content-Disposition: form-data; name="file"; filename="foo.txt""#,
"Content-Type: text/plain",
"",
"hi there",
"--X-BOUNDARY--",
"",
].join("\r\n");
let response = client.post("/")
.header(ct)
.body(body)
.dispatch();Rocket should make testing applications with forms a much simpler task.
Here's how we might hope testing the above forms would look:
let client = Client::tracked(rocket).unwrap();
let response = client.post("/")
.form(&[("field", "value"), ("is it", "a cat?")])
.dispatch();
let client = Client::tracked(rocket).unwrap();
let response = client.post("/")
.form(LocalForm::new()
.field("names[]", "abcd")
.field("names[]", "123")
.file("foo.txt", ContentType::Plain, "hi there"))
.dispatch();An API enabling this might resemble:
impl Client {
pub fn form<F: Into<LocalForm>>(&mut self, form: F) -> &mut Self {
let form = form.into();
self.set_header(form.content_type());
self.set_body(form.body_data());
self
}
}
struct LocalForm { /* .. */ }
impl LocalForm {
pub fn new() -> Self;
/// A percent-decoded `name` and `value`.
pub fn field<'v, N, V>(mut self, name: N, value: V) -> Self
where N: Into<NameBuf<'v>>, V: AsRef<str>;
/// Adds all of the `fields` to `self`.
pub fn fields<'v, I, F>(mut self, fields: I) -> Self
where I: Iterator<Item = F>, F: Into<ValueField<'v>>;
/// A percent-encoded `name` and `value`.
pub fn raw_field(mut self, name: &'v RawStr, value: &'v RawStr) -> Self;
/// Adds a field for the file with name `file_name`, content-type `ct`, and
/// file contents `data`.
pub fn file<'v, N, V>(mut self, file_name: N, ct: ContentType, data: V) -> Self
where N: Into<Option<&'v str>>, V: AsRef<[u8]>;
/// Add a data field with content-type `ct` and binary `data`.
pub fn data<'v, V>(mut self, ct: ContentType, data: V) -> Self
where V: AsRef<[u8]>;
/// The full content-type for this form.
pub fn content_type(&self) -> ContentType;
/// The full body data for this form.
pub fn body_data(&self) -> Vec<u8>;
}
impl<'v, F: Into<ValueField<'v>>, I: Iterator<Item = F>> From<I> for LocalForm { /* .. */ }cbzehner, Jackbaude, RuboGubo, spikecodes and CPU-Blanc
Metadata
Metadata
Assignees
Labels
enhancementA minor feature requestA minor feature requesthelp wantedContributions to this issue are neededContributions to this issue are needed
Type
Projects
Status
Ready