test: fixed course ui tests based on new flow
This commit is contained in:
@@ -11,7 +11,6 @@ describe("Course Creation", () => {
|
|||||||
cy.get("button").contains("Create").click();
|
cy.get("button").contains("Create").click();
|
||||||
cy.get("span").contains("New Course").click();
|
cy.get("span").contains("New Course").click();
|
||||||
cy.wait(500);
|
cy.wait(500);
|
||||||
cy.url().should("include", "/courses/new/edit");
|
|
||||||
|
|
||||||
cy.get("label").contains("Title").type("Test Course");
|
cy.get("label").contains("Title").type("Test Course");
|
||||||
cy.get("label")
|
cy.get("label")
|
||||||
@@ -35,21 +34,6 @@ describe("Course Creation", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get("label")
|
|
||||||
.contains("Preview Video")
|
|
||||||
.type("https://www.youtube.com/embed/-LPmw2Znl2c");
|
|
||||||
cy.get("[id=tags]").type("Learning{enter}Frappe{enter}ERPNext{enter}");
|
|
||||||
cy.get("label")
|
|
||||||
.contains("Category")
|
|
||||||
.parent()
|
|
||||||
.within(() => {
|
|
||||||
cy.get("button").click();
|
|
||||||
});
|
|
||||||
cy.get("[id^=headlessui-combobox-option-")
|
|
||||||
.should("be.visible")
|
|
||||||
.first()
|
|
||||||
.click();
|
|
||||||
|
|
||||||
/* Instructor */
|
/* Instructor */
|
||||||
cy.get("label")
|
cy.get("label")
|
||||||
.contains("Instructors")
|
.contains("Instructors")
|
||||||
@@ -69,13 +53,32 @@ describe("Course Creation", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cy.button("Create").last().click();
|
||||||
|
|
||||||
|
// Edit Course Details
|
||||||
|
cy.wait(500);
|
||||||
|
cy.get("label")
|
||||||
|
.contains("Preview Video")
|
||||||
|
.type("https://www.youtube.com/embed/-LPmw2Znl2c");
|
||||||
|
cy.get("[id=tags]").type("Learning{enter}Frappe{enter}ERPNext{enter}");
|
||||||
|
cy.get("label")
|
||||||
|
.contains("Category")
|
||||||
|
.parent()
|
||||||
|
.within(() => {
|
||||||
|
cy.get("button").click();
|
||||||
|
});
|
||||||
|
cy.get("[id^=headlessui-combobox-option-")
|
||||||
|
.should("be.visible")
|
||||||
|
.first()
|
||||||
|
.click();
|
||||||
|
|
||||||
cy.get("label").contains("Published").click();
|
cy.get("label").contains("Published").click();
|
||||||
cy.get("label").contains("Published On").type("2021-01-01");
|
cy.get("label").contains("Published On").type("2021-01-01");
|
||||||
cy.button("Save").click();
|
cy.button("Save").click();
|
||||||
|
|
||||||
// Add Chapter
|
// Add Chapter
|
||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
cy.button("Add Chapter").click();
|
cy.button("Add").click();
|
||||||
|
|
||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
cy.get("[data-dismissable-layer]")
|
cy.get("[data-dismissable-layer]")
|
||||||
|
|||||||
1
frontend/components.d.ts
vendored
1
frontend/components.d.ts
vendored
@@ -54,7 +54,6 @@ declare module 'vue' {
|
|||||||
CourseCardOverlay: typeof import('./src/components/CourseCardOverlay.vue')['default']
|
CourseCardOverlay: typeof import('./src/components/CourseCardOverlay.vue')['default']
|
||||||
CourseInstructors: typeof import('./src/components/CourseInstructors.vue')['default']
|
CourseInstructors: typeof import('./src/components/CourseInstructors.vue')['default']
|
||||||
CourseOutline: typeof import('./src/components/CourseOutline.vue')['default']
|
CourseOutline: typeof import('./src/components/CourseOutline.vue')['default']
|
||||||
CourseProgressSummary: typeof import('./src/components/Modals/CourseProgressSummary.vue')['default']
|
|
||||||
CourseReviews: typeof import('./src/components/CourseReviews.vue')['default']
|
CourseReviews: typeof import('./src/components/CourseReviews.vue')['default']
|
||||||
CreateOutline: typeof import('./src/components/CreateOutline.vue')['default']
|
CreateOutline: typeof import('./src/components/CreateOutline.vue')['default']
|
||||||
DateRange: typeof import('./src/components/Common/DateRange.vue')['default']
|
DateRange: typeof import('./src/components/Common/DateRange.vue')['default']
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<NumberChartGraph :title="__('Lessons')" :value="course.data?.lessons" />
|
<NumberChartGraph :title="__('Lessons')" :value="course.data?.lessons" />
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-[2fr_1fr] gap-5 items-start">
|
<div class="grid grid-cols-[2fr_1fr] gap-5 items-start">
|
||||||
<div class="border rounded-lg py-3 px-4">
|
<div v-if="course.data?.enrollments" class="border rounded-lg py-3 px-4">
|
||||||
<div class="flex items-center justify-between mb-3">
|
<div class="flex items-center justify-between mb-3">
|
||||||
<div class="text-lg font-semibold">
|
<div class="text-lg font-semibold">
|
||||||
{{ __('Students') }}
|
{{ __('Students') }}
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-5">
|
<div class="space-y-5">
|
||||||
<div class="border rounded-lg p-4">
|
<div v-if="chartDetails.data?.length" class="border rounded-lg p-4">
|
||||||
<div class="text-ink-gray-5 mb-4">
|
<div class="text-ink-gray-5 mb-4">
|
||||||
{{ __('Progress Summary') }}
|
{{ __('Progress Summary') }}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,82 +1,82 @@
|
|||||||
<template>
|
<template>
|
||||||
<Dialog
|
<Dialog
|
||||||
v-model="show"
|
v-model="show"
|
||||||
:options="{
|
:options="{
|
||||||
title: __('Create Course'),
|
title: __('Create Course'),
|
||||||
size: '3xl',
|
size: '3xl',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<template #body-content>
|
<template #body-content>
|
||||||
<div class="text-base">
|
<div class="text-base">
|
||||||
<div class="grid grid-cols-2 gap-5 border-b mb-5">
|
<div class="grid grid-cols-2 gap-5 border-b mb-5">
|
||||||
<FormControl
|
<FormControl
|
||||||
v-model="course.title"
|
v-model="course.title"
|
||||||
:label="__('Title')"
|
:label="__('Title')"
|
||||||
:required="true"
|
:required="true"
|
||||||
/>
|
/>
|
||||||
<Link
|
<Link
|
||||||
doctype="LMS Category"
|
doctype="LMS Category"
|
||||||
v-model="course.category"
|
v-model="course.category"
|
||||||
:label="__('Category')"
|
:label="__('Category')"
|
||||||
:allowCreate="true"
|
:allowCreate="true"
|
||||||
@create="
|
@create="
|
||||||
() => {
|
() => {
|
||||||
openSettings('Categories')
|
openSettings('Categories')
|
||||||
show = false
|
show = false
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<MultiSelect
|
<MultiSelect
|
||||||
v-model="course.instructors"
|
v-model="course.instructors"
|
||||||
doctype="User"
|
doctype="User"
|
||||||
:label="__('Instructors')"
|
:label="__('Instructors')"
|
||||||
:filters="{ ignore_user_type: 1 }"
|
:filters="{ ignore_user_type: 1 }"
|
||||||
:onCreate="(close: () => void) => openSettings('Members', close)"
|
:onCreate="(close: () => void) => openSettings('Members', close)"
|
||||||
:required="true"
|
:required="true"
|
||||||
/>
|
/>
|
||||||
<Uploader
|
<Uploader
|
||||||
v-model="course.image"
|
v-model="course.image"
|
||||||
:label="__('Course Image')"
|
:label="__('Course Image')"
|
||||||
:required="false"
|
:required="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<FormControl
|
<FormControl
|
||||||
v-model="course.short_introduction"
|
v-model="course.short_introduction"
|
||||||
:label="__('Short Introduction')"
|
:label="__('Short Introduction')"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:required="true"
|
:required="true"
|
||||||
:rows="4"
|
:rows="4"
|
||||||
/>
|
/>
|
||||||
<div class="">
|
<div class="">
|
||||||
<div class="mb-1.5 text-sm text-ink-gray-5">
|
<div class="mb-1.5 text-sm text-ink-gray-5">
|
||||||
{{ __('Course Description') }}
|
{{ __('Course Description') }}
|
||||||
<span class="text-ink-red-3">*</span>
|
<span class="text-ink-red-3">*</span>
|
||||||
</div>
|
</div>
|
||||||
<TextEditor
|
<TextEditor
|
||||||
:content="course.description"
|
:content="course.description"
|
||||||
@change="(val: string) => (course.description = val)"
|
@change="(val: string) => (course.description = val)"
|
||||||
:editable="true"
|
:editable="true"
|
||||||
:fixedMenu="true"
|
:fixedMenu="true"
|
||||||
editorClass="prose-sm max-w-none border-b border-x bg-surface-gray-2 rounded-b-md py-1 px-2 min-h-[10rem]"
|
editorClass="prose-sm max-w-none border-b border-x bg-surface-gray-2 rounded-b-md py-1 px-2 min-h-[10rem]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #actions="{ close }">
|
<template #actions="{ close }">
|
||||||
<div class="text-right">
|
<div class="text-right">
|
||||||
<Button variant="solid" @click="saveCourse(close)">
|
<Button variant="solid" @click="saveCourse(close)">
|
||||||
{{ __('Create') }}
|
{{ __('Create') }}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Button, Dialog, FormControl, TextEditor, toast } from 'frappe-ui'
|
import { Button, Dialog, FormControl, TextEditor, toast } from 'frappe-ui'
|
||||||
import { Link, useOnboarding, useTelemetry } from "frappe-ui/frappe"
|
import { Link, useOnboarding, useTelemetry } from 'frappe-ui/frappe'
|
||||||
import { onMounted, onBeforeUnmount, ref, watch } from 'vue';
|
import { inject, onMounted, onBeforeUnmount, ref, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { openSettings } from '@/utils'
|
import { openSettings } from '@/utils'
|
||||||
import MultiSelect from '@/components/Controls/MultiSelect.vue'
|
import MultiSelect from '@/components/Controls/MultiSelect.vue'
|
||||||
@@ -86,58 +86,64 @@ const show = defineModel<boolean>({ required: true, default: false })
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { capture } = useTelemetry()
|
const { capture } = useTelemetry()
|
||||||
const { updateOnboardingStep } = useOnboarding('learning')
|
const { updateOnboardingStep } = useOnboarding('learning')
|
||||||
|
const user = inject<any>('$user')
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courses: any
|
courses: any
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const course = ref({
|
const course = ref({
|
||||||
title: '',
|
title: '',
|
||||||
short_introduction: '',
|
short_introduction: '',
|
||||||
description: '',
|
description: '',
|
||||||
instructors: [],
|
instructors: [],
|
||||||
category: null,
|
category: null,
|
||||||
image: null,
|
image: null,
|
||||||
})
|
})
|
||||||
|
|
||||||
const saveCourse = (close: () => void = () => {}) => {
|
const saveCourse = (close: () => void = () => {}) => {
|
||||||
props.courses.insert.submit({
|
props.courses.insert.submit(
|
||||||
...course.value,
|
{
|
||||||
instructors: course.value.instructors.map((instructor) => ({
|
...course.value,
|
||||||
instructor: instructor,
|
instructors: course.value.instructors.map((instructor) => ({
|
||||||
})),
|
instructor: instructor,
|
||||||
}, {
|
})),
|
||||||
onSuccess(data: any) {
|
},
|
||||||
toast.success(__('Course created successfully'))
|
{
|
||||||
close()
|
onSuccess(data: any) {
|
||||||
capture('course_created')
|
toast.success(__('Course created successfully'))
|
||||||
updateOnboardingStep('create_first_course', true, false, () => {
|
close()
|
||||||
localStorage.setItem('firstCourse', data.name)
|
capture('course_created')
|
||||||
})
|
router.push({
|
||||||
router.push({
|
name: 'CourseDetail',
|
||||||
name: 'CourseDetail',
|
params: { courseName: data.name },
|
||||||
params: { courseName: data.name },
|
hash: '#settings',
|
||||||
hash: '#settings',
|
})
|
||||||
})
|
if (user.data?.is_system_manager) {
|
||||||
},
|
updateOnboardingStep('create_first_course', true, false, () => {
|
||||||
})
|
localStorage.setItem('firstCourse', data.name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyboardShortcut = (e: KeyboardEvent) => {
|
const keyboardShortcut = (e: KeyboardEvent) => {
|
||||||
if (
|
if (
|
||||||
e.key === 's' &&
|
e.key === 's' &&
|
||||||
(e.ctrlKey || e.metaKey) &&
|
(e.ctrlKey || e.metaKey) &&
|
||||||
e.target &&
|
e.target &&
|
||||||
e.target instanceof HTMLElement &&
|
e.target instanceof HTMLElement &&
|
||||||
!e.target.classList.contains('ProseMirror')
|
!e.target.classList.contains('ProseMirror')
|
||||||
) {
|
) {
|
||||||
saveCourse()
|
saveCourse()
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.addEventListener('keydown', keyboardShortcut)
|
window.addEventListener('keydown', keyboardShortcut)
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
|||||||
@@ -38,10 +38,11 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"grid_page_length": 50,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-12-21 15:25:16.744558",
|
"modified": "2026-01-29 16:10:47.787285",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "sayali@frappe.io",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Course Review",
|
"name": "LMS Course Review",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
@@ -60,7 +61,6 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"print": 1,
|
"print": 1,
|
||||||
@@ -69,8 +69,45 @@
|
|||||||
"role": "LMS Student",
|
"role": "LMS Student",
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Moderator",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Course Creator",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Batch Evaluator",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"row_format": "Dynamic",
|
||||||
"search_fields": "course",
|
"search_fields": "course",
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
|||||||
Reference in New Issue
Block a user