Compare commits

...

2 Commits

Author SHA1 Message Date
SagarRajput-7
106a17c306 Merge branch 'no-auth-fe' into no-auth-mode-tests 2026-05-20 03:24:20 +05:30
SagarRajput-7
49f4d4d620 feat(no-auth): added no auth centric test and test patterns 2026-05-20 03:18:44 +05:30
32 changed files with 733 additions and 27 deletions

View File

@@ -614,7 +614,7 @@ function EditMemberDrawer({
<div className="edit-member-drawer__footer-left">
<Tooltip title={getDeleteTooltip(isRootUser, isSelf)}>
<span className="edit-member-drawer__tooltip-wrapper">
<NoAuthGuard>
<NoAuthGuard testId="no-auth-delete-member">
<Button
onClick={(): void => setShowDeleteConfirm(true)}
disabled={isRootUser || isSelf}
@@ -631,7 +631,7 @@ function EditMemberDrawer({
<div className="edit-member-drawer__footer-divider" />
<Tooltip title={isRootUser ? ROOT_USER_TOOLTIP : undefined}>
<span className="edit-member-drawer__tooltip-wrapper">
<NoAuthGuard>
<NoAuthGuard testId="no-auth-generate-reset-link">
<Button
onClick={handleGenerateResetLink}
disabled={isGeneratingLink || isRootUser || isLoadingTokenStatus}
@@ -661,7 +661,7 @@ function EditMemberDrawer({
Cancel
</Button>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-save-member">
<Button
variant="solid"
color="primary"

View File

@@ -0,0 +1,113 @@
import {
useCreateResetPasswordToken,
useDeleteUser,
useGetResetPasswordToken,
useGetRolesByUserID,
useGetUser,
useRemoveUserRoleByUserIDAndRoleID,
useSetRoleByUserID,
useUpdateMyUserV2,
useUpdateUser,
} from 'api/generated/services/users';
import { MemberStatus } from 'container/MembersSettings/utils';
import { managedRoles } from 'mocks-server/__mockdata__/roles';
import { screen } from 'tests/test-utils';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
import EditMemberDrawer from '../EditMemberDrawer';
jest.mock('api/generated/services/users', () => ({
useDeleteUser: jest.fn(),
useGetUser: jest.fn(),
useGetRolesByUserID: jest.fn(),
useRemoveUserRoleByUserIDAndRoleID: jest.fn(),
useUpdateUser: jest.fn(),
useUpdateMyUserV2: jest.fn(),
useSetRoleByUserID: jest.fn(),
useGetResetPasswordToken: jest.fn(),
useCreateResetPasswordToken: jest.fn(),
getGetRolesByUserIDQueryKey: ({ id }: { id: string }): string[] => [
`/api/v2/users/${id}/roles`,
],
}));
const activeMember = {
id: 'user-1',
name: 'Alice Smith',
email: 'alice@signoz.io',
status: MemberStatus.Active,
joinedOn: '1700000000000',
updatedAt: '1710000000000',
};
function setupMocks(): void {
(useGetUser as jest.Mock).mockReturnValue({
data: {
data: {
id: 'user-1',
displayName: 'Alice Smith',
email: 'alice@signoz.io',
status: 'active',
userRoles: [
{ id: 'ur-1', roleId: managedRoles[0].id, role: managedRoles[0] },
],
},
},
isLoading: false,
refetch: jest.fn(),
});
(useGetRolesByUserID as jest.Mock).mockReturnValue({
data: { data: [managedRoles[0]] },
isLoading: false,
});
(useRemoveUserRoleByUserIDAndRoleID as jest.Mock).mockReturnValue({
mutateAsync: jest.fn().mockResolvedValue({}),
isLoading: false,
});
(useUpdateUser as jest.Mock).mockReturnValue({
mutateAsync: jest.fn().mockResolvedValue({}),
isLoading: false,
});
(useUpdateMyUserV2 as jest.Mock).mockReturnValue({
mutateAsync: jest.fn().mockResolvedValue({}),
isLoading: false,
});
(useSetRoleByUserID as jest.Mock).mockReturnValue({
mutateAsync: jest.fn().mockResolvedValue({}),
isLoading: false,
});
(useDeleteUser as jest.Mock).mockReturnValue({
mutate: jest.fn(),
isLoading: false,
});
(useGetResetPasswordToken as jest.Mock).mockReturnValue({
data: undefined,
isLoading: false,
isError: false,
});
(useCreateResetPasswordToken as jest.Mock).mockReturnValue({
mutateAsync: jest.fn().mockResolvedValue({}),
isLoading: false,
});
}
describe('EditMemberDrawer — no-auth mode', () => {
beforeEach(() => {
jest.clearAllMocks();
setupMocks();
});
it('renders no-auth guard wrappers for all member mutation buttons', () => {
renderWithNoAuth(
<EditMemberDrawer
member={activeMember}
open
onClose={jest.fn()}
onComplete={jest.fn()}
/>,
);
expect(screen.getByTestId('no-auth-delete-member')).toBeInTheDocument();
expect(screen.getByTestId('no-auth-generate-reset-link')).toBeInTheDocument();
expect(screen.getByTestId('no-auth-save-member')).toBeInTheDocument();
});
});

View File

@@ -126,7 +126,7 @@ function KeyFormPhase({
]}
enabled={!!accountId}
>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-create-key">
<Button
type="submit"
// @ts-expect-error -- form prop not in @signozhq/ui Button type - TODO: Fix this - @SagarRajput

View File

@@ -175,7 +175,7 @@ function EditKeyForm({
]}
enabled={!!accountId && !!keyItem?.id}
>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-revoke-key">
<Button variant="link" color="destructive" onClick={onRevokeClick}>
<Trash2 size={12} />
Revoke Key
@@ -191,7 +191,7 @@ function EditKeyForm({
checks={[buildAPIKeyUpdatePermission(keyItem?.id ?? '')]}
enabled={!!accountId && !!keyItem?.id}
>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-save-key">
<Button
type="submit"
// @ts-expect-error -- form prop not in @signozhq/ui Button type - TODO: Fix this - @SagarRajput

View File

@@ -53,7 +53,7 @@ export function RevokeKeyFooter({
]}
enabled={!!accountId && !!keyId}
>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-confirm-revoke">
<Button
variant="solid"
color="destructive"

View File

@@ -437,7 +437,7 @@ function ServiceAccountDrawer({
]}
enabled={!isDeleted && !!selectedAccountId}
>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-add-key">
<Button
variant="outlined"
size="sm"
@@ -553,7 +553,7 @@ function ServiceAccountDrawer({
checks={[buildSADeletePermission(selectedAccountId ?? '')]}
enabled={!!selectedAccountId}
>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-delete-service-account">
<Button
variant="link"
color="destructive"
@@ -573,7 +573,7 @@ function ServiceAccountDrawer({
<X size={14} />
Cancel
</Button>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-save-service-account">
<Button
variant="solid"
color="primary"

View File

@@ -0,0 +1,137 @@
import type { ReactNode } from 'react';
import { listRolesSuccessResponse } from 'mocks-server/__mockdata__/roles';
import { rest, server } from 'mocks-server/server';
import { NuqsTestingAdapter } from 'nuqs/adapters/testing';
import { screen, waitFor } from 'tests/test-utils';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
import ServiceAccountDrawer from '../ServiceAccountDrawer';
const ROLES_ENDPOINT = '*/api/v1/roles';
const SA_KEYS_ENDPOINT = '*/api/v1/service_accounts/:id/keys';
const SA_ENDPOINT = '*/api/v1/service_accounts/sa-1';
const SA_ROLES_ENDPOINT = '*/api/v1/service_accounts/:id/roles';
const SA_ROLE_DELETE_ENDPOINT = '*/api/v1/service_accounts/:id/roles/:rid';
const activeAccountResponse = {
id: 'sa-1',
name: 'CI Bot',
email: 'ci-bot@signoz.io',
roles: ['signoz-admin'],
status: 'ACTIVE',
createdAt: '2026-01-01T00:00:00Z',
updatedAt: '2026-01-02T00:00:00Z',
};
jest.mock('@signozhq/ui/drawer', () => ({
...jest.requireActual('@signozhq/ui/drawer'),
DrawerWrapper: ({
children,
footer,
open,
}: {
children?: ReactNode;
footer?: ReactNode;
open: boolean;
}): JSX.Element | null =>
open ? (
<div>
{children}
{footer}
</div>
) : null,
}));
jest.mock('@signozhq/ui/sonner', () => ({
...jest.requireActual('@signozhq/ui/sonner'),
toast: { success: jest.fn(), error: jest.fn() },
}));
function renderDrawer(
searchParams: Record<string, string> = { account: 'sa-1' },
): ReturnType<typeof renderWithNoAuth> {
return renderWithNoAuth(
<NuqsTestingAdapter searchParams={searchParams} hasMemory>
<ServiceAccountDrawer onSuccess={jest.fn()} />
</NuqsTestingAdapter>,
);
}
function setupBaseHandlers(): void {
server.use(
rest.get(ROLES_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json(listRolesSuccessResponse)),
),
rest.get(SA_KEYS_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ data: [] })),
),
rest.get(SA_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ data: activeAccountResponse })),
),
rest.put(SA_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ status: 'success', data: {} })),
),
rest.delete(SA_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ status: 'success', data: {} })),
),
rest.get(SA_ROLES_ENDPOINT, (_, res, ctx) =>
res(
ctx.status(200),
ctx.json({
data: listRolesSuccessResponse.data.filter(
(r) => r.name === 'signoz-admin',
),
}),
),
),
rest.post(SA_ROLES_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ status: 'success', data: {} })),
),
rest.delete(SA_ROLE_DELETE_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ status: 'success', data: {} })),
),
);
}
describe('ServiceAccountDrawer — no-auth mode', () => {
beforeEach(() => {
jest.clearAllMocks();
setupBaseHandlers();
});
afterEach(() => {
server.resetHandlers();
});
it('renders no-auth guards in the Overview tab footer', async () => {
renderDrawer();
await waitFor(() => {
expect(
screen.getByTestId('no-auth-delete-service-account'),
).toBeInTheDocument();
expect(
screen.getByTestId('no-auth-save-service-account'),
).toBeInTheDocument();
});
});
it('renders no-auth guard on Add Key button in Keys tab header', async () => {
renderDrawer({ account: 'sa-1', tab: 'keys' });
await waitFor(() => {
expect(screen.getByTestId('no-auth-add-key')).toBeInTheDocument();
});
});
it('does not render no-auth guards when drawer is closed', () => {
renderDrawer({});
expect(
screen.queryByTestId('no-auth-delete-service-account'),
).not.toBeInTheDocument();
expect(
screen.queryByTestId('no-auth-save-service-account'),
).not.toBeInTheDocument();
});
});

