Skip to main content
Glama
jprealini

MCP Cypress Page Object Generator

create_Page_Object_file

Generate TypeScript Page Object classes for Cypress testing by analyzing web page URLs to automate test creation and element interaction workflows.

Instructions

Create Page Object file directly in the Cypress project by analyzing the provided URL

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
urlYesURL of the web page
workspacePathNoWorkspace path (optional, it is detected automatically if not provided)
pageObjectNameNoCustom name for the page object (optional)

Implementation Reference

  • src/index.js:359-393 (registration)
    Registration of the MCP tool 'create_Page_Object_file' including schema and inline handler function.
    server.registerTool( 'create_Page_Object_file', { title: 'Create Page Object File', description: 'Create Page Object file directly in the Cypress project by analyzing the provided URL', inputSchema: { url: z.string().describe('URL of the web page'), workspacePath: z.string().optional().describe('Workspace path (optional, it is detected automatically if not provided)'), pageObjectName: z.string().optional().describe('Custom name for the page object (optional)') } }, async ({ url, workspacePath, pageObjectName }) => { const fileManager = new CypressFileManager() try { const workspaceRoot = await fileManager.detectWorkspace(workspacePath) await fileManager.ensureDirectoryStructure(workspaceRoot) const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }) const page = await browser.newPage() await page.goto(url, { waitUntil: 'networkidle2' }) const html = await page.content() await browser.close() const $ = cheerio.load(html) const pageObjectMeta = generatePageObjectClass($, url, pageObjectName) const pageObjectPath = await fileManager.createPageObject(workspaceRoot, url, pageObjectMeta) const indexPath = await fileManager.createIndexFile(workspaceRoot) return { content: [ { type: 'text', text: `āœ… Files created successfully:\n\nšŸ“„ Page Object: ${pageObjectPath}\nšŸ“‹ Index File: ${indexPath}\n\nWorkspace detected: ${workspaceRoot}\n\nNow you can import the page object in your tests using:\nimport { ${pageObjectMeta.className} } from '../pages/${pageObjectMeta.featureName}'` } ] } } catch (error) { return { content: [ { type: 'text', text: `āŒ Error creating Cypress files: ${error instanceof Error ? error.message : 'Unknown error'}\n\nMake sure you are in a directory with a valid Cypress project.` } ] } } } )
  • The core handler logic that fetches the webpage using Puppeteer, parses HTML with Cheerio, generates Page Object code, and writes files to the Cypress project directory.
    async ({ url, workspacePath, pageObjectName }) => { const fileManager = new CypressFileManager() try { const workspaceRoot = await fileManager.detectWorkspace(workspacePath) await fileManager.ensureDirectoryStructure(workspaceRoot) const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }) const page = await browser.newPage() await page.goto(url, { waitUntil: 'networkidle2' }) const html = await page.content() await browser.close() const $ = cheerio.load(html) const pageObjectMeta = generatePageObjectClass($, url, pageObjectName) const pageObjectPath = await fileManager.createPageObject(workspaceRoot, url, pageObjectMeta) const indexPath = await fileManager.createIndexFile(workspaceRoot) return { content: [ { type: 'text', text: `āœ… Files created successfully:\n\nšŸ“„ Page Object: ${pageObjectPath}\nšŸ“‹ Index File: ${indexPath}\n\nWorkspace detected: ${workspaceRoot}\n\nNow you can import the page object in your tests using:\nimport { ${pageObjectMeta.className} } from '../pages/${pageObjectMeta.featureName}'` } ] } } catch (error) { return { content: [ { type: 'text', text: `āŒ Error creating Cypress files: ${error instanceof Error ? error.message : 'Unknown error'}\n\nMake sure you are in a directory with a valid Cypress project.` } ] } } }
  • Zod input schema defining parameters: url (required), workspacePath and pageObjectName (optional).
    inputSchema: { url: z.string().describe('URL of the web page'), workspacePath: z.string().optional().describe('Workspace path (optional, it is detected automatically if not provided)'), pageObjectName: z.string().optional().describe('Custom name for the page object (optional)') }
  • Key helper function that generates the Cypress Page Object class code by analyzing DOM elements (buttons, inputs, links, selects, textareas) and creating appropriate locators, getters, and interaction methods.
    function generatePageObjectClass($, url, customFeatureName = null) { const featureName = customFeatureName || getFeatureName($, url) const className = featureName.charAt(0).toUpperCase() + featureName.slice(1) + 'Page' const elements = [] const getters = [] const valueGetters = [] const interactionMethods = [] let elementCounter = 1 const elementMeta = [] // BUTTONS $('button').each((i, element) => { const $el = $(element); const { locator, rawName } = getLocatorAndRawName($el, 'button', { index: i }); const elementName = toCamelCase(rawName); elements.push(` ${elementName}: () => ${locator}`); interactionMethods.push(` click${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().click() }`); valueGetters.push(` getText${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().invoke('text') }`); elementCounter++; }); // INPUTS $('input').each((i, element) => { const $el = $(element); const type = $el.attr('type') || 'text'; const { locator, rawName } = getLocatorAndRawName($el, 'input', { type, index: i }); const elementName = toCamelCase(rawName); elements.push(` ${elementName}: () => ${locator}`); getters.push(` get ${elementName}() { return this.#elements.${elementName}() }`); if (type === 'checkbox' || type === 'radio') { interactionMethods.push(` check${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().check() }`); interactionMethods.push(` uncheck${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().uncheck() }`); valueGetters.push(` isChecked${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().should('have.prop', 'checked') }`); } else if (type === 'submit' || type === 'button') { interactionMethods.push(` click${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().click() }`); valueGetters.push(` getText${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().invoke('text') }`); } else { interactionMethods.push(` type${elementName.charAt(0).toUpperCase() + elementName.slice(1)}(text) { return this.#elements.${elementName}().type(text) }`); interactionMethods.push(` clear${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().clear() }`); valueGetters.push(` getValue${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().invoke('val') }`); } elementCounter++; }); // LINKS $('a').each((i, element) => { const $el = $(element); const { locator, rawName } = getLocatorAndRawName($el, 'a', { index: i }); const elementName = toCamelCase(rawName); elements.push(` ${elementName}: () => ${locator}`); getters.push(` get ${elementName}() { return this.#elements.${elementName}() }`); interactionMethods.push(` click${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().click() }`); valueGetters.push(` getText${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().invoke('text') }`); elementCounter++; }); // SELECTS $('select').each((i, element) => { const $el = $(element); const { locator, rawName } = getLocatorAndRawName($el, 'select', { index: i }); const elementName = toCamelCase(rawName); elements.push(` ${elementName}: () => ${locator}`); getters.push(` get ${elementName}() { return this.#elements.${elementName}() }`); interactionMethods.push(` select${elementName.charAt(0).toUpperCase() + elementName.slice(1)}(value) { return this.#elements.${elementName}().select(value) }`); valueGetters.push(` getValue${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().invoke('val') }`); elementCounter++; }); // TEXTAREAS $('textarea').each((i, element) => { const $el = $(element); const { locator, rawName } = getLocatorAndRawName($el, 'textarea', { index: i }); const elementName = toCamelCase(rawName); elements.push(` ${elementName}: () => ${locator}`); getters.push(` get ${elementName}() { return this.#elements.${elementName}() }`); interactionMethods.push(` type${elementName.charAt(0).toUpperCase() + elementName.slice(1)}(text) { return this.#elements.${elementName}().type(text) }`); interactionMethods.push(` clear${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().clear() }`); valueGetters.push(` getValue${elementName.charAt(0).toUpperCase() + elementName.slice(1)}() { return this.#elements.${elementName}().invoke('val') }`); elementCounter++; }); return { classCode: `export class ${className} {\n // Private elements\n #elements = {\n${elements.join(',\n')}\n }\n\n // Element meta (currently not used for bulk actions)\n\n // Public getters\n${getters.join('\n')}\n\n // Value/State getters\n${valueGetters.join('\n')}\n\n // Interaction methods (per-element actions)\n${interactionMethods.join('\n')}\n}\n`, className, featureName } }
  • Helper method in CypressFileManager class that writes the generated Page Object code to the file system in cypress/pages directory, with backup of existing files.
    async createPageObject(workspaceRoot, url, pageObjectMeta) { const { featureName, classCode } = pageObjectMeta const fileName = `${featureName}.js` const filePath = path.join(workspaceRoot, 'cypress', 'pages', fileName) if (await this.fileExists(filePath)) { const timestamp = new Date().toISOString().replace(/[:.]/g, '-') const backupPath = path.join(workspaceRoot, 'cypress', 'pages', `${featureName}.backup.${timestamp}.js`) await fs.copyFile(filePath, backupPath) } await fs.writeFile(filePath, classCode, 'utf8') return filePath }
Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jprealini/cypress-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server