import { render, fireEvent } from "@testing-library/react";
|
import { Provider } from "mobx-react";
|
import { SkipButton } from "../buttons";
|
|
jest.mock("@humansignal/ui", () => {
|
const { forwardRef } = jest.requireActual("react");
|
return {
|
Button: forwardRef(({ children, disabled, tooltip, onClick, ...props }: any, ref: any) => {
|
return (
|
<button {...props} ref={ref} data-testid="skip-button" disabled={disabled} title={tooltip} onClick={onClick}>
|
{children}
|
</button>
|
);
|
}),
|
Tooltip: ({ children, title }: any) => {
|
return (
|
<div data-testid="tooltip" title={title}>
|
{children}
|
</div>
|
);
|
},
|
};
|
});
|
|
jest.mock("@humansignal/icons", () => ({
|
IconInfoOutline: ({ width, height, className }: any) => (
|
<svg data-testid="info-icon" width={width} height={height} className={className} />
|
),
|
}));
|
|
const createMockStore = (overrides: any = {}) => ({
|
task: { id: 1, allow_skip: true, ...overrides.task },
|
skipTask: jest.fn(),
|
hasInterface: jest.fn((name: string) => overrides.interfaces?.includes(name) ?? false),
|
annotationStore: {
|
selected: {
|
submissionInProgress: jest.fn(),
|
},
|
},
|
commentStore: {
|
commentFormSubmit: jest.fn(),
|
},
|
...overrides,
|
});
|
|
// Helper to set up window.APP_SETTINGS for role-based tests
|
const setupAppSettings = (role?: string) => {
|
(window as any).APP_SETTINGS = {
|
user: {
|
role,
|
},
|
};
|
};
|
|
describe("SkipButton", () => {
|
beforeEach(() => {
|
jest.clearAllMocks();
|
// Reset APP_SETTINGS before each test
|
(window as any).APP_SETTINGS = undefined;
|
});
|
|
test("Skip button disabled when allow_skip=false", () => {
|
const mockStore = createMockStore({
|
task: { id: 1, allow_skip: false },
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={false} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
expect(button).toBeDisabled();
|
expect(button).toHaveAttribute("title", "This task cannot be skipped");
|
});
|
|
test("Skip button enabled when allow_skip=true", () => {
|
const mockStore = createMockStore({
|
task: { id: 1, allow_skip: true },
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={false} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
expect(button).not.toBeDisabled();
|
expect(button).toHaveAttribute("title", "Cancel (skip) task [ Ctrl+Space ]");
|
});
|
|
test("Skip button enabled when allow_skip is undefined (default behavior)", () => {
|
const mockStore = createMockStore({
|
task: { id: 1 }, // no allow_skip property
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={false} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
expect(button).not.toBeDisabled();
|
expect(button).toHaveAttribute("title", "Cancel (skip) task [ Ctrl+Space ]");
|
});
|
|
test("Skip button enabled when allow_skip=null", () => {
|
const mockStore = createMockStore({
|
task: { id: 1, allow_skip: null },
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={false} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
expect(button).not.toBeDisabled();
|
expect(button).toHaveAttribute("title", "Cancel (skip) task [ Ctrl+Space ]");
|
});
|
|
test("Skip button onClick doesn't trigger when allow_skip=false", () => {
|
const mockStore = createMockStore({
|
task: { id: 1, allow_skip: false },
|
interfaces: ["skip"],
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={false} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
fireEvent.click(button);
|
|
expect(onSkipWithComment).not.toHaveBeenCalled();
|
expect(mockStore.skipTask).not.toHaveBeenCalled();
|
});
|
|
test("Skip button onClick triggers when allow_skip=true", async () => {
|
const mockStore = createMockStore({
|
task: { id: 1, allow_skip: true },
|
interfaces: ["skip", "comments:skip"],
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={false} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
fireEvent.click(button);
|
|
expect(onSkipWithComment).toHaveBeenCalled();
|
});
|
|
test("Skip button respects other disabled conditions", () => {
|
const mockStore = createMockStore({
|
task: { id: 1, allow_skip: true },
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={true} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
expect(button).toBeDisabled();
|
});
|
|
// Role-based tests (OW=Owner, AD=Admin, MA=Manager can force-skip)
|
test("Skip button enabled when allow_skip=false but user is Owner (OW)", () => {
|
setupAppSettings("OW");
|
const mockStore = createMockStore({
|
task: { id: 1, allow_skip: false },
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={false} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
expect(button).not.toBeDisabled();
|
expect(button).toHaveAttribute("title", "Cancel (skip) task [ Ctrl+Space ]");
|
// Check that info icon is shown for managers when task is unskippable
|
expect(getByTestId("info-icon")).toBeInTheDocument();
|
});
|
|
test("Skip button enabled when allow_skip=false but user is Admin (AD)", () => {
|
setupAppSettings("AD");
|
const mockStore = createMockStore({
|
task: { id: 1, allow_skip: false },
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={false} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
expect(button).not.toBeDisabled();
|
expect(button).toHaveAttribute("title", "Cancel (skip) task [ Ctrl+Space ]");
|
// Check that info icon is shown for managers when task is unskippable
|
expect(getByTestId("info-icon")).toBeInTheDocument();
|
});
|
|
test("Skip button enabled when allow_skip=false but user is Manager (MA)", () => {
|
setupAppSettings("MA");
|
const mockStore = createMockStore({
|
task: { id: 1, allow_skip: false },
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={false} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
expect(button).not.toBeDisabled();
|
expect(button).toHaveAttribute("title", "Cancel (skip) task [ Ctrl+Space ]");
|
// Check that info icon is shown for managers when task is unskippable
|
expect(getByTestId("info-icon")).toBeInTheDocument();
|
});
|
|
test("Skip button disabled when allow_skip=false and user is Annotator (AN)", () => {
|
setupAppSettings("AN");
|
const mockStore = createMockStore({
|
task: { id: 1, allow_skip: false },
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={false} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
expect(button).toBeDisabled();
|
expect(button).toHaveAttribute("title", "This task cannot be skipped");
|
});
|
|
test("Skip button disabled when allow_skip=false and user is Reviewer (RE)", () => {
|
setupAppSettings("RE");
|
const mockStore = createMockStore({
|
task: { id: 1, allow_skip: false },
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={false} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
expect(button).toBeDisabled();
|
expect(button).toHaveAttribute("title", "This task cannot be skipped");
|
});
|
|
test("Skip button onClick triggers when allow_skip=false but user is Manager", () => {
|
setupAppSettings("MA");
|
const mockStore = createMockStore({
|
task: { id: 1, allow_skip: false },
|
interfaces: ["skip", "comments:skip"],
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={false} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
fireEvent.click(button);
|
|
expect(onSkipWithComment).toHaveBeenCalled();
|
});
|
|
test("Skip button shows normal tooltip when allow_skip=true even for Manager", () => {
|
setupAppSettings("MA");
|
const mockStore = createMockStore({
|
task: { id: 1, allow_skip: true },
|
});
|
const onSkipWithComment = jest.fn();
|
|
const { getByTestId, queryByTestId } = render(
|
<Provider store={mockStore}>
|
<SkipButton disabled={false} store={mockStore as any} onSkipWithComment={onSkipWithComment} />
|
</Provider>,
|
);
|
|
const button = getByTestId("skip-button");
|
expect(button).not.toBeDisabled();
|
// When task allows skip, show normal tooltip even if user is manager
|
expect(button).toHaveAttribute("title", "Cancel (skip) task [ Ctrl+Space ]");
|
// Info icon should not be shown when task allows skip
|
expect(queryByTestId("info-icon")).not.toBeInTheDocument();
|
});
|
});
|