jsverse / transloco

πŸš€ 😍 The internationalization (i18n) library for Angular
https://jsverse.github.io/transloco/
MIT License
2.04k stars 197 forks source link

Bug(TranslocoTestingModule): Cannot find module 'flat' #714

Open vankeer opened 1 year ago

vankeer commented 1 year ago

Is there an existing issue for this?

Which Transloco package(s) are the source of the bug?

Transloco

Is this a regression?

No

Current behavior

This occurs:

Those specific Jest tests importing the TranslocoTestingModule will fail with the error:

Cannot find module 'flat' from 'node_modules/@ngneat/transloco/fesm2022/ngneat-transloco.mjs'

This does not occur when using the experimental @angular-devkit/build-angular:jest builder but this is not an option for this specific project, because that experimental builder doesn't support code coverage generation properly.

Expected behavior

Jest tests should work when importing the TranslocoTestingModule

Please provide a link to a minimal reproduction of the bug, if you won't provide a link the issue won't be handled.

https://github.com/vankeer/transloco-sandbox/tree/transloco-testing-bug

Transloco Config

export function getTranslocoTestingModule(options: TranslocoTestingOptions = {}) {
  return TranslocoTestingModule.forRoot({
    langs: { en, es },
    translocoConfig: {
      availableLangs: ['en', 'es'],
      defaultLang: 'en',
    },
    preloadLangs: true,
    ...options
  });
}

### Please provide the environment you discovered this bug in

