Skip to content

The same Angular router with types for router configuration, resolvers, components and even unit tests.

License

Notifications You must be signed in to change notification settings

smnbbrv/ngx-typed-router

Repository files navigation

ngx-typed-router

The same Angular router with types for router configuration, resolvers, components and even unit tests.

Finally, the type-safe routes with IDE hints and refactoring support.

Build Status Coverage Status

Installation

npm i ngx-typed-router

Usage

See the example application.

Router config

export const ExampleRoutes: Routes = [
  {
    path: 'test/:id',
    component: ExampleComponent,
    resolve: {
      exampleResponse: ExampleResolveService,
    } as ResolveConfig<ExampleTestRouteData>,
  },
];

export interface ExampleTestRouteQuery {
  param1: string;
}

export interface ExampleTestRoutePath {
  id: string;
}

export interface ExampleTestRouteData {
  exampleResponse: ExampleResponse;
}

Component

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.scss']
})
export class ExampleComponent {

  constructor(
    @Inject(ActivatedRoute) public route: TypedRoute<ExampleTestRouteData, ExampleTestRoutePath, ExampleTestRouteQuery>,
    // or 
    // @Inject(ActivatedRoute) public route: TypedRoute<ExampleTestRouteData>,
    // all generic types are defaulting to angular standard types
  ) { }

}

so that is typed even in your template:

<div>{{ route.snapshot.data.exampleResponse.id }}</div>
<div>{{ route.snapshot.data.exampleResponse.name }}</div>

and even in tests for this component:

class ActivatedRouteMock implements TypedRouteMock<ExampleTestRouteData, ExampleTestRoutePath, ExampleTestRouteQuery> {
  snapshot = {
    queryParams: {
      param1: 'somename',
    },
    params: {
      id: '123',
    },
    data: {
      exampleResponse: {
        id: '123',
        name: 'somename',
      },
    },
  };

  queryParams = of(this.snapshot.queryParams);
  params = of(this.snapshot.params);
  data = of(this.snapshot.data);
}

describe('ExampleComponent', () => {
  let component: ExampleComponent;
  let fixture: ComponentFixture<ExampleComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ExampleComponent],
      providers: [
        { provide: ActivatedRoute, useClass: ActivatedRouteMock }
      ],
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(ExampleComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should render two divs containing id and name', () => {
    const compiled = fixture.debugElement.nativeElement;
    expect(compiled.querySelector('div:first-child').textContent).toContain('123');
    expect(compiled.querySelector('div:last-child').textContent).toContain('somename');
  });
});

Resolver

export interface ExampleResponse {
  id: string;
  name: string;
}

export type ExampleResolveSnapshot = TypedRouteSnapshot<Partial<ExampleTestRouteData>, ExampleTestRoutePath, ExampleTestRouteQuery>;

@Injectable({
  providedIn: 'root'
})
export class ExampleResolveService implements Resolve<ExampleResponse> {

  resolve(snapshot: ExampleResolveSnapshot) {
    return {
      id: snapshot.params.id,
      name: snapshot.queryParams.param1,
    } as ExampleResponse;
  }

}

and tests for this service:

import { ExampleResolveService, ExampleResolveSnapshot } from './example-resolve.service';

describe('ExampleResolveService', () => {
  beforeEach(() => TestBed.configureTestingModule({}));

  it('should resolve the data according to provided parameters', () => {
    const service: ExampleResolveService = TestBed.get(ExampleResolveService);
    const resolved = service.resolve({
      queryParams: {
        param1: 'somename',
      },
      params: {
        id: '123',
      },
      data: {},
    } as ExampleResolveSnapshot);

    expect(resolved).toEqual({
      id: '123',
      name: 'somename',
    });
  });
});

License

MIT

About

The same Angular router with types for router configuration, resolvers, components and even unit tests.

Resources

License

Stars

Watchers

Forks

Packages

No packages published