Skip to content

Commit 7ca0201

Browse files
committed
adjust code
- refactor input loading to keep main function scope limited and easier to read - change url_config to url_configs - change some ternaries and conditional logic from copilot to be easier to understand
1 parent 88d20c3 commit 7ca0201

5 files changed

Lines changed: 103 additions & 84 deletions

File tree

.github/actions/find/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ inputs:
66
description: 'Newline-delimited list of URLs to check for accessibility issues'
77
required: false
88
multiline: true
9-
url_config:
9+
url_configs:
1010
description: "Stringified JSON array of URL config objects, each with a 'url' field and an optional 'excludeSelectors' field (array of CSS selectors to exclude from the Axe scan for that URL). When provided, takes precedence over the 'urls' input."
1111
required: false
1212
auth_context:

.github/actions/find/src/findForUrl.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type {ColorSchemePreference, Finding, ReducedMotionPreference} from './types.d.js'
1+
import type {ColorSchemePreference, Finding, ReducedMotionPreference, UrlConfig} from './types.d.js'
22
import {AxeBuilder} from '@axe-core/playwright'
33
import playwright from 'playwright'
44
import {AuthContext} from './AuthContext.js'
@@ -8,13 +8,13 @@ import {getScansContext} from './scansContextProvider.js'
88
import * as core from '@actions/core'
99

