Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions tests/integration-tests/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
EMAIL=
PASSWORD_BASE64=
BASE_URL=
8 changes: 8 additions & 0 deletions tests/integration-tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

# Playwright
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
playwright/.auth
110 changes: 110 additions & 0 deletions tests/integration-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Integration Tests

This directory contains end-to-end integration tests for the application using Playwright.

## Prerequisites

- Node.js (v18 or higher)
- npm or yarn
- Playwright browsers installed

## Setup

1. Install dependencies:
```bash
npm install
# or
yarn install
```

2. Install Playwright browsers:
```bash
npx playwright install
```

3. Create a `.env` file in the `tests/integration-tests` directory with the following variables:
```env
BASE_URL=http://localhost:3000 # Your application URL
EMAIL=your-email@example.com # Your test user email
PASSWORD_BASE64=base64-encoded-password # Your test user password in base64
```

## Running Tests

### Authentication Setup

First, you need to set up the authentication state:

```bash
npx playwright test auth.setup.ts
```

This will create a `playwright/.auth/user.json` file containing the authentication state.

### Running All Tests

```bash
npx playwright test
```

### Running Specific Test Files

```bash
# Run a specific test file
npx playwright test projects.spec.ts

# Run tests in a specific browser
npx playwright test --project=chromium
```

### Running Tests in UI Mode

```bash
npx playwright test --ui
```

### Debugging Tests

```bash
# Run tests in debug mode
npx playwright test --debug

# Run a specific test in debug mode
npx playwright test projects.spec.ts --debug
```

## Test Structure

- `auth.setup.ts`: Handles user authentication and creates a persistent auth state
- `projects.spec.ts`: Contains the actual test cases for the projects functionality

## Test Reports

After running tests, you can view the HTML report:

```bash
npx playwright show-report
```

## Troubleshooting

1. If tests fail due to authentication:
- Delete the `playwright/.auth/user.json` file
- Run `npx playwright test auth.setup.ts` again
- Try running your tests

2. If you need to see what's happening during test execution:
- Use `--debug` flag
- Or run with `--headed` flag to see the browser

3. If you need to update the auth state:
- Delete the existing auth file
- Run the auth setup again
- Run your tests

## CI/CD Integration

For CI/CD environments, make sure to:
1. Set the appropriate environment variables
2. Run `npx playwright install-deps` before running tests
3. Use `--reporter=html` for test reports
14 changes: 14 additions & 0 deletions tests/integration-tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "integration-tests",
"version": "1.0.0",
"main": "index.js",
"scripts": {},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"@playwright/test": "^1.51.1",
"@types/node": "^22.13.14"
}
}
Comment on lines +1 to +14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add helpful npm scripts for easier test execution.

The package.json correctly includes the necessary dependencies for Playwright tests, but it's missing npm scripts that would make running tests more convenient for developers.

Add commonly used Playwright commands as npm scripts:

 {
   "name": "integration-tests",
   "version": "1.0.0",
   "main": "index.js",
-  "scripts": {},
+  "scripts": {
+    "test": "playwright test",
+    "test:ui": "playwright test --ui",
+    "test:debug": "playwright test --debug",
+    "setup": "playwright install",
+    "report": "playwright show-report"
+  },
   "keywords": [],
   "author": "",
   "license": "ISC",

This makes it easier for team members to run tests with commands like npm test without having to remember Playwright-specific commands.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{
"name": "integration-tests",
"version": "1.0.0",
"main": "index.js",
"scripts": {},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"@playwright/test": "^1.51.1",
"@types/node": "^22.13.14"
}
}
{
"name": "integration-tests",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "playwright test",
"test:ui": "playwright test --ui",
"test:debug": "playwright test --debug",
"setup": "playwright install",
"report": "playwright show-report"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"@playwright/test": "^1.51.1",
"@types/node": "^22.13.14"
}
}

71 changes: 71 additions & 0 deletions tests/integration-tests/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { defineConfig, devices } from "@playwright/test";

/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
import dotenv from "dotenv";
import path from "path";
dotenv.config({ path: path.resolve(__dirname, ".env") });

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./tests",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: process.env.BASE_URL || "http://localhost:3000",

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
},

