diff --git a/frontend/tests/components/jobs/JobProgress.spec.ts b/frontend/tests/components/jobs/JobProgress.spec.ts new file mode 100644 index 00000000..402a0d0b --- /dev/null +++ b/frontend/tests/components/jobs/JobProgress.spec.ts @@ -0,0 +1,106 @@ +import { describe, test, expect } from 'vitest' +import { mount } from '@vue/test-utils' +import JobProgress from '@/components/jobs/JobProgress.vue' +import jobPending from '../../assets/job-pending.json' +import jobRunning from '../../assets/job-running.json' +import jobCompleted from '../../assets/job-completed.json' + +describe('JobProgress.vue', () => { + test('display job progress of pending job', () => { + const wrapper = mount(JobProgress, { + props: { + job: jobPending + } + }) + // Must have 3 bullets in blue + expect(wrapper.findAll('span.bg-slurmweb').length).toBe(3) + + const submittedSpans = wrapper.get('li#step-submitted').findAll('span') + expect(submittedSpans[1].classes('bg-slurmweb')).toBe(true) + + const eligibleSpans = wrapper.get('li#step-eligible').findAll('span') + expect(eligibleSpans[1].classes('bg-slurmweb')).toBe(true) + + // current + const schedulingSpans = wrapper.get('li#step-scheduling').findAll('span') + expect(schedulingSpans[1].classes('border-slurmweb')).toBe(true) + expect(schedulingSpans[1].classes('bg-white')).toBe(true) + expect(schedulingSpans[4].classes('text-slurmweb-dark')).toBe(true) + + const runningSpans = wrapper.get('li#step-running').findAll('span') + expect(runningSpans[1].classes('border-gray-300')).toBe(true) + expect(runningSpans[1].classes('bg-white')).toBe(true) + expect(runningSpans[4].classes('text-gray-500')).toBe(true) + + const completingSpans = wrapper.get('li#step-completing').findAll('span') + expect(completingSpans[1].classes('border-gray-300')).toBe(true) + expect(completingSpans[1].classes('bg-white')).toBe(true) + expect(completingSpans[4].classes('text-gray-500')).toBe(true) + + const terminatedSpans = wrapper.get('li#step-terminated').findAll('span') + expect(terminatedSpans[1].classes('border-gray-300')).toBe(true) + expect(terminatedSpans[1].classes('bg-slurmweb')).toBe(false) + expect(terminatedSpans[4].classes('text-gray-500')).toBe(true) + }) + test('display job progress of running job', () => { + const wrapper = mount(JobProgress, { + props: { + job: jobRunning + } + }) + // Must have 4 bullets in blue + expect(wrapper.findAll('span.bg-slurmweb').length).toBe(4) + + const submittedSpans = wrapper.get('li#step-submitted').findAll('span') + expect(submittedSpans[1].classes('bg-slurmweb')).toBe(true) + + const eligibleSpans = wrapper.get('li#step-eligible').findAll('span') + expect(eligibleSpans[1].classes('bg-slurmweb')).toBe(true) + + const schedulingSpans = wrapper.get('li#step-scheduling').findAll('span') + expect(schedulingSpans[1].classes('bg-slurmweb')).toBe(true) + + // current + const runningSpans = wrapper.get('li#step-running').findAll('span') + expect(runningSpans[1].classes('border-slurmweb')).toBe(true) + expect(runningSpans[1].classes('bg-white')).toBe(true) + expect(runningSpans[4].classes('text-slurmweb-dark')).toBe(true) + + const completingSpans = wrapper.get('li#step-completing').findAll('span') + expect(completingSpans[1].classes('border-gray-300')).toBe(true) + expect(completingSpans[1].classes('bg-white')).toBe(true) + expect(completingSpans[4].classes('text-gray-500')).toBe(true) + + const terminatedSpans = wrapper.get('li#step-terminated').findAll('span') + expect(terminatedSpans[1].classes('border-gray-300')).toBe(true) + expect(terminatedSpans[1].classes('bg-slurmweb')).toBe(false) + expect(terminatedSpans[4].classes('text-gray-500')).toBe(true) + }) + test('display job progress of completed job', () => { + const wrapper = mount(JobProgress, { + props: { + job: jobCompleted + } + }) + // Must have all 6 bullets in blue + expect(wrapper.findAll('span.bg-slurmweb').length).toBe(6) + + const submittedSpans = wrapper.get('li#step-submitted').findAll('span') + expect(submittedSpans[1].classes('bg-slurmweb')).toBe(true) + + const eligibleSpans = wrapper.get('li#step-eligible').findAll('span') + expect(eligibleSpans[1].classes('bg-slurmweb')).toBe(true) + + const schedulingSpans = wrapper.get('li#step-scheduling').findAll('span') + expect(schedulingSpans[1].classes('bg-slurmweb')).toBe(true) + + const runningSpans = wrapper.get('li#step-running').findAll('span') + expect(runningSpans[1].classes('bg-slurmweb')).toBe(true) + + const completingSpans = wrapper.get('li#step-completing').findAll('span') + expect(completingSpans[1].classes('bg-slurmweb')).toBe(true) + + const terminatedSpans = wrapper.get('li#step-terminated').findAll('span') + expect(terminatedSpans[1].classes('bg-slurmweb')).toBe(true) + }) +}) diff --git a/frontend/tests/components/jobs/JobProgressComment.spec.ts b/frontend/tests/components/jobs/JobProgressComment.spec.ts new file mode 100644 index 00000000..5424c099 --- /dev/null +++ b/frontend/tests/components/jobs/JobProgressComment.spec.ts @@ -0,0 +1,183 @@ +import { describe, test, expect, vi } from 'vitest' +import { mount } from '@vue/test-utils' +import JobProgressComment from '@/components/jobs/JobProgressComment.vue' +import jobPending from '../../assets/job-pending.json' +import jobRunning from '../../assets/job-running.json' +import jobCompleted from '../../assets/job-completed.json' + +//const steps = ['submitted', 'eligible', 'scheduling', 'running', 'completing', 'terminated'] + +describe('JobProgressComment.vue', () => { + // Pending job + test('pending job submitted comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobPending, + step: 'submitted' + } + }) + expect(wrapper.text().length).toBeGreaterThan(0) + }) + test('pending job eligible comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobPending, + step: 'eligible' + } + }) + expect(wrapper.text().length).toBeGreaterThan(0) + }) + test('pending job scheduling comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobPending, + step: 'scheduling' + } + }) + expect(wrapper.text().length).toBe(0) + }) + test('pending job running comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobPending, + step: 'running' + } + }) + expect(wrapper.text().length).toBe(0) + }) + test('pending job completing comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobPending, + step: 'completing' + } + }) + expect(wrapper.text().length).toBe(0) + }) + test('pending job terminated comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobPending, + step: 'terminated' + } + }) + expect(wrapper.text().length).toBe(0) + }) + + // Running job + test('running job submitted comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobRunning, + step: 'submitted' + } + }) + expect(wrapper.text().length).toBeGreaterThan(0) + }) + test('running job eligible comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobRunning, + step: 'eligible' + } + }) + expect(wrapper.text().length).toBeGreaterThan(0) + }) + test('running job scheduling comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobRunning, + step: 'scheduling' + } + }) + // Must contain start datetime + expect(wrapper.text().length).toBeGreaterThan(0) + }) + test('running job running comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobRunning, + step: 'running' + } + }) + // Must contain elapsed time + expect(wrapper.text()).toContain('elapsed') + }) + test('running job completing comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobRunning, + step: 'completing' + } + }) + expect(wrapper.text().length).toBe(0) + }) + test('running job terminated comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobRunning, + step: 'terminated' + } + }) + expect(wrapper.text().length).toBe(0) + }) + + // Completed job + test('completed job submitted comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobCompleted, + step: 'submitted' + } + }) + expect(wrapper.text().length).toBeGreaterThan(0) + }) + test('completed job eligible comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobCompleted, + step: 'eligible' + } + }) + expect(wrapper.text().length).toBeGreaterThan(0) + }) + test('completed job scheduling comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobCompleted, + step: 'scheduling' + } + }) + // Must contain start datetime + expect(wrapper.text().length).toBeGreaterThan(0) + }) + test('completed job running comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobCompleted, + step: 'running' + } + }) + // Must contain elapsed time + expect(wrapper.text()).toContain('elapsed') + }) + test('completed job completing comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobCompleted, + step: 'completing' + } + }) + expect(wrapper.text().length).toBe(0) + }) + test('completed job terminated comment', () => { + const wrapper = mount(JobProgressComment, { + props: { + job: jobCompleted, + step: 'terminated' + } + }) + // Must contain end datetime + expect(wrapper.text().length).toBeGreaterThan(0) + }) +}) diff --git a/frontend/tests/views/JobView.spec.ts b/frontend/tests/views/JobView.spec.ts new file mode 100644 index 00000000..3a21242d --- /dev/null +++ b/frontend/tests/views/JobView.spec.ts @@ -0,0 +1,50 @@ +import { describe, test, expect, beforeEach, vi } from 'vitest' +import { mount } from '@vue/test-utils' +import JobView from '@/views/JobView.vue' +import { init_plugins } from './common' +import { createRouterMock, injectRouterMock } from 'vue-router-mock' +import type { ClusterIndividualJob } from '@/composables/GatewayAPI' +import jobRunning from '../assets/job-running.json' + +const router = createRouterMock({ + spy: { + create: (fn: any) => vi.fn(fn), + reset: (spy: any) => spy.mockRestore() + } +}) + +const mockClusterDataPoller = { + data: undefined, + unable: false, + loaded: true +} as { data: ClusterIndividualJob | undefined; unable: boolean; loaded: boolean } + +vi.mock('@/composables/DataPoller', () => ({ + useClusterDataPoller: () => mockClusterDataPoller +})) + +describe('JobView.vue', () => { + beforeEach(() => { + init_plugins() + router.reset() + injectRouterMock(router) + }) + test('display job details', () => { + mockClusterDataPoller.data = jobRunning + const wrapper = mount(JobView, { + props: { + cluster: 'foo', + id: 1234 + } + }) + // Check some jobs fields + expect(wrapper.get('dl div#job-user dd').text()).toBe(jobRunning.user) + expect(wrapper.get('dl div#job-group dd').text()).toBe(jobRunning.group) + expect(wrapper.get('dl div#job-account dd').text()).toBe(jobRunning.association.account) + expect(wrapper.get('dl div#job-priority dd').text()).toBe(jobRunning.priority.number.toString()) + expect(wrapper.get('dl div#job-workdir dd').text()).toBe(jobRunning.working_directory) + expect(wrapper.get('dl div#job-nodes dd').text()).toBe(jobRunning.nodes) + expect(wrapper.get('dl div#job-partition dd').text()).toBe(jobRunning.partition) + expect(wrapper.get('dl div#job-qos dd').text()).toBe(jobRunning.qos) + }) +})