Просмотр исходного кода

Merge branch 'master' into copilot/implement-email-sending-functionality

Yuki Takei 2 месяцев назад
Родитель
Сommit
ad10e996ff

+ 34 - 3
.claude/skills/testing-patterns-with-vitest/SKILL.md

@@ -415,12 +415,43 @@ Before committing tests, ensure:
 
 
 ## Running Tests
 ## Running Tests
 
 
+### From Monorepo Root (Recommended)
+
 ```bash
 ```bash
-# Run all tests for a package
+# Run all tests for a specific package
 turbo run test --filter @growi/app
 turbo run test --filter @growi/app
+turbo run test --filter @growi/core
+
+# Or with Turborepo caching
+pnpm run test --filter @growi/app
+```
+
+### From Package Directory
+
+```bash
+# Run all tests
+pnpm vitest run
 
 
-# Run specific test file
-cd {package_dir} && pnpm vitest run src/components/Button/Button.spec.tsx
+# Run specific test file (use partial file name)
+pnpm vitest run yjs.integ
+pnpm vitest run helper.spec
+pnpm vitest run Button.spec
+
+# Run tests matching a pattern
+pnpm vitest run PageService
+```
+
+**File pattern tips**:
+- Use **partial file name** - Vitest automatically finds matching files
+- No need for `src/` prefix or full path
+- No need for `--project` flag - Vitest auto-detects based on file extension
+- Works across all packages (apps/app, packages/core, etc.)
+
+### Running Multiple Times (Flaky Test Detection)
+
+```bash
+# Repeat test execution to verify stability
+pnpm vitest run yjs.integ --repeat=10
 ```
 ```
 
 
 ## Summary: GROWI Testing Philosophy
 ## Summary: GROWI Testing Philosophy

+ 4 - 0
apps/app/AGENTS.md

@@ -29,6 +29,10 @@ pnpm run test                   # Run tests
 
 
 # Build
 # Build
 pnpm run build                  # Build for production
 pnpm run build                  # Build for production
+
+# Run Specific Tests
+pnpm vitest run yjs.integ       # Use partial file name
+pnpm vitest run helper.spec     # Vitest auto-finds matching files
 ```
 ```
 
 
 ### Key Directories
 ### Key Directories

+ 14 - 2
apps/app/src/server/service/yjs/yjs.integ.ts

@@ -1,5 +1,5 @@
 import { YDocStatus } from '@growi/core/dist/consts';
 import { YDocStatus } from '@growi/core/dist/consts';
-import { Types } from 'mongoose';
+import mongoose, { Types } from 'mongoose';
 import type { Server } from 'socket.io';
 import type { Server } from 'socket.io';
 import { mock } from 'vitest-mock-extended';
 import { mock } from 'vitest-mock-extended';
 
 
@@ -33,6 +33,10 @@ describe('YjsService', () => {
 
 
       // initialize
       // initialize
       initializeYjsService(ioMock);
       initializeYjsService(ioMock);
+
+      // Wait for index creation to complete to avoid race condition
+      const collection = mongoose.connection.collection('yjs-writings');
+      await collection.listIndexes().toArray();
     });
     });
 
 
     afterAll(async () => {
     afterAll(async () => {
@@ -42,7 +46,15 @@ describe('YjsService', () => {
       // flush yjs-writings
       // flush yjs-writings
       const yjsService = getYjsService();
       const yjsService = getYjsService();
       const privateMdb = getPrivateMdbInstance(yjsService);
       const privateMdb = getPrivateMdbInstance(yjsService);
-      await privateMdb.flushDB();
+      try {
+        await privateMdb.flushDB();
+      } catch (error) {
+        // Ignore IndexBuildAborted error (code: 276) which can occur in CI
+        // when cleanup happens while index creation is still in progress
+        if (error.code !== 276) {
+          throw error;
+        }
+      }
     });
     });
 
 
     it('returns ISOLATED when neither revisions nor YDocs exists', async () => {
     it('returns ISOLATED when neither revisions nor YDocs exists', async () => {