0

I need to check the accessibility of HTML code, herewith:

  1. I need the Node.js API (class of function), not CLI.
  2. I want to pass the HTML string as parameter, not the URI of file path.

Is should be something like:

import AccessibilityInspector from "package-which_i_need";

AccessibilityInspector.inspect({
  rawHTML_Code: `<!doctypehtml><html lang=en><meta charset=utf-8><title>title</title><link href=style.css rel=stylesheet><script src=script.js></script>`,
  standard: "WCAG2AAA"
}).
   then((issues: Array<AccessibilityInspector.Issue>): void => {
     // Log the issues
   }).
   catch((error: unknown) => {
     console.error(error);
   })

Below packages does not satisfy to above conditions:

  • The pa11y accepts only URI as the first parameter, but not the HTML code.
  • According the documentation, the access-sniff accepts only URIs too. Although the raw HTML could be also passed, "Pattern is too long" unclear error could occur. Also, the access-sniff has many vulnerabilities and not being maintained.

Other options?

Takeshi Tokugawa YD
  • 670
  • 5
  • 40
  • 124

2 Answers2

1

Run an accessibility test against a file (absolute paths only, not relative):

pa11y ./path/to/your/file.html

You can do:

const { exec } = require("child_process");

function run() {
    exec("pa11y ./path/to/your/file.html", (error, stdout, stderr) => {
    if (error) {
        console.log(`[ERROR] openCashDrawer: ${error.message}`);
        return;
    }
    
    if (stderr) {
        console.log(`[STDERROR] openCashDrawer: ${stderr}`);
        return;
    }

    console.log(`openCashDrawer: ${stdout}`); // Output response from the terminal
    });
}
Ronnie Royston
  • 16,778
  • 6
  • 77
  • 91
1

pa11y has two modes of operation: get contents from a web page by following the URL, or get contents from the provided browser and page instances directly, without making an HTTP request. The behavior is controlled by ignoreUrl parameter, which is false by default.

Get contents directly from browser and page

With the help of puppeteer, you can create browser and page instances and provide them to pa11y. You would need to set ignoreUrl to true:

import puppeteer from 'puppeteer'
import pa11y from 'pa11y'

// Here comes your raw HTML code
const htmlCode = '<html><body>Hello world!</body></html>'

async function main() {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()

  await page.setContent(htmlCode, {
    waitUntil: 'domcontentloaded',
  })

  const url = page.url()
  const a11y = await pa11y(url, {
    ignoreUrl: true,
    browser,
    page,
  })

  console.log(a11y)

  await browser.close()
}

main()

Get contents from a local server-hosted web page

Alternatively, you can spin up a local server that would respond to any request with the HTML code, effectively making your own temporary website with the said HTML code.

This can totally be implemented using the built-in http module, although it is more cumbersome that way. The below implementation uses express:

import { type Server } from 'http'
import express = require('express')
import pa11y = require('pa11y')

// Here comes your raw HTML code
const htmlCode = '<html><body>Hello world!</body></html>'

function getPort(server: Server) {
  const address = server.address()!

  if (address instanceof Object) {
    return address.port
  }

  return address.split(':').at(-1)!
}

const server = express()
  .use((req, res) => res.send(htmlCode))
  .listen(async () => {
    const port = getPort(server)
    const a11y = await pa11y(`http://localhost:${port}`)

    console.log(a11y)

    server.close()
  })

Note that the server is attached to whatever port is available at the time, which is why we have to use getPort function (or similar).

Parzh from Ukraine
  • 7,999
  • 3
  • 34
  • 65
  • Thank you for the answer! I'll report once return to accessibility checking task and try your solution. – Takeshi Tokugawa YD May 22 '23 at 13:06
  • Sorry for taking a lot of time. Just tried you solution. Unfortunately the `page.url()` returns the `about:blank`. I you don't know how to deal with it, I'll prepare the new question. By the way... we have not set the URL... Is is being set automatically? – Takeshi Tokugawa YD Jun 22 '23 at 00:44
  • 1
    Indeed, `pa11y` tried to open this URL, even though it can get all data from `browser` and `page`. Weird. Well, all is not lost though. I've updated the answer with another approach, tested it, and it works. Take a look. – Parzh from Ukraine Jun 22 '23 at 13:57
  • O'K, thank you for your efforts. I have accepted your answer. However, the puppeteer's issue gives me no peace, so I have asked for the help in the [another question](https://stackoverflow.com/q/76536400/4818123). – Takeshi Tokugawa YD Jun 23 '23 at 00:16
  • 1
    Okay, I've missed the crucial `ignoreUrl` parameter. Now it all makes sense. I've returned my previous answer back and added the usage of the parameter there. Regarding the other question, I think it overlaps significantly with this one (especially the answer, which is very similar to the first version of my answer here but with added `ignoreUrl: true` and `browser.close()`). Be careful, because similar questions might cause confusion. – Parzh from Ukraine Jun 23 '23 at 07:57