-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
994912e
commit a2c82f2
Showing
9 changed files
with
950 additions
and
15 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import { beforeEach, describe, expect, test as defaultTest, vi } from 'vitest'; | ||
import { CSVUpload } from './CSVUpload'; | ||
import { useState } from 'react'; | ||
import { Button } from 'react-bootstrap'; | ||
import { render, screen } from '@testing-library/react'; | ||
import { userEvent } from '@testing-library/user-event'; | ||
import "@testing-library/jest-dom"; | ||
|
||
function TestCSVUpload() { | ||
const [show, setShow] = useState(false); | ||
|
||
return <> | ||
<Button variant="primary" onClick={() => setShow(true)}>Open</Button> | ||
<CSVUpload show={show} closeModal={() => setShow(false)} /> | ||
</> | ||
} | ||
|
||
const test = defaultTest.extend({ user: userEvent.setup() }) | ||
|
||
// mock the "writeNewTransactionsBatched" function to cirumvent firebase auth and rules | ||
// its already been unit tested so we know it works | ||
vi.mock("../../utils/transaction", async (importOriginal) => { | ||
const mod: {} = await importOriginal(); | ||
return { | ||
...mod, | ||
writeNewTransactionsBatched: vi.fn(), | ||
} | ||
}) | ||
|
||
// mock auth.currentUser to simulate a user being signed into website | ||
vi.mock("../../utils/firebase", async (importOriginal) => { | ||
const mod: {} = await importOriginal(); | ||
return { | ||
...mod, | ||
auth: { currentUser: { uid: "100" } } | ||
} | ||
}) | ||
|
||
describe("CSVUpload Tests", () => { | ||
beforeEach(() => { | ||
render(<TestCSVUpload />) | ||
}); | ||
|
||
test("modal opens", async ({ user }) => { | ||
expect(screen.queryByText("Upload CSV Transactions")).toBeNull(); | ||
|
||
await user.click(screen.getByText("Open")); | ||
|
||
expect(screen.getByText("Upload CSV Transactions")).toBeInTheDocument(); | ||
}) | ||
|
||
test("modal closes with close button", async ({ user }) => { | ||
await user.click(screen.getByText("Open")); | ||
|
||
await user.click(screen.getByText("Close")); | ||
|
||
expect(screen.getByText("Open")).toBeVisible() | ||
}) | ||
|
||
test("stops no uploaded CSV", async ({ user }) => { | ||
await user.click(screen.getByText("Open")); | ||
|
||
await user.click(screen.getByText("Upload CSV")); | ||
|
||
expect(screen.getByText("You haven't uploaded a CSV file")).toBeVisible() | ||
}) | ||
|
||
test("non-CSV results in zero uploaded transactions", async ({ user }) => { | ||
await user.click(screen.getByText("Open")); | ||
|
||
const txt = new File(["testing"], "text.txt", { type: "text/plaintext", lastModified: Date.now() }) | ||
|
||
await user.upload(screen.getByTestId("csvUpload"), txt) | ||
|
||
await user.click(screen.getByText("Upload CSV")); | ||
|
||
expect(screen.getByText("You haven't uploaded a CSV file")).toBeVisible() | ||
}) | ||
|
||
test("empty CSV results in zero uploaded transactions", async ({ user }) => { | ||
await user.click(screen.getByText("Open")); | ||
|
||
const csv = new File([""], "emptyCSV.csv", { type: "text/csv", lastModified: Date.now() }) | ||
|
||
await user.upload(screen.getByTestId("csvUpload"), csv) | ||
|
||
await user.click(screen.getByText("Upload CSV")); | ||
|
||
expect(screen.getByText("Uploaded CSV is empty")).toBeVisible() | ||
}) | ||
|
||
test("non-Monzo CSV results in zero uploaded transactions", async ({ user }) => { | ||
await user.click(screen.getByText("Open")); | ||
|
||
const csv = new File( | ||
["testing1, 123, testing2, testing,, testing3, 5-5, testing!"], | ||
"invalidCSV.csv", | ||
{ type: "text/csv", lastModified: Date.now() } | ||
) | ||
|
||
await user.upload(screen.getByTestId("csvUpload"), csv) | ||
|
||
await user.click(screen.getByText("Upload CSV")); | ||
|
||
expect(screen.getByText("The uploaded CSV file has no valid transactions")).toBeVisible() | ||
}) | ||
|
||
test("Monzo CSV file uploads transactions", async ({ user }) => { | ||
await user.click(screen.getByText("Open")); | ||
|
||
const csv = new File( | ||
[ | ||
"Transaction ID,Date,Time,Type,Name,Emoji,Category,Amount,Currency,Local amount,Local currency,Notes and #tags,Address,Receipt,Description,Category split,Money Out,Money In\n", | ||
"tx_0000AbA3Oasz9hIuCRy3RT,26/10/2023,11:55:41,Card payment,Boots,💊,Personal care,-21.97,GBP,-21.97,GBP,,1 Newark Street,,BOOTS 2011 BATH GBR,,-21.97,\n", | ||
"tx_0000Ab8DxJ14CFwgh9JVh4,25/10/2023,14:44:35,Card payment,Aesop Bath,💄,Shopping,-25.00,GBP,-25.00,GBP,,16 New Bond Street,,Aesop Bath Bath GBR,,-25.00,\n" | ||
], | ||
"validCSV.csv", | ||
{ type: "text/csv", lastModified: Date.now() } | ||
) | ||
|
||
await user.upload(screen.getByTestId("csvUpload"), csv) | ||
|
||
await user.click(screen.getByText("Upload CSV")); | ||
|
||
expect(screen.getByText("2 transactions have been imported")).toBeVisible() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { beforeEach, describe, expect, vi, test as defaultTest } from 'vitest'; | ||
import { InputTransaction } from './InputTransaction'; | ||
import { useState } from 'react'; | ||
import { Button } from 'react-bootstrap'; | ||
import { render, screen } from '@testing-library/react'; | ||
import { writeNewTransaction } from '../../utils/transaction'; | ||
import { userEvent } from "@testing-library/user-event" | ||
import "@testing-library/jest-dom"; | ||
|
||
function TestInputTransaction() { | ||
const [show, setShow] = useState(false); | ||
|
||
return <> | ||
<Button variant="primary" onClick={() => setShow(true)}>Open</Button> | ||
<InputTransaction show={show} closeModal={() => setShow(false)} /> | ||
</> | ||
} | ||
|
||
const test = defaultTest.extend({ user: userEvent.setup() }) | ||
|
||
// mock the "writeNewTransaction" function to cirumvent firebase auth and rules | ||
// its already been unit tested so we know it works | ||
vi.mock("../../utils/transaction", async (importOriginal) => { | ||
const mod: {} = await importOriginal(); | ||
return { | ||
...mod, | ||
writeNewTransaction: vi.fn(), | ||
} | ||
}) | ||
|
||
// mock auth.currentUser to simulate a user being signed into website | ||
vi.mock("../../utils/firebase", async (importOriginal) => { | ||
const mod: {} = await importOriginal(); | ||
return { | ||
...mod, | ||
auth: { currentUser: { uid: "100" } } | ||
} | ||
}) | ||
|
||
describe("InputTransaction Tests", () => { | ||
beforeEach(() => { | ||
render(<TestInputTransaction />) | ||
}) | ||
|
||
test("modal opens", async ({ user }) => { | ||
expect(screen.queryByText("Add Transaction")).toBeNull(); | ||
|
||
await user.click(screen.getByText("Open")); | ||
|
||
// there are two elements with the text "Add Transaction" in this modal: the modal title and the submit button | ||
expect(screen.getAllByText("Add Transaction")).toHaveLength(2) | ||
}) | ||
|
||
test("modal closes with close button", async ({ user }) => { | ||
await user.click(screen.getByText("Open")); | ||
|
||
await user.click(screen.getByText("Close")); | ||
|
||
expect(screen.getByText("Open")).toBeVisible() | ||
}) | ||
|
||
test("empty required textboxes results in zero uploaded transactions", async ({ user }) => { | ||
await user.click(screen.getByText("Open")); | ||
|
||
await user.click(screen.getAllByRole("button").find((element) => element.textContent === "Add Transaction")!); | ||
|
||
expect(screen.getByText("The inputted amount is invalid")).toBeVisible() | ||
}) | ||
|
||
test("allow optional textboxes to be empty", async ({ user }) => { | ||
await user.click(screen.getByText("Open")); | ||
|
||
await user.type(screen.getByPlaceholderText("Enter name"), "Sainsburys"); | ||
await user.type(screen.getByPlaceholderText("Enter amount (use '-' for expenses, do not include currency)"), "-100"); | ||
// use default category -- income | ||
|
||
await user.click(screen.getAllByRole("button").find((element) => element.textContent === "Add Transaction")!) | ||
|
||
expect(await screen.findByText("Transaction has been successfully added")).toBeVisible() | ||
expect(writeNewTransaction).toHaveBeenCalled(); | ||
}) | ||
|
||
test("transaction uploaded when all textboxes are valid", async ({ user }) => { | ||
await user.click(screen.getByText("Open")); | ||
|
||
await user.type(screen.getByPlaceholderText("Enter name"), "Sainsburys"); | ||
await user.type(screen.getByPlaceholderText("Enter amount (use '-' for expenses, do not include currency)"), "-100"); | ||
// use default category -- income | ||
await user.type(screen.getByPlaceholderText("Enter date (DD/MM/YYYY) (optional)"), "12/12/2001"); | ||
await user.type(screen.getByPlaceholderText("Enter time (HH:MM:SS) (optional)"), "00:00:00"); | ||
await user.type(screen.getByPlaceholderText("Enter Description (optional)"), "testing description"); | ||
await user.type(screen.getByPlaceholderText("Enter Notes (optional)"), "testing notes"); | ||
await user.type(screen.getByPlaceholderText("Enter Address (optional)"), "testing address"); | ||
|
||
await user.click(screen.getAllByRole("button").find((element) => element.textContent === "Add Transaction")!) | ||
|
||
expect(await screen.findByText("Transaction has been successfully added")).toBeVisible() | ||
expect(writeNewTransaction).toHaveBeenCalled(); | ||
}) | ||
}) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,93 @@ | ||
import {describe, expect, test} from "vitest"; | ||
import {emojis} from "./Transaction.ts"; | ||
import {TransactionCategories} from "../../utils/transaction.ts"; | ||
import { describe, expect, test } from "vitest"; | ||
import { Transaction, emojis } from "./Transaction.ts"; | ||
import { TransactionCategories } from "../../utils/transaction.ts"; | ||
import _ from "lodash"; | ||
|
||
describe("Input Transaction Test", () => { | ||
test("Category Integrity Test", () => { | ||
expect(_.isEqual(new Set(Object.keys(emojis)), TransactionCategories), "Emoji keys do not match transaction categories").toBeTruthy(); | ||
}); | ||
}); | ||
}); | ||
|
||
const validationTest = test.extend({ transaction: new Transaction() }) | ||
|
||
function doesValidate(transaction: Transaction, field: string) { | ||
expect(!transaction.isValid && transaction.invalidField == field).toBeTruthy() | ||
} | ||
|
||
describe("Transaction Validator Tests", () => { | ||
validationTest("stops undefined date", ({ transaction }) => { | ||
transaction.setDate(); | ||
doesValidate(transaction, "date"); | ||
}) | ||
|
||
validationTest("stops empty string as date", ({ transaction }) => { | ||
transaction.setDate(""); | ||
doesValidate(transaction, "date"); | ||
}) | ||
|
||
validationTest("stops 00/00/00 as date", ({ transaction }) => { | ||
transaction.setDate("00/00/00"); | ||
doesValidate(transaction, "date"); | ||
}) | ||
|
||
validationTest("stops 32/21/00 as date", ({ transaction }) => { | ||
transaction.setDate("32/21/00"); | ||
doesValidate(transaction, "date"); | ||
}) | ||
|
||
validationTest("stops / as date", ({ transaction }) => { | ||
transaction.setDate("/"); | ||
doesValidate(transaction, "date"); | ||
}) | ||
|
||
validationTest("stops undefined time", ({ transaction }) => { | ||
transaction.setTime(); | ||
doesValidate(transaction, "time"); | ||
}) | ||
|
||
validationTest("stops empty string as time", ({ transaction }) => { | ||
transaction.setTime(""); | ||
doesValidate(transaction, "time"); | ||
}) | ||
|
||
validationTest("stops 25:61:61 as time", ({ transaction }) => { | ||
transaction.setTime("25:61:61"); | ||
doesValidate(transaction, "time"); | ||
}) | ||
|
||
validationTest("stops : as time", ({ transaction }) => { | ||
transaction.setTime(":"); | ||
doesValidate(transaction, "time"); | ||
}) | ||
|
||
validationTest("stops undefined names", ({ transaction }) => { | ||
transaction.setName(); | ||
doesValidate(transaction, "name"); | ||
}) | ||
|
||
validationTest("stops unknown categories", ({ transaction }) => { | ||
transaction.setCategory("testing"); | ||
doesValidate(transaction, "category"); | ||
}) | ||
|
||
validationTest("stops undefined category", ({ transaction }) => { | ||
transaction.setCategory(); | ||
doesValidate(transaction, "category"); | ||
}) | ||
|
||
validationTest("stops non-number amounts", ({ transaction }) => { | ||
transaction.setAmount("testing"); | ||
doesValidate(transaction, "amount"); | ||
}) | ||
|
||
validationTest("stops undefined amount", ({ transaction }) => { | ||
transaction.setAmount(); | ||
doesValidate(transaction, "amount"); | ||
}) | ||
|
||
validationTest("stops undefined currencies", ({ transaction }) => { | ||
transaction.setCurrency(); | ||
doesValidate(transaction, "currency"); | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.