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-6681-d3aa22e93fecce420595f7b999be60a2bc2ea924
in repository https://gitbox.apache.org/repos/asf/texera.git

commit f3cc2ddc4380684e0ce3aa0122c23f439f9355c9
Author: Matthew B. <[email protected]>
AuthorDate: Tue Jul 21 19:12:33 2026 -0700

    test(frontend): cover searchTestEntries (#6681)
    
    ### What changes were proposed in this PR?
    - Append a describe block to search-filter-parameters.spec.ts covering
    searchTestEntries.
    - Build DashboardEntry fixtures and assert keyword, date-range, owner,
    id, operator, projectId, and resource-type filtering including
    sequential combination.
    ### Any related issues, documentation, discussions?
    Closes: #6680
    ### How was this PR tested?
    - Run: `cd frontend && node --max-old-space-size=8192
    ./node_modules/nx/dist/bin/nx.js test gui --watch=false
    --include=src/app/dashboard/type/search-filter-parameters.spec.ts`,
    expect the suite passing.
    - Test-only change; no production code is modified.
    ### Was this PR authored or co-authored using generative AI tooling?
    Co-authored with Claude Opus 4.8 in compliance with ASF
---
 .../type/search-filter-parameters.spec.ts          | 222 ++++++++++++++++++++-
 1 file changed, 221 insertions(+), 1 deletion(-)

diff --git a/frontend/src/app/dashboard/type/search-filter-parameters.spec.ts 
b/frontend/src/app/dashboard/type/search-filter-parameters.spec.ts
index b30ec3b571..fcf1250f93 100644
--- a/frontend/src/app/dashboard/type/search-filter-parameters.spec.ts
+++ b/frontend/src/app/dashboard/type/search-filter-parameters.spec.ts
@@ -17,8 +17,13 @@
  * under the License.
  */
 
-import { SearchFilterParameters, toQueryStrings } from 
"./search-filter-parameters";
+import { searchTestEntries, SearchFilterParameters, toQueryStrings } from 
"./search-filter-parameters";
 import { SortMethod } from "./sort-method";
+import { DashboardEntry } from "./dashboard-entry";
+import { DashboardWorkflow } from "./dashboard-workflow.interface";
+import { DashboardDataset } from "./dashboard-dataset.interface";
+import { ExecutionMode } from "../../common/type/workflow";
+import { OperatorPredicate } from 
"../../workspace/types/workflow-common.interface";
 
 function makeEmptyFilter(): SearchFilterParameters {
   return {
@@ -161,3 +166,218 @@ describe("toQueryStrings", () => {
     expect(toQueryStrings(["alpha"], filter)).toBe("query=alpha&owner=alice");
   });
 });
+
+// Fixtures for searchTestEntries. Dates are built with local-time 
constructors so
+// endOfDay() (which uses local getHours/setHours) is deterministic in every 
timezone.
+interface WorkflowEntryOverrides {
+  name?: string;
+  wid?: number;
+  ownerName?: string;
+  creationTime?: number;
+  lastModifiedTime?: number;
+  operatorTypes?: string[];
+  projectIDs?: number[];
+}
+
+function makeWorkflowEntry(overrides: WorkflowEntryOverrides = {}): 
DashboardEntry {
+  const operators = (overrides.operatorTypes ?? []).map(
+    (operatorType, i) => ({ operatorID: `op${i}`, operatorType }) as unknown 
as OperatorPredicate
+  );
+  const workflow: DashboardWorkflow = {
+    isOwner: true,
+    ownerName: overrides.ownerName ?? "alice",
+    workflow: {
+      content: {
+        operators,
+        operatorPositions: {},
+        links: [],
+        commentBoxes: [],
+        settings: {
+          dataTransferBatchSize: 400,
+          executionMode: ExecutionMode.PIPELINED,
+        },
+      },
+      name: overrides.name ?? "workflow",
+      description: "",
+      wid: overrides.wid ?? 1,
+      creationTime: overrides.creationTime,
+      lastModifiedTime: overrides.lastModifiedTime,
+      isPublished: 0,
+      readonly: false,
+    },
+    projectIDs: overrides.projectIDs ?? [],
+    accessLevel: "WRITE",
+    ownerId: 10,
+    coverImage: null,
+  };
+  return new DashboardEntry(workflow);
+}
+
+function makeDatasetEntry(name = "dataset"): DashboardEntry {
+  const dataset: DashboardDataset = {
+    isOwner: false,
+    ownerEmail: "[email protected]",
+    dataset: {
+      did: 404,
+      ownerUid: 40,
+      name,
+      isPublic: true,
+      isDownloadable: true,
+      storagePath: "/datasets/404",
+      description: "",
+      creationTime: new Date(2024, 0, 15, 12).getTime(),
+      coverImage: "",
+    },
+    accessPrivilege: "READ",
+    size: 100,
+  };
+  return new DashboardEntry(dataset);
+}
+
+describe("searchTestEntries", () => {
+  it("returns all entries untouched when nothing is constraining", () => {
+    const entries = [makeWorkflowEntry({ name: "alpha" }), makeWorkflowEntry({ 
name: "beta" })];
+    expect(searchTestEntries([], makeEmptyFilter(), entries, 
null)).toEqual(entries);
+  });
+
+  it("keeps only entries whose name contains a keyword substring", () => {
+    const alpha = makeWorkflowEntry({ name: "alpha-report" });
+    const beta = makeWorkflowEntry({ name: "beta-report" });
+    const result = searchTestEntries(["alph"], makeEmptyFilter(), [alpha, 
beta], null);
+    expect(result).toEqual([alpha]);
+  });
+
+  it("matches when any of several keywords is a substring", () => {
+    const alpha = makeWorkflowEntry({ name: "alpha" });
+    const beta = makeWorkflowEntry({ name: "beta" });
+    const gamma = makeWorkflowEntry({ name: "gamma" });
+    const result = searchTestEntries(["alp", "bet"], makeEmptyFilter(), 
[alpha, beta, gamma], null);
+    expect(result).toEqual([alpha, beta]);
+  });
+
+  it("filters by createDateStart, keeping entries created on or after the 
start", () => {
+    const before = makeWorkflowEntry({ name: "before", creationTime: new 
Date(2024, 0, 9, 12).getTime() });
+    const onOrAfter = makeWorkflowEntry({ name: "after", creationTime: new 
Date(2024, 0, 11, 12).getTime() });
+    const filter = makeEmptyFilter();
+    filter.createDateStart = new Date(2024, 0, 10);
+    const result = searchTestEntries([], filter, [before, onOrAfter], null);
+    expect(result).toEqual([onOrAfter]);
+  });
+
+  it("filters by createDateEnd inclusively through the end of that day", () => 
{
+    // Late on the end day must still be included (endOfDay sets 23:59:59.999).
+    const lateSameDay = makeWorkflowEntry({ name: "same", creationTime: new 
Date(2024, 0, 10, 22, 0).getTime() });
+    const nextDay = makeWorkflowEntry({ name: "next", creationTime: new 
Date(2024, 0, 11, 1, 0).getTime() });
+    const filter = makeEmptyFilter();
+    filter.createDateEnd = new Date(2024, 0, 10);
+    const result = searchTestEntries([], filter, [lateSameDay, nextDay], null);
+    expect(result).toEqual([lateSameDay]);
+  });
+
+  it("filters by modifiedDateStart and modifiedDateEnd against 
lastModifiedTime", () => {
+    const stale = makeWorkflowEntry({ name: "stale", lastModifiedTime: new 
Date(2024, 2, 1, 12).getTime() });
+    const inRange = makeWorkflowEntry({ name: "inRange", lastModifiedTime: new 
Date(2024, 2, 15, 12).getTime() });
+    const tooNew = makeWorkflowEntry({ name: "tooNew", lastModifiedTime: new 
Date(2024, 2, 20, 12).getTime() });
+    const filter = makeEmptyFilter();
+    filter.modifiedDateStart = new Date(2024, 2, 10);
+    filter.modifiedDateEnd = new Date(2024, 2, 16);
+    const result = searchTestEntries([], filter, [stale, inRange, tooNew], 
null);
+    expect(result).toEqual([inRange]);
+  });
+
+  it("filters by owner name, matching any listed owner", () => {
+    const alice = makeWorkflowEntry({ name: "a", ownerName: "alice" });
+    const bob = makeWorkflowEntry({ name: "b", ownerName: "bob" });
+    const carol = makeWorkflowEntry({ name: "c", ownerName: "carol" });
+    const filter = makeEmptyFilter();
+    filter.owners = ["alice", "carol"];
+    const result = searchTestEntries([], filter, [alice, bob, carol], null);
+    expect(result).toEqual([alice, carol]);
+  });
+
+  it("filters by workflow id, comparing the wid as a string", () => {
+    const w7 = makeWorkflowEntry({ name: "w7", wid: 7 });
+    const w8 = makeWorkflowEntry({ name: "w8", wid: 8 });
+    const filter = makeEmptyFilter();
+    filter.ids = ["7"];
+    const result = searchTestEntries([], filter, [w7, w8], null);
+    expect(result).toEqual([w7]);
+  });
+
+  it("filters by operator type present in the workflow content", () => {
+    const hasCsv = makeWorkflowEntry({ name: "csv", operatorTypes: 
["CSVFileScan", "Filter"] });
+    const noCsv = makeWorkflowEntry({ name: "noCsv", operatorTypes: 
["PythonUDFV2"] });
+    const filter = makeEmptyFilter();
+    filter.operators = ["CSVFileScan"];
+    const result = searchTestEntries([], filter, [hasCsv, noCsv], null);
+    expect(result).toEqual([hasCsv]);
+  });
+
+  it("filters by projectId membership", () => {
+    const inProject = makeWorkflowEntry({ name: "in", projectIDs: [1, 2] });
+    const notInProject = makeWorkflowEntry({ name: "out", projectIDs: [3] });
+    const filter = makeEmptyFilter();
+    filter.projectIds = [2];
+    const result = searchTestEntries([], filter, [inProject, notInProject], 
null);
+    expect(result).toEqual([inProject]);
+  });
+
+  it("excludes non-workflow entries when a workflow-only filter is applied", 
() => {
+    // owners/ids/operators/projectIds all gate on e.type === "workflow".
+    const workflow = makeWorkflowEntry({ name: "wf", ownerName: "alice" });
+    const dataset = makeDatasetEntry("ds");
+    const filter = makeEmptyFilter();
+    filter.owners = ["alice"];
+    const result = searchTestEntries([], filter, [workflow, dataset], null);
+    expect(result).toEqual([workflow]);
+  });
+
+  it("filters by resource type when a type is given", () => {
+    const workflow = makeWorkflowEntry({ name: "wf" });
+    const dataset = makeDatasetEntry("ds");
+    const result = searchTestEntries([], makeEmptyFilter(), [workflow, 
dataset], "dataset");
+    expect(result).toEqual([dataset]);
+  });
+
+  it("applies all filters sequentially, keeping only entries that satisfy 
every one", () => {
+    const match = makeWorkflowEntry({
+      name: "alpha-pipeline",
+      wid: 7,
+      ownerName: "alice",
+      creationTime: new Date(2024, 0, 15, 12).getTime(),
+      lastModifiedTime: new Date(2024, 0, 16, 12).getTime(),
+      operatorTypes: ["CSVFileScan"],
+      projectIDs: [42],
+    });
+    const wrongOwner = makeWorkflowEntry({
+      name: "alpha-pipeline",
+      wid: 7,
+      ownerName: "bob",
+      creationTime: new Date(2024, 0, 15, 12).getTime(),
+      lastModifiedTime: new Date(2024, 0, 16, 12).getTime(),
+      operatorTypes: ["CSVFileScan"],
+      projectIDs: [42],
+    });
+    const wrongName = makeWorkflowEntry({
+      name: "beta-pipeline",
+      wid: 7,
+      ownerName: "alice",
+      creationTime: new Date(2024, 0, 15, 12).getTime(),
+      lastModifiedTime: new Date(2024, 0, 16, 12).getTime(),
+      operatorTypes: ["CSVFileScan"],
+      projectIDs: [42],
+    });
+    const filter: SearchFilterParameters = {
+      createDateStart: new Date(2024, 0, 10),
+      createDateEnd: new Date(2024, 0, 20),
+      modifiedDateStart: new Date(2024, 0, 10),
+      modifiedDateEnd: new Date(2024, 0, 20),
+      owners: ["alice"],
+      ids: ["7"],
+      operators: ["CSVFileScan"],
+      projectIds: [42],
+    };
+    const result = searchTestEntries(["alpha"], filter, [match, wrongOwner, 
wrongName], "workflow");
+    expect(result).toEqual([match]);
+  });
+});

Reply via email to