diff --git a/.babelrc b/.babelrc index c064a26682..ff9e845bd6 100644 --- a/.babelrc +++ b/.babelrc @@ -9,5 +9,5 @@ } ] ], - "plugins": ["macros"] + "plugins": ["macros", "lodash"] } diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml index c72a026cf8..338df4027a 100644 --- a/.github/workflows/cypress.yml +++ b/.github/workflows/cypress.yml @@ -48,11 +48,11 @@ jobs: REF_BRANCH=${REF/refs\/tags\//} BRANCH=$REF_BRANCH fi - echo "::set-output name=value::$BRANCH" + echo "value=$BRANCH" >> $GITHUB_OUTPUT - name: Extract GitHub HEAD SHA id: head_sha - run: echo "::set-output name=value::$(git rev-parse HEAD)" + run: echo "value=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - name: Get Docker image tag id: get_tag @@ -60,7 +60,7 @@ jobs: HEAD_SHA: ${{ github.event.pull_request.head.sha }} run: | short_sha="$(echo $HEAD_SHA | head -c7)" - echo "::set-output name=image_tag::adpr-$short_sha" + echo "image_tag=adpr-$short_sha" >> $GITHUB_OUTPUT cypress-test: runs-on: ubuntu-latest @@ -87,7 +87,7 @@ jobs: sudo apt-get install --no-install-recommends -y \ fluxbox \ xvfb - + - name: Yarn Build env: CI: false @@ -95,26 +95,32 @@ jobs: CURRENT_BRANCH: ${{ needs.prepare.outputs.current_branch }} NODE_OPTIONS: '--max_old_space_size=4096' run: yarn build-adpr - + - name: Install cypress - run: yarn cypress install --force - + run: yarn cypress install --force + - name: Run xvfb and fluxbox run: | Xvfb :0 -screen 0 1024x768x24 -listen tcp -ac & fluxbox & env: - DISPLAY: :0.0 + DISPLAY: :0.0 + + - name: Create env file + run: | + touch .env + echo ENV=${ENV} > .env + echo CYPRESS_BASE_URL='http://127.0.0.1:4173/' > .env - name: Run Cypress Test run: |+ #!/bin/bash yarn preview & - yarn test-e2e -e grepTags=smoke,NETWORK=Ethereum + yarn test-e2e -c baseUrl='http://127.0.0.1:4173/' -e grepTags=smoke,NETWORK=Ethereum env: DISPLAY: :0.0 - - - name: Archive e2e artifacts + + - name: Archive e2e artifacts uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 if: always() with: @@ -122,4 +128,4 @@ jobs: path: | cypress/videos cypress/screenshots - continue-on-error: true + continue-on-error: true diff --git a/.github/workflows/schedule.yml b/.github/workflows/schedule.yml index 04862cd183..ad37319e3d 100644 --- a/.github/workflows/schedule.yml +++ b/.github/workflows/schedule.yml @@ -2,7 +2,8 @@ name: 'E2E Testing Schedule' on: schedule: - - cron: '0 1,5 * * *' # run at 8AM and 12PM (GTM+7) + - cron: '*/20 1-12 * * *' + - cron: '0 13 * * *' workflow_dispatch: jobs: @@ -11,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - network: ['Ethereum', 'Arbitrum','Optimism', 'Avalanche', 'BNB'] + network: ['Ethereum', 'Arbitrum', 'Optimism', 'Avalanche', 'BNB'] steps: - name: Trigger Code Checkout uses: actions/checkout@v3 @@ -30,44 +31,39 @@ jobs: - name: Install linux deps run: | - sudo apt-get install --no-install-recommends -y \ - fluxbox \ - xvfb - + sudo apt-get install --no-install-recommends -y \ + fluxbox \ + xvfb + - name: Install cypress - run: yarn cypress install --force - + run: yarn cypress install --force + - name: Run xvfb and fluxbox run: Xvfb :0 -screen 0 1024x768x24 -listen tcp -ac & fluxbox & env: - DISPLAY: :0.0 + DISPLAY: :0.0 + + - name: Create env file + run: | + touch .env + echo ENV=${ENV} > .env + echo GITHUB_RUN_ID=${GITHUB_RUN_ID} > .env + echo CORE_PUSH_GATEWAY_URL=${{ secrets.CORE_PUSH_GATEWAY_URL }} > .env - name: Run Cypress Test run: |+ #!/bin/bash - yarn test-schedule -e grepTags=regression,NETWORK=${{ matrix.network }} - env: - DISPLAY: :0.0 - - - name: Notify on failure - if: ${{ failure() }} - uses: rtCamp/action-slack-notify@v2 + yarn test-schedule -c baseUrl='https://kyberswap.com/' -e grepTags=regression,NETWORK=${{ matrix.network }} env: - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - SLACK_CHANEL: automation-test-bot - SLACK_COLOR: ${{ job.status }} # or a specific color like 'good' or '#ff00ff' - SLACK_ICON: https://icon-library.com/images/star-wars-icon-png/star-wars-icon-png-16.jpg?size=48 - SLACK_TITLE: E2E Test ${{inputs.BASE_URL}} - SLACK_USERNAME: autoBot - SLACK_LINK_NAMES: true - - - name: Archive e2e artifacts + DISPLAY: :0.0 + + - name: Archive e2e artifacts uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 if: always() with: - name: e2e-artifacts - path: | - cypress/videos - cypress/screenshots + name: e2e-artifacts + path: | + cypress/videos + cypress/screenshots continue-on-error: true diff --git a/cypress.config.ts b/cypress.config.ts index 5da0b93d20..1085451248 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -1,8 +1,10 @@ import synpressPlugins from '@synthetixio/synpress/plugins' import { defineConfig } from 'cypress' +import client from 'prom-client' + +require('dotenv').config() export default defineConfig({ - projectId: '4x4jf8', component: { devServer: { framework: 'create-react-app', @@ -14,15 +16,133 @@ export default defineConfig({ viewportWidth: 1920, viewportHeight: 1080, env: { - grepFilterSpecs:true, - grepOmitFiltered:true + grepFilterSpecs: true, + grepOmitFiltered: true, }, e2e: { setupNodeEvents(on, config) { // eslint-disable-next-line @typescript-eslint/no-var-requires require('@cypress/grep/src/plugin')(config) synpressPlugins(on, config) + on('after:run', async results => { + if (results) { + const register = new client.Registry() + const prefix = 'e2e_cypress' + const suite = new client.Counter({ + name: `${prefix}_suite`, + help: `${prefix}_suite`, + labelNames: ['buildId', 'result', 'baseName', 'duration', 'chain'] as const, + }) + suite.reset() + const { totalPassed, totalFailed, totalTests, totalDuration, runs } = results + runs.forEach(run => { + const { stats, spec } = run + const { tests, passes, pending, failures, duration } = stats + const { baseName } = spec + suite + .labels({ + buildId: `${process.env.GITHUB_RUN_ID}`, + result: 'failed', + baseName: baseName, + duration: duration, + chain: config.env.NETWORK, + }) + .inc(failures) + + suite + .labels({ + buildId: `${process.env.GITHUB_RUN_ID}`, + result: 'passed', + baseName: baseName, + duration: duration, + chain: config.env.NETWORK, + }) + .inc(passes) + + suite + .labels({ + buildId: `${process.env.GITHUB_RUN_ID}`, + result: 'pending', + baseName: baseName, + duration: duration, + chain: config.env.NETWORK, + }) + .inc(pending) + suite + .labels({ + buildId: `${process.env.GITHUB_RUN_ID}`, + result: 'tests', + baseName: baseName, + duration: duration, + chain: config.env.NETWORK, + }) + .inc(tests) + }) + + suite + .labels({ + buildId: `${process.env.GITHUB_RUN_ID}`, + result: 'passed', + baseName: 'All Specs', + duration: totalDuration, + chain: config.env.NETWORK, + }) + .inc(totalPassed) + + suite + .labels({ + buildId: `${process.env.GITHUB_RUN_ID}`, + result: 'failed', + baseName: 'All Specs', + duration: totalDuration, + chain: config.env.NETWORK, + }) + .inc(totalFailed) + suite + .labels({ + buildId: `${process.env.GITHUB_RUN_ID}`, + result: 'total', + baseName: 'All Specs', + duration: totalDuration, + chain: config.env.NETWORK, + }) + .inc(totalTests) + + const testPass = new client.Counter({ + name: `${prefix}_test_passed`, + help: `${prefix}_pass`, + labelNames: ['buildId', 'chain'] as const, + }) + + const testFail = new client.Counter({ + name: `${prefix}_test_failed`, + help: `${prefix}_fail`, + labelNames: ['buildId', 'chain'] as const, + }) + + testPass.reset() + testFail.reset() + + testFail.labels({ buildId: `${process.env.GITHUB_RUN_ID}`, chain: config.env.NETWORK }).inc(totalFailed) + testPass.labels({ buildId: `${process.env.GITHUB_RUN_ID}`, chain: config.env.NETWORK }).inc(totalPassed) + + register.registerMetric(testPass) + register.registerMetric(testFail) + register.registerMetric(suite) + + const gateway = new client.Pushgateway(`${process.env.CORE_PUSH_GATEWAY_URL}`, [], register) + await gateway + .push({ jobName: 'ui-automation' }) + .then(({ resp, body }) => { + console.log(`Body: ${body}`) + console.log(`Response status: ${resp}`) + }) + .catch((err: any) => { + console.log('err: ', err) + }) + } + }) }, - specPattern: 'cypress/e2e/specs/*.e2e.cy.ts' + specPattern: 'cypress/e2e/specs/*.e2e.cy.ts', }, }) diff --git a/cypress/e2e/pages/farm-page.po.cy.ts b/cypress/e2e/pages/farm-page.po.cy.ts new file mode 100644 index 0000000000..3575e57f45 --- /dev/null +++ b/cypress/e2e/pages/farm-page.po.cy.ts @@ -0,0 +1,46 @@ +import { FarmLocators, HeaderLocators } from "../selectors/selectors.cy" + +export class FarmPage { + + getTvlValues() { + const arr: string[] = [] + const listData = cy.get(FarmLocators.lblTvl) + listData + .each(item => { + arr.push(item.text().split('$')[1]) + }) + return arr + } + + getAprValues() { + const arr: string[] = [] + const listData = cy.get(FarmLocators.lblApr) + listData + .each(item => { + arr.push(item.text().split('%')[0]) + }) + return arr + } + + countInvalidFarms(arrApr: string[], arrTvl: string[]) { + const totalFarms = arrApr.length + let count = 0; + for (let i = 0; i < totalFarms; i++) { + if (((arrTvl[i]) === undefined || Number(arrTvl[i]) === 0) && Number(arrApr[i]) === 0) { + count = count + 1; + } + } + return count + } + + checkExistData() { + return cy.get(FarmLocators.lblApr, {timeout: 5000}).should(() => { }).then($obj => { + if ($obj.length > 0) { + return true + } + else { + return false + } + }) + } +} \ No newline at end of file diff --git a/cypress/e2e/pages/swap-page.po.cy.ts b/cypress/e2e/pages/swap-page.po.cy.ts index 6da235890b..31dc3d5fe6 100644 --- a/cypress/e2e/pages/swap-page.po.cy.ts +++ b/cypress/e2e/pages/swap-page.po.cy.ts @@ -1,4 +1,4 @@ -import { NetworkLocators, SwapPageLocators, TokenCatalogLocators, WalletLocators } from "../selectors/selectors.cy" +import { HeaderLocators, NetworkLocators, SwapPageLocators, TokenCatalogLocators, WalletLocators } from "../selectors/selectors.cy" export interface myCallbackType { (myArgument: T): void @@ -35,14 +35,29 @@ export const SwapPage = { getStatusConnectedWallet() { cy.get(WalletLocators.statusConnected, { timeout: 10000 }).should('be.visible') - } + }, + + goToFarmPage() { + cy.get(HeaderLocators.dropdownEarn).click({ force: true }) + cy.get(HeaderLocators.lblFarms).click({ force: true }) + }, + + goToPoolPage() { + cy.get(HeaderLocators.dropdownEarn).click({ force: true }) + cy.get(HeaderLocators.lblPools).click({ force: true }) + }, + + goToMyPoolsPage() { + cy.get(HeaderLocators.dropdownEarn).click({ force: true }) + cy.get(HeaderLocators.lblMyPools).click({ force: true }) + }, } export class Network { selectNetwork(network: string) { cy.get(NetworkLocators.btnSelectNetwork, { timeout: 30000 }).should('be.visible').click() cy.get(NetworkLocators.btnNetwork).contains(network).click({ force: true }) - } + } } export class TokenCatalog { diff --git a/cypress/e2e/selectors/selectors.cy.ts b/cypress/e2e/selectors/selectors.cy.ts index e7af50485a..f3a85e1eb3 100644 --- a/cypress/e2e/selectors/selectors.cy.ts +++ b/cypress/e2e/selectors/selectors.cy.ts @@ -39,3 +39,8 @@ export const HeaderLocators = { lblMyPools: '[data-testid=my-pools-nav-link]', lblFarms: '[data-testid=farms-nav-link]', } + +export const FarmLocators = { + lblApr: '[data-testid=apr-value]', + lblTvl: '[data-testid=tvl-value]', +} \ No newline at end of file diff --git a/cypress/e2e/specs/farm-page.e2e.cy.ts b/cypress/e2e/specs/farm-page.e2e.cy.ts new file mode 100644 index 0000000000..2015017a57 --- /dev/null +++ b/cypress/e2e/specs/farm-page.e2e.cy.ts @@ -0,0 +1,24 @@ +import { FarmPage } from "../pages/farm-page.po.cy"; +import { SwapPage } from "../pages/swap-page.po.cy" +import { DEFAULT_URL, TAG, } from "../selectors/constants.cy" +const farm = new FarmPage() + +describe('Farm', { tags: TAG.regression }, () => { + beforeEach(() => { + SwapPage.open(DEFAULT_URL) + SwapPage.goToFarmPage() + farm.checkExistData().then((value) => { + if (value === true) { + cy.wrap(farm.getAprValues()).as('arrApr') + cy.wrap(farm.getTvlValues()).as('arrTvl') + } + cy.wrap(value).as('checkData') + }) + }) + it('Should be displayed APR and TVL values', function () { + if (this.checkData === true) { + const count = farm.countInvalidFarms(this.arrApr, this.arrTvl) + expect(count).not.to.equal(this.arrApr.length) + } + }) +}) diff --git a/cypress/e2e/specs/intercept.e2e.cy.ts b/cypress/e2e/specs/intercept.e2e.cy.ts index cefd5f6ce7..163e19ca92 100644 --- a/cypress/e2e/specs/intercept.e2e.cy.ts +++ b/cypress/e2e/specs/intercept.e2e.cy.ts @@ -1,7 +1,10 @@ /* eslint-disable @typescript-eslint/no-empty-function */ -import { SwapPage } from "../pages/swap-page.po.cy" -import { DEFAULT_URL, TAG, } from "../selectors/constants.cy" +import { FarmPage } from "../pages/farm-page.po.cy"; +import { SwapPage, TokenCatalog } from "../pages/swap-page.po.cy" +import { DEFAULT_URL, TAG, } from "../selectors/constants.cy" import { HeaderLocators } from "../selectors/selectors.cy" +const tokenCatalog = new TokenCatalog() +const farm = new FarmPage() describe('Intercept', { tags: TAG.regression }, () => { beforeEach(() => { @@ -19,19 +22,32 @@ describe('Intercept', { tags: TAG.regression }, () => { cy.intercept('GET', '**/farm-pools?**').as('get-farm-list') cy.intercept('GET', '**/pools?**').as('get-pool-list') cy.intercept('GET', '**/block?**').as('get-block') - cy.get(HeaderLocators.dropdownEarn).click({ force: true }) - cy.get(HeaderLocators.lblPools).click({ force: true }) + SwapPage.goToPoolPage() cy.wait('@get-farm-list', { timeout: 5000 }).its('response.statusCode').should('equal', 200) cy.wait('@get-pool-list', { timeout: 5000 }).its('response.statusCode').should('equal', 200) cy.wait('@get-block', { timeout: 60000 }).its('response.statusCode').should('equal', 200) }) + + it('Should be displayed APR and TVL values', () => { + cy.intercept('GET', '**/pools?**').as('get-pools') + SwapPage.goToPoolPage() + cy.wait('@get-pools', { timeout: 20000 }).its('response.body.data').then(response => { + const totalPools = response.pools.length; + const count = response.pools.reduce((acc: number, pool: { totalValueLockedUsd: string; apr: string }) => { + if (pool.totalValueLockedUsd === '0' && pool.apr === '0') { + return acc + 1; + } + return acc; + }, 0); + expect(count).not.to.equal(totalPools); + }) + }) }) describe('My Pools', () => { it('Should get farm list successfully', () => { cy.intercept('GET', '**/farm-pools?**').as('get-farm-list') - cy.get(HeaderLocators.dropdownEarn).click({ force: true }) - cy.get(HeaderLocators.lblPools).click({ force: true }) + SwapPage.goToMyPoolsPage() cy.wait('@get-farm-list', { timeout: 5000 }).its('response.statusCode').should('equal', 200) }) }) @@ -41,8 +57,7 @@ describe('Intercept', { tags: TAG.regression }, () => { cy.intercept('GET', '**/farm-pools?**').as('get-farm-list') cy.intercept('GET', '**/pools?**').as('get-pool-list') cy.intercept('GET', '**/block?**').as('get-block') - cy.get(HeaderLocators.dropdownEarn).click({ force: true }) - cy.get(HeaderLocators.lblFarms).click({ force: true }) + SwapPage.goToFarmPage() cy.get('[data-testid=farm-block]') .should(_ => {}) .then($list => { diff --git a/index.html b/index.html index 8a0ee5abac..ed49b2f07f 100644 --- a/index.html +++ b/index.html @@ -1,211 +1,206 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - KyberSwap - Trading Smart - - - - - - - -
- - - -
-
- -