I am triggering a click event in a jest test using fireEvent which in turn triggers an axios request. I can see that the request is being made (or attempted, it returns the error message) but I get this message from jest saying it attempted to log the error (below). How can I get the error message to log properly when using axios with jest?
Cannot log after tests are done. Did you forget to wait for something async in your test?
Attempted to log "error getting AxiosError {
message: 'Network Error',
name: 'AxiosError',
code: 'ERR_NETWORK',
config: {
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
adapter: [Function: xhrAdapter],
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: { FormData: [Function], Blob: [class Blob] },
validateStatus: [Function: validateStatus],
headers: AxiosHeaders { 'Content-Type': null, [Symbol(defaults)]: [Object] },
params: { specificURL: 'reviews/meta?product_id=37311' },
method: 'get',
url: 'http://localhost:3000/products',
data: undefined
},
request: XMLHttpRequest {}
}".
Here is my jest test:
import {render, fireEvent, screen, waitFor} from '#testing-library/react'
import React from 'react'
import ReactDOM from 'react-dom';
import RatingsAndReviews from '../RatingsAndReviews/RatingsAndReviews.js'
test('loads items eventually', async () => {
render(<RatingsAndReviews />)
const { container } = render(<RatingsAndReviews />);
const testButt = container.querySelector(`button[name="test-button"]`)
expect(testButt).toBeTruthy();
fireEvent.click(container.querySelector(`button[name="test-button"]`))
await waitFor(() => {
screen.findAllByText('Rating Test')
})
Related
I am applying internationalisation to my app with i18Next. The translation resources are severed via REST micro service. I am using i18next-http-backend plugin to fetch the translations.
The problem is that the plugin is making multiple API calls instead of one and I am not sure why
This is how my code looks like
i18n
.use(HttpApi)
.use(initReactI18next)
.init({
backend: {
backends: [
HttpApi,
HttpApi,
resourcesToBackend(localResources) // 2nd fallback
],
backendOptions: [
{
loadPath: HOST,
queryStringParams: {file: FILENAME, languageCode: `${langMap[lang]}`}, // primary API call
parse: (data) => parseTranslation(data),
},
{
loadPath: HOST,
queryStringParams: {file: FILENAME, languageCode: `${langMap['en']}`}, // 1st fallback
parse: (data) => parseTranslation(data),
}
],
},
fallbackLng: 'en',
lng: 'en', // TODO: make dynamic
debug: true,
keySeparator: false,
interpolation: {
escapeValue: false,
},
});
P.S HOST and FILENAME are variables here
const loadResources = async (locale: string) => {
return await axios
.get(`${BASE_URL}/lang/strings/${locale}/translation.json`, {
headers: { "Access-Control-Allow-Origin": "*" },
})
.then((res) => {
return JSON.stringify(res.data);
})
.catch((error) => {
console.log(error);
});
};
const backendOptions = {
loadPath: "{{lng}}|{{ns}}",
request: (options: any, url: any, payload: any, callback: any) => {
try {
const [lng] = url.split("|");
loadResources(lng).then((response) => {
callback(null, {
data: response,
status: 200,
});
});
} catch (e) {
console.log(e, "error from language");
callback(null, {
status: 500,
});
}
},
};
i18n
.use(backend)
.use(initReactI18next)
.init({
backend: backendOptions,
fallbackLng: "en",
debug: false,
lng: "en",
ns: ["translations"],
defaultNS: "translations",
interpolation: {
escapeValue: false,
formatSeparator: ",",
},
})
.then(noop)
.catch(noop);
I hope this would be helpful for you
Try to change the load option to currentlyOnly -> https://www.i18next.com/overview/configuration-options#languages-namespaces-resources like: https://github.com/i18next/i18next-http-backend/issues/61#issuecomment-812378629
Setting the fallbackLng to false may also work.
Having an issue with where i seem to be connecting to SQL Server but cannot find the server/db.
I have been trying to follow the steps in this guide for Cypress 9 but to no avail.
https://www.npmjs.com/package/cypress-sql-server
There was an answer on SO that i've been trying to use but I can't reply to a comment and add a comment but it was deleted by the mods for some reason. This is the URL to the answer I have been trying to follow but can't connect.
How to configure cypress-sql-server with no cypress.json? (updated)
Has someone please got a working example?
cypress.config.ts
const { defineConfig } = require("cypress");
const sqlServer = require("cypress-sql-server");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// allows db data to be accessed in tests
config.db = {
"userName": "x",
"password": "x",
"server": "xxx\\SQLEXPRESS",
"options": {
"database": "xxxxxx",
"encrypt": true,
"rowCollectionOnRequestCompletion": true,
"trusted_connection": true
}
}
// code from /plugins/index.js
const tasks = sqlServer.loadDBPlugin(config.db);
on('task', tasks);
return config
// implement node event listeners here
},
},
});
export default defineConfig({
chromeWebSecurity: false,
videosFolder: 'cypress/videos',
screenshotsFolder: 'cypress/screenshots',
fixturesFolder: 'cypress/fixtures',
video: false,
reporter: 'cypress-mochawesome-reporter',
reporterOptions: {
reportDir: 'cypress/reports',
charts: true,
reportPageTitle: 'xxxxxxxx',
embeddedScreenshots: true,
inlineAssets: true,
},
e2e: {
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.ts')(on, config)
},
experimentalSessionAndOrigin: true,
specPattern: 'cypress/e2e/tests/orders/*',
baseUrl: 'http://localhost:4200',
},
})
index.ts
const { defineConfig } = require('cypress')
module.exports = (on, config) => {
require('#cypress/code-coverage/task')(on, config);
require('cypress-mochawesome-reporter/plugin')(on);
return config;
}
e2e.ts
import '#cypress/code-coverage/support';
import './commands';
import 'cypress-mochawesome-reporter/register';
import sqlServer from 'cypress-sql-server';
sqlServer.loadDBCommands();
}
Tried creating a new sysadmin also on SQL Server in case it was an access issue
The TCP/IP Properties for your instance should look like this to make it listen on port 1433: On IPALL clear the TCP Dynamic Ports and set TCP Port to 1433.
You have the pattern for cypress.config.js plus the one for cypress.config.ts in your config file, but it's either/or not both at once.
See example Configuration.
Since you use typescript, try
import { defineConfig } from 'cypress'
import sqlServer from 'cypress-sql-server'
const dbSettings = {
"userName": "x",
"password": "x",
"server": "xxx\\SQLEXPRESS",
"options": {
"database": "xxxxxx",
"encrypt": true,
"rowCollectionOnRequestCompletion": true,
"trusted_connection": true
}
}
export default defineConfig({
chromeWebSecurity: false,
... // other cofinfig settings
e2e: {
setupNodeEvents(on, config) {
config.db = dbSettings;
const tasks = sqlServer.loadDBPlugin(dbSettings);
on('task', tasks);
return require('./cypress/plugins/index.ts')(on, config)
},
experimentalSessionAndOrigin: true,
specPattern: 'cypress/e2e/tests/orders/*',
baseUrl: 'http://localhost:4200',
},
})
On using internationalization in React application, Need to load the language translation files on demand using api calls and not have them defined upfront. How can this be achieved by using React-i18next?
Tried out the normal translations being picked from static predefined files using React-i18next. Tried using xhr-backend but unable to find any sample to implement this requirement of on-demand load of translation related data.
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import backend from 'i18next-http-backend';
import axiosInstance from './helpers/Axios';
const loadResources=async(locale:string)=> {
return await axiosInstance().get('/translate-data/get', { params: { lang: locale } })
.then((response) => { return response.data })
.catch((error) => { console.log(error); });
}
const backendOptions = {
loadPath: '{{lng}}|{{ns}}',
request: (options:any, url:any, payload:any, callback:any) => {
try {
const [lng] = url.split('|');
loadResources(lng).then((response) => {
callback(null, {
data: response,
status: 200,
});
});
} catch (e) {
console.error(e);
callback(null, {
status: 500,
});
}
},
};
i18n
.use(LanguageDetector)
.use(backend)
.init({
backend: backendOptions,
fallbackLng: "en",
debug: false,
load:"languageOnly",
ns: ["translations"],
defaultNS: "translations",
keySeparator: false,
interpolation: {
escapeValue: false,
formatSeparator: ","
},
react: {
wait: true
}
});
export default i18n;
Request from backend options is used to call backend API using Axios.
import i18next from 'i18next';
import XHR from 'i18next-xhr-backend';
var language = i18next.language ||'en-US';
const backendOptions = {
type: 'backend',
crossDomain: false,
allowMultiLoading: false,
loadPath: `your-backend-api/?locale_code=${language}`
}
const options = {
interpolation: {
escapeValue: false, // not needed for react!!
},
initImmediate: false ,
debug: true,
lng: language,
fallbackLng: language,
// have a common namespace used around the full app
ns: ['translations'],
defaultNS: 'translations',
react: {
wait: false,
bindI18n: 'languageChanged loaded',
bindStore: 'added removed',
nsMode: 'default',
defaultTransParent: 'div',
},
};
options['backend'] = backendOptions;
i18next
.use(XHR)
.init(options)
export default i18next;
I'm running into some issues with snapshot testing using Enzyme and I can't figure out what I'm doing wrong.
I'm using CRA (using React 16.1) with Enzyme (3.2.0) and Styled Components 2.2.3.
This is the component I'm trying to test:
// #flow
import React, { Component } from 'react'
import { Switch } from 'react-router'
import { Route } from 'react-router-dom'
import styled from 'styled-components'
import routes from './routes'
import DebugMenu from './components/DebugMenu'
type Props = {
}
const RouteWithSubRoutes = (route) => {
return (
<Route path={route.path} render={props => {
return <route.component {...props} routes={route.routes} />
}} />
)
}
class App extends Component<Props> {
render () {
return (
<AppWrapper>
{process.env.NODE_ENV === 'development' &&
<DebugMenu routes={routes} />
}
<Switch>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route} />
))}
</Switch>
</AppWrapper>
)
}
}
const AppWrapper = styled.div`
position: absolute;
width: 100%;
height: 100%;
`
export default App
And this is my test:
import React from 'react'
import { shallow } from 'enzyme'
import App from './App'
import { MemoryRouter } from 'react-router-dom'
// import renderer from 'react-test-renderer'
describe('App Specs', () => {
it('Should match with the snapshot for this component', () => {
const wrapper = shallow(
<MemoryRouter initialEntries={['/']}>
<App />
</MemoryRouter>
)
expect(wrapper).toMatchSnapshot()
})
})
I've configured my test setup for Enzyme by setting a setupTest.js file:
import Enzyme, { shallow, render, mount } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import toJson from 'enzyme-to-json'
import 'jest-styled-components'
// React 16 Enzyme adapter
Enzyme.configure({ adapter: new Adapter() })
// Make Enzyme functions available in all test files without importing
global.shallow = shallow
global.render = render
global.mount = mount
global.toJson = toJson
// Fail tests on any warning
console.error = message => {
throw new Error(message)
}
When I run yarn test in watch mode, every time I save, the snapshot for this test changes and thus fails:
FAIL src/App.spec.js
● App Specs › Should match with the snapshot for this component
expect(value).toMatchSnapshot()
Received value does not match stored snapshot 1.
- Snapshot
+ Received
## -29,11 +29,11 ##
"canGo": [Function],
"createHref": [Function],
"entries": Array [
Object {
"hash": "",
- "key": "0af0tp",
+ "key": "u968bq",
"pathname": "/",
"search": "",
"state": undefined,
},
],
## -43,11 +43,11 ##
"index": 0,
"length": 1,
"listen": [Function],
"location": Object {
"hash": "",
- "key": "0af0tp",
+ "key": "u968bq",
"pathname": "/",
"search": "",
"state": undefined,
},
"push": [Function],
## -79,11 +79,11 ##
"canGo": [Function],
"createHref": [Function],
"entries": Array [
Object {
"hash": "",
- "key": "0af0tp",
+ "key": "u968bq",
"pathname": "/",
"search": "",
"state": undefined,
},
],
## -93,11 +93,11 ##
"index": 0,
"length": 1,
"listen": [Function],
"location": Object {
"hash": "",
- "key": "0af0tp",
+ "key": "u968bq",
"pathname": "/",
"search": "",
"state": undefined,
},
"push": [Function],
at Object.it (src/App.spec.js:14:21)
at Promise (<anonymous>)
at Promise.resolve.then.el (node_modules/p-map/index.js:46:16)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:169:7)
Why is this key value changing on each save? Is this caused by Styled Components?
What am I doing wrong?
Turns out this changing key is not actually caused by Styled Components but by wrapping a component in Memory Router.
When using a shallow render of a component that is not wrapped in Memory Router, the snapshots actually match every time.
This article describes a very similar issue: https://swaac.tamouse.org/testing/2017/08/02/TIL-enzyme-shallow-render-with-memoryrouter-doesnt-work/
Following up with this on the Enzyme repo: https://github.com/airbnb/enzyme/issues/1391
I'm trying to run some tests with Jest on my react/react-native library (only some business logic inside).
We are testing actions that uses fetch function (polyfill with whatwg-fetch).
I've added whatwg-fetch (thanks to Safari) for react.
Whenever i try to run a test, i'm getting this error:
TypeError: Cannot read property 'fetch' of undefined
at node_modules/whatwg-fetch/fetch.js:4:11
at Object.<anonymous> (node_modules/whatwg-fetch/fetch.js:461:3)
at Object.<anonymous> (node_modules/jest-expo/src/setup.js:138:416)
What can cause this issue? Is there a way in the jest config to avoid this?
Here are some files for debug:
Jest config in package.json
"jest": {
"preset": "jest-expo",
"moduleFileExtensions": [
"js",
"jsx",
"ts",
"tsx"
],
"verbose": true,
"transform": {
"^.+\\.(js|ts|tsx)$": "<rootDir>/node_modules/babel-jest"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"testPathIgnorePatterns": [
"\\.snap$",
"<rootDir>/node_modules/",
"<rootDir>/dist/"
],
"transformIgnorePatterns": [
"node_modules/?!react-native"
]
},
Webpack config:
const config = {
entry: [
'whatwg-fetch',
__dirname + '/src/index.ts',
],
devtool: 'source-map',
output: {
path: path.join(__dirname, '/dist'),
filename: 'index.js',
library: 'checkinatwork-module',
libraryTarget: 'umd',
umdNamedDefine: true,
},
module: {
loaders: [
{ test: /\.(tsx|ts)?$/, loader: 'ts-loader', exclude: /node_modules/ },
],
},
resolve: {
modules: [
'./src',
'node_modules',
],
extensions: ['.js', '.ts', '.jsx', '.tsx', 'json'],
},
plugins: [
],
};
Test file:
import expect from 'expect';
import * as actions from '../../src/components/Checkin/checkin.action';
import * as reducers from '../../src/components/Checkin/checkin.reducer';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import nock from 'nock';
const middlewares = [ thunk ];
const mockStore = configureMockStore(middlewares);
describe('=> ADD CHECKIN ACTIONS', () => {
describe('- REQUEST', () => {
it('Action: ADD_CHECKIN_REQUEST should request addCawCheckin', () => {
const expectedAction = {
type: actions.ADD_CHECKIN_REQUEST,
isFetching: true,
};
expect(actions.addCheckinRequest())
.toEqual(expectedAction);
});
it('Reducer: newCheckin should trigger ADD_CHECKIN_REQUEST and initiate loading', () => {
const expectedState = {
isFetching: true,
status: null,
};
expect(reducers.newCheckin(reducers.newCheckinDefaultState, actions.addCheckinRequest()))
.toEqual(expectedState);
});
});
Action file:
export const getCheckins = (sessionId, date, url, isRefresh) => {
const config = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sessionId: {sessionId},
date: {date},
}),
};
return dispatch => {
if (!isRefresh) {
dispatch(getCheckinsRequest());
}
return fetch(url + 'getCAWCheckIns', config)
.then(response => response.json())
.then(({ checkins }) => {
dispatch(getCheckinsSuccess(checkins));
}).catch(err => {
dispatch(getCheckinsError('Get checkins failed'));
console.error('Get checkins failed: ', err);
});
};
};
Thanks!
I've done it in the spec with:
import { fetch } from 'whatwg-fetch';
global.fetch = fetch;
And it has worked as expected with Jest.
might be late to the game, but this worked for me.
Possible solution #1
Note: React.PropTypes is deprecated as of React v15.5. Please use the prop-types library instead.
If you install the npm package prop-types, it has isomorphic-fetch as a dependency. This will give you fetch as a global. You will still need to import it into your test file. You might need to exclude it from your linter too.
add this to the top of the test file.
import fetch from 'isomorphic-fetch'
I didn't need to call fetch in the test suite, but I needed to make it available.
If you use this approach, I think you would remove the 'whatwg-fetch', from your webpack entry
Hope this helps
Updated: Possible solution #2
Using the example of #zvona from above, but create a MOCKS folder in your app. then a file /globalMock.js. You might not have set it up properly.
__MOCKS__/globalMock.js
// use one of these imports
import { fetch } from 'whatwg-fetch' // if you want to keep using the polyfill
import { fetch } from 'isomorphic-fetch' // from a dependency node module that I spoke of in the previous solution.
global.fetch = fetch
Now in package.json
add this to your Jest configuration:
"jest": {
"verbose": true,
"rootDir": "app",
"setupFiles": ["<rootDir>/__MOCKS__/globalMock.js"]
}
this will allow the use of fetch in your tests.
I also had to use this same concept for localStorage. Where I keep all of my globals that Jest doesn't have access.
Upgrading react-native, jest, and babel-jest to the latest versions fixed this issue for us.
This worked for me. In your expo set up file(node_modules/jest-expo/src/setup.js) where it requires whatwg-fetch, I changed that require to require('fetch-everywhere')
const { Response, Request, Headers, fetch } =
require('fetch-everywhere');
global.Response = Response;
global.Request = Request;
global.Headers = Headers;
global.fetch = fetch;
For some reasons, only fetch everywhere was working with expo and jest.