Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
9c1f9b2
feat: add playwright config
bupd Oct 15, 2025
546bdb4
feat: add login logout playwright test
bupd Oct 15, 2025
1e8b05e
feat: add playwright workflow
bupd Oct 15, 2025
1317cb6
feat(deps): Update playwright version and Add dotenv package
vg006 Dec 9, 2025
490f414
feat(env): Add access to environmental variables in playwright tests
vg006 Dec 9, 2025
d113454
feat(test): Add few basic test cases and fixtures
vg006 Dec 9, 2025
1d0a09d
feat(test): Add tests to update and delete labels
vg006 Dec 9, 2025
ce73295
Merge branch 'goharbor:main' into pwtest-common
vg006 Dec 9, 2025
01d7ac0
feat(e2e): Add create project test cases
vg006 Dec 10, 2025
1ed0161
feat(e2e): Add delete project test case
vg006 Dec 10, 2025
c3e9544
feat(e2e): Add user view projects via logs test case
vg006 Dec 10, 2025
708893d
Merge branch 'goharbor:main' into pwtest-common
vg006 Dec 15, 2025
bc913a0
feat(e2e): Add push image test case with utilities
vg006 Dec 15, 2025
546d254
fix(e2e): Add util to traverse pagination of projects
vg006 Dec 15, 2025
b91cea5
feat(e2e): Add project level public policy test
vg006 Dec 15, 2025
60cc463
refac: Update functions to be exported
vg006 Dec 15, 2025
964bdf7
refac(e2e): Modularize the tests using appropriate utils
vg006 Dec 15, 2025
c2abc3f
feat(e2e): Add harbor api docs page test
vg006 Dec 15, 2025
b2bdaa6
feat(e2e): Add test to view repo size
vg006 Dec 15, 2025
fb41beb
feat(e2e): Add token expiration modification test
vg006 Dec 15, 2025
d4a900b
feat(e2e): Add statistics test case
vg006 Dec 15, 2025
b2eff68
feat(e2e): Add delete multi project test case
vg006 Dec 19, 2025
73d9b6c
feat(e2e): Add delete multi repos test
vg006 Dec 19, 2025
99c3e88
feat(e2e): Add delete project in card view test
vg006 Dec 19, 2025
d7bd80f
feat(e2e): Add delete multi artifacts test
vg006 Dec 19, 2025
80b6df4
feat(e2e): Add delete multiple users test
vg006 Dec 26, 2025
d1c58fb
feat(e2e): Add project admin operate labels test
vg006 Dec 26, 2025
46f96b6
feat(e2e): Add project admin add repo labels test
vg006 Dec 26, 2025
c96fc01
feat(e2e): Add copy an image test
vg006 Dec 29, 2025
a672e95
feat(e2e): Add user view logs test
vg006 Dec 29, 2025
16061d9
feat(e2e): Add manage project members test
vg006 Dec 30, 2025
c63869a
feat(e2e): Add manage project publicity test
vg006 Dec 30, 2025
39676b7
feat(e2e): Add assign sys admin test
vg006 Dec 30, 2025
d958b89
feat(e2e): Add edit project creation test
vg006 Dec 30, 2025
d579c63
feat(e2e): Add edit repo info test
vg006 Dec 30, 2025
b91f1a0
feat(e2e): Add few utilities for testing
vg006 Jan 7, 2026
e6d6b88
feat(e2e): Add read only mode test
vg006 Jan 7, 2026
20d2975
feat(e2e): Add cannot copy image test and fix locator
vg006 Jan 7, 2026
4a20920
feat(e2e): Add banner message test
vg006 Jan 8, 2026
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
91 changes: 91 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
name: Playwright Tests

env:
POSTGRESQL_HOST: localhost
POSTGRESQL_PORT: 5432
POSTGRESQL_USR: postgres
POSTGRESQL_PWD: root123
POSTGRESQL_DATABASE: registry
DOCKER_COMPOSE_VERSION: 2.27.1
HARBOR_ADMIN: admin
HARBOR_ADMIN_PASSWD: Harbor12345
CORE_SECRET: tempString
KEY_PATH: "/data/secret/keys/secretkey"
REDIS_HOST: localhost
REG_VERSION: v2.7.1-patch-2819-2553
UI_BUILDER_VERSION: 1.6.0

