Skip to content

Commit

Permalink
kwa(front): Add UI tests with Cypress (#2088)
Browse files Browse the repository at this point in the history
* kwa(front): Install Cypress

 - Install Cypress & npm scripts for UI tests
 - Remove Protractor files
 - Add README.md file to include UI tests instructions
 - Modify .gitignore

Signed-off-by: Orfeas Kourkakis <[email protected]>

* kwa(front): Add UI tests with Cypress

Add UI tests with Cypress to check that:
 - New Experiment form page loads template without errors.
 - Index page
    * has an "Experiments" title
    * lists experiments without errors
    * renders every experiment name into the table
    * renders properly Status icon for all experiments

Signed-off-by: Orfeas Kourkakis <[email protected]>

* gh-actions(kwa): Add UI tests in test-node action

Signed-off-by: Orfeas Kourkakis <[email protected]>

Signed-off-by: Orfeas Kourkakis <[email protected]>
  • Loading branch information
orfeas-k committed Jan 26, 2023
1 parent ff6441b commit c5923cb
Show file tree
Hide file tree
Showing 19 changed files with 1,568 additions and 95 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/test-node.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,35 @@ jobs:
run: |
cd pkg/new-ui/v1beta1/frontend
npm run test:prod
frontend-ui-tests:
name: UI tests with Cypress
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup node version to 12
uses: actions/setup-node@v3
with:
node-version: 12

- name: Fetch Kubeflow and install common code dependencies
run: |
COMMIT=$(cat pkg/new-ui/v1beta1/frontend/COMMIT)
cd /tmp && git clone https://github.com/kubeflow/kubeflow.git
cd kubeflow
git checkout $COMMIT
cd components/crud-web-apps/common/frontend/kubeflow-common-lib
npm i
npm run build
npm link ./dist/kubeflow
- name: Install KWA dependencies
run: |
cd pkg/new-ui/v1beta1/frontend
npm i
npm link kubeflow
- name: Serve UI & run Cypress tests in Chrome and Firefox
run: |
cd pkg/new-ui/v1beta1/frontend
npm run start & npx wait-on http://localhost:4200
npm run ui-test-ci-all
4 changes: 4 additions & 0 deletions pkg/new-ui/v1beta1/frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,7 @@ Thumbs.db

# Font files (automatically generating)
/src/assets/fonts

# Cypress
cypress/screenshots
cypress/downloads
40 changes: 40 additions & 0 deletions pkg/new-ui/v1beta1/frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Frontend

This project was generated with Angular CLI.

## Development server

Run `npm run start` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.

## Code scaffolding

Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.

## Build

Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.

## Running unit tests

Run `npm run test` to execute the unit tests via [Karma](https://karma-runner.github.io).

## Running UI tests

To run UI tests locally, make sure that node modules are installed and the frontend is serving the UI under `localhost:4200`. Then use `npm run ui-test` to execute the UI tests via [Cypress](https://www.cypress.io/). This will open Cypress and from there you may select the browser in which the tests will run.

Ideally, tests should be run both in Chrome and Firefox and for that there is the script `npm run ui-test-ci-all` that `runs` (instead of `opening`) Cypress. Note that in order for tests to run in a browser, the browser needs to be already installed on the system.

Make sure to check out these guides for system-specific information on installing and running Cypress

- https://docs.cypress.io/guides/getting-started/installing-cypress
- https://docs.cypress.io/guides/references/advanced-installation

### WSL2

In order to be run in a WSL2 installation, Cypress requires these [dependencies](https://docs.cypress.io/guides/getting-started/installing-cypress#Linux-Prerequisites).

In the case of WSL2 on _Windows 10_, [this extra setup](https://docs.cypress.io/guides/references/advanced-installation#Windows-Subsystem-for-Linux) is required in order to have an X Server running in Windows host and creating the browser window.

## Further help

To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI documents](https://angular.io/cli).
23 changes: 21 additions & 2 deletions pkg/new-ui/v1beta1/frontend/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,21 @@
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"builder": "@cypress/schematic:cypress",
"options": {
"devServerTarget": "frontend:serve",
"watch": true,
"headless": false
},
"configurations": {
"production": {
"devServerTarget": "frontend:serve:production"
}
}
},
"cypress-run": {
"builder": "@cypress/schematic:cypress",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "frontend:serve"
},
"configurations": {
Expand All @@ -140,6 +152,13 @@
"src/**/*.html"
]
}
},
"cypress-open": {
"builder": "@cypress/schematic:cypress",
"options": {
"watch": true,
"headless": false
}
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions pkg/new-ui/v1beta1/frontend/cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { defineConfig } from 'cypress';

export default defineConfig({
video: false,
e2e: {
setupNodeEvents(on, config) {},
baseUrl: 'http://localhost:4200',
},
});
14 changes: 14 additions & 0 deletions pkg/new-ui/v1beta1/frontend/cypress/e2e/form-page.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
describe('New Experiment form page', () => {
beforeEach(() => {
cy.mockDashboardRequest();
cy.mockTrialTemplate();
});

it('New Experiment form page loads template without errors', () => {
cy.visit('/new');
cy.wait(['@mockDashboardRequest', '@mockTrialTemplate']);

// after fetching the data the page should not have an error snackbar
cy.get('[data-cy-snack-status=ERROR]').should('not.exist');
});
});
78 changes: 78 additions & 0 deletions pkg/new-ui/v1beta1/frontend/cypress/e2e/index-page.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { STATUS_TYPE } from 'kubeflow';
import { parseStatus } from 'src/app/pages/experiments/utils';

describe('Index page', () => {
beforeEach(() => {
cy.mockDashboardRequest();
cy.mockNamespacesRequest();
cy.fixture('settings').then(settings => {
cy.mockExperimentsRequest(settings.namespace);
});
cy.fixture('experiments').as('experimentsRequest');
});

it('should have an "Experiments" title', () => {
cy.visit('/');
cy.get('[data-cy-toolbar-title]').contains('Experiments').should('exist');
});

it('should list Experiments without errors', () => {
cy.visit('/');
// wait for the requests to complete
cy.wait(['@mockNamespacesRequest', '@mockExperimentsRequest']);

// after fetching the data the page should not have an error snackbar
cy.get('[data-cy-snack-status=ERROR]').should('not.exist');
});

// We use function () in order to be able to access aliases via this
// tslint:disable-next-line: space-before-function-paren
it('renders every Experiment name into the table', function () {
cy.visit('/');
cy.wait(['@mockNamespacesRequest', '@mockExperimentsRequest']);

let i = 0;
const experiments = this.experimentsRequest;
// Table is sorted by Name in ascending order by default
// and experiment objects are also sorted alphabetically by name
cy.get(`[data-cy-resource-table-row="Name"]`).each(element => {
expect(element).to.contain(experiments[i].name);
i++;
});
});

// tslint:disable-next-line: space-before-function-paren
it('renders properly Status icon for all experiments', function () {
cy.visit('/');
cy.wait(['@mockNamespacesRequest', '@mockExperimentsRequest']);

let i = 0;
const experiments = this.experimentsRequest;
cy.get('[data-cy-resource-table-row="Status"]').each(element => {
const status = parseStatus(experiments[i]);
if (status.phase === STATUS_TYPE.READY) {
cy.wrap(element)
.find('lib-status>mat-icon')
.should('contain', 'check_circle');
} else if (status.phase === STATUS_TYPE.STOPPED) {
cy.wrap(element)
.find('lib-status>lib-icon')
.should('have.attr', 'icon', 'custom:stoppedResource');
} else if (status.phase === STATUS_TYPE.UNAVAILABLE) {
cy.wrap(element)
.find('lib-status>mat-icon')
.should('contain', 'timelapse');
} else if (status.phase === STATUS_TYPE.WARNING) {
cy.wrap(element)
.find('lib-status>mat-icon')
.should('contain', 'warning');
} else if (
status.phase === STATUS_TYPE.WAITING ||
status.phase === STATUS_TYPE.TERMINATING
) {
cy.wrap(element).find('mat-spinner').should('exist');
}
i++;
});
});
});
Loading

0 comments on commit c5923cb

Please sign in to comment.