diff --git a/libs/designer-ui/src/lib/card/graphContainer/__test__/__snapshots__/graphContainer.spec.tsx.snap b/libs/designer-ui/src/lib/card/graphContainer/__test__/__snapshots__/graphContainer.spec.tsx.snap
new file mode 100644
index 00000000000..06545049f95
--- /dev/null
+++ b/libs/designer-ui/src/lib/card/graphContainer/__test__/__snapshots__/graphContainer.spec.tsx.snap
@@ -0,0 +1,25 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`GraphContainer component > renders with active prop set to false 1`] = `
+
+`;
+
+exports[`GraphContainer component > renders with default props 1`] = `
+
+`;
+
+exports[`GraphContainer component > renders with selected and active props 1`] = `
+
+`;
+
+exports[`GraphContainer component > renders with selected prop 1`] = `
+
+`;
diff --git a/libs/designer-ui/src/lib/card/graphContainer/__test__/graphContainer.spec.tsx b/libs/designer-ui/src/lib/card/graphContainer/__test__/graphContainer.spec.tsx
new file mode 100644
index 00000000000..eca4dba7adb
--- /dev/null
+++ b/libs/designer-ui/src/lib/card/graphContainer/__test__/graphContainer.spec.tsx
@@ -0,0 +1,38 @@
+import { describe, it, expect } from 'vitest';
+import renderer from 'react-test-renderer';
+import { GraphContainer } from '../index';
+import React from 'react';
+
+describe('GraphContainer component', () => {
+ it('renders with default props', () => {
+ const container = renderer.create().toJSON();
+ expect(container).toMatchSnapshot();
+ expect(container).toHaveProperty('props.className', expect.stringContaining('msla-graph-container'));
+ expect(container).not.toHaveProperty('props.className', expect.stringContaining('selected'));
+ expect(container).not.toHaveProperty('props.className', expect.stringContaining('msla-card-inactive'));
+ });
+
+ it('renders with selected prop', () => {
+ const container = renderer.create().toJSON();
+ expect(container).toMatchSnapshot();
+ expect(container).toHaveProperty('props.className', expect.stringContaining('msla-graph-container'));
+ expect(container).toHaveProperty('props.className', expect.stringContaining('selected'));
+ expect(container).not.toHaveProperty('props.className', expect.stringContaining('msla-card-inactive'));
+ });
+
+ it('renders with active prop set to false', () => {
+ const container = renderer.create().toJSON();
+ expect(container).toMatchSnapshot();
+ expect(container).toHaveProperty('props.className', expect.stringContaining('msla-graph-container'));
+ expect(container).not.toHaveProperty('props.className', expect.stringContaining('selected'));
+ expect(container).toHaveProperty('props.className', expect.stringContaining('msla-card-inactive'));
+ });
+
+ it('renders with selected and active props', () => {
+ const container = renderer.create().toJSON();
+ expect(container).toMatchSnapshot();
+ expect(container).toHaveProperty('props.className', expect.stringContaining('msla-graph-container'));
+ expect(container).toHaveProperty('props.className', expect.stringContaining('selected'));
+ expect(container).toHaveProperty('props.className', expect.stringContaining('msla-card-inactive'));
+ });
+});
diff --git a/libs/designer/src/lib/ui/CustomNodes/__test__/GraphContainerNode.spec.tsx b/libs/designer/src/lib/ui/CustomNodes/__test__/GraphContainerNode.spec.tsx
new file mode 100644
index 00000000000..5c5c1f7168b
--- /dev/null
+++ b/libs/designer/src/lib/ui/CustomNodes/__test__/GraphContainerNode.spec.tsx
@@ -0,0 +1,137 @@
+import React from 'react';
+import renderer from 'react-test-renderer';
+import GraphContainerNode from '../GraphContainerNode';
+import { vi, beforeEach, describe, Mock, it, expect } from 'vitest';
+import { useMonitoringView, useReadOnly } from '../../../core/state/designerOptions/designerOptionsSelectors';
+import { useIsNodeSelectedInOperationPanel } from '../../../core/state/panel/panelSelectors';
+import { useNodeMetadata } from '../../../core';
+import { useActionMetadata, useIsLeafNode, useParentRunId, useRunData } from '../../../core/state/workflow/workflowSelectors';
+import { useNodeSize, useNodeLeafIndex, SUBGRAPH_TYPES } from '@microsoft/logic-apps-shared';
+import { NodeProps } from '@xyflow/react';
+
+vi.mock('../../../core/state/designerOptions/designerOptionsSelectors', () => ({
+ useReadOnly: vi.fn(),
+ useMonitoringView: vi.fn(),
+}));
+
+vi.mock('../../../core/state/panel/panelSelectors', () => ({
+ useIsNodeSelectedInOperationPanel: vi.fn(),
+}));
+
+vi.mock('../../../core/state/workflow/workflowSelectors', () => ({
+ useActionMetadata: vi.fn(),
+ useNodeMetadata: vi.fn(),
+ useIsLeafNode: vi.fn(),
+ useParentRunId: vi.fn(),
+ useRunData: vi.fn(),
+}));
+
+vi.mock(import('@microsoft/logic-apps-shared'), async (importOriginal) => {
+ const actual = await importOriginal();
+ return {
+ ...actual,
+ useNodeSize: vi.fn(),
+ useNodeLeafIndex: vi.fn(),
+ };
+});
+
+vi.mock(import('../../connections/dropzone'), async (importOriginal) => {
+ const actual = await importOriginal();
+ return {
+ ...actual,
+ DropZone: (({ children, ...props }) => {'DropZone'}
) as any,
+ };
+});
+
+vi.mock(import('@xyflow/react'), async (importOriginal) => {
+ const actual = await importOriginal();
+ return {
+ ...actual,
+ Handle: (({ children, ...props }) => {'Handle reactflow'}
) as any,
+ };
+});
+
+describe('GraphContainerNode', () => {
+ const defaultProps = {
+ id: 'mockId',
+ } as NodeProps;
+
+ beforeEach(() => {
+ (useReadOnly as Mock).mockReturnValue(false);
+ (useIsNodeSelectedInOperationPanel as Mock).mockReturnValue(false);
+ (useActionMetadata as Mock).mockReturnValue({});
+ (useNodeMetadata as Mock).mockReturnValue({});
+ (useIsLeafNode as Mock).mockReturnValue(false);
+ (useMonitoringView as Mock).mockReturnValue(false);
+ (useParentRunId as Mock).mockReturnValue(null);
+ (useRunData as Mock).mockReturnValue({});
+ (useNodeSize as Mock).mockReturnValue({ width: 100, height: 100 });
+ (useNodeLeafIndex as Mock).mockReturnValue(0);
+ });
+
+ it('should render without crashing', () => {
+ const tree = renderer.create().toJSON();
+ expect(tree).toMatchSnapshot();
+ });
+
+ it('should render with footer and be a subgraph', () => {
+ (useNodeMetadata as Mock).mockReturnValue({ subgraphType: SUBGRAPH_TYPES.UNTIL_DO });
+ const tree = renderer.create().toJSON();
+ expect(tree.props.className).includes('has-footer');
+ expect(tree.props.className).includes('is-subgraph');
+
+ expect(tree).toMatchSnapshot();
+ });
+
+ it('should render graph container as normal when in monitoring view', () => {
+ (useMonitoringView as Mock).mockReturnValue(true);
+ (useRunData as Mock).mockReturnValue({ status: 'Success' });
+
+ const tree = renderer.create().toJSON();
+
+ expect(tree).toMatchSnapshot();
+ });
+
+ it('should render graph container as inactive when is monitoring view', () => {
+ (useMonitoringView as Mock).mockReturnValue(true);
+ (useRunData as Mock).mockReturnValue({});
+
+ const tree = renderer.create().toJSON();
+
+ expect(tree).toMatchSnapshot();
+ });
+
+ it('should apply correct styles based on node size', () => {
+ const tree = renderer.create().toJSON();
+ expect(tree?.props.style).toEqual({ width: 100, height: 100 });
+ expect(tree).toMatchSnapshot();
+ });
+
+ it('should render the top and bottom handles', () => {
+ const tree = renderer.create().toJSON();
+ const topHandle = tree.children.find((child) => child.props.className.includes('node-handle top'));
+ const bottomHandle = tree.children.find((child) => child.props.className.includes('node-handle bottom'));
+ expect(topHandle).toBeTruthy();
+ expect(bottomHandle).toBeTruthy();
+ expect(tree).toMatchSnapshot();
+ });
+
+ it('should render DropZone when showLeafComponents is true', () => {
+ (useIsLeafNode as Mock).mockReturnValue(true);
+ (useActionMetadata as Mock).mockReturnValue({ type: 'someType' });
+
+ const tree = renderer.create().toJSON();
+
+ expect(tree.length).toBe(2);
+ expect(tree[1].props.className).toBe('edge-drop-zone-container');
+ expect(tree).toMatchSnapshot();
+ });
+
+ it('should not render DropZone when showLeafComponents is false', () => {
+ const tree = renderer.create().toJSON();
+ const dropZone = tree.children.find((child) => child.props.className.includes('edge-drop-zone-container'));
+
+ expect(dropZone).toBeFalsy();
+ expect(tree).toMatchSnapshot();
+ });
+});
diff --git a/libs/designer/src/lib/ui/CustomNodes/__test__/__snapshots__/GraphContainerNode.spec.tsx.snap b/libs/designer/src/lib/ui/CustomNodes/__test__/__snapshots__/GraphContainerNode.spec.tsx.snap
new file mode 100644
index 00000000000..2edb954989c
--- /dev/null
+++ b/libs/designer/src/lib/ui/CustomNodes/__test__/__snapshots__/GraphContainerNode.spec.tsx.snap
@@ -0,0 +1,271 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`GraphContainerNode > should apply correct styles based on node size 1`] = `
+
+
+ Handle reactflow
+
+
+
+ Handle reactflow
+
+
+`;
+
+exports[`GraphContainerNode > should not render DropZone when showLeafComponents is false 1`] = `
+
+
+ Handle reactflow
+
+
+
+ Handle reactflow
+
+
+`;
+
+exports[`GraphContainerNode > should render DropZone when showLeafComponents is true 1`] = `
+[
+
+
+ Handle reactflow
+
+
+
+ Handle reactflow
+
+
,
+ ,
+]
+`;
+
+exports[`GraphContainerNode > should render graph container as inactive when is monitoring view 1`] = `
+
+
+ Handle reactflow
+
+
+
+ Handle reactflow
+
+
+`;
+
+exports[`GraphContainerNode > should render graph container as normal when in monitoring view 1`] = `
+
+
+ Handle reactflow
+
+
+
+ Handle reactflow
+
+
+`;
+
+exports[`GraphContainerNode > should render the top and bottom handles 1`] = `
+
+
+ Handle reactflow
+
+
+
+ Handle reactflow
+
+
+`;
+
+exports[`GraphContainerNode > should render with footer and be a subgraph 1`] = `
+
+
+ Handle reactflow
+
+
+
+ Handle reactflow
+
+
+`;
+
+exports[`GraphContainerNode > should render without crashing 1`] = `
+
+
+ Handle reactflow
+
+
+
+ Handle reactflow
+
+
+`;