Skip to content

Commit

Permalink
Memoize parseUserAgent (#510)
Browse files Browse the repository at this point in the history
From #52

---------

Co-authored-by: Alfred Xing <[email protected]>
  • Loading branch information
tore-statsig and alfredxing authored Oct 17, 2024
1 parent 7230be8 commit 5f90be7
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 0 deletions.
83 changes: 83 additions & 0 deletions src/utils/__tests__/parseUserAgent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import parseUserAgent from '../parseUserAgent';

const mockUAParser = jest.fn();
jest.mock('ua-parser-js', () => ({
__esModule: true,
default: (uaString: string) => mockUAParser(uaString),
}));

describe('parseUserAgent', () => {
beforeEach(() => {
jest.resetAllMocks();
});

it('returns the parsed user agent', () => {
const uaString =
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36';

const mockRes = {
ua: uaString,
browser: { name: 'Chrome', version: '129.0.0.0', major: '129' },
engine: { name: 'Blink', version: '129.0.0.0' },
os: { name: 'Windows', version: '10' },
device: { vendor: undefined, model: undefined, type: undefined },
cpu: { architecture: 'amd64' },
};
mockUAParser.mockReturnValue(mockRes);

expect(parseUserAgent(uaString)).toEqual(mockRes);
});

it('replaces "Mac OS" with "Mac OS X"', () => {
const uaString =
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36';

mockUAParser.mockReturnValue({
ua: uaString,
browser: { name: 'Chrome', version: '129.0.0.0', major: '129' },
engine: { name: 'Blink', version: '129.0.0.0' },
os: { name: 'Mac OS', version: '10.15.7' },
device: { vendor: 'Apple', model: 'Macintosh', type: undefined },
cpu: { architecture: undefined },
});

expect(parseUserAgent(uaString).os.name).toEqual('Mac OS X');
});

it('adds "Mobile" to mobile browser names', () => {
const uaString =
'Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36';

mockUAParser.mockReturnValue({
ua: uaString,
browser: { name: 'Chrome', version: '116.0.0.0', major: '116' },
engine: { name: 'Blink', version: '116.0.0.0' },
os: { name: 'Android', version: '13' },
device: { vendor: 'Google', model: 'Pixel 7', type: 'mobile' },
cpu: { architecture: undefined },
});

expect(parseUserAgent(uaString).browser.name).toEqual('Chrome Mobile');
});

it('memoizes the most recent call', () => {
const uaString =
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36';

const mockRes = {
ua: uaString,
browser: { name: 'Chrome', version: '129.0.0.0', major: '129' },
engine: { name: 'Blink', version: '129.0.0.0' },
os: { name: 'Windows', version: '10' },
device: { vendor: undefined, model: undefined, type: undefined },
cpu: { architecture: 'amd64' },
};
mockUAParser.mockReturnValue(mockRes);

parseUserAgent(uaString);
parseUserAgent(uaString);
parseUserAgent(uaString);

expect(mockUAParser).toHaveBeenCalledTimes(1);
});
});
16 changes: 16 additions & 0 deletions src/utils/parseUserAgent.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
import uaparser from 'ua-parser-js';

// Memoize the most recent call
const parseUserAgentMemo:
| { uaString: undefined; res: undefined }
| { uaString: string; res: uaparser.IResult } = {
uaString: undefined,
res: undefined,
};

// This exists only to provide compatibility for useragent library that's used
// everywhere else.
export default function parseUserAgent(uaString: string) {
if (parseUserAgentMemo.uaString === uaString) {
return parseUserAgentMemo.res;
}

const res = uaparser(uaString);
if (res.os.name === 'Mac OS') {
res.os.name = 'Mac OS X';
Expand All @@ -13,5 +25,9 @@ export default function parseUserAgent(uaString: string) {
) {
res.browser.name += ' Mobile';
}

parseUserAgentMemo.uaString = uaString;
parseUserAgentMemo.res = res;

return res;
}

0 comments on commit 5f90be7

Please sign in to comment.