Skip to content

Commit

Permalink
chore: cypress 13 upgrade (#3040)
Browse files Browse the repository at this point in the history
Upgrade to Cypress 13. 
* This involved some folder restructuring (integration => e2e).
* Some subfolders because there are not enough suites to warrant them.
* Some steps had duplicated titles and were therefore either consolidated
to a single step in the /common folder, or else name changed.
  • Loading branch information
jenniferarnesen authored Aug 2, 2024
1 parent 9454825 commit e3303c3
Show file tree
Hide file tree
Showing 98 changed files with 3,509 additions and 4,569 deletions.
6 changes: 6 additions & 0 deletions .cypress-cucumber-preprocessorrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"nonGlobalStepDefinitions": true,
"e2e": {
"stepDefinitions": ["cypress/e2e/**/*.{js,ts}"]
}
}
2 changes: 1 addition & 1 deletion .github/workflows/dhis2-preview-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 14.x
node-version: 18.x

- uses: c-hive/gha-yarn-cache@v1
- run: yarn install --frozen-lockfile
Expand Down
80 changes: 14 additions & 66 deletions .github/workflows/dhis2-verify-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,76 +86,24 @@ jobs:
- name: Test
run: yarn d2-app-scripts test

e2e-prod:
runs-on: ubuntu-latest
needs: [test, setup-matrix]
call-workflow-e2e-prod:
if: "!contains(github.event.head_commit.message, '[skip ci]')"

strategy:
fail-fast: false
matrix:
spec-group: ${{ fromJson(needs.setup-matrix.outputs.matrix) }}

env:
SHOULD_RECORD: ${{ contains(github.event.head_commit.message, '[e2e record]') || contains(join(github.event.pull_request.labels.*.name), 'e2e record') }}

steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18.x

- uses: actions/cache@v2
id: yarn-cache
with:
path: '**/node_modules'
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}-${{ hashFiles('patches/*.patch') }}

