1
0
mirror of https://github.com/oceanprotocol/commons.git synced 2023-03-15 18:03:00 +01:00

Merge pull request #134 from oceanprotocol/feature/cypress

End-to-end testing setup with Cypress
This commit is contained in:
Matthias Kretschmann 2019-06-25 17:20:33 +02:00 committed by GitHub
commit d240ee8eab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 5895 additions and 1304 deletions

View File

@ -10,9 +10,10 @@
"prettier/standard", "prettier/standard",
"plugin:prettier/recommended", "plugin:prettier/recommended",
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended",
"prettier/@typescript-eslint" "prettier/@typescript-eslint",
"plugin:cypress/recommended"
], ],
"plugins": ["@typescript-eslint", "prettier"], "plugins": ["@typescript-eslint", "prettier", "cypress"],
"rules": { "rules": {
"@typescript-eslint/explicit-function-return-type": 0, "@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/member-delimiter-style": [ "@typescript-eslint/member-delimiter-style": [
@ -23,6 +24,7 @@
"env": { "env": {
"es6": true, "es6": true,
"browser": true, "browser": true,
"jest": true "jest": true,
"cypress/globals": true
} }
} }

4
.gitignore vendored
View File

@ -20,3 +20,7 @@ dist
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
# cypress
cypress/screenshots
cypress/videos

View File

@ -3,12 +3,28 @@ language: node_js
node_js: node_js:
- '11' - '11'
addons:
apt:
packages:
# for Cypress
- libgconf-2-4
before_install: before_install:
- npm install -g npm - npm install -g npm
- npm install -g codacy-coverage - npm install -g codacy-coverage truffle ganache-cli
script: script:
# - ./scripts/install.sh # runs automatically with npm ci # - ./scripts/install.sh # runs automatically with npm ci
# run E2E tests against these values
- export REACT_APP_NODE_URI="https://nile.dev-ocean.com"
- export REACT_APP_AQUARIUS_URI="https://aquarius.marketplace.dev-ocean.com"
- export REACT_APP_BRIZO_URI="https://brizo.marketplace.dev-ocean.com"
- export REACT_APP_SECRET_STORE_URI="https://secret-store.marketplace.dev-ocean.com"
- export REACT_APP_FAUCET_URI="https://faucet.nile.dev-ocean.com"
- export REACT_APP_BRIZO_ADDRESS="0x4aaab179035dc57b35e2ce066919048686f82972"
- export CYPRESS_NODE_URI=$REACT_APP_NODE_URI
- export CYPRESS_SEEDPHRASE="taxi music thumb unique chat sand crew more leg another off lamp"
- export CYPRESS_CONSUME_ASSET="http://localhost:3000/asset/did:op:8014d305dcb44b42a5355791a2f016a654a61184456a4d178dc6e5913deb3a5c"
- ./scripts/test.sh - ./scripts/test.sh
- ./scripts/coverage.sh - ./scripts/coverage.sh
- ./scripts/build.sh - ./scripts/build.sh
@ -16,7 +32,11 @@ script:
notifications: notifications:
email: false email: false
cache: npm cache:
npm: true
directories:
# cache folder with Cypress binary
- ~/.cache
deploy: deploy:
- provider: script - provider: script

1
cypress.json Normal file
View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,190 @@
{
"@context": "https://w3id.org/did/v1",
"id": "did:op:52f2ed716f97463e97beeb414195a075b606675874204e3da39b0c237377dbd3",
"publicKey": [
{
"id": "did:op:52f2ed716f97463e97beeb414195a075b606675874204e3da39b0c237377dbd3",
"type": "EthereumECDSAKey",
"owner": "0x5e3264A651303b93A3a3BC5eaB5c8676f5C3D7b1"
}
],
"authentication": [
{
"type": "RsaSignatureAuthentication2018",
"publicKey": "did:op:52f2ed716f97463e97beeb414195a075b606675874204e3da39b0c237377dbd3"
}
],
"service": [
{
"type": "Access",
"creator": "",
"purchaseEndpoint": "https://brizo.duero.dev-ocean.com:443/api/v1/brizo/services/access/initialize",
"serviceEndpoint": "https://brizo.duero.dev-ocean.com:443/api/v1/brizo/services/consume",
"name": "dataAssetAccessServiceAgreement",
"templateId": "0xfA16d26e9F4fffC6e40963B281a0bB08C31ed40C",
"serviceAgreementTemplate": {
"contractName": "EscrowAccessSecretStoreTemplate",
"events": [
{
"name": "AgreementCreated",
"actorType": "consumer",
"handler": {
"moduleName": "escrowAccessSecretStoreTemplate",
"functionName": "fulfillLockRewardCondition",
"version": "0.1"
}
}
],
"fulfillmentOrder": [
"lockReward.fulfill",
"accessSecretStore.fulfill",
"escrowReward.fulfill"
],
"conditionDependency": {
"lockReward": [],
"accessSecretStore": [],
"escrowReward": ["lockReward", "accessSecretStore"]
},
"conditions": [
{
"name": "lockReward",
"timelock": 0,
"timeout": 0,
"contractName": "LockRewardCondition",
"functionName": "fulfill",
"parameters": [
{
"name": "_rewardAddress",
"type": "address",
"value": "0x5e3264A651303b93A3a3BC5eaB5c8676f5C3D7b1"
},
{ "name": "_amount", "type": "uint256", "value": 0 }
],
"events": [
{
"name": "Fulfilled",
"actorType": "publisher",
"handler": {
"moduleName": "lockRewardCondition",
"functionName": "fulfillAccessSecretStoreCondition",
"version": "0.1"
}
}
]
},
{
"name": "accessSecretStore",
"timelock": 0,
"timeout": 0,
"contractName": "AccessSecretStoreCondition",
"functionName": "fulfill",
"parameters": [
{
"name": "_documentId",
"type": "bytes32",
"value": "52f2ed716f97463e97beeb414195a075b606675874204e3da39b0c237377dbd3"
},
{ "name": "_grantee", "type": "address", "value": "" }
],
"events": [
{
"name": "Fulfilled",
"actorType": "publisher",
"handler": {
"moduleName": "accessSecretStore",
"functionName": "fulfillEscrowRewardCondition",
"version": "0.1"
}
},
{
"name": "TimedOut",
"actorType": "consumer",
"handler": {
"moduleName": "accessSecretStore",
"functionName": "fulfillEscrowRewardCondition",
"version": "0.1"
}
}
]
},
{
"name": "escrowReward",
"timelock": 0,
"timeout": 0,
"contractName": "EscrowReward",
"functionName": "fulfill",
"parameters": [
{ "name": "_amount", "type": "uint256", "value": 0 },
{ "name": "_receiver", "type": "address", "value": "" },
{ "name": "_sender", "type": "address", "value": "" },
{ "name": "_lockCondition", "type": "bytes32", "value": "" },
{ "name": "_releaseCondition", "type": "bytes32", "value": "" }
],
"events": [
{
"name": "Fulfilled",
"actorType": "publisher",
"handler": {
"moduleName": "escrowRewardCondition",
"functionName": "verifyRewardTokens",
"version": "0.1"
}
}
]
}
]
},
"serviceDefinitionId": "0"
},
{
"type": "Authorization",
"service": "SecretStore",
"serviceEndpoint": "https://secret-store.duero.dev-ocean.com:443",
"serviceDefinitionId": "1"
},
{
"type": "Metadata",
"serviceEndpoint": "https://aquarius.duero.dev-ocean.com:443/api/v1/aquarius/assets/ddo/did:op:52f2ed716f97463e97beeb414195a075b606675874204e3da39b0c237377dbd3",
"metadata": {
"curation": { "rating": 0.0, "numVotes": 0, "isListed": true },
"base": {
"name": "Technical Whitepaper",
"description": "This paper presents Ocean Protocol. Ocean is a decentralized protocol and network of artificial intelligence (AI) data/services. \n\nOcean does decentralized orchestration: at its core are decentralized service agreements and decentralized access control, which execute on decentralized virtual machines. This allows connection to, monetization of, and curation of arbitrary data services. On that, Ocean adds network rewards to incentivize data sharing, including privacy-preserving data commons.",
"dateCreated": "2019-05-10T11:55:58.492Z",
"author": "Ocean Protocol",
"type": "dataset",
"license": "Public Domain",
"copyrightHolder": "Ocean Protocol Foundation Ltd.",
"files": [
{
"found": true,
"contentLength": "2989228",
"contentType": "application/pdf",
"compression": "none",
"index": 0
}
],
"categories": ["Engineering"],
"links": [],
"tags": "",
"price": 0,
"encryptedFiles": "0x95116a697eadb4b5058682749f587321cb918ec6239a193a7e1e3587d7de28e761e8819e2241e9375b035eacc3dcec4799e0da4cd52552ab583082366ff4e0fb1f72a63ae071206859cfc53abdea2135c660cfba1e81361efce10bfcec323d63b0dcf009dd2c48dfcde09c95dcf69d6c6a318e869ac26b7dc0fcb085e1421b394aaf4d4fac05e992c13a225c5c1e138a7fb27185ba5e1709760ecd43e89eafef435ad97ffb",
"checksum": "9b624a8f9cd7f9d1127c818f32453f43dc6c633472a682bb880d69093b4b9615",
"datePublished": "2019-05-10T14:40:01Z"
},
"additionalInformation": {
"updateFrequency": null,
"structuredMarkup": []
}
},
"serviceDefinitionId": "2"
}
],
"created": "2019-05-10T14:39:53Z",
"proof": {
"created": "2019-05-10T14:39:55Z",
"creator": "0x5e3264A651303b93A3a3BC5eaB5c8676f5C3D7b1",
"type": "DDOIntegritySignature",
"signatureValue": "0x94c3042facdb0601cb5c90264b1e8d1ae6902043af4303c57869d2881748621b03d943f4bb2ccd5d18429964f4ebc425d77baffc576884cfd78ae0987082c5931b"
}
}

View File

@ -0,0 +1,45 @@
/// <reference types="Cypress" />
import Web3 from 'web3'
import HDWalletProvider from 'truffle-hdwallet-provider'
context('Consume', () => {
before(() => {
cy.on('window:before:load', win => {
const provider = new HDWalletProvider(
Cypress.env('SEEDPHRASE')
? Cypress.env('SEEDPHRASE')
: 'taxi music thumb unique chat sand crew more leg another off lamp',
Cypress.env('NODE_URI')
? Cypress.env('NODE_URI')
: 'https://nile.dev-ocean.com'
)
win.web3 = new Web3(provider)
win.ethereum = win.web3
})
cy.visit(
Cypress.env('CONSUME_ASSET')
? Cypress.env('CONSUME_ASSET')
: 'http://localhost:3000/asset/did:op:8014d305dcb44b42a5355791a2f016a654a61184456a4d178dc6e5913deb3a5c'
)
// Wait for end of loading
cy.get('button', { timeout: 60000 }).should('have.length', 1)
})
it('Download button is clickable when user is connected.', () => {
cy.get('button').should('not.be.disabled')
})
it('Consume asset and check if there is no error', () => {
// Click consume button
cy.get('button').click()
// Wait consume process to end
cy.get('button', { timeout: 120000 }).should('contain', 'Get file')
// check if there is no error
cy.get('article>div').should(
'not.contain',
'. Sorry about that, can you try again?'
)
})
})

View File

@ -0,0 +1,41 @@
/// <reference types="Cypress" />
import Web3 from 'web3'
import HDWalletProvider from 'truffle-hdwallet-provider'
context('Faucet', () => {
before(() => {
cy.on('window:before:load', win => {
const provider = new HDWalletProvider(
Cypress.env('SEEDPHRASE')
? Cypress.env('SEEDPHRASE')
: 'taxi music thumb unique chat sand crew more leg another off lamp',
Cypress.env('NODE_URI')
? Cypress.env('NODE_URI')
: 'https://nile.dev-ocean.com'
)
win.web3 = new Web3(provider)
win.ethereum = win.web3
})
cy.visit('http://localhost:3000/faucet')
// Wait for end of loading
cy.get('button', { timeout: 60000 }).should('have.length', 1)
})
it('Faucet button is clickable when user is connected.', () => {
cy.get('button')
.contains('Request Ether')
.should('not.be.disabled')
})
it('Execute faucet call', () => {
// Execute call
cy.get('button')
.contains('Request Ether')
.click()
// Verify that we got response from server
cy.contains(/(Successfully added|Already requested)/, {
timeout: 60000
}).should('be.visible')
})
})

View File

@ -0,0 +1,84 @@
/// <reference types="Cypress" />
import Web3 from 'web3'
import HDWalletProvider from 'truffle-hdwallet-provider'
context('Publish', () => {
before(() => {
cy.on('window:before:load', win => {
const provider = new HDWalletProvider(
Cypress.env('SEEDPHRASE')
? Cypress.env('SEEDPHRASE')
: 'taxi music thumb unique chat sand crew more leg another off lamp',
Cypress.env('NODE_URI')
? Cypress.env('NODE_URI')
: 'https://nile.dev-ocean.com'
)
win.web3 = new Web3(provider)
win.ethereum = win.web3
})
cy.visit('http://localhost:3000/publish')
cy.get('article>div', { timeout: 60000 }).should(
'contain',
'Essentials'
)
})
it('Publish flow', () => {
// Fill title
cy.get('input#name').type('Title test')
// Open Add a file form
cy.get('button')
.contains('+ Add a file')
.click()
// Fill url of file
cy.get('input#url').type(
'https://oceanprotocol.com/tech-whitepaper.pdf'
)
// Add file to main form
cy.get('button')
.contains('Add File')
.click()
// Verify and nove to next step
cy.get('button')
.contains('Next →')
.should('not.be.disabled')
.click()
// Verify we are on next step
cy.get('article>div').should('contain', 'Information')
// Fill description
cy.get('textarea#description').type('This is test description')
// Pick category
cy.get('select#categories').select('Biology')
// Verify and move to next step
cy.get('button')
.contains('Next →')
.should('not.be.disabled')
.click()
// Verify we are on next step
cy.get('article>div').should('contain', 'Authorship')
// Fill author
cy.get('input#author').type('Super Author')
// Fill copyright holder
cy.get('input#copyrightHolder').type('Super Copyright Holder')
// Pick author
cy.get('select#license').select('Public Domain')
// Verify and move to next step
cy.get('button')
.contains('Next →')
.should('not.be.disabled')
.click()
// Verify we are on next step
cy.get('article>div').should('contain', 'Register')
// Start publish process
cy.get('button')
.contains('Register asset')
.should('not.be.disabled')
.click()
// Wait for finish
cy.contains('Your asset is published!', {
timeout: 12000
}).should('be.visible')
})
})

View File

@ -0,0 +1,38 @@
/// <reference types="Cypress" />
import Web3 from 'web3'
import HDWalletProvider from 'truffle-hdwallet-provider'
context('Search', () => {
before(() => {
cy.on('window:before:load', win => {
const provider = new HDWalletProvider(
Cypress.env('SEEDPHRASE')
? Cypress.env('SEEDPHRASE')
: 'taxi music thumb unique chat sand crew more leg another off lamp',
Cypress.env('NODE_URI')
? Cypress.env('NODE_URI')
: 'https://nile.dev-ocean.com'
)
win.web3 = new Web3(provider)
win.ethereum = win.web3
})
cy.visit('http://localhost:3000')
// Wait for end of loading
cy.get('button', { timeout: 60000 }).should('have.length', 1)
})
it('Search for assets from homepage', () => {
// Fill search phrase
cy.get('input#search').type('Title test')
// Start search
cy.get('button')
.contains('Search')
.click()
// Verify there are results
cy.get('article > a', { timeout: 60000 }).should(
'have.length.greaterThan',
0
)
})
})

View File

@ -0,0 +1,14 @@
/// <reference types="Cypress" />
context('Viewport', () => {
beforeEach(() => {
cy.visit('http://localhost:3000')
})
it('cy.viewport() - set the viewport size and dimension', () => {
cy.get('#root > div > header > div > a > h1').should('be.visible')
cy.viewport(320, 480)
cy.get('#root > div > header > div > a > h1').should('not.be.visible')
})
})

17
cypress/plugins/index.js Normal file
View File

@ -0,0 +1,17 @@
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}

0
cypress/support/index.js Normal file
View File

10
cypress/tsconfig.json Normal file
View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"strict": true,
"baseUrl": "../node_modules",
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress"]
},
"include": ["**/*.ts"]
}

