From 1afb825860cd293b8065d51746f4b23e4e8dab5d Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 12 Feb 2026 14:54:18 +0000 Subject: feat: 学習カード数の上限を撤廃 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit REVIEW_CARDS_LIMIT(復習カード80枚制限)とnewCardsPerDay(1日の新規カード制限) を削除し、期日が来たすべてのカードを制限なく返すように変更。 削除した主な要素: - REVIEW_CARDS_LIMIT定数とカード取得時のlimitパラメータ - newCardsPerDayフィールド(DB schema, 型定義, Zod schema, sync, CRDT) - countDueNewCards, countDueReviewCards, findDueNewCardsForStudy, findDueReviewCardsForStudy(CardRepository) - countTodayNewCardReviews(ReviewLogRepository) - デッキルートからのReviewLogRepository依存 https://claude.ai/code/session_018hrEJ9vg3RPoeAPyEc17gS --- src/server/routes/study.test.ts | 109 +++------------------------------------- 1 file changed, 6 insertions(+), 103 deletions(-) (limited to 'src/server/routes/study.test.ts') diff --git a/src/server/routes/study.test.ts b/src/server/routes/study.test.ts index 514d966..119b25d 100644 --- a/src/server/routes/study.test.ts +++ b/src/server/routes/study.test.ts @@ -26,12 +26,8 @@ function createMockCardRepo(): CardRepository { softDeleteByNoteId: vi.fn(), findDueCards: vi.fn(), countDueCards: vi.fn(), - countDueNewCards: vi.fn(), - countDueReviewCards: vi.fn(), findDueCardsWithNoteData: vi.fn(), findDueCardsForStudy: vi.fn(), - findDueNewCardsForStudy: vi.fn(), - findDueReviewCardsForStudy: vi.fn(), updateFSRSFields: vi.fn(), }; } @@ -49,7 +45,6 @@ function createMockDeckRepo(): DeckRepository { function createMockReviewLogRepo(): ReviewLogRepository { return { create: vi.fn(), - countTodayNewCardReviews: vi.fn().mockResolvedValue(0), }; } @@ -73,7 +68,6 @@ function createMockDeck(overrides: Partial = {}): Deck { userId: "user-uuid-123", name: "Test Deck", description: "Test description", - newCardsPerDay: 20, createdAt: new Date("2024-01-01"), updatedAt: new Date("2024-01-01"), deletedAt: null, @@ -152,14 +146,13 @@ describe("GET /api/decks/:deckId/study", () => { let app: Hono; let mockCardRepo: ReturnType; let mockDeckRepo: ReturnType; - let mockReviewLogRepo: ReturnType; let authToken: string; beforeEach(async () => { vi.clearAllMocks(); mockCardRepo = createMockCardRepo(); mockDeckRepo = createMockDeckRepo(); - mockReviewLogRepo = createMockReviewLogRepo(); + const mockReviewLogRepo = createMockReviewLogRepo(); const studyRouter = createStudyRouter({ cardRepo: mockCardRepo, deckRepo: mockDeckRepo, @@ -175,8 +168,7 @@ describe("GET /api/decks/:deckId/study", () => { vi.mocked(mockDeckRepo.findById).mockResolvedValue( createMockDeck({ id: DECK_ID }), ); - vi.mocked(mockCardRepo.findDueNewCardsForStudy).mockResolvedValue([]); - vi.mocked(mockCardRepo.findDueReviewCardsForStudy).mockResolvedValue([]); + vi.mocked(mockCardRepo.findDueCardsForStudy).mockResolvedValue([]); const res = await app.request(`/api/decks/${DECK_ID}/study`, { method: "GET", @@ -190,20 +182,14 @@ describe("GET /api/decks/:deckId/study", () => { DECK_ID, "user-uuid-123", ); - expect(mockCardRepo.findDueNewCardsForStudy).toHaveBeenCalledWith( - DECK_ID, - expect.any(Date), - 20, - ); - expect(mockCardRepo.findDueReviewCardsForStudy).toHaveBeenCalledWith( + expect(mockCardRepo.findDueCardsForStudy).toHaveBeenCalledWith( DECK_ID, expect.any(Date), - 80, ); }); it("returns due cards", async () => { - const newCards = [ + const mockCards = [ createMockCardForStudy({ id: "card-1", front: "Q1", @@ -211,8 +197,6 @@ describe("GET /api/decks/:deckId/study", () => { state: CardState.New, fieldValuesMap: {}, }), - ]; - const reviewCards = [ createMockCardForStudy({ id: "card-2", front: "Q2", @@ -224,10 +208,7 @@ describe("GET /api/decks/:deckId/study", () => { vi.mocked(mockDeckRepo.findById).mockResolvedValue( createMockDeck({ id: DECK_ID }), ); - vi.mocked(mockCardRepo.findDueNewCardsForStudy).mockResolvedValue(newCards); - vi.mocked(mockCardRepo.findDueReviewCardsForStudy).mockResolvedValue( - reviewCards, - ); + vi.mocked(mockCardRepo.findDueCardsForStudy).mockResolvedValue(mockCards); const res = await app.request(`/api/decks/${DECK_ID}/study`, { method: "GET", @@ -259,10 +240,7 @@ describe("GET /api/decks/:deckId/study", () => { vi.mocked(mockDeckRepo.findById).mockResolvedValue( createMockDeck({ id: DECK_ID }), ); - vi.mocked(mockCardRepo.findDueNewCardsForStudy).mockResolvedValue( - mockCards, - ); - vi.mocked(mockCardRepo.findDueReviewCardsForStudy).mockResolvedValue([]); + vi.mocked(mockCardRepo.findDueCardsForStudy).mockResolvedValue(mockCards); const res = await app.request(`/api/decks/${DECK_ID}/study`, { method: "GET", @@ -276,81 +254,6 @@ describe("GET /api/decks/:deckId/study", () => { expect(body.cards?.[0]?.fieldValuesMap?.Front).toBe("Question"); }); - it("limits new cards based on newCardsPerDay", async () => { - vi.mocked(mockDeckRepo.findById).mockResolvedValue( - createMockDeck({ id: DECK_ID, newCardsPerDay: 5 }), - ); - vi.mocked(mockReviewLogRepo.countTodayNewCardReviews).mockResolvedValue(3); - vi.mocked(mockCardRepo.findDueNewCardsForStudy).mockResolvedValue([]); - vi.mocked(mockCardRepo.findDueReviewCardsForStudy).mockResolvedValue([]); - - await app.request(`/api/decks/${DECK_ID}/study`, { - method: "GET", - headers: { Authorization: `Bearer ${authToken}` }, - }); - - expect(mockCardRepo.findDueNewCardsForStudy).toHaveBeenCalledWith( - DECK_ID, - expect.any(Date), - 2, - ); - }); - - it("returns 0 new cards when daily limit is reached", async () => { - vi.mocked(mockDeckRepo.findById).mockResolvedValue( - createMockDeck({ id: DECK_ID, newCardsPerDay: 5 }), - ); - vi.mocked(mockReviewLogRepo.countTodayNewCardReviews).mockResolvedValue(5); - vi.mocked(mockCardRepo.findDueNewCardsForStudy).mockResolvedValue([]); - vi.mocked(mockCardRepo.findDueReviewCardsForStudy).mockResolvedValue([]); - - await app.request(`/api/decks/${DECK_ID}/study`, { - method: "GET", - headers: { Authorization: `Bearer ${authToken}` }, - }); - - expect(mockCardRepo.findDueNewCardsForStudy).toHaveBeenCalledWith( - DECK_ID, - expect.any(Date), - 0, - ); - }); - - it("places new cards before review cards in response", async () => { - const newCards = [ - createMockCardForStudy({ - id: "new-1", - state: CardState.New, - fieldValuesMap: {}, - }), - ]; - const reviewCards = [ - createMockCardForStudy({ - id: "review-1", - state: CardState.Review, - fieldValuesMap: {}, - }), - ]; - vi.mocked(mockDeckRepo.findById).mockResolvedValue( - createMockDeck({ id: DECK_ID }), - ); - vi.mocked(mockCardRepo.findDueNewCardsForStudy).mockResolvedValue(newCards); - vi.mocked(mockCardRepo.findDueReviewCardsForStudy).mockResolvedValue( - reviewCards, - ); - - const res = await app.request(`/api/decks/${DECK_ID}/study`, { - method: "GET", - headers: { Authorization: `Bearer ${authToken}` }, - }); - - expect(res.status).toBe(200); - const body = (await res.json()) as StudyResponse; - expect(body.cards).toHaveLength(2); - expect(body.cards?.[0]?.id).toBe("new-1"); - expect(body.cards?.[1]?.id).toBe("review-1"); - }); - it("returns 404 for non-existent deck", async () => { vi.mocked(mockDeckRepo.findById).mockResolvedValue(undefined); -- cgit v1.3-1-g0d28