A proof of concept for frontend test with substrate in docker (#3371)

* React tests PoC.

* Globally start and stop substrate for all tests.

* Fix compilation problem.

* Another attempt to make both compilation and tests work.

* Apply suggestions from code review

* Run slow tests with docker only nightly.

* Update yarn.lock.

Co-authored-by: Jaco Greeff <jacogr@gmail.com>
This commit is contained in:
Krzysztof Jelski 2020-08-19 11:27:52 +02:00 committed by GitHub
parent f79e6ea832
commit 8b50b1b28c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 401 additions and 8 deletions

19
.github/workflows/test-nightly.yml vendored Normal file
View File

@ -0,0 +1,19 @@
name: Nightly tests run
on:
schedule:
- cron: '1 5 * * *'
jobs:
alltests:
strategy:
matrix:
step: ['test:all']
name: ${{ matrix.step }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: ${{ matrix.step }}
run: |
yarn install --immutable | grep -v 'YN0013'
yarn ${{ matrix.step }}

6
__mocks__/fileMock.js Normal file
View File

@ -0,0 +1,6 @@
// Copyright 2019-2020 @polkadot/extension authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
// eslint-disable-line
module.exports = '';

View File

@ -14,13 +14,30 @@ const internalModules = findPackages()
return modules;
}, {});
module.exports = Object.assign({}, config, {
const defaultConfig = {
moduleNameMapper: {
...internalModules,
'\\.(css|less)$': 'empty/object',
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'empty/object'
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'empty/object',
'\\.(md)$': '<rootDir>/__mocks__/fileMock.js'
},
testTimeout: 25000,
transformIgnorePatterns: [
'<rootDir>/node_modules'
]
};
module.exports = Object.assign({}, config, {
projects: [
{
...defaultConfig,
displayName: 'all-tests',
globalSetup: './jest/globalSetup.ts',
globalTeardown: './jest/globalTeardown.ts'
},
{
...defaultConfig,
displayName: 'fast-tests'
}
]
});

28
jest/globalSetup.ts Normal file
View File

@ -0,0 +1,28 @@
// Copyright 2017-2020 @polkadot/app-accounts authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { GenericContainer, Wait } from 'testcontainers';
import { SubstrateTestsGlobal } from './substrateTestsGlobal';
declare const global: SubstrateTestsGlobal;
const startSubstrate = async () => {
console.log('Substrate container starting...');
const startedTestContainer = await new GenericContainer('parity/substrate')
.withName('polkadot-apps-test-substrate')
.withExposedPorts(9944)
.withCmd(['--dev', '--ws-port=9944', '--unsafe-ws-external'])
.withWaitStrategy(Wait.forLogMessage('New epoch 0 launching'))
.start();
console.log('Done.');
process.env.TEST_SUBSTRATE_PORT = startedTestContainer.getMappedPort(9944)?.toString() || '';
global.__SUBSTRATE__ = startedTestContainer;
};
export default async (): Promise<void> => {
await startSubstrate();
};

15
jest/globalTeardown.ts Normal file
View File

@ -0,0 +1,15 @@
// Copyright 2017-2020 @polkadot/app-accounts authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { SubstrateTestsGlobal } from './substrateTestsGlobal';
declare const global: SubstrateTestsGlobal;
export default async (): Promise<void> => {
console.log('Shutting down Substrate container...');
await global.__SUBSTRATE__.stop();
console.log('Done.');
};

View File

@ -0,0 +1,10 @@
// Copyright 2017-2020 @polkadot/app-accounts authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { StartedTestContainer } from 'testcontainers';
export interface SubstrateTestsGlobal extends NodeJS.Global {
__SUBSTRATE__: StartedTestContainer;
// You can declare anything you need.
}

View File

@ -71,7 +71,8 @@
"lint:css": "stylelint './packages/**/src/**/*.tsx'",
"postinstall": "polkadot-dev-yarn-only",
"postinstall:electron": "electron-builder install-app-deps",
"test": "polkadot-dev-run-test packages/page-claims/src packages/apps-electron",
"test": "polkadot-dev-run-test --selectProjects=fast-tests --silent --testNamePattern='^((?!--SLOW--).)*$'",
"test:all": "polkadot-dev-run-test --selectProjects=all-tests --silent",
"test:one": "polkadot-dev-run-test",
"start": "yarn clean && cd packages/apps && webpack --config webpack.config.js",
"start:electron": "yarn clean:electronBuild && concurrently 'yarn build:devElectronMain && cd packages/apps-electron && electron ./build/electron.js' 'yarn build:devElectronRenderer'"

View File

@ -16,5 +16,9 @@
"@polkadot/vanitygen": "^0.20.0-beta.1",
"detect-browser": "^5.1.1",
"file-saver": "^2.0.2"
},
"devDependencies": {
"@testing-library/react": "^10.4.8",
"testcontainers": "^2.17.0"
}
}

