`;
const result = getVariantNumbersInTree(el, 'is-style-outline');
expect(result).toEqual([1, 2]);
});
it('returns empty array when no matches', () => {
const el = document.createElement('div');
el.className = 'wp-block-button is-style-outline';
const result = getVariantNumbersInTree(el, 'is-style-outline');
expect(result).toEqual([]);
});
it('deduplicates numbers', () => {
const el = document.createElement('div');
el.innerHTML = `
`;
const result = getVariantNumbersInTree(el, 'is-style-outline');
expect(result).toEqual([1]);
});
it('does not match classes without trailing number', () => {
const el = document.createElement('div');
el.className = 'is-style-outline is-style-outline-foo';
const result = getVariantNumbersInTree(el, 'is-style-outline');
expect(result).toEqual([]);
});
});
describe('is-style-ext-preset pattern (complex)', () => {
it('extracts number from complex class ending with --N', () => {
const el = document.createElement('div');
el.className =
'is-style-ext-preset--image--natural-1--image-1--content-bottom--13';
const result = getVariantNumbersInTree(el, 'is-style-ext-preset');
expect(result).toEqual([13]);
});
it('extracts multiple numbers from different elements', () => {
const el = document.createElement('div');
el.innerHTML = `
`;
const result = getVariantNumbersInTree(el, 'is-style-ext-preset');
expect(result).toEqual([12, 13]);
});
it('ignores classes without trailing --number', () => {
const el = document.createElement('div');
el.className = `
is-style-ext-preset-image-natural-1-image-1--content-bottom
is-style-ext-preset--image--natural-1--image-1--content-bottom
`;
const result = getVariantNumbersInTree(el, 'is-style-ext-preset');
expect(result).toEqual([]);
});
it('only extracts trailing number, not numbers in middle', () => {
const el = document.createElement('div');
el.className =
'is-style-ext-preset--image--natural-1--image-1--content-bottom--42';
const result = getVariantNumbersInTree(el, 'is-style-ext-preset');
expect(result).toEqual([42]);
});
});
it('returns empty array for null element', () => {
const result = getVariantNumbersInTree(null, 'is-style-outline');
expect(result).toEqual([]);
});
});
describe('getVariantNumbersInHtml', () => {
it('extracts numbers from HTML string', () => {
const html = '
Test
';
const result = getVariantNumbersInHtml(html, 'is-style-outline');
expect(result).toEqual([5]);
});
it('handles complex ext-preset patterns', () => {
const html =
'';
const result = getVariantNumbersInHtml(html, 'is-style-ext-preset');
expect(result).toEqual([1]);
});
});
describe('getVariantClassInfo', () => {
it('extracts prefix and number pairs', () => {
const el = document.createElement('div');
el.innerHTML = `
`;
const result = getVariantClassInfo(el, 'is-style-ext-preset');
expect(result).toEqual([
{ prefix: 'is-style-ext-preset--image--natural', number: 4 },
{ prefix: 'is-style-ext-preset--button--solid', number: 5 },
]);
});
it('extracts prefix for simple patterns', () => {
const el = document.createElement('div');
el.innerHTML = `
`;
const result = getVariantClassInfo(el, 'is-style-outline');
expect(result).toEqual([
{ prefix: 'is-style-outline', number: 3 },
{ prefix: 'is-style-outline', number: 7 },
]);
});
it('deduplicates by number', () => {
const el = document.createElement('div');
el.innerHTML = `
`;
const result = getVariantClassInfo(el, 'is-style-outline');
expect(result).toHaveLength(1);
expect(result[0].number).toBe(3);
});
it('returns empty array for null element', () => {
expect(getVariantClassInfo(null, 'is-style-outline')).toEqual([]);
});
it('returns empty array when no matches', () => {
const el = document.createElement('div');
el.className = 'wp-block-button';
const result = getVariantClassInfo(el, 'is-style-outline');
expect(result).toEqual([]);
});
});
describe('getVariantClassInfoFromHtml', () => {
it('extracts prefix and number pairs from HTML string', () => {
const html = `
`;
const result = getVariantClassInfoFromHtml(html, 'is-style-ext-preset');
expect(result).toEqual([
{ prefix: 'is-style-ext-preset--image--x', number: 4 },
{ prefix: 'is-style-ext-preset--button--y', number: 5 },
]);
});
it('handles simple patterns', () => {
const html = '
Test
';
const result = getVariantClassInfoFromHtml(html, 'is-style-outline');
expect(result).toEqual([{ prefix: 'is-style-outline', number: 5 }]);
});
});
describe('applyVariantNumberMapToHtml', () => {
describe('is-style-outline pattern', () => {
it('applies number mapping to simple pattern', () => {
const html =
'
Test
';
const map = new Map([[1, 5]]);
const result = applyVariantNumberMapToHtml(
html,
'is-style-outline',
map,
);
expect(result).toContain('is-style-outline--5');
expect(result).not.toMatch(/is-style-outline--1[^\d]/);
});
it('applies multiple mappings', () => {
const html = `
`;
const map = new Map([
[1, 10],
[2, 20],
]);
const result = applyVariantNumberMapToHtml(
html,
'is-style-outline',
map,
);
expect(result).toContain('is-style-outline--10');
expect(result).toContain('is-style-outline--20');
});
it('returns unchanged html if map is empty', () => {
const html = '
Test
';
const map = new Map();
const result = applyVariantNumberMapToHtml(
html,
'is-style-outline',
map,
);
expect(result).toContain('is-style-outline--1');
});
});
describe('is-style-ext-preset pattern', () => {
it('applies mapping to complex pattern', () => {
const html =
'';
const map = new Map([[1, 12]]);
const result = applyVariantNumberMapToHtml(
html,
'is-style-ext-preset',
map,
);
expect(result).toContain(
'is-style-ext-preset--image--natural-1--image-1--content-bottom--12',
);
});
it('preserves middle numbers when changing trailing number', () => {
const html =
'';
const map = new Map([[2, 13]]);
const result = applyVariantNumberMapToHtml(
html,
'is-style-ext-preset',
map,
);
expect(result).toContain('--natural-1--');
expect(result).toContain('--image-1--');
expect(result).toContain('content-bottom--13');
});
});
});
describe('patchVariantClasses', () => {
describe('is-style-outline pattern', () => {
it('patches HTML to match DOM variant numbers', () => {
const html =
'
Test
';
const el = document.createElement('div');
el.className = 'wp-block-button is-style-outline is-style-outline--5';
const result = patchVariantClasses(html, el, ['is-style-outline']);
expect(result).toContain('is-style-outline--5');
});
it('handles multiple variant numbers', () => {
const html = `
`;
const el = document.createElement('div');
el.innerHTML = `
`;
const result = patchVariantClasses(html, el, ['is-style-outline']);
expect(result).toContain('is-style-outline--10');
expect(result).toContain('is-style-outline--20');
});
it('returns unchanged HTML if no target numbers', () => {
const html = '
Test
';
const el = document.createElement('div');
el.className = 'wp-block-button';
const result = patchVariantClasses(html, el, ['is-style-outline']);
expect(result).toContain('is-style-outline--1');
});
});
describe('is-style-ext-preset pattern', () => {
it('patches complex variant classes', () => {
const html =
'';
const el = document.createElement('div');
el.innerHTML =
'';
const result = patchVariantClasses(html, el, ['is-style-ext-preset']);
expect(result).toContain('content-bottom--12');
});
it('handles multiple complex variants', () => {
const html = `
`;
const el = document.createElement('div');
el.innerHTML = `
`;
const result = patchVariantClasses(html, el, ['is-style-ext-preset']);
expect(result).toContain('is-style-ext-preset--a--12');
expect(result).toContain('is-style-ext-preset--b--13');
});
it('preserves non-variant classes', () => {
const html = ``;
const el = document.createElement('div');
el.innerHTML = ``;
const result = patchVariantClasses(html, el, ['is-style-ext-preset']);
// Should preserve non-variant classes
expect(result).toContain(
'is-style-ext-preset-image-natural-1-image-1--content-bottom',
);
// Should patch the variant class
expect(result).toContain('content-bottom--13');
});
});
describe('multiple bases', () => {
it('processes multiple base patterns', () => {
const html = `
`;
const el = document.createElement('div');
el.innerHTML = `
`;
const result = patchVariantClasses(html, el, [
'is-style-outline',
'is-style-ext-preset',
]);
expect(result).toContain('is-style-outline--10');
expect(result).toContain('is-style-ext-preset--a--20');
});
});
describe('element reordering (regression tests)', () => {
it('matches by element type when elements are in different order than DOM', () => {
// HTML has image first, button second
const html = `
`;
// DOM has button first, image second (different order)
const el = document.createElement('div');
el.innerHTML = `
`;
const result = patchVariantClasses(html, el, ['is-style-ext-preset']);
// Should match by prefix (element type), not by position
expect(result).toContain('is-style-ext-preset--image--x--11');
expect(result).toContain('is-style-ext-preset--button--y--10');
});
it('does not swap variant numbers when elements with same numbers are swapped', () => {
// Original: image--4 left, button--5 right
// After swap: button--5 left, image--4 right
// The variant numbers should stay with their elements
const html = `
`;
const el = document.createElement('div');
el.innerHTML = `
`;
const result = patchVariantClasses(html, el, ['is-style-ext-preset']);
// Button should get 5, image should get 4 (matched by type, not position)
expect(result).toContain('is-style-ext-preset--button--solid--5');
expect(result).toContain('is-style-ext-preset--image--natural--4');
});
it('handles multiple elements of the same type with position-based matching within type', () => {
// Two images and one button
const html = `
`;
const el = document.createElement('div');
el.innerHTML = `
`;
const result = patchVariantClasses(html, el, ['is-style-ext-preset']);
// Images should be matched by position within the image group
expect(result).toContain('is-style-ext-preset--image--a--10');
expect(result).toContain('is-style-ext-preset--image--a--20');
// Button matched by its type
expect(result).toContain('is-style-ext-preset--button--b--30');
});
});
});
});