Skip to content

Commit

Permalink
Merge pull request #106 from LCOGT/update/populateinstruments
Browse files Browse the repository at this point in the history
Update/populateinstruments
  • Loading branch information
capetillo authored Dec 16, 2024
2 parents 0018cf1 + 0edd661 commit 1072570
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 116 deletions.
22 changes: 3 additions & 19 deletions src/components/RealTimeInterface/SessionStarted.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ import { calcAltAz } from '../../utils/visibility.js'
import { useRealTimeSessionsStore } from '../../stores/realTimeSessions'
import sites from '../../utils/sites.JSON'
import { fetchApiCall } from '../../utils/api'
import { getFilterList } from '../../utils/populateInstrumentsUtils'
import { useConfigurationStore } from '../../stores/configuration'
import { useUserDataStore } from '../../stores/userData'
const realTimeSessionsStore = useRealTimeSessionsStore()
const configurationStore = useConfigurationStore()
const userDataStore = useUserDataStore()
const isCapturingImages = computed(() => {
if (configurationStore.demo == true) {
Expand Down Expand Up @@ -144,21 +143,6 @@ const sendGoCommand = async () => {
})
}
// This should change from configdbUrl/opticalelementgroups/128/ to
// https://observe.lco.global/api/instruments and map the instruments based on what telescope is being used
const getFilterList = async () => {
await fetchApiCall({
url: configurationStore.configdbUrl + 'opticalelementgroups/128/',
method: 'GET',
successCallback: (data) => {
filterList.value = data.optical_elements
.filter(filter => filter.schedulable)
.map(filter => ({ name: filter.name, code: filter.code }))
},
failCallback: (error) => { console.error('API failed with error', error) }
})
}
function updateRenderGallery (value) {
if (!value) {
realTimeSessionsStore.updateImageCaptureState(false)
Expand All @@ -174,9 +158,9 @@ watch(exposureTime, (newTime) => {
exposureError.value = ''
})
onMounted(() => {
onMounted(async () => {
loading.value = false
getFilterList()
filterList.value = await getFilterList()
})
</script>
Expand Down
25 changes: 3 additions & 22 deletions src/components/Scheduling/SchedulingSettings.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup>
import { ref, reactive, computed, defineProps, defineEmits, onMounted } from 'vue'
import { useConfigurationStore } from '../../stores/configuration.js'
import { fetchApiCall } from '../../utils/api.js'
import { getFilterList } from '../../utils/populateInstrumentsUtils.js'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
const props = defineProps({
Expand Down Expand Up @@ -36,25 +36,6 @@ const settings = reactive({
count: ''
})
const getFilterList = async () => {
await fetchApiCall({
url: configurationStore.observationPortalUrl + 'instruments',
method: 'GET',
successCallback: (data) => {
Object.values(data).forEach(instrument => {
// Checks if the instrument has a "class" of "0m4" and contains filters in optical_elements
if (instrument.class === '0m4' && instrument.optical_elements.filters) {
const schedulableFilters = instrument.optical_elements.filters
.filter(filter => filter.schedulable)
.map(filter => ({ name: filter.name, code: filter.code }))
filterList.value.push(...schedulableFilters)
}
})
},
failCallback: (error) => { console.error('API failed with error', error) }
})
}
// State for enabling/disabling fields
const targetEnabled = computed(() => {
return props.showProjectField ? projectName.value.trim() !== '' : true
Expand Down Expand Up @@ -139,8 +120,8 @@ const formatExposures = (exposures) => {
return exposures.map(exposure => `${exposure.filterName} - ${exposure.exposureTime}s x ${exposure.count}`).join(', ')
}
onMounted(() => {
getFilterList()
onMounted(async () => {
filterList.value = await getFilterList()
})
</script>
Expand Down
75 changes: 0 additions & 75 deletions src/tests/integration/components/schedulingSettings.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,6 @@ describe('SchedulingSettings.vue', () => {
fetchApiCall.mockClear()
const { pinia } = createTestStores()

fetchApiCall.mockImplementationOnce(({ successCallback }) => {
if (successCallback) {
successCallback({
'0M4-SCICAM-QHY600': {
'class': '0m4',
'optical_elements': {
'filters': [
{ name: 'Filter A', code: 'FA', schedulable: true },
{ name: 'Filter B', code: 'FB', schedulable: false }
]
}
},
'0M4-SCICAM-FLI': {
'class': '0m4',
'optical_elements': {
'filters': [
{ name: 'Filter D', code: 'FD', schedulable: true },
{ name: 'Filter E', code: 'FE', schedulable: true }
]
}
}
})
}
})

wrapper = mount(SchedulingSettings, {
global: {
plugins: [pinia],
Expand All @@ -53,28 +28,6 @@ describe('SchedulingSettings.vue', () => {
})
})

it('calls fetchApiCall to get filter list on mount', async () => {
expect(fetchApiCall).toHaveBeenCalledWith(
expect.objectContaining({
url: 'http://mock-api.com/instruments',
method: 'GET',
successCallback: expect.any(Function),
failCallback: expect.any(Function)
})
)

await flushPromises()

// filters through the non-schedulable filters
expect(wrapper.vm.filterList).toEqual([
{ name: 'Filter A', code: 'FA' },
{ name: 'Filter D', code: 'FD' },
{ name: 'Filter E', code: 'FE' }
])

expect(fetchApiCall).toHaveBeenCalledTimes(1)
})

it('fetches RA and Dec based on the target name and updates state correctly', async () => {
const mockRaDecResponse = {
'dec': '+41 16 07.50',
Expand Down Expand Up @@ -116,32 +69,4 @@ describe('SchedulingSettings.vue', () => {

expect(wrapper.vm.targetError).toBe('Target not found, try another target.')
})

it('emits exposuresUpdated when exposures are added', async () => {
// Checks that filterList has been populated correctly
expect(wrapper.vm.filterList).toEqual([
{ name: 'Filter A', code: 'FA' },
{ name: 'Filter D', code: 'FD' },
{ name: 'Filter E', code: 'FE' }
])

// Simulates selecting a filter from the dropdown
wrapper.vm.settings.filter = 'FA'
wrapper.vm.settings.filterName = 'Filter A'
wrapper.vm.settings.exposureTime = '30'
wrapper.vm.settings.count = '15'

await wrapper.vm.addExposure()

// Check that the event is emitted with the expected payload
expect(wrapper.emitted().exposuresUpdated).toBeTruthy()
expect(wrapper.emitted().exposuresUpdated[0][0]).toEqual([
{
filter: 'FA',
filterName: 'Filter A',
exposureTime: '30',
count: '15'
}
])
})
})
89 changes: 89 additions & 0 deletions src/tests/unit/utils/populateInstrumentsUtils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { vi, describe, it, expect, beforeEach } from 'vitest'
import { getFilterList } from '../../../utils/populateInstrumentsUtils.js'
import { fetchApiCall } from '../../../utils/api.js'
import { createTestStores } from '../../../utils/testUtils'

vi.mock('@/utils/api.js', () => ({
fetchApiCall: vi.fn()
}))

describe('thumbnailsUtils.js', () => {
let configurationStore

beforeEach(() => {
const { configurationStore: store } = createTestStores()
configurationStore = store
fetchApiCall.mockClear()
})

describe('getFilterList', () => {
beforeEach(() => {
fetchApiCall.mockClear()
})

it('fetches instruments and returns schedulable filters', async () => {
// Mock API response
fetchApiCall.mockResolvedValueOnce({
'0M4-SCICAM-QHY600': {
class: '0m4',
optical_elements: {
filters: [
{ name: 'Filter A', code: 'FA', schedulable: true },
{ name: 'Filter B', code: 'FB', schedulable: false }
]
}
},
'0M4-SCICAM-FLI': {
class: '0m4',
optical_elements: {
filters: [
{ name: 'Filter D', code: 'FD', schedulable: true },
{ name: 'Filter E', code: 'FE', schedulable: true }
]
}
},
// This instrument should be ignored
'1M0-SCICAM': {
class: '1m0',
optical_elements: {
filters: [
{ name: 'Filter X', code: 'FX', schedulable: true }
]
}
}
})

const result = await getFilterList()

expect(result).toEqual([
{ name: 'Filter A', code: 'FA' },
{ name: 'Filter D', code: 'FD' },
{ name: 'Filter E', code: 'FE' }
])

expect(fetchApiCall).toHaveBeenCalledWith(
expect.objectContaining({
url: expect.stringContaining('instruments'),
method: 'GET'
})
)
})

it('returns an empty array if no schedulable filters are found', async () => {
fetchApiCall.mockResolvedValueOnce({
'0M4-SCICAM-QHY600': {
class: '0m4',
optical_elements: {
filters: [
{ name: 'Filter A', code: 'FA', schedulable: false }
]
}
}
})

const result = await getFilterList()

expect(result).toEqual([])
})
})
})
24 changes: 24 additions & 0 deletions src/utils/populateInstrumentsUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { fetchApiCall } from './api.js'
import { useConfigurationStore } from '../stores/configuration.js'

export const getFilterList = async () => {
const configurationStore = useConfigurationStore()
const response = await fetchApiCall({
url: `${configurationStore.observationPortalUrl}instruments`,
method: 'GET'
})
const filterList = []
if (!response) {
return filterList
}
const instrumentClass = '0m4'
Object.values(response).forEach((instrument) => {
if (instrument.class === instrumentClass && instrument.optical_elements.filters) {
const schedulableFilters = instrument.optical_elements.filters
.filter(filter => filter.schedulable)
.map(filter => ({ name: filter.name, code: filter.code }))
filterList.push(...schedulableFilters)
}
})
return filterList
}

0 comments on commit 1072570

Please sign in to comment.