Setup JavaScript test environment

This patch setups JavaScript test environment.
- eslint
  test at local: `tox -e=eslint`
- karma
  test at local: `tox -e=karma`

Change-Id: I8b34cef1e0b7395a29af77939e534c4a31c76073
Implements: blueprint js-test-env
This commit is contained in:
Shu Muto 2016-09-12 16:09:00 +09:00
parent ee3e366a16
commit 4264fc3858
6 changed files with 367 additions and 1 deletions

60
.eslintrc Normal file
View File

@ -0,0 +1,60 @@
# Set up globals
globals:
angular: false
extends: openstack
# Most environment options are not explicitly enabled or disabled, only
# included here for completeness' sake. They are commented out, because the
# global updates.py script would otherwise override them during a global
# requirements synchronization.
#
# Individual projects should choose which platforms they deploy to.
env:
# browser global variables.
browser: true
# Adds all of the Jasmine testing global variables for version 1.3 and 2.0.
jasmine: true
# Enable eslint-plugin-angular
plugins:
- angular
# Below we adjust rules specific to horizon's usage of openstack's linting
# rules, and its own plugin inclusions.
rules:
#############################################################################
# Disabled Rules from eslint-config-openstack
#############################################################################
valid-jsdoc: [1, {
requireParamDescription: false
}]
brace-style: 1
block-scoped-var: 1
callback-return: 1
consistent-return: 1
guard-for-in: 1
no-extra-parens: 1
no-new: 1
no-redeclare: 1
no-undefined: 1
no-unneeded-ternary: 1
no-use-before-define: 1
quote-props: 0
semi-spacing: 1
space-in-parens: 1
#############################################################################
# Angular Plugin Customization
#############################################################################
angular/controller-as-vm:
- 1
- "ctrl"
# Remove after migrating to angular 1.4 or later.
angular/no-cookiestore:
- 1

5
.gitignore vendored
View File

@ -1,11 +1,16 @@
AUTHORS
ChangeLog
build
cover
dist
doc/source/sourcecode
zaqar_ui/test/.secret_key_store
node_modules
npm-debug.log
.venv
.tox
.project
.pydevproject
*.pyc
*.lock
*.egg*

35
package.json Normal file
View File

@ -0,0 +1,35 @@
{
"name": "zaqar-ui",
"description": "Zaqar UI JavaScript tests",
"repository": {
"type": "git",
"url": "git://git.openstack.org/openstack/zaqar-ui"
},
"version": "0.0.0",
"private": true,
"license": "Apache 2.0",
"author": "Openstack <openstack-dev@lists.openstack.org>",
"devDependencies": {
"eslint": "^1.10.3",
"eslint-config-openstack": "^1.2.4",
"eslint-plugin-angular": "1.0.1",
"jasmine-core": "2.4.1",
"karma": "1.1.2",
"karma-chrome-launcher": "1.0.1",
"karma-cli": "1.0.1",
"karma-coverage": "1.1.1",
"karma-jasmine": "1.0.2",
"karma-ng-html2js-preprocessor": "1.0.0",
"karma-phantomjs-launcher": "0.2.0",
"karma-threshold-reporter": "0.1.15",
"phantomjs": "1.9.17"
},
"dependencies": {},
"scripts": {
"postinstall": "if [ ! -d .tox ] || [ ! -d .tox/py27 ]; then tox -epy27 --notest; fi",
"lint": "eslint --no-color zaqar_ui/static",
"lintq": "eslint --quiet zaqar_ui/static",
"test": "karma start zaqar_ui/karma.conf.js --single-run"
}
}

97
test-shim.js Normal file
View File

