Skip to content

Commit

Permalink
A proof of concept for frontend test with substrate in docker (polkad…
Browse files Browse the repository at this point in the history
…ot-js#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 <[email protected]>
  • Loading branch information
krzysztof-jelski and jacogr authored Aug 19, 2020
1 parent f79e6ea commit 8b50b1b
Show file tree
Hide file tree
Showing 12 changed files with 401 additions and 8 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/test-nightly.yml
Original file line number Diff line number Diff line change
@@ -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 changes: 6 additions & 0 deletions __mocks__/fileMock.js
Original file line number Diff line number Diff line change
@@ -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 = '';
21 changes: 19 additions & 2 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 28 additions & 0 deletions jest/globalSetup.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions jest/globalTeardown.ts
Original file line number Diff line number Diff line change
@@ -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.');
};
10 changes: 10 additions & 0 deletions jest/substrateTestsGlobal.ts
Original file line number Diff line number Diff line change
@@ -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.
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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'"
Expand Down
4 changes: 4 additions & 0 deletions packages/page-accounts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
63 changes: 63 additions & 0 deletions packages/page-accounts/src/CreateAccount.spec.tsx
Original file line number Diff line number Diff line change
@@ -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();
});
});
35 changes: 35 additions & 0 deletions packages/page-accounts/src/test-support/MemoryStore.ts
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
1 change: 1 addition & 0 deletions packages/react-components/src/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ function Input ({ autoFocus = false, children, className, defaultValue, help, ic
: 'off'
}
autoCorrect='off'
data-testid={label}
onPaste={_onPaste}
spellCheck={false}
/>
Expand Down
Loading

0 comments on commit 8b50b1b

Please sign in to comment.