Skip to content

Commit

Permalink
Improve Cypress (#697)
Browse files Browse the repository at this point in the history
  • Loading branch information
ibacher committed Apr 29, 2021
1 parent e72a7a6 commit 2bda2e1
Show file tree
Hide file tree
Showing 41 changed files with 3,504 additions and 9,343 deletions.
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ RUN npm install
# Set environment to production
ENV NODE_ENV production

# Set the environment variables actually used in the image
ENV OCL_API_HOST https://api.qa.openconceptlab.org/
ENV TRADITIONAL_OCL_HOST https://app.qa.openconceptlab.org/
ENV OCL_SIGNUP_URL https://app.qa.openconceptlab.org/#/accounts/signup
ENV BUILD local

# Export them as React environment variables
ENV REACT_APP_OCL_API_HOST $OCL_API_HOST
ENV REACT_APP_TRADITIONAL_OCL_HOST $TRADITIONAL_OCL_HOST
ENV REACT_APP_OCL_SIGNUP_URL $OCL_SIGNUP_URL
ENV REACT_APP_BUILD $BUILD

# Create an optimized build version of the project
RUN npm run build

Expand Down
6 changes: 1 addition & 5 deletions cypress.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
{
"baseUrl": "http://localhost:8080",
"integrationFolder": "./src",
"testFiles": ["**/tests/e2e/*.test.*", "**/tests/e2e/*.spec.*"],
"defaultCommandTimeout": 60000,
"requestTimeout": 60000,
"pageLoadTimeout": 60000,
"supportFile": "cypress/support/index.ts",
"viewportWidth": 1000,
"viewportHeight": 1000,
"video": false
Expand Down
53 changes: 53 additions & 0 deletions cypress/integration/LoginPage.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/// <reference types="cypress" />
/// <reference types="../support" />

describe("Login", () => {
const username = Cypress.env('USERNAME') || 'admin';
const password = Cypress.env('PASSWORD') || 'Admin123';

const submitForm = () => cy.get('#login-form form').submit();

beforeEach(() => {
cy.logout();
cy.visit('/login');
});

it("should allow user to login", () => {
cy.get('#username').type(username);
cy.get('#password').type(password);
cy.get('button[type="submit"]').click();

cy.url().should('not.contain', '/login');
});

it("should allow user to login by pressing enter", () => {
cy.get('#username').type(username);
cy.get('#password').type(password).type('{enter}');

cy.url().should('not.contain', '/login');
});

it("should require a user name to login", () => {
cy.get('#password').type(password);
submitForm();

cy.get('#username').should('have.attr', 'aria-invalid');
});

it("should require a password to login", () => {
cy.get('#username').type(username);
submitForm();

cy.get('#password').should('have.attr', 'aria-invalid');
});

it("should display an error with invalid credentials", () => {
cy.get('#username').type('badusername');
cy.get('#password').type('badpassword');
submitForm();

cy.url().should('contain', '/login');

cy.get('[data-testid="login-status-message"]').should("be.visible")
});
});
10 changes: 1 addition & 9 deletions cypress/plugins/index.js → cypress/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,7 @@
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)

const wp = require("@cypress/webpack-preprocessor");

/**
* @type {Cypress.PluginConfig}
*/

module.exports = on => {
const options = {
webpackOptions: require("../webpack.config.js")
};
on("file:preprocessor", wp(options));
};
export default () => {};
26 changes: 0 additions & 26 deletions cypress/support/commands.js

This file was deleted.

90 changes: 90 additions & 0 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import '@testing-library/cypress/add-commands';
import { LOGIN_ACTION, LOGOUT_ACTION } from '../../src/apps/authentication/redux/actionTypes';
import { nanoid } from 'nanoid';
import { getStore } from '../utils';

const apiUrl: string = Cypress.env('API_URL') || 'http://localhost:8000';

Cypress.Commands.add('login', (
username = Cypress.env('USERNAME') || 'admin',
password = Cypress.env('PASSWORD') || 'Admin123') => {

const store = getStore();

// already logged in
if (store.getState().auth.profile?.username === username &&
store.getState().auth.token) {
return;
}

const token = Cypress.env('TOKEN');

if (!token) {
cy.request({
method: 'POST',
url: `${apiUrl}/users/login`,
body: {
"username": username,
"password": password
}
}).then((response) => {
store
.dispatch({ type: LOGIN_ACTION, payload: { token: response.body['token'] } });
});
} else {
store.dispatch({ type: LOGIN_ACTION, payload: { token: token} });
}

// delay until we've added the token to the store
while (!store.getState().auth.isLoggedIn && !store.getState().auth.token);
});

Cypress.Commands.add('logout', () => {
const store = getStore();
if (typeof store === 'undefined') {
return;
}

store.dispatch({ type: LOGOUT_ACTION });
// delay until we're actually logged out
while (store.getState().auth.isLoggedIn);
});

Cypress.Commands.add('createDictionary', (
username = Cypress.env('USERNAME') || 'admin',
dictionary = `TD-${nanoid()}`) => {

cy.request(`${apiUrl}/users/${username}/collections/${dictionary}`)
.then((response) => {
if (response.status !== 200) {
cy.request({
method: 'POST',
headers: {
'Authorization': `Token ${getStore().getState().auth.token}`
},
url: `${apiUrl}/users/${username}/collections/`,
body: {
"short_code": `${dictionary}`,
"name": "Test Dictionary",
"public_access": "None"
}
});
}
})

return cy.wrap(dictionary);
});

Cypress.Commands.add('deleteDictionary', (
dictionary,
username = Cypress.env('USERNAME') || 'admin'
) => {

cy.request({
method: 'DELETE',
headers: {
'Authorization': `Token ${getStore().getState().auth.token}`
},
url: `${apiUrl}/usrs/${username}/collections/${dictionary}`
});
});
9 changes: 5 additions & 4 deletions cypress/support/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

declare namespace Cypress {
interface Chainable<Subject> {
runAndAwait(callable: Function, method?: String, addArtificialWait?: boolean): Chainable<any>
selectByLabelText(labelText: string, item: string): Chainable<any>
selectBySelector(selector: string, item: string): Chainable<any>
login(username?: string, password?: string): Chainable<Subject>
logout(): Chainable<Subject>
createDictionary(username?: string, dictionary?: string): Chainable<string>
deleteDictionary(dictionary: string, username?: string): Chainable<Subject>
}
}
}
2 changes: 0 additions & 2 deletions cypress/support/index.js

