Set custom default import paths for Cypress - cypress

We're using Cypress for testing an app build with Create React App, and our CRA app is setting a custom import path in .env – NODE_PATH=src/ – so that we can import files "absolutely", e.g. import Foo from 'components/Foo' vs. import Foo from '../../components/Foo'
The problem is, if we import one of the files from our CRA into a Cypress test, and the imported file includes something like import routes from 'lib/routes' Cypress doesn't know how to process that path and the import fails.
Example
Let's say we have the following files:
/cypress/integration/test.js
import routes from '../../src/lib/routes';
// Tests here…
/src/lib/routes.js
import { routeHelpers } from 'lib/routes';
// Routing code here
In this scenario, when /cypress/integration/test.js imports /src/lib/routes.js it will encounter the absolute import of 'lib/routes' and have no idea how to resolve that path.
Is there a way to set custom paths for Cypress to include when searching for imports in this way? In the case of this arbitrary example, it would mean telling Cypress to use src as a directory to resolve imports from.

Easiest solution for this turned out to be simply running the cypress commands with NODE_PATH=src. So my package.json was simply updated to the following:
"scripts": {
"cypress:open": "NODE_PATH=src cypress open",
"cypress:run": "NODE_PATH=src cypress run",
},

I had a similar issue and I was using .env with NODE_PATH=src
Solution: I removed .env and created jsconfig.json for absolute imports.
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}
This is the recommended approach in the CRA docs: https://create-react-app.dev/docs/importing-a-component/#absolute-imports

Related

Nx Framework - TS2307 During compilation when importing from non-root

I am trying to migrate to Nx and setup a monorepo.
Currently running into issues with path alias imports.
#backend/kernel": ["libs/kernel/src/index.ts"],
#backend/kernel/*": ["libs/kernel/src/*"]
When issuing imports of the form
import { Something } from "#backend/kernel".
On the other hand, when doing imports that go deeper,
import { SomethingElse } from "#backend/kernel/somewhere/deeper" I get TS2307 when compiling. No issues in VSCode; all types are correctly resolved.
Anybody has some advice?
Have you export the code correctly from your lib in the root index of your library ?
If not, at the index.ts at the root of your library, just export your code like this :
export { Something } from 'your/path'
or if you already export inside your library you can use a wildcard *.
After that, remove the line
#backend/kernel/": ["libs/kernel/src/"]
from your tsconfig.base.json
Cheers

Running Cypress tests with TailwindCSS 3

I've been running my component tests via cypress open-ct for a while now, relying on importing /node_modules/tailwindcss/dist/tailwindcss.min.css.
Since upgrading to Tailwind v3 some of my tests are failing as there is no prebuilt CSS file I can import - everything is generated just in time.
For example, testing if a modal closes when clicking on a overlay that is fixed and full width fails as the whole modal is rendered so that it is inaccessible by Cypress.
Another side-issue that stems from not having access to Tailwind classes is that videos recorded when running tests in CI are unusable as they are just a bunch of random native elements.
I've been importing Tailwind like this at the top of each Test file (before describes)
import { mount } from '#cypress/vue'
import '/node_modules/tailwindcss/dist/tailwind.min.css'
import MultiSelectField from './MultiSelectField.vue'
import { ref } from "vue";
Any ideas how to include Tailwind (preferably globally) so tests won't fail?
You can use the Tailwind CLI to generate your stylesheet on the fly.
Add this plugin in cypress/plugins/tailwind.js (be sure to change the -i source from ./src/styles/globals.css to your base CSS file):
before(() => {
cy.exec('npx tailwindcss -i ./src/styles/globals.css -m').then(
({ stdout }) => {
if (!document.head.querySelector('#tailwind-style')) {
const link = document.createElement('style')
link.id = 'tailwind-style'
link.innerHTML = stdout
document.head.appendChild(link)
}
},
)
})
Then, load the plugin by importing it in cypress/support/index.js:
import '../plugins/tailwind'
You should also set up a separate config file for your component tests, such as cypress/support/component.js, and specify that in your cypress.json config file:
{
"component": {
"supportFile": "cypress/support/component.js",
},
"e2e": {
"supportFile": "cypress/support/e2e.js"
}
}
Then, only include import '../plugins/tailwind' in your cypress/support/component.js config file, so that you don't perform the JIT compilation for your E2E tests (since it's unnecessary).
Michael Hays' solution works, but it rebuilds the whole .css file every time changes to the code are made, which slows tests down. An alternative would be to run tailwind externally in watch mode.
npm i -D concurrently
package.json
"scripts": {
"test": "concurrently \"tailwindcss -i ./src/index.css -o ./dist/index.css --watch\" \"cypress open\" "
},
cypress/support/component.ts
import "../../dist/index.css";
I see you're using import '/node_modules/tailwindcss/dist/tailwind.min.css' which expects a pre-compiled bundle. If you have any customization added to the tailwind config, those would not be covered.
But if you can't use the generated css and don't have any tailwind customization, you could use the cdn version from https://cdn.tailwindcss.com/
Because you are running it in a test and don't want to add to possible "flakyness" of using remote dependency, you'll likely want to download that file and keep it in the repo and update it manually from time to time. You can also use some automation for getting the correct version from the cdn before running the test, but Ideally you'd use the generated css, since that's what you're shipping so that's the resource that should be getting tested.

