Skip to content

Commit 156e340

Browse files
committed
[APIM-11537] Add tests. Fix lint.
1 parent 83c35d5 commit 156e340

File tree

13 files changed

+343
-73
lines changed

13 files changed

+343
-73
lines changed

gravitee-apim-portal-webui-next/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
"@fontsource/roboto": "5.2.5",
6262
"@types/swagger-ui": "3.52.4",
6363
"angular-gridster2": "20.2.3",
64-
"angular-oauth2-oidc": "^20.0.2",
64+
"angular-oauth2-oidc": "20.0.2",
6565
"asciidoctor": "3.0.4",
6666
"chart.js": "4.3.0",
6767
"dompurify": "3.2.7",

gravitee-apim-portal-webui-next/src/app/log-in/log-in.component.html

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@
3939
}
4040
</mat-form-field>
4141
@if (error() === 401) {
42-
<mat-error class="log-in__form__error" i18n="@@logInError401">The username or password you entered is incorrect, please try again.</mat-error>
42+
<mat-error class="log-in__form__error" i18n="@@logInError401"
43+
>The username or password you entered is incorrect, please try again.</mat-error
44+
>
4345
}
4446
</div>
4547
<div class="log-in__form__buttons">
@@ -67,7 +69,6 @@
6769
type="button"
6870
mat-stroked-button
6971
class="log-in__sso__idp secondary-button"
70-
[style.background-color]="getProviderColor(provider)"
7172
(click)="authenticateSSO(provider)">
7273
<div class="log-in__sso__idp__container">
7374
<img class="log-in__sso__idp__logo" [src]="'assets/images/idp/' + getProviderLogo(provider)" alt="Provider Logo" />

gravitee-apim-portal-webui-next/src/app/log-in/log-in.component.scss

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
.log-in {
2424
display: flex;
2525
flex-flow: column;
26-
gap: 20px;
2726
background: #{theme.$background-color};
27+
gap: 20px;
2828

2929
&__form {
3030
display: flex;
@@ -47,7 +47,7 @@
4747
}
4848

4949
&__content:last-child {
50-
padding: 0 20px 20px;
50+
padding: 0 20px 20px;
5151
}
5252

5353
&__fields {
@@ -79,8 +79,8 @@
7979
}
8080

8181
&__error {
82-
text-align: center;
8382
font-size: 14px;
83+
text-align: center;
8484
}
8585
}
8686

@@ -116,12 +116,12 @@
116116
}
117117

