Skip to content

Commit

Permalink
feat: useBattery hook
Browse files Browse the repository at this point in the history
  • Loading branch information
congweibai committed Aug 26, 2024
1 parent 33fc55f commit 03ade52
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export * from "./useVisibilityChange";
export * from "./useObjectState";
export * from "./useDebounce";
export * from "./useHistoryState";
export * from "./useBattery";
1 change: 1 addition & 0 deletions src/hooks/useBattery/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./useBattery";
78 changes: 78 additions & 0 deletions src/hooks/useBattery/useBattery.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { renderHook, act } from "@testing-library/react-hooks";
import useBattery from "./useBattery"; // Adjust the path as needed
import { afterEach, beforeEach, describe, expect, it, Mock, vi } from "vitest";

type MockBattery = {
level: number;
charging: boolean;
chargingTime: number;
dischargingTime: number;
addEventListener: Mock;
removeEventListener: Mock;
};

describe("useBattery", () => {
let mockBattery: MockBattery;
let getBatteryMock: Mock;

beforeEach(() => {
// mock
mockBattery = {
level: 0.5,
charging: true,
chargingTime: 100,
dischargingTime: 200,
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
};

getBatteryMock = vi.fn().mockResolvedValue(mockBattery);
Object.defineProperty(navigator, "getBattery", {
value: getBatteryMock,
writable: true,
});
});

afterEach(() => {
vi.clearAllMocks();
});

it("should initialize with loading state", () => {
// act
const { result } = renderHook(() => useBattery());

// assert
expect(result.current.loading).toBe(true);
expect(result.current.supported).toBe(true);
});

it("should update battery state when getBattery is resolved", async () => {
// act
const { result, waitForNextUpdate } = renderHook(() => useBattery());

await waitForNextUpdate();

// assert
expect(result.current.loading).toBe(false);
expect(result.current.supported).toBe(true);
expect(result.current.level).toBe(0.5);
expect(result.current.charging).toBe(true);
expect(result.current.chargingTime).toBe(100);
expect(result.current.dischargingTime).toBe(200);
});

it("should update state when battery properties change", async () => {
// act
const { result, waitForNextUpdate } = renderHook(() => useBattery());

await waitForNextUpdate();

act(() => {
mockBattery.level = 0.7;
mockBattery.addEventListener.mock.calls[0][1](); // Trigger the event listener
});

// assert
expect(result.current.level).toBe(0.7);
});
});
67 changes: 67 additions & 0 deletions src/hooks/useBattery/useBattery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { useEffect, useState } from "react";

type BatteryState = {
supported: boolean;
loading: boolean;
level: number | null;
charging: boolean | null;
chargingTime: number | null;
dischargingTime: number | null;
};

export default function useBattery() {
const [batteryState, setBatteryState] = useState<BatteryState>({
supported: true,
loading: true,
level: null,
charging: null,
chargingTime: null,
dischargingTime: null,
});
useEffect(() => {
if (!navigator?.getBattery) {
setBatteryState((s) => ({
...s,
loading: false,
supported: false,
}));

return;
}
let battery: BatteryManager | null = null;

const handleBatteryChange = () => {
setBatteryState({
supported: true,
loading: false,
level: battery.level,
charging: battery.charging,
chargingTime: battery.chargingTime,
dischargingTime: battery.dischargingTime,
});
};

navigator.getBattery().then((b) => {
battery = b;
handleBatteryChange();
b.addEventListener("levelchange", handleBatteryChange);
b.addEventListener("chargingchange", handleBatteryChange);
b.addEventListener("chargingtimechange", handleBatteryChange);
b.addEventListener("dischargingtimechange", handleBatteryChange);
});

return () => {
if (battery) {
battery.removeEventListener("levelchange", handleBatteryChange);
battery.removeEventListener("chargingchange", handleBatteryChange);
battery.removeEventListener("chargingtimechange", handleBatteryChange);
battery.removeEventListener(
"dischargingtimechange",
handleBatteryChange
);
}
};
}, []);

return batteryState;
}

0 comments on commit 03ade52

Please sign in to comment.