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

ERC20 and Mother e2e tests #322

Merged
merged 13 commits into from
Jul 7, 2022
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
4 changes: 3 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
*.cjs
dist
node_modules
node_modules
cypress
*.config.ts
8 changes: 7 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup node.js
uses: actions/setup-node@v3
with:
node-version: 14

- name: Install and build
run: |
Expand All @@ -25,7 +29,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- run: |
curl -L "https://github.com/paritytech/substrate-contracts-node/releases/download/v0.15.1/substrate-contracts-node-linux.tar.gz" -O
curl -L "https://github.com/paritytech/substrate-contracts-node/releases/download/v0.16.0/substrate-contracts-node-linux.tar.gz" -O
ls -lash
- name: Save node artifact
uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -66,6 +70,7 @@ jobs:
browser: chrome
record: true
parallel: true
config-file: cypress.config.ts
group: 'UI - Chrome'
env:
CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }}
Expand Down Expand Up @@ -104,6 +109,7 @@ jobs:
browser: firefox
record: true
parallel: true
config-file: cypress.config.ts
group: 'UI - Firefox'
env:
CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }}
Expand Down
19 changes: 19 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2022 @paritytech/contracts-ui authors & contributors
// SPDX-License-Identifier: GPL-3.0-only

import { defineConfig } from 'cypress';

export default defineConfig({
projectId: 'eup7bh',

e2e: {
specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}',
},

component: {
devServer: {
framework: 'react',
bundler: 'vite',
},
},
});
3 changes: 0 additions & 3 deletions cypress.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
// Copyright 2021 @paritytech/contracts-ui authors & contributors
// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 @paritytech/contracts-ui authors & contributors
// SPDX-License-Identifier: GPL-3.0-only

