Accessibility Testing with Google Lighthouse

Using Google Lighthouse to provide accessibility testing.

Accessibility reports are crucial when testing web pages because they help to ensure that a site is usable for people of all abilities. That is why we introduced Google Lighthouse to Neodymium, an open-source tool to improve the quality of web pages.

Install Lighthouse CLI

First, it is recommended to install a package manager like npm, which will be used to install Lighthouse CLI. After installing npm, open a terminal and enter the command below.

npm install -g lighthouse

To make sure the Lighthouse installation was successful, you can run the following command.

lighthouse --version

Use Lighthouse Inside Neodymium

To create Lighthouse reports inside Neodymium, the class LighthouseUtils is used, containing the function createLightHouseReport(String reportName). By calling this function, a Lighthouse report of the current web page is generated and automatically added to the Allure report with the name specified in the reportName parameter. Note that creating a Lighthouse report only works while using Chrome or Chromium-based browsers.

The method call can be added at every point of your test and will create a report of the currently opened page. This also works for pages, which rely on session data like a login state or products that should have been added to a shopping cart. Keep in mind that it may not work on certain pages that, if refreshed, load a different page, like checkout pages for example.

Here is an example how to add createLightHouseReport() inside a test case:


@NeodymiumTest
public void testLoginAsRegisteredUser() throws Exception
{
    // go to homepage
    var homePage = OpenHomePageFlow.flow();
    LighthouseUtils.createLightHouseReport("Homepage");

    // go to register page
    var registerPage = homePage.header.userMenu.openRegisterPage();

    // send register form
    var loginPage = registerPage.sendRegisterForm(registeredOrderTestData.getUser());

    // send login form
    var accountOverviewPage = loginPage.sendLoginForm(registeredOrderTestData.getUser());
    accountOverviewPage.validateSuccessfulLogin(registeredOrderTestData.getUser().getFirstName());

    LighthouseUtils.createLightHouseReport("Account Overview Page");
}

Please note that this example uses page object model classes which are not shipped with neodymium.

Limitations

Please note, that Lighthouse does not work with modals, fly-ins, hover etc. The site will be newly loaded for the report, so every manually opened modal will be closed after a Lighthouse report. This needs to be considered when generating reports and might require changes to the test flow (e.g. if a modal is open which contains the next button the scripts wants to click).

Lighthouse Reports

The generated Lighthouse reports can be found in the target directory of the user’s repository and in the Allure report as an attachment, visualized in the following image.

Lighthouse report inside an Allure report.

A Lighthouse report consists of the following four categories.

  1. Performance
  2. Accessibility
  3. Best Practices
  4. Search Engine Optimisation (SEO)

Each of those categories is scored between 1 and 100, which reveals how well the web page performed in every category. Therefore, Google defines the following ranges.

  • 0 to 49: Poor
  • 50 to 89: Needs Improvement
  • 90 to 100: Good

Lighthouse Report Validation

This section is about how to assert metrics from the Lighthouse report.

Lighthouse Category Score Validation

To enable validating the scores of all four categories, we implemented the following score thresholds in the neodymium.properties file.

  • neodymium.lighthouse.assert.thresholdScore.performance
  • neodymium.lighthouse.assert.thresholdScore.accessibility
  • neodymium.lighthouse.assert.thresholdScore.bestPractices
  • neodymium.lighthouse.assert.thresholdScore.seo

All of those configuration properties are set to 0.5 per default, which sets all category score threshold to 50. That means each and every category needs to match or exceed a score of 50 or otherwise the test will fail. All the score thresholds can be changed depending on the user’s wishes.

Please be aware that the Lighthouse performance score is not the most stable value and is affected by many factors like network load on th the test machine. This can lead to random outliers in the measurement making your tests flaky. A check against the 75th percentile is recommended to give the test some stability (see for example here).

āš ļø Performance Testing

Lighthouse reports during test automation are not recommended for performance testing, but can serve as a lower bound check to alert if basic performance metrics degrade.

Lighthouse Audit Validation

We also implemented the property neodymium.lighthouse.assert.audits in the neodymium.properties file. This property makes it possible to validate Lighthouse audits. In order to do that the user has to specify the id of all audits that should be validated as the property itself. For example: neodymium.lighthouse.assert.audits = aria-roles aria-text validates that no error occurs in the Lighthouse audits aria-roles and aria-text. All existing audit ID’s and their corresponding titles are visualized in the table below.