View File

@@ -201,7 +201,7 @@ function MembersSettings(): JSX.Element {
/>
</div>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-invite-member">
<Button
variant="solid"
color="primary"

View File

@@ -0,0 +1,51 @@
import type { TypesUserDTO } from 'api/generated/services/sigNoz.schemas';
import { rest, server } from 'mocks-server/server';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
import { screen } from 'tests/test-utils';
import MembersSettings from '../MembersSettings';
jest.mock('@signozhq/ui/sonner', () => ({
...jest.requireActual('@signozhq/ui/sonner'),
toast: {
success: jest.fn(),
error: jest.fn(),
},
}));
const USERS_ENDPOINT = '*/api/v2/users';
const mockUsers: TypesUserDTO[] = [
{
id: 'user-1',
displayName: 'Alice Smith',
email: 'alice@signoz.io',
status: 'active',
createdAt: new Date('2024-01-01T00:00:00.000Z'),
orgId: 'org-1',
},
];
describe('MembersSettings — no-auth mode', () => {
beforeEach(() => {
jest.clearAllMocks();
server.use(
rest.get(USERS_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ data: mockUsers })),
),
);
});
afterEach(() => {
server.resetHandlers();
});
it('renders the no-auth sentinel and disables the Invite member button', async () => {
renderWithNoAuth(<MembersSettings />);
await screen.findByText('Alice Smith');
expect(screen.getByTestId('no-auth-invite-member')).toBeInTheDocument();
expect(screen.getByRole('button', { name: /invite member/i })).toBeDisabled();
});
});

