Skip to content

Commit

Permalink
test: add ut for profile
Browse files Browse the repository at this point in the history
  • Loading branch information
AlitaBernachot committed Nov 15, 2024
1 parent 87fb5e9 commit ea01eac
Show file tree
Hide file tree
Showing 20 changed files with 1,772 additions and 1,037 deletions.
1,012 changes: 1,012 additions & 0 deletions src/__fixtures__/d3-graph-elevation.fixtures.ts

Large diffs are not rendered by default.

1,022 changes: 0 additions & 1,022 deletions src/components/common/graph/d3-graph-elevation.fixtures.ts

This file was deleted.

4 changes: 4 additions & 0 deletions src/components/common/graph/d3-graph-elevation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ describe('D3GraphElevation', () => {
beforeEach(() => {
wrapper = mount(D3GraphElevation, {
props: {
labelXFormatter: () => '',
labelYFormatter: () => '',
xFormatter: (val: number) => val + '',
yFormatter: (val: number) => val + '',
showTooltip: true,
},
})
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/graph/d3-graph-elevation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { debounce } from '@/services/utils'
import D3GraphElevation from './d3-graph-elevation'
import { Elevations, Profile, ProfileOptions } from './d3-graph-elevation.d'
import { ProfileData } from './elevation-profile'
// import { dataset } from './d3-graph-elevation.fixtures' // Use these fixtures instead of api if needed (for dev debug only)
// import { dataset } from '@/__fixtures__/d3-graph-elevation.fixtures' // Use these fixtures instead of api if needed (for dev debug only)
const emit = defineEmits<{
(e: 'hover:profile', point: any, dist: number, elevations: Elevations): void
Expand Down
42 changes: 42 additions & 0 deletions src/components/common/graph/elevation-profile.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import ElevationProfile from './elevation-profile.vue'
import D3GraphElevation from './d3-graph-elevation.vue'
import { ProfileData } from './elevation-profile'

describe('ElevationProfile', () => {
it('Display an image when profileData is empty', () => {
const wrapper = mount(ElevationProfile, {
props: {
profileData: undefined,
},
})

expect(wrapper.find('img').exists()).toBe(true)
expect(wrapper.findComponent(D3GraphElevation).exists()).toBe(false)
})

it('Display the graph when profileData has values', () => {
const profileData = <ProfileData>[
{
cumulativeElevation: 42,
elevationGain: 58,
elevationLoss: 2,
},
{
cumulativeElevation: 250,
elevationGain: 22,
elevationLoss: 42,
},
]
const wrapper = mount(ElevationProfile, {
props: {
profileData,
highlightDistance: 10,
},
})

expect(wrapper.findComponent(D3GraphElevation).exists()).toBe(true)
expect(wrapper.find('img').exists()).toBe(false)
})
})
4 changes: 2 additions & 2 deletions src/components/draw/feature-menu-popup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import { DrawnFeature } from '@/services/draw/drawn-feature'
import {
exportFeatureService,
TFeatExport,
type exportFormat,
type TExportFormat,
} from '@/services/export-feature/export-feature.service'
const { t } = useTranslation()
const feature: DrawnFeature = inject('feature')!
function download(format: exportFormat) {
function download(format: TExportFormat) {
exportFeatureService.export(
feature.map,
format,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { nextTick } from 'vue'
import { mount, shallowMount } from '@vue/test-utils'
import { GlobalMountOptions } from '@vue/test-utils/dist/types'
import { createTestingPinia } from '@pinia/testing'
import { describe, it, expect, vi } from 'vitest'
import { Coordinate } from 'ol/coordinate'

import { dataset as datasetFixtures } from '@/__fixtures__/d3-graph-elevation.fixtures'
import formatMeasureDirective from '@/directives/format-measure.directive'
import { DrawnFeature } from '@/services/draw/drawn-feature'
import FeatureElevationProfile from './feature-elevation-profile.vue'
import { exportFeatureService } from '@/services/export-feature/export-feature.service'
import { useProfilePositionStore } from '@/stores/profile-position.store'
import ElevationProfile from '../common/graph/elevation-profile.vue'

const global: GlobalMountOptions | undefined = {
plugins: [formatMeasureDirective],
}

const mockedFeatureWithData = <DrawnFeature>(<unknown>{
getProfile: vi.fn(() => Promise.resolve(datasetFixtures)),
profileData: undefined,
map: { getView: () => ({ getProjection: () => 'EPSG:4326' }) },
label: 'Feature Label with data',
})

const mockedFeatureNoData = <DrawnFeature>(<unknown>{
getProfile: vi.fn(() => new Promise(() => undefined)),
profileData: undefined,
map: {},
label: 'Feature Label with NO data',
})

vi.mock('ol/proj', () => ({
transform: (coords: Coordinate) => coords,
}))

vi.mock('@/services/export-feature/export-feature.service', () => ({
exportFeatureService: {
export: vi.fn(),
},
}))

vi.mock('@/composables/map/map.composable', () => ({
default: () => ({
getOlMap: () => ({
addLayer: vi.fn(),
addFeatureLayer: vi.fn(),
getView: () => ({ getProjection: vi.fn() }),
}),
}),
PROJECTION_LUX: 'EPSG:2169',
}))

vi.mock('@/composables/map/profile-position.composable', () => ({
default: () => ({
constructProfileLine: vi.fn(),
profileData: { value: undefined },
highlightDistance: { value: undefined },
}),
}))

describe('FeatureElevationProfile', () => {
createTestingPinia({
createSpy: vi.fn,
stubActions: false,
initialState: {
'profile-position': {
x: 1,
y: 2,
},
},
})

it('Display elevation ,cumulation gain and loss according to profileData', async () => {
const wrapper = shallowMount(FeatureElevationProfile, {
props: { feature: mockedFeatureWithData },
global,
})

await nextTick() // wait for execution of `onMounted`
await nextTick()

expect(wrapper.text()).toContain('Δ+699')
expect(wrapper.text()).toContain('Δ-814')
expect(wrapper.text()).toContain('-115')
})

it('Display a waiting message when profileData is still loading', async () => {
const wrapper = mount(FeatureElevationProfile, {
props: { feature: mockedFeatureNoData },
global,
})

expect(wrapper.text()).toContain('Please wait, the profile is loading.')
})

it('Does not display a close button if there is no listerner for "onClose"', () => {
const wrapper = mount(FeatureElevationProfile, {
global,
})

expect(wrapper.find('[aria-label="Close"]').exists()).toBe(false)
})

it('Display a close button if there is a listerner for "onClose"', () => {
const wrapper = mount(FeatureElevationProfile, {
props: {
onClose: () => alert('My listener on close'),
feature: mockedFeatureNoData,
},
global,
})

expect(wrapper.find('[aria-label="Close"]').exists()).toBe(true)
})

it("Call 'exportFeatureService.export' when on click export csv button", async () => {
const wrapper = shallowMount(FeatureElevationProfile, {
props: { feature: mockedFeatureWithData },
global,
})

await nextTick()
await wrapper.find('[data-cy="featItemProfileCSV"]').trigger('click')

expect(exportFeatureService.export).toHaveBeenCalled()
})

it("Update 'profilePositionStore' when hovering the graph", async () => {
const profilePositionStore = useProfilePositionStore()
const wrapper = mount(FeatureElevationProfile, {
props: { feature: mockedFeatureWithData },
global,
})

await nextTick()

const elevationProfile = wrapper.findComponent(ElevationProfile)
elevationProfile.vm.$emit('hover:profile', { x: 10, y: 20 })

expect(profilePositionStore.setPosition).toHaveBeenCalledWith(10, 20)
})
})
22 changes: 22 additions & 0 deletions src/directives/format-measure.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,28 @@ import {
TFormatMeasureType,
} from '@/services/common/formatting.utils'

/**
* Directive for formating to measures of type "elevation", "length", or "area".
*
* Examples of usages:
* - With elevationGain = 200: `<span v-format-measure.elevation>{{ elevationGain }}</span>` => 200
* - With mCounter = 5600987.462 `<span v-format-measure.length="2">{{ mCounter }}</span>` => 5600.98km
* - With lengthValue = 42.6598742 `<span v-format-measure="4">{{ lengthValue }}</span>` => 42.6598m
*
* NB. for unit testings you may encounter a warning saying directive is missing, to fix this,
* this directive must be added to Vue instance when testing: import directing in test file and then add the directive to global plugin
* when mounting/shallowmounting component.
*
* ```
* import formatMeasureDirective from '@/directives/format-measure.directive'
* const wrapper = mount(Mycomponent, {
* props: { ... },
* global: {
* plugins: [ formatMeasureDirective ] // <= add the directive here!
* }
* })
* ```
*/
export default {
install(app: App) {
app.directive('format-measure', format)
Expand Down
125 changes: 124 additions & 1 deletion src/services/common/formatting.utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { formatDate } from './formatting.utils'
import {
formatArea,
formatDate,
formatElevation,
formatLength,
formatMeasure,
} from './formatting.utils'

describe('Formatting utils', () => {
describe('#formatDate', () => {
Expand All @@ -11,4 +17,121 @@ describe('Formatting utils', () => {
expect(date).toEqual('6/8/2016')
})
})

describe('#formatMeasure', () => {
it('formats value as a length (m) by default with 2 digits', () => {
const val = formatMeasure(42.5)
expect(val).toEqual('42.50 m')
})

it('formats value as a length (given in m) n km', () => {
const val = formatMeasure(42000)
expect(val).toEqual('42.00 km')
})

it('formats value as a length with n given digits', () => {
const val = formatMeasure(42000.5698723, 4)
expect(val).toEqual('42.0006 km')
})

it('returns empty string if given value is invalid number', () => {
const val = formatMeasure(<number>(<unknown>'test'), 4)
expect(val).toEqual('')
})

it('formats value as elevation', () => {
const val = formatMeasure(110, undefined, 'elevation')
expect(val).toEqual('110 m')
})

it('formats value as elevation always in meters', () => {
const val = formatMeasure(11000000, undefined, 'elevation')
expect(val).toEqual('11000000 m')
})

it('formats value as elevation with given digits', () => {
const val = formatMeasure(11000000.56, 2, 'elevation')
expect(val).toEqual('11000000.56 m')
})

it('returns original value if given value is invalid number', () => {
const val = formatMeasure(
<number>(<unknown>'wrong elevation'),
4,
'elevation'
)
expect(val).toEqual('wrong elevation')
})
})

describe('#formatElevation', () => {
it('formats value as a elevation (m) by default with no digits', () => {
const val = formatElevation(42.5)
expect(val).toEqual('43 m')
})

it('formats value as a elevation (m) with given digits', () => {
const val = formatElevation(42.5, 2)
expect(val).toEqual('42.50 m')
})

it('returns original value if given value is invalid number', () => {
const val = formatElevation(<number>(<unknown>'wrong elevation'), 2)
expect(val).toEqual('wrong elevation')
})
})

describe('#formatLength', () => {
it('formats value as a distance by default with 2 digits', () => {
const val = formatLength(42.5)
expect(val).toEqual('42.50 m')
})

it('formats value as a distance with no digit', () => {
const val = formatLength(42.5, 0)
expect(val).toEqual('43 m')
})

it('formats value as a distance in m', () => {
const val = formatLength(6, 0)
expect(val).toEqual('6 m')
})

it('formats value as a distance in km', () => {
const val = formatLength(6789456132.35, 5)
expect(val).toEqual('6789456.13235 km')
})

it('returns empty string if given distance is not a valid number', () => {
const val = formatLength(<number>(<unknown>'wrong dist'))
expect(val).toEqual('')
})
})

describe('#formatArea', () => {
it('formats value as an area by default with 2 digits', () => {
const val = formatArea(12)
expect(val).toEqual('12.00 m²')
})

it('formats value as an area by default with no digit', () => {
const val = formatArea(12.5, 0)
expect(val).toEqual('13 m²')
})

it('formats value as an area in m²', () => {
const val = formatArea(6, 0)
expect(val).toEqual('6 m²')
})

it('formats value as an area in km²', () => {
const val = formatArea(6789456132.35, 5)
expect(val).toEqual('6789.45613 km²')
})

it('returns empty string if given area is not a valid number', () => {
const val = formatArea(<number>(<unknown>'wrong area'))
expect(val).toEqual('')
})
})
})
Loading

0 comments on commit ea01eac

Please sign in to comment.