This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/main/pr-6602-2a152549ed68c726ad1ab44925b9bc04e7f38c04
in repository https://gitbox.apache.org/repos/asf/texera.git

commit dabc562888e1dfd16c4668089ebe2e42b0c1438d
Author: Meng Wang <[email protected]>
AuthorDate: Mon Jul 20 12:11:18 2026 -0700

    test(frontend): extend OperatorMetadataService unit test coverage (#6602)
    
    ### What changes were proposed in this PR?
    
    Extends the existing Vitest spec for `OperatorMetadataService`
    
    
(`frontend/src/app/workspace/service/operator-metadata/operator-metadata.service.ts`,
    codecov ~56%). The service fetches operator metadata once over HTTP
    (cached via
    `shareReplay`) and serves lookups from it; the existing spec only
    lightly
    touched this. Adds 8 tests using `HttpClientTestingModule`, each
    flushing the
    metadata GET with the `mockOperatorMetaData` fixture. No production code
    changed.
    
    - **`getOperatorMetadata`** — emits the fetched metadata to subscribers.
    - **`getOperatorSchema`** — returns the matching `OperatorSchema` for a
    known
    type; throws for an unknown type; throws "operator metadata is
    undefined"
      before the request resolves.
    - **`operatorTypeExists`** — `true` for a fetched type, `false` for an
    unknown
    one and before the request resolves; matches the user-friendly name only
    when
    that filter is enabled; honors case-insensitive matching when requested.
    
    ### Any related issues, documentation, discussions?
    
    Closes #6592
    
    ### How was this PR tested?
    
    Extended unit tests, run locally in `frontend/` (all green; the failure
    path was
    verified by breaking an assertion to confirm the suite goes red):
    
    ```
    ng test --watch=false --include 
src/app/workspace/service/operator-metadata/operator-metadata.service.spec.ts
    # Tests  11 passed (11)   (3 existing + 8 new)
    eslint <spec>       # clean
    prettier --check    # clean
    ```
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Opus 4.8 [1M context])
---
 .../operator-metadata.service.spec.ts              | 62 +++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git 
a/frontend/src/app/workspace/service/operator-metadata/operator-metadata.service.spec.ts
 
b/frontend/src/app/workspace/service/operator-metadata/operator-metadata.service.spec.ts
index 901c99bf6a..7b57e3aa2e 100644
--- 
a/frontend/src/app/workspace/service/operator-metadata/operator-metadata.service.spec.ts
+++ 
b/frontend/src/app/workspace/service/operator-metadata/operator-metadata.service.spec.ts
@@ -20,9 +20,11 @@
 import { TestBed } from "@angular/core/testing";
 import { HttpClient } from "@angular/common/http";
 import { HttpClientTestingModule, HttpTestingController } from 
"@angular/common/http/testing";
-import { OperatorMetadataService } from "./operator-metadata.service";
+import { OPERATOR_METADATA_ENDPOINT, OperatorMetadataService } from 
"./operator-metadata.service";
 import { mockOperatorMetaData } from "./mock-operator-metadata.data";
 import { commonTestProviders } from "../../../common/testing/test-utils";
+import { AppSettings } from "../../../common/app-setting";
+import type { OperatorMetadata } from "../../types/operator-schema.interface";
 
 describe("OperatorMetadataService", () => {
   let service: OperatorMetadataService;
@@ -57,4 +59,62 @@ describe("OperatorMetadataService", () => {
     const req = httpTestingController.match(request => request.method === 
"GET");
     req[0].flush(mockOperatorMetaData);
   });
+
+  const metadataUrl = 
`${AppSettings.getApiEndpoint()}/${OPERATOR_METADATA_ENDPOINT}`;
+
+  // The service fetches metadata once in its constructor (shareReplay), so a 
single
+  // request is pending after injection; flush it with the fixture.
+  const flushMetadata = () =>
+    httpTestingController.expectOne(req => req.method === "GET" && req.url === 
metadataUrl).flush(mockOperatorMetaData);
+
+  it("getOperatorMetadata emits the fetched metadata to subscribers", () => {
+    let emitted: OperatorMetadata | undefined;
+    service.getOperatorMetadata().subscribe(m => (emitted = m));
+    flushMetadata();
+    expect(emitted).toEqual(mockOperatorMetaData);
+  });
+
+  it("getOperatorSchema returns the schema for a known operator type", () => {
+    flushMetadata();
+    const schema = service.getOperatorSchema("ScanSource");
+    expect(schema.operatorType).toBe("ScanSource");
+    expect(schema).toEqual(mockOperatorMetaData.operators.find(op => 
op.operatorType === "ScanSource"));
+  });
+
+  it("getOperatorSchema throws for an unknown operator type", () => {
+    flushMetadata();
+    expect(() => service.getOperatorSchema("NoSuchOperator")).toThrow(
+      "can't find operator schema of type NoSuchOperator"
+    );
+  });
+
+  it("getOperatorSchema throws when the metadata has not been fetched yet", () 
=> {
+    // do not flush: the constructor's request is still pending, so metadata 
is undefined
+    expect(() => service.getOperatorSchema("ScanSource")).toThrow("operator 
metadata is undefined");
+    flushMetadata(); // drain the pending request
+  });
+
+  it("operatorTypeExists is true for a fetched type and false for an unknown 
one", () => {
+    flushMetadata();
+    expect(service.operatorTypeExists("ScanSource")).toBe(true);
+    expect(service.operatorTypeExists("NoSuchOperator")).toBe(false);
+  });
+
+  it("operatorTypeExists is false before the metadata request resolves", () => 
{
+    expect(service.operatorTypeExists("ScanSource")).toBe(false);
+    flushMetadata();
+  });
+
+  it("operatorTypeExists matches the user-friendly name only when that filter 
is enabled", () => {
+    flushMetadata();
+    // ScanSource's userFriendlyName is "Source: Scan"
+    expect(service.operatorTypeExists("Source: Scan", true)).toBe(true);
+    expect(service.operatorTypeExists("Source: Scan", false)).toBe(false);
+  });
+
+  it("operatorTypeExists honors case-insensitive matching when requested", () 
=> {
+    flushMetadata();
+    expect(service.operatorTypeExists("scansource", false, true)).toBe(true);
+    expect(service.operatorTypeExists("scansource", false, false)).toBe(false);
+  });
 });

Reply via email to