Comments (19)
Hi @GipHub123,
thanks for reporting. I'll do my best to fix it asap. However, currently, my availability is very limited.
from ng-mocks.
First of all I have to apologise for being impatient, but this bug is a definite blocker using ng-mocks together with Angular's new control-flow syntax.
from ng-mocks.
Using the mentioned workaround in the failing cases to unblock updates should be good enough until this is resolved. I added these functions in our testing library and use them whenever ngMocks fails:
/**
* @example
* findDirective(fixture, MyComponent).valueChange.emit(123);
*/
export const findDirective = <T, D>(fixture: ComponentFixture<T>, directive: Type<D>) =>
fixture.debugElement.query(By.directive(directive)).componentInstance as D;
/**
* @example
* findDirectives(fixture, MyComponent)[0].valueChange.emit(123);
*/
export const findDirectives = <T, D>(fixture: ComponentFixture<T>, directive: Type<D>) =>
fixture.debugElement.queryAll(By.directive(directive)).map((ii) => ii.componentInstance as D);
from ng-mocks.
Hi all, all issues are in my todo, but not much time to work on the lib recently. Hopefully, in a couple of weeks, I'll be back on track and can dedicate more time on open source.
Feel free to contribute and fix some issues, open source is fun and it's always right time to join.
from ng-mocks.
v14.12.2 has been released and contains a fix for the issue. Feel free to reopen the issue or to submit a new one if you meet any problems.
from ng-mocks.
@satanTime, thank you very much. I can confirm that the issue is fixed for us as well. We highly appreciate the effort.
from ng-mocks.
No worries 😊 As I mentioned problem is quite easy to fix with a work around 👍
from ng-mocks.
Hi @GipHub123,
unfortunately, I don't see the same errors on A17 with ng-mocks
. Could you post a failing test here which I could debug?
from ng-mocks.
I have this issue with newest versions (ng 17.0.3, ng-mocks 14.11.0) in multiple component tests in multiple projects. It happens only when searched instances are dynamic in the template i.e. using @if or @for or similar. It does not happen for all of those cases though.
Example template:
@if (routes$ | async; as routes) {
<rwe-navigation [routes]="routes" (actionPayload)="$event.next()" />
}
Then spec file:
...
beforeEach(() => MockBuilder(RweActionSlotsComponent).provide({provide: RweDiActionSlots, useValue: of([slot])}));
beforeEach(() => {
fixture = MockRender(RweActionSlotsComponent);
fixture.detectChanges();
});
...
it(`binds actions`, () =>
expect(ngMocks.findInstance(RweNavigationComponent).routes).toEqual([
{cssClass: 'cssClass', disabled: true, icon: 'icon', name: 'label', tooltip: 'tooltip', payload: slot.trigger$, testId: 'test-id'},
]));
Leads to:
TypeError: Cannot read properties of null (reading 'rootNodes')
32 |
33 | it(`binds actions`, () =>
> 34 | expect(ngMocks.findInstance(RweNavigationComponent).routes).toEqual([
| ^
35 | {cssClass: 'cssClass', disabled: true, icon: 'icon', name: 'label', tooltip: 'tooltip', payload: slot.trigger$, testId: 'test-id'},
36 | ]));
37 |
at f (node_modules/ng-mocks/webpack:/ng-mocks/libs/ng-mocks/src/lib/mock-helper/crawl/el-def-get-parent.ts:53:25)
at index (node_modules/ng-mocks/webpack:/ng-mocks/libs/ng-mocks/src/lib/mock-helper/crawl/el-def-get-parent.ts:41:77)
at t.default (node_modules/ng-mocks/webpack:/ng-mocks/libs/ng-mocks/src/lib/mock-helper/crawl/el-def-get-parent.ts:57:16)
at t.default (node_modules/ng-mocks/index.js:1:131407)
at u (node_modules/ng-mocks/index.js:1:133465)
at u (node_modules/ng-mocks/index.js:1:133518)
at t.default (node_modules/ng-mocks/index.js:1:128786)
at Object.nativeNode [as findInstance] (node_modules/ng-mocks/webpack:/ng-mocks/libs/ng-mocks/src/lib/mock-helper/find-instance/mock-helper.find-instance.ts:30:53)
Currently I'm using the workaround to circumvent this.
from ng-mocks.
Ah, new syntax. That makes sense. I haven't tested it yet.
from ng-mocks.
Ah, new syntax. That makes sense. I haven't tested it yet.
Sadly the answer is no, same happens when using *ngIf
at those places.
from ng-mocks.
Hi @rlexa,
I still cannot reproduce the issue, could you post a min failing example?
This is what I use, but it doesn't fail.
import { Component, Input, NgModule } from '@angular/core';
import { AsyncSubject, Observable } from 'rxjs';
import { CommonModule } from '@angular/common';
import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';
@Component({
selector: 'target',
template: `
<child
*ngIf="routes$ | async as routes"
[routes]="routes"
></child>
`,
})
class TargetComponent {
@Input() routes$: Observable<Array<string>> | null = null;
targetComponent7216() {}
}
@Component({
selector: 'child',
template: ``,
})
class ChildComponent {
@Input() routes: Array<string> | null = null;
}
@NgModule({
imports: [CommonModule],
declarations: [TargetComponent, ChildComponent],
})
class TargetModule {}
// @see https://github.com/help-me-mom/ng-mocks/issues/7216
describe('issue-7216', () => {
beforeEach(() => MockBuilder(TargetComponent, TargetModule));
it('finds ChildComponent', () => {
const routes$ = new AsyncSubject<Array<string>>();
routes$.next(['route1']);
routes$.complete();
MockRender(TargetComponent, { routes$ });
const child = ngMocks.findInstance(ChildComponent);
expect(child.routes).toEqual(['route1']);
});
});
from ng-mocks.
I'm a bit swamped this week maybe will be able to crete a repro on the weekend, but here is more about the component in question (you can see that it's OnPush and standalone). The RweDestroy decorator can be ignored, I tried without, still fails.
@Component({
selector: 'rwe-action-slots',
template: `@if (routes$ | async; as routes) {
<rwe-navigation [routes]="routes" (actionPayload)="$event.next()" />
}`,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [CommonModule, RweNavigationComponent],
})
export class RweActionSlotsComponent {
private readonly actions$ = inject(RweDiActionSlots);
@RweDestroy() private readonly slots$ = new StateSubject<RweActionSlot[] | null>(null);
/** Overwrites `RweDiActionSlots` token with input slots. */
@Input() set slots(val: RweActionSlot[] | null | undefined) {
this.slots$.next(val ?? null);
}
readonly routes$ = combineLatest([this.slots$, this.actions$]).pipe( /* complex flow but should not be relevant */);
}
and this is the relevant part of spec file (so .provide is used and also the runtime is jest):
import {ComponentFixture} from '@angular/core/testing';
import {MockBuilder, MockRender, ngMocks} from 'ng-mocks';
import {of} from 'rxjs';
import {RweNavigationComponent} from '../rwe-navigation/rwe-navigation.component';
import {RweActionSlot, RweDiActionSlots} from './rwe-action-slot';
import {RweActionSlotsComponent} from './rwe-action-slots.component';
describe('RweActionSlotsComponent', () => {
let fixture: ComponentFixture<RweActionSlotsComponent>;
const slot: RweActionSlot = {
cssClass: of('cssClass'),
disabled$: of(true),
icon: 'icon',
label: of('label'),
trigger$: {next: jest.fn()} as any,
tooltip: 'tooltip',
testId: 'test-id',
};
beforeEach(() => MockBuilder(RweActionSlotsComponent).provide({provide: RweDiActionSlots, useValue: of([slot])}));
beforeEach(() => {
fixture = MockRender(RweActionSlotsComponent);
fixture.detectChanges();
});
it(`creates instance`, () => expect(fixture.componentInstance).toBeTruthy());
it(`renders`, () => expect(fixture).toMatchSnapshot());
it(`binds actions`, () =>
expect(ngMocks.findInstance(RweNavigationComponent).routes).toEqual([
{cssClass: 'cssClass', disabled: true, icon: 'icon', name: 'label', tooltip: 'tooltip', payload: slot.trigger$, testId: 'test-id'},
]));
});
from ng-mocks.
OK while working on updating my private client I stumbled upon this in the dashboard.component.spec.ts
file (https://github.com/rlexa/dd-playground-client/blob/ng17/src/app/module/widget/dashboard/dashboard.component.spec.ts) see in branch (https://github.com/rlexa/dd-playground-client/tree/ng17). You'll may have to npm i --force
, when working in VS Code it should be possible to directly debug in this file with F5.
from ng-mocks.
What is the current status of this issue? I am experiencing the same problem using the new control-flow syntax. This is a major blocker as it prevents us to fully switch to the new approach.
from ng-mocks.
In my opinion this is still a bug and should be updated as soon as possible. I would like to use the library as intended instead of introducing alternative code. Is there a rough estimation when this issue is tackled?
from ng-mocks.
I am wondering if this project is still actively maintained as this bug is already open for quite some time. Is there any plan to fix the currently available bugs soon?
from ng-mocks.
So, I actually have a workaround for this. The actual error might be within Angular itself, but I'll have to dig a bit deeper to actually verify that. Here is a small test case which fails:
import { CommonModule } from '@angular/common';
import { Component, NgModule } from '@angular/core';
import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';
@Component({
selector: 'target',
template: `
@if (hasChild) {
<child />
}
`,
})
class TargetComponent {
public readonly hasChild = true;
}
@Component({
selector: 'child',
template: '',
})
class ChildComponent {}
@NgModule({
imports: [CommonModule],
declarations: [TargetComponent, ChildComponent],
})
class TargetModule {}
// @see https://github.com/help-me-mom/ng-mocks/issues/7216
describe('issue-7216', () => {
beforeEach(() => MockBuilder(TargetComponent, TargetModule));
it('finds child-element', () => {
MockRender(TargetComponent);
expect(ngMocks.findInstance(ChildComponent)).toBeTruthy();
});
});
The error can be solved with a quick null-check in el-def-get-parent.ts:getScanViewRefRootNodes
:
const vr = vcr.get(vrIndex);
if (!vr) {
continue;
}
The problem here is that ViewContainerRef returns a length of 1, but trying to fetch the first element returns 0. I'll create a PR for this will digging deeper.
from ng-mocks.
All creds go to @andreandersson.
Thank you for the contribution!
from ng-mocks.
Related Issues (20)
- doc: better example of `ActivatedRoute.params` HOT 2
- Feature Request: MockBuilder strict mode with standalone components
- docs: how to mock with `MockBuilder.provide`
- support vitest
- ngMocksUniverse.global
- Bug: MockMiddleware{Index} HOT 1
- update links in the repo HOT 2
- update sponsor links in the repo HOT 2
- Bug: cannot set return value of DI'ed pipe HOT 1
- Bug: `.keep(ReactiveFormsModule)` does not actually keep HOT 3
- Bug: Angular 17.1.0 `input.required()` issues HOT 14
- Feature Request: Documentation for functional route guards without the use of NgModule
- Bug: Injection of mocked service fails for nested service ... but only sometimes ...
- Bug: cannot `.replace()` a component that has an abstract base class
- Bug: formatHtml on MockedComponentFixture / DebugElement won't give expected value
- Bug: try to avoid recursive parsing when a standalone component imports itself
- Bug: Incompatibility of MockComponent with new viewChild signal function HOT 7
- Bug: MockComponent (Standalone) mocks all components not just the ones specified HOT 3
- Bug: MockRender throws an error on mat-tab HOT 2
- MockComponent function set Signal Inputs as Decorator Inputs
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ng-mocks.