mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-27 18:57:09 +00:00
fix: update NodeCard cordon tests for paid-tier gate parity (#1571)
This commit is contained in:
@@ -55,23 +55,24 @@ describe('NodeCard', () => {
|
|||||||
expect(screen.queryByText('Running')).not.toBeInTheDocument();
|
expect(screen.queryByText('Running')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hides the actions menu when the user lacks node:manage and no edit/delete affordances', () => {
|
it('hides the actions menu for a free-tier user', () => {
|
||||||
useAuthMock.mockReturnValue({ isAdmin: false, can: vi.fn(() => false) });
|
|
||||||
useLicenseMock.mockReturnValue({ isPaid: false });
|
useLicenseMock.mockReturnValue({ isPaid: false });
|
||||||
render(<NodeCard {...baseProps(onlineNode())} />);
|
render(<NodeCard {...baseProps(onlineNode())} />);
|
||||||
expect(screen.queryByRole('button', { name: 'Node actions' })).not.toBeInTheDocument();
|
expect(screen.queryByRole('button', { name: 'Node actions' })).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exposes the actions menu (cordon entry point) for a Community admin with node:manage', () => {
|
it('exposes the actions menu (cordon entry point) for a paid admin', () => {
|
||||||
useLicenseMock.mockReturnValue({ isPaid: false });
|
useLicenseMock.mockReturnValue({ isPaid: true });
|
||||||
render(<NodeCard {...baseProps(onlineNode())} />);
|
render(<NodeCard {...baseProps(onlineNode())} />);
|
||||||
|
// With no edit/delete affordances wired, the menu renders iff cordon is
|
||||||
|
// allowed: isPaid && can('node:manage'). The admin's can() returns true.
|
||||||
expect(screen.getByRole('button', { name: 'Node actions' })).toBeInTheDocument();
|
expect(screen.getByRole('button', { name: 'Node actions' })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exposes the cordon control for a node-admin via the node:manage permission', async () => {
|
it('exposes the cordon control for a node-admin via the node:manage permission', async () => {
|
||||||
const can = vi.fn((action: string) => action === 'node:manage');
|
const can = vi.fn((action: string) => action === 'node:manage');
|
||||||
useAuthMock.mockReturnValue({ isAdmin: false, can });
|
useAuthMock.mockReturnValue({ isAdmin: false, can });
|
||||||
useLicenseMock.mockReturnValue({ isPaid: false });
|
useLicenseMock.mockReturnValue({ isPaid: true });
|
||||||
render(<NodeCard {...baseProps(onlineNode())} />);
|
render(<NodeCard {...baseProps(onlineNode())} />);
|
||||||
|
|
||||||
await userEvent.click(screen.getByRole('button', { name: 'Node actions' }));
|
await userEvent.click(screen.getByRole('button', { name: 'Node actions' }));
|
||||||
@@ -79,18 +80,18 @@ describe('NodeCard', () => {
|
|||||||
expect(can).toHaveBeenCalledWith('node:manage', 'node', '2');
|
expect(can).toHaveBeenCalledWith('node:manage', 'node', '2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hides the cordon control from a user lacking node:manage', () => {
|
it('hides the cordon control from a paid user lacking node:manage', () => {
|
||||||
useAuthMock.mockReturnValue({ isAdmin: false, can: vi.fn(() => false) });
|
useAuthMock.mockReturnValue({ isAdmin: false, can: vi.fn(() => false) });
|
||||||
useLicenseMock.mockReturnValue({ isPaid: false });
|
useLicenseMock.mockReturnValue({ isPaid: true });
|
||||||
render(<NodeCard {...baseProps(onlineNode())} />);
|
render(<NodeCard {...baseProps(onlineNode())} />);
|
||||||
// node:manage alone must not surface cordon when false to a deployer/viewer/auditor.
|
// The paid tier alone must not surface cordon to a deployer/viewer/auditor.
|
||||||
expect(screen.queryByRole('button', { name: 'Node actions' })).not.toBeInTheDocument();
|
expect(screen.queryByRole('button', { name: 'Node actions' })).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows Uncordon when the node is already cordoned', async () => {
|
it('shows Uncordon when the node is already cordoned', async () => {
|
||||||
const can = vi.fn((action: string) => action === 'node:manage');
|
const can = vi.fn((action: string) => action === 'node:manage');
|
||||||
useAuthMock.mockReturnValue({ isAdmin: false, can });
|
useAuthMock.mockReturnValue({ isAdmin: false, can });
|
||||||
useLicenseMock.mockReturnValue({ isPaid: false });
|
useLicenseMock.mockReturnValue({ isPaid: true });
|
||||||
render(<NodeCard {...baseProps({ ...onlineNode(), cordoned: true, cordoned_reason: 'patching' })} />);
|
render(<NodeCard {...baseProps({ ...onlineNode(), cordoned: true, cordoned_reason: 'patching' })} />);
|
||||||
|
|
||||||
await userEvent.click(screen.getByRole('button', { name: 'Node actions' }));
|
await userEvent.click(screen.getByRole('button', { name: 'Node actions' }));
|
||||||
@@ -103,13 +104,13 @@ describe('NodeCard', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
it('renders the update button for an admin when an update is available', () => {
|
it('renders the update button for an admin when an update is available', () => {
|
||||||
useAuthMock.mockReturnValue({ isAdmin: true, can: vi.fn(() => true) });
|
useAuthMock.mockReturnValue({ isAdmin: true });
|
||||||
render(<NodeCard {...baseProps(onlineNode())} updateStatus={updateAvailableStatus} onUpdate={vi.fn()} />);
|
render(<NodeCard {...baseProps(onlineNode())} updateStatus={updateAvailableStatus} onUpdate={vi.fn()} />);
|
||||||
expect(screen.getByRole('button', { name: /Update/ })).toBeInTheDocument();
|
expect(screen.getByRole('button', { name: /Update/ })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hides the update button for a non-admin but still shows the read-only badge', () => {
|
it('hides the update button for a non-admin but still shows the read-only badge', () => {
|
||||||
useAuthMock.mockReturnValue({ isAdmin: false, can: vi.fn(() => false) });
|
useAuthMock.mockReturnValue({ isAdmin: false });
|
||||||
render(<NodeCard {...baseProps(onlineNode())} updateStatus={updateAvailableStatus} onUpdate={vi.fn()} />);
|
render(<NodeCard {...baseProps(onlineNode())} updateStatus={updateAvailableStatus} onUpdate={vi.fn()} />);
|
||||||
expect(screen.queryByRole('button', { name: /Update/ })).not.toBeInTheDocument();
|
expect(screen.queryByRole('button', { name: /Update/ })).not.toBeInTheDocument();
|
||||||
expect(screen.getByText('Update available')).toBeInTheDocument();
|
expect(screen.getByText('Update available')).toBeInTheDocument();
|
||||||
|
|||||||
Reference in New Issue
Block a user