generated from openedx/frontend-template-application
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #43 from Pearson-Advance/vue/PADV-979
feat: Classes table in courses view
- Loading branch information
Showing
24 changed files
with
785 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,28 @@ | ||
// Color variables | ||
// Primary | ||
$primary: #007394; | ||
$primary-dark: #003057; | ||
|
||
// Basic Colors | ||
$color-black: #020917; | ||
$black-80: #333; | ||
$color-white: #fefefe; | ||
$color-gray: #60646d; | ||
$gray-70: #666666; | ||
$gray-60: #808080; | ||
$gray-30: #d3d3d3; | ||
$gray-20: #dfe1e1; | ||
$color-pink: #ffecf0; | ||
$color-green: #e7f7eb; | ||
$color-yellow: #fafbe5; | ||
$color-purple: #f4e3ee; | ||
$blue-20: #e4faff; | ||
|
||
$hyperlink-color: #17897c; | ||
$color-active-button: #989ba3; | ||
$hyperlink-color: #17897c; | ||
$bg-main-color: #f3f3f3; | ||
|
||
// Gray | ||
$gray-20: #dfe1e1; | ||
$gray-30: #d3d3d3; | ||
$gray-60: #808080; | ||
$gray-70: #666666; | ||
|
||
// Blue | ||
$blue-20: #e4faff; | ||
|
||
// Black | ||
$black: #000; | ||
$black-80: #333; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
202 changes: 202 additions & 0 deletions
202
src/features/Courses/CourseDetailTable/__test__/columns.test.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
import { | ||
fireEvent, | ||
waitFor, | ||
} from '@testing-library/react'; | ||
import '@testing-library/jest-dom/extend-expect'; | ||
import { MemoryRouter, Route } from 'react-router-dom'; | ||
|
||
import { renderWithProviders } from 'test-utils'; | ||
import { columns } from 'features/Courses/CourseDetailTable/columns'; | ||
|
||
describe('columns', () => { | ||
test('returns an array of columns with correct properties', () => { | ||
expect(columns).toBeInstanceOf(Array); | ||
expect(columns).toHaveLength(7); | ||
|
||
const [ | ||
className, | ||
instructor, | ||
enrollmentStatus, | ||
studentsEnrolled, | ||
maxStudents, | ||
startDate, | ||
endDate, | ||
] = columns; | ||
|
||
expect(className).toHaveProperty('Header', 'Class'); | ||
expect(className).toHaveProperty('accessor', 'className'); | ||
|
||
expect(instructor).toHaveProperty('Header', 'Instructor'); | ||
expect(instructor).toHaveProperty('accessor', 'instructors'); | ||
|
||
expect(enrollmentStatus).toHaveProperty('Header', 'Enrollment status'); | ||
expect(enrollmentStatus).toHaveProperty('accessor', 'numberOfPendingStudents'); | ||
|
||
expect(studentsEnrolled).toHaveProperty('Header', 'Students Enrolled'); | ||
expect(studentsEnrolled).toHaveProperty('accessor', 'numberOfStudents'); | ||
|
||
expect(maxStudents).toHaveProperty('Header', 'Max'); | ||
expect(maxStudents).toHaveProperty('accessor', 'maxStudents'); | ||
|
||
expect(startDate).toHaveProperty('Header', 'Start date'); | ||
expect(startDate).toHaveProperty('accessor', 'startDate'); | ||
|
||
expect(endDate).toHaveProperty('Header', 'End date'); | ||
expect(endDate).toHaveProperty('accessor', 'endDate'); | ||
}); | ||
|
||
test('Should render the title into a span tag', () => { | ||
const title = columns[0].Cell({ row: { values: { className: 'Class example' } } }); | ||
expect(title).toHaveProperty('type', 'span'); | ||
expect(title.props).toEqual({ className: 'text-truncate', children: 'Class example' }); | ||
}); | ||
|
||
test('Should render the dates', () => { | ||
const startDate = columns[5].Cell({ row: { values: { startDate: '2024-02-13T17:42:22Z' } } }); | ||
expect(startDate).toBe('02/13/24'); | ||
|
||
const endDate = columns[5].Cell({ row: { values: { startDate: '2024-04-13T17:42:22Z' } } }); | ||
expect(endDate).toBe('04/13/24'); | ||
|
||
const nullDate = columns[5].Cell({ row: { values: { startDate: null } } }); | ||
expect(nullDate).toBe('-'); | ||
|
||
const nullDate2 = columns[6].Cell({ row: { values: { startDate: null } } }); | ||
expect(nullDate2).toBe('-'); | ||
}); | ||
|
||
test('Should render the enrollment status', () => { | ||
const pendingStudents = { row: { values: { numberOfStudents: 3, numberOfPendingStudents: 1 } } }; | ||
|
||
const enrollmentStatus = columns[2].Cell(pendingStudents); | ||
expect(enrollmentStatus.props).toEqual({ children: ['Pending (', 1, ')'], light: true, variant: 'warning' }); | ||
|
||
const completeStudents = { row: { values: { numberOfStudents: 3, numberOfPendingStudents: 0 } } }; | ||
|
||
const enrollmentStatusComplete = columns[2].Cell(completeStudents); | ||
expect(enrollmentStatusComplete.props).toEqual({ children: 'Complete', light: true, variant: 'success' }); | ||
}); | ||
|
||
test('Should render the students enrolled', () => { | ||
const values = { row: { values: { numberOfStudents: 3, numberOfPendingStudents: 1 } } }; | ||
|
||
const studentsEnrolled = columns[3].Cell(values); | ||
expect(studentsEnrolled).toHaveProperty('type', 'span'); | ||
expect(studentsEnrolled.props).toEqual({ children: 3 }); | ||
}); | ||
|
||
test('Should render the instructors', () => { | ||
const values = { | ||
row: { | ||
values: { instructors: ['Sam Sepiol'] }, | ||
original: { | ||
classId: 'Demo Course 1', | ||
}, | ||
}, | ||
}; | ||
|
||
const Component = () => columns[1].Cell(values); | ||
const mockStore = { | ||
classes: { | ||
table: { | ||
data: [ | ||
{ | ||
masterCourseName: 'Demo MasterCourse 1', | ||
className: 'Demo Class 1', | ||
startDate: '09/21/24', | ||
endDate: null, | ||
numberOfStudents: 1, | ||
maxStudents: 100, | ||
instructors: ['Sam Sepiol'], | ||
}, | ||
{ | ||
masterCourseName: 'Demo MasterCourse 2', | ||
className: 'Demo Class 2', | ||
startDate: '09/21/25', | ||
endDate: null, | ||
numberOfStudents: 2, | ||
maxStudents: 200, | ||
instructors: [], | ||
}, | ||
], | ||
count: 2, | ||
num_pages: 1, | ||
current_page: 1, | ||
}, | ||
}, | ||
}; | ||
|
||
const component = renderWithProviders( | ||
<MemoryRouter initialEntries={['/courses/Demo%20Course%201']}> | ||
<Route path="/courses/:classId"> | ||
<Component /> | ||
</Route> | ||
</MemoryRouter>, | ||
{ preloadedState: mockStore }, | ||
); | ||
|
||
expect(component.getByText('Sam Sepiol')).toBeInTheDocument(); | ||
}); | ||
|
||
test('Should render the assign button if instructor is not present', async () => { | ||
const values = { | ||
row: { | ||
values: { instructors: [] }, | ||
original: { | ||
classId: 'Demo Course 1', | ||
}, | ||
}, | ||
}; | ||
|
||
const ComponentNoInstructor = () => columns[1].Cell(values); | ||
|
||
const mockStore = { | ||
classes: { | ||
table: { | ||
data: [ | ||
{ | ||
masterCourseName: 'Demo MasterCourse 1', | ||
className: 'Demo Class 1', | ||
startDate: '09/21/24', | ||
endDate: null, | ||
numberOfStudents: 1, | ||
maxStudents: 100, | ||
instructors: ['Sam Sepiol'], | ||
}, | ||
{ | ||
masterCourseName: 'Demo MasterCourse 2', | ||
className: 'Demo Class 2', | ||
startDate: '09/21/25', | ||
endDate: null, | ||
numberOfStudents: 2, | ||
maxStudents: 200, | ||
instructors: [], | ||
}, | ||
], | ||
count: 2, | ||
num_pages: 1, | ||
current_page: 1, | ||
}, | ||
}, | ||
}; | ||
|
||
const component = renderWithProviders( | ||
<MemoryRouter initialEntries={['/courses/Demo%20Course%201']}> | ||
<Route path="/courses/:classId"> | ||
<ComponentNoInstructor /> | ||
</Route> | ||
</MemoryRouter>, | ||
{ preloadedState: mockStore }, | ||
); | ||
|
||
const modalButton = component.getByRole('button'); | ||
expect(modalButton).toBeInTheDocument(); | ||
|
||
fireEvent.click(modalButton); | ||
|
||
await waitFor(() => { | ||
const title = component.getAllByText('Assign instructor')[0]; | ||
expect(title).toBeInTheDocument(); | ||
}); | ||
}); | ||
}); |
69 changes: 69 additions & 0 deletions
69
src/features/Courses/CourseDetailTable/__test__/index.test.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import React from 'react'; | ||
import '@testing-library/jest-dom'; | ||
import { MemoryRouter, Route } from 'react-router-dom'; | ||
import { render, screen } from '@testing-library/react'; | ||
|
||
import { renderWithProviders } from 'test-utils'; | ||
import CourseDetailTable from 'features/Courses/CourseDetailTable'; | ||
import { columns } from 'features/Courses/CourseDetailTable/columns'; | ||
|
||
describe('Course Details Table', () => { | ||
test('Should render the table without data', () => { | ||
render(<CourseDetailTable data={[]} count={0} columns={[]} />); | ||
const emptyTableText = screen.getByText('No classes were found.'); | ||
expect(emptyTableText).toBeInTheDocument(); | ||
}); | ||
|
||
test('Should render the table with data', () => { | ||
const mockStore = { | ||
classes: { | ||
table: { | ||
data: [ | ||
{ | ||
masterCourseName: 'Demo MasterCourse 1', | ||
className: 'Demo Class 1', | ||
startDate: '09/21/24', | ||
endDate: null, | ||
numberOfStudents: 1, | ||
maxStudents: 100, | ||
instructors: ['instructor_1'], | ||
}, | ||
{ | ||
masterCourseName: 'Demo MasterCourse 2', | ||
className: 'Demo Class 2', | ||
startDate: '09/21/25', | ||
endDate: null, | ||
numberOfStudents: 2, | ||
maxStudents: 200, | ||
instructors: ['instructor_2'], | ||
}, | ||
], | ||
count: 2, | ||
num_pages: 1, | ||
current_page: 1, | ||
}, | ||
}, | ||
}; | ||
|
||
const component = renderWithProviders( | ||
<MemoryRouter initialEntries={['/courses']}> | ||
<Route path="/courses"> | ||
<CourseDetailTable | ||
data={mockStore.classes.table.data} | ||
count={mockStore.classes.table.data.length} | ||
columns={columns} | ||
/> | ||
</Route> | ||
</MemoryRouter>, | ||
{ preloadedState: mockStore }, | ||
); | ||
|
||
expect(component.container).toHaveTextContent('Class'); | ||
expect(component.container).toHaveTextContent('Instructor'); | ||
expect(component.container).toHaveTextContent('Enrollment status'); | ||
expect(component.container).toHaveTextContent('Students Enrolled'); | ||
expect(component.container).toHaveTextContent('Max'); | ||
expect(component.container).toHaveTextContent('Start date'); | ||
expect(component.container).toHaveTextContent('End date'); | ||
}); | ||
}); |
Oops, something went wrong.