or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

axe-test.mdconfiguration.mdimage-snapshot.mdindex.mdpuppeteer-test.md

axe-test.mddocs/

0

# Accessibility Testing

1

2

Automated accessibility audits using Axe Core integration to verify component accessibility compliance with WCAG guidelines.

3

4

## Capabilities

5

6

### Axe Test Function

7

8

Creates a test function that runs accessibility audits on Storybook stories using @axe-core/puppeteer integration.

9

10

```typescript { .api }

11

/**

12

* Creates a test function for automated accessibility testing

13

* @param customConfig - Optional configuration to override defaults

14

* @returns Test function that performs accessibility audits

15

*/

16

function axeTest(customConfig?: Partial<AxeConfig>): TestFunction;

17

18

interface AxeConfig extends CommonConfig {

19

/** Hook executed before accessibility test runs */

20

beforeAxeTest: (page: Page, options: Options) => Promise<void>;

21

}

22

```

23

24

**Usage Examples:**

25

26

```typescript

27

import initStoryshots from '@storybook/addon-storyshots';

28

import { axeTest } from '@storybook/addon-storyshots-puppeteer';

29

30

// Basic accessibility testing

31

initStoryshots({

32

suite: 'A11y checks',

33

test: axeTest()

34

});

35

36

// With pre-test setup

37

initStoryshots({

38

suite: 'Accessibility audits',

39

test: axeTest({

40

storybookUrl: 'http://localhost:6006',

41

beforeAxeTest: async (page) => {

42

// Wait for dynamic content

43

await page.waitForSelector('[data-loaded="true"]');

44

// Set focus state for testing

45

await page.focus('input[type="text"]');

46

}

47

})

48

});

49

```

50

51

### Story Parameter Integration

52

53

Accessibility test configuration uses the same `a11y` parameters as @storybook/addon-a11y for consistency.

54

55

```typescript { .api }

56

interface A11yParameters {

57

/** Element selector to test (default: '#storybook-root') */

58

element?: string;

59

/** Elements to exclude from testing */

60

exclude?: string | string[];

61

/** Axe rules to disable */

62

disabledRules?: string[];

63

/** Axe run options */

64

options?: AxeRunOptions;

65

/** Axe configuration */

66

config?: AxeConfig;

67

}

68

69

interface AxeRunOptions {

70

/** Include only specific rules */

71

runOnly?: string[] | { type: 'rule' | 'tag'; values: string[] };

72

/** Rule configuration overrides */

73

rules?: { [ruleId: string]: { enabled: boolean } };

74

/** Tags to include */

75

tags?: string[];

76

/** Result types to return */

77

resultTypes?: ('violations' | 'incomplete' | 'passes' | 'inapplicable')[];

78

}

79

```

80

81

**Usage Examples:**

82

83

```typescript

84

// Story with accessibility configuration

85

export const AccessibleForm = () => <ContactForm />;

86

87

AccessibleForm.parameters = {

88

a11y: {

89

element: '#contact-form',

90

exclude: ['.skip-a11y-test'],

91

disabledRules: ['color-contrast'], // Temporary exclusion

92

options: {

93

tags: ['wcag2a', 'wcag2aa'],

94

runOnly: {

95

type: 'tag',

96

values: ['wcag2a', 'wcag2aa']

97

}

98

}

99

}

100

};

101

102

// Testing specific accessibility rules

103

export const ColorContrastTest = () => <ThemeProvider><Button /></ThemeProvider>;

104

105

ColorContrastTest.parameters = {

106

a11y: {

107

options: {

108

runOnly: ['color-contrast']

109

}

110

}

111

};

112

```

113

114

### Axe Core Integration

115

116

Direct integration with @axe-core/puppeteer provides comprehensive accessibility testing capabilities.

117

118

