From 599033cb70f8f5cbe3ed67b0fa95ff44cd746d51 Mon Sep 17 00:00:00 2001 From: Thomas Parisot Date: Thu, 21 Mar 2024 15:14:30 +0100 Subject: [PATCH] feat(certification/exploitations): recherche avec tri --- package.json | 1 + src/cartobio-api.js | 13 +- src/components/Certification/TableSort.vue | 49 ++++ src/pages/__fixtures__/search-records.json | 51 ++++ src/pages/__fixtures__/user.json | 14 + .../certification/exploitations/index.test.js | 149 ++++++++++ .../certification/exploitations/index.vue | 270 ++++++++++++++---- vite.config.js | 11 +- 8 files changed, 493 insertions(+), 65 deletions(-) create mode 100644 src/components/Certification/TableSort.vue create mode 100644 src/pages/__fixtures__/search-records.json create mode 100644 src/pages/__fixtures__/user.json create mode 100644 src/pages/certification/exploitations/index.test.js diff --git a/package.json b/package.json index 906ffe5a..afeb8a44 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "src/components/Features/SingleItem*.test.js", "src/components/Features/Table.test.js", "src/components/OperatorSetup/*.test.js", + "src/pages/certification/exploitations/index.test.js", "src/pages/exploitations/\\[numeroBio\\]/index.test.js" ], "rules": { diff --git a/src/cartobio-api.js b/src/cartobio-api.js index 33f88d92..3cfae8b4 100644 --- a/src/cartobio-api.js +++ b/src/cartobio-api.js @@ -28,8 +28,8 @@ export async function getOperatorNcviFeatures ({ evv, numeroBio }) { * @param {string} input * @returns {Promise} */ -export async function searchOperators (input) { - const { data } = await apiClient.post(`/v2/certification/operators/search`, { input }) +export async function searchOperators ({ input, page, sort, order }) { + const { data } = await apiClient.post(`/v2/certification/search`, { input, page, sort, order }) return data } @@ -53,15 +53,6 @@ export async function pacageLookup (pacage) { return data } -/** - * @returns {Promise} - */ -export async function fetchLatestOperators () { - const { data } = await apiClient.get(`/v2/certification/operators/latest`, { timeout: 10000 }) - - return data.operators -} - /** * @param {string} numeroBio diff --git a/src/components/Certification/TableSort.vue b/src/components/Certification/TableSort.vue new file mode 100644 index 00000000..47234baf --- /dev/null +++ b/src/components/Certification/TableSort.vue @@ -0,0 +1,49 @@ + + + + + diff --git a/src/pages/__fixtures__/search-records.json b/src/pages/__fixtures__/search-records.json new file mode 100644 index 00000000..c8eb0450 --- /dev/null +++ b/src/pages/__fixtures__/search-records.json @@ -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" + } +] diff --git a/src/pages/__fixtures__/user.json b/src/pages/__fixtures__/user.json new file mode 100644 index 00000000..5af81ae0 --- /dev/null +++ b/src/pages/__fixtures__/user.json @@ -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"} +} diff --git a/src/pages/certification/exploitations/index.test.js b/src/pages/certification/exploitations/index.test.js new file mode 100644 index 00000000..6b692c44 --- /dev/null +++ b/src/pages/certification/exploitations/index.test.js @@ -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') + } + } + } + }) + }) +}) diff --git a/src/pages/certification/exploitations/index.vue b/src/pages/certification/exploitations/index.vue index 725379ee..7c4bcfca 100644 --- a/src/pages/certification/exploitations/index.vue +++ b/src/pages/certification/exploitations/index.vue @@ -11,54 +11,102 @@ meta:

Exploitations {{ user.organismeCertificateur.nom }}

-
-
-

Dernières exploitations modifiées

+
- + - + + - - - + + + + - + + + + + + + + + + - + + + + + + + +
ExploitationDate de début de conversionStatutExploitationDébut de conversionDate de l'auditStatut
+ Chargement des données… +
+ +
+ +
{{ searchRecords.length }} sur {{ pagination.total }} résultats +
    +
  • +
    + + +
    +
  • +
  • +
  • +
+
- Revenir aux exploitations -

@@ -67,78 +115,194 @@ meta: de l'Agence Bio.

- - - -