-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
fix(): Fix regex to parse the viewbox attribute to be more strict #10636
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Review or Edit in CodeSandboxOpen the branch in Web Editor • VS Code • Insiders |
Build Stats
|
does this work with a viewbox like is this even valid? it('viewBox with mixed separators', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', '0,0 100,50');
element.setAttribute('width', '200');
element.setAttribute('height', '100');
const result = applyViewboxTransform(element);
expect(result.viewBoxWidth).toBe(100);
expect(result.viewBoxHeight).toBe(50);
}); |
is that on spec? if is on spec it should work. let's add a test case for it. |
https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/viewBox
the part and/or threw me off, meaning it allows mixed stuff |
Yes SVG is crazy specs. |
apparently not export const reViewBoxAttrValue = new RegExp(
'^\\s*' +
'(' + reNum + ')' +
'(?:\\s*,?\\s+|\\s*,\\s*)' +
'(' + reNum + ')' +
'(?:\\s*,?\\s+|\\s*,\\s*)' +
'(' + reNum + ')' +
'(?:\\s*,?\\s+|\\s*,\\s*)' +
'(' + reNum + ')' +
'\\s*$'
); maybe this |
i don't get it, the comma is there. |
also I think we should not just test these constants but fully the here are some test cases I came up with describe('applyViewboxTransform()', () => {
it('return empty object for non-viewBox elements', () => {
const element = document.createElement('rect');
const result = applyViewboxTransform(element);
expect(result).toEqual({});
});
it('return empty object for unsupported elements', () => {
const element = document.createElement('circle');
const result = applyViewboxTransform(element);
expect(result).toEqual({});
});
it('handle missing viewBox with valid dimensions', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('width', '100');
element.setAttribute('height', '200');
const result = applyViewboxTransform(element);
expect(result).toEqual({
width: 100,
height: 200,
});
});
it('handle missing viewBox and missing dimensions', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
const result = applyViewboxTransform(element);
expect(result).toEqual({
width: 0,
height: 0,
});
});
it('handle missing viewBox with percentage dimensions', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('width', '100%');
element.setAttribute('height', '100%');
const result = applyViewboxTransform(element);
expect(result).toEqual({
width: 0,
height: 0,
});
});
it('handle x/y translation for missing viewBox', () => {
const parent = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'symbol',
);
parent.appendChild(element);
element.setAttribute('x', '10');
element.setAttribute('y', '20');
element.setAttribute('width', '100');
element.setAttribute('height', '200');
const result = applyViewboxTransform(element);
expect(result).toEqual({
width: 100,
height: 200,
});
expect(element.getAttribute('transform')).toContain('translate(10 20)');
expect(element.hasAttribute('x')).toBe(false);
expect(element.hasAttribute('y')).toBe(false);
});
it('handles invalid viewBox with 3 values', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', '0 0 408');
element.setAttribute('width', '100');
element.setAttribute('height', '200');
const result = applyViewboxTransform(element);
expect(result).toEqual({
width: 100,
height: 200,
});
});
it('handle invalid viewBox with malformed values', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', 'invalid values here');
element.setAttribute('width', '100');
element.setAttribute('height', '200');
const result = applyViewboxTransform(element);
expect(result).toEqual({
width: 100,
height: 200,
});
});
it('handle empty viewBox', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', '');
element.setAttribute('width', '100');
element.setAttribute('height', '200');
const result = applyViewboxTransform(element);
expect(result).toEqual({
width: 100,
height: 200,
});
});
it('parse valid viewBox with dimensions', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', '0 0 100 50');
element.setAttribute('width', '200');
element.setAttribute('height', '100');
const result = applyViewboxTransform(element);
expect(result).toEqual({
width: 200,
height: 100,
minX: 0,
minY: 0,
viewBoxWidth: 100,
viewBoxHeight: 50,
});
});
it('parse valid viewBox without dimensions', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', '10 20 100 50');
const result = applyViewboxTransform(element);
expect(result).toEqual({
width: 100,
height: 50,
minX: -10,
minY: -20,
viewBoxWidth: 100,
viewBoxHeight: 50,
});
});
it('handle negative viewBox values', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', '-10 -20 100 50');
element.setAttribute('width', '200');
element.setAttribute('height', '100');
const result = applyViewboxTransform(element);
expect(result).toEqual({
width: 200,
height: 100,
minX: 10,
minY: 20,
viewBoxWidth: 100,
viewBoxHeight: 50,
});
});
it('handle decimal viewBox values', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', '0.5 1.5 100.5 50.5');
element.setAttribute('width', '200');
element.setAttribute('height', '100');
const result = applyViewboxTransform(element);
expect(result).toEqual({
width: 200,
height: 100,
minX: -0.5,
minY: -1.5,
viewBoxWidth: 100.5,
viewBoxHeight: 50.5,
});
});
it('not generate transform for identity case', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', '0 0 100 50');
element.setAttribute('width', '100');
element.setAttribute('height', '50');
const result = applyViewboxTransform(element);
expect(result).toEqual({
width: 100,
height: 50,
minX: 0,
minY: 0,
viewBoxWidth: 100,
viewBoxHeight: 50,
});
expect(element.getAttribute('transform')).toBeFalsy();
});
it('generate transform matrix for scaling', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', '0 0 100 50');
element.setAttribute('width', '200');
element.setAttribute('height', '100');
applyViewboxTransform(element);
const gElement = element.querySelector('g');
expect(gElement).toBeTruthy();
expect(gElement?.getAttribute('transform')).toContain(
'matrix(2 0 0 2 0 0)',
);
});
it('generate transform matrix with translation', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', '10 20 100 50');
element.setAttribute('width', '200');
element.setAttribute('height', '100');
applyViewboxTransform(element);
const gElement = element.querySelector('g');
expect(gElement?.getAttribute('transform')).toContain(
'matrix(2 0 0 2 -20 -40)',
);
});
it('handle x/y attributes with viewBox', () => {
const parent = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'symbol',
);
parent.appendChild(element);
element.setAttribute('viewBox', '0 0 100 50');
element.setAttribute('width', '200');
element.setAttribute('height', '100');
element.setAttribute('x', '5');
element.setAttribute('y', '10');
applyViewboxTransform(element);
expect(element.getAttribute('transform')).toContain('translate(5 10)');
expect(element.getAttribute('transform')).toContain('matrix(2 0 0 2 0 0)');
});
it('create g wrapper for svg elements', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', '0 0 100 50');
element.setAttribute('width', '200');
element.setAttribute('height', '100');
const child = document.createElementNS(
'http://www.w3.org/2000/svg',
'rect',
);
element.appendChild(child);
applyViewboxTransform(element);
const gElement = element.querySelector('g');
expect(gElement).toBeTruthy();
expect(gElement?.contains(child)).toBe(true);
expect(element.children.length).toBe(1);
expect(element.children[0]).toBe(gElement);
});
it('apply transform directly to non-svg elements', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'symbol',
);
element.setAttribute('viewBox', '0 0 100 50');
element.setAttribute('width', '200');
element.setAttribute('height', '100');
element.setAttribute('transform', 'rotate(45)');
applyViewboxTransform(element);
expect(element.getAttribute('transform')).toContain('rotate(45)');
expect(element.getAttribute('transform')).toContain('matrix(2 0 0 2 0 0)');
expect(element.querySelector('g')).toBeFalsy();
});
it('handle scientific notation in viewBox', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', '1e-2 2e-3 1e2 5e1');
element.setAttribute('width', '200');
element.setAttribute('height', '100');
const result = applyViewboxTransform(element);
expect(result).toEqual({
width: 200,
height: 100,
minX: -0.01,
minY: -0.002,
viewBoxWidth: 100,
viewBoxHeight: 50,
});
});
it('viewBox with mixed separators', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', '0,0 100,50');
element.setAttribute('width', '200');
element.setAttribute('height', '100');
const result = applyViewboxTransform(element);
expect(result.viewBoxWidth).toBe(100);
expect(result.viewBoxHeight).toBe(50);
});
it('handle whitespace in viewBox', () => {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg',
);
element.setAttribute('viewBox', ' 0 0 100 50 ');
element.setAttribute('width', '200');
element.setAttribute('height', '100');
const result = applyViewboxTransform(element);
expect(result.viewBoxWidth).toBe(100);
expect(result.viewBoxHeight).toBe(50);
});
}); not sure if these all are valid test cases but we could pick some out |
yeah i could test higher level, but now i m changing the regex, i test the regex. I can copy paste those tests somewhere else but when i do those changes i have to hope other unit tests would catch regressions. visual or unit |
oh i see the issue, some spaces are optional, other are mandatory. that is wrong. all spaces are optional |
Yeah the tests i proposed are for a new file where apply viewbox lives |
apply viewbox transform is such a confusing function :( |
Yes, that is why i proposed more compound tests, because i wasnt sure if these return values were actually corect, mainly these with -0 |
Yeah no sure why the minus. i forgot. |
Description
closes #10635
In Action