mirror of
				https://github.com/microsoft/playwright.git
				synced 2025-06-26 21:40:17 +00:00 
			
		
		
		
	
							parent
							
								
									36c5395d2d
								
							
						
					
					
						commit
						10a82f862c
					
				| @ -124,7 +124,7 @@ function snapshotNodes(snapshot: FrameSnapshot): NodeSnapshot[] { | ||||
| } | ||||
| 
 | ||||
| function snapshotScript() { | ||||
|   function applyPlaywrightAttributes(shadowAttribute: string, scrollTopAttribute: string, scrollLeftAttribute: string) { | ||||
|   function applyPlaywrightAttributes(shadowAttribute: string, scrollTopAttribute: string, scrollLeftAttribute: string, styleSheetAttribute: string) { | ||||
|     const scrollTops: Element[] = []; | ||||
|     const scrollLefts: Element[] = []; | ||||
| 
 | ||||
| @ -152,6 +152,17 @@ function snapshotScript() { | ||||
|         template.remove(); | ||||
|         visit(shadowRoot); | ||||
|       } | ||||
| 
 | ||||
|       if ('adoptedStyleSheets' in (root as any)) { | ||||
|         const adoptedSheets: CSSStyleSheet[] = [...(root as any).adoptedStyleSheets]; | ||||
|         for (const element of root.querySelectorAll(`template[${styleSheetAttribute}]`)) { | ||||
|           const template = element as HTMLTemplateElement; | ||||
|           const sheet = new CSSStyleSheet(); | ||||
|           (sheet as any).replaceSync(template.getAttribute(styleSheetAttribute)); | ||||
|           adoptedSheets.push(sheet); | ||||
|         } | ||||
|         (root as any).adoptedStyleSheets = adoptedSheets; | ||||
|     } | ||||
|     }; | ||||
|     visit(document); | ||||
| 
 | ||||
| @ -172,5 +183,6 @@ function snapshotScript() { | ||||
|   const kShadowAttribute = '__playwright_shadow_root_'; | ||||
|   const kScrollTopAttribute = '__playwright_scroll_top_'; | ||||
|   const kScrollLeftAttribute = '__playwright_scroll_left_'; | ||||
|   return `\n(${applyPlaywrightAttributes.toString()})('${kShadowAttribute}', '${kScrollTopAttribute}', '${kScrollLeftAttribute}')`; | ||||
|   const kStyleSheetAttribute = '__playwright_style_sheet_'; | ||||
|   return `\n(${applyPlaywrightAttributes.toString()})('${kShadowAttribute}', '${kScrollTopAttribute}', '${kScrollLeftAttribute}', '${kStyleSheetAttribute}')`; | ||||
| } | ||||
|  | ||||
| @ -39,6 +39,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string) { | ||||
|   const kShadowAttribute = '__playwright_shadow_root_'; | ||||
|   const kScrollTopAttribute = '__playwright_scroll_top_'; | ||||
|   const kScrollLeftAttribute = '__playwright_scroll_left_'; | ||||
|   const kStyleSheetAttribute = '__playwright_style_sheet_'; | ||||
| 
 | ||||
|   // Symbols for our own info on Nodes/StyleSheets.
 | ||||
|   const kSnapshotFrameId = Symbol('__playwright_snapshot_frameid_'); | ||||
| @ -296,6 +297,15 @@ export function frameSnapshotStreamer(snapshotStreamer: string) { | ||||
|           } | ||||
|         }; | ||||
| 
 | ||||
|         const visitChildStyleSheet = (child: CSSStyleSheet) => { | ||||
|           const snapshot = visitStyleSheet(child); | ||||
|           if (snapshot) { | ||||
|             result.push(snapshot.n); | ||||
|             expectValue(child); | ||||
|             equals = equals && snapshot.equals; | ||||
|           } | ||||
|         }; | ||||
| 
 | ||||
|         if (nodeType === Node.DOCUMENT_FRAGMENT_NODE) | ||||
|           attrs[kShadowAttribute] = 'open'; | ||||
| 
 | ||||
| @ -345,6 +355,15 @@ export function frameSnapshotStreamer(snapshotStreamer: string) { | ||||
|           } | ||||
|           for (let child = node.firstChild; child; child = child.nextSibling) | ||||
|             visitChild(child); | ||||
|           let documentOrShadowRoot = null; | ||||
|           if (node.ownerDocument!.documentElement === node) | ||||
|             documentOrShadowRoot = node.ownerDocument; | ||||
|           else if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) | ||||
|             documentOrShadowRoot = node; | ||||
|           if (documentOrShadowRoot) { | ||||
|             for (const sheet of (documentOrShadowRoot as any).adoptedStyleSheets || []) | ||||
|               visitChildStyleSheet(sheet); | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
|         // Process iframe src attribute before bailing out since it depends on a symbol, not the DOM.
 | ||||
| @ -397,6 +416,21 @@ export function frameSnapshotStreamer(snapshotStreamer: string) { | ||||
|         return checkAndReturn(result); | ||||
|       }; | ||||
| 
 | ||||
|       const visitStyleSheet = (sheet: CSSStyleSheet) => { | ||||
|         const data = ensureCachedData(sheet); | ||||
|         const oldCSSText = data.cssText; | ||||
|         const cssText = this._updateStyleElementStyleSheetTextIfNeeded(sheet) || ''; | ||||
|         if (cssText === oldCSSText) | ||||
|           return { equals: true, n: [[ snapshotNumber - data.ref![0], data.ref![1] ]] }; | ||||
|         data.ref = [snapshotNumber, nodeCounter++]; | ||||
|         return { | ||||
|           equals: false, | ||||
|           n: ['template', { | ||||
|             [kStyleSheetAttribute]: cssText, | ||||
|           }] | ||||
|         }; | ||||
|       }; | ||||
| 
 | ||||
|       let html: NodeSnapshot; | ||||
|       if (document.documentElement) { | ||||
|         const { n } = visitNode(document.documentElement)!; | ||||
|  | ||||
| @ -75,6 +75,14 @@ it.describe('snapshots', () => { | ||||
|     expect(distillSnapshot(snapshot2)).toBe('<style>button { color: blue; }</style><BUTTON>Hello</BUTTON>'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should have a custom doctype', async ({page, server, toImpl, snapshotter}) => { | ||||
|     await page.goto(server.EMPTY_PAGE); | ||||
|     await page.setContent('<!DOCTYPE foo><body>hi</body>'); | ||||
| 
 | ||||
|     const snapshot = await snapshotter.captureSnapshot(toImpl(page), 'snapshot'); | ||||
|     expect(distillSnapshot(snapshot)).toBe('<!DOCTYPE foo>hi'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should respect subresource CSSOM change', async ({ page, server, toImpl, snapshotter }) => { | ||||
|     await page.goto(server.EMPTY_PAGE); | ||||
|     await page.route('**/style.css', route => { | ||||
| @ -166,6 +174,49 @@ it.describe('snapshots', () => { | ||||
|       expect(distillSnapshot(snapshot)).toBe('<BUTTON data="two">Hello</BUTTON>'); | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   it('should contain adopted style sheets', async ({ page, toImpl, contextFactory, snapshotPort, snapshotter, browserName }) => { | ||||
|     it.skip(browserName !== 'chromium', 'Constructed stylesheets are only in Chromium.'); | ||||
|     await page.setContent('<button>Hello</button>'); | ||||
|     await page.evaluate(() => { | ||||
|       const sheet = new CSSStyleSheet(); | ||||
|       sheet.addRule('button', 'color: red'); | ||||
|       (document as any).adoptedStyleSheets = [sheet]; | ||||
| 
 | ||||
|       const div = document.createElement('div'); | ||||
|       const root = div.attachShadow({ | ||||
|         mode: 'open' | ||||
|       }); | ||||
|       root.append('foo'); | ||||
|       const sheet2 = new CSSStyleSheet(); | ||||
|       sheet2.addRule(':host', 'color: blue'); | ||||
|       (root as any).adoptedStyleSheets = [sheet2]; | ||||
|       document.body.appendChild(div); | ||||
|     }); | ||||
|     const snapshot1 = await snapshotter.captureSnapshot(toImpl(page), 'snapshot1'); | ||||
| 
 | ||||
|     const previewContext = await contextFactory(); | ||||
|     const previewPage = await previewContext.newPage(); | ||||
|     previewPage.on('console', console.log); | ||||
|     await previewPage.goto(`http://localhost:${snapshotPort}/snapshot/`); | ||||
|     await previewPage.evaluate(snapshotId => { | ||||
|       (window as any).showSnapshot(snapshotId); | ||||
|     }, `${snapshot1.snapshot().pageId}?name=snapshot1`); | ||||
|     // wait for the render frame to load
 | ||||
|     while (previewPage.frames().length < 2) | ||||
|       await new Promise(f => previewPage.once('frameattached', f)); | ||||
|     // wait for it to render
 | ||||
|     await previewPage.frames()[1].waitForSelector('button'); | ||||
|     const buttonColor = await previewPage.frames()[1].$eval('button', button => { | ||||
|       return window.getComputedStyle(button).color; | ||||
|     }); | ||||
|     expect(buttonColor).toBe('rgb(255, 0, 0)'); | ||||
|     const divColor = await previewPage.frames()[1].$eval('div', div => { | ||||
|       return window.getComputedStyle(div).color; | ||||
|     }); | ||||
|     expect(divColor).toBe('rgb(0, 0, 255)'); | ||||
|     await previewContext.close(); | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| function distillSnapshot(snapshot) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Joel Einbinder
						Joel Einbinder