Skip to content

Commit b128742

Browse files
Merge pull request #38 from angular/master
Update upstream
2 parents a217e47 + e58bcfa commit b128742

File tree

9 files changed

+172
-27
lines changed

9 files changed

+172
-27
lines changed

Gruntfile.js

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -358,24 +358,73 @@ module.exports = function(grunt) {
358358
});
359359

360360
//alias tasks
361-
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['eslint', 'package', 'test:unit', 'test:promises-aplus', 'tests:docs', 'test:protractor']);
361+
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', [
362+
'eslint',
363+
'package',
364+
'test:unit',
365+
'test:promises-aplus',
366+
'tests:docs',
367+
'test:protractor'
368+
]);
362369
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
363370
grunt.registerTask('test:jquery', 'Run the jQuery (latest) unit tests with Karma', ['tests:jquery']);
364371
grunt.registerTask('test:jquery-2.2', 'Run the jQuery 2.2 unit tests with Karma', ['tests:jquery-2.2']);
365372
grunt.registerTask('test:jquery-2.1', 'Run the jQuery 2.1 unit tests with Karma', ['tests:jquery-2.1']);
366-
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['build', 'tests:modules']);
373+
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', [
374+
'build',
375+
'tests:modules'
376+
]);
367377
grunt.registerTask('test:docs', 'Run the doc-page tests with Karma', ['package', 'tests:docs']);
368-
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['test:jqlite', 'test:jquery', 'test:jquery-2.2', 'test:jquery-2.1', 'test:modules']);
369-
grunt.registerTask('test:protractor', 'Run the end to end tests with Protractor and keep a test server running in the background', ['webdriver', 'connect:testserver', 'protractor:normal']);
370-
grunt.registerTask('test:travis-protractor', 'Run the end to end tests with Protractor for Travis CI builds', ['connect:testserver', 'protractor:travis']);
371-
grunt.registerTask('test:ci-protractor', 'Run the end to end tests with Protractor for Jenkins CI builds', ['webdriver', 'connect:testserver', 'protractor:jenkins']);
378+
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', [
379+
'test:jqlite',
380+
'test:jquery',
381+
'test:jquery-2.2',
382+
'test:jquery-2.1',
383+
'test:modules'
384+
]);
385+
grunt.registerTask('test:protractor', 'Run the end to end tests with Protractor and keep a test server running in the background', [
386+
'webdriver',
387+
'connect:testserver',
388+
'protractor:normal'
389+
]);
390+
grunt.registerTask('test:travis-protractor', 'Run the end to end tests with Protractor for Travis CI builds', [
391+
'connect:testserver',
392+
'protractor:travis'
393+
]);
394+
grunt.registerTask('test:ci-protractor', 'Run the end to end tests with Protractor for Jenkins CI builds', [
395+
'webdriver',
396+
'connect:testserver',
397+
'protractor:jenkins'
398+
]);
372399
grunt.registerTask('test:e2e', 'Alias for test:protractor', ['test:protractor']);
373-
grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter', 'shell:promises-aplus-tests']);
374-
375-
grunt.registerTask('minify', ['bower', 'clean', 'build', 'minall']);
400+
grunt.registerTask('test:promises-aplus',[
401+
'build:promises-aplus-adapter',
402+
'shell:promises-aplus-tests'
403+
]);
404+
grunt.registerTask('minify', [
405+
'bower',
406+
'clean',
407+
'build',
408+
'minall'
409+
]);
376410
grunt.registerTask('webserver', ['connect:devserver']);
377-
grunt.registerTask('package', ['bower', 'validate-angular-files', 'clean', 'buildall', 'minall', 'collect-errors', 'write', 'docs', 'copy', 'compress']);
378-
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'eslint']);
411+
grunt.registerTask('package', [
412+
'bower',
413+
'validate-angular-files',
414+
'clean',
415+
'buildall',
416+
'minall',
417+
'collect-errors',
418+
'write',
419+
'docs',
420+
'copy',
421+
'compress'
422+
]);
423+
grunt.registerTask('ci-checks', [
424+
'ddescribe-iit',
425+
'merge-conflict',
426+
'eslint'
427+
]);
379428
grunt.registerTask('default', ['package']);
380429
};
381430

