mirror of
https://github.com/block-core/angor-hub-old.git
synced 2025-12-17 01:44:19 +01:00
Replace custom Webpack builder with Angular DevKit builder, remove webpack.config.js, and add LoginComponent unit tests
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-builders/custom-webpack:browser",
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist",
|
||||
"index": "src/index.html",
|
||||
@@ -89,7 +89,7 @@
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-builders/custom-webpack:dev-server",
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "angor:build:production"
|
||||
@@ -101,10 +101,10 @@
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-builders/custom-webpack:extract-i18n"
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-builders/custom-webpack:karma",
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"polyfills": ["zone.js", "zone.js/testing"],
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
|
||||
2926
package-lock.json
generated
2926
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -26,10 +26,10 @@
|
||||
class="mt-8"
|
||||
[appearance]="'outline'"
|
||||
[showIcon]="false"
|
||||
[type]="secAlert.type"
|
||||
[@shake]="secAlert.type === 'error'"
|
||||
[type]="secAlert().type"
|
||||
[@shake]="secAlert().type === 'error'"
|
||||
>
|
||||
{{ secAlert.message }}
|
||||
{{ secAlert().message }}
|
||||
</angor-alert>
|
||||
|
||||
|
||||
@@ -154,10 +154,10 @@
|
||||
class="mt-8"
|
||||
[appearance]="'outline'"
|
||||
[showIcon]="false"
|
||||
[type]="menemonicAlert.type"
|
||||
[@shake]="menemonicAlert.type === 'error'"
|
||||
[type]="menemonicAlert().type"
|
||||
[@shake]="menemonicAlert().type === 'error'"
|
||||
>
|
||||
{{ menemonicAlert.message }}
|
||||
{{ menemonicAlert().message }}
|
||||
</angor-alert>
|
||||
<!-- Login form with Menemonic -->
|
||||
<form
|
||||
|
||||
109
src/app/components/auth/login/login.component.spec.ts
Normal file
109
src/app/components/auth/login/login.component.spec.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { LoginComponent } from './login.component';
|
||||
import { Router } from '@angular/router';
|
||||
import { SignerService } from 'app/services/signer.service';
|
||||
import { StateService } from 'app/services/state.service';
|
||||
import { NostrLoginService } from 'app/services/nostr-login.service';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { of, throwError } from 'rxjs';
|
||||
|
||||
describe('LoginComponent', () => {
|
||||
let component: LoginComponent;
|
||||
let fixture: ComponentFixture<LoginComponent>;
|
||||
let mockRouter: jasmine.SpyObj<Router>;
|
||||
let mockSignerService: jasmine.SpyObj<SignerService>;
|
||||
let mockStateService: jasmine.SpyObj<StateService>;
|
||||
let mockNostrLoginService: jasmine.SpyObj<NostrLoginService>;
|
||||
|
||||
beforeEach(async () => {
|
||||
mockRouter = jasmine.createSpyObj('Router', ['navigateByUrl']);
|
||||
mockSignerService = jasmine.createSpyObj('SignerService', ['handleLoginWithKey', 'handleLoginWithMnemonic', 'handleLoginWithExtension', 'getPublicKey', 'setPublicKey']);
|
||||
mockStateService = jasmine.createSpyObj('StateService', ['loadUserProfile']);
|
||||
mockNostrLoginService = jasmine.createSpyObj('NostrLoginService', ['getPublicKeyObservable', 'launchLoginScreen', 'launchSignupScreen']);
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [LoginComponent],
|
||||
imports: [ReactiveFormsModule],
|
||||
providers: [
|
||||
{ provide: Router, useValue: mockRouter },
|
||||
{ provide: SignerService, useValue: mockSignerService },
|
||||
{ provide: StateService, useValue: mockStateService },
|
||||
{ provide: NostrLoginService, useValue: mockNostrLoginService },
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LoginComponent);
|
||||
component = fixture.componentInstance;
|
||||
mockNostrLoginService.getPublicKeyObservable.and.returnValue(of('mockPublicKey'));
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should initialize forms on init', () => {
|
||||
expect(component.SecretKeyLoginForm).toBeDefined();
|
||||
expect(component.MenemonicLoginForm).toBeDefined();
|
||||
});
|
||||
|
||||
it('should handle login with secret key', () => {
|
||||
component.SecretKeyLoginForm.setValue({ secretKey: 'mockSecretKey', password: 'mockPassword' });
|
||||
mockSignerService.handleLoginWithKey.and.returnValue(true);
|
||||
|
||||
component.loginWithSecretKey();
|
||||
|
||||
expect(mockSignerService.handleLoginWithKey).toHaveBeenCalledWith('mockSecretKey', 'mockPassword');
|
||||
expect(mockRouter.navigateByUrl).toHaveBeenCalledWith('/home');
|
||||
});
|
||||
|
||||
it('should handle login with mnemonic', () => {
|
||||
component.MenemonicLoginForm.setValue({ menemonic: 'mockMnemonic', passphrase: 'mockPassphrase', password: 'mockPassword' });
|
||||
mockSignerService.handleLoginWithMnemonic.and.returnValue(true);
|
||||
|
||||
component.loginWithMenemonic();
|
||||
|
||||
expect(mockSignerService.handleLoginWithMnemonic).toHaveBeenCalledWith('mockMnemonic', 'mockPassphrase', 'mockPassword');
|
||||
expect(mockRouter.navigateByUrl).toHaveBeenCalledWith('/home');
|
||||
});
|
||||
|
||||
it('should handle login with Nostr extension', async () => {
|
||||
mockSignerService.handleLoginWithExtension.and.returnValue(Promise.resolve(true));
|
||||
|
||||
await component.loginWithNostrExtension();
|
||||
|
||||
expect(mockSignerService.handleLoginWithExtension).toHaveBeenCalled();
|
||||
expect(mockRouter.navigateByUrl).toHaveBeenCalledWith('/home');
|
||||
});
|
||||
|
||||
it('should handle login failure with secret key', () => {
|
||||
component.SecretKeyLoginForm.setValue({ secretKey: 'mockSecretKey', password: 'mockPassword' });
|
||||
mockSignerService.handleLoginWithKey.and.returnValue(false);
|
||||
|
||||
component.loginWithSecretKey();
|
||||
|
||||
expect(component.loading()).toBeFalse();
|
||||
expect(component.showSecAlert()).toBeTrue();
|
||||
});
|
||||
|
||||
it('should handle login failure with mnemonic', () => {
|
||||
component.MenemonicLoginForm.setValue({ menemonic: 'mockMnemonic', passphrase: 'mockPassphrase', password: 'mockPassword' });
|
||||
mockSignerService.handleLoginWithMnemonic.and.returnValue(false);
|
||||
|
||||
component.loginWithMenemonic();
|
||||
|
||||
expect(component.loading()).toBeFalse();
|
||||
expect(component.showMenemonicAlert()).toBeTrue();
|
||||
});
|
||||
|
||||
it('should handle error during login with Nostr extension', async () => {
|
||||
mockSignerService.handleLoginWithExtension.and.returnValue(Promise.reject('error'));
|
||||
|
||||
await component.loginWithNostrExtension();
|
||||
|
||||
expect(component.loading()).toBeFalse();
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AngorAlertComponent, AngorAlertType } from '@angor/components/alert';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, inject, signal } from '@angular/core';
|
||||
import {
|
||||
FormBuilder,
|
||||
FormGroup,
|
||||
@@ -40,37 +40,33 @@ import { Subscription } from 'rxjs';
|
||||
export class LoginComponent implements OnInit {
|
||||
SecretKeyLoginForm: FormGroup;
|
||||
MenemonicLoginForm: FormGroup;
|
||||
secAlert = { type: 'error' as AngorAlertType, message: '' };
|
||||
showSecAlert = false;
|
||||
secAlert = signal({ type: 'error' as AngorAlertType, message: '' });
|
||||
showSecAlert = signal(false);
|
||||
|
||||
menemonicAlert = { type: 'error' as AngorAlertType, message: '' };
|
||||
showMenemonicAlert = false;
|
||||
menemonicAlert = signal({ type: 'error' as AngorAlertType, message: '' });
|
||||
showMenemonicAlert = signal(false);
|
||||
|
||||
loading = false;
|
||||
isInstalledExtension = false;
|
||||
loading = signal(false);
|
||||
isInstalledExtension = signal(false);
|
||||
privateKey: Uint8Array = new Uint8Array();
|
||||
publicKey: string = '';
|
||||
npub: string = '';
|
||||
nsec: string = '';
|
||||
|
||||
useNostrLogin = true;
|
||||
publicKey = signal('');
|
||||
npub = signal('');
|
||||
nsec = signal('');
|
||||
|
||||
useNostrLogin = signal(true);
|
||||
|
||||
private subscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private _formBuilder: FormBuilder,
|
||||
private _router: Router,
|
||||
private _signerService: SignerService,
|
||||
private _stateService: StateService,
|
||||
private _nostrLoginService: NostrLoginService
|
||||
) { }
|
||||
|
||||
private _formBuilder = inject(FormBuilder);
|
||||
private _router = inject(Router);
|
||||
private _signerService = inject(SignerService);
|
||||
private _stateService = inject(StateService);
|
||||
private _nostrLoginService = inject(NostrLoginService);
|
||||
|
||||
ngOnInit(): void {
|
||||
this.subscription = this._nostrLoginService.getPublicKeyObservable().subscribe({
|
||||
next: (pubkey: string) => {
|
||||
this.publicKey = pubkey;
|
||||
this.publicKey.set(pubkey);
|
||||
this._signerService.setPublicKey(pubkey);
|
||||
this.initializeAppState();
|
||||
this._router.navigateByUrl('/home');
|
||||
@@ -106,7 +102,7 @@ export class LoginComponent implements OnInit {
|
||||
|
||||
this.MenemonicLoginForm = this._formBuilder.group({
|
||||
menemonic: ['', [Validators.required, Validators.minLength(3)]],
|
||||
passphrase: [''],
|
||||
passphrase: [''],
|
||||
password: [''],
|
||||
});
|
||||
}
|
||||
@@ -120,9 +116,9 @@ export class LoginComponent implements OnInit {
|
||||
globalContext.nostr &&
|
||||
typeof globalContext.nostr.signEvent === 'function'
|
||||
) {
|
||||
this.isInstalledExtension = true;
|
||||
this.isInstalledExtension.set(true);
|
||||
} else {
|
||||
this.isInstalledExtension = false;
|
||||
this.isInstalledExtension.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,8 +130,8 @@ export class LoginComponent implements OnInit {
|
||||
const secretKey = this.SecretKeyLoginForm.get('secretKey')?.value;
|
||||
const password = this.SecretKeyLoginForm.get('password')?.value;
|
||||
|
||||
this.loading = true;
|
||||
this.showSecAlert = false;
|
||||
this.loading.set(true);
|
||||
this.showSecAlert.set(false);
|
||||
|
||||
try {
|
||||
const success = this._signerService.handleLoginWithKey(
|
||||
@@ -152,12 +148,9 @@ export class LoginComponent implements OnInit {
|
||||
}
|
||||
} catch (error) {
|
||||
// Handle login failure
|
||||
this.loading = false;
|
||||
this.secAlert.message =
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: 'An unexpected error occurred.';
|
||||
this.showSecAlert = true;
|
||||
this.loading.set(false);
|
||||
this.secAlert.update(alert => ({ ...alert, message: error instanceof Error ? error.message : 'An unexpected error occurred.' }));
|
||||
this.showSecAlert.set(true);
|
||||
console.error('Login error: ', error);
|
||||
}
|
||||
}
|
||||
@@ -172,8 +165,8 @@ export class LoginComponent implements OnInit {
|
||||
this.MenemonicLoginForm.get('passphrase')?.value || ''; // Optional passphrase
|
||||
const password = this.MenemonicLoginForm.get('password')?.value;
|
||||
|
||||
this.loading = true;
|
||||
this.showMenemonicAlert = false;
|
||||
this.loading.set(true);
|
||||
this.showMenemonicAlert.set(false);
|
||||
|
||||
const success = this._signerService.handleLoginWithMnemonic(
|
||||
menemonic,
|
||||
@@ -185,9 +178,9 @@ export class LoginComponent implements OnInit {
|
||||
this.initializeAppState();
|
||||
this._router.navigateByUrl('/home');
|
||||
} else {
|
||||
this.loading = false;
|
||||
this.menemonicAlert.message = 'Menemonic is missing or invalid.';
|
||||
this.showMenemonicAlert = true;
|
||||
this.loading.set(false);
|
||||
this.menemonicAlert.update(alert => ({ ...alert, message: 'Menemonic is missing or invalid.' }));
|
||||
this.showMenemonicAlert.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
const webpack = require('webpack');
|
||||
|
||||
module.exports = {
|
||||
resolve: {
|
||||
fallback: {
|
||||
crypto: require.resolve('crypto-browserify'),
|
||||
stream: require.resolve('stream-browserify'),
|
||||
// url: require.resolve('url/'),
|
||||
url: false,
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin({
|
||||
process: 'process/browser',
|
||||
}),
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
/node:crypto/,
|
||||
require.resolve('crypto-browserify')
|
||||
),
|
||||
new webpack.DefinePlugin({
|
||||
global: 'globalThis',
|
||||
}),
|
||||
],
|
||||
};
|
||||
Reference in New Issue
Block a user