data['projectResolver'];
@@ -131,6 +136,32 @@ export class ProjectDetailComponent implements OnInit {
ngOnInit() {
this.projectId = this.route.snapshot.params['id'];
this.getPermissionsList(this.projectId);
+ if (!this._subscription) {
+ this._subscription = this._subject.pipe(
+ debounceTime(100)
+ ).subscribe(
+ type => {
+ if (type === DOWN) {
+ this.resetTabsForDownSize();
+ } else {
+ this.resetTabsForUpSize();
+ }
+ }
+ );
+ }
+ }
+
+ ngAfterViewInit() {
+ this.previousWindowWidth = window.innerWidth;
+ setTimeout(() => {
+ this.resetTabsForDownSize();
+ }, 0);
+ }
+ ngOnDestroy() {
+ if (this._subscription) {
+ this._subscription.unsubscribe();
+ this._subscription = null;
+ }
}
getPermissionsList(projectId: number): void {
let permissionsList = [];
@@ -153,17 +184,17 @@ export class ProjectDetailComponent implements OnInit {
permissionsList.push(this.userPermissionService.getPermission(projectId,
USERSTATICPERMISSION.LABEL.KEY, USERSTATICPERMISSION.LABEL.VALUE.CREATE));
permissionsList.push(this.userPermissionService.getPermission(projectId,
- USERSTATICPERMISSION.TAG_RETENTION.KEY, USERSTATICPERMISSION.TAG_RETENTION.VALUE.READ));
+ USERSTATICPERMISSION.TAG_RETENTION.KEY, USERSTATICPERMISSION.TAG_RETENTION.VALUE.READ));
permissionsList.push(this.userPermissionService.getPermission(projectId,
USERSTATICPERMISSION.WEBHOOK.KEY, USERSTATICPERMISSION.WEBHOOK.VALUE.LIST));
permissionsList.push(this.userPermissionService.getPermission(projectId,
- USERSTATICPERMISSION.SCANNER.KEY, USERSTATICPERMISSION.SCANNER.VALUE.READ));
+ USERSTATICPERMISSION.SCANNER.KEY, USERSTATICPERMISSION.SCANNER.VALUE.READ));
forkJoin(...permissionsList).subscribe(Rules => {
[this.hasProjectReadPermission, this.hasLogListPermission, this.hasConfigurationListPermission, this.hasMemberListPermission
, this.hasLabelListPermission, this.hasRepositoryListPermission, this.hasHelmChartsListPermission, this.hasRobotListPermission
, this.hasLabelCreatePermission, this.hasTagRetentionPermission, this.hasWebhookListPermission,
- this.hasScannerReadPermission] = Rules;
+ this.hasScannerReadPermission] = Rules;
}, error => this.errorHandler.error(error));
}
@@ -188,10 +219,46 @@ export class ProjectDetailComponent implements OnInit {
isDefaultTab(tab, index) {
return this.route.snapshot.children[0].routeConfig.path !== tab.linkName && index === 0;
}
+
isTabLinkInOverFlow() {
return this.tabLinkNavList.some(tab => {
return tab.tabLinkInOverflow && this.route.snapshot.children[0].routeConfig.path === tab.linkName;
});
}
+ @HostListener('window:resize', ['$event'])
+ onResize(event) {
+ if (this.previousWindowWidth) {
+ // down size
+ if (this.previousWindowWidth > event.target.innerWidth) {
+ this._subject.next(DOWN);
+ } else { // up size
+ this._subject.next(UP);
+ }
+ }
+ this.previousWindowWidth = event.target.innerWidth;
+ }
+
+ resetTabsForDownSize(): void {
+ this.tabLinkNavList.filter(item => !item.tabLinkInOverflow).forEach((item, index) => {
+ const tabEle: HTMLElement = document.getElementById('project-' + item.linkName);
+ // strengthen code
+ if (tabEle && tabEle.getBoundingClientRect) {
+ const right: number = window.innerWidth - document.getElementById('project-' + item.linkName).getBoundingClientRect().right;
+ if (right < SHOW_ELLIPSIS_WIDTH) {
+ this.tabLinkNavList[index].tabLinkInOverflow = true;
+ }
+ }
+ });
+ }
+ resetTabsForUpSize() {
+ // 1.Set tabLinkInOverflow to false for all tabs(show all tabs)
+ for ( let i = 0; i < this.tabLinkNavList.length; i++) {
+ this.tabLinkNavList[i].tabLinkInOverflow = false;
+ }
+ // 2.Manually detect changes to rerender dom
+ this.cdf.detectChanges();
+ // 3. Hide overflowed tabs
+ this.resetTabsForDownSize();
+ }
}
diff --git a/src/portal/src/app/project/project-detail/project-detail.const.ts b/src/portal/src/app/project/project-detail/project-detail.const.ts
new file mode 100644
index 000000000..9d195ecb5
--- /dev/null
+++ b/src/portal/src/app/project/project-detail/project-detail.const.ts
@@ -0,0 +1,3 @@
+export const SHOW_ELLIPSIS_WIDTH = 80;
+export const DOWN: string = "down";
+export const UP: string = "up";
diff --git a/src/portal/src/css/common.scss b/src/portal/src/css/common.scss
new file mode 100644
index 000000000..06c40fdf5
--- /dev/null
+++ b/src/portal/src/css/common.scss
@@ -0,0 +1,11 @@
+// styles for dark and light theme should be defined here.
+.in-overflow {
+ .tabs-overflow {
+ > .nav-item {
+ > button {
+ box-shadow: 0 -3px 0 $dark-active-tab-color inset;
+ color: 0077b8;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/portal/src/css/dark-theme.scss b/src/portal/src/css/dark-theme.scss
index 53999bf2e..2ecf4eb2c 100644
--- a/src/portal/src/css/dark-theme.scss
+++ b/src/portal/src/css/dark-theme.scss
@@ -1,7 +1,9 @@
+// Variables for dark theme should be defined here.
@import "../../node_modules/@clr/ui/clr-ui-dark.min.css";
$dark-background-color: rgb(27, 42, 50) !important;
$dark-font-color1: #acbac3 !important;
$dark-font-color-title1: #eaedf0 !important;
+$dark-active-tab-color: #4aaed9;
.label-form {
background-color: #212129 !important;
@@ -110,4 +112,6 @@ clr-dg-action-overflow {
color: #1b2a32;
}
}
-}
\ No newline at end of file
+}
+
+@import "./common.scss";
\ No newline at end of file
diff --git a/src/portal/src/css/light-theme.scss b/src/portal/src/css/light-theme.scss
index b09e7465a..8d93ad912 100644
--- a/src/portal/src/css/light-theme.scss
+++ b/src/portal/src/css/light-theme.scss
@@ -1 +1,5 @@
-@import "../../node_modules/@clr/ui/clr-ui.min.css";
\ No newline at end of file
+// Variables for dark theme should be defined here.
+@import "../../node_modules/@clr/ui/clr-ui.min.css";
+
+$dark-active-tab-color: #0077b8;
+@import "./common.scss";
\ No newline at end of file
diff --git a/src/portal/src/lib/components/config/project-quotas/edit-project-quotas/edit-project-quotas.component.html b/src/portal/src/lib/components/config/project-quotas/edit-project-quotas/edit-project-quotas.component.html
index 3b41f4dc9..ccc679818 100644
--- a/src/portal/src/lib/components/config/project-quotas/edit-project-quotas/edit-project-quotas.component.html
+++ b/src/portal/src/lib/components/config/project-quotas/edit-project-quotas/edit-project-quotas.component.html
@@ -75,7 +75,7 @@
-
\ No newline at end of file
+
diff --git a/src/portal/src/lib/components/config/project-quotas/edit-project-quotas/edit-project-quotas.component.spec.ts b/src/portal/src/lib/components/config/project-quotas/edit-project-quotas/edit-project-quotas.component.spec.ts
index 0a6a1e725..2cfb9c0b4 100644
--- a/src/portal/src/lib/components/config/project-quotas/edit-project-quotas/edit-project-quotas.component.spec.ts
+++ b/src/portal/src/lib/components/config/project-quotas/edit-project-quotas/edit-project-quotas.component.spec.ts
@@ -1,10 +1,9 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
import { EditProjectQuotasComponent } from './edit-project-quotas.component';
-import { SharedModule } from '../../../../utils/shared/shared.module';
-import { InlineAlertComponent } from '../../../inline-alert/inline-alert.component';
import { SERVICE_CONFIG, IServiceConfig } from '../../../../entities/service.config';
-import { RouterModule } from '@angular/router';
+import { EditQuotaQuotaInterface } from '../../../../services';
+import { HarborLibraryModule } from '../../../../harbor-library.module';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
describe('EditProjectQuotasComponent', () => {
let component: EditProjectQuotasComponent;
@@ -12,13 +11,20 @@ describe('EditProjectQuotasComponent', () => {
let config: IServiceConfig = {
quotaUrl: "/api/quotas/testing"
};
+ const mockedEditQuota: EditQuotaQuotaInterface = {
+ editQuota: "Edit Default Project Quotas",
+ setQuota: "Set the default project quotas when creating new projects",
+ countQuota: "Default artifact count",
+ storageQuota: "Default storage consumption",
+ quotaHardLimitValue: {storageLimit: -1, storageUnit: "Byte", countLimit: -1},
+ isSystemDefaultQuota: true
+ };
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
- SharedModule,
- RouterModule.forRoot([])
+ HarborLibraryModule,
+ BrowserAnimationsModule
],
- declarations: [ EditProjectQuotasComponent, InlineAlertComponent ],
providers: [
{ provide: SERVICE_CONFIG, useValue: config },
]
@@ -34,4 +40,18 @@ describe('EditProjectQuotasComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
+ it('should open', async () => {
+ component.openEditQuota = true;
+ fixture.detectChanges();
+ await fixture.whenStable();
+ component.openEditQuotaModal(mockedEditQuota);
+ fixture.detectChanges();
+ await fixture.whenStable();
+ let countInput: HTMLInputElement = fixture.nativeElement.querySelector('#count');
+ countInput.value = "100";
+ countInput.dispatchEvent(new Event("input"));
+ fixture.detectChanges();
+ await fixture.whenStable();
+ expect(component.isValid).toBeTruthy();
+ });
});
diff --git a/src/portal/src/lib/components/config/project-quotas/project-quotas.component.html b/src/portal/src/lib/components/config/project-quotas/project-quotas.component.html
index 64b175c93..aa036572f 100644
--- a/src/portal/src/lib/components/config/project-quotas/project-quotas.component.html
+++ b/src/portal/src/lib/components/config/project-quotas/project-quotas.component.html
@@ -6,7 +6,7 @@
{{'QUOTA.PROJECT_QUOTA_DEFAULT_ARTIFACT' | translate}}
{{ quotaHardLimitValue?.countLimit === -1 ? ('QUOTA.UNLIMITED'| translate) : quotaHardLimitValue?.countLimit }}
-
diff --git a/src/portal/src/lib/components/config/project-quotas/project-quotas.component.spec.ts b/src/portal/src/lib/components/config/project-quotas/project-quotas.component.spec.ts
index f70897232..51a3e2665 100644
--- a/src/portal/src/lib/components/config/project-quotas/project-quotas.component.spec.ts
+++ b/src/portal/src/lib/components/config/project-quotas/project-quotas.component.spec.ts
@@ -1,11 +1,7 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
+import { async, ComponentFixture, ComponentFixtureAutoDetect, TestBed } from '@angular/core/testing';
import { ProjectQuotasComponent } from './project-quotas.component';
import { IServiceConfig, SERVICE_CONFIG } from '../../../entities/service.config';
-import { SharedModule } from '../../../utils/shared/shared.module';
-import { RouterModule } from '@angular/router';
-import { EditProjectQuotasComponent } from './edit-project-quotas/edit-project-quotas.component';
-import { InlineAlertComponent } from '../../inline-alert/inline-alert.component';
+import { Router } from '@angular/router';
import {
ConfigurationService, ConfigurationDefaultService, QuotaService
, QuotaDefaultService, Quota, RequestQueryParams
@@ -14,8 +10,12 @@ import { ErrorHandler } from '../../../utils/error-handler';
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
import {APP_BASE_HREF} from '@angular/common';
+import { HarborLibraryModule } from '../../../harbor-library.module';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
describe('ProjectQuotasComponent', () => {
let spy: jasmine.Spy;
+ let spyUpdate: jasmine.Spy;
+ let spyRoute: jasmine.Spy;
let quotaService: QuotaService;
let component: ProjectQuotasComponent;
@@ -43,20 +43,35 @@ describe('ProjectQuotasComponent', () => {
},
}
];
+ const fakedRouter = {
+ navigate() {
+ return undefined;
+ }
+ };
+ const fakedErrorHandler = {
+ error() {
+ return undefined;
+ },
+ info() {
+ return undefined;
+ }
+ };
+ const timeout = (ms: number) => {
+ return new Promise(resolve => setTimeout(resolve, ms));
+ };
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
- SharedModule,
- RouterModule.forRoot([])
+ HarborLibraryModule,
+ BrowserAnimationsModule
],
- declarations: [ProjectQuotasComponent, EditProjectQuotasComponent, InlineAlertComponent],
providers: [
- ErrorHandler,
+ { provide: ErrorHandler, useValue: fakedErrorHandler },
{ provide: SERVICE_CONFIG, useValue: config },
{ provide: ConfigurationService, useClass: ConfigurationDefaultService },
{ provide: QuotaService, useClass: QuotaDefaultService },
- { provide: APP_BASE_HREF, useValue : '/' }
-
+ { provide: APP_BASE_HREF, useValue : '/' },
+ { provide: Router, useValue: fakedRouter }
]
})
.compileComponents();
@@ -83,11 +98,52 @@ describe('ProjectQuotasComponent', () => {
};
return of(httpRes).pipe(delay(0));
});
-
+ spyUpdate = spyOn(quotaService, 'updateQuota').and.returnValue(of(null));
+ spyRoute = spyOn(fixture.debugElement.injector.get(Router), 'navigate').and.returnValue(of(null));
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
+ it('should open edit quota modal', async () => {
+ // wait getting list and rendering
+ await timeout(10);
+ fixture.detectChanges();
+ await fixture.whenStable();
+ const openEditButton: HTMLButtonElement = fixture.nativeElement.querySelector("#open-edit");
+ openEditButton.dispatchEvent(new Event("click"));
+ fixture.detectChanges();
+ await fixture.whenStable();
+ const modal: HTMLElement = fixture.nativeElement.querySelector("clr-modal");
+ expect(modal).toBeTruthy();
+ });
+ it('edit quota', async () => {
+ // wait getting list and rendering
+ await timeout(10);
+ fixture.detectChanges();
+ await fixture.whenStable();
+ component.editQuota(component.quotaList[0]);
+ fixture.detectChanges();
+ await fixture.whenStable();
+ const countInput: HTMLInputElement = fixture.nativeElement.querySelector('#count');
+ countInput.value = "100";
+ countInput.dispatchEvent(new Event("input"));
+ fixture.detectChanges();
+ await fixture.whenStable();
+ const saveButton: HTMLInputElement = fixture.nativeElement.querySelector('#edit-quota-save');
+ saveButton.dispatchEvent(new Event("click"));
+ fixture.detectChanges();
+ await fixture.whenStable();
+ expect(spyUpdate.calls.count()).toEqual(1);
+ });
+ it('should call navigate function', async () => {
+ // wait getting list and rendering
+ await timeout(10);
+ fixture.detectChanges();
+ await fixture.whenStable();
+ const a: HTMLElement = fixture.nativeElement.querySelector('clr-dg-cell a');
+ a.dispatchEvent(new Event("click"));
+ expect(spyRoute.calls.count()).toEqual(1);
+ });
});
diff --git a/src/replication/transfer/image/transfer.go b/src/replication/transfer/image/transfer.go
index 8a31b0ed0..497052d48 100644
--- a/src/replication/transfer/image/transfer.go
+++ b/src/replication/transfer/image/transfer.go
@@ -16,7 +16,6 @@ package image
import (
"errors"
- "fmt"
"strings"
"github.com/docker/distribution/manifest/manifestlist"
@@ -259,6 +258,7 @@ func (t *transfer) pullManifest(repository, reference string) (
return nil, "", nil
}
t.logger.Infof("pulling the manifest of image %s:%s ...", repository, reference)
+ // TODO add OCI media types
manifest, digest, err := t.src.PullManifest(repository, reference, []string{
schema1.MediaTypeManifest,
schema1.MediaTypeSignedManifest,
@@ -271,47 +271,7 @@ func (t *transfer) pullManifest(repository, reference string) (
}
t.logger.Infof("the manifest of image %s:%s pulled", repository, reference)
- // this is a solution to work around that harbor doesn't support manifest list
- return t.handleManifest(manifest, repository, digest)
-}
-
-// if the media type of the specified manifest is manifest list, just abstract one
-// manifest from the list and return it
-func (t *transfer) handleManifest(manifest distribution.Manifest, repository, digest string) (
- distribution.Manifest, string, error) {
- mediaType, _, err := manifest.Payload()
- if err != nil {
- t.logger.Errorf("failed to call the payload method for manifest of %s:%s: %v", repository, digest, err)
- return nil, "", err
- }
- // manifest
- if mediaType == schema1.MediaTypeManifest ||
- mediaType == schema1.MediaTypeSignedManifest ||
- mediaType == schema2.MediaTypeManifest {
- return manifest, digest, nil
- }
- // manifest list
- t.logger.Info("trying abstract a manifest from the manifest list...")
- manifestlist, ok := manifest.(*manifestlist.DeserializedManifestList)
- if !ok {
- err := fmt.Errorf("the object isn't a DeserializedManifestList")
- t.logger.Errorf(err.Error())
- return nil, "", err
- }
- digest = ""
- for _, reference := range manifestlist.Manifests {
- if strings.ToLower(reference.Platform.Architecture) == "amd64" &&
- strings.ToLower(reference.Platform.OS) == "linux" {
- digest = reference.Digest.String()
- t.logger.Infof("a manifest(architecture: amd64, os: linux) found, using this one: %s", digest)
- break
- }
- }
- if len(digest) == 0 {
- digest = manifest.References()[0].Digest.String()
- t.logger.Infof("no manifest(architecture: amd64, os: linux) found, using the first one: %s", digest)
- }
- return t.pullManifest(repository, digest)
+ return manifest, digest, nil
}
func (t *transfer) exist(repository, tag string) (bool, string, error) {
diff --git a/tests/resources/Harbor-Pages/Administration-Users.robot b/tests/resources/Harbor-Pages/Administration-Users.robot
index cd15d0af5..be3a67571 100644
--- a/tests/resources/Harbor-Pages/Administration-Users.robot
+++ b/tests/resources/Harbor-Pages/Administration-Users.robot
@@ -21,28 +21,28 @@ Resource ../../resources/Util.robot
*** Keywords ***
Assign User Admin
[Arguments] ${user}
- Click Element xpath=//harbor-user//hbr-filter//clr-icon
+ Retry Element Click xpath=//harbor-user//hbr-filter//clr-icon
Input Text xpath=//harbor-user//hbr-filter//input ${user}
Sleep 2
#select checkbox
- Click Element //clr-dg-row[contains(.,'${user}')]//label
+ Retry Element Click //clr-dg-row[contains(.,'${user}')]//label
#click assign admin
- Click Element //*[@id='set-admin']
+ Retry Element Click //*[@id='set-admin']
Sleep 1
Switch to User Tag
- Click Element xpath=${administration_user_tag_xpath}
+ Retry Element Click xpath=${administration_user_tag_xpath}
Sleep 1
Administration Tag Should Display
- Page Should Contain Element xpath=${administration_tag_xpath}
+ Retry Wait Until Page Contains Element xpath=${administration_tag_xpath}
User Email Should Exist
[Arguments] ${email}
Sign In Harbor ${HARBOR_URL} %{HARBOR_ADMIN} %{HARBOR_PASSWORD}
Switch to User Tag
- Page Should Contain Element xpath=//clr-dg-cell[contains(., '${email}')]
+ Retry Wait Until Page Contains Element xpath=//clr-dg-cell[contains(., '${email}')]
Add User Button Should Be Disabled
Sleep 1
- Page Should Contain Element //button[contains(.,'New') and @disabled='']
+ Retry Wait Until Page Contains Element //button[contains(.,'New') and @disabled='']
diff --git a/tests/resources/Harbor-Pages/Configuration.robot b/tests/resources/Harbor-Pages/Configuration.robot
index d619698a1..49dbf5a22 100644
--- a/tests/resources/Harbor-Pages/Configuration.robot
+++ b/tests/resources/Harbor-Pages/Configuration.robot
@@ -140,10 +140,10 @@ Self Reg Should Be Enabled
Checkbox Should Be Selected xpath=${self_reg_xpath}
Project Creation Should Display
- Page Should Contain Element xpath=${project_create_xpath}
+ Retry Wait Until Page Contains Element xpath=${project_create_xpath}
Project Creation Should Not Display
- Page Should Not Contain Element xpath=${project_create_xpath}
+ Retry Wait Until Page Not Contains Element xpath=${project_create_xpath}
## System settings
Switch To System Settings
@@ -153,6 +153,8 @@ Switch To System Settings
Sleep 1
Switch To Project Quotas
+ Sleep 1
+ Retry Element Click xpath=${configuration_xpath}
Sleep 1
Retry Element Click xpath=//clr-main-container//clr-vertical-nav//a[contains(.,'Project Quotas')]
Sleep 1
diff --git a/tests/resources/Harbor-Pages/HomePage.robot b/tests/resources/Harbor-Pages/HomePage.robot
index c5f8ad83c..0486efdc1 100644
--- a/tests/resources/Harbor-Pages/HomePage.robot
+++ b/tests/resources/Harbor-Pages/HomePage.robot
@@ -37,7 +37,7 @@ Capture Screenshot And Source
Log Source
Sign Up Should Not Display
- Page Should Not Contain Element xpath=${sign_up_button_xpath}
+ Retry Wait Until Page Not Contains Element xpath=${sign_up_button_xpath}
Create An New User
[Arguments] ${url} ${username} ${email} ${realname} ${newPassword} ${comment}
diff --git a/tests/resources/Harbor-Pages/LDAP-Mode.robot b/tests/resources/Harbor-Pages/LDAP-Mode.robot
index d14b53430..fa0cf4c43 100644
--- a/tests/resources/Harbor-Pages/LDAP-Mode.robot
+++ b/tests/resources/Harbor-Pages/LDAP-Mode.robot
@@ -21,8 +21,8 @@ Resource ../../resources/Util.robot
*** Keywords ***
Ldap User Should Not See Change Password
- Click Element //clr-header//clr-dropdown[2]//button
- Sleep 1
+ Retry Element Click //clr-header//clr-dropdown[2]//button
+ Sleep 2
Page Should Not Contain Password
diff --git a/tests/resources/Harbor-Pages/Project-Config.robot b/tests/resources/Harbor-Pages/Project-Config.robot
index 96eb835a9..c0e6c4871 100644
--- a/tests/resources/Harbor-Pages/Project-Config.robot
+++ b/tests/resources/Harbor-Pages/Project-Config.robot
@@ -42,7 +42,7 @@ Public Should Be Selected
Project Should Be Public
[Arguments] ${projectName}
- Page Should Contain Element //clr-dg-row[contains(.,'${projectName}')]//clr-dg-cell[contains(.,'Public')]
+ Retry Wait Until Page Contains Element //clr-dg-row[contains(.,'${projectName}')]//clr-dg-cell[contains(.,'Public')]
Content Trust Should Be Selected
Checkbox Should Be Selected //hbr-project-policy-config//input[@name='content-trust']
diff --git a/tests/resources/Harbor-Pages/Project-Members.robot b/tests/resources/Harbor-Pages/Project-Members.robot
index 7d8ef63cb..e506e047e 100644
--- a/tests/resources/Harbor-Pages/Project-Members.robot
+++ b/tests/resources/Harbor-Pages/Project-Members.robot
@@ -70,13 +70,13 @@ User Can Change Role
[arguments] ${username}
Retry Element Click xpath=//clr-dg-row[contains(.,'${username}')]//input/../label
Retry Element Click xpath=//*[@id='member-action']
- Page Should Not Contain Element xpath=//button[@disabled='' and contains(.,'Admin')]
+ Retry Wait Until Page Not Contains Element xpath=//button[@disabled='' and contains(.,'Admin')]
User Can Not Change Role
[arguments] ${username}
Retry Element Click xpath=//clr-dg-row[contains(.,'${username}')]//input/../label
Retry Element Click xpath=//*[@id='member-action']
- Page Should Contain Element xpath=//button[@disabled='' and contains(.,'Admin')]
+ Retry Wait Until Page Contains Element xpath=//button[@disabled='' and contains(.,'Admin')]
#this keyworkd seems will not use any more, will delete in the future
Non-admin View Member Account
@@ -84,7 +84,7 @@ Non-admin View Member Account
Xpath Should Match X Times //clr-dg-row-master ${times}
User Can Not Add Member
- Page Should Contain Element xpath=//button[@disabled='' and contains(.,'User')]
+ Retry Wait Until Page Contains Element xpath=//button[@disabled='' and contains(.,'User')]
Add Guest Member To Project
[arguments] ${member}
@@ -153,7 +153,7 @@ User Should Be Guest
Go Into Project ${project}
Switch To Member
User Can Not Add Member
- Page Should Contain Element xpath=//clr-dg-row[contains(.,'${user}')]//clr-dg-cell[contains(.,'Guest')]
+ Retry Wait Until Page Contains Element xpath=//clr-dg-row[contains(.,'${user}')]//clr-dg-cell[contains(.,'Guest')]
Logout Harbor
Pull image ${ip} ${user} ${password} ${project} hello-world
Cannot Push image ${ip} ${user} ${password} ${project} hello-world
@@ -168,7 +168,7 @@ User Should Be Developer
Go Into Project ${project}
Switch To Member
User Can Not Add Member
- Page Should Contain Element xpath=//clr-dg-row[contains(.,'${user}')]//clr-dg-cell[contains(.,'Developer')]
+ Retry Wait Until Page Contains Element xpath=//clr-dg-row[contains(.,'${user}')]//clr-dg-cell[contains(.,'Developer')]
Logout Harbor
Push Image With Tag ${ip} ${user} ${password} ${project} hello-world v1
@@ -183,7 +183,7 @@ User Should Be Admin
Switch To Member
Add Guest Member To Project ${guest}
User Can Change Role ${guest}
- Page Should Contain Element xpath=//clr-dg-row[contains(.,'${user}')]//clr-dg-cell[contains(.,'Admin')]
+ Retry Wait Until Page Contains Element xpath=//clr-dg-row[contains(.,'${user}')]//clr-dg-cell[contains(.,'Admin')]
Logout Harbor
Push Image With Tag ${ip} ${user} ${password} ${project} hello-world v2
@@ -197,7 +197,7 @@ User Should Be Master
Go Into Project ${project}
Delete Repo ${project}
Switch To Member
- Page Should Contain Element xpath=//clr-dg-row[contains(.,'${user}')]//clr-dg-cell[contains(.,'Master')]
+ Retry Wait Until Page Contains Element xpath=//clr-dg-row[contains(.,'${user}')]//clr-dg-cell[contains(.,'Master')]
Logout Harbor
Push Image With Tag ${ip} ${user} ${password} ${project} hello-world v3
@@ -206,5 +206,5 @@ Project Should Have Member
Sign In Harbor ${HARBOR_URL} %{HARBOR_ADMIN} %{HARBOR_PASSWORD}
Go Into Project ${project}
Switch To Member
- Page Should Contain Element xpath=//clr-dg-cell[contains(., '${user}')]
+ Retry Wait Until Page Contains Element xpath=//clr-dg-cell[contains(., '${user}')]
Logout Harbor
diff --git a/tests/resources/Harbor-Pages/Project-Repository_Elements.robot b/tests/resources/Harbor-Pages/Project-Repository_Elements.robot
index 52ab139d9..053133296 100644
--- a/tests/resources/Harbor-Pages/Project-Repository_Elements.robot
+++ b/tests/resources/Harbor-Pages/Project-Repository_Elements.robot
@@ -21,3 +21,6 @@ ${first_cve_xpath} //clr-dg-row[1]//clr-dg-cell//a
${view_log_xpath} //clr-dg-row[1]//clr-dg-cell[4]//a
${build_history_btn} //button[contains(.,'Build History')]
${build_history_data} //clr-dg-row
+${push_image_command_btn} //hbr-push-image-button//button
+
+
diff --git a/tests/resources/Harbor-Pages/Project.robot b/tests/resources/Harbor-Pages/Project.robot
index 047e175cd..d09f3dafb 100644
--- a/tests/resources/Harbor-Pages/Project.robot
+++ b/tests/resources/Harbor-Pages/Project.robot
@@ -27,7 +27,7 @@ Create An New Project
Capture Page Screenshot
Retry Text Input xpath=${project_name_xpath} ${projectname}
${element_project_public}= Set Variable xpath=${project_public_xpath}
- Run Keyword If '${public}' == 'true' Run Keywords Wait Until Element Is Visible And Enabled ${element_project_public} AND Click Element ${element_project_public}
+ Run Keyword If '${public}' == 'true' Run Keywords Wait Until Element Is Visible And Enabled ${element_project_public} AND Retry Element Click ${element_project_public}
Run Keyword If '${count_quota}'!='${null}' Input Count Quota ${count_quota}
Run Keyword If '${storage_quota}'!='${null}' Input Storage Quota ${storage_quota} ${storage_quota_unit}
Capture Page Screenshot
diff --git a/tests/resources/Harbor-Pages/UserProfile.robot b/tests/resources/Harbor-Pages/UserProfile.robot
index fc7b3fca0..8525fcca7 100644
--- a/tests/resources/Harbor-Pages/UserProfile.robot
+++ b/tests/resources/Harbor-Pages/UserProfile.robot
@@ -43,4 +43,4 @@ Logout Harbor
Retry Link Click Log Out
Capture Page Screenshot Logout.png
Sleep 2
- Wait Until Keyword Succeeds 5x 1 Page Should Contain Element ${sign_in_title_xpath}
\ No newline at end of file
+ Wait Until Keyword Succeeds 5x 1 Retry Wait Until Page Contains Element ${sign_in_title_xpath}
\ No newline at end of file
diff --git a/tests/robot-cases/Group1-Nightly/Common.robot b/tests/robot-cases/Group1-Nightly/Common.robot
index 4461ea6ba..47336b78b 100644
--- a/tests/robot-cases/Group1-Nightly/Common.robot
+++ b/tests/robot-cases/Group1-Nightly/Common.robot
@@ -406,7 +406,7 @@ Test Case - Developer Operate Labels
Sign In Harbor ${HARBOR_URL} user022 Test1@34
Go Into Project project${d} has_image=${false}
Sleep 3
- Page Should Not Contain Element xpath=//a[contains(.,'Labels')]
+ Retry Wait Until Page Not Contains Element xpath=//a[contains(.,'Labels')]
Close Browser
Test Case - Retag A Image Tag
@@ -431,7 +431,7 @@ Test Case - Retag A Image Tag
Page Should Contain ${target_image_name}
Go Into Repo project${random_num1}${random_num2}/${target_image_name}
Sleep 1
- Page Should Contain Element xpath=${tag_value_xpath}
+ Retry Wait Until Page Contains Element xpath=${tag_value_xpath}
Close Browser
Test Case - Create An New Project With Quotas Set
diff --git a/tests/robot-cases/Group1-Nightly/LDAP.robot b/tests/robot-cases/Group1-Nightly/LDAP.robot
index c077fca48..307565a6d 100644
--- a/tests/robot-cases/Group1-Nightly/LDAP.robot
+++ b/tests/robot-cases/Group1-Nightly/LDAP.robot
@@ -44,6 +44,7 @@ Test Case - System Admin On-board New Member
${d}= Get Current Date result_format=%m%s
Sign In Harbor ${HARBOR_URL} ${HARBOR_ADMIN} ${HARBOR_PASSWORD}
Switch To User Tag
+ Sleep 2
Page Should Not Contain mike02
Navigate To Projects
Create An New Project project${d}
@@ -60,8 +61,10 @@ Test Case - LDAP User On-borad New Member
Create An New Project project${d}
Go Into Project project${d} has_image=${false}
Switch To Member
+ Sleep 2
Page Should Not Contain mike04
Add Guest Member To Project mike04
+ Sleep 2
Page Should Contain mike04
Close Browser
diff --git a/tests/robot-cases/Group1-Nightly/Nightly.robot b/tests/robot-cases/Group1-Nightly/Nightly.robot
index 8648101a7..a4bb5ca3b 100644
--- a/tests/robot-cases/Group1-Nightly/Nightly.robot
+++ b/tests/robot-cases/Group1-Nightly/Nightly.robot
@@ -393,7 +393,7 @@ TestCase - Developer Operate Labels
Sign In Harbor ${HARBOR_URL} bob${d} Test1@34
Go Into Project project${d} has_image=${false}
Sleep 3
- Page Should Not Contain Element xpath=//a[contains(.,'Labels')]
+ Retry Wait Until Page Not Contains Element xpath=//a[contains(.,'Labels')]
Close Browser
Test Case - Scan A Tag In The Repo
diff --git a/tests/robot-cases/Group1-Nightly/UAA.robot b/tests/robot-cases/Group1-Nightly/UAA.robot
index 1d5ba63e3..11c38d901 100644
--- a/tests/robot-cases/Group1-Nightly/UAA.robot
+++ b/tests/robot-cases/Group1-Nightly/UAA.robot
@@ -36,7 +36,7 @@ Test Case - Home Page Differences With DB Mode
Sign In Harbor ${HARBOR_URL} ${HARBOR_ADMIN} ${HARBOR_PASSWORD}
Logout Harbor
Sleep 2
- Page Should Not Contain Sign up
+ Page Should Not Contain Sign up
Page Should Not Contain Forgot password
Close Browser