TS-Playwright

Playwright Typescript Test Automation Project Structure

Below is a comprehensive project structure leveraging the UI and API testing framework using Playwright, following the Page Object Model, with additional GitHub CI/CD integration and reusable utilities.


Project Structure

playwright-testing-project/
├── .github/
│   ├── CODEOWNERS
│   ├── workflows/
│   │   └── nightly-build.yml
│   └── PULL_REQUEST_TEMPLATE.md
├── src/
│   ├── api/
│   │   ├── endpoints/
│   │   │   ├── user.ts
│   │   │   ├── auth.ts
│   │   │   └── product.ts
│   │   ├── helpers/
│   │   │   ├── apiClient.ts
│   │   │   └── authHelper.ts
│   │   └── tests/
│   │       ├── userApi.test.ts
│   │       └── productApi.test.ts
│   ├── ui/
│   │   ├── pages/
│   │   │   ├── loginPage.ts
│   │   │   ├── homePage.ts
│   │   │   └── productPage.ts
│   │   ├── tests/
│   │   │   ├── login.test.ts
│   │   │   ├── navigation.test.ts
│   │   │   └── productFlow.test.ts
│   │   ├── components/
│   │   │   ├── header.ts
│   │   │   ├── footer.ts
│   │   │   └── sidebar.ts
│   │   └── utils/
│   │       ├── config.ts
│   │       ├── logger.ts
│   │       └── helperFunctions.ts
├── .gitignore
├── README.md
├── playwright.config.ts
├── package.json
├── tsconfig.json
└── allure-results/

File Descriptions and Examples

.github/

  1. CODEOWNERS

    * @username1 @username2
    

    Ensures specific team members are assigned to review PRs.

  2. workflows/nightly-build.yml

    name: Nightly Build
    
    on:
      schedule:
        - cron: "0 2 * * *"
      push:
        branches:
          - main
    
    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout Code
            uses: actions/checkout@v3
    
          - name: Setup Node.js
            uses: actions/setup-node@v3
            with:
              node-version: '18'
    
          - name: Install Dependencies
            run: npm install
    
          - name: Run Tests
            run: npm run test:all
          
          - name: Upload Allure Results
            uses: actions/upload-artifact@v3
            with:
              name: allure-results
              path: allure-results
    
  3. PULL_REQUEST_TEMPLATE.md

    # Pull Request Template
    
    ## Description
    - [ ] Added/Updated tests
    - [ ] Fixed issue #
    - [ ] Other (explain):
    
    ## How Has This Been Tested?
    - [ ] Locally
    - [ ] CI/CD
    
    ## Checklist
    - [ ] Code follows coding standards
    - [ ] No console errors or warnings
    - [ ] Documentation updated (if applicable)
    

src/api/

  1. endpoints/user.ts

    export const getUserDetails = async (id: string) => {
        const response = await fetch(`https://api.example.com/users/${id}`);
        return response.json();
    };
    
  2. helpers/apiClient.ts

    import fetch from 'node-fetch';
    
    export const apiClient = async (url: string, method: string = 'GET', body?: object) => {
        const response = await fetch(url, {
            method,
            headers: { 'Content-Type': 'application/json' },
            body: body ? JSON.stringify(body) : undefined,
        });
        return response.json();
    };
    

src/ui/pages/

  1. loginPage.ts
    import { Page } from '@playwright/test';
    
    export class LoginPage {
        constructor(private page: Page) {}
    
        async navigate() {
            await this.page.goto('/login');
        }
    
        async login(username: string, password: string) {
            await this.page.fill('#username', username);
            await this.page.fill('#password', password);
            await this.page.click('#loginButton');
        }
    }
    

Utilities

  1. src/ui/utils/config.ts

    export const config = {
        baseURL: 'https://example.com',
        apiBaseURL: 'https://api.example.com',
    };
    
  2. src/ui/utils/logger.ts

    export const log = (message: string) => console.log(`[LOG]: ${message}`);
    

Test Scripts

  1. src/ui/tests/login.test.ts

    import { test } from '@playwright/test';
    import { LoginPage } from '../pages/loginPage';
    
    test('Login test', async ({ page }) => {
        const loginPage = new LoginPage(page);
        await loginPage.navigate();
        await loginPage.login('testuser', 'password');
        // Assertions
    });
    
  2. src/api/tests/userApi.test.ts

    import { test } from '@playwright/test';
    import { getUserDetails } from '../endpoints/user';
    
    test('Get user details', async () => {
        const user = await getUserDetails('123');
        expect(user.name).toBeDefined();
    });
    

Config Files

  1. .gitignore

    node_modules/
    allure-results/
    dist/
    .env
    
  2. playwright.config.ts

    import { defineConfig } from '@playwright/test';
    
    export default defineConfig({
        testDir: './src',
        timeout: 30000,
        reporter: [['html'], ['allure-playwright']],
        use: {
            baseURL: 'https://example.com',
            headless: true,
        },
    });
    
  3. package.json

    {
        "name": "playwright-testing-project",
        "version": "1.0.0",
        "scripts": {
            "test": "playwright test",
            "test:all": "playwright test --project=all"
        },
        "dependencies": {
            "@playwright/test": "^1.38.0",
            "allure-playwright": "^2.0.0"
        }
    }
    

This structure ensures maintainability, scalability, and proper CI/CD integration for both UI and API tests.