test: add vitest
* feature(root): add vitest and some basic tests * fix(test): after rebase + added referrars test and more sites * fix(test): test broken after rebase * fix(test): provide db url to make prisma happy * fix tests
This commit is contained in:
committed by
GitHub
parent
09c83ddeb4
commit
5445d6309e
@@ -3,6 +3,7 @@
|
||||
"version": "0.0.1",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
"test": "vitest",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
170
packages/common/server/parser-user-agent.test.ts
Normal file
170
packages/common/server/parser-user-agent.test.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { getDevice, parseUserAgent } from './parser-user-agent';
|
||||
|
||||
describe('parseUserAgent', () => {
|
||||
it('should return server UA for null/undefined input', () => {
|
||||
const serverUa = {
|
||||
isServer: true,
|
||||
device: 'server',
|
||||
os: '',
|
||||
osVersion: '',
|
||||
browser: '',
|
||||
browserVersion: '',
|
||||
brand: '',
|
||||
model: '',
|
||||
};
|
||||
|
||||
expect(parseUserAgent(null)).toEqual(serverUa);
|
||||
expect(parseUserAgent(undefined)).toEqual(serverUa);
|
||||
});
|
||||
|
||||
it('should parse iPhone user agents', () => {
|
||||
const ua =
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1';
|
||||
|
||||
expect(parseUserAgent(ua)).toEqual({
|
||||
isServer: false,
|
||||
device: 'mobile',
|
||||
os: 'iOS',
|
||||
osVersion: '16.5',
|
||||
browser: 'Mobile Safari',
|
||||
browserVersion: '16.5',
|
||||
brand: 'Apple',
|
||||
model: 'iPhone',
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse iPad user agents', () => {
|
||||
const ua =
|
||||
'Mozilla/5.0 (iPad; CPU OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1';
|
||||
|
||||
expect(parseUserAgent(ua)).toEqual({
|
||||
isServer: false,
|
||||
device: 'tablet',
|
||||
os: 'iOS',
|
||||
osVersion: '16.5',
|
||||
browser: 'Mobile Safari',
|
||||
browserVersion: '16.5',
|
||||
brand: 'Apple',
|
||||
model: 'iPad',
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse iPadOS user agents', () => {
|
||||
const ua =
|
||||
'Mozilla/5.0 (iPad; iPadOS 18_0; like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/18.0';
|
||||
|
||||
expect(parseUserAgent(ua)).toEqual({
|
||||
isServer: false,
|
||||
device: 'tablet',
|
||||
os: 'Mac OS',
|
||||
osVersion: '18.0',
|
||||
browser: 'WebKit',
|
||||
browserVersion: '605.1.15',
|
||||
brand: 'Apple',
|
||||
model: 'iPad',
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse desktop Chrome user agents', () => {
|
||||
const ua =
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36';
|
||||
|
||||
expect(parseUserAgent(ua)).toEqual({
|
||||
isServer: false,
|
||||
device: 'desktop',
|
||||
os: 'Windows',
|
||||
osVersion: '10',
|
||||
browser: 'Chrome',
|
||||
browserVersion: '91.0.4472.124',
|
||||
brand: undefined,
|
||||
model: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle server user agents', () => {
|
||||
const serverUas = [
|
||||
'Go-http-client/1.0',
|
||||
'Go Http Client/1.0',
|
||||
'node-fetch/1.0',
|
||||
];
|
||||
|
||||
const expectedResult = {
|
||||
isServer: true,
|
||||
device: 'server',
|
||||
os: '',
|
||||
osVersion: '',
|
||||
browser: '',
|
||||
browserVersion: '',
|
||||
brand: '',
|
||||
model: '',
|
||||
};
|
||||
|
||||
serverUas.forEach((ua) => {
|
||||
expect(parseUserAgent(ua)).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
|
||||
it('should apply overrides when provided', () => {
|
||||
const ua =
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15';
|
||||
const overrides = {
|
||||
__os: 'Custom OS',
|
||||
__osVersion: '1.0',
|
||||
__browser: 'Custom Browser',
|
||||
__browserVersion: '2.0',
|
||||
__device: 'custom-device',
|
||||
__brand: 'Custom Brand',
|
||||
__model: 'Custom Model',
|
||||
};
|
||||
|
||||
expect(parseUserAgent(ua, overrides)).toEqual({
|
||||
isServer: false,
|
||||
device: 'custom-device',
|
||||
os: 'Custom OS',
|
||||
osVersion: '1.0',
|
||||
browser: 'Custom Browser',
|
||||
browserVersion: '2.0',
|
||||
brand: 'Custom Brand',
|
||||
model: 'Custom Model',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDevice', () => {
|
||||
it('should detect mobile devices', () => {
|
||||
const mobileUas = [
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15',
|
||||
'Mozilla/5.0 (Linux; Android 10; SM-A505FN) AppleWebKit/537.36',
|
||||
'Mozilla/5.0 (Linux; U; Android 4.0.3; ko-kr; LG-L160L Build/IML74K) AppleWebkit/534.30',
|
||||
];
|
||||
|
||||
mobileUas.forEach((ua) => {
|
||||
expect(getDevice(ua)).toBe('mobile');
|
||||
});
|
||||
});
|
||||
|
||||
it('should detect tablet devices', () => {
|
||||
const tabletUas = [
|
||||
'Mozilla/5.0 (iPad; CPU OS 16_5 like Mac OS X) AppleWebKit/605.1.15',
|
||||
'Mozilla/5.0 (Linux; Android 10.0; Tablet; rv:68.0) Gecko/68.0 Firefox/68.0',
|
||||
'Mozilla/5.0 (Linux; Android 7.0; SM-T827R4 Build/NRD90M)',
|
||||
];
|
||||
|
||||
tabletUas.forEach((ua) => {
|
||||
expect(getDevice(ua)).toBe('tablet');
|
||||
});
|
||||
});
|
||||
|
||||
it('should default to desktop for non-mobile/tablet devices', () => {
|
||||
const desktopUas = [
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36',
|
||||
];
|
||||
|
||||
desktopUas.forEach((ua) => {
|
||||
expect(getDevice(ua)).toBe('desktop');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -109,6 +109,21 @@ function isServer(res: UAParser.IResult) {
|
||||
}
|
||||
|
||||
export function getDevice(ua: string) {
|
||||
// Samsung mobile devices use SM-[A,G,N,etc]XXX pattern
|
||||
if (/SM-[ABDEFGJMNRWZ][0-9]+/i.test(ua)) {
|
||||
return 'mobile';
|
||||
}
|
||||
|
||||
// Samsung tablets use SM-TXXX pattern
|
||||
if (/SM-T[0-9]+/i.test(ua)) {
|
||||
return 'tablet';
|
||||
}
|
||||
|
||||
// LG mobile devices use LG-XXXX pattern
|
||||
if (/LG-[A-Z0-9]+/i.test(ua)) {
|
||||
return 'mobile';
|
||||
}
|
||||
|
||||
const mobile1 =
|
||||
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(
|
||||
ua,
|
||||
@@ -118,9 +133,11 @@ export function getDevice(ua: string) {
|
||||
ua.slice(0, 4),
|
||||
);
|
||||
const tablet =
|
||||
/tablet|ipad|android(?!.*mobile)|xoom|sch-i800|kindle|silk|playbook/i.test(
|
||||
ua,
|
||||
);
|
||||
/tablet|ipad|xoom|sch-i800|kindle|silk|playbook/i.test(ua) ||
|
||||
(/android/i.test(ua) &&
|
||||
!/mobile/i.test(ua) &&
|
||||
!/SM-[ABDEFGJMNRWZ][0-9]+/i.test(ua) &&
|
||||
!/LG-[A-Z0-9]+/i.test(ua));
|
||||
|
||||
if (mobile1 || mobile2) {
|
||||
return 'mobile';
|
||||
|
||||
3
packages/common/vitest.config.ts
Normal file
3
packages/common/vitest.config.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { getSharedVitestConfig } from '../../vitest.shared';
|
||||
|
||||
export default getSharedVitestConfig({ __dirname });
|
||||
@@ -85,7 +85,7 @@ export function createLogger({ name }: { name: string }): ILogger {
|
||||
level: logLevel,
|
||||
format,
|
||||
transports,
|
||||
// silent: true,
|
||||
silent: process.env.NODE_ENV === 'test',
|
||||
// Add ISO levels of logging from PINO
|
||||
levels: Object.assign(
|
||||
{ fatal: 0, warn: 4, trace: 7 },
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
export * from './src/queues';
|
||||
export type * from './src/queues';
|
||||
export { findJobByPrefix } from './src/utils';
|
||||
export type { JobsOptions } from 'bullmq';
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import type { Queue } from 'bullmq';
|
||||
|
||||
export async function findJobByPrefix<T>(
|
||||
queue: Queue<T, any, string>,
|
||||
keys: string[],
|
||||
matcher: string,
|
||||
) {
|
||||
const getTime = (val?: string) => {
|
||||
if (!val) return null;
|
||||
const match = val.match(/:(\d+)$/);
|
||||
return match?.[1] ? Number.parseInt(match[1], 10) : null;
|
||||
};
|
||||
const filtered = keys
|
||||
.filter((key) => key.includes(matcher))
|
||||
.filter((key) => getTime(key));
|
||||
filtered.sort((a, b) => {
|
||||
const aTime = getTime(a);
|
||||
const bTime = getTime(b);
|
||||
if (aTime === null) return 1;
|
||||
if (bTime === null) return -1;
|
||||
return aTime - bTime;
|
||||
});
|
||||
|
||||
async function getJob(index: number) {
|
||||
if (index >= filtered.length) return null;
|
||||
|
||||
const key = filtered[index]?.replace(/^bull:(\w+):/, '');
|
||||
// return new Promise((resolve) => )
|
||||
if (key) {
|
||||
const job = await queue.getJob(key);
|
||||
if ((await job?.getState()) === 'delayed') {
|
||||
return job;
|
||||
}
|
||||
}
|
||||
|
||||
return getJob(index + 1);
|
||||
}
|
||||
|
||||
return getJob(0);
|
||||
}
|
||||
Reference in New Issue
Block a user