```typescript { .api }

119

/**

120

* Axe Puppeteer instance methods used internally

121

*/

122

interface AxePuppeteer {

123

/** Include elements in accessibility scan */

124

include(selector: string): AxePuppeteer;

125

/** Exclude elements from accessibility scan */

126

exclude(selector: string | string[]): AxePuppeteer;

127

/** Set axe-core options */

128

options(options: AxeRunOptions): AxePuppeteer;

129

/** Disable specific rules */

130

disableRules(rules: string | string[]): AxePuppeteer;

131

/** Configure axe-core */

132

configure(config: AxeConfig): AxePuppeteer;

133

/** Run accessibility analysis */

134

analyze(): Promise<AxeResults>;

135

}

136

137

interface AxeResults {

138

/** Accessibility violations found */

139

violations: AxeViolation[];

140

/** Incomplete tests */

141

incomplete: AxeIncomplete[];

142

/** Passing tests */

143

passes: AxePass[];

144

/** Inapplicable tests */

145

inapplicable: AxeInapplicable[];

146

}

147

148

interface AxeViolation {

149

/** Rule identifier */

150

id: string;

151

/** Impact level */

152

impact: 'minor' | 'moderate' | 'serious' | 'critical';

153

/** Human-readable description */

154

description: string;

155

/** Help text and documentation */

156

help: string;

157

/** Help URL for more information */

158

helpUrl: string;

159

/** Elements that failed the rule */

160

nodes: AxeNodeResult[];

161

}

162

```

163

164

### Test Execution Flow

165

166

The axe test follows a specific execution pattern for consistent accessibility auditing.

167

168

```typescript { .api }

169

/**

170

* Internal test execution steps

171

*/

172

interface AxeTestFlow {

173

/** 1. Execute beforeAxeTest hook */

174

beforeAxeTest: (page: Page, options: Options) => Promise<void>;

175

/** 2. Create AxePuppeteer instance */

176

createAxeInstance: (page: Page) => AxePuppeteer;

177

/** 3. Configure accessibility test */

178

configureAxe: (axe: AxePuppeteer, parameters: A11yParameters) => AxePuppeteer;

179

/** 4. Run accessibility analysis */

180

analyzeAccessibility: () => Promise<AxeResults>;

181

/** 5. Assert no violations */

182

assertNoViolations: (violations: AxeViolation[]) => void;

183

}

184

```

185

186

**Test Flow Example:**

187

188

```typescript

189

// Internal test execution (for reference)

190

async function testBody(page, testOptions) {

191

const {

192

element = '#storybook-root',

193

exclude,

194

disabledRules,

195

options,

196

config,

197

} = testOptions.context.parameters.a11y || {};

198

199

// 1. Pre-test setup

200

await beforeAxeTest(page, options);

201

202

// 2. Create and configure Axe instance

203

const axe = new AxePuppeteer(page);

204

axe.include(element);

205

206

if (exclude) axe.exclude(exclude);

207

if (options) axe.options(options);

208

if (disabledRules) axe.disableRules(disabledRules);

209

if (config) axe.configure(config);

210

211

// 3. Run analysis and assert

212

const { violations } = await axe.analyze();

213

expect(violations).toHaveLength(0);

214

}

215

```

216

217

### Before Test Hook

218

219

Configure page state before accessibility testing runs.

220

221

```typescript { .api }

222

/**

223

* Hook for pre-test setup

224

* @param page - Puppeteer page instance

225

* @param options - Test context and URL information

226

* @returns Promise for async setup operations

227

*/

228

type BeforeAxeTest = (page: Page, options: Options) => Promise<void>;

229

```

230

231

**Usage Examples:**

232

233

```typescript

234

// Wait for dynamic content to load

235

const beforeAxeTest = async (page, { context }) => {

236

if (context.story.includes('loading')) {

237

await page.waitForSelector('[data-loaded="true"]', { timeout: 5000 });

238

}

239

240

// Allow animations to complete

241

await page.waitForTimeout(600);

242

243

// Set up specific interaction states

244

if (context.story.includes('focus')) {

245

await page.focus('input[type="email"]');

246

}

247

};

248

249

// Complex interaction setup

250

const beforeAxeTest = async (page) => {

251

// Open modal or dropdown

252

await page.click('[aria-haspopup="true"]');

253

await page.waitForSelector('[role="dialog"]');

254

255

// Wait for any transitions

256

await page.waitForFunction(

257

() => window.getComputedStyle(document.querySelector('[role="dialog"]')).opacity === '1'

258

);

259

};

260

261

initStoryshots({

262

suite: 'Dynamic accessibility',

263

test: axeTest({ beforeAxeTest })

264

});

265

```

266

267

### Default Configuration

268

269

Default accessibility testing configuration targets the main Storybook root element.

270

271

```typescript { .api }

272

const defaultAxeConfig: AxeConfig = {

273

...defaultCommonConfig,

274

beforeAxeTest: () => Promise.resolve(),

275

};

276

277

// Default story parameters when none specified

278

const defaultA11yParameters: A11yParameters = {

279

element: '#storybook-root',

280

exclude: undefined,

281

disabledRules: undefined,

282

options: undefined,

283

config: undefined

284

};

285

```