Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { mockAppRoot } from '@rocket.chat/mock-providers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { axe } from 'jest-axe';

import ABACUpsellModal from './ABACUpsellModal';

// Mock the hooks used by ABACUpsellModal
jest.mock('../../../hooks/useHasLicenseModule', () => ({
useHasLicenseModule: jest.fn(() => false),
}));

jest.mock('../../GenericUpsellModal/hooks', () => ({
useUpsellActions: jest.fn(() => ({
shouldShowUpsell: true,
cloudWorkspaceHadTrial: false,
handleManageSubscription: jest.fn(),
handleTalkToSales: jest.fn(),
})),
}));

// Mock getURL utility
jest.mock('../../../../app/utils/client', () => ({
getURL: (url: string) => url,
}));

const appRoot = mockAppRoot()
.withTranslations('en', 'core', {
Premium_capability: 'Premium capability',
Attribute_based_access_control: 'Attribute-Based Access Control',
Attribute_based_access_control_title: 'Automate complex access management across your entire organization',
Attribute_based_access_control_description:
'ABAC automates room access, granting or revoking access based on dynamic user attributes rather than fixed roles.',
Upgrade: 'Upgrade',
Cancel: 'Cancel',
})
.build();

describe('ABACUpsellModal', () => {
const mockOnClose = jest.fn();
const mockOnConfirm = jest.fn();

beforeEach(() => {
jest.clearAllMocks();
});

it('should render the modal with correct content', () => {
const { baseElement } = render(<ABACUpsellModal onClose={mockOnClose} onConfirm={mockOnConfirm} />, { wrapper: appRoot });
expect(baseElement).toMatchSnapshot();
});

it('should have no accessibility violations', async () => {
const { container } = render(<ABACUpsellModal onClose={mockOnClose} onConfirm={mockOnConfirm} />, { wrapper: appRoot });
const results = await axe(container);
expect(results).toHaveNoViolations();
});

it('should call onConfirm when upgrade button is clicked', async () => {
const user = userEvent.setup();
render(<ABACUpsellModal onClose={mockOnClose} onConfirm={mockOnConfirm} />, { wrapper: appRoot });

const upgradeButton = screen.getByRole('button', { name: 'Upgrade' });
await user.click(upgradeButton);

expect(mockOnConfirm).toHaveBeenCalledTimes(1);
expect(mockOnClose).not.toHaveBeenCalled();
});

it('should call onClose when cancel button is clicked', async () => {
const user = userEvent.setup();
render(<ABACUpsellModal onClose={mockOnClose} onConfirm={mockOnConfirm} />, { wrapper: appRoot });

const cancelButton = screen.getByRole('button', { name: 'Cancel' });
await user.click(cancelButton);

expect(mockOnClose).toHaveBeenCalledTimes(1);
expect(mockOnConfirm).not.toHaveBeenCalled();
});

it('should call onClose when close button is clicked', async () => {
const user = userEvent.setup();
render(<ABACUpsellModal onClose={mockOnClose} onConfirm={mockOnConfirm} />, { wrapper: appRoot });

// Look for close button (usually has aria-label or is the X button)
const closeButton = screen.getByRole('button', { name: /close/i });
await user.click(closeButton);

expect(mockOnClose).toHaveBeenCalledTimes(1);
expect(mockOnConfirm).not.toHaveBeenCalled();
});

it('should handle multiple button clicks correctly', async () => {
const user = userEvent.setup();
render(<ABACUpsellModal onClose={mockOnClose} onConfirm={mockOnConfirm} />, { wrapper: appRoot });

const upgradeButton = screen.getByRole('button', { name: 'Upgrade' });
const cancelButton = screen.getByRole('button', { name: 'Cancel' });

// Click upgrade first
await user.click(upgradeButton);
expect(mockOnConfirm).toHaveBeenCalledTimes(1);

// Click cancel
await user.click(cancelButton);
expect(mockOnClose).toHaveBeenCalledTimes(1);

// Total calls
expect(mockOnConfirm).toHaveBeenCalledTimes(1);
expect(mockOnClose).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { mockAppRoot } from '@rocket.chat/mock-providers';
import { action } from '@storybook/addon-actions';
import type { Meta } from '@storybook/react';

import ABACUpsellModal from './ABACUpsellModal';

const meta = {
component: ABACUpsellModal,
parameters: {
layout: 'centered',
},
args: {
onClose: action('onClose'),
},
decorators: [
(Story) => {
const AppRoot = mockAppRoot()
.withTranslations('en', 'core', {
Attribute_based_access_control: 'Attribute-Based Access Control',
Attribute_based_access_control_title: 'Automate complex access management across your entire organization',
Attribute_based_access_control_description:
'ABAC automates room access, granting or revoking access based on dynamic user attributes rather than fixed roles.',
})
.build();

return (
<AppRoot>
<Story />
</AppRoot>
);
},
],
} satisfies Meta<typeof ABACUpsellModal>;

export default meta;

export const Default = {
args: {
onClose: action('onClose'),
onConfirm: action('onConfirm'),
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useTranslation } from 'react-i18next';

import { getURL } from '../../../../app/utils/client';
import GenericUpsellModal from '../../GenericUpsellModal';

type ABACUpsellModalProps = {
onClose: () => void;
onConfirm: () => void;
};

const ABACUpsellModal = ({ onClose, onConfirm }: ABACUpsellModalProps) => {
const { t } = useTranslation();

return (
<GenericUpsellModal
tagline={t('Premium_capability')}
title={t('Attribute_based_access_control')}
subtitle={t('Attribute_based_access_control_title')}
description={t('Attribute_based_access_control_description')}
img={getURL('images/abac-upsell-modal.svg')}
onClose={onClose}
onConfirm={onConfirm}
onCancel={onClose}
imgHeight={256}
/>
);
};

export default ABACUpsellModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`ABACUpsellModal should render the modal with correct content 1`] = `
<body>
<div>
<dialog
aria-labelledby=":r0:-title"
aria-modal="true"
class="rcx-box rcx-box--full rcx-modal"
open=""
>
<div
class="rcx-box rcx-box--full rcx-modal__inner rcx-css-1e2ego0"
>
<header
class="rcx-box rcx-box--full rcx-modal__header"
>
<div
class="rcx-box rcx-box--full rcx-modal__header-inner"
>
<div
class="rcx-box rcx-box--full rcx-modal__header-text rcx-css-trljwa rcx-css-lma364"
>
<div
class="rcx-box rcx-box--full rcx-modal__tagline rcx-css-ar0y0g"
>
Premium capability
</div>
<h2
class="rcx-box rcx-box--full rcx-modal__title"
id=":r0:-title"
>
Attribute-Based Access Control
</h2>
</div>
<button
aria-label="Close"
class="rcx-box rcx-box--full rcx-button--small-square rcx-button--square rcx-button--icon rcx-button rcx-css-trljwa rcx-css-lma364"
type="button"
>
<i
aria-hidden="true"
class="rcx-box rcx-box--full rcx-icon--name-cross rcx-icon rcx-css-4pvxx3"
>
</i>
</button>
</div>
</header>
<div
class="rcx-box rcx-box--full rcx-modal__content rcx-css-1vw7itl"
>
<div
class="rcx-box rcx-box--full rcx-modal__content-wrapper rcx-css-r1bpeb"
>
<figure
class="rcx-modal__hero-image-wrapper"
>
<img
alt=""
class="rcx-box rcx-box--full rcx-modal__hero-image rcx-css-1qfl5uy"
src="images/abac-upsell-modal.svg"
/>
</figure>
<h3
class="rcx-box rcx-box--full rcx-css-1sfto34"
>
Automate complex access management across your entire organization
</h3>
<div
class="rcx-box rcx-box--full rcx-css-1s3t8yc"
style="white-space: break-spaces;"
>
ABAC automates room access, granting or revoking access based on dynamic user attributes rather than fixed roles.
</div>
</div>
</div>
<div
class="rcx-box rcx-box--full rcx-modal__footer rcx-css-17mu816"
>
<div
class="rcx-button-group rcx-button-group--align-end"
role="group"
>
<button
class="rcx-box rcx-box--full rcx-button--secondary rcx-button rcx-button-group__item"
type="button"
>
<span
class="rcx-button--content"
>
Cancel
</span>
</button>
<button
class="rcx-box rcx-box--full rcx-button--primary rcx-button rcx-button-group__item"
type="button"
>
<span
class="rcx-button--content"
>
Upgrade
</span>
</button>
</div>
</div>
</div>
</dialog>
</div>
</body>
`;
Loading
Loading