Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A comprehensive collection of TypeScript utility functions for modern web develo

## Features

- 🛠️ **Comprehensive**: String, object, cookie, number, validation, format, search query, and common utilities
- 🛠️ **Comprehensive**: String, object, cookie, number, validation, format, search query, device, and common utilities
- 📦 **Tree-shakable**: Import only what you need
- 🔒 **Type-safe**: Full TypeScript support with type definitions
- ⚡ **Lightweight**: Minimal dependencies and optimized for performance
Expand Down Expand Up @@ -32,6 +32,7 @@ import {
commonUtil,
formatUtil,
searchQueryUtil,
deviceUtil,
} from "kr-corekit";

// String utilities
Expand Down Expand Up @@ -72,6 +73,9 @@ const copied = await commonUtil.copyToClipboard("Hello, World!"); // true if suc
// Search Query utilities
const queryParams = searchQueryUtil.getAllQuery(); // { key: ["value1", "value2"], id: "123" }

// Device utilities
const device = deviceUtil.getDevice(); // { isMobile: false, isTablet: false, isDesktop: true, isIOS: false, isAndroid: false }

// Cookie utilities
cookieUtil.setCookie("theme", "dark");
const theme = cookieUtil.getCookie("theme");
Expand Down Expand Up @@ -121,6 +125,10 @@ const formattedPhone = formatUtil.formatPhoneNumber("01012345678"); // "010-1234

- `getAllQuery(): Record<string, string | string[]>` - Parses the current URL's query string and returns an object with key-value pairs. Values appear as arrays when the same key is used multiple times.

### DeviceUtil

- `getDevice(): DeviceInfo` - Detects the user's device environment. Returns information about device type (mobile/tablet/desktop) and operating system (iOS/Android). Uses navigator.userAgent for detection and provides safe fallback for SSR environments.

### CookieUtil

- `setCookie(name: string, value: string, options?: object): void` - Sets a cookie
Expand Down
83 changes: 83 additions & 0 deletions package/deviceUtil/getDevice/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* vitest가 JSDOM을 사용하여 브라우저 환경을 시뮬레이션하도록 설정합니다.
* 이를 통해 테스트 환경에서 window, navigator 등의 객체를 사용할 수 있습니다.
*
* @vitest-environment jsdom
*/
import { describe, test, expect, afterEach } from "vitest";
import getDevice from ".";

describe("getDevice", () => {
// userAgent를 테스트 케이스마다 다르게 설정하기 위한 헬퍼 함수
const mockUserAgent = (userAgent: string) => {
// JSDOM이 생성한 window.navigator 객체의 userAgent 속성을 덮어씁니다.
Object.defineProperty(window.navigator, "userAgent", {
value: userAgent,
writable: true,
configurable: true,
});
};

// 각 테스트가 끝난 후, 다음 테스트에 영향을 주지 않도록 userAgent를 초기화합니다.
afterEach(() => {
mockUserAgent("");
});

describe("클라이언트 (브라우저) 환경", () => {
describe("데스크톱", () => {
test("Windows Chrome User Agent를 데스크톱으로 인식해야 합니다", () => {
mockUserAgent(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
);
const { isDesktop, isMobile, isTablet } = getDevice();
expect(isDesktop).toBe(true);
expect(isMobile).toBe(false);
expect(isTablet).toBe(false);
});
});

describe("모바일", () => {
test("iPhone User Agent를 모바일 및 iOS로 인식해야 합니다", () => {
mockUserAgent(
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
);
const { isMobile, isIOS, isDesktop } = getDevice();
expect(isMobile).toBe(true);
expect(isIOS).toBe(true);
expect(isDesktop).toBe(false);
});

test("Android Phone User Agent를 모바일 및 Android로 인식해야 합니다", () => {
mockUserAgent(
"Mozilla/5.0 (Linux; Android 13; SM-S908B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36"
);
const { isMobile, isAndroid, isTablet } = getDevice();
expect(isMobile).toBe(true);
expect(isAndroid).toBe(true);
expect(isTablet).toBe(false);
});
});

describe("태블릿", () => {
test("iPad User Agent를 태블릿 및 iOS로 인식해야 합니다", () => {
mockUserAgent(
"Mozilla/5.0 (iPad; CPU OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1"
);
const { isTablet, isIOS, isMobile } = getDevice();
expect(isTablet).toBe(true);
expect(isIOS).toBe(true);
expect(isMobile).toBe(false);
});

test("Android Tablet User Agent를 태블릿 및 Android로 인식해야 합니다", () => {
mockUserAgent(
"Mozilla/5.0 (Linux; Android 12; SM-X906C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.99 Safari/537.36"
);
const { isTablet, isAndroid, isMobile } = getDevice();
expect(isTablet).toBe(true);
expect(isAndroid).toBe(true);
expect(isMobile).toBe(false);
});
});
});
});
33 changes: 33 additions & 0 deletions package/deviceUtil/getDevice/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* @typedef {object} DeviceInfo
* @property {boolean} isMobile - 모바일 디바이스 여부
* @property {boolean} isTablet - 태블릿 디바이스 여부
* @property {boolean} isDesktop - 데스크톱 디바이스 여부
* @property {boolean} isIOS - iOS 운영체제 여부
* @property {boolean} isAndroid - 안드로이드 운영체제 여부
*/

/**
* 사용자의 디바이스 환경 정보를 반환합니다.
* window.navigator.userAgent를 기반으로 분석하며, 클라이언트 사이드에서만 정확한 값을 반환합니다.
*
* @returns {DeviceInfo} 디바이스 환경 정보 객체
*/
export default function getDevice() {
// * ----- 클라이언트 환경일 경우, 실행 ----- * //
const userAgent = window.navigator.userAgent;

const isIOS = /iPhone|iPad|iPod/i.test(userAgent);

const isAndroid = /Android/i.test(userAgent);

const isTablet = /(iPad)|(tablet)|(android(?!.*mobi))/i.test(userAgent);

const isMobile =
!isTablet &&
/Mobi|iP(hone|od)|Android|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);

const isDesktop = !isMobile && !isTablet;

return { isMobile, isTablet, isDesktop, isIOS, isAndroid };
}
1 change: 1 addition & 0 deletions package/deviceUtil/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as getDevice } from "./getDevice";
Loading