nx icon indicating copy to clipboard operation
nx copied to clipboard

Test Failure with Cypress and Angular 16 when Importing from Libraries

Open mnkyjs opened this issue 1 year ago • 1 comments

Current Behavior

I am writing to report an issue I encountered while using the NX Workspace in an Angular 16 application.

I believe there might be a bug or an underlying issue causing this test failure. I would like to report this problem to the NX team as a bug issue.

Could you please guide me on the best way to proceed? I appreciate any assistance or insights you can provide to help me resolve this issue.

Thank you for your time and support.

PS when I use the relative path to the function, the test executed without any errors

Expected Behavior

  • The test function imported from the library should execute successfully within the Cypress test.
  • The test case should pass without any unexpected failures.
  • The functionality or behavior being tested should work as intended without any errors or issues.

GitHub Repo

No response

Steps to Reproduce

  1. Set up a new workspace in the latest version of NX.
  2. Ran Cypress tests, and they executed without any errors.
  3. Created a new library within the workspace.
  4. Wrote a test function within the library and used it in a Cypress test by importing it via the lib-path.
  5. However, when running the test, it failed unexpectedly with this error.

Nx Report

Node   : 18.16.1
   OS     : darwin-arm64
   npm    : 9.7.2
   
   nx                 : 16.4.1
   @nx/js             : 16.4.1
   @nx/jest           : 16.4.1
   @nx/linter         : 16.4.1
   @nx/workspace      : 16.4.1
   @nx/angular        : 16.4.1
   @nx/cypress        : 16.4.1
   @nx/devkit         : 16.4.1
   @nx/eslint-plugin  : 16.4.1
   @nrwl/tao          : 16.4.1
   @nx/web            : 16.4.1
   @nx/webpack        : 16.4.1
   typescript         : 5.1.6

Failure Logs

`Error: Webpack Compilation Error
/Users/dennis/Documents/dev/newcubator/test-me/node_modules/@angular/core/fesm2022/core.mjs 1637:50
Module parse failed: Unexpected token (1637:50)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|             dependencies: baseDef.standalone && componentDefinition.dependencies || null,
|             getStandaloneInjector: null,
>             signals: componentDefinition.signals ?? false,
|             data: componentDefinition.data || {},
|             encapsulation: componentDefinition.encapsulation || ViewEncapsulation$1.Emulated,
 @ /Users/dennis/Documents/dev/newcubator/test-me/libs/test-me-lib/src/lib/test-me-lib.module.ts 2:0-41 7:4-12
 @ /Users/dennis/Documents/dev/newcubator/test-me/libs/test-me-lib/src/index.ts
 @ ./src/e2e/app.cy.ts
    at handle (/Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/webpack-preprocessor/dist/index.js:212:23)
    at finalCallback (/Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/webpack/lib/Compiler.js:257:39)
    at /Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/webpack/lib/Compiler.js:306:14
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
    at AsyncSeriesHook.lazyCompileHook (/Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/tapable/lib/Hook.js:154:20)
    at /Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/webpack/lib/Compiler.js:304:22
    at Compiler.emitRecords (/Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/webpack/lib/Compiler.js:499:39)
    at /Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/webpack/lib/Compiler.js:298:10
    at /Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/webpack/lib/Compiler.js:485:14
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
    at AsyncSeriesHook.lazyCompileHook (/Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/tapable/lib/Hook.js:154:20)
    at /Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/webpack/lib/Compiler.js:482:27
    at /Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/neo-async/async.js:2818:7
    at done (/Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/neo-async/async.js:3522:9)
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
    at AsyncSeriesHook.lazyCompileHook (/Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/tapable/lib/Hook.js:154:20)
    at /Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/node_modules/webpack/lib/Compiler.js:464:33
    at /Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/packages/server/node_modules/graceful-fs/graceful-fs.js:143:16
    at /Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/packages/server/node_modules/graceful-fs/graceful-fs.js:143:16
    at /Users/dennis/Library/Caches/Cypress/12.16.0/Cypress.app/Contents/Resources/app/packages/server/node_modules/graceful-fs/graceful-fs.js:61:14
    at FSReqCallback.oncomplete (node:fs:198:23)`

Operating System

  • [X] macOS
  • [ ] Linux
  • [ ] Windows
  • [ ] Other (Please specify)

Additional Information

No response

mnkyjs avatar Jun 30 '23 11:06 mnkyjs

Same problem within our Monorepo after Angular 16 upgrade.

marsc avatar Jul 04 '23 11:07 marsc

It seems that in our setup a similar issue persists. We have been able to omit the error, though the tests will still fail since this is not a valid solution. (Cypress version: 12.17.0)

For this example, we have two tests as follows:

// utils/selector.ts (exported to utils/index.ts)
export const wrapSelector = (selector: string): string => {
    return `[data-cy=${selector}]`;
};
// e2e/example.cy.ts
import { wrapSelector } from '../utils';

describe('test', () => {
    it('Should not fail', () => {
        // test to ensure Cypress still works without import
        cy.visit('/');
    });

    it('should not crash', () => {
        cy.get(wrapSelector('yeet')).should('be.undefined');
    });
});

