Repository navigation
test: add unit tests to improve coverage for 9 core packages - #11855
Open
pranesh-sridhar wants to merge 7 commits into
Open
pranesh-sridhar wants to merge 7 commits into
pranesh-sridhar wants to merge 7 commits into
Conversation
- Interceptor: invoke voter functions declared directly in the @authorize metadata, for both allow and deny decisions - @authorize: throws when applied to a property Statement, function and line coverage of the package is now 100%. Signed-off-by: Pranesh Sridhar <68075088+pranesh-sridhar@users.noreply.github.com>
…configure Cover the guard for applications without mountExpressRouter, option merging with defaults, and appPath resolution. Signed-off-by: Pranesh Sridhar <68075088+pranesh-sridhar@users.noreply.github.com>
…ixin bindings - ModelBooter: default and custom options, binding of model classes - ModelApiBooter: getApiBuilderForPattern lookup and error messages - BaseArtifactBooter: artifactName, empty dirs/extensions, discover with and without debug logging - Bootstrapper: reuse booter instances when a context is passed to boot() - BootMixin: PROJECT_ROOT and BOOT_OPTIONS dynamic bindings Signed-off-by: Pranesh Sridhar <68075088+pranesh-sridhar@users.noreply.github.com>
…tion and interceptors Add unit tests for code paths that were not covered by the existing suites: - Binding: refresh without cache, unconfigured bindings, server scope resolution failures, once() - ContextView: singleValue(), open() reuse, once() - Context: findByTag with unknown or intersecting tags, observer subscribe/unsubscribe/close edge cases - Injection: hasInjections, inspectInjections, @inject.setter and @inject.binding rejecting binding filters, @config.getter/@config.view without a current binding - Interceptors: stacked @intercept on classes and methods, registering provider classes and grouped global interceptors, interception proxy - InvocationContext.toString(), invokeMethod with skipInterceptors, BindingKey.validate, isBindingAddress, uuid Signed-off-by: Pranesh Sridhar <68075088+pranesh-sridhar@users.noreply.github.com>
…d invoke provider - ExpressServer: basePath normalization, Express settings, listening and url lifecycle, serving under basePath, parent context - toMiddleware and invokeExpressMiddleware: single/chained handlers and the empty-handler error - getMiddlewareContext: missing request and bound context - MiddlewareMixin: non-Context super class and empty handler list - MiddlewareView: group ordering, refresh, validate callback, debug logging - InvokeMiddlewareProvider: handler arrays, default and custom chains - sortListOfGroups: debug logging and short group lists Signed-off-by: Pranesh Sridhar <68075088+pranesh-sridhar@users.noreply.github.com>
Add unit tests to cover code paths in `@loopback/core` and `@loopback/metadata` that the existing suites did not exercise. Coverage was measured with `nyc` over each package's `dist/` output. Only test files are changed; there are no source changes. `@loopback/authentication` is covered in loopbackio#11853. `@loopback/authorization`, `boot`, `booter-lb3app`, `context`, and `express` are covered in loopbackio#11854. | Package | Tests before | Tests after | Stmts before | Stmts after | |---|---|---|---|---| | `core` | 346 | 355 | 95.47% | 98.74% | | `metadata` | 162 | 171 | 96.18% | 98.09% | ### Tests added **`@loopback/core`** - `application-lifecycle.unit.ts`: `assertInStates()` — throws when the application is not in the expected state; does not throw when it is - `application.unit.ts`: `setMetadata()` — stores metadata under `CoreBindings.APPLICATION_METADATA`; overwrites on a second call - `component.unit.ts`: `mountComponent()` self-reference guard — skips a component instance placed directly in its own `components` array - `lifecycle-registry.unit.ts`: `getObserverGroupsByOrder()` — debug logging branch exercised by enabling the `loopback:core:lifecycle` namespace temporarily - `service.unit.ts`: `@service()` without design-time type metadata — throws "No design-time type metadata found" when `design:type` is absent; `createServiceBinding()` with a `DynamicValueProvider` class — trims the `Provider` suffix from the name; preserves a custom name **`@loopback/metadata`** - `decorator-factory.unit.ts`: Base-class abstract-method guards — `mergeWithInherited()`, `mergeWithOwn()`, and `create()` each throw "not implemented" when the subclass does not override them; `getTarget()` returns `undefined` for non-object specs; `MethodMultiDecoratorFactory` `mergeWithOwn` exercised on a standalone class with no base - `inspector.unit.ts`: `MetadataInspector.defineMetadata()` — stores and overwrites class-level metadata; `getMethodMetadata()` with `methodName` omitted defaults to the constructor key ### Verification All tests pass (`npm test` per package, `lb-tsc` build + `lb-mocha`). ESLint (`--report-unused-disable-directives`) and Prettier clean on all changed files. Signed-off-by: Pranesh Sridhar <Pranesh.Sridhar@ibm.com>
Packages covered and coverage improvements: | Package | Stmts before | Stmts after | Branches before | Branches after | |---|---|---|---|---| | model-api-builder | 0% (no tests) | 100% | 0% | 100% | | http-caching-proxy | 93.84% | 98.46% | 55.55% | 94.44% | | openapi-spec-builder | 88.60% | 100% | 72.13% | 100% | | rest-crud | 68.23% | 100% | 50% | 83.33% | | filter | 96.83% | 99.36% | 87.09% | 96.77% | | repository-json-schema | 95.48% | 98.87% | 92% | 94.66% | | repository (types) | object 68%, buffer 95% br | 100% | 75%/95% | 100% | | rest | redirect-route 71% | 100% stmts/lines | various | improved | | tsdocs | 86.39% | 88.43% | 57.62% | 62.71% | Tests added: - model-api-builder: asModelApiBuilder binding template, MODEL_API_BUILDER_PLUGINS constant - http-caching-proxy: constructor, stop() no-op, logError branches (true/false, error.stack vs error), non-ENOENT cache corruption integration test - openapi-spec-builder: withOperationReturningString, withRequestBody, withStringResponse default, OperationSpecBuilder/ComponentsSpecBuilder accumulation (??= branches), setupOperationId idempotency - rest-crud: CrudRestComponent binding, CrudRestApiBuilder.build() — missing basePath, non-Entity model, repo absent/present, readonly flag - filter: WhereBuilder.impose and FilterBuilder.impose with falsy internal state (defensive branch coverage) - repository-json-schema: getNavigationalPropertyForRelation targetsMany=false and =true, getJsonSchema with belongsTo keyFrom, multiple indexed properties - repository: BufferType.coerce with explicit options, ObjectType.coerce already-instance and invalid values, ObjectType.serialize toJSON/no-toJSON - rest: RedirectRoute.isRedirectRoute, describe, updateBindings, invokeHandler; RoutingTable.find throws NotFound; InfoSpecEnhancer.modifySpec with null pkg, overrideInfo flag, string/object/null author parsing - tsdocs: getUnscopedPackageName unscoped name, invokeExtractorForPackage silent:false logging branch Only test files are changed (plus model-api-builder package.json/tsconfig.json to wire up the test script and devDependencies, as no tests existed before). Signed-off-by: Pranesh Ravi <pranesh.ravi@ibm.com>
pranesh-sridhar
requested review from
nabdelgadir and
raymondfeng
as code owners
October 22, 2026 13:48
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add unit tests to cover code paths in nine core packages that the existing suites did not exercise. Gaps were identified from measured
nyccoverage of each package'sdist/output. Only test files are changed (plusmodel-api-builder'spackage.jsonandtsconfig.jsonto wire up the test script and devDependencies, as no tests existed there at all).Coverage summary
model-api-builderhttp-caching-proxyopenapi-spec-builderrest-crudfilterrepository-json-schemarepository(types)object.ts68%,buffer.ts95% brrestredirect-route71% stmtstsdocsTests added
asModelApiBuilderbinding template (extensionFor tag, namespace tag, tagNames, key unchanged),MODEL_API_BUILDER_PLUGINSconstantstop()no-op when not running,logError()withlogError:true/false,error.stackpresent/absent branches; integration test for non-ENOENT cache corruption (EINTEGRITY) falling back to backendwithOperationReturningStringwith and without operationName,withOperationaccepting anOperationSpecBuilder,withComponentsaccepting aComponentsSpecBuilder,withComponentsidempotency (??=),withRequestBody,withStringResponsedefault status,setupOperationIdnot overwriting an existing id, all nineComponentsSpecBuildermethods called twice to hit the??=already-initialised branchCrudRestComponentregisters binding;CrudRestApiBuilder.build()— missing basePath error, non-Entity model error, creates repo+controller when absent, reuses existing repo binding, registers readonly controllerWhereBuilder.imposeandFilterBuilder.imposewith falsy internal state (defensive!this.where/!this.filterbranches that are unreachable via the public API but reachable via direct property mutation)getNavigationalPropertyForRelationwithtargetsMany:false(returns targetRef) andtargetsMany:true(returns array);getJsonSchemawithincludeRelations:trueon abelongsTorelation (covers thekeyFromforeign-key branch); model with two indexed properties (covers the indexInfo merge path)BufferType.coercewith explicit encoding options (covers theoptions ?? {}non-null branch);ObjectType.coercefor already-correct-type instance, primitive, array;ObjectType.serializewithtoJSON, withouttoJSON, and null/undefinedRedirectRoute.isRedirectRoute— true, false (no targetLocation), false (wrong description), null, undefined;describe(),updateBindings()no-op,invokeHandler()callsresponse.redirect;RoutingTable.findthrows NotFound without external routes;InfoSpecEnhancer.modifySpec— null pkg skip, override-info path, keep-existing path;parseAuthorwith string, object, and null authorgetUnscopedPackageNamewith unscoped name (no@prefix);runExtractorForPackagewithsilent:false(covers theconsole.log('> %s', pkg.name)branch)Only test files are changed; there are no source changes.
Checklist
npm testpasses on your machine (ran each affected package's build and tests; lint-staged ran Prettier + ESLint clean on all changed files; full monoreponpm testnot run)packages/cliwere updated (n/a)examples/*were updated (n/a)