chore(build): improve reliability of the saucelabs job

Closes #4091
Closes #4047
This commit is contained in:
Marc Laval 2015-09-09 16:41:11 +02:00
parent df7f59b3a8
commit f7b6ff0520
11 changed files with 126 additions and 86 deletions

View File

@ -2,12 +2,13 @@
import {DOM} from 'angular2/src/core/dom/dom_adapter';
import {StringMapWrapper} from 'angular2/src/core/facade/collection';
import {global, isFunction} from 'angular2/src/core/facade/lang';
import {global, isFunction, Math} from 'angular2/src/core/facade/lang';
import {NgZoneZone} from 'angular2/src/core/zone/ng_zone';
import {bind} from 'angular2/src/core/di';
import {createTestInjector, FunctionWithParamTokens, inject} from './test_injector';
import {browserDetection} from './utils';
export {inject} from './test_injector';
@ -52,6 +53,7 @@ var jsmXIt = _global.xit;
var runnerStack = [];
var inIt = false;
var globalTimeOut = browserDetection.isSlow ? 3000 : jasmine.DEFAULT_TIMEOUT_INTERVAL;
var testBindings;
@ -130,8 +132,9 @@ export function beforeEachBindings(fn): void {
}
function _it(jsmFn: Function, name: string, testFn: FunctionWithParamTokens | AnyTestFn,
timeOut: number): void {
testTimeOut: number): void {
var runner = runnerStack[runnerStack.length - 1];
var timeOut = Math.max(globalTimeOut, testTimeOut);
if (testFn instanceof FunctionWithParamTokens) {
// The test case uses inject(). ie `it('test', inject([AsyncTestCompleter], (async) => { ...

View File

@ -51,6 +51,12 @@ export class BrowserDetection {
return this._ua.indexOf('AppleWebKit') > -1 && this._ua.indexOf('Edge') == -1;
}
get isIOS7(): boolean {
return this._ua.indexOf('iPhone OS 7') > -1 || this._ua.indexOf('iPad OS 7') > -1;
}
get isSlow(): boolean { return this.isAndroid || this.isIE || this.isIOS7; }
// The Intl API is only properly supported in recent Chrome and Opera.
// Note: Edge is disguised as Chrome 42, so checking the "Edge" part is needed,
// see https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx

View File

@ -180,12 +180,10 @@ export function main() {
it('should allow to import rules with relative paths',
runTest(`div {color: red}@import ${IMPORT_REL_MODULE_NAME};`,
['div {color: red}', 'span {color: blue}'],
[
['div {color: red}', 'span {color: blue}'], [
'div[_ngcontent-%COMP%] {\ncolor: red;\n}',
'span[_ngcontent-%COMP%] {\ncolor: blue;\n}'
]),
1000);
]));
});
});
}

View File