karma-shared.conf.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,16 @@ module.exports = function(config, specificOptions) {
1010
browserDisconnectTimeout: 10000,
1111
browserDisconnectTolerance: 2,
1212
browserNoActivityTimeout: 30000,
13-
14-
13+
reporters: ['spec'],
14+
specReporter: {
15+
maxLogLines: 5, // limit number of lines logged per test
16+
suppressErrorSummary: true, // do not print error summary
17+
suppressFailed: false, // do not print information about failed tests
18+
suppressPassed: true, // do not print information about passed tests
19+
suppressSkipped: false, // do not print information about skipped tests
20+
showSpecTiming: false, // print the time elapsed for each spec
21+
failFast: false // test would finish with error when a first fail occurs.
22+
},
1523
// SauceLabs config for local development.
1624
sauceLabs: {
1725
testName: specificOptions.testName || 'AngularJS',

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"karma-ng-scenario": "^1.0.0",
7070
"karma-sauce-launcher": "^1.1.0",
7171
"karma-script-launcher": "^1.0.0",
72+
"karma-spec-reporter": "^0.0.31",
7273
"load-grunt-tasks": "^3.5.0",
7374
"lodash": "~2.4.1",
7475
"log4js": "^0.6.27",

scripts/travis/before_build.sh

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,26 @@ set -e
44

55
yarn global add [email protected]
66

7-
mkdir -p $LOGS_DIR
7+
mkdir -p "$LOGS_DIR"
88

9-
if [ $JOB != "ci-checks" ]; then
9+
if [ "$JOB" != "ci-checks" ]; then
1010
echo "start_browser_provider"
1111
./scripts/travis/start_browser_provider.sh
1212
fi
1313

14-
if [ $JOB != "ci-checks" ]; then
14+
# ci-checks and unit tests do not run against the packaged code
15+
if [ "$JOB" != "ci-checks" ] && [ "$JOB" != "unit" ]; then
1516
grunt package
17+
fi
18+
19+
# unit runs the docs tests too which need a built version of the code
20+
if [ "$JOB" = "unit" ]; then
21+
grunt build
22+
fi
23+
24+
# check this after the package, because at this point the browser_provider
25+
# has probably arrived
26+
if [ "$JOB" != "ci-checks" ]; then
1627
echo "wait_for_browser_provider"
1728
./scripts/travis/wait_for_browser_provider.sh
18-
fi
29+
fi

scripts/travis/build.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ elif [ "$JOB" == "unit" ]; then
1515
fi
1616

1717
grunt test:promises-aplus
18-
grunt test:unit --browsers="$BROWSERS" --reporters=dots
19-
grunt tests:docs --browsers="$BROWSERS" --reporters=dots
18+
grunt test:unit --browsers="$BROWSERS" --reporters=spec
19+
grunt tests:docs --browsers="$BROWSERS" --reporters=spec
2020
elif [ "$JOB" == "docs-e2e" ]; then
2121
grunt test:travis-protractor --specs="docs/app/e2e/**/*.scenario.js"
2222
elif [ "$JOB" == "e2e" ]; then

src/ng/parse.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,9 @@ function isStateless($filter, filterName) {
622622
return !fn.$stateful;
623623
}
624624

625+
var PURITY_ABSOLUTE = 1;
626+
var PURITY_RELATIVE = 2;
627+
625628
// Detect nodes which could depend on non-shallow state of objects
626629
function isPure(node, parentIsPure) {
627630
switch (node.type) {
@@ -634,18 +637,18 @@ function isPure(node, parentIsPure) {
634637

635638
// Unary always convert to primative
636639
case AST.UnaryExpression:
637-
return true;
640+
return PURITY_ABSOLUTE;
638641

639642
// The binary + operator can invoke a stateful toString().
640643
case AST.BinaryExpression:
641-
return node.operator !== '+';
644+
return node.operator !== '+' ? PURITY_ABSOLUTE : false;
642645

643646
// Functions / filters probably read state from within objects
644647
case AST.CallExpression:
645648
return false;
646649
}
647650

648-
return (undefined === parentIsPure) || parentIsPure;
651+
return (undefined === parentIsPure) ? PURITY_RELATIVE : parentIsPure;
649652
}
650653

651654
function findConstantAndWatchExpressions(ast, $filter, parentIsPure) {
@@ -873,7 +876,7 @@ ASTCompiler.prototype = {
873876
forEach(inputs, function(input) {
874877
result.push('var ' + input.name + '=' + self.generateFunction(input.name, 's'));
875878
if (input.isPure) {
876-
result.push(input.name, '.isPure=true;');
879+
result.push(input.name, '.isPure=' + JSON.stringify(input.isPure) + ';');
877880
}
878881
});
879882
if (inputs.length) {
@@ -1960,10 +1963,16 @@ function $ParseProvider() {
19601963
fn.$$watchDelegate = watchDelegate;
19611964
fn.inputs = parsedExpression.inputs;
19621965
} else if (!interceptorFn.$stateful) {
1963-
// If there is an interceptor, but no watchDelegate then treat the interceptor like
1964-
// we treat filters - it is assumed to be a pure function unless flagged with $stateful
1966+
// Treat interceptor like filters - assume non-stateful by default and use the inputsWatchDelegate
19651967
fn.$$watchDelegate = inputsWatchDelegate;
1966-
fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
1968+
fn.inputs = (parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression]).map(function(e) {
1969+
// Remove the isPure flag of inputs when it is not absolute because they are now wrapped in a
1970+
// potentially non-pure interceptor function.
1971+
if (e.isPure === PURITY_RELATIVE) {
1972+
return function depurifier(s) { return e(s); };
1973+
}
1974+
return e;
1975+
});
19671976
}
19681977

19691978
return fn;

test/ng/directive/ngClassSpec.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,22 @@ describe('ngClass', function() {
517517
})
518518
);
519519

520+
// https://github.com/angular/angular.js/issues/15905
521+
it('should support a mixed literal-array/object variable', inject(function($rootScope, $compile) {
522+
element = $compile('<div ng-class="[classVar]"></div>')($rootScope);
523+
524+
$rootScope.classVar = {orange: true};
525+
$rootScope.$digest();
526+
expect(element).toHaveClass('orange');
527+
528+
$rootScope.classVar.orange = false;
529+
$rootScope.$digest();
530+
531+
expect(element).not.toHaveClass('orange');
532+
})
533+
);
534+
535+
520536
it('should do value stabilization as expected when one-time binding',
521537
inject(function($rootScope, $compile) {
522538
element = $compile('<div ng-class="::className"></div>')($rootScope);

test/ng/parseSpec.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3277,6 +3277,25 @@ describe('parser', function() {
32773277
expect(called).toBe(true);
32783278
}));
32793279

3280+
it('should always be invoked if inputs are non-primitive', inject(function($parse) {
3281+
var called = false;
3282+
function interceptor(v) {
3283+
called = true;
3284+
return v.sub;
3285+
}
3286+
3287+
scope.$watch($parse('[o]', interceptor));
3288+
scope.o = {sub: 1};
3289+
3290+
called = false;
3291+
scope.$digest();
3292+
expect(called).toBe(true);
3293+
3294+
called = false;
3295+
scope.$digest();
3296+
expect(called).toBe(true);
3297+
}));
3298+
32803299
it('should not be invoked unless the input.valueOf() changes even if the instance changes', inject(function($parse) {
32813300
var called = false;
32823301
function interceptor(v) {
@@ -3321,6 +3340,32 @@ describe('parser', function() {
33213340
scope.$digest();
33223341
expect(called).toBe(true);
33233342
}));
3343+
3344+
it('should not affect when a one-time binding becomes stable', inject(function($parse) {
3345+
scope.$watch($parse('::x'));
3346+
scope.$watch($parse('::x', identity));
3347+
scope.$watch($parse('::x', function() { return 1; })); //interceptor that returns non-undefined
3348+
3349+
scope.$digest();
3350+
expect(scope.$$watchersCount).toBe(3);
3351+
3352+
scope.x = 1;
3353+
scope.$digest();
3354+
expect(scope.$$watchersCount).toBe(0);
3355+
}));
3356+
3357+
it('should not affect when a one-time literal binding becomes stable', inject(function($parse) {
3358+
scope.$watch($parse('::[x]'));
3359+
scope.$watch($parse('::[x]', identity));
3360+
scope.$watch($parse('::[x]', function() { return 1; })); //interceptor that returns non-literal
3361+
3362+
scope.$digest();
3363+
expect(scope.$$watchersCount).toBe(3);
3364+
3365+
scope.x = 1;
3366+
scope.$digest();
3367+
expect(scope.$$watchersCount).toBe(0);
3368+
}));
33243369
});
33253370

33263371
describe('literals', function() {

yarn.lock

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1093,7 +1093,7 @@ [email protected]:
10931093
version "1.0.3"
10941094
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
10951095

1096-
colors@^1.1.0, colors@~1.1.2:
1096+
colors@^1.1.0, colors@^1.1.2, colors@~1.1.2:
10971097
version "1.1.2"
10981098
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
10991099

@@ -3649,6 +3649,12 @@ karma-script-launcher@^1.0.0:
36493649
version "1.0.0"
36503650
resolved "https://registry.yarnpkg.com/karma-script-launcher/-/karma-script-launcher-1.0.0.tgz#cd017c4de5ef09e5a9da793276176108dd4b542d"
36513651

3652+
karma-spec-reporter@^0.0.31:
3653+
version "0.0.31"
3654+
resolved "https://registry.yarnpkg.com/karma-spec-reporter/-/karma-spec-reporter-0.0.31.tgz#4830dc7148a155c7d7a186e632339a0d80fadec3"
3655+
dependencies:
3656+
colors "^1.1.2"
3657+
36523658
karma@^1.7.0:
36533659
version "1.7.0"
36543660
resolved "https://registry.yarnpkg.com/karma/-/karma-1.7.0.tgz#6f7a1a406446fa2e187ec95398698f4cee476269"

0 commit comments

Comments
 (0)