Files
discourse-hledger/test/javascripts/acceptance/hledger-test.js
T

430 lines
13 KiB
JavaScript

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" },
};
const transactionsReport = {
report_type: "transactions",
period: { begin: null, end: null },
transactions: [
{
date: "2024-01-01",
date2: null,
description: "Opening balances",
code: "",
postings: [
{
account: "assets:bank:checking",
amounts: [
{ commodity: "EUR", quantity: "1000.0", display: "1000.00 EUR" },
],
},
{
account: "equity:alice",
amounts: [
{ commodity: "EUR", quantity: "-600.0", display: "-600.00 EUR" },
],
},
{
account: "equity:bob",
amounts: [
{ commodity: "EUR", quantity: "-400.0", display: "-400.00 EUR" },
],
},
],
},
{
date: "2024-02-10",
date2: null,
description: "Hosting",
code: "",
postings: [
{
account: "expenses:hosting:server",
amounts: [
{ commodity: "EUR", quantity: "20.5", display: "20.50 EUR" },
],
},
{
account: "assets:bank:checking",
amounts: [
{ commodity: "EUR", quantity: "-20.5", display: "-20.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 = `<div class="hledger-dashboard"></div>`;
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)
);
server.get(`/hledger/topics/${TOPIC_ID}/reports/transactions`, () =>
helper.response(transactionsReport)
);
});
test("renders the dashboard in place of the journal", async function (assert) {
await visit("/t/-/45");
assert.dom(".hledger-dashboard__toolbar .btn").exists({ count: 5 });
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("P&L");
assert
.dom(".hledger-dashboard__toolbar .btn:nth-of-type(4)")
.hasText("Equity");
assert
.dom(".hledger-dashboard__toolbar .btn:nth-of-type(5)")
.hasText("Journal");
assert
.dom(
".hledger-dashboard__toolbar .btn:nth-of-type(2) .d-icon-scale-balanced"
)
.exists("renders the balance sheet icon");
assert
.dom(".hledger-dashboard__toolbar .btn:nth-of-type(3) .d-icon-chart-line")
.exists("renders the income statement icon");
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"
);
assert
.dom(".hledger-dashboard__empty")
.exists({ count: 1 }, "shows a placeholder for the empty section");
assert.dom(".hledger-dashboard__empty").hasText("No data");
assert
.dom(
".hledger-dashboard__section:nth-of-type(2) .hledger-dashboard__table"
)
.doesNotExist("omits the table for the empty section");
assert
.dom(
".hledger-dashboard__section:nth-of-type(1) .hledger-dashboard__table"
)
.exists("keeps the table for the populated section");
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");
});
test("shows the transaction log", async function (assert) {
await visit("/t/-/45");
await click(".hledger-dashboard__toolbar .btn:nth-of-type(5)");
assert
.dom(".hledger-dashboard__transaction")
.exists({ count: 2 }, "renders one block per transaction");
assert
.dom(
".hledger-dashboard__transaction:nth-of-type(1) .hledger-dashboard__transaction-date"
)
.hasText("2024-01-01", "shows the transaction date");
assert
.dom(
".hledger-dashboard__transaction:nth-of-type(1) .hledger-dashboard__transaction-description"
)
.hasText("Opening balances", "shows the transaction description");
assert
.dom(".hledger-dashboard__table")
.includesText("assets:bank:checking");
assert.dom(".hledger-dashboard__table").includesText("1000.00 EUR");
});
});