The following sections list all available audits in a Lighthouse report. The type column values are defined as the following:

  1. Metric
    • What it is: These are the heavy hitters of performance monitoring (often called “Core Web Vitals”). Unlike a simple “Pass/Fail” check, a Metric measures a specific value (usually time in milliseconds or a layout shift score).
    • Data Provided: It provides a raw numericValue (e.g., 1200 ms) and maps it to a score (0–1) based on a log-normal curve.
    • Examples: first-contentful-paint (FCP), cumulative-layout-shift (CLS), total-blocking-time (TBT).
  2. Audit (Standard/Binary)
    • What it is: These are automated checks that verify if a specific best practice is followed.
    • Data Provided: Usually a binary score. 1 = Pass or 0 = Fail.
    • Examples: doctype, is-on-https, image-alt.
  3. Manual
    • What it is: These are items that Lighthouse cannot test automatically. It detects that the element exists (e.g., " You have a custom button") but cannot verify if it works correctly for a screen reader user.
    • Data Provided: The score is usually null or 0 in the raw JSON report because the computer cannot “pass” it for you.
    • Examples: visual-order-follows-dom, focusable-controls, custom-controls-labels.
  4. Diagnostic
    • What it is: These items do not “pass” or “fail.” They are purely informational buckets of data used to help you debug why a Metric might be low.
    • Data Provided: They return a score of null (or sometimes 1 just to show they ran), but the real value is in the details object (lists of URLs, nodes, or request chains).
    • Examples: network-requests (List of every file downloaded), critical-request-chains (Tree of resources blocking the render), main-thread-tasks (Breakdown of CPU time).

Performance Audits

These audits measure metrics and suggest optimizations to improve page speed and user experience

IDTitleType
bootup-timeJavaScript execution timeAudit
critical-request-chainsMinimize Critical Requests DepthDiagnostic
cumulative-layout-shiftCumulative Layout Shift (CLS)Metric
diagnosticsDiagnosticsDiagnostic
dom-sizeAvoids an excessive DOM sizeAudit
duplicated-javascriptRemove duplicate modules in JavaScript bundlesAudit
efficient-animated-contentUse video formats for animated contentAudit
eliminate-render-blocking-resourcesEliminate render-blocking resourcesAudit
final-screenshotFinal ScreenshotDiagnostic
first-contentful-paintFirst Contentful Paint (FCP)Metric
first-meaningful-paintFirst Meaningful PaintMetric
font-displayEnsure text remains visible during webfont loadAudit
interactiveTime to Interactive (TTI)Metric
largest-contentful-paintLargest Contentful Paint (LCP)Metric
largest-contentful-paint-elementLargest Contentful Paint ElementDiagnostic
layout-shiftsLayout ShiftsDiagnostic
lcp-lazy-loadedLCP image was lazy-loadedAudit
legacy-javascriptAvoid serving legacy JavaScript to modern browsersAudit
long-tasksMinimize Main-Thread WorkDiagnostic
main-thread-tasksMain Thread TasksDiagnostic
mainthread-work-breakdownMinimize main-thread workDiagnostic
max-potential-fidMax Potential First Input DelayMetric
metricsMetricsDiagnostic
modern-image-formatsServe images in next-gen formatsAudit
network-requestsNetwork RequestsDiagnostic
network-rttNetwork Round Trip TimeDiagnostic
network-server-latencyServer Backend LatenciesDiagnostic
no-document-writeAvoids document.write()Audit
non-composited-animationsAvoid non-composited animationsAudit
offscreen-imagesDefer offscreen imagesAudit
performance-budgetPerformance budgetDiagnostic
preload-lcp-imagePreload Largest Contentful Paint imageAudit
redirectsAvoid multiple page redirectsAudit
render-blocking-resourcesEliminate render-blocking resourcesAudit
resource-summaryKeep request counts low and transfer sizes smallDiagnostic
screenshot-thumbnailsScreenshot ThumbnailsDiagnostic
script-treemap-dataScript Treemap DataDiagnostic
server-response-timeReduce initial server response time (TTFB)Audit
speed-indexSpeed IndexMetric
third-party-facadesLazy load third-party resources with facadesAudit
third-party-summaryReduce the impact of third-party codeAudit
timing-budgetTiming budgetDiagnostic
total-blocking-timeTotal Blocking Time (TBT)Metric
total-byte-weightAvoid enormous network payloadsAudit
unminified-cssMinify CSSAudit
unminified-javascriptMinify JavaScriptAudit
unsized-imagesImage elements do not have explicit width and heightAudit
unused-css-rulesReduce unused CSSAudit
unused-javascriptReduce unused JavaScriptAudit
user-timingsUser Timing marks and measuresAudit
uses-long-cache-ttlServe static assets with an efficient cache policyAudit
uses-optimized-imagesEfficiently encode imagesAudit
uses-passive-event-listenersUses passive listeners to improve scrolling performanceAudit
uses-rel-preconnectPreconnect to required originsAudit
uses-rel-preloadPreload key requestsAudit
uses-responsive-imagesProperly size imagesAudit
uses-text-compressionEnable text compressionAudit
viewport“Has a <meta name=""viewport""> tag with width or initial-scale”Audit

