Giter Club home page Giter Club logo

Comments (22)

brianmcd avatar brianmcd commented on June 5, 2024 3

I'm also seeing this with Jest and a service provided at the component level after upgrading from Angular 8 and ngx-take-until-destroy to @ngneat/until-destroy and Angular 9. I'll see if I can create a repro tomorrow.

from until-destroy.

brianmcd avatar brianmcd commented on June 5, 2024 2

@arturovt @NetanelBasal - Here is a repro repository: https://github.com/brianmcd/until-destroy-bug

What I'm seeing is that if you provide the ExampleService in a Component or Module's providers array, then the test in that repository will fail with TypeError: Cannot read property 'onDestroy' of undefined. If you provide the ExampleService via providedIn: 'root' or providedIn: 'any', then the test passes.

from until-destroy.

arturovt avatar arturovt commented on June 5, 2024 2

@Plysepter I have fixed this issue in this PR. @8.1.3 version has been published there.

from until-destroy.

PabloDotcom avatar PabloDotcom commented on June 5, 2024 1

Thanks @brianmcd. @arturovt I don't use nwrl nx in project I've got the error.

from until-destroy.

NetanelBasal avatar NetanelBasal commented on June 5, 2024

Can you reproduce it, please?

from until-destroy.

PabloDotcom avatar PabloDotcom commented on June 5, 2024

Sure @NetanelBasal. Jest is setup with 'jest-preset-angular' ver. 8.0.0.
package.json command: jest --config jest.config.js

Failed spec:

`import { CtdPopupLoginComponent } from 'layouts/ctdPopup/CtdPopupLoginComponent';
import { of } from 'rxjs';
import { createMockInstance } from 'setup/spyHelper';
import { EnvironmentService } from 'shared/services/abstract/environment/EnvironmentService';
import { UserService } from 'shared/services/abstract/user/UserService';

describe('CtdPopupLoginComponent', () => {
let component: CtdPopupLoginComponent;
let userServiceMock: jest.Mocked;
let environmentServiceMock: jest.Mocked;
let user: any;

beforeEach(() => {
jest.clearAllMocks();

user = {
    name: 'test name',
};

userServiceMock = createMockInstance(UserService, {
    user$: of(user),
});

environmentServiceMock = createMockInstance(EnvironmentService, {
    environmentConfig: {
        dashboard: 'https://test.api.com',
    } as any,
});

component = new CtdPopupLoginComponent(
    userServiceMock,
    environmentServiceMock,
);

});

it('should be a defined component', () => {
expect(component).toBeTruthy();
});

it('should open new window with params', () => {
window.open = jest.fn();
component.goToLoginPage();
expect(window.open).toBeCalled();
const params = 'height=600,width=800,top=-300,
left=-400';
expect(window.open).toBeCalledWith('https://test.api.com', 'User login page', params);
});
});`

Error:
`Test suite failed to run

TypeError: Cannot read property 'onDestroy' of undefined

3 | import { tap } from 'rxjs/operators';
4 | import { EnvironmentService } from 'shared/services/abstract/environment/EnvironmentService';

5 | import { UserService } from 'shared/services/abstract/user/UserService';
| ^
6 |
7 | @UntilDestroy()
8 | @component({

at decorateDirective (node_modules/@ngneat/until-destroy/bundles/ngneat-until-destroy.umd.js:95:49)
at node_modules/@ngneat/until-destroy/bundles/ngneat-until-destroy.umd.js:105:17
at Object..__decorate (src/app/layouts/ctdPopup/CtdPopupLoginComponent.ts:5:95)
at Object. (src/app/layouts/ctdPopup/CtdPopupLoginComponent.ts:12:36)
at Object. (test/unit/platforms/ctd-extension/popup/CtdPopupLoginComponent.spec.ts:1:1)`
I guess, it's because component is created without TestBed (it's not a good arch of tests, but it worked until now and we have a lot of legacy in unit tests now, so it's not that easy to improve them that fast). Anyway the quick fix for that is:

