@sfdc-webapps/cli 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1414 -0
- package/dist/commands/apply-patches.d.ts +23 -0
- package/dist/commands/apply-patches.d.ts.map +1 -0
- package/dist/commands/apply-patches.js +524 -0
- package/dist/commands/apply-patches.js.map +1 -0
- package/dist/commands/new-app-feature.d.ts +7 -0
- package/dist/commands/new-app-feature.d.ts.map +1 -0
- package/dist/commands/new-app-feature.js +166 -0
- package/dist/commands/new-app-feature.js.map +1 -0
- package/dist/commands/new-app.d.ts +1 -0
- package/dist/commands/new-app.d.ts.map +1 -0
- package/dist/commands/new-app.js +2 -0
- package/dist/commands/new-app.js.map +1 -0
- package/dist/commands/watch-patches.d.ts +6 -0
- package/dist/commands/watch-patches.d.ts.map +1 -0
- package/dist/commands/watch-patches.js +152 -0
- package/dist/commands/watch-patches.js.map +1 -0
- package/dist/core/dependency-resolver.d.ts +40 -0
- package/dist/core/dependency-resolver.d.ts.map +1 -0
- package/dist/core/dependency-resolver.js +122 -0
- package/dist/core/dependency-resolver.js.map +1 -0
- package/dist/core/file-operations.d.ts +37 -0
- package/dist/core/file-operations.d.ts.map +1 -0
- package/dist/core/file-operations.js +201 -0
- package/dist/core/file-operations.js.map +1 -0
- package/dist/core/package-json-merger.d.ts +30 -0
- package/dist/core/package-json-merger.d.ts.map +1 -0
- package/dist/core/package-json-merger.js +104 -0
- package/dist/core/package-json-merger.js.map +1 -0
- package/dist/core/patch-loader.d.ts +17 -0
- package/dist/core/patch-loader.d.ts.map +1 -0
- package/dist/core/patch-loader.js +100 -0
- package/dist/core/patch-loader.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +90 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +21 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/debounce.d.ts +6 -0
- package/dist/utils/debounce.d.ts.map +1 -0
- package/dist/utils/debounce.js +19 -0
- package/dist/utils/debounce.js.map +1 -0
- package/dist/utils/import-merger.d.ts +12 -0
- package/dist/utils/import-merger.d.ts.map +1 -0
- package/dist/utils/import-merger.js +240 -0
- package/dist/utils/import-merger.js.map +1 -0
- package/dist/utils/logger.d.ts +6 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +17 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/path-mappings.d.ts +88 -0
- package/dist/utils/path-mappings.d.ts.map +1 -0
- package/dist/utils/path-mappings.js +138 -0
- package/dist/utils/path-mappings.js.map +1 -0
- package/dist/utils/paths.d.ts +43 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +107 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/route-merger.d.ts +107 -0
- package/dist/utils/route-merger.d.ts.map +1 -0
- package/dist/utils/route-merger.js +303 -0
- package/dist/utils/route-merger.js.map +1 -0
- package/dist/utils/validation.d.ts +29 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +109 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +39 -0
- package/src/commands/apply-patches.ts +594 -0
- package/src/commands/new-app-feature.ts +203 -0
- package/src/commands/new-app.ts +0 -0
- package/src/commands/watch-patches.ts +173 -0
- package/src/core/dependency-resolver.ts +175 -0
- package/src/core/file-operations.ts +265 -0
- package/src/core/package-json-merger.ts +129 -0
- package/src/core/patch-loader.ts +128 -0
- package/src/index.ts +95 -0
- package/src/types.ts +23 -0
- package/src/utils/debounce.ts +23 -0
- package/src/utils/import-merger.ts +293 -0
- package/src/utils/logger.ts +21 -0
- package/src/utils/path-mappings.ts +154 -0
- package/src/utils/paths.ts +121 -0
- package/src/utils/route-merger.ts +357 -0
- package/src/utils/validation.ts +150 -0
- package/test/e2e/E2E_TEST_FIXTURES.md +509 -0
- package/test/e2e/apply-patches.spec.ts +861 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/package.json +10 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/appLayout.tsx +27 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/home.tsx +8 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/index.tsx +10 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/old-page.tsx +8 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/routes.tsx +23 -0
- package/test/e2e/fixtures/base-app/digitalExperiences/webApplications/base-app/src/styles/global.css +14 -0
- package/test/e2e/fixtures/basic-operations/dep-chain-linear/feature.ts +11 -0
- package/test/e2e/fixtures/basic-operations/dep-chain-linear/template/digitalExperiences/webApplications/dep-chain-linear/src/__inherit__appLayout.tsx +27 -0
- package/test/e2e/fixtures/basic-operations/dep-chain-linear/template/digitalExperiences/webApplications/dep-chain-linear/src/contact.tsx +8 -0
- package/test/e2e/fixtures/basic-operations/dep-chain-linear/template/digitalExperiences/webApplications/dep-chain-linear/src/routes.tsx +17 -0
- package/test/e2e/fixtures/basic-operations/feature-file-inherit-route-add/feature.ts +10 -0
- package/test/e2e/fixtures/basic-operations/feature-file-inherit-route-add/template/digitalExperiences/webApplications/feature-file-inherit-route-add/src/__inherit__appLayout.tsx +27 -0
- package/test/e2e/fixtures/basic-operations/feature-file-inherit-route-add/template/digitalExperiences/webApplications/feature-file-inherit-route-add/src/__inherit__home.tsx +0 -0
- package/test/e2e/fixtures/basic-operations/feature-file-inherit-route-add/template/digitalExperiences/webApplications/feature-file-inherit-route-add/src/about.tsx +8 -0
- package/test/e2e/fixtures/basic-operations/feature-file-inherit-route-add/template/digitalExperiences/webApplications/feature-file-inherit-route-add/src/routes.tsx +17 -0
- package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/feature.ts +10 -0
- package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/__inherit__appLayout.tsx +27 -0
- package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/routes.tsx +17 -0
- package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/settings.tsx +9 -0
- package/test/e2e/fixtures/basic-operations/feature-file-prepend-append/template/digitalExperiences/webApplications/feature-file-prepend-append/src/styles/__append__global.css +10 -0
- package/test/e2e/fixtures/basic-operations/feature-file-route-delete/feature.ts +10 -0
- package/test/e2e/fixtures/basic-operations/feature-file-route-delete/template/digitalExperiences/webApplications/feature-file-route-delete/src/__delete__old-page.tsx +2 -0
- package/test/e2e/fixtures/basic-operations/feature-file-route-delete/template/digitalExperiences/webApplications/feature-file-route-delete/src/__inherit__appLayout.tsx +27 -0
- package/test/e2e/fixtures/basic-operations/feature-file-route-delete/template/digitalExperiences/webApplications/feature-file-route-delete/src/routes.tsx +16 -0
- package/test/e2e/fixtures/composition-5-features/5-features-about/feature.ts +3 -0
- package/test/e2e/fixtures/composition-5-features/5-features-about/template/digitalExperiences/webApplications/5-features-about/src/about.tsx +8 -0
- package/test/e2e/fixtures/composition-5-features/5-features-about/template/digitalExperiences/webApplications/5-features-about/src/routes.tsx +17 -0
- package/test/e2e/fixtures/composition-5-features/5-features-analytics/feature.ts +3 -0
- package/test/e2e/fixtures/composition-5-features/5-features-analytics/template/digitalExperiences/webApplications/5-features-analytics/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/composition-5-features/5-features-footer/feature.ts +3 -0
- package/test/e2e/fixtures/composition-5-features/5-features-footer/template/digitalExperiences/webApplications/5-features-footer/src/footer.tsx +7 -0
- package/test/e2e/fixtures/composition-5-features/5-features-footer/template/digitalExperiences/webApplications/5-features-footer/src/routes.tsx +17 -0
- package/test/e2e/fixtures/composition-5-features/5-features-navigation/feature.ts +3 -0
- package/test/e2e/fixtures/composition-5-features/5-features-navigation/template/digitalExperiences/webApplications/5-features-navigation/src/navigation.tsx +7 -0
- package/test/e2e/fixtures/composition-5-features/5-features-navigation/template/digitalExperiences/webApplications/5-features-navigation/src/routes.tsx +17 -0
- package/test/e2e/fixtures/composition-5-features/5-features-theme/feature.ts +3 -0
- package/test/e2e/fixtures/composition-5-features/5-features-theme/template/digitalExperiences/webApplications/5-features-theme/src/styles/__append__global.css +5 -0
- package/test/e2e/fixtures/composition-append/composition-append-1/feature.ts +10 -0
- package/test/e2e/fixtures/composition-append/composition-append-1/template/digitalExperiences/webApplications/composition-append-1/src/styles/__append__global.css +4 -0
- package/test/e2e/fixtures/composition-append/composition-append-2/feature.ts +10 -0
- package/test/e2e/fixtures/composition-append/composition-append-2/template/digitalExperiences/webApplications/composition-append-2/src/styles/__append__global.css +4 -0
- package/test/e2e/fixtures/composition-append/composition-append-3/feature.ts +10 -0
- package/test/e2e/fixtures/composition-append/composition-append-3/template/digitalExperiences/webApplications/composition-append-3/src/styles/__append__global.css +4 -0
- package/test/e2e/fixtures/composition-inherit-modify/composition-inherit-layout/feature.ts +3 -0
- package/test/e2e/fixtures/composition-inherit-modify/composition-inherit-layout/template/digitalExperiences/webApplications/composition-inherit-layout/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/composition-inherit-modify/composition-modify-layout/feature.ts +3 -0
- package/test/e2e/fixtures/composition-inherit-modify/composition-modify-layout/template/digitalExperiences/webApplications/composition-modify-layout/src/__append__appLayout.tsx +2 -0
- package/test/e2e/fixtures/composition-prepend/composition-prepend-1/feature.ts +10 -0
- package/test/e2e/fixtures/composition-prepend/composition-prepend-1/template/digitalExperiences/webApplications/composition-prepend-1/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/composition-prepend/composition-prepend-2/feature.ts +10 -0
- package/test/e2e/fixtures/composition-prepend/composition-prepend-2/template/digitalExperiences/webApplications/composition-prepend-2/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/composition-prepend/composition-prepend-3/feature.ts +10 -0
- package/test/e2e/fixtures/composition-prepend/composition-prepend-3/template/digitalExperiences/webApplications/composition-prepend-3/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-a/feature.ts +11 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-a/template/digitalExperiences/webApplications/dep-chain-a/src/page-a.tsx +8 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-a/template/digitalExperiences/webApplications/dep-chain-a/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-b/feature.ts +11 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-b/template/digitalExperiences/webApplications/dep-chain-b/src/page-b.tsx +8 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-b/template/digitalExperiences/webApplications/dep-chain-b/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-c/feature.ts +11 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-c/template/digitalExperiences/webApplications/dep-chain-c/src/page-c.tsx +8 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-c/template/digitalExperiences/webApplications/dep-chain-c/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-d/feature.ts +10 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-d/template/digitalExperiences/webApplications/dep-chain-d/src/page-d.tsx +8 -0
- package/test/e2e/fixtures/dep-chain-long/dep-chain-d/template/digitalExperiences/webApplications/dep-chain-d/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-circular/dep-circular-a/feature.ts +11 -0
- package/test/e2e/fixtures/dep-circular/dep-circular-a/template/digitalExperiences/webApplications/dep-circular-a/src/page-a.tsx +8 -0
- package/test/e2e/fixtures/dep-circular/dep-circular-b/feature.ts +11 -0
- package/test/e2e/fixtures/dep-circular/dep-circular-b/template/digitalExperiences/webApplications/dep-circular-b/src/page-b.tsx +8 -0
- package/test/e2e/fixtures/dep-complex-graph/README.md +119 -0
- package/test/e2e/fixtures/dep-complex-graph/create-placeholders.sh +25 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/feature.ts +14 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/__delete__old-page.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/login.tsx +8 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/routes.tsx +29 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-auth/template/digitalExperiences/webApplications/dep-complex-graph-auth/src/signup.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/feature.ts +14 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/analytics.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/dashboard.tsx +8 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/reports.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-dashboard/template/digitalExperiences/webApplications/dep-complex-graph-dashboard/src/routes.tsx +32 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/feature.ts +14 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/template/digitalExperiences/webApplications/dep-complex-graph-profile/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/template/digitalExperiences/webApplications/dep-complex-graph-profile/src/profile-edit.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/template/digitalExperiences/webApplications/dep-complex-graph-profile/src/profile.tsx +8 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-profile/template/digitalExperiences/webApplications/dep-complex-graph-profile/src/routes.tsx +26 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-components/feature.ts +14 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-components/template/digitalExperiences/webApplications/dep-complex-graph-shared-components/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-components/template/digitalExperiences/webApplications/dep-complex-graph-shared-components/src/components.tsx +8 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-components/template/digitalExperiences/webApplications/dep-complex-graph-shared-components/src/routes.tsx +18 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-types/feature.ts +10 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-types/template/digitalExperiences/webApplications/dep-complex-graph-shared-types/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-types/template/digitalExperiences/webApplications/dep-complex-graph-shared-types/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-types/template/digitalExperiences/webApplications/dep-complex-graph-shared-types/src/types.tsx +8 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-utils/feature.ts +10 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-utils/template/digitalExperiences/webApplications/dep-complex-graph-shared-utils/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-utils/template/digitalExperiences/webApplications/dep-complex-graph-shared-utils/src/routes.tsx +18 -0
- package/test/e2e/fixtures/dep-complex-graph/dep-complex-graph-shared-utils/template/digitalExperiences/webApplications/dep-complex-graph-shared-utils/src/tools.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/feature.ts +15 -0
- package/test/e2e/fixtures/dep-complex-graph/template/digitalExperiences/webApplications/dep-complex-graph/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/template/digitalExperiences/webApplications/dep-complex-graph/src/admin-dashboard.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/template/digitalExperiences/webApplications/dep-complex-graph/src/admin-layout.tsx +1 -0
- package/test/e2e/fixtures/dep-complex-graph/template/digitalExperiences/webApplications/dep-complex-graph/src/routes.tsx +24 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-left/feature.ts +11 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-left/template/digitalExperiences/webApplications/dep-diamond-left/src/left-page.tsx +8 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-left/template/digitalExperiences/webApplications/dep-diamond-left/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-right/feature.ts +11 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-right/template/digitalExperiences/webApplications/dep-diamond-right/src/right-page.tsx +8 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-right/template/digitalExperiences/webApplications/dep-diamond-right/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-shared/feature.ts +10 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-shared/template/digitalExperiences/webApplications/dep-diamond-shared/src/routes.tsx +17 -0
- package/test/e2e/fixtures/dep-diamond/dep-diamond-shared/template/digitalExperiences/webApplications/dep-diamond-shared/src/shared-utils.tsx +8 -0
- package/test/e2e/fixtures/edges/edge-binary-files/feature.ts +13 -0
- package/test/e2e/fixtures/edges/edge-binary-files/template/digitalExperiences/webApplications/edge-binary-files/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/edges/edge-binary-files/template/digitalExperiences/webApplications/edge-binary-files/src/assets/test-image.png +0 -0
- package/test/e2e/fixtures/edges/edge-binary-files/template/digitalExperiences/webApplications/edge-binary-files/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/edges/edge-conflicting-prefixes/feature.ts +13 -0
- package/test/e2e/fixtures/edges/edge-conflicting-prefixes/template/digitalExperiences/webApplications/edge-conflicting-prefixes/src/__inherit____delete__conflicting.tsx +5 -0
- package/test/e2e/fixtures/edges/edge-conflicting-prefixes/template/digitalExperiences/webApplications/edge-conflicting-prefixes/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/edges/edge-empty-feature/feature.ts +16 -0
- package/test/e2e/fixtures/edges/edge-empty-feature/template/digitalExperiences/webApplications/edge-empty-feature/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/edges/edge-invalid-routes/feature.ts +12 -0
- package/test/e2e/fixtures/edges/edge-invalid-routes/template/digitalExperiences/webApplications/edge-invalid-routes/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/edges/edge-invalid-routes/template/digitalExperiences/webApplications/edge-invalid-routes/src/routes.tsx +8 -0
- package/test/e2e/fixtures/edges/edge-line-endings/feature.ts +13 -0
- package/test/e2e/fixtures/edges/edge-line-endings/template/digitalExperiences/webApplications/edge-line-endings/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/edges/edge-line-endings/template/digitalExperiences/webApplications/edge-line-endings/src/crlf.tsx +4 -0
- package/test/e2e/fixtures/edges/edge-line-endings/template/digitalExperiences/webApplications/edge-line-endings/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/edges/edge-line-endings/template/digitalExperiences/webApplications/edge-line-endings/src/styles/__append__global.css +4 -0
- package/test/e2e/fixtures/edges/edge-missing-base-files/feature.ts +13 -0
- package/test/e2e/fixtures/edges/edge-missing-base-files/template/digitalExperiences/webApplications/edge-missing-base-files/src/__inherit__missing.tsx +1 -0
- package/test/e2e/fixtures/edges/edge-missing-base-files/template/digitalExperiences/webApplications/edge-missing-base-files/src/__prepend__nonexistent.tsx +2 -0
- package/test/e2e/fixtures/edges/edge-missing-base-files/template/digitalExperiences/webApplications/edge-missing-base-files/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/edges/edge-package-json-conflicts-a/feature.ts +14 -0
- package/test/e2e/fixtures/edges/edge-package-json-conflicts-a/template/digitalExperiences/webApplications/edge-package-json-conflicts-a/src/placeholder.tsx +1 -0
- package/test/e2e/fixtures/edges/edge-package-json-conflicts-b/feature.ts +14 -0
- package/test/e2e/fixtures/edges/edge-package-json-conflicts-b/template/digitalExperiences/webApplications/edge-package-json-conflicts-b/src/placeholder.tsx +1 -0
- package/test/e2e/fixtures/edges/edge-performance-many/feature.ts +26 -0
- package/test/e2e/fixtures/edges/edge-performance-many/template/digitalExperiences/webApplications/edge-performance-many/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/path-mappings/feature-custom-mapping/feature.ts +16 -0
- package/test/e2e/fixtures/path-mappings/feature-custom-mapping/template/web/src/custom-component.tsx +3 -0
- package/test/e2e/fixtures/path-mappings/feature-custom-mapping/template/web/src/routes.tsx +8 -0
- package/test/e2e/fixtures/path-mappings/feature-mixed-paths/feature.ts +7 -0
- package/test/e2e/fixtures/path-mappings/feature-mixed-paths/template/digitalExperiences/webApplications/feature-mixed-paths/assets/icon.svg +3 -0
- package/test/e2e/fixtures/path-mappings/feature-mixed-paths/template/webApp/src/mapped-component.tsx +3 -0
- package/test/e2e/fixtures/path-mappings/feature-mixed-paths/template/webApp/src/routes.tsx +8 -0
- package/test/e2e/fixtures/path-mappings/feature-with-webapp-mapping/feature.ts +7 -0
- package/test/e2e/fixtures/path-mappings/feature-with-webapp-mapping/template/webApp/src/app.tsx +3 -0
- package/test/e2e/fixtures/path-mappings/feature-with-webapp-mapping/template/webApp/src/routes.tsx +8 -0
- package/test/e2e/fixtures/path-mappings/feature-without-mapping/feature.ts +11 -0
- package/test/e2e/fixtures/path-mappings/feature-without-mapping/template/digitalExperiences/webApplications/feature-without-mapping/src/legacy-component.tsx +3 -0
- package/test/e2e/fixtures/path-mappings/feature-without-mapping/template/digitalExperiences/webApplications/feature-without-mapping/src/routes.tsx +8 -0
- package/test/e2e/fixtures/scenarios/scenario-authentication/feature.ts +10 -0
- package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/components/LoginForm.tsx +25 -0
- package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/context/AuthContext.tsx +28 -0
- package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/login.tsx +10 -0
- package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/scenarios/scenario-authentication/template/digitalExperiences/webApplications/scenario-authentication/src/routes.tsx +17 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/feature.ts +11 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/components/ContactDetail.tsx +54 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/components/ContactForm.tsx +146 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/components/ContactList.tsx +77 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/routes.tsx +36 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/styles/__append__global.css +176 -0
- package/test/e2e/fixtures/scenarios/scenario-crud-contacts/template/digitalExperiences/webApplications/scenario-crud-contacts/src/utils/contactsApi.ts +42 -0
- package/test/e2e/fixtures/scenarios/scenario-navigation-menu/feature.ts +10 -0
- package/test/e2e/fixtures/scenarios/scenario-navigation-menu/template/digitalExperiences/webApplications/scenario-navigation-menu/src/__append__appLayout.tsx +4 -0
- package/test/e2e/fixtures/scenarios/scenario-navigation-menu/template/digitalExperiences/webApplications/scenario-navigation-menu/src/components/NavigationMenu.tsx +17 -0
- package/test/e2e/fixtures/scenarios/scenario-navigation-menu/template/digitalExperiences/webApplications/scenario-navigation-menu/src/placeholder.tsx +0 -0
- package/test/e2e/fixtures/single-operations/feature-file-append/feature.ts +10 -0
- package/test/e2e/fixtures/single-operations/feature-file-append/template/digitalExperiences/webApplications/feature-file-append/src/styles/__append__global.css +10 -0
- package/test/e2e/fixtures/single-operations/feature-file-inherit/feature.ts +10 -0
- package/test/e2e/fixtures/single-operations/feature-file-inherit/template/digitalExperiences/webApplications/feature-file-inherit/src/__inherit__appLayout.tsx +1 -0
- package/test/e2e/fixtures/single-operations/feature-file-inherit/template/digitalExperiences/webApplications/feature-file-inherit/src/__inherit__home.tsx +1 -0
- package/test/e2e/fixtures/single-operations/feature-file-prepend/feature.ts +10 -0
- package/test/e2e/fixtures/single-operations/feature-file-prepend/template/digitalExperiences/webApplications/feature-file-prepend/src/__prepend__index.tsx +2 -0
- package/test/e2e/fixtures/single-operations/feature-import-merge/feature.ts +10 -0
- package/test/e2e/fixtures/single-operations/feature-import-merge/template/digitalExperiences/webApplications/feature-import-merge/src/routes.tsx +18 -0
- package/test/e2e/fixtures/single-operations/feature-import-merge/template/digitalExperiences/webApplications/feature-import-merge/src/settings.tsx +8 -0
- package/test/e2e/fixtures/single-operations/feature-route-add/feature.ts +10 -0
- package/test/e2e/fixtures/single-operations/feature-route-add/template/digitalExperiences/webApplications/feature-route-add/src/about.tsx +8 -0
- package/test/e2e/fixtures/single-operations/feature-route-add/template/digitalExperiences/webApplications/feature-route-add/src/routes.tsx +23 -0
- package/test/e2e/fixtures/single-operations/feature-route-add/template/digitalExperiences/webApplications/feature-route-add/src/services.tsx +8 -0
- package/test/e2e/fixtures/watch/watch-add-delete-files/feature.ts +13 -0
- package/test/e2e/fixtures/watch/watch-add-delete-files/template/digitalExperiences/webApplications/watch-add-delete-files/src/initial.tsx +4 -0
- package/test/e2e/fixtures/watch/watch-add-delete-files/template/digitalExperiences/webApplications/watch-add-delete-files/src/placeholder.tsx +4 -0
- package/test/e2e/fixtures/watch/watch-basic/feature.ts +13 -0
- package/test/e2e/fixtures/watch/watch-basic/template/digitalExperiences/webApplications/watch-basic/src/placeholder.tsx +4 -0
- package/test/e2e/fixtures/watch/watch-basic/template/digitalExperiences/webApplications/watch-basic/src/watchTest.tsx +3 -0
- package/test/e2e/fixtures/watch/watch-debounce/feature.ts +13 -0
- package/test/e2e/fixtures/watch/watch-debounce/template/digitalExperiences/webApplications/watch-debounce/src/placeholder.tsx +4 -0
- package/test/e2e/fixtures/watch/watch-multiple-files/feature.ts +13 -0
- package/test/e2e/fixtures/watch/watch-multiple-files/template/digitalExperiences/webApplications/watch-multiple-files/src/components/WatchComponent.tsx +3 -0
- package/test/e2e/fixtures/watch/watch-multiple-files/template/digitalExperiences/webApplications/watch-multiple-files/src/placeholder.tsx +4 -0
- package/test/e2e/fixtures/watch/watch-multiple-files/template/digitalExperiences/webApplications/watch-multiple-files/src/styles/theme.css +4 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/package.json +10 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/about.tsx +8 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/appLayout.tsx +27 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/contact.tsx +8 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/home.tsx +8 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/index.tsx +10 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/old-page.tsx +8 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/routes.tsx +35 -0
- package/test/e2e/gold/dep-chain-linear-apply/digitalExperiences/webApplications/dep-chain-linear/src/styles/global.css +14 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/package.json +10 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/appLayout.tsx +27 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/home.tsx +8 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/index.tsx +10 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/old-page.tsx +8 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/page-a.tsx +8 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/page-b.tsx +8 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/page-c.tsx +8 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/page-d.tsx +8 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/routes.tsx +47 -0
- package/test/e2e/gold/dep-chain-long-apply/digitalExperiences/webApplications/dep-chain-a/src/styles/global.css +14 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/package.json +10 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/admin-dashboard.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/admin-layout.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/analytics.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/appLayout.tsx +27 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/components.tsx +8 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/dashboard.tsx +8 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/home.tsx +8 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/index.tsx +10 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/login.tsx +8 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/profile-edit.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/profile.tsx +8 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/reports.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/routes.tsx +94 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/signup.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/styles/global.css +14 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/tools.tsx +1 -0
- package/test/e2e/gold/dep-complex-graph-apply/digitalExperiences/webApplications/dep-complex-graph/src/types.tsx +8 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/package.json +10 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/custom-component.tsx +3 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/home.tsx +8 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/index.tsx +10 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/old-page.tsx +8 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/routes.tsx +28 -0
- package/test/e2e/gold/feature-custom-mapping-apply/digitalExperiences/webApplications/feature-custom-mapping/src/styles/global.css +14 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/package.json +10 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/about.tsx +8 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/home.tsx +8 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/index.tsx +10 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/old-page.tsx +8 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/routes.tsx +29 -0
- package/test/e2e/gold/feature-file-inherit-route-add-apply/digitalExperiences/webApplications/feature-file-inherit-route-add/src/styles/global.css +14 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/package.json +10 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/home.tsx +8 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/index.tsx +13 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/old-page.tsx +8 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/routes.tsx +29 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/settings.tsx +9 -0
- package/test/e2e/gold/feature-file-prepend-append-apply/digitalExperiences/webApplications/feature-file-prepend-append/src/styles/global.css +25 -0
- package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/package.json +10 -0
- package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/home.tsx +8 -0
- package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/index.tsx +10 -0
- package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/routes.tsx +17 -0
- package/test/e2e/gold/feature-file-route-delete-apply/digitalExperiences/webApplications/feature-file-route-delete/src/styles/global.css +14 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/assets/icon.svg +3 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/package.json +10 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/home.tsx +8 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/index.tsx +10 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/mapped-component.tsx +3 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/old-page.tsx +8 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/routes.tsx +28 -0
- package/test/e2e/gold/feature-mixed-paths-apply/digitalExperiences/webApplications/feature-mixed-paths/src/styles/global.css +14 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/package.json +10 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/app.tsx +3 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/home.tsx +8 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/index.tsx +10 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/old-page.tsx +8 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/routes.tsx +28 -0
- package/test/e2e/gold/feature-with-webapp-mapping-apply/digitalExperiences/webApplications/feature-with-webapp-mapping/src/styles/global.css +14 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/package.json +10 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/appLayout.tsx +27 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/home.tsx +8 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/index.tsx +10 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/legacy-component.tsx +3 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/old-page.tsx +8 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/routes.tsx +28 -0
- package/test/e2e/gold/feature-without-mapping-apply/digitalExperiences/webApplications/feature-without-mapping/src/styles/global.css +14 -0
- package/test/e2e/path-mappings.spec.ts +232 -0
- package/test/e2e/watch-patches.spec.ts +237 -0
- package/test/helpers/cli-runner.ts +100 -0
- package/test/helpers/compare-directories.ts +197 -0
- package/test/helpers/create-temp-dir.ts +34 -0
- package/test/helpers/fixtures.ts +67 -0
- package/test/setup.ts +6 -0
- package/test/unit/debounce.spec.ts +159 -0
- package/test/unit/dependency-resolver.spec.ts +260 -0
- package/test/unit/file-operations.spec.ts +264 -0
- package/test/unit/import-merger.spec.ts +395 -0
- package/test/unit/index.spec.ts +158 -0
- package/test/unit/new-app.spec.ts +178 -0
- package/test/unit/new-feature.spec.ts +178 -0
- package/test/unit/package-json-merger.spec.ts +275 -0
- package/test/unit/patch-loader.spec.ts +238 -0
- package/test/unit/path-mappings.spec.ts +241 -0
- package/test/unit/paths.spec.ts +247 -0
- package/test/unit/route-merger.spec.ts +265 -0
- package/test/unit/validation.spec.ts +311 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +18 -0
|
@@ -0,0 +1,861 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
import { createTempDir, cleanupTempDir } from '../helpers/create-temp-dir.js';
|
|
5
|
+
import { copyFixture, getFixturePath, getGoldPath } from '../helpers/fixtures.js';
|
|
6
|
+
import { compareOrUpdate } from '../helpers/compare-directories.js';
|
|
7
|
+
import { runApplyPatches } from '../helpers/cli-runner.js';
|
|
8
|
+
|
|
9
|
+
describe('apply-patches E2E', () => {
|
|
10
|
+
let tempDir: string;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
tempDir = createTempDir();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
cleanupTempDir(tempDir);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('Simple feature application', () => {
|
|
21
|
+
it('should apply a simple feature correctly', async () => {
|
|
22
|
+
// Setup: Copy base-app
|
|
23
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
24
|
+
const targetDir = join(tempDir, 'simple-apply');
|
|
25
|
+
const featurePath = getFixturePath('basic-operations/feature-file-inherit-route-add');
|
|
26
|
+
|
|
27
|
+
// Execute: Apply patches via CLI
|
|
28
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
29
|
+
skipDependencyChanges: true
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Assert: Command succeeded
|
|
33
|
+
expect(result.exitCode).toBe(0);
|
|
34
|
+
|
|
35
|
+
// Assert: Compare with gold files
|
|
36
|
+
const goldDir = getGoldPath('feature-file-inherit-route-add-apply');
|
|
37
|
+
const differences = compareOrUpdate(targetDir, goldDir);
|
|
38
|
+
|
|
39
|
+
expect(differences).toEqual([]);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should verify all expected files exist after simple apply', async () => {
|
|
43
|
+
// Setup
|
|
44
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
45
|
+
const targetDir = join(tempDir, 'simple-apply-verify');
|
|
46
|
+
const featurePath = getFixturePath('basic-operations/feature-file-inherit-route-add');
|
|
47
|
+
|
|
48
|
+
// Execute
|
|
49
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
50
|
+
skipDependencyChanges: true
|
|
51
|
+
});
|
|
52
|
+
expect(result.exitCode).toBe(0);
|
|
53
|
+
|
|
54
|
+
// Assert: Check that expected files exist (in feature-file-inherit-route-add nested structure)
|
|
55
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-inherit-route-add/src/about.tsx'))).toBe(true);
|
|
56
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-inherit-route-add/src/routes.tsx'))).toBe(true);
|
|
57
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-inherit-route-add/src/appLayout.tsx'))).toBe(true);
|
|
58
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-inherit-route-add/src/home.tsx'))).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('File deletion', () => {
|
|
63
|
+
it('should delete files marked with __delete__', async () => {
|
|
64
|
+
// Setup: Copy base-app
|
|
65
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
66
|
+
const targetDir = join(tempDir, 'delete-apply');
|
|
67
|
+
const featurePath = getFixturePath('basic-operations/feature-file-route-delete');
|
|
68
|
+
|
|
69
|
+
// Verify file exists before deletion (in base-app structure)
|
|
70
|
+
expect(existsSync(join(baseAppDir, 'digitalExperiences/webApplications/base-app/src/old-page.tsx'))).toBe(true);
|
|
71
|
+
|
|
72
|
+
// Execute
|
|
73
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
74
|
+
skipDependencyChanges: true
|
|
75
|
+
});
|
|
76
|
+
expect(result.exitCode).toBe(0);
|
|
77
|
+
|
|
78
|
+
// Assert: File should be deleted (feature-file-route-delete becomes the target app name)
|
|
79
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-route-delete/src/old-page.tsx'))).toBe(false);
|
|
80
|
+
|
|
81
|
+
// Compare with gold files
|
|
82
|
+
const goldDir = getGoldPath('feature-file-route-delete-apply');
|
|
83
|
+
const differences = compareOrUpdate(targetDir, goldDir);
|
|
84
|
+
expect(differences).toEqual([]);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should clean up imports from deleted files', async () => {
|
|
88
|
+
// Setup
|
|
89
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
90
|
+
const targetDir = join(tempDir, 'delete-apply-imports');
|
|
91
|
+
const featurePath = getFixturePath('basic-operations/feature-file-route-delete');
|
|
92
|
+
|
|
93
|
+
// Execute
|
|
94
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
95
|
+
skipDependencyChanges: true
|
|
96
|
+
});
|
|
97
|
+
expect(result.exitCode).toBe(0);
|
|
98
|
+
|
|
99
|
+
// Assert: Check routes file doesn't have old-page import
|
|
100
|
+
const { readFileSync } = await import('fs');
|
|
101
|
+
const routesContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-route-delete/src/routes.tsx'), 'utf-8');
|
|
102
|
+
|
|
103
|
+
// Should not contain import or reference to old-page
|
|
104
|
+
expect(routesContent).not.toContain('old-page');
|
|
105
|
+
expect(routesContent).not.toContain('OldPage');
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('Route deletion', () => {
|
|
110
|
+
it('should delete routes marked with __delete__ in path', async () => {
|
|
111
|
+
// Setup
|
|
112
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
113
|
+
const targetDir = join(tempDir, 'route-delete-apply');
|
|
114
|
+
const featurePath = getFixturePath('basic-operations/feature-file-route-delete');
|
|
115
|
+
|
|
116
|
+
// Execute
|
|
117
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
118
|
+
skipDependencyChanges: true
|
|
119
|
+
});
|
|
120
|
+
expect(result.exitCode).toBe(0);
|
|
121
|
+
|
|
122
|
+
// Assert: Check routes file doesn't have the old route
|
|
123
|
+
const { readFileSync } = await import('fs');
|
|
124
|
+
const routesContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-route-delete/src/routes.tsx'), 'utf-8');
|
|
125
|
+
|
|
126
|
+
// Should not contain path: 'old'
|
|
127
|
+
expect(routesContent).not.toMatch(/path:\s*['"]old['"]/);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('Dependency resolution', () => {
|
|
132
|
+
it('should apply features in dependency order', async () => {
|
|
133
|
+
// Setup: dep-chain-linear depends on feature-file-inherit-route-add
|
|
134
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
135
|
+
const targetDir = join(tempDir, 'deps-apply');
|
|
136
|
+
const featurePath = getFixturePath('basic-operations/dep-chain-linear');
|
|
137
|
+
|
|
138
|
+
// Execute
|
|
139
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
140
|
+
skipDependencyChanges: true
|
|
141
|
+
});
|
|
142
|
+
expect(result.exitCode).toBe(0);
|
|
143
|
+
|
|
144
|
+
// Assert: Both features should be applied
|
|
145
|
+
// From feature-file-inherit-route-add (dependency) and dep-chain-linear (main) - both write to dep-chain-linear path
|
|
146
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-chain-linear/src/about.tsx'))).toBe(true);
|
|
147
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-chain-linear/src/contact.tsx'))).toBe(true);
|
|
148
|
+
|
|
149
|
+
// Routes should have both /about and /contact
|
|
150
|
+
const { readFileSync } = await import('fs');
|
|
151
|
+
const routesContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/dep-chain-linear/src/routes.tsx'), 'utf-8');
|
|
152
|
+
expect(routesContent).toContain('about');
|
|
153
|
+
expect(routesContent).toContain('contact');
|
|
154
|
+
|
|
155
|
+
// Compare with gold files
|
|
156
|
+
const goldDir = getGoldPath('dep-chain-linear-apply');
|
|
157
|
+
const differences = compareOrUpdate(targetDir, goldDir);
|
|
158
|
+
expect(differences).toEqual([]);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('Complex operations', () => {
|
|
163
|
+
it('should handle __inherit__, __prepend__, __append__', async () => {
|
|
164
|
+
// Setup
|
|
165
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
166
|
+
const targetDir = join(tempDir, 'complex-apply');
|
|
167
|
+
const featurePath = getFixturePath('basic-operations/feature-file-prepend-append');
|
|
168
|
+
|
|
169
|
+
// Execute
|
|
170
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
171
|
+
skipDependencyChanges: true
|
|
172
|
+
});
|
|
173
|
+
expect(result.exitCode).toBe(0);
|
|
174
|
+
|
|
175
|
+
// Assert: Check files exist (in feature-file-prepend-append path)
|
|
176
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-prepend-append/src/settings.tsx'))).toBe(true);
|
|
177
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-prepend-append/src/appLayout.tsx'))).toBe(true);
|
|
178
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-prepend-append/src/index.tsx'))).toBe(true);
|
|
179
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-prepend-append/src/styles/global.css'))).toBe(true);
|
|
180
|
+
|
|
181
|
+
// Check prepend operation
|
|
182
|
+
const { readFileSync } = await import('fs');
|
|
183
|
+
const indexContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-prepend-append/src/index.tsx'), 'utf-8');
|
|
184
|
+
expect(indexContent).toContain('Feature complex initialized');
|
|
185
|
+
|
|
186
|
+
// Check append operation
|
|
187
|
+
const cssContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-prepend-append/src/styles/global.css'), 'utf-8');
|
|
188
|
+
expect(cssContent).toContain('--feature-color');
|
|
189
|
+
expect(cssContent).toContain('.feature-specific');
|
|
190
|
+
|
|
191
|
+
// Compare with gold files
|
|
192
|
+
const goldDir = getGoldPath('feature-file-prepend-append-apply');
|
|
193
|
+
const differences = compareOrUpdate(targetDir, goldDir);
|
|
194
|
+
expect(differences).toEqual([]);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should verify appLayout is inherited correctly', async () => {
|
|
198
|
+
// Setup
|
|
199
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
200
|
+
const targetDir = join(tempDir, 'complex-apply-verify');
|
|
201
|
+
const featurePath = getFixturePath('basic-operations/feature-file-prepend-append');
|
|
202
|
+
|
|
203
|
+
// Execute
|
|
204
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
205
|
+
skipDependencyChanges: true
|
|
206
|
+
});
|
|
207
|
+
expect(result.exitCode).toBe(0);
|
|
208
|
+
|
|
209
|
+
// Assert: appLayout should exist (inherited from base)
|
|
210
|
+
const { readFileSync } = await import('fs');
|
|
211
|
+
const appLayoutContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-prepend-append/src/appLayout.tsx'), 'utf-8');
|
|
212
|
+
|
|
213
|
+
// Should still have the base navigation structure
|
|
214
|
+
expect(appLayoutContent).toContain('routes[0].children?.map');
|
|
215
|
+
expect(appLayoutContent).toContain('Outlet');
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe('Error handling', () => {
|
|
220
|
+
it('should fail gracefully when feature path does not exist', async () => {
|
|
221
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
222
|
+
const targetDir = join(tempDir, 'error-test');
|
|
223
|
+
const featurePath = getFixturePath('non-existent-feature');
|
|
224
|
+
|
|
225
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
226
|
+
skipDependencyChanges: true
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
expect(result.exitCode).not.toBe(0);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('should fail when trying to delete non-existent file', async () => {
|
|
233
|
+
// Setup: Create a custom feature that tries to delete a file that doesn't exist
|
|
234
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
235
|
+
const targetDir = join(tempDir, 'delete-error-test');
|
|
236
|
+
|
|
237
|
+
// Create a feature that tries to delete a non-existent file
|
|
238
|
+
const { mkdirSync, writeFileSync } = await import('fs');
|
|
239
|
+
const customFeature = join(tempDir, 'custom-feature');
|
|
240
|
+
mkdirSync(join(customFeature, 'template/digitalExperiences/webApplications/custom-feature/src'), { recursive: true });
|
|
241
|
+
|
|
242
|
+
// Write feature.ts
|
|
243
|
+
writeFileSync(
|
|
244
|
+
join(customFeature, 'feature.ts'),
|
|
245
|
+
`export default { templateDir: 'template' };`
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
// Write a delete marker for non-existent file
|
|
249
|
+
writeFileSync(
|
|
250
|
+
join(customFeature, 'template/digitalExperiences/webApplications/custom-feature/src/__delete__non-existent.tsx'),
|
|
251
|
+
'// This file does not exist in base app'
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
const result = await runApplyPatches(customFeature, baseAppDir, targetDir, {
|
|
255
|
+
skipDependencyChanges: true
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
expect(result.exitCode).not.toBe(0);
|
|
259
|
+
expect(result.stderr).toMatch(/Cannot delete file that doesn't exist/);
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
describe('Idempotency', () => {
|
|
264
|
+
it('should handle applying patches multiple times idempotently', async () => {
|
|
265
|
+
// Setup: Copy base-app
|
|
266
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
267
|
+
const targetDir = join(tempDir, 'idempotent-test');
|
|
268
|
+
const featurePath = getFixturePath('basic-operations/feature-file-inherit-route-add');
|
|
269
|
+
|
|
270
|
+
// First application
|
|
271
|
+
const result1 = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
272
|
+
skipDependencyChanges: true
|
|
273
|
+
});
|
|
274
|
+
expect(result1.exitCode).toBe(0);
|
|
275
|
+
|
|
276
|
+
// Verify it worked
|
|
277
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-inherit-route-add/src/about.tsx'))).toBe(true);
|
|
278
|
+
|
|
279
|
+
// Apply again (should be idempotent - not fail or corrupt files)
|
|
280
|
+
const result2 = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
281
|
+
skipDependencyChanges: true
|
|
282
|
+
});
|
|
283
|
+
expect(result2.exitCode).toBe(0);
|
|
284
|
+
|
|
285
|
+
// Should still work correctly
|
|
286
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-inherit-route-add/src/about.tsx'))).toBe(true);
|
|
287
|
+
const { readFileSync } = await import('fs');
|
|
288
|
+
const routesContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-inherit-route-add/src/routes.tsx'), 'utf-8');
|
|
289
|
+
expect(routesContent).toContain('about');
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
describe('Long dependency chains', () => {
|
|
294
|
+
it('should apply features in a long chain (A → B → C → D)', async () => {
|
|
295
|
+
// Setup: dep-chain-a depends on B, which depends on C, which depends on D
|
|
296
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
297
|
+
const targetDir = join(tempDir, 'dep-chain-long-apply');
|
|
298
|
+
const featurePath = getFixturePath('dep-chain-long/dep-chain-a');
|
|
299
|
+
|
|
300
|
+
// Execute
|
|
301
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
302
|
+
skipDependencyChanges: true
|
|
303
|
+
});
|
|
304
|
+
expect(result.exitCode).toBe(0);
|
|
305
|
+
|
|
306
|
+
// Assert: All 4 features should be applied
|
|
307
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-chain-a/src/page-a.tsx'))).toBe(true);
|
|
308
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-chain-a/src/page-b.tsx'))).toBe(true);
|
|
309
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-chain-a/src/page-c.tsx'))).toBe(true);
|
|
310
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-chain-a/src/page-d.tsx'))).toBe(true);
|
|
311
|
+
|
|
312
|
+
// Routes should have all 4 pages
|
|
313
|
+
const { readFileSync } = await import('fs');
|
|
314
|
+
const routesContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/dep-chain-a/src/routes.tsx'), 'utf-8');
|
|
315
|
+
expect(routesContent).toContain('page-a');
|
|
316
|
+
expect(routesContent).toContain('page-b');
|
|
317
|
+
expect(routesContent).toContain('page-c');
|
|
318
|
+
expect(routesContent).toContain('page-d');
|
|
319
|
+
|
|
320
|
+
// Compare with gold files
|
|
321
|
+
const goldDir = getGoldPath('dep-chain-long-apply');
|
|
322
|
+
const differences = compareOrUpdate(targetDir, goldDir);
|
|
323
|
+
expect(differences).toEqual([]);
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
describe('Diamond dependencies', () => {
|
|
328
|
+
it('should apply shared dependency only once in diamond pattern', async () => {
|
|
329
|
+
// Setup: Both left and right depend on shared
|
|
330
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
331
|
+
const targetDirLeft = join(tempDir, 'dep-diamond-left-apply');
|
|
332
|
+
const targetDirRight = join(tempDir, 'dep-diamond-right-apply');
|
|
333
|
+
|
|
334
|
+
// Apply left feature (depends on shared)
|
|
335
|
+
const leftPath = getFixturePath('dep-diamond/dep-diamond-left');
|
|
336
|
+
const resultLeft = await runApplyPatches(leftPath, baseAppDir, targetDirLeft, {
|
|
337
|
+
skipDependencyChanges: true
|
|
338
|
+
});
|
|
339
|
+
expect(resultLeft.exitCode).toBe(0);
|
|
340
|
+
|
|
341
|
+
// Apply right feature (also depends on shared)
|
|
342
|
+
const rightPath = getFixturePath('dep-diamond/dep-diamond-right');
|
|
343
|
+
const resultRight = await runApplyPatches(rightPath, baseAppDir, targetDirRight, {
|
|
344
|
+
skipDependencyChanges: true
|
|
345
|
+
});
|
|
346
|
+
expect(resultRight.exitCode).toBe(0);
|
|
347
|
+
|
|
348
|
+
// Assert: Left should have shared and left-page
|
|
349
|
+
expect(existsSync(join(targetDirLeft, 'digitalExperiences/webApplications/dep-diamond-left/src/shared-utils.tsx'))).toBe(true);
|
|
350
|
+
expect(existsSync(join(targetDirLeft, 'digitalExperiences/webApplications/dep-diamond-left/src/left-page.tsx'))).toBe(true);
|
|
351
|
+
|
|
352
|
+
// Right should have shared and right-page
|
|
353
|
+
expect(existsSync(join(targetDirRight, 'digitalExperiences/webApplications/dep-diamond-right/src/shared-utils.tsx'))).toBe(true);
|
|
354
|
+
expect(existsSync(join(targetDirRight, 'digitalExperiences/webApplications/dep-diamond-right/src/right-page.tsx'))).toBe(true);
|
|
355
|
+
|
|
356
|
+
// Routes should have shared content in both
|
|
357
|
+
const { readFileSync } = await import('fs');
|
|
358
|
+
const routesLeft = readFileSync(join(targetDirLeft, 'digitalExperiences/webApplications/dep-diamond-left/src/routes.tsx'), 'utf-8');
|
|
359
|
+
const routesRight = readFileSync(join(targetDirRight, 'digitalExperiences/webApplications/dep-diamond-right/src/routes.tsx'), 'utf-8');
|
|
360
|
+
|
|
361
|
+
expect(routesLeft).toContain('shared');
|
|
362
|
+
expect(routesLeft).toContain('left');
|
|
363
|
+
expect(routesRight).toContain('shared');
|
|
364
|
+
expect(routesRight).toContain('right');
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
describe('Circular dependencies', () => {
|
|
369
|
+
it('should detect and reject circular dependencies', async () => {
|
|
370
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
371
|
+
const targetDir = join(tempDir, 'circular-error-test');
|
|
372
|
+
const featurePath = getFixturePath('dep-circular/dep-circular-a');
|
|
373
|
+
|
|
374
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
375
|
+
skipDependencyChanges: true
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
expect(result.exitCode).not.toBe(0);
|
|
379
|
+
expect(result.stderr).toMatch(/circular/i);
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
describe('Complex dependency graph', () => {
|
|
384
|
+
it('should resolve complex multi-branch dependencies correctly', async () => {
|
|
385
|
+
// Setup: Apply all 3 main features (auth, dashboard, profile)
|
|
386
|
+
// Each has different combinations of shared dependencies
|
|
387
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
388
|
+
const targetDir = join(tempDir, 'dep-complex-graph-apply');
|
|
389
|
+
|
|
390
|
+
// Apply the parent dep-complex-graph feature which depends on all 3 main features
|
|
391
|
+
const complexGraphPath = getFixturePath('dep-complex-graph');
|
|
392
|
+
const result = await runApplyPatches(complexGraphPath, baseAppDir, targetDir, {
|
|
393
|
+
skipDependencyChanges: true
|
|
394
|
+
});
|
|
395
|
+
expect(result.exitCode).toBe(0);
|
|
396
|
+
|
|
397
|
+
// Assert: All features and shared dependencies should be present
|
|
398
|
+
// Shared dependencies
|
|
399
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/tools.tsx'))).toBe(true);
|
|
400
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/types.tsx'))).toBe(true);
|
|
401
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/components.tsx'))).toBe(true);
|
|
402
|
+
|
|
403
|
+
// Main features with enhanced route manipulation
|
|
404
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/login.tsx'))).toBe(true);
|
|
405
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/signup.tsx'))).toBe(true);
|
|
406
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/dashboard.tsx'))).toBe(true);
|
|
407
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/analytics.tsx'))).toBe(true);
|
|
408
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/reports.tsx'))).toBe(true);
|
|
409
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/profile.tsx'))).toBe(true);
|
|
410
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/profile-edit.tsx'))).toBe(true);
|
|
411
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/admin-layout.tsx'))).toBe(true);
|
|
412
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/admin-dashboard.tsx'))).toBe(true);
|
|
413
|
+
|
|
414
|
+
// Verify old route was deleted
|
|
415
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/old-page.tsx'))).toBe(false);
|
|
416
|
+
|
|
417
|
+
// Routes should have all new routes
|
|
418
|
+
const { readFileSync } = await import('fs');
|
|
419
|
+
const routesContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/dep-complex-graph/src/routes.tsx'), 'utf-8');
|
|
420
|
+
expect(routesContent).toContain('tools');
|
|
421
|
+
expect(routesContent).toContain('components');
|
|
422
|
+
expect(routesContent).toContain('login');
|
|
423
|
+
expect(routesContent).toContain('signup');
|
|
424
|
+
expect(routesContent).toContain('dashboard');
|
|
425
|
+
expect(routesContent).toContain('analytics');
|
|
426
|
+
expect(routesContent).toContain('reports');
|
|
427
|
+
expect(routesContent).toContain('profile/:id');
|
|
428
|
+
expect(routesContent).toContain('edit');
|
|
429
|
+
expect(routesContent).toContain('admin');
|
|
430
|
+
expect(routesContent).not.toContain('old');
|
|
431
|
+
|
|
432
|
+
// Compare with gold files
|
|
433
|
+
const goldDir = getGoldPath('dep-complex-graph-apply');
|
|
434
|
+
const differences = compareOrUpdate(targetDir, goldDir);
|
|
435
|
+
expect(differences).toEqual([]);
|
|
436
|
+
});
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
describe('Phase 2: Single feature tests', () => {
|
|
440
|
+
it('should apply prepend-only feature correctly', async () => {
|
|
441
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
442
|
+
const targetDir = join(tempDir, 'prepend-only-apply');
|
|
443
|
+
const featurePath = getFixturePath('single-operations/feature-file-prepend');
|
|
444
|
+
|
|
445
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
446
|
+
skipDependencyChanges: true
|
|
447
|
+
});
|
|
448
|
+
expect(result.exitCode).toBe(0);
|
|
449
|
+
|
|
450
|
+
const { readFileSync } = await import('fs');
|
|
451
|
+
const indexContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-prepend/src/index.tsx'), 'utf-8');
|
|
452
|
+
expect(indexContent).toContain('Feature prepend initialized');
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
it('should apply append-only feature correctly', async () => {
|
|
456
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
457
|
+
const targetDir = join(tempDir, 'append-only-apply');
|
|
458
|
+
const featurePath = getFixturePath('single-operations/feature-file-append');
|
|
459
|
+
|
|
460
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
461
|
+
skipDependencyChanges: true
|
|
462
|
+
});
|
|
463
|
+
expect(result.exitCode).toBe(0);
|
|
464
|
+
|
|
465
|
+
const { readFileSync } = await import('fs');
|
|
466
|
+
const cssContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-append/src/styles/global.css'), 'utf-8');
|
|
467
|
+
expect(cssContent).toContain('feature-append-specific');
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it('should apply route-add feature correctly', async () => {
|
|
471
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
472
|
+
const targetDir = join(tempDir, 'route-add-apply');
|
|
473
|
+
const featurePath = getFixturePath('single-operations/feature-route-add');
|
|
474
|
+
|
|
475
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
476
|
+
skipDependencyChanges: true
|
|
477
|
+
});
|
|
478
|
+
expect(result.exitCode).toBe(0);
|
|
479
|
+
|
|
480
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-route-add/src/services.tsx'))).toBe(true);
|
|
481
|
+
|
|
482
|
+
const { readFileSync } = await import('fs');
|
|
483
|
+
const routesContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/feature-route-add/src/routes.tsx'), 'utf-8');
|
|
484
|
+
expect(routesContent).toContain('services');
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
it('should apply inherit-only feature correctly', async () => {
|
|
488
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
489
|
+
const targetDir = join(tempDir, 'inherit-only-apply');
|
|
490
|
+
const featurePath = getFixturePath('single-operations/feature-file-inherit');
|
|
491
|
+
|
|
492
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
493
|
+
skipDependencyChanges: true
|
|
494
|
+
});
|
|
495
|
+
expect(result.exitCode).toBe(0);
|
|
496
|
+
|
|
497
|
+
// Verify inherited files exist
|
|
498
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-inherit/src/appLayout.tsx'))).toBe(true);
|
|
499
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/feature-file-inherit/src/home.tsx'))).toBe(true);
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
it('should apply import-merge feature correctly', async () => {
|
|
503
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
504
|
+
const targetDir = join(tempDir, 'import-merge-apply');
|
|
505
|
+
const featurePath = getFixturePath('single-operations/feature-import-merge');
|
|
506
|
+
|
|
507
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
508
|
+
skipDependencyChanges: true
|
|
509
|
+
});
|
|
510
|
+
expect(result.exitCode).toBe(0);
|
|
511
|
+
|
|
512
|
+
// Verify route file has merged imports
|
|
513
|
+
const { readFileSync } = await import('fs');
|
|
514
|
+
const routesContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/feature-import-merge/src/routes.tsx'), 'utf-8');
|
|
515
|
+
expect(routesContent).toContain('settings');
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
describe('Phase 4: Composition tests', () => {
|
|
520
|
+
it('should handle multiple features appending to same file', async () => {
|
|
521
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
522
|
+
const targetDir1 = join(tempDir, 'append1');
|
|
523
|
+
const targetDir2 = join(tempDir, 'append2');
|
|
524
|
+
const targetDir3 = join(tempDir, 'append3');
|
|
525
|
+
|
|
526
|
+
// Apply three append features sequentially
|
|
527
|
+
const result1 = await runApplyPatches(getFixturePath('composition-append/composition-append-1'), baseAppDir, targetDir1, {
|
|
528
|
+
skipDependencyChanges: true
|
|
529
|
+
});
|
|
530
|
+
expect(result1.exitCode).toBe(0);
|
|
531
|
+
|
|
532
|
+
const result2 = await runApplyPatches(getFixturePath('composition-append/composition-append-2'), baseAppDir, targetDir2, {
|
|
533
|
+
skipDependencyChanges: true
|
|
534
|
+
});
|
|
535
|
+
expect(result2.exitCode).toBe(0);
|
|
536
|
+
|
|
537
|
+
const result3 = await runApplyPatches(getFixturePath('composition-append/composition-append-3'), baseAppDir, targetDir3, {
|
|
538
|
+
skipDependencyChanges: true
|
|
539
|
+
});
|
|
540
|
+
expect(result3.exitCode).toBe(0);
|
|
541
|
+
|
|
542
|
+
// Verify each append was applied
|
|
543
|
+
const { readFileSync } = await import('fs');
|
|
544
|
+
const css1 = readFileSync(join(targetDir1, 'digitalExperiences/webApplications/composition-append-1/src/styles/global.css'), 'utf-8');
|
|
545
|
+
const css2 = readFileSync(join(targetDir2, 'digitalExperiences/webApplications/composition-append-2/src/styles/global.css'), 'utf-8');
|
|
546
|
+
const css3 = readFileSync(join(targetDir3, 'digitalExperiences/webApplications/composition-append-3/src/styles/global.css'), 'utf-8');
|
|
547
|
+
|
|
548
|
+
expect(css1).toContain('composition-append-1');
|
|
549
|
+
expect(css2).toContain('composition-append-2');
|
|
550
|
+
expect(css3).toContain('composition-append-3');
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
it('should handle multiple features prepending to same file', async () => {
|
|
554
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
555
|
+
const targetDir1 = join(tempDir, 'prepend1');
|
|
556
|
+
|
|
557
|
+
const result = await runApplyPatches(getFixturePath('composition-prepend/composition-prepend-1'), baseAppDir, targetDir1, {
|
|
558
|
+
skipDependencyChanges: true
|
|
559
|
+
});
|
|
560
|
+
expect(result.exitCode).toBe(0);
|
|
561
|
+
|
|
562
|
+
const { readFileSync } = await import('fs');
|
|
563
|
+
const indexContent = readFileSync(join(targetDir1, 'digitalExperiences/webApplications/composition-prepend-1/src/index.tsx'), 'utf-8');
|
|
564
|
+
expect(indexContent).toContain('composition-prepend-1');
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
it('should handle five features applied together', async () => {
|
|
568
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
569
|
+
const targetDir = join(tempDir, '5-features-apply');
|
|
570
|
+
|
|
571
|
+
// Apply all 5 features to test integration
|
|
572
|
+
const result1 = await runApplyPatches(getFixturePath('composition-5-features/5-features-navigation'), baseAppDir, targetDir, {
|
|
573
|
+
skipDependencyChanges: true
|
|
574
|
+
});
|
|
575
|
+
expect(result1.exitCode).toBe(0);
|
|
576
|
+
|
|
577
|
+
const result2 = await runApplyPatches(getFixturePath('composition-5-features/5-features-footer'), baseAppDir, targetDir, {
|
|
578
|
+
skipDependencyChanges: true
|
|
579
|
+
});
|
|
580
|
+
expect(result2.exitCode).toBe(0);
|
|
581
|
+
|
|
582
|
+
const result3 = await runApplyPatches(getFixturePath('composition-5-features/5-features-theme'), baseAppDir, targetDir, {
|
|
583
|
+
skipDependencyChanges: true
|
|
584
|
+
});
|
|
585
|
+
expect(result3.exitCode).toBe(0);
|
|
586
|
+
|
|
587
|
+
const result4 = await runApplyPatches(getFixturePath('composition-5-features/5-features-analytics'), baseAppDir, targetDir, {
|
|
588
|
+
skipDependencyChanges: true
|
|
589
|
+
});
|
|
590
|
+
expect(result4.exitCode).toBe(0);
|
|
591
|
+
|
|
592
|
+
const result5 = await runApplyPatches(getFixturePath('composition-5-features/5-features-about'), baseAppDir, targetDir, {
|
|
593
|
+
skipDependencyChanges: true
|
|
594
|
+
});
|
|
595
|
+
expect(result5.exitCode).toBe(0);
|
|
596
|
+
|
|
597
|
+
// Verify at least some of the features were applied
|
|
598
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/5-features-about/src/about.tsx'))).toBe(true);
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
it('should handle inherit then modify pattern', async () => {
|
|
602
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
603
|
+
const targetDir1 = join(tempDir, 'inherit-layout');
|
|
604
|
+
const targetDir2 = join(tempDir, 'modify-layout');
|
|
605
|
+
|
|
606
|
+
// Apply inherit feature first
|
|
607
|
+
const result1 = await runApplyPatches(getFixturePath('composition-inherit-modify/composition-inherit-layout'), baseAppDir, targetDir1, {
|
|
608
|
+
skipDependencyChanges: true
|
|
609
|
+
});
|
|
610
|
+
expect(result1.exitCode).toBe(0);
|
|
611
|
+
|
|
612
|
+
// Apply modify feature
|
|
613
|
+
const result2 = await runApplyPatches(getFixturePath('composition-inherit-modify/composition-modify-layout'), baseAppDir, targetDir2, {
|
|
614
|
+
skipDependencyChanges: true
|
|
615
|
+
});
|
|
616
|
+
expect(result2.exitCode).toBe(0);
|
|
617
|
+
|
|
618
|
+
// Verify both applied correctly
|
|
619
|
+
const { readFileSync } = await import('fs');
|
|
620
|
+
const layout1 = readFileSync(join(targetDir1, 'digitalExperiences/webApplications/composition-inherit-layout/src/appLayout.tsx'), 'utf-8');
|
|
621
|
+
const layout2 = readFileSync(join(targetDir2, 'digitalExperiences/webApplications/composition-modify-layout/src/appLayout.tsx'), 'utf-8');
|
|
622
|
+
|
|
623
|
+
expect(layout1).toBeTruthy();
|
|
624
|
+
expect(layout2).toBeTruthy();
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
it('should handle multiple prepends in order (prepend-2 and prepend-3)', async () => {
|
|
628
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
629
|
+
const targetDir2 = join(tempDir, 'prepend2');
|
|
630
|
+
const targetDir3 = join(tempDir, 'prepend3');
|
|
631
|
+
|
|
632
|
+
const result2 = await runApplyPatches(getFixturePath('composition-prepend/composition-prepend-2'), baseAppDir, targetDir2, {
|
|
633
|
+
skipDependencyChanges: true
|
|
634
|
+
});
|
|
635
|
+
expect(result2.exitCode).toBe(0);
|
|
636
|
+
|
|
637
|
+
const result3 = await runApplyPatches(getFixturePath('composition-prepend/composition-prepend-3'), baseAppDir, targetDir3, {
|
|
638
|
+
skipDependencyChanges: true
|
|
639
|
+
});
|
|
640
|
+
expect(result3.exitCode).toBe(0);
|
|
641
|
+
|
|
642
|
+
const { readFileSync } = await import('fs');
|
|
643
|
+
const indexContent2 = readFileSync(join(targetDir2, 'digitalExperiences/webApplications/composition-prepend-2/src/index.tsx'), 'utf-8');
|
|
644
|
+
const indexContent3 = readFileSync(join(targetDir3, 'digitalExperiences/webApplications/composition-prepend-3/src/index.tsx'), 'utf-8');
|
|
645
|
+
|
|
646
|
+
expect(indexContent2).toContain('composition-prepend-2');
|
|
647
|
+
expect(indexContent3).toContain('composition-prepend-3');
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
describe('Phase 5: Real-world scenarios', () => {
|
|
652
|
+
it('should apply navigation menu feature', async () => {
|
|
653
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
654
|
+
const targetDir = join(tempDir, 'nav-menu-apply');
|
|
655
|
+
const featurePath = getFixturePath('scenarios/scenario-navigation-menu');
|
|
656
|
+
|
|
657
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
658
|
+
skipDependencyChanges: true
|
|
659
|
+
});
|
|
660
|
+
expect(result.exitCode).toBe(0);
|
|
661
|
+
|
|
662
|
+
// Verify navigation component exists
|
|
663
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/scenario-navigation-menu/src/components/NavigationMenu.tsx'))).toBe(true);
|
|
664
|
+
|
|
665
|
+
// Verify appLayout was modified
|
|
666
|
+
const { readFileSync } = await import('fs');
|
|
667
|
+
const appLayoutContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/scenario-navigation-menu/src/appLayout.tsx'), 'utf-8');
|
|
668
|
+
expect(appLayoutContent).toContain('NavigationMenu');
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
it('should apply authentication feature', async () => {
|
|
672
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
673
|
+
const targetDir = join(tempDir, 'auth-apply');
|
|
674
|
+
const featurePath = getFixturePath('scenarios/scenario-authentication');
|
|
675
|
+
|
|
676
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
677
|
+
skipDependencyChanges: true
|
|
678
|
+
});
|
|
679
|
+
expect(result.exitCode).toBe(0);
|
|
680
|
+
|
|
681
|
+
// Verify auth components exist
|
|
682
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/scenario-authentication/src/context/AuthContext.tsx'))).toBe(true);
|
|
683
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/scenario-authentication/src/components/LoginForm.tsx'))).toBe(true);
|
|
684
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/scenario-authentication/src/login.tsx'))).toBe(true);
|
|
685
|
+
|
|
686
|
+
// Verify routes include login
|
|
687
|
+
const { readFileSync } = await import('fs');
|
|
688
|
+
const routesContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/scenario-authentication/src/routes.tsx'), 'utf-8');
|
|
689
|
+
expect(routesContent).toContain('login');
|
|
690
|
+
expect(routesContent).toContain('Login');
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
it('should apply CRUD contacts feature', async () => {
|
|
694
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
695
|
+
const targetDir = join(tempDir, 'crud-apply');
|
|
696
|
+
const featurePath = getFixturePath('scenarios/scenario-crud-contacts');
|
|
697
|
+
|
|
698
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
699
|
+
skipDependencyChanges: true
|
|
700
|
+
});
|
|
701
|
+
expect(result.exitCode).toBe(0);
|
|
702
|
+
|
|
703
|
+
// Verify CRUD components exist
|
|
704
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/scenario-crud-contacts/src/components/ContactList.tsx'))).toBe(true);
|
|
705
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/scenario-crud-contacts/src/components/ContactDetail.tsx'))).toBe(true);
|
|
706
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/scenario-crud-contacts/src/components/ContactForm.tsx'))).toBe(true);
|
|
707
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/scenario-crud-contacts/src/utils/contactsApi.ts'))).toBe(true);
|
|
708
|
+
|
|
709
|
+
// Verify routes include contacts with nested routes
|
|
710
|
+
const { readFileSync } = await import('fs');
|
|
711
|
+
const routesContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/scenario-crud-contacts/src/routes.tsx'), 'utf-8');
|
|
712
|
+
expect(routesContent).toContain('contacts');
|
|
713
|
+
expect(routesContent).toContain(':id');
|
|
714
|
+
expect(routesContent).toContain('edit');
|
|
715
|
+
|
|
716
|
+
// Verify CSS was appended
|
|
717
|
+
const cssContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/scenario-crud-contacts/src/styles/global.css'), 'utf-8');
|
|
718
|
+
expect(cssContent).toContain('contact-list');
|
|
719
|
+
expect(cssContent).toContain('form-group');
|
|
720
|
+
});
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
describe('Phase 6: Edge cases', () => {
|
|
724
|
+
it('should handle empty feature with only dependencies', async () => {
|
|
725
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
726
|
+
const targetDir = join(tempDir, 'edge-empty-apply');
|
|
727
|
+
const featurePath = getFixturePath('edges/edge-empty-feature');
|
|
728
|
+
|
|
729
|
+
// Should succeed - empty features are valid "meta-features"
|
|
730
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
731
|
+
skipDependencyChanges: true
|
|
732
|
+
});
|
|
733
|
+
expect(result.exitCode).toBe(0);
|
|
734
|
+
|
|
735
|
+
// Dependencies should be applied
|
|
736
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/edge-empty-feature/src/appLayout.tsx'))).toBe(true);
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
it('should reject conflicting prefixes', async () => {
|
|
740
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
741
|
+
const targetDir = join(tempDir, 'edge-conflict-apply');
|
|
742
|
+
const featurePath = getFixturePath('edges/edge-conflicting-prefixes');
|
|
743
|
+
|
|
744
|
+
// Should fail - can't have both __inherit__ and __delete__
|
|
745
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
746
|
+
skipDependencyChanges: true
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
expect(result.exitCode).not.toBe(0);
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
it('should reject operations on missing base files', async () => {
|
|
753
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
754
|
+
const targetDir = join(tempDir, 'edge-missing-apply');
|
|
755
|
+
const featurePath = getFixturePath('edges/edge-missing-base-files');
|
|
756
|
+
|
|
757
|
+
// Should fail - can't prepend/append/inherit non-existent files
|
|
758
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
759
|
+
skipDependencyChanges: true
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
expect(result.exitCode).not.toBe(0);
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
it('should detect package.json version conflicts', async () => {
|
|
766
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
767
|
+
const targetDir = join(tempDir, 'edge-pkg-conflict-apply');
|
|
768
|
+
|
|
769
|
+
// Apply first feature with react@18.0.0
|
|
770
|
+
const featurePathA = getFixturePath('edges/edge-package-json-conflicts-a');
|
|
771
|
+
const resultA = await runApplyPatches(featurePathA, baseAppDir, targetDir, {
|
|
772
|
+
skipDependencyChanges: true
|
|
773
|
+
});
|
|
774
|
+
expect(resultA.exitCode).toBe(0);
|
|
775
|
+
|
|
776
|
+
// Try to apply second feature with react@18.2.0 - should conflict
|
|
777
|
+
const featurePathB = getFixturePath('edges/edge-package-json-conflicts-b');
|
|
778
|
+
const resultB = await runApplyPatches(featurePathB, targetDir, targetDir, {
|
|
779
|
+
skipDependencyChanges: true
|
|
780
|
+
});
|
|
781
|
+
|
|
782
|
+
expect(resultB.exitCode).not.toBe(0);
|
|
783
|
+
expect(resultB.stderr).toMatch(/conflict|version/i);
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
it('should reject invalid route operations', async () => {
|
|
787
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
788
|
+
const targetDir = join(tempDir, 'edge-invalid-routes-apply');
|
|
789
|
+
const featurePath = getFixturePath('edges/edge-invalid-routes');
|
|
790
|
+
|
|
791
|
+
// Should fail - trying to delete non-existent routes
|
|
792
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
793
|
+
skipDependencyChanges: true
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
expect(result.exitCode).not.toBe(0);
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
it('should handle binary files correctly', async () => {
|
|
800
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
801
|
+
const targetDir = join(tempDir, 'edge-binary-apply');
|
|
802
|
+
const featurePath = getFixturePath('edges/edge-binary-files');
|
|
803
|
+
|
|
804
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
805
|
+
skipDependencyChanges: true
|
|
806
|
+
});
|
|
807
|
+
expect(result.exitCode).toBe(0);
|
|
808
|
+
|
|
809
|
+
// Binary file should be copied
|
|
810
|
+
const imagePath = join(targetDir, 'digitalExperiences/webApplications/edge-binary-files/src/assets/test-image.png');
|
|
811
|
+
expect(existsSync(imagePath)).toBe(true);
|
|
812
|
+
|
|
813
|
+
// Verify it's actually a binary file (not corrupted)
|
|
814
|
+
const { readFileSync } = await import('fs');
|
|
815
|
+
const imageBuffer = readFileSync(imagePath);
|
|
816
|
+
expect(imageBuffer.length).toBeGreaterThan(0);
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
it('should handle different line endings correctly', async () => {
|
|
820
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
821
|
+
const targetDir = join(tempDir, 'edge-line-endings-apply');
|
|
822
|
+
const featurePath = getFixturePath('edges/edge-line-endings');
|
|
823
|
+
|
|
824
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
825
|
+
skipDependencyChanges: true
|
|
826
|
+
});
|
|
827
|
+
expect(result.exitCode).toBe(0);
|
|
828
|
+
|
|
829
|
+
// Prepend and append should work correctly regardless of line endings
|
|
830
|
+
const { readFileSync } = await import('fs');
|
|
831
|
+
const indexContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/edge-line-endings/src/index.tsx'), 'utf-8');
|
|
832
|
+
const cssContent = readFileSync(join(targetDir, 'digitalExperiences/webApplications/edge-line-endings/src/styles/global.css'), 'utf-8');
|
|
833
|
+
|
|
834
|
+
expect(indexContent).toContain('line-endings');
|
|
835
|
+
expect(cssContent).toContain('line-endings');
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
it('should handle many features with reasonable performance', async () => {
|
|
839
|
+
const baseAppDir = copyFixture('base-app', join(tempDir, 'base-app'));
|
|
840
|
+
const targetDir = join(tempDir, 'edge-performance-apply');
|
|
841
|
+
const featurePath = getFixturePath('edges/edge-performance-many');
|
|
842
|
+
|
|
843
|
+
const startTime = Date.now();
|
|
844
|
+
|
|
845
|
+
const result = await runApplyPatches(featurePath, baseAppDir, targetDir, {
|
|
846
|
+
skipDependencyChanges: true
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
const duration = Date.now() - startTime;
|
|
850
|
+
|
|
851
|
+
expect(result.exitCode).toBe(0);
|
|
852
|
+
|
|
853
|
+
// Should complete in reasonable time (12 features should take less than 5 seconds)
|
|
854
|
+
expect(duration).toBeLessThan(5000);
|
|
855
|
+
|
|
856
|
+
// Verify at least some features were applied
|
|
857
|
+
expect(existsSync(join(targetDir, 'digitalExperiences/webApplications/edge-performance-many'))).toBe(true);
|
|
858
|
+
});
|
|
859
|
+
});
|
|
860
|
+
|
|
861
|
+
});
|