Accessibility Audits

Lighthouse uses the axe-core library for most of these checks. These ensure your site is usable by people with disabilities.

IDTitleType
accesskeys[accesskey] values are uniqueAudit
aria-allowed-attr[aria-*] attributes match their rolesAudit
aria-allowed-role[role]s are valid for the elementAudit
aria-command-name“button, link, and menuitem elements have accessible names”Audit
aria-conditional-attrConditional [aria-*] attributes are validAudit
aria-deprecated-roleNo deprecated [role]s are usedAudit
aria-dialog-nameARIA dialog and alertdialog nodes have an accessible nameAudit
aria-hidden-body“[aria-hidden=““true””] is not present on the document <body>Audit
aria-hidden-focus“[aria-hidden=““true””] elements do not contain focusable descendants”Audit
aria-input-field-nameARIA input fields have accessible namesAudit
aria-meter-nameARIA meter elements have accessible namesAudit
aria-progressbar-nameARIA progressbar elements have accessible namesAudit
aria-prohibited-attrElements do not use prohibited ARIA attributesAudit
aria-required-attr[role]s have all required [aria-*] attributesAudit
aria-required-childrenElements with an ARIA [role] that require children to contain a specific [role] have all required childrenAudit
aria-required-parent[role]s are contained by their required parent elementAudit
aria-roles[role] values are validAudit
aria-textElements with the role=text attribute do not have focusable descendantsAudit
aria-toggle-field-nameARIA toggle fields have accessible namesAudit
aria-tooltip-nameARIA tooltip elements have accessible namesAudit
aria-treeitem-nameARIA treeitem elements have accessible namesAudit
aria-valid-attr[aria-*] attributes have valid valuesAudit
aria-valid-attr-value[aria-*] attributes have valid valuesAudit
button-nameButtons have an accessible nameAudit
bypass“The page contains a heading, skip link, or landmark region”Audit
color-contrastBackground and foreground colors have a sufficient contrast ratioAudit
custom-controls-labelsCustom controls have associated labelsManual
custom-controls-rolesCustom controls have ARIA rolesManual
definition-list<dl>’s contain only properly-ordered <dt> and <dd> groupsAudit
dlitemDefinition list items are wrapped in <dl> elementsAudit
document-titleDocument has a <title> elementAudit
duplicate-id-active“[id] attributes on active, focusable elements are unique”Audit
duplicate-id-ariaARIA IDs are uniqueAudit
empty-headingHeadings are not emptyAudit
focus-trapsUser focus is not accidentally trapped in a regionManual
focusable-controlsInteractive controls are keyboard focusableManual
form-field-multiple-labelsNo form fields have multiple labelsAudit
frame-title<frame> or <iframe> elements have a titleAudit
heading-orderHeading elements appear in a sequentially-descending orderAudit
html-has-lang<html> element has a [lang] attributeAudit
html-lang-valid<html> element has a valid value for its [lang] attributeAudit
html-xml-lang-mismatch<html> element does not have an [xml:lang] attribute with the same base language as the [lang] attributeAudit
identical-links-same-purposeLinks with the same name have a similar purposeAudit
image-altImage elements have [alt] attributesAudit
image-redundant-altImage elements do not have redundant [alt] attributesAudit
input-button-nameInput buttons have discernible textAudit
input-image-alt<input type=""image""> elements have [alt] text”Audit
interactive-element-affordanceInteractive elements indicate their purpose and stateManual
labelForm elements have associated labelsAudit
label-content-name-mismatchElements’ visible text is part of their accessible nameAudit
landmark-one-mainDocument has one main landmarkAudit
link-in-text-blockLinks are distinguishable from surrounding textAudit
link-nameLinks have a discernible nameAudit
listLists contain only <li> elements and script supporting elementsAudit
listitem“List items (<li>) are contained within <ul>, <ol> or <menu> parent elements”Audit
logical-tab-orderThe page has a logical tab orderManual
managed-focusThe user’s focus is directed to new content added to the pageManual
meta-refresh“The document does not use <meta http-equiv=""refresh"">Audit
meta-viewport“[user-scalable=““no””] is not used in the <meta name=""viewport""> element”Audit
object-alt<object> elements have alternate textAudit
offscreen-content-hiddenOffscreen content is hidden from assistive technologyManual
select-nameSelect elements have associated label elementsAudit
skip-linkSkip links are focusableAudit
tabindexNo element has a [tabindex] value greater than 0Audit
table-duplicate-name<caption> elements do not contain the same text as the summary attributeAudit
table-fake-captionTables use <caption> instead of cells with the [colspan] attributeAudit
target-sizeTap targets are sized appropriatelyAudit
td-has-header<td> elements in a large <table> have one or more table headersAudit
td-headers-attrCells in a <table> element that use the [headers] attribute refer to table cells within the same tableAudit
th-has-data-cells<th> elements and elements with [role=““columnheader””/““rowheader””] have data cells they describe”Audit
use-landmarksHTML landmarks are used to identify page regionsManual
valid-lang[lang] attributes have a valid valueAudit
video-caption<video> elements contain a <track> element with [kind=““captions””]”Audit
visual-order-follows-domVisual order on the page follows DOM orderManual

