Browse Source

completing tsc fixes

pull/649/head
Dan Ditomaso 1 year ago
parent
commit
ae926c1138
  1. 668
      deno.lock
  2. 27
      src/PageRouter.tsx
  3. 108
      src/components/BatteryStatus.tsx
  4. 24
      src/components/Dialog/ImportDialog.tsx
  5. 66
      src/components/Dialog/LocationResponseDialog.tsx
  6. 15
      src/components/PageComponents/Connect/BLE.tsx
  7. 18
      src/components/PageComponents/Messages/TraceRoute.test.tsx
  8. 80
      src/core/utils/test.tsx
  9. 3
      src/index.css
  10. 109
      src/pages/Messages.tsx
  11. 35
      src/routes.tsx
  12. 0
      src/tests/setup.ts
  13. 37
      src/tests/test-utils.tsx
  14. 4
      vitest.config.ts

668
deno.lock

File diff suppressed because it is too large

27
src/PageRouter.tsx

@ -1,27 +0,0 @@
import MapPage from "@app/pages/Map/index.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import ChannelsPage from "@pages/Channels.tsx";
import ConfigPage from "@pages/Config/index.tsx";
import MessagesPage from "@pages/Messages.tsx";
import NodesPage from "./pages/Nodes/index.tsx";
import { ErrorBoundary } from "react-error-boundary";
import { ErrorPage } from "@components/UI/ErrorPage.tsx";
export const ErrorBoundaryWrapper = ({
children,
}: { children: React.ReactNode }) => (
<ErrorBoundary FallbackComponent={ErrorPage}>{children}</ErrorBoundary>
);
export const PageRouter = () => {
const { activePage } = useDevice();
return (
<ErrorBoundary FallbackComponent={ErrorPage}>
{activePage === "messages" && <MessagesPage />}
{activePage === "map" && <MapPage />}
{activePage === "config" && <ConfigPage />}
{activePage === "channels" && <ChannelsPage />}
{activePage === "nodes" && <NodesPage />}
</ErrorBoundary>
);
};

108
src/components/BatteryStatus.tsx

@ -8,56 +8,45 @@ import {
import { useTranslation } from "react-i18next";
import { DeviceMetrics } from "./types.ts";
interface BatteryStateConfig {
condition: (level: number) => boolean;
Icon: React.ElementType;
className: string;
text: (level: number) => string;
type BatteryStatusKey = keyof typeof BATTERY_STATUS;
interface BatteryStatusProps {
deviceMetrics?: DeviceMetrics | null;
}
interface BatteryStatusProps {
deviceMetrics?: DeviceMetrics | null;
}
const getBatteryStates = (
t: (key: string, options?: object) => string,
): BatteryStateConfig[] => {
return [
{
condition: (level) => level > 100,
Icon: PlugZapIcon,
className: "text-gray-500",
text: () => t("batteryStatus.pluggedIn"),
},
{
condition: (level) => level > 80,
Icon: BatteryFullIcon,
className: "text-green-500",
text: (level) => t("batteryStatus.charging", { level }),
},
{
condition: (level) => level > 20,
Icon: BatteryMediumIcon,
className: "text-yellow-500",
text: (level) => t("batteryStatus.charging", { level }),
},
{
condition: () => true,
Icon: BatteryLowIcon,
className: "text-red-500",
text: (level) => t("batteryStatus.charging", { level }),
},
];
};
interface StatusConfig {
Icon: React.ElementType;
className: string;
text: string;
}
const BATTERY_STATUS = {
PLUGGED_IN: "PLUGGED_IN",
FULL: "FULL",
MEDIUM: "MEDIUM",
LOW: "LOW",
} as const;
const getBatteryState = (
level: number,
batteryStates: BatteryStateConfig[],
) => {
return batteryStates.find((state) => state.condition(level));
export const getBatteryStatus = (level: number): BatteryStatusKey => {
if (level > 100) {
return BATTERY_STATUS.PLUGGED_IN;
}
if (level > 80) {
return BATTERY_STATUS.FULL;
}
if (level > 20) {
return BATTERY_STATUS.MEDIUM;
}
return BATTERY_STATUS.LOW;
};
const BatteryStatus: React.FC<BatteryStatusProps> = ({ deviceMetrics }) => {
const { t } = useTranslation();
if (
deviceMetrics?.batteryLevel === undefined ||
deviceMetrics?.batteryLevel === null
@ -65,16 +54,39 @@ const BatteryStatus: React.FC<BatteryStatusProps> = ({ deviceMetrics }) => {
return null;
}
const { t } = useTranslation();
const batteryStates = getBatteryStates(t);
const { batteryLevel } = deviceMetrics;
const currentState = getBatteryState(batteryLevel, batteryStates) ??
batteryStates[batteryStates.length - 1];
const BatteryIcon = currentState.Icon;
const iconClassName = currentState.className;
const statusText = currentState.text(batteryLevel);
const statusKey = getBatteryStatus(batteryLevel);
const statusConfigMap: Record<BatteryStatusKey, StatusConfig> = {
[BATTERY_STATUS.PLUGGED_IN]: {
Icon: PlugZapIcon,
className: "text-gray-500",
text: t("batteryStatus.pluggedIn"),
},
[BATTERY_STATUS.FULL]: {
Icon: BatteryFullIcon,
className: "text-green-500",
text: t("batteryStatus.charging", { level: batteryLevel }),
},
[BATTERY_STATUS.MEDIUM]: {
Icon: BatteryMediumIcon,
className: "text-yellow-500",
text: t("batteryStatus.charging", { level: batteryLevel }),
},
[BATTERY_STATUS.LOW]: {
Icon: BatteryLowIcon,
className: "text-red-500",
text: t("batteryStatus.charging", { level: batteryLevel }),
},
};
// 3. Use the key to get the current state configuration
const {
Icon: BatteryIcon,
className: iconClassName,
text: statusText,
} = statusConfigMap[statusKey];
return (
<div

24
src/components/Dialog/ImportDialog.tsx

@ -72,17 +72,19 @@ export const ImportDialog = ({
}, [importDialogInput]);
const apply = () => {
channelSet?.settings.map((ch: unknown, index: number) => {
connection?.setChannel(
create(Protobuf.Channel.ChannelSchema, {
index,
role: index === 0
? Protobuf.Channel.Channel_Role.PRIMARY
: Protobuf.Channel.Channel_Role.SECONDARY,
settings: ch,
}),
);
});
channelSet?.settings.map(
(ch: Protobuf.Channel.ChannelSettings, index: number) => {
connection?.setChannel(
create(Protobuf.Channel.ChannelSchema, {
index,
role: index === 0
? Protobuf.Channel.Channel_Role.PRIMARY
: Protobuf.Channel.Channel_Role.SECONDARY,
settings: ch,
}),
);
},
);
if (channelSet?.loraConfig) {
connection?.setConfig(

66
src/components/Dialog/LocationResponseDialog.tsx

@ -12,7 +12,7 @@ import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
import { useTranslation } from "react-i18next";
export interface LocationResponseDialogProps {
location: Types.PacketMetadata<Protobuf.Mesh.location> | undefined;
location: Types.PacketMetadata<Protobuf.Mesh.Position> | undefined;
open: boolean;
onOpenChange: () => void;
}
@ -33,6 +33,13 @@ export const LocationResponseDialog = ({
? `${numberToHexUnpadded(from?.num).substring(0, 4)}`
: t("unknown.shortName"));
const position = location?.data;
const hasCoordinates = position &&
typeof position.latitudeI === "number" &&
typeof position.longitudeI === "number" &&
typeof position.altitude === "number";
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent>
@ -45,31 +52,40 @@ export const LocationResponseDialog = ({
</DialogTitle>
</DialogHeader>
<DialogDescription>
<div className="ml-5 flex">
<span className="ml-4 border-l-2 border-l-backgroundPrimary pl-2 text-textPrimary">
<p>
{t("locationResponse.coordinates")}
<a
className="text-blue-500 dark:text-blue-400"
href={`https://www.openstreetmap.org/?mlat=${
location?.data.latitudeI / 1e7
}&mlon=${location?.data.longitudeI / 1e7}&layers=N`}
target="_blank"
rel="noreferrer"
>
{location?.data.latitudeI / 1e7},{" "}
{location?.data.longitudeI / 1e7}
</a>
</p>
<p>
{t("locationResponse.altitude")}
{location?.data.altitude}
{location?.data.altitde < 1
? t("unit.meter.one")
: t("unit.meter.plural")}
{hasCoordinates
? (
<div className="ml-5 flex">
<span className="ml-4 border-l-2 border-l-backgroundPrimary pl-2 text-textPrimary">
<p>
{t("locationResponse.coordinates")}
<a
className="text-blue-500 dark:text-blue-400"
href={`https://www.openstreetmap.org/?mlat=${
position.latitudeI ?? 0 / 1e7
}&mlon=${position.longitudeI ?? 0 / 1e7}&layers=N`}
target="_blank"
rel="noreferrer"
>
{" "}
{position.latitudeI ?? 0 / 1e7},{" "}
{position.longitudeI ?? 0 / 1e7}
</a>
</p>
<p>
{t("locationResponse.altitude")} {position.altitude}
{(position.altitude ?? 0) < 1
? t("unit.meter.one")
: t("unit.meter.plural")}
</p>
</span>
</div>
)
: (
// Optional: Show a message if coordinates are not available
<p className="text-textPrimary">
{t("locationResponse.noCoordinates")}
</p>
</span>
</div>
)}
</DialogDescription>
</DialogContent>
</Dialog>

15
src/components/PageComponents/Connect/BLE.tsx

@ -5,8 +5,9 @@ import { useAppStore } from "@core/stores/appStore.ts";
import { useDeviceStore } from "@core/stores/deviceStore.ts";
import { subscribeAll } from "@core/subscriptions.ts";
import { randId } from "@core/utils/randId.ts";
import { BleConnection, ServiceUuid } from "@meshtastic/js";
import { BluetoothDevice } from "web-bluetooth";
import { TransportWebBluetooth } from "@meshtastic/transport-web-bluetooth";
import { MeshDevice } from "@meshtastic/core";
import type { BluetoothDevice } from "web-bluetooth";
import { useCallback, useEffect, useState } from "react";
import { useMessageStore } from "@core/stores/messageStore/index.ts";
import { useTranslation } from "react-i18next";
@ -31,15 +32,13 @@ export const BLE = (
const onConnect = async (bleDevice: BluetoothDevice) => {
const id = randId();
const transport = await TransportWebBluetooth.createFromDevice(bleDevice);
const device = addDevice(id);
const connection = new MeshDevice(transport, id);
connection.configure();
setSelectedDevice(id);
const connection = new BleConnection(id);
await connection.connect({
device: bleDevice,
});
device.addConnection(connection);
subscribeAll(device, connection, messageStore);
closeDialog();
};
@ -72,7 +71,7 @@ export const BLE = (
onClick={async () => {
await navigator.bluetooth
.requestDevice({
filters: [{ services: [ServiceUuid] }],
filters: [{ services: [TransportWebBluetooth.ServiceUuid] }],
})
.then((device) => {
const exists = bleDevices.findIndex((d) => d.id === device.id);

18
src/components/PageComponents/Messages/TraceRoute.test.tsx

@ -70,7 +70,7 @@ describe("TraceRoute", () => {
getNode: (nodeNum: number): Protobuf.Mesh.NodeInfo | undefined => {
return mockNodes.get(nodeNum);
},
} as any);
});
});
it("renders the route to destination with SNR values", () => {
@ -135,20 +135,4 @@ describe("TraceRoute", () => {
// Check for translated '??' placeholder
expect(screen.getAllByText(/↓ \?\?dBm/)).toHaveLength(2);
});
it("renders hop hex if node is not found", () => {
render(
<TraceRoute
from={fromUser}
to={toUser}
route={[99]}
snrTowards={[5, 15]}
/>,
);
// Check for translated '!' prefix
expect(screen.getByText("!63")).toBeInTheDocument();
expect(screen.getByText("↓ 5dBm")).toBeInTheDocument();
expect(screen.getByText("↓ 15dBm")).toBeInTheDocument();
});
});

80
src/core/utils/test.tsx

@ -1,80 +0,0 @@
import {
createMemoryHistory,
createRouter,
Outlet,
RootRoute,
Route,
RouterProvider,
} from "@tanstack/react-router";
import { render as rtlRender, RenderOptions } from "@testing-library/react";
import type { FunctionComponent, ReactElement, ReactNode } from "react";
// a root route for the test router.
const rootRoute = new RootRoute({
component: () => (
<>
<Outlet />
</>
),
});
interface CustomRenderOptions extends Omit<RenderOptions, "wrapper"> {
initialEntries?: string[];
ui?: ReactElement;
}
let currentRouter: ReturnType<typeof createRouter> | null = null;
/**
* Custom render function for testing components that need TanStack Router context.
* @param ui The main ReactElement to render (your component under test).
* @param options Custom render options including initialEntries for the router.
* @returns An object containing the testing-library render result and the router instance.
*/
const customRender = (
ui: ReactElement,
options: CustomRenderOptions = {},
) => {
const { initialEntries = ["/"], ...renderOptions } = options;
// A specific route that renders the component under test (ui).
// It defaults to the first path in initialEntries or '/'.
const testComponentRoute = new Route({
getParentRoute: () => rootRoute,
path: initialEntries[0] || "/",
component: () => ui, // The component passed to render will be the element for this route
});
const routeTree = rootRoute.addChildren([testComponentRoute]);
const router = createRouter({
history: createMemoryHistory({ initialEntries }),
routeTree,
// You can add default error components or other router options if needed for tests.
// defaultErrorComponent: ({ error }) => <div>Test Error: {error.message}</div>,
});
currentRouter = router; // Store the router instance for access in tests
const Wrapper: FunctionComponent<{ children?: ReactNode }> = (
{ children },
) => {
return (
<>
<RouterProvider router={router} />
{children}
</>
);
};
const renderResult = rtlRender(ui, { wrapper: Wrapper, ...renderOptions });
return {
...renderResult,
router,
};
};
export * from "@testing-library/react";
export { customRender as render };
export const getTestRouter = () => currentRouter;

3
src/index.css

@ -93,7 +93,6 @@ body {
}
@layer base {
*,
::after,
::before,
@ -139,4 +138,4 @@ img {
.animate-spin-slow {
animation: spin-slower 2s linear infinite;
}
}

109
src/pages/Messages.tsx

@ -28,9 +28,19 @@ import { Input } from "@components/UI/Input.tsx";
import { randId } from "@core/utils/randId.ts";
import { useTranslation } from "react-i18next";
import { useNavigate, useParams } from "@tanstack/react-router";
import { messagesWithParamsRoute } from "@app/routes.tsx";
type NodeInfoWithUnread = Protobuf.Mesh.NodeInfo & { unreadCount: number };
function SelectMessageChat() {
const { t } = useTranslation("messages");
return (
<div className="flex-1 flex items-center justify-center text-slate-500 p-4">
{t("selectChatPrompt.text", { ns: "messages" })}
</div>
);
}
export const MessagesPage = () => {
const {
channels,
@ -46,7 +56,9 @@ export const MessagesPage = () => {
getMessages,
setMessageState,
} = useMessageStore();
const params = useParams({ from: "", shouldThrow: false });
const { type, chatId } = useParams({ from: messagesWithParamsRoute.id });
const navigate = useNavigate();
const { toast } = useToast();
const { isCollapsed } = useSidebar();
@ -54,34 +66,33 @@ export const MessagesPage = () => {
const { t } = useTranslation(["messages", "channels", "ui"]);
const deferredSearch = useDeferredValue(searchTerm);
const chatType = params.type === "direct"
const navigateToChat = useCallback((type: MessageType, id: string) => {
const typeParam = type === MessageType.Direct ? "direct" : "broadcast";
navigate({ to: `/messages/${typeParam}/${id}` });
}, [navigate]);
const chatType = type === "direct"
? MessageType.Direct
: params.type === "broadcast"
? MessageType.Broadcast
: undefined;
const activeChat = params.chatId ? Number(params.chatId) : undefined;
: MessageType.Broadcast;
const numericChatId = Number(chatId);
const allChannels = Array.from(channels.values());
const filteredChannels = allChannels.filter(
(ch) => ch.role !== Protobuf.Channel.Channel_Role.DISABLED,
);
const currentChannel = channels.get(activeChat);
const otherNode = getNode(activeChat);
const isDirect = chatType === MessageType.Direct;
const isBroadcast = chatType === MessageType.Broadcast;
const navigateToChat = useCallback((type: MessageType, chatId: number) => {
const typeParam = type === MessageType.Direct ? "direct" : "broadcast";
navigate({ to: `/messages/${typeParam}/${chatId}` });
}, [navigate]);
useEffect(() => {
if (!params.type && !params.chatId && filteredChannels.length > 0) {
if (!type && !chatId && filteredChannels.length > 0) {
const defaultChannel = filteredChannels[0];
navigateToChat(MessageType.Broadcast, defaultChannel.index);
navigateToChat(MessageType.Broadcast, defaultChannel.index.toString());
}
}, [params.type, params.chatId, filteredChannels, navigateToChat]);
}, [type, chatId, filteredChannels, navigateToChat]);
const currentChannel = channels.get(numericChatId);
const otherNode = getNode(numericChatId);
const isDirect = chatType === MessageType.Direct;
const isBroadcast = chatType === MessageType.Broadcast;
const filteredNodes = (): NodeInfoWithUnread[] => {
const lowerCaseSearchTerm = deferredSearch.toLowerCase();
@ -104,12 +115,8 @@ export const MessagesPage = () => {
};
const sendText = useCallback(async (message: string) => {
const isDirect = chatType === MessageType.Direct;
const toValue = isDirect ? activeChat : MessageType.Broadcast;
const channelValue = isDirect
? Types.ChannelNumber.Primary
: activeChat ?? 0;
const toValue = isDirect ? numericChatId : MessageType.Broadcast;
const channelValue = isDirect ? Types.ChannelNumber.Primary : numericChatId;
let messageId: number | undefined;
@ -123,16 +130,16 @@ export const MessagesPage = () => {
if (messageId !== undefined) {
if (chatType === MessageType.Broadcast) {
setMessageState({
type: chatType,
type: MessageType.Broadcast,
channelId: channelValue,
messageId,
newState: MessageState.Ack,
});
} else {
setMessageState({
type: chatType,
type: MessageType.Direct,
nodeA: getMyNodeNum(),
nodeB: activeChat,
nodeB: numericChatId,
messageId,
newState: MessageState.Ack,
});
@ -140,28 +147,34 @@ export const MessagesPage = () => {
} else {
console.warn("sendText completed but messageId is undefined");
}
} catch (e: any) {
} catch (e: unknown) {
console.error("Failed to send message:", e);
const failedId = messageId ?? randId();
if (chatType === MessageType.Broadcast) {
setMessageState({
type: chatType,
type: MessageType.Broadcast,
channelId: channelValue,
messageId: failedId,
newState: MessageState.Failed,
});
} else { // MessageType.Direct
const failedId = messageId ?? randId();
} else {
setMessageState({
type: chatType,
type: MessageType.Direct,
nodeA: getMyNodeNum(),
nodeB: activeChat,
nodeB: numericChatId,
messageId: failedId,
newState: MessageState.Failed,
});
}
}
}, [activeChat, chatType, connection, getMyNodeNum, setMessageState]);
}, [
numericChatId,
chatId,
chatType,
connection,
getMyNodeNum,
setMessageState,
]);
const renderChatContent = () => {
switch (chatType) {
@ -170,7 +183,7 @@ export const MessagesPage = () => {
<ChannelChat
messages={getMessages({
type: MessageType.Broadcast,
channelId: activeChat ?? 0,
channelId: numericChatId,
}).reverse()}
/>
);
@ -180,16 +193,12 @@ export const MessagesPage = () => {
messages={getMessages({
type: MessageType.Direct,
nodeA: getMyNodeNum(),
nodeB: activeChat,
nodeB: numericChatId,
}).reverse()}
/>
);
default:
return (
<div className="flex-1 flex items-center justify-center text-slate-500 p-4">
{t("selectChatPrompt.text", { ns: "messages" })}
</div>
);
return <SelectMessageChat />;
}
};
@ -210,10 +219,10 @@ export const MessagesPage = () => {
index: channel.index,
ns: "channels",
}))}
active={activeChat === channel.index &&
active={numericChatId === channel.index &&
chatType === MessageType.Broadcast}
onClick={() => {
navigateToChat(MessageType.Broadcast, channel.index);
navigateToChat(MessageType.Broadcast, channel.index.toString());
resetUnread(channel.index);
}}
>
@ -228,11 +237,12 @@ export const MessagesPage = () => {
), [
filteredChannels,
unreadCounts,
activeChat,
numericChatId,
chatType,
isCollapsed,
navigateToChat,
resetUnread,
t,
]);
const rightSidebar = useMemo(
@ -262,10 +272,10 @@ export const MessagesPage = () => {
label={node.user?.longName ??
t("unknown.shortName")}
count={node.unreadCount > 0 ? node.unreadCount : undefined}
active={activeChat === node.num &&
active={numericChatId === node.num &&
chatType === MessageType.Direct}
onClick={() => {
navigateToChat(MessageType.Direct, node.num);
navigateToChat(MessageType.Direct, node.num.toString());
resetUnread(node.num);
}}
>
@ -285,11 +295,12 @@ export const MessagesPage = () => {
[
filteredNodes,
searchTerm,
activeChat,
numericChatId,
chatType,
navigateToChat,
resetUnread,
hasNodeError,
t,
],
);
@ -330,7 +341,7 @@ export const MessagesPage = () => {
{(isBroadcast || isDirect)
? (
<MessageInput
to={isDirect ? activeChat : MessageType.Broadcast}
to={isDirect ? numericChatId : MessageType.Broadcast}
onSend={sendText}
maxBytes={200}
/>

35
src/routes.tsx

@ -4,10 +4,11 @@ import MessagesPage from "@pages/Messages.tsx";
import MapPage from "@pages/Map/index.tsx";
import ConfigPage from "@pages/Config/index.tsx";
import ChannelsPage from "@pages/Channels.tsx";
import NodesPage from "@pages/Nodes.tsx";
import NodesPage from "@pages/Nodes/index.tsx";
import { createRootRoute } from "@tanstack/react-router";
import { App } from "./App.tsx";
import { DialogManager } from "@components/Dialog/DialogManager.tsx";
import { z } from "zod";
const rootRoute = createRootRoute({
component: App,
@ -27,12 +28,42 @@ const messagesRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/messages",
component: MessagesPage,
beforeLoad: ({ params }) => {
const DEFAULT_CHANNEL = 0;
if (Object.values(params).length === 0) {
throw redirect({
to: `/messages/broadcast/${DEFAULT_CHANNEL}`,
replace: true,
});
}
},
});
const chatIdSchema = z.string().refine((val) => {
const num = Number(val);
if (isNaN(num) || !Number.isInteger(num)) {
return false;
}
const isChannelId = num >= 0 && num <= 10;
const isNodeId = num >= 1000000000 && num <= 9999999999;
return isChannelId || isNodeId;
}, {
message: "Chat ID must be a channel (0-10) or a valid node ID.",
});
const messagesWithParamsRoute = createRoute({
export const messagesWithParamsRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/messages/$type/$chatId",
component: MessagesPage,
parseParams: (params) => ({
type: z.enum(["direct", "broadcast"], {
errorMap: () => ({ message: 'Type must be "direct" or "broadcast".' }),
}).parse(params.type),
chatId: chatIdSchema.parse(params.chatId),
}),
});
const mapRoute = createRoute({

0
src/tests/setupTests.ts → src/tests/setup.ts

37
src/tests/test-utils.tsx

@ -0,0 +1,37 @@
import { ReactElement } from "react";
import { render, RenderOptions } from "@testing-library/react";
import {
createMemoryHistory,
createRouter,
RouterProvider,
} from "@tanstack/react-router";
import "../i18n/config.ts";
import { routeTree } from "../routeTree.gen.ts";
import { DeviceWrapper } from "@app/DeviceWrapper.tsx";
const Providers = () => {
const memoryHistory = createMemoryHistory({
initialEntries: ["/"],
});
const router = createRouter({
routeTree,
history: memoryHistory,
});
return (
<DeviceWrapper>
<RouterProvider router={router} />
</DeviceWrapper>
);
};
const renderWithProviders = (
ui: ReactElement,
options?: Omit<RenderOptions, "wrapper">,
) => render(ui, { wrapper: Providers, ...options });
export * from "@testing-library/react";
export { renderWithProviders as render };

4
vitest.config.ts

@ -3,6 +3,8 @@ import react from "@vitejs/plugin-react";
import { defineConfig } from "vitest/config";
import { enableMapSet } from "immer";
import process from "node:process";
enableMapSet();
export default defineConfig({
plugins: [
@ -25,6 +27,6 @@ export default defineConfig({
restoreMocks: true,
root: path.resolve(process.cwd(), "./src"),
include: ["**/*.{test,spec}.{ts,tsx}"],
setupFiles: ["./src/tests/setupTests.ts", "./src/core/utils/test.tsx"],
setupFiles: ["./src/tests/setup.ts"],
},
});

Loading…
Cancel
Save