on:
pull_request:
branches: [ main ]
paths-ignore:
- 'docs/**'
- '**.md'
- 'tests/**'
- '!tests/**.sh'
- '!tests/apitests/**'
- '!tests/ci/**'
- '!tests/resources/**'
- '!tests/robot-cases/**'
- '!tests/robot-cases/Group1-Nightly/**'

permissions:
contents: read
pull-requests: read
actions: read

jobs:
E2E_PLAYWRIGHT:
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- name: Set up Go 1.23
uses: actions/setup-go@v5
with:
go-version: 1.23.2
- uses: actions/setup-node@v5
with:
node-version: '18'
- uses: actions/checkout@v5
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

This workflow uses actions/checkout@v5, while all other GitHub Actions workflows in this repository consistently use actions/checkout@v6 (e.g., .github/workflows/CI.yml, .github/workflows/build-package.yml, .github/workflows/codeql-analysis.yml). The checkout action version should be updated to @v6 to be consistent with the rest of the codebase.

Suggested change
- uses: actions/checkout@v5
- uses: actions/checkout@v6

Copilot uses AI. Check for mistakes.
with:
path: src/github.com/goharbor/harbor
- name: setup env
run: |
cd src/github.com/goharbor/harbor
pwd
go env
echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV
echo "GOPATH=$(go env GOPATH):$GITHUB_WORKSPACE" >> $GITHUB_ENV
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
echo "TOKEN_PRIVATE_KEY_PATH=${GITHUB_WORKSPACE}/src/github.com/goharbor/harbor/tests/private_key.pem" >> $GITHUB_ENV
IP=`hostname -I | awk '{print $1}'`
echo "IP=$IP" >> $GITHUB_ENV
echo "BASE_URL=https://$IP" >> $GITHUB_ENV
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

The workflow sets BASE_URL (line 63: echo "BASE_URL=https://$IP" >> $GITHUB_ENV), which is what playwright.config.ts uses for the Playwright baseURL configuration. However, the test fixtures (e2e/fixtures/harbor.ts) and many tests in common.spec.ts read from process.env.HARBOR_BASE_URL to construct the Harbor IP address used for Docker commands (e.g., docker login, docker push, docker pull).

Since HARBOR_BASE_URL is never set in the workflow, all those environment variable reads will return undefined, and the Docker commands will fall back to 'localhost' instead of the actual Harbor IP ($IP). This means all tests that push or pull Docker images will fail in CI because Docker commands target localhost instead of the running Harbor instance.

Either rename BASE_URL to HARBOR_BASE_URL in the workflow (and update playwright.config.ts accordingly), or add a separate step to also set HARBOR_BASE_URL=https://$IP.

Suggested change
echo "BASE_URL=https://$IP" >> $GITHUB_ENV
echo "BASE_URL=https://$IP" >> $GITHUB_ENV
echo "HARBOR_BASE_URL=https://$IP" >> $GITHUB_ENV

Copilot uses AI. Check for mistakes.
shell: bash
- name: before_install
run: |
set -x
cd src/github.com/goharbor/harbor
curl -L https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
chmod +x docker-compose
sudo mv docker-compose /usr/local/bin
- name: Start Harbor for E2E
run: |
cd src/github.com/goharbor/harbor
docker system prune -a -f
bash ./tests/showtime.sh ./tests/ci/api_common_install.sh $IP DB
- name: Install Playwright dependencies
run: |
cd src/github.com/goharbor/harbor/src/portal
npm ci
npx playwright install --with-deps
- name: Run Playwright tests
run: |
cd src/github.com/goharbor/harbor/src/portal
npx playwright test
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: src/github.com/goharbor/harbor/src/portal/playwright-report/
retention-days: 30
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,11 @@ src/server/v2.0/restapi/
harborclient/
openapi-generator-cli.jar
tests/e2e_setup/robotvars.py