View File

@ -0,0 +1,63 @@
// Copyright 2017-2020 @polkadot/app-accounts authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import AccountsApp from '@polkadot/app-accounts';
import { MemoryStore } from '@polkadot/app-accounts/test-support/MemoryStore';
import { Api } from '@polkadot/react-api';
import '@polkadot/react-components/i18n';
import { useApi } from '@polkadot/react-hooks';
import { fireEvent, render } from '@testing-library/react';
import React, { PropsWithChildren } from 'react';
import { MemoryRouter } from 'react-router-dom';
const SUBSTRATE_PORT = Number.parseInt(process.env.TEST_SUBSTRATE_PORT || '30333');
const WaitForApi = ({ children }: { children: React.ReactNode }): PropsWithChildren<any> | null => {
const api = useApi();
return api.isApiReady ? (children) : null;
};
describe('--SLOW--: Account Create', () => {
it('asks for confirmation after saving new account', async () => {
const memoryStore = new MemoryStore();
const { findByPlaceholderText, findByTestId, findByText } = render(
<MemoryRouter>
<Api store={memoryStore}
url={`ws://127.0.0.1:${SUBSTRATE_PORT}`}>
<WaitForApi>
<div>
<AccountsApp basePath='/accounts'
onStatusChange={() => { /* */
}}/>
</div>
</WaitForApi>
</Api>
</MemoryRouter>
);
const addAccountButton = await findByText('Add account', {}, { timeout: 4000 });
fireEvent.click(addAccountButton);
const nameInput = await findByPlaceholderText('new account');
fireEvent.change(nameInput, { target: { value: 'my super account' } });
const passwordInput = await findByTestId('password');
fireEvent.change(passwordInput, { target: { value: 'a' } });
const passwordRepeatInput = await findByTestId('password (repeat)');
fireEvent.change(passwordRepeatInput, { target: { value: 'a' } });
const saveButton = await findByText('Save');
fireEvent.click(saveButton);
expect(await findByText('Create and backup account')).toBeTruthy();
});
});

View File

@ -0,0 +1,35 @@
// Copyright 2017-2020 @polkadot/app-accounts authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { KeyringJson, KeyringStore } from '@polkadot/ui-keyring/types';
type AccountsMap = Record<string, KeyringJson>;
export class MemoryStore implements KeyringStore {
private accounts: AccountsMap = {};
all (cb: (key: string, value: KeyringJson) => void): void {
Object.keys(this.accounts).forEach((accountsKey) => cb(accountsKey, this.accounts[accountsKey]));
}
get (key: string, cb: (value: KeyringJson) => void): void {
cb(this.accounts[key]);
}
remove (key: string, cb: (() => void) | undefined): void {
delete this.accounts[key];
if (cb) {
cb();
}
}
set (key: string, value: KeyringJson, cb: (() => void) | undefined): void {
this.accounts[key] = value;
if (cb) {
cb();
}
}
}

View File

