Repository: Altinn/altinn-studio
Pull request #14960: feat(policy-editor): rule header shows description and is closed by default
Author: login: nkylstad
Labels: name: area/authorization
description: Area: Issues related to roles and rights on apps, such as who can instantiate, sign etc.
name: frontend
name: team/studio-core
name: skip-manual-testing
description: Deprecated: Use skip-second-approval instead.
Created: 2025-03-12T13:48:02Z | Merged: 2025-03-13T15:06:19Z

<!--- Provide a general summary of your changes in the Title above -->

## Description

For policy editor in "app" usageType:
- Rules should be closed by default
- Rule accordion header should show rule description

![Screenshot 2025-03-12 at 14 57 17](https://github.com/user-attachments/assets/c88c7766-1fc4-4901-8416-96d78cdc909b)


## Verification

- [x] **Your** code builds clean without any errors or warnings
- [x] Manual testing done (required)
- [x] Relevant automated test added (if you find this hard, leave it and we'll help out)



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

## Summary by CodeRabbit

- **New Features**
  - Introduced an option to display additional descriptive text within policy elements for enhanced clarity.

- **Enhancements**
  - Improved header styling and layout within the policy editor for a more polished visual experience.
  - Updated component behavior to conditionally display details and context-sensitive alerts, ensuring that alerts only appear when no policy rules exist.
  - Enhanced testing framework to allow for more flexible and comprehensive testing of component behavior.
  - Added tests to verify component behavior under various conditions, including empty policy rules and user interactions.
  - Introduced asynchronous user interactions in tests to simulate real-world usage scenarios.
  - Added a test case to verify that the rule list length increases when the "add rule" button is clicked.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/frontend/app-development/layout/PageHeader/SubHeader/SettingsModalButton/SettingsModal/components/Tabs/PolicyTab/PolicyTab.test.tsx b/frontend/app-development/layout/PageHeader/SubHeader/SettingsModalButton/SettingsModal/components/Tabs/PolicyTab/PolicyTab.test.tsx
index 412dec10715..3812bbd9871 100644
--- a/frontend/app-development/layout/PageHeader/SubHeader/SettingsModalButton/SettingsModal/components/Tabs/PolicyTab/PolicyTab.test.tsx
+++ b/frontend/app-development/layout/PageHeader/SubHeader/SettingsModalButton/SettingsModal/components/Tabs/PolicyTab/PolicyTab.test.tsx
@@ -104,8 +104,21 @@ describe('PolicyTab', () => {
   );
 
   it('displays the PolicyEditor component with the provided policy and data', async () => {
+    const user = userEvent.setup();
     await resolveAndWaitForSpinnerToDisappear();
 
+    await user.tab();
+
+    const elementInPolicyEditor = screen.getByText(textMock('policy_editor.rules'));
+    expect(elementInPolicyEditor).toBeInTheDocument();
+  });
+
+  it('displays the PolicyEditor component with alert if policy rule list is empty', async () => {
+    const user = userEvent.setup();
+    await resolveAndWaitForSpinnerToDisappear(() => Promise.resolve({ ...mockPolicy, rules: [] }));
+
+    await user.tab();
+
     const elementInPolicyEditor = screen.getByText(
       textMock('policy_editor.alert', { usageType: textMock('policy_editor.alert_app') }),
     );
@@ -129,8 +142,10 @@ describe('PolicyTab', () => {
   });
 });
 
-const resolveAndWaitForSpinnerToDisappear = async () => {
-  getAppPolicy.mockImplementation(() => Promise.resolve(mockPolicy));
+const resolveAndWaitForSpinnerToDisappear = async (mockGetAppPolicy?: () => void) => {
+  getAppPolicy.mockImplementation(
+    mockGetAppPolicy ? mockGetAppPolicy : () => Promise.resolve(mockPolicy),
+  );
   getPolicyActions.mockImplementation(() => Promise.resolve(mockActions));
   getPolicySubjects.mockImplementation(() => Promise.resolve(mockSubjects));
 
diff --git a/frontend/packages/policy-editor/src/PolicyEditor.test.tsx b/frontend/packages/policy-editor/src/PolicyEditor.test.tsx
index 3c22878f15a..7cd239b3f34 100644
--- a/frontend/packages/policy-editor/src/PolicyEditor.test.tsx
+++ b/frontend/packages/policy-editor/src/PolicyEditor.test.tsx
@@ -83,6 +83,28 @@ describe('PolicyEditor', () => {
 
     expect(mockOnSave).toHaveBeenCalledTimes(1);
   });
+
+  it('increases the rule list length when add rule button is clicked', async () => {
+    const user = userEvent.setup();
+    renderPolicyEditor();
+
+    const rulesTab = screen.getByRole('tab', { name: textMock('policy_editor.rules_edit') });
+    await user.click(rulesTab);
+
+    const originalLength = mockPolicy.rules.length;
+
+    const addButton = screen.getByRole('button', {
+      name: textMock('policy_editor.card_button_text'),
+    });
+
+    await user.click(addButton);
+
+    const ruleContextMenuButtons = screen.getAllByRole('button', {
+      name: textMock('policy_editor.more'),
+    });
+
+    expect(ruleContextMenuButtons.length).toEqual(originalLength + 1);
+  });
 });
 
 const renderPolicyEditor = (policyEditorProps: Partial<PolicyEditorProps> = {}) => {
diff --git a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyCardRules.test.tsx b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyCardRules.test.tsx
index e2d05081184..80e85cea405 100644
--- a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyCardRules.test.tsx
+++ b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyCardRules.test.tsx
@@ -8,6 +8,8 @@ import {
   PolicyEditorContext,
   type PolicyEditorContextProps,
 } from '../../contexts/PolicyEditorContext';
+import type { PolicyRuleCard } from '../../types';
+import { getPolicyRuleIdString } from '../../utils/PolicyRuleUtils';
 
 const defaultProps: PolicyCardRulesProps = {
   showErrorsOnAllRulesAboveNew: false,
@@ -16,30 +18,28 @@ const defaultProps: PolicyCardRulesProps = {
 describe('PolicyCardRule', () => {
   afterEach(jest.clearAllMocks);
 
-  it('displays the rules when there are more than 0 rules', async () => {
-    const user = userEvent.setup();
-    renderPolicyCardRules();
+  it.each(mockPolicyEditorContextValue.policyRules)(
+    'displays the rules when there are more than 0 rules',
+    async (rule: PolicyRuleCard) => {
+      const user = userEvent.setup();
+      renderPolicyCardRules();
 
-    const subResourceLabel = screen.getAllByText(
-      textMock('policy_editor.rule_card_sub_resource_title'),
-    );
+      const ruleTitle = screen.getByText(
+        `${textMock('policy_editor.rule')} ${getPolicyRuleIdString(rule)}`,
+      );
 
-    await user.tab();
+      await user.tab();
 
-    expect(subResourceLabel.length).toEqual(mockPolicyEditorContextValue.policyRules.length);
-  });
+      expect(ruleTitle).toBeInTheDocument();
+    },
+  );
 
-  it('displays no rules when the policy has no rules', async () => {
-    const user = userEvent.setup();
+  it('displays alert when the policy has no rules', async () => {
     renderPolicyCardRules({ policyRules: [] });
 
-    const subResourceLabel = screen.queryAllByText(
-      textMock('policy_editor.rule_card_sub_resource_title'),
-    );
-
-    await user.tab();
+    const cardButton = screen.queryAllByRole('button');
 
-    expect(subResourceLabel.length).toEqual(0);
+    expect(cardButton.length).toEqual(0);
   });
 });
 
diff --git a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.module.css b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.module.css
index eda6439af18..4491973075b 100644
--- a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.module.css
+++ b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.module.css
@@ -108,3 +108,13 @@
   padding-inline: var(--fds-spacing-5);
   padding-bottom: var(--fds-spacing-3);
 }
+
+.headerWrapper {
+  display: flex;
+  flex-direction: column;
+  align-items: start;
+}
+
+.headerDescription {
+  text-align: start;
+}
diff --git a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.test.tsx b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.test.tsx
index 90fda970ada..452f47239c8 100644
--- a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.test.tsx
+++ b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.test.tsx
@@ -4,6 +4,11 @@ import userEvent from '@testing-library/user-event';
 import type { ExpandablePolicyElementProps } from './ExpandablePolicyElement';
 import { ExpandablePolicyElement } from './ExpandablePolicyElement';
 import { textMock } from '@studio/testing/mocks/i18nMock';
+import {
+  PolicyEditorContext,
+  type PolicyEditorContextProps,
+} from '../../../../contexts/PolicyEditorContext';
+import { mockPolicyEditorContextValue } from '../../../../../test/mocks/policyEditorContextMock';
 
 const mockTitle: string = 'Test';
 const mockTextChildren: string = 'Test Content';
@@ -12,18 +17,8 @@ const mockChildren: React.ReactNode = <p>{mockTextChildren}</p>;
 describe('ExpandablePolicyElement', () => {
   afterEach(jest.clearAllMocks);
 
-  const mockHandleRemoveElement = jest.fn();
-  const mockHandleCloneElement = jest.fn();
-
-  const defaultProps: ExpandablePolicyElementProps = {
-    title: mockTitle,
-    handleRemoveElement: mockHandleRemoveElement,
-    handleCloneElement: mockHandleCloneElement,
-    children: mockChildren,
-  };
-
   it('renders the component with the provided title and children', () => {
-    render(<ExpandablePolicyElement {...defaultProps} />);
+    renderExpandablePolicyElement({}, { usageType: 'resource' });
 
     const expandButton = screen.getByRole('button', {
       name: `${mockTitle} ${textMock('policy_editor.expandable_card_close_icon')}`,
@@ -34,9 +29,44 @@ describe('ExpandablePolicyElement', () => {
     expect(contentElement).toBeInTheDocument();
   });
 
+  it('renders with open state when usageType is resource', () => {
+    renderExpandablePolicyElement({}, { usageType: 'resource' });
+
+    const expandButtonClosedBefore = screen.getByRole('button', {
+      name: `${mockTitle} ${textMock('policy_editor.expandable_card_close_icon')}`,
+    });
+    const expandButtonOpenedBefore = screen.queryByRole('button', {
+      name: `${mockTitle} ${textMock('policy_editor.expandable_card_open_icon')}`,
+    });
+
+    expect(expandButtonClosedBefore).toBeInTheDocument();
+    expect(expandButtonOpenedBefore).not.toBeInTheDocument();
+  });
+
+  it('renders with description in header when provided', () => {
+    const mockRuleDescription = 'Test Description';
+    renderExpandablePolicyElement({ description: mockRuleDescription });
+
+    const descriptionElement = screen.getByText(mockRuleDescription);
+    expect(descriptionElement).toBeInTheDocument();
+  });
+
+  it('renders with closed state when usageType is app', () => {
+    renderExpandablePolicyElement({}, { usageType: 'app' });
+    const expandButtonClosedBefore = screen.queryByRole('button', {
+      name: `${mockTitle} ${textMock('policy_editor.expandable_card_close_icon')}`,
+    });
+    const expandButtonOpenedBefore = screen.getByRole('button', {
+      name: `${mockTitle} ${textMock('policy_editor.expandable_card_open_icon')}`,
+    });
+
+    expect(expandButtonClosedBefore).not.toBeInTheDocument();
+    expect(expandButtonOpenedBefore).toBeInTheDocument();
+  });
+
   it('toggles open/close state when the expand button is clicked', async () => {
     const user = userEvent.setup();
-    render(<ExpandablePolicyElement {...defaultProps} />);
+    renderExpandablePolicyElement({}, { usageType: 'resource' });
 
     const expandButtonClosedBefore = screen.getByRole('button', {
       name: `${mockTitle} ${textMock('policy_editor.expandable_card_close_icon')}`,
@@ -45,7 +75,6 @@ describe('ExpandablePolicyElement', () => {
       name: `${mockTitle} ${textMock('policy_editor.expandable_card_open_icon')}`,
     });
 
-    expect(screen.getByText(mockTextChildren)).toBeInTheDocument();
     expect(expandButtonClosedBefore).toBeInTheDocument();
     expect(expandButtonOpenedBefore).not.toBeInTheDocument();
 
@@ -69,7 +98,8 @@ describe('ExpandablePolicyElement', () => {
 
   it('calls handleRemoveElement when the "Delete" option in the dropdown menu is clicked', async () => {
     const user = userEvent.setup();
-    render(<ExpandablePolicyElement {...defaultProps} />);
+    const mockHandleRemoveElement = jest.fn();
+    renderExpandablePolicyElement({ handleRemoveElement: mockHandleRemoveElement });
 
     const moreButton = screen.getByRole('button', {
       name: textMock('policy_editor.more'),
@@ -84,7 +114,8 @@ describe('ExpandablePolicyElement', () => {
 
   it('calls handleCloneElement when the "Copy" option in the dropdown menu is clicked', async () => {
     const user = userEvent.setup();
-    render(<ExpandablePolicyElement {...defaultProps} />);
+    const mockHandleCloneElement = jest.fn();
+    renderExpandablePolicyElement({ handleCloneElement: mockHandleCloneElement });
 
     const moreButton = screen.getByRole('button', {
       name: textMock('policy_editor.more'),
@@ -99,3 +130,21 @@ describe('ExpandablePolicyElement', () => {
     expect(mockHandleCloneElement).toHaveBeenCalledTimes(1);
   });
 });
+
+const renderExpandablePolicyElement = (
+  props: Partial<ExpandablePolicyElementProps> = {},
+  context: Partial<PolicyEditorContextProps> = {},
+) => {
+  const defaultProps: ExpandablePolicyElementProps = {
+    title: mockTitle,
+    handleRemoveElement: jest.fn(),
+    handleCloneElement: jest.fn(),
+    children: mockChildren,
+  };
+
+  return render(
+    <PolicyEditorContext.Provider value={{ ...mockPolicyEditorContextValue, ...context }}>
+      <ExpandablePolicyElement {...defaultProps} {...props} />
+    </PolicyEditorContext.Provider>,
+  );
+};
diff --git a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.tsx b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.tsx
index 6ce24c64b49..aecf4774c8b 100644
--- a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.tsx
+++ b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.tsx
@@ -4,10 +4,12 @@ import classes from './ExpandablePolicyElement.module.css';
 import { ChevronDownIcon, ChevronUpIcon } from '@studio/icons';
 import { PolicyEditorDropdownMenu } from './PolicyEditorDropdownMenu';
 import { useTranslation } from 'react-i18next';
-import { StudioLabelAsParagraph } from '@studio/components';
+import { StudioLabelAsParagraph, StudioParagraph } from '@studio/components';
+import { usePolicyEditorContext } from '../../../../contexts/PolicyEditorContext';
 
 export type ExpandablePolicyElementProps = {
   title: string;
+  description?: string;
   children: ReactNode;
   isCard?: boolean;
   handleRemoveElement: () => void;
@@ -17,6 +19,7 @@ export type ExpandablePolicyElementProps = {
 
 export const ExpandablePolicyElement = ({
   title,
+  description,
   children,
   isCard = true,
   handleRemoveElement,
@@ -24,8 +27,9 @@ export const ExpandablePolicyElement = ({
   hasError = false,
 }: ExpandablePolicyElementProps): React.ReactNode => {
   const { t } = useTranslation();
+  const { usageType } = usePolicyEditorContext();
 
-  const [isOpen, setIsOpen] = useState(true);
+  const [isOpen, setIsOpen] = useState(usageType !== 'app');
   const [isDropdownOpen, setIsDropdownOpen] = useState(false);
 
   const [isButtonFocused, setIsButtonFocused] = useState(false);
@@ -68,7 +72,14 @@ export const ExpandablePolicyElement = ({
           onFocus={() => setIsButtonFocused(true)}
           onBlur={() => setIsButtonFocused(false)}
         >
-          <StudioLabelAsParagraph size='small'>{title}</StudioLabelAsParagraph>
+          <div className={classes.headerWrapper}>
+            <StudioLabelAsParagraph size='sm'>{title}</StudioLabelAsParagraph>
+            {description && (
+              <StudioParagraph size='xs' className={classes.headerDescription}>
+                {description}
+              </StudioParagraph>
+            )}
+          </div>
           {isOpen ? (
             <ChevronUpIcon
               title={t('policy_editor.expandable_card_close_icon')}
diff --git a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.test.tsx b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.test.tsx
index 96350ac1b77..612b6a90599 100644
--- a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.test.tsx
+++ b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.test.tsx
@@ -54,7 +54,8 @@ describe('PolicyRule', () => {
 
   it('calls "savePolicy" when input fields are blurred', async () => {
     const user = userEvent.setup();
-    renderPolicyRule();
+    const mockSavePolicy = jest.fn();
+    renderPolicyRule({ usageType: 'resource', savePolicy: mockSavePolicy });
 
     const [typeInput] = screen.getAllByLabelText(
       textMock('policy_editor.narrowing_list_field_type'),
@@ -91,16 +92,28 @@ describe('PolicyRule', () => {
     await user.tab();
 
     const numFields = 5;
-    expect(mockPolicyEditorContextValue.savePolicy).toHaveBeenCalledTimes(numFields);
+    expect(mockSavePolicy).toHaveBeenCalledTimes(numFields + 1);
+  });
+
+  it('renders policy rule with description when usage type is app', () => {
+    const mockRuleDescription = 'test description';
+    renderPolicyRule(
+      { usageType: 'app' },
+      { policyRule: { ...mockPolicyRuleCard1, description: mockRuleDescription } },
+    );
+    expect(screen.getByText(mockRuleDescription)).toBeInTheDocument();
   });
 });
 
-const renderPolicyRule = (policyEditorContextProps: Partial<PolicyEditorContextProps> = {}) => {
+const renderPolicyRule = (
+  policyEditorContextProps: Partial<PolicyEditorContextProps> = {},
+  props: Partial<PolicyRuleProps> = {},
+) => {
   return render(
     <PolicyEditorContext.Provider
       value={{ ...mockPolicyEditorContextValue, ...policyEditorContextProps }}
     >
-      <PolicyRule {...defaultProps} />
+      <PolicyRule {...defaultProps} {...props} />
     </PolicyEditorContext.Provider>,
   );
 };
diff --git a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.tsx b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.tsx
index ccc93086d01..00fdb8151a2 100644
--- a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.tsx
+++ b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.tsx
@@ -26,7 +26,7 @@ export const PolicyRule = ({
   ruleIndex,
 }: PolicyRuleProps): React.ReactNode => {
   const { t } = useTranslation();
-  const { policyRules, setPolicyRules, savePolicy } = usePolicyEditorContext();
+  const { policyRules, setPolicyRules, savePolicy, usageType } = usePolicyEditorContext();
 
   const uniqueId = useId();
 
@@ -65,6 +65,11 @@ export const PolicyRule = ({
     }
   };
 
+  const usageTypeIsApp: boolean = usageType === 'app';
+  const expandablePolicyElementDescription: string | undefined = usageTypeIsApp
+    ? policyRule.description
+    : undefined;
+
   return (
     <PolicyRuleContextProvider
       policyRule={policyRule}
@@ -76,6 +81,7 @@ export const PolicyRule = ({
       <div>
         <ExpandablePolicyElement
           title={`${t('policy_editor.rule')} ${getPolicyRuleIdString(policyRule)}`}
+          description={expandablePolicyElementDescription}
           isCard
           handleCloneElement={handleCloneRule}
           handleRemoveElement={handleDeleteRule}
diff --git a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/ResourceNarrowingList/ResourceNarrowingList.test.tsx b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/ResourceNarrowingList/ResourceNarrowingList.test.tsx
index 82fd109615d..3ac4a19873b 100644
--- a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/ResourceNarrowingList/ResourceNarrowingList.test.tsx
+++ b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/ResourceNarrowingList/ResourceNarrowingList.test.tsx
@@ -27,9 +27,15 @@ const defaultProps: ResourceNarrowingListProps = {
 describe('ResourceNarrowingList', () => {
   afterEach(jest.clearAllMocks);
 
-  it('renders the list of resources', () => {
+  it('renders the list of resources', async () => {
     renderResourceNarrowingList();
 
+    const user = userEvent.setup();
+    const toggleListButton = screen.getByRole('button', {
+      name: `id1 - id2 ${textMock('policy_editor.expandable_card_open_icon')}`,
+    });
+    await user.click(toggleListButton);
+
     const removeButtons = screen.getAllByRole('button', {
       name: textMock('policy_editor.narrowing_list_field_delete'),
     });
@@ -61,6 +67,11 @@ describe('ResourceNarrowingList', () => {
     const user = userEvent.setup();
     renderResourceNarrowingList();
 
+    const toggleListButton = screen.getByRole('button', {
+      name: `id1 - id2 ${textMock('policy_editor.expandable_card_open_icon')}`,
+    });
+    await user.click(toggleListButton);
+
     const [deleteResourceButton] = screen.getAllByRole('button', {
       name: textMock('policy_editor.narrowing_list_field_delete'),
     });
@@ -75,6 +86,11 @@ describe('ResourceNarrowingList', () => {
     const user = userEvent.setup();
     renderResourceNarrowingList();
 
+    const toggleListButton = screen.getByRole('button', {
+      name: `id1 - id2 ${textMock('policy_editor.expandable_card_open_icon')}`,
+    });
+    await user.click(toggleListButton);
+
     const addResourceButton = screen.getByRole('button', {
       name: textMock('policy_editor.narrowing_list_add_button'),
     });
@@ -125,6 +141,11 @@ describe('ResourceNarrowingList', () => {
     const user = userEvent.setup();
     renderResourceNarrowingList();
 
+    const toggleListButton = screen.getByRole('button', {
+      name: `id1 - id2 ${textMock('policy_editor.expandable_card_open_icon')}`,
+    });
+    await user.click(toggleListButton);
+
     const [typeInput] = screen.getAllByLabelText(
       textMock('policy_editor.narrowing_list_field_type'),
     );
diff --git a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/SubResources.test.tsx b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/SubResources.test.tsx
index 1fdf96e0bff..090cb985248 100644
--- a/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/SubResources.test.tsx
+++ b/frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/SubResources.test.tsx
@@ -18,6 +18,11 @@ describe('SubResources', () => {
     const mockSetPolicyRules = jest.fn();
     renderSubResources({ setPolicyRules: mockSetPolicyRules });
 
+    const toggleListButton = screen.getByRole('button', {
+      name: `resource-1 - 1.2 ${textMock('policy_editor.expandable_card_open_icon')}`,
+    });
+    await user.click(toggleListButton);
+
     const [typeInput] = screen.getAllByLabelText(
       textMock('policy_editor.narrowing_list_field_type'),
     );
diff --git a/frontend/packages/policy-editor/src/components/PolicyEditorAlert/PolicyEditorAlert.test.tsx b/frontend/packages/policy-editor/src/components/PolicyEditorAlert/PolicyEditorAlert.test.tsx
index c7f96f1ef08..4f7d0fb10f6 100644
--- a/frontend/packages/policy-editor/src/components/PolicyEditorAlert/PolicyEditorAlert.test.tsx
+++ b/frontend/packages/policy-editor/src/components/PolicyEditorAlert/PolicyEditorAlert.test.tsx
@@ -12,9 +12,18 @@ import { textMock } from '@studio/testing/mocks/i18nMock';
 describe('PolicyEditorAlert', () => {
   afterEach(jest.clearAllMocks);
 
+  it('only displays the alert title when the policy has no rules', async () => {
+    renderPolicyEditorAlert({ policyRules: [] });
+    const alertTextApp = screen.getByText(
+      textMock('policy_editor.alert', { usageType: textMock('policy_editor.alert_app') }),
+    );
+
+    expect(alertTextApp).toBeInTheDocument();
+  });
+
   it('displays the alert title for app when usagetype is app', async () => {
     const user = userEvent.setup();
-    renderPolicyEditorAlert();
+    renderPolicyEditorAlert({ policyRules: [] });
 
     const alertTextApp = screen.getByText(
       textMock('policy_editor.alert', { usageType: textMock('policy_editor.alert_app') }),
@@ -31,7 +40,7 @@ describe('PolicyEditorAlert', () => {
 
   it('displays the alert title for resource when usagetype is not app', async () => {
     const user = userEvent.setup();
-    renderPolicyEditorAlert({ usageType: 'resource' });
+    renderPolicyEditorAlert({ policyRules: [], usageType: 'resource' });
 
     const alertTextApp = screen.queryByText(
       textMock('policy_editor.alert', { usageType: textMock('policy_editor.alert_app') }),
diff --git a/frontend/packages/policy-editor/src/components/PolicyEditorAlert/PolicyEditorAlert.tsx b/frontend/packages/policy-editor/src/components/PolicyEditorAlert/PolicyEditorAlert.tsx
index 961bd0a6dce..aac3d5aaf56 100644
--- a/frontend/packages/policy-editor/src/components/PolicyEditorAlert/PolicyEditorAlert.tsx
+++ b/frontend/packages/policy-editor/src/components/PolicyEditorAlert/PolicyEditorAlert.tsx
@@ -5,9 +5,13 @@ import { usePolicyEditorContext } from '../../contexts/PolicyEditorContext';
 import { useTranslation } from 'react-i18next';
 
 export const PolicyEditorAlert = (): React.ReactElement => {
-  const { usageType } = usePolicyEditorContext();
+  const { usageType, policyRules } = usePolicyEditorContext();
   const { t } = useTranslation();
 
+  if (policyRules.length > 0) {
+    return null;
+  }
+
   return (
     <Alert severity='info' className={classes.alert}>
       <Paragraph size='small'>
diff --git a/frontend/packages/policy-editor/src/components/PolicyRulesEditor/PolicyRulesEditor.test.tsx b/frontend/packages/policy-editor/src/components/PolicyRulesEditor/PolicyRulesEditor.test.tsx
index fbd1ff85265..813aeb78276 100644
--- a/frontend/packages/policy-editor/src/components/PolicyRulesEditor/PolicyRulesEditor.test.tsx
+++ b/frontend/packages/policy-editor/src/components/PolicyRulesEditor/PolicyRulesEditor.test.tsx
@@ -19,9 +19,9 @@ const mockPolicy: Policy = {
 describe('PolicyRulesEditor', () => {
   it('displays the correct number of policy rules', () => {
     renderPolicyRulesEditor();
-    const aLabelFromPolicyCard = screen.queryAllByText(
-      textMock('policy_editor.rule_card_sub_resource_title'),
-    );
+    const aLabelFromPolicyCard = screen.getAllByRole('button', {
+      name: textMock('policy_editor.more'),
+    });
     expect(aLabelFromPolicyCard.length).toEqual(mockPolicy.rules.length);
   });
 


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.test.tsx (1)</summary><blockquote>

`14-14`: **Remove unused import.**

The `PolicyRuleCard` type is imported but never used in this file, as indicated by the static analysis warning.

```diff
-import type { PolicyRuleCard } from '@altinn/policy-editor/types';
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 ESLint</summary>

[error] 14-14: 'PolicyRuleCard' is defined but never used.

(@typescript-eslint/no-unused-vars)

</details>
<details>
<summary>🪛 GitHub Check: Typechecking and linting</summary>

[failure] 14-14: 
'PolicyRuleCard' is declared but its value is never read.

</details>

</details>

</blockquote></details>
<details>
<summary>frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.test.tsx (1)</summary><blockquote>

`78-78`: **Verify if commented expectation is still needed.**

This commented-out expectation might indicate a change in behavior or could be an oversight. Please verify if this check is still relevant.

Either remove the commented code if it's no longer needed, or uncomment it if the check is still valid:

```diff
-// expect(screen.getByText(mockTextChildren)).toBeInTheDocument();
+expect(screen.getByText(mockTextChildren)).toBeInTheDocument();
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 1a553c4d705de4ad4e198755bb75905f8bbfd82f and 10f7aad957f714a24601ca569f8655c1f0ef8bd4.

</details>

<details>
<summary>📒 Files selected for processing (6)</summary>

* `frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.module.css` (1 hunks)
* `frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.test.tsx` (7 hunks)
* `frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.tsx` (3 hunks)
* `frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.test.tsx` (3 hunks)
* `frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.tsx` (2 hunks)
* `frontend/packages/policy-editor/src/components/PolicyEditorAlert/PolicyEditorAlert.tsx` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 ESLint</summary>

<details>
<summary>frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.test.tsx</summary>

[error] 14-14: 'PolicyRuleCard' is defined but never used.

(@typescript-eslint/no-unused-vars)

</details>

</details>
<details>
<summary>🪛 GitHub Check: Typechecking and linting</summary>

<details>
<summary>frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.test.tsx</summary>

[failure] 14-14: 
'PolicyRuleCard' is declared but its value is never read.

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: Build environment and run e2e test
* GitHub Check: Testing
* GitHub Check: CodeQL

</details>

<details>
<summary>🔇 Additional comments (19)</summary><blockquote>

<details>
<summary>frontend/packages/policy-editor/src/components/PolicyEditorAlert/PolicyEditorAlert.tsx (2)</summary>

`8-8`: **Proper destructuring of context variables**

The code correctly destructures both `usageType` and `policyRules` from the policy editor context.

---

`11-13`: **Conditional rendering improves user experience**

Good addition of the conditional check to hide the alert when rules exist. This aligns with the PR objective to improve the UI by not showing unnecessary alerts when rules are present.

</details>
<details>
<summary>frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.module.css (2)</summary>

`112-116`: **Well-structured header layout**

The new `headerWrapper` class provides a clean vertical layout for header content, which is necessary for displaying the title and description stacked on top of each other.

---

`118-120`: **Consistent text alignment for description**

The `headerDescription` class ensures text alignment is consistent with the rest of the UI.

</details>
<details>
<summary>frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.tsx (2)</summary>

`29-29`: **Proper destructuring of context variables**

The code correctly adds `usageType` to the destructured variables from the policy editor context.

---

`79-79`: **Conditionally displaying description based on usage type**

The implementation correctly passes the description prop only when `usageType` is 'app', which aligns with the PR objective to show rule descriptions for the app usage type.

</details>
<details>
<summary>frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.tsx (6)</summary>

`7-8`: **Updated imports to support new functionality**

The imports have been properly updated to include the necessary components for displaying the description and accessing the context.

---

`12-12`: **Added optional description prop to component interface**

Good addition of the optional `description` prop to the component props interface, maintaining backward compatibility.

---

`22-22`: **Added description to destructured props**

The description prop is properly destructured from the component props.

---

`30-30`: **Accessing usage type from context**

The code correctly accesses the `usageType` from the policy editor context.

---

`32-32`: **Rules closed by default for app usage type**

This change implements the PR objective to keep rules closed by default when the usage type is 'app'. The initial state of `isOpen` is now dependent on the usage type.

---

`75-82`: **Enhanced header layout with conditional description**

The header rendering has been improved to include a structured layout with conditional rendering of the description. This implements the PR objective to show rule descriptions in the header.

</details>
<details>
<summary>frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.test.tsx (3)</summary>

`58-59`: **LGTM! Good use of mocking and explicit test setup.**

The mock function approach and explicit `usageType` specification make the test intent clearer. The updated expectation for call count is also appropriate.



Also applies to: 96-96

---

`99-106`: **LGTM! Good test for the new description functionality.**

This test effectively verifies the new requirement that rule descriptions should be shown in the UI when the `usageType` is 'app'.

---

`109-112`: **LGTM! Great test utility enhancement.**

The refactored `renderPolicyRule` function now accepts partial props for both context and component, making the test utility more flexible and the tests more readable.

</details>
<details>
<summary>frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.test.tsx (4)</summary>

`7-11`: **LGTM! Appropriate import additions.**

The new imports for the `PolicyEditorContext` and related types are necessary for the test utility function implementation.

---

`32-65`: **LGTM! Comprehensive test cases for different states.**

These test cases effectively verify the key requirements of the PR:
1. Rules are open by default for 'resource' usageType
2. Rules are closed by default for 'app' usageType (main PR objective)
3. Description is shown in the header when provided (main PR objective)

Good coverage of the new functionality!

---

`102-103`: **LGTM! Good test independence.**

Moving the mock function creation to individual test cases improves test isolation and makes each test's dependencies clearer.



Also applies to: 118-119

---

`135-151`: **LGTM! Excellent test utility refactoring.**

Creating a dedicated render utility function with default props and context is a great practice. It:
1. Reduces code duplication
2. Makes tests more consistent
3. Centralizes component setup logic
4. Makes tests more readable and maintainable

The function signature also provides flexibility by accepting partial overrides for both props and context.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T13:51:30Z
user: login: wrt95
body: Great job! 😄 
Added some nitpick 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T10:26:33Z
user: login: wrt95
body: Setting to `Request changes` as the Playwright tests are failing 
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T10:27:33Z
user: login: nkylstad
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-13T11:11:05Z
user: login: wrt95
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T13:25:43Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 5e9c64b09676e5a517d97ba4728f853aec20f00f and 873913787695825e9034a92506fafbb8dcb22d0e.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `frontend/app-development/layout/PageHeader/SubHeader/SettingsModalButton/SettingsModal/components/Tabs/PolicyTab/PolicyTab.test.tsx` (2 hunks)
* `frontend/packages/policy-editor/src/PolicyEditor.test.tsx` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* frontend/packages/policy-editor/src/PolicyEditor.test.tsx

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 GitHub Check: Typechecking and linting</summary>

<details>
<summary>frontend/app-development/layout/PageHeader/SubHeader/SettingsModalButton/SettingsModal/components/Tabs/PolicyTab/PolicyTab.test.tsx</summary>

[failure] 109-109: 
Cannot find name 'user'.

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: Build environment and run e2e test
* GitHub Check: Testing
* GitHub Check: CodeQL

</details>

<details>
<summary>🔇 Additional comments (2)</summary><blockquote>

<details>
<summary>frontend/app-development/layout/PageHeader/SubHeader/SettingsModalButton/SettingsModal/components/Tabs/PolicyTab/PolicyTab.test.tsx (2)</summary>

`115-125`: **LGTM! New test case verifies alert for empty rule list**

This test properly checks that the PolicyEditor displays an alert when no policy rules are present, which aligns with the PR objective to improve the policy editor's UI.

---

`144-147`: **LGTM! Enhanced test helper function**

Good enhancement to the `resolveAndWaitForSpinnerToDisappear` helper function to allow custom mock implementations of `getAppPolicy`, which makes the tests more flexible.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T13:52:34Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>frontend/packages/policy-editor/src/components/PolicyRulesEditor/PolicyRulesEditor.test.tsx (1)</summary><blockquote>

`22-24`: **Query selector improved for better accessibility testing**

The change from `queryAllByText` to `getAllByRole('button')` is a good practice as it follows accessibility testing guidelines by selecting elements based on their ARIA roles rather than just text content. 

However, the variable name `aLabelFromPolicyCard` is now misleading since you're querying for buttons, not labels. Consider renaming it to something more appropriate like `policyCardButtons` or `moreActionButtons` to better reflect what you're actually selecting.

```diff
-  const aLabelFromPolicyCard = screen.getAllByRole('button', {
+  const policyCardButtons = screen.getAllByRole('button', {
     name: textMock('policy_editor.more'),
   });
-  expect(aLabelFromPolicyCard.length).toEqual(mockPolicy.rules.length);
+  expect(policyCardButtons.length).toEqual(mockPolicy.rules.length);
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 74fa8c70a5e94b17ba48d63e566bdfb39251513d and 4104a86f903d46e542e12355d5cd917428703419.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `frontend/packages/policy-editor/src/components/PolicyRulesEditor/PolicyRulesEditor.test.tsx` (1 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: Build environment and run e2e test
* GitHub Check: CodeQL
* GitHub Check: Testing

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T14:33:07Z
user: login: github-actions[bot]
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T15:06:10Z

Review comments:
diff_hunk: @@ -8,6 +8,8 @@ import {
   PolicyEditorContext,
   type PolicyEditorContextProps,
 } from '../../contexts/PolicyEditorContext';
+import type { PolicyRuleCard } from '@altinn/policy-editor/types';
+import { getPolicyRuleIdString } from '@altinn/policy-editor/utils/PolicyRuleUtils';
path: frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyCardRules.test.tsx
user: login: wrt95
body: Should use relative import here 😄 
```suggestion
import type { PolicyRuleCard } from '../../types';
import { getPolicyRuleIdString } from '../../utils/PolicyRuleUtils';
```
created_at: 2025-03-13T10:22:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -68,7 +72,14 @@ export const ExpandablePolicyElement = ({
           onFocus={() => setIsButtonFocused(true)}
           onBlur={() => setIsButtonFocused(false)}
         >
-          <StudioLabelAsParagraph size='small'>{title}</StudioLabelAsParagraph>
+          <div className={classes.headerWrapper}>
+            <StudioLabelAsParagraph size='small'>{title}</StudioLabelAsParagraph>
path: frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/ExpandablePolicyElement/ExpandablePolicyElement.tsx
user: login: wrt95
body: I believe Designsystemet has changed `small` to `sm` now 😄 
```suggestion
            <StudioLabelAsParagraph size='sm'>{title}</StudioLabelAsParagraph>
```
created_at: 2025-03-13T10:23:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -76,6 +76,7 @@ export const PolicyRule = ({
       <div>
         <ExpandablePolicyElement
           title={`${t('policy_editor.rule')} ${getPolicyRuleIdString(policyRule)}`}
+          description={usageType === 'app' ? policyRule.description : undefined}
path: frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.tsx
user: login: wrt95
body: Should we maybe move this to a variable to increase readability? 😄 

```tsx
const usageTypeIsApp: boolean = usageType === 'app';
const expandablePolicyElementDescription: string | undefined = usageTypeIsApp ? 'policyrule.description : undefined;
```
created_at: 2025-03-13T10:25:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,6 +8,8 @@ import {
   PolicyEditorContext,
   type PolicyEditorContextProps,
 } from '../../contexts/PolicyEditorContext';
+import type { PolicyRuleCard } from '@altinn/policy-editor/types';
+import { getPolicyRuleIdString } from '@altinn/policy-editor/utils/PolicyRuleUtils';
path: frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyCardRules.test.tsx
user: login: nkylstad
body: Thanks! My IDE keeps using these imports 😅 
created_at: 2025-03-13T11:11:05Z
author_association: MEMBER
diff_hunk: @@ -105,6 +105,18 @@
 
   it('displays the PolicyEditor component with the provided policy and data', async () => {
     await resolveAndWaitForSpinnerToDisappear();
+    
+    await user.tab();
+
+    const elementInPolicyEditor = screen.getByText(textMock('policy_editor.rules'));
+    expect(elementInPolicyEditor).toBeInTheDocument();
+  });
path: frontend/app-development/layout/PageHeader/SubHeader/SettingsModalButton/SettingsModal/components/Tabs/PolicyTab/PolicyTab.test.tsx
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix missing user event setup in test**

The test is trying to use a `user` object in line 109, but it's not defined in this test. This will cause a runtime error.


```diff
-  it('displays the PolicyEditor component with the provided policy and data', async () => {
-    await resolveAndWaitForSpinnerToDisappear();
-    
-    await user.tab();
-
-    const elementInPolicyEditor = screen.getByText(textMock('policy_editor.rules'));
-    expect(elementInPolicyEditor).toBeInTheDocument();
-  });
+  it('displays the PolicyEditor component with the provided policy and data', async () => {
+    const user = userEvent.setup();
+    await resolveAndWaitForSpinnerToDisappear();
+    
+    await user.tab();
+
+    const elementInPolicyEditor = screen.getByText(textMock('policy_editor.rules'));
+    expect(elementInPolicyEditor).toBeInTheDocument();
+  });
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  it('displays the PolicyEditor component with the provided policy and data', async () => {
    const user = userEvent.setup();
    await resolveAndWaitForSpinnerToDisappear();
    
    await user.tab();

    const elementInPolicyEditor = screen.getByText(textMock('policy_editor.rules'));
    expect(elementInPolicyEditor).toBeInTheDocument();
  });
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: Typechecking and linting</summary>

[failure] 109-109: 
Cannot find name 'user'.

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Fixed in commit 74fa8c7
created_at: 2025-03-13T13:52:33Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-03-12T13:48:20Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

<details>
<summary>📝 Walkthrough</summary>

## Walkthrough
This pull request introduces updates across several components of the policy editor. New CSS classes have been added for header layout styling. Component logic has been enhanced by adding an optional `description` prop and conditional rendering based on the `usageType` obtained from context. Testing utilities and assertions have been updated to support these changes with new test cases and refactored mocks. Additionally, the alert component now conditionally renders based on the presence of policy rules from the context.

## Changes
| File(s) | Change Summary |
|---------|----------------|
| `frontend/.../ExpandablePolicyElement.module.css` | Added new CSS classes: `.headerWrapper` (flexbox layout in column direction) and `.headerDescription` (text alignment set to start) for improved header styling. |
| `frontend/.../ExpandablePolicyElement.tsx`, `frontend/.../PolicyRule.tsx` | Introduced a new optional `description` prop; updated component logic to conditionally render the description based on `usageType` retrieved from context, with `PolicyRule` passing the description to `ExpandablePolicyElement`. |
| `frontend/.../ExpandablePolicyElement.test.tsx`, `frontend/.../PolicyRule.test.tsx`, `frontend/.../PolicyEditorAlert.test.tsx` | Added new testing utility functions and additional test cases to validate component behavior for different `usageType` values, refined mock function placements, and updated test signatures. |
| `frontend/.../PolicyEditorAlert.tsx` | Added a new context variable `policyRules` and introduced conditional rendering to return `null` when policy rules are present. |
| `frontend/.../PolicyCardRules/PolicyCardRules.test.tsx`, `frontend/.../PolicyCardRules/PolicyRule/SubResources/SubResources.test.tsx`, `frontend/.../PolicyCardRules/PolicyRule/SubResources/ResourceNarrowingList.test.tsx` | Enhanced tests with new user interactions and asynchronous behavior, including button clicks to toggle lists and improved assertions for rendering conditions. |
| `frontend/.../PolicyEditor.test.tsx` | Updated test for the `PolicyEditor` component to count relevant UI elements based on button roles instead of text labels. |

## Suggested labels
`area/ui-editor`, `quality/testing`, `skip-releasenotes`, `team/studio-domain1`, `skip-documentation`

## Suggested reviewers
- Jondyr
- lassopicasso

</details>

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!TIP]
> <details>
> <summary>⚡🧪 Multi-step agentic review comment chat (experimental)</summary>
> 
> - We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
> 						- To enable this feature, set early_access to true under in the settings.
> 
> </details>

<!-- announcements_end -->

---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 4104a86f903d46e542e12355d5cd917428703419 and 46337b07dd9510fd6862369a606105c7a3d80443.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `frontend/packages/policy-editor/src/PolicyEditor.test.tsx` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* frontend/packages/policy-editor/src/PolicyEditor.test.tsx

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (4)</summary>

* GitHub Check: docker-build-push / Build and push docker image
* GitHub Check: Build environment and run e2e test
* GitHub Check: CodeQL
* GitHub Check: Testing

</details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Altinn/altinn-studio&utm_content=14960):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: nkylstad
created_at: 2025-03-13T07:55:38Z
body: A comment about the failing playwright test, the same issue was present in https://github.com/Altinn/altinn-studio/pull/14888, and is solved there - so that PR should be merged first, then this one. Will look into failing unit tests!
author_association: MEMBER
user: login: codecov[bot]
created_at: 2025-03-13T09:06:36Z
body: ## [Codecov](https://app.codecov.io/gh/Altinn/altinn-studio/pull/14960?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Altinn) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 95.84%. Comparing base [(`c530091`)](https://app.codecov.io/gh/Altinn/altinn-studio/commit/c53009108dbf1e1a7666d305a292ddbcefd76075?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Altinn) to head [(`46337b0`)](https://app.codecov.io/gh/Altinn/altinn-studio/commit/46337b07dd9510fd6862369a606105c7a3d80443?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Altinn).
> Report is 1 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main   #14960      +/-   ##
==========================================
- Coverage   95.86%   95.84%   -0.02%     
==========================================
  Files        1967     1967              
  Lines       25596    25603       +7     
  Branches     2891     2894       +3     
==========================================
+ Hits        24537    24540       +3     
+ Misses        799      798       -1     
- Partials      260      265       +5     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/Altinn/altinn-studio/pull/14960?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Altinn).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Altinn).

<details><summary>🚀 New features to boost your workflow: </summary>

- ❄ [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- 📦 [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE
user: login: nkylstad
created_at: 2025-03-13T11:10:25Z
body: > Setting to `Request changes` as the Playwright tests are failing

See [comment](https://github.com/Altinn/altinn-studio/pull/14960#issuecomment-2720283477) above, this is fixed in the other PR.
author_association: MEMBER
user: login: nkylstad
created_at: 2025-03-13T15:05:50Z
body: Verified that it works as expected in dev for apps. Also verified that there are no changes to the policy editor for resources currently, as this change should only apply for apps for now.
author_association: MEMBER