# Playwright
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/playwright/.auth/
3 changes: 3 additions & 0 deletions src/portal/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
HARBOR_USERNAME="<your_admin_username>" # e.g., admin
HARBOR_PASSWORD="<your_admin_password>" # e.g., Harbor12345
HARBOR_BASE_URL="<your_harbor_instance_url>" # e.g., https://harbor.mycompany.com
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

The LOCAL_REGISTRY and LOCAL_REGISTRY_NAMESPACE environment variables are used extensively in the tests (referenced over 30 times in common.spec.ts) to pull images from a local registry before pushing to Harbor, but they are not documented in .env.sample. Developers setting up the environment will not know these variables exist or what values to use. Please add them to the sample file (e.g., LOCAL_REGISTRY="docker.io" and LOCAL_REGISTRY_NAMESPACE="library").

Suggested change
HARBOR_BASE_URL="<your_harbor_instance_url>" # e.g., https://harbor.mycompany.com
HARBOR_BASE_URL="<your_harbor_instance_url>" # e.g., https://harbor.mycompany.com
LOCAL_REGISTRY="docker.io" # e.g., docker.io for the default Docker Hub registry
LOCAL_REGISTRY_NAMESPACE="library" # e.g., library for official Docker Hub images

Copilot uses AI. Check for mistakes.
10 changes: 10 additions & 0 deletions src/portal/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

# Playwright
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/

# Files
.env
57 changes: 57 additions & 0 deletions src/portal/e2e/fixtures/harbor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { test as base, Page } from '@playwright/test';

type HarborUser = {
username: string;
password: string;
};

type HarborFixtures = {
harborPage: Page;
harborUser: HarborUser;
};

export async function login(page: Page, baseURL: string | undefined, creds: HarborUser) {
await page.goto(baseURL);
await page.getByRole('textbox', { name: 'Username' }).fill(creds.username);
await page.getByRole('textbox', { name: 'Password' }).fill(creds.password);
await page.getByRole('button', { name: 'LOG IN' }).click();
}

export async function logout(page: Page, username: string) {
await page.getByRole('button', { name: username, exact: true }).waitFor({ state: 'visible', timeout: 5000 });
await page.getByRole('button', { name: username, exact: true }).click();
await page.getByRole('menuitem', { name: 'Log Out' }).click();
}

export async function logoutIfPossible(page: Page, username: string) {
try {
await page.getByRole('button', { name: username, exact: true }).waitFor({ state: 'visible', timeout: 2000 });
} catch {
return;
}

try {
await logout(page, username);
} catch {
return;
}
}

const harborTest = base.extend<HarborFixtures>({
harborUser: async ({}, use) => {
await use({
username: process.env.HARBOR_USERNAME || 'admin',
password: process.env.HARBOR_PASSWORD || 'Harbor12345',
Comment on lines +40 to +44
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

The default password 'Harbor12345' for the admin user is hardcoded as a fallback in harborUser fixture. While having a default for local development is understandable, the same default password 'Harbor12345' is also hardcoded throughout common.spec.ts for user1 and user2 test accounts (e.g., lines 77, 130, 143, 252, 628, 1016, 1715) without any environment variable fallback for these test accounts. Consider adding HARBOR_TEST_USER_PASSWORD or similar to allow overriding test user passwords per environment.

Suggested change
const harborTest = base.extend<HarborFixtures>({
harborUser: async ({}, use) => {
await use({
username: process.env.HARBOR_USERNAME || 'admin',
password: process.env.HARBOR_PASSWORD || 'Harbor12345',
const harborPassword =
process.env.HARBOR_TEST_USER_PASSWORD ||
process.env.HARBOR_PASSWORD ||
'';
const harborTest = base.extend<HarborFixtures>({
harborUser: async ({}, use) => {
await use({
username: process.env.HARBOR_USERNAME || 'admin',
password: harborPassword,

Copilot uses AI. Check for mistakes.
});
},

harborPage: async ({ page, harborUser }, use) => {
let baseURL = process.env.HARBOR_BASE_URL;
await login(page, baseURL, harborUser);
await use(page);
await logoutIfPossible(page, harborUser.username);
},
});

export const test = harborTest;
export const expect = harborTest.expect;
Loading