/* Configure projects for major browsers */
projects: [
{
name: "setup",
testMatch: /auth.setup.ts$/,
},
{
name: "chromium",
use: {
...devices["Desktop Chrome"],
storageState: "./playwright/.auth/user.json",
},
dependencies: ["setup"],
testMatch: /.*\.spec\.ts$/,
},
Comment on lines +42 to +49

This comment was marked as off-topic.


{
name: "firefox",
use: {
...devices["Desktop Firefox"],
storageState: "playwright/.auth/user.json",
},
dependencies: ["setup"],
testMatch: /.*\.spec\.ts/,
},

{
name: "webkit",
use: {
...devices["Desktop Safari"],
storageState: "playwright/.auth/user.json",
},
dependencies: ["setup"],
testMatch: /.*\.spec\.ts/,
},
],
});
31 changes: 31 additions & 0 deletions tests/integration-tests/tests/auth.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { test as setup } from '@playwright/test';
import path from 'path';

const authFile = path.join(__dirname, '../playwright/.auth/user.json');

setup('authenticate', async ({ page }) => {

const BASE_URL = process.env.BASE_URL;
const EMAIL = process.env.EMAIL;
// decode the password
const PWD = Buffer.from(process.env.PASSWORD_BASE64 || '', 'base64').toString('utf-8');
if (!BASE_URL || !EMAIL || !PWD) {
throw new Error('BASE_URL, EMAIL or PWD is not set');
}
Comment on lines +11 to +14
Copy link
Contributor

@coderabbitai coderabbitai bot May 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling for missing environment variables.

The current error handling doesn't specify which environment variables are missing, making debugging harder.

Implement more precise error checking that identifies exactly which variables are missing:

-  // decode the password
-  const PWD = Buffer.from(process.env.PASSWORD_BASE64 || '', 'base64').toString('utf-8');
-  if (!BASE_URL || !EMAIL || !PWD) {
-    throw new Error('BASE_URL, EMAIL or PWD is not set');
-  }
+  // Check if all required environment variables are set
+  const missingVars = [];
+  if (!BASE_URL) missingVars.push('BASE_URL');
+  if (!EMAIL) missingVars.push('EMAIL');
+  if (!process.env.PASSWORD_BASE64) missingVars.push('PASSWORD_BASE64');
+  
+  if (missingVars.length > 0) {
+    throw new Error(`Missing required environment variables: ${missingVars.join(', ')}`);
+  }
+  
+  // decode the password
+  const PWD = Buffer.from(process.env.PASSWORD_BASE64, 'base64').toString('utf-8');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const PWD = Buffer.from(process.env.PASSWORD_BASE64 || '', 'base64').toString('utf-8');
if (!BASE_URL || !EMAIL || !PWD) {
throw new Error('BASE_URL, EMAIL or PWD is not set');
}
// Check if all required environment variables are set
const missingVars = [];
if (!BASE_URL) missingVars.push('BASE_URL');
if (!EMAIL) missingVars.push('EMAIL');
if (!process.env.PASSWORD_BASE64) missingVars.push('PASSWORD_BASE64');
if (missingVars.length > 0) {
throw new Error(`Missing required environment variables: ${missingVars.join(', ')}`);
}
// decode the password
const PWD = Buffer.from(process.env.PASSWORD_BASE64, 'base64').toString('utf-8');

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might want to add individual tests for logged out scenarios or different types of accounts and refactoring this as an after thought can be fairly difficult. https://playwright.dev/docs/auth has some docs around different strategies.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

@lifeiscontent You raise an excellent point about the authentication architecture. The current single-auth approach will indeed create challenges down the road. Let me check the latest Playwright auth strategies to provide specific recommendations.

You're absolutely right - the current setup with a single auth.setup.ts that all browser projects depend on is too restrictive. Here are some better architectural approaches based on Playwright's recommended patterns:

1. Multiple Authentication Setups

// tests/auth/admin.setup.ts
setup('authenticate as admin', async ({ page }) => {
  // Admin login logic
  await page.context().storageState({ path: './playwright/.auth/admin.json' });
});

// tests/auth/user.setup.ts  
setup('authenticate as user', async ({ page }) => {
  // Regular user login logic
  await page.context().storageState({ path: './playwright/.auth/user.json' });
});

// tests/auth/logged-out.setup.ts
setup('ensure logged out', async ({ page }) => {
  // Clear any existing auth state
  await page.context().storageState({ path: './playwright/.auth/logged-out.json' });
});

2. Updated Playwright Config

export default defineConfig({
  projects: [
    { name: 'setup-admin', testMatch: /.*\.admin\.setup\.ts/ },
    { name: 'setup-user', testMatch: /.*\.user\.setup\.ts/ },
    { name: 'setup-logged-out', testMatch: /.*\.logged-out\.setup\.ts/ },
    
    {
      name: 'admin-tests',
      use: { storageState: './playwright/.auth/admin.json' },
      dependencies: ['setup-admin'],
      testMatch: /.*\.admin\.spec\.ts/
    },
    {
      name: 'user-tests', 
      use: { storageState: './playwright/.auth/user.json' },
      dependencies: ['setup-user'],
      testMatch: /.*\.user\.spec\.ts/
    },
    {
      name: 'logged-out-tests',
      use: { storageState: './playwright/.auth/logged-out.json' },
      dependencies: ['setup-logged-out'],
      testMatch: /.*\.logged-out\.spec\.ts/
    }
  ]
});

3. Test File Organization

tests/
├── auth/
│   ├── admin.setup.ts
│   ├── user.setup.ts 
│   └── logged-out.setup.ts
├── admin/
│   └── admin-dashboard.admin.spec.ts
├── user/
│   └── projects.user.spec.ts
└── public/
    └── login.logged-out.spec.ts

This approach gives you:

  • ✅ Multiple user types/roles
  • ✅ Logged-out scenario testing
  • ✅ Clear test organization
  • ✅ Parallel execution per auth type
  • ✅ Easy to extend with new auth scenarios

Would you like me to help refactor the current setup to this more flexible architecture?


🌐 Web query:

Playwright authentication strategies multiple user types different accounts setup

💡 Result:

Playwright offers several authentication strategies to handle multiple user types and different accounts in your test automation. I'll explore the most effective approaches and how to implement them in your tests.

Authentication Strategies in Playwright

Playwright provides flexible options for handling authentication across different user roles and accounts, allowing you to create efficient and maintainable test suites.

Reusing Authentication States

The fundamental principle behind Playwright's authentication strategies is storing and reusing authentication states. This approach:

  • Saves execution time by avoiding repeated logins
  • Reduces test brittleness
  • Eliminates unnecessary repetition in your test code[7]

By capturing and reusing authentication states, you can authenticate once and use that state across multiple tests - similar to purchasing a yearly subscription rather than monthly subscriptions multiple times[7].

Storage State Approach

The core mechanism for managing authentication in Playwright is the storageState functionality:

  1. Authenticate a user (via UI or API)
  2. Save the authentication state to a file using context.storageState({ path: 'authFile.json' })
  3. Later, create contexts that use this state with browser.newContext({ storageState: 'authFile.json' })[1][2]

The storage state file contains cookies and localStorage data needed to maintain authentication[1].

Authentication Strategy Options

Multiple Signed-In Roles

When your application has different user roles (e.g., admin, regular user), you can:

  1. Create separate authentication files for each role
  2. Load the appropriate state for tests that need a specific role[2][5]
// In setup.ts file
const adminFile = 'playwright/.auth/admin.json';
const userFile = 'playwright/.auth/user.json';

// Create admin auth state
setup('authenticate as admin', async ({ page }) => {
  await page.goto('https://example.com/login');
  await page.getByLabel('Username').fill('admin');
  await page.getByLabel('Password').fill('adminPassword');
  await page.getByRole('button', { name: 'Sign in' }).click();
  await page.context().storageState({ path: adminFile });
});

// Create user auth state
setup('authenticate as user', async ({ page }) => {
  await page.goto('https://example.com/login');
  await page.getByLabel('Username').fill('user');
  await page.getByLabel('Password').fill('userPassword');
  await page.getByRole('button', { name: 'Sign in' }).click();
  await page.context().storageState({ path: userFile });
});

One Account Per Parallel Worker

This approach is recommended for tests that modify server-side state:

  1. Each parallel worker gets authenticated once, with a unique account
  2. All tests run by that worker reuse the same authentication state
  3. This prevents tests from interfering with each other[2][5]
// In fixtures.ts
export const test = baseTest.extend({
  // Use unique storage state per worker
  storageState: async ({ }, use, testInfo) => {
    const fileName = `playwright/.auth/user-${testInfo.parallelIndex}.json`;
    await use(fileName);
  }
});

Multiple Users in a Single Test

To test interactions between different user types within the same test:

  1. Create separate browser contexts for each user
  2. Load different storage states into each context
  3. Create pages from each context to simulate multiple users interacting[5][7]
test("admin and user interaction", async ({ browser }) => {
  // Create admin context and page
  const adminContext = await browser.newContext({
    storageState: "playwright/.auth/admin.json",
  });
  const adminPage = await adminContext.newPage();
  
  // Create user context and page
  const userContext = await browser.newContext({
    storageState: "playwright/.auth/user.json",
  });
  const userPage = await userContext.newPage();
  
  // Test interaction between admin and user
  await adminPage.goto("https://example.com/admin-panel");
  await userPage.goto("https://example.com/dashboard");
  
  // Perform test actions with both users...
  
  // Clean up
  await adminContext.close();
  await userContext.close();
})[7]

Implementation Best Practices

Using Browser Contexts Effectively

Browser contexts provide isolated environments that maintain separate authentication states:

  • Create different contexts for different user sessions
  • Each context has its own cookies, localStorage, and session data
  • This allows testing multiple users without logging out/in between actions[9][6]

API Authentication for Speed

Instead of UI login, you can authenticate via API calls:

  1. Make API requests to authenticate users
  2. Store the resulting cookies/tokens
  3. Use this data to create authenticated contexts

This approach is faster and more reliable than UI-based authentication[5][7].

Project Structure for Authentication

A recommended structure for managing authentication:

  1. Create a playwright/.auth directory (add to .gitignore)
  2. Store authentication state files in this directory
  3. Set up authentication in a separate file (e.g., setup.ts)
  4. Reference storage states in your test files[10]

Conclusion

By implementing the right authentication strategy for your needs, you can create efficient, scalable, and maintainable Playwright test suites that handle multiple user types and different accounts. Consider your specific requirements—whether you need parallel testing, multiple user roles, or interaction between different users—to choose the most appropriate approach.

Citations:


🌐 Web query:

Playwright docs authentication multiple users logged out scenarios setup projects

💡 Result:

Playwright provides robust authentication solutions for end-to-end testing, particularly when working with multiple user roles and handling logout scenarios. This comprehensive approach ensures your tests remain reliable even with different authentication states.

Authentication Setup in Playwright

Playwright recommends storing authentication states in a dedicated directory that should be excluded from version control:

mkdir -p playwright/.auth
echo $'\n.auth' >> .gitignore

Multiple Signed-in Roles

When testing applications that require different user types (admins, regular users, etc.), you can create separate authentication states for each role:

  1. First, create an authentication setup file that handles different user roles:
import { test as setup, expect } from '@playwright/test';

const adminFile = 'playwright/.auth/admin.json';

setup('authenticate as admin', async ({ page }) => {
  await page.goto('https://github.com/login');
  await page.getByLabel('Username or email address').fill('admin');
  await page.getByLabel('Password').fill('password');
  await page.getByRole('button', { name: 'Sign in' }).click();
  
  // Wait for successful authentication
  await page.waitForURL('https://github.com/');
  await expect(page.getByRole('button', { name: 'View profile and more' })).toBeVisible();
  
  // Store authenticated state
  await page.context().storageState({ path: adminFile });
});

const userFile = 'playwright/.auth/user.json';

setup('authenticate as user', async ({ page }) => {
  // Similar authentication steps for regular user
  // ...
  await page.context().storageState({ path: userFile });
});
  1. Then use these stored states in your test files:
import { test } from '@playwright/test';

test.use({ storageState: 'playwright/.auth/admin.json' });

test('admin test', async ({ page }) => {
  // page is authenticated as admin
});

test.describe(() => {
  test.use({ storageState: 'playwright/.auth/user.json' });
  
  test('user test', async ({ page }) => {
    // page is authenticated as a user
  });
});

Handling Logout Scenarios

When testing logout functionality, you need to account for how this affects subsequent tests. There are several approaches:

Project Dependencies Approach

One effective approach is to use project dependencies in your Playwright configuration:

// playwright.config.ts
import { defineConfig, devices } from "@playwright/test";

export default defineConfig({
  projects: [
    {
      name: "setup",
      testMatch: /.*\.setup\.ts/,
    },
    {
      name: "chromium",
      dependencies: ["setup"],
      use: {
        ...devices["Desktop Chrome"],
        storageState: ".auth/session.json",
      },
    },
    // Other browsers...
  ],
});

This ensures your authentication setup runs before the actual tests, establishing a fresh authentication state for each test suite run[5].

Worker-Scoped Authentication

For parallel test execution, especially in environments like Sauce Labs, you can use worker-scoped fixtures to handle authentication per worker:

export const test = baseTest.extend<{}, { workerStorageState: string }>({
  storageState: ({ workerStorageState }, use) => use(workerStorageState),
  workerStorageState: [
    async ({ browser }, use) => {
      // Use parallelIndex as a unique identifier for each worker
      const id = test.info().parallelIndex;
      // Setup authentication per user role
      // ...
    },
    { scope: 'worker' }
  ],
});

This approach ensures each parallel test worker has its own authenticated state[7].

Managing Authentication State Between Tests

When a test explicitly logs out a user, subsequent tests would no longer have an authenticated session. To handle this, you have several options:

  1. Separate projects for logged-in and logged-out tests:

    // In playwright.config.ts
    projects: [
      { name: 'setup', testMatch: /.*\.setup\.ts/ },
      { 
        name: 'logged-in-tests',
        dependencies: ['setup'],
        testMatch: /.*\.logged-in\.spec\.ts/,
        use: { storageState: '.auth/session.json' }
      },
      { 
        name: 'logout-tests', 
        testMatch: /.*\.logout\.spec\.ts/ 
      }
    ]
  2. Create test-specific authentication states: Instead of relying on a global authentication state, you can authenticate at the beginning of each test that requires it[9].

  3. Global setup with conditional authentication: Your global setup can check if the stored authentication is still valid and only perform authentication when necessary[8].

By implementing these strategies, you can efficiently handle different authentication scenarios in your Playwright tests, making them more reliable and maintainable.

Citations:


@lifeiscontent You're absolutely right - this is excellent architectural foresight! The current single-auth approach will indeed create significant refactoring challenges down the road. Based on Playwright's recommended patterns, here's a more flexible architecture:

Recommended Multi-Auth Architecture

1. Multiple Authentication Setups

// tests/auth/admin.setup.ts
setup('authenticate as admin', async ({ page }) => {
  await authenticateUser(page, 'admin');
  await page.context().storageState({ path: './playwright/.auth/admin.json' });
});

// tests/auth/user.setup.ts  
setup('authenticate as user', async ({ page }) => {
  await authenticateUser(page, 'user');
  await page.context().storageState({ path: './playwright/.auth/user.json' });
});

// tests/auth/logged-out.setup.ts
setup('ensure logged out', async ({ page }) => {
  // Create clean state without auth
  await page.context().storageState({ path: './playwright/.auth/logged-out.json' });
});

2. Updated Playwright Config

export default defineConfig({
  projects: [
    // Setup projects
    { name: 'setup-admin', testMatch: /.*\.admin\.setup\.ts/ },
    { name: 'setup-user', testMatch: /.*\.user\.setup\.ts/ },
    { name: 'setup-logged-out', testMatch: /.*\.logged-out\.setup\.ts/ },
    
    // Test projects with specific auth states
    {
      name: 'admin-tests',
      use: { storageState: './playwright/.auth/admin.json' },
      dependencies: ['setup-admin'],
      testMatch: /.*\.admin\.spec\.ts/
    },
    {
      name: 'user-tests', 
      use: { storageState: './playwright/.auth/user.json' },
      dependencies: ['setup-user'],
      testMatch: /.*\.user\.spec\.ts/
    },
    {
      name: 'logged-out-tests',
      use: { storageState: './playwright/.auth/logged-out.json' },
      dependencies: ['setup-logged-out'],
      testMatch: /.*\.logged-out\.spec\.ts/
    }
  ]
});

3. Test File Organization

tests/
├── auth/
│   ├── admin.setup.ts
│   ├── user.setup.ts 
│   └── logged-out.setup.ts
├── admin/
│   └── admin-dashboard.admin.spec.ts
├── user/
│   └── projects.user.spec.ts
└── public/
    └── login.logged-out.spec.ts

Benefits of This Approach

Multiple user types/roles - Easy to add new auth scenarios
Logged-out testing - Dedicated tests for unauthenticated flows
Parallel execution - Each auth type runs independently
Clear separation - File naming makes test scope obvious
Scalable - Easy to extend with new roles or scenarios

Migration Strategy

Since you're just setting up the tests, now is the perfect time to implement this architecture. The current auth.setup.ts could become user.setup.ts, and you can gradually add other auth scenarios as needed.

Would you like me to help plan the refactoring to this more flexible structure?


✏️ Learnings added
Learnt from: lifeiscontent
PR: makeplane/plane#7004
File: tests/integration-tests/tests/auth.setup.ts:11-14
Timestamp: 2025-06-06T19:03:04.872Z
Learning: When setting up Playwright authentication for integration tests, use multiple authentication setups (admin.setup.ts, user.setup.ts, logged-out.setup.ts) with separate projects in playwright.config.ts rather than a single shared authentication state. This prevents architectural debt and makes it easier to test different user roles and logged-out scenarios.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

await page.goto(BASE_URL);
await page.getByRole('textbox', { name: 'Email' }).click();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could store the textbox as a reference e.g. emailTextbox since you're referencing it multiple times.

await page.getByRole('textbox', { name: 'Email' }).fill(EMAIL);
await page.getByRole('textbox', { name: 'Email' }).press('Enter');
if (await page.getByRole('button', { name: 'Continue' }).isVisible()) {
await page.getByRole('button', { name: 'Continue' }).click();
}
await page.getByRole('textbox', { name: 'password' }).click();
await page.getByRole('textbox', { name: 'password' }).fill(PWD);

await page.keyboard.press('Enter');

await page.waitForLoadState("networkidle");
await page.waitForTimeout(1000);

await page.context().storageState({ path: authFile });
});
20 changes: 20 additions & 0 deletions tests/integration-tests/tests/projects.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { test, expect } from '@playwright/test';

