Skip to content

Commit a95fe52

Browse files
072324.02/first release approval button (#8700)
* Fix broken Tests * Refactor Models into Separate Files. Get Tests to all pass * All Tests Green * Enable Test Job on the pipeline * Move Projects to DotNET 8 * Enable CLient Side Tests * Switch back to net 7 * update SPA tests * Resolve Bug in First Release Approval Button * Remove rougue file
1 parent 8b89f55 commit a95fe52

42 files changed

Lines changed: 649 additions & 466 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

eng/pipelines/templates/steps/apiview-ui-tests.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ steps:
9292
"FIXTURE_DIR": "$(Build.BinariesDirectory)"
9393
"APIVIEW_API_KEY": "$(azuresdk-apiview-apikey)"
9494

95-
- task: PublishBuildArtifacts@1
95+
- task: 1ES.PublishPipelineArtifact@1
9696
inputs:
97-
pathtoPublish: '$(Build.SourcesDirectory)\src\dotnet\APIView\APIViewWeb\Client\playwright-report'
98-
artifactName: 'Client-Side Test Reports'
97+
path: '$(Build.SourcesDirectory)\src\dotnet\APIView\APIViewWeb\Client\playwright-report'
98+
artifact: 'Client-Side Test Reports'

src/dotnet/APIView/ClientSPA/src/app/_components/api-revision-options/api-revision-options.component.spec.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,33 @@
1+
import 'reflect-metadata';
12
import { ComponentFixture, TestBed } from '@angular/core/testing';
23

34
import { ApiRevisionOptionsComponent } from './api-revision-options.component';
5+
import { ActivatedRoute, convertToParamMap } from '@angular/router';
6+
import { ReviewPageModule } from 'src/app/_modules/review-page/review-page.module';
7+
import { SharedAppModule } from 'src/app/_modules/shared/shared-app.module';
48

59
describe('ApiRevisionOptionsComponent', () => {
610
let component: ApiRevisionOptionsComponent;
711
let fixture: ComponentFixture<ApiRevisionOptionsComponent>;
812

913
beforeEach(() => {
1014
TestBed.configureTestingModule({
11-
declarations: [ApiRevisionOptionsComponent]
15+
declarations: [ApiRevisionOptionsComponent],
16+
imports: [
17+
SharedAppModule,
18+
ReviewPageModule
19+
],
20+
providers: [
21+
{
22+
provide: ActivatedRoute,
23+
useValue: {
24+
snapshot: {
25+
paramMap: convertToParamMap({ reviewId: 'test' }),
26+
queryParamMap: convertToParamMap({ activeApiRevisionId: 'test', diffApiRevisionId: 'test' })
27+
}
28+
}
29+
}
30+
]
1231
});
1332
fixture = TestBed.createComponent(ApiRevisionOptionsComponent);
1433
component = fixture.componentInstance;

src/dotnet/APIView/ClientSPA/src/app/_components/code-panel/code-panel.component.spec.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,35 @@
11
import { ComponentFixture, TestBed } from '@angular/core/testing';
22

33
import { CodePanelComponent } from './code-panel.component';
4+
import { CommentsService } from 'src/app/_services/comments/comments.service';
5+
import { HttpClientTestingModule } from '@angular/common/http/testing';
6+
import { ActivatedRoute, convertToParamMap } from '@angular/router';
7+
import { SharedAppModule } from 'src/app/_modules/shared/shared-app.module';
8+
import { ReviewPageModule } from 'src/app/_modules/review-page/review-page.module';
49

510
describe('CodePanelComponent', () => {
611
let component: CodePanelComponent;
712
let fixture: ComponentFixture<CodePanelComponent>;
813

914
beforeEach(() => {
1015
TestBed.configureTestingModule({
11-
declarations: [CodePanelComponent]
16+
declarations: [CodePanelComponent],
17+
providers: [
18+
CommentsService,
19+
{
20+
provide: ActivatedRoute,
21+
useValue: {
22+
snapshot: {
23+
paramMap: convertToParamMap({ reviewId: 'test' }),
24+
queryParamMap: convertToParamMap({ activeApiRevisionId: 'test', diffApiRevisionId: 'test' })
25+
}
26+
}
27+
}
28+
],
29+
imports: [HttpClientTestingModule,
30+
SharedAppModule,
31+
ReviewPageModule
32+
]
1233
});
1334
fixture = TestBed.createComponent(CodePanelComponent);
1435
component = fixture.componentInstance;

src/dotnet/APIView/ClientSPA/src/app/_components/code-panel/code-panel.component.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild, ViewContainerRef } from '@angular/core';
1+
import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
22
import { take } from 'rxjs/operators';
3-
import { CommentItemModel, CommentType } from 'src/app/_models/review';
4-
import { CodePanelData, CodePanelRowDatatype, StructuredToken } from 'src/app/_models/revision';
5-
import { CodePanelRowData } from 'src/app/_models/revision';
3+
import { CodePanelData } from 'src/app/_models/revision';
64
import { Datasource, IDatasource, SizeStrategy } from 'ngx-ui-scroll';
75
import { CommentsService } from 'src/app/_services/comments/comments.service';
8-
import { UserProfile } from 'src/app/_models/auth_service_models';
96
import { getQueryParams } from 'src/app/_helpers/router-helpers';
107
import { ActivatedRoute, Router } from '@angular/router';
118
import { SCROLL_TO_NODE_QUERY_PARAM } from 'src/app/_helpers/literal-helpers';
9+
import { CodePanelRowData, CodePanelRowDatatype } from 'src/app/_models/codePanelRowData';
10+
import { StructuredToken } from 'src/app/_models/structuredToken';
11+
import { CommentItemModel, CommentType } from 'src/app/_models/commentItemModel';
12+
import { UserProfile } from 'src/app/_models/userProfile';
1213

1314
@Component({
1415
selector: 'app-code-panel',

src/dotnet/APIView/ClientSPA/src/app/_components/index-page/index-page.component.spec.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,10 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
44
import { IndexPageComponent } from './index-page.component';
55
import { NavBarComponent } from '../shared/nav-bar/nav-bar.component';
66
import { FooterComponent } from '../shared/footer/footer.component';
7-
import { SplitterModule } from 'primeng/splitter';
87
import { ReviewsListComponent } from '../reviews-list/reviews-list.component';
9-
import { ContextMenuModule } from 'primeng/contextmenu';
10-
import { TableModule } from 'primeng/table';
11-
import { SidebarModule } from 'primeng/sidebar';
12-
import { DropdownModule } from 'primeng/dropdown';
13-
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
14-
import { MultiSelectModule } from 'primeng/multiselect';
158
import { RevisionsListComponent } from '../revisions-list/revisions-list.component';
9+
import { AppModule } from 'src/app/app.module';
10+
import { SharedAppModule } from 'src/app/_modules/shared/shared-app.module';
1611

1712
describe('IndexPageComponent', () => {
1813
let component: IndexPageComponent;
@@ -29,14 +24,8 @@ describe('IndexPageComponent', () => {
2924
],
3025
imports: [
3126
HttpClientTestingModule,
32-
SplitterModule,
33-
ContextMenuModule,
34-
TableModule,
35-
SidebarModule,
36-
DropdownModule,
37-
ReactiveFormsModule,
38-
FormsModule,
39-
MultiSelectModule
27+
SharedAppModule,
28+
AppModule
4029
]
4130
});
4231
fixture = TestBed.createComponent(IndexPageComponent);

src/dotnet/APIView/ClientSPA/src/app/_components/review-page-options/review-page-options.component.html

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,25 @@
2727
</ng-template>
2828
</li>
2929
<li class="list-group-item text-center">
30-
<ng-container *ngIf="!reviewIsApproved && preferredApprovers.includes(userProfile?.userName!); else reviewApprovalHidden">
31-
<span class="small text-muted">Approves First Release of the package</span>
32-
<div class="d-grid gap-2">
33-
<button class="btn btn-success" type="button"
34-
(click)="handleReviewApprovalAction()"
35-
pTooltip="Package name must be approved before first preview release of a new package."
36-
tooltipPosition="bottom">
37-
Approve First Release
38-
</button>
39-
</div>
40-
<span class="small mt-2 text-muted">First Release Approval Pending</span>
30+
<ng-container *ngIf="reviewIsApproved; else reviewIsNotApproved">
31+
<span class="small text-muted mt-1" id="first-release-approval-message">Approved for First Release By: <a href="{{webAppUrl}}Assemblies/Profile/{{reviewApprover}}">{{reviewApprover}}</a></span>
4132
</ng-container>
42-
<ng-template #reviewApprovalHidden>
43-
<span class="small text-muted mt-1">
44-
Approved for First Release By: <a href="{{webAppUrl}}Assemblies/Profile/{{reviewApprover}}">{{reviewApprover}}</a>
45-
</span>
33+
<ng-template #reviewIsNotApproved>
34+
<div *ngIf="preferredApprovers.includes(userProfile?.userName!); else userIsNotAPreferedApprover">
35+
<span class="small text-muted">Approves First Release of the package</span>
36+
<div class="d-grid gap-2">
37+
<button class="btn btn-success" type="button" id="first-release-approval-button"
38+
(click)="handleReviewApprovalAction()"
39+
pTooltip="Package name must be approved before first preview release of a new package."
40+
tooltipPosition="bottom">
41+
Approve First Release
42+
</button>
43+
</div>
44+
<span class="small mt-2 text-muted" id="first-release-approval-message">First Release Approval Pending</span>
45+
</div>
46+
</ng-template>
47+
<ng-template #userIsNotAPreferedApprover>
48+
<span class="small mt-2 text-muted" id="first-release-approval-message">First Release Approval Pending</span>
4649
</ng-template>
4750
</li>
4851
</ul>

src/dotnet/APIView/ClientSPA/src/app/_components/review-page-options/review-page-options.component.spec.ts

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,49 @@
11
import { ComponentFixture, TestBed } from '@angular/core/testing';
22

33
import { ReviewPageOptionsComponent } from './review-page-options.component';
4+
import { HttpClientTestingModule } from '@angular/common/http/testing';
5+
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
6+
import { ActivatedRoute, convertToParamMap } from '@angular/router';
7+
import { HttpErrorInterceptorService } from 'src/app/_services/http-error-interceptor/http-error-interceptor.service';
8+
import { PageOptionsSectionComponent } from '../shared/page-options-section/page-options-section.component';
9+
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
10+
import { SharedAppModule } from 'src/app/_modules/shared/shared-app.module';
11+
import { ReviewPageModule } from 'src/app/_modules/review-page/review-page.module';
12+
import { UserProfile } from 'src/app/_models/userProfile';
413

514
describe('ReviewPageOptionsComponent', () => {
615
let component: ReviewPageOptionsComponent;
716
let fixture: ComponentFixture<ReviewPageOptionsComponent>;
817

918
beforeEach(() => {
1019
TestBed.configureTestingModule({
11-
declarations: [ReviewPageOptionsComponent]
20+
declarations: [
21+
ReviewPageOptionsComponent,
22+
PageOptionsSectionComponent
23+
],
24+
imports: [
25+
HttpClientTestingModule,
26+
HttpClientModule,
27+
BrowserAnimationsModule,
28+
SharedAppModule,
29+
ReviewPageModule
30+
],
31+
providers: [
32+
{
33+
provide: ActivatedRoute,
34+
useValue: {
35+
snapshot: {
36+
paramMap: convertToParamMap({ reviewId: 'test' }),
37+
queryParamMap: convertToParamMap({ activeApiRevisionId: 'test', diffApiRevisionId: 'test' })
38+
}
39+
}
40+
},
41+
{
42+
provide: HTTP_INTERCEPTORS,
43+
useClass: HttpErrorInterceptorService,
44+
multi: true
45+
}
46+
]
1247
});
1348
fixture = TestBed.createComponent(ReviewPageOptionsComponent);
1449
component = fixture.componentInstance;
@@ -18,4 +53,37 @@ describe('ReviewPageOptionsComponent', () => {
1853
it('should create', () => {
1954
expect(component).toBeTruthy();
2055
});
56+
57+
describe('First Release Approval Button', () => {
58+
it('should disable first release approval button when review is approved', () => {
59+
component.reviewIsApproved = true;
60+
fixture.detectChanges();
61+
const button = fixture.nativeElement.querySelector('#first-release-approval-button');
62+
expect(button).not.toBeTruthy();
63+
const message : HTMLElement = fixture.nativeElement.querySelector('#first-release-approval-message');
64+
expect(message.textContent?.startsWith("Approved for First Release By:")).toBeTruthy()
65+
});
66+
it('should disable first release approval button when review is not approved and user is not an approver', () => {
67+
component.reviewIsApproved = false;
68+
component.userProfile = new UserProfile();
69+
component.userProfile.userName = "test-user-1";
70+
component.preferredApprovers = ["test-user-2"]
71+
fixture.detectChanges();
72+
const button = fixture.nativeElement.querySelector('#first-release-approval-button');
73+
expect(button).not.toBeTruthy();
74+
const message : HTMLElement = fixture.nativeElement.querySelector('#first-release-approval-message');
75+
expect(message.textContent).toEqual("First Release Approval Pending");
76+
});
77+
it('should enable first release approval button when review is not approved and user is an approver', () => {
78+
component.reviewIsApproved = false;
79+
component.userProfile = new UserProfile();
80+
component.userProfile.userName = "test-user";
81+
component.preferredApprovers = ["test-user"]
82+
fixture.detectChanges();
83+
const button = fixture.nativeElement.querySelector('#first-release-approval-button');
84+
expect(button).toBeTruthy();
85+
const message : HTMLElement = fixture.nativeElement.querySelector('#first-release-approval-message');
86+
expect(message.textContent).toEqual("First Release Approval Pending");
87+
});
88+
});
2189
});

src/dotnet/APIView/ClientSPA/src/app/_components/review-page-options/review-page-options.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import { ActivatedRoute, Router } from '@angular/router';
33
import { InputSwitchOnChangeEvent } from 'primeng/inputswitch';
44
import { getQueryParams } from 'src/app/_helpers/router-helpers';
55
import { mapLanguageAliases } from 'src/app/_helpers/service-helpers';
6-
import { UserProfile } from 'src/app/_models/auth_service_models';
76
import { Review } from 'src/app/_models/review';
87
import { APIRevision } from 'src/app/_models/revision';
98
import { ConfigService } from 'src/app/_services/config/config.service';
109
import { RevisionsService } from 'src/app/_services/revisions/revisions.service';
11-
import { pipe, take } from 'rxjs';
10+
import { take } from 'rxjs';
11+
import { UserProfile } from 'src/app/_models/userProfile';
1212

1313
@Component({
1414
selector: 'app-review-page-options',

src/dotnet/APIView/ClientSPA/src/app/_components/review-page/review-page.component.spec.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
import { ComponentFixture, TestBed } from '@angular/core/testing';
22

33
import { ReviewPageComponent } from './review-page.component';
4-
import { ActivatedRoute, convertToParamMap, ParamMap } from '@angular/router';
4+
import { ActivatedRoute, convertToParamMap } from '@angular/router';
55
import { HttpClientTestingModule } from '@angular/common/http/testing';
66
import { NavBarComponent } from '../shared/nav-bar/nav-bar.component';
77
import { ReviewInfoComponent } from '../shared/review-info/review-info.component';
8-
import { MenuModule } from 'primeng/menu';
9-
import { SplitterModule } from 'primeng/splitter';
10-
import { SidebarModule } from 'primeng/sidebar';
118
import { FooterComponent } from '../shared/footer/footer.component';
12-
import { BreadcrumbModule } from 'primeng/breadcrumb';
139
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
1410
import { CodePanelComponent } from '../code-panel/code-panel.component';
11+
import { ReviewsListComponent } from '../reviews-list/reviews-list.component';
12+
import { RevisionsListComponent } from '../revisions-list/revisions-list.component';
13+
import { of } from 'rxjs';
14+
import { ApprovalPipe } from 'src/app/_pipes/approval.pipe';
15+
import { ReviewNavComponent } from '../review-nav/review-nav.component';
16+
import { ReviewPageOptionsComponent } from '../review-page-options/review-page-options.component';
17+
import { PageOptionsSectionComponent } from '../shared/page-options-section/page-options-section.component';
18+
import { SharedAppModule } from 'src/app/_modules/shared/shared-app.module';
19+
import { ReviewPageModule } from 'src/app/_modules/review-page/review-page.module';
1520

1621
describe('ReviewPageComponent', () => {
1722
let component: ReviewPageComponent;
@@ -21,27 +26,31 @@ describe('ReviewPageComponent', () => {
2126
TestBed.configureTestingModule({
2227
declarations: [
2328
ReviewPageComponent,
29+
ReviewNavComponent,
30+
ReviewPageOptionsComponent,
31+
PageOptionsSectionComponent,
2432
NavBarComponent,
2533
ReviewInfoComponent,
2634
FooterComponent,
27-
CodePanelComponent
35+
CodePanelComponent,
36+
ReviewsListComponent,
37+
RevisionsListComponent,
38+
ApprovalPipe
2839
],
2940
imports: [
3041
HttpClientTestingModule,
31-
MenuModule,
32-
SplitterModule,
33-
SidebarModule,
34-
BreadcrumbModule,
35-
BrowserAnimationsModule
42+
BrowserAnimationsModule,
43+
SharedAppModule,
44+
ReviewPageModule
3645
],
3746
providers: [
3847
{
3948
provide: ActivatedRoute,
4049
useValue: {
4150
snapshot: {
4251
paramMap: convertToParamMap({ reviewId: 'test' }),
43-
queryParamMap: convertToParamMap({ activeApiRevisionId: 'test', diffApiRevisionId: 'test' })
44-
}
52+
},
53+
queryParams: of(convertToParamMap({ activeApiRevisionId: 'test', diffApiRevisionId: 'test' }))
4554
}
4655
}
4756
]

src/dotnet/APIView/ClientSPA/src/app/_components/review-page/review-page.component.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
22
import { ActivatedRoute, Params, Router } from '@angular/router';
33
import { MenuItem, TreeNode } from 'primeng/api';
4-
import { Subject, Subscription, take, takeUntil, tap } from 'rxjs';
4+
import { Subject, take, takeUntil } from 'rxjs';
55
import { getLanguageCssSafeName } from 'src/app/_helpers/component-helpers';
66
import { getQueryParams } from 'src/app/_helpers/router-helpers';
7-
import { UserProfile } from 'src/app/_models/auth_service_models';
87
import { Review } from 'src/app/_models/review';
9-
import { APIRevision, ApiTreeBuilderData, CodePanelData, CodePanelRowData, CodePanelRowDatatype, CodePanelToggleableData, ReviewPageWorkerMessageDirective } from 'src/app/_models/revision';
8+
import { APIRevision, ApiTreeBuilderData, CodePanelData, ReviewPageWorkerMessageDirective } from 'src/app/_models/revision';
109
import { ReviewsService } from 'src/app/_services/reviews/reviews.service';
1110
import { RevisionsService } from 'src/app/_services/revisions/revisions.service';
1211
import { UserProfileService } from 'src/app/_services/user-profile/user-profile.service';
1312
import { WorkerService } from 'src/app/_services/worker/worker.service';
1413
import { CodePanelComponent } from '../code-panel/code-panel.component';
1514
import { CommentsService } from 'src/app/_services/comments/comments.service';
1615
import { ACTIVE_API_REVISION_ID_QUERY_PARAM, DIFF_API_REVISION_ID_QUERY_PARAM, DIFF_STYLE_QUERY_PARAM, REVIEW_ID_ROUTE_PARAM, SCROLL_TO_NODE_QUERY_PARAM } from 'src/app/_helpers/literal-helpers';
16+
import { CodePanelRowData, CodePanelRowDatatype } from 'src/app/_models/codePanelRowData';
17+
import { UserProfile } from 'src/app/_models/userProfile';
1718

1819
@Component({
1920
selector: 'app-review-page',

0 commit comments

Comments
 (0)