Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions .github/workflows/automated-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,21 @@ on:
- completed

jobs:
test-all:
test-sid:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- name: Checkout ${{ github.sha }}
uses: actions/checkout@v2
- name: Build and test
working-directory: ./automated-testing
run: make test
run: make test
test-ondemand:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- name: Checkout ${{ github.sha }}
uses: actions/checkout@v2
- name: Build and test
working-directory: ./automated-testing
run: make ondemand-test
22 changes: 22 additions & 0 deletions .github/workflows/manual-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: manual-tests

on:
workflow_dispatch:

jobs:
test-sid:
runs-on: ubuntu-latest
steps:
- name: Checkout ${{ github.sha }}
uses: actions/checkout@v2
- name: Sid Build and test
working-directory: ./automated-testing
run: make test
test-ondemand:
runs-on: ubuntu-latest
steps:
- name: Checkout ${{ github.sha }}
uses: actions/checkout@v2
- name: OnDemand Run and test
working-directory: ./automated-testing
run: make ondemand-test
34 changes: 28 additions & 6 deletions automated-testing/Makefile
Original file line number Diff line number Diff line change
@@ -1,26 +1,48 @@
# default build target
all:: local
.PHONY: test local remote-dev remote-fasse staging-cannon staging-fasse prod-cannon prod-fasse landing
.PHONY: sid test ondemand ondemand-test landing

DOCKER_NODE_IMAGE := node:16
DOCKER_CYPRESS_IMAGE := cypress/base:16.4.0
WORKING_DIR := $(shell pwd)
FASSE_ENV := env no_proxy=.harvard.edu http_proxy=http://rcproxy.rc.fas.harvard.edu:3128 https_proxy=http://rcproxy.rc.fas.harvard.edu:3128

remote-fasse staging-fasse prod-fasse: ENV := env no_proxy=.harvard.edu http_proxy=http://rcproxy.rc.fas.harvard.edu:3128 https_proxy=http://rcproxy.rc.fas.harvard.edu:3128
# Add FASSE proxy when running against FASSE environment.
ifeq "$(CONFIG)" "remote-fasse"
ENV:=$(FASSE_ENV)
endif
ifeq "$(CONFIG)" "staging-fasse"
ENV:=$(FASSE_ENV)
endif
ifeq "$(CONFIG)" "prod-fasse"
ENV:=$(FASSE_ENV)
endif

local remote-dev remote-fasse staging-fasse prod-fasse staging-cannon prod-cannon:
sid:
@echo "For FASSE and Cannon environments, you need to be connected to the VPN"
cp -rf cypress.env.json.$(@) cypress.env.json
cp -rf ./sid/cypress.env.json.$(CONFIG) cypress.env.json
$(ENV) npm install && $(ENV) ./node_modules/.bin/cypress run --headless --spec cypress/integration/fasrc-dashboard/*,cypress/integration/sid-dashboard/*

test:
cd ../dashboard/ && DETACHED=true make
docker pull $(DOCKER_CYPRESS_IMAGE)
./wait_for_dashboard.sh
cp -rf cypress.env.json.local cypress.env.json
cp -rf ./sid/cypress.env.json.local cypress.env.json
docker run --rm --network=host -v $(WORKING_DIR):/usr/local/app -v /usr/local/app/node_modules -w /usr/local/app --env cypress_dashboard_username=$$OOD_USERNAME --env cypress_dashboard_password=$$OOD_PASSWORD $(DOCKER_CYPRESS_IMAGE) /bin/bash -c "npm install && ./node_modules/.bin/cypress run --headless --spec cypress/integration/fasrc-dashboard/*,cypress/integration/sid-dashboard/*" || :
cd ../dashboard/ && make down

ondemand:
cp -rf ./ondemand/cypress.env.json.$(CONFIG) cypress.env.json
$(ENV) npm install && $(ENV) ./node_modules/.bin/cypress run --headless --spec "cypress/integration/ondemand/**/*.spec.js"

