76 lines
4.8 KiB
TypeScript
76 lines
4.8 KiB
TypeScript
import AxeBuilder from '@axe-core/playwright'
|
||
import { expect, Page, test } from '@playwright/test'
|
||
|
||
const projects=[
|
||
{id:'project-tv',name:'TV Hub',path:'/home/tv-hub',owner_id:'owner',owner_username:'alice',kind:'local',archived:0,full_access:0,git_available:true,execution_group:'',groups:[]},
|
||
{id:'project-player',name:'Lecteur TV',path:'/home/tv-player',owner_id:'owner',owner_username:'alice',kind:'local',archived:0,full_access:0,git_available:true,execution_group:'',groups:[]},
|
||
{id:'project-remote',name:'Télécommande',path:'/home/tv-remote',owner_id:'owner',owner_username:'alice',kind:'local',archived:0,full_access:0,git_available:true,execution_group:'',groups:[]},
|
||
]
|
||
|
||
async function mockApi(page:Page){
|
||
let groups:any[]=[]
|
||
await page.route('**/api/**',async route=>{
|
||
const request=route.request(),url=new URL(request.url()),path=url.pathname,method=request.method()
|
||
let body:unknown={}
|
||
if(path==='/api/bootstrap')body={setup_required:false,csrf_token:'csrf'}
|
||
else if(path==='/api/auth/me')body={username:'alice',is_admin:true,csrf_token:'csrf'}
|
||
else if(path==='/api/projects'&&url.searchParams.get('archived')==='true')body=[]
|
||
else if(path==='/api/projects')body=projects
|
||
else if(path==='/api/projects/activity')body={running_project_ids:['project-player']}
|
||
else if(path==='/api/application/preferences')body={auto_compact_context:false,interface_type:'dashboard',theme:'dark'}
|
||
else if(path==='/api/duck/preferences')body={enabled:true,reminder_minutes:30}
|
||
else if(path==='/api/activity')body={cards:[],counts:{running:0,waiting:0,review:0},observed_at:'2026-11-12T20:00:00Z'}
|
||
else if(path==='/api/dashboard')body={connected:true,hostname:'NasPi',platform:'Linux',cpu_percent:17,cpu_count:4,ram_percent:42,ram_used:4_000_000_000,ram_total:8_000_000_000,temperature_c:48,disk_percent:55,disk_used:55_000_000_000,disk_total:100_000_000_000,uptime_seconds:86400,active_sessions:1,total_sessions:3,docker:{available:true,version:'27'},codex:{available:true,version:'1'},git:{available:true,version:'2.47'},codex_quota:{available:false}}
|
||
else if(path==='/api/project-groups'&&method==='GET')body=groups
|
||
else if(path==='/api/project-groups'&&method==='POST'){
|
||
const input=request.postDataJSON()
|
||
groups=[{id:'group-tv',key:'tv',owner_id:'owner',owner_username:'alice',name:input.name,description:input.description,member_count:input.project_ids.length,members:projects.filter(item=>input.project_ids.includes(item.id)),updates:[],created_at:'2026-11-12T20:00:00Z',updated_at:'2026-11-12T20:00:00Z'}]
|
||
body=groups[0]
|
||
}else if(path==='/api/search')body=[]
|
||
return route.fulfill({status:200,contentType:'application/json',body:JSON.stringify(body)})
|
||
})
|
||
}
|
||
|
||
test.beforeEach(async({page})=>{
|
||
await mockApi(page)
|
||
await page.goto('/?view=company')
|
||
await expect(page.getByRole('heading',{name:'Qui fait quoi ?'})).toBeVisible()
|
||
})
|
||
|
||
test('crée un groupe à partir de plusieurs projets existants',async({page})=>{
|
||
await page.getByRole('button',{name:'+ Groupe'}).first().click()
|
||
await page.getByLabel('Nom du groupe').fill('TV')
|
||
await page.getByLabel('Objectif commun').fill('Applications qui communiquent avec la télévision.')
|
||
await page.locator('label').filter({hasText:'TV Hub'}).click()
|
||
await page.locator('label').filter({hasText:'Lecteur TV'}).click()
|
||
const requestPromise=page.waitForRequest(request=>request.url().endsWith('/api/project-groups')&&request.method()==='POST')
|
||
await page.getByRole('button',{name:'Créer le groupe'}).click()
|
||
const request=await requestPromise
|
||
expect(request.postDataJSON().project_ids.sort()).toEqual(['project-player','project-tv'])
|
||
await expect(page.locator('.company-groups article>header b').filter({hasText:/^TV$/})).toBeVisible()
|
||
})
|
||
|
||
test('conserve la vue dans l’URL, au retour et au rechargement',async({page})=>{
|
||
await page.getByRole('button',{name:'Projets',exact:true}).click()
|
||
await expect(page).toHaveURL(/view=dashboard/)
|
||
await expect(page.getByRole('heading',{name:'Projets et chefs d’équipe'})).toBeVisible()
|
||
await page.goBack()
|
||
await expect(page).toHaveURL(/view=company/)
|
||
await page.reload()
|
||
await expect(page.getByRole('heading',{name:'Qui fait quoi ?'})).toBeVisible()
|
||
})
|
||
|
||
test('le lanceur est utilisable au clavier et la vue ne présente pas de violation axe sérieuse',async({page})=>{
|
||
await page.keyboard.press('Control+K')
|
||
const dialog=page.getByRole('dialog',{name:'Rechercher et ouvrir'})
|
||
await expect(dialog).toBeVisible()
|
||
await page.keyboard.press('Escape')
|
||
await expect(dialog).toBeHidden()
|
||
const results=await new AxeBuilder({page}).withTags(['wcag2a','wcag2aa','wcag21a','wcag21aa']).analyze()
|
||
expect(results.violations.filter(item=>item.impact==='critical'||item.impact==='serious')).toEqual([])
|
||
})
|
||
|
||
test('capture la vue Organisation de référence',async({page})=>{
|
||
await expect(page).toHaveScreenshot('organisation.png',{fullPage:true})
|
||
})
|