118118
&__idp {
119+
overflow: hidden;
119120
width: 100%;
120-
font-weight: bold;
121+
padding: 0 18px;
121122
color: #{theme.$button-text-text-color};
123+
font-weight: bold;
122124
white-space: nowrap;
123-
overflow: hidden;
124-
padding: 0 18px;
125125

126126
&__container {
127127
display: flex;
@@ -135,8 +135,8 @@
135135
}
136136

137137
::ng-deep .mdc-button__label {
138-
white-space: nowrap;
139138
overflow: hidden;
139+
white-space: nowrap;
140140
}
141141

142142
&__label {

gravitee-apim-portal-webui-next/src/app/log-in/log-in.component.spec.ts

Lines changed: 102 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,41 @@ import { MatButtonHarness } from '@angular/material/button/testing';
2222
import { MatInputHarness } from '@angular/material/input/testing';
2323

2424
import { LogInComponent } from './log-in.component';
25-
import { AppTestingModule, TESTING_BASE_URL } from '../../testing/app-testing.module';
25+
import { IdentityProvider } from '../../entities/configuration/identity-provider';
26+
import { AuthService } from '../../services/auth.service';
27+
import { ConfigService } from '../../services/config.service';
28+
import { IdentityProviderService } from '../../services/identity-provider.service';
29+
import { AppTestingModule, ConfigServiceStub, IdentityProviderServiceStub, TESTING_BASE_URL } from '../../testing/app-testing.module';
30+
import { DivHarness } from '../../testing/div.harness';
2631

2732
describe('LogInComponent', () => {
2833
let fixture: ComponentFixture<LogInComponent>;
2934
let harnessLoader: HarnessLoader;
3035
let httpTestingController: HttpTestingController;
3136

37+
async function initComponent() {
38+
fixture = TestBed.createComponent(LogInComponent);
39+
harnessLoader = TestbedHarnessEnvironment.loader(fixture);
40+
httpTestingController = TestBed.inject(HttpTestingController);
41+
fixture.detectChanges();
42+
}
43+
44+
function enableLocalLogin(enable: boolean) {
45+
const configService = TestBed.inject(ConfigService) as unknown as ConfigServiceStub;
46+
configService.configuration.authentication!.localLogin!.enabled = enable;
47+
}
48+
49+
function initSsoProviders(providers: IdentityProvider[]) {
50+
const identityProviderService = TestBed.inject(IdentityProviderService) as unknown as IdentityProviderServiceStub;
51+
identityProviderService.providers = providers;
52+
}
53+
3254
beforeEach(async () => {
3355
await TestBed.configureTestingModule({
3456
imports: [LogInComponent, AppTestingModule],
3557
}).compileComponents();
3658

37-
fixture = TestBed.createComponent(LogInComponent);
38-
harnessLoader = TestbedHarnessEnvironment.loader(fixture);
39-
httpTestingController = TestBed.inject(HttpTestingController);
40-
fixture.detectChanges();
59+
await initComponent();
4160
});
4261

4362
afterEach(() => {
@@ -66,6 +85,7 @@ describe('LogInComponent', () => {
6685

6786
expect(await submitButton.isDisabled()).toEqual(true);
6887
});
88+
6989
it('should not validate form with missing password', async () => {
7090
const submitButton = await harnessLoader.getHarness(MatButtonHarness.with({ text: 'Log in' }));
7191

@@ -88,4 +108,81 @@ describe('LogInComponent', () => {
88108
httpTestingController.expectOne(`${TESTING_BASE_URL}/user`).flush({});
89109
httpTestingController.expectOne(`${TESTING_BASE_URL}/portal-menu-links`).flush({});
90110
});
111+
112+
it('should not display log-in form', async () => {
113+
enableLocalLogin(false);
114+
initSsoProviders([
115+
{
116+
id: 'github',
117+
name: 'GitHub',
118+
},
119+
]);
120+
121+
await initComponent();
122+
123+
const login = await harnessLoader.getHarnessOrNull(DivHarness.with({ selector: '.log-in__form' }));
124+
expect(login).toBeNull();
125+
126+
const orSeparator = await harnessLoader.getHarnessOrNull(DivHarness.with({ selector: '.log-in__sso__separator' }));
127+
expect(orSeparator).toBeNull();
128+
129+
const ssoProvider = await harnessLoader.getHarnessOrNull(MatButtonHarness.with({ selector: '.log-in__sso__idp' }));
130+
expect(ssoProvider).not.toBeNull();
131+
132+
const providerText = await ssoProvider!.getText();
133+
expect(providerText).toEqual('Continue with GitHub');
134+
});
135+
136+
it('should not display SSO providers', async () => {
137+
enableLocalLogin(true);
138+
initSsoProviders([]);
139+
140+
await initComponent();
141+
142+
const login = await harnessLoader.getHarnessOrNull(DivHarness.with({ selector: '.log-in__form' }));
143+
expect(login).not.toBeNull();
144+
145+
const orSeparator = await harnessLoader.getHarnessOrNull(DivHarness.with({ selector: '.log-in__sso__separator' }));
146+
expect(orSeparator).toBeNull();
147+
148+
const ssoProvider = await harnessLoader.getHarnessOrNull(MatButtonHarness.with({ selector: '.log-in__sso__idp' }));
149+
expect(ssoProvider).toBeNull();
150+
});
151+
152+
it('should display "or" separator and identity providers', async () => {
153+
const identityProviders = [
154+
{ id: 'github', name: 'GitHub' },
155+
{ id: 'google', name: 'Google' },
156+
{ id: 'graviteeio_am', name: 'Gravitee AM' },
157+
];
158+
enableLocalLogin(true);
159+
initSsoProviders(identityProviders);
160+
161+
await initComponent();
162+
163+
const orSeparator = await harnessLoader.getHarnessOrNull(DivHarness.with({ selector: '.log-in__sso__separator' }));
164+
expect(orSeparator).not.toBeNull();
165+
166+
const ssoProviders = await harnessLoader.getAllHarnesses(MatButtonHarness.with({ selector: '.log-in__sso__idp' }));
167+
const providerTexts = await Promise.all(ssoProviders.map(harness => harness.getText()));
168+
console.log('providerTexts', providerTexts);
169+
170+
for (const provider of identityProviders) {
171+
const found = providerTexts.find(text => text === `Continue with ${provider.name}`);
172+
expect(found).toBeDefined();
173+
}
174+
});
175+
176+
it('should redirect when clicked on SSO provider', async () => {
177+
enableLocalLogin(true);
178+
initSsoProviders([{ id: 'google', name: 'Google' }]);
179+
180+
const authenticateSSO = jest.spyOn(TestBed.inject(AuthService), 'authenticateSSO').mockReturnValue();
181+
182+
await initComponent();
183+
184+
const ssoProvider = await harnessLoader.getHarness(MatButtonHarness.with({ selector: '.log-in__sso__idp' }));
185+
await ssoProvider.click();
186+
expect(authenticateSSO).toHaveBeenCalledWith({ id: 'google', name: 'Google' }, '');
187+
});
91188
});

gravitee-apim-portal-webui-next/src/app/log-in/log-in.component.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,6 @@ export class LogInComponent implements OnInit {
9191
this.authService.authenticateSSO(provider, this.redirectUrl);
9292
}
9393

94-
getProviderColor(provider: IdentityProvider) {
95-
if (provider.type && provider.color) {
96-
return provider.color;
97-
}
98-
return '';
99-
}
100-
10194
getProviderLogo(provider: IdentityProvider) {
10295
const type = provider.type ?? IdentityProviderType.OIDC;
10396
return `${type?.toLowerCase()}.svg`;

gravitee-apim-portal-webui-next/src/app/log-in/reset-password/reset-password-confirmation/reset-password-confirmation.component.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
<mat-card appearance="outlined" class="reset-password-confirmation">
1919
@if (!isSubmitted) {
2020
<mat-card-header class="reset-password-confirmation__header">
21-
<mat-card-title class="reset-password-confirmation__title" i18n="@@resetPasswordConfirmationTitle">Reset password confirmation</mat-card-title>
21+
<mat-card-title class="reset-password-confirmation__title" i18n="@@resetPasswordConfirmationTitle"
22+
>Reset password confirmation</mat-card-title
23+
>
2224
</mat-card-header>
2325
@if (!isTokenExpired && !!resetPasswordConfirmationForm) {
2426
<mat-card-content class="reset-password-confirmation__content">

gravitee-apim-portal-webui-next/src/app/log-in/reset-password/reset-password-confirmation/reset-password-confirmation.component.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
display: flex;
2525
width: 400px;
2626
flex-flow: column;
27-
gap: 20px;
2827
background: #{theme.$background-color};
28+
gap: 20px;
2929

3030
&__header {
3131
padding: 20px 20px 0;

gravitee-apim-portal-webui-next/src/app/log-in/reset-password/reset-password.component.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
display: flex;
2525
width: 400px;
2626
flex-flow: column;
27-
gap: 20px;
2827
background: #{theme.$background-color};
28+
gap: 20px;
2929

3030
&__form {
3131
display: flex;

0 commit comments

Comments
 (0)