-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add unit tests to cover ClustersView and ClustersListItem component.
- Loading branch information
Showing
2 changed files
with
166 additions
and
0 deletions.
There are no files selected for viewing
105 changes: 105 additions & 0 deletions
105
frontend/tests/components/clusters/ClustersListItem.spec.ts
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,105 @@ | ||
import { describe, test, expect, beforeEach, vi } from 'vitest' | ||
import { flushPromises, shallowMount } from '@vue/test-utils' | ||
import ClusterListItem from '@/components/clusters/ClustersListItem.vue' | ||
import stats from '../../assets/stats.json' | ||
import { init_plugins } from '../../lib/common' | ||
import { useRuntimeStore } from '@/stores/runtime' | ||
import LoadingSpinner from '@/components/LoadingSpinner.vue' | ||
import { APIServerError, AuthenticationError } from '@/composables/HTTPErrors' | ||
import cluster from 'cluster' | ||
import LoadingSpinner from '@/components/LoadingSpinner.vue' | ||
|
||
const mockGatewayAPI = { | ||
stats: vi.fn() | ||
} | ||
|
||
vi.mock('@/composables/GatewayAPI', () => ({ | ||
useGatewayAPI: () => mockGatewayAPI | ||
})) | ||
|
||
let router | ||
|
||
describe('ClustersView.vue', () => { | ||
beforeEach(() => { | ||
router = init_plugins() | ||
useRuntimeStore().availableClusters = [ | ||
{ | ||
name: 'foo', | ||
permissions: { roles: [], actions: [] }, | ||
racksdb: true, | ||
infrastructure: 'foo', | ||
metrics: true | ||
} | ||
] | ||
mockGatewayAPI.stats.mockReset() | ||
}) | ||
test('cluster with permission', async () => { | ||
useRuntimeStore().availableClusters[0].permissions.actions = ['view-stats', 'view-jobs'] | ||
mockGatewayAPI.stats.mockReturnValueOnce(Promise.resolve(stats)) | ||
const wrapper = shallowMount(ClusterListItem, { | ||
props: { | ||
cluster: useRuntimeStore().availableClusters[0] | ||
} | ||
}) | ||
// Wait for result of clusters requests | ||
await flushPromises() | ||
// assert stats have been retrieved | ||
expect(mockGatewayAPI.stats).toBeCalled() | ||
// Check presence of Slurm version | ||
expect(wrapper.get('span span').text()).toContain('Slurm ') | ||
// Check presence of nodes/jobs stats | ||
const statsElements = wrapper.findAll('p') | ||
expect(statsElements[0].text()).toContain('nodes') | ||
expect(statsElements[1].text()).toContain('jobs') | ||
// Check cluster status is available | ||
expect(wrapper.get('div div p').text()).toBe('Available') | ||
}) | ||
test('cluster loading', async () => { | ||
useRuntimeStore().availableClusters[0].permissions.actions = ['view-stats', 'view-jobs'] | ||
mockGatewayAPI.stats.mockReturnValueOnce(Promise.resolve(stats)) | ||
const wrapper = shallowMount(ClusterListItem, { | ||
props: { | ||
cluster: useRuntimeStore().availableClusters[0] | ||
} | ||
}) | ||
// assert stats are being retrieved | ||
expect(mockGatewayAPI.stats).toBeCalled() | ||
// Check presence of loading spinner | ||
expect(wrapper.findComponent(LoadingSpinner).exists()).toBeTruthy() | ||
// Check cluster status is loading | ||
expect(wrapper.get('div div p').text()).toBe('Loading') | ||
}) | ||
test('cluster without permission', async () => { | ||
mockGatewayAPI.stats.mockReturnValueOnce(Promise.resolve(stats)) | ||
const wrapper = shallowMount(ClusterListItem, { | ||
props: { | ||
cluster: useRuntimeStore().availableClusters[0] | ||
} | ||
}) | ||
// Wait for result of clusters requests | ||
await flushPromises() | ||
// assert stats not retrieved | ||
expect(mockGatewayAPI.stats).not.toBeCalled() | ||
// Check Slurm version is absent | ||
expect(wrapper.find('span span').exists()).toBeFalsy() | ||
// Check there is only one paragraph for cluster status, not for stats | ||
expect(wrapper.findAll('p').length).toBe(1) | ||
expect(wrapper.get('div div p').text()).toBe('Denied') | ||
}) | ||
test('cluster without view-stats permission', async () => { | ||
useRuntimeStore().availableClusters[0].permissions.actions = ['view-jobs'] | ||
const wrapper = shallowMount(ClusterListItem, { | ||
props: { | ||
cluster: useRuntimeStore().availableClusters[0] | ||
} | ||
}) | ||
await flushPromises() | ||
// assert stats not retrieved | ||
expect(mockGatewayAPI.stats).not.toBeCalled() | ||
// Check Slurm version is absent | ||
expect(wrapper.find('span span').exists()).toBeFalsy() | ||
// Check there is only one paragraph for cluster status, not for stats | ||
expect(wrapper.findAll('p').length).toBe(1) | ||
expect(wrapper.get('div div p').text()).toBe('Available') | ||
}) | ||
}) |
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,61 @@ | ||
import { describe, test, expect, beforeEach, vi } from 'vitest' | ||
import { flushPromises, shallowMount } from '@vue/test-utils' | ||
import ClustersView from '@/views/ClustersView.vue' | ||
import clusters from '../assets/clusters.json' | ||
import { init_plugins } from '../lib/common' | ||
import LoadingSpinner from '@/components/LoadingSpinner.vue' | ||
import ClusterListItem from '@/components/clusters/ClustersListItem.vue' | ||
import { APIServerError, AuthenticationError } from '@/composables/HTTPErrors' | ||
|
||
const mockGatewayAPI = { | ||
clusters: vi.fn() | ||
} | ||
|
||
vi.mock('@/composables/GatewayAPI', () => ({ | ||
useGatewayAPI: () => mockGatewayAPI | ||
})) | ||
|
||
let router | ||
|
||
describe('ClustersView.vue', () => { | ||
beforeEach(() => { | ||
router = init_plugins() | ||
}) | ||
test('display clusters list', async () => { | ||
// Check at least one cluster is present in test asset or the test is pointless. | ||
expect(clusters.length).toBeGreaterThan(0) | ||
mockGatewayAPI.clusters.mockReturnValueOnce(Promise.resolve(clusters)) | ||
const wrapper = shallowMount(ClustersView) | ||
// Wait for result of clusters requests | ||
await flushPromises() | ||
// Check page title | ||
expect(wrapper.get('h1').text()).toBe('Select a cluster') | ||
// Check there are as many ClusterListItem as the number of clusters in test asset. | ||
expect(wrapper.findAllComponents(ClusterListItem).length).toBe(clusters.length) | ||
}) | ||
test('show loading spinner before loaded', async () => { | ||
const wrapper = shallowMount(ClustersView) | ||
wrapper.getComponent(LoadingSpinner) | ||
expect(wrapper.get('div').text()).toBe('Loading clusters…') | ||
}) | ||
test('authentication error', async () => { | ||
mockGatewayAPI.clusters.mockImplementationOnce(() => { | ||
throw new AuthenticationError('fake authentication error') | ||
}) | ||
const wrapper = shallowMount(ClustersView) | ||
// Wait for result of clusters requests | ||
await flushPromises() | ||
// Check redirect to signout on authentication error | ||
expect(router.push).toHaveBeenCalledTimes(1) | ||
expect(router.push).toHaveBeenCalledWith({ name: 'signout' }) | ||
}) | ||
test('server error', async () => { | ||
mockGatewayAPI.clusters.mockImplementationOnce(() => { | ||
throw new APIServerError(500, 'fake error') | ||
}) | ||
const wrapper = shallowMount(ClustersView) | ||
// Wait for result of clusters requests | ||
await flushPromises() | ||
expect(wrapper.get('div h3').text()).toBe('Unable to load cluster list') | ||
}) | ||
}) |