Browse Source

Integration tests (#311)

* Add base test env

* Add eslint rules for cypress

* Add configs and scripts in package json

* Added docker file for bridge and emualator

* Bridge install progress

* Bridge install next step

* Add task for integration tests

* Fixed deps

* Added baseUrl

* Added baseUrl fix

* Added npx

* Added caching for cypress bin

* Added path to binary

* Install cypress

* Finalized dockerfile

* Fixed bridge lib path

* Fixed path for binary

* Adjust script again

* Run all the things properly

* Try to run the tests

* First POC test

* First POC test in gitlab

* Fixed flow

* Fixed gitlab test url, try docker service

* export artifacts

* Test only integration tests in CI

* Test only integration tests in CI 2

* Test only integration tests in CI 3

* Added tests for initialize device

* Try to add docker in only one step

* Turn on other integration steps

* Correct node version

* Ignore cache in flow

* Run bridge and emulator in debug link mode

* Fix param

* Try to run new config in CI

* init device in docker

* Remove docker image after run

* Remove amp

* Fix path

* Artifacts on fail

* Artifacts on fail with volume

* Artifacts on fail with volume 2

* Install mkdir

* Install mkdir again

* test

* test 2

* test 3

* test 4

* test 5

* test 6

* test 7

* test 8

* test 9

* test 10

* test 11

* test 12

* test 13

* test 14

* test 15

* test 16

* test 17

* Revert "test 17"

This reverts commit f3f6c0d690.

* test 18

* test 19

* test 20

* test 21 try chrome

* test 22

* test 23

* test 24

* test 25

* test 25 try to install chrome again

* test 25 try to install chrome again

* Added missing deps

* Added debug

* Install chromium

* Install chromium 2

* turn on chromium

* turn off debug

* turn on debug

* fix folder

* turn off debug

* Fix init device

* Add header dashboard test

* Bring things back

* clean

* clean fix

* Build image in CI

* Added stage step

* Added docker image

* Added service

* Added tests to docker image

* Refactor a bit

* Correct registry image

* Build wallet again

* Add test for dashbaord content

* new node version, more tests

* Remove unused code

* typo

* Correct snapshots, moved deps to dev, beta disclaimer prop
pull/353/head
Vladimir Volek 4 years ago committed by Maroš
parent
commit
46fe6d00fc
  1. 11
      .eslintrc
  2. 1
      .flowconfig
  3. 4
      .gitignore
  4. 48
      .gitlab-ci.yml
  5. 53
      Dockerfile
  6. 11
      cypress.json
  7. 10
      package.json
  8. 4
      src/components/Button/index.js
  9. 3
      src/components/DeviceHeader/index.js
  10. 2
      src/components/Header/index.js
  11. 2
      src/views/Landing/components/BetaDisclaimer/index.js
  12. 3
      src/views/Wallet/components/LeftNavigation/components/CoinMenu/index.js
  13. 4
      src/views/Wallet/components/LeftNavigation/components/Divider/index.js
  14. 3
      src/views/Wallet/components/LeftNavigation/index.js
  15. 6
      src/views/Wallet/index.js
  16. 2
      src/views/Wallet/views/Dashboard/index.js
  17. 2
      src/views/Wallet/views/Initialize/index.js
  18. 26
      test/integration/dashboard.spec.js
  19. 7
      test/plugins/index.js
  20. 6
      test/scripts/init-device.js
  21. 20
      test/scripts/run-all.sh
  22. BIN
      test/snapshots/All Specs/Dashboard page -- content.snap.png
  23. BIN
      test/snapshots/All Specs/Dashboard page -- device header.snap.png
  24. BIN
      test/snapshots/All Specs/Dashboard page -- navigation.snap.png
  25. 5
      test/support/commands.js
  26. 5
      test/support/index.js
  27. 872
      yarn.lock

11
.eslintrc

@ -10,7 +10,8 @@
},
"env": {
"browser": true,
"jest": true
"jest": true,
"cypress/globals": true
},
"rules": {
"import/prefer-default-export": 0,
@ -32,13 +33,17 @@
"new-cap": 0,
"max-len": 0,
"eol-last": 0,
"spaced-comment": 0
"spaced-comment": 0,
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": 2
},
"plugins": [
"import",
"react",
"jest",
"flowtype"
"flowtype",
"cypress",
"chai-friendly"
],
"settings": {
"import/resolver": {

1
.flowconfig

@ -10,6 +10,7 @@
.*/_old/.*
.*/scripts/solidity/.*
.*/build/.*
.*/cache/.*
[libs]
./src/flowtype/npm/redux_v3.x.x.js

4
.gitignore vendored

@ -19,4 +19,6 @@ logs
_old
coverage
coverage
test/**/__diff_output__
test/screenshots

48
.gitlab-ci.yml

@ -1,14 +1,19 @@
image: node:9.3
image: node:10.15.1
variables:
CYPRESS_CACHE_FOLDER: "$CI_PROJECT_DIR/cache/Cypress"
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- node_modules
- ${CYPRESS_CACHE_FOLDER}
stages:
- test
- build
- deploy
- integration tests
lint:
stage: test
@ -62,7 +67,23 @@ build stable:
expire_in: 1 week
paths:
- build/stable
- scripts/s3sync.sh
- scripts/s3sync.sh
build emulator and bridge image:
variables:
CONTAINER_NAME: "$CI_REGISTRY/emulator-bridge-tests"
image: docker:latest
services:
- docker:dind
before_script:
- docker login $CI_REGISTRY -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD
stage: build
when: manual
script:
- docker pull $CONTAINER_NAME:latest || true
- docker build --cache-from $CONTAINER_NAME:latest --tag $CONTAINER_NAME:$CI_COMMIT_SHA --tag $CONTAINER_NAME:latest .
- docker push $CONTAINER_NAME:$CI_COMMIT_SHA
- docker push $CONTAINER_NAME:latest
deploy review:
stage: deploy
@ -138,3 +159,24 @@ delete review:
- branches
tags:
- deploy
integration tests:
image: docker:latest
services:
- docker:dind
stage: integration tests
script:
- 'export SHARED_PATH="$(dirname ${CI_PROJECT_DIR})/shared"'
- rm -r ${SHARED_PATH} || true
- docker build -t wallet-emulator-bridge-tests .
- mkdir -p ${SHARED_PATH}/trezor-wallet/screenshots
- mkdir -p ${SHARED_PATH}/trezor-wallet/videos
- docker run --volume ${SHARED_PATH}/trezor-wallet/screenshots:/trezor-wallet/test/screenshots --volume ${SHARED_PATH}/trezor-wallet/videos:/trezor-wallet/test/videos --rm wallet-emulator-bridge-tests
- find ${SHARED_PATH}
- mkdir trezor-wallet
- cp -r ${SHARED_PATH}/ trezor-wallet/
artifacts:
when: always
expire_in: 1 week
paths:
- trezor-wallet/

53
Dockerfile

@ -1,17 +1,50 @@
FROM node:9.3
FROM python:latest
ARG BUILD_TYPE=stable
#
# setup
#
RUN apt-get update
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
RUN apt-get install -y chromium libappindicator3-1 xdg-utils fonts-liberation nodejs wget dpkg git python python3 python3-pip xvfb libgtk2.0-0 libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2
RUN npm install -g yarn
WORKDIR /trezor-wallet-app
RUN ln -s /usr/bin/chromium /usr/local/bin/chromium-browser
COPY package.json /trezor-wallet-app
COPY yarn.lock /trezor-wallet-app
#
# build emulator
#
RUN mkdir /trezor-emulator
WORKDIR /trezor-emulator
RUN yarn install
RUN git clone https://github.com/trezor/trezor-core
WORKDIR /trezor-emulator/trezor-core
RUN git submodule update --init --recursive
COPY . /trezor-wallet-app
RUN apt-get install libusb-1.0-0
RUN pip3 install scons trezor
RUN make build_unix_noui
RUN yarn run build:${BUILD_TYPE}
#
# install bridge
#
RUN mkdir /trezor-bridge
WORKDIR /trezor-bridge
RUN wget https://wallet.trezor.io/data/bridge/2.0.25/trezor-bridge_2.0.25_amd64.deb
RUN dpkg -x /trezor-bridge/trezor-bridge_2.0.25_amd64.deb /trezor-bridge/extracted
EXPOSE 8080
CMD [ "yarn", "run", "prod-server" ]
#
# install trezor-wallet
#
RUN mkdir /trezor-wallet
WORKDIR /trezor-wallet
COPY package.json /trezor-wallet
COPY yarn.lock /trezor-wallet
RUN yarn
COPY . /trezor-wallet
RUN yarn run build:stable
#
# run
#
ENTRYPOINT ["/trezor-wallet/test/scripts/run-all.sh"]
EXPOSE 8080 21325

11
cypress.json

@ -0,0 +1,11 @@
{
"integrationFolder": "test/integration",
"fixturesFolder": "test/fixtures",
"pluginsFile": "test/plugins/index.js",
"supportFile": "test/support/index.js",
"defaultCommandTimeout": 10000,
"screenshotsFolder": "test/screenshots",
"video": false,
"trashAssetsBeforeRuns": true,
"chromeWebSecurity": false
}

10
package.json

@ -21,10 +21,14 @@
"test": "run-s test:*",
"test:unit": "npx jest",
"test-unit:watch": "npx jest -o --watch",
"test-integration:dev": "npx cypress open -c baseUrl=http://localhost:8081/#/",
"test-integration:test": "npx cypress run",
"test-integration:gitlab": "npx cypress run -c baseUrl=https://localhost:8080/#/ --browser chromium",
"server:beta": "node ./server/index.js --buildType=beta",
"server:stable": "node ./server/index.js --buildType=stable"
},
"dependencies": {
"@babel/polyfill": "^7.2.5",
"babel": "^6.23.0",
"babel-core": "^6.26.3",
"bignumber.js": "2.4.0",
@ -69,9 +73,11 @@
"redux-logger": "^3.0.6",
"redux-raven-middleware": "^1.2.0",
"redux-thunk": "^2.2.0",
"request": "^2.88.0",
"rimraf": "^2.6.2",
"styled-components": "^4.1.2",
"styled-normalize": "^8.0.4",
"trezor-bridge-communicator": "1.0.2",
"trezor-connect": "7.0.0-beta.2",
"wallet-address-validator": "^0.2.4",
"web3": "1.0.0-beta.35",
@ -94,10 +100,14 @@
"babel-preset-env": "^1.6.0",
"babel-preset-jest": "^23.2.0",
"babel-preset-react": "^6.24.1",
"cypress": "^3.1.5",
"cypress-image-snapshot": "^3.0.0",
"eslint": "^4",
"eslint-config-airbnb": "^17.0.0",
"eslint-import-resolver-babel-module": "^4.0.0",
"eslint-loader": "^2.1.0",
"eslint-plugin-chai-friendly": "^0.4.1",
"eslint-plugin-cypress": "^2.2.0",
"eslint-plugin-flowtype": "^2.50.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jest": "^21.18.0",

4
src/components/Button/index.js

@ -17,6 +17,7 @@ type Props = {
isWhite?: boolean,
isWebUsb?: boolean,
isTransparent?: boolean,
dataTest?: string
}
const Wrapper = styled.button`
@ -146,10 +147,12 @@ const Button = ({
isWhite = false,
isWebUsb = false,
isTransparent = false,
dataTest,
}: Props) => {
const newClassName = isWebUsb ? `${className} trezor-webusb-button` : className;
return (
<Wrapper
data-test={dataTest}
className={newClassName}
onClick={onClick}
onMouseEnter={onMouseEnter}
@ -176,6 +179,7 @@ Button.propTypes = {
isWhite: PropTypes.bool,
isWebUsb: PropTypes.bool,
isTransparent: PropTypes.bool,
dataTest: PropTypes.string,
};
export default Button;

3
src/components/DeviceHeader/index.js

@ -98,11 +98,13 @@ const DeviceHeader = ({
disabled = false,
isSelected = false,
className,
testId,
}) => {
const status = getStatus(device);
return (
<Wrapper
isSelected={isSelected}
data-test={testId}
isOpen={isOpen}
isHoverable={isHoverable}
disabled={disabled}
@ -134,6 +136,7 @@ DeviceHeader.propTypes = {
isSelected: PropTypes.bool,
onClickWrapper: PropTypes.func.isRequired,
className: PropTypes.string,
testId: PropTypes.string,
};
export default DeviceHeader;

2
src/components/Header/index.js

@ -112,7 +112,7 @@ type Props = {
};
const Header = ({ sidebarEnabled, sidebarOpened, toggleSidebar }: Props) => (
<Wrapper>
<Wrapper data-test="Main__page__navigation">
<LayoutWrapper>
<Left>
{ sidebarEnabled && <MenuToggler onClick={toggleSidebar}>{sidebarOpened ? '✕ Close' : '☰ Menu'}</MenuToggler>}

2
src/views/Landing/components/BetaDisclaimer/index.js

@ -68,7 +68,7 @@ const BetaDisclaimer = (props: { close: () => void }) => (
/>
Please note that the <i>Trezor Beta Wallet</i> might be collecting anonymized usage data, especially error logs, for development purposes. The <i>Trezor Wallet</i> does not log any data.
</StyledP>
<StyledButton onClick={props.close}>OK, I understand</StyledButton>
<StyledButton dataTest="Modal__disclaimer__button__confirm" onClick={props.close}>OK, I understand</StyledButton>
</ModalWindow>
</Wrapper>
);

3
src/views/Wallet/components/LeftNavigation/components/CoinMenu/index.js

@ -57,7 +57,7 @@ class CoinMenu extends PureComponent<Props> {
render() {
const { config } = this.props.localStorage;
return (
<Wrapper>
<Wrapper data-test="Main__page__coin__menu">
{config.networks.map(item => (
<NavLink
key={item.shortcut}
@ -72,6 +72,7 @@ class CoinMenu extends PureComponent<Props> {
</NavLink>
))}
<Divider
testId="Main__page__coin__menu__divider"
textLeft="Other coins"
textRight="(You will be redirected)"
hasBorder

4
src/views/Wallet/components/LeftNavigation/components/Divider/index.js

@ -23,9 +23,10 @@ const TextLeft = styled.p`
`;
const Divider = ({
textLeft, textRight, hasBorder = false, className,
textLeft, textRight, hasBorder = false, className, testId,
}) => (
<Wrapper
data-test={testId}
hasBorder={hasBorder}
className={className}
>
@ -39,6 +40,7 @@ Divider.propTypes = {
textLeft: PropTypes.string,
textRight: PropTypes.string,
hasBorder: PropTypes.bool,
testId: PropTypes.string,
};
export default Divider;

3
src/views/Wallet/components/LeftNavigation/index.js

@ -207,6 +207,7 @@ class LeftNavigation extends React.PureComponent<Props, State> {
<Sidebar isOpen={props.wallet.showSidebar}>
<Header
isSelected
testId="Main__page__device__header"
isHoverable={false}
onClickWrapper={() => {
if (isDeviceAccessible || this.props.devices.length > 1) {
@ -237,7 +238,7 @@ class LeftNavigation extends React.PureComponent<Props, State> {
{dropdownOpened && <DeviceMenu ref={this.deviceMenuRef} {...this.props} />}
{isDeviceAccessible && menu}
</Body>
<Footer key="sticky-footer">
<Footer data-test="Main__page__footer" key="sticky-footer">
<Help>
<A
href="https://trezor.io/support/"

6
src/views/Wallet/index.js

@ -114,7 +114,11 @@ const StyledBackdrop = styled(Backdrop)`
const Wallet = (props: Props) => (
<AppWrapper>
<Header sidebarEnabled={!!props.wallet.selectedDevice} sidebarOpened={props.wallet.showSidebar} toggleSidebar={props.toggleSidebar} />
<Header
sidebarEnabled={!!props.wallet.selectedDevice}
sidebarOpened={props.wallet.showSidebar}
toggleSidebar={props.toggleSidebar}
/>
<AppNotifications />
<WalletWrapper>
<StyledBackdrop show={props.wallet.showSidebar} onClick={props.toggleSidebar} animated />

2
src/views/Wallet/views/Dashboard/index.js

@ -49,7 +49,7 @@ const Image = styled.img`
const Dashboard = () => (
<Content>
<Wrapper>
<Row>
<Row data-test="Dashboard__page__content">
<H1>Please select your coin</H1>
<StyledP>You will gain access to receiving &amp; sending selected coin</StyledP>
<Overlay>

2
src/views/Wallet/views/Initialize/index.js

@ -26,7 +26,7 @@ const StyledParagraph = styled(Paragraph)`
`;
const Initialize = () => (
<Wrapper>
<Wrapper data-test="Page__device__not__initialized">
<Row>
<H1>Your device is not initialized</H1>
<StyledParagraph>Please use Bitcoin wallet interface to start initialization process</StyledParagraph>

26
test/integration/dashboard.spec.js

@ -0,0 +1,26 @@
describe('Dashboard page', () => {
beforeEach(() => {
cy.viewport(1366, 1800);
cy.visit('/');
});
it('navigation', () => {
cy.getTestElement('Main__page__navigation')
.should('be.visible')
.matchImageSnapshot();
});
it('content', () => {
cy.getTestElement('Dashboard__page__content')
.should('be.visible')
.matchImageSnapshot();
});
// Menu
it('device header', () => {
cy.getTestElement('Main__page__device__header')
.should('be.visible')
.matchImageSnapshot();
});
});

7
test/plugins/index.js

@ -0,0 +1,7 @@
const {
addMatchImageSnapshotPlugin,
} = require('cypress-image-snapshot/plugin');
module.exports = (on) => {
addMatchImageSnapshotPlugin(on);
};

6
test/scripts/init-device.js

@ -0,0 +1,6 @@
import '@babel/polyfill';
import { initSeedAllDevice } from 'trezor-bridge-communicator';
(async () => {
await initSeedAllDevice();
})();

20
test/scripts/run-all.sh

@ -0,0 +1,20 @@
#!/bin/bash
# go to root
cd "$(dirname "$0")"
cd ..
# run bridge
cd /trezor-bridge && ./extracted/usr/bin/trezord -ed 21324:21325 -u=false &
# run emulator
cd /trezor-emulator/trezor-core && PYOPT=0 ./emu.sh &
# run wallet
cd /trezor-wallet && yarn run server:stable &
# init device
npx babel-node /trezor-wallet/test/scripts/init-device.js &
# run tests
yarn run test-integration:gitlab -c baseUrl="https://localhost:8080/#/"

BIN
test/snapshots/All Specs/Dashboard page -- content.snap.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
test/snapshots/All Specs/Dashboard page -- device header.snap.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
test/snapshots/All Specs/Dashboard page -- navigation.snap.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

5
test/support/commands.js

@ -0,0 +1,5 @@
import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command';
addMatchImageSnapshotCommand();
Cypress.Commands.add('getTestElement', selector => cy.get(`[data-test="${selector}"]`));

5
test/support/index.js

@ -0,0 +1,5 @@
import './commands';
beforeEach(() => {
window.localStorage.setItem('/betaModalPrivacy', true);
});

872
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save