1010
export async function findForUrl(
11-
url: string,
11+
urlConfig: UrlConfig,
1212
authContext?: AuthContext,
1313
includeScreenshots: boolean = false,
1414
reducedMotion?: ReducedMotionPreference,
1515
colorScheme?: ColorSchemePreference,
16-
exclude?: string[],
1716
): Promise<Finding[]> {
17+
const {url, excludeSelectors} = urlConfig
1818
const browser = await playwright.chromium.launch({
1919
headless: true,
2020
executablePath: process.env.CI ? '/usr/bin/google-chrome' : undefined,
@@ -57,7 +57,7 @@ export async function findForUrl(
5757
}
5858

5959
if (scansContext.shouldPerformAxeScan) {
60-
await runAxeScan({page, addFinding, exclude})
60+
await runAxeScan({page, addFinding, excludeSelectors})
6161
}
6262
} catch (e) {
6363
core.error(`Error during accessibility scan: ${e}`)
@@ -70,17 +70,17 @@ export async function findForUrl(
7070
async function runAxeScan({
7171
page,
7272
addFinding,
73-
exclude,
73+
excludeSelectors,
7474
}: {
7575
page: playwright.Page
7676
addFinding: (findingData: Finding, options?: {includeScreenshots?: boolean}) => Promise<void>
77-
exclude?: string[]
77+
excludeSelectors?: string[]
7878
}) {
7979
const url = page.url()
8080
core.info(`Scanning ${url}`)
81-
const axeBuilder = exclude && exclude.length > 0
82-
? exclude.reduce((builder, selector) => builder.exclude(selector), new AxeBuilder({page}))
83-
: new AxeBuilder({page})
81+
const axeBuilder = new AxeBuilder({page})
82+
excludeSelectors?.forEach(selector => axeBuilder.exclude(selector))
83+
8484
const rawFindings = await axeBuilder.analyze()
8585

8686
if (rawFindings) {

.github/actions/find/src/index.ts

Lines changed: 72 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,67 +7,22 @@ import {findForUrl} from './findForUrl.js'
77

88
export default async function () {
99
core.info("Starting 'find' action")
10-
const urlConfigInput = core.getInput('url_config', {required: false})
11-
let urlConfigs: UrlConfig[] | undefined
12-
if (urlConfigInput) {
13-
try {
14-
const parsed = JSON.parse(urlConfigInput)
15-
if (!Array.isArray(parsed)) {
16-
throw new Error("Input 'url_config' must be a JSON array.")
17-
}
18-
for (const item of parsed) {
19-
if (typeof item !== 'object' || item === null || typeof item.url !== 'string') {
20-
throw new Error("Each entry in 'url_config' must be an object with a 'url' string field.")
21-
}
22-
}
23-
urlConfigs = parsed as UrlConfig[]
24-
} catch (e) {
25-
throw new Error(`Invalid 'url_config' input: ${(e as Error).message}`)
26-
}
27-
}
10+
let urlConfigs = loadUrlConfigs()
11+
let urls = loadUrls({urlConfigs})
12+
let reducedMotion = loadReducedMotion()
13+
let colorScheme = loadColorScheme()
2814

29-
let urls: string[]
30-
if (urlConfigs) {
31-
core.debug(`Input: 'url_config: ${JSON.stringify(urlConfigs)}'`)
32-
urls = urlConfigs.map(c => c.url)
33-
} else {
34-
urls = core.getMultilineInput('urls', {required: false})
35-
core.debug(`Input: 'urls: ${JSON.stringify(urls)}'`)
36-
if (urls.length === 0) {
37-
throw new Error("Either 'urls' or 'url_config' input must be provided.")
38-
}
39-
}
15+
const actualUrls = urlConfigs || urls || []
4016

4117
const authContextInput: AuthContextInput = JSON.parse(core.getInput('auth_context', {required: false}) || '{}')
4218
const authContext = new AuthContext(authContextInput)
43-
4419
const includeScreenshots = core.getInput('include_screenshots', {required: false}) !== 'false'
45-
const reducedMotionInput = core.getInput('reduced_motion', {required: false})
46-
let reducedMotion: ReducedMotionPreference | undefined
47-
if (reducedMotionInput) {
48-
if (!['reduce', 'no-preference', null].includes(reducedMotionInput)) {
49-
throw new Error(
50-
"Input 'reduced_motion' must be one of: 'reduce', 'no-preference', or null per Playwright documentation.",
51-
)
52-
}
53-
reducedMotion = reducedMotionInput as ReducedMotionPreference
54-
}
55-
const colorSchemeInput = core.getInput('color_scheme', {required: false})
56-
let colorScheme: ColorSchemePreference | undefined
57-
if (colorSchemeInput) {
58-
if (!['light', 'dark', 'no-preference', null].includes(colorSchemeInput)) {
59-
throw new Error(
60-
"Input 'color_scheme' must be one of: 'light', 'dark', 'no-preference', or null per Playwright documentation.",
61-
)
62-
}
63-
colorScheme = colorSchemeInput as ColorSchemePreference
64-
}
6520

6621
const findings = []
67-
for (const url of urls) {
22+
for (const urlConfig of actualUrls) {
23+
const {url} = urlConfig
6824
core.info(`Preparing to scan ${url}`)
69-
const excludeSelectors = urlConfigs?.find(c => c.url === url)?.excludeSelectors
70-
const findingsForUrl = await findForUrl(url, authContext, includeScreenshots, reducedMotion, colorScheme, excludeSelectors)
25+
const findingsForUrl = await findForUrl(urlConfig, authContext, includeScreenshots, reducedMotion, colorScheme)
7126
if (findingsForUrl.length === 0) {
7227
core.info(`No accessibility gaps were found on ${url}`)
7328
continue
@@ -84,3 +39,67 @@ export default async function () {
8439
core.info(`Found ${findings.length} findings in total`)
8540
core.info("Finished 'find' action")
8641
}
42+
43+
function loadUrlConfigs() {
44+
const urlConfigInput = core.getInput('url_configs', {required: false})
45+
46+
if (!urlConfigInput) return
47+
48+
try {
49+
const parsed = JSON.parse(urlConfigInput)
50+
51+
if (!Array.isArray(parsed)) {
52+
throw new Error("Input 'url_configs' must be a JSON array.")
53+
}
54+
55+
for (const item of parsed) {
56+
if (typeof item !== 'object' || item === null || typeof item.url !== 'string') {
57+
throw new Error("Each entry in 'url_configs' must be an object with a 'url' string field.")
58+
}
59+
}
60+
61+
return parsed as UrlConfig[]
62+
} catch (e) {
63+
throw new Error(`Invalid 'url_configs' input: ${(e as Error).message}`)
64+
}
65+
}
66+
67+
function loadUrls({urlConfigs}: {urlConfigs?: UrlConfig[]} = {}) {
68+
// - no need to process this input if url_configs is provided
69+
if (urlConfigs) return
70+
71+
let urls: string[]
72+
urls = core.getMultilineInput('urls', {required: false})
73+
core.debug(`Input: 'urls: ${JSON.stringify(urls)}'`)
74+
75+
if (urls.length === 0) {
76+
throw new Error("Either 'urls' or 'url_configs' input must be provided.")
77+
}
78+
79+
return urls.map(url => ({url})) as UrlConfig[]
80+
}
81+
82+
function loadReducedMotion() {
83+
const reducedMotionInput = core.getInput('reduced_motion', {required: false})
84+
if (!reducedMotionInput) return
85+
86+
if (!['reduce', 'no-preference', null].includes(reducedMotionInput)) {
87+
throw new Error(
88+
"Input 'reduced_motion' must be one of: 'reduce', 'no-preference', or null per Playwright documentation.",
89+
)
90+
}
91+
return reducedMotionInput as ReducedMotionPreference
92+
}
93+
94+
function loadColorScheme() {
95+
const colorSchemeInput = core.getInput('color_scheme', {required: false})
96+
if (!colorSchemeInput) return
97+
98+
if (!['light', 'dark', 'no-preference', null].includes(colorSchemeInput)) {
99+
throw new Error(
100+
"Input 'color_scheme' must be one of: 'light', 'dark', 'no-preference', or null per Playwright documentation.",
101+
)
102+
}
103+
104+
return colorSchemeInput as ColorSchemePreference
105+
}

0 commit comments

Comments
 (0)