Skip to content

Commit

Permalink
stream #4
Browse files Browse the repository at this point in the history
  • Loading branch information
Xotabu4 committed Dec 27, 2023
1 parent 0af302e commit 3314145
Show file tree
Hide file tree
Showing 23 changed files with 161 additions and 50 deletions.
2 changes: 2 additions & 0 deletions api/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { request } from "@playwright/test"
import { step } from "../misc/reporters/step"

// fetch("https://shopdemo-alex-hot.koyeb.app/api/auth/register", {
// "headers": {
Expand Down Expand Up @@ -55,6 +56,7 @@ export interface UserCreateRequest {
}

export class API {
@step()
async createNewUser(data: UserCreateRequest): Promise<UserCreatedResponse> {
const req = await request.newContext();
const resp = await req.post('https://shopdemo-alex-hot.koyeb.app/api/auth/register', {
Expand Down
3 changes: 3 additions & 0 deletions app/abstractClasses.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import type { Page } from '@playwright/test';
import { step } from '../misc/reporters/step';

export abstract class PageHolder {
constructor(protected page: Page) { }
}
export abstract class Component extends PageHolder {
abstract expectLoaded(message?: string): Promise<void>;

@step()
async isLoaded(): Promise<boolean> {
try {
await this.expectLoaded()
Expand All @@ -26,6 +28,7 @@ export abstract class AppPage extends Component {
/**
* Opens the page in the browser and expectLoaded should pass
*/
@step()
async open(path?: string) {
await this.page.goto(path ?? this.pagePath);
await this.expectLoaded();
Expand Down
6 changes: 6 additions & 0 deletions app/component/header.component.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import { expect } from "@playwright/test";
import { Component } from "../abstractClasses";
import { step } from "../../misc/reporters/step";

export class Header extends Component {
private shopLink = this.page.getByRole('link', { name: 'Shop' })
private cartLink = this.page.getByRole('button', { name: 'your cart' })

@step()
async expectLoaded(message = 'Expected Header to be loaded'): Promise<void> {
await expect(this.shopLink, message).toBeVisible();
}

@step()
async openCart() {
await this.cartLink.click();
}

@step()
async openShop() {
await this.shopLink.click()
}
Expand Down
6 changes: 6 additions & 0 deletions app/component/minicart.component.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import { expect } from "@playwright/test";
import { Component } from "../abstractClasses";
import { step } from "../../misc/reporters/step";

export class MiniCart extends Component {
private proceedToCheckoutButton = this.page.getByRole('button', { name: 'Proceed To Checkout' });
private placeOrderButton = this.page.getByRole('button', { name: 'Place Order' });

@step()
async expectLoaded() {
await expect(this.proceedToCheckoutButton.or(this.placeOrderButton)).toBeVisible();
}

@step()
async proceedToCheckout() {
await this.proceedToCheckoutButton.click();
}

@step()
async placeOrder() {
await this.placeOrderButton.click();
}
Expand Down
2 changes: 2 additions & 0 deletions app/page/account/details.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { expect } from "@playwright/test";
import { AppPage } from "../../abstractClasses";
import { Header } from "../../component/header.component";
import { MiniCart } from "../../component/minicart.component";
import { step } from "../../../misc/reporters/step";

export class AccountDetails extends AppPage {
public pagePath = '/details'
Expand All @@ -11,6 +12,7 @@ export class AccountDetails extends AppPage {

private heading = this.page.getByRole('heading', { name: 'Account Details' })

@step()
async expectLoaded() {
await expect(this.heading).toBeVisible();
}
Expand Down
3 changes: 3 additions & 0 deletions app/page/confirmation.page.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { expect } from "@playwright/test";
import { AppPage } from "../abstractClasses";
import { step } from "../../misc/reporters/step";

export class Confirmation extends AppPage {
public pagePath = 'order/success/';

private successMessage = this.page.getByRole('heading', { name: 'Thank you for your order.' })

@step()
async expectLoaded(message = 'Expected confirmation page to be loaded') {
await expect(this.successMessage, message).toBeVisible();
}

@step()
async expectOrderPlaced() {
await this.expectLoaded('Expected order to be placed sucessfully');
}
Expand Down
3 changes: 3 additions & 0 deletions app/page/contactus.page.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { expect } from "@playwright/test";
import { AppPage } from "../abstractClasses";
import { step } from "../../misc/reporters/step";

export class ContactUs extends AppPage {
public pagePath = '/contact'
Expand All @@ -9,13 +10,15 @@ export class ContactUs extends AppPage {
private messageInput = this.page.getByPlaceholder('Please Describe Your Message');
private submitButton = this.page.getByRole('button', { name: 'Submit' });

@step()
async expectLoaded() {
await expect(this.fullNameInput).toBeVisible();
await expect(this.emailInput).toBeVisible();
await expect(this.messageInput).toBeVisible();
await expect(this.submitButton).toBeVisible();
}

@step()
async submitContactUsForm(options: { fullName: string, email: string, message: string }) {
await this.expectLoaded();
await this.fullNameInput.fill(options.fullName);
Expand Down
2 changes: 2 additions & 0 deletions app/page/home.page.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { expect } from "@playwright/test";
import { AppPage } from "../abstractClasses";
import { Header } from "../component/header.component";
import { step } from "../../misc/reporters/step";

export class Home extends AppPage {
public pagePath = '/';

public header = new Header(this.page);
private carousel = this.page.locator('.main .homepage .home-carousel')

@step()
async expectLoaded(message = 'Expected Home page to be opened') {
await expect(this.carousel, message).toBeVisible();
}
Expand Down
10 changes: 8 additions & 2 deletions app/page/product/component/review.component.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import { expect } from "@playwright/test";
import { Component } from "../../../abstractClasses";
import { step } from "../../../../misc/reporters/step";

export class Review extends Component {
starRating = (star: number) => this.page.locator(`.react-stars [data-index="${star}"] .fa-star`);
titleInput = this.page.getByPlaceholder('Enter Review title');
commentInput = this.page.getByPlaceholder('Write Review');
publishButton = this.page.getByRole('button', { name: 'Publish Review' });
confirmation = this.page.locator('.notification-title');


@step()
async expectLoaded(): Promise<void> {
await expect(this.starRating(0)).toBeVisible();
await expect(this.starRating(4)).toBeVisible();
await expect(this.titleInput).toBeVisible();
await expect(this.commentInput).toBeVisible();
await expect(this.publishButton).toBeVisible();
}

@step()
async add(options: { title: string, comment: string, stars: number }) {
await this.expectLoaded();
if (options.stars < 0 || options.stars > 4) throw new Error('Stars should be between 0 and 4');
Expand All @@ -24,7 +28,9 @@ export class Review extends Component {
await this.starRating(options.stars).click();
await this.publishButton.click();
}

@step()
async expectReviewAdded() {
await expect(this.confirmation).toHaveText('Your review has been added successfully and will appear when approved!')
await expect(this.page.getByRole('heading', { name: 'Your review has been added' })).toBeVisible();
}
}
4 changes: 4 additions & 0 deletions app/page/product/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AppPage } from "../../abstractClasses";
import { Header } from "../../component/header.component";
import { MiniCart } from "../../component/minicart.component";
import { Review } from "./component/review.component";
import { step } from "../../../misc/reporters/step";

export class Product extends AppPage {
public pagePath = '/product';
Expand All @@ -15,17 +16,20 @@ export class Product extends AppPage {

public reviewComponent = new Review(this.page);

@step()
async expectLoaded(message = 'Expected Product page to be opened') {
await expect(this.addToBagButton
.or(this.removeFromBagButton),
message
).toBeVisible();
}

@step()
override async open(productPath: string): Promise<void> {
await this.page.goto(productPath);
}

@step()
async addToBag() {
await this.expectLoaded();
await this.addToBagButton.click();
Expand Down
3 changes: 3 additions & 0 deletions app/page/shop.page.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { expect } from "@playwright/test";
import { AppPage } from "../abstractClasses";
import { Header } from "../component/header.component";
import { step } from "../../misc/reporters/step";

export class Shop extends AppPage {
public pagePath = '/shop';
Expand All @@ -9,10 +10,12 @@ export class Shop extends AppPage {

private productList = this.page.locator('.shop .product-list')

@step()
async expectLoaded(message = 'Expected Shop page to be opened') {
await expect(this.productList, message).toBeVisible()
}

@step()
async openProductDetailsByName(name: string) {
await this.page.getByRole('heading', { name }).click();
}
Expand Down
19 changes: 4 additions & 15 deletions app/page/signin.page.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { expect } from "@playwright/test";
import { AppPage } from "../abstractClasses";
import { step } from "../../misc/reporters/step";

export class SignIn extends AppPage {
public pagePath = '/login'
Expand All @@ -8,30 +9,18 @@ export class SignIn extends AppPage {
private emailInput = this.page.getByRole('main').getByPlaceholder('Please Enter Your Email')
private passwordInput = this.page.getByPlaceholder('Please Enter Your Password')

@step()
async expectLoaded() {
await expect(this.signInButton).toBeVisible();
await expect(this.emailInput).toBeVisible();
await expect(this.passwordInput).toBeVisible();
}

@step()
async signIn(user: { email: string, password: string }) {
await this.expectLoaded();
await this.emailInput.fill(user.email)
await this.passwordInput.fill(user.password)
await this.signInButton.click()
}
}

/**
export const signIn2 = (page: Page) => {
return {
signInButton: page.getByRole('button', { name: 'Login' }),
emailInput: page.getByRole('main').getByPlaceholder('Please Enter Your Email'),
passwordInput: page.getByPlaceholder('Please Enter Your Password'),
async signIn(user: { email: string, password: string }) {
await this.emailInput.fill(user.email);
await this.passwordInput.fill(user.password);
await this.signInButton.click()
}
}
}
*/
3 changes: 3 additions & 0 deletions app/page/signup.page.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { expect } from "@playwright/test";
import { AppPage } from "../abstractClasses";
import { step } from "../../misc/reporters/step";

export class SignUp extends AppPage {
public pagePath = '/register';
Expand All @@ -10,10 +11,12 @@ export class SignUp extends AppPage {
private passwordInput = this.page.getByPlaceholder('Please Enter Your Password')
private signUpButton = this.page.getByRole('button', { name: 'Sign Up' });

@step()
async expectLoaded() {
await expect(this.emailInput, 'Expected SignUp page to be opened').toBeVisible();
}

@step()
async signUpNewUser() {
await this.emailInput.fill(`test+${Date.now()}@test.com`);
await this.firstNameInput.fill('test');
Expand Down
35 changes: 35 additions & 0 deletions misc/reporters/slowStepReporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type {
Reporter, FullConfig, Suite, TestCase, TestResult, FullResult, TestStep, Location
} from '@playwright/test/reporter';

class SlowStepReporter implements Reporter {
private steps: Array<{ count: number, name: string, location: string | undefined, duration: number }> = [];

onStepEnd(test: TestCase, result: TestResult, step: TestStep) {
if (step.category === 'test.step') {
const stepToReport = {
count: 1,
name: step.titlePath().join('->'),
location: `${step.location?.file}:${step.location?.line}`,
duration: step.duration
}
const alreadyReported = this.steps.find(s => s.name === stepToReport.name);

if (alreadyReported) {
alreadyReported.count++
} else {
this.steps.push(stepToReport);
}
}
}

onEnd() {
console.warn('TOP-10 slowest steps')
console.table(
// Slowest first
this.steps.sort((a, b) => b.duration - a.duration)
// TOP-10 slowest steps
.slice(0, 10))
}
}
export default SlowStepReporter;
28 changes: 28 additions & 0 deletions misc/reporters/step.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { test } from '@playwright/test';

/**
* Decorator that wraps a function with a Playwright test step.
* Used for reporting purposes.
*
* @example
```
import { step } from './step_decorator';
class MyTestClass {
@step('optional step name')
async myTestFunction() {
// Test code goes here
}
}
```
*/
export function step<This, Args extends any[], Return>(message?: string) {
return function actualDecorator(target: (this: This, ...args: Args) => Promise<Return>, context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Promise<Return>>) {
function replacementMethod(this: any, ...args: Args) {
const name = message ?? `${this.constructor.name}.${context.name as string}`;

return test.step(name, async () => target.call(this, ...args), { box: true });
}

return replacementMethod;
}
}
Loading

0 comments on commit 3314145

Please sign in to comment.