diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 4cecc9e9c..7293ff485 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -41,7 +41,8 @@ jobs: run: node common/scripts/install-run-rush.js update --bypass-policy - name: Install rush run: node common/scripts/install-run-rush.js install --bypass-policy + - name: Source tests (without build artifacts) + run: node common/scripts/install-run-rush.js test --only tag:package - run: node common/scripts/install-run-rush.js build --only tag:package - - name: Pre unit test - run: cd packages/vrender && node ../../common/scripts/install-run-rushx.js test && cd ../.. - - run: node common/scripts/install-run-rush.js test --only tag:package + - name: Published artifact tests + run: node common/scripts/install-run-rush.js test:artifacts --only tag:package diff --git a/common/config/rush/command-line.json b/common/config/rush/command-line.json index a21e413e2..5b81c28fe 100644 --- a/common/config/rush/command-line.json +++ b/common/config/rush/command-line.json @@ -35,6 +35,15 @@ "ignoreDependencyOrder": true, "allowWarningsInSuccessfulBuild": true }, + { + "name": "test:artifacts", + "summary": "Validate published artifacts after building packages", + "enableParallelism": false, + "commandKind": "bulk", + "ignoreMissingScript": true, + "ignoreDependencyOrder": true, + "allowWarningsInSuccessfulBuild": true + }, { "name": "run", "summary": "", diff --git a/docs/agent/VRENDER_TEST_AND_VERIFICATION.md b/docs/agent/VRENDER_TEST_AND_VERIFICATION.md index 3a420dcb0..0682ff115 100644 --- a/docs/agent/VRENDER_TEST_AND_VERIFICATION.md +++ b/docs/agent/VRENDER_TEST_AND_VERIFICATION.md @@ -12,6 +12,7 @@ - `rush compile -t @visactor/vrender-core` - `rush test` - `rush test -t @visactor/vrender` +- `rush test:artifacts --only tag:package`(先 build,再检查发布产物) - `rush eslint` - `rush lint-staged` - `rush start` @@ -41,6 +42,23 @@ ## 单包 Test +`rush test`、各包 `rushx test` 和 pre-push 只运行源码测试:仓库内包通过 +`share/jest-config/source-module-name-mapper.js` 解析到本地 `src`,不依赖 `es/cjs/dist`。 +第三方 npm 依赖仍使用安装版本。CI 在 build 之前运行源码测试,避免旧产物掩盖源码问题。 + +构建产物断言位于各包 `__tests__/artifacts/`,默认单测和 Electron 测试不会收集它们。 +`vrender-core`、`vrender-kits`、`vrender` 提供独立的 `rushx test:artifacts`;这些测试不启用源码映射, +并在缺少构建文件时失败。跨包产物检查需要先构建全部 package: + +```bash +rush build --only tag:package +rush test:artifacts --only tag:package +``` + +新增测试时,运行时行为及源码/配置契约归入默认单测;读取构建输出或验证发布包入口的断言归入 artifacts。 +同时包含两类断言的文件应拆分。验证源码测试独立性时,在没有各包 `es/cjs/dist` 的干净 worktree 中执行 +`rush test --only tag:package`,不通过跳过失败用例或自动 build 消除依赖。 + 在对应 package 下: - `cd packages/vrender-core && rushx test` @@ -135,7 +153,7 @@ root: - `packages/vrender/__tests__/unit/shared-browser-lite-entry.test.ts` - `packages/vrender/__tests__/unit/app-bootstrap-binding.test.ts` - `packages/vrender/__tests__/unit/node-app-runtime.test.ts` -- `packages/vrender/__tests__/unit/build-artifact-consistency.test.ts` +- 发布产物检查:`packages/vrender/__tests__/artifacts/*` ## Animate 测试 diff --git a/packages/react-vrender-utils/jest.config.js b/packages/react-vrender-utils/jest.config.js index 7723b5d3a..c3519ed9c 100644 --- a/packages/react-vrender-utils/jest.config.js +++ b/packages/react-vrender-utils/jest.config.js @@ -1,4 +1,3 @@ -const path = require('path'); const { createStablePackageJestConfig } = require('../../share/jest-config/create-package-config'); module.exports = createStablePackageJestConfig({ @@ -22,7 +21,5 @@ module.exports = createStablePackageJestConfig({ '!**/interface.ts', '!**/**.d.ts' ], - moduleNameMapper: { - '@visactor/react-vrender': path.resolve(__dirname, '../react-vrender/src/index.ts') - } + moduleNameMapper: require('../../share/jest-config/source-module-name-mapper') }); diff --git a/packages/react-vrender/jest.config.js b/packages/react-vrender/jest.config.js index f7cea21c7..6f6e565cf 100644 --- a/packages/react-vrender/jest.config.js +++ b/packages/react-vrender/jest.config.js @@ -1,4 +1,3 @@ -const path = require('path'); const { createStablePackageJestConfig } = require('../../share/jest-config/create-package-config'); module.exports = createStablePackageJestConfig({ @@ -22,11 +21,5 @@ module.exports = createStablePackageJestConfig({ '!**/interface.ts', '!**/**.d.ts' ], - moduleNameMapper: { - '@visactor/vrender': path.resolve(__dirname, '../vrender/src/index.ts'), - '@visactor/vrender-core': path.resolve(__dirname, '../vrender-core/src/index.ts'), - '@visactor/vrender-kits': path.resolve(__dirname, '../vrender-kits/src/index.ts'), - '@visactor/vrender-animate': path.resolve(__dirname, '../vrender-animate/src/index.ts'), - '@visactor/vrender-components': path.resolve(__dirname, '../vrender-components/src/index.ts') - } + moduleNameMapper: require('../../share/jest-config/source-module-name-mapper') }); diff --git a/packages/vrender-animate/jest.config.js b/packages/vrender-animate/jest.config.js index 8f3c7183f..2a0aaf36e 100644 --- a/packages/vrender-animate/jest.config.js +++ b/packages/vrender-animate/jest.config.js @@ -1,4 +1,3 @@ -const path = require('path'); const { createStablePackageJestConfig } = require('../../share/jest-config/create-package-config'); module.exports = createStablePackageJestConfig({ @@ -21,17 +20,5 @@ module.exports = createStablePackageJestConfig({ '!**/interface.ts', '!**/**.d.ts' ], - moduleNameMapper: { - '^@visactor/vrender-core/event/constant$': path.resolve(__dirname, '../vrender-core/src/event/public-constant.ts'), - '^@visactor/vrender-core/render/draw-interceptor$': path.resolve( - __dirname, - '../vrender-core/src/render/contributions/render/draw-interceptor.ts' - ), - '^@visactor/vrender-core/render/symbol$': path.resolve( - __dirname, - '../vrender-core/src/render/contributions/render/symbol.ts' - ), - '^@visactor/vrender-core/(.*)$': path.resolve(__dirname, '../vrender-core/src/$1'), - '^@visactor/vrender-core$': path.resolve(__dirname, '../vrender-core/src/index.ts') - } + moduleNameMapper: require('../../share/jest-config/source-module-name-mapper') }); diff --git a/packages/vrender-components/jest.config.js b/packages/vrender-components/jest.config.js index 77d273fc3..f771948d3 100644 --- a/packages/vrender-components/jest.config.js +++ b/packages/vrender-components/jest.config.js @@ -1,4 +1,3 @@ -const path = require('path'); const { createStablePackageJestConfig } = require('../../share/jest-config/create-package-config'); module.exports = createStablePackageJestConfig({ @@ -10,24 +9,5 @@ module.exports = createStablePackageJestConfig({ tsconfig: './tsconfig.test.json', collectCoverageFrom: ['src/**/*.ts', '!**/type/**'], coveragePathIgnorePatterns: ['node_modules', '__tests__', 'interface.ts', '.d.ts', 'typings', 'type.ts'], - moduleNameMapper: { - '^@visactor/vrender-kits/(.*)$': path.resolve(__dirname, '../vrender-kits/src/$1'), - '^@visactor/vrender-kits$': path.resolve(__dirname, '../vrender-kits/src/index.ts'), - '^@visactor/vrender-core/event/constant$': path.resolve(__dirname, '../vrender-core/src/event/public-constant.ts'), - '^@visactor/vrender-core/render/draw-interceptor$': path.resolve( - __dirname, - '../vrender-core/src/render/contributions/render/draw-interceptor.ts' - ), - '^@visactor/vrender-core/render/symbol$': path.resolve( - __dirname, - '../vrender-core/src/render/contributions/render/symbol.ts' - ), - '^@visactor/vrender-core/(.*)$': path.resolve(__dirname, '../vrender-core/src/$1'), - '^@visactor/vrender-core$': path.resolve(__dirname, '../vrender-core/src/index.ts'), - '^@visactor/vrender/es/core$': path.resolve(__dirname, '../vrender/src/index.ts'), - '^@visactor/vrender/es/register$': path.resolve(__dirname, '../vrender/src/register.ts'), - '^@visactor/vrender/es/kits$': path.resolve(__dirname, '../vrender/src/kits.ts'), - '^@visactor/vrender-animate/(.*)$': path.resolve(__dirname, '../vrender-animate/src/$1'), - '^@visactor/vrender-animate$': path.resolve(__dirname, '../vrender-animate/src/index.ts') - } + moduleNameMapper: require('../../share/jest-config/source-module-name-mapper') }); diff --git a/packages/vrender-core/__tests__/artifacts/container-compatibility.test.ts b/packages/vrender-core/__tests__/artifacts/container-compatibility.test.ts new file mode 100644 index 000000000..0a81e3d1c --- /dev/null +++ b/packages/vrender-core/__tests__/artifacts/container-compatibility.test.ts @@ -0,0 +1,26 @@ +declare const require: any; +export {}; + +const fs = require('fs'); +const path = require('path'); +const process = require('process'); +const packageRoot = process.cwd(); + +function readArtifact(relativePath: string) { + return fs.readFileSync(path.join(packageRoot, relativePath), 'utf8'); +} + +describe('vrender-core published container compatibility', () => { + test('es artifacts should expose legacy container compatibility surface', () => { + expect(readArtifact('es/modules.js')).toContain('export const container'); + expect(readArtifact('es/modules.d.ts')).toContain('container'); + expect(readArtifact('es/index.d.ts')).toContain("from './modules'"); + expect(readArtifact('es/index.d.ts')).toContain('container'); + }); + + test('cjs root export should expose container as the legacy binding context', () => { + const vrenderCore = require(path.join(packageRoot, 'cjs/index.js')); + + expect(vrenderCore.container).toBe(vrenderCore.getLegacyBindingContext()); + }); +}); diff --git a/packages/vrender-core/__tests__/artifacts/root-esm-exports.test.ts b/packages/vrender-core/__tests__/artifacts/root-esm-exports.test.ts new file mode 100644 index 000000000..a15422675 --- /dev/null +++ b/packages/vrender-core/__tests__/artifacts/root-esm-exports.test.ts @@ -0,0 +1,81 @@ +/** + * @jest-environment node + */ + +declare const __dirname: string; +declare const require: any; +export {}; + +const fs = require('fs'); +const path = require('path'); +const packageRoot = path.resolve(__dirname, '../..'); + +describe('vrender-core published root exports', () => { + test('keeps BytePack-sensitive root runtime exports explicit in the ESM artifact', () => { + const artifact = fs.readFileSync(path.join(packageRoot, 'es/index.js'), 'utf8'); + const explicitExports = new Set(); + const exportPattern = /export\s+\{([^}]+)\}/g; + let match: RegExpExecArray | null; + + while ((match = exportPattern.exec(artifact))) { + match[1] + .split(',') + .map((item: string) => item.trim()) + .filter(Boolean) + .forEach((specifier: string) => { + const exportedName = specifier.match(/\s+as\s+([A-Za-z0-9_$]+)$/)?.[1] ?? specifier; + explicitExports.add(exportedName.trim()); + }); + } + + const expectedExplicitRuntimeExports = [ + 'CustomEvent', + 'CustomPath2D', + 'GradientParser', + 'IContainPointMode', + 'Symbol', + 'builtInSymbolStrMap', + 'builtinSymbols', + 'builtinSymbolsMap', + 'container', + 'createArc', + 'createArc3d', + 'createArea', + 'createGlyph', + 'createGroup', + 'createImage', + 'createLine', + 'createPath', + 'createPolygon', + 'createPyramid3d', + 'createRect', + 'createRect3d', + 'createRichText', + 'createSymbol', + 'createText', + 'getRichTextBounds', + 'getTextBounds', + 'graphicCreator', + 'isBrowserEnv', + 'mapToCanvasPointForCanvas', + 'matrixAllocate', + 'registerDirectionalLight', + 'registerGlobalEventTransformer', + 'registerHtmlAttributePlugin', + 'registerOrthoCamera', + 'registerReactAttributePlugin', + 'registerViewTransform3dPlugin', + 'registerWindowEventTransformer', + 'transformPointForCanvas', + 'vglobal', + 'waitForAllSubLayers' + ]; + + expect(expectedExplicitRuntimeExports.filter(name => !explicitExports.has(name))).toEqual([]); + + expect(artifact).toContain('export { Symbol, createSymbol } from "./graphic/symbol"'); + expect(artifact).toContain( + 'export { builtInSymbolStrMap, builtinSymbols, builtinSymbolsMap } from "./graphic/builtin-symbol"' + ); + }); +}); diff --git a/packages/vrender-core/__tests__/unit/xml-parser-bundle-safe.test.ts b/packages/vrender-core/__tests__/artifacts/xml-parser-bundle-safe.test.ts similarity index 100% rename from packages/vrender-core/__tests__/unit/xml-parser-bundle-safe.test.ts rename to packages/vrender-core/__tests__/artifacts/xml-parser-bundle-safe.test.ts diff --git a/packages/vrender-core/__tests__/unit/modules/container-compatibility.test.ts b/packages/vrender-core/__tests__/unit/modules/container-compatibility.test.ts index 84364003c..16c5fa832 100644 --- a/packages/vrender-core/__tests__/unit/modules/container-compatibility.test.ts +++ b/packages/vrender-core/__tests__/unit/modules/container-compatibility.test.ts @@ -1,16 +1,11 @@ declare const require: any; export {}; -const fs = require('fs'); const path = require('path'); const process = require('process'); const packageRoot = process.cwd(); -function readArtifact(relativePath: string) { - return fs.readFileSync(path.join(packageRoot, relativePath), 'utf8'); -} - describe('vrender-core container compatibility', () => { test('application should use realm-level shared state for duplicated ESM entry evaluation', () => { const { application } = require(path.join(packageRoot, 'src/application')); @@ -19,17 +14,4 @@ describe('vrender-core container compatibility', () => { expect(state).toBeDefined(); expect(state.application).toBe(application); }); - - test('es artifacts should expose legacy container compatibility surface', () => { - expect(readArtifact('es/modules.js')).toContain('export const container'); - expect(readArtifact('es/modules.d.ts')).toContain('container'); - expect(readArtifact('es/index.d.ts')).toContain("from './modules'"); - expect(readArtifact('es/index.d.ts')).toContain('container'); - }); - - test('cjs root export should expose container as the legacy binding context', () => { - const vrenderCore = require(path.join(packageRoot, 'cjs/index.js')); - - expect(vrenderCore.container).toBe(vrenderCore.getLegacyBindingContext()); - }); }); diff --git a/packages/vrender-core/__tests__/unit/public-subpath-exports.test.ts b/packages/vrender-core/__tests__/unit/public-subpath-exports.test.ts index e9e698d6c..96cf86347 100644 --- a/packages/vrender-core/__tests__/unit/public-subpath-exports.test.ts +++ b/packages/vrender-core/__tests__/unit/public-subpath-exports.test.ts @@ -77,72 +77,4 @@ describe('vrender-core public subpath exports', () => { expect(packageJson.typesVersions?.['*']).toEqual(expectedTypesVersions); }); - - test('keeps BytePack-sensitive root runtime exports explicit in the ESM artifact', () => { - const artifact = fs.readFileSync(path.join(packageRoot, 'es/index.js'), 'utf8'); - const explicitExports = new Set(); - const exportPattern = /export\s+\{([^}]+)\}/g; - let match: RegExpExecArray | null; - - while ((match = exportPattern.exec(artifact))) { - match[1] - .split(',') - .map((item: string) => item.trim()) - .filter(Boolean) - .forEach((specifier: string) => { - const exportedName = specifier.match(/\s+as\s+([A-Za-z0-9_$]+)$/)?.[1] ?? specifier; - explicitExports.add(exportedName.trim()); - }); - } - - const expectedExplicitRuntimeExports = [ - 'CustomEvent', - 'CustomPath2D', - 'GradientParser', - 'IContainPointMode', - 'Symbol', - 'builtInSymbolStrMap', - 'builtinSymbols', - 'builtinSymbolsMap', - 'container', - 'createArc', - 'createArc3d', - 'createArea', - 'createGlyph', - 'createGroup', - 'createImage', - 'createLine', - 'createPath', - 'createPolygon', - 'createPyramid3d', - 'createRect', - 'createRect3d', - 'createRichText', - 'createSymbol', - 'createText', - 'getRichTextBounds', - 'getTextBounds', - 'graphicCreator', - 'isBrowserEnv', - 'mapToCanvasPointForCanvas', - 'matrixAllocate', - 'registerDirectionalLight', - 'registerGlobalEventTransformer', - 'registerHtmlAttributePlugin', - 'registerOrthoCamera', - 'registerReactAttributePlugin', - 'registerViewTransform3dPlugin', - 'registerWindowEventTransformer', - 'transformPointForCanvas', - 'vglobal', - 'waitForAllSubLayers' - ]; - - expect(expectedExplicitRuntimeExports.filter(name => !explicitExports.has(name))).toEqual([]); - - expect(artifact).toContain('export { Symbol, createSymbol } from "./graphic/symbol"'); - expect(artifact).toContain( - 'export { builtInSymbolStrMap, builtinSymbols, builtinSymbolsMap } from "./graphic/builtin-symbol"' - ); - }); }); diff --git a/packages/vrender-core/jest.artifacts.config.js b/packages/vrender-core/jest.artifacts.config.js new file mode 100644 index 000000000..5b0698ca3 --- /dev/null +++ b/packages/vrender-core/jest.artifacts.config.js @@ -0,0 +1,3 @@ +const { createArtifactPackageJestConfig } = require('../../share/jest-config/create-package-config'); + +module.exports = createArtifactPackageJestConfig(); diff --git a/packages/vrender-core/jest.config.js b/packages/vrender-core/jest.config.js index 216f18390..ce06cacae 100644 --- a/packages/vrender-core/jest.config.js +++ b/packages/vrender-core/jest.config.js @@ -1,4 +1,3 @@ -const path = require('path'); const { createStablePackageJestConfig } = require('../../share/jest-config/create-package-config'); module.exports = createStablePackageJestConfig({ @@ -29,17 +28,5 @@ module.exports = createStablePackageJestConfig({ statements: 80 } }, - moduleNameMapper: { - '^@visactor/vrender-core/event/constant$': path.resolve(__dirname, './src/event/public-constant.ts'), - '^@visactor/vrender-core/render/draw-interceptor$': path.resolve( - __dirname, - './src/render/contributions/render/draw-interceptor.ts' - ), - '^@visactor/vrender-core/render/symbol$': path.resolve( - __dirname, - './src/render/contributions/render/symbol.ts' - ), - '^@visactor/vrender-core/(.*)$': path.resolve(__dirname, './src/$1'), - '^@visactor/vrender-core$': path.resolve(__dirname, './src/index.ts') - } + moduleNameMapper: require('../../share/jest-config/source-module-name-mapper') }); diff --git a/packages/vrender-core/package.json b/packages/vrender-core/package.json index ebba386fe..f133c6e51 100644 --- a/packages/vrender-core/package.json +++ b/packages/vrender-core/package.json @@ -59,6 +59,7 @@ "dev": "cross-env DEBUG='Bundler*' bundle --clean -f es -w", "start": "vite ./__tests__/browser", "test": "jest -c jest.config.js", + "test:artifacts": "jest -c jest.artifacts.config.js", "test:electron": "jest -c jest.electron.config.js --runInBand --passWithNoTests --testPathPattern='__tests__/(browser|electron)/'", "test-live": "npm run test-watch __tests__/unit/theme/line.test.ts", "test-watch": "cross-env DEBUG_MODE=1 jest --watch -c jest.config.js", diff --git a/packages/vrender-kits/__tests__/unit/build-artifact-imports.test.ts b/packages/vrender-kits/__tests__/artifacts/build-artifact-imports.test.ts similarity index 94% rename from packages/vrender-kits/__tests__/unit/build-artifact-imports.test.ts rename to packages/vrender-kits/__tests__/artifacts/build-artifact-imports.test.ts index 1b44b0ceb..6f8354ac0 100644 --- a/packages/vrender-kits/__tests__/unit/build-artifact-imports.test.ts +++ b/packages/vrender-kits/__tests__/artifacts/build-artifact-imports.test.ts @@ -51,10 +51,6 @@ const forbiddenCoreRootRuntimeImports = [ function collectArtifactFiles(relativeDir: string): string[] { const absoluteDir = path.join(packageRoot, relativeDir); - if (!fs.existsSync(absoluteDir)) { - return []; - } - const entries = fs.readdirSync(absoluteDir, { withFileTypes: true }); return entries.flatMap((entry: { isDirectory: () => boolean; name: string }) => { const relativePath = path.join(relativeDir, entry.name); @@ -69,12 +65,14 @@ function collectArtifactFiles(relativeDir: string): string[] { describe('vrender-kits published artifacts', () => { test('should not reference workspace source directories', () => { - const offenders = buildRoots.flatMap(buildRoot => - collectArtifactFiles(buildRoot).flatMap(relativePath => { + const offenders = buildRoots.flatMap(buildRoot => { + const artifactFiles = collectArtifactFiles(buildRoot); + expect(artifactFiles.length).toBeGreaterThan(0); + return artifactFiles.flatMap(relativePath => { const artifact = fs.readFileSync(path.join(packageRoot, relativePath), 'utf8'); return forbiddenWorkspaceSourcePatterns.some(pattern => pattern.test(artifact)) ? [relativePath] : []; - }) - ); + }); + }); expect(offenders).toEqual([]); }); diff --git a/packages/vrender-kits/__tests__/unit/root-installer-exports.test.ts b/packages/vrender-kits/__tests__/artifacts/root-installer-exports.test.ts similarity index 100% rename from packages/vrender-kits/__tests__/unit/root-installer-exports.test.ts rename to packages/vrender-kits/__tests__/artifacts/root-installer-exports.test.ts diff --git a/packages/vrender-kits/jest.artifacts.config.js b/packages/vrender-kits/jest.artifacts.config.js new file mode 100644 index 000000000..5b0698ca3 --- /dev/null +++ b/packages/vrender-kits/jest.artifacts.config.js @@ -0,0 +1,3 @@ +const { createArtifactPackageJestConfig } = require('../../share/jest-config/create-package-config'); + +module.exports = createArtifactPackageJestConfig(); diff --git a/packages/vrender-kits/jest.config.js b/packages/vrender-kits/jest.config.js index 261684d3b..2a0aaf36e 100644 --- a/packages/vrender-kits/jest.config.js +++ b/packages/vrender-kits/jest.config.js @@ -1,4 +1,3 @@ -const path = require('path'); const { createStablePackageJestConfig } = require('../../share/jest-config/create-package-config'); module.exports = createStablePackageJestConfig({ @@ -21,18 +20,5 @@ module.exports = createStablePackageJestConfig({ '!**/interface.ts', '!**/**.d.ts' ], - moduleNameMapper: { - '^@visactor/vrender-core/event/constant$': path.resolve(__dirname, '../vrender-core/src/event/public-constant.ts'), - '^@visactor/vrender-core/render/draw-interceptor$': path.resolve( - __dirname, - '../vrender-core/src/render/contributions/render/draw-interceptor.ts' - ), - '^@visactor/vrender-core/render/symbol$': path.resolve( - __dirname, - '../vrender-core/src/render/contributions/render/symbol.ts' - ), - '^@visactor/vrender-core/(.*)$': path.resolve(__dirname, '../vrender-core/src/$1'), - '^@visactor/vrender-core$': path.resolve(__dirname, '../vrender-core/src/index.ts'), - '@visactor/vrender-animate': path.resolve(__dirname, '../vrender-animate/src/index.ts') - } + moduleNameMapper: require('../../share/jest-config/source-module-name-mapper') }); diff --git a/packages/vrender-kits/package.json b/packages/vrender-kits/package.json index 555c288c2..5f5342587 100644 --- a/packages/vrender-kits/package.json +++ b/packages/vrender-kits/package.json @@ -31,6 +31,7 @@ "dev": "cross-env DEBUG='Bundler*' bundle --clean -f es -w", "start": "vite ./vite", "test": "jest -c jest.config.js", + "test:artifacts": "jest -c jest.artifacts.config.js", "test:electron": "jest -c jest.electron.config.js --runInBand --passWithNoTests --testPathPattern='__tests__/(browser|electron)/'", "test-cov": "jest -c jest.config.js --coverage", "test-watch": "cross-env DEBUG_MODE=1 jest --watch -c jest.config.js" diff --git a/packages/vrender/__tests__/unit/build-artifact-consistency.test.ts b/packages/vrender/__tests__/artifacts/build-artifact-consistency.test.ts similarity index 100% rename from packages/vrender/__tests__/unit/build-artifact-consistency.test.ts rename to packages/vrender/__tests__/artifacts/build-artifact-consistency.test.ts diff --git a/packages/vrender/__tests__/unit/build-artifact-root-imports.test.ts b/packages/vrender/__tests__/artifacts/build-artifact-root-imports.test.ts similarity index 81% rename from packages/vrender/__tests__/unit/build-artifact-root-imports.test.ts rename to packages/vrender/__tests__/artifacts/build-artifact-root-imports.test.ts index a4e6e3396..bf5f49a72 100644 --- a/packages/vrender/__tests__/unit/build-artifact-root-imports.test.ts +++ b/packages/vrender/__tests__/artifacts/build-artifact-root-imports.test.ts @@ -28,10 +28,6 @@ function collectPackageDirs(): string[] { function collectArtifactFiles(packageRoot: string, relativeDir: string): string[] { const absoluteDir = path.join(packageRoot, relativeDir); - if (!fs.existsSync(absoluteDir)) { - return []; - } - return fs .readdirSync(absoluteDir, { withFileTypes: true }) .flatMap((entry: { isDirectory: () => boolean; name: string }) => { @@ -85,27 +81,21 @@ function collectRootNamedImports(artifact: string, packageName: string): string[ describe('published root bundle imports', () => { test('root named imports between VRender package artifacts should exist in target root bundle exports', () => { - const packages = collectPackageDirs() - .map((dir: string) => { - const packageRoot = path.join(packagesRoot, dir); - const bundlePath = path.join(packageRoot, rootBundlePath); - - if (!fs.existsSync(bundlePath)) { - return null; - } - - const packageJson = JSON.parse(readText(path.join(packageRoot, 'package.json'))); - const artifact = readText(bundlePath); - - return { - name: packageJson.name, - dir, - packageRoot, - artifactFiles: scannedBuildRoots.flatMap(relativeDir => collectArtifactFiles(packageRoot, relativeDir)), - exports: new Set(collectBundleNamedExports(artifact)) - }; - }) - .filter(Boolean); + const packages = collectPackageDirs().map((dir: string) => { + const packageRoot = path.join(packagesRoot, dir); + const bundlePath = path.join(packageRoot, rootBundlePath); + + const packageJson = JSON.parse(readText(path.join(packageRoot, 'package.json'))); + const artifact = readText(bundlePath); + + return { + name: packageJson.name, + dir, + packageRoot, + artifactFiles: scannedBuildRoots.flatMap(relativeDir => collectArtifactFiles(packageRoot, relativeDir)), + exports: new Set(collectBundleNamedExports(artifact)) + }; + }); const failures: string[] = []; diff --git a/packages/vrender/__tests__/unit/source-module-resolution.test.ts b/packages/vrender/__tests__/unit/source-module-resolution.test.ts new file mode 100644 index 000000000..30b8d524c --- /dev/null +++ b/packages/vrender/__tests__/unit/source-module-resolution.test.ts @@ -0,0 +1,37 @@ +/** + * @jest-environment node + */ + +declare const require: any; +declare const __dirname: string; +export {}; + +const path = require('path'); +const packagesRoot = path.resolve(__dirname, '../../..'); + +describe('workspace source module resolution', () => { + test.each([ + 'vrender', + 'vrender-core', + 'vrender-kits', + 'vrender-animate', + 'vrender-components', + 'react-vrender', + 'react-vrender-utils' + ])('%s resolves to its own source entry without a build', packageName => { + expect(require.resolve(`@visactor/${packageName}`)).toBe(path.join(packagesRoot, packageName, 'src/index.ts')); + }); + + test.each([ + ['vrender/entries/node', 'vrender/src/entries/node.ts'], + ['vrender-core/event/constant', 'vrender-core/src/event/public-constant.ts'], + ['vrender-core/render/draw-interceptor', 'vrender-core/src/render/contributions/render/draw-interceptor.ts'], + ['vrender-core/render/symbol', 'vrender-core/src/render/contributions/render/symbol.ts'], + ['vrender-kits/register/register-line', 'vrender-kits/src/register/register-line.ts'], + ['vrender-animate/register', 'vrender-animate/src/register.ts'], + ['vrender-components/brush', 'vrender-components/src/brush/index.ts'], + ['react-vrender/processProps', 'react-vrender/src/processProps.ts'] + ])('%s resolves to its source subpath', (specifier, source) => { + expect(require.resolve(`@visactor/${specifier}`)).toBe(path.join(packagesRoot, source)); + }); +}); diff --git a/packages/vrender/jest.artifacts.config.js b/packages/vrender/jest.artifacts.config.js new file mode 100644 index 000000000..5b0698ca3 --- /dev/null +++ b/packages/vrender/jest.artifacts.config.js @@ -0,0 +1,3 @@ +const { createArtifactPackageJestConfig } = require('../../share/jest-config/create-package-config'); + +module.exports = createArtifactPackageJestConfig(); diff --git a/packages/vrender/jest.config.js b/packages/vrender/jest.config.js index 8ea2959d0..ce06cacae 100644 --- a/packages/vrender/jest.config.js +++ b/packages/vrender/jest.config.js @@ -1,4 +1,3 @@ -const path = require('path'); const { createStablePackageJestConfig } = require('../../share/jest-config/create-package-config'); module.exports = createStablePackageJestConfig({ @@ -29,22 +28,5 @@ module.exports = createStablePackageJestConfig({ statements: 80 } }, - moduleNameMapper: { - '^@visactor/vrender-kits/(.*)$': path.resolve(__dirname, '../vrender-kits/src/$1'), - '^@visactor/vrender-kits$': path.resolve(__dirname, '../vrender-kits/src/index.ts'), - '^@visactor/vrender-animate/(.*)$': path.resolve(__dirname, '../vrender-animate/src/$1'), - '^@visactor/vrender-core/event/constant$': path.resolve(__dirname, '../vrender-core/src/event/public-constant.ts'), - '^@visactor/vrender-core/render/draw-interceptor$': path.resolve( - __dirname, - '../vrender-core/src/render/contributions/render/draw-interceptor.ts' - ), - '^@visactor/vrender-core/render/symbol$': path.resolve( - __dirname, - '../vrender-core/src/render/contributions/render/symbol.ts' - ), - '^@visactor/vrender-core/(.*)$': path.resolve(__dirname, '../vrender-core/src/$1'), - '^@visactor/vrender-core$': path.resolve(__dirname, '../vrender-core/src/index.ts'), - '^@visactor/vrender-animate$': path.resolve(__dirname, '../vrender-animate/src/index.ts'), - '^@visactor/vrender-components$': path.resolve(__dirname, '../vrender-components/src/index.ts') - } + moduleNameMapper: require('../../share/jest-config/source-module-name-mapper') }); diff --git a/packages/vrender/package.json b/packages/vrender/package.json index c5f6ce1b7..aedd1c87c 100644 --- a/packages/vrender/package.json +++ b/packages/vrender/package.json @@ -25,6 +25,7 @@ "dev": "cross-env DEBUG='Bundler*' bundle --clean -f es -w", "start": "vite ./__tests__/browser --host", "test": "jest -c jest.config.js", + "test:artifacts": "jest -c jest.artifacts.config.js", "test:electron": "jest -c jest.electron.config.js --runInBand --passWithNoTests --testPathPattern='__tests__/(browser|electron)/'", "test-cov": "jest -c jest.config.js -w 16 --coverage", "test-live": "npm run test-watch __tests__/unit/theme/line.test.ts", diff --git a/share/jest-config/create-package-config.js b/share/jest-config/create-package-config.js index 57af303a1..76b2dfca3 100644 --- a/share/jest-config/create-package-config.js +++ b/share/jest-config/create-package-config.js @@ -62,7 +62,7 @@ function createStablePackageJestConfig(options = {}) { verbose, coverageReporters, coveragePathIgnorePatterns, - testPathIgnorePatterns, + testPathIgnorePatterns: ['/node_modules/', '/__tests__/artifacts/', ...testPathIgnorePatterns], collectCoverageFrom }; @@ -77,6 +77,17 @@ function createStablePackageJestConfig(options = {}) { return config; } +function createArtifactPackageJestConfig() { + return { + ...createStablePackageJestConfig({ + environment: 'node', + testRegex: '/__tests__/artifacts/.*\\.test\\.ts$' + }), + // Published package imports must resolve normally, without source aliases. + testPathIgnorePatterns: ['/node_modules/'] + }; +} + function createElectronPackageJestConfig(options = {}) { const { rootDir, ...rest } = options; @@ -91,5 +102,6 @@ function createElectronPackageJestConfig(options = {}) { module.exports = { createStablePackageJestConfig, + createArtifactPackageJestConfig, createElectronPackageJestConfig }; diff --git a/share/jest-config/source-module-name-mapper.js b/share/jest-config/source-module-name-mapper.js new file mode 100644 index 000000000..be5700ce5 --- /dev/null +++ b/share/jest-config/source-module-name-mapper.js @@ -0,0 +1,31 @@ +const path = require('path'); + +const packagesRoot = path.resolve(__dirname, '../../packages'); + +// Public subpaths whose source filenames differ from their import paths. +const mapper = { + '^@visactor/vrender-core/event/constant$': path.join(packagesRoot, 'vrender-core/src/event/public-constant.ts'), + '^@visactor/vrender-core/render/draw-interceptor$': path.join( + packagesRoot, + 'vrender-core/src/render/contributions/render/draw-interceptor.ts' + ), + '^@visactor/vrender-core/render/symbol$': path.join( + packagesRoot, + 'vrender-core/src/render/contributions/render/symbol.ts' + ) +}; + +for (const packageName of [ + 'vrender', + 'vrender-core', + 'vrender-kits', + 'vrender-animate', + 'vrender-components', + 'react-vrender', + 'react-vrender-utils' +]) { + mapper[`^@visactor/${packageName}$`] = path.join(packagesRoot, packageName, 'src/index.ts'); + mapper[`^@visactor/${packageName}/(.*)$`] = path.join(packagesRoot, packageName, 'src/$1'); +} + +module.exports = mapper;