Bläddra i källkod

@
test(app): replace type assertions in bulk-export cleanup tests with mock<T>()

Address review feedback on PR #11229: the test code used several
`as unknown as Crowi` casts and an implicit-any `let user`, which the
strengthened test type-safety guidance (master 4cbd0e1ab9) discourages.

- Replace `{...} as unknown as Crowi` with `mock<Crowi>({...})` from
vitest-mock-extended (type-checked overrides, auto-stubbed rest) in
both the cleanup-cron integ test and the attachment unit spec.
- Type `let user` as `Awaited<ReturnType<typeof User.create>>` and drop
the `noImplicitAnyLet` biome-ignore.
- Replace the untyped `fakeAttachment` literal with
`mock<IAttachmentDocument>({ remove })`.

The two remaining `as any` casts on `Attachment.findById` mocks are kept:
`findById` returns a Mongoose Query, not a Promise, so `mockResolvedValue`
unavoidably mismatches the declared return type; their existing
`noExplicitAny` ignore comments document this.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@

tomoyuki-t 1 vecka sedan
förälder
incheckning
033436cded

+ 4 - 4
apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-clean-up-cron.integ.ts

@@ -1,4 +1,5 @@
 import mongoose from 'mongoose';
+import { mock } from 'vitest-mock-extended';
 
 import type Crowi from '~/server/crowi';
 import { configManager } from '~/server/service/config-manager';
@@ -37,13 +38,12 @@ vi.mock('./page-bulk-export-job-cron', () => {
 
 describe('PageBulkExportJobCleanUpCronService', () => {
   const removeAttachmentMock = vi.fn(() => Promise.resolve());
-  const crowi = {
+  const crowi = mock<Crowi>({
     attachmentService: {
       removeAttachment: removeAttachmentMock,
     },
-  } as unknown as Crowi;
-  // biome-ignore lint/suspicious/noImplicitAnyLet: ignore
-  let user;
+  });
+  let user: Awaited<ReturnType<typeof User.create>>;
 
   beforeAll(async () => {
     await configManager.loadConfigs();

+ 10 - 5
apps/app/src/server/service/attachment.spec.ts

@@ -1,4 +1,7 @@
+import { mock } from 'vitest-mock-extended';
+
 import type Crowi from '../crowi';
+import type { IAttachmentDocument } from '../models/attachment';
 import { Attachment } from '../models/attachment';
 import { AttachmentService } from './attachment';
 
@@ -15,9 +18,9 @@ describe('AttachmentService.removeAttachment', () => {
       // biome-ignore lint/suspicious/noExplicitAny: Mongoose query shape is irrelevant to the contract under test
       .mockResolvedValue(null as any);
     const deleteFile = vi.fn();
-    const crowi = {
+    const crowi = mock<Crowi>({
       fileUploadService: { deleteFile },
-    } as unknown as Crowi;
+    });
     const service = new AttachmentService(crowi);
 
     await expect(
@@ -30,7 +33,9 @@ describe('AttachmentService.removeAttachment', () => {
 
   test('should propagate the error and not drop the metadata doc when the file store fails', async () => {
     const attachmentRemove = vi.fn().mockResolvedValue(undefined);
-    const fakeAttachment = { _id: 'some-id', remove: attachmentRemove };
+    const fakeAttachment = mock<IAttachmentDocument>({
+      remove: attachmentRemove,
+    });
     const findByIdSpy = vi
       .spyOn(Attachment, 'findById')
       // biome-ignore lint/suspicious/noExplicitAny: Mongoose query shape is irrelevant to the contract under test
@@ -38,9 +43,9 @@ describe('AttachmentService.removeAttachment', () => {
     const deleteFile = vi
       .fn()
       .mockRejectedValue(new Error('S3 is temporarily unavailable'));
-    const crowi = {
+    const crowi = mock<Crowi>({
       fileUploadService: { deleteFile },
-    } as unknown as Crowi;
+    });
     const service = new AttachmentService(crowi);
     service.detachHandlers = [];