This README provides step-by-step instructions for setting up, configuring, and running the project using Playwright and other development tools such as Prettier, ESLint, and TypeScript.
Playwright documentation: https://playwright.dev/docs/intro
- Pre-requisites
- Setting Up the Project
- Adding and Configuring Environments
- Project Folder Structure
- Running Tests
- Recording and Playing with Playwright Test Generator
- Playwright extension VS code
- Code Formatting with Prettier
- Linting with ESLint
- TypeScript Configuration (
tsconfig.json)
Before you start, ensure the following:
- Install Visual Studio Code
- Install Git
- Install Node.js
- Download and install Node.js from here.
- Creating a New Repo from This Template
- Go to the template repository.
- Click Use this template at the top right.
- Choose Create a new repository.
- Fill in the repo name, description, and visibility (public/private).
- Click Create repository from template.
- Clone your new repository locally:
git clone https://new-repo.git
cd new-repo- Set up the project by installing dependencies
- Navigate to the project directory and run:
npm run setup
- Navigate to the project directory and run:
To keep sensitive data secure and easily configurable, we use environment file(s) to manage environment-specific variables such as API keys, URLs, or credentials. Ensure you create and configure this file before running the tests.
This project supports multiple environments (e.g., local, dev, qa) for flexible configuration. Here’s how to add and configure them:
Steps to Add Environments
-
Create Environment Files:
- Create
environmentsfolder in the project root. - Add environment-specific
.envfiles to environments, such as:local.envdev.envqa.env
- Create
-
Configure Environment Variables:
- Define the variables required by your project in each
.envfile. - Example content for
local.env:environment=local USERNAME=test_user PASSWORD=test_pass URL=https://local.company.com
- Example content for
dev.env:environment=dev USERNAME=test_user PASSWORD=test_pass URL=https://dev.company.com
- Example content for
qa.env:environment=qa USERNAME=test_user PASSWORD=test_pass URL=https://qa.company.com
environments/ ├── local.env # Configuration for the local environment ├── dev.env # Configuration for the development environment └── qa.env # Configuration for the QA environment
- Define the variables required by your project in each
-
Configuring Environments in
playwright.config.ts- The
playwright.config.tsfile is set up to load environment-specific configurations based on theNODE_ENVvariable.
- The
- The environment is determined by the value of
NODE_ENV. - Based on the selected environment, the corresponding
.envfile is loaded, and its variables are made available in the runtime environment. - If no environment is specified, the
localenvironment is used by default.
- loadEnv(env: string): Loads environment variables from the corresponding .env file based on the provided environment (local by default).
- Purpose: Environment files (
.env) store environment-specific settings securely and allow you to switch between configurations easily. - Examples of Common Content in Environment Files:
- URLs: Base URLs for services or APIs (
BASE_URL). - Keys: API keys or secrets required for authentication (
API_KEY). - Timeouts: Configuration for network request timeouts (
TIMEOUT). - Custom Variables: Any other key-value pairs specific to the project requirements.
- Credentials: Credentials required for login (
USER_NAME,USER_PWD)
- URLs: Base URLs for services or APIs (
- Environment variables can be accessed anywhere into the project through
process.env.{variable_name_as_per_env_file}.
This section provides an overview of the src directory's structure, explains the Page Object Model (POM) design pattern, and outlines what each folder contains.
The src directory is organized as follows:
src
├── pages
│ │── ui # Specific UI page objects that contains classes for UI components (e.g., LoginPage, DashboardPage)
│ │── api # Specific API page objects that contains classes or modules for interacting with API endpoints
├── shared
│ ├── mock-data # Shared test data
│ ├── types # Shared types
│ ├── utils # Shared helper functions, configurations, or utilities
├── tests
│ ├── ui # UI test scripts and fixtures for validating components and interactions
| ├── e2e # End-to-end test scripts and fixtures for validating user journeys across systems
│ ├── api # API test scripts and fixtures for validating responses and workflows
The Page Object Model (POM) is utilized for organizing UI, API, and end-to-end test files. Each application page or endpoint is represented by a class or module, enabling a clean separation of concerns and improving maintainability.
- Pages: Represents the application's UI pages or API endpoints. Contains all related elements and actions.
- Tests: Contains test scripts to validate functionality by using methods from the
pages. - Utils: Provides shared helpers, mock data, constants, and utilities.
- Purpose: Stores shared resources and logic that can be used across all projects.
- Structure:
- mock-data: Contains test data which can be used to validate functionalities
- Example:
export const projectMockData: Project = { name: "New Project - Test 1", description: "New Project - Description", type: "Default", group: "new_group", coordinates: [], };
- Example:
- types: Contains types.
- Example:
export type Project = { name: string; description: string; type: string; group: string; coordinates: Coordinates[]; };
- Example:
- utils: Provides custom logger, global helper functions or utility scripts, e.g., data formatting methods or mock generators or api utils.
- custom-logger.ts file contains implementation of logger functionality that helps in recording steps taken to execute each tests.
- mock-data: Contains test data which can be used to validate functionalities
-
ui: Contains classes to model individual pages/components and includes methods to interact with page elements (e.g., clicking buttons, entering text, validating UI elements).- Example:
class LoginPage { async enterUsername(username) { await page.locator('#username').fill(username); } async enterPassword(password) { await page.locator('#password').fill(password); } async clickLogin() { await page.locator('#loginBtn').click(); } }
- Example:
-
api: Manages API endpoint interactions with reusable methods.- Example:
class UserAPI { getUser(userId) { /* API call logic */ } createUser(data) { /* API call logic */ } }
- Example:
ui: Contains test scripts for UI components and interactions.- Example:
test('login form validation', async () => { await loginPage.enterUsername('user'); await loginPage.enterPassword(''); await loginPage.clickLogin(); expect(await loginPage.errorText).toBe('Password is required'); });
- Example:
e2e: Implements end-to-end testing scenarios to validate workflows.- Example:
test('create project', async () => { await loginPage.login('user', 'password'); await projectPage.createProject({ name: 'New Project', type: 'default' }); });
- Example:
api: Validates API responses, status codes, and workflows.- Example:
test('should fetch user details', async () => { const user = await userApi.getUser(1); expect(user.name).toBe('John Doe'); });
- Example:
What Pages Will Include:
- Web Elements: Locators for UI elements or endpoints for APIs.
- Example (for UI):
this.loginButton = page.locator('#loginBtn');
- Example (for UI):
- Actions: Methods for interacting with the elements (e.g.,
clickLogin(),enterUsername()). - Reusable Functions: Methods for common tasks like navigation or API requests.
What Tests Will Include:
- Scenario Definitions: Scripts to validate specific functionalities or workflows.
- Example: "Verify that the user can log in successfully."
- Assertions: Checks to validate expected outcomes.
- Example:
expect(page.url()).toBe('https://example.com/dashboard');
- Example:
- Setup and Teardown: Initialization and cleanup code to prepare the test environment. This can be moved to fixtures folder. Fixtures encapsulates setup/teardown, are reusable beween test files and can help with grouping
This section provides information about various test scripts defined in package.json.
Here are the defined test commands and their purposes:
| Command | Description |
|---|---|
npm run test |
Runs all Playwright tests in headless mode. |
npm run test:local |
Runs all Playwright tests using local environment variables in headless mode. |
npm run test:dev |
Runs all Playwright tests using dev environment variables in headless mode. |
npm run test:headed |
Runs all Playwright tests in headed mode. |
npm run test:custom |
Launches an interactive prompt to customize and execute test runs based on environment, browser, test mode, test type, and test group. |
npm run test:ui |
Opens the Playwright Test Runner UI for interactive test execution and debugging. |
npm run test:report:playwright |
Opens the latest Playwright test execution HTML report. |
npm run test:report:custom |
Opens the latest test execution custom HTML report. |
npm run test:debug |
Runs Playwright tests in debug mode for step-by-step troubleshooting. |
npm run test:trace |
Executes Playwright tests with tracing enabled for performance analysis and debugging. |
Interactive Test Execution: Custom Tests
npm run test:customThe test:custom command runs the run-custom-tests.ts script. The run-custom-tests.ts script is an interactive tool for flexible test execution. It allows you to select the environment, browser, test type, test group and test mode. Based on your choices, it dynamically constructs and runs the appropriate Playwright command, simplifying custom test runs without manual configuration changes.
Usage Example
To run the custom test flow:
- Execute the script:
npm run test:custom
- Follow the prompts to select your environment, browser, test type, test group and test mode.
- The script will execute the selected tests and display the output.
For more details on how the script works, refer to Custom Test Script: run-custom-tests.ts.
The run-custom-tests.ts script enables dynamic test execution through interactive prompts. It allows users to select the following options:
-
Environment:
- Select an environment:
LocalDevQA
- Select an environment:
-
Browser:
- Select the browser:
ChromiumFirefoxWebKit
- Select the browser:
-
Test Type:
- Specify the type of tests:
APIUIE2E
- Specify the type of tests:
-
Test Group:
- Filter tests by tag:
RegressionSmoke
- Filter tests by tag:
-
Test Mode:
- Filter tests by tag:
HeadlessUI
- Filter tests by tag:
Sample Command Generated by Script If the user selects:
- Environment:
QA - Browser:
Chromium - Test Type:
UI - Test Group:
Regression - TestMode:
Default => Headless
The generated command will look like:
npx cross-env NODE_ENV=local playwright test --project=chromium .src/tests/ui --grep "@regression"The script dynamically builds this command, ensuring flexible and efficient test execution.
- For test generator tutorial, refer Test generator.
- For more test generation capabilities tutorial, refer Codegen
The Playwright VS Code extension integrates Playwright's end-to-end testing capabilities directly into Visual Studio Code. It allows users to install Playwright, run tests with a single click, debug step-by-step, and view test results in the testing sidebar. The extension supports multiple browsers, configurations, and even GitHub Actions for CI/CD workflows. It also helps with generating tests, please refer Playwright VS code.
Prettier is configured for consistent and readable code formatting across the project.
printWidth: 120: Wraps lines longer than 120 characters.tabWidth: 2: Sets indentation to 2 spaces.useTabs: true: Uses tabs for indentation.semi: true: Adds semicolons at the end of statements.trailingComma: "all": Includes trailing commas where valid.bracketSpacing: true: Adds spaces between brackets in object literals.arrowParens: "always": Requires parentheses for all arrow function parameters.
- Open Visual Studio Code.
- Go to the Extensions view (
Ctrl+Shift+X). - Search for "Prettier - Code formatter" and click Install.
- Go to Settings in VS code > Text Editor > Formatting.
- Check the Format On Save checkbox.
This section explains the ESLint configuration file (eslint.config.mjs) and how it integrates with TypeScript and Prettier to ensure consistent and maintainable code quality.
ESLint is a powerful static code analysis tool designed to detect potential errors, enforce coding standards, and maintain consistent formatting in JavaScript and TypeScript projects. By integrating custom and predefined rules, it ensures code quality, prevents bugs, and aligns with industry best practices. ESLint's flexibility allows for integration with tools like Prettier for code formatting while excluding unnecessary files to optimize performance. Overall, it simplifies collaboration within teams, enhances readability, and promotes maintainable and reliable codebases.
The eslint.config.mjs file is configured to lint TypeScript files while incorporating Prettier for code formatting. It provides:
- TypeScript-specific linting rules.
- Integration with Prettier for consistent formatting.
- Custom rules tailored for project requirements.
- Exclusion of unnecessary directories to optimize linting.
Targeted Files
files: ["**/*.ts"]Specifies that ESLint will target all TypeScript files (.ts) in the project.
Ignored Directories
ignores: [
"node_modules/**",
"test-results/**",
"playwright-report/**",
"./vs/**"
]Defines directories that ESLint will ignore during linting:
node_modules: Excludes dependencies.test-results: Avoids linting test result files.playwright-report: Excludes Playwright reports../vs: Ignores specific IDE-related directories.
Language Options
languageOptions: {
parser: tsparser,
sourceType: "module",
parserOptions: {
project: "./tsconfig.json",
},
}Specifies settings for TypeScript files:
- Parser:
@typescript-eslint/parseris used to process TypeScript syntax. - Source Type: Indicates that ECMAScript modules (
module) are being used. - Parser Options: Points to
tsconfig.jsonfor TypeScript compilation settings, ensuring ESLint aligns with the TypeScript compiler.
Plugins
plugins: {
"@typescript-eslint": tseslint,
prettier: prettierPlugin,
}@typescript-eslint: Provides TypeScript-specific linting rules.prettier: Integrates Prettier with ESLint to enforce consistent formatting.
rules: {
...tseslint.configs.recommended.rules,
...prettierConfig.rules,
"@typescript-eslint/no-unused-vars": "warn",
"no-console": "warn",
semi: ["error", "always"],
quotes: ["error", "double", { avoidEscape: true }],
"prettier/prettier": "error",
}Defines linting rules for TypeScript and Prettier:
- TypeScript Rules:
- Uses recommended rules from
@typescript-eslint. - Warns about unused variables:
"@typescript-eslint/no-unused-vars": "warn".
- Uses recommended rules from
- Custom Rules:
- Warns against
console.logand similar statements:"no-console": "warn". - Requires semicolons at the end of statements:
"semi": ["error", "always"]. - Enforces double quotes for strings, avoiding escape sequences:
"quotes": ["error", "double", { avoidEscape: true }].
- Warns against
- Prettier Integration:
- Enforces Prettier formatting rules:
"prettier/prettier": "error".
- Enforces Prettier formatting rules:
-
TypeScript Integration:
- Ensures TypeScript syntax and coding practices are followed.
- Aligns linting settings with the TypeScript compiler through
tsconfig.json.
-
Prettier Integration:
- Automates formatting with Prettier while resolving conflicts between ESLint and Prettier rules.
-
Customizable Rules:
- Allows flexibility to tailor linting and formatting based on project-specific requirements.
-
Optimization:
- Excludes unnecessary files and directories to streamline linting.
For more details on ESLint configurations, check the ESLint Documentation.
The tsconfig.json file is a configuration file for the TypeScript compiler that specifies how the project should be compiled. Below is a detailed explanation of its settings:
Target
"target": "es2016"Specifies the version of Typescript to which TypeScript code will be compiled. es2016 ensures compatibility with ES2016 features.
Module
"module": "commonjs"Defines the module system to use in the compiled Typescript. commonjs is commonly used in Node.js environments.
Base URL
"baseUrl": "./"Sets the base directory for module resolution. In this case, it is set to the project's root directory.
Paths
"paths": {
"*": ["./src/*"]
}Defines module aliasing. It maps imports to the src directory, enabling easier imports without using relative paths.
OutDir
"outDir": "./dist"Specifies the directory where compiled Typescript files will be output, which in this case is the dist folder.
ES Module Interop
"esModuleInterop": trueEnables interoperability between CommonJS and ES Modules, allowing default imports from CommonJS modules.
Force Consistent Casing in File Names
"forceConsistentCasingInFileNames": trueEnsures that file names are treated case-sensitively, helping prevent issues on case-sensitive operating systems.
No Implicit Any
"noImplicitAny": trueRequires all variables to have explicit types, improving type safety by disallowing the use of any as a default type.
Strict
"strict": trueEnables all strict type-checking options, enhancing overall code reliability and reducing the risk of type errors.
Include
"include": ["src", "./eslint.config.mjs", "./playwright.config.ts"]Specifies files and directories to include in the compilation process:
src: Includes thesrcfolder, where the main project code resides../eslint.config.mjs: Includes the ESLint configuration file../playwright.config.ts: Includes the Playwright configuration file.
Exclude
"exclude": ["node_modules", "dist"]Defines directories to exclude from compilation:
node_modules: Excludes installed dependencies to avoid recompiling them.dist: Excludes the output directory to prevent re-compilation of already built files.
This configuration is designed for a Node.js-based TypeScript project with:
- Clean and structured paths for imports.
- Strict type checking for improved code quality.
- Compatibility with modern Typescript features (ES2016).
- Easy integration with tools like ESLint and Playwright.
By including eslint.config.mjs and playwright.config.ts, this configuration is tailored for projects that require robust linting and testing setups alongside TypeScript compilation.
For more details on TypeScript configurations, check the TypeScript Documentation
