test: Migration to jest (#935)

* jest initialised

* refactor: `connect()` and `openApp()`

* test: integrate to jest

* chore: renaming jests test commands

* chore: adding override rule for non `commands/serve` directories to skip jest rules
This commit is contained in:
Ahmad Mirzaei
2022-09-26 11:02:32 +02:00
committed by GitHub
parent dcebeb157c
commit 5990d85a95
11 changed files with 1486 additions and 143 deletions

View File

@@ -1,13 +1,14 @@
{
"root": true,
"env": {
"browser": true
"browser": true,
"jest/globals": true
},
"parserOptions": {
"sourceType": "module"
},
"extends": ["airbnb", "prettier"],
"plugins": ["prettier"],
"plugins": ["prettier", "jest"],
"rules": {
"max-len": 0,
"no-plusplus": 0,
@@ -18,12 +19,24 @@
"react/prop-types": 0,
"react/no-deprecated": 0,
"import/no-extraneous-dependencies": [2, { "devDependencies": true }],
"import/no-dynamic-require": 0
"import/no-dynamic-require": 0,
"jest/no-disabled-tests": "warn",
"jest/no-focused-tests": "error",
"jest/no-identical-title": "error",
"jest/prefer-to-have-length": "warn",
"jest/valid-expect": "error"
},
"globals": {
"__NEBULA_DEV__": false
},
"overrides": [
{
"files": ["apis/**/*", "packages/**/*", "commands/create/**/*", "commands/sense/src/**/*"],
"rules": {
"jest/valid-expect": 0,
"jest/no-identical-title": 0
}
},
{
"files": ["scripts/**/*", "**/apis/*/scripts/**/*"],
"rules": {

View File

@@ -2,15 +2,7 @@ module.exports = {
env: {
test: {
presets: [['@babel/preset-env', { targets: { node: 'current' } }]],
plugins: [
['@babel/plugin-transform-react-jsx'],
[
'istanbul',
{
exclude: ['**/test/**', '**/__test__/**', '**/dist/**'],
},
],
],
plugins: ['@babel/plugin-transform-react-jsx'],
},
},
};

View File

@@ -21,7 +21,7 @@ import Step from '@mui/material/Step';
import StepLabel from '@mui/material/StepLabel';
import CircularProgress from '@mui/material/CircularProgress';
import { info as connectionInfo, connect } from '../connect';
import { getConnectionInfo, connect } from '../connect';
import storageFn from '../storage';
const storage = storageFn({});
@@ -268,7 +268,7 @@ export default function Hub() {
};
useEffect(() => {
connectionInfo.then((i) => {
getConnectionInfo().then((i) => {
if (i.enigma.appId) {
window.location.href = `/dev/${window.location.search}`;
return;

View File

@@ -61,51 +61,37 @@ const parseEngineURL = (url) => {
};
};
const connectionInfo = fetch('/info')
.then((response) => response.json())
.then(async (n) => {
let info = n;
if (params.engine_url) {
info = {
const getConnectionInfo = () =>
fetch('/info')
.then((response) => response.json())
.then(async (n) => {
let info = n;
if (params.engine_url) {
info = {
...info,
...parseEngineURL(params.engine_url),
};
} else if (params.app) {
info = {
...info,
enigma: {
...info.enigma,
appId: params.app,
},
};
}
if (params['qlik-web-integration-id']) {
info.webIntegrationId = params['qlik-web-integration-id'];
}
if (info.invalid) {
return info;
}
const rootPath = `${info.enigma.secure ? 'https' : 'http'}://${info.enigma.host}`;
return {
...info,
...parseEngineURL(params.engine_url),
rootPath,
};
} else if (params.app) {
info = {
...info,
enigma: {
...info.enigma,
appId: params.app,
},
};
}
if (params['qlik-web-integration-id']) {
info.webIntegrationId = params['qlik-web-integration-id'];
}
if (info.invalid) {
return info;
}
const rootPath = `${info.enigma.secure ? 'https' : 'http'}://${info.enigma.host}`;
return {
...info,
rootPath,
};
});
let headers;
const getHeaders = (authInstance) => {
if (!authInstance) return 401;
headers = {
'qlik-web-integration-id': authInstance.config.webIntegrationId,
'qlik-csrf-token': authInstance.config.csrfToken,
};
return headers;
};
const defaultConfig = {
secure: false,
};
});
const getAuthInstance = ({ webIntegrationId, host }) => {
const authInstance = new Auth({
@@ -118,69 +104,73 @@ const getAuthInstance = ({ webIntegrationId, host }) => {
return authInstance;
};
let connection;
const connect = () => {
if (!connection) {
connection = connectionInfo.then(({ webIntegrationId, enigma: enigmaInfo, enigma: { host } }) => {
if (webIntegrationId) {
const authInstance = getAuthInstance({ webIntegrationId, host });
if (!headers) headers = getHeaders(authInstance);
if (headers === 401) return { status: 401 };
const connect = async () => {
try {
const {
webIntegrationId,
enigma: enigmaInfo,
enigma: { host },
} = await getConnectionInfo();
return {
getDocList: async () => {
const url = `/items?resourceType=app&limit=30&sort=-updatedAt`;
const { data = [] } = await (await authInstance.rest(url)).json();
return data.map((d) => ({
qDocId: d.resourceId,
qTitle: d.name,
}));
},
getConfiguration: async () => ({}),
};
}
const url = SenseUtilities.buildUrl({
...defaultConfig,
...enigmaInfo,
});
return enigma
.create({
schema: qixSchema,
url,
})
.open();
});
}
return connection;
};
const openApp = (id) =>
connectionInfo.then(async ({ webIntegrationId, enigma: enigmaInfo, enigma: { host } }) => {
let urlParams = {};
if (webIntegrationId) {
const authInstance = getAuthInstance({ webIntegrationId, host });
if (!headers) headers = getHeaders(authInstance);
urlParams = { ...headers };
return {
getDocList: async () => {
const url = `/items?resourceType=app&limit=30&sort=-updatedAt`;
const { data = [] } = await (await authInstance.rest(url)).json();
return data.map((d) => ({
qDocId: d.resourceId,
qTitle: d.name,
}));
},
getConfiguration: async () => ({}),
};
}
const url = SenseUtilities.buildUrl({
secure: false,
...enigmaInfo,
});
return enigma
.create({
schema: qixSchema,
url,
})
.open();
} catch (error) {
throw new Error('Failed to return enigma instance');
}
};
const openApp = async (id) => {
try {
const {
webIntegrationId,
enigma: enigmaInfo,
enigma: { host },
} = await getConnectionInfo();
if (webIntegrationId) {
const authInstance = getAuthInstance({ webIntegrationId, host });
const url = await authInstance.generateWebsocketUrl(id);
const enigmaGlobal = await enigma.create({ schema: qixSchema, url }).open();
return enigmaGlobal.openDoc(id);
}
const url = SenseUtilities.buildUrl({
...defaultConfig,
secure: false,
...enigmaInfo,
urlParams,
urlParams: {},
appId: id,
});
return enigma
.create({ schema: qixSchema, url })
.open()
.then((global) => global.openDoc(id));
});
} catch (error) {
throw new Error('Failed to open app!');
}
};
export { connect, openApp, params, connectionInfo as info };
export { connect, openApp, params, getConnectionInfo, getAuthInstance };

View File

@@ -3,10 +3,10 @@ import ReactDOM from 'react-dom';
import App from './components/App';
import { openApp, info } from './connect';
import { openApp, getConnectionInfo } from './connect';
import initiateWatch from './hot';
info.then(($) => {
getConnectionInfo().then(($) => {
if (!$.enigma.appId) {
window.location.href = `/${window.location.search}`;
}

View File

@@ -2,7 +2,7 @@
import { embed } from '@nebula.js/stardust';
import snapshooter from '@nebula.js/snapshooter/client';
import { openApp, params, info as serverInfo } from './connect';
import { openApp, params, getConnectionInfo } from './connect';
import initiateWatch from './hot';
import renderFixture from './render-fixture';
@@ -31,7 +31,7 @@ const nuke = async ({ app, supernova: { name }, themes, theme, language }) => {
};
async function renderWithEngine() {
const info = await serverInfo;
const info = await getConnectionInfo();
initiateWatch(info);
if (!info.enigma.appId) {
location.href = location.origin; //eslint-disable-line
@@ -79,7 +79,7 @@ async function renderWithEngine() {
}
async function renderSnapshot() {
const info = await serverInfo;
const info = await getConnectionInfo();
const { themes, supernova } = info;
initiateWatch(info);
const element = document.querySelector('#chart-container');

View File

@@ -1,7 +1,7 @@
import { embed } from '@nebula.js/stardust';
import EnigmaMocker from '@nebula.js/enigma-mocker';
import extend from 'extend';
import { info as getServerInfo } from './connect';
import { getConnectionInfo } from './connect';
import { getModule } from './hot';
const getDefaultGenericObject = ({ type }) => ({
@@ -101,7 +101,7 @@ function getQId(genericObjects = []) {
const renderFixture = async (params) => {
const element = document.querySelector('#chart-container');
const serverInfo = await getServerInfo;
const serverInfo = await getConnectionInfo();
const fixture = await getFixture(params.fixture);
const { type, load, genericObjects, instanceConfig, snConfig } = await getOptions({ fixture, params, serverInfo });
const mockedApp = await EnigmaMocker.fromGenericObjects(genericObjects);

16
jest.config.js Normal file
View File

@@ -0,0 +1,16 @@
module.exports = {
clearMocks: true,
testEnvironment: 'jest-environment-jsdom',
testRegex: ['commands/serve/web/.+\\.(test|spec)\\.[jt]sx?$'],
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
collectCoverageFrom: [
'commands/serve/web/**/*.{js,jsx}',
'!commands/serve/web/**/*.spec.{js,jsx}',
'!commands/serve/web/**/*.test.{js,jsx}',
'!commands/serve/web/**/__tests__/**/*',
'!**/dist/**',
'!**/node_modules/**',
],
coverageReporters: ['json', 'lcov', 'text-summary', 'clover'],
};

2
jest.setup.js Normal file
View File

@@ -0,0 +1,2 @@
import '@testing-library/jest-dom';
import 'whatwg-fetch';

View File

@@ -15,6 +15,9 @@
"build-storybook": "build-storybook",
"spec": "lerna run spec --stream --concurrency 99 && lerna run ts --stream --concurrency 99 ",
"test": "yarn run test:unit",
"test:jest": "jest",
"test:jest:watch": "jest --watch",
"test:jest:coverage": "jest --coverage",
"mashup": "node scripts/start-mashup.js",
"test:mashup": "aw puppet -c aw.config.js --testExt '*.int.js' --glob 'test/mashup/**/*.int.js'",
"test:integration": "aw puppet -c aw.config.js --testExt '*.int.js' --glob 'test/integration/**/*.int.js'",
@@ -36,8 +39,8 @@
"@babel/cli": "7.18.10",
"@babel/core": "7.18.13",
"@babel/helper-plugin-utils": "7.18.9",
"@babel/plugin-transform-react-jsx": "7.18.10",
"@babel/plugin-proposal-object-rest-spread": "7.18.9",
"@babel/plugin-transform-react-jsx": "7.18.10",
"@babel/preset-env": "7.18.10",
"@babel/preset-react": "7.18.6",
"@commitlint/cli": "17.1.2",
@@ -46,9 +49,9 @@
"@rollup/plugin-json": "4.1.0",
"@rollup/plugin-node-resolve": "13.3.0",
"@rollup/plugin-replace": "4.0.0",
"@storybook/addon-docs": "6.5.10",
"@storybook/addon-controls": "6.5.10",
"@storybook/addon-actions": "6.5.10",
"@storybook/addon-controls": "6.5.10",
"@storybook/addon-docs": "6.5.10",
"@storybook/addon-essentials": "6.5.10",
"@storybook/addon-interactions": "6.5.10",
"@storybook/addon-links": "6.5.10",
@@ -56,6 +59,7 @@
"@storybook/manager-webpack5": "6.5.10",
"@storybook/react": "6.5.10",
"@storybook/testing-library": "0.0.13",
"@testing-library/jest-dom": "^5.16.5",
"babel-loader": "8.2.5",
"babel-plugin-istanbul": "6.1.1",
"body-parser": "1.20.0",
@@ -65,6 +69,7 @@
"eslint-config-airbnb": "19.0.4",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-jest": "^27.0.4",
"eslint-plugin-jsx-a11y": "6.6.1",
"eslint-plugin-mocha": "10.1.0",
"eslint-plugin-prettier": "4.2.1",
@@ -72,6 +77,8 @@
"eslint-plugin-storybook": "0.6.4",
"express": "4.18.1",
"husky": "8.0.1",
"jest": "^29.0.3",
"jest-environment-jsdom": "^29.0.3",
"jimp": "0.16.1",
"lerna": "5.5.0",
"lint-staged": "13.0.3",
@@ -86,6 +93,7 @@
"rollup-plugin-dependency-flow": "0.3.0",
"rollup-plugin-sass": "1.2.13",
"rollup-plugin-terser": "7.0.2",
"whatwg-fetch": "^3.6.2",
"yargs": "17.5.1"
},
"resolutions": {

1380
yarn.lock

File diff suppressed because it is too large Load Diff