UNPKG

computed-styles-regression-test

Version:

DOM & CSSOM based regression testing utility

164 lines 6.79 kB
function compareElements(expected, actual, path, options) { const differences = []; // Compare tag names if (expected.nodeName !== actual.nodeName) { differences.push({ type: 'structure', path: `${path}.nodeName`, expected: expected.nodeName, actual: actual.nodeName, description: `Node name mismatch at ${path}`, }); } // Compare attributes (if not ignoring class names) if (!options.ignoreClassNames) { const expectedAttrs = { ...expected.attributes }; const actualAttrs = { ...actual.attributes }; for (const [key, value] of Object.entries(expectedAttrs)) { if (actualAttrs[key] !== value) { differences.push({ type: 'structure', path: `${path}.attributes.${key}`, expected: value, actual: actualAttrs[key], description: `Attribute ${key} mismatch at ${path}`, }); } } for (const key of Object.keys(actualAttrs)) { if (!(key in expectedAttrs)) { differences.push({ type: 'structure', path: `${path}.attributes.${key}`, expected: undefined, actual: actualAttrs[key], description: `Unexpected attribute ${key} at ${path}`, }); } } } // Compare computed styles const expectedStyles = new Map(Object.entries(expected.computedStyles)); const actualStyles = new Map(Object.entries(actual.computedStyles)); const stylesToCheck = options.styleProperties || Array.from(expectedStyles.keys()); for (const property of stylesToCheck) { const expectedValue = expectedStyles.get(property); const actualValue = actualStyles.get(property); if (expectedValue !== actualValue) { differences.push({ type: 'style', path: `${path}.styles.${property}`, expected: expectedValue, actual: actualValue, description: `Style property ${property} mismatch at ${path}`, }); } } // Compare pseudo-states const expectedPseudoStates = expected.pseudoStates || {}; const actualPseudoStates = actual.pseudoStates || {}; const allPseudoStates = new Set([ ...Object.keys(expectedPseudoStates), ...Object.keys(actualPseudoStates), ]); for (const pseudoState of allPseudoStates) { const expectedPseudo = expectedPseudoStates[pseudoState]; const actualPseudo = actualPseudoStates[pseudoState]; if (!expectedPseudo && actualPseudo) { differences.push({ type: 'style', path: `${path}:${pseudoState}`, expected: undefined, actual: 'present', description: `Unexpected pseudo-state ${pseudoState} at ${path}`, }); } else if (expectedPseudo && !actualPseudo) { differences.push({ type: 'style', path: `${path}:${pseudoState}`, expected: 'present', actual: undefined, description: `Missing pseudo-state ${pseudoState} at ${path}`, }); } else if (expectedPseudo && actualPseudo) { // Compare the styles within the pseudo-state const expectedPseudoStylesMap = new Map(Object.entries(expectedPseudo)); const actualPseudoStylesMap = new Map(Object.entries(actualPseudo)); const pseudoStylesToCheck = options.styleProperties || Array.from(expectedPseudoStylesMap.keys()); for (const property of pseudoStylesToCheck) { const expectedPseudoValue = expectedPseudoStylesMap.get(property); const actualPseudoValue = actualPseudoStylesMap.get(property); if (expectedPseudoValue !== actualPseudoValue) { differences.push({ type: 'style', path: `${path}:${pseudoState}.styles.${property}`, expected: expectedPseudoValue, actual: actualPseudoValue, description: `Pseudo-state ${pseudoState} style property ${property} mismatch at ${path}`, }); } } } } // Compare children count if strict structure comparison if (options.strictStructureComparison && expected.children.length !== actual.children.length) { differences.push({ type: 'structure', path: `${path}.children.length`, expected: expected.children.length, actual: actual.children.length, description: `Children count mismatch at ${path}`, }); } // Compare children recursively const minChildrenLength = Math.min(expected.children.length, actual.children.length); for (let i = 0; i < minChildrenLength; i++) { const childDifferences = compareElements(expected.children[i], actual.children[i], `${path} > ${expected.children[i].uniqueSelector}`, options); differences.push(...childDifferences); } return differences; } export function compareSnapshots(expected, actual, options = {}) { const differences = []; // Compare trees count if (expected.trees.length !== actual.trees.length) { differences.push({ type: 'structure', path: 'trees.length', expected: expected.trees.length, actual: actual.trees.length, description: 'Root elements count mismatch', }); } // Compare each tree const minTreesLength = Math.min(expected.trees.length, actual.trees.length); for (let i = 0; i < minTreesLength; i++) { const treeDifferences = compareElements(expected.trees[i], actual.trees[i], `trees[${i}]`, options); differences.push(...treeDifferences); } return { isEqual: differences.length === 0, differences, }; } export function findElementByPath(snapshot, path) { const pathParts = path.split('.'); let current = snapshot; for (const part of pathParts) { if (part.includes('[') && part.includes(']')) { const [key, indexStr] = part.split('['); const index = Number.parseInt(indexStr.replace(']', ''), 10); current = current[key]?.[index]; } else { current = current[part]; } if (current == null) { return null; } } return current; } //# sourceMappingURL=comparison.js.map