Przeglądaj źródła

Merge branch 'release/1.1.0'

Olivier Massot 3 lat temu
rodzic
commit
f7c2f94ea1

+ 8 - 8
.gitlab-ci.yml

@@ -35,8 +35,8 @@ chrome:
   artifacts:
     when: on_failure
     paths:
-      - test/cypress/videos/**/*.mp4
-      - test/cypress/screenshots/**/*.png
+      - tests/cypress/videos/**/*.mp4
+      - tests/cypress/screenshots/**/*.png
     expire_in: 3 day
 
 chrome-mobile:
@@ -48,8 +48,8 @@ chrome-mobile:
   artifacts:
     when: on_failure
     paths:
-      - test/cypress/videos/**/*.mp4
-      - test/cypress/screenshots/**/*.png
+      - tests/cypress/videos/**/*.mp4
+      - tests/cypress/screenshots/**/*.png
     expire_in: 3 day
 
 firefox:
@@ -61,8 +61,8 @@ firefox:
   artifacts:
     when: on_failure
     paths:
-      - test/cypress/videos/**/*.mp4
-      - test/cypress/screenshots/**/*.png
+      - tests/cypress/videos/**/*.mp4
+      - tests/cypress/screenshots/**/*.png
     expire_in: 3 day
 
 firefox-mobile:
@@ -74,6 +74,6 @@ firefox-mobile:
   artifacts:
     when: on_failure
     paths:
-      - test/cypress/videos/**/*.mp4
-      - test/cypress/screenshots/**/*.png
+      - tests/cypress/videos/**/*.mp4
+      - tests/cypress/screenshots/**/*.png
     expire_in: 3 day

+ 12 - 2
README.md

@@ -27,13 +27,13 @@ Si le fichier .env n'existe pas, on créé un symlink vers le .env.xxx voulu sou
     ln -s .env.xxx .env
 
 Le projet frames n'utilisant pas le SSR, on n'a pas besoin de PM2 pour faire tourner un service.
-On lance la commande:
+On lance la commande :
 
     yarn deploy
 
 > Cette commande est un alias qui équivaut à lancer les commandes suivantes: `git pull && yarn install && yarn build`
 
-S'il n'existe pas encore, il faut aussi créer un fichier dist/.htaccess contenant les lignes suivantes:
+S'il n'existe pas encore, il faut aussi créer un fichier dist/.htaccess contenant les lignes suivantes :
 
     <ifModule mod_rewrite.c>
       RewriteEngine On
@@ -42,6 +42,16 @@ S'il n'existe pas encore, il faut aussi créer un fichier dist/.htaccess contena
       RewriteRule (.*) index.html [QSA,L]
     </ifModule>
 
+## Revenir à une version précédente
+
+Pour revenir à une version précédente:
+
+    git reset --hard <id du commit>
+    yarn build
+
+> **/!\ Non testé: ** Si la version précédente implique des version différentes des node_modules, il faudra sans doute supprimer le 
+> répertoire node_modules et le fichier yarn.lock, et relancer un `yarn install`
+
 ## Run tests
 
 To run unit tests:

+ 9 - 8
components/Ui/Map/Structures.vue

