Cypress: unit testing the pure React component is throwing error - reactjs

I am writing unit tests using Cypress for my React JS web application. I can write functional tests using Cypress. But I also need to write the unit tests for my presentation components in my app. So I am using this Cypress wrapper for React, https://github.com/cypress-io/cypress/tree/master/npm/react. But, when I write the unit test for my component, it is throwing an error. Following is how I installed and wrote the unit test for my pure component.
First I installed the required libraries running the following command.
npm install --save-dev cypress #cypress/react #cypress/webpack-dev-server
Then I added the following line into the cypress/plugins/index.js
module.exports = (on, config) => {
require('#cypress/react/plugins/react-scripts')(on, config)
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}
Then I created a test file called, no_result.spec.js with the following code.
import React from 'react';
import { mount } from '#cypress/react';
import NoResult from "../../../src/components/NoResult";
describe("NoResult Component", () => {
it ('should display message', () => {
mount(<NoResult message={"No data available."} />);
cy.contains('No data available').should('be.visible');
})
})
Then I opened the cypress and run that no_result.js test and I got the following error.
AssertionError
Timed out retrying after 4000ms: Expected to find element: #__cy_root, but never found it.
Because this error occurred during a before each hook we are skipping all of the remaining tests.
node_modules/#cypress/react/dist/cypress-react.esm-bundler.js:317:1
315 | return cy.then(function () {
316 | var selector = "#" + ROOT_ID;
> 317 | return cy.get(selector, { log: false }).then(function ($el) {
| ^
318 | var wasUnmounted = unmountComponentAtNode($el[0]);
319 | if (wasUnmounted && options.log) {
320 | cy.log('Unmounted component at', $el);
What is missing in my configuration and how can I fix it?

Related

Playwright & Vite - test block cannot find an element, although exists

I'm running some e2e tests with playwright with vite frontend application.
This is my code:
import { test, expect } from '#playwright/test';
test.describe('Auth page #auth-page', () => {
test('auth page should have brand logo', async ({ page }) => {
await page.goto('http://localhost:8080/');
const isBrandLogoElementVisible = await page.locator("[data-test-id='auth-brand-logo']").isVisible();
expect(isBrandLogoElementVisible).toBe(true);
});
});
I run this script: playwright test -c ./playwright.config.ts
When I run the test the output is
basic/auth.spec.ts:4:6 › Auth page #auth-page › auth page should have brand logo ==============
Error: expect(received).toBe(expected) // Object.is equality
Expected: true
Received: false
7 | const isBrandLogoElementVisible = await page.locator("[data-test-id='auth-brand-logo']").isVisible();
8 |
> 9 | expect(isBrandLogoElementVisible).toBe(true);
| ^
10 | });
11 |
12 | test('auth page should have main header', async ({ page }) => {
But, when I run playwright test -c ./playwright.config.ts --debug it succeeds. I guesss it's because the test waits for my inputs on debug mode and then the element start rendering.
How can I change it to work?
I Expect Playwright to find the element as it exists
According to the docs, page.locator(...).isVisible() does not wait for the element to become visible. The recommended way to do this is to use expect(page.locator(...)).toBeVisible() which does wait for a specific, configurable amount of time.
await expect(page.locator("[data-test-id='auth-brand-logo']")).toBeVisible()

Can't import #testing-library/jest-dom, expect.extend is not a function

I'm trying to add #testing-library/jest-dom to my project with no luck. It is installed by yarn into my dev dependencies and imported in setupTests.js with:
import '#testing-library/jest-dom';
The test fails with:
Invalid Chai property: toBeDisabled
40 | it('should be disabled', async () => {
41 | const button = screen.getByRole('button', { name: 'Create button' });
> 42 | expect(button).toBeDisabled();
| ^
43 | });
44 | });
Where am I going wrong?
Looks like you're using both Chai and Jest in the same test suite, both of which have an expect function. In this test you're expecting to use Jest but it's Chai that's getting called. Chai's expect does not have a toBeDisabled function property, thus the error.
Are you also importing Chai in that file? If so, remove that import. If you need both testing frameworks I'd recommend separating your tests into different files so that in one file you're only running tests with one framework.

How to import other applications exported files in .test.js files in single-spa environment

Hi I actually need to import exported files from one application(commons) to other application(login) in some jest files, but it is not getting detected by jest.
Jest Test file:
import { auth as ServiceAuth } from "#dfs/standard"
import { ContextAlert } from '#dfs/standard';
describe("login page", () => {
it("test case 1", () => {
const ContextAlert = useContext(ContextAlert );
expect(ContextAlert).toBeTruthy()
})
})
Error Message:
FAIL src/Components/LoginPage.test.js
● Test suite failed to run
Cannot find module '#dfs/standard' from 'LoginPage.test.js'
> 1 | import { auth as ServiceAuth } from "#dfs/standard"
| ^
2 | import { ContextAlert } from '#dfs/standard';
3 |
4 | describe("login page", () => {
at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:299:11)
at Object.<anonymous> (src/Components/LoginPage.test.js:1:1)
jest.config.js
module.exports = {
transform: {
"^.+\\.(j|t)sx?$": "babel-jest"
},
moduleNameMapper: {
"\\.(css)$": "identity-obj-proxy",
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "identity-
obj-proxy",
}
};
But the file is getting imported in the component files with the same syntax.
How can I import the file in the jest test file ?
Jest is a very different environment than the browser, and resolving modules is also different. The code being loaded in Jest is not bundled and has not been processed through Webpack so externals are not resolved at run-time.
To enable unit tests with cross microfrontend imports, these are your options:
Publish mocks for that shared dependency (so that the mock and the actual implementation are nearest to each other)
Mock the shared dependency with Jest’s moduleNameMapper configuration
Mock the shared dependency locally in a __mocks__ file
Publish the shared dependency to a registry (npm or some other internal registry such as artifactory) and install it as a devDependency locally so that Jest can resolve it locally (though this will likely require a separate build to execute in jest/node environment)
The option you choose depends on your organization's needs.
See also: https://github.com/single-spa/single-spa.js.org/issues/389

Apollo - React (Typescript) Invariant Error when building production build

I am creating a new react app with gatsby, typescript, and apollo (for graphql queries).
When testing in dev, the app compiles and runs with no errors thrown.
When I transpile the build, using 'gatsby build', it fails with an error.
I don't understand why or where this is being triggered. It seems to be something to do with the way webpack is checking as it's building, but I don't know how to pinpoint the issue and there doesn't seem to be any material out there with a clear answer for me.
It seems to be caused by the httplink module. The code that triggers the error when present in any .tsx file is:
import { HttpLink } from 'apollo-link-http'
const link = new HttpLink({
uri: 'http://localhost:3001/graphql'
})
The error shown is the following:
error Building static HTML failed
See our docs page on debugging HTML builds for help https://gatsby.dev/debug-html
10 | function InvariantError(message) {
11 | if (message === void 0) { message = genericMessage; }
> 12 | var _this = _super.call(this, typeof message === "number"
| ^
13 | ? genericMessage + ": " + message + " (see https://github.com/apollographql/invariant-packages)"
14 | : message) || this;
15 | _this.framesToPop = 1;
WebpackError: Invariant Violation: Invariant Violation: 1 (see https://github.com/apollographql/invariant-packages)
- invariant.esm.js:12 new InvariantError
[lib]/[apollo-link-http-common]/[ts-invariant]/lib/invariant.esm.js:12:1
- bundle.esm.js:64 checkFetcher
[lib]/[apollo-link-http-common]/lib/bundle.esm.js:64:52
- bundle.esm.js:8 createHttpLink
[lib]/[apollo-link-http]/lib/bundle.esm.js:8:17
- bundle.esm.js:139 new HttpLink
[lib]/[apollo-link-http]/lib/bundle.esm.js:139:1
- Strategy.tsx:6 Module../src/components/Strategy.tsx
lib/src/components/Strategy.tsx:6:14
- bootstrap:19 __webpack_require__
lib/webpack/bootstrap:19:1
- bootstrap:19 __webpack_require__
lib/webpack/bootstrap:19:1
- sync-requires.js:10 Object../.cache/sync-requires.js
lib/.cache/sync-requires.js:10:56
- bootstrap:19 __webpack_require__
lib/webpack/bootstrap:19:1
- static-entry.js:9 Module../.cache/static-entry.js
lib/.cache/static-entry.js:9:22
- bootstrap:19 __webpack_require__
lib/webpack/bootstrap:19:1
- bootstrap:83
lib/webpack/bootstrap:83:1
- universalModuleDefinition:3 webpackUniversalModuleDefinition
lib/webpack/universalModuleDefinition:3:1
- universalModuleDefinition:10 Object.<anonymous>
lib/webpack/universalModuleDefinition:10:2"
Is this typescript issue, gatsby issue, apollo issue, or a webpack issue? Or a combination?
Thank you for any help you can give! I'm struggling with my understanding of all the pieces here.
I understand that Invariant Violations are about an issue with the wrong types being referenced. Because this occurs in the module, I'm not sure if I'm doing something wrong, or if it's an issue inside the imported library. Maybe it's an issue that I'm forcing typescript checks on a basic javascript based library. I still didn't quite come to a conclusion on this.
I tried adding the following config to gatsby-node.js to ignore the module checks (as suggested here: https://gatsby.dev/debug-html), with no successful build, though the error did change, as it could not see the module.
exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
if (stage === "build-html") {
actions.setWebpackConfig({
module: {
rules: [
{
test: /apollo-link-http/,
use: loaders.null(),
},
],
},
})
}
}
To recap, this is the code designed to create the client object to enable queries to the graphql endpoint. When running 'gatsby build' the in variant error occurs (see above).
import * as React from 'react'
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { HttpLink } from 'apollo-link-http'
const cache = new InMemoryCache()
const link = new HttpLink({
uri: 'http://localhost:3001/graphql'
})
const client = new ApolloClient({
cache,
link
})
I'm a newbie at this. After hours of looking I finally tracked down the error in the file. On closer inspection, when the environment is production (process.env.NODE_ENV === "production"), then the error is not detailed. So I looked at what the error would be if the environment was something else, and changed the file to output this to the console. What I got back was:
fetch is not found globally and no fetcher passed, to fix pass a fetch for
your environment like https://www.npmjs.com/package/node-fetch.
For example:
import fetch from 'node-fetch';
import { createHttpLink } from 'apollo-link-http';
const link = createHttpLink({ uri: '/graphql', fetch: fetch });
I added fetch to my code, and it built a production version with no errors.
I don't understand why this error was not thrown with the dev environment, but I guess it's something to do with the lazy loading.
Problem fixed.

How to use react-native-i18n in detox[react-native]

I want to test the alert message in detox,and the message use i18n.
const i18n = require("react-native-i18n");
describe("Example", () => {
beforeEach(async () => {
await device.reloadReactNative();
});
it("should show hello screen after tap", async () => {
await element(by.id("btnLogin")).tap();
I18n.t(LocaleKeys.errorMsg_invalidUsername);
await expect(element(by.text(I18n.t(LocaleKeys.errorMsg_invalidUsername)))).toBeVisible();
// await expect(element(by.text("Please input the email and password."))).toBeVisible();
});
});
Run test and get the following error.
Test suite failed to run
/Users/leogeng/Desktop/studentREP/student-app/node_modules/react-native-i18n/index.js:14
export const getLanguages = () => RNI18n.getLanguages();
^^^^^^
SyntaxError: Unexpected token export
at ScriptTransformer._transformAndBuildScript (../node_modules/jest-runtime/build/script_transformer.js:305:17)
at Object.<anonymous> (firstTest.spec.js:1:114)
at Generator.next (<anonymous>)
Then I add the following code for jest:
{
"preset": "react-native",
"transformIgnorePatterns": [
"/node_modules/(?!(react-native(.*)?/|native-base(.*)?/|react-navigation/))"
]
}
and get error again:
Validation Error:
Module <rootDir>/node_modules/react-native/jest/setup.js in the setupFiles option was not found.
Actually i confirm 'setup,js' exist in node_modules/react-native/jest.
I do not know why the error happens, anybody can help me?
Thanks
Most likely it's because you're using an old version of node, try to update and see if it solves the issue. Also, it's completely unrelated to Jest and you should probably revert your attempts to modify Jest settings if you don't have any issues with Jest unit tests; in anyway, it will not fix the detox issues.
In case you have some requirement or reason which forces you to keep node at a specific old version, you can bypass it by performing the test differently: have a demo screen only for the e2e tests (or even create a whole demo project just for e2e), in the demo screen you can have a button which performs what you need with i18n (changing locale or whatever), and in the detox test you tap this "demo" button before testing what you actually want.
I've had the same problem. I resolve it by importing i18n-js instead of react-native-i18n.
Because react-native-i18n is not a plain javascript framework, Detox can't import it.
But react-native-i18n is using i18n-js, so you can access your translations without any problem
const I18n = require('i18n-js')
// and then you can use it for your tests
...
await element(by.text( I18n.t('hello') )).tap()

Resources