Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jest config #10855

Merged
merged 16 commits into from
Apr 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,9 @@ jobs:
- store_artifacts:
path: coverage
destination: coverage
- store_artifacts:
path: jest-coverage
destination: jest-coverage
- store_artifacts:
path: test-artifacts
destination: test-artifacts
Expand Down Expand Up @@ -501,11 +504,15 @@ jobs:
- run:
name: test:coverage
command: yarn test:coverage
- run:
name: test:coverage:jest
command: yarn test:coverage:jest
- persist_to_workspace:
root: .
paths:
- .nyc_output
- coverage
- jest-coverage
test-unit-global:
executor: node-browsers
steps:
Expand Down
7 changes: 7 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ module.exports = {
'test-*/**',
'docs/**',
'coverage/',
'jest-coverage/',
'development/chromereload.js',
'app/vendor/**',
'test/e2e/send-eth-with-private-key-test/**',
Expand Down Expand Up @@ -107,11 +108,16 @@ module.exports = {
},
{
files: ['**/*.test.js'],
excludedFiles: ['ui/app/pages/swaps/**/*.test.js'],
extends: ['@metamask/eslint-config-mocha'],
rules: {
'mocha/no-setup-in-describe': 'off',
},
},
{
files: ['ui/app/pages/swaps/**/*.test.js'],
extends: ['@metamask/eslint-config-jest'],
},
{
files: [
'development/**/*.js',
Expand All @@ -135,6 +141,7 @@ module.exports = {
'test/lib/wait-until-called.js',
'test/env.js',
'test/setup.js',
'jest.config.js',
],
parserOptions: {
sourceType: 'script',
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ app/.DS_Store

storybook-build/
coverage/
jest-coverage/
dist
builds/
builds.zip
Expand Down
6 changes: 6 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
restoreMocks: true,
coverageDirectory: 'jest-coverage/',
setupFiles: ['./test/setup.js', './test/env.js'],
testMatch: ['**/ui/app/pages/swaps/**/?(*.)+(test).js'],
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please add coverageThreshold for Jest? Something like we have in the Controllers repo: https://github.com/MetaMask/controllers/blob/develop/package.json#L108
We can start with whatever numbers we get now from the coverage report and slowly but surely keep increasing them with new code.

Once we have this minimum threshold set up, I can send a PR for setting up enforcement of that threshold on every Git push. It could be done e.g. via the husky node module: https://github.com/typicode/husky
image

Then whoever is contributing to the Swaps feature (and later on to any feature in this repo) will have to add enough unit tests, otherwise they won't be able to push their code.

Let me know what you think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting a minimum coverage goal and ratcheting it up is a good idea - that's basically what we've done with the test:unit:strict and test:unit:lax scripts (the "strict" ones have 100% coverage).

Not sure it needs to go in at this point though? The coverage is incredibly low at the moment. Seems like it could wait for another PR.

The Husky suggestion is bound to be controversial 😅 Some people find husky very irritating. Certainly a discussion to have elsewhere. I've been considering removing the husky setup from the controllers repo and replacing it with something where the git hook is still version-controlled but is opt-in rather than automatic, so that people who prefer not using it or have their IDE running the linter/tests on each change already don't have to add --no-verify to every command.

11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,25 @@
"benchmark:firefox": "SELENIUM_BROWSER=firefox node test/e2e/benchmark.js",
"build:test": "yarn build test",
"build:test:metrics": "SEGMENT_HOST='http://localhost:9090' SEGMENT_WRITE_KEY='FAKE' SEGMENT_LEGACY_WRITE_KEY='FAKE' yarn build test",
"test": "yarn test:unit && yarn lint",
"test": "yarn lint && yarn test:unit && yarn test:unit:jest",
"dapp": "node development/static-server.js node_modules/@metamask/test-dapp/dist --port 8080",
"dapp-chain": "GANACHE_ARGS='-b 2' concurrently -k -n ganache,dapp -p '[{time}][{name}]' 'yarn ganache:start' 'sleep 5 && yarn dapp'",
"forwarder": "node ./development/static-server.js ./node_modules/@metamask/forwarder/dist/ --port 9010",
"dapp-forwarder": "concurrently -k -n forwarder,dapp -p '[{time}][{name}]' 'yarn forwarder' 'yarn dapp'",
"sendwithprivatedapp": "node development/static-server.js test/e2e/send-eth-with-private-key-test --port 8080",
"test:unit": "mocha --exit --require test/env.js --require test/setup.js --recursive './{ui,app,shared}/**/*.test.js'",
"test:unit": "mocha --exit --require test/env.js --require test/setup.js --ignore './ui/app/pages/swaps/**/*.test.js' --recursive './{ui,app,shared}/**/*.test.js'",
"test:unit:global": "mocha --exit --require test/env.js --require test/setup.js --recursive test/unit-global/*.test.js",
"test:unit:lax": "mocha --exit --require test/env.js --require test/setup.js --ignore './app/scripts/controllers/permissions/*.test.js' --recursive './{ui,app,shared}/**/*.test.js'",
"test:unit:jest": "jest",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

"test:unit:jest:ci": "jest --maxWorkers=2",
"test:unit:lax": "mocha --exit --require test/env.js --require test/setup.js --ignore './app/scripts/controllers/permissions/*.test.js' --ignore './ui/app/pages/swaps/**/*.test.js' --recursive './{ui,app,shared}/**/*.test.js'",
"test:unit:strict": "mocha --exit --require test/env.js --require test/setup.js --recursive './app/scripts/controllers/permissions/*.test.js'",
"test:unit:path": "mocha --exit --require test/env.js --require test/setup.js --recursive",
"test:e2e:chrome": "SELENIUM_BROWSER=chrome test/e2e/run-all.sh",
"test:e2e:chrome:metrics": "SELENIUM_BROWSER=chrome mocha test/e2e/metrics.spec.js",
"test:e2e:firefox": "SELENIUM_BROWSER=firefox test/e2e/run-all.sh",
"test:e2e:firefox:metrics": "SELENIUM_BROWSER=firefox mocha test/e2e/metrics.spec.js",
"test:coverage": "nyc --silent --check-coverage yarn test:unit:strict && nyc --silent --no-clean yarn test:unit:lax && nyc report --reporter=text --reporter=html",
"test:coverage:jest": "jest --coverage --maxWorkers=2 --collectCoverageFrom=**/ui/app/pages/swaps/**",
"test:coverage:strict": "nyc --check-coverage yarn test:unit:strict",
"test:coverage:path": "nyc --check-coverage yarn test:unit:path",
"ganache:start": "./development/run-ganache.sh",
Expand Down Expand Up @@ -201,6 +204,7 @@
"@babel/register": "^7.5.5",
"@lavamoat/allow-scripts": "^1.0.4",
"@metamask/eslint-config": "^6.0.0",
"@metamask/eslint-config-jest": "^6.0.0",
"@metamask/eslint-config-mocha": "^6.0.0",
"@metamask/eslint-config-nodejs": "^6.0.0",
"@metamask/forwarder": "^1.1.0",
Expand Down Expand Up @@ -233,6 +237,7 @@
"eslint": "^7.23.0",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jest": "^24.3.4",
"eslint-plugin-mocha": "^8.1.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.3.1",
Expand Down
108 changes: 54 additions & 54 deletions ui/app/pages/swaps/swaps.util.test.js
Original file line number Diff line number Diff line change
@@ -1,54 +1,31 @@
import { strict as assert } from 'assert';
import proxyquire from 'proxyquire';
import nock from 'nock';
import { MAINNET_CHAIN_ID } from '../../../../shared/constants/network';
import {
TRADES_BASE_PROD_URL,
TOKENS_BASE_PROD_URL,
AGGREGATOR_METADATA_BASE_PROD_URL,
TOP_ASSET_BASE_PROD_URL,
TOKENS,
EXPECTED_TOKENS_RESULT,
MOCK_TRADE_RESPONSE_2,
AGGREGATOR_METADATA,
TOP_ASSETS,
} from './swaps-util-test-constants';

const swapsUtils = proxyquire('./swaps.util.js', {
'../../helpers/utils/fetch-with-cache': {
default: (url, fetchObject) => {
assert.strictEqual(fetchObject.method, 'GET');
if (url.match(TRADES_BASE_PROD_URL)) {
assert.strictEqual(
url,
'https://api.metaswap.codefi.network/trades?destinationToken=0xE41d2489571d322189246DaFA5ebDe1F4699F498&sourceToken=0x617b3f8050a0BD94b6b1da02B4384eE5B4DF13F4&sourceAmount=2000000000000000000000000000000000000&slippage=3&timeout=10000&walletAddress=0xmockAddress',
);
return Promise.resolve(MOCK_TRADE_RESPONSE_2);
}
if (url.match(TOKENS_BASE_PROD_URL)) {
assert.strictEqual(url, TOKENS_BASE_PROD_URL);
return Promise.resolve(TOKENS);
}
if (url.match(AGGREGATOR_METADATA_BASE_PROD_URL)) {
assert.strictEqual(url, AGGREGATOR_METADATA_BASE_PROD_URL);
return Promise.resolve(AGGREGATOR_METADATA);
}
if (url.match(TOP_ASSET_BASE_PROD_URL)) {
assert.strictEqual(url, TOP_ASSET_BASE_PROD_URL);
return Promise.resolve(TOP_ASSETS);
}
return Promise.resolve();
},
},
});
const {
import {
fetchTradesInfo,
fetchTokens,
fetchAggregatorMetadata,
fetchTopAssets,
} = swapsUtils;
} from './swaps.util';

jest.mock('../../../lib/storage-helpers.js', () => ({
getStorageItem: jest.fn(),
setStorageItem: jest.fn(),
}));

describe('Swaps Util', function () {
describe('fetchTradesInfo', function () {
describe('Swaps Util', () => {
afterEach(() => {
nock.cleanAll();
});

describe('fetchTradesInfo', () => {
const expectedResult1 = {
zeroEx: {
trade: {
Expand Down Expand Up @@ -90,7 +67,12 @@ describe('Swaps Util', function () {
sourceAmount: '20000000000000000',
},
};
it('should fetch trade info on prod', async function () {
it('should fetch trade info on prod', async () => {
nock('https://api.metaswap.codefi.network')
.get('/trades')
.query(true)
.reply(200, MOCK_TRADE_RESPONSE_2);

const result = await fetchTradesInfo(
{
TOKENS,
Expand All @@ -106,35 +88,53 @@ describe('Swaps Util', function () {
},
{ chainId: MAINNET_CHAIN_ID },
);
assert.deepStrictEqual(result, expectedResult2);
expect(result).toStrictEqual(expectedResult2);
});
});

describe('fetchTokens', function () {
it('should fetch tokens', async function () {
describe('fetchTokens', () => {
beforeEach(() => {
nock('https://api.metaswap.codefi.network')
.get('/tokens')
.reply(200, TOKENS);
});

it('should fetch tokens', async () => {
const result = await fetchTokens(MAINNET_CHAIN_ID);
assert.deepStrictEqual(result, EXPECTED_TOKENS_RESULT);
expect(result).toStrictEqual(EXPECTED_TOKENS_RESULT);
});

it('should fetch tokens on prod', async function () {
it('should fetch tokens on prod', async () => {
const result = await fetchTokens(MAINNET_CHAIN_ID);
assert.deepStrictEqual(result, EXPECTED_TOKENS_RESULT);
expect(result).toStrictEqual(EXPECTED_TOKENS_RESULT);
});
});

describe('fetchAggregatorMetadata', function () {
it('should fetch aggregator metadata', async function () {
describe('fetchAggregatorMetadata', () => {
beforeEach(() => {
nock('https://api.metaswap.codefi.network')
.get('/aggregatorMetadata')
.reply(200, AGGREGATOR_METADATA);
});

it('should fetch aggregator metadata', async () => {
const result = await fetchAggregatorMetadata(MAINNET_CHAIN_ID);
assert.deepStrictEqual(result, AGGREGATOR_METADATA);
expect(result).toStrictEqual(AGGREGATOR_METADATA);
});

it('should fetch aggregator metadata on prod', async function () {
it('should fetch aggregator metadata on prod', async () => {
const result = await fetchAggregatorMetadata(MAINNET_CHAIN_ID);
assert.deepStrictEqual(result, AGGREGATOR_METADATA);
expect(result).toStrictEqual(AGGREGATOR_METADATA);
});
});

describe('fetchTopAssets', function () {
describe('fetchTopAssets', () => {
beforeEach(() => {
nock('https://api.metaswap.codefi.network')
.get('/topAssets')
.reply(200, TOP_ASSETS);
});

const expectedResult = {
'0x514910771af9ca656af840dff83e8264ecf986ca': {
index: '0',
Expand All @@ -152,14 +152,14 @@ describe('Swaps Util', function () {
index: '4',
},
};
it('should fetch top assets', async function () {
it('should fetch top assets', async () => {
const result = await fetchTopAssets(MAINNET_CHAIN_ID);
assert.deepStrictEqual(result, expectedResult);
expect(result).toStrictEqual(expectedResult);
});

it('should fetch top assets on prod', async function () {
it('should fetch top assets on prod', async () => {
const result = await fetchTopAssets(MAINNET_CHAIN_ID);
assert.deepStrictEqual(result, expectedResult);
expect(result).toStrictEqual(expectedResult);
});
});
});
25 changes: 12 additions & 13 deletions ui/app/pages/swaps/view-quote/view-quote-price-difference.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import assert from 'assert';
import React from 'react';
import { shallow } from 'enzyme';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import { NETWORK_TYPE_RPC } from '../../../../../shared/constants/network';
import ViewQuotePriceDifference from './view-quote-price-difference';

describe('View Price Quote Difference', function () {
describe('View Price Quote Difference', () => {
const t = (key) => `translate ${key}`;

const state = {
Expand Down Expand Up @@ -98,53 +97,53 @@ describe('View Price Quote Difference', function () {
);
}

afterEach(function () {
afterEach(() => {
component.unmount();
});

it('does not render when there is no quote', function () {
it('does not render when there is no quote', () => {
const props = { ...DEFAULT_PROPS, usedQuote: null };
renderComponent(props);

const wrappingDiv = component.find(
'.view-quote__price-difference-warning-wrapper',
);
assert.strictEqual(wrappingDiv.length, 0);
expect(wrappingDiv).toHaveLength(0);
});

it('does not render when the item is in the low bucket', function () {
it('does not render when the item is in the low bucket', () => {
const props = { ...DEFAULT_PROPS };
props.usedQuote.priceSlippage.bucket = 'low';

renderComponent(props);
const wrappingDiv = component.find(
'.view-quote__price-difference-warning-wrapper',
);
assert.strictEqual(wrappingDiv.length, 0);
expect(wrappingDiv).toHaveLength(0);
});

it('displays an error when in medium bucket', function () {
it('displays an error when in medium bucket', () => {
const props = { ...DEFAULT_PROPS };
props.usedQuote.priceSlippage.bucket = 'medium';

renderComponent(props);
assert.strictEqual(component.html().includes('medium'), true);
expect(component.html()).toContain('medium');
});

it('displays an error when in high bucket', function () {
it('displays an error when in high bucket', () => {
const props = { ...DEFAULT_PROPS };
props.usedQuote.priceSlippage.bucket = 'high';

renderComponent(props);
assert.strictEqual(component.html().includes('high'), true);
expect(component.html()).toContain('high');
});

it('displays a fiat error when calculationError is present', function () {
it('displays a fiat error when calculationError is present', () => {
const props = { ...DEFAULT_PROPS, priceSlippageUnknownFiatValue: true };
props.usedQuote.priceSlippage.calculationError =
'Could not determine price.';

renderComponent(props);
assert.strictEqual(component.html().includes('fiat-error'), true);
expect(component.html()).toContain('fiat-error');
});
});
Loading