Skip to content

Commit

Permalink
Cypress based E2E tests (#3019)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrieldutra authored and arikfr committed Nov 7, 2018
1 parent bf6a09c commit 7d601cb
Show file tree
Hide file tree
Showing 17 changed files with 265 additions and 70 deletions.
71 changes: 21 additions & 50 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,26 @@ jobs:
- run: npm install
- run: npm run bundle
- run: npm test
frontend-e2e-tests:
environment:
COMPOSE_FILE: .circleci/docker-compose.cypress.yml
COMPOSE_PROJECT_NAME: cypress
docker:
- image: circleci/node:8
steps:
- setup_remote_docker
- checkout
- run:
name: Install npm dependencies
command: npm install
- run:
name: Setup Redash server
command: |
npm run cypress:server start-ci
docker-compose run cypress node ./cypress/cypress-server.js setup
- run:
name: Execute Cypress tests
command: docker-compose run cypress ./node_modules/.bin/cypress run
build-tarball:
docker:
- image: circleci/node:8
Expand All @@ -77,64 +97,15 @@ jobs:
- run: docker login -u $DOCKER_USER -p $DOCKER_PASS
- run: docker build -t redash/redash:$(.circleci/docker_tag) .
- run: docker push redash/redash:$(.circleci/docker_tag)
integration-tests:
working_directory: ~/redash
machine: true
environment:
REDASH_SERVER_URL : "http://127.0.0.1:5000/"
DOCKER_IMAGE: mozilla/redash-ui-tests
steps:
- checkout
- run:
name: Install Docker Compose
command: |
set -x
pip install --upgrade pip
pip install docker-compose>=1.18
docker-compose --version
- run:
name: Pull redash images
command: |
set -x
docker-compose -f docker-compose.yml up --no-start
sleep 10
- run:
name: Pull redash-ui-tests
command: docker pull "${DOCKER_IMAGE}":latest
- run:
name: Setup redash instance
command: |
set -x
docker-compose run --rm --user root server create_db
docker-compose run --rm postgres psql -h postgres -U postgres -c "create database tests"
docker-compose run --rm --user root server /app/manage.py users create_root root@example.com "rootuser" --password "IAMROOT" --org default
docker-compose run --rm --user root server /app/manage.py ds new "ui-tests" --type "url" --options '{"title": "uitests"}'
docker-compose run -d -p 5000:5000 --user root server
docker-compose start postgres
docker-compose run --rm --user root server npm install
docker-compose run --rm --user root server npm run bundle
docker-compose run --rm --user root server npm run build
- run:
name: Run tests
command: |
set -x
docker run --net="host" --env REDASH_SERVER_URL="${REDASH_SERVER_URL}" "${DOCKER_IMAGE}"
- store_artifacts:
path: report.html
workflows:
version: 2
# integration_tests:
# jobs:
# - integration-tests:
# filters:
# branches:
# only: master
build:
jobs:
- python-flake8-tests
- legacy-python-flake8-tests
- backend-unit-tests
- frontend-unit-tests
- frontend-e2e-tests
- build-tarball:
requires:
- backend-unit-tests
Expand Down
43 changes: 43 additions & 0 deletions .circleci/docker-compose.cypress.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
version: '2'
services:
server:
build: ../
command: dev_server
depends_on:
- postgres
- redis
ports:
- "5000:5000"
environment:
PYTHONUNBUFFERED: 0
REDASH_LOG_LEVEL: "INFO"
REDASH_REDIS_URL: "redis://redis:6379/0"
REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
worker:
build: ../
command: scheduler
depends_on:
- server
environment:
PYTHONUNBUFFERED: 0
REDASH_LOG_LEVEL: "INFO"
REDASH_REDIS_URL: "redis://redis:6379/0"
REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
QUEUES: "queries,scheduled_queries,celery"
WORKERS_COUNT: 2
cypress:
build:
context: ../
dockerfile: Dockerfile.cypress
depends_on:
- server
- worker
environment:
CYPRESS_baseUrl: "http://server:5000"
redis:
image: redis:3.0-alpine
restart: unless-stopped
postgres:
image: postgres:9.5.6-alpine
command: "postgres -c fsync=off -c full_page_writes=off -c synchronous_commit=OFF"
restart: unless-stopped
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ node_modules
.sass-cache
npm-debug.log

cypress/screenshots
cypress/videos
10 changes: 10 additions & 0 deletions Dockerfile.cypress
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM cypress/browsers:chrome67

WORKDIR /usr/src/app

RUN npm install cypress > /dev/null

COPY cypress /usr/src/app/cypress
COPY cypress.json /usr/src/app/cypress.json

RUN ./node_modules/.bin/cypress verify
3 changes: 2 additions & 1 deletion client/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
module.exports = {
root: true,
extends: ["airbnb", "plugin:jest/recommended"],
plugins: ["jest"],
plugins: ["jest", "cypress"],
settings: {
"import/resolver": "webpack"
},
parser: "babel-eslint",
env: {
"jest/globals": true,
"cypress/globals": true,
"browser": true,
"node": true
},
Expand Down
2 changes: 1 addition & 1 deletion client/app/components/app-header/app-header.html
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
<!--<a href="users" title="Settings"><i class="fa fa-cog"></i></a>-->
<!--</li>-->
<li class="dropdown" uib-dropdown>
<a href="#" class="dropdown-toggle dropdown--profile" uib-dropdown-toggle>
<a href="#" class="dropdown-toggle dropdown--profile" uib-dropdown-toggle data-cy="dropdown-profile">
<img ng-src="{{ $ctrl.currentUser.profile_image_url }}" class="profile__image--navbar" width="20"/>
<span class="dropdown--profile__username" ng-bind="$ctrl.currentUser.name"></span> <span
class="caret caret--nav"></span></a>
Expand Down
6 changes: 4 additions & 2 deletions client/app/components/dynamic-form.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
<div class="form-group" ng-class='{"has-error": (inner.input | showError), "required": field.property.required}' ng-form="inner" ng-repeat="field in fields">
<label ng-if="field.property.type !== 'checkbox'" class="control-label">{{field.property.title || field.name | toHuman}}</label>
<input name="input" type="{{field.property.type}}" class="form-control" ng-model="target.options[field.name]" ng-required="field.property.required"
ng-if="field.property.type !== 'file' && field.property.type !== 'checkbox'" accesskey="tab" placeholder="{{field.property.default}}">
ng-if="field.property.type !== 'file' && field.property.type !== 'checkbox'" accesskey="tab" placeholder="{{field.property.default}}"
data-cy="{{field.property.title || field.name | toHuman}}">

<label ng-if="field.property.type=='checkbox'">
<input name="input" type="{{field.property.type}}" ng-model="target.options[field.name]" ng-required="field.property.required"
ng-if="field.property.type !== 'file'" accesskey="tab" placeholder="{{field.property.default}}">
ng-if="field.property.type !== 'file'" accesskey="tab" placeholder="{{field.property.default}}"
data-cy="{{field.property.title || field.name | toHuman}}">
{{field.property.title || field.name | toHuman}}
</label>

Expand Down
3 changes: 3 additions & 0 deletions cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"baseUrl": "http://localhost:5000"
}
52 changes: 52 additions & 0 deletions cypress/cypress-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* eslint-disable import/no-extraneous-dependencies, no-console */
const { execSync } = require('child_process');
const { post } = require('request');

function execSetup() {
console.log('Running setup...');

const setupData = {
name: 'Example Admin',
email: 'admin@redash.io',
password: 'password',
org_name: 'Redash',
};

const baseUrl = process.env.CYPRESS_baseUrl || 'http://localhost:5000';

post(baseUrl + '/setup', { formData: setupData });
}

function startServer() {
console.log('Starting the server...');

execSync('docker-compose -p cypress build --build-arg skip_ds_deps=true', { stdio: 'inherit' });
execSync('docker-compose -p cypress up -d', { stdio: 'inherit' });
execSync('docker-compose -p cypress run server create_db', { stdio: 'inherit' });
}

function stopServer() {
console.log('Stopping the server...');
execSync('docker-compose -p cypress down', { stdio: 'inherit' });
}

const command = process.argv[2];

switch (command) {
case 'start':
startServer();
execSetup();
break;
case 'start-ci':
startServer();
break;
case 'setup':
execSetup();
break;
case 'stop':
stopServer();
break;
default:
console.log('Usage: npm run cypress:server start|stop');
break;
}
19 changes: 19 additions & 0 deletions cypress/integration/data-source/create_data_source_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
describe('Create Data Source', () => {
beforeEach(() => {
cy.login();
cy.visit('/data_sources');
});

it('creates a new PostgreSQL data source', () => {
cy.contains('New Data Source').click();
cy.contains('PostgreSQL').click();

cy.get('[name=targetName]').type('Redash');
cy.get('[data-cy=Host]').type('{selectall}localhost');
cy.get('[data-cy=User]').type('postgres');
cy.get('[data-cy=Password]').type('postgres');
cy.get('[data-cy="Database Name"]').type('postgres{enter}');

cy.contains('Saved.');
});
});
24 changes: 24 additions & 0 deletions cypress/integration/user/login_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
describe('Login', () => {
beforeEach(() => {
cy.visit('/login');
});

it('greets the user', () => {
cy.contains('h3', 'Login to Redash');
});

it('shows message on failed login', () => {
cy.get('#inputEmail').type('admin@redash.io');
cy.get('#inputPassword').type('wrongpassword{enter}');

cy.get('.alert').should('contain', 'Wrong email or password.');
});

it('navigates to homepage with successful login', () => {
cy.get('#inputEmail').type('admin@redash.io');
cy.get('#inputPassword').type('password{enter}');

cy.title().should('eq', 'Redash');
cy.contains('Example Admin');
});
});
13 changes: 13 additions & 0 deletions cypress/integration/user/logout_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
describe('Logout', () => {
beforeEach(() => {
cy.login();
cy.visit('/');
});

it('shows login page after logout', () => {
cy.get('[data-cy=dropdown-profile]').click();
cy.contains('Log out').click();

cy.title().should('eq', 'Login to Redash');
});
});
1 change: 1 addition & 0 deletions cypress/plugins/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = () => {};
15 changes: 15 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Cypress.Commands.add('login', () => {
const users = {
admin: {
email: 'admin@redash.io',
password: 'password',
},
};

cy.request({
url: '/login',
method: 'POST',
form: true,
body: users.admin,
});
});
1 change: 1 addition & 0 deletions cypress/support/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './commands';
Loading

0 comments on commit 7d601cb

Please sign in to comment.