From 3e1e52b16d6eff4bc946c8b29638c637d7fab1e5 Mon Sep 17 00:00:00 2001 From: sairina Date: Mon, 18 Jul 2022 21:39:21 -0700 Subject: [PATCH 01/14] Add activity duration component tests and refactor some methods --- .../components/edit/ActivityDuration.vue | 20 +- .../edit/__tests__/activityDuration.spec.js | 194 ++++++++++++++++++ 2 files changed, 204 insertions(+), 10 deletions(-) create mode 100644 contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/activityDuration.spec.js diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/ActivityDuration.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/ActivityDuration.vue index debdbeadc3..071892dc3f 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/ActivityDuration.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/ActivityDuration.vue @@ -96,6 +96,9 @@ }, computed: { showRequiredLabel() { + if (this.audioVideoUpload) { + return false; + } return ( this.selectedDuration !== DurationDropdownMap.EXACT_TIME && this.selectedCompletion === CompletionDropdownMap.completeDuration @@ -121,7 +124,7 @@ return this.convertToMinutes(this.value); }, set(value) { - this.handleValidateMinutes(value); + this.handleUpdatedInput(value); }, }, maxRange() { @@ -152,20 +155,17 @@ }, }, created() { - this.handleValidateMinutes = debounce(this.validateMinutes, 500); + this.handleUpdatedInput = debounce(this.handleInput, 500); }, methods: { convertToMinutes(seconds) { return Math.floor(seconds / 60); }, - validateMinutes(value) { - if (this.selectedDuration === DurationDropdownMap.EXACT_TIME) { - this.$emit('input', value * 60); - } else { - if (value >= this.minRange && value <= this.maxRange) { - this.$emit('input', value * 60); - } - } + convertToSeconds(minutes) { + return minutes * 60; + }, + handleInput(value) { + this.$emit('input', this.convertToSeconds(value)); }, }, $trs: { diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/activityDuration.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/activityDuration.spec.js new file mode 100644 index 0000000000..b72e72639f --- /dev/null +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/activityDuration.spec.js @@ -0,0 +1,194 @@ +import Vue from 'vue'; +import Vuetify from 'vuetify'; +import { shallowMount, mount } from '@vue/test-utils'; +import ActivityDuration from '../ActivityDuration.vue'; + +Vue.use(Vuetify); + +describe('ActivityDuration', () => { + it('smoke test', () => { + const wrapper = shallowMount(ActivityDuration); + expect(wrapper.isVueInstance()).toBe(true); + }); + + describe(`minutes input`, () => { + const shortActivityMin = 1; + const shortActivityMax = 30; + const longActivityMin = 31; + const longActivityMax = 120; + describe(`default state for audio/video resources`, () => { + it(`should display a static upload time when 'Exact time to complete' for audio/video resources as initial state`, () => { + const defaultValue = '17:12'; + const wrapper = shallowMount(ActivityDuration); + expect(wrapper.vm.defaultUploadTime).toEqual(defaultValue); + }); + it(`should display the file's time at upload when 'Exact time to complete' is chosen in Completiond dropdown`, () => { + // TODO: defaultValue will need to be changed when file-upload-duration is implemented + const defaultValue = '17:12'; + const wrapper = shallowMount(ActivityDuration, { + propsData: { duration: 123 }, + }); + expect(wrapper.props('duration')).toEqual(123); + expect(wrapper.vm.defaultUploadTime).not.toEqual(defaultValue); + expect(wrapper.vm.defaultUploadTime).toEqual(123); + }); + it(`should display a "stand-in" at upload if file's time at upload is not available when 'Exact time to complete' is chosen in Completiond dropdown`, () => { + // TODO: defaultValue will need to be changed when file-upload-duration is implemented + const defaultValue = '17:12'; + const wrapper = shallowMount(ActivityDuration, { + propsData: { duration: null }, + }); + expect(wrapper.props('duration')).toEqual(null); + expect(wrapper.vm.defaultUploadTime).toEqual(defaultValue); + expect(wrapper.vm.defaultUploadTime).not.toEqual(null); + }); + }); + + describe(`convert seconds to minutes for display`, () => { + it(`should convert seconds into minutes`, () => { + const wrapper = shallowMount(ActivityDuration); + expect(wrapper.vm.convertToMinutes(3000)).toBe(50); + }); + it(`should display the seconds passed down from parent as minutes`, () => { + const wrapper = shallowMount(ActivityDuration, { + propsData: { value: 600 }, + }); + let seconds = wrapper.props('value'); + expect(wrapper.props('value')).toEqual(600); + expect(wrapper.vm.convertToMinutes(seconds)).toBe(10); + + wrapper.setProps({ value: 4800 }); + seconds = wrapper.props('value'); + expect(wrapper.props('value')).toEqual(4800); + expect(wrapper.vm.convertToMinutes(seconds)).toBe(80); + }); + }); + + describe(`convert minutes to seconds to emit to parent`, () => { + it(`should convert minutes to seconds before emitting`, () => { + const wrapper = shallowMount(ActivityDuration); + expect(wrapper.vm.convertToSeconds(40)).toBe(2400); + }); + it(`should emit time to parent`, () => { + const seconds = 2400; + const wrapper = mount(ActivityDuration); + wrapper.vm.$emit('input', seconds); + + return Vue.nextTick().then(() => { + const emittedTime = wrapper.emitted('input').pop()[0]; + expect(emittedTime).toEqual(seconds); + }); + }); + }); + + describe(`in 'Short activity'`, () => { + const wrapper = mount(ActivityDuration, { + propsData: { + selectedDuration: 'shortActivity', + }, + }); + it(`should increment by 5-minute intervals`, () => { + expect(wrapper.html()).toContain(`step="5"`); + expect(wrapper.html()).not.toContain(`step="10"`); + }); + it(`minimum accepted input should be 1 minute`, () => { + expect(wrapper.vm.minRange).toBe(shortActivityMin); + expect(wrapper.vm.minRange).not.toBe(longActivityMin); + }); + it(`maximum accepted input should be 30 minutes`, () => { + expect(wrapper.vm.maxRange).toBe(shortActivityMax); + expect(wrapper.vm.maxRange).not.toBe(longActivityMax); + }); + }); + + describe(`in 'Long activity'`, () => { + const wrapper = mount(ActivityDuration, { + propsData: { + selectedDuration: 'longActivity', + }, + }); + it(`should increment by 10-minute intervals`, () => { + expect(wrapper.html()).toContain(`step="10"`); + expect(wrapper.html()).not.toContain(`step="5"`); + }); + it(`minimum accepted input should be 31 minutes`, () => { + expect(wrapper.vm.minRange).not.toBe(shortActivityMin); + expect(wrapper.vm.minRange).toBe(longActivityMin); + }); + it(`maximum accepted input should be 120 minutes`, () => { + expect(wrapper.vm.maxRange).not.toBe(shortActivityMax); + expect(wrapper.vm.maxRange).toBe(longActivityMax); + }); + }); + + describe(`hints`, () => { + const optionalHint = + '(Optional) Duration until resource is marked as complete. This value will not be shown to learners.'; + const requiredHint = + 'Duration until resource is marked as complete. This value will not be shown to learners.'; + describe(`audio/video resource`, () => { + it(`should display optional hint when 'Short activity' is chosen`, () => { + const wrapper = shallowMount(ActivityDuration, { + propsData: { + audioVideoUpload: true, + selectedDuration: 'shortActivity', + }, + }); + expect(wrapper.html()).toContain(optionalHint); + }); + it(`should display optional hint when 'Long activity' is chosen`, () => { + const wrapper = shallowMount(ActivityDuration, { + propsData: { + audioVideoUpload: true, + selectedDuration: 'longActivity', + }, + }); + expect(wrapper.html()).toContain(optionalHint); + }); + it(`should not display any hints when 'Exact time to complete' is chosen`, () => { + const wrapper = shallowMount(ActivityDuration, { + propsData: { + audioVideoUpload: true, + selectedDuration: 'exactTime', + }, + }); + expect(wrapper.html()).not.toContain(requiredHint); + expect(wrapper.html()).not.toContain(optionalHint); + }); + }); + describe(`all other resources`, () => { + it(`should display optional hint when 'All content viewed' is selected in the Completion dropdown and 'Short/Long activity' is chosen`, () => { + const wrapper = shallowMount(ActivityDuration, { + propsData: { + audioVideoUpload: false, + selectedCompletion: 'allContent', + selectedDuration: 'shortActivity', + }, + }); + expect(wrapper.html()).toContain(optionalHint); + }); + it(`should display required hint when 'Complete duration' is selected in the Completion dropdown and 'Short/Long activity' is chosen`, () => { + const wrapper = shallowMount(ActivityDuration, { + propsData: { + audioVideoUpload: false, + selectedCompletion: 'completeDuration', + selectedDuration: 'shortActivity', + }, + }); + expect(wrapper.html()).not.toContain('(Optional)'); + expect(wrapper.html()).toContain(requiredHint); + }); + it(`should not display any hints when 'Exact time to complete' is chosen`, () => { + const wrapper = shallowMount(ActivityDuration, { + propsData: { + audioVideoUpload: false, + selectedDuration: 'exactTime', + }, + }); + expect(wrapper.html()).not.toContain(requiredHint); + expect(wrapper.html()).not.toContain(optionalHint); + }); + }); + }); + }); +}); From 7b489d1bf9df5003f11c5e60461457d262ac0dc6 Mon Sep 17 00:00:00 2001 From: sairina Date: Wed, 20 Jul 2022 09:47:58 -0700 Subject: [PATCH 02/14] Update MasteryGoal and test --- .../components/edit/MasteryCriteriaGoal.vue | 10 +- .../__tests__/masteryCriteriaGoal.spec.js | 97 +++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/masteryCriteriaGoal.spec.js diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/MasteryCriteriaGoal.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/MasteryCriteriaGoal.vue index f56ba17306..f0d5985070 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/MasteryCriteriaGoal.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/MasteryCriteriaGoal.vue @@ -13,6 +13,7 @@ :placeholder="placeholder" :required="required" :readonly="readonly" + :disabled="disabled" :rules="masteryRules" menu-props="offsetY" class="mb-2" @@ -27,7 +28,10 @@ diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js new file mode 100644 index 0000000000..d3684f2f43 --- /dev/null +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js @@ -0,0 +1,298 @@ +import Vue from 'vue'; +import Vuetify from 'vuetify'; +import { shallowMount, mount } from '@vue/test-utils'; +import CompletionOptions from '../CompletionOptions.vue'; + +Vue.use(Vuetify); + +describe('CompletionOptions', () => { + it('smoke test', () => { + const wrapper = shallowMount(CompletionOptions); + expect(wrapper.isVueInstance()).toBe(true); + }); + + describe(`completion dropdown`, () => { + it(`renders the completion dropdown`, () => { + const wrapper = mount(CompletionOptions); + const dropdown = wrapper.find({ ref: 'completion' }); + expect(dropdown.exists()).toBe(true); + }); + describe(`initial, default states`, () => { + describe(`audio or video`, () => { + it(`'Complete duration' should be displayed by default`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'audio', + value: { model: null }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('completeDuration'); + }); + it(`'Complete duration' should be displayed if the model in the backend is 'exact time', 'short activity', or 'long activity'`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'audio', + value: { model: 'exactTime' }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('completeDuration'); + }); + it(`'Complete duration' should be displayed if the model in the backend is 'exact time'`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'audio', + value: { model: 'exactTime' }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('completeDuration'); + }); + it(`'Complete duration' should be displayed if the model in the backend is 'short activity'`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'audio', + value: { model: 'shortActivity' }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('completeDuration'); + }); + it(`'Complete duration' should be displayed if the model in the backend is 'long activity'`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'audio', + value: { model: 'longActivity' }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('completeDuration'); + }); + it(`'Reference' should be displayed if the model in the backend is 'reference'`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'audio', + value: { model: 'reference' }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('reference'); + }); + }); + describe(`document`, () => { + it(`'All content viewed' should be displayed by default`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: null }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('allContent'); + }); + it(`'All content viewed' should be displayed if the model in the backend is 'reference'`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'reference' }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('allContent'); + }); + it(`'All content viewed' should be displayed if the model in the backend is 'pages'`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'pages' }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('allContent'); + }); + it(`'Complete duration' should be displayed if the model in the backend is 'exact time'`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'exactTime' }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('completeDuration'); + }); + it(`'Complete duration' should be displayed if the model in the backend is 'short activity'`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'shortActivity' }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('completeDuration'); + }); + it(`'Complete duration' should be displayed if the model in the backend is 'long activity'`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'shortActivity' }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('completeDuration'); + }); + }); + describe(`exercise`, () => { + it(`'Practice until goal is met' should be displayed by default if 'practice quiz' is enabled `, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { model: null }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('goal'); + }); + it(`Completion dropdown should not be displayed if 'practice quiz' is not enabled while 'Practice until goal is met' is set in background`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { model: null, modality: 'QUIZ' }, + practiceQuizzesAllowed: false, + }, + }); + expect(wrapper.find({ ref: 'completion' }).exists()).toBe(false); + expect(wrapper.vm.completionDropdown).toBe('goal'); + }); + }); + describe(`html5 or h5p`, () => { + it(`'Complete duration' should be displayed by default for html5`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'html5', + value: { model: null }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('completeDuration'); + }); + it(`'Determined by this resource' should be displayed if there is no model in the backend for h5p`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'h5p', + value: { model: null }, + }, + }); + expect(wrapper.vm.completionDropdown).toBe('determinedByResource'); + }); + }); + }); + }); + + xdescribe(`duration dropdown`, () => { + describe(`default states`, () => { + it(`'Exact time to complete' should be displayed by default for audio or video`, () => { + //done + }); + it(`duration dropdown is empty by default for documents`, () => { + //done + }); + it(`duration dropdown is empty by default for exercises`, () => {}); + it(`duration dropdown is empty by default for html5`, () => { + //done + }); + it(`duration dropdown is hidden by default for h5p`, () => {}); + }); + describe(`displayed states`, () => { + it(`'Reference' should be displayed if the model is 'reference'`, () => { + //done + }); + it(`'Exact time' should be displayed if the 'suggested_duration_type' is 'exact time'`, () => { + //done + }); + it(`'Short activity' should be displayed if the 'suggested_duration_type' is 'approx_time' and 'suggested_duration' is less than the midpoint`, () => { + //done + }); + it(`'Long activity' should be displayed if the 'suggested_duration_type' is 'approx_time' and 'suggested_duration' is greater than the midpoint`, () => { + //done + }); + }); + describe(`when completion dropdown is 'Complete duration'`, () => { + it(`model and suggested_duration_type should be 'approx_time' when duration dropdown is 'Short activity'`, () => { + //done + }); + it(`model and suggested_duration_type should be 'approx_time' when duration dropdown is 'Long activity'`, () => { + //done + }); + it(`model and suggested_duration_type should be 'time' when duration dropdown is 'Exact time'`, () => { + //done + }); + }); + describe(`when completion dropdown is 'All content viewed'`, () => { + it(`model should be 'pages' and suggested_duration_type should be 'approx_time' when duration dropdown is 'Short activity'`, () => { + //done + }); + it(`model should be 'pages' and suggested_duration_type should be 'approx_time' when duration dropdown is 'Long activity'`, () => { + //done + }); + it(`model should be 'pages' and suggested_duration_type should be 'time' when duration dropdown is 'Exact time'`, () => { + //done + }); + it(`model should be 'reference' when duration dropdown is 'Reference'`, () => { + //done + }); + }); + describe(`when completion dropdown is 'Practice quiz'`, () => { + it(`'Goal' dropdown is removed`, () => { + //done + }); + }); + describe(`when completion dropdown is 'Practice until goal is met'`, () => { + it(``, () => {}); + it(``, () => {}); + it(``, () => {}); + }); + describe(`when completion dropdown is 'Determined by this resource'`, () => {}); + }); + xdescribe(`minutes input`, () => { + //Note: while the component itself is in another component, + //the logic to get the data ready for the BE is in this component + //test for the initial state (does it show or not show) when you click on resources + describe(`in 'Short activity'`, () => { + it(`should increment by 5-minute intervals`, () => { + // const wrapper = mount(ActivityDuration, { + // propsData: { + // selectedDuration: 'longActivity', + // }, + // }); + // expect(wrapper.html()).toContain(`step="5"`); + // expect(wrapper.html()).not.toContain(`step="10"`); + }); + it(`should round to the nearest 5-minute`, () => { + // const wrapper = mount(ActivityDuration); + }); + it(`minimum accepted input should be 5 minutes`, () => {}); + it(`maximum accepted input should be 30 minutes`, () => {}); + }); + + xdescribe(`default states`, () => { + it(`time from file should be displayed when duration dropdown is 'Exact time to complete'`, () => { + //done + }); + it(`minutes input should not be displayed for documents`, () => { + //done + }); + it(`duration dropdown is empty by default for exercises`, () => { + //done + }); + it(`duration dropdown is empty by default for html5 or h5p`, () => {}); + }); + xdescribe(`displayed states`, () => { + it(`'Reference' should be displayed if the model is 'reference'`, () => {}); + it(`'Exact time' should be displayed if the 'suggested_duration_type' is 'exact time'`, () => {}); + it(`'Short activity' should be displayed if the 'suggested_duration_type' is 'approx_time' and 'suggested_duration' is less than the midpoint`, () => {}); + it(`'Long activity' should be displayed if the 'suggested_duration_type' is 'approx_time' and 'suggested_duration' is greater than the midpoint`, () => {}); + }); + + xdescribe(`when completion dropdown is 'Complete duration'`, () => { + it(`model and suggested_duration_type should be 'approx_time' when duration dropdown is 'Short activity'`, () => {}); + it(`model and suggested_duration_type should be 'approx_time' when duration dropdown is 'Long activity'`, () => {}); + it(`model and suggested_duration_type should be 'time' when duration dropdown is 'Exact time'`, () => {}); + }); + xdescribe(`when completion dropdown is 'All content viewed'`, () => { + it(`model should be 'pages' and suggested_duration_type should be 'approx_time' when duration dropdown is 'Short activity'`, () => {}); + it(`model should be 'pages' and suggested_duration_type should be 'approx_time' when duration dropdown is 'Long activity'`, () => {}); + it(`model should be 'pages' and suggested_duration_type should be 'time' when duration dropdown is 'Exact time'`, () => {}); + it(`model should be 'reference' when duration dropdown is 'Reference'`, () => {}); + }); + xdescribe(`when completion dropdown is 'Practice quiz'`, () => {}); + xdescribe(`when completion dropdown is 'Practice until goal is met'`, () => {}); + xdescribe(`when completion dropdown is 'Determined by this resource'`, () => {}); + }); +}); From 5c583f52c6c2e7b582a71f55e7357175421a2730 Mon Sep 17 00:00:00 2001 From: sairina Date: Wed, 20 Jul 2022 20:51:41 -0700 Subject: [PATCH 06/14] Add duration dropdown default states tests and update code --- .../edit/__tests__/completionOptions.spec.js | 64 +++++++++++++++---- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js index d3684f2f43..6fd087af3d 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js @@ -175,21 +175,61 @@ describe('CompletionOptions', () => { }); }); - xdescribe(`duration dropdown`, () => { + describe(`duration dropdown`, () => { + it(`renders the duration dropdown`, () => { + const wrapper = mount(CompletionOptions); + const dropdown = wrapper.find({ ref: 'duration' }); + expect(dropdown.exists()).toBe(true); + }); describe(`default states`, () => { it(`'Exact time to complete' should be displayed by default for audio or video`, () => { - //done + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'audio', + value: { suggested_duration: null }, + }, + }); + expect(wrapper.vm.durationDropdown).toBe('exactTime'); }); it(`duration dropdown is empty by default for documents`, () => { - //done + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { suggested_duration: null }, + }, + }); + expect(wrapper.vm.durationDropdown).toBe(''); + }); + it(`duration dropdown is empty by default for exercises`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { suggested_duration: null }, + }, + }); + expect(wrapper.vm.durationDropdown).toBe(''); }); - it(`duration dropdown is empty by default for exercises`, () => {}); it(`duration dropdown is empty by default for html5`, () => { - //done + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'html5', + value: { suggested_duration: null }, + }, + }); + expect(wrapper.vm.durationDropdown).toBe(''); + }); + it(`duration dropdown is hidden by default for h5p`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'h5p', + value: { suggested_duration: null }, + }, + }); + const dropdown = wrapper.find({ ref: 'duration' }); + expect(dropdown.exists()).toBe(false); }); - it(`duration dropdown is hidden by default for h5p`, () => {}); }); - describe(`displayed states`, () => { + xdescribe(`displayed states`, () => { it(`'Reference' should be displayed if the model is 'reference'`, () => { //done }); @@ -203,7 +243,7 @@ describe('CompletionOptions', () => { //done }); }); - describe(`when completion dropdown is 'Complete duration'`, () => { + xdescribe(`when completion dropdown is 'Complete duration'`, () => { it(`model and suggested_duration_type should be 'approx_time' when duration dropdown is 'Short activity'`, () => { //done }); @@ -214,7 +254,7 @@ describe('CompletionOptions', () => { //done }); }); - describe(`when completion dropdown is 'All content viewed'`, () => { + xdescribe(`when completion dropdown is 'All content viewed'`, () => { it(`model should be 'pages' and suggested_duration_type should be 'approx_time' when duration dropdown is 'Short activity'`, () => { //done }); @@ -228,17 +268,17 @@ describe('CompletionOptions', () => { //done }); }); - describe(`when completion dropdown is 'Practice quiz'`, () => { + xdescribe(`when completion dropdown is 'Practice quiz'`, () => { it(`'Goal' dropdown is removed`, () => { //done }); }); - describe(`when completion dropdown is 'Practice until goal is met'`, () => { + xdescribe(`when completion dropdown is 'Practice until goal is met'`, () => { it(``, () => {}); it(``, () => {}); it(``, () => {}); }); - describe(`when completion dropdown is 'Determined by this resource'`, () => {}); + xdescribe(`when completion dropdown is 'Determined by this resource'`, () => {}); }); xdescribe(`minutes input`, () => { //Note: while the component itself is in another component, From 88307c68675b65f652e3977d78b56b9c4e822905 Mon Sep 17 00:00:00 2001 From: sairina Date: Wed, 20 Jul 2022 21:38:41 -0700 Subject: [PATCH 07/14] Add tests for emitting --- .../edit/__tests__/completionOptions.spec.js | 88 ++++++++++++++++--- 1 file changed, 74 insertions(+), 14 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js index 6fd087af3d..6c898953a6 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js @@ -18,7 +18,7 @@ describe('CompletionOptions', () => { expect(dropdown.exists()).toBe(true); }); describe(`initial, default states`, () => { - describe(`audio or video`, () => { + describe(`audio/video`, () => { it(`'Complete duration' should be displayed by default`, () => { const wrapper = mount(CompletionOptions, { propsData: { @@ -173,6 +173,39 @@ describe('CompletionOptions', () => { }); }); }); + describe(`changing states`, () => { + describe('emitted events', () => { + it('input should be emitted when completion dropdown is updated', async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: null }, + }, + }); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'allContent'); + await wrapper.vm.$nextTick(); + + expect(wrapper.emitted('input')).toBeTruthy(); + }); + }); + describe(`audio/video`, () => { + it(`'Duration dropdown' is not visible and reference hint is visible when 'Reference' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'audio', + value: { model: null }, + }, + }); + expect(wrapper.vm.showReferenceHint).toBe(false); + expect(wrapper.find({ ref: 'duration' }).exists()).toBe(true); + + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'reference'); + await wrapper.vm.$nextTick(); + expect(wrapper.vm.showReferenceHint).toBe(true); + expect(wrapper.find({ ref: 'duration' }).exists()).toBe(false); + }); + }); + }); }); describe(`duration dropdown`, () => { @@ -229,21 +262,48 @@ describe('CompletionOptions', () => { expect(dropdown.exists()).toBe(false); }); }); - xdescribe(`displayed states`, () => { - it(`'Reference' should be displayed if the model is 'reference'`, () => { - //done - }); - it(`'Exact time' should be displayed if the 'suggested_duration_type' is 'exact time'`, () => { - //done - }); - it(`'Short activity' should be displayed if the 'suggested_duration_type' is 'approx_time' and 'suggested_duration' is less than the midpoint`, () => { - //done + describe(`when completion dropdown is 'Complete duration'`, () => { + describe('emitted events', () => { + it('input should be emitted when duration dropdown is updated', async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: null }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); + await wrapper.vm.$nextTick(); + + expect(wrapper.emitted('input')).toBeTruthy(); + }); }); - it(`'Long activity' should be displayed if the 'suggested_duration_type' is 'approx_time' and 'suggested_duration' is greater than the midpoint`, () => { - //done + describe(`audio/video`, () => { + it(`minutes input is displayed when 'Short activity' is chosen`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'audio', + value: { model: null }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + }); + it(`minutes input is displayed when 'Long activity' is chosen`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'audio', + value: { model: null }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'longActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + }); }); - }); - xdescribe(`when completion dropdown is 'Complete duration'`, () => { + describe(`document`, () => {}); + describe(`exercise`, () => {}); + describe(`html5 or h5p`, () => {}); it(`model and suggested_duration_type should be 'approx_time' when duration dropdown is 'Short activity'`, () => { //done }); From dc7f15a8a2edf0c614f186a3d87134e61e1c4540 Mon Sep 17 00:00:00 2001 From: sairina Date: Thu, 21 Jul 2022 15:09:19 -0700 Subject: [PATCH 08/14] Add tests for document changing state in all content viewed --- .../edit/__tests__/completionOptions.spec.js | 97 +++++++++++++++++-- 1 file changed, 87 insertions(+), 10 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js index 6c898953a6..f07c5d0907 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js @@ -189,20 +189,23 @@ describe('CompletionOptions', () => { }); }); describe(`audio/video`, () => { - it(`'Duration dropdown' is not visible and reference hint is visible when 'Reference' is selected`, async () => { + it(`'Duration dropdown' is not visible and reference hint is visible when 'Reference' is selected`, () => { const wrapper = mount(CompletionOptions, { propsData: { kind: 'audio', - value: { model: null }, + value: { model: 'reference' }, }, }); - expect(wrapper.vm.showReferenceHint).toBe(false); - expect(wrapper.find({ ref: 'duration' }).exists()).toBe(true); - - wrapper.find({ ref: 'completion' }).vm.$emit('input', 'reference'); - await wrapper.vm.$nextTick(); expect(wrapper.vm.showReferenceHint).toBe(true); expect(wrapper.find({ ref: 'duration' }).exists()).toBe(false); + + // wrapper.find({ ref: 'completion' }).vm.$emit('input', 'reference'); + // await wrapper.vm.$nextTick(); + + // console.log(wrapper.vm.audioVideoResource) + // console.log(wrapper.vm.value); + // expect(wrapper.vm.showReferenceHint).toBe(true); + // expect(wrapper.find({ ref: 'duration' }).exists()).toBe(false); }); }); }); @@ -278,7 +281,7 @@ describe('CompletionOptions', () => { }); }); describe(`audio/video`, () => { - it(`minutes input is displayed when 'Short activity' is chosen`, async () => { + it(`minutes input is displayed when 'Short activity' is selected`, async () => { const wrapper = mount(CompletionOptions, { propsData: { kind: 'audio', @@ -288,8 +291,9 @@ describe('CompletionOptions', () => { wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); await wrapper.vm.$nextTick(); expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); }); - it(`minutes input is displayed when 'Long activity' is chosen`, async () => { + it(`minutes input is displayed when 'Long activity' is selected`, async () => { const wrapper = mount(CompletionOptions, { propsData: { kind: 'audio', @@ -299,9 +303,82 @@ describe('CompletionOptions', () => { wrapper.find({ ref: 'duration' }).vm.$emit('input', 'longActivity'); await wrapper.vm.$nextTick(); expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + }); + describe(`document`, () => { + describe(`'All content viewed' is selected as completion`, () => { + it(`minutes input is displayed when 'Short activity' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'pages' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is displayed when 'Long activity' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'pages' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'longActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is displayed when 'Exact time' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'pages' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'exactTime'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is hidden and reference hint is displayed when 'Reference' is selected`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'reference' }, + }, + }); + // wrapper.find({ ref: 'completion' }).vm.$emit('input', 'allContent'); + // wrapper.find({ ref: 'duration' }).vm.$emit('input', + // { + // completion_criteria: { model: 'reference', threshold: null }, + // suggested_duration: NaN, + // suggested_duration_type: 'approx_time', + // modality: undefined + // } + // ); + + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(false); + expect(wrapper.vm.showActivityDurationInput).toBe(false); + expect(wrapper.vm.showReferenceHint).toBe(true); + }); + }); + describe(`'Complete duration' is selected as completion`, () => { + it(`.... when 'Short activity' is selected`, () => {}); + it(`.... when 'Long activity' is selected`, () => {}); + it(`.... when 'Exact time' is selected`, () => {}); + it(`.... when 'Reference' is selected`, () => {}); + }); + describe(`Switching between 'All content viewed' and 'Complete duration'`, () => { + it(`.... when switching betweeen 'Short activity' in ACV and CD`, () => {}); + it(`.... when switching betweeen 'Long activity' in ACV and CD`, () => {}); + it(`.... when switching betweeen 'Exact time' in ACV and CD`, () => {}); + it(`.... when switching betweeen 'Reference' in ACV and CD`, () => {}); }); }); - describe(`document`, () => {}); describe(`exercise`, () => {}); describe(`html5 or h5p`, () => {}); it(`model and suggested_duration_type should be 'approx_time' when duration dropdown is 'Short activity'`, () => { From aa56d59c18c505a3e35f0ee5cada917ef7345485 Mon Sep 17 00:00:00 2001 From: sairina Date: Thu, 21 Jul 2022 16:42:01 -0700 Subject: [PATCH 09/14] Add tests for document changing state in complete duration --- .../edit/__tests__/completionOptions.spec.js | 160 +++++++++++++----- 1 file changed, 114 insertions(+), 46 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js index f07c5d0907..89726fd269 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js @@ -198,14 +198,6 @@ describe('CompletionOptions', () => { }); expect(wrapper.vm.showReferenceHint).toBe(true); expect(wrapper.find({ ref: 'duration' }).exists()).toBe(false); - - // wrapper.find({ ref: 'completion' }).vm.$emit('input', 'reference'); - // await wrapper.vm.$nextTick(); - - // console.log(wrapper.vm.audioVideoResource) - // console.log(wrapper.vm.value); - // expect(wrapper.vm.showReferenceHint).toBe(true); - // expect(wrapper.find({ ref: 'duration' }).exists()).toBe(false); }); }); }); @@ -351,32 +343,128 @@ describe('CompletionOptions', () => { value: { model: 'reference' }, }, }); - // wrapper.find({ ref: 'completion' }).vm.$emit('input', 'allContent'); - // wrapper.find({ ref: 'duration' }).vm.$emit('input', - // { - // completion_criteria: { model: 'reference', threshold: null }, - // suggested_duration: NaN, - // suggested_duration_type: 'approx_time', - // modality: undefined - // } - // ); - expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(false); expect(wrapper.vm.showActivityDurationInput).toBe(false); expect(wrapper.vm.showReferenceHint).toBe(true); }); }); describe(`'Complete duration' is selected as completion`, () => { - it(`.... when 'Short activity' is selected`, () => {}); - it(`.... when 'Long activity' is selected`, () => {}); - it(`.... when 'Exact time' is selected`, () => {}); - it(`.... when 'Reference' is selected`, () => {}); + it(`minutes input is displayed when 'Short activity' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'approx_time' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is displayed when 'Long activity' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'approx_time' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'longActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is displayed when 'Exact time' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'time' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'exactTime'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`'Reference' is disabled`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'time' }, + }, + }); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'completeDuration'); + await wrapper.vm.$nextTick(); + + const clickableDurationDropdown = wrapper.vm.selectableDurationOptions; + const reference = clickableDurationDropdown.filter( + option => option.value === 'reference' + ); + expect(clickableDurationDropdown.length).toBe(4); + expect(reference[0].disabled).toBe(true); + }); }); describe(`Switching between 'All content viewed' and 'Complete duration'`, () => { - it(`.... when switching betweeen 'Short activity' in ACV and CD`, () => {}); - it(`.... when switching betweeen 'Long activity' in ACV and CD`, () => {}); - it(`.... when switching betweeen 'Exact time' in ACV and CD`, () => {}); - it(`.... when switching betweeen 'Reference' in ACV and CD`, () => {}); + it(`Duration dropdown and minutes input stay the same when switching betweeen 'Short activity' in ACV and CD`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { + model: 'approx_time', + suggested_duration: 1200, + suggested_duration_type: 'approx_time', + }, + }, + }); + expect(wrapper.vm.durationDropdown).toBe('shortActivity'); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'allContent'); + await wrapper.vm.$nextTick(); + + expect(wrapper.vm.durationDropdown).toBe('shortActivity'); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + expect(wrapper.vm.minutes).toBe(1200); + }); + it(`Duration dropdown and minutes input stay the same when switching betweeen 'Long activity' in ACV and CD`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { + model: 'approx_time', + suggested_duration: 6000, + suggested_duration_type: 'approx_time', + }, + }, + }); + expect(wrapper.vm.durationDropdown).toBe('longActivity'); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'allContent'); + await wrapper.vm.$nextTick(); + + expect(wrapper.vm.durationDropdown).toBe('longActivity'); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + expect(wrapper.vm.minutes).toBe(6000); + }); + it(`Duration dropdown and minutes input stay the same when switching betweeen 'Exact time' in ACV and CD`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { + model: 'pages', + threshold: '100%', + suggested_duration: 1234, + suggested_duration_type: 'time', + }, + }, + }); + expect(wrapper.vm.durationDropdown).toBe('exactTime'); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'completeDuration'); + await wrapper.vm.$nextTick(); + + expect(wrapper.vm.durationDropdown).toBe('exactTime'); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + expect(wrapper.vm.minutes).toBe(1234); + }); }); }); describe(`exercise`, () => {}); @@ -391,20 +479,6 @@ describe('CompletionOptions', () => { //done }); }); - xdescribe(`when completion dropdown is 'All content viewed'`, () => { - it(`model should be 'pages' and suggested_duration_type should be 'approx_time' when duration dropdown is 'Short activity'`, () => { - //done - }); - it(`model should be 'pages' and suggested_duration_type should be 'approx_time' when duration dropdown is 'Long activity'`, () => { - //done - }); - it(`model should be 'pages' and suggested_duration_type should be 'time' when duration dropdown is 'Exact time'`, () => { - //done - }); - it(`model should be 'reference' when duration dropdown is 'Reference'`, () => { - //done - }); - }); xdescribe(`when completion dropdown is 'Practice quiz'`, () => { it(`'Goal' dropdown is removed`, () => { //done @@ -450,12 +524,6 @@ describe('CompletionOptions', () => { }); it(`duration dropdown is empty by default for html5 or h5p`, () => {}); }); - xdescribe(`displayed states`, () => { - it(`'Reference' should be displayed if the model is 'reference'`, () => {}); - it(`'Exact time' should be displayed if the 'suggested_duration_type' is 'exact time'`, () => {}); - it(`'Short activity' should be displayed if the 'suggested_duration_type' is 'approx_time' and 'suggested_duration' is less than the midpoint`, () => {}); - it(`'Long activity' should be displayed if the 'suggested_duration_type' is 'approx_time' and 'suggested_duration' is greater than the midpoint`, () => {}); - }); xdescribe(`when completion dropdown is 'Complete duration'`, () => { it(`model and suggested_duration_type should be 'approx_time' when duration dropdown is 'Short activity'`, () => {}); From 6bd38d17a6db97977f1217a870a03e0ca45e7bec Mon Sep 17 00:00:00 2001 From: sairina Date: Thu, 21 Jul 2022 21:26:59 -0700 Subject: [PATCH 10/14] Add tests for exercises and duration dropdown states --- .../edit/__tests__/completionOptions.spec.js | 547 +++++++++++------- 1 file changed, 340 insertions(+), 207 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js index 89726fd269..8970723455 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js @@ -10,7 +10,6 @@ describe('CompletionOptions', () => { const wrapper = shallowMount(CompletionOptions); expect(wrapper.isVueInstance()).toBe(true); }); - describe(`completion dropdown`, () => { it(`renders the completion dropdown`, () => { const wrapper = mount(CompletionOptions); @@ -75,6 +74,7 @@ describe('CompletionOptions', () => { }); }); describe(`document`, () => { + //! TODO FIX it(`'All content viewed' should be displayed by default`, () => { const wrapper = mount(CompletionOptions, { propsData: { @@ -200,9 +200,22 @@ describe('CompletionOptions', () => { expect(wrapper.find({ ref: 'duration' }).exists()).toBe(false); }); }); + describe(`exercise`, () => { + it(`Goal and MofN components should not be displayed when switching to PQ from PUGIM`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { model: 'mastery', modality: 'QUIZ' }, + }, + }); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'practiceQuiz'); + await wrapper.vm.$nextTick(); + expect(wrapper.vm.showMasteryCriteriaGoalDropdown).toBe(false); + expect(wrapper.vm.showMofN).toBe(false); + }); + }); }); }); - describe(`duration dropdown`, () => { it(`renders the duration dropdown`, () => { const wrapper = mount(CompletionOptions); @@ -232,11 +245,24 @@ describe('CompletionOptions', () => { const wrapper = mount(CompletionOptions, { propsData: { kind: 'exercise', - value: { suggested_duration: null }, + value: { model: 'mastery', suggested_duration: null }, }, }); expect(wrapper.vm.durationDropdown).toBe(''); }); + it(`'Reference' is disabled for exercises`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { model: 'mastery' }, + }, + }); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'completeDuration'); + await wrapper.vm.$nextTick(); + + const clickableDurationDropdown = wrapper.vm.selectableDurationOptions; + expect(clickableDurationDropdown.length).toBe(3); + }); it(`duration dropdown is empty by default for html5`, () => { const wrapper = mount(CompletionOptions, { propsData: { @@ -257,27 +283,102 @@ describe('CompletionOptions', () => { expect(dropdown.exists()).toBe(false); }); }); - describe(`when completion dropdown is 'Complete duration'`, () => { - describe('emitted events', () => { - it('input should be emitted when duration dropdown is updated', async () => { + describe('emitted events', () => { + it('input should be emitted when duration dropdown is updated', async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: null }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); + await wrapper.vm.$nextTick(); + + expect(wrapper.emitted('input')).toBeTruthy(); + }); + }); + describe(`audio/video`, () => { + it(`minutes input is displayed when 'Short activity' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'audio', + value: { model: null }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is displayed when 'Long activity' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'audio', + value: { model: null }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'longActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + }); + describe(`document`, () => { + describe(`'All content viewed' is selected as completion`, () => { + it(`minutes input is displayed when 'Short activity' is selected`, async () => { const wrapper = mount(CompletionOptions, { propsData: { kind: 'document', - value: { model: null }, + value: { model: 'pages' }, }, }); wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); await wrapper.vm.$nextTick(); - - expect(wrapper.emitted('input')).toBeTruthy(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is displayed when 'Long activity' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'pages' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'longActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is displayed when 'Exact time' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'pages' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'exactTime'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is hidden and reference hint is displayed when 'Reference' is selected`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'reference' }, + }, + }); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(false); + expect(wrapper.vm.showActivityDurationInput).toBe(false); + expect(wrapper.vm.showReferenceHint).toBe(true); }); }); - describe(`audio/video`, () => { + describe(`'Complete duration' is selected as completion`, () => { it(`minutes input is displayed when 'Short activity' is selected`, async () => { const wrapper = mount(CompletionOptions, { propsData: { - kind: 'audio', - value: { model: null }, + kind: 'document', + value: { model: 'approx_time' }, }, }); wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); @@ -288,8 +389,8 @@ describe('CompletionOptions', () => { it(`minutes input is displayed when 'Long activity' is selected`, async () => { const wrapper = mount(CompletionOptions, { propsData: { - kind: 'audio', - value: { model: null }, + kind: 'document', + value: { model: 'approx_time' }, }, }); wrapper.find({ ref: 'duration' }).vm.$emit('input', 'longActivity'); @@ -297,199 +398,246 @@ describe('CompletionOptions', () => { expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); expect(wrapper.vm.showActivityDurationInput).toBe(true); }); + it(`minutes input is displayed when 'Exact time' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'time' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'exactTime'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`'Reference' is disabled`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { model: 'time' }, + }, + }); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'completeDuration'); + await wrapper.vm.$nextTick(); + + const clickableDurationDropdown = wrapper.vm.selectableDurationOptions; + const reference = clickableDurationDropdown.filter( + option => option.value === 'reference' + ); + expect(clickableDurationDropdown.length).toBe(4); + expect(reference[0].disabled).toBe(true); + }); }); - describe(`document`, () => { - describe(`'All content viewed' is selected as completion`, () => { - it(`minutes input is displayed when 'Short activity' is selected`, async () => { - const wrapper = mount(CompletionOptions, { - propsData: { - kind: 'document', - value: { model: 'pages' }, - }, - }); - wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); - await wrapper.vm.$nextTick(); - expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); - expect(wrapper.vm.showActivityDurationInput).toBe(true); - }); - it(`minutes input is displayed when 'Long activity' is selected`, async () => { - const wrapper = mount(CompletionOptions, { - propsData: { - kind: 'document', - value: { model: 'pages' }, - }, - }); - wrapper.find({ ref: 'duration' }).vm.$emit('input', 'longActivity'); - await wrapper.vm.$nextTick(); - expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); - expect(wrapper.vm.showActivityDurationInput).toBe(true); - }); - it(`minutes input is displayed when 'Exact time' is selected`, async () => { - const wrapper = mount(CompletionOptions, { - propsData: { - kind: 'document', - value: { model: 'pages' }, - }, - }); - wrapper.find({ ref: 'duration' }).vm.$emit('input', 'exactTime'); - await wrapper.vm.$nextTick(); - expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); - expect(wrapper.vm.showActivityDurationInput).toBe(true); - }); - it(`minutes input is hidden and reference hint is displayed when 'Reference' is selected`, () => { - const wrapper = mount(CompletionOptions, { - propsData: { - kind: 'document', - value: { model: 'reference' }, - }, - }); - expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(false); - expect(wrapper.vm.showActivityDurationInput).toBe(false); - expect(wrapper.vm.showReferenceHint).toBe(true); - }); - }); - describe(`'Complete duration' is selected as completion`, () => { - it(`minutes input is displayed when 'Short activity' is selected`, async () => { - const wrapper = mount(CompletionOptions, { - propsData: { - kind: 'document', - value: { model: 'approx_time' }, - }, - }); - wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); - await wrapper.vm.$nextTick(); - expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); - expect(wrapper.vm.showActivityDurationInput).toBe(true); - }); - it(`minutes input is displayed when 'Long activity' is selected`, async () => { - const wrapper = mount(CompletionOptions, { - propsData: { - kind: 'document', - value: { model: 'approx_time' }, - }, - }); - wrapper.find({ ref: 'duration' }).vm.$emit('input', 'longActivity'); - await wrapper.vm.$nextTick(); - expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); - expect(wrapper.vm.showActivityDurationInput).toBe(true); - }); - it(`minutes input is displayed when 'Exact time' is selected`, async () => { - const wrapper = mount(CompletionOptions, { - propsData: { - kind: 'document', - value: { model: 'time' }, + describe(`switching between 'All content viewed (ACV)' and 'Complete duration (CD)'`, () => { + it(`Duration dropdown and minutes input stay the same when switching betweeen 'Short activity' in ACV and CD`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { + model: 'approx_time', + suggested_duration: 1200, + suggested_duration_type: 'approx_time', }, - }); - wrapper.find({ ref: 'duration' }).vm.$emit('input', 'exactTime'); - await wrapper.vm.$nextTick(); - expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); - expect(wrapper.vm.showActivityDurationInput).toBe(true); - }); - it(`'Reference' is disabled`, async () => { - const wrapper = mount(CompletionOptions, { - propsData: { - kind: 'document', - value: { model: 'time' }, + }, + }); + expect(wrapper.vm.durationDropdown).toBe('shortActivity'); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'allContent'); + await wrapper.vm.$nextTick(); + + expect(wrapper.vm.durationDropdown).toBe('shortActivity'); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + expect(wrapper.vm.minutes).toBe(1200); + }); + it(`Duration dropdown and minutes input stay the same when switching betweeen 'Long activity' in ACV and CD`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { + model: 'approx_time', + suggested_duration: 6000, + suggested_duration_type: 'approx_time', }, - }); - wrapper.find({ ref: 'completion' }).vm.$emit('input', 'completeDuration'); - await wrapper.vm.$nextTick(); + }, + }); + expect(wrapper.vm.durationDropdown).toBe('longActivity'); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'allContent'); + await wrapper.vm.$nextTick(); - const clickableDurationDropdown = wrapper.vm.selectableDurationOptions; - const reference = clickableDurationDropdown.filter( - option => option.value === 'reference' - ); - expect(clickableDurationDropdown.length).toBe(4); - expect(reference[0].disabled).toBe(true); - }); - }); - describe(`Switching between 'All content viewed' and 'Complete duration'`, () => { - it(`Duration dropdown and minutes input stay the same when switching betweeen 'Short activity' in ACV and CD`, async () => { - const wrapper = mount(CompletionOptions, { - propsData: { - kind: 'document', - value: { - model: 'approx_time', - suggested_duration: 1200, - suggested_duration_type: 'approx_time', - }, + expect(wrapper.vm.durationDropdown).toBe('longActivity'); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + expect(wrapper.vm.minutes).toBe(6000); + }); + it(`Duration dropdown and minutes input stay the same when switching betweeen 'Exact time' in ACV and CD`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { + model: 'pages', + threshold: '100%', + suggested_duration: 1234, + suggested_duration_type: 'time', }, - }); - expect(wrapper.vm.durationDropdown).toBe('shortActivity'); - wrapper.find({ ref: 'completion' }).vm.$emit('input', 'allContent'); - await wrapper.vm.$nextTick(); + }, + }); + expect(wrapper.vm.durationDropdown).toBe('exactTime'); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'completeDuration'); + await wrapper.vm.$nextTick(); - expect(wrapper.vm.durationDropdown).toBe('shortActivity'); - expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); - expect(wrapper.vm.showActivityDurationInput).toBe(true); - expect(wrapper.vm.minutes).toBe(1200); - }); - it(`Duration dropdown and minutes input stay the same when switching betweeen 'Long activity' in ACV and CD`, async () => { - const wrapper = mount(CompletionOptions, { - propsData: { - kind: 'document', - value: { - model: 'approx_time', - suggested_duration: 6000, - suggested_duration_type: 'approx_time', - }, + expect(wrapper.vm.durationDropdown).toBe('exactTime'); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + expect(wrapper.vm.minutes).toBe(1234); + }); + }); + }); + describe(`exercise`, () => { + describe(`when completion dropdown is 'Practice until goal is met'`, () => { + it(`minutes input is displayed when 'Short activity' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { model: 'mastery' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is displayed when 'Long activity' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { model: 'mastery' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'longActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is displayed when 'Exact time' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { model: 'mastery' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'exactTime'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + }); + describe(`when completion dropdown is 'Practice quiz'`, () => { + it(`minutes input is displayed when 'Short activity' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { model: 'mastery', modality: 'QUIZ' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is displayed when 'Long activity' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { model: 'mastery', modality: 'QUIZ' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'longActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is displayed when 'Exact time' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { model: 'mastery', modality: 'QUIZ' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'exactTime'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + }); + describe(`switching between 'Practice until goal is met (PUGIM)' and 'Practice quiz (PQ)'`, () => { + it(`Duration dropdown and minutes input stay the same when switching betweeen 'Short activity' in PUGIM and PQ`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { + model: 'mastery', + modality: 'QUIZ', + suggested_duration: 1200, + suggested_duration_type: 'approx_time', }, - }); - expect(wrapper.vm.durationDropdown).toBe('longActivity'); - wrapper.find({ ref: 'completion' }).vm.$emit('input', 'allContent'); - await wrapper.vm.$nextTick(); + }, + }); + expect(wrapper.vm.durationDropdown).toBe('shortActivity'); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'goal'); + await wrapper.vm.$nextTick(); - expect(wrapper.vm.durationDropdown).toBe('longActivity'); - expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); - expect(wrapper.vm.showActivityDurationInput).toBe(true); - expect(wrapper.vm.minutes).toBe(6000); - }); - it(`Duration dropdown and minutes input stay the same when switching betweeen 'Exact time' in ACV and CD`, async () => { - const wrapper = mount(CompletionOptions, { - propsData: { - kind: 'document', - value: { - model: 'pages', - threshold: '100%', - suggested_duration: 1234, - suggested_duration_type: 'time', - }, + expect(wrapper.vm.durationDropdown).toBe('shortActivity'); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + expect(wrapper.vm.minutes).toBe(1200); + }); + it(`Duration dropdown and minutes input stay the same when switching betweeen 'Long activity' in PUGIM and PQ`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { + model: 'mastery', + modality: 'QUIZ', + suggested_duration: 6000, + suggested_duration_type: 'approx_time', }, - }); - expect(wrapper.vm.durationDropdown).toBe('exactTime'); - wrapper.find({ ref: 'completion' }).vm.$emit('input', 'completeDuration'); - await wrapper.vm.$nextTick(); + }, + }); + expect(wrapper.vm.durationDropdown).toBe('longActivity'); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'goal'); + await wrapper.vm.$nextTick(); - expect(wrapper.vm.durationDropdown).toBe('exactTime'); - expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); - expect(wrapper.vm.showActivityDurationInput).toBe(true); - expect(wrapper.vm.minutes).toBe(1234); + expect(wrapper.vm.durationDropdown).toBe('longActivity'); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + expect(wrapper.vm.minutes).toBe(6000); + }); + it(`Duration dropdown and minutes input stay the same when switching betweeen 'Exact time' in PUGIM and PQ`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'exercise', + value: { + model: 'mastery', + modality: 'QUIZ', + suggested_duration: 1234, + suggested_duration_type: 'time', + }, + }, }); + expect(wrapper.vm.durationDropdown).toBe('exactTime'); + wrapper.find({ ref: 'completion' }).vm.$emit('input', 'completeDuration'); + await wrapper.vm.$nextTick(); + + expect(wrapper.vm.durationDropdown).toBe('exactTime'); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + expect(wrapper.vm.minutes).toBe(1234); }); }); - describe(`exercise`, () => {}); - describe(`html5 or h5p`, () => {}); - it(`model and suggested_duration_type should be 'approx_time' when duration dropdown is 'Short activity'`, () => { - //done - }); - it(`model and suggested_duration_type should be 'approx_time' when duration dropdown is 'Long activity'`, () => { - //done - }); - it(`model and suggested_duration_type should be 'time' when duration dropdown is 'Exact time'`, () => { - //done - }); - }); - xdescribe(`when completion dropdown is 'Practice quiz'`, () => { - it(`'Goal' dropdown is removed`, () => { - //done - }); }); - xdescribe(`when completion dropdown is 'Practice until goal is met'`, () => { - it(``, () => {}); - it(``, () => {}); - it(``, () => {}); + describe(`html5 or h5p`, () => { + xdescribe(`when completion dropdown is 'Determined by this resource'`, () => {}); }); - xdescribe(`when completion dropdown is 'Determined by this resource'`, () => {}); }); xdescribe(`minutes input`, () => { //Note: while the component itself is in another component, @@ -524,20 +672,5 @@ describe('CompletionOptions', () => { }); it(`duration dropdown is empty by default for html5 or h5p`, () => {}); }); - - xdescribe(`when completion dropdown is 'Complete duration'`, () => { - it(`model and suggested_duration_type should be 'approx_time' when duration dropdown is 'Short activity'`, () => {}); - it(`model and suggested_duration_type should be 'approx_time' when duration dropdown is 'Long activity'`, () => {}); - it(`model and suggested_duration_type should be 'time' when duration dropdown is 'Exact time'`, () => {}); - }); - xdescribe(`when completion dropdown is 'All content viewed'`, () => { - it(`model should be 'pages' and suggested_duration_type should be 'approx_time' when duration dropdown is 'Short activity'`, () => {}); - it(`model should be 'pages' and suggested_duration_type should be 'approx_time' when duration dropdown is 'Long activity'`, () => {}); - it(`model should be 'pages' and suggested_duration_type should be 'time' when duration dropdown is 'Exact time'`, () => {}); - it(`model should be 'reference' when duration dropdown is 'Reference'`, () => {}); - }); - xdescribe(`when completion dropdown is 'Practice quiz'`, () => {}); - xdescribe(`when completion dropdown is 'Practice until goal is met'`, () => {}); - xdescribe(`when completion dropdown is 'Determined by this resource'`, () => {}); }); }); From 7ca87d1991bc5f5597be4ca79303bfb1ad2b0788 Mon Sep 17 00:00:00 2001 From: sairina Date: Thu, 21 Jul 2022 22:15:47 -0700 Subject: [PATCH 11/14] Add tests and fix code for HTML5 and H5P --- .../edit/__tests__/completionOptions.spec.js | 57 ++++++++++++++++--- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js index 8970723455..00006c1917 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js @@ -636,7 +636,55 @@ describe('CompletionOptions', () => { }); }); describe(`html5 or h5p`, () => { - xdescribe(`when completion dropdown is 'Determined by this resource'`, () => {}); + describe(`when completion dropdown is 'Determined by this resource'`, () => { + it(`minutes input is displayed when 'Short activity' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'html5', + value: { suggested_duration: null, model: 'approx_time' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'shortActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is displayed when 'Long activity' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'html5', + value: { suggested_duration: null, model: 'approx_time' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'longActivity'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is displayed when 'Exact time' is selected`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'html5', + value: { suggested_duration: null, model: 'time' }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'exactTime'); + await wrapper.vm.$nextTick(); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(true); + expect(wrapper.vm.showActivityDurationInput).toBe(true); + }); + it(`minutes input is hidden and reference hint is displayed when 'Reference' is selected`, () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'html5', + value: { suggested_duration: null, model: 'reference' }, + }, + }); + expect(wrapper.find({ ref: 'activity_duration' }).exists()).toBe(false); + expect(wrapper.vm.showActivityDurationInput).toBe(false); + expect(wrapper.vm.showReferenceHint).toBe(true); + }); + }); }); }); xdescribe(`minutes input`, () => { @@ -664,13 +712,6 @@ describe('CompletionOptions', () => { it(`time from file should be displayed when duration dropdown is 'Exact time to complete'`, () => { //done }); - it(`minutes input should not be displayed for documents`, () => { - //done - }); - it(`duration dropdown is empty by default for exercises`, () => { - //done - }); - it(`duration dropdown is empty by default for html5 or h5p`, () => {}); }); }); }); From 60a83620c600388068d867fa310e69ec745efae6 Mon Sep 17 00:00:00 2001 From: sairina Date: Fri, 22 Jul 2022 11:12:12 -0700 Subject: [PATCH 12/14] Add tests for minutes input and move logic for handling rounding into separate method --- .../components/edit/CompletionOptions.vue | 95 +++++++++++-------- .../edit/__tests__/completionOptions.spec.js | 95 +++++++++++++++---- 2 files changed, 130 insertions(+), 60 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/CompletionOptions.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/CompletionOptions.vue index 65471001e6..251ee9db43 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/CompletionOptions.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/CompletionOptions.vue @@ -177,9 +177,9 @@ export default { }, hideCompletionDropdown() { /* - This condition can be removed once practice quizzes are fully implemented in 0.16 - Named "hide" instead of "show" because "show" is the default behavior - */ + This condition can be removed once practice quizzes are fully implemented in 0.16 + Named "hide" instead of "show" because "show" is the default behavior + */ return this.practiceQuizzesAllowed; }, audioVideoResource() { @@ -204,8 +204,8 @@ export default { }, showReferenceHint() { /* - The reference hint should be shown only when "Reference" is selected - */ + The reference hint should be shown only when "Reference" is selected + */ if (this.value) { if (this.kind === ContentKindsNames.H5P || this.kind === ContentKindsNames.HTML5) { if (this.currentCompletionDropdown === CompletionDropdownMap.determinedByResource) { @@ -230,10 +230,10 @@ export default { }, showActivityDurationInput() { /* The `ActivityDuration` component should visible when: - - Long activity, short activity, or exact time are chosen if it is not an AV resource - - Long activity or short activity are chosen if it is an AV resource - - Long activity, short activity, or exact time are chosen in HTML5 - */ + - Long activity, short activity, or exact time are chosen if it is not an AV resource + - Long activity or short activity are chosen if it is an AV resource + - Long activity, short activity, or exact time are chosen in HTML5 + */ if (this.value) { const switchingFromReferenceBetweenAllContentViewedAndCompleteDuration = this.value.suggested_duration === null || this.value.suggested_duration_type === null; @@ -426,7 +426,10 @@ export default { const defaultStateWhenSwitchingFromGoalToPracticeQuiz = this.value.threshold.mastery_model === MasteryModelsNames.M_OF_N && this.currentCompletionDropdown === null; - if (this.currentCompletionDropdown === CompletionDropdownMap.goal) { + if ( + this.currentCompletionDropdown === CompletionDropdownMap.goal && + this.value.threshold.mastery_model === MasteryModelsNames.M_OF_N + ) { return true; } if (defaultStateWhenSwitchingFromGoalToPracticeQuiz) { @@ -578,21 +581,17 @@ export default { } if (duration === DurationDropdownMap.SHORT_ACTIVITY) { update.suggested_duration_type = SuggestedDurationTypesMap.APPROX_TIME; - const roundedValue = Math.round(this.value.suggested_duration / 300) * 300; - if (roundedValue > SHORT_LONG_ACTIVITY_MIDPOINT || roundedValue <= 0) { - update.suggested_duration = DEFAULT_SHORT_ACTIVITY; - } else { - update.suggested_duration = roundedValue; - } + update.suggested_duration = this.handleMinutesInputFromActivityDuration( + this.value.suggested_duration, + duration + ); } if (duration === DurationDropdownMap.LONG_ACTIVITY) { update.suggested_duration_type = SuggestedDurationTypesMap.APPROX_TIME; - const roundedValue = Math.round(this.value.suggested_duration / 600) * 600; - if (roundedValue < SHORT_LONG_ACTIVITY_MIDPOINT || roundedValue > 7200) { - update.suggested_duration = DEFAULT_LONG_ACTIVITY; - } else { - update.suggested_duration = roundedValue; - } + update.suggested_duration = this.handleMinutesInputFromActivityDuration( + this.value.suggested_duration, + duration + ); } update.completion_criteria = { model: CompletionCriteriaModels.PAGES, @@ -607,12 +606,10 @@ export default { ) { if (duration === DurationDropdownMap.SHORT_ACTIVITY) { update.suggested_duration_type = SuggestedDurationTypesMap.APPROX_TIME; - const roundedValue = Math.round(this.value.suggested_duration / 300) * 300; - if (roundedValue > SHORT_LONG_ACTIVITY_MIDPOINT || roundedValue <= 0) { - update.suggested_duration = DEFAULT_SHORT_ACTIVITY; - } else { - update.suggested_duration = roundedValue; - } + update.suggested_duration = this.handleMinutesInputFromActivityDuration( + this.value.suggested_duration, + duration + ); update.completion_criteria = { model: CompletionCriteriaModels.APPROX_TIME, threshold: update.suggested_duration, @@ -620,12 +617,10 @@ export default { } if (duration === DurationDropdownMap.LONG_ACTIVITY) { update.suggested_duration_type = SuggestedDurationTypesMap.APPROX_TIME; - const roundedValue = Math.round(this.value.suggested_duration / 600) * 600; - if (roundedValue < SHORT_LONG_ACTIVITY_MIDPOINT || roundedValue > 7200) { - update.suggested_duration = DEFAULT_LONG_ACTIVITY; - } else { - update.suggested_duration = roundedValue; - } + update.suggested_duration = this.handleMinutesInputFromActivityDuration( + this.value.suggested_duration, + duration + ); update.completion_criteria = { model: CompletionCriteriaModels.APPROX_TIME, threshold: update.suggested_duration, @@ -643,13 +638,10 @@ export default { if (this.value.model === CompletionCriteriaModels.MASTERY) { if (duration === DurationDropdownMap.SHORT_ACTIVITY) { - update.suggested_duration_type = SuggestedDurationTypesMap.APPROX_TIME; - const roundedValue = Math.round(this.value.suggested_duration / 300) * 300; - if (roundedValue > SHORT_LONG_ACTIVITY_MIDPOINT || roundedValue <= 0) { - update.suggested_duration = DEFAULT_SHORT_ACTIVITY; - } else { - update.suggested_duration = roundedValue; - } + update.suggested_duration = this.handleMinutesInputFromActivityDuration( + this.value.suggested_duration, + duration + ); update.completion_criteria = { model: this.value.model, threshold: this.value.threshold, @@ -804,6 +796,27 @@ export default { trackClick(label) { this.$analytics.trackClick('channel_editor_modal_details', label); }, + handleMinutesInputFromActivityDuration(minutes, duration) { + let suggested_duration; + let roundedValue; + if (duration === DurationDropdownMap.SHORT_ACTIVITY) { + roundedValue = Math.round(minutes / 300) * 300; + if (roundedValue > SHORT_LONG_ACTIVITY_MIDPOINT || roundedValue <= 0) { + suggested_duration = DEFAULT_SHORT_ACTIVITY; + } else { + suggested_duration = roundedValue; + } + } + if (duration === DurationDropdownMap.LONG_ACTIVITY) { + roundedValue = Math.round(minutes / 600) * 600; + if (roundedValue < SHORT_LONG_ACTIVITY_MIDPOINT || roundedValue > 7200) { + suggested_duration = DEFAULT_LONG_ACTIVITY; + } else { + suggested_duration = roundedValue; + } + } + return suggested_duration; + }, handleInput({ completion_criteria, suggested_duration, diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js index 00006c1917..82ee129492 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/completionOptions.spec.js @@ -18,6 +18,7 @@ describe('CompletionOptions', () => { }); describe(`initial, default states`, () => { describe(`audio/video`, () => { + //!TODO FIX it(`'Complete duration' should be displayed by default`, () => { const wrapper = mount(CompletionOptions, { propsData: { @@ -72,6 +73,9 @@ describe('CompletionOptions', () => { }); expect(wrapper.vm.completionDropdown).toBe('reference'); }); + it(`time from file should be displayed when duration dropdown is 'Exact time to complete'`, () => { + //! TODO FIX + }); }); describe(`document`, () => { //! TODO FIX @@ -687,30 +691,83 @@ describe('CompletionOptions', () => { }); }); }); - xdescribe(`minutes input`, () => { - //Note: while the component itself is in another component, + describe(`minutes input`, () => { + //Note: while the 'ActivityDuration' component itself is in another component, //the logic to get the data ready for the BE is in this component - //test for the initial state (does it show or not show) when you click on resources - describe(`in 'Short activity'`, () => { - it(`should increment by 5-minute intervals`, () => { - // const wrapper = mount(ActivityDuration, { - // propsData: { - // selectedDuration: 'longActivity', - // }, - // }); - // expect(wrapper.html()).toContain(`step="5"`); - // expect(wrapper.html()).not.toContain(`step="10"`); + describe(`correct handling of values for switching from 'Exact time' to 'Short activity' or 'Long activity'`, () => { + it(`displays default 'Short activity' value when input > the max allowed for 'Short activity'`, () => { + const shortActivityDefaultValue = 600; + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { + model: 'pages', + threshold: '100%', + suggested_duration: 3060, + suggested_duration_type: 'time', + }, + }, + }); + + expect(wrapper.vm.handleMinutesInputFromActivityDuration(3060, `shortActivity`)).toBe( + shortActivityDefaultValue + ); }); - it(`should round to the nearest 5-minute`, () => { - // const wrapper = mount(ActivityDuration); + it(`displays default 'Long activity' value when input < the min allowed for 'Long activity'`, () => { + const longActivityDefaultValue = 3000; + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { + model: 'pages', + threshold: '100%', + suggested_duration: 50, + suggested_duration_type: 'time', + }, + }, + }); + + expect(wrapper.vm.handleMinutesInputFromActivityDuration(50, `longActivity`)).toBe( + longActivityDefaultValue + ); }); - it(`minimum accepted input should be 5 minutes`, () => {}); - it(`maximum accepted input should be 30 minutes`, () => {}); }); + describe(`correct handling of values for switching from 'Short activity' or 'Long activity' to 'Exact Time'`, () => { + it(`displays 'Long activity' value`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { + model: 'pages', + threshold: '100%', + suggested_duration: 4200, + suggested_duration_type: 'approx_time', + }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'exactTime'); + await wrapper.vm.$nextTick(); + + expect(wrapper.vm.currentDurationDropdown).toBe('exactTime'); + expect(wrapper.vm.minutes).toBe(4200); + }); + it(`displays 'Short activity' value`, async () => { + const wrapper = mount(CompletionOptions, { + propsData: { + kind: 'document', + value: { + model: 'pages', + threshold: '100%', + suggested_duration: 200, + suggested_duration_type: 'approx_time', + }, + }, + }); + wrapper.find({ ref: 'duration' }).vm.$emit('input', 'exactTime'); + await wrapper.vm.$nextTick(); - xdescribe(`default states`, () => { - it(`time from file should be displayed when duration dropdown is 'Exact time to complete'`, () => { - //done + expect(wrapper.vm.currentDurationDropdown).toBe('exactTime'); + expect(wrapper.vm.minutes).toBe(200); }); }); }); From 56479985a111b520c524db8d85acee0f1be7461d Mon Sep 17 00:00:00 2001 From: sairina Date: Fri, 22 Jul 2022 11:37:47 -0700 Subject: [PATCH 13/14] Fix model for default states tests --- .../components/edit/CompletionOptions.vue | 1351 +++++++++-------- .../components/edit/MasteryCriteriaGoal.vue | 5 +- .../edit/__tests__/completionOptions.spec.js | 88 +- 3 files changed, 730 insertions(+), 714 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/CompletionOptions.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/CompletionOptions.vue index 251ee9db43..5cc78523ac 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/CompletionOptions.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/CompletionOptions.vue @@ -1,4 +1,5 @@ diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/MasteryCriteriaGoal.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/MasteryCriteriaGoal.vue index f0d5985070..60832864e6 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/MasteryCriteriaGoal.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/MasteryCriteriaGoal.vue @@ -28,10 +28,7 @@