@musecat/functionkit 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +17 -1
- package/packages/cookie/cookie.shared.ts +10 -2
- package/packages/utils/floatingMotion.ts +1 -3
- package/.agents/references/components/ScrolltoTop.md +0 -36
- package/.agents/references/components/SwitchCase.md +0 -47
- package/.agents/references/components/ViewportPortal.md +0 -34
- package/.agents/references/cookie/cookie.md +0 -47
- package/.agents/references/datetime/dateTime.client.md +0 -42
- package/.agents/references/datetime/dateTime.server.md +0 -42
- package/.agents/references/datetime/dateTime.shared.md +0 -86
- package/.agents/references/hooks/useAvoidKeyboard.md +0 -29
- package/.agents/references/hooks/useCheckInvisible.md +0 -36
- package/.agents/references/hooks/useCheckScroll.md +0 -36
- package/.agents/references/hooks/useClientDateTime.md +0 -39
- package/.agents/references/hooks/useDebounce.md +0 -46
- package/.agents/references/hooks/useDebouncedCallback.md +0 -34
- package/.agents/references/hooks/useDoubleClick.md +0 -40
- package/.agents/references/hooks/useGeolocation.md +0 -37
- package/.agents/references/hooks/useHasMounted.md +0 -27
- package/.agents/references/hooks/useIntersectionObserver.md +0 -41
- package/.agents/references/hooks/useInterval.md +0 -44
- package/.agents/references/hooks/useKeyboardHeight.md +0 -33
- package/.agents/references/hooks/useKeyboardListNavigation.md +0 -58
- package/.agents/references/hooks/useLongPress.md +0 -48
- package/.agents/references/hooks/usePreservedCallback.md +0 -37
- package/.agents/references/hooks/usePreservedReference.md +0 -34
- package/.agents/references/hooks/useRefEffect.md +0 -35
- package/.agents/references/hooks/useRelativeDateTime.md +0 -35
- package/.agents/references/hooks/useTimeout.md +0 -42
- package/.agents/references/hooks/useToggleState.md +0 -39
- package/.agents/references/hooks/useViewportHeight.md +0 -26
- package/.agents/references/hooks/useViewportMatch.md +0 -32
- package/.agents/references/utils/browserStorage.md +0 -41
- package/.agents/references/utils/buildContext.md +0 -47
- package/.agents/references/utils/clipboardShare.md +0 -59
- package/.agents/references/utils/floatingMotion.md +0 -67
- package/.agents/references/utils/getDeviceInfo.md +0 -43
- package/.agents/references/utils/isEditableKeyboardTarget.md +0 -35
- package/.agents/references/utils/mergeRefs.md +0 -29
- package/.agents/references/utils/seen.md +0 -37
- package/.agents/references/utils/subscribeKeyboardHeight.md +0 -35
- package/.gitattributes +0 -2
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -31
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -22
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -22
- package/.github/workflows/ci.yml +0 -20
- package/.local/state/gh/device-id +0 -1
- package/.prettierrc +0 -8
- package/AGENTS.md +0 -119
- package/CODE_OF_CONDUCT.md +0 -55
- package/CONTRIBUTING.md +0 -39
- package/biome.json +0 -25
- package/tests/components/ScrolltoTop.test.tsx +0 -15
- package/tests/components/SwitchCase.test.tsx +0 -33
- package/tests/components/ViewportPortal.test.tsx +0 -46
- package/tests/cookie/cookie.test.ts +0 -192
- package/tests/datetime/datetime.test.ts +0 -461
- package/tests/hooks/useAvoidKeyboard.test.ts +0 -43
- package/tests/hooks/useCheckInvisible.test.ts +0 -59
- package/tests/hooks/useCheckScroll.test.ts +0 -23
- package/tests/hooks/useClientDateTime.test.ts +0 -12
- package/tests/hooks/useDebounce.test.ts +0 -96
- package/tests/hooks/useDebouncedCallback.test.ts +0 -63
- package/tests/hooks/useDoubleClick.test.ts +0 -82
- package/tests/hooks/useGeolocation.test.ts +0 -201
- package/tests/hooks/useHasMounted.test.ts +0 -10
- package/tests/hooks/useIntersectionObserver.test.ts +0 -78
- package/tests/hooks/useInterval.test.ts +0 -56
- package/tests/hooks/useKeyboardHeight.test.ts +0 -10
- package/tests/hooks/useKeyboardListNavigation.test.ts +0 -404
- package/tests/hooks/useLongPress.test.ts +0 -214
- package/tests/hooks/usePreservedCallback.test.ts +0 -33
- package/tests/hooks/usePreservedReference.test.ts +0 -42
- package/tests/hooks/useRefEffect.test.ts +0 -67
- package/tests/hooks/useRelativeDateTime.test.ts +0 -21
- package/tests/hooks/useTimeout.test.ts +0 -72
- package/tests/hooks/useToggleState.test.ts +0 -43
- package/tests/hooks/useViewportHeight.test.ts +0 -32
- package/tests/hooks/useViewportMatch.test.ts +0 -35
- package/tests/setup.ts +0 -9
- package/tests/utils/browserStorage.test.ts +0 -114
- package/tests/utils/buildContext.test.tsx +0 -26
- package/tests/utils/checkDevice.test.ts +0 -140
- package/tests/utils/clipboardShare.test.ts +0 -152
- package/tests/utils/floatingMotion.test.ts +0 -135
- package/tests/utils/keyboardTarget.test.ts +0 -85
- package/tests/utils/mergeRefs.test.ts +0 -50
- package/tests/utils/seen.test.ts +0 -40
- package/tests/utils/subscribeKeyboardHeight.test.ts +0 -172
- package/tsconfig.json +0 -18
- package/vitest.config.ts +0 -22
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { act, renderHook } from "@testing-library/react";
|
|
2
|
-
import { describe, expect, test, vi } from "vitest";
|
|
3
|
-
import { useRefEffect } from "@/packages/hooks/useRefEffect";
|
|
4
|
-
|
|
5
|
-
describe("useRefEffect", () => {
|
|
6
|
-
test("calls callback with element and cleanup on unmount", () => {
|
|
7
|
-
const cleanup = vi.fn();
|
|
8
|
-
const callback = vi.fn(() => cleanup);
|
|
9
|
-
const { result } = renderHook(() => useRefEffect(callback, []));
|
|
10
|
-
|
|
11
|
-
const element = document.createElement("div");
|
|
12
|
-
act(() => {
|
|
13
|
-
(result.current as (el: HTMLElement | null) => void)(element);
|
|
14
|
-
});
|
|
15
|
-
expect(callback).toHaveBeenCalledWith(element);
|
|
16
|
-
|
|
17
|
-
act(() => {
|
|
18
|
-
(result.current as (el: HTMLElement | null) => void)(null);
|
|
19
|
-
});
|
|
20
|
-
expect(cleanup).toHaveBeenCalledOnce();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test("stores cleanup when callback returns a function", () => {
|
|
24
|
-
const cleanup = vi.fn();
|
|
25
|
-
const callback = vi.fn(() => cleanup);
|
|
26
|
-
const { result } = renderHook(() => useRefEffect(callback, []));
|
|
27
|
-
|
|
28
|
-
const element = document.createElement("div");
|
|
29
|
-
act(() => {
|
|
30
|
-
(result.current as (el: HTMLElement | null) => void)(element);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
act(() => {
|
|
34
|
-
(result.current as (el: HTMLElement | null) => void)(null);
|
|
35
|
-
});
|
|
36
|
-
expect(cleanup).toHaveBeenCalled();
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test("handles callback returning undefined (no cleanup)", () => {
|
|
40
|
-
const { result } = renderHook(() => useRefEffect(() => {}, []));
|
|
41
|
-
|
|
42
|
-
const element = document.createElement("div");
|
|
43
|
-
act(() => {
|
|
44
|
-
(result.current as (el: HTMLElement | null) => void)(element);
|
|
45
|
-
});
|
|
46
|
-
// Should not throw when cleanup is undefined
|
|
47
|
-
act(() => {
|
|
48
|
-
(result.current as (el: HTMLElement | null) => void)(null);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test("calls cleanup before setting new element", () => {
|
|
53
|
-
const cleanup = vi.fn();
|
|
54
|
-
const callback = vi.fn(() => cleanup);
|
|
55
|
-
const { result } = renderHook(() => useRefEffect(callback, []));
|
|
56
|
-
|
|
57
|
-
const el1 = document.createElement("div");
|
|
58
|
-
const el2 = document.createElement("span");
|
|
59
|
-
act(() => {
|
|
60
|
-
(result.current as (el: HTMLElement | null) => void)(el1);
|
|
61
|
-
});
|
|
62
|
-
act(() => {
|
|
63
|
-
(result.current as (el: HTMLElement | null) => void)(el2);
|
|
64
|
-
});
|
|
65
|
-
expect(cleanup).toHaveBeenCalledOnce();
|
|
66
|
-
});
|
|
67
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { renderHook } from "@testing-library/react";
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
3
|
-
import { useRelativeDateTime } from "@/packages/hooks/useRelativeDateTime";
|
|
4
|
-
|
|
5
|
-
describe("useRelativeDateTime", () => {
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
vi.useFakeTimers();
|
|
8
|
-
});
|
|
9
|
-
afterEach(() => {
|
|
10
|
-
vi.useRealTimers();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test("returns relative time text", () => {
|
|
14
|
-
const now = Date.now();
|
|
15
|
-
const fiveMinAgo = new Date(now - 5 * 60 * 1000).toISOString();
|
|
16
|
-
const { result } = renderHook(() => useRelativeDateTime(fiveMinAgo, { locale: "ko" }));
|
|
17
|
-
expect(result.current.ready).toBe(true);
|
|
18
|
-
expect(result.current.isRelative).toBe(true);
|
|
19
|
-
expect(result.current.text).toBeTruthy();
|
|
20
|
-
});
|
|
21
|
-
});
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { act, renderHook } from "@testing-library/react";
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
3
|
-
import { useTimeout } from "@/packages/hooks/useTimeout";
|
|
4
|
-
|
|
5
|
-
describe("useTimeout", () => {
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
vi.useFakeTimers();
|
|
8
|
-
});
|
|
9
|
-
afterEach(() => {
|
|
10
|
-
vi.useRealTimers();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test("calls callback after delay", () => {
|
|
14
|
-
const fn = vi.fn();
|
|
15
|
-
renderHook(() => useTimeout(fn, 100));
|
|
16
|
-
expect(fn).not.toHaveBeenCalled();
|
|
17
|
-
vi.advanceTimersByTime(100);
|
|
18
|
-
expect(fn).toHaveBeenCalledOnce();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test("does not call when disabled", () => {
|
|
22
|
-
const fn = vi.fn();
|
|
23
|
-
renderHook(() => useTimeout(fn, 100, { enabled: false }));
|
|
24
|
-
vi.advanceTimersByTime(200);
|
|
25
|
-
expect(fn).not.toHaveBeenCalled();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test("clear cancels pending timeout", () => {
|
|
29
|
-
const fn = vi.fn();
|
|
30
|
-
const { result } = renderHook(() => useTimeout(fn, 100));
|
|
31
|
-
|
|
32
|
-
act(() => {
|
|
33
|
-
result.current.clear();
|
|
34
|
-
});
|
|
35
|
-
vi.advanceTimersByTime(100);
|
|
36
|
-
expect(fn).not.toHaveBeenCalled();
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test("start and clear controls", () => {
|
|
40
|
-
const fn = vi.fn();
|
|
41
|
-
const { result } = renderHook(() => useTimeout(fn, 1000, { enabled: false }));
|
|
42
|
-
expect(result.current.isPending()).toBe(false);
|
|
43
|
-
act(() => {
|
|
44
|
-
result.current.start(50);
|
|
45
|
-
});
|
|
46
|
-
expect(result.current.isPending()).toBe(true);
|
|
47
|
-
vi.advanceTimersByTime(50);
|
|
48
|
-
expect(fn).toHaveBeenCalledOnce();
|
|
49
|
-
expect(result.current.isPending()).toBe(false);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test("reset restarts the timeout", () => {
|
|
53
|
-
const fn = vi.fn();
|
|
54
|
-
const { result } = renderHook(() => useTimeout(fn, 500));
|
|
55
|
-
vi.advanceTimersByTime(200);
|
|
56
|
-
act(() => {
|
|
57
|
-
result.current.reset(100);
|
|
58
|
-
});
|
|
59
|
-
vi.advanceTimersByTime(100);
|
|
60
|
-
expect(fn).toHaveBeenCalledOnce();
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test("start overrides default delay", () => {
|
|
64
|
-
const fn = vi.fn();
|
|
65
|
-
const { result } = renderHook(() => useTimeout(fn, 500, { enabled: false }));
|
|
66
|
-
act(() => {
|
|
67
|
-
result.current.start(50);
|
|
68
|
-
});
|
|
69
|
-
vi.advanceTimersByTime(50);
|
|
70
|
-
expect(fn).toHaveBeenCalledOnce();
|
|
71
|
-
});
|
|
72
|
-
});
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { act, renderHook } from "@testing-library/react";
|
|
2
|
-
import { describe, expect, test } from "vitest";
|
|
3
|
-
import { useToggleState } from "@/packages/hooks/useToggleState";
|
|
4
|
-
|
|
5
|
-
describe("useToggleState", () => {
|
|
6
|
-
test("initializes with false by default", () => {
|
|
7
|
-
const { result } = renderHook(() => useToggleState());
|
|
8
|
-
expect(result.current.value).toBe(false);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
test("initializes with provided value", () => {
|
|
12
|
-
const { result } = renderHook(() => useToggleState(true));
|
|
13
|
-
expect(result.current.value).toBe(true);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
test("setTrue sets value to true", () => {
|
|
17
|
-
const { result } = renderHook(() => useToggleState(false));
|
|
18
|
-
act(() => {
|
|
19
|
-
result.current.setTrue();
|
|
20
|
-
});
|
|
21
|
-
expect(result.current.value).toBe(true);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test("setFalse sets value to false", () => {
|
|
25
|
-
const { result } = renderHook(() => useToggleState(true));
|
|
26
|
-
act(() => {
|
|
27
|
-
result.current.setFalse();
|
|
28
|
-
});
|
|
29
|
-
expect(result.current.value).toBe(false);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("toggle switches value", () => {
|
|
33
|
-
const { result } = renderHook(() => useToggleState(false));
|
|
34
|
-
act(() => {
|
|
35
|
-
result.current.toggle();
|
|
36
|
-
});
|
|
37
|
-
expect(result.current.value).toBe(true);
|
|
38
|
-
act(() => {
|
|
39
|
-
result.current.toggle();
|
|
40
|
-
});
|
|
41
|
-
expect(result.current.value).toBe(false);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { act, renderHook } from "@testing-library/react";
|
|
2
|
-
import { describe, expect, test, vi } from "vitest";
|
|
3
|
-
import { useViewportHeight } from "@/packages/hooks/useViewportHeight";
|
|
4
|
-
|
|
5
|
-
describe("useViewportHeight", () => {
|
|
6
|
-
test("returns a height value", () => {
|
|
7
|
-
const { result } = renderHook(() => useViewportHeight());
|
|
8
|
-
expect(result.current.height).toBeGreaterThanOrEqual(0);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
test("updates height on window resize", () => {
|
|
12
|
-
const { result } = renderHook(() => useViewportHeight());
|
|
13
|
-
|
|
14
|
-
act(() => {
|
|
15
|
-
window.innerHeight = 500;
|
|
16
|
-
window.dispatchEvent(new Event("resize"));
|
|
17
|
-
});
|
|
18
|
-
expect(result.current.height).toBe(500);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test("removes event listeners on unmount", () => {
|
|
22
|
-
const addResize = vi.spyOn(window, "addEventListener");
|
|
23
|
-
const removeResize = vi.spyOn(window, "removeEventListener");
|
|
24
|
-
|
|
25
|
-
const { unmount } = renderHook(() => useViewportHeight());
|
|
26
|
-
unmount();
|
|
27
|
-
|
|
28
|
-
expect(removeResize).toHaveBeenCalledWith("resize", expect.any(Function));
|
|
29
|
-
addResize.mockRestore();
|
|
30
|
-
removeResize.mockRestore();
|
|
31
|
-
});
|
|
32
|
-
});
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { renderHook } from "@testing-library/react";
|
|
2
|
-
import { beforeEach, describe, expect, test, vi } from "vitest";
|
|
3
|
-
import { useViewportMatch } from "@/packages/hooks/useViewportMatch";
|
|
4
|
-
|
|
5
|
-
describe("useViewportMatch", () => {
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
vi.stubGlobal(
|
|
8
|
-
"matchMedia",
|
|
9
|
-
vi.fn().mockImplementation((query: string) => ({
|
|
10
|
-
matches: false,
|
|
11
|
-
media: query,
|
|
12
|
-
addEventListener: vi.fn(),
|
|
13
|
-
removeEventListener: vi.fn(),
|
|
14
|
-
})),
|
|
15
|
-
);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test("returns false initially", () => {
|
|
19
|
-
const { result } = renderHook(() => useViewportMatch("(min-width: 768px)"));
|
|
20
|
-
expect(result.current).toBe(false);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test("returns true when matched", () => {
|
|
24
|
-
vi.stubGlobal(
|
|
25
|
-
"matchMedia",
|
|
26
|
-
vi.fn().mockImplementation(() => ({
|
|
27
|
-
matches: true,
|
|
28
|
-
addEventListener: vi.fn(),
|
|
29
|
-
removeEventListener: vi.fn(),
|
|
30
|
-
})),
|
|
31
|
-
);
|
|
32
|
-
const { result } = renderHook(() => useViewportMatch("(min-width: 768px)"));
|
|
33
|
-
expect(result.current).toBe(true);
|
|
34
|
-
});
|
|
35
|
-
});
|
package/tests/setup.ts
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
getLocalStorage,
|
|
4
|
-
getSessionStorage,
|
|
5
|
-
removeLocalStorage,
|
|
6
|
-
removeSessionStorage,
|
|
7
|
-
updateLocalStorage,
|
|
8
|
-
updateSessionStorage,
|
|
9
|
-
} from "@/packages/utils/browserStorage";
|
|
10
|
-
|
|
11
|
-
describe("browserStorage", () => {
|
|
12
|
-
let mockStorage: Record<string, string>;
|
|
13
|
-
let mockStorage2: Record<string, string>;
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
mockStorage = {};
|
|
17
|
-
mockStorage2 = {};
|
|
18
|
-
|
|
19
|
-
const createMockStorage = (store: Record<string, string>) => ({
|
|
20
|
-
getItem: vi.fn((key) => store[key] ?? null),
|
|
21
|
-
setItem: vi.fn((key, value) => {
|
|
22
|
-
store[key] = value.toString();
|
|
23
|
-
}),
|
|
24
|
-
removeItem: vi.fn((key) => {
|
|
25
|
-
delete store[key];
|
|
26
|
-
}),
|
|
27
|
-
clear: vi.fn(() => {
|
|
28
|
-
Object.keys(store).forEach((k) => delete store[k]);
|
|
29
|
-
}),
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
vi.stubGlobal("localStorage", createMockStorage(mockStorage));
|
|
33
|
-
vi.stubGlobal("sessionStorage", createMockStorage(mockStorage2));
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
afterEach(() => {
|
|
37
|
-
vi.unstubAllGlobals();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test("localStorage operations", () => {
|
|
41
|
-
updateLocalStorage("foo", { bar: "baz" });
|
|
42
|
-
expect(localStorage.getItem("foo")).toBe('{"bar":"baz"}');
|
|
43
|
-
expect(getLocalStorage("foo")).toEqual({ bar: "baz" });
|
|
44
|
-
|
|
45
|
-
removeLocalStorage("foo");
|
|
46
|
-
expect(getLocalStorage("foo")).toBeNull();
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test("sessionStorage operations", () => {
|
|
50
|
-
updateSessionStorage("foo", { bar: "baz" });
|
|
51
|
-
expect(sessionStorage.getItem("foo")).toBe('{"bar":"baz"}');
|
|
52
|
-
expect(getSessionStorage("foo")).toEqual({ bar: "baz" });
|
|
53
|
-
|
|
54
|
-
removeSessionStorage("foo");
|
|
55
|
-
expect(getSessionStorage("foo")).toBeNull();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("handles invalid json gracefully", () => {
|
|
59
|
-
localStorage.setItem("invalid", "not-json");
|
|
60
|
-
expect(getLocalStorage("invalid")).toBeNull();
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test("returns null when window is undefined (SSR)", () => {
|
|
64
|
-
const win = global.window;
|
|
65
|
-
// @ts-expect-error
|
|
66
|
-
delete global.window;
|
|
67
|
-
expect(getLocalStorage("foo")).toBeNull();
|
|
68
|
-
expect(getSessionStorage("foo")).toBeNull();
|
|
69
|
-
updateLocalStorage("foo", "bar");
|
|
70
|
-
global.window = win;
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test("handles storage setItem throwing", () => {
|
|
74
|
-
const storage = localStorage;
|
|
75
|
-
vi.spyOn(storage, "setItem").mockImplementation(() => {
|
|
76
|
-
throw new Error("QuotaExceededError");
|
|
77
|
-
});
|
|
78
|
-
updateLocalStorage("foo", "bar");
|
|
79
|
-
expect(storage.setItem).toHaveBeenCalled();
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
test("removeStorage handles missing storage gracefully", () => {
|
|
83
|
-
const win = global.window;
|
|
84
|
-
// @ts-expect-error
|
|
85
|
-
delete global.window;
|
|
86
|
-
removeLocalStorage("foo");
|
|
87
|
-
removeSessionStorage("foo");
|
|
88
|
-
global.window = win;
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test("getLocalStorage returns null when getItem throws", () => {
|
|
92
|
-
const storage = localStorage;
|
|
93
|
-
vi.spyOn(storage, "getItem").mockImplementation(() => {
|
|
94
|
-
throw new Error("StorageError");
|
|
95
|
-
});
|
|
96
|
-
expect(getLocalStorage("foo")).toBeNull();
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test("removeLocalStorage handles removeItem throwing", () => {
|
|
100
|
-
const storage = localStorage;
|
|
101
|
-
vi.spyOn(storage, "removeItem").mockImplementation(() => {
|
|
102
|
-
throw new Error("StorageError");
|
|
103
|
-
});
|
|
104
|
-
expect(() => removeLocalStorage("foo")).not.toThrow();
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("getLocalStorage returns null for non-existent key", () => {
|
|
108
|
-
expect(getLocalStorage("non-existent-key")).toBeNull();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
test("sessionStorage returns null for non-existent key", () => {
|
|
112
|
-
expect(getSessionStorage("non-existent-key")).toBeNull();
|
|
113
|
-
});
|
|
114
|
-
});
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { render, screen } from "@testing-library/react";
|
|
2
|
-
import { describe, expect, test } from "vitest";
|
|
3
|
-
import { buildContext } from "@/packages/utils/buildContext";
|
|
4
|
-
|
|
5
|
-
describe("buildContext", () => {
|
|
6
|
-
const [Provider, useValue] = buildContext<string>("default");
|
|
7
|
-
|
|
8
|
-
function TestComponent() {
|
|
9
|
-
const val = useValue();
|
|
10
|
-
return <div data-testid="val">{val}</div>;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
test("returns default value when not wrapped in provider", () => {
|
|
14
|
-
render(<TestComponent />);
|
|
15
|
-
expect(screen.getByTestId("val").textContent).toBe("default");
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test("returns provided value", () => {
|
|
19
|
-
render(
|
|
20
|
-
<Provider value="provided">
|
|
21
|
-
<TestComponent />
|
|
22
|
-
</Provider>,
|
|
23
|
-
);
|
|
24
|
-
expect(screen.getByTestId("val").textContent).toBe("provided");
|
|
25
|
-
});
|
|
26
|
-
});
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, test } from "vitest";
|
|
2
|
-
import { getDeviceInfo } from "@/packages/utils/checkDevice";
|
|
3
|
-
|
|
4
|
-
describe("getDeviceInfo", () => {
|
|
5
|
-
const originalUserAgent = navigator.userAgent;
|
|
6
|
-
|
|
7
|
-
afterEach(() => {
|
|
8
|
-
Object.defineProperty(navigator, "userAgent", {
|
|
9
|
-
value: originalUserAgent,
|
|
10
|
-
writable: true,
|
|
11
|
-
configurable: true,
|
|
12
|
-
});
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
test("returns default values in SSR (no window)", () => {
|
|
16
|
-
const win = global.window;
|
|
17
|
-
(global as any).window = undefined;
|
|
18
|
-
const info = getDeviceInfo();
|
|
19
|
-
expect(info.isMobile).toBe(false);
|
|
20
|
-
expect(info.browser).toBe("unknown");
|
|
21
|
-
global.window = win;
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test("detects mobile Chrome", () => {
|
|
25
|
-
Object.defineProperty(navigator, "userAgent", {
|
|
26
|
-
value:
|
|
27
|
-
"Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36",
|
|
28
|
-
writable: true,
|
|
29
|
-
configurable: true,
|
|
30
|
-
});
|
|
31
|
-
const info = getDeviceInfo();
|
|
32
|
-
expect(info.isMobile).toBe(true);
|
|
33
|
-
expect(info.isAndroid).toBe(true);
|
|
34
|
-
expect(info.browser).toBe("chrome");
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
test("detects iOS Safari", () => {
|
|
38
|
-
Object.defineProperty(navigator, "userAgent", {
|
|
39
|
-
value:
|
|
40
|
-
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",
|
|
41
|
-
writable: true,
|
|
42
|
-
configurable: true,
|
|
43
|
-
});
|
|
44
|
-
const info = getDeviceInfo();
|
|
45
|
-
expect(info.isMobile).toBe(true);
|
|
46
|
-
expect(info.isIOS).toBe(true);
|
|
47
|
-
expect(info.isSafari).toBe(true);
|
|
48
|
-
expect(info.isIOSSafari).toBe(true);
|
|
49
|
-
expect(info.browser).toBe("safari");
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test("detects desktop Chrome", () => {
|
|
53
|
-
Object.defineProperty(navigator, "userAgent", {
|
|
54
|
-
value:
|
|
55
|
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
56
|
-
writable: true,
|
|
57
|
-
configurable: true,
|
|
58
|
-
});
|
|
59
|
-
const info = getDeviceInfo();
|
|
60
|
-
expect(info.isMobile).toBe(false);
|
|
61
|
-
expect(info.browser).toBe("chrome");
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test("detects Mac Safari", () => {
|
|
65
|
-
Object.defineProperty(navigator, "userAgent", {
|
|
66
|
-
value:
|
|
67
|
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/604.1",
|
|
68
|
-
writable: true,
|
|
69
|
-
configurable: true,
|
|
70
|
-
});
|
|
71
|
-
const info = getDeviceInfo();
|
|
72
|
-
expect(info.isMobile).toBe(false);
|
|
73
|
-
expect(info.isMacSafari).toBe(true);
|
|
74
|
-
expect(info.isSafari).toBe(true);
|
|
75
|
-
expect(info.browser).toBe("safari");
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test("detects Firefox browser", () => {
|
|
79
|
-
Object.defineProperty(navigator, "userAgent", {
|
|
80
|
-
value: "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0",
|
|
81
|
-
writable: true,
|
|
82
|
-
configurable: true,
|
|
83
|
-
});
|
|
84
|
-
const info = getDeviceInfo();
|
|
85
|
-
expect(info.browser).toBe("firefox");
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("detects Edge browser", () => {
|
|
89
|
-
Object.defineProperty(navigator, "userAgent", {
|
|
90
|
-
value:
|
|
91
|
-
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/44.18362.1.0",
|
|
92
|
-
writable: true,
|
|
93
|
-
configurable: true,
|
|
94
|
-
});
|
|
95
|
-
const info = getDeviceInfo();
|
|
96
|
-
expect(info.browser).toBe("edge");
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test("returns unknown browser for unrecognized UA", () => {
|
|
100
|
-
Object.defineProperty(navigator, "userAgent", {
|
|
101
|
-
value: "SomeUnknownBrowser/1.0",
|
|
102
|
-
writable: true,
|
|
103
|
-
configurable: true,
|
|
104
|
-
});
|
|
105
|
-
const info = getDeviceInfo();
|
|
106
|
-
expect(info.browser).toBe("unknown");
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
test("detects Samsung Browser", () => {
|
|
110
|
-
Object.defineProperty(navigator, "userAgent", {
|
|
111
|
-
value:
|
|
112
|
-
"Mozilla/5.0 (Linux; Android 14) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/24.0 Chrome/120.0.6099.230 Mobile Safari/537.36",
|
|
113
|
-
writable: true,
|
|
114
|
-
configurable: true,
|
|
115
|
-
});
|
|
116
|
-
const info = getDeviceInfo();
|
|
117
|
-
expect(info.isSamsungBrowser).toBe(true);
|
|
118
|
-
expect(info.browser).toBe("samsung");
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
test("detects isTouchDevice correctly", () => {
|
|
122
|
-
const hasTouch = "ontouchstart" in window;
|
|
123
|
-
const info = getDeviceInfo();
|
|
124
|
-
expect(info.isTouchDevice).toBe(hasTouch);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test("detects desktop Safari correctly distinguishes from mobile", () => {
|
|
128
|
-
Object.defineProperty(navigator, "userAgent", {
|
|
129
|
-
value:
|
|
130
|
-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/604.1",
|
|
131
|
-
writable: true,
|
|
132
|
-
configurable: true,
|
|
133
|
-
});
|
|
134
|
-
const info = getDeviceInfo();
|
|
135
|
-
expect(info.isSafari).toBe(true);
|
|
136
|
-
expect(info.isMacSafari).toBe(true);
|
|
137
|
-
expect(info.isIOSSafari).toBe(false);
|
|
138
|
-
expect(info.isMobile).toBe(false);
|
|
139
|
-
});
|
|
140
|
-
});
|