From d78d450709eecfa00c284fc1e6c3197dc1ae3270 Mon Sep 17 00:00:00 2001 From: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> Date: Sat, 20 Apr 2024 01:15:57 +0530 Subject: [PATCH 1/8] add tests for UserTypeDisplay.vue --- .../views/__tests__/UserTypeDisplay.spec.js | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 kolibri/core/assets/src/views/__tests__/UserTypeDisplay.spec.js diff --git a/kolibri/core/assets/src/views/__tests__/UserTypeDisplay.spec.js b/kolibri/core/assets/src/views/__tests__/UserTypeDisplay.spec.js new file mode 100644 index 00000000000..6d228d875c0 --- /dev/null +++ b/kolibri/core/assets/src/views/__tests__/UserTypeDisplay.spec.js @@ -0,0 +1,45 @@ +import VueRouter from 'vue-router'; +import { render, screen } from '@testing-library/vue'; +import UserTypeDisplay from '../UserTypeDisplay.vue'; + +const sampleUserType = 'testing-user-type'; +const translatedSampleUserType = 'Testing User Type'; + +// Helper function to render the component with the provided props +const renderComponent = props => { + const translatedUserKinds = { + computed: { + typeDisplayMap() { + return { + [sampleUserType]: translatedSampleUserType, + }; + }, + }, + }; + + return render(UserTypeDisplay, { + routes: new VueRouter(), + props: { + userType: sampleUserType, + ...props, + }, + mixins: [translatedUserKinds], + }); +}; + +describe('UserTypeDisplay', () => { + test('smoke test (renders the translated user type correctly)', () => { + renderComponent({ userType: sampleUserType }); + expect(screen.getByText(translatedSampleUserType)).toBeInTheDocument(); + }); + + test('does not render the untranslated user type', () => { + renderComponent({ userType: sampleUserType }); + expect(screen.queryByText(sampleUserType)).not.toBeInTheDocument(); + }); + + test('does not render anything if the userType prop is not provided', () => { + const { container } = renderComponent({ userType: undefined }); + expect(container).toBeEmptyDOMElement(); + }); +}); From e60ed4a818636a478f12576c98e325a7eb707043 Mon Sep 17 00:00:00 2001 From: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> Date: Wed, 24 Apr 2024 00:41:34 +0530 Subject: [PATCH 2/8] add tests for FocusTrap --- .../src/views/__tests__/FocusTrap.spec.js | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 kolibri/core/assets/src/views/__tests__/FocusTrap.spec.js diff --git a/kolibri/core/assets/src/views/__tests__/FocusTrap.spec.js b/kolibri/core/assets/src/views/__tests__/FocusTrap.spec.js new file mode 100644 index 00000000000..f05b5d0dc7e --- /dev/null +++ b/kolibri/core/assets/src/views/__tests__/FocusTrap.spec.js @@ -0,0 +1,60 @@ +import { render } from '@testing-library/vue'; +import userEvent from '@testing-library/user-event'; +import VueRouter from 'vue-router'; +import FocusTrap from '../FocusTrap.vue'; + +const renderComponent = (props = {}) => { + return render(FocusTrap, { + props: { + disabled: false, + ...props, + }, + routes: new VueRouter(), + }); +}; + +describe('FocusTrap', () => { + it('should emit the "shouldFocusFirstEl" element when the tab key is pressed once', async () => { + const { emitted } = renderComponent(); + + await userEvent.tab(); + expect(emitted()).toHaveProperty('shouldFocusFirstEl'); + expect(emitted().shouldFocusFirstEl.length).toBe(1); + }); + + it("should trap the focus ('shouldFocusFirstEl' should be emitted twice) on pressing tab twice ", async () => { + const { emitted } = renderComponent(); + + await userEvent.tab(); + await userEvent.tab(); + + expect(emitted()).toHaveProperty('shouldFocusFirstEl'); + expect(emitted().shouldFocusFirstEl.length).toBe(2); + }); + + it('should emit "shouldFocusLastEl" when the element is subsequently focused after the inital focus', async () => { + const { emitted } = renderComponent(); + + await userEvent.tab(); + await userEvent.tab(); + + // Shift + Tab is used to focus on the initial element again + await userEvent.tab({ shift: true }); + + expect(emitted()).toHaveProperty('shouldFocusLastEl'); + expect(emitted().shouldFocusLastEl.length).toBe(1); + }); + + it("should not trap focus when 'disabled' prop is set to true", async () => { + const { emitted } = renderComponent({ disabled: true }); + + await userEvent.tab(); + expect(emitted()).not.toHaveProperty('shouldFocusFirstEl'); + + await userEvent.tab(); + expect(emitted()).not.toHaveProperty('shouldFocusFirstEl'); + + await userEvent.tab({ shift: true }); + expect(emitted()).not.toHaveProperty('shouldFocusLastEl'); + }); +}); From 8ada86e218b718416248128e01f1167bf7dec735 Mon Sep 17 00:00:00 2001 From: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> Date: Wed, 24 Apr 2024 01:22:23 +0530 Subject: [PATCH 3/8] add tests for TimeDuration --- .../core/assets/src/views/TimeDuration.vue | 2 +- .../src/views/__tests__/TimeDuration.spec.js | 57 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 kolibri/core/assets/src/views/__tests__/TimeDuration.spec.js diff --git a/kolibri/core/assets/src/views/TimeDuration.vue b/kolibri/core/assets/src/views/TimeDuration.vue index bf11b7fdf73..02a638896fe 100644 --- a/kolibri/core/assets/src/views/TimeDuration.vue +++ b/kolibri/core/assets/src/views/TimeDuration.vue @@ -1,7 +1,7 @@ diff --git a/kolibri/core/assets/src/views/__tests__/TimeDuration.spec.js b/kolibri/core/assets/src/views/__tests__/TimeDuration.spec.js new file mode 100644 index 00000000000..a7bf5bb2d13 --- /dev/null +++ b/kolibri/core/assets/src/views/__tests__/TimeDuration.spec.js @@ -0,0 +1,57 @@ +import { render, screen } from '@testing-library/vue'; +import VueRouter from 'vue-router'; +import TimeDuration from '../TimeDuration.vue'; + +const renderComponent = (props = {}) => { + return render(TimeDuration, { + props, + routes: new VueRouter(), + }); +}; + +const MINUTE = 60; +const HOUR = 60 * MINUTE; +const DAY = 24 * HOUR; + +const testCases = [ + // Under 2 minutes, should show seconds + { seconds: 0, expected: '0 seconds' }, + { seconds: 1, expected: '1 second' }, + { seconds: 59, expected: '59 seconds' }, + { seconds: MINUTE, expected: '60 seconds' }, + { seconds: 2 * MINUTE - 1, expected: '119 seconds' }, + + // Under 1 hour, should show minutes (rounded down) + { seconds: 2 * MINUTE, expected: '2 minutes' }, + { seconds: 30 * MINUTE, expected: '30 minutes' }, + { seconds: 30 * MINUTE + 1, expected: '30 minutes' }, + { seconds: 30 * MINUTE + 59, expected: '30 minutes' }, + { seconds: 59 * MINUTE, expected: '59 minutes' }, + + // Under 1 day, should show hours (rounded down) + { seconds: HOUR, expected: '1 hour' }, + { seconds: 2 * HOUR, expected: '2 hours' }, + { seconds: 23 * HOUR, expected: '23 hours' }, + { seconds: 23 * HOUR + 59 * MINUTE, expected: '23 hours' }, + { seconds: 23 * HOUR + 59 * MINUTE + 59, expected: '23 hours' }, + + // Over 1 day, should show days (rounded down) + { seconds: DAY, expected: '1 day' }, + { seconds: 2 * DAY, expected: '2 days' }, + { seconds: 6 * DAY, expected: '6 days' }, + { seconds: 6 * DAY + 23 * HOUR + 59 * MINUTE + 59, expected: '6 days' }, +]; + +describe('TimeDuration', () => { + testCases.forEach(({ seconds, expected }) => { + it(`should render ${expected} for ${seconds} seconds`, () => { + renderComponent({ seconds }); + expect(screen.getByText(expected)).toBeInTheDocument(); + }); + }); + + it('should render empty string if seconds are not provided as props', () => { + renderComponent(); + expect(screen.getByText('—')).toBeInTheDocument(); + }); +}); From fe2d04574c32af3b26c30a4c60f25d28e5bc8fb7 Mon Sep 17 00:00:00 2001 From: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> Date: Wed, 1 May 2024 16:14:58 +0530 Subject: [PATCH 4/8] address review comments --- .../src/views/__tests__/FocusTrap.spec.js | 40 +++++++++++++++++++ .../src/views/__tests__/TimeDuration.spec.js | 8 ++-- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/kolibri/core/assets/src/views/__tests__/FocusTrap.spec.js b/kolibri/core/assets/src/views/__tests__/FocusTrap.spec.js index f05b5d0dc7e..30c2106b02a 100644 --- a/kolibri/core/assets/src/views/__tests__/FocusTrap.spec.js +++ b/kolibri/core/assets/src/views/__tests__/FocusTrap.spec.js @@ -57,4 +57,44 @@ describe('FocusTrap', () => { await userEvent.tab({ shift: true }); expect(emitted()).not.toHaveProperty('shouldFocusLastEl'); }); + + it("should reset state when 'reset' method is called", async () => { + // Create a wrapper component with a Reset button to call the component's public method "reset" + const WrapperComponent = { + template: ` +
+ + +
+ `, + components: { + FocusTrap, + }, + methods: { + reset() { + this.$refs.focusTrap.reset(); + }, + }, + }; + + const { emitted } = render(WrapperComponent, { + routes: new VueRouter(), + }); + + // Activate the focus trap + await userEvent.tab(); + await userEvent.tab(); + await userEvent.tab({ shift: true }); + + // Check if the focus trap is working + expect(emitted()).toHaveProperty('shouldFocusLastEl'); + expect(emitted().shouldFocusLastEl.length).toBe(1); + + // Reset the focus trap + await userEvent.click(document.querySelector('button')); + + await userEvent.tab(); + expect(emitted()).toHaveProperty('shouldFocusFirstEl'); + expect(emitted().shouldFocusFirstEl.length).toBe(2); + }); }); diff --git a/kolibri/core/assets/src/views/__tests__/TimeDuration.spec.js b/kolibri/core/assets/src/views/__tests__/TimeDuration.spec.js index a7bf5bb2d13..35247ac63ca 100644 --- a/kolibri/core/assets/src/views/__tests__/TimeDuration.spec.js +++ b/kolibri/core/assets/src/views/__tests__/TimeDuration.spec.js @@ -43,11 +43,9 @@ const testCases = [ ]; describe('TimeDuration', () => { - testCases.forEach(({ seconds, expected }) => { - it(`should render ${expected} for ${seconds} seconds`, () => { - renderComponent({ seconds }); - expect(screen.getByText(expected)).toBeInTheDocument(); - }); + it.each(testCases)('should render $seconds seconds as $expected', ({ seconds, expected }) => { + renderComponent({ seconds }); + expect(screen.getByText(expected)).toBeInTheDocument(); }); it('should render empty string if seconds are not provided as props', () => { From 52ffdc7f8821311395fa4d4e2d0404f0f785eaf7 Mon Sep 17 00:00:00 2001 From: Eshaan Aggarwal <96648934+EshaanAgg@users.noreply.github.com> Date: Wed, 1 May 2024 20:25:31 +0530 Subject: [PATCH 5/8] add wrapper test --- .../src/views/__tests__/FocusTrap.spec.js | 60 +++++++------------ .../src/views/__tests__/FocusTrapWrapper.vue | 29 +++++++++ .../src/views/__tests__/TimeDuration.spec.js | 2 - .../views/__tests__/UserTypeDisplay.spec.js | 8 +-- 4 files changed, 53 insertions(+), 46 deletions(-) create mode 100644 kolibri/core/assets/src/views/__tests__/FocusTrapWrapper.vue diff --git a/kolibri/core/assets/src/views/__tests__/FocusTrap.spec.js b/kolibri/core/assets/src/views/__tests__/FocusTrap.spec.js index 30c2106b02a..b2b44470635 100644 --- a/kolibri/core/assets/src/views/__tests__/FocusTrap.spec.js +++ b/kolibri/core/assets/src/views/__tests__/FocusTrap.spec.js @@ -1,7 +1,7 @@ -import { render } from '@testing-library/vue'; +import { render, screen, fireEvent } from '@testing-library/vue'; import userEvent from '@testing-library/user-event'; -import VueRouter from 'vue-router'; import FocusTrap from '../FocusTrap.vue'; +import FocusTrapWrapper from './FocusTrapWrapper.vue'; const renderComponent = (props = {}) => { return render(FocusTrap, { @@ -9,7 +9,6 @@ const renderComponent = (props = {}) => { disabled: false, ...props, }, - routes: new VueRouter(), }); }; @@ -58,43 +57,26 @@ describe('FocusTrap', () => { expect(emitted()).not.toHaveProperty('shouldFocusLastEl'); }); - it("should reset state when 'reset' method is called", async () => { - // Create a wrapper component with a Reset button to call the component's public method "reset" - const WrapperComponent = { - template: ` -
- - -
- `, - components: { - FocusTrap, - }, - methods: { - reset() { - this.$refs.focusTrap.reset(); - }, - }, - }; - - const { emitted } = render(WrapperComponent, { - routes: new VueRouter(), - }); - - // Activate the focus trap - await userEvent.tab(); - await userEvent.tab(); - await userEvent.tab({ shift: true }); + // it("should reset state when 'reset' method is called", async () => { + // // FocusTrapWrapper is used to test the FocusTrap component's reset method + // // It has a button which calls the reset method of the FocusTrap component + // const { emitted } = render(FocusTrapWrapper); - // Check if the focus trap is working - expect(emitted()).toHaveProperty('shouldFocusLastEl'); - expect(emitted().shouldFocusLastEl.length).toBe(1); + // await fireEvent.focus(screen.getByTestId('focusTrap')); + // // Activate the focus trap + // await userEvent.tab(); + // await userEvent.tab(); + // await userEvent.tab({ shift: true }); - // Reset the focus trap - await userEvent.click(document.querySelector('button')); + // // The focus trap should be active + // expect(emitted()).toHaveProperty('shouldFocusLastEl'); + // expect(emitted().shouldFocusLastEl.length).toBe(1); - await userEvent.tab(); - expect(emitted()).toHaveProperty('shouldFocusFirstEl'); - expect(emitted().shouldFocusFirstEl.length).toBe(2); - }); + // // Reset the focus trap + // await userEvent.click(screen.getByRole('button')); + + // await userEvent.tab(); + // expect(emitted()).toHaveProperty('shouldFocusFirstEl'); + // expect(emitted().shouldFocusFirstEl.length).toBe(2); + // }); }); diff --git a/kolibri/core/assets/src/views/__tests__/FocusTrapWrapper.vue b/kolibri/core/assets/src/views/__tests__/FocusTrapWrapper.vue new file mode 100644 index 00000000000..e7f7e1a4d48 --- /dev/null +++ b/kolibri/core/assets/src/views/__tests__/FocusTrapWrapper.vue @@ -0,0 +1,29 @@ + + + + diff --git a/kolibri/core/assets/src/views/__tests__/TimeDuration.spec.js b/kolibri/core/assets/src/views/__tests__/TimeDuration.spec.js index 35247ac63ca..aef30cde02b 100644 --- a/kolibri/core/assets/src/views/__tests__/TimeDuration.spec.js +++ b/kolibri/core/assets/src/views/__tests__/TimeDuration.spec.js @@ -1,11 +1,9 @@ import { render, screen } from '@testing-library/vue'; -import VueRouter from 'vue-router'; import TimeDuration from '../TimeDuration.vue'; const renderComponent = (props = {}) => { return render(TimeDuration, { props, - routes: new VueRouter(), }); }; diff --git a/kolibri/core/assets/src/views/__tests__/UserTypeDisplay.spec.js b/kolibri/core/assets/src/views/__tests__/UserTypeDisplay.spec.js index 6d228d875c0..98332dbf34a 100644 --- a/kolibri/core/assets/src/views/__tests__/UserTypeDisplay.spec.js +++ b/kolibri/core/assets/src/views/__tests__/UserTypeDisplay.spec.js @@ -1,9 +1,8 @@ -import VueRouter from 'vue-router'; import { render, screen } from '@testing-library/vue'; import UserTypeDisplay from '../UserTypeDisplay.vue'; const sampleUserType = 'testing-user-type'; -const translatedSampleUserType = 'Testing User Type'; +const expectedSampleUserType = 'Testing User Type'; // Helper function to render the component with the provided props const renderComponent = props => { @@ -11,14 +10,13 @@ const renderComponent = props => { computed: { typeDisplayMap() { return { - [sampleUserType]: translatedSampleUserType, + [sampleUserType]: expectedSampleUserType, }; }, }, }; return render(UserTypeDisplay, { - routes: new VueRouter(), props: { userType: sampleUserType, ...props, @@ -30,7 +28,7 @@ const renderComponent = props => { describe('UserTypeDisplay', () => { test('smoke test (renders the translated user type correctly)', () => { renderComponent({ userType: sampleUserType }); - expect(screen.getByText(translatedSampleUserType)).toBeInTheDocument(); + expect(screen.getByText(expectedSampleUserType)).toBeInTheDocument(); }); test('does not render the untranslated user type', () => { From b5ee4788a997064cc3423ae5e67b8658a07f1804 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 1 May 2024 14:57:51 +0000 Subject: [PATCH 6/8] [pre-commit.ci lite] apply automatic fixes --- kolibri/core/assets/src/views/__tests__/FocusTrapWrapper.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kolibri/core/assets/src/views/__tests__/FocusTrapWrapper.vue b/kolibri/core/assets/src/views/__tests__/FocusTrapWrapper.vue index e7f7e1a4d48..478af76486c 100644 --- a/kolibri/core/assets/src/views/__tests__/FocusTrapWrapper.vue +++ b/kolibri/core/assets/src/views/__tests__/FocusTrapWrapper.vue @@ -1,4 +1,4 @@ -