Repository: oppia/oppia
File: core/templates/services/svg-sanitizer.service.spec.ts (TypeScript)

Code before:
            tags: ['circel'],
            attrs: ['svg:data-name'],
          },
          correctURL:
            'https://github.com/oppia/oppia/issues/new?title=Uploaded%20SVG%20image%20looks%20distorted%20in%20the%20preview&body=The%20image%20file%20is%20attached%20below%3A%0A%0A%7B%7B%20IMAGE_HERE%20%7D%7D%0A%0AScreenshots%20of%20the%20problem%3A%0A%0A%7B%7B%20SCREENSHOTS_HERE%20%7D%7D%0A%0AThe%20invalid%20tags%20and%20attributes%20reported%3A%0ATags%3A%20circel%2C%20%0AAttributes%3A%20svg%3Adata-name',
        },
      ];
      testCases.forEach(testCase => {
        let testCaseResult = svgSanitizerService.getIssueURL(
          testCase.invalidTagsAndAttributes
        );
        expect(testCaseResult).toEqual(testCase.correctURL);
      });
    }
  );

  it('should remove unwanted/unnecessary attributes and return a safe SVG', () => {
    const testCases = [
      {
        svgString:
          '<svg width="100" height="100"' +
          ' xmlns="http://www.w3.org/2000/svg"' +
          ' xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"' +
          ' xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"' +
          ' xmlns:xlink="http://www.w3.org/1999/xlink"' +
          ' xmlns:dc="http://purl.org/dc/elements/1.1/">' +
          ' <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />' +
          ' </svg>',
        expectedSvgString:
          '<svg xmlns="http://www.w3.org/2000/svg"' +
          ' xmlns:xlink="http://www.w3.org/1999/xlink"' +
          ' width="100" height="100">' +
          ' <circle cx="50" cy="50" r="40" stroke="black"' +
          ' stroke-width="3" fill="red"/>' +
          ' </svg>',
      },
      {
        svgString:
          '<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"' +
          ' xmlns:dc="http://purl.org/dc/elements/1.1/"' +
          ' xmlns:xlink="http://www.w3.org/1999/xlink"' +
          ' xmlns="http://www.w3.org/2000/svg"' +
          ' xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"' +
          ' width="100" height="100">' +
          ' <circle cx="50" cy="50" r="40" stroke="black"' +
          ' stroke-width="3" fill="red" />' +
          ' </svg>',
        expectedSvgString:
          '<svg xmlns:xlink="http://www.w3.org/1999/xlink"' +
          ' xmlns="http://www.w3.org/2000/svg" width="100" height="100">' +
          ' <circle cx="50" cy="50" r="40"' +

Review comment (suggestion):
Having some simple one-line comments above each test, along the lines of 

`// In this image, xmlns:rdf, xmlns:sodipodi, xmlns:dc are removed.`

would help make it easier for the reader to see what's going on.

Code after:
            tags: ['circel'],
            attrs: ['svg:data-name'],
          },
          correctURL:
            'https://github.com/oppia/oppia/issues/new?title=Uploaded%20SVG%20image%20looks%20distorted%20in%20the%20preview&body=The%20image%20file%20is%20attached%20below%3A%0A%0A%7B%7B%20IMAGE_HERE%20%7D%7D%0A%0AScreenshots%20of%20the%20problem%3A%0A%0A%7B%7B%20SCREENSHOTS_HERE%20%7D%7D%0A%0AThe%20invalid%20tags%20and%20attributes%20reported%3A%0ATags%3A%20circel%2C%20%0AAttributes%3A%20svg%3Adata-name',
        },
      ];
      testCases.forEach(testCase => {
        let testCaseResult = svgSanitizerService.getIssueURL(
          testCase.invalidTagsAndAttributes
        );
        expect(testCaseResult).toEqual(testCase.correctURL);
      });
    }
  );

  // This test checks that unwanted attributes like xmlns:rdf, xmlns:sodipodi, and xmlns:dc
  // are removed from the SVG while keeping valid attributes unchanged.
  // Note: The order of attributes may change because when the SVG is parsed into a DOM document
  // and then serialized back to a string, browsers standardize the attribute order.
  // This is an expected behavior and does not affect the validity of the SVG.
  it('should remove unwanted/unnecessary attributes and return a safe SVG', () => {
    const testCases = [
      // In this image, xmlns:rdf, xmlns:sodipodi, and xmlns:dc are removed.
      {
        svgString:
          '<svg width="100" height="100"' +
          ' xmlns="http://www.w3.org/2000/svg"' +
          ' xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"' +
          ' xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"' +
          ' xmlns:xlink="http://www.w3.org/1999/xlink"' +
          ' xmlns:dc="http://purl.org/dc/elements/1.1/">' +
          ' <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />' +
          ' </svg>',
        expectedSvgString:
          '<svg xmlns="http://www.w3.org/2000/svg"' +
          ' xmlns:xlink="http://www.w3.org/1999/xlink"' +
          ' width="100" height="100">' +
          ' <circle cx="50" cy="50" r="40" stroke="black"' +
          ' stroke-width="3" fill="red"/>' +
          ' </svg>',
      },
      // In this image, xmlns:rdf, xmlns:sodipodi, and xmlns:dc are removed.
      {
        svgString:
          '<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"' +
          ' xmlns:dc="http://purl.org/dc/elements/1.1/"' +
          ' xmlns:xlink="http://www.w3.org/1999/xlink"' +
          ' xmlns="http://www.w3.org/2000/svg"' +
          ' xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"' +
          ' width="100" height="100">' +