test: ui test for stock levels
diff --git a/cypress/integration/test_item.js b/cypress/integration/test_item.js
new file mode 100644
index 0000000..fcb7533
--- /dev/null
+++ b/cypress/integration/test_item.js
@@ -0,0 +1,44 @@
+describe("Test Item Dashboard", () => {
+	before(() => {
+		cy.login();
+		cy.visit("/app/item");
+		cy.insert_doc(
+			"Item",
+			{
+				item_code: "e2e_test_item",
+				item_group: "All Item Groups",
+				opening_stock: 42,
+				valuation_rate: 100,
+			},
+			true
+		);
+		cy.go_to_doc("item", "e2e_test_item");
+	});
+
+	it("should show dashboard with correct data on first load", () => {
+		cy.get(".stock-levels").contains("Stock Levels").should("be.visible");
+		cy.get(".stock-levels").contains("e2e_test_item").should("exist");
+
+		// reserved and available qty
+		cy.get(".stock-levels .inline-graph-count")
+			.eq(0)
+			.contains("0")
+			.should("exist");
+		cy.get(".stock-levels .inline-graph-count")
+			.eq(1)
+			.contains("42")
+			.should("exist");
+	});
+
+	it("should persist on field change", () => {
+		cy.get('input[data-fieldname="disabled"]').check();
+		cy.wait(500);
+		cy.get(".stock-levels").contains("Stock Levels").should("be.visible");
+		cy.get(".stock-levels").should("have.length", 1);
+	});
+
+	it("should persist on reload", () => {
+		cy.reload();
+		cy.get(".stock-levels").contains("Stock Levels").should("be.visible");
+	});
+});
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index 7929a2e..7ddc80a 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -23,3 +23,9 @@
 //
 // -- This is will overwrite an existing command --
 // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... });
+
+const slug = (name) => name.toLowerCase().replace(" ", "-");
+
+Cypress.Commands.add("go_to_doc", (doctype, name) => {
+	cy.visit(`/app/${slug(doctype)}/${encodeURIComponent(name)}`);
+});