diff --git a/package-lock.json b/package-lock.json index 60a45964..b7635a36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@types/eslint": "^8.56.12", "@typescript-eslint/eslint-plugin": "^7.18.0", "@typescript-eslint/parser": "^7.18.0", + "color-contrast-checker": "^2.1.0", "eslint": "^8.57.1", "eslint-config-prettier": "^9.1.0", "eslint-plugin-storybook": "^0.11.1", @@ -2980,6 +2981,12 @@ } } }, + "node_modules/color-contrast-checker": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-contrast-checker/-/color-contrast-checker-2.1.0.tgz", + "integrity": "sha512-6Y0aIEej3pwZTVlicIqVzhO6T4izDWouaIXnYoDdTuFFAMQ9nnN0dgHNP9J94jRnH6asjPq1/wzUKxwoNbWtRQ==", + "dev": true + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", diff --git a/package.json b/package.json index 3e83e31a..d55d9126 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@types/eslint": "^8.56.12", "@typescript-eslint/eslint-plugin": "^7.18.0", "@typescript-eslint/parser": "^7.18.0", + "color-contrast-checker": "^2.1.0", "eslint": "^8.57.1", "eslint-config-prettier": "^9.1.0", "eslint-plugin-storybook": "^0.11.1", diff --git a/src/utils/contrast.test.ts b/src/utils/contrast.test.ts new file mode 100644 index 00000000..7aafe7f6 --- /dev/null +++ b/src/utils/contrast.test.ts @@ -0,0 +1,46 @@ +import { expect, test } from 'vitest'; +import ColorContrastChecker from 'color-contrast-checker'; +import type { ReviewMetadata } from '$lib/types/reviews'; + +const reviews = await fetch(`https://api.audioxide.com/reviews.json`); +const data: { + metadata: ReviewMetadata; +}[] = await reviews.json(); + +const ccc = new ColorContrastChecker(); + +test('Colour contrast on review pages', () => { + const passingReviews: string[] = []; + const failingReviews: string[] = []; + + data.forEach(({ metadata }) => { + const primaryColor = metadata.colours[0]; + const secondaryColor = metadata.colours[1]; + const tertiaryColor = metadata.colours[2]; + const summaryTextColour = metadata.colours[3] ? metadata.colours[3] : primaryColor; + + const primaryContrast = ccc.isLevelAA(primaryColor, '#ffffff', 40); + const secondaryContrast = ccc.isLevelAA(secondaryColor, primaryColor); + const tertiaryContrast = ccc.isLevelAA(tertiaryColor, primaryColor); + const summaryContrast = ccc.isLevelAA(summaryTextColour, '#ffffff', 18); + + const allTestsPass = + primaryContrast && secondaryContrast && tertiaryContrast && summaryContrast; + + if (!allTestsPass) { + failingReviews.push(metadata.album); + } else { + passingReviews.push(metadata.album); + } + + expect(allTestsPass).toBe(true); + }); + + console.log('Passing reviews: ' + passingReviews.length); + console.log('Failing reviews: ' + failingReviews.length); + + console.warn('Reviews failing WCAG AA contrast requirements:'); + failingReviews.forEach((album) => { + console.warn(album); + }); +});