@ -11,7 +11,8 @@ import {
xit,
Log,
isInInnerZone,
browserDetection
browserDetection,
TIMEOUT_INTERVAL_FOR_SLOW_BROWSERS
} from 'angular2/test_lib';
import {PromiseCompleter, PromiseWrapper, TimerWrapper} from 'angular2/src/core/facade/async';
@ -19,8 +20,9 @@ import {BaseException} from 'angular2/src/core/facade/exceptions';
import {NgZone} from 'angular2/src/core/zone/ng_zone';
var needsLongerTimers =
browserDetection.isAndroid || browserDetection.isEdge || browserDetection.isIE;
var needsLongerTimers = browserDetection.isSlow || browserDetection.isEdge;
var resultTimer = 1000;
var testTimeout = browserDetection.isEdge ? 1200 : 100;
// Schedules a macrotask (using a timer)
function macroTask(fn: Function, timer = 1): void {
// adds longer timers for passing tests in IE and Edge
@ -83,7 +85,7 @@ export function main() {
async.done();
});
});
}));
}), testTimeout);
it('should produce long stack traces (when using microtasks)',
inject([AsyncTestCompleter], (async) => {
@ -106,7 +108,7 @@ export function main() {
async.done();
});
});
}));
}), testTimeout);
});
describe('short stack trace', () => {
@ -134,7 +136,7 @@ export function main() {
async.done();
});
});
}));
}), testTimeout);
});
});
}
@ -144,14 +146,14 @@ function commonTests() {
() => {it('should return whether the code executes in the inner zone', () => {
expect(isInInnerZone()).toEqual(false);
_zone.run(() => { expect(isInInnerZone()).toEqual(true); });
})});
}, testTimeout)});
describe('run', () => {
it('should return the body return value from run', inject([AsyncTestCompleter], (async) => {
macroTask(() => { expect(_zone.run(() => { return 6; })).toEqual(6); });
macroTask(() => { async.done(); });
}));
}), testTimeout);
it('should call onTurnStart and onTurnDone', inject([AsyncTestCompleter], (async) => {
macroTask(() => { _zone.run(_log.fn('run')); });
@ -160,7 +162,7 @@ function commonTests() {
expect(_log.result()).toEqual('onTurnStart; run; onTurnDone');
async.done();
});
}));
}), testTimeout);
it('should call onEventDone once at the end of event', inject([AsyncTestCompleter], (async) => {
// The test is set up in a way that causes the zone loop to run onTurnDone twice
@ -183,8 +185,8 @@ function commonTests() {
macroTask(() => {
expect(_log.result()).toEqual('run; onTurnDone 1; onTurnDone 2; onEventDone');
async.done();
}, 80);
}));
}, resultTimer);
}), testTimeout);
it('should call standalone onEventDone', inject([AsyncTestCompleter], (async) => {
_zone.overrideOnTurnStart(null);
@ -197,8 +199,8 @@ function commonTests() {
macroTask(() => {
expect(_log.result()).toEqual('run; onEventDone');
async.done();
}, 80);
}));
}, resultTimer);
}), testTimeout);
it('should not allow onEventDone to cause further digests',
inject([AsyncTestCompleter], (async) => {
@ -221,8 +223,8 @@ function commonTests() {
macroTask(() => {
expect(_log.result()).toEqual('run; onTurnDone; onEventDone');
async.done();
}, 150);
}), 200);
}, resultTimer);
}), testTimeout);
it('should run async tasks scheduled inside onEventDone outside Angular zone',
inject([AsyncTestCompleter], (async) => {
@ -243,9 +245,9 @@ function commonTests() {
TimerWrapper.setTimeout(() => {
expect(_log.result()).toEqual('run; onTurnDone; onEventDone; asyncTask');
async.done();
}, 20);
}, 50);
});
}));
}), testTimeout);
it('should call onTurnStart once before a turn and onTurnDone once after the turn',
inject([AsyncTestCompleter], (async) => {
@ -262,8 +264,8 @@ function commonTests() {
// The microtask (async) is executed after the macrotask (run)
expect(_log.result()).toEqual('onTurnStart; run start; run end; async; onTurnDone');
async.done();
}, 80);
}));
}, resultTimer);
}), testTimeout);
it('should not run onTurnStart and onTurnDone for nested Zone.run',
inject([AsyncTestCompleter], (async) => {
@ -283,8 +285,8 @@ function commonTests() {
.toEqual(
'onTurnStart; start run; nested run; end run; nested run microtask; onTurnDone');
async.done();
}, 150);
}), 200);
}, resultTimer);
}), testTimeout);
it('should not run onTurnStart and onTurnDone for nested Zone.run invoked from onTurnDone',
inject([AsyncTestCompleter], (async) => {
@ -301,8 +303,8 @@ function commonTests() {
expect(_log.result())
.toEqual('start run; onTurnDone:started; nested run; onTurnDone:finished');
async.done();
}, 80);
}));
}, resultTimer);
}), testTimeout);
it('should call onTurnStart and onTurnDone before and after each top-level run',
inject([AsyncTestCompleter], (async) => {
@ -314,8 +316,8 @@ function commonTests() {
expect(_log.result())
.toEqual('onTurnStart; run1; onTurnDone; onTurnStart; run2; onTurnDone');
async.done();
});
}));
}, resultTimer);
}), testTimeout);
it('should call onTurnStart and onTurnDone before and after each turn',
inject([AsyncTestCompleter], (async) => {
@ -345,8 +347,8 @@ function commonTests() {
.toEqual(
'onTurnStart; run start; onTurnDone; onTurnStart; a then; b then; onTurnDone');
async.done();
}, 80);
}));
}, resultTimer);
}), testTimeout);
it('should run a function outside of the angular zone',
inject([AsyncTestCompleter], (async) => {
@ -356,7 +358,7 @@ function commonTests() {
expect(_log.result()).toEqual('run');
async.done()
});
}));
}), testTimeout);
it('should call onTurnStart and onTurnDone when an inner microtask is scheduled from outside angular',
inject([AsyncTestCompleter], (async) => {
@ -385,8 +387,8 @@ function commonTests() {
// Third VM Turn => execute the microtask (inside angular)
'onTurnStart; executedMicrotask; onTurnDone');
async.done();
}, 80);
}));
}, resultTimer);
}), testTimeout);
it('should call onTurnStart before executing a microtask scheduled in onTurnDone as well as ' +
'onTurnDone after executing the task',
@ -415,8 +417,8 @@ function commonTests() {
// Second VM Turn => microtask enqueued from onTurnDone
'onTurnStart; executedMicrotask; onTurnDone(begin); onTurnDone(end)');
async.done();
}, 150);
}), 200);
}, resultTimer);
}), testTimeout);
it('should call onTurnStart and onTurnDone for a scheduleMicrotask in onTurnDone triggered by ' +
'a scheduleMicrotask in run',
@ -450,8 +452,8 @@ function commonTests() {
// Second VM Turn => the microtask enqueued from onTurnDone
'onTurnStart; onTurnDone(executeMicrotask); onTurnDone(begin); onTurnDone(end)');
async.done();
}, 150);
}), 200);
}, resultTimer);
}), testTimeout);
it('should execute promises scheduled in onTurnStart before promises scheduled in run',
inject([AsyncTestCompleter], (async) => {
@ -505,8 +507,8 @@ function commonTests() {
// Second VM turn: execute the microtask from onTurnEnd
'onTurnStart(begin); onTurnStart(end); onTurnDone(executePromise); onTurnDone(begin); onTurnDone(end)');
async.done();
}, 150);
}), 200);
}, resultTimer);
}), testTimeout);
it('should call onTurnStart and onTurnDone before and after each turn, respectively',
inject([AsyncTestCompleter], (async) => {
@ -526,7 +528,7 @@ function commonTests() {
macroTask(() => { _zone.run(() => { completerA.resolve(null); }); }, 20);
macroTask(() => { _zone.run(() => { completerB.resolve(null); }); }, 120);
macroTask(() => { _zone.run(() => { completerB.resolve(null); }); }, 500);
macroTask(() => {
expect(_log.result())
@ -538,8 +540,8 @@ function commonTests() {
// Third VM turn
'onTurnStart; b then; onTurnDone');
async.done();
}, 180);
}), 200);
}, resultTimer);
}), testTimeout);
it('should call onTurnStart and onTurnDone before and after (respectively) all turns in a chain',
inject([AsyncTestCompleter], (async) => {
@ -558,8 +560,8 @@ function commonTests() {
expect(_log.result())
.toEqual('onTurnStart; run start; run end; async1; async2; onTurnDone');
async.done();
}, 150);
}), 200);
}, resultTimer);
}), testTimeout);
it('should call onTurnStart and onTurnDone for promises created outside of run body',
inject([AsyncTestCompleter], (async) => {
@ -580,8 +582,8 @@ function commonTests() {
expect(_log.result())
.toEqual('onTurnStart; zone run; onTurnDone; onTurnStart; promise then; onTurnDone');
async.done();
}, 150);
}), 200);
}, resultTimer);
}), testTimeout);
});
describe('exceptions', () => {
@ -598,7 +600,7 @@ function commonTests() {
expect(_errors[0]).toBe(exception);
async.done();
});
}));
}), testTimeout);
it('should call onError for errors from microtasks', inject([AsyncTestCompleter], (async) => {
_zone.overrideOnErrorHandler(logError);
@ -611,8 +613,8 @@ function commonTests() {
expect(_errors.length).toBe(1);
expect(_errors[0]).toEqual(exception);
async.done();
}, 150);
}), 200);
}, resultTimer);
}), testTimeout);
it('should call onError when onTurnDone throws and the zone is sync',
inject([AsyncTestCompleter], (async) => {
@ -627,8 +629,8 @@ function commonTests() {
expect(_errors.length).toBe(1);
expect(_errors[0]).toEqual(exception);
async.done();
}, 80);
}));
}, resultTimer);
}), testTimeout);
it('should call onError when onTurnDone throws and the zone is async',
inject([AsyncTestCompleter], (async) => {
@ -646,7 +648,7 @@ function commonTests() {
expect(_errors.length).toBe(1);
expect(_errors[0]).toEqual(exception);
async.done();
}, 80);
}));
}, resultTimer);
}), testTimeout);
});
}

View File

@ -97,7 +97,7 @@ export function main() {
expect(log).toEqual(['activate: null -> /on-activate']);
async.done();
});
}), 2000);
}));
it('should wait for a parent component\'s onActivate hook to resolve before calling its child\'s',
inject([AsyncTestCompleter], (async) => {
@ -120,7 +120,7 @@ export function main() {
async.done();
});
});
}), 2000);
}));
it('should call the onDeactivate hook', inject([AsyncTestCompleter], (async) => {
compile()
@ -133,7 +133,7 @@ export function main() {
expect(log).toEqual(['deactivate: /on-deactivate -> /a']);
async.done();
});
}), 2000);
}));
it('should wait for a child component\'s onDeactivate hook to resolve before calling its parent\'s',
inject([AsyncTestCompleter], (async) => {
@ -158,7 +158,7 @@ export function main() {
async.done();
});
});
}), 2000);
}));
it('should reuse a component when the canReuse hook returns true',
inject([AsyncTestCompleter], (async) => {
@ -179,7 +179,7 @@ export function main() {
expect(cmpInstanceCount).toBe(1);
async.done();
});
}), 2000);
}));
it('should not reuse a component when the canReuse hook returns false',
@ -201,7 +201,7 @@ export function main() {
expect(cmpInstanceCount).toBe(2);
async.done();
});
}), 2000);
}));
it('should navigate when canActivate returns true', inject([AsyncTestCompleter], (async) => {
@ -221,7 +221,7 @@ export function main() {
async.done();
});
});
}), 2000);
}));
it('should not navigate when canActivate returns false',
inject([AsyncTestCompleter], (async) => {
@ -241,7 +241,7 @@ export function main() {
async.done();
});
});
}), 2000);
}));
it('should navigate away when canDeactivate returns true',
inject([AsyncTestCompleter], (async) => {
@ -266,7 +266,7 @@ export function main() {
async.done();
});
});
}), 2000);
}));
it('should not navigate away when canDeactivate returns false',
inject([AsyncTestCompleter], (async) => {
@ -291,7 +291,7 @@ export function main() {
async.done();
});
});
}), 2000);
}));
it('should run activation and deactivation hooks in the correct order',
@ -319,7 +319,7 @@ export function main() {
]);
async.done();
});
}), 2000);
}));
it('should only run reuse hooks when reusing', inject([AsyncTestCompleter], (async) => {
compile()
@ -346,7 +346,7 @@ export function main() {
]);
async.done();
});
}), 2000);
}));
it('should not run reuse hooks when not reusing', inject([AsyncTestCompleter], (async) => {
compile()
@ -375,7 +375,7 @@ export function main() {
]);
async.done();
});
}), 2000);
}));
});
}

