From 0176d65eb8ce02445f0da0a60680db8898bd6a4b Mon Sep 17 00:00:00 2001 From: sairina Date: Thu, 14 Apr 2022 12:43:34 -0700 Subject: [PATCH 01/18] Add grade_levels field --- .../components/edit/DetailsTabView.vue | 12 ++++ .../components/edit/LevelsOptions.vue | 70 +++++++++++++++++++ .../channelEdit/vuex/contentNode/actions.js | 5 ++ .../frontend/shared/constants.js | 1 + 4 files changed, 88 insertions(+) create mode 100644 contentcuration/contentcuration/frontend/channelEdit/components/edit/LevelsOptions.vue diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue index 0fbeaf408b..13e9b97644 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue @@ -44,6 +44,14 @@ box @focus="trackClick('Description')" /> + + + + + + + + + + + diff --git a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js index 9120c8e488..407a2dfb8d 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js +++ b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js @@ -178,6 +178,7 @@ export function createContentNode(context, { parent, kind, ...payload }) { ...contentDefaults, role_visibility: contentDefaults.role_visibility || RolesNames.LEARNER, accessibility_labels: {}, + grade_levels: {}, ...payload, }; @@ -211,6 +212,7 @@ function generateContentNodeData({ prerequisite = NOVALUE, complete = NOVALUE, accessibility_labels = NOVALUE, + grade_levels = NOVALUE, } = {}) { const contentNodeData = {}; if (title !== NOVALUE) { @@ -252,6 +254,9 @@ function generateContentNodeData({ if (accessibility_labels !== NOVALUE) { contentNodeData.accessibility_labels = accessibility_labels; } + if (grade_levels !== NOVALUE) { + contentNodeData.grade_levels = grade_levels; + } if (extra_fields !== NOVALUE) { contentNodeData.extra_fields = contentNodeData.extra_fields || {}; diff --git a/contentcuration/contentcuration/frontend/shared/constants.js b/contentcuration/contentcuration/frontend/shared/constants.js index 04a76f2059..1c6e35bd5e 100644 --- a/contentcuration/contentcuration/frontend/shared/constants.js +++ b/contentcuration/contentcuration/frontend/shared/constants.js @@ -5,6 +5,7 @@ export { default as CompletionCriteriaModels } from 'kolibri-constants/Completio export { default as ContentLevel } from 'kolibri-constants/labels/Levels'; export { default as Categories } from 'kolibri-constants/labels/Subjects'; export { default as AccessibilityCategories } from 'kolibri-constants/labels/AccessibilityCategories'; +export { default as ContentLevels } from 'kolibri-constants/labels/Levels'; export const ContentDefaults = { author: 'author', From 2fc9a5de4f3afe3d88e7963abdf10c4b8fb0f3c8 Mon Sep 17 00:00:00 2001 From: sairina Date: Thu, 14 Apr 2022 13:07:36 -0700 Subject: [PATCH 02/18] Add tests for grade_levels field --- .../edit/__tests__/detailsTabView.spec.js | 1 + .../edit/__tests__/levelsOptions.spec.js | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/levelsOptions.spec.js diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/detailsTabView.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/detailsTabView.spec.js index 50efa2b3cf..e730d63dc1 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/detailsTabView.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/detailsTabView.spec.js @@ -61,6 +61,7 @@ describe.skip('detailsTabView', () => { }); describe('on render', () => { // TODO: add defaults for 'accessibility' field + // TODO: add defaults for 'grade_levels' field it('all fields should match node field values', () => { let keys = [ 'language', diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/levelsOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/levelsOptions.spec.js new file mode 100644 index 0000000000..304e5b5b4b --- /dev/null +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/levelsOptions.spec.js @@ -0,0 +1,23 @@ +import Vue from 'vue'; +import Vuetify from 'vuetify'; +import { shallowMount } from '@vue/test-utils'; +import LevelsOptions from '../LevelsOptions.vue'; +import { ContentLevels } from 'shared/constants'; + +Vue.use(Vuetify); + +describe('LevelsOptions', () => { + it('smoke test', () => { + const wrapper = shallowMount(LevelsOptions); + + expect(wrapper.isVueInstance()).toBe(true); + }); + + it('number of items in the dropdown should be equal to number of items available in ContentLevels', () => { + const wrapper = shallowMount(LevelsOptions); + const numberOfAvailableLevels = Object.keys(ContentLevels).length; + const dropdownItems = wrapper.attributes()['items'].split(',').length; + + expect(dropdownItems).toBe(numberOfAvailableLevels); + }); +}); From 1e99cf0e275145e59d5629058a16b04df0bf0def Mon Sep 17 00:00:00 2001 From: sairina Date: Thu, 14 Apr 2022 13:22:41 -0700 Subject: [PATCH 03/18] Add learner_needs field --- .../components/edit/DetailsTabView.vue | 12 +++++ .../edit/ResourcesNeededOptions.vue | 54 +++++++++++++++++++ .../channelEdit/vuex/contentNode/actions.js | 5 ++ .../frontend/shared/constants.js | 1 + 4 files changed, 72 insertions(+) create mode 100644 contentcuration/contentcuration/frontend/channelEdit/components/edit/ResourcesNeededOptions.vue diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue index 13e9b97644..9bf146e665 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue @@ -52,6 +52,14 @@ @focus="trackClick('Levels dropdown')" /> + + + + + + + + + + + diff --git a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js index 407a2dfb8d..03370d8a0f 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js +++ b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js @@ -179,6 +179,7 @@ export function createContentNode(context, { parent, kind, ...payload }) { role_visibility: contentDefaults.role_visibility || RolesNames.LEARNER, accessibility_labels: {}, grade_levels: {}, + learner_needs: {}, ...payload, }; @@ -213,6 +214,7 @@ function generateContentNodeData({ complete = NOVALUE, accessibility_labels = NOVALUE, grade_levels = NOVALUE, + learner_needs = NOVALUE, } = {}) { const contentNodeData = {}; if (title !== NOVALUE) { @@ -257,6 +259,9 @@ function generateContentNodeData({ if (grade_levels !== NOVALUE) { contentNodeData.grade_levels = grade_levels; } + if (learner_needs !== NOVALUE) { + contentNodeData.learner_needs = learner_needs; + } if (extra_fields !== NOVALUE) { contentNodeData.extra_fields = contentNodeData.extra_fields || {}; diff --git a/contentcuration/contentcuration/frontend/shared/constants.js b/contentcuration/contentcuration/frontend/shared/constants.js index 1c6e35bd5e..7036968bd9 100644 --- a/contentcuration/contentcuration/frontend/shared/constants.js +++ b/contentcuration/contentcuration/frontend/shared/constants.js @@ -6,6 +6,7 @@ export { default as ContentLevel } from 'kolibri-constants/labels/Levels'; export { default as Categories } from 'kolibri-constants/labels/Subjects'; export { default as AccessibilityCategories } from 'kolibri-constants/labels/AccessibilityCategories'; export { default as ContentLevels } from 'kolibri-constants/labels/Levels'; +export { default as ResourcesNeededTypes } from 'kolibri-constants/labels/Needs'; export const ContentDefaults = { author: 'author', From c485d63d8f1febf8599a6864e0d84b2e83c80159 Mon Sep 17 00:00:00 2001 From: sairina Date: Thu, 14 Apr 2022 14:10:58 -0700 Subject: [PATCH 04/18] Update strings for resources needed/learner_needs field --- .../components/edit/ResourcesNeededOptions.vue | 17 +++++++++++++++-- .../contentcuration/frontend/shared/mixins.js | 9 +++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/ResourcesNeededOptions.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/ResourcesNeededOptions.vue index 609206199d..04b20b6973 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/ResourcesNeededOptions.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/ResourcesNeededOptions.vue @@ -15,6 +15,7 @@ + diff --git a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js index 03370d8a0f..c608db3528 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js +++ b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js @@ -180,6 +180,7 @@ export function createContentNode(context, { parent, kind, ...payload }) { accessibility_labels: {}, grade_levels: {}, learner_needs: {}, + learning_activities: {}, ...payload, }; @@ -215,6 +216,7 @@ function generateContentNodeData({ accessibility_labels = NOVALUE, grade_levels = NOVALUE, learner_needs = NOVALUE, + learning_activities = NOVALUE, } = {}) { const contentNodeData = {}; if (title !== NOVALUE) { @@ -262,6 +264,9 @@ function generateContentNodeData({ if (learner_needs !== NOVALUE) { contentNodeData.learner_needs = learner_needs; } + if (learning_activities !== NOVALUE) { + contentNodeData.learning_activities = learning_activities; + } if (extra_fields !== NOVALUE) { contentNodeData.extra_fields = contentNodeData.extra_fields || {}; From 4c49de4f125599d342e4014fa5fd8f31ffbcc3fe Mon Sep 17 00:00:00 2001 From: sairina Date: Mon, 18 Apr 2022 15:33:48 -0700 Subject: [PATCH 08/18] Add validation to learning_activities --- .../edit/LearningActivityOptions.vue | 21 +--------------- .../frontend/shared/constants.js | 1 + .../frontend/shared/translator.js | 1 + .../frontend/shared/utils/validation.js | 25 ++++++++++++++++++- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/LearningActivityOptions.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/LearningActivityOptions.vue index 5ceefc1cb8..70450e2b39 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/LearningActivityOptions.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/LearningActivityOptions.vue @@ -10,17 +10,7 @@ multiple deletableChips :rules="learningActivityRules" - > - - + /> @@ -44,11 +34,6 @@ default: () => [], }, }, - data() { - return { - learningActivityText: null, - }; - }, computed: { learningActivity: { get() { @@ -75,10 +60,6 @@ return getLearningActivityValidators().map(translateValidator); }, }, - $trs: { - noActivitiesText: - 'No results found for "{text}". Press \'Enter\' key to create a new learning activity', - }, }; diff --git a/contentcuration/contentcuration/frontend/shared/constants.js b/contentcuration/contentcuration/frontend/shared/constants.js index 7036968bd9..c7af961529 100644 --- a/contentcuration/contentcuration/frontend/shared/constants.js +++ b/contentcuration/contentcuration/frontend/shared/constants.js @@ -161,6 +161,7 @@ export const ValidationErrors = { INVALID_NUMBER_OF_CORRECT_ANSWERS: 'INVALID_NUMBER_OF_CORRECT_ANSWERS', NO_VALID_PRIMARY_FILES: 'NO_VALID_PRIMARY_FILES', INVALID_COMPLETION_CRITERIA_MODEL: 'INVALID_COMPLETION_CRITERIA_MODEL', + LEARNING_ACTIVITY_REQUIRED: 'LEARNING_ACTIVITY_REQUIRED', ...fileErrors, }; diff --git a/contentcuration/contentcuration/frontend/shared/translator.js b/contentcuration/contentcuration/frontend/shared/translator.js index a30ed48453..5188bc5f9c 100644 --- a/contentcuration/contentcuration/frontend/shared/translator.js +++ b/contentcuration/contentcuration/frontend/shared/translator.js @@ -14,6 +14,7 @@ const MESSAGES = { masteryModelNGtZero: 'Must be at least 1', masteryModelNWholeNumber: 'Must be a whole number', confirmLogout: 'Changes you made may not be saved. Are you sure you want to leave this page?', + learningActivityRequired: 'Learning activity is required', }; export default createTranslator('sharedVue', MESSAGES); diff --git a/contentcuration/contentcuration/frontend/shared/utils/validation.js b/contentcuration/contentcuration/frontend/shared/utils/validation.js index d89b416990..8ae07297e1 100644 --- a/contentcuration/contentcuration/frontend/shared/utils/validation.js +++ b/contentcuration/contentcuration/frontend/shared/utils/validation.js @@ -94,6 +94,10 @@ function _getMasteryModel(node) { return node.extra_fields; } +function _getLearningActivity(node) { + return Object.keys(node.learning_activities); +} + function _getErrorMsg(error) { const messages = { [ValidationErrors.TITLE_REQUIRED]: translator.$tr('titleRequired'), @@ -108,6 +112,7 @@ function _getErrorMsg(error) { [ValidationErrors.MASTERY_MODEL_N_REQUIRED]: translator.$tr('masteryModelNRequired'), [ValidationErrors.MASTERY_MODEL_N_WHOLE_NUMBER]: translator.$tr('masteryModelNWholeNumber'), [ValidationErrors.MASTERY_MODEL_N_GT_ZERO]: translator.$tr('masteryModelNGtZero'), + [ValidationErrors.LEARNING_ACTIVITY_REQUIRED]: translator.$tr('learningActivityRequired'), }; return messages[error]; @@ -134,6 +139,10 @@ export function getCopyrightHolderValidators() { return [value => Boolean(value && value.trim()) || ValidationErrors.COPYRIGHT_HOLDER_REQUIRED]; } +export function getLearningActivityValidators() { + return [value => Boolean(value.length) || ValidationErrors.LEARNING_ACTIVITY_REQUIRED]; +} + export function getLicenseDescriptionValidators() { return [value => Boolean(value && value.trim()) || ValidationErrors.LICENSE_DESCRIPTION_REQUIRED]; } @@ -184,6 +193,13 @@ export function getNodeCopyrightHolderErrors(node) { .filter(value => value !== true); } +export function getNodeLearningActivityErrors(node) { + const learningActivity = _getLearningActivity(node); + return getLearningActivityValidators() + .map(validator => validator(learningActivity)) + .filter(value => value !== true); +} + export function getNodeLicenseDescriptionErrors(node) { const license = _getLicense(node); if (!license || !license.is_custom) { @@ -251,6 +267,14 @@ export function getNodeDetailsErrors(node) { } } + // learning activity is a required field for resources + if (node.kind !== ContentKindsNames.TOPIC) { + const learningActivityErrors = getNodeLearningActivityErrors(node); + if (learningActivityErrors.length) { + errors = errors.concat(learningActivityErrors); + } + } + // mastery is required on exercises if (node.kind === ContentKindsNames.EXERCISE) { const masteryModelErrors = getNodeMasteryModelErrors(node); @@ -267,7 +291,6 @@ export function getNodeDetailsErrors(node) { errors = errors.concat(masteryModelNErrors); } } - return errors; } From 7af90a3527beead76090fdfd5e0c63b5da27761a Mon Sep 17 00:00:00 2001 From: sairina Date: Mon, 18 Apr 2022 17:00:58 -0700 Subject: [PATCH 09/18] Remove default upload for learning_activity for now --- .../channelEdit/components/edit/DetailsTabView.vue | 2 +- .../components/edit/LearningActivityOptions.vue | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue index b70776fc7b..bb01214fb3 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue @@ -49,7 +49,6 @@ @@ -415,6 +414,7 @@ * - `grade_levels` (sometimes referred to as `content_levels`) * - `learner_needs` (resources needed) * - `accessibility_labels` (accessibility options) + * - `learning_activities` (learning activities) */ function generateNestedNodesGetterSetter(key) { return { diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/LearningActivityOptions.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/LearningActivityOptions.vue index 70450e2b39..c9a7e33351 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/LearningActivityOptions.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/LearningActivityOptions.vue @@ -25,10 +25,6 @@ name: 'LearningActivityOptions', mixins: [constantsTranslationMixin, metadataTranslationMixin], props: { - kind: { - type: String, - default: '', - }, value: { type: Array, default: () => [], @@ -37,13 +33,6 @@ computed: { learningActivity: { get() { - if (this.kind === 'video') { - return this.value || [LearningActivities.WATCH]; - } else if (this.kind === 'document') { - return this.value || [LearningActivities.READ]; - } else if (this.kind === 'audio') { - return this.value || [LearningActivities.LISTEN]; - } return this.value; }, set(value) { From 25a29be410ffd182b183b2e67f247a9cb6c83c64 Mon Sep 17 00:00:00 2001 From: sairina Date: Mon, 18 Apr 2022 20:45:32 -0700 Subject: [PATCH 10/18] Add tests for learning activities --- .../__tests__/learningActivityOptions.spec.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/learningActivityOptions.spec.js diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/learningActivityOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/learningActivityOptions.spec.js new file mode 100644 index 0000000000..58b731c8b3 --- /dev/null +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/learningActivityOptions.spec.js @@ -0,0 +1,22 @@ +import Vue from 'vue'; +import Vuetify from 'vuetify'; +import { shallowMount } from '@vue/test-utils'; +import LearningActivityOptions from '../LearningActivityOptions.vue'; +import { LearningActivities } from 'shared/constants'; + +Vue.use(Vuetify); + +describe('LearningActivityOptions', () => { + it('smoke test', () => { + const wrapper = shallowMount(LearningActivityOptions); + expect(wrapper.isVueInstance()).toBe(true); + }); + + it('number of items in the dropdown should be equal to number of items available in ', () => { + const wrapper = shallowMount(LearningActivityOptions); + const numberOfDropdownItems = Object.keys(LearningActivities).length; + const dropdownItems = wrapper.attributes()['items'].split(',').length; + + expect(dropdownItems).toBe(numberOfDropdownItems); + }); +}); From 2c3b79d5528669efd76d733e5b9d8f977419514a Mon Sep 17 00:00:00 2001 From: sairina Date: Mon, 18 Apr 2022 22:45:50 -0700 Subject: [PATCH 11/18] Update validation tests with learning activities --- .../frontend/shared/utils/validation.spec.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/contentcuration/contentcuration/frontend/shared/utils/validation.spec.js b/contentcuration/contentcuration/frontend/shared/utils/validation.spec.js index 539426b741..5b84f426f3 100644 --- a/contentcuration/contentcuration/frontend/shared/utils/validation.spec.js +++ b/contentcuration/contentcuration/frontend/shared/utils/validation.spec.js @@ -18,6 +18,7 @@ import { sanitizeAssessmentItemHints, sanitizeAssessmentItem, getAssessmentItemErrors, + getNodeLearningActivityErrors, } from './validation'; import { MasteryModelsNames } from 'shared/leUtils/MasteryModels'; import { ContentKindsNames } from 'shared/leUtils/ContentKinds'; @@ -175,6 +176,23 @@ describe('channelEdit utils', () => { }); }); + describe('getNodeLearningActivityErrors', () => { + it(`returns an error for an empty learning activity input`, () => { + const node = { + learning_activities: {}, + }; + expect(getNodeLearningActivityErrors(node)).toEqual([ + ValidationErrors.LEARNING_ACTIVITY_REQUIRED, + ]); + }); + it('returns no errors when learning activity is specified', () => { + const node = { + learning_activities: { test: true }, + }; + expect(getNodeLearningActivityErrors(node)).toEqual([]); + }); + }); + describe('getNodeMasteryModelErrors', () => { it('returns an error for an empty mastery model', () => { const node = { extra_fields: null }; @@ -347,6 +365,7 @@ describe('channelEdit utils', () => { title: 'Exercise', kind: ContentKindsNames.EXERCISE, license: { id: 8 }, + learning_activities: { '#j8L0eq3': true }, extra_fields: { mastery_model: MasteryModelsNames.DO_ALL, options: { @@ -457,6 +476,7 @@ describe('channelEdit utils', () => { title: 'A node', license: { id: 8 }, kind, + learning_activities: { '#j8L0eq3': true }, extra_fields: { options: { completion_criteria: { @@ -548,6 +568,7 @@ describe('channelEdit utils', () => { title: '', kind: 'document', license: 8, + learning_activities: { '#j8L0eq3': true }, }) ).toEqual([ValidationErrors.TITLE_REQUIRED]); }); @@ -558,6 +579,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'document', license: null, + learning_activities: { '#j8L0eq3': true }, }, [ValidationErrors.LICENSE_REQUIRED], ], @@ -566,6 +588,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'document', license: 8, + learning_activities: { '#j8L0eq3': true }, }, [], ], @@ -575,6 +598,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'topic', license: null, + learning_activities: { '#j8L0eq3': true }, }, [], ], @@ -584,6 +608,7 @@ describe('channelEdit utils', () => { title: 'Title', freeze_authoring_data: true, license: null, + learning_activities: { '#j8L0eq3': true }, }, [], ], @@ -597,6 +622,7 @@ describe('channelEdit utils', () => { { title: 'Title', license: 1, + learning_activities: { '#j8L0eq3': true }, }, [ValidationErrors.COPYRIGHT_HOLDER_REQUIRED], ], @@ -605,6 +631,7 @@ describe('channelEdit utils', () => { title: 'Title', license: 1, copyright_holder: 'Copyright holder', + learning_activities: { '#j8L0eq3': true }, }, [], ], @@ -619,6 +646,7 @@ describe('channelEdit utils', () => { title: 'Title', license: 9, copyright_holder: 'Copyright holder', + learning_activities: { '#j8L0eq3': true }, }, [ValidationErrors.LICENSE_DESCRIPTION_REQUIRED], ], @@ -628,6 +656,7 @@ describe('channelEdit utils', () => { license: 9, copyright_holder: 'Copyright holder', license_description: 'My custom license', + learning_activities: { '#j8L0eq3': true }, }, [], ], @@ -641,6 +670,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'exercise', license: 8, + learning_activities: { '#j8L0eq3': true }, }, [ValidationErrors.MASTERY_MODEL_REQUIRED], ], @@ -649,6 +679,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'exercise', license: 8, + learning_activities: { '#j8L0eq3': true }, extra_fields: { mastery_model: 'do_all', }, @@ -660,6 +691,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'exercise', license: 8, + learning_activities: { '#j8L0eq3': true }, extra_fields: { mastery_model: 'm_of_n', m: 3, @@ -677,6 +709,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'exercise', license: 8, + learning_activities: { '#j8L0eq3': true }, extra_fields: { mastery_model: 'm_of_n', m: 3, @@ -690,6 +723,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'exercise', license: 8, + learning_activities: { '#j8L0eq3': true }, extra_fields: { mastery_model: 'm_of_n', m: 2, From 04a671ec974cd61343aa25be45695b171d58050a Mon Sep 17 00:00:00 2001 From: sairina Date: Mon, 18 Apr 2022 22:50:26 -0700 Subject: [PATCH 12/18] Add learning activities for tests in actions --- .../channelEdit/vuex/contentNode/__tests__/actions.spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/__tests__/actions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/__tests__/actions.spec.js index 11e8c7d606..9067852d65 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/__tests__/actions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/__tests__/actions.spec.js @@ -108,6 +108,7 @@ describe('contentNode actions', () => { title: 'notatest', description: 'very', language: 'no', + learning_activities: { test: true }, }) .then(() => { expect(updateSpy).toHaveBeenCalledWith(id, { @@ -116,6 +117,7 @@ describe('contentNode actions', () => { language: 'no', changed: true, complete: false, + learning_activities: { test: true }, }); updateSpy.mockRestore(); }); From 62adde474ab4dfd9791dd13f4ea1d6fef61e0603 Mon Sep 17 00:00:00 2001 From: sairina Date: Tue, 19 Apr 2022 14:02:09 -0700 Subject: [PATCH 13/18] Update Basic Information section to two column format --- .../components/edit/DetailsTabView.vue | 149 ++++++++++-------- 1 file changed, 86 insertions(+), 63 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue index bb01214fb3..1cebc6c074 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/DetailsTabView.vue @@ -32,69 +32,80 @@ box @focus="trackClick('Title')" /> - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -861,6 +872,18 @@ } } } + + .basicInfoColumn { + display: flex; + /deep/ .v-input { + // Stretches the "Description" text area to fill the column vertically + align-items: stretch; + } + /deep/ .v-input__control { + // Makes sure that the character count does not get pushed to second column + flex-wrap: nowrap; + } + } } } From d6a0d94390fed6ea05fc034c07490d3cd22ef418 Mon Sep 17 00:00:00 2001 From: sairina Date: Wed, 20 Apr 2022 10:36:27 -0700 Subject: [PATCH 14/18] Change key for learning_activity in tests --- .../frontend/shared/utils/validation.spec.js | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/contentcuration/contentcuration/frontend/shared/utils/validation.spec.js b/contentcuration/contentcuration/frontend/shared/utils/validation.spec.js index 5b84f426f3..9c2d4dbe24 100644 --- a/contentcuration/contentcuration/frontend/shared/utils/validation.spec.js +++ b/contentcuration/contentcuration/frontend/shared/utils/validation.spec.js @@ -365,7 +365,7 @@ describe('channelEdit utils', () => { title: 'Exercise', kind: ContentKindsNames.EXERCISE, license: { id: 8 }, - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, extra_fields: { mastery_model: MasteryModelsNames.DO_ALL, options: { @@ -476,7 +476,7 @@ describe('channelEdit utils', () => { title: 'A node', license: { id: 8 }, kind, - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, extra_fields: { options: { completion_criteria: { @@ -568,7 +568,7 @@ describe('channelEdit utils', () => { title: '', kind: 'document', license: 8, - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, }) ).toEqual([ValidationErrors.TITLE_REQUIRED]); }); @@ -579,7 +579,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'document', license: null, - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, }, [ValidationErrors.LICENSE_REQUIRED], ], @@ -588,7 +588,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'document', license: 8, - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, }, [], ], @@ -598,7 +598,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'topic', license: null, - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, }, [], ], @@ -608,7 +608,7 @@ describe('channelEdit utils', () => { title: 'Title', freeze_authoring_data: true, license: null, - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, }, [], ], @@ -622,7 +622,7 @@ describe('channelEdit utils', () => { { title: 'Title', license: 1, - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, }, [ValidationErrors.COPYRIGHT_HOLDER_REQUIRED], ], @@ -631,7 +631,7 @@ describe('channelEdit utils', () => { title: 'Title', license: 1, copyright_holder: 'Copyright holder', - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, }, [], ], @@ -646,7 +646,7 @@ describe('channelEdit utils', () => { title: 'Title', license: 9, copyright_holder: 'Copyright holder', - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, }, [ValidationErrors.LICENSE_DESCRIPTION_REQUIRED], ], @@ -656,7 +656,7 @@ describe('channelEdit utils', () => { license: 9, copyright_holder: 'Copyright holder', license_description: 'My custom license', - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, }, [], ], @@ -670,7 +670,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'exercise', license: 8, - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, }, [ValidationErrors.MASTERY_MODEL_REQUIRED], ], @@ -679,7 +679,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'exercise', license: 8, - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, extra_fields: { mastery_model: 'do_all', }, @@ -691,7 +691,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'exercise', license: 8, - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, extra_fields: { mastery_model: 'm_of_n', m: 3, @@ -709,7 +709,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'exercise', license: 8, - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, extra_fields: { mastery_model: 'm_of_n', m: 3, @@ -723,7 +723,7 @@ describe('channelEdit utils', () => { title: 'Title', kind: 'exercise', license: 8, - learning_activities: { '#j8L0eq3': true }, + learning_activities: { test: true }, extra_fields: { mastery_model: 'm_of_n', m: 2, From 201c6e4573993f44cac4486e6625ceff80ea552a Mon Sep 17 00:00:00 2001 From: sairina Date: Mon, 25 Apr 2022 20:45:07 -0700 Subject: [PATCH 15/18] Move update method to module scope --- .../edit/ResourcesNeededOptions.vue | 43 +++++++++---------- .../__tests__/resourcesNeededOptions.spec.js | 20 ++++++--- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/ResourcesNeededOptions.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/ResourcesNeededOptions.vue index 7549f7a6f9..d89cd9bccc 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/ResourcesNeededOptions.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/ResourcesNeededOptions.vue @@ -21,7 +21,28 @@ //the variable below can be changed or removed when metadata/Kolibri is updated const keysToBeTemporarilyRemoved = ['PEERS', 'TEACHER', 'PRIOR_KNOWLEDGE', 'MATERIALS']; + const dropdown = updateResourcesDropdown(keysToBeTemporarilyRemoved) || ResourcesNeededTypes; + /** + * @param {array} listOfKeys + * @returns {Object} + * + * Determines resources to show in the dropdown, to remove resources + * that do not currently need to be displayed in Kolibri + */ + function updateResourcesDropdown(listOfKeys) { + if (listOfKeys) { + return Object.keys(ResourcesNeededTypes).reduce((acc, key) => { + if (listOfKeys.indexOf(key) === -1) { + acc[key] = ResourcesNeededTypes[key]; + } + return acc; + }, {}); + } + } + export const exportedForTesting = { + updateResourcesDropdown, + }; export default { name: 'ResourcesNeededOptions', mixins: [constantsTranslationMixin, metadataTranslationMixin], @@ -41,33 +62,12 @@ }, }, resources() { - const dropdown = - this.updateResourcesDropdown(keysToBeTemporarilyRemoved) || ResourcesNeededTypes; return Object.entries(dropdown).map(resource => ({ text: this.translateMetadataString(resource[0]), value: resource[1], })); }, }, - methods: { - /** - * @param {array} listOfKeys - * @returns {Object} - * - * Determines resources to show in the dropdown, to remove resources - * that do not currently need to be displayed in Kolibri - */ - updateResourcesDropdown(listOfKeys) { - if (listOfKeys) { - return Object.keys(ResourcesNeededTypes).reduce((acc, key) => { - if (listOfKeys.indexOf(key) === -1) { - acc[key] = ResourcesNeededTypes[key]; - } - return acc; - }, {}); - } - }, - }, $trs: { resourcesNeededLabel: 'What you will need', }, @@ -75,5 +75,4 @@ diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/resourcesNeededOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/resourcesNeededOptions.spec.js index f9bb630943..3d17a56776 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/resourcesNeededOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/resourcesNeededOptions.spec.js @@ -1,9 +1,11 @@ import Vue from 'vue'; import Vuetify from 'vuetify'; import { shallowMount } from '@vue/test-utils'; -import ResourcesNeededOptions from '../ResourcesNeededOptions.vue'; +import ResourcesNeededOptions, { exportedForTesting } from '../ResourcesNeededOptions.vue'; import { ResourcesNeededTypes } from 'shared/constants'; +const { updateResourcesDropdown } = exportedForTesting; + Vue.use(Vuetify); describe('ResourcesNeededOptions', () => { @@ -16,8 +18,7 @@ describe('ResourcesNeededOptions', () => { it('when there is a list of keys to remove from ResourcesNeededTypes, return updated map for ResourcesNeededTypes for dropdown', () => { const list = ['FOR_BEGINNERS', 'INTERNET']; const numberOfAvailableResources = Object.keys(ResourcesNeededTypes).length - list.length; - const wrapper = shallowMount(ResourcesNeededOptions); - const dropdownItemsLength = Object.keys(wrapper.vm.updateResourcesDropdown(list)).length; + const dropdownItemsLength = Object.keys(updateResourcesDropdown(list)).length; expect(dropdownItemsLength).toBe(numberOfAvailableResources); }); @@ -25,9 +26,18 @@ describe('ResourcesNeededOptions', () => { it('when there are no keys to remove from ResourcesNeededTypes, dropdown should contain all resources', () => { const list = []; const numberOfAvailableResources = Object.keys(ResourcesNeededTypes).length - list.length; - const wrapper = shallowMount(ResourcesNeededOptions); - const dropdownItemsLength = Object.keys(wrapper.vm.updateResourcesDropdown(list)).length; + const dropdownItemsLength = Object.keys(updateResourcesDropdown(list)).length; expect(dropdownItemsLength).toBe(numberOfAvailableResources); }); + + it('emits expected data', () => { + const wrapper = shallowMount(ResourcesNeededOptions); + const value = 'test resource'; + wrapper.vm.$emit('input', value); + + expect(wrapper.emitted().input).toBeTruthy(); + expect(wrapper.emitted().input.length).toBe(1); + expect(wrapper.emitted().input[0]).toEqual([value]); + }); }); From ff3a1fe0c4655c9cb3ed6cb3280c3c65227ce92a Mon Sep 17 00:00:00 2001 From: sairina Date: Mon, 25 Apr 2022 20:46:52 -0700 Subject: [PATCH 16/18] Add test for emitting with v-model --- .../edit/__tests__/learningActivityOptions.spec.js | 10 ++++++++++ .../components/edit/__tests__/levelsOptions.spec.js | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/learningActivityOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/learningActivityOptions.spec.js index 58b731c8b3..a304855d19 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/learningActivityOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/learningActivityOptions.spec.js @@ -19,4 +19,14 @@ describe('LearningActivityOptions', () => { expect(dropdownItems).toBe(numberOfDropdownItems); }); + + it('emits expected data', () => { + const wrapper = shallowMount(LearningActivityOptions); + const value = 'Create'; + wrapper.vm.$emit('input', value); + + expect(wrapper.emitted().input).toBeTruthy(); + expect(wrapper.emitted().input.length).toBe(1); + expect(wrapper.emitted().input[0]).toEqual([value]); + }); }); diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/levelsOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/levelsOptions.spec.js index 304e5b5b4b..c1c2c38ab3 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/levelsOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/levelsOptions.spec.js @@ -20,4 +20,14 @@ describe('LevelsOptions', () => { expect(dropdownItems).toBe(numberOfAvailableLevels); }); + + it('emits expected data', () => { + const wrapper = shallowMount(LevelsOptions); + const value = 'Preschool'; + wrapper.vm.$emit('input', value); + + expect(wrapper.emitted().input).toBeTruthy(); + expect(wrapper.emitted().input.length).toBe(1); + expect(wrapper.emitted().input[0]).toEqual([value]); + }); }); From 2305dd92265bf16e4ebc5ff07b4a0ae1771d56a1 Mon Sep 17 00:00:00 2001 From: sairina Date: Tue, 26 Apr 2022 09:45:02 -0700 Subject: [PATCH 17/18] Move update method and export --- .../components/edit/ResourcesNeededOptions.vue | 14 ++++++-------- .../edit/__tests__/resourcesNeededOptions.spec.js | 4 +--- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/ResourcesNeededOptions.vue b/contentcuration/contentcuration/frontend/channelEdit/components/edit/ResourcesNeededOptions.vue index d89cd9bccc..b866b1853f 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/ResourcesNeededOptions.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/ResourcesNeededOptions.vue @@ -19,10 +19,6 @@ import { ResourcesNeededTypes } from 'shared/constants'; import { constantsTranslationMixin, metadataTranslationMixin } from 'shared/mixins'; - //the variable below can be changed or removed when metadata/Kolibri is updated - const keysToBeTemporarilyRemoved = ['PEERS', 'TEACHER', 'PRIOR_KNOWLEDGE', 'MATERIALS']; - const dropdown = updateResourcesDropdown(keysToBeTemporarilyRemoved) || ResourcesNeededTypes; - /** * @param {array} listOfKeys * @returns {Object} @@ -30,7 +26,7 @@ * Determines resources to show in the dropdown, to remove resources * that do not currently need to be displayed in Kolibri */ - function updateResourcesDropdown(listOfKeys) { + export function updateResourcesDropdown(listOfKeys) { if (listOfKeys) { return Object.keys(ResourcesNeededTypes).reduce((acc, key) => { if (listOfKeys.indexOf(key) === -1) { @@ -40,9 +36,11 @@ }, {}); } } - export const exportedForTesting = { - updateResourcesDropdown, - }; + + //the variable below can be changed or removed when metadata/Kolibri is updated + const keysToBeTemporarilyRemoved = ['PEERS', 'TEACHER', 'PRIOR_KNOWLEDGE', 'MATERIALS']; + const dropdown = updateResourcesDropdown(keysToBeTemporarilyRemoved) || ResourcesNeededTypes; + export default { name: 'ResourcesNeededOptions', mixins: [constantsTranslationMixin, metadataTranslationMixin], diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/resourcesNeededOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/resourcesNeededOptions.spec.js index 3d17a56776..c827d28f11 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/resourcesNeededOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/resourcesNeededOptions.spec.js @@ -1,11 +1,9 @@ import Vue from 'vue'; import Vuetify from 'vuetify'; import { shallowMount } from '@vue/test-utils'; -import ResourcesNeededOptions, { exportedForTesting } from '../ResourcesNeededOptions.vue'; +import ResourcesNeededOptions, { updateResourcesDropdown } from '../ResourcesNeededOptions.vue'; import { ResourcesNeededTypes } from 'shared/constants'; -const { updateResourcesDropdown } = exportedForTesting; - Vue.use(Vuetify); describe('ResourcesNeededOptions', () => { From 27b40d3df11de5e8e5554dcc09a968db47dcd14c Mon Sep 17 00:00:00 2001 From: sairina Date: Wed, 27 Apr 2022 15:24:22 -0700 Subject: [PATCH 18/18] Update tests to add change of state with emit --- .../__tests__/learningActivityOptions.spec.js | 41 +++++++++++++++---- .../edit/__tests__/levelsOptions.spec.js | 41 +++++++++++++++---- .../__tests__/resourcesNeededOptions.spec.js | 41 +++++++++++++++---- 3 files changed, 99 insertions(+), 24 deletions(-) diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/learningActivityOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/learningActivityOptions.spec.js index a304855d19..e0547bf13d 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/learningActivityOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/learningActivityOptions.spec.js @@ -1,11 +1,19 @@ import Vue from 'vue'; import Vuetify from 'vuetify'; -import { shallowMount } from '@vue/test-utils'; +import { shallowMount, mount } from '@vue/test-utils'; import LearningActivityOptions from '../LearningActivityOptions.vue'; import { LearningActivities } from 'shared/constants'; Vue.use(Vuetify); +function makeWrapper(value) { + return mount(LearningActivityOptions, { + propsData: { + value, + }, + }); +} + describe('LearningActivityOptions', () => { it('smoke test', () => { const wrapper = shallowMount(LearningActivityOptions); @@ -20,13 +28,30 @@ describe('LearningActivityOptions', () => { expect(dropdownItems).toBe(numberOfDropdownItems); }); - it('emits expected data', () => { - const wrapper = shallowMount(LearningActivityOptions); - const value = 'Create'; - wrapper.vm.$emit('input', value); + describe('updating state', () => { + it('should update learning_activity field with new values received from a parent', () => { + const learningActivity = ['activity_1', 'activity_2']; + const wrapper = makeWrapper(learningActivity); + const dropdown = wrapper.find({ name: 'v-select' }); + + expect(dropdown.props('value')).toEqual(learningActivity); + + wrapper.setProps({ + value: ['activity_4'], + }); + expect(dropdown.props('value')).toEqual(['activity_4']); + }); + + it('should emit new input values', () => { + const learningActivity = ['activity_1', 'activity_2', 'activity_3']; + const wrapper = makeWrapper({}); + const dropdown = wrapper.find({ name: 'v-select' }); + dropdown.vm.$emit('input', learningActivity); - expect(wrapper.emitted().input).toBeTruthy(); - expect(wrapper.emitted().input.length).toBe(1); - expect(wrapper.emitted().input[0]).toEqual([value]); + return Vue.nextTick().then(() => { + const emittedLevels = wrapper.emitted('input').pop()[0]; + expect(emittedLevels).toEqual(learningActivity); + }); + }); }); }); diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/levelsOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/levelsOptions.spec.js index c1c2c38ab3..a3541e494a 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/levelsOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/levelsOptions.spec.js @@ -1,11 +1,19 @@ import Vue from 'vue'; import Vuetify from 'vuetify'; -import { shallowMount } from '@vue/test-utils'; +import { shallowMount, mount } from '@vue/test-utils'; import LevelsOptions from '../LevelsOptions.vue'; import { ContentLevels } from 'shared/constants'; Vue.use(Vuetify); +function makeWrapper(value) { + return mount(LevelsOptions, { + propsData: { + value, + }, + }); +} + describe('LevelsOptions', () => { it('smoke test', () => { const wrapper = shallowMount(LevelsOptions); @@ -21,13 +29,30 @@ describe('LevelsOptions', () => { expect(dropdownItems).toBe(numberOfAvailableLevels); }); - it('emits expected data', () => { - const wrapper = shallowMount(LevelsOptions); - const value = 'Preschool'; - wrapper.vm.$emit('input', value); + describe('updating state', () => { + it('should update levels field with new values received from a parent', () => { + const levels = ['abc', 'gefo']; + const wrapper = makeWrapper(levels); + const dropdown = wrapper.find({ name: 'v-select' }); + + expect(dropdown.props('value')).toEqual(levels); + + wrapper.setProps({ + value: ['def'], + }); + expect(dropdown.props('value')).toEqual(['def']); + }); + + it('should emit new input values', () => { + const levels = ['abc', 'gefo', '8hw']; + const wrapper = makeWrapper({}); + const dropdown = wrapper.find({ name: 'v-select' }); + dropdown.vm.$emit('input', levels); - expect(wrapper.emitted().input).toBeTruthy(); - expect(wrapper.emitted().input.length).toBe(1); - expect(wrapper.emitted().input[0]).toEqual([value]); + return Vue.nextTick().then(() => { + const emittedLevels = wrapper.emitted('input').pop()[0]; + expect(emittedLevels).toEqual(levels); + }); + }); }); }); diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/resourcesNeededOptions.spec.js b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/resourcesNeededOptions.spec.js index c827d28f11..28b6348ab0 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/resourcesNeededOptions.spec.js +++ b/contentcuration/contentcuration/frontend/channelEdit/components/edit/__tests__/resourcesNeededOptions.spec.js @@ -1,11 +1,19 @@ import Vue from 'vue'; import Vuetify from 'vuetify'; -import { shallowMount } from '@vue/test-utils'; +import { shallowMount, mount } from '@vue/test-utils'; import ResourcesNeededOptions, { updateResourcesDropdown } from '../ResourcesNeededOptions.vue'; import { ResourcesNeededTypes } from 'shared/constants'; Vue.use(Vuetify); +function makeWrapper(value) { + return mount(ResourcesNeededOptions, { + propsData: { + value, + }, + }); +} + describe('ResourcesNeededOptions', () => { it('smoke test', () => { const wrapper = shallowMount(ResourcesNeededOptions); @@ -29,13 +37,30 @@ describe('ResourcesNeededOptions', () => { expect(dropdownItemsLength).toBe(numberOfAvailableResources); }); - it('emits expected data', () => { - const wrapper = shallowMount(ResourcesNeededOptions); - const value = 'test resource'; - wrapper.vm.$emit('input', value); + describe('updating state', () => { + it('should update resources field with new values received from a parent', () => { + const resourcesNeeded = ['person', 'book']; + const wrapper = makeWrapper(resourcesNeeded); + const dropdown = wrapper.find({ name: 'v-select' }); + + expect(dropdown.props('value')).toEqual(resourcesNeeded); + + wrapper.setProps({ + value: ['cat'], + }); + expect(dropdown.props('value')).toEqual(['cat']); + }); + + it('should emit new input values', () => { + const resourcesNeeded = ['person', 'book', 'train']; + const wrapper = makeWrapper({}); + const dropdown = wrapper.find({ name: 'v-select' }); + dropdown.vm.$emit('input', resourcesNeeded); - expect(wrapper.emitted().input).toBeTruthy(); - expect(wrapper.emitted().input.length).toBe(1); - expect(wrapper.emitted().input[0]).toEqual([value]); + return Vue.nextTick().then(() => { + const emittedLevels = wrapper.emitted('input').pop()[0]; + expect(emittedLevels).toEqual(resourcesNeeded); + }); + }); }); });