-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(certification/exploitations): recherche avec tri
- Loading branch information
1 parent
1f0bc45
commit 599033c
Showing
8 changed files
with
493 additions
and
65 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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<template> | ||
<label v-if="$slots.default" :for="id"> | ||
<slot name="default" /> | ||
</label> | ||
|
||
<button v-if="showControl" type="button" :aria-pressed="isAscending || isDescending" :id="id" class="fr-btn fr-btn--tertiary-no-outline" @click="emit('update:modelValue', { sort: code, order: !isAscending ? 'asc' : 'desc' })"> | ||
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 0L13 6H1L7 0Z" :fill="isAscending ? '#000091' : '#929292'"/> | ||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 16L1 10L13 10L7 16Z" :fill="isDescending ? '#000091' : '#929292'"/> | ||
</svg> | ||
</button> | ||
</template> | ||
|
||
<script setup> | ||
import { computed } from 'vue' | ||
const emit = defineEmits(['update:modelValue']) | ||
const props = defineProps({ | ||
code: { | ||
type: String, | ||
required: true | ||
}, | ||
modelValue: { | ||
type: Object, | ||
required: true | ||
}, | ||
showControl: { | ||
type: Boolean, | ||
default : true | ||
} | ||
}) | ||
const isAscending = computed(() => props.modelValue.sort === props.code && props.modelValue.order === 'asc') | ||
const isDescending = computed(() => props.modelValue.sort === props.code && props.modelValue.order === 'desc') | ||
const id = computed(() => `sort-order-${props.code}`) | ||
</script> | ||
|
||
<style scoped> | ||
label, | ||
button { | ||
cursor: pointer; | ||
vertical-align: middle; | ||
} | ||
button { | ||
padding: .5rem; | ||
} | ||
</style> |
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,51 @@ | ||
[ | ||
{ | ||
"commune": "Crest", | ||
"codePostal": "26400", | ||
"numeroBio": 1, | ||
"nom": "opérateur 1", | ||
"dateEngagement": null, | ||
"record_id": null, | ||
"audit_date": null, | ||
"certification_date_debut": null, | ||
"certification_date_fin": null, | ||
"certification_state": null | ||
}, | ||
{ | ||
"commune": "Crest", | ||
"codePostal": "26400", | ||
"numeroBio": 2, | ||
"nom": "opérateur 2", | ||
"dateEngagement": null, | ||
"record_id": null, | ||
"audit_date": null, | ||
"certification_date_debut": null, | ||
"certification_date_fin": null, | ||
"certification_state": null | ||
}, | ||
|
||
{ | ||
"commune": "Die", | ||
"codePostal": "26150", | ||
"numeroBio": 3, | ||
"nom": "opérateur 3", | ||
"dateEngagement": "2020-02-02", | ||
"record_id": "a-b-c-d", | ||
"audit_date": null, | ||
"certification_date_debut": null, | ||
"certification_date_fin": null, | ||
"certification_state": "OPERATOR_DRAFT" | ||
}, | ||
{ | ||
"commune": "Die", | ||
"codePostal": "26150", | ||
"numeroBio": 4, | ||
"nom": "opérateur 4", | ||
"dateEngagement": "2020-02-02", | ||
"record_id": "e-f-g-h", | ||
"audit_date": "2024-01-01", | ||
"certification_date_debut": "2024-01-01", | ||
"certification_date_fin": "2024-03-31", | ||
"certification_state": "CERTIFIED" | ||
} | ||
] |
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,14 @@ | ||
{ | ||
"id": 1, | ||
"prenom": "Test", | ||
"nom": "Utilisateur", | ||
"organismeCertificateur": { | ||
"id": 999, | ||
"nom": "CartobiOC", | ||
"numeroControleEu": "FR-BIO-999" | ||
}, | ||
"groups": [ | ||
{ "nom": "Auditeur"} | ||
], | ||
"mainGroup": {"nom": "Auditeur"} | ||
} |
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,149 @@ | ||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest" | ||
import { flushPromises, mount } from "@vue/test-utils" | ||
import { createTestingPinia } from "@pinia/testing" | ||
import axios, { AxiosError } from 'axios' | ||
|
||
import { useUserStore } from '@/stores/index.js' | ||
|
||
import records from '../../__fixtures__/search-records.json' assert { type: 'json' } | ||
import userFixture from '../../__fixtures__/user.json' assert { type: 'json' } | ||
|
||
import Page from './index.vue' | ||
|
||
const pinia = createTestingPinia({ createSpy: vi.fn, stubActions: false }) | ||
const user = useUserStore(pinia) | ||
|
||
beforeEach(() => user.user = userFixture) | ||
afterEach(() => user.$reset()) | ||
|
||
describe("certification/exploitations", () => { | ||
it("should display a page with a warning because of no results", async () => { | ||
axios.__createMock.post.mockResolvedValueOnce({ | ||
data: { | ||
pagination: { | ||
total: 0, | ||
page: 1, | ||
page_max: 1 | ||
}, | ||
records: [] | ||
} | ||
}) | ||
|
||
const wrapper = mount(Page) | ||
|
||
expect(wrapper.find('tbody').text()).toContain('Chargement des données…') | ||
|
||
await flushPromises() | ||
expect(wrapper.find('.fr-alert__title').text()).toContain('Aucune exploitation trouvée') | ||
}) | ||
|
||
it("should display a page with 2 results and 2 pages", async () => { | ||
axios.__createMock.post.mockResolvedValueOnce({ | ||
data: { | ||
pagination: { | ||
total: 4, | ||
page: 1, | ||
page_max: 2 | ||
}, | ||
records: records.slice(0, 2) | ||
} | ||
}) | ||
|
||
const wrapper = mount(Page) | ||
|
||
await flushPromises() | ||
expect(axios.__createMock.post).toHaveBeenCalled(1) | ||
expect(wrapper.findAll('.operator-record')).toHaveLength(2) | ||
expect(wrapper.find('.results-total').text()).toEqual('2 sur 4 résultats') | ||
expect(wrapper.find('.pagination-page-previous').attributes('disabled')).toEqual('') | ||
expect(wrapper.find('.pagination-page-next').attributes('disabled')).toBeUndefined() | ||
|
||
// navigate to next page | ||
axios.__createMock.post.mockResolvedValue({ | ||
data: { | ||
pagination: { | ||
total: 4, | ||
page: 2, | ||
page_max: 2 | ||
}, | ||
records: records.slice(2, 4) | ||
} | ||
}) | ||
|
||
await wrapper.find('.pagination-page-next').trigger('click') | ||
await wrapper.setProps({ page: '2' }) // workaround vue-router not picking up above change | ||
await flushPromises() | ||
|
||
expect(axios.__createMock.post).toHaveBeenCalled(2) | ||
expect(wrapper.find('.pagination-page-previous').attributes('disabled')).toBeUndefined() | ||
expect(wrapper.find('.pagination-page-next').attributes('disabled')).toEqual('') | ||
|
||
await wrapper.find('#search-results-page-selector').setValue('1') | ||
wrapper.setProps({ page: '1' }) // workaround vue-router not picking up above change | ||
expect(wrapper.emitted()).toHaveProperty('change') | ||
await flushPromises() | ||
expect(axios.__createMock.post).toHaveBeenCalled(3) | ||
}) | ||
|
||
it("should search, sort then reset filters", async () => { | ||
axios.__createMock.post.mockResolvedValue({ | ||
data: { | ||
pagination: { | ||
total: 4, | ||
page: 1, | ||
page_max: 1 | ||
}, | ||
records | ||
} | ||
}) | ||
|
||
const wrapper = mount(Page, { | ||
props: { search: 'ferme', page: '2', sort: 'nom', order: 'asc' } | ||
}) | ||
|
||
await flushPromises() | ||
expect(wrapper.findAll('.operator-record')).toHaveLength(4) | ||
expect(wrapper.findAll('thead [aria-sort]')).toHaveLength(1) | ||
expect(wrapper.find('.table-header-nom').attributes()).toHaveProperty('aria-sort', 'ascending') | ||
expect(wrapper.find('.table-header-nom button').attributes()).toHaveProperty('aria-pressed', 'true') | ||
|
||
// // change search to nothing | ||
// // it should reset the filters | ||
await wrapper.find('#search-input').setValue('') | ||
await wrapper.find('form').trigger('submit') | ||
|
||
// todo: rather test against a router that works in tests, outside of components | ||
await wrapper.setProps({ search: '', page: '1' }) | ||
await flushPromises() | ||
|
||
expect(axios.__createMock.post).toHaveBeenLastCalledWith('/v2/certification/search', { input: '', page: 1, sort: 'audit_date', order: 'desc' }) | ||
expect(wrapper.find('.table-header-audit_date').attributes()).toHaveProperty('aria-sort', 'descending') | ||
expect(wrapper.find('.table-header-audit_date button').attributes()).toHaveProperty('aria-pressed', 'true') | ||
}) | ||
|
||
it('should respond with an error in case server is unreachable', async () => { | ||
const error = new AxiosError('Network Error', 'ERR_NETWORK') | ||
axios.__createMock.post.mockRejectedValueOnce(error) | ||
|
||
const wrapper = mount(Page) | ||
await flushPromises() | ||
|
||
expect(wrapper.find('tbody').text()).toContain('Une erreur de réseau est survenue') | ||
}) | ||
|
||
it('should throw an error when uncaught', () => { | ||
const error = new AxiosError('Server is down') | ||
error.response = { status: 500 } | ||
axios.__createMock.post.mockRejectedValueOnce(error) | ||
|
||
const wrapper = mount(Page, { | ||
global: { | ||
config: { | ||
errorHandler (error) { | ||
expect(error.message).toBe('Server is down') | ||
} | ||
} | ||
} | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.