From fd55629ede666bf402b8301e4c16ecaa3f69e70b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joona=20K=C3=A4rkk=C3=A4inen?= Date: Thu, 8 Feb 2024 22:50:48 +0200 Subject: [PATCH] test: add tests for listing invoices --- src/api/invoices.rs | 2 +- src/models.rs | 20 +++++++++------ src/tests/invoices.rs | 60 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/api/invoices.rs b/src/api/invoices.rs index e0840b0..38effad 100644 --- a/src/api/invoices.rs +++ b/src/api/invoices.rs @@ -79,7 +79,7 @@ pub struct CreateInvoiceAttachment { } /// A populated invoice type that is returned to the user -#[derive(Clone, Debug, Serialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct PopulatedInvoice { pub id: i32, pub status: crate::models::InvoiceStatus, diff --git a/src/models.rs b/src/models.rs index e4afd16..4541187 100644 --- a/src/models.rs +++ b/src/models.rs @@ -15,7 +15,7 @@ use serde_derive::{Deserialize, Serialize}; // - Is VAT really necessary to account for? I'm leaving it out for now // - I'm also leaving InvoiceType out, at least for now -#[derive(diesel_derive_enum::DbEnum, Debug, Clone, Copy, Serialize)] +#[derive(diesel_derive_enum::DbEnum, Debug, Clone, Copy, Serialize, Deserialize)] #[ExistingTypePath = "crate::schema::sql_types::InvoiceStatus"] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum InvoiceStatus { @@ -25,7 +25,7 @@ pub enum InvoiceStatus { } /// A party of the invoice -#[derive(Identifiable, Queryable, Selectable, Clone, Debug, Serialize)] +#[derive(Identifiable, Queryable, Selectable, Clone, Debug, Serialize, Deserialize)] #[diesel(table_name = parties)] pub struct Party { pub id: i32, @@ -83,13 +83,15 @@ pub struct NewInvoice { } /// A single row of an invoice -#[derive(Identifiable, Queryable, Selectable, Associations, Clone, Debug, Serialize)] +#[derive( + Identifiable, Queryable, Selectable, Associations, Clone, Debug, Serialize, Deserialize, +)] #[diesel(belongs_to(Invoice))] #[diesel(table_name = invoice_rows)] pub struct InvoiceRow { - #[serde(skip_serializing)] + #[serde(skip_serializing, skip_deserializing)] pub id: i32, - #[serde(skip_serializing)] + #[serde(skip_serializing, skip_deserializing)] pub invoice_id: i32, /// The product can be at most 128 characters pub product: String, @@ -113,13 +115,15 @@ pub struct NewInvoiceRow { /// The metadata for an invoice attachment /// The file itself can be requested using its hash and filename /// => /somepath/{hash}/{filename} -#[derive(Identifiable, Queryable, Selectable, Associations, Clone, Debug, Serialize)] +#[derive( + Identifiable, Queryable, Selectable, Associations, Clone, Debug, Serialize, Deserialize, +)] #[diesel(belongs_to(Invoice))] #[diesel(table_name = invoice_attachments)] pub struct Attachment { - #[serde(skip_serializing)] + #[serde(skip_serializing, skip_deserializing)] pub id: i32, - #[serde(skip_serializing)] + #[serde(skip_serializing, skip_deserializing)] pub invoice_id: i32, /// The filename can be at most 128 characters pub filename: String, diff --git a/src/tests/invoices.rs b/src/tests/invoices.rs index 699ef98..c4fba27 100644 --- a/src/tests/invoices.rs +++ b/src/tests/invoices.rs @@ -1,5 +1,5 @@ use crate::api::app; -use crate::api::invoices::{CreateInvoice, CreateInvoiceRow}; +use crate::api::invoices::{CreateInvoice, CreateInvoiceRow, PopulatedInvoice}; use crate::models::NewParty; use axum::http::StatusCode; @@ -49,3 +49,61 @@ async fn create() { assert_eq!(response.status_code(), StatusCode::CREATED); } + +#[tokio::test] +async fn list_all() { + let app = app().with_state(crate::database::new().await); + let server = TestServer::new(app).unwrap(); + + let response = server.get("/invoices").await; + assert_eq!(response.status_code(), StatusCode::OK); +} + +#[tokio::test] +async fn create_list_all() { + let app = app().with_state(crate::database::new().await); + + let body = CreateInvoice { + counter_party: NewParty { + name: String::from("Velkoja"), + street: String::from("Otakaari"), + city: String::from("Espoo"), + zip: String::from("02jotain"), + bank_account: String::from("ei ole"), + }, + due_date: chrono::Local::now().date_naive(), + rows: vec![ + CreateInvoiceRow { + product: String::from("pleikkari"), + quantity: 69, + unit: String::from("kpl"), + unit_price: 4200, + }, + CreateInvoiceRow { + product: String::from("xbox"), + quantity: 1, + unit: String::from("kpl"), + unit_price: 4200, + }, + CreateInvoiceRow { + product: String::from("nintendo wii"), + quantity: 2, + unit: String::from("kpl"), + unit_price: 4200, + }, + ], + attachments: vec![], + }; + + let server = TestServer::new(app).unwrap(); + let body = MultipartForm::new().add_text("data", serde_json::to_string(&body).unwrap()); + + let create_response = server.post("/invoices").multipart(body).await; + assert_eq!(create_response.status_code(), StatusCode::CREATED); + + let list_response = server.get("/invoices").await; + assert_eq!(list_response.status_code(), StatusCode::OK); + + let result = std::panic::catch_unwind(|| list_response.json::>()); + assert!(result.is_ok_and(|invoices| !invoices.is_empty())); +}