fix: add more testsx

This commit is contained in:
master 2025-01-31 08:01:26 +08:00
parent c9d0066d64
commit 28da493462
17 changed files with 2144 additions and 128 deletions

1
.gitignore vendored
View File

@ -55,3 +55,4 @@ debug.log
/playwright-report/ /playwright-report/
/blob-report/ /blob-report/
/playwright/.cache/ /playwright/.cache/
/.vitest

View File

@ -6,7 +6,8 @@
"style": { "style": {
"noNonNullAssertion": "off", "noNonNullAssertion": "off",
"noParameterAssign": "off", "noParameterAssign": "off",
"useFilenamingConvention": "warn" "useFilenamingConvention": "warn",
"noParameterProperties": "off"
}, },
"suspicious": { "suspicious": {
"noExplicitAny": "off" "noExplicitAny": "off"
@ -21,7 +22,8 @@
} }
}, },
"nursery": { "nursery": {
"noEnum": "off" "noEnum": "off",
"useConsistentMemberAccessibility": "off"
} }
} }
}, },

View File

@ -26,14 +26,15 @@
"scripts": { "scripts": {
"build": "rslib build", "build": "rslib build",
"dev": "rslib build --watch", "dev": "rslib build --watch",
"test": "vitest --code-coverage", "test": "vitest --browser.headless",
"test-ci": "vitest --watch=false --browsers=ChromeHeadlessNoSandbox --code-coverage", "test-ci": "vitest --watch=false --browser.headless --coverage",
"pack": "npm run build && npm pack ./dist", "pack": "npm run build && npm pack ./dist",
"publish": "npm run build && npm publish ./dist", "publish": "npm run build && npm publish ./dist",
"coverage": "vitest run --coverage", "coverage": "vitest run --coverage",
"lint": "ultracite lint", "lint": "ultracite lint",
"format": "ultracite format", "format": "ultracite format",
"cli": "tsx scripts/cli.ts" "cli": "tsx scripts/cli.ts",
"test:browser": "vitest --workspace=vitest.workspace.ts"
}, },
"dependencies": { "dependencies": {
"@ngify/http": "^2.0.4", "@ngify/http": "^2.0.4",
@ -52,17 +53,21 @@
"@rslib/core": "^0.3.1", "@rslib/core": "^0.3.1",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/node": "^22.12.0", "@types/node": "^22.12.0",
"@vitest/coverage-v8": "^3.0.1", "@vitest/browser": "^3.0.4",
"@vitest/coverage-v8": "^3.0.4",
"commander": "^13.1.0", "commander": "^13.1.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"oxc-parser": "^0.48.1", "oxc-parser": "^0.48.1",
"oxc-walker": "^0.2.2", "oxc-walker": "^0.2.2",
"playwright": "^1.50.0",
"rfc4648": "^1.5.0", "rfc4648": "^1.5.0",
"rxjs": "^7.4.0", "rxjs": "^7.4.0",
"tsx": "^4.19.2", "tsx": "^4.19.2",
"typescript": "^5.7.3", "typescript": "^5.7.3",
"ultracite": "^4.1.15", "ultracite": "^4.1.15",
"vitest": "^3.0.1" "vite-tsconfig-paths": "^5.1.4",
"vitest": "^3.0.4",
"webdriverio": "^9.7.2"
}, },
"keywords": [ "keywords": [
"rxjs", "rxjs",

2089
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,5 @@
import { TestBed } from '@/testing'; import { TestBed, mockRouterProvider } from '@/testing';
import { Router } from '@angular/router'; import { AbstractRouter } from 'oidc-client-rx/router';
import { RouterTestingModule } from '@angular/router/testing';
import { vi } from 'vitest'; import { vi } from 'vitest';
import { StoragePersistenceService } from '../storage/storage-persistence.service'; import { StoragePersistenceService } from '../storage/storage-persistence.service';
import { mockProvider } from '../testing/mock'; import { mockProvider } from '../testing/mock';
@ -9,14 +8,18 @@ import { AutoLoginService } from './auto-login.service';
describe('AutoLoginService ', () => { describe('AutoLoginService ', () => {
let autoLoginService: AutoLoginService; let autoLoginService: AutoLoginService;
let storagePersistenceService: StoragePersistenceService; let storagePersistenceService: StoragePersistenceService;
let router: Router; let router: AbstractRouter;
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [RouterTestingModule], imports: [],
providers: [AutoLoginService, mockProvider(StoragePersistenceService)], providers: [
mockRouterProvider(),
AutoLoginService,
mockProvider(StoragePersistenceService),
],
}); });
router = TestBed.inject(Router); router = TestBed.inject(AbstractRouter);
autoLoginService = TestBed.inject(AutoLoginService); autoLoginService = TestBed.inject(AutoLoginService);
storagePersistenceService = TestBed.inject(StoragePersistenceService); storagePersistenceService = TestBed.inject(StoragePersistenceService);
}); });

View File

@ -1,6 +1,7 @@
import { inject, Injectable } from 'injection-js'; import { Injectable, inject } from 'injection-js';
import { Router } from '@angular/router';
import type { OpenIdConfiguration } from '../config/openid-configuration'; import type { OpenIdConfiguration } from '../config/openid-configuration';
import { injectAbstractType } from '../injection';
import { AbstractRouter } from '../router';
import { StoragePersistenceService } from '../storage/storage-persistence.service'; import { StoragePersistenceService } from '../storage/storage-persistence.service';
const STORAGE_KEY = 'redirect'; const STORAGE_KEY = 'redirect';
@ -9,7 +10,7 @@ const STORAGE_KEY = 'redirect';
export class AutoLoginService { export class AutoLoginService {
private readonly storageService = inject(StoragePersistenceService); private readonly storageService = inject(StoragePersistenceService);
private readonly router = inject(Router); private readonly router = injectAbstractType(AbstractRouter);
checkSavedRedirectRouteAndNavigate(config: OpenIdConfiguration | null): void { checkSavedRedirectRouteAndNavigate(config: OpenIdConfiguration | null): void {
if (!config) { if (!config) {

View File

@ -1,4 +1,3 @@
import { Router } from '@angular/router';
import { Injectable, inject } from 'injection-js'; import { Injectable, inject } from 'injection-js';
import { type Observable, throwError } from 'rxjs'; import { type Observable, throwError } from 'rxjs';
import { catchError, tap } from 'rxjs/operators'; import { catchError, tap } from 'rxjs/operators';
@ -6,13 +5,15 @@ import type { OpenIdConfiguration } from '../config/openid-configuration';
import type { CallbackContext } from '../flows/callback-context'; import type { CallbackContext } from '../flows/callback-context';
import { FlowsDataService } from '../flows/flows-data.service'; import { FlowsDataService } from '../flows/flows-data.service';
import { FlowsService } from '../flows/flows.service'; import { FlowsService } from '../flows/flows.service';
import { injectAbstractType } from '../injection';
import { AbstractRouter } from '../router';
import { IntervalService } from './interval.service'; import { IntervalService } from './interval.service';
@Injectable() @Injectable()
export class CodeFlowCallbackService { export class CodeFlowCallbackService {
private readonly flowsService = inject(FlowsService); private readonly flowsService = inject(FlowsService);
private readonly router = inject(Router); private readonly router = injectAbstractType(AbstractRouter);
private readonly flowsDataService = inject(FlowsDataService); private readonly flowsDataService = inject(FlowsDataService);

View File

@ -1,4 +1,3 @@
import { Router } from '@angular/router';
import { Injectable, inject } from 'injection-js'; import { Injectable, inject } from 'injection-js';
import { type Observable, throwError } from 'rxjs'; import { type Observable, throwError } from 'rxjs';
import { catchError, tap } from 'rxjs/operators'; import { catchError, tap } from 'rxjs/operators';
@ -6,13 +5,15 @@ import type { OpenIdConfiguration } from '../config/openid-configuration';
import type { CallbackContext } from '../flows/callback-context'; import type { CallbackContext } from '../flows/callback-context';
import { FlowsDataService } from '../flows/flows-data.service'; import { FlowsDataService } from '../flows/flows-data.service';
import { FlowsService } from '../flows/flows.service'; import { FlowsService } from '../flows/flows.service';
import { injectAbstractType } from '../injection';
import { AbstractRouter } from '../router';
import { IntervalService } from './interval.service'; import { IntervalService } from './interval.service';
@Injectable() @Injectable()
export class ImplicitFlowCallbackService { export class ImplicitFlowCallbackService {
private readonly flowsService = inject(FlowsService); private readonly flowsService = inject(FlowsService);
private readonly router = inject(Router); private readonly router = injectAbstractType(AbstractRouter);
private readonly flowsDataService = inject(FlowsDataService); private readonly flowsDataService = inject(FlowsDataService);

View File

@ -1,6 +1,6 @@
import { Injectable, inject } from 'injection-js'; import { Injectable, inject } from 'injection-js';
import { DOCUMENT } from '../../dom';
import type { OpenIdConfiguration } from '../config/openid-configuration'; import type { OpenIdConfiguration } from '../config/openid-configuration';
import { DOCUMENT } from '../dom';
import { LoggerService } from '../logging/logger.service'; import { LoggerService } from '../logging/logger.service';
@Injectable() @Injectable()

View File

@ -70,9 +70,8 @@ export class SilentRenewService {
config: OpenIdConfiguration, config: OpenIdConfiguration,
allConfigs: OpenIdConfiguration[] allConfigs: OpenIdConfiguration[]
): Observable<CallbackContext> { ): Observable<CallbackContext> {
const params = new HttpParams({ // TODO: fix @ngify/http
fromString: urlParts[1], const params = new HttpParams(urlParts[1] || undefined);
});
const errorParam = params.get('error'); const errorParam = params.get('error');

View File

@ -1,5 +1,4 @@
import { TestBed } from '@/testing'; import { TestBed } from '@/testing';
import { CommonModule } from '@angular/common';
import { lastValueFrom, of } from 'rxjs'; import { lastValueFrom, of } from 'rxjs';
import { vi } from 'vitest'; import { vi } from 'vitest';
import { StoragePersistenceService } from '../storage/storage-persistence.service'; import { StoragePersistenceService } from '../storage/storage-persistence.service';
@ -21,7 +20,7 @@ describe('LoginService', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [CommonModule], imports: [],
providers: [ providers: [
LoginService, LoginService,
mockProvider(ParLoginService), mockProvider(ParLoginService),

View File

@ -1,5 +1,4 @@
import { Injectable, inject } from 'injection-js'; import { Injectable, inject } from 'injection-js';
import { toSignal } from 'injection-js/rxjs-interop';
import type { Observable } from 'rxjs'; import type { Observable } from 'rxjs';
import { concatMap, map, shareReplay } from 'rxjs/operators'; import { concatMap, map, shareReplay } from 'rxjs/operators';
import type { AuthOptions, LogoutAuthOptions } from './auth-options'; import type { AuthOptions, LogoutAuthOptions } from './auth-options';
@ -62,14 +61,6 @@ export class OidcSecurityService {
return this.userService.userData$; return this.userService.userData$;
} }
/**
* Provides information about the user after they have logged in.
*
* @returns Returns an object containing either the user data directly (single config) or
* the user data per config in case you are running with multiple configs
*/
userData = toSignal(this.userData$, { requireSync: true });
/** /**
* Emits each time an authorization event occurs. * Emits each time an authorization event occurs.
* *
@ -83,17 +74,6 @@ export class OidcSecurityService {
return this.authStateService.authenticated$; return this.authStateService.authenticated$;
} }
/**
* Emits each time an authorization event occurs.
*
* @returns Returns an object containing if you are authenticated or not.
* Single Config: true if config is authenticated, false if not.
* Multiple Configs: true is all configs are authenticated, false if only one of them is not
*
* The `allConfigsAuthenticated` property contains the auth information _per config_.
*/
authenticated = toSignal(this.isAuthenticated$, { requireSync: true });
/** /**
* Emits each time the server sends a CheckSession event and the value changed. This property will always return * Emits each time the server sends a CheckSession event and the value changed. This property will always return
* true. * true.

View File

@ -10,22 +10,28 @@ export interface RouterStateSnapshot {
url: string; url: string;
} }
export interface UrlTree {
toString(): string;
}
export interface NavigationExtras {
[key: string]: any;
}
export interface Navigation {
id: number;
initialUrl: UrlTree;
extractedUrl: UrlTree;
finalUrl?: UrlTree | undefined;
trigger: 'imperative' | 'popstate' | 'hashchange';
previousNavigation: Navigation | null;
extras?: NavigationExtras;
}
export abstract class AbstractRouter { export abstract class AbstractRouter {
navigateByUrl(_url: string): void { abstract navigateByUrl(url: string): void;
// TODO
// Implementation of navigating to a URL
}
getCurrentNavigation(): any { abstract getCurrentNavigation(): Navigation;
// TODO
// Implementation of getting the current navigation
return null;
}
// TODO abstract parseUrl(_url: string): any;
parseUrl(_url: string): any {
// TODO
// Implementation of getting the current navigation
return null;
}
} }

View File

@ -1,8 +1,34 @@
import type { Provider } from 'injection-js'; import type { Provider } from 'injection-js';
import { AbstractRouter } from 'oidc-client-rx'; import { AbstractRouter, type Navigation, type UrlTree } from 'oidc-client-rx';
// TODO export class MockRouter extends AbstractRouter {
export class MockRouter extends AbstractRouter {} navigation: Navigation = {
id: 1,
extras: {},
initialUrl: new URL('https://localhost/'),
extractedUrl: new URL('https://localhost/'),
trigger: 'imperative',
previousNavigation: null,
};
navigateByUrl(url: string): void {
const prevNavigation = this.navigation;
this.navigation = {
id: prevNavigation.id + 1,
extras: {},
initialUrl: prevNavigation.initialUrl,
extractedUrl: new URL(url),
trigger: prevNavigation.trigger,
previousNavigation: prevNavigation,
};
}
getCurrentNavigation(): Navigation {
return this.navigation;
}
parseUrl(url: string): UrlTree {
return new URL(url);
}
}
export function mockRouterProvider(): Provider { export function mockRouterProvider(): Provider {
return { return {

View File

@ -1,6 +1,5 @@
import { TestBed } from '@/testing'; import { TestBed } from '@/testing';
import { PLATFORM_ID } from '@angular/core'; import { PLATFORM_ID, PlatformProvider } from './platform.provider';
import { PlatformProvider } from './platform.provider';
describe('PlatformProvider Tests', () => { describe('PlatformProvider Tests', () => {
it('should create', () => { it('should create', () => {

View File

@ -873,7 +873,8 @@ export class UrlService {
private createHttpParams(existingParams?: string): HttpParams { private createHttpParams(existingParams?: string): HttpParams {
existingParams = existingParams ?? ''; existingParams = existingParams ?? '';
return new HttpParams(existingParams, { // @TODO @ngify/http
return new HttpParams(existingParams || undefined, {
encoder: new UriEncoder(), encoder: new UriEncoder(),
}); });
} }

17
vitest.config.ts Normal file
View File

@ -0,0 +1,17 @@
import tsconfigPaths from 'vite-tsconfig-paths';
import { defineConfig } from 'vitest/config';
export default defineConfig({
cacheDir: '.vitest',
test: {
include: ['src/**/*.spec.ts', 'tests-examples'],
globals: true,
browser: {
provider: 'playwright', // or 'webdriverio'
enabled: true,
// at least one instance is required
instances: [{ browser: 'chromium' }],
},
},
plugins: [tsconfigPaths({})],
});