Skip to main content
Glama

setup_playwright_tests

Generate Playwright end-to-end test setup for documentation sites, including containers and CI/CD integration, to automate testing workflows.

Instructions

Generate Playwright E2E test setup for documentation site (containers + CI/CD)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
repositoryPathYesPath to documentation repository
ssgYes
projectNameYesProject name for tests
mainBranchNomain
includeAccessibilityTestsNo
includeDockerfileNo
includeGitHubActionsNo

Implementation Reference

  • The main handler function that implements the logic for setting up Playwright E2E tests, including generating config files, tests, Dockerfiles, GitHub Actions workflows, and updating package.json based on the SSG type.
    export async function setupPlaywrightTests(
      args: unknown,
    ): Promise<ToolResponse> {
      const {
        repositoryPath,
        ssg,
        projectName,
        mainBranch,
        includeAccessibilityTests,
        includeDockerfile,
        includeGitHubActions,
      } = inputSchema.parse(args);
    
      try {
        const config = SSG_CONFIGS[ssg];
        const templatesDir = path.join(__dirname, "../templates/playwright");
    
        // Create directories
        const testsDir = path.join(repositoryPath, "tests/e2e");
        await fs.mkdir(testsDir, { recursive: true });
    
        if (includeGitHubActions) {
          const workflowsDir = path.join(repositoryPath, ".github/workflows");
          await fs.mkdir(workflowsDir, { recursive: true });
        }
    
        // Read and process templates
        const filesCreated: string[] = [];
    
        // 1. Playwright config
        const configTemplate = await fs.readFile(
          path.join(templatesDir, "playwright.config.template.ts"),
          "utf-8",
        );
        const playwrightConfig = configTemplate.replace(
          /{{port}}/g,
          config.port.toString(),
        );
    
        await fs.writeFile(
          path.join(repositoryPath, "playwright.config.ts"),
          playwrightConfig,
        );
        filesCreated.push("playwright.config.ts");
    
        // 2. Link validation tests
        const linkTestTemplate = await fs.readFile(
          path.join(templatesDir, "link-validation.spec.template.ts"),
          "utf-8",
        );
        const linkTest = linkTestTemplate.replace(/{{projectName}}/g, projectName);
    
        await fs.writeFile(
          path.join(testsDir, "link-validation.spec.ts"),
          linkTest,
        );
        filesCreated.push("tests/e2e/link-validation.spec.ts");
    
        // 3. Accessibility tests (if enabled)
        if (includeAccessibilityTests) {
          const a11yTemplate = await fs.readFile(
            path.join(templatesDir, "accessibility.spec.template.ts"),
            "utf-8",
          );
    
          await fs.writeFile(
            path.join(testsDir, "accessibility.spec.ts"),
            a11yTemplate,
          );
          filesCreated.push("tests/e2e/accessibility.spec.ts");
        }
    
        // 4. Dockerfile (if enabled)
        if (includeDockerfile) {
          const dockerTemplate = await fs.readFile(
            path.join(templatesDir, "Dockerfile.template"),
            "utf-8",
          );
          const dockerfile = dockerTemplate
            .replace(/{{ssg}}/g, ssg)
            .replace(/{{buildCommand}}/g, config.buildCommand)
            .replace(/{{buildDir}}/g, config.buildDir);
    
          await fs.writeFile(
            path.join(repositoryPath, "Dockerfile.playwright"),
            dockerfile,
          );
          filesCreated.push("Dockerfile.playwright");
        }
    
        // 5. GitHub Actions workflow (if enabled)
        if (includeGitHubActions) {
          const workflowTemplate = await fs.readFile(
            path.join(templatesDir, "docs-e2e.workflow.template.yml"),
            "utf-8",
          );
          const workflow = workflowTemplate
            .replace(/{{mainBranch}}/g, mainBranch)
            .replace(/{{buildCommand}}/g, config.buildCommand)
            .replace(/{{buildDir}}/g, config.buildDir)
            .replace(/{{port}}/g, config.port.toString());
    
          await fs.writeFile(
            path.join(repositoryPath, ".github/workflows/docs-e2e-tests.yml"),
            workflow,
          );
          filesCreated.push(".github/workflows/docs-e2e-tests.yml");
        }
    
        // 6. Update package.json
        const packageJsonPath = path.join(repositoryPath, "package.json");
        let packageJson: any = {};
    
        try {
          const existing = await fs.readFile(packageJsonPath, "utf-8");
          packageJson = JSON.parse(existing);
        } catch {
          // Create new package.json
          packageJson = {
            name: projectName.toLowerCase().replace(/\s+/g, "-"),
            version: "1.0.0",
            private: true,
            scripts: {},
            dependencies: {},
            devDependencies: {},
          };
        }
    
        // Add Playwright dependencies
        packageJson.devDependencies = {
          ...packageJson.devDependencies,
          "@playwright/test": "^1.55.1",
          ...(includeAccessibilityTests
            ? { "@axe-core/playwright": "^4.10.2" }
            : {}),
        };
    
        // Add test scripts
        packageJson.scripts = {
          ...packageJson.scripts,
          "test:e2e": "playwright test",
          "test:e2e:ui": "playwright test --ui",
          "test:e2e:report": "playwright show-report",
          "test:e2e:docker":
            "docker build -t docs-test -f Dockerfile.playwright . && docker run --rm docs-test",
        };
    
        await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
        filesCreated.push("package.json (updated)");
    
        // 7. Create .gitignore entries
        const gitignorePath = path.join(repositoryPath, ".gitignore");
        const gitignoreEntries = [
          "test-results/",
          "playwright-report/",
          "playwright-results.json",
          "playwright/.cache/",
        ].join("\n");
    
        try {
          const existing = await fs.readFile(gitignorePath, "utf-8");
          if (!existing.includes("test-results/")) {
            await fs.writeFile(
              gitignorePath,
              `${existing}\n\n# Playwright\n${gitignoreEntries}\n`,
            );
            filesCreated.push(".gitignore (updated)");
          }
        } catch {
          await fs.writeFile(gitignorePath, `# Playwright\n${gitignoreEntries}\n`);
          filesCreated.push(".gitignore");
        }
    
        return {
          content: [
            {
              type: "text" as const,
              text: JSON.stringify(
                {
                  success: true,
                  filesCreated,
                  nextSteps: [
                    "Run `npm install` to install Playwright dependencies",
                    "Run `npx playwright install` to download browser binaries",
                    "Test locally: `npm run test:e2e`",
                    includeDockerfile
                      ? "Build container: `docker build -t docs-test -f Dockerfile.playwright .`"
                      : "",
                    includeGitHubActions
                      ? "Push to trigger GitHub Actions workflow"
                      : "",
                  ].filter(Boolean),
                  configuration: {
                    ssg,
                    buildCommand: config.buildCommand,
                    buildDir: config.buildDir,
                    port: config.port,
                    testsIncluded: {
                      linkValidation: true,
                      accessibility: includeAccessibilityTests,
                    },
                    integrations: {
                      docker: includeDockerfile,
                      githubActions: includeGitHubActions,
                    },
                  },
                },
                null,
                2,
              ),
            },
          ],
        };
      } catch (error: any) {
        return {
          content: [
            {
              type: "text" as const,
              text: JSON.stringify(
                {
                  success: false,
                  error: error.message,
                },
                null,
                2,
              ),
            },
          ],
          isError: true,
        };
      }
    }
  • Zod schema defining the input parameters for the tool, including repository path, SSG type, project name, and optional flags for accessibility tests, Dockerfile, and GitHub Actions.
    const inputSchema = z.object({
      repositoryPath: z.string().describe("Path to the documentation repository"),
      ssg: z.enum(["jekyll", "hugo", "docusaurus", "mkdocs", "eleventy"]),
      projectName: z.string().describe("Project name for tests"),
      mainBranch: z.string().optional().default("main"),
      includeAccessibilityTests: z.boolean().optional().default(true),
      includeDockerfile: z.boolean().optional().default(true),
      includeGitHubActions: z.boolean().optional().default(true),
    });

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/tosin2013/documcp'

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