You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by sb...@apache.org on 2015/05/19 12:05:46 UTC

svn commit: r1680224 - in /sling/trunk/contrib/explorers/resourceeditor: frontend/ src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/ src/test/javascript/e2e/spec/ src/test/javascript/spec/

Author: sboehme
Date: Tue May 19 10:05:45 2015
New Revision: 1680224

URL: http://svn.apache.org/r1680224
Log:
SLING-4555 Resource Editor: added JavaScript unit tests, smaller JavaScript refactorings, fixed "multi delete" e2e test, added spec reporter for Jasmine Karma unit tests

Modified:
    sling/trunk/contrib/explorers/resourceeditor/frontend/Gruntfile.js
    sling/trunk/contrib/explorers/resourceeditor/frontend/package.json
    sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/JSTreeAdapter.js
    sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/TreeController.js
    sling/trunk/contrib/explorers/resourceeditor/src/test/javascript/e2e/spec/e2e_spec.js
    sling/trunk/contrib/explorers/resourceeditor/src/test/javascript/spec/resource_editor_spec.js

Modified: sling/trunk/contrib/explorers/resourceeditor/frontend/Gruntfile.js
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/explorers/resourceeditor/frontend/Gruntfile.js?rev=1680224&r1=1680223&r2=1680224&view=diff
==============================================================================
--- sling/trunk/contrib/explorers/resourceeditor/frontend/Gruntfile.js (original)
+++ sling/trunk/contrib/explorers/resourceeditor/frontend/Gruntfile.js Tue May 19 10:05:45 2015
@@ -50,8 +50,10 @@ module.exports = function(grunt) {
 			},
 			karma : {
 				files:[
-				         staticContentFolder+'/js/**/*.js',
-				         '../src/test/javascript/**/*spec.js'],
+			            staticContentFolder+'/generated/3rd_party/js/**/*.js',
+			            staticContentFolder+'/js/**/*.js',
+			            '../src/test/javascript/spec/*spec.js'
+				        ],
 				tasks: ['karma:desktop_build']
 				
 			}
@@ -102,27 +104,29 @@ module.exports = function(grunt) {
 	    	    runnerPort: 9999,
 	    	    singleRun: true,
 	    	    browsers: ['Chrome', 'Firefox', 'PhantomJS'],
-	    	    plugins : ['karma-jasmine', 'karma-phantomjs-launcher', 'karma-chrome-launcher', 'karma-firefox-launcher', 'karma-ie-launcher'],
+	    	    reporters: ["spec"],
+	    	    specReporter: {maxLogLines: 5},
+	    	    plugins : ['karma-jasmine', 'karma-phantomjs-launcher', 'karma-chrome-launcher', 'karma-firefox-launcher', 'karma-ie-launcher', 
+	    	               'karma-spec-reporter'],
 	    	    frameworks: ['jasmine'],
-			    files: ['../src/test/javascript/spec/*spec.js',
+			    files: [
 			            staticContentFolder+'/generated/3rd_party/js/jquery.min.js',
 			            staticContentFolder+'/generated/3rd_party/js/**/*.js',
-			            staticContentFolder+'/js/**/*.js'
+			            staticContentFolder+'/js/**/*.js',
+			            '../src/test/javascript/spec/*spec.js'
 			           ]
 	    	},  
 	    	desktop_build: {
 	    	    singleRun: true,
 	    	    browsers: ['Chrome', 'Firefox']
 	    	},
+	    	multi_run: {
+	    	    singleRun: false,
+	    	    browsers: ['Chrome', 'Firefox']
+	    	},
 	    	build: {
 	    	    singleRun: true,
 	    	    browsers: ['PhantomJS']
-	    	},
-	    	watch: {
-	    	    reporters: 'dots',
-	    	    autoWatch: true,
-	    	    background: true,
-	    	    singleRun: false
 	    	}
 	    },
         webdriver: {

Modified: sling/trunk/contrib/explorers/resourceeditor/frontend/package.json
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/explorers/resourceeditor/frontend/package.json?rev=1680224&r1=1680223&r2=1680224&view=diff
==============================================================================
--- sling/trunk/contrib/explorers/resourceeditor/frontend/package.json (original)
+++ sling/trunk/contrib/explorers/resourceeditor/frontend/package.json Tue May 19 10:05:45 2015
@@ -23,6 +23,7 @@
     "grunt-contrib-watch": "0.6.1",
     "grunt-karma": "0.10.1",
     "karma-jasmine": "0.3.5",
+    "karma-spec-reporter": "0.0.19",
     "karma-phantomjs-launcher": "~0.1.4",
     "karma-chrome-launcher": "0.1.7",
     "karma-firefox-launcher": "0.1.4",

Modified: sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/JSTreeAdapter.js
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/JSTreeAdapter.js?rev=1680224&r1=1680223&r2=1680224&view=diff
==============================================================================
--- sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/JSTreeAdapter.js (original)
+++ sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/JSTreeAdapter.js Tue May 19 10:05:45 2015
@@ -37,22 +37,14 @@ org.apache.sling.reseditor.JSTreeAdapter
 		this.settings = settings;
 		this.treeController = treeController;
 		this.mainController = mainController;
-var pathSuffix = ".html";
-var pathEndsWithPathSuffix = settings.resourcePath.substring(settings.resourcePath.length-pathSuffix.length) == pathSuffix;
-var resourcePath = (pathEndsWithPathSuffix) ? settings.resourcePath.substring(0,settings.resourcePath.length-pathSuffix.length) : settings.resourcePath; 
-var currentNodePath = this.mainController.encodeToHTML(resourcePath);
-var paths = currentNodePath.substring(1).split("/");
-var selectingNodeWhileOpeningTree=true;
 
-var thisJSTreeAdapter = this;
+		var thisJSTreeAdapter = this;
 
 $(document).ready(function() {
 	$(window).resize( function() {
 		thisJSTreeAdapter.mainController.adjust_height();
 	});
 	
-	var selectorFromCurrentPath = treeController.getSelectorFromPath(currentNodePath);
-	
 	var scrollToPathFinished=false;
 	
 	thisJSTreeAdapter.mainController.adjust_height();
@@ -62,10 +54,12 @@ $(document).ready(function() {
 	// select the tree container using jQuery
 	$("#tree")
 	.bind("loaded.jstree", function (event, data) {
-		if (currentNodePath != "/") {
-			treeController.openElement($("#tree > ul > li[nodename=''] > ul"), paths);
+		var pathElements = treeController.getPathElements(settings.resourcePath);
+		
+		if (pathElements.length >= 1 && pathElements[0] != "") {
+			treeController.openElement($("#tree > ul > li[nodename=''] > ul"), pathElements);
 		}
-		selectingNodeWhileOpeningTree=false;
+		
 		// position the info-icon
 		$('#tree-info-icon').show();
 		$('#root i:first').before($('#tree-info-icon'));

Modified: sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/TreeController.js
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/TreeController.js?rev=1680224&r1=1680223&r2=1680224&view=diff
==============================================================================
--- sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/TreeController.js (original)
+++ sling/trunk/contrib/explorers/resourceeditor/src/main/resources/SLING-INF/libs/sling/resource-editor-static-content/js/tree/TreeController.js Tue May 19 10:05:45 2015
@@ -132,6 +132,14 @@ org.apache.sling.reseditor.TreeControlle
 		}
 	}
 	
+	TreeController.prototype.getPathElements = function(resourcePath){
+		var pathSuffix = ".html";
+		var pathEndsWithPathSuffix = resourcePath.substring(resourcePath.length-pathSuffix.length) == pathSuffix;
+		var resourcePathWithoutSuffix = (pathEndsWithPathSuffix) ? resourcePath.substring(0,resourcePath.length-pathSuffix.length) : resourcePath; 
+		var currentNodePath = this.mainController.encodeToHTML(resourcePathWithoutSuffix);
+		return currentNodePath.substring(1).split("/");
+	}
+	
 	TreeController.prototype.getSelectorFromPath = function(path){
 		var paths = path.substring(1).split("/");
 		return "#tree > ul [nodename='"+paths.join("'] > ul > [nodename='")+"']";
@@ -166,9 +174,7 @@ org.apache.sling.reseditor.TreeControlle
 						if (paths.length>0){
 							thisTreeController.openElement($("#"+pathElementLi.attr('id')).children("ul"), paths);
 						} else  {
-							selectingNodeWhileOpeningTree=true;
-							$('#tree').jstree('select_node', pathElementLi.attr('id'), 'true'/*doesn't seem to work*/);
-							selectingNodeWhileOpeningTree=false;
+							$('#tree').jstree('select_node', pathElementLi.attr('id'), 'true');
 					        var target = $('#'+pathElementLi.attr('id')+' a:first');
 					        target.focus();
 						}
@@ -237,7 +243,7 @@ org.apache.sling.reseditor.TreeControlle
 		var confirmationMsg = "You are about to delete '"+resourcePathToDelete+"' and all its sub nodes. Are you sure?";
 		var decodedResourcePath = this.mainController.decodeFromHTML(resourcePathToDelete);
 		var encodedResourcePathToDelete = this.mainController.encodeURL(decodedResourcePath);
-		bootbox.confirm(confirmationMsg, function(result) {
+		var sendDeletePost = function(result) {
 			if (result){
 		    	$.ajax({
 		        	  type: 'POST',
@@ -256,7 +262,8 @@ org.apache.sling.reseditor.TreeControlle
 		        	  }
 		        });
 			}
-		});
+		};
+		bootbox.confirm(confirmationMsg, sendDeletePost);
 	}
 
 	TreeController.prototype.openAddNodeDialog = function(li) {

Modified: sling/trunk/contrib/explorers/resourceeditor/src/test/javascript/e2e/spec/e2e_spec.js
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/explorers/resourceeditor/src/test/javascript/e2e/spec/e2e_spec.js?rev=1680224&r1=1680223&r2=1680224&view=diff
==============================================================================
--- sling/trunk/contrib/explorers/resourceeditor/src/test/javascript/e2e/spec/e2e_spec.js (original)
+++ sling/trunk/contrib/explorers/resourceeditor/src/test/javascript/e2e/spec/e2e_spec.js Tue May 19 10:05:45 2015
@@ -168,7 +168,7 @@ describe('A user of the Apache Sling Res
 		  client = client.url(homeURL);
 		  client
 		  .waitForExist('#last-element').click("#root li[nodename=\"aTestNode\"] i.add-icon")
-		  	.waitForVisible('#addNodeDialog.add-node-finished').click('#addNodeDialog .btn.btn-primary.submit')
+		  	.waitForVisible('#addNodeDialog.add-node-finished', 1000).click('#addNodeDialog .btn.btn-primary.submit')
 		  	// The open node animation will take longer than 500ms thus setting 2000ms as max.
 		  	.waitForExist('#root li[nodename="aTestNode"].opened', 2000).elements('#root li[nodename="aTestNode"].opened li a .jstree-themeicon', function(err, res) {
 			    client

Modified: sling/trunk/contrib/explorers/resourceeditor/src/test/javascript/spec/resource_editor_spec.js
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/explorers/resourceeditor/src/test/javascript/spec/resource_editor_spec.js?rev=1680224&r1=1680223&r2=1680224&view=diff
==============================================================================
--- sling/trunk/contrib/explorers/resourceeditor/src/test/javascript/spec/resource_editor_spec.js (original)
+++ sling/trunk/contrib/explorers/resourceeditor/src/test/javascript/spec/resource_editor_spec.js Tue May 19 10:05:45 2015
@@ -18,18 +18,245 @@
  */
 
 describe('The Resource Editor', function() {
+	MockNodeTypeManager = (function() {
+		function MockNodeTypeManager(settings, ntManager){
+			this.settings = settings;
+			this.ntManager = ntManager;
+			this.nodeTypesJson =  {
+				"nt:unstructured": {
+				    "declaredChildNodeDefinitions": [{
+				        "name": "*",
+				        "onParentVersion": "VERSION",
+				        "allowsSameNameSiblings": true,
+				        "defaultPrimaryType": "nt:unstructured"
+				        }],
+				      "declaredPropertyDefinitions": [
+				        {
+				        "name": "*",
+				        "requiredType": "undefined",
+				        "multiple": true
+				        },
+				        {
+				        "name": "*",
+				        "requiredType": "undefined"
+				        }
+				      ],
+				      "orderableChildNodes": true
+				},
+				"nt:folder": {
+		    	    "declaredChildNodeDefinitions": [{
+		    	      "name": "*",
+		    	      "onParentVersion": "VERSION",
+		    	      "requiredPrimaryTypes": ["nt:hierarchyNode"]
+		    	      }],
+		    	    "declaredSupertypes": ["nt:hierarchyNode"]
+		    	},
+		    	"nt:hierarchyNode": {"declaredSupertypes": [
+	                "mix:created",
+	                "nt:base"
+                ]},
+		    	"nt:base": {
+		    	}
+			}
+		}
+	
+		MockNodeTypeManager.prototype.getNodeTypeNames = function() {
+			return ["nt:unstructured", "nt:folder", "nt:hierarchyNode", "nt:base"];
+		}
+		
+		MockNodeTypeManager.prototype.getNodeType = function(name) {
+			var nt = this.nodeTypesJson[name];
+			if (typeof nt.name === "undefined"){
+				nt.name = name;
+				nt.canAddProperty = function(propertyName, propertyType){
+					return true;
+				};
+			}
+			return nt;
+		}
+		
+		return MockNodeTypeManager;
+	}());
+	
+	var mockNtManager = new MockNodeTypeManager();
 
-	it('\'s MainController', function() {
-//		it('can encode a URL', function() {
-			// Mock it!
-//			var ntManager = new de.sandroboehme.NodeTypeManager();
-			var mainControllerSettings = {
-					contextPath: "/"//,
-//					nodeTypes: ntManager.getNodeTypeNames() 
-			};
-			var mainController = new org.apache.sling.reseditor.MainController(mainControllerSettings, null);
+	var mainControllerSettings = {
+		contextPath: "/",
+		nodeTypes: mockNtManager.getNodeTypeNames() 
+	};
+	
+	describe('\'s MainController', function() {
+		var mainController;
+
+		beforeEach(function() {
+			mainController = new org.apache.sling.reseditor.MainController(mainControllerSettings, mockNtManager);
+		});
+
+		it('can encode a URL', function() {
 			var urlToEncode = "/reseditor/testnode/$&?äöß<> test.html";
 			expect(mainController.encodeURL(urlToEncode)).toEqual("/reseditor/testnode/%24%26%3F%C3%A4%C3%B6%C3%9F%3C%3E%20test.html");
-//		});
+		});
+
+		it('can encode HTML', function() {
+			expect(mainController.encodeToHTML("a<>b")).toEqual("a&lt;&gt;b");
+		});
+
+		it('can dencode HTML', function() {
+			expect(mainController.decodeFromHTML("a&lt;&gt;b")).toEqual("a<>b");
+		});
+		
+	});
+	
+	describe('\'s TreeController', function() {
+		var treeControllerSettings = {
+			contextPath: "/",
+			nodeTypes: mockNtManager.getNodeTypeNames() 
+		};
+
+		var mainController;
+		var treeController;
+
+		beforeEach(function() {
+			mainController = new org.apache.sling.reseditor.MainController(mainControllerSettings, mockNtManager);
+			treeController = new org.apache.sling.reseditor.TreeController(treeControllerSettings, mainController);
+		});
+		  
+		it("can rename nodes", function() {
+			var htmlEncodedNewName = "newNodeName";
+			var data = {
+					text: htmlEncodedNewName,
+					old: "oldNodeName",
+					node: {id: "li_id"}
+			};
+			spyOn(treeController, "getPathFromLi").and.returnValue("/testnode/oldNodeName");
+			spyOn($, "ajax");
+			treeController.renameNode(null, data);
+			
+			expect($.ajax.calls.mostRecent().args[0]["url"]).toEqual("/testnode/oldNodeName");
+			expect($.ajax.calls.mostRecent().args[0]["data"][":dest"]).toEqual("/testnode/newNodeName");
+			expect($.ajax.calls.mostRecent().args[0]["data"][":operation"]).toEqual("move");
+			expect($.ajax.calls.mostRecent().args[0]["data"]["_charset_"]).toEqual("utf-8");
+		});
+		
+		it("can split the URL into path elements for deep links", function(){
+			var pathElements = treeController.getPathElements("/");
+			expect(pathElements.length).toBe(1);
+			expect(pathElements).toContain("");
+			
+			pathElements = treeController.getPathElements("/testnodes");
+			expect(pathElements.length).toBe(1);
+			expect(pathElements).toContain("testnodes");
+			
+			pathElements = treeController.getPathElements("/testnodes/level2/level3");
+			expect(pathElements.length).toBe(3);
+			expect(pathElements[0]).toBe("testnodes");
+			expect(pathElements[1]).toBe("level2");
+			expect(pathElements[2]).toBe("level3");
+			
+			// Sometimes the path contains the ".html" suffix. Check that it still works 
+			pathElements = treeController.getPathElements("/.html");
+			expect(pathElements.length).toBe(1);
+			expect(pathElements).toContain("");
+			
+			pathElements = treeController.getPathElements("/testnodes.html");
+			expect(pathElements.length).toBe(1);
+			expect(pathElements).toContain("testnodes");
+			
+			pathElements = treeController.getPathElements("/testnodes/level2/level3.html");
+			expect(pathElements.length).toBe(3);
+			expect(pathElements[0]).toBe("testnodes");
+			expect(pathElements[1]).toBe("level2");
+			expect(pathElements[2]).toBe("level3");
+		});
+
+		it("can delete nodes", function(){
+			spyOn(treeController, "getURLEncodedPathFromLi").and.returnValue("/testnode");
+			spyOn($.fn, "jstree").and.returnValue(["j1_18", "j1_20"]);
+			var getPathFromLiCount = 0;
+			spyOn(treeController,"getPathFromLi").and.callFake(function(){
+				getPathFromLiCount++;
+				switch(getPathFromLiCount) {
+				    case 1:
+				        return "/testnode/node1_to_delete";
+				    case 2:
+				        return "/testnode/node3_to_delete";
+				}
+			});
+			
+			spyOn(bootbox, "confirm").and.callFake(function(){
+				var result = true;
+				/*
+				 * The confirm dialog cannot be clicked in this test. We spy on this dialog, retrieve the function 
+				 * that gets called after the user clicked ok and then call this function to check our expectations.
+				 */
+				// calling 'sendDeletePost()'
+				bootbox.confirm.calls.argsFor(0)[1](result);
+			});
+			
+			spyOn($, "ajax");
+			
+			treeController.deleteNodes({});
+			
+			expect(treeController.getPathFromLi.calls.count()).toBe(2);
+
+			expect($.ajax.calls.mostRecent().args[0]["url"]).toEqual("/testnode");
+			expect($.ajax.calls.mostRecent().args[0]["data"][":operation"]).toEqual("delete");
+			expect($.ajax.calls.mostRecent().args[0]["data"]["_charset_"]).toEqual("utf-8");
+			expect($.ajax.calls.mostRecent().args[0]["data"][":applyTo"][0]).toEqual("/testnode/node1_to_delete");
+			expect($.ajax.calls.mostRecent().args[0]["data"][":applyTo"][1]).toEqual("/testnode/node3_to_delete");
+		});
+		
+		it("can delete a single node", function(){
+			spyOn(treeController,"getPathFromLi").and.returnValue("/testnode/node2delete");
+
+			spyOn(bootbox, "confirm").and.callFake(function(){
+				var result = true;
+				/*
+				 * The confirm dialog cannot be clicked in this test. We spy on this dialog, retrieve the function 
+				 * that gets called after the user clicked ok and then call this function to check our expectations.
+				 */
+				// calling 'sendDeletePost()'
+				bootbox.confirm.calls.argsFor(0)[1](result);
+			});
+
+			spyOn($, "ajax");
+			
+			treeController.deleteSingleNode({});
+
+			expect($.ajax.calls.mostRecent().args[0]["url"]).toEqual("/testnode/node2delete");
+			expect($.ajax.calls.mostRecent().args[0]["data"][":operation"]).toEqual("delete");
+		});
+	});
+	
+	describe('\'s AddNodeController', function() {
+		var mainController;
+		var addNodeController;
+
+		beforeEach(function() {
+			mainController = new org.apache.sling.reseditor.MainController(mainControllerSettings, mockNtManager);
+			addNodeController = new org.apache.sling.reseditor.AddNodeController({}, mainController);
+		});
+		
+		it("can add a node", function(){
+			spyOn(mainController, "encodeURL").and.returnValue("/testnode");
+
+			spyOn($.fn, "select2").and.returnValue("nt:unstructured");
+			
+			spyOn($, 'ajax').and.callFake(function (req) {
+			    var d = $.Deferred();
+			    d.resolve({});
+			    return d.promise();
+			});
+			
+			spyOn(mainController,"redirectTo").and.returnValue(null);
+			
+			addNodeController.addNode();
+
+			expect($.ajax.calls.mostRecent().args[0]["url"]).toEqual("/testnode");
+			expect($.ajax.calls.mostRecent().args[0]["data"]["_charset_"]).toEqual("utf-8");
+			expect($.ajax.calls.mostRecent().args[0]["data"]["jcr:primaryType"]).toEqual("nt:unstructured");
+		});
 	});
+		
+		
 });
\ No newline at end of file