Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jest unit testing no longer works with Ionic 4 beta 9-11 #15695

Closed
russcarver opened this issue Sep 20, 2018 · 37 comments
Closed

Jest unit testing no longer works with Ionic 4 beta 9-11 #15695

russcarver opened this issue Sep 20, 2018 · 37 comments
Labels
package: angular @ionic/angular package package: core @ionic/core package triage type: bug a confirmed bug report

Comments

@russcarver
Copy link

Bug Report

Ionic Info
Run ionic info from a terminal/cmd prompt and paste the output below.

Ionic:

   ionic (Ionic CLI)          : 4.1.2
   Ionic Framework            : @ionic/angular 4.0.0-beta.11
   @angular-devkit/core       : 0.8.3
   @angular-devkit/schematics : 0.8.3
   @angular/cli               : 6.2.3
   @ionic/ng-toolkit          : 1.0.7
   @ionic/schematics-angular  : 1.0.6

Cordova:

   cordova (Cordova CLI) : 7.1.0
   Cordova Platforms     : none
   Cordova Plugins       : no whitelisted plugins (0 plugins total)

System:

   Android SDK Tools : 26.1.1 (/Users/rc101077/Library/Android/sdk)
   ios-deploy        : 2.0.0
   ios-sim           : 7.0.0
   NodeJS            : v8.11.4 (/Users/rc101077/.nvm/versions/node/v8.11.4/bin/node)
   npm               : 6.4.1
   OS                : macOS High Sierra
   Xcode             : Xcode 9.4.1 Build version 9F2000

Describe the Bug
Jest unit testing no longer works with Ionic 4 beta 9. An error appears for each spec file that relies on Ionic as such:

Cannot find module '@ionic/core/loader' from 'app-initialize.js'
  at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:221:17)
  at Object.<anonymous> (node_modules/@ionic/angular/dist/app-initialize.js:1:1)

Steps to Reproduce
Steps to reproduce the behavior:

  1. Create an Ionic project with a Jest unit test setup (Jest version 22+)
  2. Run the unit tests
  3. See the error above for every file using Ionic imports

Expected Behavior
There should be no errors and all the unit tests should pass.

Additional Context
This looks to be broken with Ionic 4 beta 9, 10 and 11. It works fine in beta 8.

@ionitron-bot ionitron-bot bot added the triage label Sep 20, 2018
@tja4472
Copy link
Contributor

tja4472 commented Sep 21, 2018

  • Create blank file, <rootDir>/node_modules/@ionic/core/loader/loader.ts

  • Add the following to package.json, moduleNameMapper

    "^@ionic/core/loader":"<rootDir>/node_modules/@ionic/core/loader/loader.ts"

My package.json Jest config

  "jest": {
    "preset": "jest-preset-angular",
    "setupTestFrameworkScriptFile": "<rootDir>/src/setupJest.ts",
    "moduleNameMapper": {
      "^@app/(.*)": "<rootDir>/src/app/$1",
      "^@ionic/core/loader": "<rootDir>/node_modules/@ionic/core/loader/loader.ts"
    },
    "transformIgnorePatterns": [
      "<rootDir>/node_modules/(?!@ngrx|@ionic-native|@ionic)"
    ]
  }

@paulsouche
Copy link

paulsouche commented Sep 21, 2018

Hi,

Same issue here ! That's because @ionic/core/loader package.json has no main property. Looking forward to find how to tell jest to resolve module property.

{"name":"loader","typings":"./index.d.ts","module":"../dist/esm/es5/ionic.define.js","es2017":"../dist/esm/es2017/ionic.define.js"}

EDIT

It works with

"moduleNameMapper": {
  "^@ionic/core/loader": "<rootDir>/node_modules/@ionic/core/dist/esm/es5/ionic.define.js"
},

But should be better to not add this...

@russcarver
Copy link
Author

Thanks @paulsouche your moduleNameMapper worked for me! But I agree we shouldn't have to put this in.

@russcarver
Copy link
Author

FYI, this problem still exists in Ionic beta 12. But in addition, the same tests in beta 12 now show this error:

 FAIL  src/app/app.component.spec.ts
  Test suite failed to run

    Cannot find module '@ionic/angular' from 'app.component.spec.ts'

       5 | import { SplashScreen } from '@ionic-native/splash-screen/ngx';
       6 | import { StatusBar } from '@ionic-native/status-bar/ngx';
    >  7 | import { Platform } from '@ionic/angular';

