From 63b075636fdc9ec613717343982f7a097ca62343 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 31 Jul 2020 17:22:00 +0100 Subject: [PATCH] Added libraryDeployment tests --- .../src/commands/createContract.ts | 32 +++++ .../src/commands/getAddressAtPosition.ts | 29 ++++ .../src/commands/getEditorValue.ts | 21 +++ .../src/commands/getModalBody.ts | 4 +- .../src/commands/selectContract.ts | 23 ++++ .../src/commands/testConstantFunction.ts | 37 ++++++ .../src/commands/verifyContracts.ts | 2 +- apps/remix-ide-e2e/src/tests/editor.test.ts | 5 +- .../src/tests/fileExplorer.test.ts | 6 +- .../src/tests/fileManager_api.test.ts | 5 +- .../src/tests/generalSettings.test.ts | 5 +- apps/remix-ide-e2e/src/tests/gist.test.ts | 4 +- .../src/tests/libraryDeployment.test.ts | 124 ++++++++++++++++++ apps/remix-ide-e2e/src/types/index.d.ts | 14 +- 14 files changed, 292 insertions(+), 19 deletions(-) create mode 100644 apps/remix-ide-e2e/src/commands/createContract.ts create mode 100644 apps/remix-ide-e2e/src/commands/getAddressAtPosition.ts create mode 100644 apps/remix-ide-e2e/src/commands/getEditorValue.ts create mode 100644 apps/remix-ide-e2e/src/commands/selectContract.ts create mode 100644 apps/remix-ide-e2e/src/commands/testConstantFunction.ts create mode 100644 apps/remix-ide-e2e/src/tests/libraryDeployment.test.ts diff --git a/apps/remix-ide-e2e/src/commands/createContract.ts b/apps/remix-ide-e2e/src/commands/createContract.ts new file mode 100644 index 0000000000..2503a839c9 --- /dev/null +++ b/apps/remix-ide-e2e/src/commands/createContract.ts @@ -0,0 +1,32 @@ +import { NightwatchBrowser } from "nightwatch" +import EventEmitter from "events" + +class CreateContract extends EventEmitter { + command (this: NightwatchBrowser, inputParams: string): NightwatchBrowser { + this.api.perform((done) => { + createContract(this.api, inputParams, () => { + done() + this.emit('complete') + }) + }) + return this + } +} + +function createContract (browser: NightwatchBrowser, inputParams: string, callback: VoidFunction) { + if (inputParams) { + browser.clickLaunchIcon('settings').clickLaunchIcon('udapp') + .setValue('div[class^="contractActionsContainerSingle"] input', inputParams, function () { + browser.click('#runTabView button[class^="instanceButton"]').pause(500).perform(function () { callback() }) + }) + } else { + browser + .clickLaunchIcon('settings') + .clickLaunchIcon('udapp') + .click('#runTabView button[class^="instanceButton"]') + .pause(500) + .perform(function () { callback() }) + } +} + +module.exports = CreateContract diff --git a/apps/remix-ide-e2e/src/commands/getAddressAtPosition.ts b/apps/remix-ide-e2e/src/commands/getAddressAtPosition.ts new file mode 100644 index 0000000000..f2f531d7c6 --- /dev/null +++ b/apps/remix-ide-e2e/src/commands/getAddressAtPosition.ts @@ -0,0 +1,29 @@ +import { NightwatchBrowser } from "nightwatch" +import EventEmitter from "events" + +class GetAddressAtPosition extends EventEmitter { + command (this: NightwatchBrowser, index: number, cb: (pos: string) => void): NightwatchBrowser { + this.api.perform((done) => { + getAddressAtPosition(this.api, index, (pos) => { + done() + cb(pos) + this.emit('complete') + }) + }) + return this + } +} + +function getAddressAtPosition (browser: NightwatchBrowser, index: number, callback: (pos: string) => void) { + browser.waitForElementPresent('*[data-shared="universalDappUiInstance"]') + .execute(function (index) { + const deployedContracts = document.querySelectorAll('*[data-shared="universalDappUiInstance"]') + const id = deployedContracts[index].getAttribute('id') + + return id.replace('instance', '') + }, [index], function (result) { + typeof result.value === 'string' && callback(result.value) + }) +} + +module.exports = GetAddressAtPosition diff --git a/apps/remix-ide-e2e/src/commands/getEditorValue.ts b/apps/remix-ide-e2e/src/commands/getEditorValue.ts new file mode 100644 index 0000000000..bb15efc9a3 --- /dev/null +++ b/apps/remix-ide-e2e/src/commands/getEditorValue.ts @@ -0,0 +1,21 @@ +import { NightwatchBrowser } from "nightwatch" +import EventEmitter from "events" + +class GetEditorValue extends EventEmitter { + command (this: NightwatchBrowser, callback: (content: string) => void): NightwatchBrowser { + this.api.perform((client, done) => { + this.api.execute(function () { + const elem: any = document.getElementById('input') + + elem.editor.getValue() + }, [], (result) => { + done() + callback(typeof result.value === 'string' ? result.value : '') + this.emit('complete') + }) + }) + return this + } +} + +module.exports = GetEditorValue diff --git a/apps/remix-ide-e2e/src/commands/getModalBody.ts b/apps/remix-ide-e2e/src/commands/getModalBody.ts index 6f9b78a18f..b185348dc6 100644 --- a/apps/remix-ide-e2e/src/commands/getModalBody.ts +++ b/apps/remix-ide-e2e/src/commands/getModalBody.ts @@ -2,11 +2,11 @@ import { NightwatchBrowser } from "nightwatch" import EventEmitter from "events" class GetModalBody extends EventEmitter { - command (this: NightwatchBrowser, callback: CallableFunction) { + command (this: NightwatchBrowser, callback: (value: string, cb: VoidFunction) => void) { this.api.waitForElementVisible('.modal-body') .getText('.modal-body', (result) => { console.log(result) - callback(result.value, () => { + typeof result.value === 'string' && callback(result.value, () => { this.emit('complete') }) }) diff --git a/apps/remix-ide-e2e/src/commands/selectContract.ts b/apps/remix-ide-e2e/src/commands/selectContract.ts new file mode 100644 index 0000000000..b228ef85f6 --- /dev/null +++ b/apps/remix-ide-e2e/src/commands/selectContract.ts @@ -0,0 +1,23 @@ +import { NightwatchBrowser } from 'nightwatch' +import EventEmitter from "events" + +class SelectContract extends EventEmitter { + command (this: NightwatchBrowser, contractName: string): NightwatchBrowser { + this.api.perform((done) => { + selectContract(this.api, contractName, () => { + done() + this.emit('complete') + }) + }) + return this + } +} + +function selectContract (browser: NightwatchBrowser, contractName: string, callback: VoidFunction) { + browser.clickLaunchIcon('settings').clickLaunchIcon('udapp') + .setValue('#runTabView select[class^="contractNames"]', contractName).perform(() => { + callback() + }) +} + +module.exports = SelectContract diff --git a/apps/remix-ide-e2e/src/commands/testConstantFunction.ts b/apps/remix-ide-e2e/src/commands/testConstantFunction.ts new file mode 100644 index 0000000000..1446796a2f --- /dev/null +++ b/apps/remix-ide-e2e/src/commands/testConstantFunction.ts @@ -0,0 +1,37 @@ +import { NightwatchBrowser, NightwatchTestConstantFunctionExpectedInput } from "nightwatch" +import EventEmitter from "events" + +class TestConstantFunction extends EventEmitter { + command (this: NightwatchBrowser, address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput | null, expectedOutput: string): NightwatchBrowser { + console.log('TestConstantFunction ' + address + ' fnFullName') + this.api.perform((done) => { + testConstantFunction(this.api, address, fnFullName, expectedInput, expectedOutput, () => { + done() + this.emit('complete') + }) + }) + return this + } +} + +function testConstantFunction (browser: NightwatchBrowser, address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput, expectedOutput: string, cb: VoidFunction) { + browser.waitForElementPresent('.instance button[title="' + fnFullName + '"]').perform(function (client, done) { + client.execute(function () { + document.querySelector('#runTabView').scrollTop = document.querySelector('#runTabView').scrollHeight + }, [], function () { + if (expectedInput) { + client.setValue('#runTabView input[title="' + expectedInput.types + '"]', expectedInput.values) + } + done() + }) + }) + .click('.instance button[title="' + fnFullName + '"]') + .pause(1000) + .waitForElementPresent('#instance' + address + ' div[class^="contractActionsContainer"] div[class^="value"]') + .scrollInto('#instance' + address + ' div[class^="contractActionsContainer"] div[class^="value"]') + .assert.containsText('#instance' + address + ' div[class^="contractActionsContainer"] div[class^="value"]', expectedOutput).perform(() => { + cb() + }) +} + +module.exports = TestConstantFunction diff --git a/apps/remix-ide-e2e/src/commands/verifyContracts.ts b/apps/remix-ide-e2e/src/commands/verifyContracts.ts index 8cab02424f..6f938e5b37 100644 --- a/apps/remix-ide-e2e/src/commands/verifyContracts.ts +++ b/apps/remix-ide-e2e/src/commands/verifyContracts.ts @@ -13,7 +13,7 @@ class VerifyContracts extends EventEmitter { } } -function getCompiledContracts (browser: NightwatchBrowser, opts: NightwatchVerifyContractOpts, callback: CallableFunction) { +function getCompiledContracts (browser: NightwatchBrowser, opts: NightwatchVerifyContractOpts, callback: (result: NightwatchCallbackResult) => void) { browser .clickLaunchIcon('solidity') .pause(opts.wait) diff --git a/apps/remix-ide-e2e/src/tests/editor.test.ts b/apps/remix-ide-e2e/src/tests/editor.test.ts index 1154e53997..90cb39e939 100644 --- a/apps/remix-ide-e2e/src/tests/editor.test.ts +++ b/apps/remix-ide-e2e/src/tests/editor.test.ts @@ -1,9 +1,8 @@ 'use strict' import { NightwatchBrowser } from "nightwatch" - -const init = require('../helpers/init') -const sauce = require('./sauce') +import init from '../helpers/init' +import sauce from './sauce' module.exports = { diff --git a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts index 37db537c19..efe81e206c 100644 --- a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts +++ b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts @@ -1,9 +1,9 @@ 'use strict' import { NightwatchBrowser } from "nightwatch" +import init from '../helpers/init' +import sauce from './sauce' +import * as path from 'path' -const init = require('../helpers/init') -const sauce = require('./sauce') -const path = require('path') const testData = { testFile1: path.resolve(__dirname + '/editor.test.js'), // eslint-disable-line testFile2: path.resolve(__dirname + '/fileExplorer.test.js'), // eslint-disable-line diff --git a/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts b/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts index a53cf12edf..f9416e4cff 100644 --- a/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts +++ b/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts @@ -1,8 +1,7 @@ 'use strict' import { NightwatchBrowser } from "nightwatch" - -const init = require('../helpers/init') -const sauce = require('./sauce') +import init from '../helpers/init' +import sauce from './sauce' module.exports = { before: function (browser: NightwatchBrowser, done: VoidFunction) { diff --git a/apps/remix-ide-e2e/src/tests/generalSettings.test.ts b/apps/remix-ide-e2e/src/tests/generalSettings.test.ts index b6900fdecb..2c139c66c9 100644 --- a/apps/remix-ide-e2e/src/tests/generalSettings.test.ts +++ b/apps/remix-ide-e2e/src/tests/generalSettings.test.ts @@ -1,8 +1,7 @@ 'use strict' import { NightwatchBrowser } from "nightwatch" - -const init = require('../helpers/init') -const sauce = require('./sauce') +import init from '../helpers/init' +import sauce from './sauce' module.exports = { before: function (browser: NightwatchBrowser, done: VoidFunction) { diff --git a/apps/remix-ide-e2e/src/tests/gist.test.ts b/apps/remix-ide-e2e/src/tests/gist.test.ts index 276ec009a8..94aa5457a8 100644 --- a/apps/remix-ide-e2e/src/tests/gist.test.ts +++ b/apps/remix-ide-e2e/src/tests/gist.test.ts @@ -1,8 +1,8 @@ 'use strict' import { NightwatchBrowser } from "nightwatch" +import init from '../helpers/init' +import sauce from './sauce' -const init = require('../helpers/init') -const sauce = require('./sauce') const testData = { validGistId: '1859c97c6e1efc91047d725d5225888e', invalidGistId: '6368b389f9302v32902msk2402' diff --git a/apps/remix-ide-e2e/src/tests/libraryDeployment.test.ts b/apps/remix-ide-e2e/src/tests/libraryDeployment.test.ts new file mode 100644 index 0000000000..cb9da5b6b3 --- /dev/null +++ b/apps/remix-ide-e2e/src/tests/libraryDeployment.test.ts @@ -0,0 +1,124 @@ +'use strict' +import { NightwatchBrowser } from "nightwatch" +import init from '../helpers/init' +import sauce from './sauce' + +module.exports = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + init(browser, done) + }, + + '@sources': function () { + return sources + }, + + 'Add Lib Test File': function (browser: NightwatchBrowser) { + browser.addFile('Untitled5.sol', sources[0]['browser/Untitled5.sol']) + .clickLaunchIcon('udapp') + .selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite + }, + + 'Test Auto Deploy Lib': function (browser: NightwatchBrowser) { + let addressRef: string + browser.verifyContracts(['test']) + .selectContract('test') + .createContract('') + .getAddressAtPosition(0, (address) => { + console.log('testAutoDeployLib ' + address) + addressRef = address + }) + .waitForElementPresent('.instance:nth-of-type(2)') + .click('.instance:nth-of-type(2) > div > button') + .perform((done) => { + browser.testConstantFunction(addressRef, 'get - call', null, '0:\nuint256: 45').perform(() => { + done() + }) + }) + }, + + 'Test Manual Deploy Lib': function (browser: NightwatchBrowser) { + console.log('testManualDeployLib') + browser.click('*[data-id="deployAndRunClearInstances"]') + .pause(5000) + .clickLaunchIcon('settings') + .click('#generatecontractmetadata') + .clickLaunchIcon('solidity') + .click('#compileTabView button[title="Compile"]') // that should generate the JSON artefact + .verifyContracts(['test']) + .selectContract('lib') // deploy lib + .createContract('') + .perform((done) => { + browser.getAddressAtPosition(0, (address) => { + console.log(address) + checkDeployShouldFail(browser, () => { + checkDeployShouldSucceed(browser, address, () => { + done() + }) + }) + }) + }) + .end() + }, + + tearDown: sauce +} + +function checkDeployShouldFail (browser: NightwatchBrowser, callback: VoidFunction) { + let config + browser.openFile('browser/artifacts').openFile('browser/artifacts/test.json') + .getEditorValue((content) => { + config = JSON.parse(content) + config.deploy['VM:-'].autoDeployLib = false + }) + .perform(() => { + browser.setEditorValue(JSON.stringify(config)) + }) + .openFile('browser/Untitled5.sol') + .selectContract('test') // deploy lib + .createContract('') + .assert.containsText('div[class^="terminal"]', '
is not a valid address') + .perform(() => { callback() }) +} + +function checkDeployShouldSucceed (browser: NightwatchBrowser, address: string, callback: VoidFunction) { + let addressRef: string + let config + browser.openFile('browser/artifacts').openFile('browser/artifacts/test.json') + .getEditorValue((content) => { + config = JSON.parse(content) + config.deploy['VM:-'].autoDeployLib = false + config.deploy['VM:-']['linkReferences']['browser/Untitled5.sol'].lib = address + }) + .perform(() => { + browser.setEditorValue(JSON.stringify(config)) + }) + .openFile('browser/Untitled5.sol') + .selectContract('test') // deploy lib + .createContract('') + .getAddressAtPosition(1, (address) => { + addressRef = address + }) + .waitForElementPresent('.instance:nth-of-type(3)') + .click('.instance:nth-of-type(3) > div > button') + .perform(() => { + browser + .testConstantFunction(addressRef, 'get - call', null, '0:\nuint256: 45') + .perform(() => { callback() }) + }) +} + +const sources = [ + { + 'browser/Untitled5.sol': {content: `library lib { + function getInt () public view returns (uint) { + return 45; + } + } + + contract test { + function get () public view returns (uint) { + return lib.getInt(); + } + }`} + } +] diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index ec96dff931..caec88488d 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -31,8 +31,13 @@ declare module "nightwatch" { renameFile(path: string, newFileName: string, renamedPath: string): NightwatchBrowser, rightClick(cssSelector: string): NightwatchBrowser, waitForElementContainsText(id: string, value: string): NightwatchBrowser, - getModalBody(callback: CallableFunction): NightwatchBrowser, - modalFooterCancelClick(): NightwatchBrowser + getModalBody(callback: (value: string, cb: VoidFunction) => void): NightwatchBrowser, + modalFooterCancelClick(): NightwatchBrowser, + selectContract(contractName: string): NightwatchBrowser, + createContract(inputParams: string): NightwatchBrowser, + getAddressAtPosition(index: number, cb: (pos: string) => void): NightwatchBrowser, + testConstantFunction(address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput | null, expectedOutput: string): NightwatchBrowser, + getEditorValue(callback: (content: string) => void): NightwatchBrowser } export interface NightwatchBrowser { @@ -62,5 +67,10 @@ declare module "nightwatch" { [key: string]: any } + export interface NightwatchTestConstantFunctionExpectedInput { + types: string, + values: string + } + export type NightwatchCheckVariableDebugValue = NightwatchTestFunctionExpectedInput } \ No newline at end of file