6685
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,9 +6,12 @@
"scripts": { "scripts": {
"install": "./scripts/install.sh", "install": "./scripts/install.sh",
"start": "concurrently \"cd client && npm start\" \"cd server && npm start\"", "start": "concurrently \"cd client && npm start\" \"cd server && npm start\"",
"start:commons-and-ganache": "concurrently 'npm run start:ganache' 'npm run start'",
"build": "./scripts/build.sh", "build": "./scripts/build.sh",
"test": "npm run lint && scripts/test.sh", "test": "npm run lint && scripts/test.sh",
"test:e2e": "start-test start:commons-and-ganache http-get://localhost:3000 cypress:run",
"test:watch": "npm run lint && concurrently \"cd client && npm run test:watch\" \"cd server && npm run test:watch\"", "test:watch": "npm run lint && concurrently \"cd client && npm run test:watch\" \"cd server && npm run test:watch\"",
"start:ganache": "ganache-cli -m 'stamp polar cup smart ill agree human episode reform trigger text forget' -i 5777",
"format:js": "prettier --parser typescript --write '**/*.{js,jsx,ts,tsx}'", "format:js": "prettier --parser typescript --write '**/*.{js,jsx,ts,tsx}'",
"format:css": "prettier-stylelint --ignore-path .gitignore --write --quiet '**/*.{css,scss}'", "format:css": "prettier-stylelint --ignore-path .gitignore --write --quiet '**/*.{css,scss}'",
"format": "npm run format:js && npm run format:css", "format": "npm run format:js && npm run format:css",
@ -17,22 +20,31 @@
"lint:fix": "eslint --fix --ignore-path .gitignore --ignore-path .prettierignore --ext .ts,.tsx .", "lint:fix": "eslint --fix --ignore-path .gitignore --ignore-path .prettierignore --ext .ts,.tsx .",
"lint": "npm run lint:js && npm run lint:css", "lint": "npm run lint:js && npm run lint:css",
"release": "release-it --non-interactive", "release": "release-it --non-interactive",
"changelog": "auto-changelog -p" "changelog": "auto-changelog -p",
"cypress:run": "cypress run --browser chrome",
"cypress:open": "cypress open"
},
"dependencies": {
"react-collapsed": "^2.0.1",
"truffle-hdwallet-provider": "^1.0.10",
"web3": "1.0.0-beta.37"
}, },
"dependencies": {},
"devDependencies": { "devDependencies": {
"@release-it/bumper": "^1.0.2", "@release-it/bumper": "^1.0.2",
"@typescript-eslint/eslint-plugin": "^1.7.0", "@typescript-eslint/eslint-plugin": "^1.7.0",
"@typescript-eslint/parser": "^1.7.0", "@typescript-eslint/parser": "^1.7.0",
"auto-changelog": "^1.13.0", "auto-changelog": "^1.13.0",
"concurrently": "^4.1.0", "concurrently": "^4.1.0",
"cypress": "^3.2.0",
"eslint": "^5.16.0", "eslint": "^5.16.0",
"eslint-config-oceanprotocol": "^1.3.0", "eslint-config-oceanprotocol": "^1.3.0",
"eslint-config-prettier": "^4.2.0", "eslint-config-prettier": "^4.2.0",
"eslint-plugin-cypress": "^2.2.1",
"eslint-plugin-prettier": "^3.0.1", "eslint-plugin-prettier": "^3.0.1",
"prettier": "^1.17.0", "prettier": "^1.17.0",
"prettier-stylelint": "^0.4.2", "prettier-stylelint": "^0.4.2",
"release-it": "^11.0.2", "release-it": "^11.0.2",
"start-server-and-test": "^1.9.0",
"stylelint": "^10.0.1", "stylelint": "^10.0.1",
"stylelint-config-bigchaindb": "^1.2.2", "stylelint-config-bigchaindb": "^1.2.2",
"stylelint-config-css-modules": "^1.4.0", "stylelint-config-css-modules": "^1.4.0",

View File

@ -10,3 +10,7 @@ do
npm test npm test
cd .. cd ..
done done
echo "Running End-to-End tests"
npm run test:e2e

View File

@ -3,6 +3,7 @@ import express from 'express'
import compression from 'compression' import compression from 'compression'
import morgan from 'morgan' import morgan from 'morgan'
import bodyParser from 'body-parser' import bodyParser from 'body-parser'
import pkg from '../../package.json'
// routes // routes
import UrlCheckRouter from './routes/UrlCheckRouter' import UrlCheckRouter from './routes/UrlCheckRouter'
@ -51,6 +52,15 @@ app.use(bodyParser.urlencoded({ extended: false }))
app.use(compression()) app.use(compression())
// routes // routes
app.get('/', (req, res) => {
res.send(
`<strong><code>
🏄 <br />
Ocean Protocol Commons Server v${pkg.version}<br />
<a href="https://github.com/oceanprotocol/commons" style="text-decoration:none;color:#f6388a">github.com/oceanprotocol/commons</a>
</code></strong>`
)
})
app.use('/api/v1/urlcheck', UrlCheckRouter) app.use('/api/v1/urlcheck', UrlCheckRouter)
/// catch 404 /// catch 404

View File

@ -5,6 +5,13 @@ afterAll(done => {
server.close(done) server.close(done)
}) })
describe('GET /', () => {
it('responds with success', async () => {
const response = await request(server).get('/')
expect(response.status).toBe(200)
})
})
describe('POST /api/v1/urlcheck', () => { describe('POST /api/v1/urlcheck', () => {
it('responds with json', async () => { it('responds with json', async () => {
const response = await request(server).post('/api/v1/urlcheck') const response = await request(server).post('/api/v1/urlcheck')

View File

@ -2,6 +2,7 @@
"compilerOptions": { "compilerOptions": {
"module": "commonjs", "module": "commonjs",
"esModuleInterop": true, "esModuleInterop": true,
"resolveJsonModule": true,
"target": "es6", "target": "es6",
"noImplicitAny": false, "noImplicitAny": false,
"moduleResolution": "node", "moduleResolution": "node",