Merge branch 'develop' into staging
diff --git a/erpnext/schools/doctype/assessment_group/test_assessment_group.js b/erpnext/schools/doctype/assessment_group/test_assessment_group.js
new file mode 100644
index 0000000..aa6da47
--- /dev/null
+++ b/erpnext/schools/doctype/assessment_group/test_assessment_group.js
@@ -0,0 +1,86 @@
+// School Assessment module
+QUnit.module('schools');
+
+QUnit.test('Test: Assessment Group', function(assert){
+	assert.expect(4);
+	let done = assert.async();
+
+	frappe.run_serially([
+		() => frappe.set_route('Tree', 'Assessment Group'),
+
+		// Checking adding child without selecting any Node
+		() => frappe.tests.click_button('New'),
+		() => frappe.timeout(0.2),
+		() => {assert.equal($(`.msgprint`).text(), "Select a group node first.", "Error message success");},
+		() => frappe.tests.click_button('Close'),
+		() => frappe.timeout(0.2),
+
+		// Creating child nodes
+		() => frappe.tests.click_link('All Assessment Groups'),
+		() => frappe.map_group.make('Assessment-group-1'),
+		() => frappe.map_group.make('Assessment-group-2'),
+		() => frappe.map_group.make('Assessment-group-3'),
+		() => frappe.map_group.make('Assessment-group-4', "All Assessment Groups", 1),
+		() => frappe.tests.click_link('Assessment-group-4'),
+		() => frappe.map_group.make('Assessment-group-5', "Assessment-group-3", 0),
+
+		// Checking Edit button
+		() => frappe.timeout(0.5),
+		() => frappe.tests.click_link('Assessment-group-1'),
+		() => frappe.tests.click_button('Edit'),
+		() => frappe.timeout(0.5),
+		() => {assert.deepEqual(frappe.get_route(), ["Form", "Assessment Group", "Assessment-group-1"], "Edit route checks");},
+
+		// Deleting child Node
+		() => frappe.set_route('Tree', 'Assessment Group'),
+		() => frappe.timeout(0.5),
+		() => frappe.tests.click_link('Assessment-group-1'),
+		() => frappe.tests.click_button('Delete'),
+		() => frappe.timeout(0.5),
+		() => frappe.tests.click_button('Yes'),
+
+		// Renaming Child node
+		() => frappe.timeout(0.5),
+		() => frappe.tests.click_link('Assessment-group-2'),
+		() => frappe.tests.click_button('Rename'),
+		() => frappe.timeout(0.4),
+		() => cur_dialog.set_value('new_name', 'Assessment-group-6'),
+		() => frappe.tests.click_button('Rename'),
+		() => frappe.tests.click_button('Close'),
+
+		// Merging 2 child nodes into 1
+		() => frappe.timeout(0.5),
+		() => frappe.tests.click_link('Assessment-group-6'),
+		() => frappe.tests.click_button('Rename'),
+		() => frappe.timeout(0.4),
+		() => cur_dialog.set_value('merge', 1),
+		() => cur_dialog.set_value('new_name', 'Assessment-group-3'),
+		() => frappe.tests.click_button('Rename'),
+		() => frappe.tests.click_button('Close'),
+
+		// Checking Collapse and Expand button
+		() => frappe.timeout(1),
+		() => frappe.tests.click_link('Assessment-group-4'),
+		() => frappe.click_button('Collapse'),
+		() => frappe.tests.click_link('All Assessment Groups'),
+		() => frappe.click_button('Collapse'),
+		() => {assert.ok($('.opened').size() == 0, 'Collapsed');},
+		() => frappe.click_button('Expand'),
+		() => {assert.ok($('.opened').size() > 0, 'Expanded');},
+
+		() => done()
+	]);
+});
+
+frappe.map_group = {
+	make:function(assessment_group_name, parent_assessment_group = 'All Assessment Groups', is_group = 0){
+		return frappe.run_serially([
+			() => frappe.click_button('Add Child'),
+			() => frappe.timeout(0.2),
+			() => cur_dialog.set_value('is_group', is_group),
+			() => cur_dialog.set_value('assessment_group_name', assessment_group_name),
+			() => cur_dialog.set_value('parent_assessment_group', parent_assessment_group),
+			() => frappe.click_button('Create New'),
+		]);
+	}
+};
\ No newline at end of file
diff --git a/erpnext/schools/doctype/assessment_plan/test_assessment_plan.js b/erpnext/schools/doctype/assessment_plan/test_assessment_plan.js
new file mode 100644
index 0000000..b75a41a
--- /dev/null
+++ b/erpnext/schools/doctype/assessment_plan/test_assessment_plan.js
@@ -0,0 +1,58 @@
+// Testing Assessment Module in Schools
+QUnit.module('schools');
+
+QUnit.test('Test: Assessment Plan', function(assert){
+	assert.expect(7);
+	let done = assert.async();
+	let room_name, instructor_name, assessment_name;
+
+	frappe.run_serially([
+		() => frappe.db.get_value('Room', {'room_name': 'Room 1'}, 'name'),
+		(room) => {room_name = room.message.name;}, // Fetching Room name
+		() => frappe.db.get_value('Instructor', {'instructor_name': 'Instructor 1'}, 'name'),
+		(instructor) => {instructor_name = instructor.message.name;}, // Fetching Instructor name
+
+		() => {
+			return frappe.tests.make('Assessment Plan', [
+				{assessment_name: "Test-Mid-Term"},
+				{assessment_group: 'Assessment-group-5'},
+				{maximum_assessment_score: 100},
+				{student_group: 'test-course-wise-group-2'},
+				{course: 'Test_Sub'},
+				{grading_scale: 'GTU'},
+				{schedule_date: frappe.datetime.nowdate()},
+				{room: room_name},
+				{examiner: instructor_name},
+				{supervisor: instructor_name},
+				{from_time: "12:30:00"},
+				{to_time: "2:30:00"}
+			]);
+		},
+
+		() => {
+			assessment_name = cur_frm.doc.name; // Storing the name of current Assessment Plan
+			assert.equal(cur_frm.doc.assessment_criteria[0].assessment_criteria, 'Pass', 'Assessment Criteria auto-filled correctly');
+			assert.equal(cur_frm.doc.assessment_criteria[0].maximum_score, 100, 'Maximum score correctly set');
+		}, // Checking if the table was auto-filled upon selecting appropriate fields
+
+		() => frappe.timeout(1),
+		() => frappe.tests.click_button('Submit'),
+		() => frappe.timeout(0.5),
+		() => frappe.tests.click_button('Yes'),
+		() => frappe.timeout(0.5),
+		() => {assert.equal(cur_frm.doc.docstatus, 1, "Assessment Plan submitted successfully");},
+
+		() => frappe.click_button('Assessment Result'), // Checking out Assessment Result button option
+		() => frappe.timeout(0.5),
+		() => {
+			assert.deepEqual(frappe.get_route(), ["Form", "Assessment Result Tool"], 'Assessment Result properly linked');
+			assert.equal(cur_frm.doc.assessment_plan, assessment_name, 'Assessment correctly set');
+			assert.equal(cur_frm.doc.student_group, 'test-course-wise-group-2', 'Course for Assessment correctly set');
+		},
+		() => cur_frm.print_doc(),
+		() => frappe.timeout(1),
+		() => {assert.ok($('.btn-print-print').is(':visible'), "Print Format Available");},
+
+		() => done()
+	]);
+});
\ No newline at end of file
diff --git a/erpnext/schools/doctype/assessment_result/test_assessment_result.js b/erpnext/schools/doctype/assessment_result/test_assessment_result.js
new file mode 100644
index 0000000..83aca6b
--- /dev/null
+++ b/erpnext/schools/doctype/assessment_result/test_assessment_result.js
@@ -0,0 +1,72 @@
+// School Assessment module
+QUnit.module('schools');
+
+QUnit.test('Test: Assessment Result', function(assert){
+	assert.expect(25);
+	let done = assert.async();
+	let student_list = [];
+	let assessment_name;
+	let tasks = []
+
+	frappe.run_serially([
+		// Saving Assessment Plan name
+		() => frappe.db.get_value('Assessment Plan', {'assessment_name': 'Test-Mid-Term'}, 'name'),
+		(assessment_plan) => {assessment_name = assessment_plan.message.name;},
+		// Fetching list of Student for which Result is supposed to be set
+		() => frappe.set_route('Form', 'Assessment Plan', assessment_name),
+		() => frappe.timeout(1),
+		() => frappe.tests.click_button('Assessment Result'),
+		() => frappe.timeout(1),
+		() => cur_frm.refresh(),
+		() => frappe.timeout(1),
+		() => {
+			for(i = 0; i < $('tbody tr').size() * 4; i = (i + 4))
+				student_list.push($(`tbody td:eq("${i}")`).text());
+		},
+
+		// Looping through each student in the list and setting up their score
+		() => {
+			student_list.forEach(index => {
+				tasks.push(
+					() => frappe.set_route('List', 'Assessment Result', 'List'),
+					() => frappe.timeout(0.5),
+					() => frappe.tests.click_button('New'),
+					() => frappe.timeout(0.5),
+					() => cur_frm.set_value('student', index),
+					() => cur_frm.set_value('assessment_plan', assessment_name),
+					() => frappe.timeout(0.2),
+					() => cur_frm.doc.details[0].score = (39 + (15 * student_list.indexOf(index))),
+					() => cur_frm.save(),
+					() => frappe.timeout(0.5),
+
+					() => frappe.db.get_value('Assessment Plan', {'name': 'ASP00001'}, ['grading_scale', 'maximum_assessment_score']),
+					(assessment_plan) => {
+						assert.equal(cur_frm.doc.grading_scale, assessment_plan.message.grading_scale, 'Grading scale correctly fetched');
+						assert.equal(cur_frm.doc.maximum_score, assessment_plan.message.maximum_assessment_score, 'Maximum score correctly fetched');
+
+						frappe.call({
+							method: "erpnext.schools.api.get_grade",
+							args: {
+								"grading_scale": assessment_plan.message.grading_scale,
+								"percentage": cur_frm.doc.total_score
+							},
+							callback: function(r){
+								assert.equal(cur_frm.doc.grade, r.message, "Grade correctly calculated");
+							}
+						});
+					},
+
+					() => frappe.tests.click_button('Submit'),
+					() => frappe.timeout(0.5),
+					() => frappe.tests.click_button('Yes'),
+					() => frappe.timeout(0.5),
+					() => {assert.equal();},
+					() => {assert.equal(cur_frm.doc.docstatus, 1, "Submitted successfully");},
+				);
+			});
+			return frappe.run_serially(tasks);
+		},
+
+		() => done()
+	]);
+});
\ No newline at end of file
diff --git a/erpnext/schools/doctype/assessment_result_tool/test_assessment_result_tool.js b/erpnext/schools/doctype/assessment_result_tool/test_assessment_result_tool.js
new file mode 100644
index 0000000..7d9c7d3
--- /dev/null
+++ b/erpnext/schools/doctype/assessment_result_tool/test_assessment_result_tool.js
@@ -0,0 +1,29 @@
+// School Assessment module
+QUnit.module('schools');
+
+QUnit.test('Test: Assessment Result Tool', function(assert){
+	assert.expect(1);
+	let done = assert.async();
+	let i, count = 0, assessment_name;
+
+	frappe.run_serially([
+		// Saving Assessment Plan name
+		() => frappe.db.get_value('Assessment Plan', {'assessment_name': 'Test-Mid-Term'}, 'name'),
+		(assessment_plan) => {assessment_name = assessment_plan.message.name;},
+
+		() => frappe.set_route('Form', 'Assessment Plan', assessment_name),
+		() => frappe.timeout(1),
+		() => frappe.tests.click_button('Assessment Result'),
+		() => frappe.timeout(1),
+		() => cur_frm.refresh(),
+		() => frappe.timeout(1),
+		() => {
+			for(i = 2; i < $('tbody tr').size() * 4; i = (i + 4)){
+				if(($(`tbody td:eq("${i}")`) != "") && ($(`tbody td:eq("${i+1}")`) != ""))
+					count++;
+			}
+			assert.equal($('tbody tr').size(), count, 'All grades correctly displayed');
+		},
+		() => done()
+	]);
+});
\ No newline at end of file
diff --git a/erpnext/schools/doctype/grading_scale/test_grading_scale.js b/erpnext/schools/doctype/grading_scale/test_grading_scale.js
index 6539343..c686924 100644
--- a/erpnext/schools/doctype/grading_scale/test_grading_scale.js
+++ b/erpnext/schools/doctype/grading_scale/test_grading_scale.js
@@ -2,13 +2,61 @@
 QUnit.module('schools');
 
 QUnit.test('Test: Grading Scale', function(assert){
-	assert.expect(0);
+	assert.expect(3);
 	let done = assert.async();
 	frappe.run_serially([
 		() => {
 			return frappe.tests.make('Grading Scale', [
 				{grading_scale_name: 'GTU'},
-				{description: 'The score will be set according to 10 based system.'},
+				{description: 'The score will be set according to 100 based system.'},
+				{intervals: [
+					[
+						{grade_code: 'AA'},
+						{threshold: '95'},
+						{grade_description: 'First Class + Distinction'}
+					],
+					[
+						{grade_code: 'AB'},
+						{threshold: '90'},
+						{grade_description: 'First Class'}
+					],
+					[
+						{grade_code: 'BB'},
+						{threshold: '80'},
+						{grade_description: 'Distinction'}
+					],
+					[
+						{grade_code: 'BC'},
+						{threshold: '70'},
+						{grade_description: 'Second Class'}
+					],
+					[
+						{grade_code: 'CC'},
+						{threshold: '60'},
+						{grade_description: 'Third Class'}
+					],
+					[
+						{grade_code: 'CD'},
+						{threshold: '50'},
+						{grade_description: 'Average'}
+					],
+					[
+						{grade_code: 'DD'},
+						{threshold: '40'},
+						{grade_description: 'Pass'}
+					],
+					[
+						{grade_code: 'FF'},
+						{threshold: '0'},
+						{grade_description: 'Fail'}
+					],
+				]}
+			]);
+		},
+		() => {
+			return frappe.tests.make('Grading Scale', [
+				{grading_scale_name: 'GTU-2'},
+				{description: 'The score will be set according to 100 based system.'},
 				{intervals: [
 					[
 						{grade_code: 'AA'},
@@ -23,6 +71,32 @@
 				]}
 			]);
 		},
+
+		() => {
+			let grading_scale = ['GTU', 'GTU-2'];
+			let tasks = [];
+			grading_scale.forEach(index => {
+				tasks.push(
+					() => frappe.set_route('Form', 'Grading Scale', index),
+					() => frappe.timeout(0.5),
+					() => frappe.tests.click_button('Submit'),
+					() => frappe.timeout(0.5),
+					() => frappe.tests.click_button('Yes'),
+					() => {assert.equal(cur_frm.doc.docstatus, 1, 'Submitted successfully');}
+				);
+			});
+			return frappe.run_serially(tasks);
+		},
+
+		() => frappe.timeout(1),
+		() => frappe.set_route('Form', 'Grading Scale','GTU-2'),
+		() => frappe.timeout(0.5),
+		() => frappe.tests.click_button('Cancel'),
+		() => frappe.timeout(0.5),
+		() => frappe.tests.click_button('Yes'),
+		() => frappe.timeout(0.5),
+		() => {assert.equal(cur_frm.doc.docstatus, 2, 'Cancelled successfully');},
+
 		() => done()
 	]);
 });
\ No newline at end of file
diff --git a/erpnext/tests/ui/tests.txt b/erpnext/tests/ui/tests.txt
index fff54c6..5634935 100644
--- a/erpnext/tests/ui/tests.txt
+++ b/erpnext/tests/ui/tests.txt
@@ -72,4 +72,8 @@
 erpnext/schools/doctype/student_attendance_tool/test_student_attendance_tool.js
 erpnext/schools/doctype/student_attendance/test_student_attendance.js
 erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_issue.js
-erpnext/buying/doctype/supplier/test_supplier.js
\ No newline at end of file
+erpnext/schools/doctype/assessment_group/test_assessment_group.js
+erpnext/schools/doctype/assessment_plan/test_assessment_plan.js
+erpnext/schools/doctype/assessment_result/test_assessment_result.js
+erpnext/schools/doctype/assessment_result_tool/test_assessment_result_tool.js
+erpnext/buying/doctype/supplier/test_supplier.js