describe('ERC20 Contract ', () => {
const initialSupply = 77;
const transferValue = 2;
const timeout = 25000;
const allowance = 25;

it('contract file uploads', () => {
cy.visit('http://localhost:8081/instantiate');
cy.get('[data-cy="file-input"]').attachFile('erc20.contract');
cy.get('[data-cy="next-btn"]').should('not.be.disabled');
});

it('moves to step 2', () => {
cy.get('[data-cy="next-btn"]').click();
cy.contains('Deployment Constructor').should('be.visible');
Expand All @@ -29,37 +30,44 @@ describe('ERC20 Contract ', () => {
});

it('submits instantiate transaction', () => {
cy.get('[data-cy="submit-btn"]').click();
cy.get('[data-cy="transaction-complete"]', { timeout })
.should('be.visible')
.and('contain', 'contracts:Instantiated')
.and('contain', 'system:NewAccount')
.and('contain', 'balances:Endowed')
.and('contain', 'balances:Transfer')
.and('contain', 'balances:Reserved')
.and('contain', 'balances:Withdraw')
.and('contain', 'system:ExtrinsicSuccess');

cy.get('[data-cy="dismiss-notification"]').click();
cy.instantiate();
});

it('redirects to contract page after instantiation', () => {
cy.url().should('contain', '/contract/');
});

it(`calling totalSupply() returns ${initialSupply}`, () => {
cy.contains('Read').click();
cy.get('[data-cy="totalSupply"]').find('.return-value').should('contain', `${initialSupply}`);
cy.assertReturnValue('totalSupply', `${initialSupply}`);
});

it(`transfers ${transferValue} Units to another account`, () => {
cy.get('.constructorDropdown').click().find('.dropdown__option').eq(3).click();
cy.get('.constructorDropdown').find('.dropdown__single-value').should('contain', 'transfer');
cy.selectMessage('transfer', 3);
cy.get('.form-field.to').find('.dropdown').click().find('.dropdown__option').eq(3).click();
cy.get('.form-field.value').find('input[type="text"]').eq(0).type(`${transferValue}`);
cy.contains('Call').click();
cy.get('[data-cy="transaction-complete"]', { timeout })
.should('be.visible')
.and('contain', 'system:ExtrinsicSuccess')
.and('contain', 'balances:Transfer')
.and('contain', 'balances:Reserved')
.and('contain', 'balances:Withdraw');
cy.call();
cy.selectMessage('balanceOf', 1);
cy.assertReturnValue('balanceOf', `${initialSupply - transferValue}`);
});

it(`successfully approves allowance`, () => {
cy.selectMessage('approve', 4);
cy.get('.form-field.spender').find('.dropdown').click().find('.dropdown__option').eq(2).click();
cy.get('.form-field.value').find('input[type="text"]').type(`${allowance}`);
cy.call();
cy.selectMessage('allowance', 2);
cy.get('.form-field.spender').find('.dropdown').click().find('.dropdown__option').eq(2).click();
cy.assertReturnValue('allowance', `${allowance}`);
});

it(`transfers ${transferValue} on behalf of alice`, () => {
cy.get('.form-field.caller').click().find('.dropdown__option').eq(2).click();
cy.selectMessage('transferFrom', 5);
cy.get('.form-field.to').find('.dropdown').click().find('.dropdown__option').eq(2).click();
cy.get('.form-field.value').find('input[type="text"]').type(`${transferValue}`);
cy.call();
cy.selectMessage('balanceOf', 1);
cy.get('.form-field.owner').find('.dropdown').click().find('.dropdown__option').eq(2).click();
cy.assertReturnValue('balanceOf', `${transferValue}`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,41 +26,25 @@ describe('Flipper Contract ', () => {
});

it(`submits instantiate transaction`, () => {
cy.get('[data-cy="submit-btn"]').click();
cy.get('[data-cy="transaction-complete"]', { timeout })
.should('be.visible')
.and('contain', 'contracts:Instantiated')
.and('contain', 'system:NewAccount')
.and('contain', 'balances:Endowed')
.and('contain', 'balances:Transfer')
.and('contain', 'balances:Reserved')
.and('contain', 'balances:Withdraw')
.and('contain', 'system:ExtrinsicSuccess');

cy.get('[data-cy="dismiss-notification"]').click();
cy.instantiate();
});
it('redirects to contract page after instantiation', () => {
cy.url().should('contain', '/contract/');
});
it('calling get() returns true', () => {
cy.get('.constructorDropdown').click().find('.dropdown__option').eq(1).click();
cy.get('.constructorDropdown').find('.dropdown__single-value').should('contain', 'get');
cy.contains('Read').click();
cy.get('[data-cy="get"]').find('.return-value').should('contain', 'true');
cy.selectMessage('get', 1);
cy.assertReturnValue('get', 'true');
});
it(`submits flip() transaction`, () => {
cy.get('.constructorDropdown').click().find('.dropdown__option').eq(0).click();
cy.get('.constructorDropdown').find('.dropdown__single-value').should('contain', 'flip');
cy.selectMessage('flip', 0);
cy.contains('Call').click();
cy.get('[data-cy="transaction-complete"]', { timeout })
.should('be.visible')
.and('contain', 'system:ExtrinsicSuccess')
.and('contain', 'balances:Withdraw');
});
it('calling get() returns false', () => {
cy.get('.constructorDropdown').click().find('.dropdown__option').eq(1).click();
cy.get('.constructorDropdown').find('.dropdown__single-value').should('contain', 'get');
cy.contains('Read').click();
cy.get('[data-cy="get"]').find('.return-value').should('contain', 'false');
cy.selectMessage('get', 1);
cy.assertReturnValue('get', 'false');
});
});
132 changes: 132 additions & 0 deletions cypress/e2e/contracts/mother.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright 2022 @paritytech/contracts-ui authors & contributors
// SPDX-License-Identifier: GPL-3.0-only

describe('Mother Contract ', () => {
it('contract file uploads', () => {
cy.visit('http://localhost:8081/instantiate');
cy.get('[data-cy="file-input"]').attachFile('mother.contract');
cy.get('[data-cy="upload-confirmation"]').should('contain', 'mother.contract');
cy.get('.validation.success').should('be.visible').and('contain', 'Valid contract bundle');
});

it('moves to step 2', () => {
cy.get('[data-cy="next-btn"]').should('not.be.disabled');
cy.get('[data-cy="next-btn"]').click();
cy.contains('Deployment Constructor').should('be.visible');
cy.contains('Deployment Salt').scrollIntoView().should('be.visible');
cy.contains('Max Gas Allowed').should('be.visible');
cy.contains('Storage Deposit Limit').should('be.visible');
});

it('displays `name: Text` input correctly', () => {
cy.get('.form-field.name')
.scrollIntoView()
.within(() => {
cy.contains('name: Text').should('be.visible');
cy.get("input[type='text']").should('be.visible').and('be.empty');
});
});

it('displays `subject: Hash` input correctly', () => {
cy.get('.form-field.subject').within(() => {
cy.contains('subject: Hash').should('be.visible');
cy.get("input[type='text']").should('be.visible');
});
});

it('displays `bids: Auction` input correctly ', () => {
cy.get('.form-field.bids').within(() => {
cy.contains('Vec<Vec<Option<(AccountId,u128)>>>').should('be.visible');
cy.contains('Vec<Option<(AccountId,u128)>>').should('be.visible');
cy.get('.vector-field-1').should('have.lengthOf', 1);
cy.get('.vector-field-2')
.should('have.lengthOf', 1)
.find("input[type='text']")
.should('have.attr', 'placeholder', 'Do not supply');
cy.get('.vector-field-3').should('not.exist');
});
});

it('adds inputs on a parent Vector component', () => {
cy.get('.form-field.bids').within(() => {
cy.get('[data-cy="vector-add-1"]').click().click();
cy.get('.vector-field-1').should('have.lengthOf', 3);
});
});

it('adds inputs on a nested Vector component', () => {
cy.get('.form-field.bids .vector-field-1')
.first()
.within(() => {
cy.get('[data-cy="vector-add-2"]').click().click();
cy.get('.vector-field-2').should('have.lengthOf', 3);
});
});
it('displays inputs for `Option<(AccountId,u128)` and sets values', () => {
cy.get('.form-field.bids .vector-field-2')
.first()
.each($el => {
cy.wrap($el)
.scrollIntoView()
.within(() => {
cy.get('[data-cy="switch-button"]').click();
cy.contains('0: AccountId').should('be.visible');
cy.get('.dropdown').should('have.lengthOf', 1);
cy.contains('1: u128').should('be.visible');
cy.get("input[type='number']").should('have.lengthOf', 1).type('99999');
cy.selectAccount('bob', 2);
});
});
});
it('removes inputs on a parent Vector component', () => {
cy.get('.form-field.bids').within(() => {
cy.get('[data-cy="vector-remove-1"]').click().click();
cy.get('.vector-field-1').should('have.lengthOf', 1);
});
});

it('displays 3 number inputs for `terms: [u32;3]` and sets their value', () => {
cy.get('.form-field.terms')
.scrollIntoView()
.within(() => {
cy.contains('terms: [BlockNumber;3]').should('be.visible');
cy.get("input[type='number']").should('have.lengthOf', 3).and('be.visible');
cy.get("input[type='number']").each($el => {
cy.wrap($el).type('123');
});
});
});

it('displays nested enum variants for status: Status', () => {
cy.get('.form-field.status')
.scrollIntoView()
.within(() => {
cy.contains('status: Status').should('be.visible');
cy.get('.dropdown').should('have.lengthOf', 1).and('be.visible');
cy.get('.dropdown').click().find('.dropdown__option').eq(2).click();
cy.get('.dropdown').find('.dropdown__single-value').should('contain', 'EndingPeriod');
cy.contains('BlockNumber').should('exist');
cy.get("input[type='number']").should('have.lengthOf', 1).type('99999');
cy.get('.dropdown').click().find('.dropdown__option').eq(3).click();
cy.get('.dropdown').should('have.lengthOf', 2);

cy.get('.dropdown').first().find('.dropdown__single-value').should('contain', 'Ended');
cy.contains('Outline').should('exist');
cy.get('.dropdown').eq(1).find('.dropdown__single-value').should('contain', 'NoWinner');
});
});

it.skip('moves to step 3', () => {
cy.get('[data-cy="next-btn"]').click();
cy.get('[data-cy="transaction-queued"]').should('be.visible');
});
// todo: find out why gas estimation is too low when the app runs in cypress env
// and why setting custom gas doesn't work
it.skip('submits instantiate transaction', () => {
cy.instantiate();
});

it.skip('redirects to contract page after instantiation', () => {
cy.url().should('contain', '/contract/');
});
});
2 changes: 1 addition & 1 deletion cypress/fixtures/erc20.contract

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion cypress/fixtures/flipper.contract

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions cypress/fixtures/mother.contract

Large diffs are not rendered by default.

5 changes: 0 additions & 5 deletions cypress/support/commands.js

This file was deleted.

14 changes: 14 additions & 0 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/// <reference types="cypress" />
import 'cypress-file-upload';

declare global {
namespace Cypress {
interface Chainable {
instantiate(): Chainable<Element>;
call(): Chainable<Element>;
selectMessage(name: string, index: number): Chainable<Element>;
selectAccount(name: string, index: number): Chainable<Element>;
assertReturnValue(messageName: string, value: string): Chainable<Element>;
}
}
}
12 changes: 12 additions & 0 deletions cypress/support/component-index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Components App</title>
</head>
<body>
<div data-cy-root></div>
</body>
</html>
12 changes: 12 additions & 0 deletions cypress/support/component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import './commands';

import { mount } from 'cypress/react';
declare global {
namespace Cypress {
interface Chainable {
mount: typeof mount;
}
}
}

Cypress.Commands.add('mount', mount);
Loading