Best Practices Audits

These audits check for general code health and modern web standards.

IDTitleType
appcache-manifestAvoids Application CacheAudit
bf-cachePage is eligible for Back/Forward CacheAudit
csp-xssContent Security Policy (CSP) protects against XSSAudit
deprecationsAvoids deprecated APIsAudit
doctypePage has the HTML doctypeAudit
errors-in-consoleNo browser errors logged to the consoleAudit
external-anchors-use-rel-noopenerLinks to cross-origin destinations are safeAudit
geolocation-on-startAvoids requesting the geolocation permission on page loadAudit
image-aspect-ratioDisplays images with correct aspect ratioAudit
image-size-responsiveServes images with appropriate resolutionAudit
inspector-issuesNo issues in the Issues panel in Chrome DevtoolsAudit
is-on-httpsUses HTTPSAudit
js-librariesDetected JavaScript librariesDiagnostic
no-vulnerable-librariesAvoids front-end JavaScript libraries with known security vulnerabilitiesAudit
notification-on-startAvoids requesting the notification permission on page loadAudit
password-inputs-can-be-pasted-intoAllows users to paste into password fieldsAudit
third-party-cookiesThird-party cookiesDiagnostic
uses-http2Use HTTP/2Audit
valid-source-mapsPage has valid source mapsDiagnostic

SEO Audits

Checks that ensure your page is discoverable and optimized for search engine crawlers.

IDTitleType
canonicalDocument has a valid rel=canonicalAudit
crawlable-anchorsLinks are crawlableAudit
document-titleDocument has a <title> elementAudit
font-sizeDocument uses legible font sizesAudit
hreflangDocument has a valid hreflangAudit
http-status-codePage has successful HTTP status codeAudit
is-crawlablePage is not blocked from indexingAudit
link-textLinks have descriptive textAudit
meta-descriptionDocument has a meta descriptionAudit
plugins“Document avoids plugins (e.g., Flash, Java)”Audit
robots-txtrobots.txt is validAudit
structured-dataStructured data is validAudit
tap-targetsTap targets are sized appropriatelyAudit

PWA (Progressive Web App) Audits

Checks for PWA validation, including installability and offline capabilities.

IDTitleType
apple-touch-iconProvides a valid apple-touch-iconAudit
content-widthContent is sized correctly for the viewportAudit
installable-manifestWeb app manifest meets the installability requirementsAudit
maskable-iconManifest has a maskable iconAudit
pwa-cross-browserSite works cross-browserAudit
pwa-each-page-has-urlEach page has a URLAudit
pwa-page-transitionsPage transitions don’t feel like they block on the networkManual
redirects-httpRedirects HTTP traffic to HTTPSAudit
service-workerRegisters a service worker that controls page and start_urlAudit
splash-screenConfigured for a custom splash screenAudit
themed-omniboxSets a theme color for the address barAudit
Last modified February 18, 2026: remove numbers from filenames (27bdd4a5)