This file was deleted.

1 change: 1 addition & 0 deletions cypress/support/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './commands';
7 changes: 3 additions & 4 deletions cypress/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
"compilerOptions": {
"strict": true,
"baseUrl": "../node_modules",
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress", "@types/testing-library__cypress"]
"isolatedModules": false,
"types": [ "cypress", "@testing-library/cypress" ]
},
"include": [
"**/tests/e2e/*.ts"
"./**/*.ts"
]
}
6 changes: 6 additions & 0 deletions cypress/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Store } from 'redux';
import { AppState } from '../src/redux/types';

export const getStore = (): Store<AppState> => window.store;
export const currentUser = (): string =>
getStore().getState().auth.profile?.username || 'admin'
23 changes: 0 additions & 23 deletions cypress/webpack.config.js

This file was deleted.

6 changes: 3 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ services:
build:
context: .
environment:
- OCL_API_HOST=${OCL_API_HOST:-https://api.qa.openconceptlab.org/}
- TRADITIONAL_OCL_HOST=${TRADITIONAL_OCL_HOST:-https://qa.openconceptlab.org}
- OCL_SIGNUP_URL=${OCL_SIGNUP_URL:-https://app.qa.openconceptlab.org/#/accounts/signup}
- REACT_APP_OCL_API_HOST=${OCL_API_HOST:-https://api.qa.openconceptlab.org/}
- REACT_APP_TRADITIONAL_OCL_HOST=${TRADITIONAL_OCL_HOST:-https://qa.openconceptlab.org}
- REACT_APP_OCL_SIGNUP_URL=${OCL_SIGNUP_URL:-https://app.qa.openconceptlab.org/#/accounts/signup}
- ENVIRONMENT=${ENVIRONMENT:-dev}
ports:
- 8080:80
Expand Down
Loading

0 comments on commit 2bda2e1

Please sign in to comment.