Developer/ CEO / Founder @ Digital Tack
Mail: david@digitaltack.com
Accessibility is the design of products, devices, services, vehicles, or environments so as to be usable by people with disabilities.
Disability is the experience of any condition that makes it more difficult for a person to do certain activities or have equitable access within a given society.
An estimated 1.3 billion people – about 16% of the global population – currently experience significant disability.
The 2024 report on the accessibility of the top 1,000,000 home pages
From 2016, mandatory for all the websites of the public sector.
From the 28th of June of 2025, mandatory for all websites, apps and products from companies with more than 10 employees or more than 2 million € of annual balance.
import { describe, expect, it } from 'vitest'
import { render, screen } from '@testing-library/vue'
import Button from '@/infrastructure/components/Button.vue'
import { ButtonColor } from '@/infrastructure/types/Button'
describe('A button', () => {
it('is rendered', () => {
const options = {
slots: {
default: 'Add to cart'
}
}
render(Button, options)
const button = screen.getByText('Add to cart')
expect(button).toBeTruthy()
})
})
import { describe, expect, it } from 'vitest'
import { render, screen } from '@testing-library/vue'
import Button from '@/infrastructure/components/Button.vue'
import { ButtonColor } from '@/infrastructure/types/Button'
describe('A button', () => {
it('is rendered', () => {
const options = {
slots: {
default: 'Add to cart'
}
}
render(Button, options)
const button = screen.getByRole('button')
expect(button).toBeTruthy()
})
})
Semantic HTML is the use of HTML markup to reinforce the semantics, or meaning, of the information in web pages and web applications rather than merely to define its presentation or look.
Many semantic elements in HTML have a role; for example, <input type="radio"> has the "radio" role.
Non-semantic elements in HTML do not have a role
The role attribute can provide semantics
A contrast ratio of 3:1 is the minimum level recommended
The contrast ratio of 4.5:1 was chosen for level AA
The contrast ratio of 7:1 was chosen for level AAA
test.describe('contrast checkers', () => {
test('can check the contrast of an element', async ({ page }) => {
const contrastChecker = new ColorContrastChecker()
await page.goto('http://localhost:8000')
const title = page.getByText('Products')
await expect(title).toBeVisible()
const style = await title.evaluate((title) => {
return window.getComputedStyle(title)
})
const bgColor = rgbaToHex(style['backgroundColor'])
const color = rgbaToHex(style['color'])
const fontSize = parseInt(style['fontSize'])
expect(contrastChecker.isLevelAA(bgColor, color, fontSize)).toBeTruthy()
})
})
describe('An image', () => {
it('has an alternative text', () => {
const fakeImage: TImage = {
sizes: {
small: 'test.jpg',
},
alt: 'Alt text'
}
const props = {
image: fakeImage,
size: ImageSize.small
}
render(Image, { props })
const image = screen.getByRole('img')
expect(image.getAttribute('alt')).toBe(fakeImage.alt)
})
})
<label for="input">Input Label</label>
<input id="input" />
<label>Input Label<input /></label>
<input aria-label="Input Label" />
<span id="label">Input Label</span>
<input aria-labelledby="label" />
describe('A text input', () => {
it('has a label', () => {
const options = {
props: {
name: 'search',
label: 'Search',
placeholder: 'Search for a product'
}
}
render(TextInput, options)
const input = screen.getByLabelText(options.props.label)
expect(input).toBeTruthy()
})
})
<a href="/"><i class="fa fa-home" /></a>
describe('The menu', () => {
it('has a link to the home page', () => {
const options = {
global: {
plugins: [router]
}
}
render(Menu, options)
const link = screen.getByRole('link', { name: 'Home' })
expect(link).toBeTruthy()
})
})
<button><i class="fa fa-magnifying-glass" /></button>
describe('A button', () => {
it('has is not empty', () => {
const options = {
slots: {
default: 'Add to cart'
}
}
render(Button, options)
const button = screen.getByRole('button', { name: 'Add to cart' })
expect(button).toBeTruthy()
})
})
describe('A button', () => {
it('has a label', () => {
const options = {
slots: {
default: 'Add to cart'
},
props: {
ariaLabel: 'Add pineapple to cart'
}
}
render(Button, options)
const button = screen.getByRole('button', { label: options.props.ariaLabel })
expect(button).toBeTruthy()
})
})
import { expect, test } from "@playwright/test";
test.describe('site language', () => {
test('is configured', async ({ page }) => {
await page.goto('http://localhost:8000')
const title = page.getByText('Products')
await expect(title).toBeVisible()
const content = await page.content()
expect(content).toContain('<html lang="en">')
})
})
describe('A search form', () => {
it('can search', () => {
render(SearchForm)
const input = screen.getByLabelText('Search product')
const button = screen.getByText('Search')
input.focus()
fireEvent.change(input, { target: { value: 'Pineapple' }})
fireEvent.keyPress(input, { key: 'Enter', code: 13, charCode: 13 })
const pineappleButton = await screen.getByText('Add Pineapple to cart')
expect(pineappleButton.isVisible()).toBeTruthy()
const melonButton = await screen.getByText('Add Melon to cart')
expect(melonButton.isVisible()).toBeFalsy()
})
})