View File

@ -63,7 +63,7 @@ export function main() {
async.done();
});
});
}), 1000);
}));
});
describe('broken app', () => {
@ -79,7 +79,7 @@ export function main() {
async.done();
});
});
}), 1000);
}));
});
describe('back button app', () => {
@ -153,7 +153,7 @@ export function main() {
});
router.navigateByUrl('/parent/child');
});
}), 1000);
}));
describe('custom app base ref', () => {
beforeEachBindings(() => { return [bind(APP_BASE_HREF).toValue('/my/app')]; });
@ -173,8 +173,7 @@ export function main() {
});
router.navigateByUrl('/parent/child');
});
}),
1000);
}));
});
});
// TODO: add a test in which the child component has bindings
@ -201,7 +200,7 @@ export function main() {
router.navigateByUrl('/qs?q=search-for-something');
rootTC.detectChanges();
});
}), 1000);
}));
});
});
}

View File

@ -277,7 +277,7 @@ export function main() {
async.done();
});
});
}), 1000);
}));
it('should navigate to link hrefs in presence of base href',
inject([AsyncTestCompleter], (async) => {
@ -298,7 +298,7 @@ export function main() {
async.done();
});
});
}), 1000);
}));
});
});
}

View File

@ -63,7 +63,7 @@ export function main() {
expect(ev['url']).toEqual('/user/btford');
async.done();
})
}), 2000);
}));
it('should normalize location path', () => {
locationStrategy.internalPath = '/my/app/user/btford';

View File

@ -68,7 +68,7 @@ export function main() {
});
router.navigateByUrl('/parent/child');
});
}), 1000);
}));
it('should work in an app with redirects', inject([AsyncTestCompleter], (async) => {
@ -83,7 +83,7 @@ export function main() {
});
router.navigateByUrl('/before');
});
}), 1000);
}));
it('should work in an app with async components', inject([AsyncTestCompleter], (async) => {
@ -97,7 +97,7 @@ export function main() {
});
router.navigateByUrl('/hello');
});
}), 1000);
}));
it('should work in an app with a constructor component',
@ -114,7 +114,7 @@ export function main() {
});
router.navigateByUrl('/hello');
});
}), 1000);
}));
it('should throw if a config is missing a target',
inject(

View File

@ -13,6 +13,8 @@ export function main() {
isEdge: false,
isIE: false,
isWebkit: true,
isIOS7: false,
isSlow: false,
supportsIntlApi: true
},
{
@ -23,6 +25,8 @@ export function main() {
isEdge: false,
isIE: false,
isWebkit: true,
isIOS7: false,
isSlow: false,
supportsIntlApi: true
},
{
@ -33,6 +37,8 @@ export function main() {
isEdge: false,
isIE: false,
isWebkit: false,
isIOS7: false,
isSlow: false,
supportsIntlApi: false
},
{
@ -43,6 +49,8 @@ export function main() {
isEdge: false,
isIE: true,
isWebkit: false,
isIOS7: false,
isSlow: true,
supportsIntlApi: false
},
{
@ -53,6 +61,8 @@ export function main() {
isEdge: false,
isIE: true,
isWebkit: false,
isIOS7: false,
isSlow: true,
supportsIntlApi: false
},
{
@ -63,6 +73,8 @@ export function main() {
isEdge: false,
isIE: true,
isWebkit: false,
isIOS7: false,
isSlow: true,
supportsIntlApi: false
},
{
@ -73,6 +85,8 @@ export function main() {
isEdge: true,
isIE: false,
isWebkit: false,
isIOS7: false,
isSlow: false,
supportsIntlApi: false
},
{
@ -83,6 +97,8 @@ export function main() {
isEdge: false,
isIE: false,
isWebkit: true,
isIOS7: false,
isSlow: true,
supportsIntlApi: false
},
{
@ -93,6 +109,8 @@ export function main() {
isEdge: false,
isIE: false,
isWebkit: true,
isIOS7: false,
isSlow: true,
supportsIntlApi: false
},
{
@ -103,6 +121,8 @@ export function main() {
isEdge: false,
isIE: false,
isWebkit: true,
isIOS7: false,
isSlow: true,
supportsIntlApi: false
},
{
@ -113,6 +133,8 @@ export function main() {
isEdge: false,
isIE: false,
isWebkit: true,
isIOS7: false,
isSlow: false,
supportsIntlApi: false
},
{
@ -123,6 +145,8 @@ export function main() {
isEdge: false,
isIE: false,
isWebkit: true,
isIOS7: false,
isSlow: false,
supportsIntlApi: false
},
{
@ -133,6 +157,8 @@ export function main() {
isEdge: false,
isIE: false,
isWebkit: true,
isIOS7: false,
isSlow: false,
supportsIntlApi: false
},
{
@ -143,6 +169,8 @@ export function main() {
isEdge: false,
isIE: false,
isWebkit: true,
isIOS7: true,
isSlow: true,
supportsIntlApi: false
},
{
@ -153,6 +181,8 @@ export function main() {
isEdge: false,
isIE: false,
isWebkit: true,
isIOS7: false,
isSlow: false,
supportsIntlApi: false
}
];
@ -165,6 +195,8 @@ export function main() {
expect(bd.isEdge).toBe(StringMapWrapper.get(browser, 'isEdge'));
expect(bd.isIE).toBe(StringMapWrapper.get(browser, 'isIE'));
expect(bd.isWebkit).toBe(StringMapWrapper.get(browser, 'isWebkit'));
expect(bd.isIOS7).toBe(StringMapWrapper.get(browser, 'isIOS7'));
expect(bd.isSlow).toBe(StringMapWrapper.get(browser, 'isSlow'));
expect(bd.supportsIntlApi).toBe(StringMapWrapper.get(browser, 'supportsIntlApi'));
});
});

View File

@ -38,7 +38,7 @@ export function main() {
});
var toEmitter = bus.to(CHANNEL);
ObservableWrapper.callNext(toEmitter, MESSAGE);
}), 1000);
}));
it("should broadcast", inject([AsyncTestCompleter], (async) => {
const CHANNEL = "CHANNEL 1";
@ -111,7 +111,7 @@ export function main() {
* Flushes pending messages and then runs the given function.
*/
// TODO(mlaval): timeout is fragile, test to be rewritten
function flushMessages(fn: () => void) { TimerWrapper.setTimeout(fn, 40); }
function flushMessages(fn: () => void) { TimerWrapper.setTimeout(fn, 50); }
beforeEach(() => { bus = createConnectedMessageBus(); });
@ -133,7 +133,7 @@ export function main() {
async.done();
});
});
}));
}), 500);
it("should send messages immediatly when run outside the zone",
inject([AsyncTestCompleter, NgZone], (async, zone: MockNgZone) => {
@ -147,6 +147,6 @@ export function main() {
expect(wasCalled).toBeTruthy();
async.done();
});
}));
}), 500);
});
}