2
0
Yuki Takei 1 сар өмнө
parent
commit
698a1fc3e5

+ 7 - 9
apps/app/src/server/service/mail/mail.spec.ts

@@ -1,6 +1,7 @@
-import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { type DeepMockProxy, mockDeep } from 'vitest-mock-extended';
 
 import type Crowi from '../../crowi';
+import type { IConfigManagerForApp } from '../config-manager';
 import MailService from './mail';
 import { createOAuth2Client } from './oauth2';
 
@@ -14,15 +15,12 @@ vi.mock('../../models/failed-email', () => ({
 describe('MailService', () => {
   let mailService: MailService;
   let mockCrowi: Crowi;
-  let mockConfigManager: any;
-  let mockS2sMessagingService: any;
-  let mockAppService: any;
+  let mockConfigManager: DeepMockProxy<IConfigManagerForApp>;
+  let mockS2sMessagingService: { publish: ReturnType<typeof vi.fn> };
+  let mockAppService: { getAppTitle: ReturnType<typeof vi.fn> };
 
   beforeEach(() => {
-    mockConfigManager = {
-      getConfig: vi.fn(),
-      loadConfigs: vi.fn(),
-    };
+    mockConfigManager = mockDeep<IConfigManagerForApp>();
 
     mockS2sMessagingService = {
       publish: vi.fn(),
@@ -36,7 +34,7 @@ describe('MailService', () => {
       configManager: mockConfigManager,
       s2sMessagingService: mockS2sMessagingService,
       appService: mockAppService,
-    } as any;
+    } as unknown as Crowi;
 
     mailService = new MailService(mockCrowi);
   });

+ 9 - 10
apps/app/src/server/service/mail/oauth2.spec.ts

@@ -1,18 +1,17 @@
-import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { type DeepMockProxy, mockDeep } from 'vitest-mock-extended';
 
+import type { IConfigManagerForApp } from '../config-manager';
 import { createOAuth2Client } from './oauth2';
 
 describe('createOAuth2Client', () => {
-  let mockConfigManager: any;
+  let mockConfigManager: DeepMockProxy<IConfigManagerForApp>;
 
   beforeEach(() => {
-    mockConfigManager = {
-      getConfig: vi.fn(),
-    };
+    mockConfigManager = mockDeep<IConfigManagerForApp>();
   });
 
   const validCredentials = (
-    overrides: Record<string, string | null> = {},
+    overrides: Record<string, string | undefined> = {},
   ): void => {
     mockConfigManager.getConfig.mockImplementation((key: string) => {
       const defaults: Record<string, string> = {
@@ -27,7 +26,7 @@ describe('createOAuth2Client', () => {
 
   describe('credential validation with type guards', () => {
     it('should return null when clientId is missing', () => {
-      validCredentials({ 'mail:oauth2ClientId': null });
+      validCredentials({ 'mail:oauth2ClientId': undefined });
 
       const result = createOAuth2Client(mockConfigManager);
 
@@ -35,7 +34,7 @@ describe('createOAuth2Client', () => {
     });
 
     it('should return null when clientSecret is missing', () => {
-      validCredentials({ 'mail:oauth2ClientSecret': null });
+      validCredentials({ 'mail:oauth2ClientSecret': undefined });
 
       const result = createOAuth2Client(mockConfigManager);
 
@@ -43,7 +42,7 @@ describe('createOAuth2Client', () => {
     });
 
     it('should return null when refreshToken is missing', () => {
-      validCredentials({ 'mail:oauth2RefreshToken': null });
+      validCredentials({ 'mail:oauth2RefreshToken': undefined });
 
       const result = createOAuth2Client(mockConfigManager);
 
@@ -51,7 +50,7 @@ describe('createOAuth2Client', () => {
     });
 
     it('should return null when user is missing', () => {
-      validCredentials({ 'mail:oauth2User': null });
+      validCredentials({ 'mail:oauth2User': undefined });
 
       const result = createOAuth2Client(mockConfigManager);
 

+ 8 - 9
apps/app/src/server/service/mail/ses.spec.ts

@@ -1,20 +1,19 @@
-import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { type DeepMockProxy, mockDeep } from 'vitest-mock-extended';
 
+import type { IConfigManagerForApp } from '../config-manager';
 import { createSESClient } from './ses';
 
 describe('createSESClient', () => {
-  let mockConfigManager: any;
+  let mockConfigManager: DeepMockProxy<IConfigManagerForApp>;
 
   beforeEach(() => {
-    mockConfigManager = {
-      getConfig: vi.fn(),
-    };
+    mockConfigManager = mockDeep<IConfigManagerForApp>();
   });
 
   describe('credential validation', () => {
     it('should return null when accessKeyId is missing', () => {
       mockConfigManager.getConfig.mockImplementation((key: string) => {
-        if (key === 'mail:sesAccessKeyId') return null;
+        if (key === 'mail:sesAccessKeyId') return undefined;
         if (key === 'mail:sesSecretAccessKey') return 'secretKey123';
         return undefined;
       });
@@ -27,7 +26,7 @@ describe('createSESClient', () => {
     it('should return null when secretAccessKey is missing', () => {
       mockConfigManager.getConfig.mockImplementation((key: string) => {
         if (key === 'mail:sesAccessKeyId') return 'AKIAIOSFODNN7EXAMPLE';
-        if (key === 'mail:sesSecretAccessKey') return null;
+        if (key === 'mail:sesSecretAccessKey') return undefined;
         return undefined;
       });
 
@@ -38,8 +37,8 @@ describe('createSESClient', () => {
 
     it('should return null when both credentials are missing', () => {
       mockConfigManager.getConfig.mockImplementation((key: string) => {
-        if (key === 'mail:sesAccessKeyId') return null;
-        if (key === 'mail:sesSecretAccessKey') return null;
+        if (key === 'mail:sesAccessKeyId') return undefined;
+        if (key === 'mail:sesSecretAccessKey') return undefined;
         return undefined;
       });
 

+ 1 - 1
apps/app/src/server/service/mail/ses.ts

@@ -1,5 +1,6 @@
 import type { Transporter } from 'nodemailer';
 import nodemailer from 'nodemailer';
+import ses from 'nodemailer-ses-transport';
 
 import loggerFactory from '~/utils/logger';
 
@@ -36,7 +37,6 @@ export function createSESClient(
     };
   }
 
-  const ses = require('nodemailer-ses-transport');
   const client = nodemailer.createTransport(ses(option));
 
   logger.debug('mailer set up for SES', client);

+ 8 - 9
apps/app/src/server/service/mail/smtp.spec.ts

@@ -1,20 +1,19 @@
-import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { type DeepMockProxy, mockDeep } from 'vitest-mock-extended';
 
+import type { IConfigManagerForApp } from '../config-manager';
 import { createSMTPClient } from './smtp';
 
 describe('createSMTPClient', () => {
-  let mockConfigManager: any;
+  let mockConfigManager: DeepMockProxy<IConfigManagerForApp>;
 
   beforeEach(() => {
-    mockConfigManager = {
-      getConfig: vi.fn(),
-    };
+    mockConfigManager = mockDeep<IConfigManagerForApp>();
   });
 
   describe('credential validation', () => {
     it('should return null when host is missing', () => {
       mockConfigManager.getConfig.mockImplementation((key: string) => {
-        if (key === 'mail:smtpHost') return null;
+        if (key === 'mail:smtpHost') return undefined;
         if (key === 'mail:smtpPort') return 587;
         return undefined;
       });
@@ -27,7 +26,7 @@ describe('createSMTPClient', () => {
     it('should return null when port is missing', () => {
       mockConfigManager.getConfig.mockImplementation((key: string) => {
         if (key === 'mail:smtpHost') return 'smtp.example.com';
-        if (key === 'mail:smtpPort') return null;
+        if (key === 'mail:smtpPort') return undefined;
         return undefined;
       });
 
@@ -38,8 +37,8 @@ describe('createSMTPClient', () => {
 
     it('should return null when both host and port are missing', () => {
       mockConfigManager.getConfig.mockImplementation((key: string) => {
-        if (key === 'mail:smtpHost') return null;
-        if (key === 'mail:smtpPort') return null;
+        if (key === 'mail:smtpHost') return undefined;
+        if (key === 'mail:smtpPort') return undefined;
         return undefined;
       });