@eui/mcp 1.0.3 → 1.2.0
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/dist/config/__tests__/schema.property.test.d.ts +2 -0
- package/dist/config/__tests__/schema.property.test.d.ts.map +1 -0
- package/dist/config/__tests__/schema.property.test.js +203 -0
- package/dist/config/__tests__/schema.property.test.js.map +1 -0
- package/dist/config/__tests__/schema.test.d.ts +2 -0
- package/dist/config/__tests__/schema.test.d.ts.map +1 -0
- package/dist/config/__tests__/schema.test.js +454 -0
- package/dist/config/__tests__/schema.test.js.map +1 -0
- package/dist/config/loader.js +4 -4
- package/dist/config/loader.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/loader/__tests__/cache-manager.property.test.d.ts +2 -0
- package/dist/loader/__tests__/cache-manager.property.test.d.ts.map +1 -0
- package/dist/loader/__tests__/cache-manager.property.test.js +245 -0
- package/dist/loader/__tests__/cache-manager.property.test.js.map +1 -0
- package/dist/loader/__tests__/cache-manager.test.d.ts +2 -0
- package/dist/loader/__tests__/cache-manager.test.d.ts.map +1 -0
- package/dist/loader/__tests__/cache-manager.test.js +256 -0
- package/dist/loader/__tests__/cache-manager.test.js.map +1 -0
- package/dist/loader/__tests__/documentation-loader.integration.test.d.ts +2 -0
- package/dist/loader/__tests__/documentation-loader.integration.test.d.ts.map +1 -0
- package/dist/loader/__tests__/documentation-loader.integration.test.js +498 -0
- package/dist/loader/__tests__/documentation-loader.integration.test.js.map +1 -0
- package/dist/loader/__tests__/documentation-loader.property.test.d.ts +2 -0
- package/dist/loader/__tests__/documentation-loader.property.test.d.ts.map +1 -0
- package/dist/loader/__tests__/documentation-loader.property.test.js +258 -0
- package/dist/loader/__tests__/documentation-loader.property.test.js.map +1 -0
- package/dist/loader/__tests__/errors.test.d.ts +2 -0
- package/dist/loader/__tests__/errors.test.d.ts.map +1 -0
- package/dist/loader/__tests__/errors.test.js +132 -0
- package/dist/loader/__tests__/errors.test.js.map +1 -0
- package/dist/loader/__tests__/http-client.property.test.d.ts +2 -0
- package/dist/loader/__tests__/http-client.property.test.d.ts.map +1 -0
- package/dist/loader/__tests__/http-client.property.test.js +288 -0
- package/dist/loader/__tests__/http-client.property.test.js.map +1 -0
- package/dist/loader/__tests__/http-client.test.d.ts +2 -0
- package/dist/loader/__tests__/http-client.test.d.ts.map +1 -0
- package/dist/loader/__tests__/http-client.test.js +497 -0
- package/dist/loader/__tests__/http-client.test.js.map +1 -0
- package/dist/loader/__tests__/local-documentation-source.property.test.d.ts +2 -0
- package/dist/loader/__tests__/local-documentation-source.property.test.d.ts.map +1 -0
- package/dist/loader/__tests__/local-documentation-source.property.test.js +373 -0
- package/dist/loader/__tests__/local-documentation-source.property.test.js.map +1 -0
- package/dist/loader/__tests__/local-documentation-source.test.d.ts +2 -0
- package/dist/loader/__tests__/local-documentation-source.test.d.ts.map +1 -0
- package/dist/loader/__tests__/local-documentation-source.test.js +544 -0
- package/dist/loader/__tests__/local-documentation-source.test.js.map +1 -0
- package/dist/loader/__tests__/path-type-detector.property.test.d.ts +2 -0
- package/dist/loader/__tests__/path-type-detector.property.test.d.ts.map +1 -0
- package/dist/loader/__tests__/path-type-detector.property.test.js +245 -0
- package/dist/loader/__tests__/path-type-detector.property.test.js.map +1 -0
- package/dist/loader/__tests__/path-type-detector.test.d.ts +2 -0
- package/dist/loader/__tests__/path-type-detector.test.d.ts.map +1 -0
- package/dist/loader/__tests__/path-type-detector.test.js +390 -0
- package/dist/loader/__tests__/path-type-detector.test.js.map +1 -0
- package/dist/loader/__tests__/remote-documentation-source.property.test.d.ts +2 -0
- package/dist/loader/__tests__/remote-documentation-source.property.test.d.ts.map +1 -0
- package/dist/loader/__tests__/remote-documentation-source.property.test.js +462 -0
- package/dist/loader/__tests__/remote-documentation-source.property.test.js.map +1 -0
- package/dist/loader/__tests__/remote-documentation-source.test.d.ts +2 -0
- package/dist/loader/__tests__/remote-documentation-source.test.d.ts.map +1 -0
- package/dist/loader/__tests__/remote-documentation-source.test.js +707 -0
- package/dist/loader/__tests__/remote-documentation-source.test.js.map +1 -0
- package/dist/loader/remote-documentation-source.d.ts +0 -4
- package/dist/loader/remote-documentation-source.d.ts.map +1 -1
- package/dist/loader/remote-documentation-source.js +1 -4
- package/dist/loader/remote-documentation-source.js.map +1 -1
- package/dist/main.js +0 -0
- package/dist/main.js.map +1 -1
- package/dist/mcp/__tests__/server.property.test.d.ts +2 -0
- package/dist/mcp/__tests__/server.property.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/server.property.test.js +286 -0
- package/dist/mcp/__tests__/server.property.test.js.map +1 -0
- package/dist/mcp/__tests__/server.test.d.ts +2 -0
- package/dist/mcp/__tests__/server.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/server.test.js +101 -0
- package/dist/mcp/__tests__/server.test.js.map +1 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +16 -4
- package/dist/mcp/server.js.map +1 -1
- package/dist/publish/__tests__/publish-utils.test.d.ts +5 -0
- package/dist/publish/__tests__/publish-utils.test.d.ts.map +1 -0
- package/dist/publish/__tests__/publish-utils.test.js +189 -0
- package/dist/publish/__tests__/publish-utils.test.js.map +1 -0
- package/dist/query/__tests__/deprecation-parser.test.d.ts +2 -0
- package/dist/query/__tests__/deprecation-parser.test.d.ts.map +1 -0
- package/dist/query/__tests__/deprecation-parser.test.js +154 -0
- package/dist/query/__tests__/deprecation-parser.test.js.map +1 -0
- package/dist/query/__tests__/deprecation-query.test.d.ts +2 -0
- package/dist/query/__tests__/deprecation-query.test.d.ts.map +1 -0
- package/dist/query/__tests__/deprecation-query.test.js +199 -0
- package/dist/query/__tests__/deprecation-query.test.js.map +1 -0
- package/dist/query/__tests__/index-builder-debug.test.d.ts +2 -0
- package/dist/query/__tests__/index-builder-debug.test.d.ts.map +1 -0
- package/dist/query/__tests__/index-builder-debug.test.js +34 -0
- package/dist/query/__tests__/index-builder-debug.test.js.map +1 -0
- package/dist/query/__tests__/index-builder.property.test.d.ts +2 -0
- package/dist/query/__tests__/index-builder.property.test.d.ts.map +1 -0
- package/dist/query/__tests__/index-builder.property.test.js +422 -0
- package/dist/query/__tests__/index-builder.property.test.js.map +1 -0
- package/dist/query/__tests__/index-builder.test.d.ts +2 -0
- package/dist/query/__tests__/index-builder.test.d.ts.map +1 -0
- package/dist/query/__tests__/index-builder.test.js +55 -0
- package/dist/query/__tests__/index-builder.test.js.map +1 -0
- package/dist/query/__tests__/result-formatter-deprecation.test.d.ts +2 -0
- package/dist/query/__tests__/result-formatter-deprecation.test.d.ts.map +1 -0
- package/dist/query/__tests__/result-formatter-deprecation.test.js +159 -0
- package/dist/query/__tests__/result-formatter-deprecation.test.js.map +1 -0
- package/dist/query/__tests__/result-formatter.integration.test.d.ts +2 -0
- package/dist/query/__tests__/result-formatter.integration.test.d.ts.map +1 -0
- package/dist/query/__tests__/result-formatter.integration.test.js +140 -0
- package/dist/query/__tests__/result-formatter.integration.test.js.map +1 -0
- package/dist/query/__tests__/result-formatter.property.test.d.ts +2 -0
- package/dist/query/__tests__/result-formatter.property.test.d.ts.map +1 -0
- package/dist/query/__tests__/result-formatter.property.test.js +163 -0
- package/dist/query/__tests__/result-formatter.property.test.js.map +1 -0
- package/dist/query/__tests__/result-formatter.test.d.ts +2 -0
- package/dist/query/__tests__/result-formatter.test.d.ts.map +1 -0
- package/dist/query/__tests__/result-formatter.test.js +85 -0
- package/dist/query/__tests__/result-formatter.test.js.map +1 -0
- package/dist/query/__tests__/search-engine.property.test.d.ts +2 -0
- package/dist/query/__tests__/search-engine.property.test.d.ts.map +1 -0
- package/dist/query/__tests__/search-engine.property.test.js +389 -0
- package/dist/query/__tests__/search-engine.property.test.js.map +1 -0
- package/dist/query/deprecation-parser.d.ts +46 -0
- package/dist/query/deprecation-parser.d.ts.map +1 -0
- package/dist/query/deprecation-parser.js +81 -0
- package/dist/query/deprecation-parser.js.map +1 -0
- package/dist/query/deprecation-query.d.ts +19 -0
- package/dist/query/deprecation-query.d.ts.map +1 -0
- package/dist/query/deprecation-query.js +73 -0
- package/dist/query/deprecation-query.js.map +1 -0
- package/dist/query/result-formatter.d.ts +27 -0
- package/dist/query/result-formatter.d.ts.map +1 -1
- package/dist/query/result-formatter.js +64 -5
- package/dist/query/result-formatter.js.map +1 -1
- package/dist/tools/__tests__/deprecation-tools.test.d.ts +2 -0
- package/dist/tools/__tests__/deprecation-tools.test.d.ts.map +1 -0
- package/dist/tools/__tests__/deprecation-tools.test.js +178 -0
- package/dist/tools/__tests__/deprecation-tools.test.js.map +1 -0
- package/dist/tools/__tests__/get-component-docs.property.test.d.ts +2 -0
- package/dist/tools/__tests__/get-component-docs.property.test.d.ts.map +1 -0
- package/dist/tools/__tests__/get-component-docs.property.test.js +594 -0
- package/dist/tools/__tests__/get-component-docs.property.test.js.map +1 -0
- package/dist/tools/__tests__/get-component-docs.test.d.ts +2 -0
- package/dist/tools/__tests__/get-component-docs.test.d.ts.map +1 -0
- package/dist/tools/__tests__/get-component-docs.test.js +137 -0
- package/dist/tools/__tests__/get-component-docs.test.js.map +1 -0
- package/dist/tools/__tests__/get-component-examples.property.test.d.ts +2 -0
- package/dist/tools/__tests__/get-component-examples.property.test.d.ts.map +1 -0
- package/dist/tools/__tests__/get-component-examples.property.test.js +245 -0
- package/dist/tools/__tests__/get-component-examples.property.test.js.map +1 -0
- package/dist/tools/__tests__/get-component-examples.test.d.ts +2 -0
- package/dist/tools/__tests__/get-component-examples.test.d.ts.map +1 -0
- package/dist/tools/__tests__/get-component-examples.test.js +128 -0
- package/dist/tools/__tests__/get-component-examples.test.js.map +1 -0
- package/dist/tools/__tests__/get-component-inputs.property.test.d.ts +2 -0
- package/dist/tools/__tests__/get-component-inputs.property.test.d.ts.map +1 -0
- package/dist/tools/__tests__/get-component-inputs.property.test.js +310 -0
- package/dist/tools/__tests__/get-component-inputs.property.test.js.map +1 -0
- package/dist/tools/__tests__/get-component-inputs.test.d.ts +2 -0
- package/dist/tools/__tests__/get-component-inputs.test.d.ts.map +1 -0
- package/dist/tools/__tests__/get-component-inputs.test.js +245 -0
- package/dist/tools/__tests__/get-component-inputs.test.js.map +1 -0
- package/dist/tools/__tests__/get-component-outputs.property.test.d.ts +2 -0
- package/dist/tools/__tests__/get-component-outputs.property.test.d.ts.map +1 -0
- package/dist/tools/__tests__/get-component-outputs.property.test.js +227 -0
- package/dist/tools/__tests__/get-component-outputs.property.test.js.map +1 -0
- package/dist/tools/__tests__/get-component-outputs.test.d.ts +2 -0
- package/dist/tools/__tests__/get-component-outputs.test.d.ts.map +1 -0
- package/dist/tools/__tests__/get-component-outputs.test.js +189 -0
- package/dist/tools/__tests__/get-component-outputs.test.js.map +1 -0
- package/dist/tools/__tests__/get-library-version.property.test.d.ts +2 -0
- package/dist/tools/__tests__/get-library-version.property.test.d.ts.map +1 -0
- package/dist/tools/__tests__/get-library-version.property.test.js +115 -0
- package/dist/tools/__tests__/get-library-version.property.test.js.map +1 -0
- package/dist/tools/__tests__/get-library-version.test.d.ts +2 -0
- package/dist/tools/__tests__/get-library-version.test.d.ts.map +1 -0
- package/dist/tools/__tests__/get-library-version.test.js +97 -0
- package/dist/tools/__tests__/get-library-version.test.js.map +1 -0
- package/dist/tools/__tests__/list-components.property.test.d.ts +2 -0
- package/dist/tools/__tests__/list-components.property.test.d.ts.map +1 -0
- package/dist/tools/__tests__/list-components.property.test.js +241 -0
- package/dist/tools/__tests__/list-components.property.test.js.map +1 -0
- package/dist/tools/__tests__/list-components.test.d.ts +2 -0
- package/dist/tools/__tests__/list-components.test.d.ts.map +1 -0
- package/dist/tools/__tests__/list-components.test.js +170 -0
- package/dist/tools/__tests__/list-components.test.js.map +1 -0
- package/dist/tools/__tests__/search-components.test.d.ts +2 -0
- package/dist/tools/__tests__/search-components.test.d.ts.map +1 -0
- package/dist/tools/__tests__/search-components.test.js +239 -0
- package/dist/tools/__tests__/search-components.test.js.map +1 -0
- package/dist/tools/get-deprecation-info.d.ts +42 -0
- package/dist/tools/get-deprecation-info.d.ts.map +1 -0
- package/dist/tools/get-deprecation-info.js +55 -0
- package/dist/tools/get-deprecation-info.js.map +1 -0
- package/dist/tools/get-library-version.d.ts +33 -0
- package/dist/tools/get-library-version.d.ts.map +1 -0
- package/dist/tools/get-library-version.js +62 -0
- package/dist/tools/get-library-version.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +3 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/list-deprecated.d.ts +47 -0
- package/dist/tools/list-deprecated.d.ts.map +1 -0
- package/dist/tools/list-deprecated.js +56 -0
- package/dist/tools/list-deprecated.js.map +1 -0
- package/dist/types/compodoc.d.ts +1 -0
- package/dist/types/compodoc.d.ts.map +1 -1
- package/dist/types/deprecation.d.ts +33 -0
- package/dist/types/deprecation.d.ts.map +1 -0
- package/dist/types/deprecation.js +5 -0
- package/dist/types/deprecation.js.map +1 -0
- package/dist/utils/__tests__/credential-masking.property.test.d.ts +2 -0
- package/dist/utils/__tests__/credential-masking.property.test.d.ts.map +1 -0
- package/dist/utils/__tests__/credential-masking.property.test.js +145 -0
- package/dist/utils/__tests__/credential-masking.property.test.js.map +1 -0
- package/dist/utils/__tests__/credential-masking.test.d.ts +2 -0
- package/dist/utils/__tests__/credential-masking.test.d.ts.map +1 -0
- package/dist/utils/__tests__/credential-masking.test.js +188 -0
- package/dist/utils/__tests__/credential-masking.test.js.map +1 -0
- package/dist/utils/__tests__/errors.test.d.ts +2 -0
- package/dist/utils/__tests__/errors.test.d.ts.map +1 -0
- package/dist/utils/__tests__/errors.test.js +110 -0
- package/dist/utils/__tests__/errors.test.js.map +1 -0
- package/dist/utils/__tests__/integration.test.d.ts +2 -0
- package/dist/utils/__tests__/integration.test.d.ts.map +1 -0
- package/dist/utils/__tests__/integration.test.js +142 -0
- package/dist/utils/__tests__/integration.test.js.map +1 -0
- package/dist/utils/__tests__/logger.test.d.ts +2 -0
- package/dist/utils/__tests__/logger.test.d.ts.map +1 -0
- package/dist/utils/__tests__/logger.test.js +119 -0
- package/dist/utils/__tests__/logger.test.js.map +1 -0
- package/dist/utils/__tests__/retry.test.d.ts +2 -0
- package/dist/utils/__tests__/retry.test.d.ts.map +1 -0
- package/dist/utils/__tests__/retry.test.js +84 -0
- package/dist/utils/__tests__/retry.test.js.map +1 -0
- package/dist/utils/credential-masking.js +4 -4
- package/dist/utils/credential-masking.js.map +1 -1
- package/dist/version/__tests__/changelog-commit-grouping.property.test.d.ts +2 -0
- package/dist/version/__tests__/changelog-commit-grouping.property.test.d.ts.map +1 -0
- package/dist/version/__tests__/changelog-commit-grouping.property.test.js +297 -0
- package/dist/version/__tests__/changelog-commit-grouping.property.test.js.map +1 -0
- package/dist/version/__tests__/changelog-commit-parsing.property.test.d.ts +2 -0
- package/dist/version/__tests__/changelog-commit-parsing.property.test.d.ts.map +1 -0
- package/dist/version/__tests__/changelog-commit-parsing.property.test.js +396 -0
- package/dist/version/__tests__/changelog-commit-parsing.property.test.js.map +1 -0
- package/dist/version/__tests__/changelog-file-updates.property.test.d.ts +11 -0
- package/dist/version/__tests__/changelog-file-updates.property.test.d.ts.map +1 -0
- package/dist/version/__tests__/changelog-file-updates.property.test.js +452 -0
- package/dist/version/__tests__/changelog-file-updates.property.test.js.map +1 -0
- package/dist/version/__tests__/dry-run-action.property.test.d.ts +8 -0
- package/dist/version/__tests__/dry-run-action.property.test.d.ts.map +1 -0
- package/dist/version/__tests__/dry-run-action.property.test.js +50 -0
- package/dist/version/__tests__/dry-run-action.property.test.js.map +1 -0
- package/dist/version/__tests__/dry-run-changelog.property.test.d.ts +8 -0
- package/dist/version/__tests__/dry-run-changelog.property.test.d.ts.map +1 -0
- package/dist/version/__tests__/dry-run-changelog.property.test.js +53 -0
- package/dist/version/__tests__/dry-run-changelog.property.test.js.map +1 -0
- package/dist/version/__tests__/dry-run-utils.test.d.ts +7 -0
- package/dist/version/__tests__/dry-run-utils.test.d.ts.map +1 -0
- package/dist/version/__tests__/dry-run-utils.test.js +205 -0
- package/dist/version/__tests__/dry-run-utils.test.js.map +1 -0
- package/dist/version/__tests__/dry-run-version.property.test.d.ts +8 -0
- package/dist/version/__tests__/dry-run-version.property.test.d.ts.map +1 -0
- package/dist/version/__tests__/dry-run-version.property.test.js +59 -0
- package/dist/version/__tests__/dry-run-version.property.test.js.map +1 -0
- package/dist/version/__tests__/git-tag-annotation.property.test.d.ts +11 -0
- package/dist/version/__tests__/git-tag-annotation.property.test.d.ts.map +1 -0
- package/dist/version/__tests__/git-tag-annotation.property.test.js +271 -0
- package/dist/version/__tests__/git-tag-annotation.property.test.js.map +1 -0
- package/dist/version/__tests__/git-tag-format.property.test.d.ts +11 -0
- package/dist/version/__tests__/git-tag-format.property.test.d.ts.map +1 -0
- package/dist/version/__tests__/git-tag-format.property.test.js +411 -0
- package/dist/version/__tests__/git-tag-format.property.test.js.map +1 -0
- package/dist/version/__tests__/git-tag-utils.test.d.ts +2 -0
- package/dist/version/__tests__/git-tag-utils.test.d.ts.map +1 -0
- package/dist/version/__tests__/git-tag-utils.test.js +142 -0
- package/dist/version/__tests__/git-tag-utils.test.js.map +1 -0
- package/dist/version/__tests__/npm-tag-selection.property.test.d.ts +2 -0
- package/dist/version/__tests__/npm-tag-selection.property.test.d.ts.map +1 -0
- package/dist/version/__tests__/npm-tag-selection.property.test.js +79 -0
- package/dist/version/__tests__/npm-tag-selection.property.test.js.map +1 -0
- package/dist/version/__tests__/release-title-format.property.test.d.ts +11 -0
- package/dist/version/__tests__/release-title-format.property.test.d.ts.map +1 -0
- package/dist/version/__tests__/release-title-format.property.test.js +422 -0
- package/dist/version/__tests__/release-title-format.property.test.js.map +1 -0
- package/dist/version/__tests__/release-utils.test.d.ts +7 -0
- package/dist/version/__tests__/release-utils.test.d.ts.map +1 -0
- package/dist/version/__tests__/release-utils.test.js +176 -0
- package/dist/version/__tests__/release-utils.test.js.map +1 -0
- package/dist/version/__tests__/rollback-changelog.property.test.d.ts +8 -0
- package/dist/version/__tests__/rollback-changelog.property.test.d.ts.map +1 -0
- package/dist/version/__tests__/rollback-changelog.property.test.js +61 -0
- package/dist/version/__tests__/rollback-changelog.property.test.js.map +1 -0
- package/dist/version/__tests__/rollback-utils.test.d.ts +7 -0
- package/dist/version/__tests__/rollback-utils.test.d.ts.map +1 -0
- package/dist/version/__tests__/rollback-utils.test.js +74 -0
- package/dist/version/__tests__/rollback-utils.test.js.map +1 -0
- package/dist/version/__tests__/version-manager.property.test.d.ts +2 -0
- package/dist/version/__tests__/version-manager.property.test.d.ts.map +1 -0
- package/dist/version/__tests__/version-manager.property.test.js +143 -0
- package/dist/version/__tests__/version-manager.property.test.js.map +1 -0
- package/dist/version/__tests__/version-manager.test.d.ts +2 -0
- package/dist/version/__tests__/version-manager.test.d.ts.map +1 -0
- package/dist/version/__tests__/version-manager.test.js +203 -0
- package/dist/version/__tests__/version-manager.test.js.map +1 -0
- package/dist/version/version-manager.d.ts.map +1 -1
- package/dist/version/version-manager.js +0 -4
- package/dist/version/version-manager.js.map +1 -1
- package/package.json +1 -1
- package/dist/test-error.ts +0 -1
|
@@ -0,0 +1,707 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for RemoteDocumentationSource
|
|
3
|
+
* Feature: url-based-documentation-path
|
|
4
|
+
* Tests successful fetch, polling, 304 responses, error handling, and cleanup
|
|
5
|
+
* Requirements: 5.1, 5.2, 5.4, 5.5, 8.4, 8.5
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect, jest, beforeEach, afterEach } from '@jest/globals';
|
|
8
|
+
import { RemoteDocumentationSource } from '../remote-documentation-source.js';
|
|
9
|
+
import { HttpClient } from '../http-client.js';
|
|
10
|
+
// Helper to create minimal valid CompodocDocumentation
|
|
11
|
+
const createMockDocumentation = (id = 'default') => ({
|
|
12
|
+
components: [{ name: `Component${id}`, id: `comp-${id}`, file: 'test.ts', type: 'component', deprecated: false }],
|
|
13
|
+
modules: [],
|
|
14
|
+
directives: [],
|
|
15
|
+
pipes: [],
|
|
16
|
+
classes: [],
|
|
17
|
+
interfaces: [],
|
|
18
|
+
injectables: [],
|
|
19
|
+
});
|
|
20
|
+
describe('RemoteDocumentationSource Unit Tests', () => {
|
|
21
|
+
let source;
|
|
22
|
+
let originalFetch;
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
jest.clearAllMocks();
|
|
25
|
+
jest.useRealTimers();
|
|
26
|
+
// Store original fetch method
|
|
27
|
+
originalFetch = HttpClient.prototype.fetch;
|
|
28
|
+
});
|
|
29
|
+
afterEach(async () => {
|
|
30
|
+
// Restore original fetch method
|
|
31
|
+
HttpClient.prototype.fetch = originalFetch;
|
|
32
|
+
if (source) {
|
|
33
|
+
await source.dispose();
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
describe('Successful Fetch and Parse (Requirement 5.1)', () => {
|
|
37
|
+
it('should successfully fetch and parse documentation from URL', async () => {
|
|
38
|
+
const mockDoc = createMockDocumentation('test1');
|
|
39
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
40
|
+
status: 200,
|
|
41
|
+
statusText: 'OK',
|
|
42
|
+
data: JSON.stringify(mockDoc),
|
|
43
|
+
headers: new Map(),
|
|
44
|
+
});
|
|
45
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
46
|
+
source = new RemoteDocumentationSource({
|
|
47
|
+
url: 'https://example.com/docs.json',
|
|
48
|
+
timeout: 5000,
|
|
49
|
+
maxRetries: 3,
|
|
50
|
+
pollingInterval: 60000,
|
|
51
|
+
});
|
|
52
|
+
const result = await source.load();
|
|
53
|
+
expect(result.success).toBe(true);
|
|
54
|
+
expect(result.data).toBeDefined();
|
|
55
|
+
expect(result.data?.components).toHaveLength(1);
|
|
56
|
+
expect(result.data?.components[0].name).toBe('Componenttest1');
|
|
57
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
58
|
+
});
|
|
59
|
+
it('should store fetched documentation in currentData', async () => {
|
|
60
|
+
const mockDoc = createMockDocumentation('test2');
|
|
61
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
62
|
+
status: 200,
|
|
63
|
+
statusText: 'OK',
|
|
64
|
+
data: JSON.stringify(mockDoc),
|
|
65
|
+
headers: new Map(),
|
|
66
|
+
});
|
|
67
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
68
|
+
source = new RemoteDocumentationSource({
|
|
69
|
+
url: 'https://example.com/docs.json',
|
|
70
|
+
timeout: 5000,
|
|
71
|
+
maxRetries: 3,
|
|
72
|
+
pollingInterval: 60000,
|
|
73
|
+
});
|
|
74
|
+
await source.load();
|
|
75
|
+
const currentData = source.getCurrentData();
|
|
76
|
+
expect(currentData).toBeDefined();
|
|
77
|
+
expect(currentData?.components[0].name).toBe('Componenttest2');
|
|
78
|
+
});
|
|
79
|
+
it('should cache documentation with ETag header', async () => {
|
|
80
|
+
const mockDoc = createMockDocumentation('cached');
|
|
81
|
+
const headers = new Map();
|
|
82
|
+
headers.set('ETag', '"abc123"');
|
|
83
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
84
|
+
status: 200,
|
|
85
|
+
statusText: 'OK',
|
|
86
|
+
data: JSON.stringify(mockDoc),
|
|
87
|
+
headers,
|
|
88
|
+
});
|
|
89
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
90
|
+
source = new RemoteDocumentationSource({
|
|
91
|
+
url: 'https://example.com/docs.json',
|
|
92
|
+
timeout: 5000,
|
|
93
|
+
maxRetries: 3,
|
|
94
|
+
pollingInterval: 60000,
|
|
95
|
+
});
|
|
96
|
+
await source.load();
|
|
97
|
+
// Second load should include If-None-Match header
|
|
98
|
+
mockFetch.mockResolvedValue({
|
|
99
|
+
status: 304,
|
|
100
|
+
statusText: 'Not Modified',
|
|
101
|
+
data: '',
|
|
102
|
+
headers: new Map(),
|
|
103
|
+
});
|
|
104
|
+
const result = await source.load();
|
|
105
|
+
expect(result.success).toBe(true);
|
|
106
|
+
expect(result.data).toBeDefined();
|
|
107
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
108
|
+
// Verify conditional header was sent
|
|
109
|
+
const calls = mockFetch.mock.calls;
|
|
110
|
+
const conditionalHeaders = calls[1]?.[1];
|
|
111
|
+
expect(conditionalHeaders?.get('If-None-Match')).toBe('"abc123"');
|
|
112
|
+
});
|
|
113
|
+
it('should parse complex documentation structures', async () => {
|
|
114
|
+
const complexDoc = {
|
|
115
|
+
components: [
|
|
116
|
+
{ name: 'Button', id: 'btn-1', file: 'button.ts', type: 'component', deprecated: false, selector: 'app-button' },
|
|
117
|
+
{ name: 'Input', id: 'inp-1', file: 'input.ts', type: 'component', deprecated: true, deprecationMessage: 'Use Input2' },
|
|
118
|
+
],
|
|
119
|
+
modules: [
|
|
120
|
+
{ name: 'AppModule', id: 'mod-1', file: 'app.module.ts', type: 'module', deprecated: false },
|
|
121
|
+
],
|
|
122
|
+
directives: [],
|
|
123
|
+
pipes: [],
|
|
124
|
+
classes: [],
|
|
125
|
+
interfaces: [],
|
|
126
|
+
injectables: [],
|
|
127
|
+
};
|
|
128
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
129
|
+
status: 200,
|
|
130
|
+
statusText: 'OK',
|
|
131
|
+
data: JSON.stringify(complexDoc),
|
|
132
|
+
headers: new Map(),
|
|
133
|
+
});
|
|
134
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
135
|
+
source = new RemoteDocumentationSource({
|
|
136
|
+
url: 'https://example.com/docs.json',
|
|
137
|
+
timeout: 5000,
|
|
138
|
+
maxRetries: 3,
|
|
139
|
+
pollingInterval: 60000,
|
|
140
|
+
});
|
|
141
|
+
const result = await source.load();
|
|
142
|
+
expect(result.success).toBe(true);
|
|
143
|
+
expect(result.data?.components).toHaveLength(2);
|
|
144
|
+
expect(result.data?.modules).toHaveLength(1);
|
|
145
|
+
expect(result.data?.components[1].deprecationMessage).toBe('Use Input2');
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
describe('Polling Interval Timing (Requirement 5.1, 5.2)', () => {
|
|
149
|
+
it('should start polling at configured interval', async () => {
|
|
150
|
+
jest.useFakeTimers();
|
|
151
|
+
const mockDoc = createMockDocumentation('poll1');
|
|
152
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
153
|
+
status: 200,
|
|
154
|
+
statusText: 'OK',
|
|
155
|
+
data: JSON.stringify(mockDoc),
|
|
156
|
+
headers: new Map(),
|
|
157
|
+
});
|
|
158
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
159
|
+
source = new RemoteDocumentationSource({
|
|
160
|
+
url: 'https://example.com/docs.json',
|
|
161
|
+
timeout: 5000,
|
|
162
|
+
maxRetries: 3,
|
|
163
|
+
pollingInterval: 10000, // 10 seconds
|
|
164
|
+
});
|
|
165
|
+
await source.load();
|
|
166
|
+
mockFetch.mockClear();
|
|
167
|
+
source.startMonitoring();
|
|
168
|
+
// Advance time by 10 seconds
|
|
169
|
+
jest.advanceTimersByTime(10000);
|
|
170
|
+
await Promise.resolve(); // Allow promises to resolve
|
|
171
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
172
|
+
// Advance another 10 seconds
|
|
173
|
+
jest.advanceTimersByTime(10000);
|
|
174
|
+
await Promise.resolve();
|
|
175
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
176
|
+
jest.useRealTimers();
|
|
177
|
+
});
|
|
178
|
+
it('should not start polling if already monitoring', async () => {
|
|
179
|
+
jest.useFakeTimers();
|
|
180
|
+
const mockDoc = createMockDocumentation('poll2');
|
|
181
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
182
|
+
status: 200,
|
|
183
|
+
statusText: 'OK',
|
|
184
|
+
data: JSON.stringify(mockDoc),
|
|
185
|
+
headers: new Map(),
|
|
186
|
+
});
|
|
187
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
188
|
+
source = new RemoteDocumentationSource({
|
|
189
|
+
url: 'https://example.com/docs.json',
|
|
190
|
+
timeout: 5000,
|
|
191
|
+
maxRetries: 3,
|
|
192
|
+
pollingInterval: 10000,
|
|
193
|
+
});
|
|
194
|
+
await source.load();
|
|
195
|
+
mockFetch.mockClear();
|
|
196
|
+
source.startMonitoring();
|
|
197
|
+
source.startMonitoring(); // Call again
|
|
198
|
+
jest.advanceTimersByTime(10000);
|
|
199
|
+
await Promise.resolve();
|
|
200
|
+
// Should only poll once, not twice
|
|
201
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
202
|
+
jest.useRealTimers();
|
|
203
|
+
});
|
|
204
|
+
it('should stop polling when stopMonitoring is called', async () => {
|
|
205
|
+
jest.useFakeTimers();
|
|
206
|
+
const mockDoc = createMockDocumentation('poll3');
|
|
207
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
208
|
+
status: 200,
|
|
209
|
+
statusText: 'OK',
|
|
210
|
+
data: JSON.stringify(mockDoc),
|
|
211
|
+
headers: new Map(),
|
|
212
|
+
});
|
|
213
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
214
|
+
source = new RemoteDocumentationSource({
|
|
215
|
+
url: 'https://example.com/docs.json',
|
|
216
|
+
timeout: 5000,
|
|
217
|
+
maxRetries: 3,
|
|
218
|
+
pollingInterval: 10000,
|
|
219
|
+
});
|
|
220
|
+
await source.load();
|
|
221
|
+
mockFetch.mockClear();
|
|
222
|
+
source.startMonitoring();
|
|
223
|
+
// Advance time and verify polling happens
|
|
224
|
+
jest.advanceTimersByTime(10000);
|
|
225
|
+
await Promise.resolve();
|
|
226
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
227
|
+
// Stop monitoring
|
|
228
|
+
await source.stopMonitoring();
|
|
229
|
+
mockFetch.mockClear();
|
|
230
|
+
// Advance time again - should not poll
|
|
231
|
+
jest.advanceTimersByTime(10000);
|
|
232
|
+
await Promise.resolve();
|
|
233
|
+
expect(mockFetch).not.toHaveBeenCalled();
|
|
234
|
+
jest.useRealTimers();
|
|
235
|
+
});
|
|
236
|
+
it('should invoke onReload callback when polling detects changes', async () => {
|
|
237
|
+
jest.useFakeTimers();
|
|
238
|
+
const mockDoc1 = createMockDocumentation('v1');
|
|
239
|
+
const mockDoc2 = createMockDocumentation('v2');
|
|
240
|
+
let callCount = 0;
|
|
241
|
+
const mockFetch = jest.fn().mockImplementation(() => {
|
|
242
|
+
callCount++;
|
|
243
|
+
return Promise.resolve({
|
|
244
|
+
status: 200,
|
|
245
|
+
statusText: 'OK',
|
|
246
|
+
data: JSON.stringify(callCount === 1 ? mockDoc1 : mockDoc2),
|
|
247
|
+
headers: new Map(),
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
251
|
+
const onReloadSpy = jest.fn();
|
|
252
|
+
source = new RemoteDocumentationSource({
|
|
253
|
+
url: 'https://example.com/docs.json',
|
|
254
|
+
timeout: 5000,
|
|
255
|
+
maxRetries: 3,
|
|
256
|
+
pollingInterval: 10000,
|
|
257
|
+
onReload: onReloadSpy,
|
|
258
|
+
});
|
|
259
|
+
await source.load();
|
|
260
|
+
expect(onReloadSpy).not.toHaveBeenCalled(); // Not called on initial load
|
|
261
|
+
source.startMonitoring();
|
|
262
|
+
// Advance time to trigger poll
|
|
263
|
+
jest.advanceTimersByTime(10000);
|
|
264
|
+
await Promise.resolve();
|
|
265
|
+
expect(onReloadSpy).toHaveBeenCalledTimes(1);
|
|
266
|
+
expect(onReloadSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
267
|
+
components: expect.arrayContaining([
|
|
268
|
+
expect.objectContaining({ name: 'Componentv2' })
|
|
269
|
+
])
|
|
270
|
+
}));
|
|
271
|
+
jest.useRealTimers();
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
describe('304 Not Modified Response Handling (Requirement 8.4)', () => {
|
|
275
|
+
it('should use cached data when server returns 304', async () => {
|
|
276
|
+
const mockDoc = createMockDocumentation('cached');
|
|
277
|
+
const headers = new Map();
|
|
278
|
+
headers.set('ETag', '"version1"');
|
|
279
|
+
const mockFetch = jest.fn()
|
|
280
|
+
.mockResolvedValueOnce({
|
|
281
|
+
status: 200,
|
|
282
|
+
statusText: 'OK',
|
|
283
|
+
data: JSON.stringify(mockDoc),
|
|
284
|
+
headers,
|
|
285
|
+
})
|
|
286
|
+
.mockResolvedValueOnce({
|
|
287
|
+
status: 304,
|
|
288
|
+
statusText: 'Not Modified',
|
|
289
|
+
data: '',
|
|
290
|
+
headers: new Map(),
|
|
291
|
+
});
|
|
292
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
293
|
+
source = new RemoteDocumentationSource({
|
|
294
|
+
url: 'https://example.com/docs.json',
|
|
295
|
+
timeout: 5000,
|
|
296
|
+
maxRetries: 3,
|
|
297
|
+
pollingInterval: 60000,
|
|
298
|
+
});
|
|
299
|
+
// First load
|
|
300
|
+
const result1 = await source.load();
|
|
301
|
+
expect(result1.success).toBe(true);
|
|
302
|
+
expect(result1.data?.components[0].name).toBe('Componentcached');
|
|
303
|
+
// Second load with 304
|
|
304
|
+
const result2 = await source.load();
|
|
305
|
+
expect(result2.success).toBe(true);
|
|
306
|
+
expect(result2.data?.components[0].name).toBe('Componentcached');
|
|
307
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
308
|
+
});
|
|
309
|
+
it('should not invoke onReload callback when polling returns 304', async () => {
|
|
310
|
+
jest.useFakeTimers();
|
|
311
|
+
const mockDoc = createMockDocumentation('unchanged');
|
|
312
|
+
const headers = new Map();
|
|
313
|
+
headers.set('ETag', '"same"');
|
|
314
|
+
const mockFetch = jest.fn()
|
|
315
|
+
.mockResolvedValueOnce({
|
|
316
|
+
status: 200,
|
|
317
|
+
statusText: 'OK',
|
|
318
|
+
data: JSON.stringify(mockDoc),
|
|
319
|
+
headers,
|
|
320
|
+
})
|
|
321
|
+
.mockResolvedValue({
|
|
322
|
+
status: 304,
|
|
323
|
+
statusText: 'Not Modified',
|
|
324
|
+
data: '',
|
|
325
|
+
headers: new Map(),
|
|
326
|
+
});
|
|
327
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
328
|
+
const onReloadSpy = jest.fn();
|
|
329
|
+
source = new RemoteDocumentationSource({
|
|
330
|
+
url: 'https://example.com/docs.json',
|
|
331
|
+
timeout: 5000,
|
|
332
|
+
maxRetries: 3,
|
|
333
|
+
pollingInterval: 10000,
|
|
334
|
+
onReload: onReloadSpy,
|
|
335
|
+
});
|
|
336
|
+
await source.load();
|
|
337
|
+
source.startMonitoring();
|
|
338
|
+
// Advance time to trigger poll
|
|
339
|
+
jest.advanceTimersByTime(10000);
|
|
340
|
+
await Promise.resolve();
|
|
341
|
+
// onReload should not be called for 304
|
|
342
|
+
expect(onReloadSpy).not.toHaveBeenCalled();
|
|
343
|
+
jest.useRealTimers();
|
|
344
|
+
});
|
|
345
|
+
it('should send conditional headers when cache exists', async () => {
|
|
346
|
+
const mockDoc = createMockDocumentation('test');
|
|
347
|
+
const headers = new Map();
|
|
348
|
+
headers.set('ETag', '"etag123"');
|
|
349
|
+
headers.set('Last-Modified', 'Wed, 21 Oct 2015 07:28:00 GMT');
|
|
350
|
+
const mockFetch = jest.fn()
|
|
351
|
+
.mockResolvedValueOnce({
|
|
352
|
+
status: 200,
|
|
353
|
+
statusText: 'OK',
|
|
354
|
+
data: JSON.stringify(mockDoc),
|
|
355
|
+
headers,
|
|
356
|
+
})
|
|
357
|
+
.mockResolvedValueOnce({
|
|
358
|
+
status: 304,
|
|
359
|
+
statusText: 'Not Modified',
|
|
360
|
+
data: '',
|
|
361
|
+
headers: new Map(),
|
|
362
|
+
});
|
|
363
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
364
|
+
source = new RemoteDocumentationSource({
|
|
365
|
+
url: 'https://example.com/docs.json',
|
|
366
|
+
timeout: 5000,
|
|
367
|
+
maxRetries: 3,
|
|
368
|
+
pollingInterval: 60000,
|
|
369
|
+
});
|
|
370
|
+
await source.load();
|
|
371
|
+
await source.load(); // Second load
|
|
372
|
+
// Verify conditional headers were sent on second call
|
|
373
|
+
const calls = mockFetch.mock.calls;
|
|
374
|
+
const conditionalHeaders = calls[1]?.[1];
|
|
375
|
+
expect(conditionalHeaders?.get('If-None-Match')).toBe('"etag123"');
|
|
376
|
+
expect(conditionalHeaders?.get('If-Modified-Since')).toBe('Wed, 21 Oct 2015 07:28:00 GMT');
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
describe('Error Handling During Polling (Requirement 5.4)', () => {
|
|
380
|
+
it('should continue using cached data when polling encounters error', async () => {
|
|
381
|
+
jest.useFakeTimers();
|
|
382
|
+
const mockDoc = createMockDocumentation('stable');
|
|
383
|
+
const mockFetch = jest.fn()
|
|
384
|
+
.mockResolvedValueOnce({
|
|
385
|
+
status: 200,
|
|
386
|
+
statusText: 'OK',
|
|
387
|
+
data: JSON.stringify(mockDoc),
|
|
388
|
+
headers: new Map(),
|
|
389
|
+
})
|
|
390
|
+
.mockRejectedValue(new Error('Network error'));
|
|
391
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
392
|
+
source = new RemoteDocumentationSource({
|
|
393
|
+
url: 'https://example.com/docs.json',
|
|
394
|
+
timeout: 5000,
|
|
395
|
+
maxRetries: 3,
|
|
396
|
+
pollingInterval: 10000,
|
|
397
|
+
});
|
|
398
|
+
await source.load();
|
|
399
|
+
const dataBefore = source.getCurrentData();
|
|
400
|
+
source.startMonitoring();
|
|
401
|
+
// Advance time to trigger poll with error
|
|
402
|
+
jest.advanceTimersByTime(10000);
|
|
403
|
+
await Promise.resolve();
|
|
404
|
+
const dataAfter = source.getCurrentData();
|
|
405
|
+
// Data should remain unchanged
|
|
406
|
+
expect(dataAfter).toEqual(dataBefore);
|
|
407
|
+
expect(dataAfter?.components[0].name).toBe('Componentstable');
|
|
408
|
+
jest.useRealTimers();
|
|
409
|
+
});
|
|
410
|
+
it('should invoke onError callback when polling fails', async () => {
|
|
411
|
+
jest.useFakeTimers();
|
|
412
|
+
const mockDoc = createMockDocumentation('test');
|
|
413
|
+
const networkError = new Error('Connection timeout');
|
|
414
|
+
const mockFetch = jest.fn()
|
|
415
|
+
.mockResolvedValueOnce({
|
|
416
|
+
status: 200,
|
|
417
|
+
statusText: 'OK',
|
|
418
|
+
data: JSON.stringify(mockDoc),
|
|
419
|
+
headers: new Map(),
|
|
420
|
+
})
|
|
421
|
+
.mockRejectedValue(networkError);
|
|
422
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
423
|
+
const onErrorSpy = jest.fn();
|
|
424
|
+
source = new RemoteDocumentationSource({
|
|
425
|
+
url: 'https://example.com/docs.json',
|
|
426
|
+
timeout: 5000,
|
|
427
|
+
maxRetries: 3,
|
|
428
|
+
pollingInterval: 10000,
|
|
429
|
+
onError: onErrorSpy,
|
|
430
|
+
});
|
|
431
|
+
await source.load();
|
|
432
|
+
source.startMonitoring();
|
|
433
|
+
// Advance time to trigger poll with error
|
|
434
|
+
jest.advanceTimersByTime(10000);
|
|
435
|
+
await Promise.resolve();
|
|
436
|
+
expect(onErrorSpy).toHaveBeenCalledTimes(1);
|
|
437
|
+
expect(onErrorSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
438
|
+
message: 'Connection timeout'
|
|
439
|
+
}));
|
|
440
|
+
jest.useRealTimers();
|
|
441
|
+
});
|
|
442
|
+
it('should handle HTTP errors during polling gracefully', async () => {
|
|
443
|
+
jest.useFakeTimers();
|
|
444
|
+
const mockDoc = createMockDocumentation('test');
|
|
445
|
+
const mockFetch = jest.fn()
|
|
446
|
+
.mockResolvedValueOnce({
|
|
447
|
+
status: 200,
|
|
448
|
+
statusText: 'OK',
|
|
449
|
+
data: JSON.stringify(mockDoc),
|
|
450
|
+
headers: new Map(),
|
|
451
|
+
})
|
|
452
|
+
.mockResolvedValue({
|
|
453
|
+
status: 500,
|
|
454
|
+
statusText: 'Internal Server Error',
|
|
455
|
+
data: '',
|
|
456
|
+
headers: new Map(),
|
|
457
|
+
});
|
|
458
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
459
|
+
const onErrorSpy = jest.fn();
|
|
460
|
+
source = new RemoteDocumentationSource({
|
|
461
|
+
url: 'https://example.com/docs.json',
|
|
462
|
+
timeout: 5000,
|
|
463
|
+
maxRetries: 3,
|
|
464
|
+
pollingInterval: 10000,
|
|
465
|
+
onError: onErrorSpy,
|
|
466
|
+
});
|
|
467
|
+
await source.load();
|
|
468
|
+
const dataBefore = source.getCurrentData();
|
|
469
|
+
source.startMonitoring();
|
|
470
|
+
// Advance time to trigger poll
|
|
471
|
+
jest.advanceTimersByTime(10000);
|
|
472
|
+
await Promise.resolve();
|
|
473
|
+
// Should invoke error callback
|
|
474
|
+
expect(onErrorSpy).toHaveBeenCalled();
|
|
475
|
+
// Data should remain unchanged
|
|
476
|
+
expect(source.getCurrentData()).toEqual(dataBefore);
|
|
477
|
+
jest.useRealTimers();
|
|
478
|
+
});
|
|
479
|
+
it('should handle parse errors during polling gracefully', async () => {
|
|
480
|
+
jest.useFakeTimers();
|
|
481
|
+
const mockDoc = createMockDocumentation('test');
|
|
482
|
+
const mockFetch = jest.fn()
|
|
483
|
+
.mockResolvedValueOnce({
|
|
484
|
+
status: 200,
|
|
485
|
+
statusText: 'OK',
|
|
486
|
+
data: JSON.stringify(mockDoc),
|
|
487
|
+
headers: new Map(),
|
|
488
|
+
})
|
|
489
|
+
.mockResolvedValue({
|
|
490
|
+
status: 200,
|
|
491
|
+
statusText: 'OK',
|
|
492
|
+
data: 'invalid json {',
|
|
493
|
+
headers: new Map(),
|
|
494
|
+
});
|
|
495
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
496
|
+
const onErrorSpy = jest.fn();
|
|
497
|
+
source = new RemoteDocumentationSource({
|
|
498
|
+
url: 'https://example.com/docs.json',
|
|
499
|
+
timeout: 5000,
|
|
500
|
+
maxRetries: 3,
|
|
501
|
+
pollingInterval: 10000,
|
|
502
|
+
onError: onErrorSpy,
|
|
503
|
+
});
|
|
504
|
+
await source.load();
|
|
505
|
+
const dataBefore = source.getCurrentData();
|
|
506
|
+
source.startMonitoring();
|
|
507
|
+
// Advance time to trigger poll
|
|
508
|
+
jest.advanceTimersByTime(10000);
|
|
509
|
+
await Promise.resolve();
|
|
510
|
+
// Should invoke error callback
|
|
511
|
+
expect(onErrorSpy).toHaveBeenCalled();
|
|
512
|
+
// Data should remain unchanged
|
|
513
|
+
expect(source.getCurrentData()).toEqual(dataBefore);
|
|
514
|
+
jest.useRealTimers();
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
describe('Cleanup on Dispose (Requirement 5.5, 8.5)', () => {
|
|
518
|
+
it('should stop polling when dispose is called', async () => {
|
|
519
|
+
jest.useFakeTimers();
|
|
520
|
+
const mockDoc = createMockDocumentation('test');
|
|
521
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
522
|
+
status: 200,
|
|
523
|
+
statusText: 'OK',
|
|
524
|
+
data: JSON.stringify(mockDoc),
|
|
525
|
+
headers: new Map(),
|
|
526
|
+
});
|
|
527
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
528
|
+
source = new RemoteDocumentationSource({
|
|
529
|
+
url: 'https://example.com/docs.json',
|
|
530
|
+
timeout: 5000,
|
|
531
|
+
maxRetries: 3,
|
|
532
|
+
pollingInterval: 10000,
|
|
533
|
+
});
|
|
534
|
+
await source.load();
|
|
535
|
+
mockFetch.mockClear();
|
|
536
|
+
source.startMonitoring();
|
|
537
|
+
await source.dispose();
|
|
538
|
+
// Advance time - should not poll
|
|
539
|
+
jest.advanceTimersByTime(10000);
|
|
540
|
+
await Promise.resolve();
|
|
541
|
+
expect(mockFetch).not.toHaveBeenCalled();
|
|
542
|
+
jest.useRealTimers();
|
|
543
|
+
});
|
|
544
|
+
it('should clear cached data when dispose is called', async () => {
|
|
545
|
+
const mockDoc = createMockDocumentation('test');
|
|
546
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
547
|
+
status: 200,
|
|
548
|
+
statusText: 'OK',
|
|
549
|
+
data: JSON.stringify(mockDoc),
|
|
550
|
+
headers: new Map(),
|
|
551
|
+
});
|
|
552
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
553
|
+
source = new RemoteDocumentationSource({
|
|
554
|
+
url: 'https://example.com/docs.json',
|
|
555
|
+
timeout: 5000,
|
|
556
|
+
maxRetries: 3,
|
|
557
|
+
pollingInterval: 60000,
|
|
558
|
+
});
|
|
559
|
+
await source.load();
|
|
560
|
+
expect(source.getCurrentData()).toBeDefined();
|
|
561
|
+
await source.dispose();
|
|
562
|
+
expect(source.getCurrentData()).toBeUndefined();
|
|
563
|
+
});
|
|
564
|
+
it('should clear callbacks when dispose is called', async () => {
|
|
565
|
+
jest.useFakeTimers();
|
|
566
|
+
const mockDoc = createMockDocumentation('test');
|
|
567
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
568
|
+
status: 200,
|
|
569
|
+
statusText: 'OK',
|
|
570
|
+
data: JSON.stringify(mockDoc),
|
|
571
|
+
headers: new Map(),
|
|
572
|
+
});
|
|
573
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
574
|
+
const onReloadSpy = jest.fn();
|
|
575
|
+
const onErrorSpy = jest.fn();
|
|
576
|
+
source = new RemoteDocumentationSource({
|
|
577
|
+
url: 'https://example.com/docs.json',
|
|
578
|
+
timeout: 5000,
|
|
579
|
+
maxRetries: 3,
|
|
580
|
+
pollingInterval: 10000,
|
|
581
|
+
onReload: onReloadSpy,
|
|
582
|
+
onError: onErrorSpy,
|
|
583
|
+
});
|
|
584
|
+
await source.load();
|
|
585
|
+
await source.dispose();
|
|
586
|
+
// Callbacks should be cleared and not invoked
|
|
587
|
+
// This is verified by the fact that dispose clears the callbacks
|
|
588
|
+
expect(onReloadSpy).not.toHaveBeenCalled();
|
|
589
|
+
expect(onErrorSpy).not.toHaveBeenCalled();
|
|
590
|
+
jest.useRealTimers();
|
|
591
|
+
});
|
|
592
|
+
it('should handle dispose when not monitoring', async () => {
|
|
593
|
+
const mockDoc = createMockDocumentation('test');
|
|
594
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
595
|
+
status: 200,
|
|
596
|
+
statusText: 'OK',
|
|
597
|
+
data: JSON.stringify(mockDoc),
|
|
598
|
+
headers: new Map(),
|
|
599
|
+
});
|
|
600
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
601
|
+
source = new RemoteDocumentationSource({
|
|
602
|
+
url: 'https://example.com/docs.json',
|
|
603
|
+
timeout: 5000,
|
|
604
|
+
maxRetries: 3,
|
|
605
|
+
pollingInterval: 60000,
|
|
606
|
+
});
|
|
607
|
+
await source.load();
|
|
608
|
+
// Dispose without starting monitoring
|
|
609
|
+
await expect(source.dispose()).resolves.not.toThrow();
|
|
610
|
+
});
|
|
611
|
+
it('should handle multiple dispose calls gracefully', async () => {
|
|
612
|
+
const mockDoc = createMockDocumentation('test');
|
|
613
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
614
|
+
status: 200,
|
|
615
|
+
statusText: 'OK',
|
|
616
|
+
data: JSON.stringify(mockDoc),
|
|
617
|
+
headers: new Map(),
|
|
618
|
+
});
|
|
619
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
620
|
+
source = new RemoteDocumentationSource({
|
|
621
|
+
url: 'https://example.com/docs.json',
|
|
622
|
+
timeout: 5000,
|
|
623
|
+
maxRetries: 3,
|
|
624
|
+
pollingInterval: 60000,
|
|
625
|
+
});
|
|
626
|
+
await source.load();
|
|
627
|
+
await source.dispose();
|
|
628
|
+
// Second dispose should not throw
|
|
629
|
+
await expect(source.dispose()).resolves.not.toThrow();
|
|
630
|
+
});
|
|
631
|
+
});
|
|
632
|
+
describe('Error Scenarios', () => {
|
|
633
|
+
it('should return error for non-200 status codes', async () => {
|
|
634
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
635
|
+
status: 404,
|
|
636
|
+
statusText: 'Not Found',
|
|
637
|
+
data: '',
|
|
638
|
+
headers: new Map(),
|
|
639
|
+
});
|
|
640
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
641
|
+
source = new RemoteDocumentationSource({
|
|
642
|
+
url: 'https://example.com/docs.json',
|
|
643
|
+
timeout: 5000,
|
|
644
|
+
maxRetries: 3,
|
|
645
|
+
pollingInterval: 60000,
|
|
646
|
+
});
|
|
647
|
+
const result = await source.load();
|
|
648
|
+
expect(result.success).toBe(false);
|
|
649
|
+
expect(result.error).toBeDefined();
|
|
650
|
+
expect(result.error).toContain('404');
|
|
651
|
+
});
|
|
652
|
+
it('should return error for invalid JSON', async () => {
|
|
653
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
654
|
+
status: 200,
|
|
655
|
+
statusText: 'OK',
|
|
656
|
+
data: 'not valid json {',
|
|
657
|
+
headers: new Map(),
|
|
658
|
+
});
|
|
659
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
660
|
+
source = new RemoteDocumentationSource({
|
|
661
|
+
url: 'https://example.com/docs.json',
|
|
662
|
+
timeout: 5000,
|
|
663
|
+
maxRetries: 3,
|
|
664
|
+
pollingInterval: 60000,
|
|
665
|
+
});
|
|
666
|
+
const result = await source.load();
|
|
667
|
+
expect(result.success).toBe(false);
|
|
668
|
+
expect(result.error).toBeDefined();
|
|
669
|
+
expect(result.error).toMatch(/parse|json/i);
|
|
670
|
+
});
|
|
671
|
+
it('should return error for invalid documentation structure', async () => {
|
|
672
|
+
const invalidDoc = { components: 'not an array' };
|
|
673
|
+
const mockFetch = jest.fn().mockResolvedValue({
|
|
674
|
+
status: 200,
|
|
675
|
+
statusText: 'OK',
|
|
676
|
+
data: JSON.stringify(invalidDoc),
|
|
677
|
+
headers: new Map(),
|
|
678
|
+
});
|
|
679
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
680
|
+
source = new RemoteDocumentationSource({
|
|
681
|
+
url: 'https://example.com/docs.json',
|
|
682
|
+
timeout: 5000,
|
|
683
|
+
maxRetries: 3,
|
|
684
|
+
pollingInterval: 60000,
|
|
685
|
+
});
|
|
686
|
+
const result = await source.load();
|
|
687
|
+
expect(result.success).toBe(false);
|
|
688
|
+
expect(result.error).toBeDefined();
|
|
689
|
+
expect(result.error).toMatch(/must be an array/i);
|
|
690
|
+
});
|
|
691
|
+
it('should return error for network failures', async () => {
|
|
692
|
+
const mockFetch = jest.fn().mockRejectedValue(new Error('Network connection failed'));
|
|
693
|
+
HttpClient.prototype.fetch = mockFetch;
|
|
694
|
+
source = new RemoteDocumentationSource({
|
|
695
|
+
url: 'https://example.com/docs.json',
|
|
696
|
+
timeout: 5000,
|
|
697
|
+
maxRetries: 3,
|
|
698
|
+
pollingInterval: 60000,
|
|
699
|
+
});
|
|
700
|
+
const result = await source.load();
|
|
701
|
+
expect(result.success).toBe(false);
|
|
702
|
+
expect(result.error).toBeDefined();
|
|
703
|
+
expect(result.error).toContain('Network connection failed');
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
});
|
|
707
|
+
//# sourceMappingURL=remote-documentation-source.test.js.map
|