```markdown
Transloco: 5
Angular: 16(.2)
Node: 18(.18) (also occurs in 16)
Package Manager: NPM 9.8.1
OS: Mac OS X Ventura 13.5.2

Browser

N/A

Additional context

Explicitly installing the flat module does not help (but should not be necessary anyway).

Run npx jest or npx ng test in the linked demo repo.

Side-note, but commit 290920b645b94845ff0265451e2af560b083b98d shows a working version using the experimental @angular-devkit builder for Jest.

Related issues (that do not provide a solution for this specific problem as far as I can tell):

I would like to make a pull request for this bug

No

Digni commented 1 year ago

We have the same issue after upgrading to Transloco Version 5, an upgrade to version 6 does not help. Downgrading to version 4.X.X lets us run our tests again. We' re on Angular 16, so version 5 is recommended but at least in our case it seems to be working so far.

devfservant commented 1 year ago

Personally, I have no issue with Transloco v5, only with v6

danipavic commented 1 year ago

Have this issue on a new project using Transloco 6.0.0 and Jest 29.4.1

minijus commented 1 year ago

Looks like a duplicate of https://github.com/ngneat/transloco/issues/704. It seems v6 was on purpose released as major version because of this breaking change, see comment https://github.com/ngneat/transloco/issues/704#issuecomment-1729253257.

I have minimal nx workspace setup with reproduction of this issue:

image Full run details: https://github.com/minijus/transloco-jest/actions/runs/6546630677/job/17777465759

Update: "quick fix" could be to override flat with v5.0.2 as in this change: https://github.com/minijus/transloco-jest/pull/1/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519

jkremlacek commented 1 year ago

Same issue for us.

I managed to make Jest work with Transloco v6 by switching option useESM: true in Jest config (combined with many other changes that are consequence of switching Jest to use ESM when combined with jest-preset-angular). However this solution cannot be used outside of development experimentation for us as it requires node --experimental-vm-modules --no-cache to be used as launcher for Jest.

Piiiiiiiiiiiim commented 1 year ago

the flat package is now distributed in the ECMAScript module syntax. You'll need to transform code inside the flat package into plain JavaScript. You can do this by including it in the Jest code transformation. e.g. your jest.config.ts should look like this:

  transform: {
    '^.+\\.(ts|mjs|js|html)$': [
      'jest-preset-angular',
      {
        tsconfig: '<rootDir>/tsconfig.spec.json',
        stringifyContentPathRegex: '\\.(html|svg)$',
      },
    ],
  },
 // Ignore node_modules except for .mjs files and the @ngneat package. 
  transformIgnorePatterns: ['node_modules/?!(.*\\.mjs$|@ngneat)'],
jkremlacek commented 1 year ago

What ended up working for us was changing jest.config.js to contain:

const { pathsToModuleNameMapper } = require('ts-jest');

const moduleNameMapper = pathsToModuleNameMapper({}, {
  prefix: '<rootDir>/',
});

moduleNameMapper['flat'] = '<rootDir>/node_modules/flat/index.js';

module.exports = {
    ...
  moduleNameMapper,
  transformIgnorePatterns: ['node_modules/?!(.*\\.mjs$)']
};

Tests run a bit slower (cache enabled), from about 30s went up to 40s.

vankeer commented 1 year ago

Thanks for your replies!

@jkremlacek that Jest config ended up working for me: I updated the ng16 sandbox repo provided with this issue https://github.com/vankeer/transloco-sandbox/blob/bugfix/714-cannot-find-module-flat/jest.config.ts

Downgrading to 5.0.7 instead of 5.0.10 also fixes the issue, so the issue is clearly related to the last changes in those Transloco patch versions.

When I run Jest with ng test I still get the error: Expected to be running in 'ProxyZone', but it was not found.. This is fixed when I comment out the line in setup-jest.ts (or remove setupFilesAfterEnv in the jest config) but then the jest command doesn't work anymore because zone-testing.js is missing.

dmytro-afonin commented 1 year ago

When should we expect fix?

dmytro-afonin commented 1 year ago

Indeed downgrading to 5.0.7 works for me as well

shaharkazaz commented 1 year ago

@dmytro-afonin When the war in my country is over.

This is more of a documentation issue. flat is used by Transloco at runtime so it makes sense to use ESM instead of commonjs as it was up until now ( there was no ESM distribution ).

As I wrote (and you can see both on the versions themselves and on the Transloco changelog) versions 5.0.8-10 are deprecated as they contain the breaking change of upgrading flat to ESM.

I invite all of you to find and share the best solution for using ESM on jest as this change should stay IMO (security reasons, ESM on browser).

You are welcome to share thoughts, though please note that I won't be available to respond anytime soon.

wall-street-dev commented 1 year ago

Perhaps a simpler solution could be mapping the flat dependency? Here's how my jest.preset.js looks like:


const nxPreset = require('@nrwl/jest/preset').default;

module.exports = {
    ...nxPreset,
    setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
    coverageReporters: ['html', 'json', 'lcov'],
    transform: {
        '^.+\\.(ts|mjs|html)$': [
            'jest-preset-angular',
            {
                tsconfig: '<rootDir>/tsconfig.spec.json',
                stringifyContentPathRegex: '\\.(html|svg)$',
                isolatedModules: true,
                diagnostics: false
            }
        ]
    },
    transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
    moduleNameMapper: {
        '^flat': 'node_modules/flat/index.js'
    },
    snapshotSerializers: [
        'jest-preset-angular/build/serializers/no-ng-attributes',
        'jest-preset-angular/build/serializers/ng-snapshot',
        'jest-preset-angular/build/serializers/html-comment'
    ]
};
maximeqontrol commented 1 year ago

Perhaps a simpler solution could be mapping the flat dependency? Here's how my jest.preset.js looks like:


const nxPreset = require('@nrwl/jest/preset').default;

module.exports = {
    ...nxPreset,
    setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
    coverageReporters: ['html', 'json', 'lcov'],
    transform: {
        '^.+\\.(ts|mjs|html)$': [
            'jest-preset-angular',
            {
                tsconfig: '<rootDir>/tsconfig.spec.json',
                stringifyContentPathRegex: '\\.(html|svg)$',
                isolatedModules: true,
                diagnostics: false
            }
        ]
    },
    transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
    moduleNameMapper: {
        '^flat': 'node_modules/flat/index.js'
    },
    snapshotSerializers: [
        'jest-preset-angular/build/serializers/no-ng-attributes',
        'jest-preset-angular/build/serializers/ng-snapshot',
        'jest-preset-angular/build/serializers/html-comment'
    ]
};

This solution works fine for me thank you !

kevintyj commented 11 months ago

Been trying all of these solutions, does not seem to work on a pnpm based nx monorepo. Have tried: Explicitly adding @5.0.2 as a dev dependency and using moduleNameMapper to map the dependency Tried adding |@ngneat pattern to transformIgnorePatterns Downgrading transloco to v 5 or below (Seems to not work properly with ng17/standalone components)

shaharkazaz commented 11 months ago

@kevintyj Transloco v5.0.7 should have the cjs version of flat and ng 16 support

kevintyj commented 11 months ago

@kevintyj Transloco v5.0.7 should have the cjs version of flat and ng 16 support

Thank you so much for the response. We would love to stay on ng17, still looking for ways to fix this, but it's quite a big of a bottleneck for our pipeline at the moment. We are going to try to manually transpile ESM flat dependency to CJS somehow in the build step reliably, but it seems to spit out other errors.

shaharkazaz commented 11 months ago

@kevintyj I'll clarify, it supports v16 and above (at least it should) so you can keep using angular v17.

Did you encounter any issues?

dziraev commented 11 months ago

Have this issue on a project with angular v17, Transloco 6.0.1 and Jest 29.5.10

elmarbeckmann commented 10 months ago

@guzmanoj Perfect, this is the easiest solution, thank you. Hopefully Jest will make it easier for us in the future.

I am now using the following combination: NX 17.2.8 Angular 17.0.9 Jest 29.7.0 jest-preset-angular 13.1.6 @ngneat/transloco 6.0.4

All is now working by adding the following to jest.preset.js in the root.

  moduleNameMapper: {
    '^flat': 'node_modules/flat/index.js',
  },
jjs98 commented 8 months ago

As mentioned in #704 already:

transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$|.pnpm|flat/)'],

works just fine for me

using version "nx": "18.2.1", "@jsverse/transloco": "^7.1.0",

dhutaryan commented 7 months ago

@jjs98 didn't work for me, still have the following error

Details:

    /node_modules/@jsverse/transloco/node_modules/flat/index.js:12
    export function flatten (target, opts) {
    ^^^^^^

    SyntaxError: Unexpected token 'export'

"@jsverse/transloco": "^7.1.0"

shaharkazaz commented 6 months ago

Would anyone want to add a documentation section on the possible solutions for the jest/ESM issues addressed here?

skatterwe commented 4 months ago

@jjs98 didn't work for me, still have the following error

Details:

    /node_modules/@jsverse/transloco/node_modules/flat/index.js:12
    export function flatten (target, opts) {
    ^^^^^^

    SyntaxError: Unexpected token 'export'

"@jsverse/transloco": "^7.1.0"

Make sure that the transformIgnorePattern is correct. I had a slightly wrong version before and also got that error after having added the mapping. instead of this: transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], try this: transformIgnorePatterns: ['node_modules/?!(.\\*.mjs$|@jsverse)'],

We needed to make this change for any repo that used a library that had transloco as a peerDependency.

Find a bit more things I investigated here: https://github.com/jsverse/transloco/discussions/735#discussioncomment-10187588

rnogueira-namoadigital commented 3 months ago

this help me out to upgrade angular 17 to 18 and Transloco 6 to 7. I only had to use in jest config

    moduleNameMapper: {
        '^flat': 'node_modules/flat/index.js'
    },
Kaemmelot commented 1 week ago

In case someone else has this problem in an Nx monorepo: Keep in mind that there are jest configs in each module that probably already define the transformIgnorePatterns that you might be tempted to define in the jest.preset.js. I spend too much time without realizing that my changes in the preset had no effect because this setting was overwritten in the modules.