Skip to content

Commit be07390

Browse files
committed
refactor(test_lib): BrowserDetection util
Closes angular#3805
1 parent 551d9a1 commit be07390

File tree

8 files changed

+223
-38
lines changed

8 files changed

+223
-38
lines changed

modules/angular2/src/test_lib/utils.ts

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,42 @@ export class Log {
2222
result(): string { return ListWrapper.join(this._result, "; "); }
2323
}
2424

25+
26+
export class BrowserDetection {
27+
private _ua: string;
28+
29+
constructor(ua: string) {
30+
if (isPresent(ua)) {
31+
this._ua = ua;
32+
} else {
33+
this._ua = isPresent(DOM) ? DOM.getUserAgent() : '';
34+
}
35+
}
36+
37+
get isFirefox(): boolean { return this._ua.indexOf('Firefox') > -1; }
38+
39+
get isAndroid(): boolean {
40+
return this._ua.indexOf('Mozilla/5.0') > -1 && this._ua.indexOf('Android') > -1 &&
41+
this._ua.indexOf('AppleWebKit') > -1 && this._ua.indexOf('Chrome') == -1;
42+
}
43+
44+
get isEdge(): boolean { return this._ua.indexOf('Edge') > -1; }
45+
46+
get isIE(): boolean { return this._ua.indexOf('Trident') > -1; }
47+
48+
get isWebkit(): boolean {
49+
return this._ua.indexOf('AppleWebKit') > -1 && this._ua.indexOf('Edge') == -1;
50+
}
51+
52+
// The Intl API is only properly supported in recent Chrome and Opera.
53+
// Note: Edge is disguised as Chrome 42, so checking the "Edge" part is needed,
54+
// see https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
55+
get supportsIntlApi(): boolean {
56+
return this._ua.indexOf('Chrome/4') > -1 && this._ua.indexOf('Edge') == -1;
57+
}
58+
}
59+
export var browserDetection = new BrowserDetection(null);
60+
2561
export function dispatchEvent(element, eventType) {
2662
DOM.dispatchEvent(element, DOM.createEvent(eventType));
2763
}
@@ -92,26 +128,3 @@ export function stringifyElement(el): string {
92128

93129
return result;
94130
}
95-
96-
// The Intl API is only properly supported in recent Chrome and Opera.
97-
// Note: Edge is disguised as Chrome 42, so checking the "Edge" part is needed,
98-
// see https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
99-
export function supportsIntlApi(): boolean {
100-
return DOM.getUserAgent().indexOf('Chrome/4') > -1 && DOM.getUserAgent().indexOf('Edge') == -1;
101-
}
102-
103-
// TODO(mlaval): extract all browser detection checks from all tests
104-
export function isFirefox(): boolean {
105-
return DOM.getUserAgent().indexOf("Firefox") > -1;
106-
}
107-
export function isAndroid(): boolean {
108-
var ua = DOM.getUserAgent();
109-
return ua.indexOf('Mozilla/5.0') > -1 && ua.indexOf('Android ') > -1 &&
110-
ua.indexOf('AppleWebKit') > -1 && ua.indexOf('Chrome') == -1;
111-
}
112-
export function isEdge(): boolean {
113-
return DOM.getUserAgent().indexOf('Edge') > -1;
114-
}
115-
export function isIE(): boolean {
116-
return DOM.getUserAgent().indexOf('Trident') > -1;
117-
}

modules/angular2/test/core/render/dom/compiler/shadow_css_spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import {
77
iit,
88
SpyObject,
99
el,
10-
normalizeCSS
10+
normalizeCSS,
11+
browserDetection
1112
} from 'angular2/test_lib';
1213
import {ShadowCss} from 'angular2/src/core/render/dom/compiler/shadow_css';
1314

@@ -66,8 +67,7 @@ export function main() {
6667
});
6768
}
6869

