nextjs-hackathon-stack 0.1.11 → 0.1.12
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/dist/index.js +7 -0
- package/package.json +1 -1
- package/template/.husky/pre-commit +1 -0
- package/template/_env.example +4 -4
- package/template/package.json.tmpl +8 -2
- package/template/src/app/__tests__/auth-callback.test.ts +72 -0
- package/template/src/app/__tests__/error.test.tsx +71 -0
- package/template/src/app/__tests__/layout.test.tsx +22 -0
- package/template/src/app/__tests__/login-page.test.tsx +34 -0
- package/template/src/app/__tests__/protected-layout.test.tsx +43 -0
- package/template/src/app/__tests__/protected-page.test.tsx +41 -0
- package/template/src/app/api/chat/route.ts +3 -1
- package/template/src/features/auth/__tests__/login-form.test.tsx +53 -2
- package/template/src/features/auth/__tests__/login.action.test.ts +82 -0
- package/template/src/features/auth/__tests__/logout.action.test.ts +32 -0
- package/template/src/features/auth/actions/login.action.ts +1 -1
- package/template/src/features/auth/components/login-form.tsx +4 -3
- package/template/src/features/chat/__tests__/chat-ui.test.tsx +97 -7
- package/template/src/features/chat/__tests__/route.test.ts +66 -3
- package/template/src/features/chat/__tests__/use-chat.test.ts +15 -0
- package/template/src/features/chat/components/chat-ui.tsx +1 -1
- package/template/src/features/tts/__tests__/route.test.ts +78 -3
- package/template/src/features/tts/__tests__/tts-player.test.tsx +65 -3
- package/template/src/features/video/__tests__/route.test.ts +78 -3
- package/template/src/features/video/__tests__/video-generator.test.tsx +65 -3
- package/template/src/shared/__tests__/middleware.test.ts +34 -0
- package/template/src/shared/__tests__/schema.test.ts +16 -3
- package/template/src/shared/__tests__/supabase-middleware.test.ts +162 -0
- package/template/src/shared/__tests__/supabase-server.test.ts +76 -3
- package/template/src/shared/__tests__/ui-button.test.tsx +52 -0
- package/template/src/shared/__tests__/ui-card.test.tsx +78 -0
- package/template/src/shared/__tests__/utils.test.ts +30 -0
- package/template/src/shared/lib/ai.ts +2 -2
- package/template/vitest.config.ts +5 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
|
|
3
|
+
const mockGetUser = vi.fn();
|
|
4
|
+
const mockCreateServerClient = vi.fn();
|
|
5
|
+
const mockNextResponseNext = vi.fn();
|
|
6
|
+
const mockNextResponseRedirect = vi.fn();
|
|
7
|
+
|
|
8
|
+
vi.mock("@supabase/ssr", () => ({
|
|
9
|
+
createServerClient: (...args: unknown[]) => mockCreateServerClient(...args),
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
vi.mock("next/server", async () => {
|
|
13
|
+
const actual = await vi.importActual<typeof import("next/server")>("next/server");
|
|
14
|
+
return {
|
|
15
|
+
...actual,
|
|
16
|
+
NextResponse: {
|
|
17
|
+
next: (...args: unknown[]) => mockNextResponseNext(...args),
|
|
18
|
+
redirect: (...args: unknown[]) => mockNextResponseRedirect(...args),
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
type CookieOptions = { path?: string; maxAge?: number };
|
|
24
|
+
type CookieItem = { name: string; value: string; options: CookieOptions };
|
|
25
|
+
type CookieCallbacks = {
|
|
26
|
+
getAll: () => CookieItem[];
|
|
27
|
+
setAll: (cookies: CookieItem[]) => void;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function makeRequest(pathname: string) {
|
|
31
|
+
return {
|
|
32
|
+
nextUrl: {
|
|
33
|
+
pathname,
|
|
34
|
+
clone: () => ({ pathname, toString: () => `http://localhost${pathname}` }),
|
|
35
|
+
},
|
|
36
|
+
cookies: { getAll: vi.fn(() => []), set: vi.fn() },
|
|
37
|
+
headers: new Headers(),
|
|
38
|
+
url: `http://localhost${pathname}`,
|
|
39
|
+
} as unknown as import("next/server").NextRequest;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
describe("supabase middleware (updateSession)", () => {
|
|
43
|
+
let capturedCookieCallbacks: CookieCallbacks | undefined;
|
|
44
|
+
const fakeResponse = {
|
|
45
|
+
cookies: { set: vi.fn(), getAll: vi.fn(() => []) },
|
|
46
|
+
status: 200,
|
|
47
|
+
headers: new Headers(),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
vi.clearAllMocks();
|
|
52
|
+
capturedCookieCallbacks = undefined;
|
|
53
|
+
mockNextResponseNext.mockReturnValue(fakeResponse);
|
|
54
|
+
mockNextResponseRedirect.mockImplementation((url: unknown) => ({
|
|
55
|
+
status: 307,
|
|
56
|
+
headers: new Headers({ location: String(url) }),
|
|
57
|
+
}));
|
|
58
|
+
mockCreateServerClient.mockImplementation(
|
|
59
|
+
(_u: unknown, _k: unknown, opts: { cookies: CookieCallbacks }) => {
|
|
60
|
+
capturedCookieCallbacks = opts.cookies;
|
|
61
|
+
return { auth: { getUser: mockGetUser } };
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("returns nextResponse for authenticated user on protected route", async () => {
|
|
67
|
+
// Arrange
|
|
68
|
+
mockGetUser.mockResolvedValue({ data: { user: { id: "user-1" } } });
|
|
69
|
+
const { updateSession } = await import("../lib/supabase/middleware");
|
|
70
|
+
const req = makeRequest("/dashboard");
|
|
71
|
+
|
|
72
|
+
// Act
|
|
73
|
+
const response = await updateSession(req);
|
|
74
|
+
|
|
75
|
+
// Assert
|
|
76
|
+
expect(response).toBeDefined();
|
|
77
|
+
expect(mockNextResponseRedirect).not.toHaveBeenCalled();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("invokes getAll cookie callback", async () => {
|
|
81
|
+
// Arrange
|
|
82
|
+
mockGetUser.mockResolvedValue({ data: { user: { id: "user-1" } } });
|
|
83
|
+
const { updateSession } = await import("../lib/supabase/middleware");
|
|
84
|
+
const req = makeRequest("/dashboard");
|
|
85
|
+
await updateSession(req);
|
|
86
|
+
|
|
87
|
+
// Act
|
|
88
|
+
capturedCookieCallbacks!.getAll();
|
|
89
|
+
|
|
90
|
+
// Assert
|
|
91
|
+
expect(req.cookies.getAll).toHaveBeenCalled();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("invokes setAll cookie callback and updates request + response cookies", async () => {
|
|
95
|
+
// Arrange
|
|
96
|
+
mockGetUser.mockResolvedValue({ data: { user: { id: "user-1" } } });
|
|
97
|
+
const { updateSession } = await import("../lib/supabase/middleware");
|
|
98
|
+
const req = makeRequest("/dashboard");
|
|
99
|
+
await updateSession(req);
|
|
100
|
+
|
|
101
|
+
// Act
|
|
102
|
+
capturedCookieCallbacks!.setAll([
|
|
103
|
+
{ name: "sb-token", value: "abc", options: { path: "/" } },
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
// Assert
|
|
107
|
+
expect(req.cookies.set).toHaveBeenCalledWith("sb-token", "abc");
|
|
108
|
+
expect(fakeResponse.cookies.set).toHaveBeenCalledWith("sb-token", "abc", { path: "/" });
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("redirects unauthenticated user from protected route", async () => {
|
|
112
|
+
// Arrange
|
|
113
|
+
mockGetUser.mockResolvedValue({ data: { user: null } });
|
|
114
|
+
const { updateSession } = await import("../lib/supabase/middleware");
|
|
115
|
+
const req = makeRequest("/dashboard");
|
|
116
|
+
|
|
117
|
+
// Act
|
|
118
|
+
await updateSession(req);
|
|
119
|
+
|
|
120
|
+
// Assert
|
|
121
|
+
expect(mockNextResponseRedirect).toHaveBeenCalled();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("does not redirect unauthenticated user on login route", async () => {
|
|
125
|
+
// Arrange
|
|
126
|
+
mockGetUser.mockResolvedValue({ data: { user: null } });
|
|
127
|
+
const { updateSession } = await import("../lib/supabase/middleware");
|
|
128
|
+
const req = makeRequest("/login");
|
|
129
|
+
|
|
130
|
+
// Act
|
|
131
|
+
await updateSession(req);
|
|
132
|
+
|
|
133
|
+
// Assert
|
|
134
|
+
expect(mockNextResponseRedirect).not.toHaveBeenCalled();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("does not redirect unauthenticated user on root path", async () => {
|
|
138
|
+
// Arrange
|
|
139
|
+
mockGetUser.mockResolvedValue({ data: { user: null } });
|
|
140
|
+
const { updateSession } = await import("../lib/supabase/middleware");
|
|
141
|
+
const req = makeRequest("/");
|
|
142
|
+
|
|
143
|
+
// Act
|
|
144
|
+
await updateSession(req);
|
|
145
|
+
|
|
146
|
+
// Assert
|
|
147
|
+
expect(mockNextResponseRedirect).not.toHaveBeenCalled();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("does not redirect on /api/auth routes", async () => {
|
|
151
|
+
// Arrange
|
|
152
|
+
mockGetUser.mockResolvedValue({ data: { user: null } });
|
|
153
|
+
const { updateSession } = await import("../lib/supabase/middleware");
|
|
154
|
+
const req = makeRequest("/api/auth/callback");
|
|
155
|
+
|
|
156
|
+
// Act
|
|
157
|
+
await updateSession(req);
|
|
158
|
+
|
|
159
|
+
// Assert
|
|
160
|
+
expect(mockNextResponseRedirect).not.toHaveBeenCalled();
|
|
161
|
+
});
|
|
162
|
+
});
|
|
@@ -1,22 +1,95 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from "vitest";
|
|
2
2
|
|
|
3
|
+
const mockSet = vi.fn();
|
|
4
|
+
const mockGetAll = vi.fn().mockReturnValue([]);
|
|
5
|
+
const mockCreateServerClient = vi.fn();
|
|
6
|
+
|
|
3
7
|
vi.mock("@supabase/ssr", () => ({
|
|
4
|
-
createServerClient:
|
|
8
|
+
createServerClient: (...args: unknown[]) => mockCreateServerClient(...args),
|
|
5
9
|
}));
|
|
6
10
|
|
|
7
11
|
vi.mock("next/headers", () => ({
|
|
8
12
|
cookies: vi.fn(() =>
|
|
9
13
|
Promise.resolve({
|
|
10
|
-
getAll:
|
|
11
|
-
set:
|
|
14
|
+
getAll: mockGetAll,
|
|
15
|
+
set: mockSet,
|
|
12
16
|
})
|
|
13
17
|
),
|
|
14
18
|
}));
|
|
15
19
|
|
|
16
20
|
describe("supabase server", () => {
|
|
17
21
|
it("createClient returns a supabase client", async () => {
|
|
22
|
+
// Arrange
|
|
23
|
+
mockCreateServerClient.mockReturnValue({ auth: {} });
|
|
18
24
|
const { createClient } = await import("../lib/supabase/server");
|
|
25
|
+
|
|
26
|
+
// Act
|
|
19
27
|
const client = await createClient();
|
|
28
|
+
|
|
29
|
+
// Assert
|
|
20
30
|
expect(client).toBeDefined();
|
|
21
31
|
});
|
|
32
|
+
|
|
33
|
+
it("passes cookie getAll to server client config", async () => {
|
|
34
|
+
// Arrange
|
|
35
|
+
let capturedGetAll: (() => unknown) | undefined;
|
|
36
|
+
mockCreateServerClient.mockImplementation(
|
|
37
|
+
(_u: unknown, _k: unknown, opts: { cookies: { getAll: () => unknown } }) => {
|
|
38
|
+
capturedGetAll = opts.cookies.getAll;
|
|
39
|
+
return { auth: {} };
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
const { createClient } = await import("../lib/supabase/server");
|
|
43
|
+
|
|
44
|
+
// Act
|
|
45
|
+
await createClient();
|
|
46
|
+
capturedGetAll!();
|
|
47
|
+
|
|
48
|
+
// Assert
|
|
49
|
+
expect(mockGetAll).toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("setAll sets cookies via cookieStore", async () => {
|
|
53
|
+
// Arrange
|
|
54
|
+
let capturedSetAll:
|
|
55
|
+
| ((cookies: { name: string; value: string; options: object }[]) => void)
|
|
56
|
+
| undefined;
|
|
57
|
+
mockCreateServerClient.mockImplementation(
|
|
58
|
+
(_u: unknown, _k: unknown, opts: { cookies: { setAll: (c: { name: string; value: string; options: object }[]) => void } }) => {
|
|
59
|
+
capturedSetAll = opts.cookies.setAll;
|
|
60
|
+
return { auth: {} };
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
const { createClient } = await import("../lib/supabase/server");
|
|
64
|
+
await createClient();
|
|
65
|
+
|
|
66
|
+
// Act
|
|
67
|
+
capturedSetAll!([{ name: "token", value: "abc", options: { path: "/" } }]);
|
|
68
|
+
|
|
69
|
+
// Assert
|
|
70
|
+
expect(mockSet).toHaveBeenCalledWith("token", "abc", { path: "/" });
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("setAll silently swallows errors from server components", async () => {
|
|
74
|
+
// Arrange
|
|
75
|
+
mockSet.mockImplementation(() => {
|
|
76
|
+
throw new Error("Cannot set cookie");
|
|
77
|
+
});
|
|
78
|
+
let capturedSetAll:
|
|
79
|
+
| ((cookies: { name: string; value: string; options: object }[]) => void)
|
|
80
|
+
| undefined;
|
|
81
|
+
mockCreateServerClient.mockImplementation(
|
|
82
|
+
(_u: unknown, _k: unknown, opts: { cookies: { setAll: (c: { name: string; value: string; options: object }[]) => void } }) => {
|
|
83
|
+
capturedSetAll = opts.cookies.setAll;
|
|
84
|
+
return { auth: {} };
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
const { createClient } = await import("../lib/supabase/server");
|
|
88
|
+
await createClient();
|
|
89
|
+
|
|
90
|
+
// Act + Assert
|
|
91
|
+
expect(() =>
|
|
92
|
+
capturedSetAll!([{ name: "token", value: "abc", options: {} }])
|
|
93
|
+
).not.toThrow();
|
|
94
|
+
});
|
|
22
95
|
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { describe, it, expect } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { Button } from "../components/ui/button";
|
|
5
|
+
|
|
6
|
+
describe("Button", () => {
|
|
7
|
+
it("renders with default variant", () => {
|
|
8
|
+
// Arrange + Act
|
|
9
|
+
render(<Button>Click me</Button>);
|
|
10
|
+
|
|
11
|
+
// Assert
|
|
12
|
+
expect(screen.getByRole("button", { name: /click me/i })).toBeInTheDocument();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("renders as disabled when disabled prop is set", () => {
|
|
16
|
+
// Arrange + Act
|
|
17
|
+
render(<Button disabled>Submit</Button>);
|
|
18
|
+
|
|
19
|
+
// Assert
|
|
20
|
+
expect(screen.getByRole("button")).toBeDisabled();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("renders with custom className", () => {
|
|
24
|
+
// Arrange + Act
|
|
25
|
+
render(<Button className="custom-class">Click</Button>);
|
|
26
|
+
|
|
27
|
+
// Assert
|
|
28
|
+
expect(screen.getByRole("button")).toHaveClass("custom-class");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("renders as a Slot (asChild) when asChild is true", () => {
|
|
32
|
+
// Arrange + Act
|
|
33
|
+
render(
|
|
34
|
+
<Button asChild>
|
|
35
|
+
<a href="/home">Go home</a>
|
|
36
|
+
</Button>
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// Assert
|
|
40
|
+
expect(screen.getByRole("link", { name: /go home/i })).toBeInTheDocument();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("renders with destructive variant", () => {
|
|
44
|
+
// Arrange + Act
|
|
45
|
+
render(<Button variant="destructive">Delete</Button>);
|
|
46
|
+
|
|
47
|
+
// Assert
|
|
48
|
+
const btn = screen.getByRole("button", { name: /delete/i });
|
|
49
|
+
expect(btn).toBeInTheDocument();
|
|
50
|
+
expect(btn.className).toContain("destructive");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { describe, it, expect } from "vitest";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
Card,
|
|
6
|
+
CardAction,
|
|
7
|
+
CardContent,
|
|
8
|
+
CardDescription,
|
|
9
|
+
CardFooter,
|
|
10
|
+
CardHeader,
|
|
11
|
+
CardTitle,
|
|
12
|
+
} from "../components/ui/card";
|
|
13
|
+
|
|
14
|
+
describe("Card components", () => {
|
|
15
|
+
it("renders Card with children", () => {
|
|
16
|
+
// Arrange + Act
|
|
17
|
+
render(<Card data-testid="card">content</Card>);
|
|
18
|
+
|
|
19
|
+
// Assert
|
|
20
|
+
expect(screen.getByTestId("card")).toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("renders CardHeader", () => {
|
|
24
|
+
// Arrange + Act
|
|
25
|
+
render(<CardHeader data-testid="header">header</CardHeader>);
|
|
26
|
+
|
|
27
|
+
// Assert
|
|
28
|
+
expect(screen.getByTestId("header")).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("renders CardTitle", () => {
|
|
32
|
+
// Arrange + Act
|
|
33
|
+
render(<CardTitle>My Title</CardTitle>);
|
|
34
|
+
|
|
35
|
+
// Assert
|
|
36
|
+
expect(screen.getByText("My Title")).toBeInTheDocument();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("renders CardDescription", () => {
|
|
40
|
+
// Arrange + Act
|
|
41
|
+
render(<CardDescription>My Description</CardDescription>);
|
|
42
|
+
|
|
43
|
+
// Assert
|
|
44
|
+
expect(screen.getByText("My Description")).toBeInTheDocument();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("renders CardContent", () => {
|
|
48
|
+
// Arrange + Act
|
|
49
|
+
render(<CardContent data-testid="content">body</CardContent>);
|
|
50
|
+
|
|
51
|
+
// Assert
|
|
52
|
+
expect(screen.getByTestId("content")).toBeInTheDocument();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("renders CardAction", () => {
|
|
56
|
+
// Arrange + Act
|
|
57
|
+
render(<CardAction data-testid="action">action</CardAction>);
|
|
58
|
+
|
|
59
|
+
// Assert
|
|
60
|
+
expect(screen.getByTestId("action")).toBeInTheDocument();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("renders CardFooter", () => {
|
|
64
|
+
// Arrange + Act
|
|
65
|
+
render(<CardFooter data-testid="footer">footer</CardFooter>);
|
|
66
|
+
|
|
67
|
+
// Assert
|
|
68
|
+
expect(screen.getByTestId("footer")).toBeInTheDocument();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("applies custom className to Card", () => {
|
|
72
|
+
// Arrange + Act
|
|
73
|
+
render(<Card className="custom-class" data-testid="card">content</Card>);
|
|
74
|
+
|
|
75
|
+
// Assert
|
|
76
|
+
expect(screen.getByTestId("card")).toHaveClass("custom-class");
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../lib/utils";
|
|
4
|
+
|
|
5
|
+
describe("cn", () => {
|
|
6
|
+
it("merges multiple class names", () => {
|
|
7
|
+
// Arrange + Act + Assert
|
|
8
|
+
expect(cn("foo", "bar")).toBe("foo bar");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("omits falsy conditional classes", () => {
|
|
12
|
+
// Arrange + Act + Assert
|
|
13
|
+
expect(cn("foo", false && "bar", "baz")).toBe("foo baz");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("handles undefined values", () => {
|
|
17
|
+
// Arrange + Act + Assert
|
|
18
|
+
expect(cn("foo", undefined, "bar")).toBe("foo bar");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("deduplicates conflicting tailwind classes (last one wins)", () => {
|
|
22
|
+
// Arrange + Act + Assert
|
|
23
|
+
expect(cn("p-2", "p-4")).toBe("p-4");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("handles empty call", () => {
|
|
27
|
+
// Arrange + Act + Assert
|
|
28
|
+
expect(cn()).toBe("");
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createOpenAI } from "@ai-sdk/openai";
|
|
2
2
|
|
|
3
3
|
const provider = createOpenAI({
|
|
4
|
-
baseURL: process.env.AI_BASE_URL ?? "https://api.
|
|
4
|
+
baseURL: process.env.AI_BASE_URL ?? "https://api.minimax.io/v1",
|
|
5
5
|
apiKey: process.env.AI_API_KEY ?? "",
|
|
6
6
|
});
|
|
7
7
|
|
|
8
|
-
export const aiModel = provider(process.env.AI_MODEL ?? "MiniMax-
|
|
8
|
+
export const aiModel = provider(process.env.AI_MODEL ?? "MiniMax-M2.7");
|
|
@@ -5,8 +5,10 @@ import { resolve } from "path";
|
|
|
5
5
|
export default defineConfig({
|
|
6
6
|
plugins: [react()],
|
|
7
7
|
test: {
|
|
8
|
+
globals: true,
|
|
8
9
|
environment: "jsdom",
|
|
9
10
|
setupFiles: ["./src/test-setup.ts"],
|
|
11
|
+
exclude: ["node_modules/**", "src/e2e/**"],
|
|
10
12
|
coverage: {
|
|
11
13
|
provider: "v8",
|
|
12
14
|
thresholds: {
|
|
@@ -22,6 +24,9 @@ export default defineConfig({
|
|
|
22
24
|
"**/*.config.*",
|
|
23
25
|
"**/index.ts",
|
|
24
26
|
"src/app/globals.css",
|
|
27
|
+
".next/**",
|
|
28
|
+
"next-env.d.ts",
|
|
29
|
+
"**/*.d.ts",
|
|
25
30
|
],
|
|
26
31
|
},
|
|
27
32
|
},
|