getsaf / shallow-render Goto Github PK
View Code? Open in Web Editor NEWAngular testing made easy with shallow rendering and easy mocking. https://getsaf.github.io/shallow-render
License: MIT License
Angular testing made easy with shallow rendering and easy mocking. https://getsaf.github.io/shallow-render
License: MIT License
How to handle cases when module is using BrowserAnimationsModule
? Previously you would use NoopAnimationsModule
for that.
The README.md is OK. A Wiki may help organize things.
I have an Angular 5-based module (5.2 to be precise) and when I use the latest version (6.2.0) I get the following error message during the test run:
$ yarn test
yarn run v1.7.0
$ ng test
10% building modules 1/1 modules 0 active16 10 2018 13:38:59.629:WARN [karma]: No captured browser, open http://localhost:9876/
16 10 2018 13:38:59.643:INFO [karma]: Karma v3.0.0 server started at http://0.0.0.0:9876/
16 10 2018 13:38:59.645:INFO [launcher]: Launching browser ChromeHeadless with unlimited concurrency
16 10 2018 13:38:59.651:INFO [launcher]: Starting browser ChromeHeadless
[./src/polyfills.ts] ./src/polyfills.ts 0 bytes {polyfills} [built]
[0] multi ./src/polyfills.ts 28 bytes {polyfills} [built]
[./src/test.ts] ./src/test.ts 0 bytes {main} [built]
ERROR in node_modules/shallow-render/dist/lib/models/test-setup.d.ts(9,50): error TS2315: Type 'ModuleWithProviders' is not generic.
node_modules/shallow-render/dist/lib/models/test-setup.d.ts(9,88): error TS2315: Type 'ModuleWithProviders' is not generic.
If I edit the test-setup.d.ts file at line 9 and change it (removing the <any>
following ModuleWithProviders
):
readonly moduleReplacements: Map<Type<any> | ModuleWithProviders, Type<any> | ModuleWithProviders>;
compilation now completes. I tried stepping back to v6.1.3 but the error still occurred.
Is there a version I could use so that I didn't have to manually edit the file (worried about deploying this to my co-workers so they can start writing tests using the shallow-render package).
I'm just forging into the world of testing frontend code involving Angular. Happy to provide additional info if I haven't provide sufficient details. Trying to get testing to work first then consider migrations to Angular 6 and beyond if possible.
Loved the idea of this project, but can't use in the most simplest of tests of a child component, which is contained in a module that has routing.
None of the recommendations work for the issue previously, and the stackblitz examples fail with the same error.
https://stackblitz.com/edit/github-frqbzt-dek4h5?file=examples%2Fcomponent-with-routing.spec.ts
Thanks for the awesome library.
I get this error when using shallow-render with angular v6:
npm WARN @angular/[email protected] requires a peer of rxjs@^5.5.0 but none is installed. You must install peer dependencies yourself.
npm WARN @angular/[email protected] requires a peer of rxjs@^5.5.0 but none is installed. You must install peer dependencies yourself.
npm WARN @angular/[email protected] requires a peer of rxjs@^5.5.0 but none is installed. You must install peer dependencies yourself.
I am using shallow-render version 0.13.0
I haven't gotten to the root of this one, but my normal Angular tests are passing fine, but those that leverage shallow-render
are failing now that I have added some material components that support hammerjs.
See https://material.angular.io/guide/getting-started#step-5-gesture-support
When running in the browser, the console merely states that hammerjs is needed to support some gestures. I haven't added hammerjs to the project yet.
Instead of seeing the warning in my tests, I see
TypeError: Cannot read property 'indexOf' of undefined
at HammerGesturesPlugin.isCustomEvent (../packages/platform-browser/src/dom/events/hammer_gestures.ts:236:74)
at HammerGesturesPlugin.supports (../packages/platform-browser/src/dom/events/hammer_gestures.ts:163:71)
at EventManager._findPluginFor (../packages/platform-browser/src/dom/events/event_manager.ts:83:18)
at EventManager.addEventListener (../packages/platform-browser/src/dom/events/event_manager.ts:50:25)
at DefaultDomRenderer2.listen (../packages/platform-browser/src/dom/dom_renderer.ts:218:42)
at BaseAnimationRenderer.listen (../../packages/platform-browser/animations/src/animation_renderer.ts:194:26)
So it appears that some hammer placeholder module is being mocked when it shouldn't be.
The "component with routing" example you have on Stackblitz isn't quite right.
In a real component/app, I would be using RouterModule.forRoot()
and not simply RouterModule
.
When I add that to the example, it breaks.
I immediately get the following error:
Error: Unexpected value '[object Object]' imported by the module 'DynamicTestModule'. Please add a @NgModule annotation.
I thought it might work similar to .dontMock()
in that you need to save a reference to var = Module.forRoot()
and put var
in .dontMock(var)
. That didn't work either. I get the error:
TypeError: this.appInits[i] is not a function
I'm guessing that this means the .replaceModule()
line is ignored altogether.
Do I also need to use .provide()
or something?
Also, is there a way to send you a few dollars/btc for all the work you've done? It's been very helpful for me at work.
Congrats with such an intuitive package.
Request: Could we have a shallow-cli to generate the boiler-plate. This would even reduce the amount of code we write.
Regards
First off, thank you so much for the library. I am having an issue when I have animations triggers though with using this library. Example:
@Component({
selector: 'app-applications-grid',
templateUrl: './applications-grid.component.html',
styleUrls: ['./applications-grid.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
animations: [
trigger('applicationAnimation', [
transition('* => *', [
query(
':enter',
[
style({ opacity: 0, transform: 'translateY(-100px)' }),
stagger(50, [animate('400ms ease-out', style({ opacity: 1, transform: 'none' }))]),
],
{ optional: true }
),
]),
]),
],
})
export class ApplicationsGridComponent {
@Input() applications: ApplicationDetail[];
trackByFn(idx, { name }: ApplicationDetail) {
return name;
}
}
with a template of
<section class="application-grid" [@applicationAnimation]="applications?.length">
<app-applications-grid-item *ngFor="let application of applications; trackBy: trackByFn" [item]="application"></app-applications-grid-item>
</section>
This error is thrown:
HeadlessChrome 0.0.0 (Linux 0.0.0) ApplicationsGridComponent should create FAILED
Error: Found the synthetic property @applicationAnimation. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.
at checkNoSyntheticProp node_modules/@angular/platform-browser/fesm5/platform-browser.js:1296:1)
at EmulatedEncapsulationDomRenderer2.push../node_modules/@angular/platform-browser/fesm5/platform-browser.js.DefaultDomRenderer2.setProperty node_modules/@angular/platform-browser/fesm5/platform-browser.js:1280:1)
at DebugRenderer2.push../node_modules/@angular/core/fesm5/core.js.DebugRenderer2.setProperty node_modules/@angular/core/fesm5/core.js:11207:1)
at setElementProperty node_modules/@angular/core/fesm5/core.js:7966:1)
at checkAndUpdateElementValue node_modules/@angular/core/fesm5/core.js:7917:1)
at checkAndUpdateElementInline node_modules/@angular/core/fesm5/core.js:7864:1)
at checkAndUpdateNodeInline node_modules/@angular/core/fesm5/core.js:10205:1)
at checkAndUpdateNode node_modules/@angular/core/fesm5/core.js:10171:1)
at debugCheckAndUpdateNode node_modules/@angular/core/fesm5/core.js:10804:1)
at debugCheckRenderNodeFn node_modules/@angular/core/fesm5/core.js:10790:1)
HeadlessChrome 0.0.0 (Linux 0.0.0) ApplicationsGridComponent should create FAILED
Error: Found the synthetic property @applicationAnimation. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.
at checkNoSyntheticProp node_modules/@angular/platform-browser/fesm5/platform-browser.js:1296:1)
at EmulatedEncapsulationDomRenderer2.push../node_modules/@angular/platform-browser/fesm5/platform-browser.js.DefaultDomRenderer2.setProperty node_modules/@angular/platform-browser/fesm5/platform-browser.js:1280:1)
at DebugRenderer2.push../node_modules/@angular/core/fesm5/core.js.DebugRenderer2.setProperty node_modules/@angular/core/fesm5/core.js:11207:1)
at setElementProperty node_modules/@angular/core/fesm5/core.js:7966:1)
at checkAndUpdateElementValue node_modules/@angular/core/fesm5/core.js:7917:1)
at checkAndUpdateElementInline node_modules/@angular/core/fesm5/core.js:7864:1)
at checkAndUpdateNodeInline node_modules/@angular/core/fesm5/core.js:10205:1)
at checkAndUpdateNode node_modules/@angular/core/fesm5/core.js:10171:1)
at debugCheckAndUpdateNode node_modules/@angular/core/fesm5/core.js:10804:1)
If I create a testing module that imports the NoopAnimationsModule
,
@NgModule({
imports: [NoopAnimationsModule, ApplicationsModule],
exports: [ApplicationsModule],
})
export class ApplicationsTestModule {
}
describe('ApplicationsGridComponent', () => {
let shallow: Shallow<ApplicationsGridComponent>;
beforeEach(() => {
shallow = new Shallow(ApplicationsGridComponent, ApplicationsTestModule);
});
const applications = mockApps;
it('should create', async () => {
const res = await shallow.render(
`<app-applications-grid [applications]="applications"></app-applications-grid>`,
{ bind: { applications } },
);
});
});
the test fails with the following error:
HeadlessChrome 0.0.0 (Linux 0.0.0) ApplicationsGridComponent should create FAILED
TypeError: this.delegate.createRenderer is not a function
at DebugRendererFactory2.push../node_modules/@angular/core/fesm5/core.js.DebugRendererFactory2.createRenderer node_modules/@angular/core/fesm5/core.js:11067:1)
at createRootData node_modules/@angular/core/fesm5/core.js:10538:1)
at Object.debugCreateRootView [as createRootView] node_modules/@angular/core/fesm5/core.js:10531:1)
at ComponentFactory_.push../node_modules/@angular/core/fesm5/core.js.ComponentFactory_.create node_modules/@angular/core/fesm5/core.js:8361:1)
at initComponent node_modules/@angular/core/fesm5/testing.js:1163:1)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke node_modules/zone.js/dist/zone.js:388:1)
at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke node_modules/zone.js/dist/zone-testing.js:288:1)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke node_modules/zone.js/dist/zone.js:387:1)
at Object.onInvoke node_modules/@angular/core/fesm5/core.js:3671:1)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke node_modules/zone.js/dist/zone.js:38HeadlessChrome 0.0.0 (Linux 0.0.0): Executed 1 of 125 (1 FAILED) (skipped 124) ERROR (0.096 secs / 0.072 secs)
Any ideas?
I apologize if this is too basic of a question, but I couldn't seem to find it in the docs. I'm liking the shallow-render
approach, however several of my components are route destinations. Is there any hook I should use for testing those?
Or should I stick with the router testing from the Angular site? (https://angular.io/guide/testing#routed-components)
I apologize if I'm just misusing the library. Here is a test case demonstrating the failure: https://stackblitz.com/edit/shallow-render-jz9ubo?file=examples/multiple-components.spec.ts
If I have a child component and I need to mock out a method that is called (getThing()
in the code below):
class AwesomeListComponent {
@Input() topItem: string;
@Input() boldTopItem = false;
@ViewChild('listContainer') listContainer: ListContainerComponent;
ngAfterViewInit(): void {
console.log(this.listContainer.getThing())
}
}
I would expect to be able to mock it out by: .mock(ListContainerComponent, {getThing : () => 'Test Thing'});
However I get TypeError: this.listContainer.getThing is not a function
Test run fails with the following error when using Angular Universal with an import BrowserModule.withServerTransition({ appId: 'serverApp' })
:
TypeError: this._moduleRef.injector.get(...).runInitializers is not a function
at TestBedViewEngine.push.../../node_modules/@angular/core/fesm5/testing.js.TestBedViewEngine._initIfNeeded (http://localhost:9876/C:/GIT/game-monorepo/game/node_modules/@angular/core/fesm5/testing.js?:1702:59)
at TestBedViewEngine.push.../../node_modules/@angular/core/fesm5/testing.js.TestBedViewEngine.createComponent (http://localhost:9876/C:/GIT/game-monorepo/game/node_modules/@angular/core/fesm5/testing.js?:1861:1)
at Function.push.../../node_modules/@angular/core/fesm5/testing.js.TestBedViewEngine.createComponent (http://localhost:9876/C:/GIT/game-monorepo/game/node_modules/@angular/core/fesm5/testing.js?:1554:1)
at Renderer.<anonymous> (http://localhost:9876/C:/GIT/game-monorepo/game/node_modules/shallow-render/dist/lib/models/renderer.js?:149:1)
at step (http://localhost:9876/C:/GIT/game-monorepo/game/node_modules/shallow-render/dist/lib/models/renderer.js?:50:1)
at Object.next (http://localhost:9876/C:/GIT/game-monorepo/game/node_modules/shallow-render/dist/lib/models/renderer.js?:31:45)
at fulfilled (http://localhost:9876/C:/GIT/game-monorepo/game/node_modules/shallow-render/dist/lib/models/renderer.js?:22:42)
at ZoneDelegate.../../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/C:/GIT/game-monorepo/game/node_modules/zone.js/dist/zone.js?:388:1)
at ProxyZoneSpec.push.../../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9876/C:/GIT/game-monorepo/game/node_modules/zone.js/dist/zone-testing.js?:288:1)
Stackblitz example https://stackblitz.com/edit/github-ccz1rn?file=examples%2Fmodule-with-server-transition.spec.ts
Please do let me know if you need any help with the investigation.
The theory here is that when mocking modules, we may not need to mock ALL dependencies all the way down. Maybe we can get away with mocking:
exports[]
of any other imported moduleIf this pans out, it could seriously cut down on how many modules/services/components are mocked for each test.
const r = shallow.dontMock(ReactiveFormsModule)
.render(
'<example [something]="data"></example>',
{ bind: { data: { type: 'number' } } },
);
const input = r.find('input').nativeElement;
// works fine
expect(input.getAttribute('ng-reflect-type'))
.toBe('number'); // true
// doesn't work
expect(input.getAttribute('type'))
.toBe('number'); // Expected null to be 'number
// elsewhere
@Component({
selector: 'example',
template: `<input [type]="data.type">`,
})
export class ExampleComponent {
@Input() something: IData;
}
Am I forgetting some dependency? Why is <input type="number">
never happening?
For some reason the message is [object Object]
. I think I know why, but it sucks for the user to see that because it's not very descriptive. :-(
Hi, thanks for a great lib, I really considering to use it for my projects. Now to the actual question:
when I try to query some element in my test:
expect(find('p')).toBeFalsy();
test throws an error:
context.js:243 Unhandled Promise rejection: Could not find the element you were looking for. Your test tried to access the 'prototype' property on a QueryResult but your query had no results. ; Zone: ProxyZone ; Task: Promise.then ; Value: Error: Could not find the element you were looking for. Your test tried to access the 'prototype' property on a QueryResult but your query had no results.
at new NoMatchesError (VM40572 query-match.js:16)
at throwErrorIfNotOneMatch (VM40572 query-match.js:31)
at Object.getPrototypeOf (VM40572 query-match.js:71)
at Function.[Symbol.hasInstance] (<anonymous>)
at Proxy.Object.toString (VM267 zone.js:1466)
at exports.instanceOf (VM23 context.js:90)
at ContextKarma.stringify (VM23 context.js:39)
at ContextKarma.log (VM23 context.js:138)
I'm kind of used to do this technique with fixture.debugElement.query
to make sure that some elements are not rendered in some cases. Don't you think that throwing an error in #find
is a little bit too much? Or I just should stick to using fixture.debugElement.query
in this case?
When a component does not have a selector:
https://github.com/angular/angular/blob/master/packages/compiler/src/metadata_resolver.ts#L356
Hi,
I started using shallow-render
today, as it seems to perfectly align with how we want to test our Angular application. So far so good, if it weren't for the fact that I currently keep running into the same error that's blocking me from writing tests using shallow-render
.
I'm currently testing a really easy component using the following setup:
let shallow: Shallow<OverviewCourseComponent>;
beforeEach(() => {
shallow = new Shallow(OverviewCourseComponent, UIModule);
});
it('should create', async () => {
const { instance } = await shallow.render('<overview-course></overview-course>');
expect(instance).toBeTruthy();
});
I get thrown following error however:
Directive MockOfHeaderPickerComponent has no selector, please add it!
Analysing this error, it seems to originate from this HeaderPickerComponent that is part of ng-zorro-antd
, a UI library I use.
As the error specifies: this specific component does not have a selector defined. This specific component is part of an external repository I have no control over, so adding one is not possible.
Is there a way around this issue, or is this a problem with the current implementation of shallow-render
? I'm currently using version 6.1.2
in my Angular 6.1.4
project.
Thanks!
Nils
Is there any way to add RouterTestingModule
to TestingModule? I see that we can manipulate mocking of components, providers, but nothing about modules.
I'm used to test "href" attribute of anchor elements in my test, plus I would like to test the click event (to expect Router.navigate() to have been called for example).
I couldn't test components using @select decorator of ngxs/store, I'm without new ideas how to test it!
if I try to provide store I've got this error:
SelectFactory not connected to store!
at LoginComponent.createSelect (node_modules/@ngxs/store/bundles/ng:/@ngxs/store/packages/store/src/select.ts:45:15)
at LoginComponent.get [as conf] (node_modules/@ngxs/store/bundles/ng:/@ngxs/store/packages/store/src/select.ts:73:1)
at Object.View_LoginComponent_0._co [as updateDirectives] (ng:/DynamicTestModule/LoginComponent.ngfactory.js:237:31)
at Object.debugUpdateDirectives [as updateDirectives] (../../../../../execroot/angular/packages/core/src/view/services.ts:384:19)
at checkAndUpdateView (../../../../../execroot/angular/packages/core/src/view/view.ts:359:12)
If I try to provide store and don't mock it, I've got this one:
β LoginComponent Shallow Render βΊ should log in
StaticInjectorError(DynamicTestModule)[Store -> StateStream]:
StaticInjectorError(Platform: core)[Store -> StateStream]:
NullInjectorError: No provider for StateStream!```
Possibly just doing this wrong, but exactly what is not obvious to me. Maybe it's a bug?
Here's what I have:
////// Module Setup //////
@Directive({
selector: '[exampleHost]'
})
export class ExampleHostDirective {
constructor(public viewContainerRef: ViewContainerRef) {}
}
@Component({
selector: 'example',
template: '<ng-template exampleHost></ng-template>',
})
export class ExampleContainerComponent implements OnInit {
constructor(private cfr: ComponentFactoryResolver) {}
@ViewChild(ExampleHostDirective) cellHost: ExampleHostDirective;
@Input() data: { component: new () => { data } };
template: string;
ngOnInit() {
const componentFactory = this.cfr.resolveComponentFactory(this.data.component);
const viewContainerRef = this.cellHost.viewContainerRef;
viewContainerRef.clear();
viewContainerRef.createComponent(componentFactory);
}
}
@Component({
selector: 'example-two',
template: '<span>{{biz}}</span>',
})
export class ExampleContainerComponentTwo {
biz = 'baz';
}
@NgModule({
imports: [ReactiveFormsModule, MatFormFieldModule],
declarations: [ExampleContainerComponent, ExampleHostDirective, ExampleContainerComponentTwo],
entryComponents: [ExampleContainerComponentTwo]
})
class ExampleModule {}
//////////////////////////
describe('component with bindings', () => {
let shallow: Shallow<ExampleContainerComponent>;
beforeEach(() => {
shallow = new Shallow(ExampleContainerComponent, ExampleModule)
.dontMock(ExampleHostDirective);
});
const data = {
foo: 'bar'
};
fit('sets type on an input', async () => {
const {find} = await shallow.render(
'<example [data]="data"></example>',
{ bind: { data: { component: ExampleContainerComponentTwo } } }
);
console.log(find('input').nativeElement);
expect(find('input').nativeElement.getAttribute('type'))
.toBe('number');
});
});
My test fails with the error:
Failed: No component factory found for ExampleContainerComponentTwo. Did you add it to @NgModule.entryComponents?
It is in entryComponents though.
I have components those subscribe valueChanges of a FormGroup, but I can't trigger them!
Current alwaysReplaceModule function does not allow to use a ModuleWithProviders as a replacementModule, and this should be allowed.
I created a stackblitz in an attempt to recreate my issue I'm having in a real app. I'm my real app the [disabled]
property is always false but I see the ng-reflect-disabled
attribute updating to true | false
This is what I have to do in my real app test
function expectSignButtonDisabled(find: any, disabled: boolean) {
const signButton = find('#sign-button');
// signButton.nativeElement.disabled always returns false ???
expect(signButton.attributes['ng-reflect-disabled'] === `${disabled}`).toBe(disabled);
}
In my stackblitz app it doesn't appear to be responding to my click()
which seems odd but I even tried hardcoding [disabled]
to be true | false
.
Why does .nativeElement.disabled
always returning false? I assume I'm missing something...
import { Component, NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms'
import { Shallow } from 'shallow-render';
////// Module Setup //////
interface Person {
firstName: string;
lastName: string;
birthDate: Date;
}
@Component({
selector: 'my-comp',
template: `
<input type="checkbox" id="cbox" name="cbox" #cbox [(ngModel)]="cbox.selected">
<button id="btn" [disabled]="!cbox.selected" [innerText]="cbox.selected? 'Submit': 'Disabled'">Submit</button>
`,
})
class MyComponent {
}
@NgModule({
imports: [FormsModule],
declarations: [MyComponent]
})
class MyModule {}
//////////////////////////
describe('component with bindings', () => {
let shallow: Shallow<MyComponent>;
beforeEach(() => {
shallow = new Shallow(MyComponent, MyModule);
});
it('button should be disabled, text should say Disabled', async () => {
const {find, fixture} = await shallow.render(
'<my-comp></my-comp>'
);
let btn = find('#btn');
let checkbox = find ('#cbox');
expect(btn.nativeElement.disabled).toBe(true);
expect(btn.nativeElement.innerText).toBe('Disabled');
});
it('button should be enabled, text should say Submit', async () => {
const {find, fixture} = await shallow.render(
'<my-comp></my-comp>'
);
let checkbox = find('#cbox');
let btn = find('#btn');
checkbox.nativeElement.click();
expect(btn.nativeElement.innerText).toBe('Submit');
expect(btn.nativeElement.disabled).toBeFalsy();
});
});
First of all, great library. Thanks for the hard work.
Secondly, is it possible to test functions defined in the component class? All the examples/documentation tests against the template. If it is possible, could you please provide a small example?
I'd like to propose to add Angular schematics, so when you create a component with Angular CLI, instead of a default spec file, a shallow-render spec file is generated.
Let's say you execute: ng g c app/shallow-component
It would generate the following spec file:
import { ShallowComponentComponent } from './shallow-component.component';
import { AppModule } from './app.module';
import { Shallow } from 'shallow-render/dist';
describe('ShallowComponentComponent', () => {
let shallow: Shallow<ShallowComponentComponent>;
beforeEach(() => {
shallow = new Shallow(ShallowComponentComponent, AppModule);
});
it('should create', async () => {
const { instance } = await shallow.render();
expect(instance).toBeTruthy();
});
});
@getsaf If you are interested, I can help with a PR as I have got a working solution already.
I looked in the stackblitz example and didn't see any nice example of dealing with dialogs. Think we could get a good example in the stackblitz when you get some time?
Can't wrap my head around this. So I have this code:
constructor(private store: FooStore) {
this.foo= this.store.foo
}
Is it possible to mock what this.store.foo
returns?
Hi,
I've got a simple component, where a button is disabled or enabled on the validation of an input field.
I'm finding that the tests are running in reverse order, and more importantly, nativeElement.disabled is always false, whereas componentInstance.disabled is always true.
This is even after either fixture.detectChanges(); and await fixture.detectChange
It's possible that a user would specify a mock for an injectable that is not contained in the test-module or any of the subsequent module mocks. If this happens, it would be an oversight on the developer's part that they provided a mock for a thing that is not possible to be provided in their module. Shallow should throw an error in this case as a helpful note to the user.
Hello,
I have the next component tree:
AppComponent
|
|
ParentComponent
|
|
ChildComponent
The ParentComponent has a ViewChild reference to ChildComponent. When i mock ChildComponent by hand in the ParentComponent spec, it renders but never gets the reference to the ViewChild. Is any way to solve this using shallow-render?
If it helps, this repo has an example of the case i explained above: https://github.com/Ivykp/test-viewchild-mock
Thanks!
Let's say I have a condition rendering in my template. I want to test that conditional rendering. find
method throws an error about element not existing Could not find the element you were looking for. Your test tried to access the 'prototype' property on a QueryResult but your query had no results.
I either need to wrap that into a try/catch
block or in some different way.
Ideally I would like to determine if element exists only by using find
method.
So I have situation when I use @ngx-translate/i18n-polyfill
. It is injected in constructor constructor(private i18n: I18n) {}
and then used a function this.i18n({ ... })
. Mocking is not working for me since this.i18n
returns MockOfI18n
object and is not a function.
I've bypassed this by spying upon instance.i18n
after the render.
First of all, I'd like to thank you for creating such a great library! It already saved us loads of time!
Issue details:
Error: <DirectiveType> was not found in test template
"Steps to reproduce:
Findings:
I cloned the source code. Exception is thrown in rendering.ts on line 22
. It seems that the code on line 19 this.fixture.debugElement.query(By.directive(this._setup.testComponent));
returns a null object.
I'd be happy to help to resolve the issue if you can point to the right direction.
How can I achieve following using shallow-render mocking approach.
spyOn(util, "foo").and.returnValues(true, false);
expect(util.foo()).toBeTruthy();
expect(util.foo()).toBeFalsy();
I get the following error when trying to apply the demo @ https://github.com/getsaf/shallow-render/wiki into my app.
Error: Template parse errors:ββ
ββUnexpected closing tag "__MockOfEmptyOutletComponent-selector". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags ("<__MockOfEmptyOutletComponent-selector>[ERROR ->]</__MockOfEmptyOutletComponent-selector>"): @0:39ββ
I just want to share the fix to the problem that I've recently encountered when using Angular Material:
Failed: Cannot read property 'indexOf' of undefined
TypeError: Cannot read property 'indexOf' of undefined
at HammerGesturesPlugin.push../node_modules/@angular/platform-browser/fesm5/platform-browser.js.HammerGesturesPlugin.isCustomEvent (http://localhost:9876/node_modules/@angular/platform-browser/fesm5/platform-browser.js?:1585:74)// Remaining of the stack trace....
The error appears when adding one of the modules: MatSliderModule, MatSlideToggleModule or MatTooltipModule
To fix the problem add Shallow.neverMock(HAMMER_GESTURE_CONFIG);
to your tests or better to append it to the end of the test.ts file.
Explanation:
Aforementioned modules have the following provider declared as part of the module declaration
{provide: HAMMER_GESTURE_CONFIG, useClass: GestureConfig}
As shallow-render mock the implementation, test execution fails. Adding Shallow.neverMock
prevents the error.
On https://github.com/getsaf/shallow-render/wiki/Getting-Started#your-first-test the example has a typo:
template: '<h1>{labelText}</h1>'
should have double {{
and should be label
instead of labelText
.
Hey there!
First of all, awesome piece of work!
It really does simplify the process of testing angular applications :)
But I have one issue that makes me pulling my hair out of my head:
I've got a component that has a two way binding implemented on in:
@Component({
selector: 'bc-checkbox',
templateUrl: './checkbox.component.html',
styleUrls: ['./checkbox.component.scss'],
})
export class CheckboxComponent {
private static idCounter: number = 0;
@Input() public id: string = `bc-checkbox-${++CheckboxComponent.idCounter}`;
@Input() public disabled: boolean = false;
@Input() public checked: boolean = false;
@Output() public checkedChange: EventEmitter<boolean> = new EventEmitter();
public get checkedValue(): boolean {
return this.checked;
}
public set checkedValue(value: boolean) {
this.checked = value;
this.checkedChange.emit(this.checked);
}
public change(): void {
if (this.disabled) {
return;
}
this.checkedValue = !this.checkedValue;
}
}
<div (click)="change()" class="bc-checkbox">
<input id="{{id}}" type="checkbox" [disabled]="disabled" [checked]="checkedValue" (change)="change()">
<label for="{{id}}">
<ng-content></ng-content>
</label>
</div>
Now I want to unit test this binding (checked):
it('should emit the checked value on click on input', fakeAsync(async () => {
const { find, bindings } = await shallow.render(
`<bc-checkbox [(checked)]="checked"></bc-checkbox>`,
{ bind: { checked: false } },
);
find('input').triggerEventHandler('change', null);
expect(bindings.checked).toBe(true);
}));
But checked is not set to True
.
Event when I use fixture.detectChanges
.
Can you help me? :)
Cheers and a nice day
I created a Stackblitz example showing the issue: https://stackblitz.com/edit/shallow-render-angular?file=examples%2Findex.ts
I'm using the dynamic component loading pattern described in the angular guide here: https://angular.io/guide/dynamic-component-loader
The error that displays:
Error: No component factory found for TestEntryComponent. Did you add it to @NgModule.entryComponents?
I added the entry component to the module definition, but it didn't help:
@NgModule({
declarations: [OuterComponent, TestHostDirective],
entryComponents: [TestEntryComponent]
})
class TestModule {}
I also tried to use .dontMock(TestEntryComponent)
but that didn't help either :/
I don't know if this is something with shallow-render or something just due to our module design. But figured I'd ask and see what help you can provide.
My test file:
import { Shallow } from 'shallow-render'
import { DialogSortComponent } from '@agilitypr/app/briefing/composition/sortTool/sort-tool.component';
import { BriefingModule} from "@agilitypr/app/briefing/briefing.module";
describe (
'DialogSortComponent',
() => {
let shallow: Shallow<DialogSortComponent>;
beforeEach(() => {
shallow = new Shallow(DialogSortComponent, BriefingModule)
}
);
it(
'Sort Component created',
async () => {
const {find} = await shallow.render('<sorttool-dialog></sorttool-dialog>');
}
);
}
);
When I try to run the test, I an error:
$ yarn test --environment dev_web1mars1 --watch=false
yarn run v1.7.0
$ ng test --environment dev_web1mars1 --watch=false
10% building modules 1/1 modules 0 active18 10 2018 10:41:36.599:INFO [karma]: Karma v3.0.0 server started at http://0.0.0.0:9876/
18 10 2018 10:41:36.602:INFO [launcher]: Launching browser ChromeHeadless with unlimited concurrency
18 10 2018 10:41:36.615:INFO [launcher]: Starting browser ChromeHeadless
18 10 2018 10:41:51.868:INFO [HeadlessChrome 0.0.0 (Ubuntu 0.0.0)]: Connected on socket JNNa6hVTyM3iXaiPAAAA with id 67817959
DialogSortComponent
β Sort Component created
TypeError: this.appInits[i] is not a function
at <Jasmine>
at ApplicationInitStatus.webpackJsonp../node_modules/@angular/core/esm5/core.js.ApplicationInitStatus.runInitializers node_modules/@angular/core/esm5/core.js:3574:34)
at TestBed.webpackJsonp../node_modules/@angular/core/esm5/testing.js.TestBed._initIfNeeded node_modules/@angular/core/esm5/testing.js:1011:59)
at TestBed.webpackJsonp../node_modules/@angular/core/esm5/testing.js.TestBed.createComponent node_modules/@angular/core/esm5/testing.js:1138:1)
at Function.webpackJsonp../node_modules/@angular/core/esm5/testing.js.TestBed.createComponent node_modules/@angular/core/esm5/testing.js:837:1)
at Renderer.<anonymous> node_modules/shallow-render/dist/lib/models/renderer.js:149:1)
at step node_modules/shallow-render/dist/lib/models/renderer.js:50:1)
at Object.next node_modules/shallow-render/dist/lib/models/renderer.js:31:45)
at fulfilled node_modules/shallow-render/dist/lib/models/renderer.js:22:42)
at ZoneDelegate.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke node_modules/zone.js/dist/zone.js:388:1)
at ProxyZoneSpec.webpackJsonp../node_modules/zone.js/dist/proxy.js.ProxyZoneSpec.onInvoke node_modules/zone.js/dist/proxy.js:128:1)
HeadlessChrome 0.0.0 (Ubuntu 0.0.0) DialogSortComponent Sort Component created FAILED
TypeError: this.appInits[i] is not a function
at <Jasmine>
at ApplicationInitStatus.webpackJsonp../node_modules/@angular/core/esm5/core.js.ApplicationInitStatus.runInitializers node_modules/@angular/core/esm5/core.js:3574:34)
at TestBed.webpackJsonp../node_modules/@angular/core/esm5/testing.js.TestBed._initIfNeeded node_modules/@angular/core/esm5/testing.js:1011:59)
at TestBed.webpackJsonp../node_modules/@angular/core/esm5/testing.js.TestBed.createComponent node_modules/@angular/core/esm5/testing.js:1138:1)
at Function.webpackJsonp../node_modules/@angular/core/esm5/testing.js.TestBed.createComponent node_modules/@angular/core/esm5/testing.js:837:1)
at Renderer.<anonymous> node_modules/shallow-render/dist/lib/models/renderer.js:149:1)
at step node_modules/shallow-render/dist/lib/models/renderer.js:50:1)
at Object.next node_modules/shallow-render/dist/lib/models/renderer.js:31:45)
at fulfilled node_modules/shallow-render/dist/lib/models/renderer.js:22:42)
at ZoneDelegate.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke node_modules/zone.js/dist/zone.js:388:1)
at ProxyZoneSpec.webpackJsonp../node_modules/zone.js/dist/proxy.js.ProxyZoneSpec.onInvoke node_modules/zone.js/dist/proxy.js:128:1)
HeadlessChrome 0.0.0 (Ubuntu 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.889 secs / 0.807 secs)
I know the test doesn't do much but the line 19 causes the error (remove it and the error goes away, with it and things go bang).
A snippet for the component, to show the selector:
@Component({
selector: 'sorttool-dialog',
templateUrl: './sort-tool.component.html',
styleUrls: [
'../../shared/css/briefings.css',
'./sort-tool.component.css',
],
providers: [
ConfirmationService,
StringTokenService
],
Any guidance - is this error coming from shallow-render and something that can be dealt with? Is this something due to the complexity of our module? This module is based on Angular 5.2.
At the bottom of the readme, the example titled "Component with custom providers" 404's for me. :)
On https://github.com/getsaf/shallow-render/wiki/Querying#example
the template {{text}}
should be {{label}}
(and probably should be renamed so it doesn't get confused with the <label>
element anyways)
Current:
<h1 *ngIf="big" class="large">{{text}}</h1>
<label *ngIf="!big">{{text}</label>
Should be
<h1 *ngIf="big" class="large">{{label}}</h1>
<label *ngIf="!big">{{label}}</label>
Also missing a }
on the second line.
I provide a value like this:
shallow = new Shallow(FooComponent, FooModule)
.provide(
{provide: 'myValue', useValue: 'world'},
);
And use it like this:
constructor(@Inject('myValue') myValue: string) {
this.message = "Hello " + myValue;
console.log(myValue);
}
Expected value of message:
Hello world
Actual value of message:
Hello [object Object]
The log statement outputs:
LOG: MockProvider{mockOf: Object{provide: 'myValue', useValue: 'world'}}
Complete test case:
foo.component.spec.ts.txt
Check if there is already a spy on the provided mock function before adding one. This will allow the user to use another mocking library if they want.
If NgbModule from ng-bootstrap is imported, the test fails with the following Error.
I realize that you cannot support all combinations of third-party frameworks but I'm curious if this is only a problem with ng-bootstrap or something that could be fixed in shallow-render.
Example: https://stackblitz.com/edit/shallow-render-mock-method-provider-dy21dd
error properties: Object({ ngSyntaxError: true })
Error: MockOfNgbModalBackdrop cannot be used as an entry component.
at syntaxError (https://shallow-render-mock-method-provider-dy21dd.stackblitz.io/turbo_modules/@angular/[email protected]/bundles/compiler.umd.js:1093:21)
at CompileMetadataResolver._getEntryComponentMetadata (https://shallow-render-mock-method-provider-dy21dd.stackblitz.io/turbo_modules/@angular/[email protected]/bundles/compiler.umd.js:11087:23)
at eval (https://shallow-render-mock-method-provider-dy21dd.stackblitz.io/turbo_modules/@angular/[email protected]/bundles/compiler.umd.js:10727:57)
at <Jasmine>
at CompileMetadataResolver.getNgModuleMetadata (https://shallow-render-mock-method-provider-dy21dd.stackblitz.io/turbo_modules/@angular/[email protected]/bundles/compiler.umd.js:10727:22)
at CompileMetadataResolver.getNgModuleSummary (https://shallow-render-mock-method-provider-dy21dd.stackblitz.io/turbo_modules/@angular/[email protected]/bundles/compiler.umd.js:10553:39)
at eval (https://shallow-render-mock-method-provider-dy21dd.stackblitz.io/turbo_modules/@angular/[email protected]/bundles/compiler.umd.js:10640:59)
at <Jasmine>
at CompileMetadataResolver.getNgModuleMetadata (https://shallow-render-mock-method-provider-dy21dd.stackblitz.io/turbo_modules/@angular/[email protected]/bundles/compiler.umd.js:10618:53)
at CompileMetadataResolver.getNgModuleSummary (https://shallow-render-mock-method-provider-dy21dd.stackblitz.io/turbo_modules/@angular/[email protected]/bundles/compiler.umd.js:10553:39)
After upgrading to the latest shallow render, my tests started failing. Before, I was at 6.0.6.
Here is the error:
Unexpected closing tag "__MockOfEmptyOutletComponent-selector". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags ("<__MockOfEmptyOutletComponent-selector>[ERROR ->]</__MockOfEmptyOutletComponent-selector>"): @0:39
at syntaxError (./node_modules/@angular/compiler/fesm5/compiler.js?:1275:17)
at TemplateParser.parse (./node_modules/@angular/compiler/fesm5/compiler.js?:15084:19)
at JitCompiler._parseTemplate (./node_modules/@angular/compiler/fesm5/compiler.js?:24272:37)
at JitCompiler._compileTemplate (./node_modules/@angular/compiler/fesm5/compiler.js?:24259:23)
at eval (./node_modules/@angular/compiler/fesm5/compiler.js?:24202:62)
at Set.forEach (<anonymous>)
at JitCompiler._compileComponents (./node_modules/@angular/compiler/fesm5/compiler.js?:24202:19)
at eval (./node_modules/@angular/compiler/fesm5/compiler.js?:24120:19)
at Object.then (./node_modules/@angular/compiler/fesm5/compiler.js?:1266:77)
Downgrading to 6.1.2 solves the issue.
Commit that seemed to cause it: 07ac3a3
When you:
It looks like this:
imports: [
StoreModule.forRoot({}), // This is the extra import
StoreModule.forFeature('yourFeature', fromFeature.reducers)
]
Without the extra import, you can't use the Store
service within your component. It complains about missing providers.
But you can't just add StoreModule.forRoot({})
to your feature module since it would defeat the whole purpose of having StoreModule.forFeature('yourFeature', fromFeature.reducers)
. The extra import is only for the test.
Is there a way to add new imports?
I recall there used to be an .imports()
method on the shallow class instance, but it's no longer there.
Hi there
i'm struggling to setup shallow-render in my meteor angular project. Hopefully you can help me.
I'm getting following error:
TypeError: Cannot read property 'injector' of null
at TestBedViewEngine._createCompilerAndModule (packages/modules.js?hash=9bf6a4a74870f7e24c465ccdd26da1c74b199b4c:42029:49)
at TestBedViewEngine.compileComponents (packages/modules.js?hash=9bf6a4a74870f7e24c465ccdd26da1c74b199b4c:41942:35)
at Function.TestBedViewEngine.compileComponents (packages/modules.js?hash=9bf6a4a74870f7e24c465ccdd26da1c74b199b4c:41802:81)
at Renderer.\u003Canonymous> (packages/modules.js?hash=9bf6a4a74870f7e24c465ccdd26da1c74b199b4c:2680:16)
at step (packages/modules.js?hash=9bf6a4a74870f7e24c465ccdd26da1c74b199b4c:2538:19)
at Object.next (packages/modules.js?hash=9bf6a4a74870f7e24c465ccdd26da1c74b199b4c:2468:14)
at packages/modules.js?hash=9bf6a4a74870f7e24c465ccdd26da1c74b199b4c:2440:67
at new Promise (\u003Canonymous>)
at __awaiter (packages/modules.js?hash=9bf6a4a74870f7e24c465ccdd26da1c74b199b4c:2417:10)
at Renderer.render (packages/modules.js?hash=9bf6a4a74870f7e24c465ccdd26da1c74b199b4c:2644:12)`
i have following packages installed:
"devDependencies": {
"chai": "^4.2.0",
"chromedriver": "^2.41.0",
"faker": "^4.1.0",
"shallow-render": "^7.1.2",
"selenium-webdriver": "^3.6.0",
"sinon": "^7.2.3"
},
and in packages:
And following Code:
import { AppModule } from '../../app.module';`
import { ServersFormComponent } from "../servers-form.component";`
import { Shallow } from 'shallow-render';`
describe("ServersFormComponent", () => {
let shallow: Shallow<ServersFormComponent>;
beforeEach(()=>{
shallow = new Shallow(ServersFormComponent, AppModule);
});
it('should render this', async () => {
const {find} = await shallow.render('<servers-form></servers-form>');
console.log(find("h5"));
});
});
I run the tests with:
TEST_BROWSER_DRIVER=chrome meteor test --once --driver-package meteortesting:mocha
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.