Files
marketplaces/src/app/components/header/header.component.spec.ts
sdarbinyan 14c72d1a6a feat: extract auth into @marketplaces/auth package, add backoffice admin provisioning spec
- 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>
2026-08-18 01:05:16 +04:00

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();
});
});