nx
nx copied to clipboard
Test Failure with Cypress and Angular 16 when Importing from Libraries
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
- Set up a new workspace in the latest version of NX.
- Ran Cypress tests, and they executed without any errors.
- Created a new library within the workspace.
- Wrote a test function within the library and used it in a Cypress test by importing it via the lib-path.
- 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
Same problem within our Monorepo after Angular 16 upgrade.
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.
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
@mnkyjs have you been able to resolve the reported issue?
Hi @WHeirstrate we have still the same error and are back on Angular 15 for now.
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
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!
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 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 thanks for the extra clarifications. We'll look into it!
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.