From 7a2e58d25bd98c3889fb4d39ae8c3182534cd7b3 Mon Sep 17 00:00:00 2001 From: Michaela Date: Fri, 4 Jun 2021 12:19:28 +0200 Subject: [PATCH] Add learning activity bar component --- .../assets/src/views/LearningActivityBar.vue | 268 ++++++++++++++++++ .../test/views/learning-activity-bar.spec.js | 194 +++++++++++++ 2 files changed, 462 insertions(+) create mode 100644 kolibri/plugins/learn/assets/src/views/LearningActivityBar.vue create mode 100644 kolibri/plugins/learn/assets/test/views/learning-activity-bar.spec.js diff --git a/kolibri/plugins/learn/assets/src/views/LearningActivityBar.vue b/kolibri/plugins/learn/assets/src/views/LearningActivityBar.vue new file mode 100644 index 00000000000..00f31d9dab9 --- /dev/null +++ b/kolibri/plugins/learn/assets/src/views/LearningActivityBar.vue @@ -0,0 +1,268 @@ + + + + + + + diff --git a/kolibri/plugins/learn/assets/test/views/learning-activity-bar.spec.js b/kolibri/plugins/learn/assets/test/views/learning-activity-bar.spec.js new file mode 100644 index 00000000000..b0258478d69 --- /dev/null +++ b/kolibri/plugins/learn/assets/test/views/learning-activity-bar.spec.js @@ -0,0 +1,194 @@ +import { shallowMount, mount } from '@vue/test-utils'; + +import { LearningActivityKinds } from 'kolibri.coreVue.vuex.constants'; +import LearningActivityBar from '../../src/views/LearningActivityBar'; + +function makeWrapper({ propsData } = {}) { + return mount(LearningActivityBar, { propsData }); +} + +describe('LearningActivityBar', () => { + it('smoke test', () => { + const wrapper = shallowMount(LearningActivityBar); + expect(wrapper.exists()).toBe(true); + }); + + it('should show a resource title in the bar', () => { + const wrapper = makeWrapper({ + propsData: { resourceTitle: 'Practice and applications of math' }, + }); + expect(wrapper.text()).toContain('Practice and applications of math'); + }); + + it('should show the back button in the bar', () => { + const wrapper = makeWrapper(); + expect(wrapper.find('[data-test="backButton"]').exists()).toBeTruthy(); + }); + + it('should emit `navigateBack` event on the back button click', () => { + const wrapper = makeWrapper(); + wrapper.find('[data-test="backButton"]').trigger('click'); + expect(wrapper.emitted().navigateBack.length).toBe(1); + }); + + it('should show a learning activity icon in the bar', () => { + const wrapper = makeWrapper({ + propsData: { + learningActivityKind: LearningActivityKinds.WATCH, + }, + }); + expect(wrapper.find('[data-test="learningActivityIcon"]').exists()).toBeTruthy(); + }); + + // Although there are basic tests for distribution + // of action buttons between the bar and the menu in the following tests, + // their position can further change based on the window size. + // Purpose of these tests is rather functional. Testing all screen + // sizes here would result in a huge test case and it needs to be + // tested visually anyways. For that reason, the following tests always + // assume a large screen. + describe('on a large screen', () => { + describe('in the lesson context', () => { + let wrapper; + + beforeEach(() => { + wrapper = makeWrapper({ propsData: { isLessonContext: true } }); + }); + + it("shouldn't show 'View topic resources' button in the bar", () => { + expect(wrapper.find("[data-test='bar_viewTopicResourcesButton']").exists()).toBeFalsy(); + }); + + it("should show 'View lesson plan' button in the bar", () => { + expect(wrapper.find("[data-test='bar_viewLessonPlanButton']").exists()).toBeTruthy(); + }); + + it("should emit `viewResourceList` event on the 'View lesson plan' button click", () => { + wrapper.find('[data-test="bar_viewLessonPlanButton"]').trigger('click'); + expect(wrapper.emitted().viewResourceList.length).toBe(1); + }); + }); + + describe('in the non-lesson context', () => { + let wrapper; + + beforeEach(() => { + wrapper = makeWrapper({ propsData: { isLessonContext: false } }); + }); + + it("shouldn't show 'View lesson plan' button in the bar", () => { + expect(wrapper.find("[data-test='bar_viewLessonPlanButton']").exists()).toBeFalsy(); + }); + + it("should show 'View topic resources' button in the bar", () => { + expect(wrapper.find("[data-test='bar_viewTopicResourcesButton']").exists()).toBeTruthy(); + }); + + it("should emit `viewResourceList` event on the 'View topic resources' button click", () => { + wrapper.find('[data-test="bar_viewTopicResourcesButton"]').trigger('click'); + expect(wrapper.emitted().viewResourceList.length).toBe(1); + }); + }); + + describe('when a resource is bookmarked', () => { + let wrapper; + + beforeEach(() => { + wrapper = makeWrapper({ propsData: { isBookmarked: true } }); + }); + + it("shouldn't show the add bookmark button in the bar", () => { + expect(wrapper.find("[data-test='bar_addBookmarkButton']").exists()).toBeFalsy(); + }); + + it('should show the remove bookmark button in the bar', () => { + expect(wrapper.find("[data-test='bar_removeBookmarkButton']").exists()).toBeTruthy(); + }); + + it('should emit `toogleBookmark` event on the remove bookmark button click', () => { + wrapper.find("[data-test='bar_removeBookmarkButton']").trigger('click'); + expect(wrapper.emitted().toogleBookmark.length).toBe(1); + }); + }); + + describe('when a resource is not bookmarked', () => { + let wrapper; + + beforeEach(() => { + wrapper = makeWrapper({ propsData: { isBookmarked: false } }); + }); + + it("shouldn't show the remove bookmark button in the bar", () => { + expect(wrapper.find("[data-test='bar_removeBookmarkButton']").exists()).toBeFalsy(); + }); + + it('should show the add bookmark button in the bar', () => { + expect(wrapper.find("[data-test='bar_addBookmarkButton']").exists()).toBeTruthy(); + }); + + it('should emit `toogleBookmark` event on the add bookmark button click', () => { + wrapper.find("[data-test='bar_addBookmarkButton']").trigger('click'); + expect(wrapper.emitted().toogleBookmark.length).toBe(1); + }); + }); + + describe('if a resource can be manually marked as complete', () => { + let wrapper; + + beforeEach(() => { + wrapper = makeWrapper({ propsData: { allowMarkComplete: true } }); + }); + + it('should show the menu button', () => { + expect(wrapper.find("[data-test='menuButton']").exists()).toBeTruthy(); + }); + + it("should show 'Mark resource as finished' button in the menu", () => { + expect(wrapper.find("[data-test='bar_markCompleteButton']").exists()).toBeFalsy(); + expect(wrapper.find("[data-test='menu_markCompleteButton']").exists()).toBeTruthy(); + }); + + it("should emit `markComplete` event on the 'Mark resource as finished' button click", () => { + wrapper.find("[data-test='menu_markCompleteButton']").vm.$emit('select'); + expect(wrapper.emitted().markComplete.length).toBe(1); + }); + + it("should show 'View information' button in the menu", () => { + expect(wrapper.find("[data-test='bar_viewInfoButton']").exists()).toBeFalsy(); + expect(wrapper.find("[data-test='menu_viewInfoButton']").exists()).toBeTruthy(); + }); + + it("should emit `viewInfo` event on the 'View information' menu button click", () => { + wrapper.find("[data-test='menu_viewInfoButton']").vm.$emit('select'); + expect(wrapper.emitted().viewInfo.length).toBe(1); + }); + }); + + describe("if a resource can't be manually marked as complete", () => { + let wrapper; + + beforeEach(() => { + wrapper = makeWrapper({ propsData: { allowMarkComplete: false } }); + }); + + it("shouldn't show the menu button", () => { + expect(wrapper.find("[data-test='menuButton']").exists()).toBeFalsy(); + }); + + it("shouldn't show 'Mark resource as finished' button", () => { + expect(wrapper.find("[data-test='bar_markCompleteButton']").exists()).toBeFalsy(); + expect(wrapper.find("[data-test='menu_markCompleteButton']").exists()).toBeFalsy(); + }); + + it("should show 'View information' button in the bar", () => { + expect(wrapper.find("[data-test='menu_viewInfoButton']").exists()).toBeFalsy(); + expect(wrapper.find("[data-test='bar_viewInfoButton']").exists()).toBeTruthy(); + }); + + it("should emit `viewInfo` event on the 'View information' bar button click", () => { + wrapper.find("[data-test='bar_viewInfoButton']").trigger('click'); + expect(wrapper.emitted().viewInfo.length).toBe(1); + }); + }); + }); +});