import { click, visit } from "@ember/test-helpers"; import { test } from "qunit"; import { cloneJSON } from "discourse/lib/object"; import topicFixtures from "discourse/tests/fixtures/topic"; import { acceptance } from "discourse/tests/helpers/qunit-helpers"; const TOPIC_ID = 28830; const accountsReport = { report_type: "accounts", period: { begin: null, end: null }, sections: [ { title: null, rows: [ { account: "assets", label: "Assets", depth: 0, root: true, amounts: [ { commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" }, ], }, { account: "assets:bank", label: "Bank", depth: 1, root: false, amounts: [ { commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" }, ], }, { account: "assets:bank:checking", label: "Checking", depth: 2, root: false, amounts: [ { commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" }, ], }, ], total: [{ commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" }], }, ], net: null, meta: { hledger_version: "1.52.1" }, }; const equityReport = { report_type: "equity", period: { begin: null, end: null }, groups: [ { commodity: "EUR", total: { commodity: "EUR", quantity: "1000.0", display: "1000.0 EUR" }, rows: [ { account: "equity:alice", label: "Alice", depth: 0, amounts: [ { commodity: "EUR", quantity: "600.0", display: "600.0 EUR" }, ], percentage: "60.00", }, { account: "equity:bob", label: "Bob", depth: 0, amounts: [ { commodity: "EUR", quantity: "400.0", display: "400.0 EUR" }, ], percentage: "40.00", }, ], }, ], meta: { hledger_version: "1.52.1" }, }; const balanceSheetReport = { report_type: "balance_sheet", period: { begin: null, end: null }, sections: [ { title: "Assets", rows: [ { account: "assets:bank", label: "Bank", depth: 0, root: false, amounts: [ { commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" }, ], }, { account: "assets:bank:checking", label: "Checking", depth: 1, root: false, amounts: [ { commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" }, ], }, ], total: [{ commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" }], }, { title: "Liabilities", rows: [], total: [{ commodity: "EUR", quantity: "0.0", display: "0.00 EUR" }], }, ], net: [{ commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" }], meta: { hledger_version: "1.52.1" }, }; const incomeStatementReport = { report_type: "income_statement", period: { begin: null, end: null }, sections: [ { title: "Revenues", rows: [ { account: "revenues:donations", label: "Donations", depth: 0, root: false, amounts: [ { commodity: "EUR", quantity: "50.0", display: "50.00 EUR" }, ], }, ], total: [{ commodity: "EUR", quantity: "50.0", display: "50.00 EUR" }], }, { title: "Expenses", rows: [ { account: "expenses:hosting", label: "Hosting", depth: 0, root: false, amounts: [ { commodity: "EUR", quantity: "20.5", display: "20.50 EUR" }, ], }, { account: "expenses:hosting:server", label: "Server", depth: 1, root: false, amounts: [ { commodity: "EUR", quantity: "20.5", display: "20.50 EUR" }, ], }, ], total: [{ commodity: "EUR", quantity: "20.5", display: "20.50 EUR" }], }, ], net: [{ commodity: "EUR", quantity: "29.5", display: "29.50 EUR" }], meta: { hledger_version: "1.52.1" }, }; acceptance("Hledger plugin", function (needs) { needs.settings({ hledger_enabled: true }); needs.pretender((server, helper) => { server.get("/t/45.json", () => { const topic = cloneJSON(topicFixtures["/t/28830/1.json"]); topic.post_stream.posts[0].cooked = `
`; return helper.response(topic); }); server.get(`/hledger/topics/${TOPIC_ID}/reports/accounts`, () => helper.response(accountsReport) ); server.get(`/hledger/topics/${TOPIC_ID}/reports/equity`, () => helper.response(equityReport) ); server.get(`/hledger/topics/${TOPIC_ID}/reports/balance_sheet`, () => helper.response(balanceSheetReport) ); server.get(`/hledger/topics/${TOPIC_ID}/reports/income_statement`, () => helper.response(incomeStatementReport) ); }); test("renders the dashboard in place of the journal", async function (assert) { await visit("/t/-/45"); assert.dom(".hledger-dashboard__toolbar .btn").exists({ count: 4 }); assert .dom(".hledger-dashboard__toolbar .btn:nth-of-type(1)") .hasText("Accounts"); assert .dom(".hledger-dashboard__toolbar .btn:nth-of-type(2)") .hasText("Balance sheet"); assert .dom(".hledger-dashboard__toolbar .btn:nth-of-type(3)") .hasText("Income statement"); assert .dom(".hledger-dashboard__toolbar .btn:nth-of-type(4)") .hasText("Equity"); assert.dom(".hledger-dashboard__table").includesText("Total"); assert.dom(".hledger-dashboard__table").includesText("Assets"); assert.dom(".hledger-dashboard__table").includesText("Bank"); assert.dom(".hledger-dashboard__table").includesText("Checking"); assert.dom(".hledger-dashboard__table").includesText("1000.00 EUR"); assert.dom(".hledger-dashboard__account.--depth-1").hasText("Bank"); assert.dom(".hledger-dashboard__account.--depth-2").hasText("Checking"); assert .dom('.hledger-dashboard__account[title="assets:bank"]') .hasText("Bank"); const rootAccount = document.querySelector( ".hledger-dashboard__account.--depth-0" ); const childAccount = document.querySelector( ".hledger-dashboard__account.--depth-1" ); const grandchildAccount = document.querySelector( ".hledger-dashboard__account.--depth-2" ); const amountCell = rootAccount .closest("tr") .querySelector(".hledger-dashboard__amount"); const paddingStart = (element) => parseFloat( getComputedStyle(element).getPropertyValue("padding-inline-start") ); assert.true( paddingStart(childAccount) > paddingStart(rootAccount), "indents child accounts" ); assert.true( paddingStart(grandchildAccount) > paddingStart(childAccount), "indents grandchild accounts" ); assert.true( ["end", "right"].includes(getComputedStyle(amountCell).textAlign), "aligns amounts to the end" ); assert.true( parseInt( getComputedStyle( document.querySelector(".hledger-dashboard__account.--root") ).fontWeight, 10 ) >= 700, "bolds root accounts" ); }); test("switches to the equity distribution", async function (assert) { await visit("/t/-/45"); await click(".hledger-dashboard__toolbar .btn:nth-of-type(4)"); assert.dom(".hledger-dashboard__table").includesText("Alice"); assert.dom(".hledger-dashboard__table").includesText("60.00%"); assert .dom('.hledger-dashboard__account[title="equity:alice"]') .hasText("Alice"); assert.dom(".hledger-dashboard__account.--depth-0").exists({ count: 2 }); assert .dom(".hledger-dashboard__account.--root") .doesNotExist("equity rows are never bold"); }); test("renders the balance sheet and income statement as trees", async function (assert) { await visit("/t/-/45"); await click(".hledger-dashboard__toolbar .btn:nth-of-type(2)"); assert.dom(".hledger-dashboard__section-title").exists({ count: 2 }); assert .dom('.hledger-dashboard__account[title="assets:bank"]') .hasText("Bank"); assert .dom('.hledger-dashboard__account[title="assets:bank:checking"]') .hasText("Checking"); assert .dom(".hledger-dashboard__account.--depth-0") .hasText("Bank", "starts the tree flush under the heading"); assert.dom(".hledger-dashboard__account.--depth-1").hasText("Checking"); assert .dom(".hledger-dashboard__account.--root") .doesNotExist("no root rows once the heading stands in for the root"); const bank = document.querySelector( '.hledger-dashboard__account[title="assets:bank"]' ); const checking = document.querySelector( '.hledger-dashboard__account[title="assets:bank:checking"]' ); assert.true( parseFloat( getComputedStyle(checking).getPropertyValue("padding-inline-start") ) > parseFloat( getComputedStyle(bank).getPropertyValue("padding-inline-start") ), "indents below the heading's first level" ); await click(".hledger-dashboard__toolbar .btn:nth-of-type(3)"); assert .dom('.hledger-dashboard__account[title="revenues:donations"]') .hasText("Donations"); assert .dom('.hledger-dashboard__account[title="expenses:hosting:server"]') .hasText("Server"); }); });