If we run this, we get the exact error specified in the bug report at the top. If, however, we remove the import but keep the rest of the file, the test will not crash as fatally. The test will fail on the missing import, but every test suite is found.

Example test failing

Regardless of the size of the test, commenting (or removing) all the imports will not show the initial error, but as said earlier, this is not a solution. Importing from a sibling file does not work either.

NX report:

   Node   : 16.17.0
   OS     : darwin-x64
   npm    : 8.15.0

   nx                 : 16.4.2
   @nx/js             : 16.4.2
   @nx/jest           : 16.4.2
   @nx/linter         : 16.4.2
   @nx/workspace      : 16.4.2
   @nx/angular        : 16.4.2
   @nx/cypress        : 16.4.2
   @nx/devkit         : 16.4.2
   @nx/eslint-plugin  : 16.4.2
   @nrwl/tao          : 16.4.2
   @nx/webpack        : 16.4.2
   typescript         : 5.1.6

WHeirstrate avatar Jul 07 '23 10:07 WHeirstrate

@mnkyjs have you been able to resolve the reported issue?

WHeirstrate avatar Jul 18 '23 12:07 WHeirstrate

Hi @WHeirstrate we have still the same error and are back on Angular 15 for now.

mnkyjs avatar Jul 19 '23 12:07 mnkyjs

this looks like you are importing angular code within a e2e test for cypress, which is going to cause all kinds of issues and shouldn't be done.

if your entrypoint (usually index.ts) for the library includes any usage of angular dependencies you'll end up loaded that as well even if you only using 1 function that doesn't use angular code since the whole index.ts file is used.

here is an example repo showing an angular app being tested with cypress e2e and using another library to create utils to use within cypress tests.

I'll need a repo to know exactly what's going on here, but I suspect the library contains angular imports which won't work within cypress since they are designed to run in the browser and not within a e2e spec file.

edit: never linked the example repo, oops! https://github.com/barbados-clemens/cy-shared-lib

barbados-clemens avatar Jul 26 '23 15:07 barbados-clemens

Damn @barbados-clemens you are my hero! 🚀

You are right, there was a litte tiny import from an Angular Library within the Cypress Library. I removed this import and Cypress is working now.

Thank you for your support!

mnkyjs avatar Jul 27 '23 15:07 mnkyjs

While I understand that trying to avoid functional Angular code being imported out of a "best practice" standpoint, it's a bit verbose/unpractical to avoid this all together just because of this issue.

In our use case our lib exports both functional code but also constants, interfaces, ... This issue means that we can no longer use interfaces from those libs in our Cypress code. Because importing those will cause the abovementioned error.

For example. Let's say we have a lib overview that exposes some components, a module and some interfaces on @project/overview. This means that we can no longer import interfaces like this import { MyInterface } from '@project/overview without breaking our Cypress setup.

We could switch to importing from the file directly to avoid the barrel file, but that will only work if that interface/const/enum file does not import from other libs through their barrel files.

So when you consider the above, the suggested resolution here boils down to making duplicates of those enums/consts/interfaces within our Cypress setup to avoid importing those from their dedicated libs. Which is hard to maintain and beats the purpose of storing those parts of code in shareable libs to avoid duplication.

Is there a specific/fixable reason why this was working on ng15 but broke with ng16?

DenisValcke avatar Aug 16 '23 09:08 DenisValcke

@DenisValcke I am unsure why it used to work but now doesn't. Off the top of my head could have been a number of things.

  • Changes in the underlying Cypress webpack config
  • Changes in some dependency that Cypress was using i.e. TypeScript

You can try type only imports as those should not end up in the final bundle and executed.

import type { MyInterface } from '@org/my-lib-with-ng-stuff'

But like I mentioned anything that is within that file being imported is going to come along for the ride for when the file is loaded, odds are things will be optimized out if not used, but processor that cypress uses (webpack by default) will still have to evaluate those files.

You can look at using your own file preprocessor as well. Cypress has some docs around that. https://github.com/cypress-io/cypress/tree/develop/npm/webpack-preprocessor

As for how I would specifically get around this is by composing types together based off the consumer i.e. all the base non framework types would use a plain js library, nx g @nx/js:lib.

Then in each framework specific project that needs framework specific metadata about it I would extend that interface and override/add anything extra specific to that framework

i.e.

import { MyBaseInterface } from '@org/base-js-lib';
import { SomeAngularThing } from '@angular/core';

export interface MyAngularInterface extends MyBaseInterface {
  prop: SomeAngularThing
}

this way you can import from the base js lib for things like cypress and not worry about bringing in angular code breaking the build. I would also recommend setting up the eslint ban imports for those base libraries to framework specific codes doesn't make it in. https://nx.dev/recipes/enforce-module-boundaries/ban-external-imports#ban-external-imports

barbados-clemens avatar Aug 16 '23 14:08 barbados-clemens

@barbados-clemens thanks for the extra clarifications. We'll look into it!

DenisValcke avatar Aug 16 '23 14:08 DenisValcke

This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.

github-actions[bot] avatar Sep 16 '23 00:09 github-actions[bot]