Skip to content

Commit

Permalink
fix(core): detecting and mocking standalone directives correctly #3100
Browse files Browse the repository at this point in the history
  • Loading branch information
satanTime committed Jul 15, 2022
1 parent e432f30 commit 560b334
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 14 deletions.
13 changes: 5 additions & 8 deletions libs/ng-mocks/src/lib/mock-component/mock-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,11 @@ coreDefineProperty(ComponentMockBase, 'parameters', [

const decorateClass = (component: Type<any>, mock: Type<any>): void => {
const meta = coreReflectDirectiveResolve(component);
const template = generateTemplate(meta.queries);
const mockParams = {
exportAs: meta.exportAs,
selector: meta.selector,
standalone: meta.standalone,
template,
};
Component(decorateDeclaration(component, mock, meta, mockParams))(mock);
Component(
decorateDeclaration(component, mock, meta, {
template: generateTemplate(meta.queries),
}),
)(mock);
};

/**
Expand Down
3 changes: 1 addition & 2 deletions libs/ng-mocks/src/lib/mock-directive/mock-directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ coreDefineProperty(DirectiveMockBase, 'parameters', [

const decorateClass = (directive: Type<any>, mock: Type<any>): void => {
const meta = coreReflectDirectiveResolve(directive);
const mockParams = { exportAs: meta.exportAs, selector: meta.selector };
const options = decorateDeclaration(directive, mock, meta, mockParams);
const options = decorateDeclaration(directive, mock, meta, {});
Directive(options)(mock);
};

Expand Down
21 changes: 17 additions & 4 deletions libs/ng-mocks/src/lib/mock/decorate-declaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,23 @@ export default <T extends Component & Directive>(
hostBindings?: Array<[string, any]>;
hostListeners?: Array<[string, any, any]>;
imports?: any[];
standalone?: boolean;
},
params: T & { standalone?: boolean },
) => {
const options: T & { imports?: any[] } = { ...params };
params: T,
): Component & Directive => {
const options: T & { imports?: any[]; standalone?: boolean } = {
...params,
};

if (meta.exportAs !== undefined) {
options.exportAs = meta.exportAs;
}
if (meta.selector !== undefined) {
options.selector = meta.selector;
}
if (meta.standalone !== undefined) {
options.standalone = meta.standalone;
}

const { setControlValueAccessor, providers } = cloneProviders(source, mock, meta.providers || []);
providers.push(toExistingProvider(source, mock));
Expand All @@ -54,7 +67,7 @@ export default <T extends Component & Directive>(
options.viewProviders = viewProviders;
}

if (params.standalone && meta.imports) {
if (meta.standalone && meta.imports) {
const { imports } = mockNgDef({ imports: meta.imports })[1];
if (imports?.length) {
options.imports = imports as never;
Expand Down
61 changes: 61 additions & 0 deletions tests/issue-3100/test.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {
AfterViewInit,
Component,
Directive,
ElementRef,
Input,
VERSION,
} from '@angular/core';

import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';

@Directive(
{
selector: '[testDirective]',
standalone: true,
} as never /* TODO: remove after upgrade to a14 */,
)
class TestDirective implements AfterViewInit {
@Input() color = 'red';

constructor(private el: ElementRef) {}

ngAfterViewInit(): void {
this.el.nativeElement.style.backgroundColor = this.color;
}
}

@Component(
{
selector: 'app-target',
standalone: true,
template: `<a testDirective>name: {{ name }}</a>`,
imports: [TestDirective],
} as never /* TODO: remove after upgrade to a14 */,
)
class TargetComponent {
@Input() public readonly name: string = '';
}

// @see https://github.com/help-me-mom/ng-mocks/issues/3100
describe('issue-3100', () => {
if (Number.parseInt(VERSION.major, 10) < 14) {
it('needs a14', () => {
// pending('Need Angular > 5');
expect(true).toBeTruthy();
});

return;
}

beforeEach(() => MockBuilder(TargetComponent));

it('should do something', () => {
MockRender(TargetComponent, {
name: 'sandbox',
});

expect(() => ngMocks.findInstance(TargetComponent)).not.toThrow();
expect(() => ngMocks.findInstance(TestDirective)).not.toThrow();
});
});

0 comments on commit 560b334

Please sign in to comment.