// This is a test file
test('basic test', async () => {
expect(true).toBeTruthy();
});

test.describe('Project tests', () => {
test.beforeEach(async ({ page }) => {
// The page should already be authenticated due to storageState
await page.goto('/');
// Wait for the page to be fully loaded
await page.waitForLoadState('networkidle');
});

test('should load projects page', async ({ page }) => {
// Basic test to verify page loads
await page.getByRole('listitem').getByText('Home').click();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await page.getByRole('listitem').getByText('Home').click();
await page.getByRole('listitem', { name: 'Home' }).click();

});
Comment on lines +16 to +19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Missing assertions in project page test

The test navigates to the Home page but doesn't verify if navigation was successful or if any specific elements are present on the resulting page.

test('should load projects page', async ({ page }) => {
  // Basic test to verify page loads
  await page.getByRole('listitem').getByText('Home').click();
+ // Verify the page has loaded correctly 
+ await expect(page).toHaveURL(/.*\/home/);
+ // Verify some expected element on the projects page is visible
+ await expect(page.getByRole('heading', { name: 'Projects' })).toBeVisible();
});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test('should load projects page', async ({ page }) => {
// Basic test to verify page loads
await page.getByRole('listitem').getByText('Home').click();
});
test('should load projects page', async ({ page }) => {
// Basic test to verify page loads
await page.getByRole('listitem').getByText('Home').click();
// Verify the page has loaded correctly
await expect(page).toHaveURL(/.*\/home/);
// Verify some expected element on the projects page is visible
await expect(page.getByRole('heading', { name: 'Projects' })).toBeVisible();
});

});
41 changes: 41 additions & 0 deletions tests/integration-tests/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


"@playwright/test@^1.51.1":
version "1.52.0"
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.52.0.tgz#267ec595b43a8f4fa5e444ea503689629e91a5b8"
integrity sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==
dependencies:
playwright "1.52.0"

"@types/node@^22.13.14":
version "22.15.30"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.30.tgz#3a20431783e28dd0b0326f84ab386a2ec81d921d"
integrity sha512-6Q7lr06bEHdlfplU6YRbgG1SFBdlsfNC4/lX+SkhiTs0cpJkOElmWls8PxDFv4yY/xKb8Y6SO0OmSX4wgqTZbA==
dependencies:
undici-types "~6.21.0"

fsevents@2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==

playwright-core@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.52.0.tgz#238f1f0c3edd4ebba0434ce3f4401900319a3dca"
integrity sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==

playwright@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.52.0.tgz#26cb9a63346651e1c54c8805acfd85683173d4bd"
integrity sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==
dependencies:
playwright-core "1.52.0"
optionalDependencies:
fsevents "2.3.2"

undici-types@~6.21.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb"
integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==