50+ real interactive Cypress labs.
The same 50+ widgets from the Playwright playground, but with Cypress-native code (cy.intercept, cy.session, selectFile, includeShadowDom). Mirror labs let you compare frameworks side-by-side and pick the right tool for each project.
Dynamic Locators
Locate elements whose IDs change on every page load using resilient Playwright locators like [id^="submit-"] regex matches.
describe('Dynamic Locators', () => {
it('clicks button with dynamic id', () => {
cy.visit('/p/playwright-labs.html#dynamic-locators');
class=class="s">"c">// Use data-cy or attribute selector — survives id changes
cy.get('button[id^="submit-"]').click();
cy.get('#result-dynamic-id').should('have.text', 'Clicked!');
});
});
describe('Dynamic Locators', () => {
it('clicks button with dynamic id', () => {
cy.visit('/p/playwright-labs.html#dynamic-locators');
cy.get('button[id^="submit-"]').click();
cy.get('#result-dynamic-id').should('have.text', 'Clicked!');
});
});
Auto Waiting
Playwright auto-waits for elements to be visible, enabled, and stable before interacting — no more flaky page.waitForTimeout() calls.
describe('Auto Waiting', () => {
it('clicks delayed button without cy.wait()', () => {
cy.visit('/p/playwright-labs.html#auto-waiting');
class=class="s">"c">// Cypress auto-retries — no cy.wait() needed
cy.get('#delayed-button').click({ timeout: 10000 });
cy.get('#result-auto-wait').should('have.text', 'Loaded!');
});
});
describe('Auto Waiting', () => {
it('clicks delayed button without cy.wait()', () => {
cy.visit('/p/playwright-labs.html#auto-waiting');
cy.get('#delayed-button').click({ timeout: 10000 });
cy.get('#result-auto-wait').should('have.text', 'Loaded!');
});
});
Frames (iFrame)
Use Playwright's frameLocator() to interact with elements inside same-origin iframes. Modern alternative to legacy frame(name) API.
describe('Frames (iFrame)', () => {
it('clicks button inside iframe', () => {
cy.visit('/p/playwright-labs.html#frames');
cy.frameLoaded('#lab-iframe');
cy.iframe('#lab-iframe').find('#iframe-button').click();
cy.iframe('#lab-iframe').find('#iframe-result').should('have.text', 'Iframe clicked!');
});
});
class=class="s">"c">// Requires cypress-iframe plugin: npm i -D cypress-iframe
class=class="s">"c">// In cypress/support/e2e.js: import 'cypress-iframe';
describe('Frames (iFrame)', () => {
it('clicks button inside iframe', () => {
cy.visit('/p/playwright-labs.html#frames');
cy.frameLoaded('#lab-iframe');
cy.iframe('#lab-iframe').find('#iframe-button').click();
cy.iframe('#lab-iframe').find('#iframe-result').should('have.text', 'Iframe clicked!');
});
});
class=class="s">"c">// Requires cypress-iframe plugin: npm i -D cypress-iframe
class=class="s">"c">// In cypress/support/e2e.js: import 'cypress-iframe';
Nested Frames
Chain frameLocator() calls to drill into frames within frames — the modern alternative to traversing window.frames.
describe('Nested Frames', () => {
it('clicks button in nested iframe', () => {
cy.visit('/p/playwright-labs.html#nested-frames');
class=class="s">"c">// Cypress requires entering each iframe level
cy.frameLoaded('#outer-frame');
cy.iframe('#outer-frame').find('#inner-frame').should('exist');
class=class="s">"c">// For deeper nesting, use the cypress-iframe plugin's iframe()
cy.iframe('#outer-frame').within(() => {
cy.iframe('#inner-frame').find('#nested-button').click();
});
});
});
describe('Nested Frames', () => {
it('clicks button in nested iframe', () => {
cy.visit('/p/playwright-labs.html#nested-frames');
cy.frameLoaded('#outer-frame');
cy.iframe('#outer-frame').find('#inner-frame').should('exist');
cy.iframe('#outer-frame').within(() => {
cy.iframe('#inner-frame').find('#nested-button').click();
});
});
});
Drag and Drop
Use dragTo() for simple HTML5 drag and drop, or manual mouse.down()/move()/up() for pixel-perfect scenarios.
describe('Drag and Drop', () => {
it('drags card to done column', () => {
cy.visit('/p/playwright-labs.html#drag-and-drop');
class=class="s">"c">// Requires @4tw/cypress-drag-drop plugin
cy.get('[data-testid="card-a"]').drag('[data-testid="col-done"]');
cy.get('[data-testid="col-done"]').find('[data-testid="card-a"]').should('exist');
});
});
class=class="s">"c">// npm i -D @4tw/cypress-drag-drop
class=class="s">"c">// In cypress/support/e2e.js: require('@4tw/cypress-drag-drop');
describe('Drag and Drop', () => {
it('drags card to done column', () => {
cy.visit('/p/playwright-labs.html#drag-and-drop');
cy.get('[data-testid="card-a"]').drag('[data-testid="col-done"]');
cy.get('[data-testid="col-done"]').find('[data-testid="card-a"]').should('exist');
});
});
Alert Dialogs
Auto-dismiss native window.alert() dialogs by registering a page.on('dialog') handler before triggering the action.
describe('Alert Dialogs', () => {
it('auto-accepts alert', () => {
const stub = cy.stub();
cy.on('window:alert', stub);
cy.visit('/p/playwright-labs.html#alerts');
cy.get('#alert-button').click()
.then(() => expect(stub).to.be.calledWith('Hello from QA CSEIAN!'));
cy.get('#result-alert').should('have.text', 'Alert accepted');
});
});
describe('Alert Dialogs', () => {
it('auto-accepts alert', () => {
const stub = cy.stub();
cy.on('window:alert', stub);
cy.visit('/p/playwright-labs.html#alerts');
cy.get('#alert-button').click()
.then(() => expect(stub).to.be.calledWith('Hello from QA CSEIAN!'));
cy.get('#result-alert').should('have.text', 'Alert accepted');
});
});
Confirm Dialogs
Accept or dismiss window.confirm() dialogs programmatically by passing true/false to dialog.accept().
describe('Confirm Dialogs', () => {
it('accepts confirm dialog', () => {
cy.visit('/p/playwright-labs.html#confirm-dialogs');
cy.on('window:confirm', () => true);
cy.get('#confirm-button').click();
cy.get('#result-confirm').should('have.text', 'Confirmed');
});
});
describe('Confirm Dialogs', () => {
it('accepts confirm dialog', () => {
cy.visit('/p/playwright-labs.html#confirm-dialogs');
cy.on('window:confirm', () => true);
cy.get('#confirm-button').click();
cy.get('#result-confirm').should('have.text', 'Confirmed');
});
});
Prompt Dialogs
Provide text input to window.prompt() dialogs by passing the text to dialog.accept('text').
describe('Prompt Dialogs', () => {
it('provides text to prompt', () => {
cy.visit('/p/playwright-labs.html#prompt-dialogs');
cy.window().then(win => cy.stub(win, 'prompt').returns('Cypress'));
cy.get('#prompt-button').click();
cy.get('#result-prompt').should('have.text', 'Hello, Cypress!');
});
});
describe('Prompt Dialogs', () => {
it('provides text to prompt', () => {
cy.visit('/p/playwright-labs.html#prompt-dialogs');
cy.window().then((win) => cy.stub(win, 'prompt').returns('Cypress'));
cy.get('#prompt-button').click();
cy.get('#result-prompt').should('have.text', 'Hello, Cypress!');
});
});
File Upload
Upload files via setInputFiles() — works even on hidden inputs without triggering the OS file picker.
describe('File Upload', () => {
it('uploads file via selectFile', () => {
cy.visit('/p/playwright-labs.html#file-upload');
cy.get('#file-input').selectFile({
contents: Cypress.Buffer.from('id,name\\n1,QACSEIAN'),
fileName: 'sample.csv',
mimeType: 'text/csv'
});
cy.get('#result-upload').should('contain', 'sample.csv');
});
});
describe('File Upload', () => {
it('uploads file via selectFile', () => {
cy.visit('/p/playwright-labs.html#file-upload');
cy.get('#file-input').selectFile({
contents: Cypress.Buffer.from('id,name\\n1,QACSEIAN'),
fileName: 'sample.csv',
mimeType: 'text/csv'
});
cy.get('#result-upload').should('contain', 'sample.csv');
});
});
Multiple File Upload
Upload multiple files in a single setInputFiles() call by passing an array.
describe('Multiple File Upload', () => {
it('uploads multiple files', () => {
cy.visit('/p/playwright-labs.html#multiple-file-upload');
cy.get('#multi-file-input').selectFile([
{ contents: Cypress.Buffer.from('aaa'), fileName: 'a.txt' },
{ contents: Cypress.Buffer.from('bbb'), fileName: 'b.txt' }
]);
cy.get('#result-multi-upload').should('contain', 'a.txt').and('contain', 'b.txt');
});
});
describe('Multiple File Upload', () => {
it('uploads multiple files', () => {
cy.visit('/p/playwright-labs.html#multiple-file-upload');
cy.get('#multi-file-input').selectFile([
{ contents: Cypress.Buffer.from('aaa'), fileName: 'a.txt' },
{ contents: Cypress.Buffer.from('bbb'), fileName: 'b.txt' }
]);
cy.get('#result-multi-upload').should('contain', 'a.txt').and('contain', 'b.txt');
});
});
File Download
Capture file downloads via the download event and save them to disk with download.saveAs().
describe('File Download', () => {
it('captures downloaded file', () => {
cy.visit('/p/playwright-labs.html#file-download');
cy.get('#download-button').click();
class=class="s">"c">// Cypress 12+ reads downloads from cypress/downloads/
cy.readFile('cypress/downloads/qa-cseian-report.txt').should('contain', 'QA CSEIAN');
});
});
describe('File Download', () => {
it('captures downloaded file', () => {
cy.visit('/p/playwright-labs.html#file-download');
cy.get('#download-button').click();
cy.readFile('cypress/downloads/qa-cseian-report.txt').should('contain', 'QA CSEIAN');
});
});
New Window
Capture new windows opened via window.open() using page.waitForEvent('popup').
describe('New Window', () => {
it('captures popup window', () => {
cy.visit('/p/playwright-labs.html#new-window');
class=class="s">"c">// Cypress doesn't support multi-tab natively — remove target
cy.window().then(win => {
cy.stub(win, 'open').callsFake(url => {
win.location.href = url;
});
});
cy.get('#popup-button').click();
});
});
describe('New Window', () => {
it('captures popup window', () => {
cy.visit('/p/playwright-labs.html#new-window');
cy.window().then((win) => {
cy.stub(win, 'open').callsFake((url) => {
win.location.href = url;
});
});
cy.get('#popup-button').click();
});
});
Multiple Tabs
Same as new window — Playwright treats every browser tab as a new Page context. Use page.context().pages to enumerate.
describe('Multiple Tabs', () => {
it('opens link in same tab', () => {
cy.visit('/p/playwright-labs.html#multiple-tabs');
class=class="s">"c">// Cypress single-tab: remove target=_blank
cy.get('#popup-link').invoke('removeAttr', 'target').click();
cy.url().should('include', 'about:blank');
});
});
describe('Multiple Tabs', () => {
it('opens link in same tab', () => {
cy.visit('/p/playwright-labs.html#multiple-tabs');
cy.get('#popup-link').invoke('removeAttr', 'target').click();
cy.url().should('include', 'about:blank');
});
});
Hover
Trigger CSS :hover states reliably with locator.hover() — useful for tooltips, dropdown menus, and revealing hidden elements.
describe('Hover', () => {
it('reveals tooltip on hover', () => {
cy.visit('/p/playwright-labs.html#hover');
cy.get('#hover-target').trigger('mouseover');
cy.get('#hover-tooltip').should('be.visible').and('have.text', 'You hovered!');
});
});
describe('Hover', () => {
it('reveals tooltip on hover', () => {
cy.visit('/p/playwright-labs.html#hover');
cy.get('#hover-target').trigger('mouseover');
cy.get('#hover-tooltip').should('be.visible').and('have.text', 'You hovered!');
});
});
Keyboard Actions
Use page.keyboard to type text, press keys, and trigger shortcuts like Ctrl+Enter or Shift+Tab.
describe('Keyboard Actions', () => {
it('types and presses Enter', () => {
cy.visit('/p/playwright-labs.html#keyboard-actions');
cy.get('#kbd-input').type('QA CSEIAN{enter}');
cy.get('#result-keyboard').should('have.text', 'Submitted: QA CSEIAN');
});
});
describe('Keyboard Actions', () => {
it('types and presses Enter', () => {
cy.visit('/p/playwright-labs.html#keyboard-actions');
cy.get('#kbd-input').type('QA CSEIAN{enter}');
cy.get('#result-keyboard').should('have.text', 'Submitted: QA CSEIAN');
});
});
Mouse Actions
Use page.mouse for pixel-perfect interactions — down(), move(), up(), and wheel() for scroll.
describe('Mouse Actions', () => {
it('clicks at coordinates', () => {
cy.visit('/p/playwright-labs.html#mouse-actions');
cy.get('#mouse-area').click(50, 50);
cy.get('#result-mouse').should('contain', '50,50');
});
});
describe('Mouse Actions', () => {
it('clicks at coordinates', () => {
cy.visit('/p/playwright-labs.html#mouse-actions');
cy.get('#mouse-area').click(50, 50);
cy.get('#result-mouse').should('contain', '50,50');
});
});
Shadow DOM
Playwright pierces open AND closed shadow roots by default — no special CSS combinators needed.
describe('Shadow DOM', () => {
it('clicks button in shadow root', () => {
cy.visit('/p/playwright-labs.html#shadow-dom');
class=class="s">"c">// Use includeShadowDom option (Cypress 10+)
cy.get('button', { includeShadowDom: true }).contains('Activate').click();
cy.get('#shadow-host').should('contain', 'Shadow clicked!');
});
});
describe('Shadow DOM', () => {
it('clicks button in shadow root', () => {
cy.visit('/p/playwright-labs.html#shadow-dom');
cy.get('button', { includeShadowDom: true }).contains('Activate').click();
cy.get('#shadow-host').should('contain', 'Shadow clicked!');
});
});
Infinite Scroll
Use page.mouse.wheel() or scrollIntoViewIfNeeded() to load additional content as the user scrolls.
describe('Infinite Scroll', () => {
it('loads more items on scroll', () => {
cy.visit('/p/playwright-labs.html#infinite-scroll');
cy.get('#scroll-list li').should('have.length', 5);
cy.get('#scroll-list').scrollTo('bottom');
cy.get('#scroll-list li').should('have.length.at.least', 10);
});
});
describe('Infinite Scroll', () => {
it('loads more items on scroll', () => {
cy.visit('/p/playwright-labs.html#infinite-scroll');
cy.get('#scroll-list li').should('have.length', 5);
cy.get('#scroll-list').scrollTo('bottom');
cy.get('#scroll-list li').should('have.length.at.least', 10);
});
});
Lazy Loading
Wait for IntersectionObserver-triggered image loads using Playwright's network idle or img loading states.
describe('Lazy Loading', () => {
it('loads images on scroll', () => {
cy.visit('/p/playwright-labs.html#lazy-loading');
cy.get('#lazy-grid img').each($img => {
cy.wrap($img).scrollIntoView().should($el => {
expect($el[0].naturalWidth).to.be.greaterThan(0);
});
});
});
});
describe('Lazy Loading', () => {
it('loads images on scroll', () => {
cy.visit('/p/playwright-labs.html#lazy-loading');
cy.get('#lazy-grid img').each(($img) => {
cy.wrap($img).scrollIntoView().should(($el) => {
expect($el[0].naturalWidth).to.be.greaterThan(0);
});
});
});
});
Network Interception
Use page.route() to intercept, modify, or fully mock XHR and fetch responses in your tests.
describe('Network Interception', () => {
it('mocks API response with cy.intercept', () => {
cy.intercept('GET', '/api/lab-data', {
statusCode: 200,
body: { items: ['Mocked A', 'Mocked B'] }
}).as('labData');
cy.visit('/p/playwright-labs.html#network-interception');
cy.get('#fetch-button').click();
cy.wait('@labData');
cy.get('#result-network').should('contain', 'Mocked A').and('contain', 'Mocked B');
});
});
describe('Network Interception', () => {
it('mocks API response with cy.intercept', () => {
cy.intercept('GET', '/api/lab-data', {
statusCode: 200,
body: { items: ['Mocked A', 'Mocked B'] }
}).as('labData');
cy.visit('/p/playwright-labs.html#network-interception');
cy.get('#fetch-button').click();
cy.wait('@labData');
cy.get('#result-network').should('contain', 'Mocked A').and('contain', 'Mocked B');
});
});
API Mocking
Same as network interception — stub any HTTP call with computed responses, fixtures, or status codes.
describe('API Mocking', () => {
it('mocks 500 error', () => {
cy.intercept('GET', '/api/lab-data', {
statusCode: 500,
body: 'Server error'
}).as('errApi');
cy.visit('/p/playwright-labs.html#api-mocking');
cy.get('#fetch-button').click();
cy.get('#result-network').should('have.text', 'Error: 500');
});
});
describe('API Mocking', () => {
it('mocks 500 error', () => {
cy.intercept('GET', '/api/lab-data', {
statusCode: 500,
body: 'Server error'
}).as('errApi');
cy.visit('/p/playwright-labs.html#api-mocking');
cy.get('#fetch-button').click();
cy.get('#result-network').should('have.text', 'Error: 500');
});
});
Route Mocking
Mock entire route trees including query strings and POST bodies — useful for testing state transitions without backend.
describe('Route Mocking', () => {
it('mocks route with query string', () => {
cy.intercept('GET', '/api/lab-data**', (req) => {
const page = new URL(req.url).searchParams.get('page') || '1';
req.reply({
statusCode: 200,
body: { items: [class="s">`Item from page ${page}`] }
});
}).as('routeApi');
cy.visit('/p/playwright-labs.html#route-mocking');
cy.get('#fetch-button').click();
cy.get('#result-network').should('contain', 'Item from page 1');
});
});
describe('Route Mocking', () => {
it('mocks route with query string', () => {
cy.intercept('GET', '/api/lab-data**', (req) => {
const page = new URL(req.url).searchParams.get('page') || '1';
req.reply({
statusCode: 200,
body: { items: [class="s">`Item from page ${page}`] }
});
}).as('routeApi');
cy.visit('/p/playwright-labs.html#route-mocking');
cy.get('#fetch-button').click();
cy.get('#result-network').should('contain', 'Item from page 1');
});
});
Authentication
Save authenticated storage state once with storageState() and reuse across every test for fast, parallel runs.
class=class="s">"c">// cypress/e2e/auth.cy.js
describe('Authentication with cy.session', () => {
beforeEach(() => {
cy.session('qa-user', () => {
cy.visit('/p/playwright-labs.html#authentication');
cy.get('#auth-username').type('qa@imcseian.com');
cy.get('#auth-login').click();
cy.get('#auth-status').should('contain', 'Logged in');
});
});
it('preserves session across tests', () => {
cy.visit('/p/playwright-labs.html#authentication');
class=class="s">"c">// Already logged in — no need to log in again
});
});
class=class="s">"c">// cypress/e2e/auth.cy.ts
describe('Authentication with cy.session', () => {
beforeEach(() => {
cy.session('qa-user', () => {
cy.visit('/p/playwright-labs.html#authentication');
cy.get('#auth-username').type('qa@imcseian.com');
cy.get('#auth-login').click();
cy.get('#auth-status').should('contain', 'Logged in');
});
});
it('preserves session across tests', () => {
cy.visit('/p/playwright-labs.html#authentication');
});
});
Local Storage
Read, write, and clear localStorage entries pre-test using page.evaluate() or context.addInitScript().
describe('Local Storage', () => {
it('pre-sets localStorage value', () => {
cy.visit('/p/playwright-labs.html#local-storage', {
onBeforeLoad(win) {
win.localStorage.setItem('qa-cseian-theme', 'dark');
}
});
cy.get('#storage-display').should('contain', 'qa-cseian-theme=dark');
});
});
describe('Local Storage', () => {
it('pre-sets localStorage value', () => {
cy.visit('/p/playwright-labs.html#local-storage', {
onBeforeLoad(win: Window) {
win.localStorage.setItem('qa-cseian-theme', 'dark');
}
});
cy.get('#storage-display').should('contain', 'qa-cseian-theme=dark');
});
});
Session Storage
Persist session-only keys between page reloads using sessionStorage — cleared when the tab closes.
describe('Session Storage', () => {
it('sets sessionStorage via window', () => {
cy.visit('/p/playwright-labs.html#session-storage');
cy.window().then(win => {
win.sessionStorage.setItem('qa-cseian-session', 'abc123');
});
cy.reload();
cy.get('#storage-display').should('contain', 'qa-cseian-session=abc123');
});
});
describe('Session Storage', () => {
it('sets sessionStorage via window', () => {
cy.visit('/p/playwright-labs.html#session-storage');
cy.window().then((win) => {
win.sessionStorage.setItem('qa-cseian-session', 'abc123');
});
cy.reload();
cy.get('#storage-display').should('contain', 'qa-cseian-session=abc123');
});
});
Cookies
Inspect, set, and clear cookies with context.addCookies() and context.cookies().
describe('Cookies', () => {
it('pre-sets cookie via cy.setCookie', () => {
cy.visit('/p/playwright-labs.html#cookies');
cy.setCookie('qa-cseian-user', 'ram');
cy.reload();
cy.get('#cookie-display').should('have.text', 'ram');
});
});
describe('Cookies', () => {
it('pre-sets cookie via cy.setCookie', () => {
cy.visit('/p/playwright-labs.html#cookies');
cy.setCookie('qa-cseian-user', 'ram');
cy.reload();
cy.get('#cookie-display').should('have.text', 'ram');
});
});
Web Tables
Read and assert tabular data row-by-row using locator.locator('tr') and toContainText() assertions.
describe('Web Tables', () => {
it('finds row by text', () => {
cy.visit('/p/playwright-labs.html#web-tables');
cy.get('#web-table tr').contains('Ram Pothuraju').parent('tr').within(() => {
cy.get('td').eq(1).should('have.text', 'Test Engineer');
cy.get('td').eq(2).should('have.text', 'qa@imcseian.com');
});
});
});
describe('Web Tables', () => {
it('finds row by text', () => {
cy.visit('/p/playwright-labs.html#web-tables');
cy.get('#web-table tr').contains('Ram Pothuraju').parent('tr').within(() => {
cy.get('td').eq(1).should('have.text', 'Test Engineer');
cy.get('td').eq(2).should('have.text', 'qa@imcseian.com');
});
});
});
Dynamic Tables
Handle tables whose rows appear after async fetches — wait for the row count to grow.
describe('Dynamic Tables', () => {
it('waits for table rows', () => {
cy.visit('/p/playwright-labs.html#dynamic-tables');
cy.get('#load-table').click();
cy.get('#dynamic-table tbody tr').should('have.length', 5);
});
});
describe('Dynamic Tables', () => {
it('waits for table rows', () => {
cy.visit('/p/playwright-labs.html#dynamic-tables');
cy.get('#load-table').click();
cy.get('#dynamic-table tbody tr').should('have.length', 5);
});
});
Pagination
Walk through numbered pagination by clicking Next/Prev and verifying the active page changes.
describe('Pagination', () => {
it('navigates to last page', () => {
cy.visit('/p/playwright-labs.html#pagination');
cy.get('#page-next').click().click();
cy.get('#page-indicator').should('have.text', 'Page 3 of 3');
});
});
describe('Pagination', () => {
it('navigates to last page', () => {
cy.visit('/p/playwright-labs.html#pagination');
cy.get('#page-next').click().click();
cy.get('#page-indicator').should('have.text', 'Page 3 of 3');
});
});
Calendar
Navigate custom calendar widgets by clicking next/prev and selecting the day cell.
describe('Calendar', () => {
it('picks date from calendar', () => {
cy.visit('/p/playwright-labs.html#calendar');
cy.get('#cal-open').click();
cy.get('#cal-next').click();
cy.get('#cal-grid [data-day="15"]').click();
cy.get('#result-calendar').should('contain', '15');
});
});
describe('Calendar', () => {
it('picks date from calendar', () => {
cy.visit('/p/playwright-labs.html#calendar');
cy.get('#cal-open').click();
cy.get('#cal-next').click();
cy.get('#cal-grid [data-day="15"]').click();
cy.get('#result-calendar').should('contain', '15');
});
});
Date Picker
Fill native date inputs with ISO-format strings (YYYY-MM-DD) for reliable cross-browser behavior.
describe('Date Picker', () => {
it('fills date input', () => {
cy.visit('/p/playwright-labs.html#date-picker');
cy.get('#date-input').type('2025-12-25');
cy.get('#date-input').should('have.value', '2025-12-25');
cy.get('#result-date').should('have.text', '2025-12-25');
});
});
describe('Date Picker', () => {
it('fills date input', () => {
cy.visit('/p/playwright-labs.html#date-picker');
cy.get('#date-input').type('2025-12-25');
cy.get('#date-input').should('have.value', '2025-12-25');
cy.get('#result-date').should('have.text', '2025-12-25');
});
});
Slider
Set the value of native range sliders via fill() or simulate drag with mouse events.
describe('Slider', () => {
it('sets slider value', () => {
cy.visit('/p/playwright-labs.html#slider');
cy.get('#range-slider').invoke('val', 75).trigger('input');
cy.get('#result-slider').should('have.text', '75');
});
});
describe('Slider', () => {
it('sets slider value', () => {
cy.visit('/p/playwright-labs.html#slider');
cy.get('#range-slider').invoke('val', 75).trigger('input');
cy.get('#result-slider').should('have.text', '75');
});
});
Dropdown
Select single-value native dropdowns with selectOption() — works with value, label, or index.
describe('Dropdown', () => {
it('selects option by value', () => {
cy.visit('/p/playwright-labs.html#dropdown');
cy.get('#tool-select').select('cypress');
cy.get('#result-dropdown').should('have.text', 'cypress');
});
});
describe('Dropdown', () => {
it('selects option by value', () => {
cy.visit('/p/playwright-labs.html#dropdown');
cy.get('#tool-select').select('cypress');
cy.get('#result-dropdown').should('have.text', 'cypress');
});
});
Multi Select
Choose multiple options in select[multiple] by passing an array to selectOption().
describe('Multi Select', () => {
it('selects multiple options', () => {
cy.visit('/p/playwright-labs.html#multi-select');
cy.get('#multi-select').select(['playwright', 'cypress']);
cy.get('#result-multi-select').should('contain', 'playwright').and('contain', 'cypress');
});
});
describe('Multi Select', () => {
it('selects multiple options', () => {
cy.visit('/p/playwright-labs.html#multi-select');
cy.get('#multi-select').select(['playwright', 'cypress']);
cy.get('#result-multi-select').should('contain', 'playwright').and('contain', 'cypress');
});
});
SVG
Click SVG paths and assert on attribute changes — Playwright treats SVG elements like any other.
describe('SVG', () => {
it('clicks SVG circle', () => {
cy.visit('/p/playwright-labs.html#svg');
cy.get('#svg-circle').click();
cy.get('#result-svg').should('have.text', 'SVG clicked!');
});
});
describe('SVG', () => {
it('clicks SVG circle', () => {
cy.visit('/p/playwright-labs.html#svg');
cy.get('#svg-circle').click();
cy.get('#result-svg').should('have.text', 'SVG clicked!');
});
});
Canvas
Interact with canvas pixels by clicking at specific coordinates — use boundingBox() to compute positions.
describe('Canvas', () => {
it('clicks canvas at center', () => {
cy.visit('/p/playwright-labs.html#canvas');
cy.get('#lab-canvas').click('center');
cy.get('#result-canvas').should('contain', 'Clicks: 1');
});
});
describe('Canvas', () => {
it('clicks canvas at center', () => {
cy.visit('/p/playwright-labs.html#canvas');
cy.get('#lab-canvas').click('center');
cy.get('#result-canvas').should('contain', 'Clicks: 1');
});
});
Charts
Assert on chart series data via data attributes or aria-labels — most modern chart libraries expose these.
describe('Charts', () => {
it('asserts on chart bars', () => {
cy.visit('/p/playwright-labs.html#charts');
cy.get('#chart-bars [role="img"]').should('have.length', 5);
cy.get('#chart-bars [role="img"]').eq(2).should('have.attr', 'data-value', '30');
});
});
describe('Charts', () => {
it('asserts on chart bars', () => {
cy.visit('/p/playwright-labs.html#charts');
cy.get('#chart-bars [role="img"]').should('have.length', 5);
cy.get('#chart-bars [role="img"]').eq(2).should('have.attr', 'data-value', '30');
});
});
Dynamic Forms
Fill forms whose fields appear based on previous inputs — wait for the conditional field before filling.
describe('Dynamic Forms', () => {
it('reveals conditional field', () => {
cy.visit('/p/playwright-labs.html#dynamic-forms');
cy.get('#role-select').select('other');
cy.get('#specify-field').should('be.visible').type('SDET');
cy.get('#result-form').should('have.text', 'SDET');
});
});
describe('Dynamic Forms', () => {
it('reveals conditional field', () => {
cy.visit('/p/playwright-labs.html#dynamic-forms');
cy.get('#role-select').select('other');
cy.get('#specify-field').should('be.visible').type('SDET');
cy.get('#result-form').should('have.text', 'SDET');
});
});
Auto Complete
Trigger autocomplete suggestions by typing, then click the desired option from the dropdown.
describe('Auto Complete', () => {
it('selects from suggestions', () => {
cy.visit('/p/playwright-labs.html#auto-complete');
cy.get('#auto-input').type('play');
cy.get('#auto-suggestions').should('be.visible');
cy.get('#auto-suggestions [data-value="Playwright"]').click();
cy.get('#auto-input').should('have.value', 'Playwright');
});
});
describe('Auto Complete', () => {
it('selects from suggestions', () => {
cy.visit('/p/playwright-labs.html#auto-complete');
cy.get('#auto-input').type('play');
cy.get('#auto-suggestions').should('be.visible');
cy.get('#auto-suggestions [data-value="Playwright"]').click();
cy.get('#auto-input').should('have.value', 'Playwright');
});
});
Accordions
Expand and collapse accordion sections by clicking headers and asserting on the body visibility.
describe('Accordions', () => {
it('expands second accordion', () => {
cy.visit('/p/playwright-labs.html#accordions');
cy.get('#acc-header-2').click();
cy.get('#acc-body-2').should('be.visible').and('have.text', 'Cypress content here.');
});
});
describe('Accordions', () => {
it('expands second accordion', () => {
cy.visit('/p/playwright-labs.html#accordions');
cy.get('#acc-header-2').click();
cy.get('#acc-body-2').should('be.visible').and('have.text', 'Cypress content here.');
});
});
Tree View
Expand tree nodes by clicking the expand icon and assert on nested children appearing.
describe('Tree View', () => {
it('expands tree node', () => {
cy.visit('/p/playwright-labs.html#tree-view');
cy.get('#tree-node-automation .expand-btn').click();
cy.get('#tree-node-playwright').should('be.visible');
});
});
describe('Tree View', () => {
it('expands tree node', () => {
cy.visit('/p/playwright-labs.html#tree-view');
cy.get('#tree-node-automation .expand-btn').click();
cy.get('#tree-node-playwright').should('be.visible');
});
});
Modal Dialog
Open, assert, and close modal dialogs reliably with role-based locators.
describe('Modal Dialog', () => {
it('opens and closes modal', () => {
cy.visit('/p/playwright-labs.html#modal-dialog');
cy.get('#open-modal').click();
cy.get('#lab-modal').should('be.visible');
cy.get('#modal-text').should('have.text', 'Are you sure?');
cy.get('#close-modal').click();
cy.get('#lab-modal').should('not.be.visible');
});
});
describe('Modal Dialog', () => {
it('opens and closes modal', () => {
cy.visit('/p/playwright-labs.html#modal-dialog');
cy.get('#open-modal').click();
cy.get('#lab-modal').should('be.visible');
cy.get('#modal-text').should('have.text', 'Are you sure?');
cy.get('#close-modal').click();
cy.get('#lab-modal').should('not.be.visible');
});
});
Toast Messages
Wait for transient toast notifications using toBeVisible() — they auto-dismiss after a timeout.
describe('Toast Messages', () => {
it('waits for toast', () => {
cy.visit('/p/playwright-labs.html#toast-messages');
cy.get('#toast-button').click();
cy.get('#lab-toast').should('be.visible').and('have.text', 'Saved successfully');
});
});
describe('Toast Messages', () => {
it('waits for toast', () => {
cy.visit('/p/playwright-labs.html#toast-messages');
cy.get('#toast-button').click();
cy.get('#lab-toast').should('be.visible').and('have.text', 'Saved successfully');
});
});
Loading Spinner
Wait for spinners to disappear before the next action using toBeHidden().
describe('Loading Spinner', () => {
it('waits for spinner to hide', () => {
cy.visit('/p/playwright-labs.html#loading-spinner');
cy.get('#submit-spinner').click();
cy.get('#lab-spinner').should('not.be.visible', { timeout: 5000 });
cy.get('#result-spinner').should('have.text', 'Done!');
});
});
describe('Loading Spinner', () => {
it('waits for spinner to hide', () => {
cy.visit('/p/playwright-labs.html#loading-spinner');
cy.get('#submit-spinner').click();
cy.get('#lab-spinner').should('not.be.visible', { timeout: 5000 });
cy.get('#result-spinner').should('have.text', 'Done!');
});
});
Retry Logic & Flakiness
Configure retries at the runner level and detect flaky tests using the HTML reporter.
class=class="s">"c">// cypress.config.js
const { defineConfig } = require('cypress');
module.exports = defineConfig({
e2e: {
retries: 2,
reporter: 'mochawesome',
reporterOptions: { reportDir: 'cypress/reports', overwrite: false }
}
});
class=class="s">"c">// spec
describe('Retry Logic', () => {
it('handles flaky button', () => {
cy.visit('/p/playwright-labs.html#retry-logic');
cy.get('#flaky-button').click();
cy.get('#result-retry').should('have.text', 'Success');
});
});
class=class="s">"c">// cypress.config.ts
import { defineConfig } from 'cypress';
export default defineConfig({
e2e: {
retries: 2,
reporter: 'mochawesome',
reporterOptions: { reportDir: 'cypress/reports', overwrite: false }
}
});
class=class="s">"c">// spec
describe('Retry Logic', () => {
it('handles flaky button', () => {
cy.visit('/p/playwright-labs.html#retry-logic');
cy.get('#flaky-button').click();
cy.get('#result-retry').should('have.text', 'Success');
});
});
XPath Practice
Master XPath axes: parent, ancestor, following-sibling, and more. Use page.locator('xpath=...') syntax.
describe('XPath Practice', () => {
it('uses xpath selector', () => {
cy.visit('/p/playwright-labs.html#xpath-practice');
class=class="s">"c">// Requires cypress-xpath plugin: npm i -D cypress-xpath
cy.xpath('class=class="s">"c">//label[text()="QA"]/following-sibling::button').click();
cy.get('#result-xpath').should('have.text', 'XPath found me!');
});
});
class=class="s">"c">// In cypress/support/e2e.js: require('cypress-xpath');
describe('XPath Practice', () => {
it('uses xpath selector', () => {
cy.visit('/p/playwright-labs.html#xpath-practice');
cy.xpath('class=class="s">"c">//label[text()="QA"]/following-sibling::button').click();
cy.get('#result-xpath').should('have.text', 'XPath found me!');
});
});
CSS Selector Practice
Nth-child, attribute, and pseudo-class selector drills for resilient test locators.
describe('CSS Selector Practice', () => {
it('uses nth-child selector', () => {
cy.visit('/p/playwright-labs.html#css-selector-practice');
cy.get('#css-list li:nth-child(2) button').click();
cy.get('#result-css').should('have.text', 'Item 2 clicked');
});
});
describe('CSS Selector Practice', () => {
it('uses nth-child selector', () => {
cy.visit('/p/playwright-labs.html#css-selector-practice');
cy.get('#css-list li:nth-child(2) button').click();
cy.get('#result-css').should('have.text', 'Item 2 clicked');
});
});
Popup Windows
Capture popups with waitForEvent('popup') and assert on their content.
describe('Popup Windows', () => {
it('captures popup', () => {
cy.visit('/p/playwright-labs.html#popup-windows');
cy.window().then(win => {
cy.stub(win, 'open').callsFake(() => {
return { document: { write: cy.stub(), close: cy.stub() } };
});
});
cy.get('#popup-button').click();
});
});
describe('Popup Windows', () => {
it('captures popup', () => {
cy.visit('/p/playwright-labs.html#popup-windows');
cy.window().then((win) => {
cy.stub(win, 'open').callsFake(() => ({
document: { write: cy.stub(), close: cy.stub() }
}));
});
cy.get('#popup-button').click();
});
});
iFrame (Same Origin)
Same-origin iframes are accessible via frameLocator() — no special permissions needed.