app.js : 100% lignes, 100% fonctions, 99.5% statements - 3 tests prefill branches (fetch error, missing fields, hosting no fetch) entreprise-search.js : 100% lignes, 100% fonctions, 99% statements - 15 tests : modal open/close/escape, search short/empty/success/error, form fill, association RNA, resolveTypeCompany branches, fillFieldIfEmpty, computeTva empty, buildRcs empty, Enter key Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
392 lines
17 KiB
JavaScript
392 lines
17 KiB
JavaScript
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
import { initEntrepriseSearch } from '../../assets/modules/entreprise-search.js'
|
|
|
|
describe('entreprise-search.js', () => {
|
|
beforeEach(() => {
|
|
document.body.innerHTML = ''
|
|
vi.restoreAllMocks()
|
|
})
|
|
|
|
it('does nothing without modal or openBtn', () => {
|
|
document.body.innerHTML = '<div></div>'
|
|
initEntrepriseSearch()
|
|
expect(true).toBe(true)
|
|
})
|
|
|
|
it('opens modal on openBtn click', () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise" class="hidden"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
`
|
|
initEntrepriseSearch()
|
|
document.getElementById('btn-search-entreprise').click()
|
|
expect(document.getElementById('modal-entreprise').classList.contains('hidden')).toBe(false)
|
|
})
|
|
|
|
it('closes modal on closeBtn click', () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
`
|
|
initEntrepriseSearch()
|
|
document.getElementById('modal-close').click()
|
|
expect(document.getElementById('modal-entreprise').classList.contains('hidden')).toBe(true)
|
|
})
|
|
|
|
it('closes modal on overlay click', () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
`
|
|
initEntrepriseSearch()
|
|
document.getElementById('modal-overlay').click()
|
|
expect(document.getElementById('modal-entreprise').classList.contains('hidden')).toBe(true)
|
|
})
|
|
|
|
it('closes modal on Escape key', () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
`
|
|
initEntrepriseSearch()
|
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))
|
|
expect(document.getElementById('modal-entreprise').classList.contains('hidden')).toBe(true)
|
|
})
|
|
|
|
it('does not search when query is too short', async () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input" value="a">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
`
|
|
globalThis.fetch = vi.fn()
|
|
initEntrepriseSearch()
|
|
document.getElementById('search-entreprise-btn').click()
|
|
await new Promise(r => setTimeout(r, 100))
|
|
expect(globalThis.fetch).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('shows no results message', async () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input" value="zzzzz">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
`
|
|
globalThis.fetch = vi.fn(() => Promise.resolve({ json: () => Promise.resolve({ results: [], total_results: 0 }) }))
|
|
initEntrepriseSearch()
|
|
document.getElementById('search-entreprise-btn').click()
|
|
await new Promise(r => setTimeout(r, 100))
|
|
expect(document.getElementById('search-entreprise-status').textContent).toContain('Aucun resultat')
|
|
})
|
|
|
|
it('shows results and fills form on click', async () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input" value="acme">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
<input id="raisonSociale">
|
|
<input id="siret">
|
|
<input id="rcs">
|
|
<input id="numTva">
|
|
<input id="ape">
|
|
<input id="address">
|
|
<input id="zipCode">
|
|
<input id="city">
|
|
<input id="geoLat">
|
|
<input id="geoLong">
|
|
<input id="typeCompany">
|
|
<input id="rna">
|
|
<input id="firstName">
|
|
<input id="lastName">
|
|
`
|
|
globalThis.fetch = vi.fn(() => Promise.resolve({
|
|
json: () => Promise.resolve({
|
|
results: [{
|
|
nom_raison_sociale: 'ACME SA',
|
|
nom_complet: 'ACME SA COMPLETE',
|
|
siren: '123456789',
|
|
etat_administratif: 'A',
|
|
activite_principale: '6201Z',
|
|
nature_juridique: '5710',
|
|
siege: {
|
|
siret: '12345678901234',
|
|
numero_voie: '42',
|
|
type_voie: 'rue',
|
|
libelle_voie: 'de la Paix',
|
|
code_postal: '75001',
|
|
libelle_commune: 'Paris',
|
|
geo_adresse: '42 rue de la Paix 75001 Paris',
|
|
latitude: '48.8',
|
|
longitude: '2.3',
|
|
},
|
|
dirigeants: [{ nom: 'DUPONT', prenoms: 'Jean Pierre' }],
|
|
complements: { identifiant_association: '' },
|
|
}],
|
|
total_results: 1,
|
|
})
|
|
}))
|
|
initEntrepriseSearch()
|
|
document.getElementById('search-entreprise-btn').click()
|
|
await new Promise(r => setTimeout(r, 100))
|
|
|
|
const status = document.getElementById('search-entreprise-status')
|
|
expect(status.textContent).toContain('1 resultat(s)')
|
|
|
|
const results = document.getElementById('search-entreprise-results')
|
|
expect(results.innerHTML).toContain('ACME SA')
|
|
expect(results.innerHTML).toContain('Actif')
|
|
|
|
// Click to fill form
|
|
results.querySelector('div').click()
|
|
expect(document.getElementById('raisonSociale').value).toBe('ACME SA')
|
|
expect(document.getElementById('siret').value).toBe('12345678901234')
|
|
expect(document.getElementById('numTva').value).toContain('FR')
|
|
expect(document.getElementById('ape').value).toBe('6201Z')
|
|
expect(document.getElementById('address').value).toBe('42 rue de la Paix')
|
|
expect(document.getElementById('zipCode').value).toBe('75001')
|
|
expect(document.getElementById('city').value).toBe('Paris')
|
|
expect(document.getElementById('typeCompany').value).toBe('sas')
|
|
expect(document.getElementById('firstName').value).toBe('Jean')
|
|
expect(document.getElementById('lastName').value).toBe('Dupont')
|
|
})
|
|
|
|
it('handles association type with RNA', async () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input" value="asso">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
<input id="raisonSociale">
|
|
<input id="typeCompany">
|
|
<input id="rna">
|
|
`
|
|
globalThis.fetch = vi.fn(() => Promise.resolve({
|
|
json: () => Promise.resolve({
|
|
results: [{
|
|
nom_complet: 'Asso Test',
|
|
siren: '999888777',
|
|
etat_administratif: 'C',
|
|
nature_juridique: '9220',
|
|
siege: {},
|
|
complements: { identifiant_association: 'W123456789' },
|
|
}],
|
|
total_results: 1,
|
|
})
|
|
}))
|
|
initEntrepriseSearch()
|
|
document.getElementById('search-entreprise-btn').click()
|
|
await new Promise(r => setTimeout(r, 100))
|
|
|
|
const results = document.getElementById('search-entreprise-results')
|
|
expect(results.innerHTML).toContain('Association')
|
|
expect(results.innerHTML).toContain('Ferme')
|
|
expect(results.innerHTML).toContain('W123456789')
|
|
|
|
results.querySelector('div').click()
|
|
expect(document.getElementById('rna').value).toBe('W123456789')
|
|
expect(document.getElementById('typeCompany').value).toBe('association')
|
|
})
|
|
|
|
it('handles fetch error', async () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input" value="fail">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
`
|
|
globalThis.fetch = vi.fn(() => Promise.reject(new Error('Network fail')))
|
|
initEntrepriseSearch()
|
|
document.getElementById('search-entreprise-btn').click()
|
|
await new Promise(r => setTimeout(r, 100))
|
|
expect(document.getElementById('search-entreprise-status').textContent).toContain('Erreur')
|
|
})
|
|
|
|
it('Enter key triggers search', async () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input" value="test">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
`
|
|
globalThis.fetch = vi.fn(() => Promise.resolve({ json: () => Promise.resolve({ results: [], total_results: 0 }) }))
|
|
initEntrepriseSearch()
|
|
document.getElementById('search-entreprise-input').dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }))
|
|
await new Promise(r => setTimeout(r, 100))
|
|
expect(globalThis.fetch).toHaveBeenCalled()
|
|
})
|
|
|
|
it('covers resolveTypeCompany branches', async () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input" value="multi">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
<input id="typeCompany">
|
|
`
|
|
const types = [
|
|
{ code: '1000', expected: 'auto-entrepreneur' },
|
|
{ code: '5400', expected: 'sarl' },
|
|
{ code: '5599', expected: 'sarl' }, // 55xx matches sarl before sa check
|
|
{ code: '5200', expected: 'eurl' },
|
|
{ code: '6500', expected: 'sci' },
|
|
{ code: '9999', expected: '' },
|
|
]
|
|
|
|
for (const { code, expected } of types) {
|
|
globalThis.fetch = vi.fn(() => Promise.resolve({
|
|
json: () => Promise.resolve({
|
|
results: [{ nom_complet: 'Test', siren: '111', nature_juridique: code, siege: {} }],
|
|
total_results: 1,
|
|
})
|
|
}))
|
|
initEntrepriseSearch()
|
|
document.getElementById('search-entreprise-btn').click()
|
|
await new Promise(r => setTimeout(r, 100))
|
|
|
|
const results = document.getElementById('search-entreprise-results')
|
|
results.querySelector('div').click()
|
|
|
|
const typeVal = document.getElementById('typeCompany').value
|
|
if (expected) {
|
|
expect(typeVal).toBe(expected)
|
|
}
|
|
document.getElementById('typeCompany').value = ''
|
|
}
|
|
})
|
|
|
|
it('fillFieldIfEmpty does not overwrite existing value', async () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input" value="pre">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
<input id="firstName" value="Existing">
|
|
<input id="lastName">
|
|
`
|
|
globalThis.fetch = vi.fn(() => Promise.resolve({
|
|
json: () => Promise.resolve({
|
|
results: [{ nom_complet: 'Test', siren: '111', siege: {}, dirigeants: [{ nom: 'NEW', prenoms: 'Name' }] }],
|
|
total_results: 1,
|
|
})
|
|
}))
|
|
initEntrepriseSearch()
|
|
document.getElementById('search-entreprise-btn').click()
|
|
await new Promise(r => setTimeout(r, 100))
|
|
|
|
document.getElementById('search-entreprise-results').querySelector('div').click()
|
|
expect(document.getElementById('firstName').value).toBe('Existing')
|
|
expect(document.getElementById('lastName').value).toBe('New')
|
|
})
|
|
|
|
it('computeTva returns empty for falsy siren', async () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input" value="no-siren">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
<input id="numTva">
|
|
`
|
|
globalThis.fetch = vi.fn(() => Promise.resolve({
|
|
json: () => Promise.resolve({
|
|
results: [{ nom_complet: 'No Siren', siege: {} }],
|
|
total_results: 1,
|
|
})
|
|
}))
|
|
initEntrepriseSearch()
|
|
document.getElementById('search-entreprise-btn').click()
|
|
await new Promise(r => setTimeout(r, 100))
|
|
|
|
document.getElementById('search-entreprise-results').querySelector('div').click()
|
|
expect(document.getElementById('numTva').value).toBe('')
|
|
})
|
|
|
|
it('buildRcs returns empty when no siren or city', async () => {
|
|
document.body.innerHTML = `
|
|
<div id="modal-entreprise"></div>
|
|
<div id="modal-overlay"></div>
|
|
<button id="modal-close"></button>
|
|
<button id="btn-search-entreprise"></button>
|
|
<input id="search-entreprise-input" value="norcs">
|
|
<button id="search-entreprise-btn"></button>
|
|
<div id="search-entreprise-results"></div>
|
|
<div id="search-entreprise-status" class="hidden"></div>
|
|
<input id="rcs">
|
|
`
|
|
globalThis.fetch = vi.fn(() => Promise.resolve({
|
|
json: () => Promise.resolve({
|
|
results: [{ nom_complet: 'No RCS', siege: {} }],
|
|
total_results: 1,
|
|
})
|
|
}))
|
|
initEntrepriseSearch()
|
|
document.getElementById('search-entreprise-btn').click()
|
|
await new Promise(r => setTimeout(r, 100))
|
|
|
|
document.getElementById('search-entreprise-results').querySelector('div').click()
|
|
expect(document.getElementById('rcs').value).toBe('')
|
|
})
|
|
})
|