aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatias Niemelä2013-06-18 09:37:29 -0400
committerMatias Niemelä2013-06-18 09:37:29 -0400
commitf6be59c1b9253ad8438ec65ab959e294686c65ab (patch)
treee6f012c6c0114589a7ef6cdcedf5baa1cc9ab680
parent46dfb92afd185c93f60ca90a72653f33d7cb18e8 (diff)
downloadangular.js-f6be59c1b9253ad8438ec65ab959e294686c65ab.tar.bz2
chore(ngdocs): provide test code for lunr search in docs
-rw-r--r--docs/component-spec/NavigationCtrlSpec.js72
-rw-r--r--docs/component-spec/docsSearchSpec.js59
-rw-r--r--docs/src/templates/css/docs.css1
-rw-r--r--docs/src/templates/js/docs.js154
4 files changed, 199 insertions, 87 deletions
diff --git a/docs/component-spec/NavigationCtrlSpec.js b/docs/component-spec/NavigationCtrlSpec.js
new file mode 100644
index 00000000..d7a9da45
--- /dev/null
+++ b/docs/component-spec/NavigationCtrlSpec.js
@@ -0,0 +1,72 @@
+describe("DocsNavigationCtrl", function() {
+
+ beforeEach(module('docsApp'));
+
+ var ctrl, $scope;
+
+ beforeEach(function() {
+ module(function($provide) {
+ $provide.value('docsPages', []);
+ $provide.factory('docsSearch', function() {
+ return function(q) {
+ return ['one','two','three'];
+ };
+ });
+ });
+ inject(function($controller, $rootScope, $location, docsSearch) {
+ $scope = $rootScope.$new();
+ ctrl = $controller('DocsNavigationCtrl', {
+ $scope : $scope,
+ $location : $location,
+ docsSearch : docsSearch
+ });
+ });
+ });
+
+ it("should search and return data from docsSearch", function() {
+ $scope.search('1234')
+ expect($scope.results.join(',')).toBe('one,two,three');
+ expect($scope.hasResults).toBe(true);
+ });
+
+ it("should avoid searching if the search term is too short", function() {
+ $scope.search('1')
+ expect($scope.results.length).toBe(0);
+ expect($scope.hasResults).toBe(false);
+ });
+
+ it("should set the columns classname based on the total grouped results", function() {
+ $scope.search('1234');
+ expect($scope.colClassName).toBe('cols-3');
+
+ $scope.search('1');
+ expect($scope.colClassName).toBe(null);
+ });
+
+ it("should hide and clear the results when called", function() {
+ $scope.hasResults = true;
+ $scope.results = ['one'];
+ $scope.colClassName = '...';
+ $scope.hideResults();
+ expect($scope.hasResults).toBe(false);
+ expect($scope.results.length).toBe(0);
+ expect($scope.colClassName).toBe(null);
+ });
+
+ it("should hide, clear and change the path of the page when submitted", inject(function($location) {
+ $scope.hasResults = true;
+ $scope.results = {
+ api : [
+ {url : '/home'}
+ ],
+ tutorial : [
+ {url : '/tutorial'}
+ ]
+ };
+ $scope.submit();
+ expect($location.path()).toBe('/home');
+ expect($scope.results.length).toBe(0);
+ expect($scope.hasResults).toBe(false);
+ }));
+
+});
diff --git a/docs/component-spec/docsSearchSpec.js b/docs/component-spec/docsSearchSpec.js
new file mode 100644
index 00000000..38e6937a
--- /dev/null
+++ b/docs/component-spec/docsSearchSpec.js
@@ -0,0 +1,59 @@
+describe("docsSearch", function() {
+
+ beforeEach(module('docsApp'));
+
+ var interceptedLunrResults;
+ beforeEach(function() {
+ interceptedLunrResults = [];
+ });
+
+ beforeEach(function() {
+ module(function($provide) {
+ var results = [];
+ results[0] = { section: 'tutorial', shortName: 'item one', keywords: 'item, one, 1' };
+ results[1] = { section: 'tutorial', shortName: 'item man', keywords: 'item, man' };
+ results[2] = { section: 'api', shortName: 'item other', keywords: 'item, other' };
+ results[3] = { section: 'cookbook', shortName: 'item cookbook', keywords: 'item, other' };
+ results[4] = { section: 'api', shortName: 'ngRepeat', keywords: 'item, other' };
+
+ $provide.value('NG_PAGES', results);
+ $provide.factory('lunrSearch', function() {
+ return function() {
+ return {
+ store : function(value) {
+ interceptedLunrResults.push(value);
+ },
+ search : function(q) {
+ var data = [];
+ angular.forEach(results, function(res, i) {
+ data.push({ ref : i });
+ });
+ return data;
+ }
+ }
+ };
+ });
+ });
+ });
+
+ it("should lookup and organize values properly", inject(function(docsSearch) {
+ var items = docsSearch('item');
+ expect(items['api'].length).toBe(2);
+ }));
+
+ it("should place cookbook items in the tutorial", inject(function(docsSearch) {
+ var items = docsSearch('item');
+ expect(items['tutorial'].length).toBe(3);
+ }));
+
+ it("should return all results without a search", inject(function(docsSearch) {
+ var items = docsSearch();
+ expect(items['tutorial'].length).toBe(3);
+ expect(items['api'].length).toBe(2);
+ }));
+
+ it("should store values with and without a ng prefix", inject(function(docsSearch) {
+ expect(interceptedLunrResults[4].title).toBe('ngRepeat repeat');
+ }));
+
+});
diff --git a/docs/src/templates/css/docs.css b/docs/src/templates/css/docs.css
index 6977d205..5d769b29 100644
--- a/docs/src/templates/css/docs.css
+++ b/docs/src/templates/css/docs.css
@@ -461,6 +461,7 @@ pre ol li {
box-shadow:-6px 0 5px #555;
display:block;
border-radius:10px;
+}
.docs-version-jump {
width:180px;
diff --git a/docs/src/templates/js/docs.js b/docs/src/templates/js/docs.js
index ae0f1e58..88a4a9d1 100644
--- a/docs/src/templates/js/docs.js
+++ b/docs/src/templates/js/docs.js
@@ -62,29 +62,31 @@ docsApp.controller.DocsVersionsCtrl = ['$scope', '$window', 'NG_VERSIONS', funct
};
}];
-docsApp.controller.DocsNavigationCtrl = ['$scope', 'fullTextSearch', '$location', function($scope, fullTextSearch, $location) {
- fullTextSearch.init();
+docsApp.controller.DocsNavigationCtrl = ['$scope', '$location', 'docsSearch', function($scope, $location, docsSearch) {
+ function clearResults() {
+ $scope.results = [];
+ $scope.colClassName = null;
+ $scope.hasResults = false;
+ }
+
$scope.search = function(q) {
- fullTextSearch.search(q, function(results) {
- if(q && q.length >= 4) {
- $scope.results = results;
- var totalSections = 0;
- for(var i in results) {
- ++totalSections;
- }
- if(totalSections > 0) {
- $scope.colClassName = 'cols-' + totalSections;
- $scope.hasResults = true;
- }
- else {
- $scope.hasResults = false;
- }
+ var MIN_SEARCH_LENGTH = 4;
+ if(q.length >= MIN_SEARCH_LENGTH) {
+ var results = docsSearch(q);
+ var totalSections = 0;
+ for(var i in results) {
+ ++totalSections;
}
- else {
- $scope.hasResults = false;
+ if(totalSections > 0) {
+ $scope.colClassName = 'cols-' + totalSections;
+ $scope.hasResults = true;
}
- if(!$scope.$$phase) $scope.$apply();
- });
+ $scope.results = results;
+ }
+ else {
+ clearResults();
+ }
+ if(!$scope.$$phase) $scope.$apply();
};
$scope.submit = function() {
var result;
@@ -100,82 +102,60 @@ docsApp.controller.DocsNavigationCtrl = ['$scope', 'fullTextSearch', '$location'
}
};
$scope.hideResults = function() {
- $scope.hasResults = false;
+ clearResults();
$scope.q = '';
};
}];
-docsApp.serviceFactory.fullTextSearch = ['$q', '$rootScope', 'NG_PAGES', function($q, $rootScope, NG_PAGES) {
- return {
- dbName : 'docs',
- indexName : 'docsindex',
+docsApp.serviceFactory.lunrSearch = function() {
+ return function(properties) {
+ var engine = lunr(properties);
+ return {
+ store : function(values) {
+ engine.add(values);
+ },
+ search : function(q) {
+ return engine.search(q);
+ }
+ };
+ };
+};
- init : function(onReady) {
- this.init = function() {};
+docsApp.serviceFactory.docsSearch = ['$rootScope','lunrSearch', 'NG_PAGES',
+ function($rootScope, lunrSearch, NG_PAGES) {
- var self = this;
- this.deferReady = $q.defer();
- this.readyPromise = this.deferReady.promise;
+ var index = lunrSearch(function() {
+ this.ref('id');
+ this.field('title', {boost: 50});
+ this.field('description', { boost : 20 });
+ });
- this.engine = lunr(function () {
- this.ref('id');
- this.field('title', {boost: 50});
- this.field('description', { boost : 20 });
- });
- this.prepare();
- this.onReady();
- },
- onReady : function() {
- this.ready = true;
- var self = this;
- self.deferReady.resolve();
- if(!$rootScope.$$phase) {
- $rootScope.$apply();
- }
- },
- whenReady : function(fn) {
- if(this.ready) {
- fn();
- }
- else {
- this.init();
- this.readyPromise.then(fn);
+ angular.forEach(NG_PAGES, function(page, i) {
+ var title = page.shortName;
+ if(title.charAt(0) == 'n' && title.charAt(1) == 'g') {
+ title = title + ' ' + title.charAt(2).toLowerCase() + title.substr(3);
+ }
+ index.store({
+ id: i,
+ title: title,
+ description: page.keywords
+ });
+ });
+
+ return function(q) {
+ var results = {};
+ angular.forEach(index.search(q), function(result) {
+ var item = NG_PAGES[result.ref];
+ var section = item.section;
+ if(section == 'cookbook') {
+ section = 'tutorial';
}
- },
- prepare : function(injector, callback) {
- for(var i=0;i<NG_PAGES.length;i++) {
- var page = NG_PAGES[i];
- var title = page.shortName;
- if(title.charAt(0) == 'n' && title.charAt(1) == 'g') {
- title = title + ' ' + title.substr(2);
- }
- this.engine.add({
- id: i,
- title: title,
- description: page.keywords
- });
+ results[section] = results[section] || [];
+ if(results[section].length < 15) {
+ results[section].push(item);
}
- },
- search : function(q, onReady) {
- var self = this;
- this.whenReady(function() {
- var data = [];
- var results = self.engine.search(q);
- var groups = {};
- angular.forEach(results, function(result) {
- var item = NG_PAGES[result.ref];
- var section = item.section;
- if(section == 'cookbook') {
- section = 'tutorial';
- }
- groups[section] = groups[section] || [];
- if(groups[section].length < 15) {
- groups[section].push(item);
- }
- });
- onReady(groups);
- });
- }
+ });
+ return results;
};
}];