@ -0,0 +1,97 @@
/*
* Shim for Javascript unit tests; supplying expected global features.
* This should be removed from the codebase once i18n services are provided.
* Taken from default i18n file provided by Django.
*/
var horizonPlugInModules = [];
(function (globals) {
var django = globals.django || (globals.django = {});
django.pluralidx = function (count) { return (count == 1) ? 0 : 1; };
/* gettext identity library */
django.gettext = function (msgid) { return msgid; };
django.ngettext = function (singular, plural, count) { return (count == 1) ? singular : plural; };
django.gettext_noop = function (msgid) { return msgid; };
django.pgettext = function (context, msgid) { return msgid; };
django.npgettext = function (context, singular, plural, count) { return (count == 1) ? singular : plural; };
django.interpolate = function (fmt, obj, named) {
if (named) {
return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
} else {
return fmt.replace(/%s/g, function(match){return String(obj.shift())});
}
};
/* formatting library */
django.formats = {
"DATETIME_FORMAT": "N j, Y, P",
"DATETIME_INPUT_FORMATS": [
"%Y-%m-%d %H:%M:%S",
"%Y-%m-%d %H:%M:%S.%f",
"%Y-%m-%d %H:%M",
"%Y-%m-%d",
"%m/%d/%Y %H:%M:%S",
"%m/%d/%Y %H:%M:%S.%f",
"%m/%d/%Y %H:%M",
"%m/%d/%Y",
"%m/%d/%y %H:%M:%S",
"%m/%d/%y %H:%M:%S.%f",
"%m/%d/%y %H:%M",
"%m/%d/%y"
],
"DATE_FORMAT": "N j, Y",
"DATE_INPUT_FORMATS": [
"%Y-%m-%d",
"%m/%d/%Y",
"%m/%d/%y"
],
"DECIMAL_SEPARATOR": ".",
"FIRST_DAY_OF_WEEK": "0",
"MONTH_DAY_FORMAT": "F j",
"NUMBER_GROUPING": "3",
"SHORT_DATETIME_FORMAT": "m/d/Y P",
"SHORT_DATE_FORMAT": "m/d/Y",
"THOUSAND_SEPARATOR": ",",
"TIME_FORMAT": "P",
"TIME_INPUT_FORMATS": [
"%H:%M:%S",
"%H:%M:%S.%f",
"%H:%M"
],
"YEAR_MONTH_FORMAT": "F Y"
};
django.get_format = function (format_type) {
var value = django.formats[format_type];
if (typeof(value) == 'undefined') {
return format_type;
} else {
return value;
}
};
/* add to global namespace */
globals.pluralidx = django.pluralidx;
globals.gettext = django.gettext;
globals.ngettext = django.ngettext;
globals.gettext_noop = django.gettext_noop;
globals.pgettext = django.pgettext;
globals.npgettext = django.npgettext;
globals.interpolate = django.interpolate;
globals.get_format = django.get_format;
globals.STATIC_URL = '/static/';
globals.WEBROOT = '/';
}(this));

16
tox.ini
View File

