nrwl-Nx and Cypress, verification timing out with failed --smoke-test in Windows 7 - node.js

I'm trying to follow along with this tutorial on the NX website. The 2nd part has us setting up e2e testing with Cypress. I followed everything as said and even went as far as commenting out my code and pasting theirs into my files. I'm not getting any errors in the console. The error I see in Node says
Cypress verification timed out
This command failed with the following output:
C:.....\Cache\3.3.1\Cypress\Cypress.exe --smoke-test --ping=852
The tutorial also says there's a UI that should pop up on our app, which I don't see anything of the sort.
After generating the workspace and the application it has us modify the app.po.ts file by adding a couple constants, so far mine looks like this
export const getGreeting = () => cy.get('h1');
export const getTodos = () => cy.get('li.todo');
export const getAddTodoButton = () => cy.get('button#add-todo');
next it tells us to update the app.spec.ts file of the e2e test by adding this
import { getAddTodoButton, getTodos } from '../support/app.po';
describe('TodoApps', () => {
beforeEach(() => cy.visit('/'));
it('should display todos', () => {
getTodos().should(t => expect(t.length).equal(2));
getAddTodoButton().click();
getTodos().should(t => expect(t.length).equal(3));
});
});
The version of this file generated by Nx comes with this already in it
import { getGreeting } from '../support/app.po';
describe('todos', () => {
beforeEach(() => cy.visit('/'));
it('should display welcome message', () => {
getGreeting().contains('Welcome to todos!');
});
});
I originally tried adding the extra test underneath it and added the new imports. After getting the error message I thought maybe I needed to combine the tests into one test which looks like this.
describe('TodoApps', () => {
beforeEach(() => cy.visit('/'));
it('should display welcome message', () => {
getGreeting().contains('Welcome to todos!');
});
it('should display todos', () => {
getTodos().should(t => expect(t.length).equal(2));
getAddTodoButton().click();
getTodos().should(t => expect(t.length).equal(3));
});
});
I'm still getting the same error in Node and have no clue as to what I'm doing wrong. Prior to starting the project I updated node, npm and angular cli. I downloaded Angular Console for VS Code but am running into problems with it so I've just been using the Node Terminal and Brackets. Can anyone help?

if you in windows then you can solve this verification timeout issue by navigating to:
'C:\Users\<user>\AppData\Local\Cypress\Cache\3.4.0\Cypress'
then just double click on Cypress.exe.
After this close it and go back to your ide or terminal and redo what threw the error

Related

Next.js router error while testing using React-testing-library

I was just trying to do a preliminary test of rendering a component that is redirecting the user on the basis of the login status and thus using router from next/router in componentDidMount but getting the following error:
No router instance found.
You should only use "next/router" inside the client side of your app.
It appears to me that from client side it means using the router or Link has to be used inside of the render method as that is what makes the DOM and other methods like lifecycle, hooks, and server-side doesn't so in those cases it would throw an error.
I know that testing the entire component beats the purpose of unit testing but I wanted to do this anyway. Therefore, I followed this discussion and it appears that the router has to be mocked in order to be used by the React-Testing-Library but none of the solutions work for me.
Here is the code that I tried:
describe('Home Page', () => {
it('renders without crashing', async () => {
render(<Home />)
})
})
a solution like:
import { useRouter } from 'next/router'
...
jest.mock('next/router', () => ({
useRouter: jest.fn(),
}))
...
;(useRouter as jest.Mock).mockImplementation(() => ({
pathname: '/',
push: mockPush,
}))
will work.
the error you're encountering will be triggered if you do not mock useRouter in the initial mock (i.e.:
...
jest.mock('next/router')
...
Mocked the router using the next-router-mock library. Just pasted jest.mock('next/router', () => require('next-router-mock')); before the test and the tests are passing.
jest.mock('next/router', () => require('next-router-mock'));
describe('Home Page', () => {
it('renders without crashing', async () => {
render(<Home />)
})
})
Although, the test is passing but getting this warning that is not making any sense to me.
› 1 snapshot obsolete.
• Home Page renders without crashing 1
Snapshot Summary
› 1 snapshot obsolete from 1 test suite. To remove it, press `u`.
↳ tests/homePage.test.js
• Home Page renders without crashing 1
Assuming that there is a better way to mock the router.

