DEV Community

Cover image for Explore generating tests with Playwright MCP Server and Claude 3.7 Sonnet (Thinking)
idavidov13
idavidov13

Posted on • Edited on

Explore generating tests with Playwright MCP Server and Claude 3.7 Sonnet (Thinking)

Introduction

As we setup the stage in Part 2 we are ready to continue exploration. Next is Claude 3.7 Sonnet (Thinking).

Prerequisites

  1. Claude 3.7 Sonnet (Thinking) is selected as a model
  2. The following prompt is run:
Create a test case utilizing provided constants for navigating to the web app, login, create/edit/delete an article. Try to verify the result after every major step. Use provided instructions
Enter fullscreen mode Exit fullscreen mode

Generated POM (Page Object Model)

class ConduitPage {
  readonly page: Page;

  constructor(page: Page) {
    this.page = page;
  }

  // Locators
  get loginButton() { return this.page.getByRole('link', { name: 'Sign in' }); }
  get emailInput() { return this.page.getByRole('textbox', { name: 'Email' }); }
  get passwordInput() { return this.page.getByRole('textbox', { name: 'Password' }); }
  get signInButton() { return this.page.getByRole('button', { name: 'Sign in' }); }
  get newArticleButton() { return this.page.getByRole('link', { name: ' New Article' }); }
  get articleTitleInput() { return this.page.getByRole('textbox', { name: 'Article Title' }); }
  get articleAboutInput() { return this.page.getByRole('textbox', { name: 'What\'s this article about?' }); }
  get articleContentInput() { return this.page.getByRole('textbox', { name: 'Write your article (in' }); }
  get publishArticleButton() { return this.page.getByRole('button', { name: 'Publish Article' }); }
  get editArticleButton() { return this.page.getByRole('link', { name: ' Edit Article' }).first(); }
  get deleteArticleButton() { return this.page.getByRole('button', { name: ' Delete Article' }).first(); }
  get articleTitleHeading() { return this.page.getByRole('heading', { level: 1 }); }
  get yourFeedTab() { return this.page.getByText('Your Feed'); }

  // Actions
  async navigate() {
    await this.page.goto(url);
  }

  async login() {
    // Check if already logged in
    if (await this.page.getByRole('link', { name: 'Sign in' }).isVisible()) {
      await this.loginButton.click();
      await this.emailInput.fill(email);
      await this.passwordInput.fill(password);
      await this.signInButton.click();
      // Verify login successful
      await expect(this.page.getByRole('link', { name: 'idavidov' })).toBeVisible();
    }
  }

  async createArticle(title: string, about: string, content: string) {
    await this.newArticleButton.click();
    await this.articleTitleInput.fill(title);
    await this.articleAboutInput.fill(about);
    await this.articleContentInput.fill(content);
    await this.publishArticleButton.click();

    // Verify article was created
    await expect(this.articleTitleHeading).toHaveText(title);
  }

  async editArticle(title: string, about: string, content: string) {
    await this.editArticleButton.click();
    await this.articleTitleInput.fill(title);
    await this.articleAboutInput.fill(about);
    await this.articleContentInput.fill(content);
    await this.publishArticleButton.click();

    // Verify article was updated
    await expect(this.articleTitleHeading).toHaveText(title);
  }

  async deleteArticle() {
    await this.deleteArticleButton.click();
    // Verify we're redirected to home page
    await expect(this.yourFeedTab).toBeVisible();
  }
}
Enter fullscreen mode Exit fullscreen mode

NOTE The provided example was generated from the first time. Only update which was needed to be made was to remove 'articleContent' locator due to wrong behavior.

Pros of the selected pattern

  1. Lazy Evaluation: Locators are created only when accessed, ensuring up-to-date references.
  2. Readability: Clean, property-like access (pageObject.usernameInput).
  3. Encapsulation: Easy to add logic or assertions in the getter if needed.
  4. IntelliSense: Good support in editors for auto-completion.

Cons of the selected pattern

  1. Performance: Each access creates a new locator (though Playwright locators are lightweight).
  2. Inheritance: Overriding getters in subclasses can be less straightforward than overriding fields.

What's next?

Stay tuned for next article in which we will explore SWE-1.
Please, do not hesitate to start conversation regarding the test or it's result.

🙏🏻 Thank you for reading! Building robust, scalable automation frameworks is a journey best taken together. If you found this article helpful, consider joining a growing community of QA professionals 🚀 who are passionate about mastering modern testing.

Join the community and get the latest articles and tips by signing up for the newsletter.

Top comments (0)