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

tests: Add tests for some components #11910

Merged
merged 7 commits into from
Mar 4, 2024
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
77 changes: 77 additions & 0 deletions kolibri/core/assets/src/views/__tests__/TotalPoints.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import VueRouter from 'vue-router';
import { render, screen, fireEvent } from '@testing-library/vue';
import TotalPoints from '../TotalPoints.vue';
import '@testing-library/jest-dom';

let store, storeActions;

// Create a mock Vuex store with the required getters and actions
// This is a helper function to avoid create a new store for each test and not reuse the same object
const getMockStore = () => {
return {
getters: {
totalPoints: () => store.totalPoints,
currentUserId: () => store.currentUserId,
isUserLoggedIn: () => store.isUserLoggedIn,
},
actions: {
fetchPoints: storeActions.fetchPoints,
},
};
};

// Helper function to render the component with Vuex store
const renderComponent = store => {
return render(TotalPoints, {
store,
routes: new VueRouter(),
});
};

describe('TotalPoints', () => {
beforeEach(() => {
store = {
totalPoints: 0,
currentUserId: 1,
isUserLoggedIn: false,
};
storeActions = {
fetchPoints: jest.fn(),
};
});

test('renders when user is logged in', async () => {
store.isUserLoggedIn = true;
store.totalPoints = 100;
renderComponent(getMockStore());

expect(screen.getByRole('presentation')).toBeInTheDocument();
expect(screen.getByText(store.totalPoints)).toBeInTheDocument();
});

test('does not render when user is not logged in', async () => {
store.isUserLoggedIn = false;
store.totalPoints = 100;
renderComponent(getMockStore());

expect(screen.queryByRole('presentation')).not.toBeInTheDocument();
expect(screen.queryByText(store.totalPoints)).not.toBeInTheDocument();
});

test('fetchPoints method is called on created', async () => {
store.isUserLoggedIn = true;
const mockedStore = getMockStore();
renderComponent(mockedStore);

expect(mockedStore.actions.fetchPoints).toHaveBeenCalledTimes(1);
});

test('tooltip message is displayed correctly when the mouse hovers over the icon', async () => {
store.isUserLoggedIn = true;
store.totalPoints = 100;
renderComponent(getMockStore());

await fireEvent.mouseOver(screen.getByRole('presentation'));
AlexVelezLl marked this conversation as resolved.
Show resolved Hide resolved
expect(screen.getByText(`You earned ${store.totalPoints} points`)).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import VueRouter from 'vue-router';
import { render, screen } from '@testing-library/vue';
import { FacilityUserGender } from 'kolibri.coreVue.vuex.constants';
import GenderDisplayText from '../GenderDisplayText.vue';
import '@testing-library/jest-dom';

const renderComponent = gender => {
return render(GenderDisplayText, {
routes: new VueRouter(),
props: {
gender,
},
});
};

describe('GenderDisplayText', () => {
const testCases = [
{
name: 'does not render when gender is not specified',
gender: FacilityUserGender.NOT_SPECIFIED,
shouldContain: [],
shouldNotContain: ['Male', 'Female'],
},
{
name: 'does not render when gender is deffered',
gender: FacilityUserGender.DEFERRED,
shouldContain: [],
shouldNotContain: ['Male', 'Female'],
},
{
name: 'renders when the gender is male',
gender: FacilityUserGender.MALE,
shouldContain: ['Male'],
shouldNotContain: ['Female'],
},
{
name: 'renders when the gender is female',
gender: FacilityUserGender.FEMALE,
shouldContain: ['Female'],
shouldNotContain: ['Male'],
},
];

testCases.forEach(testCase => {
it(testCase.name, () => {
renderComponent(testCase.gender);

testCase.shouldContain.forEach(text => {
expect(screen.getByText(text)).toBeInTheDocument();
});
testCase.shouldNotContain.forEach(text => {
expect(screen.queryByText(text)).not.toBeInTheDocument();
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { render, screen, fireEvent } from '@testing-library/vue';
import VueRouter from 'vue-router';
import GenderSelect from '../GenderSelect.vue';
import '@testing-library/jest-dom';

const renderComponent = () => {
return render(GenderSelect, {
routes: new VueRouter(),
});
};

describe('GenderSelect', () => {
const labelOptions = ['Male', 'Female', 'Not specified'];

test('renders correctly with label placeholder and options', async () => {
renderComponent();

expect(screen.getByText('Gender')).toBeInTheDocument();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could use getByLabel, to diferentiate that this is the label of the input. And we can add an array of options that it should contain.

Also, the component is responsible for emitting events when a selected value changes, which could be another test case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using getByLabelText does not work for this particular component. I suspect it's due to the markup that's surrounding it.

<div class="ui-select-label-text is-inline">
   Gender
</div>

labelOptions.forEach(option => {
expect(screen.getByText(option)).toBeInTheDocument();
});
});

test("emits 'update:value' event when an option is selected", async () => {
const { emitted } = renderComponent();

const selectedOption = labelOptions[0];
await fireEvent.click(screen.getByText(selectedOption));

const emittedEvents = emitted();
expect(emittedEvents).toHaveProperty('update:value');
expect(emittedEvents['update:value'][0]).toEqual([selectedOption.toUpperCase()]);
});

test("the value of 'update:value' event is changed when a different option is selected", async () => {
const { emitted } = renderComponent();

const selectedOption = labelOptions[0];
await fireEvent.click(screen.getByText(selectedOption));
const newSelectedOption = labelOptions[1];
await fireEvent.click(screen.getByText(newSelectedOption));

const emittedEvents = emitted();
expect(emittedEvents).toHaveProperty('update:value');
expect(emittedEvents['update:value']).toHaveLength(2); // As the event is emitted twice
expect(emittedEvents['update:value']).toEqual([
[selectedOption.toUpperCase()],
[newSelectedOption.toUpperCase()],
]);
});
});