Introduction
As we setup the stage in Part 1 we are ready to continue exploration. We will start with GPT-4.1.
Prerequisites
- GPT-4.1 is selected as a model
- 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
Generated POM (Page Object Model)
class ArticlePage {
constructor(private page: Page) {}
get nav() {
return {
signIn: this.page.getByRole('link', { name: 'Sign in' }),
newArticle: this.page.getByRole('link', { name: /New Article/ }),
username: (username: string) => this.page.getByRole('link', { name: username }),
};
}
get loginForm() {
return {
email: this.page.getByRole('textbox', { name: 'Email' }),
password: this.page.getByRole('textbox', { name: 'Password' }),
submit: this.page.getByRole('button', { name: 'Sign in' }),
};
}
get editorForm() {
return {
title: this.page.getByRole('textbox', { name: 'Article Title' }),
about: this.page.getByRole('textbox', { name: "What's this article about?" }),
content: this.page.getByRole('textbox', { name: /Write your article/ }),
publish: this.page.getByRole('button', { name: 'Publish Article' }),
};
}
get article() {
return {
title: (title: string) => this.page.getByRole('heading', { name: title }),
edit: this.page.getByRole('link', { name: /Edit Article/ }).first(),
delete: this.page.getByRole('button', { name: /Delete Article/ }).first(),
};
}
async login(email: string, password: string, username: string) {
await this.nav.signIn.click();
await this.loginForm.email.fill(email);
await this.loginForm.password.fill(password);
await this.loginForm.submit.click();
await expect(this.nav.username(username)).toBeVisible();
}
async createArticle(title: string, about: string, content: string) {
await this.nav.newArticle.click();
await this.editorForm.title.fill(title);
await this.editorForm.about.fill(about);
await this.editorForm.content.fill(content);
await this.editorForm.publish.click();
await expect(this.article.title(title)).toBeVisible();
}
async editArticle(updatedTitle: string, updatedAbout: string, updatedContent: string) {
await this.article.edit.click();
await this.editorForm.title.fill(updatedTitle);
await this.editorForm.about.fill(updatedAbout);
await this.editorForm.content.fill(updatedContent);
await this.editorForm.publish.click();
await expect(this.article.title(updatedTitle)).toBeVisible();
}
async deleteArticle() {
await this.article.delete.click();
// After deletion, should be redirected to home/profile, article should not be visible
}
}
NOTE The provided example was generated from the first time. Only update which was needed to be made was to specify .first()
for the delete button and edit button.
Pros of the selected pattern
- Lazy Evaluation: Locators are created only when accessed, ensuring up-to-date references.
- Centralized: All locators are grouped in one object, making them easy to find and update.
- Encapsulation: Easy to add logic or assertions in the getter if needed.
- IntelliSense: Good support in editors for auto-completion.
Cons of the selected pattern
- Performance: Each access creates a new locator (though Playwright locators are lightweight).
- 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 Claude 3.7 Sonnet (Thinking).
Please, do not hesitate to start conversation regarding the test or it's result.
Top comments (2)
pretty cool setup tbh, makes me wanna dig into what actually makes some test patterns stick better over time - you ever feel like itβs more about personal style or does the pattern really change team speed?
Spoiler alert π¨ all 5 LLMs produced different outcomes. In my opinion there are two camps - first do not want to change, because the comfort zone is way to comfortable, the other one - searches for better solution every day.
I started these experiments and I am fascinated - whit every one I find something that I was not aware of.
Depending on the project, I think lightweight POM or Functional Helpers are the best way to go. The teamβs speed depends on maturity and on the pattern they are using, but whit modern frameworks as Playwright and Cypress, there is no need to over complicate the design.