69-
if (DOM.getUserAgent().indexOf('AppleWebKit') > -1 &&
70-
DOM.getUserAgent().indexOf('Edge') == -1) {
70+
if (browserDetection.isWebkit) {
7171
it('should handle -webkit-keyframes rules', () => {
7272
var css = '@-webkit-keyframes foo {0% {-webkit-transform: translate(-50%) scaleX(0);}}';
7373
var passRe =

modules/angular2/test/core/zone/ng_zone_spec.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,16 @@ import {
1111
xit,
1212
Log,
1313
isInInnerZone,
14-
isAndroid,
15-
isEdge,
16-
isIE
14+
browserDetection
1715
} from 'angular2/test_lib';
1816

1917
import {PromiseCompleter, PromiseWrapper, TimerWrapper} from 'angular2/src/core/facade/async';
2018
import {BaseException} from 'angular2/src/core/facade/lang';
2119

2220
import {NgZone} from 'angular2/src/core/zone/ng_zone';
2321

24-
var needsLongerTimers = isAndroid() || isEdge() || isIE();
22+
var needsLongerTimers =
23+
browserDetection.isAndroid || browserDetection.isEdge || browserDetection.isIE;
2524
// Schedules a macrotask (using a timer)
2625
function macroTask(fn: Function, timer = 1): void {
2726
// adds longer timers for passing tests in IE and Edge

modules/angular2/test/forms/integration_spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
inject,
1616
iit,
1717
xit,
18-
isFirefox
18+
browserDetection
1919
} from 'angular2/test_lib';
2020

2121
import {DOM} from 'angular2/src/core/dom/dom_adapter';
@@ -740,7 +740,7 @@ export function main() {
740740

741741
// In Firefox, effective text selection in the real DOM requires an actual focus
742742
// of the field. This is not an issue in a new HTML document.
743-
if (isFirefox()) {
743+
if (browserDetection.isFirefox) {
744744
var fakeDoc = DOM.createHtmlDocument();
745745
DOM.appendChild(fakeDoc.body, rootTC.nativeElement);
746746
}

modules/angular2/test/pipes/async_pipe_spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import {
99
afterEach,
1010
AsyncTestCompleter,
1111
inject,
12-
SpyObject
12+
SpyObject,
13+
browserDetection
1314
} from 'angular2/test_lib';
1415
import {SpyChangeDetectorRef} from './spies';
1516

@@ -120,7 +121,7 @@ export function main() {
120121
var completer;
121122
var ref;
122123
// adds longer timers for passing tests in IE
123-
var timer = (!isBlank(DOM) && DOM.getUserAgent().indexOf("Trident") > -1) ? 50 : 0;
124+
var timer = (!isBlank(DOM) && browserDetection.isIE) ? 50 : 0;
124125

125126
beforeEach(() => {
126127
completer = PromiseWrapper.completer();

modules/angular2/test/pipes/date_pipe_spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
expect,
88
beforeEach,
99
afterEach,
10-
supportsIntlApi
10+
browserDetection
1111
} from 'angular2/test_lib';
1212

1313
import {DatePipe} from 'angular2/pipes';
@@ -35,7 +35,7 @@ export function main() {
3535

3636
// TODO(mlaval): enable tests when Intl API is no longer used, see
3737
// https://github.com/angular/angular/issues/3333
38-
if (supportsIntlApi()) {
38+
if (browserDetection.supportsIntlApi) {
3939
describe("transform", () => {
4040
it('should format each component correctly', () => {
4141
expect(pipe.transform(date, ['y'])).toEqual('2015');

modules/angular2/test/pipes/number_pipe_spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ import {
77
expect,
88
beforeEach,
99
afterEach,
10-
supportsIntlApi
10+
browserDetection
1111
} from 'angular2/test_lib';
1212

1313
import {DecimalPipe, PercentPipe, CurrencyPipe} from 'angular2/pipes';
1414

1515
export function main() {
1616
// TODO(mlaval): enable tests when Intl API is no longer used, see
1717
// https://github.com/angular/angular/issues/3333
18-
if (supportsIntlApi()) {
18+
if (browserDetection.supportsIntlApi) {
1919
describe("DecimalPipe", () => {
2020
var pipe;
2121

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import {describe, it, iit, ddescribe, expect, BrowserDetection} from 'angular2/test_lib';
2+
import {StringMapWrapper} from 'angular2/src/core/facade/collection';
3+
4+
export function main() {
5+
describe('BrowserDetection', () => {
6+
7+
var browsers = [
8+
{
9+
name: 'Chrome',
10+
ua: 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36',
11+
isFirefox: false,
12+
isAndroid: false,
13+
isEdge: false,
14+
isIE: false,
15+
isWebkit: true,
16+
supportsIntlApi: true
17+
},
18+
{
19+
name: 'Chrome mobile',
20+
ua: 'Mozilla/5.0 (Linux; Android 5.1.1; D5803 Build/23.4.A.0.546) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.133 Mobile Safari/537.36',
21+
isFirefox: false,
22+
isAndroid: false,
23+
isEdge: false,
24+
isIE: false,
25+
isWebkit: true,
26+
supportsIntlApi: true
27+
},
28+
{
29+
name: 'Firefox',
30+
ua: 'Mozilla/5.0 (X11; Linux i686; rv:40.0) Gecko/20100101 Firefox/40.0',
31+
isFirefox: true,
32+
isAndroid: false,
33+
isEdge: false,
34+
isIE: false,
35+
isWebkit: false,
36+
supportsIntlApi: false
37+
},
38+
{
39+
name: 'IE9',
40+
ua: 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727)',
41+
isFirefox: false,
42+
isAndroid: false,
43+
isEdge: false,
44+
isIE: true,
45+
isWebkit: false,
46+
supportsIntlApi: false
47+
},
48+
{
49+
name: 'IE10',
50+
ua: 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C)',
51+
isFirefox: false,
52+
isAndroid: false,
53+
isEdge: false,
54+
isIE: true,
55+
isWebkit: false,
56+
supportsIntlApi: false
57+
},
58+
{
59+
name: 'IE11',
60+
ua: 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; .NET4.0E; .NET4.0C; rv:11.0) like Gecko',
61+
isFirefox: false,
62+
isAndroid: false,
63+
isEdge: false,
64+
isIE: true,
65+
isWebkit: false,
66+
supportsIntlApi: false
67+
},
68+
{
69+
name: 'Edge',
70+
ua: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10136',
71+
isFirefox: false,
72+
isAndroid: false,
73+
isEdge: true,
74+
isIE: false,
75+
isWebkit: false,
76+
supportsIntlApi: false
77+
},
78+
{
79+
name: 'Android4.1',
80+
ua: 'Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Android SDK built for x86 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
81+
isFirefox: false,
82+
isAndroid: true,
83+
isEdge: false,
84+
isIE: false,
85+
isWebkit: true,
86+
supportsIntlApi: false
87+
},
88+
{
89+
name: 'Android4.2',
90+
ua: 'Mozilla/5.0 (Linux; U; Android 4.2; en-us; Android SDK built for x86 Build/JOP40C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
91+
isFirefox: false,
92+
isAndroid: true,
93+
isEdge: false,
94+
isIE: false,
95+
isWebkit: true,
96+
supportsIntlApi: false
97+
},
98+
{
99+
name: 'Android4.3',
100+
ua: 'Mozilla/5.0 (Linux; U; Android 4.3; en-us; Android SDK built for x86 Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
101+
isFirefox: false,
102+
isAndroid: true,
103+
isEdge: false,
104+
isIE: false,
105+
isWebkit: true,
106+
supportsIntlApi: false
107+
},
108+
{
109+
name: 'Android4.4',
110+
ua: 'Mozilla/5.0 (Linux; Android 4.4.2; Android SDK built for x86 Build/KK) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36',
111+
isFirefox: false,
112+
isAndroid: false,
113+
isEdge: false,
114+
isIE: false,
115+
isWebkit: true,
116+
supportsIntlApi: false
117+
},
118+
{
119+
name: 'Safari7',
120+
ua: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/7.1.7 Safari/537.85.16',
121+
isFirefox: false,
122+
isAndroid: false,
123+
isEdge: false,
124+
isIE: false,
125+
isWebkit: true,
126+
supportsIntlApi: false
127+
},
128+
{
129+
name: 'Safari8',
130+
ua: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.12',
131+
isFirefox: false,
132+
isAndroid: false,
133+
isEdge: false,
134+
isIE: false,
135+
isWebkit: true,
136+
supportsIntlApi: false
137+
},
138+
{
139+
name: 'iOS7',
140+
ua: 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D167 Safari/9537.53',
141+
isFirefox: false,
142+
isAndroid: false,
143+
isEdge: false,
144+
isIE: false,
145+
isWebkit: true,
146+
supportsIntlApi: false
147+
},
148+
{
149+
name: 'iOS8',
150+
ua: 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_4 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H141 Safari/600.1.4',
151+
isFirefox: false,
152+
isAndroid: false,
153+
isEdge: false,
154+
isIE: false,
155+
isWebkit: true,
156+
supportsIntlApi: false
157+
}
158+
];
159+
160+
browsers.forEach((browser) => {
161+
it(`should detect ${StringMapWrapper.get(browser, 'name')}`, () => {
162+
var bd = new BrowserDetection(<string>StringMapWrapper.get(browser, 'ua'));
163+
expect(bd.isFirefox).toBe(StringMapWrapper.get(browser, 'isFirefox'));
164+
expect(bd.isAndroid).toBe(StringMapWrapper.get(browser, 'isAndroid'));
165+
expect(bd.isEdge).toBe(StringMapWrapper.get(browser, 'isEdge'));
166+
expect(bd.isIE).toBe(StringMapWrapper.get(browser, 'isIE'));
167+
expect(bd.isWebkit).toBe(StringMapWrapper.get(browser, 'isWebkit'));
168+
expect(bd.supportsIntlApi).toBe(StringMapWrapper.get(browser, 'supportsIntlApi'));
169+
});
170+
});
171+
});
172+
}

0 commit comments

Comments
 (0)