Project import from github
This commit is contained in:
commit
0add58254d
179 changed files with 23756 additions and 0 deletions
446
tests/stores/auth.test.ts
Normal file
446
tests/stores/auth.test.ts
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
import { describe, expect, it, vi, beforeEach } from "vitest";
|
||||
import { setActivePinia, createPinia } from "pinia";
|
||||
import { useAuthStore } from "~/stores/auth";
|
||||
|
||||
// Mock better-auth/vue
|
||||
const { mockUseSession, mockSignInEmail, mockSignOut } = vi.hoisted(() => ({
|
||||
mockUseSession: vi.fn(),
|
||||
mockSignInEmail: vi.fn(),
|
||||
mockSignOut: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("better-auth/vue", () => ({
|
||||
createAuthClient: () => ({
|
||||
useSession: mockUseSession,
|
||||
signIn: {
|
||||
email: mockSignInEmail,
|
||||
},
|
||||
signOut: mockSignOut,
|
||||
}),
|
||||
}));
|
||||
|
||||
// Mock navigateTo
|
||||
const navigateToMock = vi.fn();
|
||||
vi.stubGlobal("navigateTo", navigateToMock);
|
||||
|
||||
// Mock useFetch
|
||||
const useFetchMock = vi.fn();
|
||||
vi.stubGlobal("useFetch", useFetchMock);
|
||||
|
||||
describe("useAuthStore", () => {
|
||||
beforeEach(() => {
|
||||
// Create a fresh pinia instance for each test
|
||||
setActivePinia(createPinia());
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("init", () => {
|
||||
it("should initialize session with user data", async () => {
|
||||
const mockSessionData = {
|
||||
data: {
|
||||
user: {
|
||||
id: "123",
|
||||
name: "Test User",
|
||||
email: "test@example.com",
|
||||
emailVerified: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
image: "avatar.png",
|
||||
},
|
||||
session: {
|
||||
id: "session-123",
|
||||
userId: "123",
|
||||
expiresAt: new Date(),
|
||||
token: "token-123",
|
||||
ipAddress: "127.0.0.1",
|
||||
userAgent: "test-agent",
|
||||
},
|
||||
},
|
||||
isPending: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
mockUseSession.mockResolvedValue(mockSessionData);
|
||||
|
||||
const store = useAuthStore();
|
||||
await store.init();
|
||||
|
||||
expect(mockUseSession).toHaveBeenCalledWith(useFetchMock);
|
||||
expect(store.user).toEqual(mockSessionData.data.user);
|
||||
expect(store.loading).toBe(false);
|
||||
expect(store.lastError).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should handle session with no user (logged out state)", async () => {
|
||||
const mockSessionData = {
|
||||
data: null,
|
||||
isPending: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
mockUseSession.mockResolvedValue(mockSessionData);
|
||||
|
||||
const store = useAuthStore();
|
||||
await store.init();
|
||||
|
||||
expect(mockUseSession).toHaveBeenCalledWith(useFetchMock);
|
||||
expect(store.user).toBeUndefined();
|
||||
expect(store.loading).toBe(false);
|
||||
expect(store.lastError).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should clear lastError when init is called", async () => {
|
||||
const mockSessionData = {
|
||||
data: null,
|
||||
isPending: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
mockUseSession.mockResolvedValue(mockSessionData);
|
||||
|
||||
const store = useAuthStore();
|
||||
// Set an error first
|
||||
store.lastError = "Previous error";
|
||||
|
||||
await store.init();
|
||||
|
||||
expect(store.lastError).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should handle pending session state", async () => {
|
||||
const mockSessionData = {
|
||||
data: null,
|
||||
isPending: true,
|
||||
error: null,
|
||||
};
|
||||
|
||||
mockUseSession.mockResolvedValue(mockSessionData);
|
||||
|
||||
const store = useAuthStore();
|
||||
await store.init();
|
||||
|
||||
expect(store.loading).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("signIn", () => {
|
||||
it("should successfully sign in with valid credentials", async () => {
|
||||
mockSignInEmail.mockResolvedValue({ error: null });
|
||||
|
||||
const store = useAuthStore();
|
||||
await store.signIn("test@example.com", "password123");
|
||||
|
||||
expect(mockSignInEmail).toHaveBeenCalledWith({
|
||||
email: "test@example.com",
|
||||
password: "password123", // NOSONAR - Mocked value
|
||||
callbackURL: "/",
|
||||
});
|
||||
expect(store.lastError).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should set lastError when sign in fails", async () => {
|
||||
const errorMessage = "Invalid credentials";
|
||||
mockSignInEmail.mockResolvedValue({
|
||||
error: { message: errorMessage },
|
||||
});
|
||||
|
||||
const store = useAuthStore();
|
||||
await store.signIn("test@example.com", "wrongpassword");
|
||||
|
||||
expect(mockSignInEmail).toHaveBeenCalledWith({
|
||||
email: "test@example.com",
|
||||
password: "wrongpassword", // NOSONAR - Mocked value
|
||||
callbackURL: "/",
|
||||
});
|
||||
expect(store.lastError).toBe(errorMessage);
|
||||
});
|
||||
|
||||
it("should handle network errors during sign in", async () => {
|
||||
const errorMessage = "Network error";
|
||||
mockSignInEmail.mockResolvedValue({
|
||||
error: { message: errorMessage },
|
||||
});
|
||||
|
||||
const store = useAuthStore();
|
||||
await store.signIn("test@example.com", "password123");
|
||||
|
||||
expect(store.lastError).toBe(errorMessage);
|
||||
});
|
||||
|
||||
it("should clear previous error on successful sign in", async () => {
|
||||
mockSignInEmail.mockResolvedValue({ error: null });
|
||||
|
||||
const store = useAuthStore();
|
||||
store.lastError = "Previous error";
|
||||
|
||||
await store.signIn("test@example.com", "password123");
|
||||
|
||||
// Note: lastError is only set when there's an error, not cleared on success
|
||||
// This test documents the current behavior
|
||||
expect(store.lastError).toBe("Previous error");
|
||||
});
|
||||
});
|
||||
|
||||
describe("signOut", () => {
|
||||
it("should call signOut and navigate to home", async () => {
|
||||
mockSignOut.mockResolvedValue({});
|
||||
|
||||
const store = useAuthStore();
|
||||
await store.signOut();
|
||||
|
||||
expect(mockSignOut).toHaveBeenCalledWith({});
|
||||
expect(navigateToMock).toHaveBeenCalledWith("/");
|
||||
});
|
||||
|
||||
it("should navigate to home even if signOut fails", async () => {
|
||||
mockSignOut.mockRejectedValue(new Error("Sign out failed"));
|
||||
|
||||
const store = useAuthStore();
|
||||
|
||||
// The current implementation doesn't handle errors, so this will throw
|
||||
await expect(store.signOut()).rejects.toThrow("Sign out failed");
|
||||
|
||||
// navigateTo is not called because the error is thrown before it
|
||||
expect(navigateToMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("computed properties", () => {
|
||||
it("should return user from session data", async () => {
|
||||
const mockUser = {
|
||||
id: "123",
|
||||
name: "Test User",
|
||||
email: "test@example.com",
|
||||
emailVerified: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
image: "avatar.png",
|
||||
};
|
||||
|
||||
const mockSessionData = {
|
||||
data: {
|
||||
user: mockUser,
|
||||
session: {
|
||||
id: "session-123",
|
||||
userId: "123",
|
||||
expiresAt: new Date(),
|
||||
token: "token-123",
|
||||
ipAddress: "127.0.0.1",
|
||||
userAgent: "test-agent",
|
||||
},
|
||||
},
|
||||
isPending: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
mockUseSession.mockResolvedValue(mockSessionData);
|
||||
|
||||
const store = useAuthStore();
|
||||
await store.init();
|
||||
|
||||
expect(store.user).toEqual(mockUser);
|
||||
});
|
||||
|
||||
it("should return undefined when no user is logged in", async () => {
|
||||
const mockSessionData = {
|
||||
data: null,
|
||||
isPending: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
mockUseSession.mockResolvedValue(mockSessionData);
|
||||
|
||||
const store = useAuthStore();
|
||||
await store.init();
|
||||
|
||||
expect(store.user).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return loading state from session", async () => {
|
||||
const mockSessionData = {
|
||||
data: null,
|
||||
isPending: true,
|
||||
error: null,
|
||||
};
|
||||
|
||||
mockUseSession.mockResolvedValue(mockSessionData);
|
||||
|
||||
const store = useAuthStore();
|
||||
await store.init();
|
||||
|
||||
expect(store.loading).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for loading when session is loaded", async () => {
|
||||
const mockSessionData = {
|
||||
data: {
|
||||
user: {
|
||||
id: "123",
|
||||
name: "Test User",
|
||||
email: "test@example.com",
|
||||
emailVerified: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
image: "avatar.png",
|
||||
},
|
||||
session: {
|
||||
id: "session-123",
|
||||
userId: "123",
|
||||
expiresAt: new Date(),
|
||||
token: "token-123",
|
||||
ipAddress: "127.0.0.1",
|
||||
userAgent: "test-agent",
|
||||
},
|
||||
},
|
||||
isPending: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
mockUseSession.mockResolvedValue(mockSessionData);
|
||||
|
||||
const store = useAuthStore();
|
||||
await store.init();
|
||||
|
||||
expect(store.loading).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("store state management", () => {
|
||||
it("should maintain state across multiple operations", async () => {
|
||||
const mockUser = {
|
||||
id: "123",
|
||||
name: "Test User",
|
||||
email: "test@example.com",
|
||||
emailVerified: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
image: "avatar.png",
|
||||
};
|
||||
|
||||
const mockSessionData = {
|
||||
data: {
|
||||
user: mockUser,
|
||||
session: {
|
||||
id: "session-123",
|
||||
userId: "123",
|
||||
expiresAt: new Date(),
|
||||
token: "token-123",
|
||||
ipAddress: "127.0.0.1",
|
||||
userAgent: "test-agent",
|
||||
},
|
||||
},
|
||||
isPending: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
mockUseSession.mockResolvedValue(mockSessionData);
|
||||
mockSignInEmail.mockResolvedValue({ error: null });
|
||||
|
||||
const store = useAuthStore();
|
||||
|
||||
// Initialize
|
||||
await store.init();
|
||||
expect(store.user).toEqual(mockUser);
|
||||
|
||||
// Sign in
|
||||
await store.signIn("test@example.com", "password123");
|
||||
expect(store.user).toEqual(mockUser); // User should still be there
|
||||
|
||||
// Sign out
|
||||
mockSignOut.mockResolvedValue({});
|
||||
await store.signOut();
|
||||
expect(navigateToMock).toHaveBeenCalledWith("/");
|
||||
});
|
||||
|
||||
it("should handle error state persistence", async () => {
|
||||
const errorMessage = "Authentication failed";
|
||||
mockSignInEmail.mockResolvedValue({
|
||||
error: { message: errorMessage },
|
||||
});
|
||||
|
||||
const store = useAuthStore();
|
||||
|
||||
// First failed sign in
|
||||
await store.signIn("test@example.com", "wrongpassword");
|
||||
expect(store.lastError).toBe(errorMessage);
|
||||
|
||||
// Error should persist
|
||||
expect(store.lastError).toBe(errorMessage);
|
||||
|
||||
// Init should clear the error
|
||||
mockUseSession.mockResolvedValue({
|
||||
data: null,
|
||||
isPending: false,
|
||||
error: null,
|
||||
});
|
||||
await store.init();
|
||||
expect(store.lastError).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("edge cases", () => {
|
||||
it("should handle empty email and password", async () => {
|
||||
mockSignInEmail.mockResolvedValue({ error: null });
|
||||
|
||||
const store = useAuthStore();
|
||||
await store.signIn("", "");
|
||||
|
||||
expect(mockSignInEmail).toHaveBeenCalledWith({
|
||||
email: "",
|
||||
password: "",
|
||||
callbackURL: "/",
|
||||
});
|
||||
});
|
||||
|
||||
it("should handle special characters in credentials", async () => {
|
||||
mockSignInEmail.mockResolvedValue({ error: null });
|
||||
|
||||
const store = useAuthStore();
|
||||
const specialEmail = "test+special@example.com";
|
||||
const specialPassword = "p@ssw0rd!#$%"; // NOSONAR - Mocked value
|
||||
|
||||
await store.signIn(specialEmail, specialPassword);
|
||||
|
||||
expect(mockSignInEmail).toHaveBeenCalledWith({
|
||||
email: specialEmail,
|
||||
password: specialPassword,
|
||||
callbackURL: "/",
|
||||
});
|
||||
});
|
||||
|
||||
it("should handle session data with missing user properties", async () => {
|
||||
const mockSessionData = {
|
||||
data: {
|
||||
user: {
|
||||
id: "123",
|
||||
name: "Test User",
|
||||
email: "test@example.com",
|
||||
emailVerified: false,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
// image is optional and missing
|
||||
},
|
||||
session: {
|
||||
id: "session-123",
|
||||
userId: "123",
|
||||
expiresAt: new Date(),
|
||||
token: "token-123",
|
||||
ipAddress: "127.0.0.1",
|
||||
userAgent: "test-agent",
|
||||
},
|
||||
},
|
||||
isPending: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
mockUseSession.mockResolvedValue(mockSessionData);
|
||||
|
||||
const store = useAuthStore();
|
||||
await store.init();
|
||||
|
||||
expect(store.user).toBeDefined();
|
||||
expect(store.user?.id).toBe("123");
|
||||
expect(store.user?.image).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue