Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: masquerade dropdown not showing current selection #30

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
50 changes: 29 additions & 21 deletions src/instructor-toolbar/masquerade-widget/MasqueradeWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
this.state = {
autoFocus: false,
masquerade: 'Staff',
options: [],
active: {},
available: [],
shouldShowUserNameInput: false,
masqueradeUsername: null,
};
Expand Down Expand Up @@ -58,41 +59,49 @@
}

onSuccess(data) {
const options = this.parseAvailableOptions(data);
const { active, available } = this.parseAvailableOptions(data);
this.setState({
options,
active,
available,
});
}

getOptions() {
const options = this.state.available.map((group) => (
<MasqueradeWidgetOption
groupId={group.groupId}
groupName={group.name}
key={group.name}
role={group.role}
selected={this.state.active}
userName={group.userName}
userPartitionId={group.userPartitionId}
userNameInputToggle={(...args) => this.toggle(...args)}
onSubmit={(payload) => this.onSubmit(payload)}

Check warning on line 80 in src/instructor-toolbar/masquerade-widget/MasqueradeWidget.jsx

View check run for this annotation

Codecov / codecov/patch

src/instructor-toolbar/masquerade-widget/MasqueradeWidget.jsx#L80

Added line #L80 was not covered by tests
/>
));
return options;
}

clearError() {
this.props.onError('');
}

