test: UI tests for org chart desktop
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
new file mode 100644
index 0000000..d50d551
--- /dev/null
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -0,0 +1,102 @@
+context('Organizational Chart', () => {
+	before(() => {
+		cy.login();
+		cy.visit('/app/website');
+
+		cy.visit(`app/organizational-chart`);
+		cy.fill_field('company', 'Test Org Chart');
+		cy.get('body').click();
+		cy.wait(500);
+	});
+
+	beforeEach(() => {
+		cy.window().its('frappe').then(frappe => {
+			return frappe.call('erpnext.tests.ui_test_helpers.create_employee_records');
+		}).as('employee_records');
+	});
+
+	it('renders root nodes and loads children for the first expandable node', () => {
+		// check rendered root nodes and the node name, title, connections
+		cy.get('.hierarchy').find('.root-level ul.node-children').children()
+			.should('have.length', 2)
+			.first()
+			.as('first-child');
+
+		cy.get('@first-child').get('.node-name').contains('Test Employee 1');
+		cy.get('@first-child').get('.node-info').find('.node-title').contains('CEO');
+		cy.get('@first-child').get('.node-info').find('.node-connections').contains('· 2 Connections');
+
+		// check children of first node
+		cy.get('@employee_records').then(employee_records => {
+			// children of 1st root visible
+			cy.get(`[data-parent="${employee_records.message[0]}"]`).as('child-node')
+			cy.get('@child-node')
+				.should('have.length', 1)
+				.should('be.visible');
+			cy.get('@child-node').get('.node-name').contains('Test Employee 3');
+
+			// connectors between first root node and immediate child
+			cy.get(`path[data-parent="${employee_records.message[0]}"]`)
+				.should('be.visible')
+				.invoke('attr', 'data-child')
+  				.should('equal', employee_records.message[2]);
+		});
+	});
+
+	it('hides active nodes children and connectors on expanding sibling node', () => {
+		cy.get('@employee_records').then(employee_records => {
+			// click sibling
+			cy.get(`#${employee_records.message[1]}`)
+				.click()
+				.should('have.class', 'active');
+
+			// child nodes and connectors hidden
+			cy.get(`[data-parent="${employee_records.message[0]}"]`).should('not.be.visible');
+			cy.get(`path[data-parent="${employee_records.message[0]}"]`).should('not.be.visible');
+		});
+	});
+
+	it('collapses previous level nodes and refreshes connectors on expanding child node', () => {
+		cy.get('@employee_records').then(employee_records => {
+			// click child node
+			cy.get(`#${employee_records.message[3]}`)
+				.click()
+				.should('have.class', 'active');
+
+			// previous level nodes: parent should be on active-path; other nodes should be collapsed
+			cy.get(`#${employee_records.message[0]}`).should('have.class', 'collapsed');
+			cy.get(`#${employee_records.message[1]}`).should('have.class', 'active-path');
+
+			// previous level connectors refreshed
+			cy.get(`path[data-parent="${employee_records.message[1]}"]`)
+				.should('have.class', 'collapsed-connector');
+
+			// child node's children and connectors rendered
+			cy.get(`[data-parent="${employee_records.message[3]}"]`).should('be.visible');
+			cy.get(`path[data-parent="${employee_records.message[3]}"]`).should('be.visible');
+		});
+	});
+
+	it('expands previous level nodes', () => {
+		cy.get('@employee_records').then(employee_records => {
+			cy.get(`#${employee_records.message[0]}`)
+				.click()
+				.should('have.class', 'active');
+
+			cy.get(`[data-parent="${employee_records.message[0]}"]`)
+				.should('be.visible');
+
+			cy.get('ul.hierarchy').children().should('have.length', 2);
+			cy.get(`#connectors`).children().should('have.length', 1);
+		});
+	});
+
+	it('edit node navigates to employee master', () => {
+		cy.get('@employee_records').then(employee_records => {
+			cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
+				.click();
+
+			cy.url().should('include', `/employee/${employee_records.message[0]}`);
+		});
+	});
+});
diff --git a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
index 374787c..fe4d17c 100644
--- a/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
+++ b/erpnext/public/js/hierarchy_chart/hierarchy_chart_desktop.js
@@ -49,7 +49,8 @@
 			title: node.title,
 			image: node.image,
 			parent: node.parent_id,
-			connections: node.connections
+			connections: node.connections,
+			is_mobile: false
 		});
 
 		node.parent.append(node_card);
diff --git a/erpnext/tests/ui_test_helpers.py b/erpnext/tests/ui_test_helpers.py
new file mode 100644
index 0000000..8e67b1c
--- /dev/null
+++ b/erpnext/tests/ui_test_helpers.py
@@ -0,0 +1,53 @@
+import frappe
+from frappe import _
+from frappe.utils import getdate
+
+@frappe.whitelist()
+def create_employee_records():
+	company = create_company()
+	create_missing_designation()
+
+	emp1 = create_employee('Test Employee 1', 'CEO')
+	emp2 = create_employee('Test Employee 2', 'CTO')
+	emp3 = create_employee('Test Employee 3', 'Head of Marketing and Sales', emp1)
+	emp4 = create_employee('Test Employee 4', 'Project Manager', emp2)
+	emp5 = create_employee('Test Employee 5', 'Analyst', emp3)
+	emp6 = create_employee('Test Employee 6', 'Software Developer', emp4)
+
+	employees = [emp1, emp2, emp3, emp4, emp5, emp6]
+	return employees
+
+def create_company():
+	company = frappe.db.exists('Company', 'Test Org Chart')
+	if not company:
+		company = frappe.get_doc({
+			'doctype': 'Company',
+			'company_name': 'Test Org Chart',
+			'country': 'India',
+			'default_currency': 'INR'
+		}).insert().name
+
+	return company
+
+def create_employee(first_name, designation, reports_to=None):
+	employee = frappe.db.exists('Employee', {'first_name': first_name, 'designation': designation})
+	if not employee:
+		employee = frappe.get_doc({
+			'doctype': 'Employee',
+			'first_name': first_name,
+			'company': 'Test Org Chart',
+			'gender': 'Female',
+			'date_of_birth': getdate('08-12-1998'),
+			'date_of_joining': getdate('01-01-2021'),
+			'designation': designation,
+			'reports_to': reports_to
+		}).insert().name
+
+	return employee
+
+def create_missing_designation():
+	if not frappe.db.exists('Designation', 'CTO'):
+		frappe.get_doc({
+			'doctype': 'Designation',
+			'designation_name': 'CTO'
+		}).insert()
\ No newline at end of file