Jasmine - Load nested describes from external files?

I'm writing e2e tests using Jasmine and Protractor with AngularJS. I have a parent describe which describes the page, and some setup call in beforeAll that goes to the correct page for the following tests. I've broken these tests up into multiple describes per feature. Here is an example:
describe('Page Detail', () => {
beforeAll(() => {
utils.doSomething();
})
describe('Location Section'), () => ...
describe('Information Section', () => ...
The problem I'm having is that there are a lot of features within this module, and the tests are starting to push 300-400 lines of code. I would ideally like to put the nested describes in seperate files and import them. I've done something like this:
const describeLocation = require('./folder/location'),
describeInformation = require('./folder/information');
describe('Page Detail', () => {
beforeAll(() => {
utils.doSomething();
})
describeLocation();
describeInformation();
In the other files I'm simply exporting an anonymous function and including the nested describe's code. This works, but unfortunately the tests don't have the jasmine context (can't access anything in beforeAll).
I'm curious if there is a standard or better way to accomplish this?
//export.js
describe(...
)
//Import or your main specs file
describe('',()=>{
require('./export');
})
Don't export in a form of a method just write your spec and import it using require in the main describe.

Jest test passed but get Error: connect ECONNREFUSED 127.0.0.1:80 at the end

I'm using node with TypeScript on my back end and Jest and Supertest as my test framework on my back end.
When I'm trying to test I have the result pass but I get an error at the end. Here's the result:
PASS test/controllers/user.controller.test.ts
Get all users
✓ should return status code 200 (25ms)
console.log node_modules/#overnightjs/logger/lib/Logger.js:173
[2019-12-05T04:54:26.811Z]: Setting up database ...
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.284s
Ran all test suites.
server/test/controllers/user.controller.test.ts:32
throw err;
^
Error: connect ECONNREFUSED 127.0.0.1:80
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1104:14)
npm ERR! Test failed. See above for more details.
Here's my test code:
import request from "supertest";
import { AppServer } from '../../config/server';
const server = new AppServer();
describe('Get all users', () => {
it('should return status code 200', async () => {
server.startDB();
const appInstance = server.appInstance;
const req = request(appInstance);
req.get('api/v1/users/')
.expect(200)
.end((err, res) => {
if (err) throw err;
})
})
})
Here's my server setup. I'm using overnightjs on my back end.
I created a getter to get the Express instance. This is coming from overnight.js.
// this should be the very top, should be called before the controllers
require('dotenv').config();
import 'reflect-metadata';
import { Server } from '#overnightjs/core';
import { Logger } from '#overnightjs/logger';
import { createConnection } from 'typeorm';
import helmet from 'helmet';
import * as bodyParser from 'body-parser';
import * as controllers from '../src/controllers/controller_imports';
export class AppServer extends Server {
constructor() {
super(process.env.NODE_ENV === 'development');
this.app.use(helmet());
this.app.use(bodyParser.json());
this.app.use(bodyParser.urlencoded({ extended: true }));
this.setupControllers();
}
get appInstance(): any {
return this.app;
}
private setupControllers(): void {
const controllerInstances = [];
// eslint-disable-next-line
for (const name of Object.keys(controllers)) {
const Controller = (controllers as any)[name];
if (typeof Controller === 'function') {
controllerInstances.push(new Controller());
}
}
/* You can add option router as second argument */
super.addControllers(controllerInstances);
}
private startServer(portNum?: number): void {
const port = portNum || 8000;
this.app.listen(port, () => {
Logger.Info(`Server Running on port: ${port}`);
});
}
/**
* start Database first then the server
*/
public async startDB(): Promise<any> {
Logger.Info('Setting up database ...');
try {
await createConnection();
this.startServer();
Logger.Info('Database connected');
} catch (error) {
Logger.Warn(error);
return Promise.reject('Server Failed, Restart again...');
}
}
}
I read this question - that's why I called the method startDB.
So I figured out and the solution is quite easy. I can't explain why though.
This req.get('api/v1/users/') should be /api/v1/users - you need a leading /.
For Frontend...
If you are making use of axios and come across this error, go to the testSetup.js file and add this line
axios.defaults.baseURL = "https://yourbaseurl.com/"
This worked for me. So, typically, this is a baseURL issue.
I had this error in my React frontend app tests.
I was using React testing library's findBy* function in my assert:
expect(await screen.findByText('first')).toBeInTheDocument();
expect(await screen.findByText('second')).toBeInTheDocument();
expect(await screen.findByText('third')).toBeInTheDocument();
After I changed it to:
await waitFor(async () => {
expect(await screen.findByText('first')).toBeInTheDocument();
expect(await screen.findByText('second')).toBeInTheDocument();
expect(await screen.findByText('third')).toBeInTheDocument();
});
the error is gone.
I don't know exactly why, but maybe it will help someone
UPDATE: I was mocking fetch incorrectly, so my test called real API and caused that error
I put this line in my setupTests file:
global.fetch = jest.fn()
It mocks fetch for all tests globally. Then, you can mock specific responses right in your tests:
jest.mocked(global.fetch).mockResolvedValue(...)
// OR
jest.spyOn(global, 'fetch').mockResolvedValue(...)
Slightly different issue, but same error message...
I was having this error when using node-fetch when trying to connect to my own localhost (http://localhost:4000/graphql), and after trying what felt like everything under the sun, my most reliable solution was:
using this script in package.json: "test": "NODE_ENV=test jest --watch"
If the terminal shows connection error I just go to the terminal with Jest watching and press a to rerun all tests and they pass without any issue.
¯\_(ツ)_/¯
Success rate continued to improve by renaming the testing folder to __tests__ and moving my index.js to src/index.js.
Very strange, but I am too exhausted to look at the Jest internals to figure out why.
The rules for supertest are the same as the rules for express. OvernightJS does not require any leading or ending "/" though.
For anyone landing on this, but not having issues with trailing slashes:
jest can also return a ECONNREFUSED when your express app takes some time (even just a second) to restart/init. If you are using nodemon like me, you can disable restarts for test files like --ignore *.test.ts.
This error also occurs if you have not set up a server to catch the request at all (depending on your implementation code and your test, the test may still pass).
I didn't get to the bottom of this error - it wasn't related to the (accepted) leading slash answer.
However, my "fix" was to move the mocks up into the suite definition - into beforeAll and afterAll for cleanup between tests).
Before, I was mocking (global.fetch) in each test, and it was the last test in the suite to use the mock that would cause the error.
In my case, the issue was related to package react-inlinesvg. Package makes a fetch request to get the svg file and since server is not running, it gets redirected to default 127.0.0.1:80.
I mocked react-inlinesvg globally to output props including svg filename to assert in testing.
jest.mock('react-inlinesvg', () => (props) => (
<svg data-testid="mocked-svg">{JSON.stringify(props)}</svg>
));

Different browser behavior when pass .env variables in command for run tests

It's not actually a problem, but I do not fully understand, what happened and why.
I have this runner for my test. I test a React app.
let testcafe = null
const isCiEnv = process.env.CI === 'true'
const exit = async err => {
console.log('Exiting...')
if (testcafe) {
console.log('Closing TestCafe...')
testcafe.close()
}
console.log('Exiting process...')
process.exit(err ? 1 : 0)
}
console.log('Is CI ENV: ', isCiEnv)
console.log('Creating TestCafe...')
createTestCafe('localhost', 1337, 1338)
.then(tc => {
testcafe = tc
})
.then(() => {
console.log('Starting server...')
return startServer()
})
.then(() => {
console.log('Starting client...')
return startClient()
})
.then(() => {
console.log('Creating TestCafe Runner...')
return testcafe.createRunner()
})
.then(runner => {
console.log('About to start TestCafe Runner...')
return runner
.src([
'test/e2e/fixtures/auth.js'
])
.browsers({
path: isCiEnv
? '/usr/bin/chromium-browser'
: 'Chrome',
cmd: isCiEnv
? '--no-sandbox --disable-gpu'
: undefined
})
.screenshots('screenshots', true)
.run({
skipJsErrors: true,
selectorTimeout: 25000,
assertionTimeout: 25000
})
})
.then(failedCount => {
console.log('failed count:', failedCount)
return exit(failedCount)
})
.catch(err => {
console.error('ERR', err)
return exit(err)
})
In package.json i have this command for run test
"test:e2e": "HOST=0.0.0.0 NODE_ENV=test NODE_PATH=server babel-node test/e2e/index.js --presets stage-2"
But in the local environment, I run a test with this command
sudo REDIS_HOST=127.0.0.1 PORT=80 yarn test:e2e
That because on my local machine I have different config and I don't want to change it for everyone else.
Usually, test runs in a different, clear version of the browser, without any account data, plugins and etc. But in this case, tests run in a new browser window, but with all plugins and my account name. But, it's doesn't have cookie and session auth data from the browser window, in which I usually work (because I authorized on-site in the working browser and doesn't auth in test browser).
And if I change "Chrome" to "chrome" it stops run completely. Same behavior for Firefox and Safari.
Earlier, without passing REDIS_HOST and HOST, it works as usual and runs in a clean new browser window.
It's not a big problem, for now at least, but it's unexpected behavior and I don't understand, why it works this way.
I'm not very familiar with Node and React, and maybe this related to them.
Spec: macOS 10.12.5, Testcafe 0.20.3, Chrome 67
Specifying browsers using { path, cmd } is a legacy low-level option, you shouldn't use it. When a browser is specified in this way, TestCafe doesn't try to guess browser's type (Chrome, Firefox) and doesn't perform advanced initialization steps like creating a clean profile (because profile structure depends on browser's type). So it's better to use the following runner code:
.browsers(isCiEnv ? 'chromium --no-sandbox --disable-gpu' : 'chrome')

Cannot mock filesystem in nodejs unit tests

Overview
I have a simple module written in nodejs that uses fs-extra package to test if a file exists. The module throws when the path exists and proceed to next procedure otherwise. Here is the source file:
// - main.js -
import fs from 'fs-extra'
export default async (pathName) => {
// Do not proceed if path already exists.
if (await fs.pathExists(projectPath)) {
throw new Error(chalk.red.bold(`${projectPath} already exists`))
}
// more logic here
}
I want to write a unit test that tests the bellow logic:
If filepath exists, we expect to throw an error
I don't want to mess up with the real filesystem -in case my code contains some nasty bug that could destroy it- so I went to an alternative solution, mocking the filesystem using mock-fs. Here is the spec file:
// - main.js spec file -
import mainFunction from '../main'
import mockfs from 'mock-fs'
describe('test main function', () => {
beforeEach(() => {
mockfs({
home: {
user: {
dummy: {}
}
}
})
})
test('expect to throw', async () => {
await mainFunction('/home/user/dummy')
})
afterEach(() => {
mockfs.restore()
})
})
What's the problem?
Every time I run the test, the main function does not throw. This happens because mockfs fake-filesystem was declared in the spec file, so the fs module in main source file does not know for the mockfs fake-filesystem and checks the real one. By the time that I do not have a folder named /home/user/dummy in my real filesystem the check always fails.
Expected behaviour
mainFunction in spec file should throw
Actual behaviour
mainFunction in spec file DOES NOT throw
Other info
I guess that I can turn this unit test into an integration test. But I do not want to. Is there any fix for this? Do I have to use another packages?
My test suit is Jest 22.3.0.
After some search, I found the appropriate way to unit test the branch. We really do not have to use the mock-fs module. We just have to mock pathExists method of fs-extra module to return one time the value false and one time the value true. Bellow, I post a working version of my spec file:
import mainFunction from '../main'
require('fs-extra').pathExists = jest.fn().mockReturnValueOnce(false).mockReturnValueOnce(true)
describe('test main function', () => {
beforeEach(() => {
jest.clearAllMocks()
})
test('expect to not throw', async () => {
await expect(mainFunction('/dummy/path/does/not/matter')).resolves
})
test('expect to throw', async () => {
await expect(mainFunction('/dummy/path/does/not/matter')).rejects.toBeInstanceOf(Error)
})
})

Resources