I've tried adding "^@ionic/angular": "<rootDir>/node_modules/@ionic/angular/dist/index", to the moduleNameMapper of Jest, but that just changes the error to:

 FAIL  src/app/app.component.spec.ts
  Test suite failed to run

    TypeError: require.context is not a function

      at Object.<anonymous> (node_modules/@ionic/core/dist/ionic/svg/index.js:1:36)
      at Object.<anonymous> (node_modules/@ionic/angular/dist/app-initialize.js:5:1)
      at Object.<anonymous> (node_modules/@ionic/angular/dist/ionic-module.js:6:24)
      at Object.<anonymous> (node_modules/@ionic/angular/dist/index.js:7:22)
      at Object.<anonymous> (src/app/app.component.spec.ts:90:17)

For now, I'm reverting back to beta 11 until a solution can be found.

@ajcrites
Copy link
Contributor

ajcrites commented Oct 9, 2018

Using version 11 of the beta with the suggested configuration above, I get:

    SyntaxError: Unexpected token {

from import { StatusBar } from '@ionic-native/status-bar'.

I can fix this using babel: https://stackoverflow.com/questions/52651907/unexpected-token-export-with-jest

...but then I get a very strange unexpected token error from the import loader .js files.

@russcarver
Copy link
Author

Don't forget you need /ngx on the end of that import.

@ajcrites
Copy link
Contributor

ajcrites commented Oct 9, 2018

@russcarver thank you, but now I get import { Injectable } from '@angular/core';: SyntaxError: Unexpected token { in @ionic-native/status-bar/ngx/index.js:22. By any chance do you have a publicly available repository with working jest for Ionic 4?

@russcarver
Copy link
Author

Yes! Here's a link to my Ionic4 starter repo that I've been keeping up to date over the months.

https://github.com/russcarver/ionic4-project-template

The master branch is up to date as of today and should have what you need.

@ajcrites
Copy link
Contributor

ajcrites commented Oct 10, 2018

Ultimately my problem was not having allowJs in my TypeScript configuration. My configurations:

Jest configuration:

module.exports = {
  preset: 'jest-preset-angular',
  setupTestFrameworkScriptFile: '<rootDir>/src/setupJest.ts',
  moduleNameMapper: {
    '^@ionic/core/loader': '<rootDir>/node_modules/@ionic/core/dist/esm/es5/ionic.define.js',
  },
  transformIgnorePatterns: [
    '<rootDir>/node_modules/(?!@ngrx|@ionic-native|@ionic|ionic-angular|@angular)',
  ],
  transform: {
    '^.+\\.(ts|js|html)$': '<rootDir>/node_modules/jest-preset-angular/preprocessor.js',
    '^.+\\.ts': '<rootDir>/node_modules/ts-jest/preprocessor.js',
  },
};

tsconfig:

{
  "compilerOptions": {
    "allowJs": true,
    "target": "esnext",
    "module": "commonjs",
    "moduleResolution": "node",
    "declaration": false,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "skipLibCheck": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": ["es6", "dom"]
  }
}

@russcarver
Copy link
Author

Glad you figured it out!

@paulsouche
Copy link

Hi,

Since beta.12 (and in beta.13), @russcarver Error TypeError: require.context is not a function is still present. This is due to svg imports in /dist/ionic/index.js

require.context('!!file-loader?name=[name].[ext]&outputPath=svg!./', false, /.svg$/);

In beta.11 require.context was tested

if (require && require.context) {
  require.context('!!file-loader?name=[name].[ext]&outputPath=svg!./', false, /.svg$/);
}

Looking forward for a workaround trying to declare require.context in jest setup but didn't find one yet... If anyone has a clue help is really appreciated.

Thanks

@russcarver
Copy link
Author

I put in a temporary fix for this by substituting the missing check into a replacement script loaded by Jest.

Now I have:

"moduleNameMapper": {
      "^@ionic/core/loader": "<rootDir>/node_modules/@ionic/core/dist/esm/es5/ionic.define.js",
      "^@ionic/core/dist/ionic/svg": "<rootDir>/scripts/svgoverride.js"
 },

and my svgoverride.js script is:

if (require && require.context) {
  require.context('!!file-loader?name=[name].[ext]&outputPath=svg!./', false, /.svg$/);
}

Feel free to check it out on my repo (currently master or v0.0.2). I've also updated a lot of packages to the latest:
https://github.com/russcarver/ionic4-project-template/tree/master

@picheli20
Copy link

@ajcrites love you man! :P I'm hours trying to figure out that!

@paulstelzer
Copy link
Contributor

Thanks for your issue! I think you made workarounds, correct? Could you please explain how it can be fixed or maybe push a PR? Otherwise I would set it under investigation

@paulstelzer paulstelzer added needs: reply the issue needs a response from the user and removed triage labels Dec 7, 2018
@russcarver
Copy link
Author

You can see my temporary fix in my last comment above. I have not tried removing the fix since to see if anything has changed.

@ionitron-bot ionitron-bot bot added triage and removed needs: reply the issue needs a response from the user labels Dec 7, 2018
@ajcrites
Copy link
Contributor

ajcrites commented Dec 7, 2018

@russcarver @paulstelzer I've tested with beta 17. Most of the advice in this thread still applies, summarized here:

  • allowJs needs to be true for TypeScript config.
  • Your svgoverride.js needs to be mapped if you have tests that import Ionic modules. This is true regardless of whether your app has or uses any svgs at all.

From what I can see, the @ionic/core/loader mapping is no longer needed.

My currently working jest configuration:

module.exports = {
  preset: 'jest-preset-angular',
  // just has `import 'jest-preset-angular';` as required
  setupTestFrameworkScriptFile: '<rootDir>/src/setupJest.ts',
  moduleNameMapper: {
    '^@ionic/core/dist/ionic/svg': '<rootDir>/svgoverride.js',
  },
  transformIgnorePatterns: [
    '<rootDir>/node_modules/(?!@ngrx|@ionic)',
  ],
};

The svgoverride.js is what you provided:

if (require && require.context) {
  require.context('!!file-loader?name=[name].[ext]&outputPath=svg!./', false, /.svg$/);
}

Note that allowJs is not set in the configuration created by ionic start. You will have to add it to whatever TypeScript configuration you use for testing.


In summary, the only fix for jest I would suggest is to update/fix svgoverride.js to check for require.context, although I'm not sure why this is needed. It's possibly something that can be fixed on the jest side.

I'm not sure why allowJs is not in the default config either, but adding it may have other implications. I haven't seen this yet, though. It could possibly be enabled for tsconfig.spec.json, but I'm not sure if that would impact the jasmine tests.

I'm also not 100% sure that the core module mapper is not needed. It might be needed in some other cases.

@Majed93
Copy link

Majed93 commented Dec 17, 2018

New error on beta.19


..\node_modules\ionicons\icons\index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){export * from '../dist/ionicons/svg/index.esm.js';
                                                                                             ^^^^^^

    SyntaxError: Unexpected token export

@ajcrites
Copy link
Contributor

See jestjs/jest#2663

There are potentially many ways to fix it. I updated my jest config like so and it seems to be working:

{
  transform: {
    '^.+\\.svg$': 'jest-transform-stub',
  },
  preset: 'jest-preset-angular',

  // imports 'jest-preset-angular'
  setupTestFrameworkScriptFile: '<rootDir>/src/setupJest.ts',

  // added 'ionicons'
  transformIgnorePatterns: [
    '<rootDir>/node_modules/(?!@ngrx|@ionic|ionicons)',
  ],
};

Seems like the svgoverride.js may no longer be needed, though.

@Majed93
Copy link

Majed93 commented Dec 17, 2018

Yeah i tried that but get this:

TypeError: ionicons_1.addIcons is not a function 

beforeEach(async () => {
fixture = TestBed.createComponent(TestPage);
                            ^

@ptitjes
Copy link
Contributor

ptitjes commented Dec 25, 2018

@ajcrites, thanks. That worked for me.

@ajcrites
Copy link
Contributor

ajcrites commented Jan 24, 2019

I've taken another look at this now that Ionic v4 has been published. This issue can probably be closed, although arguably there are some changes that can be made to tsconfig.spec.json.

My latest updates + walkthrough for jest setup:

Sample repository: https://github.com/ajcrites/ionic-jest-testing-example

First, npm install --save-dev jest jest-preset-angular.

Create your jest configuration as you see fit. Minimally you will need:

{
  preset: 'jest-preset-angular',
  setupTestFrameworkScriptFile: '<rootDir>/src/setupJest.ts',
  transformIgnorePatterns: [
    '<rootDir>/node_modules/(?!@ionic)',
  ],
};

You will also need to create the setupTestFrameworkScriptFile. You can make this file whatever you want. I've named it src/setupJest.ts and put it there. It should at least contain:

import 'jest-preset-angular';

If you are using tsconfig.spec.json you will have to add "module": "commonjs" and "allowJs": true". Mine looked like this after updating:

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/spec",
    "types": [
      "jasmine",
      "node"
    ],
    "module": "commonjs",
    "allowJs": true
  },
  "files": [
    "test.ts",
    "polyfills.ts"
  ],
  "include": [
    "**/*.spec.ts",
    "**/*.d.ts"
  ]
}

Now you're all set to test with jest.

e2e should still work, but it does depend on karma and jasmine.


The default test for app.component.spec.ts uses jasmine for some things, so you will have to update it if you want to use it. I've done this in the sample repo: https://github.com/ajcrites/ionic-jest-testing-example/blob/master/src/app/app.component.spec.ts.

Individual needs for TypeScript configuration will also vary. I got the tests to work using just:

{
  "compilerOptions": {
    "module": "commonjs",
    "allowJs": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true
  }
}

@russcarver
Copy link
Author

I was able to get the hacks removed finally. I've removed the following section completely.

"moduleNameMapper": {
      "^@ionic/core/loader": "<rootDir>/node_modules/@ionic/core/dist/esm/es5/ionic.define.js",
      "^@ionic/core/dist/ionic/svg": "<rootDir>/scripts/svgoverride.js"
 },

I'm now using:

"@types/jest": "24.0.9",
"jest": "23.6.0",
"jest-preset-angular": "6.0.2",
"jest-zone-patch": "0.0.10"

And my ionic/cordova config is:

   ionic (Ionic CLI)             : 4.9.0
   Ionic Framework               : @ionic/angular 4.0.0
   @angular-devkit/build-angular : 0.12.3
   @angular-devkit/schematics    : 7.2.3
   @angular/cli                  : 7.3.4
   @ionic/angular-toolkit        : 1.2.3

Cordova:
   cordova (Cordova CLI) : 7.1.0

For Angular, I'm using 7.2.7

I will note that Jest 24.0.0+ makes some changes that are breaking. I have not had time to figure out all of these yet.

@russcarver
Copy link
Author

russcarver commented Mar 9, 2019

I have updated my Git repo with the changes (and updates to Ionic4 and Angular7).

https://github.com/russcarver/ionic4-project-template

@ajcrites
Copy link
Contributor

ajcrites commented Mar 9, 2019

My current setup is:

// jest config
module.exports = {
  preset: 'jest-preset-angular',
  setupFilesAfterEnv: ['<rootDir>/src/setupJest.ts'],
  transformIgnorePatterns: [
    '<rootDir>/node_modules/(?!@ngrx|@ionic|ionicons)',
  ],
};
// setupJest.ts
import 'jest-preset-angular';

tsconfig:

{
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "moduleResolution": "node",
    "declaration": false,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "forceConsistentCasingInFileNames": true,
    "lib": ["dom", "es7"],
    "skipLibCheck": true,
    "noEmit": true,
    "allowJs": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true
  }
}

This works without any hacks per se with:

  • @ionic/angular - v4.1
  • jest - v24.3
  • jest-preset-angular - v6.0
  • Angular v7

However, there may be certain other libraries or items tested that may require additional hacks.

@GregOnNet
Copy link

GregOnNet commented Apr 25, 2019

I experience the same issue.
Since jest-preset-angular received a major update to version 7 russcarver/ionic4-project-template stopped working for me.

I spent a little time investigating the problem and set up a new ionic project using the following package-versions

package version
@ionic/angular 4.1
@angular-builders/jest 7.4.2
jest-preset-angular 7.1
@angular/* 7.2.2
@babel/preset-env 7.4.3

Here is the sample repository: GregOnNet/ionic-4-jest-setup

I wrote a small article discussing why @ionic/angular fails to run with Jest: How to set up Jest in an Ionic 4 project

I am glad if this helps somebody.

@abierbaum
Copy link

@GregOnNet Looks like something changed in the deps for https://github.com/GregOnNet/ionic-4-jest-setup in the last couple weeks that broke the method this repo uses to work.

> yarn install
> npm run test

Gets this error:

 FAIL  src/app/app.component.spec.ts
  ● Test suite failed to run

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

    Details:

    /home/allenb/Source/ionic-4-jest-setup/node_modules/@ionic/core/dist/esm/es5/ionic.core.js:120
                  return import(
                         ^^^^^^

    SyntaxError: Unexpected token import

      at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:471:17)

Test Suites: 1 failed, 4 passed, 5 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        8.291s
Ran all test suites.

I am going to hack on it a bit and see if I find what changed, but wanted to check to see if you have seen this breakage as well.

@abierbaum
Copy link

Found the issue. Needs an allowJs added to the tsconfig.spec.json file.

@brandyscarney
Copy link
Member

Thank you for the issue and all of the debugging by everyone! Would anyone be willing to submit a PR to our Angular starter for what all needs to change to make this work? Here is the source for it: https://github.com/ionic-team/starters/tree/master/angular/base

@russcarver
Copy link
Author

I have updated https://github.com/russcarver/ionic4-project-template/tree/master with the upgrade as well.

@aphiratnimanussonkul
Copy link

Ultimately my problem was not having allowJs in my TypeScript configuration. My configurations:

Jest configuration:

module.exports = {
  preset: 'jest-preset-angular',
  setupTestFrameworkScriptFile: '<rootDir>/src/setupJest.ts',
  moduleNameMapper: {
    '^@ionic/core/loader': '<rootDir>/node_modules/@ionic/core/dist/esm/es5/ionic.define.js',
  },
  transformIgnorePatterns: [
    '<rootDir>/node_modules/(?!@ngrx|@ionic-native|@ionic|ionic-angular|@angular)',
  ],
  transform: {
    '^.+\\.(ts|js|html)$': '<rootDir>/node_modules/jest-preset-angular/preprocessor.js',
    '^.+\\.ts': '<rootDir>/node_modules/ts-jest/preprocessor.js',
  },
};

tsconfig:

{
  "compilerOptions": {
    "allowJs": true,
    "target": "esnext",
    "module": "commonjs",
    "moduleResolution": "node",
    "declaration": false,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "skipLibCheck": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": ["es6", "dom"]
  }
}

Thank so much i spend my whole week for this error

@Yohandah
Copy link

Yohandah commented Jun 12, 2020

Still having the issue. As everyone said previously I had to add this to my jest config (jest-setup.ts or package.json > "jest" object) :

"transformIgnorePatterns": [
    "node_modules/(?!@ionic-native|@ionic)"
],

and this to my tsconfig.spec.json :

"compilerOptions": {
    "allowJs": true,
    ...
}

@EduardoSimon
Copy link

@Yohandah Worked for me!

@liamdebeasi
Copy link
Contributor

Hi everyone,

Does this issue still reproduce in the latest version of Ionic 6?

@liamdebeasi liamdebeasi added the needs: reply the issue needs a response from the user label Sep 28, 2022
@GregOnNet
Copy link

Hi @liamdebeasi,

sorry, but I cannot answer your question.
I haven't worked with Ionic for a couple of months and have no time to investigate in this issue.

@ionitron-bot ionitron-bot bot added triage and removed needs: reply the issue needs a response from the user labels Oct 3, 2022
@Yohandah
Copy link

Yohandah commented Oct 3, 2022

It works with my fix never tried without it. And I no longer work on an Ionic project atm sorry Liam

@liamdebeasi
Copy link
Contributor

No problem at all. I am going to close this issue for now, but feel free to reply to this if anyone is still running into issues. Thanks!

@ionitron-bot
Copy link

ionitron-bot bot commented Nov 2, 2022

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

@ionitron-bot ionitron-bot bot locked and limited conversation to collaborators Nov 2, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
package: angular @ionic/angular package package: core @ionic/core package triage type: bug a confirmed bug report
Projects
None yet
Development

No branches or pull requests