|
| 1 | +import { StyleProvider } from '@ant-design/cssinjs'; |
| 2 | +import { ConfigProvider } from 'antd'; |
| 3 | +import type { CssStylesheetAST, CssAtRuleAST } from '@adobe/css-tools'; |
| 4 | +import { parse, CssTypes } from '@adobe/css-tools'; |
| 5 | +import { extractStyle } from '../src'; |
| 6 | +import fs from 'fs'; |
| 7 | + |
| 8 | +function extractSelectors(ast: CssStylesheetAST): Set<string> { |
| 9 | + const selectors = new Set<string>(); |
| 10 | + |
| 11 | + function walk(rules: CssAtRuleAST[]) { |
| 12 | + for (const rule of rules) { |
| 13 | + switch (rule.type) { |
| 14 | + case CssTypes.rule: |
| 15 | + rule.selectors?.forEach(sel => selectors.add(sel)); |
| 16 | + break; |
| 17 | + case CssTypes.media: |
| 18 | + case CssTypes.supports: |
| 19 | + case CssTypes.layer: |
| 20 | + if (rule.rules) walk(rule.rules); |
| 21 | + break; |
| 22 | + default: |
| 23 | + // Ignore other rule types (comments, keyframes, font-face, etc.) |
| 24 | + break; |
| 25 | + } |
| 26 | + } |
| 27 | + } |
| 28 | + |
| 29 | + if (ast.stylesheet?.rules) { |
| 30 | + walk(ast.stylesheet.rules); |
| 31 | + } |
| 32 | + return selectors; |
| 33 | +} |
| 34 | + |
| 35 | +describe('CSS Coverage', () => { |
| 36 | + it('should extract all antd selectors', () => { |
| 37 | + // Extract CSS with: |
| 38 | + // - hashPriority='high' to avoid :where() wrapper |
| 39 | + // - hashed: false to avoid hash class prefixes |
| 40 | + const extractedCss = extractStyle((node) => ( |
| 41 | + <StyleProvider hashPriority="high"> |
| 42 | + <ConfigProvider theme={{ hashed: false }}> |
| 43 | + {node} |
| 44 | + </ConfigProvider> |
| 45 | + </StyleProvider> |
| 46 | + )); |
| 47 | + |
| 48 | + const antdCssPath = require.resolve('antd/dist/antd.css'); |
| 49 | + const antdCss = fs.readFileSync(antdCssPath, 'utf-8'); |
| 50 | + |
| 51 | + const antdAst = parse(antdCss); |
| 52 | + const extractedAst = parse(extractedCss); |
| 53 | + |
| 54 | + const antdSelectors = extractSelectors(antdAst); |
| 55 | + const extractedSelectors = extractSelectors(extractedAst); |
| 56 | + |
| 57 | + const missing = [...antdSelectors].filter( |
| 58 | + sel => !extractedSelectors.has(sel) |
| 59 | + ); |
| 60 | + |
| 61 | + const coverage = ((antdSelectors.size - missing.length) / antdSelectors.size * 100).toFixed(2); |
| 62 | + console.log(`CSS Coverage: ${coverage}% (${missing.length} missing of ${antdSelectors.size} selectors)`); |
| 63 | + |
| 64 | + if (missing.length > 0) { |
| 65 | + console.log('Missing selectors:', JSON.stringify(missing, null, 2)); |
| 66 | + } |
| 67 | + |
| 68 | + expect(missing).toEqual([]); |
| 69 | + }); |
| 70 | +}); |
0 commit comments