From d3b93c15902215e550f01f8beadbd4b1a40d6244 Mon Sep 17 00:00:00 2001 From: Marlon Harrison <92547717+marlon-ionic@users.noreply.github.com> Date: Mon, 13 Jun 2022 16:55:41 -0500 Subject: [PATCH] feat(mock-doc): add matrix and tspan props for svgelement (#3408) this pr adds the following members per request from ZenDesk ticket 41657: - Added following members were added to MockDoc: createSVGPoint(), getBBox(), getComputedTextLength(), getCTM(), getScreenCTM() - add focus() and blur() to `MockElement`, removing them from `MockSVGElement` (which inherits from the former) --- src/mock-doc/element.ts | 141 ++++++++++++++++++++- src/mock-doc/node.ts | 6 + src/mock-doc/test/html-parse.spec.ts | 35 +++++ src/testing/puppeteer/puppeteer-element.ts | 2 +- 4 files changed, 177 insertions(+), 7 deletions(-) diff --git a/src/mock-doc/element.ts b/src/mock-doc/element.ts index 3a9a0317702..da2ca330214 100644 --- a/src/mock-doc/element.ts +++ b/src/mock-doc/element.ts @@ -65,7 +65,28 @@ export function createElementNS(ownerDocument: any, namespaceURI: string, tagNam if (namespaceURI === 'http://www.w3.org/1999/xhtml') { return createElement(ownerDocument, tagName); } else if (namespaceURI === 'http://www.w3.org/2000/svg') { - return new MockSVGElement(ownerDocument, tagName); + switch (tagName.toLowerCase()) { + case 'text': + case 'tspan': + case 'tref': + case 'altglyph': + case 'textpath': + return new MockSVGTextContentElement(ownerDocument, tagName); + case 'circle': + case 'ellipse': + case 'image': + case 'line': + case 'path': + case 'polygon': + case 'polyline': + case 'rect': + case 'use': + return new MockSVGGraphicsElement(ownerDocument, tagName); + case 'svg': + return new MockSVGSVGElement(ownerDocument, tagName); + default: + return new MockSVGElement(ownerDocument, tagName); + } } else { return new MockElement(ownerDocument, tagName); } @@ -237,6 +258,95 @@ patchPropAttributes(MockScriptElement.prototype, { type: String, }); +export class MockDOMMatrix { + static fromMatrix() { + return new MockDOMMatrix(); + } + a: number = 1; + b: number = 0; + c: number = 0; + d: number = 1; + e: number = 0; + f: number = 0; + m11: number = 1; + m12: number = 0; + m13: number = 0; + m14: number = 0; + m21: number = 0; + m22: number = 1; + m23: number = 0; + m24: number = 0; + m31: number = 0; + m32: number = 0; + m33: number = 1; + m34: number = 0; + m41: number = 0; + m42: number = 0; + m43: number = 0; + m44: number = 1; + is2D: boolean = true; + isIdentity: boolean = true; + inverse() { + return new MockDOMMatrix(); + } + flipX() { + return new MockDOMMatrix(); + } + flipY() { + return new MockDOMMatrix(); + } + multiply() { + return new MockDOMMatrix(); + } + rotate() { + return new MockDOMMatrix(); + } + rotateAxisAngle() { + return new MockDOMMatrix(); + } + rotateFromVector() { + return new MockDOMMatrix(); + } + scale() { + return new MockDOMMatrix(); + } + scaleNonUniform() { + return new MockDOMMatrix(); + } + skewX() { + return new MockDOMMatrix(); + } + skewY() { + return new MockDOMMatrix(); + } + toJSON() {} + toString() {} + transformPoint() { + return new MockDOMPoint(); + } + translate() { + return new MockDOMMatrix(); + } +} + +export class MockDOMPoint { + w: number = 1; + x: number = 0; + y: number = 0; + z: number = 0; + toJSON() {} + matrixTransform() { + return new MockDOMMatrix(); + } +} + +export class MockSVGRect { + height: number = 10; + width: number = 10; + x: number = 0; + y: number = 0; +} + export class MockStyleElement extends MockHTMLElement { sheet: MockCSSStyleSheet; @@ -266,7 +376,6 @@ export class MockStyleElement extends MockHTMLElement { setStyleElementText(this, value); } } - export class MockSVGElement extends MockElement { // SVGElement properties and methods get ownerSVGElement(): SVGSVGElement { @@ -275,10 +384,6 @@ export class MockSVGElement extends MockElement { get viewportElement(): SVGElement { return null; } - - focus() { - /**/ - } onunload() { /**/ } @@ -299,6 +404,30 @@ export class MockSVGElement extends MockElement { } } +export class MockSVGGraphicsElement extends MockSVGElement { + getBBox(_options?: { clipped: boolean; fill: boolean; markers: boolean; stroke: boolean }): MockSVGRect { + return new MockSVGRect(); + } + getCTM(): MockDOMMatrix { + return new MockDOMMatrix(); + } + getScreenCTM(): MockDOMMatrix { + return new MockDOMMatrix(); + } +} + +export class MockSVGSVGElement extends MockSVGGraphicsElement { + createSVGPoint(): MockDOMPoint { + return new MockDOMPoint(); + } +} + +export class MockSVGTextContentElement extends MockSVGGraphicsElement { + getComputedTextLength(): number { + return 0; + } +} + export class MockBaseElement extends MockHTMLElement { constructor(ownerDocument: any) { super(ownerDocument, 'base'); diff --git a/src/mock-doc/node.ts b/src/mock-doc/node.ts index 393deda66cd..f49d4b006c6 100644 --- a/src/mock-doc/node.ts +++ b/src/mock-doc/node.ts @@ -235,6 +235,10 @@ export class MockElement extends MockNode { return shadowRoot; } + blur() { + /**/ + } + get shadowRoot() { return this.__shadowRoot || null; } @@ -316,6 +320,8 @@ export class MockElement extends MockNode { return this.children[0] || null; } + focus(_options?: { preventScroll?: boolean }) {} + getAttribute(attrName: string) { if (attrName === 'style') { if (this.__style != null && this.__style.length > 0) { diff --git a/src/mock-doc/test/html-parse.spec.ts b/src/mock-doc/test/html-parse.spec.ts index 17d29264e77..eb3286ae924 100644 --- a/src/mock-doc/test/html-parse.spec.ts +++ b/src/mock-doc/test/html-parse.spec.ts @@ -2,6 +2,7 @@ import { createFragment } from '../document'; import { MockDocument } from '../document'; import { NODE_TYPES } from '../constants'; import { parseHtmlToDocument, parseHtmlToFragment } from '../parse-html'; +import { MockDOMMatrix, MockDOMPoint, MockSVGRect, MockSVGSVGElement, MockSVGTextContentElement } from '../element'; describe('parseHtml', () => { let doc: MockDocument; @@ -87,6 +88,40 @@ describe('parseHtml', () => { expect(doc.body.firstElementChild.attributes.item(0).name).toEqual('viewBox'); }); + it('svg matrix members', () => { + doc = new MockDocument(` + + + + + + `); + const svgElem: MockSVGSVGElement = doc.body.firstElementChild?.firstElementChild as MockSVGSVGElement; + expect(svgElem).toBeDefined(); + expect(svgElem.getBBox()).toEqual(new MockSVGRect()); + expect(svgElem.createSVGPoint()).toEqual(new MockDOMPoint()); + expect(svgElem.getScreenCTM()).toEqual(new MockDOMMatrix()); + expect(svgElem.getCTM()).toEqual(new MockDOMMatrix()); + }); + + it('svg text members', () => { + doc = new MockDocument(` + + + Hello + world + + + `); + const text: MockSVGTextContentElement = doc.body.firstElementChild?.firstElementChild as MockSVGTextContentElement; + expect(text).toBeDefined(); + expect(text.tagName).toEqual('text'); + + const tspan: MockSVGTextContentElement = text.firstElementChild as MockSVGTextContentElement; + expect(tspan).toBeDefined(); + expect(tspan.getComputedTextLength()).toEqual(0); + }); + it('template', () => { doc = new MockDocument(` diff --git a/src/testing/puppeteer/puppeteer-element.ts b/src/testing/puppeteer/puppeteer-element.ts index 7582376396e..1c9db5f9742 100644 --- a/src/testing/puppeteer/puppeteer-element.ts +++ b/src/testing/puppeteer/puppeteer-element.ts @@ -55,7 +55,7 @@ export class E2EElement extends MockHTMLElement implements pd.E2EElementInternal await this._page.waitForChanges(); } - async focus() { + override async focus() { await this._elmHandle.focus(); await this._page.waitForChanges(); }