Skip to content

WIP: Migration to ESM#4526

Draft
cianmSAP wants to merge 273 commits intomainfrom
esm-update
Draft

WIP: Migration to ESM#4526
cianmSAP wants to merge 273 commits intomainfrom
esm-update

Conversation

@cianmSAP
Copy link
Copy Markdown
Contributor

@cianmSAP cianmSAP commented Apr 7, 2026

Work in progress

Summary

Summary

This branch contains a comprehensive ESM (ECMAScript Module) migration and test stabilization effort across open-ux-tools.


✅ Work Completed

  1. ESM Configuration Migrations
  • Root configurations: eslint.config.mjs, esbuildConfig.mjs, .prettierrc.cjs
  • Jest setup: Created jest.base.mjs and jest.setup.mjs
  • All 80+ packages: Migrated eslint.config.js → .mjs, jest.config.js → .mjs, esbuild.js → .mjs
  • TypeScript configs: Updated tsconfig.json across all packages + new root tsconfig-esm.json
  1. Source Code ESM Updates
  • Import statements: Converted CommonJS require() to ESM import statements
  • Package.json: Added "type": "module" where needed
  • ESM compatibility fixes:
    • Added .js extensions to relative imports (78 packages with automated post-build scripts)
    • Fixed directory imports to include /index.js explicitly
    • Replaced require.resolve() with ESM-compatible path resolution
    • Added with { type: 'json' } attributes to JSON imports
    • Implemented __dirname equivalents using import.meta.url
  1. Test Infrastructure Fixes (6 Patterns)
  • fiori-generator-shared: Fixed ESM mocking - converted jest.spyOn() to jest.unstable_mockModule()
  • fiori-elements-writer: Increased test timeouts (15s → 30s → 60s for CI compatibility)
  • fiori-app-sub-generator:
    • Disabled telemetry in headless integration tests
    • Increased suite timeout (60s → 120s)
    • Increased slow LROP v4 test timeout (→ 300s)
  • eslint-plugin-fiori-tools: Increased Node.js heap size (2GB → 4GB)
  • preview-middleware:
  • Fixed require.resolve() in playwright.config.ts
  • Added ESM __dirname setup in integration tests
  • Added JSON import attributes (Pattern 14)
  • adp-tooling: Added JSON import attributes
  1. ESM Import Automation
  • Created fix-esm-imports.js script: Automatically adds .js extensions and converts directory imports
  • Applied to 78 packages: Permanent post-build automation ensures ESM compatibility
  • Prevents regressions: Runs after every tsc --build invocation
  1. Documentation
  • LINT-FIX-GUIDE.md: Added 5 new reusable patterns (Patterns 10-14):
    • Pattern 10: ESM mocking with jest.unstable_mockModule()
    • Pattern 11: Disabling telemetry in tests
    • Pattern 12: Increasing Node.js heap size
    • Pattern 13: Replacing require() in ESM scope
    • Pattern 14: JSON import attributes

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 7, 2026

🦋 Changeset detected

Latest commit: 59d672f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sap-ux/deploy-config-sub-generator Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

cianmSAP added 29 commits April 9, 2026 13:01
- Fix __dirname for ESM in src/index.ts and src/defaults.ts
- Fix fs-extra named export issue in test files
- Fix lodash named import in listdetail.test.ts
- Convert generateOPATests.test.ts to use jest.unstable_mockModule
- Convert basic.test.ts to use jest.unstable_mockModule for cap-config-writer mock
- Move common.ts import to dynamic import in basic.test.ts to prevent premature module loading
- Fix __dirname and require.resolve in test/common.ts for ESM compatibility
- Update snapshot for basic_with_toolsId (real package info instead of mocked values)
- Convert jest.mock() calls to jest.unstable_mockModule() for ESM compatibility
- Pre-import actual modules before mocking to preserve all exports
- Replace jest.spyOn on frozen ESM modules with mock functions
- Use dynamic imports for modules under test after mock setup
- Add import { jest } from '@jest/globals'
cianmSAP and others added 30 commits April 14, 2026 12:37
…s compatibility

The test-ut script was using NODE_OPTIONS directly without cross-env, which fails
on Windows command prompt. All other test scripts already use cross-env correctly.

Fixes Windows CI failure:
'NODE_OPTIONS' is not recognized as an internal or external command
…SM error

The root jest.setup.mjs file cannot be loaded on Windows because Jest doesn't
treat .mjs files as ES modules by default, causing 'Cannot use import statement
outside a module' errors.

Since all tests in this package already import from @jest/globals, they don't
need the global injection from the setup file. Override setupFiles to empty array
to skip the problematic root setup file.

Fixes Windows CI failure where Jest couldn't parse jest.setup.mjs
Resolved conflict in packages/adp-tooling/test/unit/cf/core/auth.test.ts by consolidating
ESM-style mocks using jest.unstable_mockModule for both cfGetAvailableOrgs and cfGetAuthToken.
Removed duplicate CommonJS-style jest.mock() that was causing conflicts.
…T_FOUND errors

