Skip to content

Commit

Permalink
feat: support passing template in factory (#299) (#311)
Browse files Browse the repository at this point in the history
  • Loading branch information
kremerd committed May 24, 2020
1 parent 5bed723 commit 5135fab
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 8 deletions.
19 changes: 19 additions & 0 deletions docs/docs/testing-directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,22 @@ describe('HighlightDirective', () => {
});
});
```

### Setting factory defaults

It is also possible to set a default template when creating the factory. Here is an example:

```ts
describe('DirectiveProviderDirective', () => {
const createDirective = createDirectiveFactory({
directive: HighlightDirective,
template: `<div class="default" directiveProvider>Testing Directive Providers</div>`
});

it('should get the instance', () => {
const spectator = createDirective();
const instance = spectator.directive;
expect(instance).toBeDefined();
});
});
```
27 changes: 27 additions & 0 deletions docs/docs/testing-pipes.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,33 @@ The `createPipe()` function returns `SpectatorPipe` with the following propertie
- `detectChanges()` - A proxy for Angular `TestBed.fixture.detectChanges()`
- `inject()` - A proxy for Angular `TestBed.inject()`

### Setting factory defaults

It is possible to set a default template when creating the factory. Here is an example:

```ts
import { SpectatorPipe, createPipeFactory } from '@ngneat/spectator';

import { AlternatingSumPipe } from './alternating-sum.pipe';