ondemand-test:
cd ../ondemand/ && DETACHED=true make
docker pull $(DOCKER_CYPRESS_IMAGE)
env ENDPOINT=https://localhost:33000/pun/sys/dashboard ./wait_for_dashboard.sh
cp -rf ./ondemand/cypress.env.json.local cypress.env.json
docker run --rm --network=host -v $(WORKING_DIR):/usr/local/app -v /usr/local/app/node_modules -w /usr/local/app --env cypress_dashboard_username=$$OOD_USERNAME --env cypress_dashboard_password=$$OOD_PASSWORD $(DOCKER_CYPRESS_IMAGE) /bin/bash -c 'npm install && ./node_modules/.bin/cypress run --headless --spec "cypress/integration/ondemand/**/*.spec.js"' || :
cd ../ondemand/ && make down

landing:
cp -rf cypress.env.json.$(@) cypress.env.json
cp -rf landing/cypress.env.json.landing cypress.env.json
$(ENV) npm install && $(ENV) ./node_modules/.bin/cypress run --headless --spec cypress/integration/sid-landing-site/*
36 changes: 18 additions & 18 deletions automated-testing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Cypress is a testing tool [https://docs.cypress.io](https://docs.cypress.io)
## TL;DR
To install the dependencies and run the tests locally run:
* `npm install`
* `make local`
* `make sid CONFIG=local`

## Installing testing tooling - Cypress
`npm install`
Expand All @@ -14,23 +14,23 @@ To install the dependencies and run the tests locally run:
To run tests against `remote-dev`, `staging`, `FASSE`, and `Cannon`, you need to connect to the VPN.

Cypress can be configured using environment variables. We use a feature of Cypress to setup and environment file: `cypress.env.json` with environment specific configuration. In order to support the multiple Sid2 environments, we have created several configuration files for each one of them:
* `cypress.env.json.local`
* `cypress.env.json.remote-dev`
* `cypress.env.json.remote-fasse`
* `cypress.env.json.staging-cannon`
* `cypress.env.json.staging-fasse`
* `cypress.env.json.prod-cannon`
* `cypress.env.json.prod-fasse`
* `sid/cypress.env.json.local`
* `sid/cypress.env.json.remote-dev`
* `sid/cypress.env.json.remote-fasse`
* `sid/cypress.env.json.staging-cannon`
* `sid/cypress.env.json.staging-fasse`
* `sid/cypress.env.json.prod-cannon`
* `sid/cypress.env.json.prod-fasse`

Each `make` task that executes a test will create a copy of the enviroment specific file as `cypress.env.json`
The following `make` tasks will execute the tests locally against each environment using a Docker image to run the tests:
* `make local`
* `make remote-dev`
* `make remote-fasse`
* `make staging-cannon`
* `make staging-fasse`
* `make prod-cannon`
* `make prod-fasse`
The following `make` tasks will execute the tests locally against each environment using a Cypress runtime to run the tests:
* `make sid CONFIG=local`
* `make sid CONFIG=remote-dev`
* `make sid CONFIG=remote-fasse`
* `make sid CONFIG=staging-cannon`
* `make sid CONFIG=staging-fasse`
* `make sid CONFIG=prod-cannon`
* `make sid CONFIG=prod-fasse`

There is a special make task that is used to run the tests within GitHub action: `make test`
This task will first start the Sid Dashboard in the local Docker environment and then run the tests against it.
Expand All @@ -40,7 +40,7 @@ In order to connect to the Sid dashboard, we need to provide the automated tests
* `OOD_USERNAME`
* `OOD_PASSWORD`

example: `env OOD_USERNAME=ood OOD_PASSWORD=ood make prod-fasse`
example: `env OOD_USERNAME=ood OOD_PASSWORD=ood make sid CONFIG=prod-fasse`

The credentials file can be droped at the root of the project: `credentials.json`. This is a JSON format file with the username and password, example:
```
Expand All @@ -50,7 +50,7 @@ In order to connect to the Sid dashboard, we need to provide the automated tests
}
```

For the local environment: `cypress.env.json.local`, the credentials are already configured.
For the local environment: `sid/cypress.env.json.local`, the credentials are already configured.

## CLI
We can run `Cypress` through `npm`, a `cypress` script was added to the `package.json` file.
Expand Down
128 changes: 128 additions & 0 deletions automated-testing/cypress/integration/ondemand/fasrc/header.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { NAVIGATION, loadHomepage } from "../../../support/utils/navigation.js";
import { changeProfile } from "../../../support/utils/profiles.js";

describe('FASRC Dashboard - Header', () => {

const interactiveApps = cy.sid.ondemandApplications.filter(l => Cypress.env('fasrc_dashboard_applications').includes(l.id))
Cypress.config('baseUrl', NAVIGATION.baseUrl);

before(() => {
loadHomepage()
changeProfile('FASRC')
})

beforeEach(() => {
//DEFAULT SIZE FOR THESE TESTS
cy.viewport(cy.sid.screen.largeWidth, cy.sid.screen.height)
loadHomepage()
})

it('Should display FASRC logo with homepage link', () => {
cy.get('nav a.navbar-brand-logo')
.should($logoElement => {
expect($logoElement).to.have.length(1)
expect($logoElement.attr('href')).to.match(new RegExp(NAVIGATION.rootPath))
})
.find('img').should($imageElement => {
expect($imageElement).to.have.length(1)
expect($imageElement.attr('src')).to.match(/.*fasrc_logo.png$/i)
})
})

it('Should display Clusters navigation item', () => {
cy.get('nav li[title="Clusters"]').as('navItem')
cy.get('@navItem').find('> a').invoke('text').should('match', /clusters/i)
cy.get('@navItem').find('> a').click()
cy.get('@navItem').find('ul li').as('menu').should('have.length', 1)

cy.get('@menu').first().should('be.visible')
cy.get('@menu').first().find('a').should($submenuElement => {
expect($submenuElement.attr('target')).to.equal('_blank')
})
})

it('Should display Files navigation item with home directory link', () => {
cy.get('nav li[title="Files"]').as('navItem')
cy.get('@navItem').find('> a').invoke('text').should('match', /files/i)
cy.get('@navItem').find('> a').click()
cy.get('@navItem').find('ul li').as('menu').its('length').should('be.gte', 1)

cy.get('@menu').first().should('be.visible')
cy.get('@menu').first().find('a').should($submenuElement => {
expect($submenuElement.text().trim()).to.match(/home directory/i)
})
})

it('Should display Jobs navigation item', () => {
cy.get('nav li[title="Jobs"]').as('navItem')
cy.get('@navItem').find('> a').invoke('text').should('match', /jobs/i)
cy.get('@navItem').find('> a').click()
cy.get('@navItem').find('ul li').as('menu').should('have.length', 2)

cy.get('@menu').eq(0).should('be.visible')
cy.get('@menu').eq(0).find('a').should($submenuElement => {
expect($submenuElement.text().trim()).to.match(/active jobs/i)
})

cy.get('@menu').eq(1).should('be.visible')
cy.get('@menu').eq(1).find('a').should($submenuElement => {
expect($submenuElement.text().trim()).to.match(/job composer/i)
expect($submenuElement.attr('target')).to.equal('_blank')
})
})

it('Should display Interactive Apps navigation item with installed apps', () => {
cy.get('nav li[title="Interactive Apps"]').as('navItem')
cy.get('@navItem').find('> a').invoke('text').should('match', /interactive apps/i)
cy.get('@navItem').find('> a').click()
cy.get('@navItem').find('ul li a').as('menu').should('have.length.gte', interactiveApps.length)

interactiveApps.forEach( (app) => {
cy.get('@menu').filter(`a[title="${app.name}"]`).should($appElement => {
$appElement.is(':visible')
expect($appElement.text().trim()).to.contain(app.name)
expect($appElement.attr('href')).to.contain(app.token)
})
})
})

it('Should display Interactive Sessions navigation item', () => {
cy.get('nav li[title="My Interactive Sessions"]').as('navItem')
cy.get('@navItem').find('> a').should($navElement => {
$navElement.is(':visible')
expect($navElement.text().trim()).to.match(/my interactive sessions/i)
expect($navElement.attr('href')).to.contain('/batch_connect/sessions')
})
})

it('Should display Help links', () => {
cy.get('nav li[title="Help"] ul.dropdown-menu').as('helpMenu')
cy.get('@helpMenu').find('a').should($helpLinks => {
//SUPPORT TICKET IS FIRST ITEM INSIDE HELP MENU
expect($helpLinks.first().text().trim()).to.match(/submit support ticket/i)
expect($helpLinks.first().attr('href')).to.match(/support$/)
})

// PROFILE LINKS
cy.get('@helpMenu').find('li.dropdown-header').should($profileHeaderElement => {
expect($profileHeaderElement.text().trim()).to.match(/interface/i)
})
cy.get('@helpMenu').find('a[title="FASRC"]').should($profileLinkElement => {
expect($profileLinkElement.text().trim()).to.match(/fasrc/i)
expect($profileLinkElement.attr('href')).to.match(new RegExp('/settings.*fasrc', 'i'))
})
cy.get('@helpMenu').find('a[title="Sid"]').should($profileLinkElement => {
expect($profileLinkElement.text().trim()).to.match(/sid/i)
expect($profileLinkElement.attr('href')).to.match(new RegExp('/settings.*sid', 'i'))
})
})

it.only('Should display User and Logout items', () => {
cy.get('nav a.nav-link.disabled').contains('Logged in as')

cy.get('nav a.nav-link[href="/logout"]').should($logoutLinkElement => {
expect($logoutLinkElement.text().trim()).to.match(/log out/i)
})
})

})
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { NAVIGATION, loadHomepage } from "../../../support/utils/navigation.js";
import { changeProfile } from "../../../support/utils/profiles.js";
import { cleanupSessions} from "../../../support/utils/sessions.js";

describe('FASRC Dashboard - Homepage', () => {
const activePinnedApps = cy.sid.ondemandApplications.filter(l => Cypress.env('fasrc_pinned_apps').includes(l.id))
Cypress.config('baseUrl', NAVIGATION.baseUrl);

before(() => {
loadHomepage()
changeProfile('FASRC')
})

beforeEach(() => {
//DEFAULT SIZE FOR THESE TESTS
cy.viewport(cy.sid.screen.largeWidth, cy.sid.screen.height)
cleanupSessions()
loadHomepage()
})

activePinnedApps.forEach( app => {
it(`FASRC Pinned Apps: ${app.id}`, () => {
// CLICK PINNED APPS
cy.get(`div[data-toggle="launcher-button"] a:contains(${app.name})`).should('be.visible')
cy.get(`div[data-toggle="launcher-button"] a:contains(${app.name})`).click()
// VERIFY APP FORM
cy.get('div[role="main"] h3').should('contain.text', app.name)

})
})

it('Documentation main sections', () => {
cy.get('div img[alt="fas-rc"]').should($imageElement => {
expect($imageElement).to.have.length(1)
expect($imageElement.attr('src')).to.match(/.*rc-logo-text_2017.png$/i)
})
cy.get('div h1').invoke('text').should('match', /Welcome to FAS-RC Cluster/)
cy.get('div h2').eq(0).invoke('text').should('match', /Documentation and Training/)
cy.get('div h2').eq(1).invoke('text').should('match', /System Status and Planned Downtime/)
})

})
Loading