@@ -97,8 +97,8 @@ export default Vue.extend({
   async mounted () {
     const defaultCenter: L.LatLngTuple = [46.71, 1.94]
     const defaultZoom: number = 5.5
-    const layerSource: string = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png'
-    const attribution: string = '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
+    const layerSource: string = 'https://{s}.tile.osm.org/{z}/{x}/{y}.png'
+    const attribution: string = '&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors'
 
     const options: L.MapOptions = { scrollWheelZoom: false, zoomSnap: 0.25 }
 
@@ -133,10 +133,10 @@ export default Vue.extend({
       // populate new layer
       const clusters = L.markerClusterGroup()
       for (const s of this.structures) {
-        if (!s.latitude || !s.longitude) { continue }
+        if (!s.mapAddress || !s.mapAddress.latitude || !s.mapAddress.longitude) { continue }
 
-        const marker = L.marker([s.latitude, s.longitude])
-        marker.bindPopup(`<b>${s.name}</b><br/>${s.postalCode} ${s.addressCity}<br/><a href="${s.website}" target="_blank">${s.website}</a>`)
+        const marker = L.marker([s.mapAddress.latitude, s.mapAddress.longitude])
+        marker.bindPopup(`<b>${s.name}</b><br/>${s.mapAddress.postalCode} ${s.mapAddress.addressCity}<br/><a href="${s.website}" target="_blank">${s.website}</a>`)
         clusters.addLayer(marker)
       }
       this.map.addLayer(clusters)
@@ -167,12 +167,13 @@ export default Vue.extend({
       const coords: L.LatLngBoundsLiteral = this.structures.filter(
         (s: Structure) => {
           return (
-            s.latitude && typeof s.latitude !== 'undefined' &&
-            s.longitude && typeof s.latitude !== 'undefined'
+            s.mapAddress !== null &&
+            s.mapAddress.latitude && typeof s.mapAddress.latitude !== 'undefined' &&
+            s.mapAddress.longitude && typeof s.mapAddress.latitude !== 'undefined'
           )
         }
       ).map(
-        (s: Structure) => { return [s.latitude as number, s.longitude as number] as L.LatLngTuple }
+        (s: Structure) => { return [(s.mapAddress as Address).latitude as number, (s.mapAddress as Address).longitude as number] as L.LatLngTuple }
       )
 
       if (!(coords.length > 0)) {

+ 2 - 2
components/Ui/Search/Address.vue

@@ -91,10 +91,10 @@ export default Vue.extend({
   },
   data () {
     return {
-      model: null as Address | null,
+      model: null as UiSearchAddressItem | null,
       search: null,
       features: [] as Array<Feature>,
-      items: [] as Array<Address>,
+      items: [] as Array<UiSearchAddressItem>,
       loading: false,
       errorMsg: '',
       geolocalized: false

+ 6 - 6
cypress.json

@@ -1,11 +1,11 @@
 {
   "baseUrl": "http://localhost:3004",
-  "fixturesFolder": "test/cypress/fixtures",
-  "integrationFolder": "test/cypress/integration",
-  "pluginsFile": "test/cypress/plugins/index.js",
-  "screenshotsFolder": "test/cypress/screenshots",
-  "supportFile": "test/cypress/support/index.js",
-  "videosFolder": "test/cypress/videos",
+  "fixturesFolder": "tests/cypress/fixtures",
+  "integrationFolder": "tests/cypress/integration",
+  "pluginsFile": "tests/cypress/plugins/index.js",
+  "screenshotsFolder": "tests/cypress/screenshots",
+  "supportFile": "tests/cypress/support/index.js",
+  "videosFolder": "tests/cypress/videos",
   "env": {
     "apiUrl": "http://nginx"
   },

+ 10 - 4
jest.config.js

@@ -3,7 +3,8 @@ module.exports = {
   moduleNameMapper: {
     '^@/(.*)$': '<rootDir>/$1',
     '^~/(.*)$': '<rootDir>/$1',
-    '^vue$': 'vue/dist/vue.common.js'
+    '^vue$': 'vue/dist/vue.common.js',
+    '\\.(css|sass)$': 'identity-obj-proxy'
   },
   moduleFileExtensions: [
     'ts',
@@ -19,8 +20,13 @@ module.exports = {
   collectCoverage: true,
   collectCoverageFrom: [
     '<rootDir>/components/**/*.vue',
-    '<rootDir>/pages/**/*.vue'
+    '<rootDir>/pages/**/*.vue',
+    '<rootDir>/services/**/*.ts'
   ],
-  testEnvironment: 'jsdom',
-  setupFiles: ['<rootDir>/tests/unit/index.ts']
+  setupFiles: ['<rootDir>/tests/unit/jest.setup.ts'],
+  testPathIgnorePatterns: [
+    'node_modules',
+    'tests/cypress'
+  ],
+  testEnvironment: 'jsdom'
 }

+ 1 - 0
lang/fr-FR.js

@@ -34,6 +34,7 @@ export default (_context, _locale) => {
     geolocation_not_supported: 'La géolocalisation n\'est pas supportée par votre navigateur',
     show_tel: 'Montrer le numéro de téléphone',
     show_email: 'Montrer l\'adresse e-mail',
+    see_national_network: 'Voir le réseau national',
     BIG_BAND: 'Big band',
     BRASS_BAND: 'Brass band',
     ORCHESTRA_CLASS: "Classe d'orchestre",

+ 1 - 1
nuxt.config.js

@@ -84,7 +84,7 @@ export default {
     theme: {
       themes: {
         light: {
-          primary: '#0aa5ec'
+          primary: '#e4611b'
         }
       },
       options: {

+ 2 - 0
package.json

@@ -39,6 +39,7 @@
   },
   "devDependencies": {
     "@babel/eslint-parser": "^7.14.7",
+    "@nuxt/test-utils": "^0.2.2",
     "@nuxt/types": "^2.15.7",
     "@nuxt/typescript-build": "^2.1.0",
     "@nuxtjs/eslint-config-typescript": "^6.0.1",
@@ -53,6 +54,7 @@
     "eslint-plugin-cypress": "^2.12.1",
     "eslint-plugin-nuxt": "^2.0.0",
     "eslint-plugin-vue": "^7.12.1",
+    "identity-obj-proxy": "^3.0.0",
     "jest": "^27.0.5",
     "ts-jest": "^27.0.3",
     "vue-jest": "^3.0.4"

+ 25 - 7
pages/structures/_id.vue

@@ -4,7 +4,7 @@
       <v-layout>
         <v-btn
           v-if="parent"
-          :to="{path: '/structures', query: { parent: parent, view: view, theme: theme }}"
+          :to="{path: '/structures', query: { parent: parent, view: view, theme: theme, hideTitle: hideTitle }}"
           nuxt
           plain
         >
@@ -37,6 +37,9 @@
           <a v-if="structure.twitter" :href="structure.twitter" class="twitter" target="_blank" title="$t('find_us_on') + ' Twitter'">
             <font-awesome-icon class="icon social-icon" :icon="['fab', 'twitter']" />
           </a>
+          <a v-if="structure.youtube" :href="structure.youtube" class="youtube" target="_blank" title="$t('find_us_on') + ' Youtube'">
+            <font-awesome-icon class="icon social-icon" :icon="['fab', 'youtube']" />
+          </a>
         </div>
       </v-layout>
 
@@ -74,7 +77,7 @@
           <v-btn
             v-for="article in structure.articles"
             :key="article.id"
-            :href="(article.link.match(/https?:\/\/.*/) ? '' : 'https://') + article.link "
+            :href="article.link ? ((article.link.match(/https?:\/\/.*/) ? '' : 'https://') + article.link) : ''"
             target="_blank"
             small
             color="primary"
@@ -118,14 +121,26 @@
           </div>
 
           <table>
-            <tr>
+            <tr
+              v-if="structure.mapAddress && structure.mapAddress.postalCode !== structure.postalAddress.postalCode && structure.mapAddress.streetAddress !== structure.postalAddress.streetAddress"
+            >
               <td>
                 <font-awesome-icon class="icon" :icon="['fas', 'map-marker-alt']" />
               </td>
               <td class="mx-2">
-                <span v-if="structure.streetAddress">{{ structure.streetAddress }}<br></span>
-                <span v-if="structure.postalCode">{{ structure.postalCode }} </span>
-                {{ structure.addressCity }}
+                <span v-if="structure.mapAddress.streetAddress" style="white-space: pre-line;">{{ structure.mapAddress.streetAddress }}<br></span>
+                <span v-if="structure.mapAddress.postalCode">{{ structure.mapAddress.postalCode }} </span>
+                {{ structure.mapAddress.addressCity }}
+              </td>
+            </tr>
+            <tr v-if="structure.postalAddress">
+              <td>
+                <font-awesome-icon class="icon" :icon="['fas', 'envelope']" />
+              </td>
+              <td class="mx-2">
+                <span v-if="structure.postalAddress.streetAddress" style="white-space: pre-line;">{{ structure.postalAddress.streetAddress }}<br></span>
+                <span v-if="structure.postalAddress.postalCode">{{ structure.postalAddress.postalCode }} </span>
+                {{ structure.postalAddress.addressCity }}
               </td>
             </tr>
             <tr>
@@ -210,7 +225,9 @@
                 >
                   <l-popup>
                     <b>{{ structure.name }}</b><br>
-                    {{ structure.postalCode }} {{ structure.addressCity }}<br>
+                    <span v-if="structure.mapAddress">
+                      {{ structure.mapAddress.postalCode }} {{ structure.mapAddress.addressCity }}
+                    </span><br>
                     <a :href="structure.website" target="_blank">{{ structure.website }}</a>
                   </l-popup>
                 </l-marker>
@@ -242,6 +259,7 @@ export default Vue.extend({
       parent: this.$route.query.parent ? parseInt(this.$route.query.parent as string) : null,
       view: this.$route.query.view ?? 'map',
       theme: this.$route.query.theme ?? 'orange',
+      hideTitle: this.$route.query.hideTitle ?? false,
       showTel: false,
       showMail: false
     }

+ 40 - 19
pages/structures/index.vue

@@ -5,9 +5,10 @@
     <!-- Header -->
     <v-row>
       <v-layout>
-        <h2 class="flex">
+        <h2 v-if="!hideTitle">
           {{ $t("member_companies") }}
         </h2>
+        <div class="flex" />
         <v-btn-toggle mandatory dense :value="mapview ? 0 : 1" @change="viewChanged">
           <v-btn>
             {{ $t("map") }}
@@ -197,7 +198,7 @@
                     outlined
                     :class="'structure-card pa-3 d-flex ' + ((mapview || $vuetify.breakpoint.smAndDown) ? 'flex-column' : 'flex-row align-items-center')"
                   >
-                    <div class="d-flex justify-center max-w100" >
+                    <div class="d-flex justify-center max-w100">
                       <v-img
                         v-if="structure.logoId"
                         :src="'https://api.opentalent.fr/app.php/_internal/secure/files/' + structure.logoId"
@@ -208,11 +209,10 @@
                         :contain="true"
                         style="margin: 12px;"
                       />
-                      <div v-else style="height: 104px; width: 264px"></div>
+                      <div v-else style="height: 104px; width: 264px" />
                     </div>
 
                     <div :class="'d-flex flex-column' + (listview ? ' flex-grow-1' : '')">
-
                       <v-card-title class="title">
                         <nuxt-link :to="{path: '/structures/' + structure.id, query: { parent: parent, view: view, theme: theme }}">
                           {{ structure.name }}
@@ -221,14 +221,14 @@
 
                       <v-card-text class="infos">
                         <table>
-                          <tr>
+                          <tr v-if="structure.mapAddress">
                             <td>
                               <font-awesome-icon class="icon" :icon="['fas', 'map-marker-alt']" />
                             </td>
                             <td>
-                              <span v-if="structure.streetAddress">{{ structure.streetAddress }}<br></span>
-                              <span v-if="structure.postalCode" class="postalCode">{{ structure.postalCode }} </span>
-                              {{ structure.addressCity }}
+                              <span v-if="structure.mapAddress.streetAddress" style="white-space: pre-line;">{{ structure.mapAddress.streetAddress }}<br></span>
+                              <span v-if="structure.mapAddress.postalCode" class="postalCode">{{ structure.mapAddress.postalCode }} </span>
+                              {{ structure.mapAddress.addressCity }}
                             </td>
                           </tr>
                           <tr>
@@ -274,7 +274,7 @@
                     <v-card-actions :class="listview ? 'align-self-end' : 'justify-end'">
                       <v-btn
                         class="see"
-                        :to="{path: '/structures/' + structure.id, query: { parent: parent, view: view, theme: theme }}"
+                        :to="{path: '/structures/' + structure.id, query: { parent: parent, view: view, theme: theme, hideTitle: hideTitle }}"
                         nuxt
                       >
                         <span style="margin-right: 6px;">{{ $t("see_more") }}</span>
@@ -298,6 +298,17 @@
         </div>
       </v-col>
     </v-row>
+    <div class="d-flex w100 justify-center">
+      <v-btn
+        v-if="!parentIsCmf"
+        :href="cmfStructuresPageUrl"
+        target="_blank"
+        class="my-auto ma-4"
+      >
+        <font-awesome-icon :icon="['fas', 'external-link-alt']" class="mr-2" />
+        {{ $t('see_national_network') }}
+      </v-btn>
+    </div>
   </LayoutContainer>
 </template>
 
@@ -310,6 +321,7 @@ import sphericDistance from '@/services/utils/geo'
 import StructuresProvider from '~/services/data/StructuresProvider'
 
 const CMF_ID = 12097
+const CMF_STRUCTURES_PAGE_URL = 'https://www.cmf-musique.org/la-cmf/la-cmf-en-region/cmf-en-region/'
 
 export default Vue.extend({
   validate ({ query }) {
@@ -330,6 +342,7 @@ export default Vue.extend({
       parent: parseInt(this.$route.query.parent as string),
       view: this.$route.query.view ?? 'map',
       theme: this.$route.query.theme ?? 'orange',
+      hideTitle: this.$route.query.hideTitle === 'true',
       structures: [] as Array<Structure>,
       filteredStructures: [] as Array<Structure>,
       federations: [] as Array<{ id: number | null, name: string | null }>,
@@ -371,6 +384,9 @@ export default Vue.extend({
     parentIsCmf (): Boolean {
       return this.parent === CMF_ID
     },
+    cmfStructuresPageUrl (): string {
+      return CMF_STRUCTURES_PAGE_URL
+    },
     onMapFilteredStructures (): Array<Structure> {
       if (this.mapview && this.mapBoundsFilterStarted) {
         return this.filteredStructures.filter((s) => {
@@ -469,12 +485,15 @@ export default Vue.extend({
      */
     matchLocationFilter (structure: Structure): boolean {
       if (!this.locationFilter) { return true }
-      if (!structure.latitude || !structure.longitude) { return false }
+      if (structure.mapAddress === null || !structure.mapAddress.latitude || !structure.mapAddress.longitude) { return false }
 
       const radius = Number(this.distanceFilter) ?? 5
 
       return sphericDistance(
-        this.locationFilter.latitude, this.locationFilter.longitude, structure.latitude, structure.longitude
+        this.locationFilter.latitude,
+        this.locationFilter.longitude,
+        structure.mapAddress.latitude,
+        structure.mapAddress.longitude
       ) <= radius
     },
     /**
@@ -493,10 +512,12 @@ export default Vue.extend({
      */
     matchDepartmentFilter (structure: Structure): boolean {
       if (!this.departmentFilter) { return true }
-      return structure.postalCode !== null &&
+      return structure.mapAddress !== null &&
+        typeof structure.mapAddress.postalCode !== 'undefined' &&
+        structure.mapAddress.postalCode !== null &&
         (
-          structure.postalCode.startsWith(this.departmentFilter) ||
-          (['2A', '2B'].includes(this.departmentFilter) && structure.postalCode.startsWith('20'))
+          structure.mapAddress.postalCode.startsWith(this.departmentFilter) ||
+          (['2A', '2B'].includes(this.departmentFilter) && structure.mapAddress.postalCode.startsWith('20'))
         )
     },
     /**
@@ -515,11 +536,11 @@ export default Vue.extend({
      */
     matchMapBounds (structure: Structure): boolean {
       if (!this.mapBoundsFilter) { return true }
-      if (!(structure.latitude && structure.longitude)) { return false }
-      return this.mapBoundsFilter.getSouth() <= structure.latitude &&
-             structure.latitude <= this.mapBoundsFilter.getNorth() &&
-             this.mapBoundsFilter.getWest() <= structure.longitude &&
-             structure.longitude <= this.mapBoundsFilter.getEast()
+      if (structure.mapAddress === null || !(structure.mapAddress.latitude && structure.mapAddress.longitude)) { return false }
+      return this.mapBoundsFilter.getSouth() <= structure.mapAddress.latitude &&
+             structure.mapAddress.latitude <= this.mapBoundsFilter.getNorth() &&
+             this.mapBoundsFilter.getWest() <= structure.mapAddress.longitude &&
+             structure.mapAddress.longitude <= this.mapBoundsFilter.getEast()
     },
     /**
      * Does the structure match each of the page filters

+ 13 - 0
services/data/StructuresProvider.ts

@@ -8,10 +8,23 @@ class StructuresProvider extends BaseProvider {
     s.n4Id = s.n4Id ? parseInt(s.n4Id) : null
     s.n5Id = s.n5Id ? parseInt(s.n5Id) : null
     s.practices = s.practices ? s.practices.split(',') : []
+    s.addresses = ((s.addresses && s.addresses !== '{}') ? JSON.parse('[' + s.addresses + ']') : []) as Array<Address>
+
+    // Define the on-map address according to the chosen priorities
+    s.mapAddress = s.addresses.find((a: Address) => { return a.type === 'ADDRESS_PRACTICE' }) ||
+                   s.addresses.find((a: Address) => { return a.type === 'ADDRESS_HEAD_OFFICE' }) ||
+                   s.addresses.find((a: Address) => { return a.type === 'ADDRESS_CONTACT' }) ||
+                   null
+    // Define the postal address according to the chosen priorities
+    s.postalAddress = s.addresses.find((a: Address) => { return a.type === 'ADDRESS_CONTACT' }) ||
+                      s.addresses.find((a: Address) => { return a.type === 'ADDRESS_HEAD_OFFICE' }) ||
+                      null
+
     s.latitude = s.latitude ? parseFloat(s.latitude) : null
     s.longitude = s.longitude ? parseFloat(s.longitude) : null
     s.parents = s.parents ? s.parents.split(',').map((i: string) => Number(i)) : []
     s.articles = (s.articles && s.articles !== '{}') ? JSON.parse('[' + s.articles + ']').reverse() : []
+    s.articles.sort((a: Article, b: Article) => { return a.date > b.date ? -1 : 1 })
     return s
   }
 

+ 0 - 10
store/README.md

@@ -1,10 +0,0 @@
-# STORE
-
-**This directory is not required, you can delete it if you don't want to use it.**
-
-This directory contains your Vuex Store files.
-Vuex Store option is implemented in the Nuxt.js framework.
-
-Creating a file in this directory automatically activates the option in the framework.
-
-More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store).

+ 0 - 2
test/cypress/.gitignore

@@ -1,2 +0,0 @@
-/screenshots/
-/videos/

+ 0 - 21
test/unit/component/Ui/Search/Address.spec.js

@@ -1,21 +0,0 @@
-import { mount } from '@vue/test-utils'
-import Vuetify from 'vuetify'
-import Address from '~/components/Ui/Search/Address'
-
-let wrapper
-let vuetify
-beforeEach(() => {
-  vuetify = new Vuetify()
-  wrapper = mount(Address, {
-    vuetify
-  })
-})
-
-describe('components/ui/search/address', () => {
-  it('an input of 1+ cars shall display results', async () => {})
-  it('position shall be set when a result is clicked', async () => {})
-  it('position shall be cleared when input is cleared', async () => {})
-  it('first result shall be selected when enter key is pressed', async () => {})
-  it('user position shall be set when localize icon is clicked', async () => {})
-  it('error message shall be displayed if the browser does not support localization', async () => {})
-})

+ 0 - 6
test/unit/index.ts

@@ -1,6 +0,0 @@
-import Vuex from 'vuex'
-import Vue from 'vue'
-import Vuetify from 'vuetify'
-
-Vue.use(Vuetify)
-Vue.use(Vuex)

+ 0 - 9
test/unit/pages/structures/index.spec.js

@@ -1,9 +0,0 @@
-import Vuetify from 'vuetify'
-
-let vuetify
-beforeEach(() => {
-  vuetify = new Vuetify()
-})
-
-describe('pages/structures/index.vue', () => {
-})

+ 0 - 0
test/cypress/.eslintrc.json → tests/cypress/.eslintrc.json


+ 0 - 0
test/cypress/fixtures/structure-by-id.json → tests/cypress/fixtures/structure-by-id.json


+ 0 - 0
test/cypress/fixtures/structures.json → tests/cypress/fixtures/structures.json


+ 0 - 0
test/cypress/integration/structures/_id.spec.js → tests/cypress/integration/structures/_id.spec.js


+ 2 - 2
test/cypress/integration/structures/index.spec.js → tests/cypress/integration/structures/index.spec.js

@@ -119,7 +119,7 @@ describe('Test the /structures page', () => {
 
   it('The results shall be filtered according to the location filter', () => {
     cy.getByLabel('input:visible', 'Où ?').type('strasbourg')
-    cy.get('.v-list-item__title').contains(/Strasbourg \(\d{5}\)/).click()
+    cy.get('.v-list-item__title').contains(/Strasbourg \(\d{5}\)/, { timeout: 8000 }).click()
     cy.get('button').contains('Rechercher').click()
 
     // we check that there is not a postal code that is not like '67xxx'
@@ -172,7 +172,7 @@ describe('Test the /structures page', () => {
   it('Reinitialize shall clear each filter field, display all results, and reset map bounds (in both map and list view)', () => {
     cy.getByLabel('input', 'Quoi ?').type('some long text that will hopefully match no result')
     cy.getByLabel('input:visible', 'Où ?').type('vesoul')
-    cy.get('.v-list-item div', { timeout: 10000 }).contains(/Vesoul \(\d{5}\)/).click()
+    cy.get('.v-list-item div').contains(/Vesoul \(\d{5}\)/, { timeout: 8000 }).click()
     cy.getByLabel('input:visible', 'Type').click()
     cy.get('.v-list-item').contains('Big band').click()
     cy.getByLabel('input:visible', 'Département').click()

+ 0 - 0
test/cypress/plugins/index.js → tests/cypress/plugins/index.js


+ 0 - 0
test/cypress/support/commands.js → tests/cypress/support/commands.js


+ 0 - 0
test/cypress/support/index.js → tests/cypress/support/index.js


+ 0 - 0
test/cypress/support/leaflet.js → tests/cypress/support/leaflet.js


+ 0 - 0
test/cypress/support/vuetify.js → tests/cypress/support/vuetify.js


+ 0 - 0
test/unit/component/Ui/Map/Structures.spec.js → tests/unit/component/Ui/Map/Structures.spec.js


+ 42 - 0
tests/unit/component/Ui/Search/Address.spec.js

@@ -0,0 +1,42 @@
+import { mount } from '@vue/test-utils'
+import Vuetify from 'vuetify'
+import Address from '~/components/Ui/Search/Address'
+import response from '~/tests/unit/component/Ui/Search/fixtures/response'
+
+global.fetch = jest.fn(() =>
+  Promise.resolve({
+    json: () => Promise.resolve(
+      response
+    )
+  })
+)
+
+let wrapper
+let vuetify
+
+beforeEach(() => {
+  vuetify = new Vuetify()
+  fetch.mockClear()
+})
+
+describe('components/ui/search/address', () => {
+  it('an input of 1+ cars shall display results', async () => {
+    wrapper = mount(Address, {
+      vuetify
+    })
+
+    const addressSearchBar = wrapper.find('.v-autocomplete')
+    // addressSearchBar.element.search = 'paris'
+    // await addressSearchBar.trigger('click')
+    addressSearchBar.find('input[type="text"]').setValue('paris')
+
+    const resultsList = wrapper.find('v-autocomplete__content')
+    expect(resultsList.exists()).toBeTruthy()
+    expect(resultsList.find('div:contains("Paris")').exists()).toBeTruthy()
+  })
+  it('position shall be set when a result is clicked', async () => {})
+  it('position shall be cleared when input is cleared', async () => {})
+  it('first result shall be selected when enter key is pressed', async () => {})
+  it('user position shall be set when localize icon is clicked', async () => {})
+  it('error message shall be displayed if the browser does not support localization', async () => {})
+})

+ 264 - 0
tests/unit/component/Ui/Search/fixtures/response.js

@@ -0,0 +1,264 @@
+
+export default {
+  type: 'FeatureCollection',
+  version: 'draft',
+  features: [
+    {
+      type: 'Feature',
+      geometry: {
+        type: 'Point',
+        coordinates: [
+          2.347,
+          48.859
+        ]
+      },
+      properties: {
+        label: 'Paris',
+        score: 0.9704590909090908,
+        id: '75056',
+        type: 'municipality',
+        name: 'Paris',
+        postcode: '75001',
+        citycode: '75056',
+        x: 652089.7,
+        y: 6862305.26,
+        population: 2190327,
+        city: 'Paris',
+        context: '75, Paris, \u00CEle-de-France',
+        importance: 0.67505
+      }
+    },
+    {
+      type: 'Feature',
+      geometry: {
+        type: 'Point',
+        coordinates: [
+          2.295289,
+          48.841959
+        ]
+      },
+      properties: {
+        label: 'Paris 15e Arrondissement',
+        score: 0.8693736363636363,
+        id: '75115',
+        type: 'municipality',
+        name: 'Paris 15e Arrondissement',
+        postcode: '75015',
+        citycode: '75115',
+        x: 648278.87,
+        y: 6860443.09,
+        population: 233484,
+        city: 'Paris 15e Arrondissement',
+        context: '75, Paris, \u00CEle-de-France',
+        importance: 0.56311
+      }
+    },
+    {
+      type: 'Feature',
+      geometry: {
+        type: 'Point',
+        coordinates: [
+          2.397152,
+          48.863367
+        ]
+      },
+      properties: {
+        label: 'Paris 20e Arrondissement',
+        score: 0.8685690909090908,
+        id: '75120',
+        type: 'municipality',
+        name: 'Paris 20e Arrondissement',
+        postcode: '75020',
+        citycode: '75120',
+        x: 655772.96,
+        y: 6862761.58,
+        population: 195604,
+        city: 'Paris 20e Arrondissement',
+        context: '75, Paris, \u00CEle-de-France',
+        importance: 0.55426
+      }
+    },
+    {
+      type: 'Feature',
+      geometry: {
+        type: 'Point',
+        coordinates: [
+          2.348679,
+          48.892045
+        ]
+      },
+      properties: {
+        label: 'Paris 18e Arrondissement',
+        score: 0.8685563636363636,
+        id: '75118',
+        type: 'municipality',
+        name: 'Paris 18e Arrondissement',
+        postcode: '75018',
+        citycode: '75118',
+        x: 652243.19,
+        y: 6865978.62,
+        population: 195060,
+        city: 'Paris 18e Arrondissement',
+        context: '75, Paris, \u00CEle-de-France',
+        importance: 0.55412
+      }
+    },
+    {
+      type: 'Feature',
+      geometry: {
+        type: 'Point',
+        coordinates: [
+          2.387708,
+          48.887252
+        ]
+      },
+      properties: {
+        label: 'Paris 19e Arrondissement',
+        score: 0.86835,
+        id: '75119',
+        type: 'municipality',
+        name: 'Paris 19e Arrondissement',
+        postcode: '75019',
+        citycode: '75119',
+        x: 655100.72,
+        y: 6865422.77,
+        population: 186393,
+        city: 'Paris 19e Arrondissement',
+        context: '75, Paris, \u00CEle-de-France',
+        importance: 0.55185
+      }
+    },
+    {
+      type: 'Feature',
+      geometry: {
+        type: 'Point',
+        coordinates: [
+          2.365001,
+          48.830193
+        ]
+      },
+      properties: {
+        label: 'Paris 13e Arrondissement',
+        score: 0.868230909090909,
+        id: '75113',
+        type: 'municipality',
+        name: 'Paris 13e Arrondissement',
+        postcode: '75013',
+        citycode: '75113',
+        x: 653384.64,
+        y: 6859091.43,
+        population: 181552,
+        city: 'Paris 13e Arrondissement',
+        context: '75, Paris, \u00CEle-de-France',
+        importance: 0.55054
+      }
+    },
+    {
+      type: 'Feature',
+      geometry: {
+        type: 'Point',
+        coordinates: [
+          2.304844,
+          48.887702
+        ]
+      },
+      properties: {
+        label: 'Paris 17e Arrondissement',
+        score: 0.8678736363636362,
+        id: '75117',
+        type: 'municipality',
+        name: 'Paris 17e Arrondissement',
+        postcode: '75017',
+        citycode: '75117',
+        x: 649024.91,
+        y: 6865523.11,
+        population: 167835,
+        city: 'Paris 17e Arrondissement',
+        context: '75, Paris, \u00CEle-de-France',
+        importance: 0.54661
+      }
+    },
+    {
+      type: 'Feature',
+      geometry: {
+        type: 'Point',
+        coordinates: [
+          2.267032,
+          48.856305
+        ]
+      },
+      properties: {
+        label: 'Paris 16e Arrondissement',
+        score: 0.8678081818181818,
+        id: '75116',
+        type: 'municipality',
+        name: 'Paris 16e Arrondissement',
+        postcode: '75016',
+        citycode: '75116',
+        x: 646219.86,
+        y: 6862057.09,
+        population: 165446,
+        city: 'Paris 16e Arrondissement',
+        context: '75, Paris, \u00CEle-de-France',
+        importance: 0.54589
+      }
+    },
+    {
+      type: 'Feature',
+      geometry: {
+        type: 'Point',
+        coordinates: [
+          2.381844,
+          48.860162
+        ]
+      },
+      properties: {
+        label: 'Paris 11e Arrondissement',
+        score: 0.8672718181818182,
+        id: '75111',
+        type: 'municipality',
+        name: 'Paris 11e Arrondissement',
+        postcode: '75011',
+        citycode: '75111',
+        x: 654647.14,
+        y: 6862413.89,
+        population: 147017,
+        city: 'Paris 11e Arrondissement',
+        context: '75, Paris, \u00CEle-de-France',
+        importance: 0.53999
+      }
+    },
+    {
+      type: 'Feature',
+      geometry: {
+        type: 'Point',
+        coordinates: [
+          2.415411,
+          48.833494
+        ]
+      },
+      properties: {
+        label: 'Paris 12e Arrondissement',
+        score: 0.8670972727272728,
+        id: '75112',
+        type: 'municipality',
+        name: 'Paris 12e Arrondissement',
+        postcode: '75012',
+        citycode: '75112',
+        x: 657087.89,
+        y: 6859429.89,
+        population: 141494,
+        city: 'Paris 12e Arrondissement',
+        context: '75, Paris, \u00CEle-de-France',
+        importance: 0.53807
+      }
+    }
+  ],
+  attribution: 'BAN',
+  licence: 'ETALAB-2.0',
+  query: 'paris',
+  filters: {
+    type: 'municipality'
+  },
+  limit: 10
+}

+ 15 - 0
tests/unit/jest.setup.ts

@@ -0,0 +1,15 @@
+import Vuex from 'vuex'
+import Vue from 'vue'
+import Vuetify from 'vuetify'
+import { config } from '@vue/test-utils'
+
+Vue.config.silent = true
+
+// Mock Nuxt components
+config.stubs['nuxt-link'] = true // string stabs like '<a><slot /></a>' are now depreciated
+config.stubs['no-ssr'] = true
+config.mocks.$t = (i: any) => i
+config.mocks.localePath = (i: any) => i
+
+Vue.use(Vuetify)
+Vue.use(Vuex)

+ 1 - 0
tsconfig.json

@@ -25,6 +25,7 @@
     },
     "types": [
       "@nuxt/types",
+      "@types/jest",
       "@nuxtjs/i18n",
       "nuxt-leaflet",
       "@nuxtjs/axios",

+ 26 - 8
types/interfaces.d.ts

@@ -1,22 +1,40 @@
 /**
  * Structures data as returned by the API and consumed by the structures page
  */
+
+interface Address {
+  type: string,
+  // type: 'ADDRESS_PRACTICE' | 'ADDRESS_OTHER' | 'ADDRESS_HEAD_OFFICE' | 'ADDRESS_CONTACT' | 'ADDRESS_BILL',
+  latitude: number,
+  longitude: number,
+  streetAddress: string,
+  postalCode: string,
+  addressCity: string,
+  country: string
+}
+
+interface Article {
+  id: number,
+  date: string,
+  link: string,
+  title: string
+}
+
 interface Structure {
   readonly id: number,
   name: string,
   logoId: string | null,
   principalType: string | null,
   website: string | null,
-  latitude: number | null,
-  longitude: number | null,
-  streetAddress: string | null,
-  postalCode: string | null,
-  addressCity: string | null,
-  country: string | null,
+  mapAddress: Address | null,
+  postalAddress: Address | null,
+  addresses: Array<Address>,
   telphone: string | null,
   email: string | null,
   facebook: string | null,
   twitter: string | null,
+  instagram: string | null,
+  youtube: string | null,
   practices: Array<string>,
   n1Id: number | null,
   n1Name: string | null,
@@ -27,7 +45,7 @@ interface Structure {
   parents: Array<number>,
   description: string | null,
   imageId: string | null,
-  articles: Array<{id: number, title: string, date: string, link: string}>
+  articles: Array<Article>
 }
 
 interface Coordinates {
@@ -38,7 +56,7 @@ interface Coordinates {
 /**
  * Items of the UiSearchAddress component
  */
-interface Address {
+interface UiSearchAddressItem {
   text: string,
   value: Coordinates,
   disabled?: boolean

Plik diff jest za duży
+ 471 - 338
yarn.lock


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików