Note: This repo has tests written for https://testingmaster.in
This document provides a comprehensive guide to using the Playwright automation framework. This framework enables fast and reliable end-to-end testing for modern web applications, supporting Chromium, Firefox, and WebKit. It is designed to facilitate cross-browser web automation, particularly for complex web applications.
Before you begin, ensure you have the following installed:
- Node.js: Version 12 or higher.
- npm or yarn: Package managers for insta*lling dependencies.
- Visual Studio Code (VS Code): Recommended / for development.
- Git: For cloning the project repository.
-
Execute PowerShell Command: Launch PowerShell in administrator mode and run the following command to set the execution policy:
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser
-
Install Node.js: Download and install Node.js from the official website: Node.js Downloads.
- Navigate to the automation project repository.
- Clone the repository to your local machine using Git:
git clone <repository-url>
- Open a command prompt in the framework folder.
- Install the project dependencies using npm:
npm install
- Install Playwright browsers:
npx playwright install
Execute the tests using the following command:
npm run testsOnAIMS_QAThe project follows a structured architecture to promote maintainability and scalability. Here's an overview of the key directories:
src
├── main
│ ├── resources
│ │ └── env
│ │ | └── envConfig.json
│ │ |── allure
│ │ |──smtp-email
│ └── typescript
│ ├── base
│ │ └── BasePage.ts
│ │ └── customFixtures.ts
│ ├── helpers
│ │ └── CustomReporter.ts
│ │ └── Decorators.ts
│ │ ├── env.ts
│ │ ├── global-setup.ts
│ │ ├── log.ts
│ │ └── Utility.ts
│ └── pages
│ ├── actions
│ └── locators
├── test
│ ├── resources
│ └── typescript
│ └── StandardTestSpecFile.spec.ts- src/main/resources/env: Contains environment-specific configuration files.
- envConfig.json: JSON configuration file for managing environment settings.
- src/main/typescript/base: Contains base classes for page objects.
- BasePage.ts: The base class for page objects, providing common functionality.
- src/main/typescript/helpers: Contains helper functions and utilities.
- env.ts: Helper functions for environment management.
- global-setup.ts: Global setup logic executed before the test suite.
- log.ts: Utility for handling and managing test logs.
- Utility.ts: Generic utility functions used across the framework.
- src/main/typescript/pages: Contains page object classes, separating actions and locators.
- test/resources: Contains additional resources for test cases, such as mock data.
- test/typescript: Contains test specification files.
- StandardTestSpecFile.spec.ts: A sample test specification file.
- Start with the
asynckeyword. - Name methods descriptively (e.g.,
loginToHomePage). - Use the following syntax:
async function loginToHomePage() {
// Your code here
}- Use
awaitbefore every asynchronous operation. - Open the browser and launch the application using:
await page.goto('<URL>');- Consistency: Ensure file names and class names are the same.
- Test Files: Use the format
sanity-tests.spec.tsfor test files.
- Standard Imports: Import necessary modules like
test,expect, andpagefrom Playwright. - Environment Variables: Import environment variables from
helpers/env.ts.
- Parallel Configuration: Configure tests to run in parallel.
- Before Each Test: Use
test.beforeEachfor setup tasks.
Organize tests using the Page Object Model (POM). Each page should have its own class with methods representing actions on that page.
import { BasePage } from '../../base/BasePage'
export class NaukariPageActions extends BasePage {
static loginBtn='//a[text()="Login"]'
static usernameField='//input[@placeholder="Enter your active Email ID / Username"]'
static passwordField='//input[@placeholder="Enter your password"]'
static signinBtn='//button[text()="Login"]'
static viewProfile='//div[@class="view-profile-wrapper"]'
static editResumeHeadLineBtn='//span[text()="Resume headline"]//following-sibling::span[text()="editOneTheme"]'
static saveBtn='//button[text()="Save"]'
static successMsg='//p[text()="Success"]'
async loginintoNaukari() {
await this.page.goto(this.ENV.BASE_URL)
await this.utility.waitUntilPageIsLoaded()
await this.page.locator(NaukariPageActions.loginBtn).waitFor({ state: 'visible',timeout:120000 })
await this.utility.waitForLocator({ selector: NaukariPageActions.loginBtn })
await this.utility.click({ selector: NaukariPageActions.loginBtn })
await this.utility.typeText({ selector: NaukariPageActions.usernameField, text: this.ENV.USERNAME})
await this.utility.typeText({ selector: NaukariPageActions.passwordField, text: this.ENV.PASSWORD})
await this.utility.click({ selector: NaukariPageActions.signinBtn })
await this.utility.waitUntilPageIsLoaded()
await this.utility.click({ selector: NaukariPageActions.viewProfile })
await this.utility.click({ selector: NaukariPageActions.editResumeHeadLineBtn })
await this.utility.click({ selector: NaukariPageActions.saveBtn })
await this.utility.waitForLocator({ selector: NaukariPageActions.successMsg })
await this.utility.waitUntilPageIsLoaded()
}
}await this.utility.click({ selector: NaukariPageActions.editResumeHeadLineBtn })await page.fill('#inputField', 'value');await this.utility.typeText({ selector: NaukariPageActions.usernameField, text: '100' }) await this.utility.selectDropDownValue({ selector: NaukariPageActions.slctPPTypeDropdown, text: 'Person' });-
Create a Test File:
- Create a new test file in the
test/typescriptdirectory. - Follow the naming convention:
[feature-name].spec.ts(e.g.,business-entity.spec.ts).
- Create a new test file in the
-
Import Necessary Modules:
- Import
testandexpectfrom@playwright/test. - Import the required page object classes using custom fixtures.
- Import
-
Define the Test:
- Use the
testfunction to define your test case. - Provide a descriptive name for the test.
- Use the
asynckeyword to define an asynchronous test function.
- Use the
-
Use Custom Fixtures:
- Access page object classes through custom fixtures.
- Call methods from the page object classes to perform actions.
- Use
awaitfor asynchronous operations.
-
Add Assertions:
- Use
expectto add assertions and validate the expected behavior.
- Use
-
Open customFixtures.ts:
- Navigate to the base directory and open the
customFixtures.tsfile.
- Navigate to the base directory and open the
-
Import the Page Object Class:
- Import the page object class you want to use as a custom fixture.
import {NaukariPageActions} from '../pages/actions/NaukariPageActions'
-
Add the Page to the MyFixtures Type:
- Add a new entry to the
MyFixturestype definition.
type MyFixtures = { naukariPageActions: NaukariPageActions // ... other fixtures };
- Add a new entry to the
-
Extend the Test Object:
- Use the
base.extendmethod to add the custom fixture.
export const test = base.extend<MyFixtures>({ naukariPageActions: async ({ page }, use) => { return await use(new NaukariPageActions(page)) } // ... other fixtures });
- Use the
import { test as base } from '@playwright/test'
import { GoogleHomePageActions } from '../pages/actions/GoogleHomePageActions'
import { LoginPageActions } from '../pages/actions/LoginPageActions'
import {NaukariPageActions} from '../pages/actions/NaukariPageActions'
type MyFixtures = {
googleHomePageActions: GoogleHomePageActions
loginPageActions: LoginPageActions
naukariPageActions: NaukariPageActions
}
export const test = base.extend<MyFixtures>({
googleHomePageActions: async ({ page }, use) => {
return await use(new GoogleHomePageActions(page))
},
loginPageActions: async ({ page }, use) => {
return await use(new LoginPageActions(page))
},
naukariPageActions: async ({ page }, use) => {
return await use(new NaukariPageActions(page))
}
})
export { expect } from '@playwright/test'To run tests in UI mode, follow these steps:
-
Modify package.json:
- Open the
package.jsonfile. - Add the
--uiflag to thetestscript.
"scripts": { "test": "cross-env environmentToRun=prod npx playwright test --workers=3", // ... other scripts }
- Open the
-
Run the Tests:
- Execute the tests using the following command:
npm run test
When writing tests using Playwright, ensure the following:
- Use descriptive test names.
- Include setup and teardown logic where necessary.
- Use assertions to validate the expected behavior.
import { test, expect } from '@playwright/test';
test('example test', async ({ page }) => {
await page.goto('https://example.com');
const title = await page.title();
expect(title).toBe('Example Domain');
});You can switch between different environment configurations by updating the envConfig.json file located in the src/main/resources/env folder.
Global setup ensures the environment and browser contexts are properly initialized before the test suite runs. It is defined in global-setup.ts.
This README provides an overview of the Playwright framework session where we covered essential aspects of TypeScript errors, using Prettier for code formatting, and ESLint for linting the Playwright tests. Additionally, we explored how to configure and apply linting and formatting rules for a cleaner, error-free codebase.
- Introduction
- Prettier Setup
- ESLint Setup
- Running Linting and Formatting
- Common Issues and Fixes
- Further Reading
In this session, we addressed the following key topics:
- Fixing TypeScript Errors: How to identify and correct TypeScript errors in Playwright tests.
- Prettier: Code formatting tool that ensures consistency in code structure.
- ESLint: Static code analysis tool used to identify problematic patterns in JavaScript/TypeScript code.
Prettier helps in maintaining a consistent code style across the project. Here’s how to set it up and run it:
-
Install Prettier:
npm install --save-dev prettier
-
Create a
.prettierrc.jsconfiguration file:module.exports = { arrowParens: 'avoid', endOfLine: 'lf', semi: false, trailingComma: 'all', singleQuote: true, printWidth: 120, tabWidth: 4, bracketSameLine: false, overrides: [ { files: 'src/**/*.ts', options: { printWidth: 250, }, }, ], }
-
Add a script to your
package.json:{ "scripts": { "prettify": "prettier --config \".prettierrc.js\" --write \"./**/*.{ts,tsx,js,jsx,json,yaml,yml,eslintrc,md}\" " } } -
Add .prettierignore:
node_modules playwright-report test-results build-js/ allure-results
-
Run Prettier to format your code:
npm run prettify
ESLint helps in identifying TypeScript and JavaScript issues that could lead to potential errors. Here’s how to configure ESLint for your Playwright project:
-
Add below to your devDependencies:
"eslint": "^8.30.0", "eslint-config-standard-with-typescript": "^24.0.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-n": "^15.6.0", "eslint-plugin-promise": "^6.1.1", "eslint-plugin-simple-import-sort": "^8.0.0"
-
Create an
.eslintrc.jonfile for configuration:{ "parser": "@typescript-eslint/parser", "parserOptions": { "project": "./tsconfig.json" }, "plugins": ["@typescript-eslint", "simple-import-sort"], "rules": { "@typescript-eslint/no-floating-promises": "error", "@typescript-eslint/await-thenable": "error", "@typescript-eslint/indent": "off", "@typescript-eslint/member-delimiter-style": [ "error", { "multiline": { "delimiter": "none", "requireLast": true }, "singleline": { "delimiter": "semi", "requireLast": false } } ], "@typescript-eslint/naming-convention": [ "error", { "selector": "variable", "format": ["camelCase", "UPPER_CASE", "PascalCase"], "leadingUnderscore": "allow", "trailingUnderscore": "forbid" } ], "@typescript-eslint/no-array-constructor": "error", "@typescript-eslint/no-this-alias": "error", "@typescript-eslint/no-unnecessary-boolean-literal-compare": "off", "@typescript-eslint/quotes": ["error", "single"], "@typescript-eslint/semi": ["error", "never"], "@typescript-eslint/type-annotation-spacing": "off", //"arrow-body-style": ["error", "as-needed"], "arrow-parens": ["off", "always"], "brace-style": ["off", "off"], "comma-dangle": [ "error", { "objects": "always-multiline", "arrays": "always-multiline", "functions": "always-multiline" } ], "curly": ["error", "multi-line"], "eol-last": "off", "eqeqeq": ["error", "smart"], "id-denylist": [ "error", "any", "Number", "number", "String", "string", "Boolean", "boolean", "Undefined", "undefined" ], "id-match": "error", "import/no-internal-modules": "off", "indent": "off", "linebreak-style": "off", "max-len": "off", "new-parens": "off", "newline-per-chained-call": "off", "no-array-constructor": "off", "no-console": "off", "no-duplicate-imports": "error", "no-else-return": "error", "no-eval": "error", "no-extra-semi": "error", "no-irregular-whitespace": "off", "no-multiple-empty-lines": "error", "no-multi-spaces": "error", "no-new-wrappers": "error", //"no-param-reassign": "error", //"no-plusplus": "error", "no-trailing-spaces": "off", "no-underscore-dangle": "off", "no-var": "error", "object-shorthand": "error", "one-var": ["error", "never"], "padded-blocks": [ "off", { "blocks": "never" }, { "allowSingleLineBlocks": true } ], "prefer-arrow/prefer-arrow-functions": "off", "prefer-const": "error", "prefer-template": "error", "quote-props": ["error", "as-needed"], "quotes": [2, "single"], "radix": "error", "semi": "off", "simple-import-sort/imports": "error", "simple-import-sort/exports": "error", "space-before-function-paren": "off", "space-in-parens": ["off", "never"], "spaced-comment": [ "error", "always", { "markers": ["/"] } ] } } -
Add ESLint to the
package.json:{ "scripts": { "lint": "eslint --ignore-path .eslintignore --ext .js,.ts,.tsx .", "lintFix": "eslint --fix src/**/*.ts" } } -
Add .prettierignore:
node_modules/ /test-results/ /playwright-report/ /playwright/.cache/ logs/ build-js/
-
Run ESLint:
npm run lint
-
To automatically fix issues, run:
npm run lintFix
-
Run Prettier: Formats the code to maintain style consistency.
npm run pretty
-
Run ESLint: Detects issues in the code.
npm run lint
-
Auto-fix issues: Fixes minor issues automatically.
npm run lintFix
-
Unnecessary
awaitin Promises: Some Playwright functions do not return promises. Make sure to check if the function is synchronous or asynchronous and avoid usingawaitwhere not necessary.// Example fix const element = await page.getByText('Submit') // Incorrect const element = page.getByText('Submit') // Correct
-
Extra Semicolons: ESLint rules help catch unnecessary semicolons.
const name = 'Playwright'; // Incorrect const name = 'Playwright' // Correct
-
Quotes Mismatch: Ensure consistent usage of single or double quotes as per the ESLint configuration.
const message = 'Hello' // Incorrect const message = 'Hello' // Correct
-
Missing
await: ESLint warns if a promise is not awaited, which can lead to runtime issues.await page.click('button') // Correct if it returns a promise.
Sometimes you want to tag your tests as @bvt or @regression, and then filter by tag in the test report. Or you might want to only run tests that have a certain tag.
To tag a test, either provide an additional details object when declaring a test, or add @-token to the test title. Note that tags must start with @ symbol.
import { test, expect } from '@playwright/test';
test.describe('group', () => { test('test report header', async ({ page }) => { // ... });
test('test full report', {tag: ['@bvt', '@regression']}, async ({ page }) => { // ... }); });
You can now run tests that have a particular tag with --grep command line option.
cross-env environmentToRun=prod npx playwright test --workers 3 --project=RegressionTests --grep "@bvt"Or if you want the opposite, you can skip the tests with a certain tag:
cross-env environmentToRun=prod npx playwright test --workers 3 --project=RegressionTests --grep-invert "@bvt"To run tests containing either tag (logical OR operator):
cross-env environmentToRun=prod npx playwright test --workers 3 --project=RegressionTests --grep --% "@bvt^|@regression"Or run tests containing both tags (logical AND operator) using regex lookaheads:
cross-env environmentToRun=prod npx playwright test --workers 3 --project=RegressionTests --grep "(?=.*@bvt)(?=.*@regression)"