toggle(show) {
toggle(show, groupId, groupName, role, userName, userPartitionId) {
this.setState(prevState => ({
autoFocus: true,
masquerade: 'Specific Student...',
masquerade: groupName,
shouldShowUserNameInput: show === undefined ? !prevState.shouldShowUserNameInput : show,
active: {
...prevState.active, groupId, role, userName, userPartitionId,
},
}));
}

parseAvailableOptions(postData) {
const data = postData || {};
const active = data.active || {};
const available = data.available || [];
const options = available.map((group) => (
<MasqueradeWidgetOption
groupId={group.groupId}
groupName={group.name}
key={group.name}
role={group.role}
selected={active}
userName={group.userName}
userPartitionId={group.userPartitionId}
userNameInputToggle={(...args) => this.toggle(...args)}
onSubmit={(payload) => this.onSubmit(payload)}
/>
));
if (active.userName) {
this.setState({
autoFocus: false,
Expand All @@ -105,14 +114,13 @@
} else if (active.role === 'student') {
this.setState({ masquerade: 'Learner' });
}
return options;
return { active, available };
}

render() {
const {
autoFocus,
masquerade,
options,
shouldShowUserNameInput,
masqueradeUsername,
} = this.state;
Expand All @@ -126,7 +134,7 @@
{masquerade}
</Dropdown.Toggle>
<Dropdown.Menu>
{options}
{this.getOptions()}
</Dropdown.Menu>
</Dropdown>
</div>
Expand Down
137 changes: 137 additions & 0 deletions src/instructor-toolbar/masquerade-widget/MasqueradeWidget.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import React from 'react';
import { getAllByRole } from '@testing-library/dom';
import { act } from '@testing-library/react';
import { getConfig } from '@edx/frontend-platform';
import MockAdapter from 'axios-mock-adapter';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import MasqueradeWidget from './MasqueradeWidget';
import {
render, screen, fireEvent, initializeTestStore, waitFor, logUnhandledRequests,
} from '../../setupTest';

const originalConfig = jest.requireActual('@edx/frontend-platform').getConfig();
jest.mock('@edx/frontend-platform', () => ({
...jest.requireActual('@edx/frontend-platform'),
getConfig: jest.fn(),
}));
getConfig.mockImplementation(() => originalConfig);

describe('Masquerade Widget Dropdown', () => {
let mockData;
let courseware;
let mockResponse;
let axiosMock;
let masqueradeUrl;
const masqueradeOptions = [
{
name: 'Staff',
role: 'staff',
},
{
name: 'Specific Student...',
role: 'student',
user_name: '',
},
{
group_id: 1,
name: 'Audit',
role: 'student',
user_partition_id: 50,
},
];

beforeAll(async () => {
const store = await initializeTestStore();
courseware = store.getState().courseware;
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
masqueradeUrl = `${getConfig().LMS_BASE_URL}/courses/${courseware.courseId}/masquerade`;
mockData = {
courseId: courseware.courseId,
onError: () => {},
};
});

beforeEach(() => {
mockResponse = {
success: true,
active: {
course_key: courseware.courseId,
group_id: null,
role: 'staff',
user_name: null,
user_partition_id: null,
group_name: null,
},
available: masqueradeOptions,
};
axiosMock.reset();
axiosMock.onGet(masqueradeUrl).reply(200, mockResponse);
logUnhandledRequests(axiosMock);
});

it('renders masquerade name correctly', async () => {
render(<MasqueradeWidget {...mockData} />);
await waitFor(() => expect(axiosMock.history.get).toHaveLength(1));
expect(screen.getByRole('button')).toHaveTextContent('Staff');
});

masqueradeOptions.forEach((option) => {
it(`marks role ${option.role} as active`, async () => {
const active = {
course_key: courseware.courseId,
group_id: option.group_id ?? null,
role: option.role,
user_name: option.user_name ?? null,
user_partition_id: option.user_partition_id ?? null,
group_name: null,
};

mockResponse = {
success: true,
active,
available: masqueradeOptions,
};

axiosMock.reset();
axiosMock.onGet(masqueradeUrl).reply(200, mockResponse);

const { container } = render(<MasqueradeWidget {...mockData} />);
const dropdownToggle = container.querySelector('.dropdown-toggle');
await act(async () => {
await fireEvent.click(dropdownToggle);
});
const dropdownMenu = container.querySelector('.dropdown-menu');
getAllByRole(dropdownMenu, 'button', { hidden: true }).forEach(button => {
if (button.textContent === option.name) {
expect(button).toHaveClass('active');
} else {
expect(button).not.toHaveClass('active');
}
});
});
});

it('handles the clicks with toggle', async () => {
const { container } = render(<MasqueradeWidget {...mockData} />);
await waitFor(() => expect(axiosMock.history.get).toHaveLength(1));

const dropdownToggle = container.querySelector('.dropdown-toggle');
await act(async () => {
await fireEvent.click(dropdownToggle);
});
const dropdownMenu = container.querySelector('.dropdown-menu');
const studentOption = getAllByRole(dropdownMenu, 'button', { hidden: true }).filter(
button => (button.textContent === 'Specific Student...'),
)[0];
await act(async () => {
await fireEvent.click(studentOption);
});
getAllByRole(dropdownMenu, 'button', { hidden: true }).forEach(button => {
if (button.textContent === 'Specific Student...') {
expect(button).toHaveClass('active');
} else {
expect(button).not.toHaveClass('active');
}
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ class MasqueradeWidgetOption extends Component {
event.target.parentNode.parentNode.click();
const {
groupId,
groupName,
role,
userName,
userPartitionId,
userNameInputToggle,
} = this.props;
const payload = {};
if (userName || userName === '') {
userNameInputToggle(true);
userNameInputToggle(true, groupId, groupName, role, userName, userPartitionId);
return false;
}
if (role) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';
import { getAllByRole } from '@testing-library/dom';
import { act } from '@testing-library/react';
import { getConfig } from '@edx/frontend-platform';
import MasqueradeWidgetOption from './MasqueradeWidgetOption';
import {
render, fireEvent, initializeTestStore,
} from '../../setupTest';

const originalConfig = jest.requireActual('@edx/frontend-platform').getConfig();
jest.mock('@edx/frontend-platform', () => ({
...jest.requireActual('@edx/frontend-platform'),
getConfig: jest.fn(),
}));
getConfig.mockImplementation(() => originalConfig);

describe('Masquerade Widget Dropdown', () => {
let courseware;
let mockDataStaff;
let mockDataStudent;
let active;

beforeAll(async () => {
const store = await initializeTestStore();
courseware = store.getState().courseware;
active = {
courseKey: courseware.courseId,
groupId: null,
role: 'staff',
userName: null,
userPartitionId: null,
groupName: null,
};
mockDataStaff = {
groupId: null,
groupName: 'Staff',
key: 'Staff',
role: 'staff',
selected: active,
userName: null,
userPartitionId: null,
userNameInputToggle: () => {},
onSubmit: () => {},
};
mockDataStudent = {
groupId: null,
groupName: 'Specific Student...',
key: 'Specific Student...',
role: 'student',
selected: active,
userName: '',
userPartitionId: null,
userNameInputToggle: () => {},
onSubmit: () => {},
};
Object.defineProperty(global, 'location', {
configurable: true,
value: { reload: jest.fn() },
});
});

it('renders masquerade active option correctly', async () => {
const { container } = render(<MasqueradeWidgetOption {...mockDataStaff} />);
const button = getAllByRole(container, 'button', { hidden: true })[0];
expect(button).toHaveTextContent('Staff');
expect(button).toHaveClass('active');
});

it('renders masquerade inactive option correctly', async () => {
const { container } = render(<MasqueradeWidgetOption {...mockDataStudent} />);
const button = getAllByRole(container, 'button', { hidden: true })[0];
expect(button).toHaveTextContent('Specific Student...');
expect(button).not.toHaveClass('active');
});

it('handles the clicks regular option', () => {
const onSubmit = jest.fn().mockImplementation(() => Promise.resolve());
const { container } = render(<MasqueradeWidgetOption {...mockDataStaff} onSubmit={onSubmit} />);
const button = getAllByRole(container, 'button', { hidden: true })[0];
act(() => {
fireEvent.click(button);
});
expect(onSubmit).toHaveBeenCalled();
});

it('handles the clicks student option', () => {
const userNameInputToggle = jest.fn().mockImplementation(() => Promise.resolve());
const { container } = render(
<MasqueradeWidgetOption {...mockDataStudent} userNameInputToggle={userNameInputToggle} />,
);
const button = getAllByRole(container, 'button', { hidden: true })[0];
act(() => {
fireEvent.click(button);
});
expect(userNameInputToggle).toHaveBeenCalled();
});
});
Loading