### Run Playwright .NET tests Source: https://github.com/microsoft/playwright-dotnet/blob/main/CLAUDE.md Commands to install browser dependencies and execute the test suite. ```bash # Install browsers (pick one: chromium, firefox, webkit) pwsh src/Playwright/bin/Debug/netstandard2.0/playwright.ps1 install --with-deps chromium # Run tests BROWSER=chromium dotnet test ./src/Playwright.Tests/Playwright.Tests.csproj -c Debug -f net8.0 --logger:"console;verbosity=detailed" ``` ```bash BROWSER=chromium dotnet test ./src/Playwright.Tests/Playwright.Tests.csproj \ -c Debug -f net8.0 --logger:"console;verbosity=detailed" > /tmp/test-results.txt 2>&1 grep "^ Failed" /tmp/test-results.txt # list failures tail -5 /tmp/test-results.txt # summary ``` -------------------------------- ### Install and Use ReportGenerator for Test Coverage Source: https://github.com/microsoft/playwright-dotnet/blob/main/CONTRIBUTING.md Installs the dotnet-reportgenerator-globaltool, runs tests with coverage collection, generates a Cobertura report, and then uses reportgenerator to create an HTML coverage report. Ensure the reportgenerator tool is installed globally. ```shell dotnet tool install -g dotnet-reportgenerator-globaltool dotnet test -f net8.0 ./src/Playwright.Tests/Playwright.Tests.csproj --logger:"console;verbosity=detailed" -p:CollectCoverage=true -p:CoverletOutputFormat=cobertura -p:CoverletOutput="coverage.xml" --filter "Playwright.Tests.Assertions.PageAssertionsTests" reportgenerator -reports:src/Playwright.Tests/coverage.net8.0.xml -targetdir:coverage-report -reporttypes:HTML open coverage-report/index.html ``` -------------------------------- ### Launch Browser and Navigate Source: https://github.com/microsoft/playwright-dotnet/blob/main/README.md Launches a Chromium browser in non-headless mode, navigates to a URL, and takes a screenshot. Ensure Playwright is installed via NuGet. ```csharp using System.Threading.Tasks; using Microsoft.Playwright; using var playwright = await Playwright.CreateAsync(); await using var browser = await playwright.Chromium.LaunchAsync(new() { Headless = false }); var page = await browser.NewPageAsync(); await page.GotoAsync("https://playwright.dev/dotnet"); await page.ScreenshotAsync(new() { Path = "screenshot.png" }); ``` -------------------------------- ### Keyboard Event Listener Setup Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/input/keyboard.html Attaches event listeners to a textarea to log keyboard activity. Requires a textarea element to be present in the DOM. ```javascript window.result = ""; let textarea = document.querySelector('textarea'); textarea.focus(); textarea.addEventListener('keydown', event => { log('Keydown:', event.key, event.code, event.which, modifiers(event)); }); textarea.addEventListener('keypress', event => { log('Keypress:', event.key, event.code, event.which, event.charCode, modifiers(event)); }); textarea.addEventListener('keyup', event => { log('Keyup:', event.key, event.code, event.which, modifiers(event)); }); function modifiers(event) { let m = []; if (event.altKey) m.push('Alt') if (event.ctrlKey) m.push('Control'); if (event.shiftKey) m.push('Shift') return '[' + m.join(' ') + ']'; } function log(...args) { console.log.apply(console, args); result += args.join(' ') + '\n'; } function getResult() { let temp = result.trim(); result = ""; return temp; } ``` -------------------------------- ### Basic JavaScript Function Example Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/jscoverage/involved.html A simple JavaScript function demonstrating conditional logic and arrow functions. This can be used for basic scripting or utility functions. ```javascript function foo() { if (1 > 2) console.log(1); if (1 < 2) console.log(2); let x = 1 > 2 ? 'foo' : 'bar'; let y = 1 < 2 ? 'foo' : 'bar'; let z = () => {}; let q = () => {}; q(); } foo(); ``` -------------------------------- ### JavaScript Interstitial Logic Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/input/handle-locator.html Handles event listeners for clicks and the setup of interstitial visibility behaviors. ```javascript const target = document.querySelector('#target'); const interstitial = document.querySelector('#interstitial'); const close = document.querySelector('#close'); target.addEventListener('click', () => { window.clicked = (window.clicked ?? 0) + 1; }, false); close.addEventListener('click', () => { const closeInterstitial = () => { interstitial.classList.remove('visible'); target.classList.remove('hidden'); target.classList.remove('removed'); }; if (interstitial.classList.contains('timeout')) setTimeout(closeInterstitial, 3000); else closeInterstitial(); }); let timesToShow = 0; function setupAnnoyingInterstitial(event, times, capture) { timesToShow = times; const listener = () => { timesToShow--; interstitial.classList.add('visible'); interstitial.getBoundingClientRect(); if (!timesToShow && event !== 'none') target.removeEventListener(event, listener, capture === 'capture'); }; if (event === 'hide' || event === 'timeout') { target.classList.add('hidden'); listener(); if (event === 'timeout') interstitial.classList.add('timeout'); } else if (event === 'remove') { target.classList.add('removed'); listener(); } else if (event === 'none') { listener(); } else { target.addEventListener(event, listener, capture === 'capture'); } } ``` -------------------------------- ### Handle Drag and Drop Events Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/drag-n-drop.html JavaScript code to handle drag start, drag over, and drop events for drag-and-drop functionality. Ensure the target element is set up to receive dropped elements. ```javascript function dragstart_handler(ev) { ev.currentTarget.style.border = "dashed"; ev.dataTransfer.setData("text/plain", ev.target.id); } function dragover_handler(ev) { ev.preventDefault(); } function drop_handler(ev) { console.log("Drop"); ev.preventDefault(); var data = ev.dataTransfer.getData("text"); ev.target.appendChild(document.getElementById(data)); } ``` -------------------------------- ### Get Geolocation Coordinates in JavaScript Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/geolocation.html This snippet demonstrates how to asynchronously retrieve the user's current geolocation coordinates using the browser's Geolocation API and store them in a Promise. ```javascript window.geolocationPromise = new Promise(resolve => { navigator.geolocation.getCurrentPosition(position => { resolve({latitude: position.coords.latitude, longitude: position.coords.longitude}); }); }); ``` -------------------------------- ### Build the Playwright .NET solution Source: https://github.com/microsoft/playwright-dotnet/blob/main/CLAUDE.md Commands to prepare the environment and compile the source code. ```bash ./build.sh --download-driver # download the Playwright driver dotnet build ./src # build the entire solution ``` -------------------------------- ### Initialize WebGL Shader Program Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/screenshots/webgl.html Compiles vertex and fragment shaders and links them into a usable WebGL program. ```javascript function shaderProgram(gl, vs, fs) { var prog = gl.createProgram(); var addshader = function(type, source) { var s = gl.createShader((type == 'vertex') ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER); gl.shaderSource(s, source); gl.compileShader(s); if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) { throw "Could not compile "+type+ " shader:\n\n"+gl.getShaderInfoLog(s); } gl.attachShader(prog, s); }; addshader('vertex', vs); addshader('fragment', fs); gl.linkProgram(prog); if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) { throw "Could not link the shader program!"; } return prog; } ``` -------------------------------- ### Initialize Shadow DOM v1 Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/shadow.html Sets up a shadow root on the document body and appends an h1 and a button element. ```javascript let h1 = null; window.button = null; let clicked = false; window.addEventListener('DOMContentLoaded', () => { const shadowRoot = document.body.attachShadow({mode: 'open'}); h1 = document.createElement('h1'); h1.textContent = 'Hellow Shadow DOM v1'; button = document.createElement('button'); button.textContent = 'Click'; button.addEventListener('click', () => clicked = true); shadowRoot.appendChild(h1); shadowRoot.appendChild(button); }); ``` -------------------------------- ### Execute WebGL Rendering Pipeline Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/screenshots/webgl.html Initializes the WebGL context, compiles shaders, sets vertex data, and draws a triangle strip. ```javascript var gl = document.getElementById("webgl") .getContext("experimental-webgl"); gl.clearColor(0.8, 0.8, 0.8, 1); gl.clear(gl.COLOR_BUFFER_BIT); var prog = shaderProgram(gl, "attribute vec3 pos;"+ "void main() {"+ " gl_Position = vec4(pos, 2.0);"+ "}", "void main() {"+ " gl_FragColor = vec4(0.5, 0.5, 1.0, 1.0);"+ "}" ); gl.useProgram(prog); attributeSetFloats(gl, prog, "pos", 3, [ -1, 0, 0, 0, 1, 0, 0, -1, 0, 1, 0, 0 ]); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); ``` -------------------------------- ### Initialize React Components in Browser Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/mui.html Sets up global variables for creating and rendering React components directly in the browser's console. Useful for debugging or interactive testing. ```javascript window.e = React.createElement; window.reactRoot = document.querySelector('.react-root'); window.renderComponent = c => ReactDOM.render(c, window.reactRoot); ``` -------------------------------- ### Initialize Selection Test Environment Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/input/select.html Sets up the result tracking object and event listeners for select element interactions. ```javascript window.result = { onInput: null, onChange: null, onBubblingChange: null, onBubblingInput: null, }; let select = document.querySelector('select'); function makeEmpty() { for (let i = select.options.length - 1; i >= 0; --i) { select.remove(i); } } function makeMultiple() { select.setAttribute('multiple', true); } select.addEventListener('input', () => { result.onInput = Array.from(select.querySelectorAll('option:checked')).map((option) => { return option.value; }); }, false); select.addEventListener('change', () => { result.onChange = Array.from(select.querySelectorAll('option:checked')).map((option) => { return option.value; }); }, false); document.body.addEventListener('input', () => { result.onBubblingInput = Array.from(select.querySelectorAll('option:checked')).map((option) => { return option.value; }); }, false); document.body.addEventListener('change', () => { result.onBubblingChange = Array.from(select.querySelectorAll('option:checked')).map((option) => { return option.value; }); }, false); ``` -------------------------------- ### Set up iframe and button with event listeners Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/button-overlay-oopif.html This JavaScript code sets up an iframe and a button within a web page. The iframe loads a 'grid.html' page, and the button triggers a global flag when clicked. Ensure the 'grid.html' is accessible. ```javascript window.addEventListener('DOMContentLoaded', () => { const iframe = document.createElement('iframe'); const url = new URL(location.href); url.hostname = url.hostname === 'localhost' ? '127.0.0.1' : 'localhost'; url.pathname = '/grid.html'; iframe.src = url.toString(); document.body.append(iframe); const button = document.createElement('button'); button.textContent = 'CLICK ME'; button.addEventListener('click', () => { window.BUTTON_CLICKED = true; }, false); document.body.append(button); }, false); ``` -------------------------------- ### Initialize and listen to a Web Worker Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/worker/worker.html Instantiates a new worker from a script file and sets up a callback to log received messages. ```javascript var worker = new Worker('worker.js'); worker.onmessage = function(message) { console.log(message.data); }; ``` -------------------------------- ### Implement React Components and Mounting Logic Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/reading-list/react17.html Defines various React components including AppHeader, NewBook, ColorButton, ButtonGrid, BookItem, BookList, and the main App component. Includes global functions for mounting the application to the DOM. ```javascript const e = React.createElement; function AppHeader(props) { return e(React.Fragment, null, e('h1', null, `reactjs@${React.version}`), e('h3', null, `Reading List: ${props.bookCount}`), ); } class NewBook extends React.Component { constructor(props) { super(props); this.state = ''; } onInput(event) { this.state = event.target.value; } render() { return e(React.Fragment, null, e('input', {onInput: this.onInput.bind(this)}, null), e('button', { onClick: () => this.props.onNewBook(this.state), }, `new book`), ); } } function ColorButton (props) { return e('button', {className: props.color, disabled: !props.enabled}, 'button ' + props.nested.index); } function ButtonGrid() { const buttons = []; for (let i = 0; i < 9; ++i) { buttons.push(e(ColorButton, { color: ['red', 'green', 'blue'][i % 3], enabled: i % 2 === 0, nested: { index: i, value: i + 0.1, } }, null)); }; return e(React.Fragment, null, ...buttons); } class BookItem extends React.Component { render() { return e('div', null, this.props.name); } } class BookList extends React.Component { render() { return e('ol', null, this.props.books.map(book => e('li', {key: book.name}, e(BookItem, { name: book.name })))); } } class App extends React.Component { constructor(props) { super(props); this.mountPoint = React.createRef(); this.state = { books: [ {name: 'Pride and Prejudice' }, {name: 'To Kill a Mockingbird' }, {name: 'The Great Gatsby' }, ], }; } render() { return e(React.Fragment, null, e(AppHeader, {bookCount: this.state.books.length}, null), e(NewBook, {onNewBook: bookName => this.onNewBook(bookName)}, null), e(BookList, {books: this.state.books}, null), e(ButtonGrid, null, null), e('div', {ref: this.mountPoint}, null), ); } onNewBook(bookName) { this.setState({ books: [...this.state.books, {name: bookName}], }); } } window.mountApp = element => ReactDOM.render(e(App, null, null), element); window.app = window.mountApp(document.getElementById('root')); window.mountNestedApp = () => window.mountApp(window.app.mountPoint.current); ``` -------------------------------- ### Simulate Touch Events in JavaScript Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/input/touches.html This JavaScript snippet sets up event listeners for touchstart, touchend, and touchmove on a button element. It logs the identifiers of the changed touches for each event. Use this to test touch interactions in a browser environment. ```javascript window.result = []; const button = document.querySelector('button'); button.style.height = '200px'; button.style.width = '200px'; button.focus(); button.addEventListener('touchstart', event => { log('Touchstart:', ...Array.from(event.changedTouches).map(touch => touch.identifier)); }); button.addEventListener('touchend', event => { log('Touchend:', ...Array.from(event.changedTouches).map(touch => touch.identifier)); }); button.addEventListener('touchmove', event => { log('Touchmove:', ...Array.from(event.changedTouches).map(touch => touch.identifier)); }); function log(...args) { console.log.apply(console, args); result.push(args.join(' ')); } function getResult() { let temp = result; result = []; return temp; } ``` -------------------------------- ### Mount Vue App and Define Components Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/reading-list/vue3.html This JavaScript code defines a Vue.js application with several components, including a header, a form to add new books, a list of books, and a button grid. It demonstrates how to create, configure, and mount a Vue application to a specified DOM element. The `mountApp` function returns the mounted app instance. ```javascript window.mountApp = element => { const app = Vue.createApp({ template: `
`, data() { return { books: [ {name: 'Pride and Prejudice'}, {name: 'To Kill a Mockingbird'}, {name: 'The Great Gatsby'}, ], }; }, methods: { addNewBook(name) { this.books.push({name}); } }, }); app.component('app-header', { template: `

