Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { mount } from '@vue/test-utils';
import { render, screen, within, configure } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import VueRouter from 'vue-router';
import { Store } from 'vuex';
import ChannelSelectionList from '../ChannelSelectionList';
import { ChannelListTypes } from 'shared/constants';

// Configure VTL to use 'data-test' instead of the default 'data-testid'
configure({ testIdAttribute: 'data-test' });

const searchWord = 'search test';

const editChannel = {
id: 'editchannel',
name: searchWord,
Expand All @@ -14,108 +20,162 @@ const editChannel = {

const editChannel2 = {
id: 'editchannel2',
name: '',
name: 'Another Channel',
description: '',
edit: true,
published: true,
};

const publicChannel = {
id: 'publicchannel',
name: 'Public Channel',
public: true,
published: true,
};

const getters = {
channels: jest.fn(() => [editChannel, editChannel2, publicChannel]),
getChannel: jest.fn(() => () => editChannel),
};

const actions = {
const mockActions = {
loadChannelList: jest.fn(() => Promise.resolve()),
};

const store = new Store({
modules: {
channel: {
namespaced: true,
getters,
actions,
const makeStore = () =>
new Store({
modules: {
channel: {
namespaced: true,
state: {},
getters: {
channels: () => [editChannel, editChannel2, publicChannel],
getChannel: () => id => [editChannel, editChannel2, publicChannel].find(c => c.id === id),
},
actions: mockActions,
mutations: {
ADD_CHANNELS() {},
},
},
},
},
});
});

function makeWrapper() {
const loadChannelList = jest.spyOn(ChannelSelectionList.methods, 'loadChannelList');
loadChannelList.mockImplementation(() => Promise.resolve());
const renderComponent = (props = {}) => {
const router = new VueRouter({
routes: [{ path: '/', name: 'Home' }],
});

const wrapper = mount(ChannelSelectionList, {
propsData: {
return render(ChannelSelectionList, {
router,
store: makeStore(),
props: {
listType: ChannelListTypes.EDITABLE,
value: [], // Default to empty
...props, // Allow overriding props for specific tests
},
computed: {
channels() {
return [editChannel, editChannel2, publicChannel];
},
},
store,
});
};

return [wrapper, { loadChannelList }];
}

describe('channelSelectionList', () => {
let wrapper, mocks;

describe('ChannelSelectionList', () => {
beforeEach(() => {
[wrapper, mocks] = makeWrapper();
jest.clearAllMocks();
});

afterEach(() => {
mocks.loadChannelList.mockRestore();
});
it('renders a list of editable channels and hides non-editable ones', async () => {
await renderComponent();

it('should show the correct channels based on listType', async () => {
await wrapper.setData({ loading: false });
expect(wrapper.vm.listChannels.find(c => c.id === editChannel.id)).toBeTruthy();
expect(wrapper.vm.listChannels.find(c => c.id === editChannel2.id)).toBeTruthy();
expect(wrapper.vm.listChannels.find(c => c.id === publicChannel.id)).toBeFalsy();
// Specific wait avoids wrapping the whole block in waitFor
expect(await screen.findByLabelText(/search for a channel/i)).toBeInTheDocument();

expect(screen.getByText(editChannel.name)).toBeInTheDocument();
expect(screen.getByText(editChannel2.name)).toBeInTheDocument();
expect(screen.queryByText(publicChannel.name)).not.toBeInTheDocument();
});

it('should select channels when the channel has been checked', async () => {
await wrapper.setData({ loading: false });
await wrapper.findComponent(`[data-test="checkbox-${editChannel.id}"]`).trigger('click');
it('filters the channel list when the user types in the search box', async () => {
const user = userEvent.setup();
await renderComponent();

// Wait for data load
expect(await screen.findByText(editChannel.name)).toBeInTheDocument();
expect(screen.getByText(editChannel2.name)).toBeInTheDocument();

expect(wrapper.emitted('input')[0][0]).toEqual([editChannel.id]);
const searchInput = screen.getByLabelText(/search for a channel/i);
await user.clear(searchInput);
await user.type(searchInput, editChannel.name);

// Verify filter happened
expect(await screen.findByText(editChannel.name)).toBeInTheDocument();
expect(screen.queryByText(editChannel2.name)).not.toBeInTheDocument();
});

it('should deselect channels when the channel has been unchecked', async () => {
await wrapper.setData({ loading: false });
await wrapper.findComponent(`[data-test="checkbox-${editChannel.id}"]`).trigger('click'); // Check the channel
await wrapper.findComponent(`[data-test="checkbox-${editChannel.id}"]`).trigger('click'); // Uncheck the channel
it('selects a channel when the user clicks the checkbox', async () => {
const user = userEvent.setup();
const { emitted } = await renderComponent();

await screen.findByText(editChannel.name);

// Using getByTestId because the component doesn't expose unique
// accessible roles for individual channel checkboxes
const checkboxRow = screen.getByTestId(`checkbox-${editChannel.id}`);

// Find the checkbox strictly within this row
const checkbox = within(checkboxRow).getByRole('checkbox');

expect(wrapper.emitted('input')[0].length).toEqual(1); // Only one event should be emitted (corresponding to the initial check)
expect(wrapper.emitted('input')[0][0]).toEqual([editChannel.id]); // The initial check event should be emitted
await user.click(checkbox);

expect(emitted()).toHaveProperty('input');
expect(emitted().input).toHaveLength(1);
expect(emitted().input[0][0]).toEqual([editChannel.id]);
});

it('should filter channels based on the search text', async () => {
await wrapper.setData({ loading: false, search: searchWord });
expect(wrapper.vm.listChannels.find(c => c.id === editChannel.id)).toBeTruthy();
expect(wrapper.vm.listChannels.find(c => c.id === editChannel2.id)).toBeFalsy();
it('deselects a channel when the user clicks the checkbox of an already selected channel', async () => {
const user = userEvent.setup();

// Initialize with the channel already selected
const { emitted } = await renderComponent({ value: [editChannel.id] });

await screen.findByText(editChannel.name);

// Using getByTestId because the component doesn't expose unique
// accessible roles for individual channel checkboxes
const checkboxRow = screen.getByTestId(`checkbox-${editChannel.id}`);
const checkbox = within(checkboxRow).getByRole('checkbox');

// Click the checkbox to deselect
await user.click(checkbox);

expect(emitted()).toHaveProperty('input');
expect(emitted().input).toHaveLength(1);
expect(emitted().input[0][0]).toEqual([]);
});

it('should select channels when the channel card has been clicked', async () => {
await wrapper.setData({ loading: false });
await wrapper.findComponent(`[data-test="channel-item-${editChannel.id}"]`).trigger('click');
expect(wrapper.emitted('input')[0][0]).toEqual([editChannel.id]);
it('selects a channel when the user clicks the channel card', async () => {
const user = userEvent.setup();
const { emitted } = await renderComponent();

await screen.findByText(editChannel.name);

// Using getByTestId because the component doesn't expose accessible
// roles for channel cards
const card = screen.getByTestId(`channel-item-${editChannel.id}`);
await user.click(card);

expect(emitted()).toHaveProperty('input');
expect(emitted().input).toHaveLength(1);
expect(emitted().input[0][0]).toEqual([editChannel.id]);
});

it('should deselect channels when the channel card has been clicked', async () => {
await wrapper.setData({ loading: false });
await wrapper.findComponent(`[data-test="channel-item-${editChannel.id}"]`).trigger('click'); // Check the channel
await wrapper.findComponent(`[data-test="channel-item-${editChannel.id}"]`).trigger('click'); // Uncheck the channel
it('deselects a channel when the user clicks a selected channel card', async () => {
const user = userEvent.setup();

// Initialize with the channel already selected
const { emitted } = await renderComponent({ value: [editChannel.id] });

await screen.findByText(editChannel.name);

// Using getByTestId because the component doesn't expose accessible
// roles for channel cards
const card = screen.getByTestId(`channel-item-${editChannel.id}`);
await user.click(card);

expect(wrapper.emitted('input')[0].length).toEqual(1); // Only one event should be emitted (corresponding to the initial check)
expect(wrapper.emitted('input')[0][0]).toEqual([editChannel.id]); // The initial check event should be emitted
expect(emitted()).toHaveProperty('input');
expect(emitted().input).toHaveLength(1);
expect(emitted().input[0][0]).toEqual([]);
});
});