You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@texera.apache.org by gi...@apache.org on 2026/07/22 02:27:00 UTC
(texera) 01/01: test(frontend): cover searchTestEntries (#6681)
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. <mg...@uci.edu>
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: "dataset-owner@example.com",
+ 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]);
+ });
+});