jest.mock('@ngneat/until-destroy', () => ({ ...jest.requireActual('@ngneat/until-destroy'), UntilDestroy: jest.fn().mockImplementation((options: any = {}) => { return (target: any) => { if (!target.ɵprov) { target.ɵprov = true; } return jest.requireActual('@ngneat/until-destroy').UntilDestroy(options)(target); }; }), }));

Maybe there is a better way of checking Injectable than depending on target.ɵprov (injected by ivy compiler)?

from until-destroy.

NetanelBasal avatar NetanelBasal commented on June 5, 2024

Why it's a @component and not @Component?

from until-destroy.

PabloDotcom avatar PabloDotcom commented on June 5, 2024

It was formatted when I've pasted that. Its @Component in source code and in error.
Screen Shot 2020-02-14 at 4 24 36 PM

Sorry for that.

In source code:

`import { Component, OnDestroy } from '@angular/core';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { tap } from 'rxjs/operators';
import { EnvironmentService } from 'shared/services/abstract/environment/EnvironmentService';
import { UserService } from 'shared/services/abstract/user/UserService';

@UntilDestroy()
@component({
selector: 'ctd-popup-login',
templateUrl: 'ctd-popup-login.html',
})
export class CtdPopupLoginComponent implements OnDestroy {`

Those services for tests are created with:
import createMockInstance1 from 'jest-create-mock-instance';

It's obviously problem with Jest environment, but it's because of usage of ivy flags in 'take-until'.
Probably more devs will have problem with that in other runtiime envs too, I guess.

from until-destroy.

NetanelBasal avatar NetanelBasal commented on June 5, 2024

We test the project with Jest, both the playground and the library, and it works fine.

from until-destroy.

arturovt avatar arturovt commented on June 5, 2024

Gentlemen, that would be awesome if you could create a minimal reproducible example for us.

from until-destroy.

arturovt avatar arturovt commented on June 5, 2024

Thank you, Brian! I will try to have a look during the week when I get some free time!

from until-destroy.

brianmcd avatar brianmcd commented on June 5, 2024

No problem. Thanks for looking into it, Artur. I should mention that I generated the repro project with Nx, since that's an easy way to get an app running with Jest. My real project that's hitting this bug is also using Nx. I don't think that should make a difference, but wanted to mention it just in case.

from until-destroy.

arturovt avatar arturovt commented on June 5, 2024

@brianmcd

I was able to reproduce your problem. The issue is here:

ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points

Jest uses the CJS module system and those bundles are provided via UMD.

Before making any changes you can put this into app.component.spec.ts:

import { ɵivyEnabled as ivyEnabled } from '@angular/core';
console.log(`ivyEnabled = ${ivyEnabled}`);
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';

You will see that ivyEnabled = false in your test environment.

You have to remove all flags because Angular Ivy guide mentions that:

Don't use --create-ivy-entry-points as this will cause Node not to resolve the Ivy version of the packages correctly.

Also --first-only is not needed, from its description:

If specified then only the first matching
package.json property will be compiled

So basically that seems weird that you pass these options es2015 browser module main with the --first-only since es2015 will be taken.

So when I ran plain ngcc command w/o anything and then yarn ng test --watch I received that output:
image

from until-destroy.

brianmcd avatar brianmcd commented on June 5, 2024

Thanks so much for looking into this, @arturovt. I changed the postinstall to just run ngcc and things are working now.

The postinstall command ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points was added automatically by Nx, but is also mentioned here. Like you said, the docs do later mention that the flags will cause issue with module resolution in Node.

From digging through issues, it looks like Nx adds the postinstall so that ngcc runs before anything else, which was required for parallel builds. From what I could gather, the Angular CLI team is working on introducing a lockfile that should remove the need for the postinstall script for Nx users.

The relevant issues are:

It's also worth noting that the standard Angular CLI doesn't add any postinstall step, and it seems to only build esm2015 versions, so I think users of the stock CLI who use Jest will see this behavior, too.

from until-destroy.

Rush avatar Rush commented on June 5, 2024