View File

@@ -136,7 +136,7 @@ function UserInfo(): JSX.Element {
</div>
<div className="user-info-update-section">
<NoAuthGuard>
<NoAuthGuard testId="no-auth-update-name">
<Button
type="default"
className="periscope-btn secondary"
@@ -147,7 +147,7 @@ function UserInfo(): JSX.Element {
</Button>
</NoAuthGuard>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-reset-password">
<Button
type="default"
className="periscope-btn secondary"
@@ -166,7 +166,7 @@ function UserInfo(): JSX.Element {
closable
onCancel={hideUpdateNameModal}
footer={[
<NoAuthGuard key="submit">
<NoAuthGuard key="submit" testId="no-auth-update-name-submit">
<Button
type="primary"
icon={<Check size={16} />}

View File

@@ -0,0 +1,33 @@
import UserInfo from 'container/MySettings/UserInfo';
import { screen } from 'tests/test-utils';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
jest.mock('api/generated/services/users', () => ({
...jest.requireActual('api/generated/services/users'),
useUpdateMyUserV2: jest.fn(() => ({
mutateAsync: jest.fn(),
isLoading: false,
})),
}));
jest.mock('api/common/logEvent', () => ({
__esModule: true,
default: jest.fn(),
}));
jest.mock('hooks/useNotifications', () => ({
useNotifications: (): any => ({
notifications: {
error: jest.fn(),
success: jest.fn(),
},
}),
}));
describe('UserInfo — no-auth mode', () => {
it('renders no-auth guard wrappers for Update name and Reset password buttons', () => {
renderWithNoAuth(<UserInfo />);
expect(screen.getByTestId('no-auth-update-name')).toBeInTheDocument();
expect(screen.getByTestId('no-auth-reset-password')).toBeInTheDocument();
});
});

View File

@@ -369,7 +369,7 @@ function InviteTeamMembers({
)}
<div className="onboarding-buttons-container">
<NoAuthGuard>
<NoAuthGuard testId="no-auth-onboarding-invite">
<Button
variant="solid"
color="primary"

View File

@@ -0,0 +1,31 @@
import InviteTeamMembers from 'container/OnboardingQuestionaire/InviteTeamMembers/InviteTeamMembers';
import { screen } from 'tests/test-utils';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
jest.mock('api/common/logEvent', () => ({
__esModule: true,
default: jest.fn(),
}));
jest.mock('hooks/useNotifications', () => ({
useNotifications: (): any => ({
notifications: {
error: jest.fn(),
success: jest.fn(),
},
}),
}));
describe('OnboardingQuestionaire InviteTeamMembers — no-auth mode', () => {
it('renders no-auth guard wrapper for the invite button', () => {
renderWithNoAuth(
<InviteTeamMembers
isLoading={false}
teamMembers={null}
setTeamMembers={jest.fn()}
onNext={jest.fn()}
/>,
);
expect(screen.getByTestId('no-auth-onboarding-invite')).toBeInTheDocument();
});
});

View File

@@ -650,7 +650,7 @@ function OnboardingAddDataSource(): JSX.Element {
</div>
<div className="header-right-section">
<NoAuthGuard>
<NoAuthGuard testId="no-auth-invite-teammate">
<Button
type="default"
className="periscope-btn invite-teammate-btn outlined"

View File

@@ -0,0 +1,31 @@
import { screen } from 'tests/test-utils';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
import OnboardingAddDataSource from '../AddDataSource';
jest.mock('api/common/logEvent', () => ({
__esModule: true,
default: jest.fn().mockResolvedValue(undefined),
}));
jest.mock('hooks/useSafeNavigate', () => ({
useSafeNavigate: (): { safeNavigate: jest.Mock } => ({
safeNavigate: jest.fn(),
}),
}));
jest.mock('api/generated/services/global', () => ({
useGetGlobalConfig: jest.fn(() => ({ data: undefined })),
}));
jest.mock('components/LaunchChatSupport/LaunchChatSupport', () => ({
__esModule: true,
default: (): JSX.Element => <button type="button">Contact Support</button>,
}));
describe('OnboardingAddDataSource — no-auth mode', () => {
it('renders no-auth guard wrapper for the invite teammate button', () => {
renderWithNoAuth(<OnboardingAddDataSource />);
expect(screen.getByTestId('no-auth-invite-teammate')).toBeInTheDocument();
});
});

View File

@@ -0,0 +1,32 @@
import InviteTeamMembers from 'container/OnboardingV2Container/InviteTeamMembers/InviteTeamMembers';
import { screen } from 'tests/test-utils';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
jest.mock('api/common/logEvent', () => ({
__esModule: true,
default: jest.fn(),
}));
jest.mock('hooks/useNotifications', () => ({
useNotifications: (): any => ({
notifications: {
error: jest.fn(),
success: jest.fn(),
},
}),
}));
describe('OnboardingV2Container InviteTeamMembers — no-auth mode', () => {
it('renders no-auth guard wrapper for the invite button', () => {
renderWithNoAuth(
<InviteTeamMembers
isLoading={false}
teamMembers={null}
setTeamMembers={jest.fn()}
onNext={jest.fn()}
onClose={jest.fn()}
/>,
);
expect(screen.getByTestId('no-auth-v2-invite')).toBeInTheDocument();
});
});

View File

@@ -282,7 +282,7 @@ function InviteTeamMembers({
Cancel
</Button>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-v2-invite">
<Button
type="primary"
className="next-button periscope-btn primary"

View File

@@ -0,0 +1,32 @@
import { fireEvent, screen } from 'tests/test-utils';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
import CreateEdit from './CreateEdit';
import { mockGoogleAuthDomain } from '../__tests__/mocks';
describe('CreateEdit — no-auth mode', () => {
it('renders no-auth guard sentinel for Save Changes button', () => {
renderWithNoAuth(
<CreateEdit
isCreate={false}
record={mockGoogleAuthDomain}
onClose={jest.fn()}
/>,
);
expect(screen.getByTestId('no-auth-save-auth-domain')).toBeInTheDocument();
});
it('renders no-auth guard sentinel for Save Changes button in create mode after selecting provider', async () => {
renderWithNoAuth(<CreateEdit isCreate onClose={jest.fn()} />);
const configureButtons = await screen.findAllByRole('button', {
name: /configure/i,
});
fireEvent.click(configureButtons[0]);
await expect(
screen.findByTestId('no-auth-save-auth-domain'),
).resolves.toBeInTheDocument();
});
});

View File

@@ -258,7 +258,7 @@ function CreateOrEdit(props: CreateOrEditProps): JSX.Element {
Cancel
</Button>
)}
<NoAuthGuard>
<NoAuthGuard testId="no-auth-save-auth-domain">
<Button
onClick={onSubmitHandler}
variant="solid"

View File

@@ -66,7 +66,7 @@ function SSOEnforcementToggle({
};
return (
<NoAuthGuard>
<NoAuthGuard testId="no-auth-sso-toggle">
<Switch disabled={isLoading} value={isChecked} onChange={onChangeHandler} />
</NoAuthGuard>
);

View File

@@ -0,0 +1,26 @@
import { rest, server } from 'mocks-server/server';
import { screen, waitFor } from 'tests/test-utils';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
import AuthDomain from '../index';
import { AUTH_DOMAINS_LIST_ENDPOINT, mockEmptyDomainsResponse } from './mocks';
describe('AuthDomain — no-auth mode', () => {
afterEach(() => {
server.resetHandlers();
});
it('renders no-auth guard sentinel for Add Domain button', async () => {
server.use(
rest.get(AUTH_DOMAINS_LIST_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json(mockEmptyDomainsResponse)),
),
);
renderWithNoAuth(<AuthDomain />);
await waitFor(() => {
expect(screen.getByTestId('no-auth-add-domain')).toBeInTheDocument();
});
});
});

View File

@@ -0,0 +1,36 @@
import { screen } from 'tests/test-utils';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
jest.mock('@signozhq/ui/switch', () => ({
...jest.requireActual('@signozhq/ui/switch'),
Switch: ({
value,
disabled,
}: {
value: boolean;
disabled?: boolean;
}): JSX.Element => (
<button
type="button"
role="switch"
aria-checked={value}
disabled={disabled}
/>
),
}));
import SSOEnforcementToggle from '../SSOEnforcementToggle';
import { mockGoogleAuthDomain } from './mocks';
describe('SSOEnforcementToggle — no-auth mode', () => {
it('renders no-auth guard sentinel when isNoAuthMode is true', () => {
renderWithNoAuth(
<SSOEnforcementToggle
isDefaultChecked={false}
record={mockGoogleAuthDomain}
/>,
);
expect(screen.getByTestId('no-auth-sso-toggle')).toBeInTheDocument();
});
});

View File

@@ -154,7 +154,7 @@ function AuthDomain(): JSX.Element {
width: 100,
render: (_, record: AuthtypesGettableAuthDomainDTO): JSX.Element => (
<section className="auth-domain-list-column-action">
<NoAuthGuard>
<NoAuthGuard testId="no-auth-configure-sso">
<Button
className="auth-domain-list-action-link"
onClick={(): void => setRecord(record)}
@@ -163,7 +163,7 @@ function AuthDomain(): JSX.Element {
Configure {SSOType.get(record.config?.ssoType || '')}
</Button>
</NoAuthGuard>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-delete-domain">
<Button
className="auth-domain-list-action-link delete"
onClick={(): void => showDeleteModal(record)}
@@ -183,7 +183,7 @@ function AuthDomain(): JSX.Element {
<div className="auth-domain">
<section className="auth-domain-header">
<h3 className="auth-domain-title">Authenticated Domains</h3>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-add-domain">
<Button
prefix={<Plus size="md" />}
onClick={(): void => {
@@ -238,7 +238,7 @@ function AuthDomain(): JSX.Element {
>
Cancel
</Button>,
<NoAuthGuard key="submit">
<NoAuthGuard key="submit" testId="no-auth-delete-domain-confirm">
<Button
prefix={<Trash2 size={16} />}
onClick={handleDeleteDomain}

View File

@@ -0,0 +1,37 @@
import { Form } from 'antd';
import InviteUserModal from 'container/OrganizationSettings/InviteUserModal/InviteUserModal';
import { screen } from 'tests/test-utils';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
jest.mock('hooks/useNotifications', () => ({
useNotifications: (): any => ({
notifications: {
error: jest.fn(),
success: jest.fn(),
},
}),
}));
jest.mock('api/v1/invite/create', () => ({
__esModule: true,
default: jest.fn(),
}));
function TestWrapper(): JSX.Element {
const [form] = Form.useForm();
return (
<InviteUserModal
isInviteTeamMemberModalOpen
toggleModal={jest.fn()}
form={form}
onClose={jest.fn()}
/>
);
}
describe('InviteUserModal — no-auth mode', () => {
it('renders no-auth guard wrapper for the invite submit button', () => {
renderWithNoAuth(<TestWrapper />);
expect(screen.getByTestId('no-auth-invite-user')).toBeInTheDocument();
});
});

View File

@@ -86,7 +86,10 @@ function InviteUserModal(props: InviteUserModalProps): JSX.Element {
ns: 'common',
})}
</Button>,
<NoAuthGuard key={t('invite_team_members').toString()}>
<NoAuthGuard
key={t('invite_team_members').toString()}
testId="no-auth-invite-user"
>
<Button
onClick={modalForm.submit}
data-testid="invite-team-members-button"

View File

@@ -0,0 +1,12 @@
import { screen } from 'tests/test-utils';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
import CreateRoleModal from './CreateRoleModal';
describe('CreateRoleModal — no-auth mode', () => {
it('renders no-auth guard sentinel for Create Role button', () => {
renderWithNoAuth(<CreateRoleModal isOpen onClose={jest.fn()} />);
expect(screen.getByTestId('no-auth-save-role')).toBeInTheDocument();
});
});

View File

@@ -149,7 +149,7 @@ function CreateRoleModal({
<X size={14} />
Cancel
</Button>,
<NoAuthGuard key="submit">
<NoAuthGuard key="submit" testId="no-auth-save-role">
<Button
variant="solid"
color="primary"

View File

@@ -43,7 +43,7 @@ function RolesSettings(): JSX.Element {
/>
{isRolesEnabled && (
<AuthZTooltip checks={[RoleCreatePermission]}>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-create-custom-role">
<Button
variant="solid"
color="primary"

View File

@@ -0,0 +1,37 @@
import { listRolesSuccessResponse } from 'mocks-server/__mockdata__/roles';
import { rest, server } from 'mocks-server/server';
import { useAuthZ } from 'hooks/useAuthZ/useAuthZ';
import { mockUseAuthZGrantAll } from 'tests/authz-test-utils';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
import { screen } from 'tests/test-utils';
import RolesSettings from '../RolesSettings';
jest.mock('hooks/useAuthZ/useAuthZ');
const mockUseAuthZ = useAuthZ as jest.MockedFunction<typeof useAuthZ>;
const ROLES_ENDPOINT = '*/api/v1/roles';
describe('RolesSettings — no-auth mode', () => {
beforeEach(() => {
mockUseAuthZ.mockImplementation(mockUseAuthZGrantAll);
server.use(
rest.get(ROLES_ENDPOINT, (_req, res, ctx) =>
res(ctx.status(200), ctx.json(listRolesSuccessResponse)),
),
);
});
afterEach(() => {
jest.clearAllMocks();
server.resetHandlers();
});
it('renders the no-auth sentinel for the Custom role button', async () => {
renderWithNoAuth(<RolesSettings />);
await screen.findByText('signoz-admin');
expect(screen.getByTestId('no-auth-create-custom-role')).toBeInTheDocument();
});
});

View File

@@ -265,7 +265,7 @@ function ServiceAccountsSettings(): JSX.Element {
</div>
<AuthZTooltip checks={[SACreatePermission]}>
<NoAuthGuard>
<NoAuthGuard testId="no-auth-new-service-account">
<Button
variant="solid"
color="primary"

View File

@@ -0,0 +1,70 @@
import { listRolesSuccessResponse } from 'mocks-server/__mockdata__/roles';
import { rest, server } from 'mocks-server/server';
import { NuqsTestingAdapter } from 'nuqs/adapters/testing';
import { setupAuthzAdmin } from 'tests/authz-test-utils';
import { renderWithNoAuth } from 'tests/no-auth-test-utils';
import { screen } from 'tests/test-utils';
import ServiceAccountsSettings from '../ServiceAccountsSettings';
const SA_LIST_ENDPOINT = '*/api/v1/service_accounts';
const SA_ENDPOINT = '*/api/v1/service_accounts/:id';
const SA_KEYS_ENDPOINT = '*/api/v1/service_accounts/:id/keys';
const SA_ROLES_ENDPOINT = '*/api/v1/service_accounts/:id/roles';
const ROLES_ENDPOINT = '*/api/v1/roles';
const mockServiceAccountsAPI = [
{
id: 'sa-1',
name: 'CI Bot',
email: 'ci-bot@signoz.io',
roles: ['signoz-admin'],
status: 'ACTIVE',
createdAt: 1700000000,
updatedAt: 1700000001,
},
];
describe('ServiceAccountsSettings — no-auth mode', () => {
beforeEach(() => {
jest.clearAllMocks();
server.use(
setupAuthzAdmin(),
rest.get(SA_LIST_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ data: mockServiceAccountsAPI })),
),
rest.get(SA_ENDPOINT, (req, res, ctx) => {
const { id } = req.params as { id: string };
const account = mockServiceAccountsAPI.find((a) => a.id === id);
return account
? res(ctx.status(200), ctx.json({ data: account }))
: res(ctx.status(404), ctx.json({ message: 'Not found' }));
}),
rest.get(SA_KEYS_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ data: [] })),
),
rest.get(SA_ROLES_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ data: [] })),
),
rest.get(ROLES_ENDPOINT, (_, res, ctx) =>
res(ctx.status(200), ctx.json(listRolesSuccessResponse)),
),
);
});
afterEach(() => {
server.resetHandlers();
});
it('renders the no-auth sentinel for the New Service Account button', async () => {
renderWithNoAuth(
<NuqsTestingAdapter>
<ServiceAccountsSettings />
</NuqsTestingAdapter>,
);
await screen.findByText('CI Bot');
expect(screen.getByTestId('no-auth-new-service-account')).toBeInTheDocument();
});
});

View File

@@ -0,0 +1,25 @@
import type { IAppContext } from 'providers/App/types';
import { render } from './test-utils';
export const NO_AUTH_CONTEXT: Partial<IAppContext> = {
isNoAuthMode: true,
isPreflightLoading: false,
};
/**
* Renders a component with no-auth mode enabled in the app context.
* Mirrors the authz-test-utils pattern for consistent no-auth test setup.
*/
export function renderWithNoAuth(
...args: Parameters<typeof render>
): ReturnType<typeof render> {
const [ui, options, providerProps = {}] = args;
return render(ui, options, {
...providerProps,
appContextOverrides: {
...providerProps.appContextOverrides,
...NO_AUTH_CONTEXT,
},
});
}