@ -198,6 +198,7 @@ function Input ({ autoFocus = false, children, className, defaultValue, help, ic
: 'off'
}
autoCorrect='off'
data-testid={label}
onPaste={_onPaste}
spellCheck={false}
/>

204
yarn.lock
View File

@ -1428,7 +1428,17 @@ __metadata:
languageName: node
linkType: hard
"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.11.0, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4":
"@babel/runtime-corejs3@npm:^7.10.2":
version: 7.11.2
resolution: "@babel/runtime-corejs3@npm:7.11.2"
dependencies:
core-js-pure: ^3.0.0
regenerator-runtime: ^0.13.4
checksum: 151da4e97bb558d5a58e2a94eb89bcd505b7273c00b6ad8fe1988aefbe16aee01aa83dba0e90e56370a3e99d974d4f5fb081a6489161dc414e322d70bf19bc92
languageName: node
linkType: hard
"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.11.0, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4":
version: 7.11.2
resolution: "@babel/runtime@npm:7.11.2"
dependencies:
@ -3099,8 +3109,10 @@ __metadata:
"@babel/runtime": ^7.11.2
"@polkadot/react-components": 0.55.0-beta.4
"@polkadot/vanitygen": ^0.20.0-beta.1
"@testing-library/react": ^10.4.8
detect-browser: ^5.1.1
file-saver: ^2.0.2
testcontainers: ^2.17.0
languageName: unknown
linkType: soft
@ -3925,6 +3937,32 @@ __metadata:
languageName: node
linkType: hard
"@testing-library/dom@npm:^7.17.1":
version: 7.22.2
resolution: "@testing-library/dom@npm:7.22.2"
dependencies:
"@babel/runtime": ^7.10.3
"@types/aria-query": ^4.2.0
aria-query: ^4.2.2
dom-accessibility-api: ^0.5.0
pretty-format: ^25.5.0
checksum: 9894fb1e1ca335099b1c3d8e5ecc2c3222bfa7ec0345c9053943d27657a554ea9c326af14a400c63cb8431de59a03baf1ec1ae4d28ec9d3abfc40db230879bc0
languageName: node
linkType: hard
"@testing-library/react@npm:^10.4.8":
version: 10.4.8
resolution: "@testing-library/react@npm:10.4.8"
dependencies:
"@babel/runtime": ^7.10.3
"@testing-library/dom": ^7.17.1
peerDependencies:
react: "*"
react-dom: "*"
checksum: 8e725f094be47651b852a356e7fff9bcde2ab665c8ba7b0d9ef8e2140dd1158c8b58d4fcbebd4f5d03e32cff34c4c035a4d5a761903f1c908bebc2fe6abc8ec2
languageName: node
linkType: hard
"@types/anymatch@npm:*":
version: 1.3.1
resolution: "@types/anymatch@npm:1.3.1"
@ -3932,6 +3970,13 @@ __metadata:
languageName: node
linkType: hard
"@types/aria-query@npm:^4.2.0":
version: 4.2.0
resolution: "@types/aria-query@npm:4.2.0"
checksum: 196c811653507cc0601bb1260ddeb58d80797306cf71638605d64d26ae324345b4b95514617942aadf5b899602623cf848ba6780e921526ef5cf0b0cae80825f
languageName: node
linkType: hard
"@types/babel__core@npm:^7.0.0, @types/babel__core@npm:^7.1.7":
version: 7.1.9
resolution: "@types/babel__core@npm:7.1.9"
@ -4036,6 +4081,15 @@ __metadata:
languageName: node
linkType: hard
"@types/dockerode@npm:^2.5.34":
version: 2.5.34
resolution: "@types/dockerode@npm:2.5.34"
dependencies:
"@types/node": "*"
checksum: ae3893a618b3cc43569b4face73196d82065a82b28fafc379dd75eb812097e33c8ec5151d608f3dd28cf5f60e313f3ea1b88e4f11954c46aaad371346709ad56
languageName: node
linkType: hard
"@types/eslint-visitor-keys@npm:^1.0.0":
version: 1.0.0
resolution: "@types/eslint-visitor-keys@npm:1.0.0"
@ -5709,6 +5763,16 @@ __metadata:
languageName: node
linkType: hard
"aria-query@npm:^4.2.2":
version: 4.2.2
resolution: "aria-query@npm:4.2.2"
dependencies:
"@babel/runtime": ^7.10.2
"@babel/runtime-corejs3": ^7.10.2
checksum: dc7631b6f9aee453aee3587f1b4e998e2fca89909a7d2587d91694165d161850a8b64c433348efde78297e35473df6d79deb7abea8571f82485dad9b5401c390
languageName: node
linkType: hard
"arr-diff@npm:^2.0.0":
version: 2.0.0
resolution: "arr-diff@npm:2.0.0"
@ -5869,7 +5933,7 @@ __metadata:
languageName: node
linkType: hard
"asn1@npm:~0.2.3":
"asn1@npm:~0.2.0, asn1@npm:~0.2.3":
version: 0.2.4
resolution: "asn1@npm:0.2.4"
dependencies:
@ -6267,7 +6331,7 @@ __metadata:
languageName: node
linkType: hard
"bcrypt-pbkdf@npm:^1.0.0":
"bcrypt-pbkdf@npm:^1.0.0, bcrypt-pbkdf@npm:^1.0.2":
version: 1.0.2
resolution: "bcrypt-pbkdf@npm:1.0.2"
dependencies:
@ -8190,6 +8254,13 @@ __metadata:
languageName: node
linkType: hard
"core-js-pure@npm:^3.0.0":
version: 3.6.5
resolution: "core-js-pure@npm:3.6.5"
checksum: 91fc8e0b699d5bcb11f265ad4544d08c98096b86ad6c9b4c00109616db0aa992ceb58ea82d0dbae2a16658a7aaf2922aa6f9fc1107dc3b0055270799d0414a3f
languageName: node
linkType: hard
"core-js@npm:^2.4.0, core-js@npm:^2.6.5":
version: 2.6.11
resolution: "core-js@npm:2.6.11"
@ -9395,6 +9466,35 @@ __metadata:
languageName: node
linkType: hard
"docker-compose@npm:^0.23.5":
version: 0.23.5
resolution: "docker-compose@npm:0.23.5"
checksum: 77085cabb40fa111cb96c1a2ce3e2ed8f3487525916d928c0ab863fb3720f636c3e0abca83b67ce4c8292b124ff7c952de1303f2aa9cc0764e0533b3c6660ed5
languageName: node
linkType: hard
"docker-modem@npm:^2.1.0":
version: 2.1.4
resolution: "docker-modem@npm:2.1.4"
dependencies:
debug: ^4.1.1
readable-stream: ^3.5.0
split-ca: ^1.0.1
ssh2: ^0.8.7
checksum: 6a6a4be66ff68dff4182ba0b3b444c03786850268e6e2b3f764a3c78b9962545939cf37cfe533178d8c89156494b32ce048be911d532f4fdd4ecbec61b523ea7
languageName: node
linkType: hard
"dockerode@npm:^3.2.0":
version: 3.2.1
resolution: "dockerode@npm:3.2.1"
dependencies:
docker-modem: ^2.1.0
tar-fs: ~2.0.1
checksum: 9b539b40002d0a32560a30378d03bb78b37429437078b1db67edf3d2258e5f3bd61cd5511b3aea1bbda0c37458b509b6db81226de81f900087fd8f1342ed57b8
languageName: node
linkType: hard
"docsearch.js@npm:^2.5.2":
version: 2.6.3
resolution: "docsearch.js@npm:2.6.3"
@ -9438,6 +9538,13 @@ __metadata:
languageName: node
linkType: hard
"dom-accessibility-api@npm:^0.5.0":
version: 0.5.0
resolution: "dom-accessibility-api@npm:0.5.0"
checksum: 7dd37012f2d841e4d8898aea47ee5b36ad0d4d49182d2ddd293ae70b58b1c1b88bfab433a06e888e11ecb0200d9cd9ffedbad5ff84916e71a36ea35cffe17073
languageName: node
linkType: hard
"dom-converter@npm:^0.2":
version: 0.2.0
resolution: "dom-converter@npm:0.2.0"
@ -11577,6 +11684,13 @@ __metadata:
languageName: node
linkType: hard
"get-port@npm:^5.1.1":
version: 5.1.1
resolution: "get-port@npm:5.1.1"
checksum: 75a5af5cef1e601cfa5a071d1b205ba94338f69f83f1092039bdf8e15351a76f5e6b7df7d3987bd3b7ad5d6893759d2bc28d36d8a4ee65976c3868d7efe7cf8c
languageName: node
linkType: hard
"get-stdin@npm:^4.0.1":
version: 4.0.1
resolution: "get-stdin@npm:4.0.1"
@ -16829,6 +16943,13 @@ __metadata:
languageName: node
linkType: hard
"node-duration@npm:^1.0.4":
version: 1.0.4
resolution: "node-duration@npm:1.0.4"
checksum: 28e395acc52d294b3970e06081047cfb7ca1226fe0ccbd8f9988e02fee0b8c057117775a318c781f9e2536ecfe1277dcb337722502f5c26d1b52b9af5e691403
languageName: node
linkType: hard
"node-fetch-npm@npm:^2.0.2":
version: 2.0.4
resolution: "node-fetch-npm@npm:2.0.4"
@ -19846,7 +19967,7 @@ __metadata:
languageName: node
linkType: hard
"readable-stream@npm:^3.0.2, readable-stream@npm:^3.0.6, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0":
"readable-stream@npm:^3.0.2, readable-stream@npm:^3.0.6, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0":
version: 3.6.0
resolution: "readable-stream@npm:3.6.0"
dependencies:
@ -21588,6 +21709,13 @@ __metadata:
languageName: node
linkType: hard
"split-ca@npm:^1.0.1":
version: 1.0.1
resolution: "split-ca@npm:1.0.1"
checksum: 66f620e52429cb1ba265d1c6da62b84cee724eba9b38ad1614ff72336ea69862dbc49b9f2e7689f4d1d55fdcce8d45b0d74fc78ca91297b5822b13bf01ea6497
languageName: node
linkType: hard
"split-on-first@npm:^1.0.0":
version: 1.1.0
resolution: "split-on-first@npm:1.1.0"
@ -21636,6 +21764,26 @@ __metadata:
languageName: node
linkType: hard
"ssh2-streams@npm:~0.4.10":
version: 0.4.10
resolution: "ssh2-streams@npm:0.4.10"
dependencies:
asn1: ~0.2.0
bcrypt-pbkdf: ^1.0.2
streamsearch: ~0.1.2
checksum: a49e4a8b8f94a7c02762a2c0653961c62b1d4968f5d9044900af57c9768fea832d348d96180ff11910eb38d62a48e7f100de5eac9a72e3215cc51e99f3d278ee
languageName: node
linkType: hard
"ssh2@npm:^0.8.7":
version: 0.8.9
resolution: "ssh2@npm:0.8.9"
dependencies:
ssh2-streams: ~0.4.10
checksum: dcaf4440883b8cd18cd0b18046756f89d73eb8e4f1f93afcc41547111cbb5acbac5c6dff60df2eccb75f217e519ccddf9ac6286b0acac2b692778bab862dc07d
languageName: node
linkType: hard
"sshpk@npm:^1.7.0":
version: 1.16.1
resolution: "sshpk@npm:1.16.1"
@ -21799,6 +21947,22 @@ __metadata:
languageName: node
linkType: hard
"stream-to-array@npm:^2.3.0":
version: 2.3.0
resolution: "stream-to-array@npm:2.3.0"
dependencies:
any-promise: ^1.1.0
checksum: b313d7dfa5230674ffd3442ae985d64b9f95ad7d122aa7d3fd9ebe21bf7129548afda51dda2af781e2cd31c84911253bbf549061e96a63941a45686329ccba3f
languageName: node
linkType: hard
"streamsearch@npm:~0.1.2":
version: 0.1.2
resolution: "streamsearch@npm:0.1.2"
checksum: f72befba95082d49be19cd4318112bc141f6cd7cbb201ee8079887f6f3cbcdf79c311977ce0eaa93d7d8c3e6b9727412f6177a87ced5b98d0fd4075723ad8eaf
languageName: node
linkType: hard
"strict-uri-encode@npm:^1.0.0":
version: 1.1.0
resolution: "strict-uri-encode@npm:1.1.0"
@ -22409,7 +22573,7 @@ __metadata:
languageName: node
linkType: hard
"tar-fs@npm:^2.0.0":
"tar-fs@npm:^2.0.0, tar-fs@npm:^2.1.0":
version: 2.1.0
resolution: "tar-fs@npm:2.1.0"
dependencies:
@ -22421,6 +22585,18 @@ __metadata:
languageName: node
linkType: hard
"tar-fs@npm:~2.0.1":
version: 2.0.1
resolution: "tar-fs@npm:2.0.1"
dependencies:
chownr: ^1.1.1
mkdirp-classic: ^0.5.2
pump: ^3.0.0
tar-stream: ^2.0.0
checksum: 890f546bf67836f092fc15b48324b6f29692a12ed809f36aa4855c66f2ef101a5295e196b0c9f5cf8fde5c18f44a935e7766748c29b1d9699a9d8f779b06965b
languageName: node
linkType: hard
"tar-stream@npm:^2.0.0":
version: 2.1.3
resolution: "tar-stream@npm:2.1.3"
@ -22598,6 +22774,24 @@ __metadata:
languageName: node
linkType: hard
"testcontainers@npm:^2.17.0":
version: 2.20.0
resolution: "testcontainers@npm:2.20.0"
dependencies:
"@types/dockerode": ^2.5.34
byline: ^5.0.0
debug: ^4.1.1
docker-compose: ^0.23.5
dockerode: ^3.2.0
get-port: ^5.1.1
glob: ^7.1.6
node-duration: ^1.0.4
stream-to-array: ^2.3.0
tar-fs: ^2.1.0
checksum: 389b2e2f689872ec0b82061fbea1d3af98b95587bacf9b023748902bd7e02f66aa07d65d70a0234e92bc4b1655d5be157481468ce31e30d46deb0fc3d0256c11
languageName: node
linkType: hard
"text-extensions@npm:^1.0.0":
version: 1.9.0
resolution: "text-extensions@npm:1.9.0"