From fa27a923b4ebd198e19fc532b97f0b3f2f84d41b Mon Sep 17 00:00:00 2001 From: 1fanwang <1fannnw@gmail.com> Date: Mon, 24 Aug 2026 06:27:23 -0400 Subject: [PATCH 1/2] fix(breadcrumbs): link to the executed workflow, not the launch plan The execution breadcrumb read its self-link, name, version, project, and domain from the launch-plan identifier. When a launch plan name differed from its workflow name, the breadcrumb pointed at a workflow page that did not exist. Read the identity from the executed workflow and relabel the breadcrumb as Workflow Name. Signed-off-by: 1fanwang <1fannnw@gmail.com> --- .../Breadcrumbs/async/executionContext.ts | 21 +- .../async/tests/executionContext.test.ts | 281 ++++++++++++++++++ .../registry/contextualDefaults.ts | 2 +- 3 files changed, 297 insertions(+), 7 deletions(-) create mode 100644 packages/oss-console/src/components/Breadcrumbs/async/tests/executionContext.test.ts diff --git a/packages/oss-console/src/components/Breadcrumbs/async/executionContext.ts b/packages/oss-console/src/components/Breadcrumbs/async/executionContext.ts index 3e27034d2..decdcb22c 100644 --- a/packages/oss-console/src/components/Breadcrumbs/async/executionContext.ts +++ b/packages/oss-console/src/components/Breadcrumbs/async/executionContext.ts @@ -50,17 +50,23 @@ const getExecutionData = async (projectId: string, domainId: string, executionId }; const isExecutionTaskOrWorkflow = (executionData: Execution) => { - return executionData.spec.launchPlan.resourceType === ResourceType.TASK + // Check the resourceType of the actual executed entity (workflowId), + // not the launch plan identifier + return executionData.closure.workflowId.resourceType === ResourceType.TASK ? ResourceType.TASK : ResourceType.WORKFLOW; }; const getTaskOrWorkflowName = (executionData: Execution): string => { - return executionData.spec.launchPlan.name; + // Return the actual workflow/task name from closure.workflowId, + // not the launch plan name from spec.launchPlan + return executionData.closure.workflowId.name; }; const getTaskOrWorkflowVersion = (executionData: Execution): string => { - return executionData.spec.launchPlan.version; + // Return the actual workflow/task version from closure.workflowId, + // not the launch plan version from spec.launchPlan + return executionData.closure.workflowId.version; }; const getExecutionValue = (location: Location) => { @@ -126,8 +132,9 @@ export const executonTaskWorkFlowNameAsyncSelfLink: BreadcrumbEntitySelfLinkAsyn const resourceName = getTaskOrWorkflowName(executionData); const resourceType = isExecutionTaskOrWorkflow(executionData); + // Use closure.workflowId (the actual workflow) instead of spec.launchPlan const { project: desinationProject, domain: desinationDomain } = getExecutionSpecProjectDomain( - executionData.spec.launchPlan, + executionData.closure.workflowId, breadcrumb, ); @@ -153,8 +160,9 @@ export const executionTaskWorkflowVersions: BreadcrumbAsyncPopOverData = async ( const entityResourceName = getTaskOrWorkflowName(executionData); const entityResourceVersion = getTaskOrWorkflowVersion(executionData); + // Use closure.workflowId (the actual workflow) instead of spec.launchPlan const { project: desinationProject, domain: desinationDomain } = getExecutionSpecProjectDomain( - executionData.spec.launchPlan, + executionData.closure.workflowId, breadcrumb, ); @@ -340,8 +348,9 @@ export const executionTaskWorkflowViewAll: BreadcrumbAsyncViewAllLink = async ( const executionType = isExecutionTaskOrWorkflow(executionData); const entityResourceName = getTaskOrWorkflowName(executionData); + // Use closure.workflowId (the actual workflow) instead of spec.launchPlan const { project: desinationProject, domain: desinationDomain } = getExecutionSpecProjectDomain( - executionData.spec.launchPlan, + executionData.closure.workflowId, breadcrumb, ); diff --git a/packages/oss-console/src/components/Breadcrumbs/async/tests/executionContext.test.ts b/packages/oss-console/src/components/Breadcrumbs/async/tests/executionContext.test.ts new file mode 100644 index 000000000..846b4cfaf --- /dev/null +++ b/packages/oss-console/src/components/Breadcrumbs/async/tests/executionContext.test.ts @@ -0,0 +1,281 @@ +import Core from '@clients/common/flyteidl/core'; +import { Execution } from '../../../../models/Execution/types'; + +// Mock the SimpleCacheCallbackManager +jest.mock('@clients/primitives/SimpleCache/SimpleCacheCallbackManager', () => ({ + SimpleCacheCallbackManager: jest.fn().mockImplementation(() => ({ + getCachedOrFetch: jest.fn((_key: string, fn: () => Promise) => fn()), + })), +})); + +// Mock the execution API +const mockGetExecution = jest.fn(); +jest.mock('../../../../models/Execution/api', () => ({ + getExecution: (...args: unknown[]) => mockGetExecution(...args), + listExecutions: jest.fn(), +})); + +// Mock the routes +jest.mock('../../../../routes/routes', () => ({ + Routes: { + WorkflowDetails: { + makeUrl: jest.fn((project: string, domain: string, name: string) => + `/projects/${project}/domains/${domain}/workflows/${name}`), + }, + TaskDetails: { + makeUrl: jest.fn((project: string, domain: string, name: string) => + `/projects/${project}/domains/${domain}/tasks/${name}`), + }, + ExecutionDetails: { + makeUrl: jest.fn(({ project, domain, name }: { project: string; domain: string; name: string }) => + `/projects/${project}/domains/${domain}/executions/${name}`), + }, + EntityVersionDetails: { + makeUrl: jest.fn(), + }, + }, +})); + +// Import after mocking +import { + executonTaskWorkFlowNameAsyncValue, + executonTaskWorkFlowNameAsyncSelfLink, + executonNamedEntityAsyncValue, +} from '../executionContext'; + +/** + * Creates a mock execution where the launch plan name differs from the workflow name. + * This simulates the bug scenario where: + * - Launch plan name: 'hello_world_lp' + * - Actual workflow name: 'hello_world_wf' + */ +const createMockExecutionWithDifferentNames = (): Execution => ({ + id: { + project: 'flytesnacks', + domain: 'development', + name: 'wf-execution-001', + }, + spec: { + launchPlan: { + resourceType: Core.ResourceType.LAUNCH_PLAN, + project: 'flytesnacks', + domain: 'development', + name: 'hello_world_lp', // Launch plan name + version: '2025-04-09-15-56-08', + }, + inputs: { literals: {} }, + metadata: { + mode: 0, + principal: 'user', + nesting: 0, + }, + notifications: { notifications: [] }, + }, + closure: { + workflowId: { + resourceType: Core.ResourceType.WORKFLOW, + project: 'flytesnacks', + domain: 'development', + name: 'hello_world_wf', // Actual workflow name (different!) + version: '2025-04-09-15-56-08', + }, + phase: 4, // ABORTED + createdAt: { seconds: { low: 1732000000, high: 0, unsigned: false }, nanos: 0 }, + startedAt: { seconds: { low: 1732000000, high: 0, unsigned: false }, nanos: 0 }, + }, +}); + +/** + * Creates a mock execution for a task (not a workflow) + */ +const createMockTaskExecution = (): Execution => ({ + id: { + project: 'test-project', + domain: 'development', + name: 'task-execution-001', + }, + spec: { + launchPlan: { + resourceType: Core.ResourceType.LAUNCH_PLAN, + project: 'test-project', + domain: 'development', + name: 'my-task-launch-plan', + version: 'v1', + }, + inputs: { literals: {} }, + metadata: { + mode: 0, + principal: 'user', + nesting: 0, + }, + notifications: { notifications: [] }, + }, + closure: { + workflowId: { + resourceType: Core.ResourceType.TASK, + project: 'test-project', + domain: 'development', + name: 'my-actual-task', + version: 'v1', + }, + phase: 3, // SUCCEEDED + createdAt: { seconds: { low: 1732000000, high: 0, unsigned: false }, nanos: 0 }, + startedAt: { seconds: { low: 1732000000, high: 0, unsigned: false }, nanos: 0 }, + }, +}); + +describe('executionContext breadcrumb functions', () => { + const mockBreadcrumb = { + projectId: 'flytesnacks', + domainId: 'development', + value: '', + defaultValue: () => '', + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('executonTaskWorkFlowNameAsyncValue', () => { + it('should return the workflow name from closure.workflowId, NOT the launch plan name', async () => { + const mockExecution = createMockExecutionWithDifferentNames(); + mockGetExecution.mockResolvedValue(mockExecution); + + const mockLocation = { + pathname: '/projects/flytesnacks/domains/development/executions/wf-execution-001', + } as Location; + + const result = await executonTaskWorkFlowNameAsyncValue(mockLocation, mockBreadcrumb as any); + + // Should return the WORKFLOW name, not the launch plan name + expect(result).toBe('hello_world_wf'); + // Should NOT return the launch plan name + expect(result).not.toBe('hello_world_lp'); + }); + + it('should return the task name for task executions', async () => { + const mockExecution = createMockTaskExecution(); + mockGetExecution.mockResolvedValue(mockExecution); + + const mockLocation = { + pathname: '/projects/test-project/domains/development/executions/task-execution-001', + } as Location; + + const result = await executonTaskWorkFlowNameAsyncValue(mockLocation, { + ...mockBreadcrumb, + projectId: 'test-project', + } as any); + + expect(result).toBe('my-actual-task'); + expect(result).not.toBe('my-task-launch-plan'); + }); + }); + + describe('executonNamedEntityAsyncValue', () => { + it('should return "workflows" for workflow executions', async () => { + const mockExecution = createMockExecutionWithDifferentNames(); + mockGetExecution.mockResolvedValue(mockExecution); + + const mockLocation = { + pathname: '/projects/flytesnacks/domains/development/executions/wf-execution-001', + } as Location; + + const result = await executonNamedEntityAsyncValue(mockLocation, mockBreadcrumb as any); + + expect(result).toBe('workflows'); + }); + + it('should return "tasks" for task executions', async () => { + const mockExecution = createMockTaskExecution(); + mockGetExecution.mockResolvedValue(mockExecution); + + const mockLocation = { + pathname: '/projects/test-project/domains/development/executions/task-execution-001', + } as Location; + + const result = await executonNamedEntityAsyncValue(mockLocation, { + ...mockBreadcrumb, + projectId: 'test-project', + } as any); + + expect(result).toBe('tasks'); + }); + }); + + describe('executonTaskWorkFlowNameAsyncSelfLink', () => { + it('should generate link to the actual workflow, not the launch plan', async () => { + const mockExecution = createMockExecutionWithDifferentNames(); + mockGetExecution.mockResolvedValue(mockExecution); + + const mockLocation = { + pathname: '/projects/flytesnacks/domains/development/executions/wf-execution-001', + } as Location; + + const result = await executonTaskWorkFlowNameAsyncSelfLink(mockLocation, mockBreadcrumb as any); + + // Should link to the workflow details page with the WORKFLOW name + expect(result).toContain('hello_world_wf'); + expect(result).toContain('/workflows/'); + // Should NOT contain the launch plan name + expect(result).not.toContain('hello_world_lp'); + }); + + it('should generate link to task details for task executions', async () => { + const mockExecution = createMockTaskExecution(); + mockGetExecution.mockResolvedValue(mockExecution); + + const mockLocation = { + pathname: '/projects/test-project/domains/development/executions/task-execution-001', + } as Location; + + const result = await executonTaskWorkFlowNameAsyncSelfLink(mockLocation, { + ...mockBreadcrumb, + projectId: 'test-project', + } as any); + + expect(result).toContain('my-actual-task'); + expect(result).toContain('/tasks/'); + expect(result).not.toContain('my-task-launch-plan'); + }); + }); + + describe('Bug scenario: Launch plan name differs from workflow name', () => { + /** + * This test verifies the fix for the bug where: + * 1. User is on Launch Plan page showing 'hello_world_lp' + * 2. User clicks into an execution + * 3. Breadcrumb should show the WORKFLOW name 'hello_world_wf' + * 4. NOT the launch plan name 'hello_world_lp' + * + * Before the fix, clicking the breadcrumb would navigate to: + * /workflows/hello_world_lp (empty page - wrong!) + * + * After the fix, clicking the breadcrumb navigates to: + * /workflows/hello_world_wf (correct workflow page) + */ + it('should use workflow name in breadcrumb, not launch plan name', async () => { + const mockExecution = createMockExecutionWithDifferentNames(); + mockGetExecution.mockResolvedValue(mockExecution); + + const mockLocation = { + pathname: '/projects/flytesnacks/domains/development/executions/wf-execution-001', + } as Location; + + // Get the workflow/task name shown in breadcrumb + const breadcrumbName = await executonTaskWorkFlowNameAsyncValue(mockLocation, mockBreadcrumb as any); + + // Get the self-link URL when clicking the breadcrumb + const selfLinkUrl = await executonTaskWorkFlowNameAsyncSelfLink(mockLocation, mockBreadcrumb as any); + + // Verify the breadcrumb shows the correct workflow name + expect(breadcrumbName).toBe('hello_world_wf'); + + // Verify clicking the breadcrumb navigates to the correct workflow page + expect(selfLinkUrl).toBe('/projects/flytesnacks/domains/development/workflows/hello_world_wf'); + + // Verify we're NOT using the launch plan name + expect(breadcrumbName).not.toBe('hello_world_lp'); + expect(selfLinkUrl).not.toContain('hello_world_lp'); + }); + }); +}); diff --git a/packages/oss-console/src/components/Breadcrumbs/registry/contextualDefaults.ts b/packages/oss-console/src/components/Breadcrumbs/registry/contextualDefaults.ts index 197c38468..58f7f3b3d 100644 --- a/packages/oss-console/src/components/Breadcrumbs/registry/contextualDefaults.ts +++ b/packages/oss-console/src/components/Breadcrumbs/registry/contextualDefaults.ts @@ -67,7 +67,7 @@ export const contextualBreadcrumbRegistryList: Breadcrumb[] = [ }), makeBreadcrumb({ id: 'executions:task-workflow-name', - label: 'Launch Plan Name', + label: 'Workflow Name', defaultValue: 'Executions', popoverTitle: 'Versions', asyncValue: executonTaskWorkFlowNameAsyncValue, From c8ac8f0e472367290cc9153f47ea81fd81e94ba0 Mon Sep 17 00:00:00 2001 From: 1fanwang <1fannnw@gmail.com> Date: Mon, 24 Aug 2026 06:01:55 -0400 Subject: [PATCH 2/2] test(breadcrumbs): distinguish workflow identity from launch plan Identical project and domain values let the self-link test pass even when it read the launch-plan identifier. Separate every identity so the route assertion covers project and domain as well as the workflow name. Signed-off-by: 1fanwang <1fannnw@gmail.com> --- .../Breadcrumbs/async/executionContext.ts | 9 -- .../async/tests/executionContext.test.ts | 120 ++++++------------ 2 files changed, 36 insertions(+), 93 deletions(-) diff --git a/packages/oss-console/src/components/Breadcrumbs/async/executionContext.ts b/packages/oss-console/src/components/Breadcrumbs/async/executionContext.ts index decdcb22c..9acfd91f4 100644 --- a/packages/oss-console/src/components/Breadcrumbs/async/executionContext.ts +++ b/packages/oss-console/src/components/Breadcrumbs/async/executionContext.ts @@ -50,22 +50,16 @@ const getExecutionData = async (projectId: string, domainId: string, executionId }; const isExecutionTaskOrWorkflow = (executionData: Execution) => { - // Check the resourceType of the actual executed entity (workflowId), - // not the launch plan identifier return executionData.closure.workflowId.resourceType === ResourceType.TASK ? ResourceType.TASK : ResourceType.WORKFLOW; }; const getTaskOrWorkflowName = (executionData: Execution): string => { - // Return the actual workflow/task name from closure.workflowId, - // not the launch plan name from spec.launchPlan return executionData.closure.workflowId.name; }; const getTaskOrWorkflowVersion = (executionData: Execution): string => { - // Return the actual workflow/task version from closure.workflowId, - // not the launch plan version from spec.launchPlan return executionData.closure.workflowId.version; }; @@ -132,7 +126,6 @@ export const executonTaskWorkFlowNameAsyncSelfLink: BreadcrumbEntitySelfLinkAsyn const resourceName = getTaskOrWorkflowName(executionData); const resourceType = isExecutionTaskOrWorkflow(executionData); - // Use closure.workflowId (the actual workflow) instead of spec.launchPlan const { project: desinationProject, domain: desinationDomain } = getExecutionSpecProjectDomain( executionData.closure.workflowId, breadcrumb, @@ -160,7 +153,6 @@ export const executionTaskWorkflowVersions: BreadcrumbAsyncPopOverData = async ( const entityResourceName = getTaskOrWorkflowName(executionData); const entityResourceVersion = getTaskOrWorkflowVersion(executionData); - // Use closure.workflowId (the actual workflow) instead of spec.launchPlan const { project: desinationProject, domain: desinationDomain } = getExecutionSpecProjectDomain( executionData.closure.workflowId, breadcrumb, @@ -348,7 +340,6 @@ export const executionTaskWorkflowViewAll: BreadcrumbAsyncViewAllLink = async ( const executionType = isExecutionTaskOrWorkflow(executionData); const entityResourceName = getTaskOrWorkflowName(executionData); - // Use closure.workflowId (the actual workflow) instead of spec.launchPlan const { project: desinationProject, domain: desinationDomain } = getExecutionSpecProjectDomain( executionData.closure.workflowId, breadcrumb, diff --git a/packages/oss-console/src/components/Breadcrumbs/async/tests/executionContext.test.ts b/packages/oss-console/src/components/Breadcrumbs/async/tests/executionContext.test.ts index 846b4cfaf..8950eccef 100644 --- a/packages/oss-console/src/components/Breadcrumbs/async/tests/executionContext.test.ts +++ b/packages/oss-console/src/components/Breadcrumbs/async/tests/executionContext.test.ts @@ -1,34 +1,42 @@ import Core from '@clients/common/flyteidl/core'; import { Execution } from '../../../../models/Execution/types'; +import { + executonTaskWorkFlowNameAsyncValue, + executonTaskWorkFlowNameAsyncSelfLink, + executonNamedEntityAsyncValue, +} from '../executionContext'; -// Mock the SimpleCacheCallbackManager jest.mock('@clients/primitives/SimpleCache/SimpleCacheCallbackManager', () => ({ SimpleCacheCallbackManager: jest.fn().mockImplementation(() => ({ getCachedOrFetch: jest.fn((_key: string, fn: () => Promise) => fn()), })), })); -// Mock the execution API const mockGetExecution = jest.fn(); jest.mock('../../../../models/Execution/api', () => ({ getExecution: (...args: unknown[]) => mockGetExecution(...args), listExecutions: jest.fn(), })); -// Mock the routes jest.mock('../../../../routes/routes', () => ({ Routes: { WorkflowDetails: { - makeUrl: jest.fn((project: string, domain: string, name: string) => - `/projects/${project}/domains/${domain}/workflows/${name}`), + makeUrl: jest.fn( + (project: string, domain: string, name: string) => + `/projects/${project}/domains/${domain}/workflows/${name}`, + ), }, TaskDetails: { - makeUrl: jest.fn((project: string, domain: string, name: string) => - `/projects/${project}/domains/${domain}/tasks/${name}`), + makeUrl: jest.fn( + (project: string, domain: string, name: string) => + `/projects/${project}/domains/${domain}/tasks/${name}`, + ), }, ExecutionDetails: { - makeUrl: jest.fn(({ project, domain, name }: { project: string; domain: string; name: string }) => - `/projects/${project}/domains/${domain}/executions/${name}`), + makeUrl: jest.fn( + ({ project, domain, name }: { project: string; domain: string; name: string }) => + `/projects/${project}/domains/${domain}/executions/${name}`, + ), }, EntityVersionDetails: { makeUrl: jest.fn(), @@ -36,31 +44,18 @@ jest.mock('../../../../routes/routes', () => ({ }, })); -// Import after mocking -import { - executonTaskWorkFlowNameAsyncValue, - executonTaskWorkFlowNameAsyncSelfLink, - executonNamedEntityAsyncValue, -} from '../executionContext'; - -/** - * Creates a mock execution where the launch plan name differs from the workflow name. - * This simulates the bug scenario where: - * - Launch plan name: 'hello_world_lp' - * - Actual workflow name: 'hello_world_wf' - */ const createMockExecutionWithDifferentNames = (): Execution => ({ id: { - project: 'flytesnacks', - domain: 'development', + project: 'execution-project', + domain: 'execution-domain', name: 'wf-execution-001', }, spec: { launchPlan: { resourceType: Core.ResourceType.LAUNCH_PLAN, - project: 'flytesnacks', - domain: 'development', - name: 'hello_world_lp', // Launch plan name + project: 'launch-plan-project', + domain: 'launch-plan-domain', + name: 'hello_world_lp', version: '2025-04-09-15-56-08', }, inputs: { literals: {} }, @@ -74,20 +69,17 @@ const createMockExecutionWithDifferentNames = (): Execution => ({ closure: { workflowId: { resourceType: Core.ResourceType.WORKFLOW, - project: 'flytesnacks', - domain: 'development', - name: 'hello_world_wf', // Actual workflow name (different!) + project: 'workflow-project', + domain: 'workflow-domain', + name: 'hello_world_wf', version: '2025-04-09-15-56-08', }, - phase: 4, // ABORTED + phase: 4, createdAt: { seconds: { low: 1732000000, high: 0, unsigned: false }, nanos: 0 }, startedAt: { seconds: { low: 1732000000, high: 0, unsigned: false }, nanos: 0 }, }, }); -/** - * Creates a mock execution for a task (not a workflow) - */ const createMockTaskExecution = (): Execution => ({ id: { project: 'test-project', @@ -118,7 +110,7 @@ const createMockTaskExecution = (): Execution => ({ name: 'my-actual-task', version: 'v1', }, - phase: 3, // SUCCEEDED + phase: 3, createdAt: { seconds: { low: 1732000000, high: 0, unsigned: false }, nanos: 0 }, startedAt: { seconds: { low: 1732000000, high: 0, unsigned: false }, nanos: 0 }, }, @@ -126,8 +118,8 @@ const createMockTaskExecution = (): Execution => ({ describe('executionContext breadcrumb functions', () => { const mockBreadcrumb = { - projectId: 'flytesnacks', - domainId: 'development', + projectId: 'workflow-domain', + domainId: 'browsing-domain', value: '', defaultValue: () => '', }; @@ -147,9 +139,7 @@ describe('executionContext breadcrumb functions', () => { const result = await executonTaskWorkFlowNameAsyncValue(mockLocation, mockBreadcrumb as any); - // Should return the WORKFLOW name, not the launch plan name expect(result).toBe('hello_world_wf'); - // Should NOT return the launch plan name expect(result).not.toBe('hello_world_lp'); }); @@ -211,12 +201,14 @@ describe('executionContext breadcrumb functions', () => { pathname: '/projects/flytesnacks/domains/development/executions/wf-execution-001', } as Location; - const result = await executonTaskWorkFlowNameAsyncSelfLink(mockLocation, mockBreadcrumb as any); + const result = await executonTaskWorkFlowNameAsyncSelfLink( + mockLocation, + mockBreadcrumb as any, + ); - // Should link to the workflow details page with the WORKFLOW name - expect(result).toContain('hello_world_wf'); - expect(result).toContain('/workflows/'); - // Should NOT contain the launch plan name + expect(result).toBe( + '/projects/workflow-project/domains/workflow-domain/workflows/hello_world_wf', + ); expect(result).not.toContain('hello_world_lp'); }); @@ -238,44 +230,4 @@ describe('executionContext breadcrumb functions', () => { expect(result).not.toContain('my-task-launch-plan'); }); }); - - describe('Bug scenario: Launch plan name differs from workflow name', () => { - /** - * This test verifies the fix for the bug where: - * 1. User is on Launch Plan page showing 'hello_world_lp' - * 2. User clicks into an execution - * 3. Breadcrumb should show the WORKFLOW name 'hello_world_wf' - * 4. NOT the launch plan name 'hello_world_lp' - * - * Before the fix, clicking the breadcrumb would navigate to: - * /workflows/hello_world_lp (empty page - wrong!) - * - * After the fix, clicking the breadcrumb navigates to: - * /workflows/hello_world_wf (correct workflow page) - */ - it('should use workflow name in breadcrumb, not launch plan name', async () => { - const mockExecution = createMockExecutionWithDifferentNames(); - mockGetExecution.mockResolvedValue(mockExecution); - - const mockLocation = { - pathname: '/projects/flytesnacks/domains/development/executions/wf-execution-001', - } as Location; - - // Get the workflow/task name shown in breadcrumb - const breadcrumbName = await executonTaskWorkFlowNameAsyncValue(mockLocation, mockBreadcrumb as any); - - // Get the self-link URL when clicking the breadcrumb - const selfLinkUrl = await executonTaskWorkFlowNameAsyncSelfLink(mockLocation, mockBreadcrumb as any); - - // Verify the breadcrumb shows the correct workflow name - expect(breadcrumbName).toBe('hello_world_wf'); - - // Verify clicking the breadcrumb navigates to the correct workflow page - expect(selfLinkUrl).toBe('/projects/flytesnacks/domains/development/workflows/hello_world_wf'); - - // Verify we're NOT using the launch plan name - expect(breadcrumbName).not.toBe('hello_world_lp'); - expect(selfLinkUrl).not.toContain('hello_world_lp'); - }); - }); });