docs(testing): add tests that involve Angular 2
This commit is contained in:
parent
bd079369f3
commit
dd7b5176a8
1
public/docs/_examples/.gitignore
vendored
1
public/docs/_examples/.gitignore
vendored
@ -10,3 +10,4 @@ tsconfig.json
|
|||||||
tslint.json
|
tslint.json
|
||||||
npm-debug*.
|
npm-debug*.
|
||||||
**/protractor.config.js
|
**/protractor.config.js
|
||||||
|
_test-output
|
||||||
|
@ -1,68 +1,91 @@
|
|||||||
// Tun on full stack traces in errors to help debugging
|
/*global jasmine, __karma__, window*/
|
||||||
Error.stackTraceLimit=Infinity;
|
(function () {
|
||||||
|
|
||||||
|
// Error.stackTraceLimit = Infinity;
|
||||||
|
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
|
||||||
|
|
||||||
// // Cancel Karma's synchronous start,
|
// Cancel Karma's synchronous start,
|
||||||
// // we will call `__karma__.start()` later, once all the specs are loaded.
|
// we call `__karma__.start()` later, once all the specs are loaded.
|
||||||
__karma__.loaded = function() {};
|
__karma__.loaded = function () { };
|
||||||
|
|
||||||
|
// SET THE RUNTIME APPLICATION ROOT HERE
|
||||||
|
var appRoot ='app'; // no trailing slash!
|
||||||
|
|
||||||
System.config({
|
// RegExp for client application base path within karma (which always starts 'base\')
|
||||||
packages: {
|
var karmaBase = '^\/base\/'; // RegEx string for base of karma folders
|
||||||
'base/app': {
|
var appPackage = 'base/' + appRoot; //e.g., base/app
|
||||||
defaultExtension: false,
|
var appRootRe = new RegExp(karmaBase + appRoot + '\/');
|
||||||
// removed because of issues with raw .js files not being found.
|
var onlyAppFilesRe = new RegExp(karmaBase + appRoot + '\/(?!.*\.spec\.js$)([a-z0-9-_\.\/]+)\.js$');
|
||||||
// format: 'register',
|
|
||||||
map: Object.keys(window.__karma__.files).
|
|
||||||
filter(onlyAppFiles).
|
|
||||||
reduce(function createPathRecords(pathsMapping, appPath) {
|
|
||||||
// creates local module name mapping to global path with karma's fingerprint in path, e.g.:
|
|
||||||
// './hero.service': '/base/src/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e'
|
|
||||||
var moduleName = appPath.replace(/^\/base\/app\//, './').replace(/\.js$/, '');
|
|
||||||
pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath]
|
|
||||||
return pathsMapping;
|
|
||||||
}, {})
|
|
||||||
|
|
||||||
}
|
var moduleNames = [];
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// old code from angular 44
|
// Configure systemjs packages to use the .js extension for imports from the app folder
|
||||||
// System.import('angular2/src/core/dom/browser_adapter').then(function(browser_adapter) {
|
var packages = {};
|
||||||
// new path for angular 51
|
packages[appPackage] = {
|
||||||
System.import('angular2/src/platform/browser/browser_adapter').then(function(browser_adapter) {
|
defaultExtension: false,
|
||||||
browser_adapter.BrowserDomAdapter.makeCurrent();
|
format: 'register',
|
||||||
}).then(function() {
|
map: Object.keys(window.__karma__.files)
|
||||||
|
.filter(onlyAppFiles)
|
||||||
|
// Create local module name mapping to karma file path for app files
|
||||||
|
// with karma's fingerprint in query string, e.g.:
|
||||||
|
// './hero.service': '/base/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e'
|
||||||
|
.reduce(function (pathsMapping, appPath) {
|
||||||
|
var moduleName = appPath.replace(appRootRe, './').replace(/\.js$/, '');
|
||||||
|
pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath];
|
||||||
|
return pathsMapping;
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
|
||||||
|
System.config({ packages: packages });
|
||||||
|
|
||||||
|
// Configure Angular for the browser and
|
||||||
|
// with test versions of the platform providers
|
||||||
|
System.import('angular2/testing')
|
||||||
|
.then(function (testing) {
|
||||||
|
return System.import('angular2/platform/testing/browser')
|
||||||
|
.then(function (providers) {
|
||||||
|
testing.setBaseTestProviders(
|
||||||
|
providers.TEST_BROWSER_PLATFORM_PROVIDERS,
|
||||||
|
providers.TEST_BROWSER_APPLICATION_PROVIDERS
|
||||||
|
);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
// Load all spec files
|
||||||
|
// (e.g. 'base/app/hero.service.spec.js')
|
||||||
|
.then(function () {
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
Object.keys(window.__karma__.files) // All files served by Karma.
|
Object.keys(window.__karma__.files)
|
||||||
.filter(onlySpecFiles)
|
.filter(onlySpecFiles)
|
||||||
// .map(filePath2moduleName) // Normalize paths to module names.
|
.map(function (moduleName) {
|
||||||
.map(function(moduleName) {
|
moduleNames.push(moduleName);
|
||||||
// loads all spec files via their global module names (e.g. 'base/src/app/hero.service.spec')
|
return System.import(moduleName);
|
||||||
return System.import(moduleName);
|
}));
|
||||||
}));
|
|
||||||
})
|
})
|
||||||
.then(function() {
|
|
||||||
__karma__.start();
|
|
||||||
}, function(error) {
|
|
||||||
__karma__.error(error.stack || error);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
.then(success, fail);
|
||||||
|
|
||||||
function filePath2moduleName(filePath) {
|
////// Helpers //////
|
||||||
return filePath.
|
|
||||||
replace(/^\//, ''). // remove / prefix
|
|
||||||
replace(/\.\w+$/, ''); // remove suffix
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function onlyAppFiles(filePath) {
|
function onlyAppFiles(filePath) {
|
||||||
return /^\/base\/app\/.*\.js$/.test(filePath) && !onlySpecFiles(filePath);
|
return onlyAppFilesRe.test(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function onlySpecFiles(filePath) {
|
function onlySpecFiles(filePath) {
|
||||||
return /\.spec\.js$/.test(filePath);
|
return /\.spec\.js$/.test(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function success () {
|
||||||
|
console.log(
|
||||||
|
'Spec files loaded:\n ' +
|
||||||
|
moduleNames.join('\n ') +
|
||||||
|
'\nStarting Jasmine testrunner');
|
||||||
|
__karma__.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
function fail(error) {
|
||||||
|
__karma__.error(error.stack || error);
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
||||||
|
@ -1,43 +1,82 @@
|
|||||||
module.exports = function(config) {
|
module.exports = function(config) {
|
||||||
|
|
||||||
|
var appBase = 'app/'; // transpiled app JS files
|
||||||
|
var appAssets ='base/app/'; // component assets fetched by Angular's compiler
|
||||||
|
|
||||||
config.set({
|
config.set({
|
||||||
|
|
||||||
basePath: '',
|
basePath: '',
|
||||||
|
|
||||||
frameworks: ['jasmine'],
|
frameworks: ['jasmine'],
|
||||||
|
plugins: [
|
||||||
files: [
|
require('karma-jasmine'),
|
||||||
// paths loaded by Karma
|
require('karma-chrome-launcher'),
|
||||||
{pattern: 'node_modules/systemjs/dist/system.src.js', included: true, watched: true},
|
require('karma-htmlfile-reporter')
|
||||||
{pattern: 'node_modules/angular2/bundles/angular2.js', included: true, watched: true},
|
|
||||||
{pattern: 'node_modules/angular2/bundles/testing.js', included: true, watched: true},
|
|
||||||
{pattern: 'karma-test-shim.js', included: true, watched: true},
|
|
||||||
{pattern: 'app/test/*.js', included: true, watched: true},
|
|
||||||
|
|
||||||
// paths loaded via module imports
|
|
||||||
{pattern: 'app/**/*.js', included: false, watched: true},
|
|
||||||
|
|
||||||
// paths loaded via Angular's component compiler
|
|
||||||
// (these paths need to be rewritten, see proxies section)
|
|
||||||
{pattern: 'app/**/*.html', included: false, watched: true},
|
|
||||||
{pattern: 'app/**/*.css', included: false, watched: true},
|
|
||||||
|
|
||||||
// paths to support debugging with source maps in dev tools
|
|
||||||
{pattern: 'app/**/*.ts', included: false, watched: false},
|
|
||||||
{pattern: 'app/**/*.js.map', included: false, watched: false}
|
|
||||||
],
|
],
|
||||||
|
|
||||||
// proxied base paths
|
customLaunchers: {
|
||||||
proxies: {
|
// From the CLI. Not used here but interesting
|
||||||
// required for component assests fetched by Angular's compiler
|
// chrome setup for travis CI using chromium
|
||||||
"/app/": "/base/app/"
|
Chrome_travis_ci: {
|
||||||
|
base: 'Chrome',
|
||||||
|
flags: ['--no-sandbox']
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
reporters: ['progress'],
|
files: [
|
||||||
port: 9877,
|
// Angular and shim libraries loaded by Karma
|
||||||
|
{ pattern: 'node_modules/systemjs/dist/system-polyfills.js', included: true, watched: true },
|
||||||
|
{ pattern: 'node_modules/systemjs/dist/system.src.js', included: true, watched: true },
|
||||||
|
{ pattern: 'node_modules/es6-shim/es6-shim.js', included: true, watched: true },
|
||||||
|
{ pattern: 'node_modules/angular2/bundles/angular2-polyfills.js', included: true, watched: true },
|
||||||
|
{ pattern: 'node_modules/rxjs/bundles/Rx.js', included: true, watched: true },
|
||||||
|
{ pattern: 'node_modules/angular2/bundles/angular2.js', included: true, watched: true },
|
||||||
|
{ pattern: 'node_modules/angular2/bundles/testing.dev.js', included: true, watched: true },
|
||||||
|
|
||||||
|
// External libraries loaded by Karma
|
||||||
|
{ pattern: 'node_modules/angular2/bundles/http.dev.js', included: true, watched: true },
|
||||||
|
{ pattern: 'node_modules/angular2/bundles/router.dev.js', included: true, watched: true },
|
||||||
|
{ pattern: 'node_modules/a2-in-memory-web-api/web-api.js', included: true, watched: true },
|
||||||
|
|
||||||
|
// Configures module loader w/ app and specs, then launch karma
|
||||||
|
{ pattern: 'karma-test-shim.js', included: true, watched: true },
|
||||||
|
|
||||||
|
// transpiled application & spec code paths loaded via module imports
|
||||||
|
{pattern: appBase + '**/*.js', included: false, watched: true},
|
||||||
|
|
||||||
|
// asset (HTML & CSS) paths loaded via Angular's component compiler
|
||||||
|
// (these paths need to be rewritten, see proxies section)
|
||||||
|
{pattern: appBase + '**/*.html', included: false, watched: true},
|
||||||
|
{pattern: appBase + '**/*.css', included: false, watched: true},
|
||||||
|
|
||||||
|
// paths for debugging with source maps in dev tools
|
||||||
|
{pattern: appBase + '**/*.ts', included: false, watched: false},
|
||||||
|
{pattern: appBase + '**/*.js.map', included: false, watched: false}
|
||||||
|
],
|
||||||
|
|
||||||
|
// proxied base paths for loading assets
|
||||||
|
proxies: {
|
||||||
|
// required for component assets fetched by Angular's compiler
|
||||||
|
"/app/": appAssets
|
||||||
|
},
|
||||||
|
|
||||||
|
exclude: [],
|
||||||
|
preprocessors: {},
|
||||||
|
reporters: ['progress', 'html'],
|
||||||
|
|
||||||
|
// HtmlReporter configuration
|
||||||
|
htmlReporter: {
|
||||||
|
// Open this file to see results in browser
|
||||||
|
outputFile: '_test-output/tests.html',
|
||||||
|
|
||||||
|
// Optional
|
||||||
|
pageTitle: 'Unit Tests',
|
||||||
|
subPageTitle: __dirname
|
||||||
|
},
|
||||||
|
|
||||||
|
port: 9876,
|
||||||
colors: true,
|
colors: true,
|
||||||
logLevel: config.LOG_INFO,
|
logLevel: config.LOG_INFO,
|
||||||
autoWatch: true,
|
autoWatch: true,
|
||||||
browsers: ['Chrome'],
|
browsers: ['Chrome'],
|
||||||
singleRun: true
|
singleRun: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
// Karma configuration
|
|
||||||
// Generated on Mon Aug 10 2015 11:36:40 GMT-0700 (Pacific Daylight Time)
|
|
||||||
|
|
||||||
module.exports = function(config) {
|
|
||||||
config.set({
|
|
||||||
|
|
||||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
|
||||||
basePath: '',
|
|
||||||
|
|
||||||
|
|
||||||
// frameworks to use
|
|
||||||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
|
||||||
frameworks: ['jasmine'],
|
|
||||||
|
|
||||||
|
|
||||||
// list of files / patterns to load in the browser
|
|
||||||
files: [
|
|
||||||
{ pattern: 'https://code.angularjs.org/2.0.0-alpha.34/angular2.sfx.dev.js', watched: false },
|
|
||||||
|
|
||||||
'**/js/*.js',
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
// list of files to exclude
|
|
||||||
exclude: [
|
|
||||||
'**/*.e2e-spec.js'
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
// preprocess matching files before serving them to the browser
|
|
||||||
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
|
||||||
preprocessors: {
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
// test results reporter to use
|
|
||||||
// possible values: 'dots', 'progress'
|
|
||||||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
|
||||||
reporters: ['progress'],
|
|
||||||
|
|
||||||
|
|
||||||
// web server port
|
|
||||||
port: 9876,
|
|
||||||
|
|
||||||
|
|
||||||
// enable / disable colors in the output (reporters and logs)
|
|
||||||
colors: true,
|
|
||||||
|
|
||||||
|
|
||||||
// level of logging
|
|
||||||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
|
||||||
logLevel: config.LOG_INFO,
|
|
||||||
|
|
||||||
|
|
||||||
// enable / disable watching file and executing tests whenever any file changes
|
|
||||||
autoWatch: true,
|
|
||||||
|
|
||||||
|
|
||||||
// start these browsers
|
|
||||||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
|
|
||||||
|
|
||||||
// Continuous Integration mode
|
|
||||||
// if true, Karma captures browsers, runs the tests and exits
|
|
||||||
singleRun: false
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
// Karma configuration
|
|
||||||
// Generated on Mon Aug 10 2015 11:36:40 GMT-0700 (Pacific Daylight Time)
|
|
||||||
|
|
||||||
module.exports = function(config) {
|
|
||||||
config.set({
|
|
||||||
|
|
||||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
|
||||||
basePath: '',
|
|
||||||
|
|
||||||
|
|
||||||
// frameworks to use
|
|
||||||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
|
||||||
frameworks: ['jasmine'],
|
|
||||||
|
|
||||||
|
|
||||||
// list of files / patterns to load in the browser
|
|
||||||
files: [
|
|
||||||
{ pattern: 'https://github.jspm.io/jmcriffey/bower-traceur-runtime@0.0.87/traceur-runtime.js', watched: false },
|
|
||||||
{ pattern: 'https://jspm.io/system@0.16.js', watched: false },
|
|
||||||
{ pattern: 'https://code.angularjs.org/2.0.0-alpha.34/angular2.dev.js', watched: false },
|
|
||||||
|
|
||||||
'**/ts/**/*.spec.js'
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
// list of files to exclude
|
|
||||||
exclude: [
|
|
||||||
'**/*.e2e-spec.js'
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
// preprocess matching files before serving them to the browser
|
|
||||||
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
|
||||||
preprocessors: {
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
// test results reporter to use
|
|
||||||
// possible values: 'dots', 'progress'
|
|
||||||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
|
||||||
reporters: ['progress'],
|
|
||||||
|
|
||||||
|
|
||||||
// web server port
|
|
||||||
port: 9876,
|
|
||||||
|
|
||||||
|
|
||||||
// enable / disable colors in the output (reporters and logs)
|
|
||||||
colors: true,
|
|
||||||
|
|
||||||
|
|
||||||
// level of logging
|
|
||||||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
|
||||||
logLevel: config.LOG_INFO,
|
|
||||||
|
|
||||||
|
|
||||||
// enable / disable watching file and executing tests whenever any file changes
|
|
||||||
autoWatch: true,
|
|
||||||
|
|
||||||
|
|
||||||
// start these browsers
|
|
||||||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
|
|
||||||
|
|
||||||
// Continuous Integration mode
|
|
||||||
// if true, Karma captures browsers, runs the tests and exits
|
|
||||||
singleRun: false
|
|
||||||
})
|
|
||||||
}
|
|
@ -4,12 +4,12 @@
|
|||||||
"description": "Master package.json, the superset of all dependencies for all of the _example package.json files.",
|
"description": "Master package.json, the superset of all dependencies for all of the _example package.json files.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\" ",
|
"start": "tsc && concurrently \"tsc -w\" \"lite-server\" ",
|
||||||
"tsc": "tsc",
|
"tsc": "tsc",
|
||||||
"tsc:w": "tsc -w",
|
"tsc:w": "tsc -w",
|
||||||
"lite": "lite-server",
|
"lite": "lite-server",
|
||||||
"live": "live-server",
|
"live": "live-server",
|
||||||
"test": "karma start karma.conf.js",
|
"test": "tsc && concurrently \"tsc -w\" \"karma start karma.conf.js\"",
|
||||||
"build-and-test": "npm run tsc && npm run test",
|
"build-and-test": "npm run tsc && npm run test",
|
||||||
"http-server": "tsc && http-server",
|
"http-server": "tsc && http-server",
|
||||||
"http-server:e2e": "http-server",
|
"http-server:e2e": "http-server",
|
||||||
@ -42,6 +42,7 @@
|
|||||||
"karma": "^0.13.22",
|
"karma": "^0.13.22",
|
||||||
"karma-chrome-launcher": "^0.2.3",
|
"karma-chrome-launcher": "^0.2.3",
|
||||||
"karma-cli": "^0.1.2",
|
"karma-cli": "^0.1.2",
|
||||||
|
"karma-htmlfile-reporter": "^0.2.2",
|
||||||
"karma-jasmine": "^0.3.8",
|
"karma-jasmine": "^0.3.8",
|
||||||
"live-server": "^0.9.2",
|
"live-server": "^0.9.2",
|
||||||
"protractor": "^3.2.2",
|
"protractor": "^3.2.2",
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
exports.config = {
|
|
||||||
onPrepare: function() {
|
|
||||||
patchProtractorWait(browser);
|
|
||||||
},
|
|
||||||
seleniumAddress: 'http://localhost:4444/wd/hub',
|
|
||||||
baseUrl: 'http://localhost:8080/',
|
|
||||||
specs: [
|
|
||||||
'**/*e2e-spec.js'
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
// Disable waiting for Angular as we don't have an integration layer yet...
|
|
||||||
// TODO(tbosch): Implement a proper debugging API for Ng2.0, remove this here
|
|
||||||
// and the sleeps in all tests.
|
|
||||||
function patchProtractorWait(browser) {
|
|
||||||
browser.ignoreSynchronization = true;
|
|
||||||
var _get = browser.get;
|
|
||||||
var sleepInterval = process.env.TRAVIS || process.env.JENKINS_URL ? 14000 : 8000;
|
|
||||||
browser.get = function() {
|
|
||||||
var result = _get.apply(this, arguments);
|
|
||||||
browser.sleep(sleepInterval);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
// #docregion
|
// #docregion
|
||||||
import {Injectable} from 'angular2/core';
|
import {Injectable} from 'angular2/core';
|
||||||
import {Http, Response} from 'angular2/http';
|
import {Http} from 'angular2/http';
|
||||||
import {Headers, RequestOptions} from 'angular2/http';
|
import {Headers, RequestOptions} from 'angular2/http';
|
||||||
import {Hero} from './hero';
|
import {Hero} from './hero';
|
||||||
|
|
||||||
@ -32,13 +32,13 @@ export class HeroService {
|
|||||||
.then(res => <Hero> res.json().data)
|
.then(res => <Hero> res.json().data)
|
||||||
.catch(this.handleError);
|
.catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleError (error: any) {
|
private handleError (error: any) {
|
||||||
// in a real world app, we may send the error to some remote logging infrastructure
|
// in a real world app, we may send the error to some remote logging infrastructure
|
||||||
// instead of just logging it to the console
|
console.error(error); // log to console instead
|
||||||
console.error(error);
|
let errMsg = error.message || 'Server error';
|
||||||
return Promise.reject(error.message || error.json().error || 'Server error');
|
return Promise.reject(errMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #enddocregion methods
|
// #enddocregion methods
|
||||||
}
|
}
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
// #docregion v1
|
// #docregion v1
|
||||||
import {Injectable} from 'angular2/core';
|
import {Injectable} from 'angular2/core';
|
||||||
import {Http, Response} from 'angular2/http';
|
import {Http} from 'angular2/http';
|
||||||
// #enddocregion v1
|
// #enddocregion v1
|
||||||
// #docregion import-request-options
|
// #docregion import-request-options
|
||||||
import {Headers, RequestOptions} from 'angular2/http';
|
import {Headers, RequestOptions} from 'angular2/http';
|
||||||
@ -32,10 +32,10 @@ export class HeroService {
|
|||||||
|
|
||||||
// #docregion methods
|
// #docregion methods
|
||||||
// #docregion error-handling
|
// #docregion error-handling
|
||||||
getHeroes () {
|
getHeroes (): Observable<Hero[]> {
|
||||||
// #docregion http-get, http-get-v1
|
// #docregion http-get, http-get-v1
|
||||||
return this.http.get(this._heroesUrl)
|
return this.http.get(this._heroesUrl)
|
||||||
.map(res => <Hero[]> res.json().data)
|
.map(this.extractData)
|
||||||
// #enddocregion v1, http-get-v1, error-handling
|
// #enddocregion v1, http-get-v1, error-handling
|
||||||
.do(data => console.log(data)) // eyeball results in the console
|
.do(data => console.log(data)) // eyeball results in the console
|
||||||
// #docregion v1, http-get-v1, error-handling
|
// #docregion v1, http-get-v1, error-handling
|
||||||
@ -46,27 +46,36 @@ export class HeroService {
|
|||||||
// #enddocregion v1
|
// #enddocregion v1
|
||||||
|
|
||||||
// #docregion addhero
|
// #docregion addhero
|
||||||
addHero (name: string) : Observable<Hero> {
|
addHero (name: string): Observable<Hero> {
|
||||||
|
|
||||||
let body = JSON.stringify({ name });
|
let body = JSON.stringify({ name });
|
||||||
//#docregion headers
|
// #docregion headers
|
||||||
let headers = new Headers({ 'Content-Type': 'application/json' });
|
let headers = new Headers({ 'Content-Type': 'application/json' });
|
||||||
let options = new RequestOptions({ headers: headers });
|
let options = new RequestOptions({ headers: headers });
|
||||||
|
|
||||||
return this.http.post(this._heroesUrl, body, options)
|
return this.http.post(this._heroesUrl, body, options)
|
||||||
//#enddocregion headers
|
// #enddocregion headers
|
||||||
.map(res => <Hero> res.json().data)
|
.map(this.extractData)
|
||||||
.catch(this.handleError)
|
.catch(this.handleError);
|
||||||
}
|
}
|
||||||
// #enddocregion addhero
|
// #enddocregion addhero
|
||||||
|
|
||||||
// #docregion v1
|
// #docregion v1
|
||||||
|
|
||||||
|
private extractData(res: Response) {
|
||||||
|
if (res.status < 200 || res.status >= 300) {
|
||||||
|
throw new Error('Bad response status: ' + res.status);
|
||||||
|
}
|
||||||
|
let body = res.json();
|
||||||
|
return body.data || { };
|
||||||
|
}
|
||||||
|
|
||||||
// #docregion error-handling
|
// #docregion error-handling
|
||||||
private handleError (error: Response) {
|
private handleError (error: any) {
|
||||||
// in a real world app, we may send the error to some remote logging infrastructure
|
// in a real world app, we may send the error to some remote logging infrastructure
|
||||||
// instead of just logging it to the console
|
console.error(error); // log to console instead
|
||||||
console.error(error);
|
let errMsg = error.message || 'Server error';
|
||||||
return Observable.throw(error.json().error || 'Server error');
|
return Observable.throw(errMsg);
|
||||||
}
|
}
|
||||||
// #enddocregion error-handling
|
// #enddocregion error-handling
|
||||||
// #enddocregion methods
|
// #enddocregion methods
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
export interface Hero {
|
export class Hero {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
148
public/docs/_examples/testing/ts/app/http-hero.service.spec.ts
Normal file
148
public/docs/_examples/testing/ts/app/http-hero.service.spec.ts
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
/* tslint:disable:no-unused-variable */
|
||||||
|
import {
|
||||||
|
it,
|
||||||
|
iit,
|
||||||
|
xit,
|
||||||
|
describe,
|
||||||
|
ddescribe,
|
||||||
|
xdescribe,
|
||||||
|
expect,
|
||||||
|
fakeAsync,
|
||||||
|
tick,
|
||||||
|
beforeEach,
|
||||||
|
inject,
|
||||||
|
injectAsync,
|
||||||
|
withProviders,
|
||||||
|
beforeEachProviders
|
||||||
|
} from 'angular2/testing';
|
||||||
|
|
||||||
|
import { provide } from 'angular2/core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
MockBackend,
|
||||||
|
MockConnection } from 'angular2/src/http/backends/mock_backend';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BaseRequestOptions,
|
||||||
|
ConnectionBackend,
|
||||||
|
Request,
|
||||||
|
RequestMethod,
|
||||||
|
RequestOptions,
|
||||||
|
Response,
|
||||||
|
ResponseOptions,
|
||||||
|
URLSearchParams,
|
||||||
|
HTTP_PROVIDERS,
|
||||||
|
XHRBackend,
|
||||||
|
Http} from 'angular2/http';
|
||||||
|
|
||||||
|
// Add all operators to Observable
|
||||||
|
import 'rxjs/Rx';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
|
||||||
|
import { Hero } from './hero';
|
||||||
|
import { HeroService } from './http-hero.service';
|
||||||
|
|
||||||
|
type HeroData = {id: string, name: string}
|
||||||
|
|
||||||
|
const makeHeroData = () => [
|
||||||
|
{ "id": "1", "name": "Windstorm" },
|
||||||
|
{ "id": "2", "name": "Bombasto" },
|
||||||
|
{ "id": "3", "name": "Magneta" },
|
||||||
|
{ "id": "4", "name": "Tornado" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// HeroService expects response data like {data: {the-data}}
|
||||||
|
const makeResponseData = (data: {}) => {return { data }; };
|
||||||
|
|
||||||
|
//////// SPECS /////////////
|
||||||
|
describe('Http-HeroService (mockBackend)', () => {
|
||||||
|
|
||||||
|
beforeEachProviders(() => [
|
||||||
|
HTTP_PROVIDERS,
|
||||||
|
provide(XHRBackend, {useClass: MockBackend})
|
||||||
|
]);
|
||||||
|
|
||||||
|
it('can instantiate service when inject service',
|
||||||
|
withProviders(() => [HeroService])
|
||||||
|
.inject([HeroService], (service: HeroService) => {
|
||||||
|
expect(service instanceof HeroService).toBe(true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('can instantiate service with "new"', inject([Http], (http: Http) => {
|
||||||
|
expect(http).not.toBeNull('http should be provided');
|
||||||
|
let service = new HeroService(http);
|
||||||
|
expect(service instanceof HeroService).toBe(true, 'new service should be ok');
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('can provide the mockBackend as XHRBackend',
|
||||||
|
inject([XHRBackend], (backend: MockBackend) => {
|
||||||
|
expect(backend).not.toBeNull('backend should be provided');
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('when getHeroes', () => {
|
||||||
|
let backend: MockBackend;
|
||||||
|
let service: HeroService;
|
||||||
|
let fakeHeroes: HeroData[];
|
||||||
|
let response: Response;
|
||||||
|
|
||||||
|
|
||||||
|
beforeEach(inject([Http, XHRBackend], (http: Http, be: MockBackend) => {
|
||||||
|
backend = be;
|
||||||
|
service = new HeroService(http);
|
||||||
|
fakeHeroes = makeHeroData();
|
||||||
|
let options = new ResponseOptions({status: 200, body: {data: fakeHeroes}});
|
||||||
|
response = new Response(options);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should have expected fake heroes (then)', injectAsync([], () => {
|
||||||
|
backend.connections.subscribe((c: MockConnection) => c.mockRespond(response));
|
||||||
|
|
||||||
|
return service.getHeroes().toPromise()
|
||||||
|
// .then(() => Promise.reject('deliberate'))
|
||||||
|
.then(heroes => {
|
||||||
|
expect(heroes.length).toEqual(fakeHeroes.length,
|
||||||
|
'should have expected no. of heroes');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should have expected fake heroes (Observable.do)', injectAsync([], () => {
|
||||||
|
backend.connections.subscribe((c: MockConnection) => c.mockRespond(response));
|
||||||
|
|
||||||
|
return service.getHeroes()
|
||||||
|
.do(heroes => {
|
||||||
|
expect(heroes.length).toEqual(fakeHeroes.length,
|
||||||
|
'should have expected no. of heroes');
|
||||||
|
})
|
||||||
|
.toPromise();
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should be OK returning no heroes', injectAsync([], () => {
|
||||||
|
let resp = new Response(new ResponseOptions({status: 200, body: {data: []}}));
|
||||||
|
backend.connections.subscribe((c: MockConnection) => c.mockRespond(resp));
|
||||||
|
|
||||||
|
return service.getHeroes()
|
||||||
|
.do(heroes => {
|
||||||
|
expect(heroes.length).toEqual(0, 'should have no heroes');
|
||||||
|
})
|
||||||
|
.toPromise();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should treat 404 as an Observable error', injectAsync([], () => {
|
||||||
|
let resp = new Response(new ResponseOptions({status: 404}));
|
||||||
|
backend.connections.subscribe((c: MockConnection) => c.mockRespond(resp));
|
||||||
|
|
||||||
|
return service.getHeroes()
|
||||||
|
.do(heroes => {
|
||||||
|
fail('should not respond with heroes');
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
expect(err).toMatch(/Bad response status/, 'should catch bad response status code');
|
||||||
|
return Observable.of(null); // failure is the expected test result
|
||||||
|
})
|
||||||
|
.toPromise();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
44
public/docs/_examples/testing/ts/app/http-hero.service.ts
Normal file
44
public/docs/_examples/testing/ts/app/http-hero.service.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// #docplaster
|
||||||
|
// #docregion
|
||||||
|
import {Injectable} from 'angular2/core';
|
||||||
|
import {Http, Response} from 'angular2/http';
|
||||||
|
import {Headers, RequestOptions} from 'angular2/http';
|
||||||
|
import {Hero} from './hero';
|
||||||
|
import {Observable} from 'rxjs/Observable';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class HeroService {
|
||||||
|
constructor (private http: Http) {}
|
||||||
|
private _heroesUrl = 'app/heroes'; // URL to web api
|
||||||
|
getHeroes (): Observable<Hero[]> {
|
||||||
|
return this.http.get(this._heroesUrl)
|
||||||
|
.map(this.extractData)
|
||||||
|
// .do(data => console.log(data)) // eyeball results in the console
|
||||||
|
.catch(this.handleError);
|
||||||
|
}
|
||||||
|
|
||||||
|
addHero (name: string): Observable<Hero> {
|
||||||
|
let body = JSON.stringify({ name });
|
||||||
|
let headers = new Headers({ 'Content-Type': 'application/json' });
|
||||||
|
let options = new RequestOptions({ headers: headers });
|
||||||
|
|
||||||
|
return this.http.post(this._heroesUrl, body, options)
|
||||||
|
.map(this.extractData)
|
||||||
|
.catch(this.handleError);
|
||||||
|
}
|
||||||
|
|
||||||
|
private extractData(res: Response) {
|
||||||
|
if (res.status < 200 || res.status >= 300) {
|
||||||
|
throw new Error('Bad response status: ' + res.status);
|
||||||
|
}
|
||||||
|
let body = res.json();
|
||||||
|
return body.data || { };
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleError (error: any) {
|
||||||
|
// in a real world app, we may send the error to some remote logging infrastructure
|
||||||
|
let errMsg = error.message || 'Server error';
|
||||||
|
console.error(errMsg); // log to console instead
|
||||||
|
return Observable.throw(errMsg);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
<span>from external template</span>
|
458
public/docs/_examples/testing/ts/app/public.spec.ts
Normal file
458
public/docs/_examples/testing/ts/app/public.spec.ts
Normal file
@ -0,0 +1,458 @@
|
|||||||
|
// Based on https://github.com/angular/angular/blob/master/modules/angular2/test/testing/testing_public_spec.ts
|
||||||
|
/* tslint:disable:no-unused-variable */
|
||||||
|
import {
|
||||||
|
BadTemplateUrl, ButtonComp,
|
||||||
|
ChildChildComp, ChildComp, ChildWithChildComp,
|
||||||
|
ExternalTemplateComp,
|
||||||
|
FancyService, MockFancyService,
|
||||||
|
MyIfComp,
|
||||||
|
MockChildComp, MockChildChildComp,
|
||||||
|
ParentComp,
|
||||||
|
TestProvidersComp, TestViewProvidersComp
|
||||||
|
} from './public';
|
||||||
|
|
||||||
|
import {
|
||||||
|
it,
|
||||||
|
iit,
|
||||||
|
xit,
|
||||||
|
describe,
|
||||||
|
ddescribe,
|
||||||
|
xdescribe,
|
||||||
|
expect,
|
||||||
|
fakeAsync,
|
||||||
|
tick,
|
||||||
|
beforeEach,
|
||||||
|
inject,
|
||||||
|
injectAsync,
|
||||||
|
withProviders,
|
||||||
|
beforeEachProviders,
|
||||||
|
TestComponentBuilder
|
||||||
|
} from 'angular2/testing';
|
||||||
|
|
||||||
|
import { provide } from 'angular2/core';
|
||||||
|
import { ViewMetadata } from 'angular2/core';
|
||||||
|
import { PromiseWrapper } from 'angular2/src/facade/promise';
|
||||||
|
import { XHR } from 'angular2/src/compiler/xhr';
|
||||||
|
import { XHRImpl } from 'angular2/src/platform/browser/xhr_impl';
|
||||||
|
|
||||||
|
/////////// Module Preparation ///////////////////////
|
||||||
|
interface Done {
|
||||||
|
(): void;
|
||||||
|
fail: (err: any) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////// SPECS /////////////
|
||||||
|
|
||||||
|
/// Verify can use Angular testing's DOM abstraction to access DOM
|
||||||
|
|
||||||
|
describe('angular2 jasmine matchers', () => {
|
||||||
|
describe('toHaveCssClass', () => {
|
||||||
|
it('should assert that the CSS class is present', () => {
|
||||||
|
let el = document.createElement('div');
|
||||||
|
el.classList.add('matias');
|
||||||
|
expect(el).toHaveCssClass('matias');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should assert that the CSS class is not present', () => {
|
||||||
|
let el = document.createElement('div');
|
||||||
|
el.classList.add('matias');
|
||||||
|
expect(el).not.toHaveCssClass('fatias');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('toHaveCssStyle', () => {
|
||||||
|
it('should assert that the CSS style is present', () => {
|
||||||
|
let el = document.createElement('div');
|
||||||
|
expect(el).not.toHaveCssStyle('width');
|
||||||
|
|
||||||
|
el.style.setProperty('width', '100px');
|
||||||
|
expect(el).toHaveCssStyle('width');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should assert that the styles are matched against the element', () => {
|
||||||
|
let el = document.createElement('div');
|
||||||
|
expect(el).not.toHaveCssStyle({width: '100px', height: '555px'});
|
||||||
|
|
||||||
|
el.style.setProperty('width', '100px');
|
||||||
|
expect(el).toHaveCssStyle({width: '100px'});
|
||||||
|
expect(el).not.toHaveCssStyle({width: '100px', height: '555px'});
|
||||||
|
|
||||||
|
el.style.setProperty('height', '555px');
|
||||||
|
expect(el).toHaveCssStyle({height: '555px'});
|
||||||
|
expect(el).toHaveCssStyle({width: '100px', height: '555px'});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('using the test injector with the inject helper', () => {
|
||||||
|
it('should run normal tests', () => { expect(true).toEqual(true); });
|
||||||
|
|
||||||
|
it('should run normal async tests', (done: Done) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(true).toEqual(true);
|
||||||
|
done();
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('provides a real XHR instance',
|
||||||
|
inject([XHR], (xhr: any) => { expect(xhr).toBeAnInstanceOf(XHRImpl); }));
|
||||||
|
|
||||||
|
describe('setting up Providers with FancyService', () => {
|
||||||
|
beforeEachProviders(() => [
|
||||||
|
provide(FancyService, {useValue: new FancyService()})
|
||||||
|
]);
|
||||||
|
|
||||||
|
it('should use FancyService',
|
||||||
|
inject([FancyService], (service: FancyService) => {
|
||||||
|
expect(service.value).toEqual('real value');
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('test should wait for FancyService.getAsyncValue',
|
||||||
|
injectAsync([FancyService], (service: FancyService) => {
|
||||||
|
return service.getAsyncValue().then(
|
||||||
|
(value) => { expect(value).toEqual('async value'); });
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Experimental: write async tests synchonously by faking async processing
|
||||||
|
it('should allow the use of fakeAsync (Experimental)',
|
||||||
|
inject([FancyService], fakeAsync((service: FancyService) => {
|
||||||
|
let value: any;
|
||||||
|
service.getAsyncValue().then((val: any) => value = val);
|
||||||
|
tick(); // Trigger JS engine cycle until all promises resolve.
|
||||||
|
expect(value).toEqual('async value');
|
||||||
|
})));
|
||||||
|
|
||||||
|
describe('using inner beforeEach to inject-and-modify FancyService', () => {
|
||||||
|
beforeEach(inject([FancyService], (service: FancyService) => {
|
||||||
|
service.value = 'value modified in beforeEach';
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should use modified providers',
|
||||||
|
inject([FancyService], (service: FancyService) => {
|
||||||
|
expect(service.value).toEqual('value modified in beforeEach');
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('using async within beforeEach', () => {
|
||||||
|
beforeEach(injectAsync([FancyService], (service: FancyService) => {
|
||||||
|
return service.getAsyncValue().then(value => { service.value = value; });
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should use asynchronously modified value ... in synchronous test',
|
||||||
|
inject([FancyService], (service: FancyService) => {
|
||||||
|
expect(service.value).toEqual('async value'); }));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('using `withProviders` for per-test provision', () => {
|
||||||
|
it('should inject test-local FancyService for this test',
|
||||||
|
// `withProviders`: set up providers at individual test level
|
||||||
|
withProviders(() => [provide(FancyService, {useValue: {value: 'fake value'}})])
|
||||||
|
|
||||||
|
// now inject and test
|
||||||
|
.inject([FancyService], (service: FancyService) => {
|
||||||
|
expect(service.value).toEqual('fake value');
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('test component builder', function() {
|
||||||
|
it('should instantiate a component with valid DOM',
|
||||||
|
injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
|
|
||||||
|
return tcb.createAsync(ChildComp).then(fixture => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('Original Child');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should allow changing members of the component',
|
||||||
|
injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
|
|
||||||
|
return tcb.createAsync(MyIfComp).then(fixture => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('MyIf()');
|
||||||
|
|
||||||
|
fixture.debugElement.componentInstance.showMore = true;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('MyIf(More)');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should support clicking a button',
|
||||||
|
injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
|
|
||||||
|
return tcb.createAsync(ButtonComp).then(fixture => {
|
||||||
|
|
||||||
|
let comp = <ButtonComp> fixture.componentInstance;
|
||||||
|
expect(comp.wasClicked).toEqual(false, 'wasClicked should be false at start');
|
||||||
|
|
||||||
|
let btn = fixture.debugElement.query(el => el.name === 'button');
|
||||||
|
btn.triggerEventHandler('click', null);
|
||||||
|
// btn.nativeElement.click(); // this works too; which is "better"?
|
||||||
|
expect(comp.wasClicked).toEqual(true, 'wasClicked should be true after click');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should override a template',
|
||||||
|
injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
|
|
||||||
|
return tcb.overrideTemplate(MockChildComp, '<span>Mock</span>')
|
||||||
|
.createAsync(MockChildComp)
|
||||||
|
.then(fixture => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('Mock');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should override a view',
|
||||||
|
injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
|
|
||||||
|
return tcb.overrideView(
|
||||||
|
ChildComp,
|
||||||
|
new ViewMetadata({template: '<span>Modified {{childBinding}}</span>'})
|
||||||
|
)
|
||||||
|
.createAsync(ChildComp)
|
||||||
|
.then(fixture => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('Modified Child');
|
||||||
|
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should override component dependencies',
|
||||||
|
injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
|
|
||||||
|
return tcb.overrideDirective(ParentComp, ChildComp, MockChildComp)
|
||||||
|
.createAsync(ParentComp)
|
||||||
|
.then(fixture => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('Parent(Mock)');
|
||||||
|
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should override child component\'s dependencies',
|
||||||
|
injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
|
|
||||||
|
return tcb.overrideDirective(ParentComp, ChildComp, ChildWithChildComp)
|
||||||
|
.overrideDirective(ChildWithChildComp, ChildChildComp, MockChildChildComp)
|
||||||
|
.createAsync(ParentComp)
|
||||||
|
.then(fixture => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement)
|
||||||
|
.toHaveText('Parent(Original Child(ChildChild Mock))');
|
||||||
|
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should override a provider',
|
||||||
|
injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
|
|
||||||
|
return tcb.overrideProviders(
|
||||||
|
TestProvidersComp,
|
||||||
|
[provide(FancyService, {useClass: MockFancyService})]
|
||||||
|
)
|
||||||
|
.createAsync(TestProvidersComp)
|
||||||
|
.then(fixture => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement)
|
||||||
|
.toHaveText('injected value: mocked out value');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should override a viewProvider',
|
||||||
|
injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
|
|
||||||
|
return tcb.overrideViewProviders(
|
||||||
|
TestViewProvidersComp,
|
||||||
|
[provide(FancyService, {useClass: MockFancyService})]
|
||||||
|
)
|
||||||
|
.createAsync(TestViewProvidersComp)
|
||||||
|
.then(fixture => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement)
|
||||||
|
.toHaveText('injected value: mocked out value');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should allow an external templateUrl',
|
||||||
|
injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
|
|
||||||
|
return tcb.createAsync(ExternalTemplateComp)
|
||||||
|
.then(fixture => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement)
|
||||||
|
.toHaveText('from external template\n');
|
||||||
|
});
|
||||||
|
}), 10000); // Long timeout because this test makes an actual XHR.
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('errors', () => {
|
||||||
|
let originalJasmineIt: any;
|
||||||
|
let originalJasmineBeforeEach: any;
|
||||||
|
|
||||||
|
let patchJasmineIt = () => {
|
||||||
|
let deferred = PromiseWrapper.completer();
|
||||||
|
originalJasmineIt = jasmine.getEnv().it;
|
||||||
|
jasmine.getEnv().it = (description: string, fn: Function) => {
|
||||||
|
let done = () => { deferred.resolve(); };
|
||||||
|
(<any>done).fail = (err: any) => { deferred.reject(err); };
|
||||||
|
fn(done);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
return deferred.promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
let restoreJasmineIt = () => { jasmine.getEnv().it = originalJasmineIt; };
|
||||||
|
|
||||||
|
let patchJasmineBeforeEach = () => {
|
||||||
|
let deferred = PromiseWrapper.completer();
|
||||||
|
originalJasmineBeforeEach = jasmine.getEnv().beforeEach;
|
||||||
|
jasmine.getEnv().beforeEach = (fn: any) => {
|
||||||
|
let done = () => { deferred.resolve(); };
|
||||||
|
(<any>done).fail = (err: any) => { deferred.reject(err); };
|
||||||
|
fn(done);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
return deferred.promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
let restoreJasmineBeforeEach =
|
||||||
|
() => { jasmine.getEnv().beforeEach = originalJasmineBeforeEach; };
|
||||||
|
|
||||||
|
const shouldNotSucceed =
|
||||||
|
(done: Done) => () => done.fail( 'Expected function to throw, but it did not');
|
||||||
|
|
||||||
|
const shouldFail =
|
||||||
|
(done: Done, emsg: string) => (err: any) => { expect(err).toEqual(emsg); done(); };
|
||||||
|
|
||||||
|
it('injectAsync should fail when return was forgotten in it', (done: Done) => {
|
||||||
|
let itPromise = patchJasmineIt();
|
||||||
|
it('forgets to return a proimse', injectAsync([], () => { return true; }));
|
||||||
|
|
||||||
|
itPromise.then(
|
||||||
|
shouldNotSucceed(done),
|
||||||
|
shouldFail(done,
|
||||||
|
'Error: injectAsync was expected to return a promise, but the returned value was: true')
|
||||||
|
);
|
||||||
|
restoreJasmineIt();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('inject should fail if a value was returned', (done: Done) => {
|
||||||
|
let itPromise = patchJasmineIt();
|
||||||
|
it('returns a value', inject([], () => { return true; }));
|
||||||
|
|
||||||
|
itPromise.then(
|
||||||
|
shouldNotSucceed(done),
|
||||||
|
shouldFail(done,
|
||||||
|
'Error: inject returned a value. Did you mean to use injectAsync? Returned value was: true')
|
||||||
|
);
|
||||||
|
restoreJasmineIt();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('injectAsync should fail when return was forgotten in beforeEach', (done: Done) => {
|
||||||
|
let beforeEachPromise = patchJasmineBeforeEach();
|
||||||
|
beforeEach(injectAsync([], () => { return true; }));
|
||||||
|
|
||||||
|
beforeEachPromise.then(
|
||||||
|
shouldNotSucceed(done),
|
||||||
|
shouldFail(done,
|
||||||
|
'Error: injectAsync was expected to return a promise, but the returned value was: true')
|
||||||
|
);
|
||||||
|
restoreJasmineBeforeEach();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('inject should fail if a value was returned in beforeEach', (done: Done) => {
|
||||||
|
let beforeEachPromise = patchJasmineBeforeEach();
|
||||||
|
beforeEach(inject([], () => { return true; }));
|
||||||
|
|
||||||
|
beforeEachPromise.then(
|
||||||
|
shouldNotSucceed(done),
|
||||||
|
shouldFail(done,
|
||||||
|
'Error: inject returned a value. Did you mean to use injectAsync? Returned value was: true')
|
||||||
|
);
|
||||||
|
restoreJasmineBeforeEach();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail when an error occurs inside inject', (done: Done) => {
|
||||||
|
let itPromise = patchJasmineIt();
|
||||||
|
|
||||||
|
it('throws an error', inject([], () => { throw new Error('foo'); }));
|
||||||
|
|
||||||
|
itPromise.then(
|
||||||
|
shouldNotSucceed(done),
|
||||||
|
err => { expect(err.message).toEqual('foo'); done(); }
|
||||||
|
);
|
||||||
|
restoreJasmineIt();
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO(juliemr): reenable this test when we are using a test zone and can capture this error.
|
||||||
|
xit('should fail when an asynchronous error is thrown', (done: Done) => {
|
||||||
|
let itPromise = patchJasmineIt();
|
||||||
|
|
||||||
|
it('throws an async error',
|
||||||
|
injectAsync([], () => { setTimeout(() => { throw new Error('bar'); }, 0); }));
|
||||||
|
|
||||||
|
itPromise.then(
|
||||||
|
shouldNotSucceed(done),
|
||||||
|
err => { expect(err.message).toEqual('bar'); done(); }
|
||||||
|
);
|
||||||
|
restoreJasmineIt();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail when a returned promise is rejected', (done: Done) => {
|
||||||
|
let itPromise = patchJasmineIt();
|
||||||
|
|
||||||
|
it('should fail with an error from a promise', injectAsync([], () => {
|
||||||
|
let deferred = PromiseWrapper.completer();
|
||||||
|
let p = deferred.promise.then(() => { expect(1).toEqual(2); });
|
||||||
|
|
||||||
|
deferred.reject('baz');
|
||||||
|
return p;
|
||||||
|
}));
|
||||||
|
|
||||||
|
itPromise.then(
|
||||||
|
shouldNotSucceed(done),
|
||||||
|
shouldFail(done, 'baz')
|
||||||
|
);
|
||||||
|
restoreJasmineIt();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail when an XHR fails', (done: Done) => {
|
||||||
|
let itPromise = patchJasmineIt();
|
||||||
|
|
||||||
|
it('should fail with an error from a promise',
|
||||||
|
injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
|
return tcb.createAsync(BadTemplateUrl);
|
||||||
|
}));
|
||||||
|
|
||||||
|
itPromise.then(
|
||||||
|
shouldNotSucceed(done),
|
||||||
|
shouldFail(done, 'Failed to load non-existant.html')
|
||||||
|
);
|
||||||
|
restoreJasmineIt();
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
describe('using beforeEachProviders', () => {
|
||||||
|
beforeEachProviders(() => [provide(FancyService, {useValue: new FancyService()})]);
|
||||||
|
|
||||||
|
beforeEach(
|
||||||
|
inject([FancyService], (service: FancyService) => { expect(service.value).toEqual('real value'); }));
|
||||||
|
|
||||||
|
describe('nested beforeEachProviders', () => {
|
||||||
|
|
||||||
|
it('should fail when the injector has already been used', () => {
|
||||||
|
patchJasmineBeforeEach();
|
||||||
|
expect(() => {
|
||||||
|
beforeEachProviders(() => [provide(FancyService, {useValue: new FancyService()})]);
|
||||||
|
})
|
||||||
|
.toThrowError('beforeEachProviders was called after the injector had been used ' +
|
||||||
|
'in a beforeEach or it block. This invalidates the test injector');
|
||||||
|
restoreJasmineBeforeEach();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
133
public/docs/_examples/testing/ts/app/public.ts
Normal file
133
public/docs/_examples/testing/ts/app/public.ts
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
// Based on https://github.com/angular/angular/blob/master/modules/angular2/test/testing/testing_public_spec.ts
|
||||||
|
import { Component, Injectable } from 'angular2/core';
|
||||||
|
import { NgIf } from 'angular2/common';
|
||||||
|
|
||||||
|
// Let TypeScript know about the special SystemJS __moduleName variable
|
||||||
|
declare var __moduleName: string;
|
||||||
|
|
||||||
|
// moduleName is not set in some module loaders; set it explicitly
|
||||||
|
if (!__moduleName) {
|
||||||
|
__moduleName = `http://${location.host}/${location.pathname}/app/`;
|
||||||
|
}
|
||||||
|
// console.log(`The __moduleName is ${__moduleName} `);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////// The App: Services and Components for the tests. //////////////
|
||||||
|
|
||||||
|
////////// Services ///////////////
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class FancyService {
|
||||||
|
value: string = 'real value';
|
||||||
|
getAsyncValue() { return Promise.resolve('async value'); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MockFancyService extends FancyService {
|
||||||
|
value: string = 'mocked out value';
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////// Components /////////////
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'button-comp',
|
||||||
|
template: `<button (click)='clicked()'>Click me!</button>`
|
||||||
|
})
|
||||||
|
export class ButtonComp {
|
||||||
|
wasClicked = false;
|
||||||
|
clicked() { this.wasClicked = true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'child-comp',
|
||||||
|
template: `<span>Original {{childBinding}}</span>`
|
||||||
|
})
|
||||||
|
export class ChildComp {
|
||||||
|
childBinding = 'Child';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'child-comp',
|
||||||
|
template: `<span>Mock</span>`
|
||||||
|
})
|
||||||
|
export class MockChildComp { }
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'parent-comp',
|
||||||
|
template: `Parent(<child-comp></child-comp>)`,
|
||||||
|
directives: [ChildComp]
|
||||||
|
})
|
||||||
|
export class ParentComp { }
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-if-comp',
|
||||||
|
template: `MyIf(<span *ngIf="showMore">More</span>)`,
|
||||||
|
directives: [NgIf]
|
||||||
|
})
|
||||||
|
export class MyIfComp {
|
||||||
|
showMore: boolean = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'child-child-comp',
|
||||||
|
template: '<span>ChildChild</span>'
|
||||||
|
})
|
||||||
|
export class ChildChildComp { }
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'child-comp',
|
||||||
|
template: `<span>Original {{childBinding}}(<child-child-comp></child-child-comp>)</span>`,
|
||||||
|
directives: [ChildChildComp]
|
||||||
|
})
|
||||||
|
export class ChildWithChildComp {
|
||||||
|
childBinding = 'Child';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'child-child-comp',
|
||||||
|
template: `<span>ChildChild Mock</span>`
|
||||||
|
})
|
||||||
|
export class MockChildChildComp { }
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-service-comp',
|
||||||
|
template: `injected value: {{fancyService.value}}`,
|
||||||
|
providers: [FancyService]
|
||||||
|
})
|
||||||
|
export class TestProvidersComp {
|
||||||
|
constructor(private fancyService: FancyService) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-service-comp',
|
||||||
|
template: `injected value: {{fancyService.value}}`,
|
||||||
|
viewProviders: [FancyService]
|
||||||
|
})
|
||||||
|
export class TestViewProvidersComp {
|
||||||
|
constructor(private fancyService: FancyService) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
moduleId: __moduleName,
|
||||||
|
selector: 'external-template-comp',
|
||||||
|
templateUrl: 'public-external-template.html'
|
||||||
|
})
|
||||||
|
export class ExternalTemplateComp { }
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'bad-template-comp',
|
||||||
|
templateUrl: 'non-existant.html'
|
||||||
|
})
|
||||||
|
export class BadTemplateUrl { }
|
48
public/docs/_examples/testing/ts/test-shim.js
Normal file
48
public/docs/_examples/testing/ts/test-shim.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*global jasmine, __karma__, window*/
|
||||||
|
|
||||||
|
// Browser testing shim
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
// Error.stackTraceLimit = Infinity;
|
||||||
|
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
|
||||||
|
|
||||||
|
// Configure systemjs to use the .js extension for imports from the app folder
|
||||||
|
System.config({
|
||||||
|
packages: {
|
||||||
|
app: {
|
||||||
|
format: 'register',
|
||||||
|
defaultExtension: 'js'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configure Angular for the browser and with test versions of the platform providers
|
||||||
|
System.import('angular2/testing')
|
||||||
|
.then(function (testing) {
|
||||||
|
return System.import('angular2/platform/testing/browser')
|
||||||
|
.then(function (providers) {
|
||||||
|
testing.setBaseTestProviders(
|
||||||
|
providers.TEST_BROWSER_PLATFORM_PROVIDERS,
|
||||||
|
providers.TEST_BROWSER_APPLICATION_PROVIDERS
|
||||||
|
);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
// Load the spec files (__spec_files__) explicitly
|
||||||
|
.then(function () {
|
||||||
|
console.log('loading spec files: '+__spec_files__.join(', '));
|
||||||
|
return Promise.all(__spec_files__.map(function(spec) { return System.import(spec);} ));
|
||||||
|
})
|
||||||
|
|
||||||
|
// After all imports load, re-execute `window.onload` which
|
||||||
|
// triggers the Jasmine test-runner start or explain what went wrong
|
||||||
|
.then(success, console.error.bind(console));
|
||||||
|
|
||||||
|
function success () {
|
||||||
|
console.log('Spec files loaded; starting Jasmine testrunner');
|
||||||
|
window.onload();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
})();
|
32
public/docs/_examples/testing/ts/unit-tests-public.html
Normal file
32
public/docs/_examples/testing/ts/unit-tests-public.html
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<!-- #docregion -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
||||||
|
<title>Angular Public Unit Tests</title>
|
||||||
|
<link rel="stylesheet" href="node_modules/jasmine-core/lib/jasmine-core/jasmine.css">
|
||||||
|
|
||||||
|
<script src="node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
|
||||||
|
<script src="node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js"></script>
|
||||||
|
<script src="node_modules/jasmine-core/lib/jasmine-core/boot.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<script src="node_modules/es6-shim/es6-shim.min.js"></script>
|
||||||
|
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
|
||||||
|
<script src="node_modules/angular2/es6/dev/src/testing/shims_for_IE.js"></script>
|
||||||
|
|
||||||
|
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
|
||||||
|
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||||
|
<script src="node_modules/rxjs/bundles/Rx.js"></script>
|
||||||
|
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
|
||||||
|
|
||||||
|
<script src="node_modules/angular2/bundles/testing.dev.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var __spec_files__ = ['app/public.spec'];
|
||||||
|
</script>
|
||||||
|
<script src="test-shim.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
Loading…
x
Reference in New Issue
Block a user