@ -32,11 +32,25 @@ commands =
pip install django>=1.8,<1.9
python manage.py test {posargs}
[testenv:eslint]
whitelist_externals = npm
commands =
npm install
npm run {posargs:postinstall}
npm run {posargs:lint}
[testenv:karma]
whitelist_externals = npm
commands =
npm install
npm run {posargs:postinstall}
npm run {posargs:test}
[testenv:docs]
commands = python setup.py build_sphinx
[flake8]
exclude = .venv,.git,.tox,dist,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py,*/local/*,*/test/test_plugins/*,.ropeproject
exclude = .venv,.git,.tox,dist,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py,*/local/*,*/test/test_plugins/*,.ropeproject,node_modules
max-complexity = 20
[hacking]

155
zaqar_ui/karma.conf.js Normal file
View File

@ -0,0 +1,155 @@
/*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var fs = require('fs');
var path = require('path');
module.exports = function (config) {
// This tox venv is setup in the post-install npm step
var toxPath = '../.tox/py27/lib/python2.7/site-packages/';
config.set({
preprocessors: {
// Used to collect templates for preprocessing.
// NOTE: the templates must also be listed in the files section below.
'./static/**/*.html': ['ng-html2js'],
// Used to indicate files requiring coverage reports.
'./static/**/!(*.spec).js': ['coverage'],
},
// Sets up module to process templates.
ngHtml2JsPreprocessor: {
prependPrefix: '/',
moduleName: 'templates'
},
basePath: './',
// Contains both source and test files.
files: [
/*
* shim, partly stolen from /i18n/js/horizon/
* Contains expected items not provided elsewhere (dynamically by
* Django or via jasmine template.
*/
'../test-shim.js',
// from jasmine.html
toxPath + 'xstatic/pkg/jquery/data/jquery.js',
toxPath + 'xstatic/pkg/angular/data/angular.js',
toxPath + 'xstatic/pkg/angular/data/angular-route.js',
toxPath + 'xstatic/pkg/angular/data/angular-mocks.js',
toxPath + 'xstatic/pkg/angular/data/angular-cookies.js',
toxPath + 'xstatic/pkg/angular_bootstrap/data/angular-bootstrap.js',
toxPath + 'xstatic/pkg/angular_gettext/data/angular-gettext.js',
toxPath + 'xstatic/pkg/angular/data/angular-sanitize.js',
toxPath + 'xstatic/pkg/d3/data/d3.js',
toxPath + 'xstatic/pkg/rickshaw/data/rickshaw.js',
toxPath + 'xstatic/pkg/angular_smart_table/data/smart-table.js',
toxPath + 'xstatic/pkg/angular_lrdragndrop/data/lrdragndrop.js',
toxPath + 'xstatic/pkg/spin/data/spin.js',
toxPath + 'xstatic/pkg/spin/data/spin.jquery.js',
toxPath + 'xstatic/pkg/tv4/data/tv4.js',
toxPath + 'xstatic/pkg/objectpath/data/ObjectPath.js',
toxPath + 'xstatic/pkg/angular_schema_form/data/schema-form.js',
// TODO: These should be mocked.
toxPath + '/horizon/static/horizon/js/horizon.js',
/**
* Include framework source code from horizon that we need.
* Otherwise, karma will not be able to find them when testing.
* These files should be mocked in the foreseeable future.
*/
toxPath + 'horizon/static/framework/**/*.module.js',
toxPath + 'horizon/static/framework/**/!(*.spec|*.mock).js',
toxPath + 'openstack_dashboard/static/**/*.module.js',
toxPath + 'openstack_dashboard/static/**/!(*.spec|*.mock).js',
toxPath + 'openstack_dashboard/dashboards/**/static/**/*.module.js',
toxPath + 'openstack_dashboard/dashboards/**/static/**/!(*.spec|*.mock).js',
/**
* First, list all the files that defines application's angular modules.
* Those files have extension of `.module.js`. The order among them is
* not significant.
*/
'./static/**/*.module.js',
/**
* Followed by other JavaScript files that defines angular providers
* on the modules defined in files listed above. And they are not mock
* files or spec files defined below. The order among them is not
* significant.
*/
'./static/**/!(*.spec|*.mock).js',
/**
* Then, list files for mocks with `mock.js` extension. The order
* among them should not be significant.
*/
toxPath + 'openstack_dashboard/static/**/*.mock.js',
/**
* Finally, list files for spec with `spec.js` extension. The order
* among them should not be significant.
*/
'./static/**/*.spec.js',
/**
* Angular external templates
*/
'./static/**/*.html'
],
autoWatch: true,
frameworks: ['jasmine'],
browsers: ['PhantomJS'],
browserNoActivityTimeout: 60000,
phantomjsLauncher: {
// Have phantomjs exit if a ResourceError is encountered
// (useful if karma exits without killing phantom)
exitOnResourceError: true
},
reporters: ['progress', 'coverage', 'threshold'],
plugins: [
'karma-phantomjs-launcher',
'karma-jasmine',
'karma-ng-html2js-preprocessor',
'karma-coverage',
'karma-threshold-reporter'
],
// Places coverage report in HTML format in the subdirectory below.
coverageReporter: {
type: 'html',
dir: '../cover/karma/'
},
// Coverage threshold values.
thresholdReporter: {
statements: 10, // target 100
branches: 0, // target 100
functions: 10, // target 100
lines: 10 // target 100
}
});
};