- ADR-0001: decision to extract auth/payment into shared @marketplaces/* packages - Scaffold packages/auth, packages/payment; @marketplaces/auth now holds the real telegram (customer+admin QR/session) and ed25519 (future admin challenge/response) auth implementation, pushed to sources.vitanova.network/sdarbinyan/vitanovaPackages - Rewire ~30 call sites to import from @marketplaces/auth; delete migrated originals from core/auth, core/admin-auth, services/, models/ - Replace environment coupling with AUTH_API_URL/TELEGRAM_BOT_USERNAME injection tokens and isDevMode(); wired as file:packages/auth pending registry publish - Add TRACK-S §8: bootstrap per-marketplace admin login + marketplace-scoped sub-admin invite/role endpoints - Build, arch:check:boundaries, and full test suite (103/103) all green Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
88 lines
4.5 KiB
TypeScript
88 lines
4.5 KiB
TypeScript
import { TestBed } from '@angular/core/testing';
|
|
import { provideRouter } from '@angular/router';
|
|
import { provideHttpClient } from '@angular/common/http';
|
|
import { provideHttpClientTesting } from '@angular/common/http/testing';
|
|
import { of } from 'rxjs';
|
|
import { BootstrapConfig } from '../../shared/models/config';
|
|
import { CONFIG_PROVIDER } from '../../core/config/config-provider.token';
|
|
import { ConfigService } from '../../core/config/config.service';
|
|
import { AuthService, AUTH_API_URL } from '@marketplaces/auth';
|
|
import { HeaderComponent } from './header.component';
|
|
|
|
function makeBootstrap(): BootstrapConfig {
|
|
return {
|
|
schemaVersion: '1', generatedAt: new Date().toISOString(),
|
|
tenant: { id: 't1', slug: 't1', code: 't1', host: 'dexar.market', name: 'Dexar', websiteBaseUrl: 'https://dexar.market', builderBaseUrl: 'https://dexar.market', backofficeBaseUrl: 'https://dexar.market', defaultLocale: 'en', supportedLocales: ['en'], defaultCurrency: 'USD', supportedCurrencies: ['USD'], timezone: 'UTC' },
|
|
branding: { brandName: 'Dexar', legalName: 'Dexar LLC', logoUrl: 'logo.png', faviconUrl: 'favicon.png' },
|
|
theme: { themeId: 'default', mode: 'light', palette: {} as any, typography: {} as any, spacing: {} as any, borderRadiusScale: {}, shadows: {}, iconSet: 'default' },
|
|
company: { companyName: 'Dexar LLC', address: { country: 'US', city: 'NY' }, contacts: { email: 'sales@dexar.market' } },
|
|
featureFlags: {} as any,
|
|
apiEndpoints: {} as any,
|
|
localization: { defaultLocale: 'en', supportedLocales: ['en'], currencyByLocale: {}, dictionaries: [] },
|
|
seo: { default: { title: 'Dexar', description: 'Dexar' }, byPageKey: {} },
|
|
permissions: { definitions: [], roles: [] },
|
|
header: { showLogo: true, showSearch: true, showCategories: true, showLanguages: true, showCart: true, showProfile: true, showWishlist: true, showCompare: true, showRegion: true, sticky: true, layout: 'default' },
|
|
navigation: { header: [], footer: [] },
|
|
pages: [],
|
|
} as unknown as BootstrapConfig;
|
|
}
|
|
|
|
describe('HeaderComponent profile control (login/logout gating regression)', () => {
|
|
function configure(isAuthenticated: boolean): void {
|
|
// Full fake - TelegramLoginComponent (rendered inside the profile control) reads
|
|
// several signals/methods off AuthService directly, not just isAuthenticated.
|
|
const fakeAuth = {
|
|
session: () => null,
|
|
status: () => (isAuthenticated ? 'authenticated' : 'unauthenticated'),
|
|
isAuthenticated: () => isAuthenticated,
|
|
showLoginDialog: () => false,
|
|
displayName: () => null,
|
|
requestLogin: jasmine.createSpy('requestLogin'),
|
|
logout: jasmine.createSpy('logout'),
|
|
hideLogin: jasmine.createSpy('hideLogin'),
|
|
createWebSession: () => of({ webSessionID: 'x', botLoginUrl: '' }),
|
|
checkSessionOnce: () => of(null),
|
|
getTelegramAppLoginUrl: () => '',
|
|
onTelegramLoginComplete: jasmine.createSpy('onTelegramLoginComplete'),
|
|
};
|
|
|
|
TestBed.configureTestingModule({
|
|
providers: [
|
|
provideRouter([]),
|
|
provideHttpClient(),
|
|
provideHttpClientTesting(),
|
|
{ provide: CONFIG_PROVIDER, useValue: { loadBootstrap: () => of(makeBootstrap()) } },
|
|
{ provide: AUTH_API_URL, useValue: 'https://test.local' },
|
|
{ provide: AuthService, useValue: fakeAuth },
|
|
],
|
|
});
|
|
|
|
// Deterministically prime the bootstrap snapshot before component creation -
|
|
// resolveHeaderConfig() reads getBootstrapSnapshot() synchronously and falls
|
|
// back to DEFAULT_HEADER_CONFIG (showProfile: false) if it isn't populated yet.
|
|
TestBed.inject(ConfigService).loadBootstrap().subscribe();
|
|
}
|
|
|
|
it('shows a login button (not logout) when logged out', () => {
|
|
configure(false);
|
|
const fixture = TestBed.createComponent(HeaderComponent);
|
|
fixture.detectChanges();
|
|
|
|
// Aria-labels render translated text (Russian by default), so assert on the
|
|
// icon name attribute instead - stable regardless of active language.
|
|
const compiled = fixture.nativeElement as HTMLElement;
|
|
expect(compiled.querySelector('app-icon[name="user"]')).toBeTruthy();
|
|
expect(compiled.querySelector('app-icon[name="logOut"]')).toBeFalsy();
|
|
});
|
|
|
|
it('shows a logout button (not login) when logged in - never both', () => {
|
|
configure(true);
|
|
const fixture = TestBed.createComponent(HeaderComponent);
|
|
fixture.detectChanges();
|
|
|
|
const compiled = fixture.nativeElement as HTMLElement;
|
|
expect(compiled.querySelector('app-icon[name="logOut"]')).toBeTruthy();
|
|
expect(compiled.querySelector('app-icon[name="user"]')).toBeFalsy();
|
|
});
|
|
});
|