describe('AlternatingSumPipe', () => {
let spectator: SpectatorPipe<AlternatingSumPipe>;
const createPipe = createPipeFactory({
pipe: AlternatingSumPipe,
template: `{{ prop | alternatingSum }}`
});

it('should compute the alternating sum of a given list of numbers (prop)', () => {
spectator = createPipe({
hostProps: {
prop: [1, 2, 3]
}
});
expect(spectator.element).toHaveText('2');
});
});
```

### Using Custom Host Component

The following example illustrates how to test a pipe using a custom host component:
Expand Down
24 changes: 24 additions & 0 deletions docs/docs/testing-with-host.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,30 @@ The host method returns an instance of `SpectatorHost` which extends `Spectator`
- `queryHost` - Read more about [querying](./queries) in Spectator
- `queryHostAll` - Read more about [querying](./queries) in Spectator

### Setting factory defaults

It is possible to set a default template when creating the factory. Here is an example:

```ts
describe('With default template', () => {
let spectator: SpectatorWithHost<ZippyComponent>;

const createHost = createHostFactory({
component: ZippyComponent,
template: `<zippy [title]="title"></zippy>`
});

it('should display the title from host property', () => {
spectator = createHost(undefined, {
hostProps: {
title: 'Spectator is Awesome'
}
});
expect(spectator.query('.zippy__title')).toHaveText('Spectator is Awesome');
});
});
```

### Custom Host Component
Sometimes it's helpful to pass your own host implementation. We can pass a custom host component to the `createHostComponentFactory()` that will replace the default one:

Expand Down
17 changes: 17 additions & 0 deletions projects/spectator/jest/src/lib/spectator-directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,23 @@ export type SpectatorDirectiveFactory<D, H = HostComponent> = <HP>(
/**
* @publicApi
*/
export type PresetSpectatorDirectiveFactory<D, H> = <HP>(
template?: string,
overrides?: SpectatorDirectiveOverrides<D, H, HP>
) => SpectatorDirective<D, H & HostComponent extends H ? HP : unknown>;

/**
* @publicApi
*/
export function createDirectiveFactory<D, H = HostComponent>(
options: SpectatorDirectiveOptions<D, H> & { template: string }
): PresetSpectatorDirectiveFactory<D, H>;
/**
* @publicApi
*/
export function createDirectiveFactory<D, H = HostComponent>(
typeOrOptions: Type<D> | SpectatorDirectiveOptions<D, H>
): SpectatorDirectiveFactory<D, H>;
export function createDirectiveFactory<D, H = HostComponent>(
typeOrOptions: Type<D> | SpectatorDirectiveOptions<D, H>
): SpectatorDirectiveFactory<D, H> {
Expand Down
15 changes: 15 additions & 0 deletions projects/spectator/jest/src/lib/spectator-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ export type SpectatorHostFactory<C, H> = <HP>(
overrides?: SpectatorHostOverrides<C, H, HP>
) => SpectatorHost<C, H & HostComponent extends H ? HP : unknown>;

/**
* @publicApi
*/
export type PresetSpectatorHostFactory<C, H> = <HP>(
template?: string,
overrides?: SpectatorHostOverrides<C, H, HP>
) => SpectatorHost<C, H & (HostComponent extends H ? HP : unknown)>;

/**
* @deprecated Use createHostFactory instead. To be removed in v5.
*/
Expand All @@ -53,6 +61,13 @@ export function createHostComponentFactory<C, H = HostComponent>(
/**
* @publicApi
*/
export function createHostFactory<C, H = HostComponent>(
options: SpectatorHostOptions<C, H> & { template: string }
): PresetSpectatorHostFactory<C, H>;
/**
* @publicApi
*/
export function createHostFactory<C, H = HostComponent>(typeOrOptions: Type<C> | SpectatorHostOptions<C, H>): SpectatorHostFactory<C, H>;
export function createHostFactory<C, H = HostComponent>(typeOrOptions: Type<C> | SpectatorHostOptions<C, H>): SpectatorHostFactory<C, H> {
return baseCreateHostFactory({
mockProvider,
Expand Down
21 changes: 19 additions & 2 deletions projects/spectator/src/lib/spectator-directive/create-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ export type SpectatorDirectiveFactory<D, H> = <HP>(
overrides?: SpectatorDirectiveOverrides<D, H, HP>
) => SpectatorDirective<D, H & (HostComponent extends H ? HP : unknown)>;

/**
* @publicApi
*/
export type PresetSpectatorDirectiveFactory<D, H> = <HP>(
template?: string,
overrides?: SpectatorDirectiveOverrides<D, H, HP>
) => SpectatorDirective<D, H & (HostComponent extends H ? HP : unknown)>;

/**
* @publicApi
*/
Expand All @@ -35,6 +43,15 @@ export interface SpectatorDirectiveOverrides<D, H, HP> extends BaseSpectatorOver
/**
* @publicApi
*/
export function createDirectiveFactory<D, H = HostComponent>(
options: SpectatorDirectiveOptions<D, H> & { template: string }
): PresetSpectatorDirectiveFactory<D, H>;
/**
* @publicApi
*/
export function createDirectiveFactory<D, H = HostComponent>(
typeOrOptions: Type<D> | SpectatorDirectiveOptions<D, H>
): SpectatorDirectiveFactory<D, H>;
export function createDirectiveFactory<D, H = HostComponent>(
typeOrOptions: Type<D> | SpectatorDirectiveOptions<D, H>
): SpectatorDirectiveFactory<D, H> {
Expand All @@ -49,7 +66,7 @@ export function createDirectiveFactory<D, H = HostComponent>(
TestBed.configureTestingModule(moduleMetadata);
}));

return <HP>(template: string, overrides?: SpectatorDirectiveOverrides<D, H, HP>) => {
return <HP>(template?: string, overrides?: SpectatorDirectiveOverrides<D, H, HP>) => {
const defaults: SpectatorDirectiveOverrides<D, H, HP> = {
props: {},
hostProps: {} as any,
Expand All @@ -69,7 +86,7 @@ export function createDirectiveFactory<D, H = HostComponent>(
entryComponents: moduleMetadata.entryComponents
}
}).overrideComponent(options.host, {
set: { template }
set: { template: template || options.template }
});

if (options.directiveProviders.length || options.directiveMocks.length) {
Expand Down
19 changes: 17 additions & 2 deletions projects/spectator/src/lib/spectator-host/create-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ export type SpectatorHostFactory<C, H> = <HP>(
overrides?: SpectatorHostOverrides<C, H, HP>
) => SpectatorHost<C, H & (HostComponent extends H ? HP : unknown)>;

/**
* @publicApi
*/
export type PresetSpectatorHostFactory<C, H> = <HP>(
template?: string,
overrides?: SpectatorHostOverrides<C, H, HP>
) => SpectatorHost<C, H & (HostComponent extends H ? HP : unknown)>;

/**
* @publicApi
*/
Expand All @@ -41,6 +49,13 @@ export function createHostComponentFactory<C, H = HostComponent>(
/**
* @publicApi
*/
export function createHostFactory<C, H = HostComponent>(
options: SpectatorHostOptions<C, H> & { template: string }
): PresetSpectatorHostFactory<C, H>;
/**
* @publicApi
*/
export function createHostFactory<C, H = HostComponent>(typeOrOptions: Type<C> | SpectatorHostOptions<C, H>): SpectatorHostFactory<C, H>;
export function createHostFactory<C, H = HostComponent>(typeOrOptions: Type<C> | SpectatorHostOptions<C, H>): SpectatorHostFactory<C, H> {
const options = isType(typeOrOptions)
? getSpectatorHostDefaultOptions<C, H>({ component: typeOrOptions })
Expand All @@ -55,7 +70,7 @@ export function createHostFactory<C, H = HostComponent>(typeOrOptions: Type<C> |
overrideComponentIfProviderOverridesSpecified(options);
}));

return <HP>(template: string, overrides?: SpectatorHostOverrides<C, H, HP>) => {
return <HP>(template?: string, overrides?: SpectatorHostOverrides<C, H, HP>) => {
const defaults: SpectatorHostOverrides<C, H, HP> = { props: {}, hostProps: {} as any, detectChanges: true, providers: [] };
const { detectChanges, props, hostProps, providers } = { ...defaults, ...overrides };

Expand All @@ -70,7 +85,7 @@ export function createHostFactory<C, H = HostComponent>(typeOrOptions: Type<C> |
entryComponents: moduleMetadata.entryComponents
}
}).overrideComponent(options.host, {
set: { template }
set: { template: template || options.template }
});

const spectator = createSpectatorHost(options, props, hostProps);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function createPipeFactory<P, H = HostComponent>(typeOrOptions: Type<P> |
};
const resolvedOverrides = typeof templateOrOverrides === 'object' ? templateOrOverrides : overrides;
const { detectChanges, hostProps, providers } = { ...defaults, ...resolvedOverrides };
const template = typeof templateOrOverrides === 'string' ? templateOrOverrides : undefined;
const template = typeof templateOrOverrides === 'string' ? templateOrOverrides : options.template;

if (providers && providers.length) {
providers.forEach((provider: Provider) => {
Expand Down
16 changes: 13 additions & 3 deletions projects/spectator/test/directive-providers.directive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,22 @@ describe('DirectiveProviderDirective', () => {
const createHost = createDirectiveFactory({
directive: DirectiveProviderDirective,
directiveProviders: [{ provide: directiveProviderToken, useValue: 'notTest' }],
directiveMocks: [FormBuilder]
directiveMocks: [FormBuilder],
template: `<div class="default" directiveProvider>Testing Directive Providers</div>`
});

it('should inject the provided value', () => {
host = createHost(`<div directiveProvider>Testing Directive Providers</div>`);

host = createHost();
expect(host.directive.provider).toEqual('notTest');
});

it('should use the default template by default', () => {
host = createHost();
expect('.default').toExist();
});

it('should use more specific templates if given', () => {
host = createHost(`<div class="override" directiveProvider>Testing Directive Providers</div>`);
expect('.override').toExist();
});
});
38 changes: 38 additions & 0 deletions projects/spectator/test/pipe/alternating-sum.pipe.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { SpectatorPipe, createPipeFactory } from '@ngneat/spectator';

import { StatsService } from './stats.service';
import { AlternatingSumPipe } from './alternating-sum.pipe';

describe('AlternatingSumPipe', () => {
let spectator: SpectatorPipe<AlternatingSumPipe>;
const createPipe = createPipeFactory({
pipe: AlternatingSumPipe,
template: `{{ prop | alternatingSum }}`
});

it('should compute the alternating sum of a given list of numbers (prop)', () => {
spectator = createPipe({
hostProps: {
prop: [1, 2, 3]
}
});
expect(spectator.element).toHaveText('2');
});

it('should compute the alternating sum of a given list of numbers (template override)', () => {
spectator = createPipe(`{{ [3, 4, 5] | alternatingSum }}`);
expect(spectator.element).toHaveText('4');
});

it('should delegate the computation to the service', () => {
const alternatingSum = () => 42;
const provider = { provide: StatsService, useValue: { alternatingSum } };
spectator = createPipe({
hostProps: {
prop: []
},
providers: [provider]
});
expect(spectator.element).toHaveText('42');
});
});
14 changes: 14 additions & 0 deletions projects/spectator/test/pipe/alternating-sum.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Pipe, PipeTransform } from '@angular/core';

import { StatsService } from './stats.service';

@Pipe({
name: 'alternatingSum'
})
export class AlternatingSumPipe implements PipeTransform {
constructor(private readonly statsService: StatsService) {}

public transform(value: number[]): number {
return this.statsService.alternatingSum(value);
}
}
4 changes: 4 additions & 0 deletions projects/spectator/test/pipe/stats.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { Injectable } from '@angular/core';
providedIn: 'root'
})
export class StatsService {
public alternatingSum(input: number[]): number {
return input.reduce((sum, x, i) => sum + Math.pow(-1, i) * x, 0);
}

public sum(input: number[]): number {
return input.reduce((sum, x) => sum + x, 0);
}
Expand Down
19 changes: 19 additions & 0 deletions projects/spectator/test/zippy/zippy.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,25 @@ describe('ZippyComponent', () => {
});
});

describe('ZippyComponent with default template', () => {
let host: SpectatorWithHost<ZippyComponent>;

const createHost = createHostFactory({
component: ZippyComponent,
componentProviders: [{ provide: QueryService, useValue: 'componentProviders' }],
template: `<zippy [title]="title"></zippy>`
});

it('should display the title from host property', () => {
host = createHost(undefined, {
hostProps: {
title: 'ZIPPY_DEFAULT'
}
});
expect(host.query('.zippy__title')).toHaveText('ZIPPY_DEFAULT');
});
});

@Component({ selector: 'app-custom-host', template: '' })
class CustomHostComponent {
public title = 'Custom HostComponent';
Expand Down

0 comments on commit 5135fab

Please sign in to comment.