What this is
The practice ledger is a working accounting app. Every screen in the navigation is real — sales invoices and quotes, bills and purchase orders, contacts, projects, bank reconciliation, the chart of accounts, and four reports including a Profit and Loss and a Balance Sheet. It behaves like the software you already use every day: forms that validate, dropdowns you have to pick from, tables that paginate, and saves that take a moment.
It is seeded with 68 invoices, 40 bills, 32 quotes, 24 purchase orders, 40 contacts, 12 projects and 32 unreconciled bank lines. The reports are calculated from those same records rather than made up, so the Balance Sheet genuinely balances and the Aged Receivables total genuinely equals Accounts Receivable — which is what makes checking your own work possible.
It opens with a sign-in screen. Use demo@practice.invalid with the
password practice — both are printed on the screen itself, because
they are not a secret. There is no real account behind the form; it is there
because signing in is the first step of most real automations and you need one
to practise on.
It is not connected to anything. All the data lives in your own browser's local storage. Nothing is sent anywhere, nobody else sees your changes, and Reset demo data puts everything back exactly as it started. Break it as hard as you like.
How to run your code
Two ways, and you should learn both.
1. The browser console — for experimenting
Open the ledger, press F12 (or Ctrl+Shift+J),
click the Console tab, paste your code and press Enter. Fast to
iterate, gone when you reload the page.
// paste this on the invoice list to see it work
document.querySelectorAll('#invoice-table tbody tr').length
2. A bookmarklet — for actually using it
A bookmarklet is your script saved as a browser bookmark, so it runs on a page with one click. That is how a finished automation gets handed to somebody who does not write code. Wrap the script like this, then save the whole thing as the URL of a new bookmark:
javascript:(function(){ /* your code here */ })();
The three rules
- Read the page before you write to it. Find your elements in the console first. Confirm the selector returns what you expect, and only then write the loop that acts on them.
- Never assume the page is ready. Saving, loading and filtering all take time. Use the Latency switch in the yellow bar to prove your script survives a slow day.
- Setting a value is not the same as typing it. Assigning
input.valuedoes not tell the app anything happened. You have to dispatch the event too. This one catches everybody once.
Helpers you can use
The ledger exposes a few utilities on window so you do not have
to write the boring parts:
LabUI.parseCsv(text)— turn CSV text into an array of rows.LabUI.toCsv(rows)— turn an array of rows back into CSV text.LabUI.downloadText(filename, text, mime)— download a file.
You will also find LabData on the page, which is the app's own
data store. Reading it directly is a shortcut past every exercise here — but it
is worth knowing it exists, because plenty of real web apps leave something
similar lying around, and finding it can turn a two-day job into an hour.