diff --git a/account.js b/account.js deleted file mode 100644 index 823a757..0000000 --- a/account.js +++ /dev/null @@ -1,48 +0,0 @@ -module.exports = class Account { - #balance = 0; - #transactions = []; - #transaction; - #printer; - - constructor(transaction, printer) { - this.#transaction = transaction; - this.#printer = printer; - } - - getBalance() { - return this.#balance; - } - - deposit(amount) { - this.#checkDepositValue(amount); - this.#balance += amount; - this.#transactions.unshift(this.#generateTransaction({ credit: amount })); - } - - withdraw(amount) { - this.#checkSufficientFunds(amount); - this.#balance -= amount; - this.#transactions.unshift(this.#generateTransaction({ debit: amount })); - } - - printStatement() { - return this.#printer.printStatement(this.#transactions); - } - - #checkSufficientFunds(amount) { - if (amount > this.#balance) { - throw "Withdrawal failed: Insufficient funds"; - } - } - - #checkDepositValue(amount) { - if (amount <= 0) { - throw "Deposit failed: Amount must be positive"; - } - } - - #generateTransaction(creditOrDebit) { - creditOrDebit.balance = this.#balance; - return new this.#transaction(creditOrDebit); - } -}; diff --git a/printer.js b/printer.js deleted file mode 100644 index edf17f6..0000000 --- a/printer.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = class Printer { - #header = "date || credit || debit || balance"; - - printStatement(transactions) { - return this.#header + "\n" + this.#formatTransactions(transactions); - } - - #formatTransactions(transactions) { - return transactions.map(this.#formatTransaction).join("\n"); - } - - #formatTransaction(transaction) { - return [ - transaction.getDate(), - transaction.getCredit(), - transaction.getDebit(), - transaction.getBalance(), - ].join(" || "); - } -}; diff --git a/src/account.js b/src/account.js new file mode 100644 index 0000000..8f2ab3a --- /dev/null +++ b/src/account.js @@ -0,0 +1,48 @@ +module.exports = class Account { + #transactions = []; + #transaction; + #printer; + + constructor(transaction, printer) { + this.#transaction = transaction; + this.#printer = printer; + } + + getBalance() { + if (this.#transactions[this.#transactions.length - 1]) { + return this.#transactions[this.#transactions.length - 1].getBalance(); + } else return 0; + } + + deposit(amount) { + this.#checkDepositValue(amount); + this.#transactions.push( + new this.#transaction({ + credit: amount, + balance: this.getBalance() + amount, + }) + ); + } + + withdraw(amount) { + this.#checkSufficientFunds(amount); + this.#transactions.push( + new this.#transaction({ + debit: amount, + balance: this.getBalance() - amount, + }) + ); + } + + printStatement() { + return this.#printer.printStatement(this.#transactions); + } + + #checkSufficientFunds(amount) { + if (amount > this.getBalance()) throw "Withdraw failed: Insufficient funds"; + } + + #checkDepositValue(amount) { + if (amount <= 0) throw "Deposit failed: Amount must be positive"; + } +}; diff --git a/account.test.js b/src/account.test.js similarity index 78% rename from account.test.js rename to src/account.test.js index c254a18..22f3694 100644 --- a/account.test.js +++ b/src/account.test.js @@ -18,18 +18,16 @@ describe("Account", () => { }); describe("getBalance", () => { - it("should return the balance of the account", () => { - expect(accountWithCash.getBalance()).toEqual(500); - }); - }); + it("should call the latest transaction for the current balance", () => { + const spy = jest.spyOn(Transaction.prototype, "getBalance"); - describe(".deposit", () => { - it("should increase the balance by the amount deposited", () => { - emptyAccount.deposit(500); + accountWithCash.getBalance(); - expect(emptyAccount.getBalance()).toEqual(500); + expect(spy).toHaveBeenCalledTimes(1); }); + }); + describe(".deposit", () => { it("should create a new transaction", () => { emptyAccount.deposit(500); @@ -47,12 +45,6 @@ describe("Account", () => { }); describe(".withdraw", () => { - it("should decrease the balance by the amount deposited", () => { - accountWithCash.withdraw(250); - - expect(accountWithCash.getBalance()).toEqual(250); - }); - it("should throw an error if amount to withdraw is greater than current balance", () => { expect(() => emptyAccount.withdraw(500)).toThrow( "Withdrawal failed: Insufficient funds" @@ -60,6 +52,10 @@ describe("Account", () => { }); it("should create a new transaction", () => { + jest.spyOn(Transaction.prototype, "getBalance").mockImplementation(() => { + return 500; + }); + accountWithCash.withdraw(250); expect(Transaction).toHaveBeenCalledWith({ diff --git a/feature.test.js b/src/feature.test.js similarity index 93% rename from feature.test.js rename to src/feature.test.js index 6b043e9..997af71 100644 --- a/feature.test.js +++ b/src/feature.test.js @@ -7,10 +7,6 @@ beforeAll(() => { jest.setSystemTime(new Date("2022-06-20")); }); -afterAll(() => { - jest.useRealTimers(); -}); - it("should allow deposits, withdrawals and be able to print statement showing those transactions", () => { const account = new Account(Transaction, new Printer()); diff --git a/src/printer.js b/src/printer.js new file mode 100644 index 0000000..bfbe3de --- /dev/null +++ b/src/printer.js @@ -0,0 +1,33 @@ +module.exports = class Printer { + #header = "date || credit || debit || balance"; + + printStatement(transactions) { + return this.#header + "\n" + this.#formatTransactions(transactions); + } + + #formatTransactions(transactions) { + return transactions + .reverse() + .map(this.#getTransactionData) + .map(this.#formatTransactionData) + .join("\n"); + } + + #getTransactionData(transaction) { + return [ + transaction.getDate(), + transaction.getCredit(), + transaction.getDebit(), + transaction.getBalance(), + ]; + } + + #formatTransactionData(entries) { + return entries + .map((entry) => { + if (typeof entry == "number") return entry.toFixed(2); + else return entry; + }) + .join(" || "); + } +}; diff --git a/printer.test.js b/src/printer.test.js similarity index 96% rename from printer.test.js rename to src/printer.test.js index 8dbefd6..dca1a56 100644 --- a/printer.test.js +++ b/src/printer.test.js @@ -58,7 +58,7 @@ describe("Printer", () => { }); it("should handle multiple transactions", () => { - expect(printer.printStatement([secondTransaction, transaction])).toEqual( + expect(printer.printStatement([transaction, secondTransaction])).toEqual( "date || credit || debit || balance\n20/06/2022 || 500.00 || || 1000.00\n19/06/2022 || 500.00 || || 500.00" ); }); diff --git a/src/transaction.js b/src/transaction.js new file mode 100644 index 0000000..2931240 --- /dev/null +++ b/src/transaction.js @@ -0,0 +1,26 @@ +module.exports = class Transaction { + #date = new Date(Date.now()).toLocaleDateString(); + #credit; + #debit; + #balance; + + constructor({ credit = null, debit = null, balance = null } = {}) { + [this.#credit, this.#debit, this.#balance] = [credit, debit, balance]; + } + + getDate() { + return this.#date; + } + + getCredit() { + return this.#credit; + } + + getDebit() { + return this.#debit; + } + + getBalance() { + return this.#balance; + } +}; diff --git a/transaction.test.js b/src/transaction.test.js similarity index 83% rename from transaction.test.js rename to src/transaction.test.js index d9e9bcb..da310bc 100644 --- a/transaction.test.js +++ b/src/transaction.test.js @@ -24,19 +24,19 @@ describe("Transaction", () => { describe("getCredit", () => { it("should return the credit amount formatted as a float to 2 decimals", () => { - expect(creditTransaction.getCredit()).toEqual("500.00"); + expect(creditTransaction.getCredit()).toEqual(500); }); }); describe("getDebit()", () => { it("should return the debt amount formatted as a float to 2 decimals", () => { - expect(debitTransaction.getDebit()).toEqual("500.00"); + expect(debitTransaction.getDebit()).toEqual(500); }); }); describe("getBalance()", () => { it("should return the balance amount formatted as a float to 2 decimals", () => { - expect(debitTransaction.getBalance()).toEqual("1000.00"); + expect(debitTransaction.getBalance()).toEqual(1000); }); }); }); diff --git a/transaction.js b/transaction.js deleted file mode 100644 index 7bfcc18..0000000 --- a/transaction.js +++ /dev/null @@ -1,36 +0,0 @@ -module.exports = class Transaction { - #date = new Date(Date.now()).toLocaleDateString(); - #credit; - #debit; - #balance; - - constructor({ credit = null, debit = null, balance = null } = {}) { - this.#credit = credit; - this.#debit = debit; - this.#balance = balance; - } - - getDate() { - return this.#date; - } - - getCredit() { - return this.#formatCurrency(this.#credit); - } - - getDebit() { - return this.#formatCurrency(this.#debit); - } - - getBalance() { - return this.#formatCurrency(this.#balance); - } - - #formatCurrency(amount) { - if (amount) { - return amount.toFixed(2); - } else { - return amount; - } - } -};