Unfortunately in some cases --create-ivy-entry-points is needed, as per this ticket angular/angular#35000 (comment)

from until-destroy.

arturovt avatar arturovt commented on June 5, 2024

Gentlemen, is it resolved? Can the issue be closed?

from until-destroy.

brianmcd avatar brianmcd commented on June 5, 2024

For me, everything is working with running ngcc with no flags in the postinstall step. Thanks again for your help, @arturovt.

from until-destroy.

Plysepter avatar Plysepter commented on June 5, 2024

I am not sure that this should be considered closed just yet. I've been experiencing this issue myself and running ngcc without any parameters does remove the TypeError: Cannot read property 'onDestroy' of undefined error but I instead encounter the following error when using jest's snapshot feature: PrettyFormatPluginError: Cannot read property 'element' of undefinedTypeError: Cannot read property 'element' of undefined

However if I remove the usage of this library from the code while using NX's default ngcc parameters, the tests all pass. I haven't been able to find the exact reasoning as to why snapshots of the fixture fail when the extra parameters have been added to the ngcc command / when ivy is enabled. However this conflict is preventing my tests from passing and I would greatly appreciate if anyone else might have other suggestions or insights into the matter.

I have forked @brianmcd's example repo here and have added a few branches demonstrating the different variations which can be tested by removing and reinstalling the node_modules folder to recompile with ngcc followed by running the tests ng t. Master is the base that has already been tested but updated with a snapshot test. The other branches are variations of the master branch but either with the ngcc parameters removed or this library commented out.

If anyone can help resolve this, I would be extremely grateful!

from until-destroy.

kremerd avatar kremerd commented on June 5, 2024

I had this issue as well. Changing the postinstall script as suggested by @arturovt solved the primary error described above, but also introduced a new, i18n-related error:

It looks like your application or one of its dependencies is using i18n.
Angular 9 introduced a global `$localize()` function that needs to be loaded.
Please run `ng add @angular/localize` from the Angular CLI.
(For non-CLI projects, add `import '@angular/localize/init';` to your `polyfills.ts` file.
For server-side rendering applications add the import to your `main.server.ts` file.)

In total my tests kept on failing. Fortunately, the solution for this problem was more straight forward: You have to add the line

setupFiles: ['@angular/localize/init']

to the projects test configuration file jest.config.js.

In case that's not clear enough, here's a small bash script to get a minimal example for this scenario up and running:

# Set up a simple nx workspace
npx create-nx-workspace@latest demo
? What to create in the new workspace angular
? Application name demo
? Default stylesheet format CSS
cd demo

# Add some i18n
sed "s/<h1>/<h1 i18n>/" -i apps/demo/src/app/app.component.html
ng add @angular/localize

# Install and use `until-destroy`
npm install @ngneat/until-destroy
sed -e "2i import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';" \
  -e "2i import { of } from 'rxjs';" \
  -e "3i @UntilDestroy()" \
  -e "10i obs$ = of().pipe(untilDestroyed(this));" \
  -i apps/demo/src/app/app.component.ts

# Update the `postinstall` script to `ngcc`
sed "s/ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points/ngcc/" -i package.json
rm -rf node_modules
npm install

# Update Jest config
sed "5i setupFiles: ['./jest.setup.ts']," -i apps/demo/jest.config.js
echo "import '@angular/localize/init';" > apps/demo/jest.setup.ts

# Tests now pass again
ng test

from until-destroy.

Plysepter avatar Plysepter commented on June 5, 2024

As an update on my report: It looks like there are compatibility issues within jest-preset-angular and ivy in the serializer. I believe (at least in the minimum reproduction instance) that running ngcc without any parameters will resolve my use case once thymikee/jest-preset-angular#351 is resolved

from until-destroy.

Plysepter avatar Plysepter commented on June 5, 2024

Thank you @arturovt, it is greatly appreciated!

from until-destroy.

NetanelBasal avatar NetanelBasal commented on June 5, 2024

I'm closing this issue. Please re-open with a reproduction if the problem still exists. Thanks.

from until-destroy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.