Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): update detectable user agent for getClientInfo #12661

Merged
merged 1 commit into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 0 additions & 42 deletions packages/core/__tests__/utils/getClientInfo.test.ts

This file was deleted.

182 changes: 182 additions & 0 deletions packages/core/__tests__/utils/getClientInfo/getClientInfo.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { getClientInfo } from '../../../src/utils/getClientInfo/getClientInfo';

const testCases: [string, string, object][] = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Would it be helpful to use this API (or something similar) to keep this test case up to date automatically?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add this as a canary test item.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Move to some testUtils/testCases.ts file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These test cases are tight to this particular suite, I don't think it will be reused elsewhere... keeping inline should be fine? 😅

[
'latest Chrome on Windows',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
{
model: 'Chrome',
version: '119.0.0.0',
},
],
[
'latest Chrome on macOS',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
{
model: 'Chrome',
version: '119.0.0.0',
},
],
[
'latest Chrome on Linux',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
{
model: 'Chrome',
version: '119.0.0.0',
},
],
[
'latest Chrome on iOS',
'Mozilla/5.0 (iPhone; CPU iPhone OS 17_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/120.0.6099.50 Mobile/15E148 Safari/604.1',
{
model: 'CriOS',
version: '120.0.6099.50',
},
],
[
'Latest Chrome on Android',
'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.193 Mobile Safari/537.36',
{
model: 'Chrome',
version: '119.0.6045.193',
},
],
[
'Firefox on Windows',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/120.0',
{
model: 'Firefox',
version: '120.0',
},
],
[
'Firefox on macOS',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.1; rv:109.0) Gecko/20100101 Firefox/120.0',
{
model: 'Firefox',
version: '120.0',
},
],
[
'Firefox on Linux',
'Mozilla/5.0 (X11; Linux i686; rv:109.0) Gecko/20100101 Firefox/120.0',
{
model: 'Firefox',
version: '120.0',
},
],
[
'Firefox on Linux',
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/120.0',
{
model: 'Firefox',
version: '120.0',
},
],
[
'Firefox on iOS',
'Mozilla/5.0 (iPhone; CPU iPhone OS 14_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/120.0 Mobile/15E148 Safari/605.1.15',
{
model: 'FxiOS',
version: '120.0',
},
],
[
'Firefox on Android',
'Mozilla/5.0 (Android 14; Mobile; rv:109.0) Gecko/120.0 Firefox/120.0',
{
model: 'Firefox',
version: '120.0',
},
],
[
'Safari on macOS',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15',
{
model: 'Safari',
version: '605.1.15',
},
],
[
'Safari on iOS',
'Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Mobile/15E148 Safari/604.1',
{
model: 'Safari',
version: '604.1',
},
],
[
'Edge on Windows',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.2151.97',
{
model: 'Edg',
version: '119.0.2151.97',
},
],
[
'Edge on macOS',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.2151.97',
{
model: 'Edg',
version: '119.0.2151.97',
},
],
[
'Edge on Android',
'Mozilla/5.0 (Linux; Android 10; HD1913) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.193 Mobile Safari/537.36 EdgA/119.0.2151.78',
{
model: 'EdgA',
version: '119.0.2151.78',
},
],
[
'Edge on iOS',
'Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 EdgiOS/119.2151.96 Mobile/15E148 Safari/605.1.15',
{
model: 'EdgiOS',
version: '119.2151.96',
},
],
[
'Opera on Windows',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 OPR/105.0.0.0',
{
model: 'OPR',
version: '105.0.0.0',
},
],
[
'Opera on macOS',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 OPR/105.0.0.0',
{
model: 'OPR',
version: '105.0.0.0',
},
],
];

describe('getClientInfo', () => {
let mockNavigator: jest.SpyInstance<typeof window.navigator>;

beforeAll(() => {
mockNavigator = jest.spyOn(window, 'navigator', 'get');
});

afterAll(() => {
jest.clearAllMocks();
});

test.each(testCases)(
'given %p with user agent: %p, should return %p',
(_, userAgent, expectedResult) => {
mockNavigator.mockReturnValueOnce({
userAgent,
} as any);
const result = getClientInfo();
expect(result).toEqual(expect.objectContaining(expectedResult));
}
);
});
25 changes: 19 additions & 6 deletions packages/core/src/utils/getClientInfo/getClientInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ export function getClientInfo() {
function browserClientInfo() {
if (typeof window === 'undefined') {
logger.warn('No window object available to get browser client info');

return {};
}

const nav = window.navigator;
if (!nav) {
logger.warn('No navigator object available to get browser client info');

return {};
}

Expand All @@ -41,38 +43,49 @@ function browserClientInfo() {

function browserTimezone() {
const tzMatch = /\(([A-Za-z\s].*)\)/.exec(new Date().toString());

return tzMatch ? tzMatch[1] || '' : '';
}

function getBrowserType(userAgent: string) {
const operaMatch = /.+(Opera[\s[A-Z]*|OPR[\sA-Z]*)\/([0-9\.]+).*/i.exec(
// The latest user agents for Opera: https://www.whatismybrowser.com/guides/the-latest-user-agent/opera
const operaMatch = /.+(Opera[\s[A-Z]*|OPR[\sA-Z]*)\/([0-9.]+).*/i.exec(
userAgent
);
if (operaMatch) {
return { type: operaMatch[1], version: operaMatch[2] };
}

const ieMatch = /.+(Trident|Edge)\/([0-9\.]+).*/i.exec(userAgent);
// The latest user agents for Edge: https://www.whatismybrowser.com/guides/the-latest-user-agent/edge
const ieMatch = /.+(Trident|Edge|Edg|EdgA|EdgiOS)\/([0-9.]+).*/i.exec(
userAgent
);
if (ieMatch) {
return { type: ieMatch[1], version: ieMatch[2] };
}

const cfMatch = /.+(Chrome|Firefox|FxiOS)\/([0-9\.]+).*/i.exec(userAgent);
// The latest user agents for web browsers on Firefox and Chrome
// https://www.whatismybrowser.com/guides/the-latest-user-agent/firefox
// https://www.whatismybrowser.com/guides/the-latest-user-agent/chrome
const cfMatch = /.+(Chrome|CriOS|Firefox|FxiOS)\/([0-9.]+).*/i.exec(
userAgent
);
if (cfMatch) {
return { type: cfMatch[1], version: cfMatch[2] };
}

const sMatch = /.+(Safari)\/([0-9\.]+).*/i.exec(userAgent);
// The latest user agents for Safari: https://www.whatismybrowser.com/guides/the-latest-user-agent/safari
const sMatch = /.+(Safari)\/([0-9.]+).*/i.exec(userAgent);
if (sMatch) {
return { type: sMatch[1], version: sMatch[2] };
}

const awkMatch = /.+(AppleWebKit)\/([0-9\.]+).*/i.exec(userAgent);
const awkMatch = /.+(AppleWebKit)\/([0-9.]+).*/i.exec(userAgent);
if (awkMatch) {
return { type: awkMatch[1], version: awkMatch[2] };
}

const anyMatch = /.*([A-Z]+)\/([0-9\.]+).*/i.exec(userAgent);
const anyMatch = /.*([A-Z]+)\/([0-9.]+).*/i.exec(userAgent);
if (anyMatch) {
return { type: anyMatch[1], version: anyMatch[2] };
}
Expand Down