All 51 test failures were caused by require.resolve() trying to resolve
@sap-ux/control-property-editor-sources at runtime in addEditorRoutes().
The package's dist/app.js entry point hasn't been built in the test environment,
causing MODULE_NOT_FOUND errors.

Fixed by:
- Added jest.unstable_mockModule for node:module in both test files
- Mocked createRequire to return a require.resolve that points to a dummy fixture
- Created test/fixtures/dummy-cpe/index.js as a minimal placeholder

This allows tests to run without requiring the full control-property-editor-sources
build, while still testing the middleware routing logic.

All tests now pass: 159/159 tests, 8/8 suites
Coverage: 94.9% statements (above 80% threshold)
- Replace jest.mock() with jest.unstable_mockModule() for ESM compatibility
- Move all mock declarations before jest.unstable_mockModule calls
- Import modules under test with await import() after mocks are set up
- Use direct mock function references instead of jest.requireMock()

This fixes 16 failing tests where isLoggedInCf mock was not being applied properly.
- Resolved conflicts in package.json files (abap-deploy-config-inquirer, odata-vocabularies)
  - Kept both @jest/globals 30.3.0 (for ESM) and axios 1.15.0 (security upgrade)
- Resolved conflict in axios-extension/test/factory.test.ts
  - Integrated new per-request proxy resolution logic with ESM mocking
  - Updated test to use mockGetProxyForUrl (ESM mock) instead of getProxyForUrlSpy
- Includes axios security upgrade from 1.13.6 to 1.15.0 across affected packages
…resolution

- Updated 'create' test to expect full URL in getProxyForUrl call (not just server)
- Added mockClear() in 'create with proxy' test to avoid cross-test contamination
- Aligns with main branch changes where proxy is resolved per-request, not at construction time
…h normalization

- Only replace backslashes with forward slashes on Windows
- On non-Windows platforms, use the path as-is (already has forward slashes)
- Resolves CodeQL warning: 'replacement of substring with itself'

Fixes a logic error where on non-Windows platforms, forward slashes were being
replaced with themselves, which was redundant and flagged by CodeQL.
- Keep ESM configuration (type: module, NODE_OPTIONS, @jest/globals)
- Use version 0.3.97 from main branch
- Maintain ESM-specific build and test scripts from esm-update branch
…ndex.js imports

- Changed 'from ..' to 'from ../index.js' in normalization.ts, parse.ts, metadata.ts
- Directory imports are not supported in ESM - must explicitly reference index.js
- Fixes ESLint error on CI: 'Directory import is not supported resolving ES modules'

This ensures the package builds correctly on CI where dist files are generated fresh.
Resolved conflicts:
- cf-deploy-config-writer/package.json: kept ESM config with version 0.3.98 from main
- ui5-test-writer/src/fiori-elements-opa-writer.ts: merged imports (dirname, fileURLToPath from HEAD + existsSync from main)
- ui5-test-writer/test/unit/fiori-elements.test.ts: combined ESM mocking with unstable_mockModule and dynamic import
…-writer

ui5-test-writer:
- Replace jest.requireActual() with await import() for ESM compatibility
- Updated 6 occurrences in test/unit/fiori-elements.test.ts
- Mock factories for node:fs and opaQUnitUtils now use dynamic imports
- beforeAll and afterEach hooks use await import() to restore real implementations

fiori-freestyle-writer:
- Update snapshot for basic_with_toolsId test (version bump 2.5.91 -> 2.5.93)

All tests pass:
- ui5-test-writer: 7 suites, 217 tests, 22 snapshots ✓
- fiori-freestyle-writer: 5 suites, 36 tests, 27 snapshots ✓
- abap-deploy-config-sub-generator: 4 suites, 21 tests ✓
- cf-deploy-config-sub-generator: 4 suites, 26 tests ✓

All lint and build checks pass with 0 errors.
# Conflicts:
#	packages/adp-tooling/test/unit/btp/api.test.ts
#	packages/adp-tooling/test/unit/cf/project/yaml.test.ts
#	packages/adp-tooling/test/unit/cf/services/api.test.ts
#	packages/adp-tooling/test/unit/prompts/add-new-model/index.test.ts
#	packages/adp-tooling/test/unit/writer/cf.test.ts
#	packages/adp-tooling/test/unit/writer/changes/writers/index.test.ts
#	packages/create/test/unit/cli/add/new-model.test.ts
#	packages/generator-adp/test/unit/add-new-model/index.test.ts
…nd add createNewModelData to mocks

- Remove dataSourceName prompt test in adp-tooling (merged into modelAndDatasourceName)
- Add createNewModelData export to adp-tooling mock in create package
- Fixes failing tests after main merge
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant