-
Notifications
You must be signed in to change notification settings - Fork 647
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
creating useTotalProgress composable and migrating code to use it
- Loading branch information
1 parent
65db937
commit 4515dc2
Showing
14 changed files
with
162 additions
and
85 deletions.
There are no files selected for viewing
62 changes: 62 additions & 0 deletions
62
kolibri/core/assets/src/composables/__mocks__/useTotalProgress.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/** | ||
* `useTotalProgress` composable function mock. | ||
* | ||
* If default values are sufficient for tests, | ||
* you only need call `jest.mock('<useTotalProgress file path>')` | ||
* at the top of a test file. | ||
* | ||
* If you need to override some default values for some tests, | ||
* or if you need to inspect the state of the refs during tests, | ||
* you can import a helper function `useTotalProgressMock` that accepts | ||
* an object with values to be overriden and use it together | ||
* with `mockImplementation` as follows: | ||
* | ||
* ``` | ||
* // eslint-disable-next-line import/named | ||
* import useTotalProgress, { useTotalProgressMock } from '<useTotalProgress file path>'; | ||
* | ||
* jest.mock('<useTotalProgress file path>') | ||
* describe('describe test', function () { | ||
* let totalProgressMock = { totalProgress: ref(null) } | ||
* | ||
* beforeAll(() => { | ||
* useTotalProgress.mockImplementation(() => useTotalProgressMock(totalProgressMock) | ||
* }) | ||
* | ||
* it('the test', () => { | ||
* expect(get(totalProgressMock.totalProgress)).toEqual(null); | ||
* ) | ||
* }) | ||
* ``` | ||
*/ | ||
import { ref, computed } from 'kolibri.lib.vueCompositionApi'; | ||
import { get, set } from '@vueuse/core'; | ||
import { MaxPointsPerContent } from '../../constants'; | ||
|
||
const MOCK_DEFAULTS = { | ||
totalProgress: ref(null), | ||
}; | ||
|
||
export function useTotalProgressMock(overrides = {}) { | ||
const mocks = { | ||
...MOCK_DEFAULTS, | ||
...overrides, | ||
}; | ||
|
||
const totalPoints = computed(() => mocks.totalProgress.value * MaxPointsPerContent); | ||
|
||
const fetchPoints = jest.fn(); | ||
|
||
const incrementTotalProgress = progress => { | ||
set(mocks.totalProgress, get(mocks.totalProgress) + progress); | ||
}; | ||
|
||
return { | ||
totalPoints, | ||
fetchPoints, | ||
incrementTotalProgress, | ||
...mocks, | ||
}; | ||
} | ||
|
||
export default jest.fn(() => useTotalProgressMock()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { ref, computed } from 'kolibri.lib.vueCompositionApi'; | ||
import { get, set } from '@vueuse/core'; | ||
import useUser from 'kolibri.coreVue.composables.useUser'; | ||
import { UserProgressResource } from 'kolibri.resources'; | ||
import { MaxPointsPerContent } from '../constants'; | ||
|
||
const totalProgress = ref(null); | ||
|
||
export default function useTotalProgress() { | ||
const totalPoints = computed(() => totalProgress.value * MaxPointsPerContent); | ||
|
||
const fetchPoints = () => { | ||
const { isUserLoggedIn, currentUserId } = useUser(); | ||
if (get(isUserLoggedIn) && get(totalProgress) === null) { | ||
UserProgressResource.fetchModel({ id: get(currentUserId) }).then(progress => { | ||
set(totalProgress, progress.progress); | ||
}); | ||
} | ||
}; | ||
|
||
const incrementTotalProgress = progress => { | ||
set(totalProgress, get(totalProgress) + progress); | ||
}; | ||
|
||
return { | ||
totalProgress, | ||
totalPoints, | ||
fetchPoints, | ||
incrementTotalProgress, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 23 additions & 42 deletions
65
kolibri/core/assets/src/views/__tests__/TotalPoints.spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,58 @@ | ||
import { render, screen, fireEvent } from '@testing-library/vue'; | ||
import useUser, { useUserMock } from 'kolibri.coreVue.composables.useUser'; | ||
import TotalPoints from '../TotalPoints.vue'; | ||
import useTotalProgress, { | ||
useTotalProgressMock, | ||
} from 'kolibri.coreVue.composables.useTotalProgress'; | ||
import '@testing-library/jest-dom'; | ||
|
||
let store, storeActions; | ||
import { ref } from 'kolibri.lib.vueCompositionApi'; | ||
import { get, set } from '@vueuse/core'; | ||
import TotalPoints from '../TotalPoints.vue'; | ||
|
||
jest.mock('kolibri.coreVue.composables.useUser'); | ||
|
||
// 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, | ||
}, | ||
actions: { | ||
fetchPoints: storeActions.fetchPoints, | ||
}, | ||
}; | ||
}; | ||
|
||
// Helper function to render the component with Vuex store | ||
const renderComponent = store => { | ||
return render(TotalPoints, { | ||
store, | ||
}); | ||
}; | ||
jest.mock('kolibri.coreVue.composables.useTotalProgress'); | ||
|
||
describe('TotalPoints', () => { | ||
let totalPointsMock; | ||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
useUser.mockImplementation(() => useUserMock()); | ||
store = { | ||
totalPoints: 0, | ||
}; | ||
|
||
storeActions = { | ||
fetchPoints: jest.fn(), | ||
}; | ||
totalPointsMock = { totalPoints: ref(0), fetchPoints: jest.fn() }; | ||
useTotalProgress.mockImplementation(() => useTotalProgressMock(totalPointsMock)); | ||
}); | ||
|
||
test('renders when user is logged in', async () => { | ||
useUser.mockImplementation(() => useUserMock({ currentUserId: 1, isUserLoggedIn: true })); | ||
store.totalPoints = 100; | ||
renderComponent(getMockStore()); | ||
set(totalPointsMock.totalPoints, 100); | ||
render(TotalPoints); | ||
|
||
expect(screen.getByRole('presentation')).toBeInTheDocument(); | ||
expect(screen.getByText(store.totalPoints)).toBeInTheDocument(); | ||
expect(screen.getByText(get(totalPointsMock.totalPoints))).toBeInTheDocument(); | ||
}); | ||
|
||
test('does not render when user is not logged in', async () => { | ||
useUser.mockImplementation(() => useUserMock({ currentUserId: 1, isUserLoggedIn: false })); | ||
store.totalPoints = 100; | ||
renderComponent(getMockStore()); | ||
set(totalPointsMock.totalPoints, 100); | ||
render(TotalPoints); | ||
|
||
expect(screen.queryByRole('presentation')).not.toBeInTheDocument(); | ||
expect(screen.queryByText(store.totalPoints)).not.toBeInTheDocument(); | ||
expect(screen.queryByText(get(totalPointsMock.totalPoints))).not.toBeInTheDocument(); | ||
}); | ||
|
||
test('fetchPoints method is called on created', async () => { | ||
useUser.mockImplementation(() => useUserMock({ currentUserId: 1, isUserLoggedIn: true })); | ||
const mockedStore = getMockStore(); | ||
renderComponent(mockedStore); | ||
render(TotalPoints); | ||
|
||
expect(mockedStore.actions.fetchPoints).toHaveBeenCalledTimes(1); | ||
expect(totalPointsMock.fetchPoints).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
test('tooltip message is displayed correctly when the mouse hovers over the icon', async () => { | ||
useUser.mockImplementation(() => useUserMock({ currentUserId: 1, isUserLoggedIn: true })); | ||
store.totalPoints = 100; | ||
renderComponent(getMockStore()); | ||
set(totalPointsMock.totalPoints, 100); | ||
render(TotalPoints); | ||
|
||
await fireEvent.mouseOver(screen.getByRole('presentation')); | ||
expect(screen.getByText(`You earned ${store.totalPoints} points`)).toBeInTheDocument(); | ||
expect( | ||
screen.getByText(`You earned ${get(totalPointsMock.totalPoints)} points`), | ||
).toBeInTheDocument(); | ||
}); | ||
}); |
Oops, something went wrong.