mirror of
https://github.com/SigNoz/signoz.git
synced 2026-07-04 05:40:31 +01:00
* fix(styles): little fix for callout I will upstream this fix eventually * fix(settings): ensure tab content can use height: 100% We will need this fix for the create/edit role page later during json mode * refactor(authz): define the verbs that supports selectorId * refactor(roles): drop old components We will rewrite them * refactor(roles): use css modules on role settings * refactor(roles): rewrite delete role modal to use dialog component * feat(roles): add initial type files * feat(error-in-place): add testId to allow assert on future tests * refactor(permission-denied-full-page): change the wording a little bit to match the API This change was requested by Vikrant * feat(service-account-drawer): add copy button for ID Suggested by https://github.com/SigNoz/platform-pod/issues/2529#issuecomment-4776975323 * fix(service-account-drawer): not validating the permissions correctly for read/update Found at https://github.com/SigNoz/platform-pod/issues/2529#issuecomment-4776975323 * feat(timezone): add little helper to allow format optional dates * refactor(authz): export parse permission to get objectId when needed * test(authz): add helper to grant by prefix * test(test-utils): include tooltip provider * feat(hooks): add hook to block navigation via history * feat(roles): add hook to map API interface to own interface for easier integration * feat(roles): add hook to fetch role permissions * feat(roles): add config object around how to define each section for each resource * feat(roles): add config for monaco when showing json * feat(view-roles): add selected ids component * feat(view-roles): add component row to render selected roles * feat(view-roles): add card component to render each resource selected * feat(view-roles): add overview component to view roles * feat(view-roles): add readonly json viewer * feat(view-roles): add view role page * test(view-roles): add tests for view roles * feat(create-edit-roles): add hook for form validation * feat(create-edit-roles): add hook for unsaved changes * feat(create-edit-roles): add hook for generic logic for create-edit * feat(create-edit-roles): add component to render json * feat(create-edit-roles): add component to add new selectors for a permission * feat(create-edit-roles): add component to select scopes of a permission * feat(create-edit-roles): add component render resources to be selected * feat(create-edit-roles): add component render permission editor * feat(create-edit-roles): add page to create/edit roles * test(create-edit-roles): add tests for page and subcomponents * feat(list-roles): refactor to css modules & add row click to open view role page * fix(list-roles): change description when feature gate is disabled * refactor(roles): removed action labels and use function instead * refactor(authz): add todo about permission.config * feat(roles): add routes for create/edit/view * test(service-account): update missing tests * fix(pr): address comments * fix(pr): rename suffix of hooks from callbacks to actions * fix(pr): remove all usages of getByText * test(use-navigation-blocker): fix test
Testing Guide
Tech Stack
- React Testing Library (RTL)
- Jest (runner, assertions, mocking)
- MSW (Mock Service Worker) for HTTP
- TypeScript (type-safe tests)
- JSDOM (browser-like env)
Unit Testing: What, Why, How
- What: Small, isolated tests for components, hooks, and utilities to verify behavior and edge cases.
- Why: Confidence to refactor, faster feedback than E2E, catches regressions early, documents intended behavior.
- How: Use our test harness with providers, mock external boundaries (APIs, router), assert on visible behavior and accessible roles, not implementation details.
Basic Template
import { render, screen, userEvent, waitFor } from 'tests/test-utils';
import { server, rest } from 'mocks-server/server';
import MyComponent from '../MyComponent';
describe('MyComponent', () => {
it('renders and interacts', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
server.use(
rest.get('*/api/v1/example', (_req, res, ctx) => res(ctx.status(200), ctx.json({ value: 42 })))
);
render(<MyComponent />, undefined, { initialRoute: '/foo' });
expect(await screen.findByText(/value: 42/i)).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: /refresh/i }));
await waitFor(() => expect(screen.getByText(/loading/i)).toBeInTheDocument());
});
});
.cursorrules (Highlights)
- Import from
tests/test-utilsonly. - Prefer
userEventfor real interactions; usefireEventonly for low-level events (scroll/resize/settingscrollTop). - Use MSW to mock network calls; large JSON goes in
mocks-server/__mockdata__. - Keep tests type-safe (
jest.MockedFunction<T>, avoidany). - Prefer accessible queries (
getByRole,findByRole) before text anddata-testid. - Pin time only when asserting relative dates; avoid global fake timers otherwise.
Repo-specific reasons:
- The harness wires Redux, React Query, i18n, timezone, preferences, so importing from RTL directly bypasses critical providers.
- Some infra deps are globally mocked (e.g.,
uplot) to keep tests fast and stable. - For virtualization (react-virtuoso), there is no
userEventscroll helper; usefireEvent.scrollafter settingelement.scrollTop.
Example patterns (from components/QuickFilters/tests/QuickFilters.test.tsx)
MSW overrides per test:
server.use(
rest.get(`${ENVIRONMENT.baseURL}/api/v1/orgs/me/filters/logs`, (_req, res, ctx) =>
res(ctx.status(200), ctx.json(quickFiltersListResponse)),
),
rest.put(`${ENVIRONMENT.baseURL}/api/v1/orgs/me/filters`, async (req, res, ctx) => {
// capture payload if needed
return res(ctx.status(200), ctx.json({}));
}),
);
Mock hooks minimally at module level:
jest.mock('hooks/queryBuilder/useQueryBuilder', () => ({
useQueryBuilder: jest.fn(),
}));
Interact via accessible roles:
const user = userEvent.setup({ pointerEventsCheck: 0 });
await user.click(screen.getByRole('button', { name: /save changes/i }));
expect(screen.getByText(/ADDED FILTERS/i)).toBeInTheDocument();
Virtualized scroll:
const scroller = container.querySelector('[data-test-id="virtuoso-scroller"]') as HTMLElement;
scroller.scrollTop = 500;
fireEvent.scroll(scroller);
Routing-dependent behavior:
render(<Page />, undefined, { initialRoute: '/logs-explorer?panelType=list' });
Notes
- Global mocks configured in Jest:
uplot→__mocks__/uplotMock.ts. - If a test needs custom behavior (e.g., different API response), override with
server.use(...)locally.