- name: Set Cypress Record Environment Variables
if: env.SHOULD_RECORD == 'true'
run: |
echo "CYPRESS_GROUP=e2e-${{ matrix.spec-group.id }}" >> $GITHUB_ENV
echo "CYPRESS_TAG=${{ github.event_name }}" >> $GITHUB_ENV
echo "CYPRESS_CI_BUILD_ID=${{ github.run_id }}" >> $GITHUB_ENV
- name: Debug Environment Variables
run: |
echo "SHOULD_RECORD=${{ env.SHOULD_RECORD }}"
echo "CI Build ID=${{ github.run_id }}"
echo "Computed Group=${{ env.SHOULD_RECORD == 'true' && env.CYPRESS_GROUP || '' }}"
echo "Computed Tag=${{ env.SHOULD_RECORD == 'true' && env.CYPRESS_TAG || '' }}"
echo "Computed CI Build ID=${{ env.SHOULD_RECORD == 'true' && env.CYPRESS_CI_BUILD_ID || '' }}"
echo "Spec=${{ join(matrix.spec-group.tests, ',') }}"
- name: End-to-End tests
uses: cypress-io/github-action@v2
with:
start: ${{ env.SERVER_START_CMD }}
wait-on: ${{ env.SERVER_URL }}
wait-on-timeout: 300
cache-key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}-${{ hashFiles('patches/*.patch') }}
record: ${{ env.SHOULD_RECORD }}
parallel: ${{ env.SHOULD_RECORD }}
group: ${{ env.SHOULD_RECORD == 'true' && env.CYPRESS_GROUP || '' }}
tag: ${{ env.SHOULD_RECORD == 'true' && env.CYPRESS_TAG || '' }}
ci-build-id: ${{ env.SHOULD_RECORD == 'true' && env.CYPRESS_CI_BUILD_ID || '' }}
spec: ${{ join(matrix.spec-group.tests, ',') }}
env:
CI: true
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title }}
SERVER_START_CMD: 'yarn cypress:start'
SERVER_URL: 'http://localhost:3000'
cypress_dhis2_api_stub_mode: 'DISABLED'
REACT_APP_DHIS2_BASE_URL: ${{ secrets.CYPRESS_DHIS2_BASE_URL_41 }}
cypress_dhis2_base_url: ${{ secrets.CYPRESS_DHIS2_BASE_URL_41}}
cypress_dhis2_username: ${{ secrets.CYPRESS_DHIS2_USERNAME }}
cypress_dhis2_password: ${{ secrets.CYPRESS_DHIS2_PASSWORD }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
needs: [build, lint, test, setup-matrix]
uses: dhis2/workflows/.github/workflows/analytics-e2e-tests-prod.yml@master
with:
should_record: ${{ contains(github.event.head_commit.message, '[e2e record]') || contains(join(github.event.pull_request.labels.*.name), 'e2e record')}}
spec-group: ${{ needs.setup-matrix.outputs.matrix }}
secrets:
username: ${{ secrets.CYPRESS_DHIS2_USERNAME }}
password: ${{ secrets.CYPRESS_DHIS2_PASSWORD }}
recordkey: ${{ secrets.CYPRESS_RECORD_KEY }}
reportportal_api_key: ${{ secrets.REPORTPORTAL_API_KEY }}
reportportal_endpoint: ${{ vars.REPORTPORTAL_ENDPOINT }}
reportportal_project: ${{ vars.REPORTPORTAL_PROJECT }}

release:
runs-on: ubuntu-latest
needs: e2e-prod
needs: call-workflow-e2e-prod
if: |
!github.event.push.repository.fork &&
github.actor != 'dependabot[bot]' &&
Expand Down
32 changes: 12 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,9 @@ Open [http://localhost:3000](http://localhost:3000) to view it in the browser.

#### Configuration

Two environment variables need to be set for running dashboards-app in development mode. It is recommended to set these environment variables in a `.env` or `.env.local` file.

##### api base url: REACT_APP_DHIS2_BASE_URL

The api base url points to a running DHIS2 instance. This can be for example `http://localhost:8080`.

```
REACT_APP_DHIS2_BASE_URL=http://localhost:8080
```

##### api authentication: REACT_APP_DHIS2_AUTHORIZATION

In order for maps, event reports and event charts to display in development mode, you also need to provide the authenticaion credentials for the api. The following example is the base64 encoded value for the username/password combination of `admin:district`:
In order for event reports and event charts to display in development mode, you need to set up the REACT_APP_DHIS2_AUTHORIZATION environment variable. The following example is the base64 encoded value for the username/password combination of `admin:district`:

```
REACT_APP_DHIS2_AUTHORIZATION=Basic YWRtaW46ZGlzdHJpY3Q=
Expand All @@ -31,23 +21,25 @@ REACT_APP_DHIS2_AUTHORIZATION=Basic YWRtaW46ZGlzdHJpY3Q=

#### Configuration

Additional environment variables are needed in order to run the Cypress e2e tests. It is recommended to define these in the same place as the REACT_APP_DHIS2_BASE_URL env var (for example. `.env`). REACT_APP_DHIS2_BASE_URL and CYPRESS_DHIS2_BASE_URL must match.
Additional environment variables are needed in order to run the Cypress e2e tests. You can configure these in a local file `cypress.env.json`

```
REACT_APP_DHIS2_BASE_URL=http://localhost:8080
CYPRESS_DHIS2_BASE_URL=http://localhost:8080
CYPRESS_DHIS2_USERNAME=admin
CYPRESS_DHIS2_PASSWORD=district
{
"dhis2BaseUrl": "https://test.e2e.dhis2.org/analytics-2.41",
"dhis2InstanceVersion": "2.41",
"dhis2Username": "admin",
"dhis2Password": "district"
}
```

#### Run the e2e tests

The following commands can be used to run the tests:

| Comman | Backend | Environment | Tests |
| -------------- | :--------: | ----------: | ----: |
| `yarn cy:open` | API server | Cypress UI | All |
| `yarn cy:run` | API server | Headless | All |
| Comman | Environment | Tests |
| -------------- | ----------: | ----: |
| `yarn cy:open` | Cypress UI | All |
| `yarn cy:run` | Headless | All |

### `yarn test`

Expand Down
3 changes: 0 additions & 3 deletions cypress-cucumber-preprocessor.config.js

This file was deleted.

53 changes: 53 additions & 0 deletions cypress.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const {
addCucumberPreprocessorPlugin,
} = require('@badeball/cypress-cucumber-preprocessor')
const createEsbuildPlugin = require('@badeball/cypress-cucumber-preprocessor/esbuild')
const createBundler = require('@bahmutov/cypress-esbuild-preprocessor')
const { chromeAllowXSiteCookies } = require('@dhis2/cypress-plugins')
const { defineConfig } = require('cypress')

async function setupNodeEvents(on, config) {
await addCucumberPreprocessorPlugin(on, config)
chromeAllowXSiteCookies(on, config)

on(
'file:preprocessor',
createBundler({
plugins: [createEsbuildPlugin.default(config)],
})
)

return config
}

module.exports = defineConfig({
projectId: '5fk191',
chromeWebSecurity: false,
e2e: {
setupNodeEvents,
baseUrl: 'http://localhost:3000',
specPattern: 'cypress/e2e/*.feature',
viewportWidth: 1280,
viewportHeight: 800,
defaultCommandTimeout: 45000,
/* Globally disable test isolation because the test suite
* contains many tests with sequential steps */
testIsolation: false,
// Record video
video: true,
// Enabled to reduce the risk of out-of-memory issues
experimentalMemoryManagement: true,
// Set to a low number to reduce the risk of out-of-memory issues
numTestsKeptInMemory: 5,
/* When allowing 1 retry on CI, the test suite will pass if
* it's flaky. And/but we also get to identify flaky tests on the
* Cypress Dashboard. */
retries: {
runMode: 1,
openMode: 0,
},
},
env: {
networkMode: 'live',
},
})
9 changes: 0 additions & 9 deletions cypress.json

This file was deleted.

18 changes: 18 additions & 0 deletions cypress/e2e/common/SL_dashboard_displays_in_view_mode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Then } from '@badeball/cypress-cucumber-preprocessor'
import { dashboards } from '../../assets/backends/index.js'
// import { gridItemSel, chartSel } from '../../elements/dashboardItem.js'
import { dashboardTitleSel } from '../../elements/viewDashboard.js'
// import { EXTENDED_TIMEOUT } from '../../support/utils.js'

Then('the {string} dashboard displays in view mode', (title) => {
cy.location().should((loc) => {
expect(loc.hash).to.equal(dashboards[title].route)
})

cy.get(dashboardTitleSel).should('be.visible').and('contain', title)
// cy.get(gridItemSel)
// .first()
// .getIframeBody()
// .find(chartSel, EXTENDED_TIMEOUT)
// .should('exist')
})
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { When } from 'cypress-cucumber-preprocessor/steps'
import { When } from '@badeball/cypress-cucumber-preprocessor'
import {
unselectedItemsSel,
filterDimensionsPanelSel,
orgUnitTreeSel,
} from '../../../elements/dashboardFilter.js'
import { EXTENDED_TIMEOUT } from '../../../support/utils.js'
} from '../../elements/dashboardFilter.js'
import { EXTENDED_TIMEOUT } from '../../support/utils.js'

const PERIOD = 'Last 6 months'
const OU_ID = 'ImspTQPwCqd' //Sierra Leone
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { When } from 'cypress-cucumber-preprocessor/steps'
import { When } from '@badeball/cypress-cucumber-preprocessor'

When('dashboard items are added', () => {
cy.get('[data-test="item-search"]').click()
Expand Down
6 changes: 6 additions & 0 deletions cypress/e2e/common/choose_to_delete_dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { When } from '@badeball/cypress-cucumber-preprocessor'
import { clickEditActionButton } from '../../elements/editDashboard.js'

When('I choose to delete dashboard', () => {
clickEditActionButton('Delete')
})
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { When, Then } from 'cypress-cucumber-preprocessor/steps'
import { titleInputSel } from '../../../elements/editDashboard.js'
import { titleBarSel } from '../../../elements/viewDashboard.js'
import { EXTENDED_TIMEOUT } from '../../../support/utils.js'
import { When, Then } from '@badeball/cypress-cucumber-preprocessor'
import { titleInputSel } from '../../elements/editDashboard.js'
import { titleBarSel } from '../../elements/viewDashboard.js'
import { EXTENDED_TIMEOUT } from '../../support/utils.js'

const ROUTE_EDIT = 'edit'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { When } from 'cypress-cucumber-preprocessor/steps'
import { filterBadgeSel } from '../../../elements/dashboardFilter.js'
import { When } from '@badeball/cypress-cucumber-preprocessor'
import { filterBadgeSel } from '../../elements/dashboardFilter.js'

When('I click on the {string} filter badge', (filterName) => {
cy.get(filterBadgeSel).find('span:visible').contains(filterName).click()
Expand Down
9 changes: 9 additions & 0 deletions cypress/e2e/common/close_item_selector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { When } from '@badeball/cypress-cucumber-preprocessor'
import { itemMenuSel } from '../../elements/editDashboard.js'

When('I close the item selector', () => {
//close modal
cy.get('[data-test="dhis2-uicore-layer"]').click('topLeft')

cy.get(itemMenuSel).should('not.exist')
})
6 changes: 6 additions & 0 deletions cypress/e2e/common/confirm_delete.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { When } from '@badeball/cypress-cucumber-preprocessor'
import { confirmActionDialogSel } from '../../elements/editDashboard.js'

When('I confirm delete', () => {
cy.get(confirmActionDialogSel).find('button').contains('Delete').click()
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { When } from 'cypress-cucumber-preprocessor/steps'
import { confirmActionDialogSel } from '../../../elements/editDashboard.js'
import { When } from '@badeball/cypress-cucumber-preprocessor'
import { confirmActionDialogSel } from '../../elements/editDashboard.js'

When('I confirm I want to discard changes', () => {
cy.get(confirmActionDialogSel)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { When } from 'cypress-cucumber-preprocessor/steps'
import { dashboardTitleSel } from '../../../elements/viewDashboard.js'
import { When } from '@badeball/cypress-cucumber-preprocessor'
import { dashboardTitleSel } from '../../elements/viewDashboard.js'

When('I click to exit print preview', () => {
cy.get('button').not('.small').contains('Exit print preview').click()
Expand Down
6 changes: 6 additions & 0 deletions cypress/e2e/common/exit_without_saving.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { When } from '@badeball/cypress-cucumber-preprocessor'
import { clickEditActionButton } from '../../elements/editDashboard.js'

When('I click Exit without saving', () => {
clickEditActionButton('Exit without saving')
})
14 changes: 14 additions & 0 deletions cypress/e2e/common/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import './before_each_visit_root.js'
import './add_dashboard_items.js'
import './confirm_discard_changes.js'
import './exit_without_saving.js'
import './add_a_FILTERTYPE_filter.js'
import './choose_to_edit_dashboard.js'
import './click_on_the_FILTERTYPE_filter_badge.js'
import './exit_print_layout.js'
import './open_print_layout.js'
import './open_the_SL_dashboard.js'
import './print_layout_displays.js'
import './start_new_dashboard.js'
import './the_dashboard_description_is_(not)_displayed.js'
import './SL_dashboard_displays_in_view_mode.js'
7 changes: 7 additions & 0 deletions cypress/e2e/common/message_dashboard_not_found.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Then } from '@badeball/cypress-cucumber-preprocessor'
import { dashboardTitleSel } from '../../elements/viewDashboard.js'

Then('a message displays informing that the dashboard is not found', () => {
cy.contains('Requested dashboard not found').should('be.visible')
cy.get(dashboardTitleSel).should('not.exist')
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { When } from 'cypress-cucumber-preprocessor/steps'
import { clickViewActionButton } from '../../../elements/viewDashboard.js'
import { When } from '@badeball/cypress-cucumber-preprocessor'
import { clickViewActionButton } from '../../elements/viewDashboard.js'

When('I click to preview the print layout', () => {
clickViewActionButton('More')
Expand Down
24 changes: 24 additions & 0 deletions cypress/e2e/common/open_the_SL_dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Given } from '@badeball/cypress-cucumber-preprocessor'
import { dashboards } from '../../assets/backends/index.js'
// import { gridItemSel, chartSel } from '../../elements/dashboardItem.js'
import {
dashboardTitleSel,
dashboardChipSel,
} from '../../elements/viewDashboard.js'
import { EXTENDED_TIMEOUT } from '../../support/utils.js'

Given('I open the {string} dashboard', (title) => {
cy.get(dashboardChipSel, EXTENDED_TIMEOUT).contains(title).click()

cy.location().should((loc) => {
expect(loc.hash).to.equal(dashboards[title].route)
})

cy.get(dashboardTitleSel).should('be.visible').and('contain', title)
// cy.get(`${gridItemSel}.VISUALIZATION`)
// .first()
// .getIframeBody()
// .find(chartSel, EXTENDED_TIMEOUT)
// .as('vis')
// cy.get('@vis').should('exist')
})
Loading

0 comments on commit e3303c3

Please sign in to comment.