Question about the react-redux documentation

I am confused by something on the react-redux documentation
https://redux-docs.netlify.com/recipes/configuring-your-store/
specifically, in attempting to build the prototype app (which is provided here https://github.com/reduxjs/redux/tree/master/examples/todos/src), I am confused about the line
import rootReducer from './reducers'
what is confusing is that in the app directory, there is no such file reducers.js, there is only a folder reducers/ which contains
index.js
todos.js
todos.spec.js
visibilityFilter.js
I see no file for rootReducer, so I am assuming (correctly?) that the ES6 syntax for the above code is importing the default export from
reducers/index.js
is that correct?
In that file, I see
export default combineReducers({
todos,
visibilityFilter
})
do I understand correctly the defaulted export anonymous function, exported from reducers/index.js, is then imported into index.js as rootReducer ?
Yes. That's ES6 "default export" syntax, combined with an index.js file. When an index.js file exists in a folder, you can specify just the folder name in the import statement, and the bundler knows to look at index.js automatically.

How to use only a part of rxjs-compat, or write a custom rxjs-compat?

We've updated our project to use Angular & Rxjs 6 and all works fine.
We've also updated the code to use the pipe operators, so we would like to drop rxjs-compat.
The only issue is that one of our dependencies still uses the old import syntax for Observable and Subject.
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
Is there any way to provide our own minimal rxjs-compat just for these two classes?
The library does not do anything fancy with Observable and Subject, and doesn't use any operators, so it seems overkill to import the full rxjs-compat package.
I don't think you need to copy any files when using the paths option.
I'd try something like this:
"compilerOptions": {
"baseUrl": ".",
"paths": {
"rxjs/Observable": ["./node_modules/rxjs/internal/Observable"],
"rxjs/Subject": ["./node_modules/rxjs/internal/Subject"]
}
}
Note that baseUrl must be specified.
The question is whether or not the paths option affects other dependencies in node_modules. I'm not sure and I didn't try it.
Using paths as metioned by #cartant I managed to get it to compile without rxjs-compat, but the output main.js is even larger than using the full compat library...
With rxjs-compat = 691 KB
With patched library import = 671 KB (ideal size)
with rxjs-compat paths hack = 700 KB
I've probably done something wrong, but I don't have time to investigate this further.
Steps for the hack:
Create a folder src\rxjs-compat\node_modules (note the node_modules name, it's used to bypass a webpack bug)
Copy the d.ts and .js files you need from rxjs-compat (in my case Observable and Subject)
Edit tsconfig.app.json and add the following paths in the compilerOptions:
"paths": {
"rxjs-compat/Observable": [ "rxjs-compat/node_modules/Observable"],
"rxjs/Subject": [ "rxjs-compat/node_modules/Subject"]
}

How do I import WebSocketSubject in TypeScript?

As suggested I installed using
npm install #reactivex/rxjs#5.0.0-beta.11
I can import almost everything this way:
import { Observable, Subscriber } from '#reactivex/rxjs';
but not WebSocketSubject. I've tried:
import { WebSocketSubject } from '#reactivex/rxjs';
import { WebSocketSubject } from '#reactivex/rxjs/observable/dom';
... and many other variations.
dom is not a file, but a folder, so there will nothing to import :)
Try this one:
import { WebSocketSubject } from '#reactivex/rxjs/src/observable/dom/WebSocketSubject';
The import will give you the TypeScript source file, but I would recommend installing rxjs#5.0.0-beta.11 rather than #reactivex/rxjs so you can do this:
import { WebSocketSubject } from 'rxjs/observable/dom/WebSocketSubject';
The above import will give you the .js file, not the .ts file. Autocompletion and all the good TypeScript stuff will still work, because the package has the .d.ts files!
One more tip: If you having problems finding the correct import path:
Go to node_modules/[<organization_name>/]<package_name> (the organization name is optional, they all start with #).
This is your starting point for all imports, from there you can append any folder/file path to the [<organization_name>/]<package_name> and the import should work.
But if you only point to the import statement to [<organization_name>/]<package_name> Typescript will pick up the real path to the import file from the main property of the package.json. Which in the case of #reactivex/rxjs points to index.js and that file again will do a require('./dist/cjs/Rx'). So when you do #reactivex/rxjs the path gets resolved to node_modules/#reactivex/rxjs/dist/cjs/Rx.js.
Hope this explaination wasn't to confusing, but the path resolution sometimes can be :-x

Resources