vuejs@${Vue.version}

Reading List: {{ bookCount }}

`, props: [ 'bookCount' ], }); app.component('new-book', { data() { return { name: '', } }, template: ` `, emits: ['newbook'], methods: { onNewBook() { this.$emit('newbook', this.name); } }, }); app.component('book-item', { template: `
{{ name }}
`, props: ['name'], }); app.component('book-list', { props: ['books'], template: `
`, }); app.component('color-button', { props: { color: String, enabled: Boolean, nested: { index: Number, value: Number, }, }, template: ` `, }); app.component('button-grid', { render() { const buttons = []; const ColorButton = Vue.resolveComponent('color-button'); for (let i = 0; i < 9; ++i) { buttons.push(Vue.h(ColorButton, { color: ['red', 'green', 'blue'][i % 3], enabled: i % 2 === 0, nested: { index: i, value: i + 0.1, } }, null)); }; return buttons; } }); return app.mount(element); } ``` -------------------------------- ### Define Vue Components and Mount Application Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/reading-list/vue2.html Registers multiple Vue components and provides a global function to mount the application to a DOM element. ```javascript Vue.component('app-header', { template: `

vuejs@${Vue.version}

Reading List: {{ bookCount }}

`, props: [ 'bookCount' ], }); Vue.component('new-book', { data() { return { name: '', } }, template: `
`, emits: ['newbook'], methods: { onNewBook() { this.$emit('newbook', this.name); } }, }); Vue.component('book-item', { template: `
{{ name }}
`, props: ['name'], }); Vue.component('book-list', { props: ['books'], template: `
`, }); Vue.component('color-button', { props: { color: String, enabled: Boolean, nested: Object, }, template: ` `, }); Vue.component('button-grid', { render(createElement) { const buttons = []; for (let i = 0; i < 9; ++i) { buttons.push(createElement('color-button', { props: { color: ['red', 'green', 'blue'][i % 3], enabled: i % 2 === 0, nested: { index: i, value: i + 0.1, } } }, null)); }; return createElement('div', null, buttons); } }); window.mountApp = element => new Vue({ el: element, template: `
`, data() { return { books: [ {name: 'Pride and Prejudice' }, {name: 'To Kill a Mockingbird' }, {name: 'The Great Gatsby' }, ], }; }, methods: { addNewBook(name) { console.log('here'); this.books.push({name}); } }, }); window.app = window.mountApp(document.querySelector('#root div')); window.mountNestedApp = () => window.mountApp(window.app.$refs.mountPoint); ``` -------------------------------- ### Load and Instantiate WebAssembly Table Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/wasm/table2.html Use this function to load a WebAssembly module that imports a table. Ensure the table is correctly defined with its initial size and element type. The instantiation process links the JavaScript table to the WASM module. ```javascript async function loadTable() { const tbl = new WebAssembly.Table({ initial: 2, element: 'anyfunc' }); const response = await fetch('table2.wasm'); const body = await response.arrayBuffer(); await WebAssembly.instantiate(body, { js: { tbl: tbl } }); return `${tbl.get(0)( )}, ${tbl.get(1)()}`; } ``` -------------------------------- ### Set up DOM for Playwright Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/grid-iframe-in-shadow.html This JavaScript code sets up the DOM by creating a container, attaching a shadow root, and appending an iframe. It's used to prepare the environment for Playwright interactions. ```javascript body, html { margin: 0; } window.addEventListener('DOMContentLoaded', () => { const container = document.createElement('div'); document.body.appendChild(container); const shadow = container.attachShadow({mode: 'open'}); const iframe = document.createElement('iframe'); iframe.src = './grid.html'; iframe.style.cssText = 'width: 300px; height: 300px; margin: 0; padding: 0; border: 0;'; shadow.appendChild(iframe); }); ``` -------------------------------- ### Format code and create semantic commits Source: https://github.com/microsoft/playwright-dotnet/blob/main/CLAUDE.md Commands for maintaining code style and submitting changes via Git and GitHub CLI. ```bash dotnet format ./src/ -v:diag ``` ```bash git checkout -b fix-39562 # ... make changes ... git add git commit -m "$(cat <<'EOF' fix(proxy): handle SOCKS proxy authentication Fixes: https://github.com/microsoft/playwright/issues/39562 EOF )" git push origin fix-39562 gh pr create --repo microsoft/playwright --head username:fix-39562 \ --title "fix(proxy): handle SOCKS proxy authentication" \ --body "$(cat <<'EOF' ## Summary - Fixes https://github.com/microsoft/playwright/issues/39562 EOF )" ``` -------------------------------- ### Regenerate Certificates with Bash Script Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/client-certificates/README.md Run this bash script to regenerate all client certificates. Ensure the script has execute permissions. ```bash bash generate.sh ``` -------------------------------- ### React App Component and Mounting Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/reading-list/react16.html The main application component that orchestrates other components and manages the list of books. It includes methods for adding new books and mounting the application to the DOM. ```javascript class App extends React.Component { constructor(props) { super(props); this.mountPoint = React.createRef(); this.state = { books: [ {name: 'Pride and Prejudice' }, {name: 'To Kill a Mockingbird' }, {name: 'The Great Gatsby' }, ], }; } render() { return e(React.Fragment, null, e(AppHeader, {bookCount: this.state.books.length}, null), e(NewBook, {onNewBook: bookName => this.onNewBook(bookName)}, null), e(BookList, {books: this.state.books}, null), e(ButtonGrid, null, null), e('div', {ref: this.mountPoint}, null), ); } onNewBook(bookName) { this.setState({ books: [...this.state.books, {name: bookName}], }); } } window.mountApp = element => ReactDOM.render(e(App, null, null), element); window.app = window.mountApp(document.getElementById('root')); window.mountNestedApp = () => window.mountApp(window.app.mountPoint.current); ``` -------------------------------- ### Inject CSS and Generate DOM Elements Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/overflow.html Applies basic grid styling and appends 200 div elements with alternating background colors to the document body. ```css body { margin: 0; padding: 0; } div { display: inline-flex; width: 50px; height: 50px; border-right: 1px solid black; border-bottom: 1px solid black; } ``` ```javascript const colors = ['#222', '#444', '#666', '#888', '#aaa']; for (let i = 0; i < 200; ++i) { const div = document.createElement('div'); div.style.setProperty('background-color', colors[i % 5]); document.body.appendChild(div); } ``` -------------------------------- ### Simulate Local Storage Iteration in Browser Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/redirectloop1.html This JavaScript snippet simulates iteration using localStorage. It appends 'a' to a stored string and redirects if the string length reaches 10. Use this to test browser-based loops or state management. ```javascript setTimeout(() => { const iter = window.localStorage.iter || ''; window.localStorage.iter = iter + 'a'; if (iter.length === 10) return; window.location.href = window.location.href.replace('loop1', 'loop2'); }, 1); ``` -------------------------------- ### Initialize Worker and Handle Messages Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/worker/worker-http-import.html Creates a new worker from the specified script and updates the status element with received data. ```javascript new Worker('worker-http-import.js').addEventListener("message", ({ data }) => { document.getElementById("status").innerText = data; }); ``` -------------------------------- ### Listen to Load and DOMContentLoaded Events Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/load-event/load-event.html This JavaScript snippet sets up event listeners for 'load' and 'DOMContentLoaded' events and pushes a string to a results array when the 'load' event fires. It also pushes a string after the script tag. Use this to verify event order and timing. ```javascript window.results = []; window.addEventListener('load', function() { window.results.push('load'); }); window.addEventListener('DOMContentLoaded', function() { window.results.push('DOMContentLoaded'); }); window.results.push('script tag after after module'); ``` -------------------------------- ### Define Box Layout and Animation Styles Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/grid.html Provides CSS rules for box sizing, flex alignment, and a keyframe animation for movement. ```css body { margin: 0; padding: 0; } .box { font-family: arial; display: inline-flex; align-items: center; justify-content: center; margin: 0; padding: 0; width: 50px; height: 50px; box-sizing: border-box; border: 1px solid darkgray; } ::-webkit-scrollbar { display: none; } @keyframes move { from { left: -500px; background-color: cyan; } to { left: 0; background-color: rgb(255, 210, 204); } } .box.animation { position: relative; animation: 2s linear 0s move forwards; } ``` -------------------------------- ### Simulate Button Click and Capture Event Data Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/input/button.html This JavaScript snippet sets up an event listener on a button to capture click event details. It initializes result variables and then updates them when the button is clicked. Use this to verify click interactions and event properties in your tests. ```javascript window.result = 'Was not clicked'; window.offsetX = undefined; window.offsetY = undefined; window.pageX = undefined; window.pageY = undefined; window.shiftKey = undefined; window.pageX = undefined; window.pageY = undefined; window.bubbles = undefined; document.querySelector('button').addEventListener('click', e => { result = 'Clicked'; offsetX = e.offsetX; offsetY = e.offsetY; pageX = e.pageX; pageY = e.pageY; shiftKey = e.shiftKey; bubbles = e.bubbles; cancelable = e.cancelable; composed = e.composed; }, false); ``` -------------------------------- ### Roll Playwright.NET Driver Source: https://github.com/microsoft/playwright-dotnet/blob/main/ROLLING.md Execute the build script to roll the Playwright.NET driver. This command handles downloading and setting the new driver, regenerating API and transport channels, and updating the README file. ```bash ./build.sh --roll ``` -------------------------------- ### Create Nested Shadow DOM Structure Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/deep-shadow.html This JavaScript code demonstrates how to programmatically create a complex DOM structure with nested shadow roots. It's useful for setting up intricate test environments or simulating complex UI components. ```javascript window.addEventListener('DOMContentLoaded', () => { const outer = document.createElement('section'); document.body.appendChild(outer); const root1 = document.createElement('div'); root1.setAttribute('id', 'root1'); outer.appendChild(root1); const shadowRoot1 = root1.attachShadow({mode: 'open'}); const span1 = document.createElement('span'); span1.setAttribute('data-testid', 'foo'); span1.textContent = 'Hello from root1'; shadowRoot1.appendChild(span1); const root2 = document.createElement('div'); shadowRoot1.appendChild(root2); const shadowRoot2 = root2.attachShadow({mode: 'open'}); const span2 = document.createElement('span'); span2.setAttribute('data-testid', 'foo'); span2.setAttribute('id', 'target'); span2.textContent = 'Hello from root2'; shadowRoot2.appendChild(span2); const root3 = document.createElement('div'); shadowRoot1.appendChild(root3); const shadowRoot3 = root3.attachShadow({mode: 'open'}); const span3 = document.createElement('span'); span3.setAttribute('data-testid', 'foo'); span3.textContent = 'Hello from root3'; shadowRoot3.appendChild(span3); const span4 = document.createElement('span'); span4.textContent = 'Hello from root3 #2'; span4.setAttribute('attr', 'value space'); shadowRoot3.appendChild(span4); }); ``` -------------------------------- ### Handle beforeunload Event Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/beforeunload.html Use this snippet to add an event listener for 'beforeunload'. It sets the return value for Chromium/WebKit and uses preventDefault() for Firefox. Ensure the event listener is added before navigation. ```javascript window.addEventListener('beforeunload', event => { // Chromium & WebKit way. event.returnValue = 'Leave?'; // Firefox way. event.preventDefault(); }); ``` -------------------------------- ### Trigger Blob Download in Browser Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/download-blob.html Uses a hidden anchor element to initiate a file download from a string or binary data blob. Ensure this is executed in a browser environment where the DOM is accessible. ```javascript const download = (data, filename) => { const a = document.createElement("a"); a.style = "display: none"; document.body.appendChild(a); a.style = "display: none"; const blob = new Blob([data], { type: "octet/stream" }); const url = window.URL.createObjectURL(blob); a.href = url; a.download = filename; a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); }; const downloadIt = () => { download("Hello world", "example.txt"); } ``` -------------------------------- ### Apply CSS layout styles Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/wrappedlink.html Defines root font, body flexbox alignment, and specific div transformations. ```css :root { font-family: monospace; } body { display: flex; align-items: center; justify-content: center; } div { width: 10ch; word-wrap: break-word; border: 1px solid blue; transform: rotate(33deg); line-height: 8ch; padding: 2ch; } a { margin-left: 7ch; } ``` -------------------------------- ### Generate Dynamic Palette and DOM Elements Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/grid.html Creates a color palette using HSL values and populates the document body with boxes containing digit images. ```javascript document.addEventListener('DOMContentLoaded', function() { function generatePalette(amount) { var result = []; var hueStep = 360 / amount; for (var i = 0; i < amount; ++i) result.push('hsl(' + (hueStep * i) + ', 100%, 90%)'); return result; } var palette = generatePalette(100); for (var i = 0; i < 200; ++i) { var box = document.createElement('div'); box.classList.add('box'); box.style.setProperty('background-color', palette[i % palette.length]); var x = i; do { var digit = x % 10; x = (x / 10)|0; var img = document.createElement('img'); img.src = `./digits/${digit}.png`; box.insertBefore(img, box.firstChild); } while (x); document.body.appendChild(box); } }); ``` -------------------------------- ### Mount Vue App to DOM Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/reading-list/vue3.html This JavaScript code mounts the previously defined Vue application to a specific DOM element identified by the ID '#root div'. It also makes the mounted app instance available globally as `window.app` for debugging or further interaction. ```javascript window.app = window.mountApp(document.querySelector('#root div')); ``` -------------------------------- ### React AppHeader Component Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/reading-list/react16.html Displays the React version and the current book count. Use this component to provide a header for your React application. ```javascript const e = React.createElement; class AppHeader extends React.Component { render() { return e(React.Fragment, null, e('h1', null, `reactjs@${React.version}`), e('h3', null, `Reading List: ${this.props.bookCount}`), ); } } ``` -------------------------------- ### React Component Definitions Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/reading-list/react15.html A suite of React components including AppHeader, ColorButton, ButtonGrid, NewBook, BookItem, BookList, and the main App container. ```javascript const e = React.createElement; class AppHeader extends React.Component { render() { return e('div', null, e('h1', null, `reactjs@${React.version}`), e('h3', null, `Reading List: ${this.props.bookCount}`), ); } } class ColorButton extends React.Component { render() { return e('button', {className: this.props.color, disabled: !this.props.enabled}, 'button ' + this.props.nested.index); } } class ButtonGrid extends React.Component { render() { const buttons = []; for (let i = 0; i < 9; ++i) { buttons.push(e(ColorButton, { color: ['red', 'green', 'blue'][i % 3], enabled: i % 2 === 0, nested: { index: i, value: i + 0.1, } }, null)); }; return e('div', null, ...buttons); } } class NewBook extends React.Component { constructor(props) { super(props); this.state = { text: '', }; } onInput(event) { this.state.text = event.target.value; } render() { return e('div', null, e('input', {onInput: this.onInput.bind(this)}, null), e('button', { onClick: () => this.props.onNewBook(this.state.text), }, `new book`), ); } } class BookItem extends React.Component { render() { return e('div', null, this.props.name); } } class BookList extends React.Component { render() { return e('ol', null, this.props.books.map(book => e('li', {key: book.name}, e(BookItem, { name: book.name })))); } } class App extends React.Component { constructor(props) { super(props); this.state = { books: [ {name: 'Pride and Prejudice' }, {name: 'To Kill a Mockingbird' }, {name: 'The Great Gatsby' }, ], }; } render() { return e('div', null, e(AppHeader, {bookCount: this.state.books.length}, null), e(NewBook, {onNewBook: bookName => this.onNewBook(bookName)}, null), e(BookList, {books: this.state.books}, null), e(ButtonGrid, null, null), e('div', { ref: 'mountPoint', }, null), ); } onNewBook(bookName) { this.setState({ books: [...this.state.books, {name: bookName}], }); } } window.mountApp = element => ReactDOM.render(e(App, null, null), element); window.app = window.mountApp(document.getElementById('root')); window.mountNestedApp = () => window.mountApp(window.app.refs.mountPoint); ``` -------------------------------- ### Register Service Worker and Fetch Content Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/serviceworkers/fetchdummy/sw.html Registers a service worker from 'sw.js' and provides an asynchronous function to fetch resources. ```javascript window.registrationPromise = navigator.serviceWorker.register('sw.js'); window.activationPromise = new Promise(resolve => navigator.serviceWorker.oncontrollerchange = resolve); async function fetchDummy(name) { const response = await fetch(name); if (!response.ok) return 'FAILURE: ' + response.statusText; const text = await response.text(); return text; } ``` -------------------------------- ### Define a Custom Element with Shadow DOM Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/shadow-dom-link.html Registers a new custom element named 'my-link' that clones a template into an open shadow root. ```javascript customElements.define('my-link', class extends HTMLElement { constructor() { super(); const template = document.getElementById('my-link-template'); const templateContent = template.content; this.attachShadow({mode: 'open'}).appendChild( templateContent.cloneNode(true) ); } } ); window.clickCount = 0; ``` -------------------------------- ### Simulate Checkbox Events in JavaScript Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/input/checkbox.html Attaches event listeners to a checkbox to track 'change', 'click', and other events. Records the checked state for specific events and logs all triggered events. ```javascript window.result = { check: null, events: [], }; let checkbox = document.querySelector('input'); const events = [ 'change', 'click', 'dblclick', 'input', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover', 'mouseup', ]; for (let event of events) { checkbox.addEventListener(event, () => { if (['change', 'click', 'dblclick', 'input'].includes(event) === true) { result.check = checkbox.checked; } result.events.push(event); }, false); } ``` -------------------------------- ### Set Vertex Attribute Data Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/screenshots/webgl.html Creates a buffer, uploads float data, and configures the vertex attribute pointer for a specific program attribute. ```javascript function attributeSetFloats(gl, prog, attr_name, rsize, arr) { gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(arr), gl.STATIC_DRAW); var attr = gl.getAttribLocation(prog, attr_name); gl.enableVertexAttribArray(attr); gl.vertexAttribPointer(attr, rsize, gl.FLOAT, false, 0, 0); } ``` -------------------------------- ### Create and Style Div Elements with JavaScript Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/overflow-large.html This JavaScript code dynamically creates and styles 'div' elements, appending them to the document body. It's useful for generating visual elements based on specific logic or data. ```javascript body { margin: 0; padding: 0; } div { display: inline-flex; width: 50px; height: 50px; border-right: 1px solid black; border-bottom: 1px solid black; } const colors = ['#222', '#444', '#666', '#888', '#aaa']; for (let i = 0; i < 1000; ++i) { const div = document.createElement('div'); div.style.setProperty('background-color', colors[i % 5]); document.body.appendChild(div); } ``` -------------------------------- ### Register Service Worker and Handle Activation Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/serviceworkers/fetch/sw.html Register a service worker and wait for its activation. This is useful for setting up background tasks or offline capabilities. ```javascript window.registrationPromise = navigator.serviceWorker.register('sw.js'); window.activationPromise = new Promise(resolve => navigator.serviceWorker.oncontrollerchange = resolve); ``` -------------------------------- ### Play Video for One Frame Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/player.html Plays the video and pauses it after one frame. Useful for frame-by-frame analysis. Requires a video element in the DOM. ```javascript async function playOneFrame() { const video = document.querySelector('video'); const result = new Promise(r => video.onpause = r); video.ontimeupdate = () => { video.pause(); video.ontimeupdate = null; }; video.play(); return await result; } ``` -------------------------------- ### Simulate Button Click with Rotation Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/input/rotatedButton.html This snippet demonstrates how to interact with a button that has a CSS transform applied, simulating a click. Ensure the 'clicked' function is defined in the page's scope. ```javascript Click target button { transform: rotateY(180deg); } window.result = 'Was not clicked'; function clicked() { result = 'Clicked'; } ``` -------------------------------- ### CSS Button Layout Configuration Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/offscreenbuttons.html Defines absolute positioning and offsets for a series of buttons within the document body. ```css button { position: absolute; width: 100px; height: 20px; margin: 0; } body, html { margin: 0; padding: 0; height: 100%; width: 100%; position: relative; } div { position: absolute; left: 0; top: 0; right: 0; bottom: 0; } #btn0 { right: 0px; top: 0; } #btn1 { right: -10px; top: 25px; } #btn2 { right: -20px; top: 50px; } #btn3 { right: -30px; top: 75px; } #btn4 { right: -40px; top: 100px; } #btn5 { right: -50px; top: 125px; } #btn6 { right: -60px; top: 150px; } #btn7 { right: -70px; top: 175px; } #btn8 { right: -80px; top: 200px; } #btn9 { right: -90px; top: 225px; } #btn10 { right: -100px; top: 250px; } ``` -------------------------------- ### React NewBook Component Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/reading-list/react16.html An input field and a button to add a new book. It manages its own input state and calls a callback function when the 'new book' button is clicked. ```javascript class NewBook extends React.Component { constructor(props) { super(props); this.state = ''; } onInput(event) { this.state = event.target.value; } render() { return e(React.Fragment, null, e('input', {onInput: this.onInput.bind(this)}, null), e('button', { onClick: () => this.props.onNewBook(this.state), }, `new book`), ); } } ``` -------------------------------- ### Play Video for N Frames Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/player.html Plays the video for a specified number of frames by repeatedly calling playOneFrame. Requires a video element in the DOM. ```javascript async function playNFrames(n) { for (let i = 0; i < n; i++) await playOneFrame(); } ``` -------------------------------- ### React ButtonGrid Component Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/reading-list/react16.html Generates a grid of ColorButton components, each with a different color and enabled state based on its position. This component demonstrates loop-based component generation. ```javascript class ButtonGrid extends React.Component { render() { const buttons = []; for (let i = 0; i < 9; ++i) { buttons.push(e(ColorButton, { color: ['red', 'green', 'blue'][i % 3], enabled: i % 2 === 0, nested: { index: i, value: i + 0.1, } }, null)); }; return e(React.Fragment, null, ...buttons); } } ``` -------------------------------- ### React BookItem Component Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/reading-list/react16.html A simple component to display the name of a single book. It receives the book name as a prop. ```javascript class BookItem extends React.Component { render() { return e('div', null, this.props.name); } } ``` -------------------------------- ### JavaScript Frame Attachment Function Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/frames/nested-frames.html Creates and appends an iframe to the document body, returning a promise that resolves once the frame has loaded. ```javascript async function attachFrame(frameId, url) { var frame = document.createElement('iframe'); frame.src = url; frame.id = frameId; document.body.appendChild(frame); await new Promise(x => frame.onload = x); return 'kazakh'; } ``` -------------------------------- ### Perform Canvas Drawing Operations Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/screenshots/canvas.html Initializes a 2D context on a canvas element to draw and clear rectangular shapes. ```javascript const canvas = document.querySelector('canvas'); const ctx = canvas.getContext('2d'); ctx.fillRect(25, 25, 100, 100); ctx.clearRect(45, 45, 60, 60); ctx.strokeRect(50, 50, 50, 50); ``` -------------------------------- ### Add click event listener Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/wrappedlink.html Attaches a click listener to the first anchor element to set a global property. ```javascript document.querySelector('a').addEventListener('click', () => { window.__clicked = true; }); ``` -------------------------------- ### React BookList Component Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/reading-list/react16.html Renders an ordered list of books using the BookItem component. It maps over an array of book objects passed via props. ```javascript class BookList extends React.Component { render() { return e('ol', null, this.props.books.map(book => e('li', {key: book.name}, e(BookItem, { name: book.name })))); } } ``` -------------------------------- ### Generate Feature Report with Modernizr Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/modernizr.html This script generates a report of Modernizr features and device-specific events, then displays it on the page. It filters out internal Modernizr properties and adds custom checks for device motion and orientation. ```javascript const report = {}; for (const name in Modernizr) { if (name.startsWith('__')) continue; if (['on', 'testAllProps', 'testProp', 'addTest', 'prefixed'].includes(name)) continue; let value = Modernizr[name]; report[name] = value; } report['devicemotion2'] = 'ondevicemotion' in window; report['deviceorientation2'] = 'orientation' in window; report['deviceorientation3'] = 'ondeviceorientation' in window; document.body.style.whiteSpace = 'pre'; document.body.textContent = JSON.stringify(report, undefined, 4); window.report = JSON.parse(document.body.textContent); ``` -------------------------------- ### Change background color via URL hash Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/background-color.html Updates the document body background color based on the hash fragment of the current URL. Requires the hash to be a valid CSS color string. ```javascript function changeBackground() { const color = location.hash.substr(1); document.body.style.backgroundColor = color; } ``` -------------------------------- ### Capture input events from textarea and input elements Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/input/textarea.html Attaches event listeners to textarea and input elements to store their values in a global result variable. ```javascript window.result = ''; let textarea = document.querySelector('textarea'); textarea.addEventListener('input', () => result = textarea.value, false); let input = document.querySelector('input'); input.addEventListener('input', () => result = input.value, false); ``` -------------------------------- ### Mount Nested Vue App Source: https://github.com/microsoft/playwright-dotnet/blob/main/src/Playwright.Tests/assets/reading-list/vue3.html This JavaScript function `mountNestedApp` mounts another instance of the Vue application. It targets a specific mount point within the already mounted app, indicated by `window.app.$refs.mountPoint`. This is useful for creating nested or independent Vue applications within a larger structure. ```javascript window.mountNestedApp = () => window.mountApp(window.app.$refs.mountPoint); ```