Skip to content

Commit

Permalink
Merge pull request #2826 from Northeastern-Electric-Racing/New-Change…
Browse files Browse the repository at this point in the history
…-Request-System-Tests

New Change Request System Tests
  • Loading branch information
Peyton-McKee committed Sep 8, 2024
2 parents 7725288 + 94d1982 commit 4e5ec12
Show file tree
Hide file tree
Showing 11 changed files with 230 additions and 17 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"eslint": "^7.0.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-cypress": "latest",
"eslint-plugin-prettier": "^4.2.1",
"prettier": "^2.0.5",
"rimraf": "^3.0.2",
Expand All @@ -76,7 +77,8 @@
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
"react-app/jest",
"plugin:cypress/recommended"
],
"rules": {
"guard-for-in": "error",
Expand Down Expand Up @@ -136,7 +138,6 @@
"public",
"lib",
"dist",
"system-tests/**",
"scripts"
]
},
Expand Down
4 changes: 3 additions & 1 deletion src/backend/src/utils/reimbursement-requests.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,9 @@ export const validateUserEditRRPermissions = async (
reimbursementRequest.recipientId !== user.userId ||
reimbursementRequest.reimbursementStatuses.some((status) => status.type === ReimbursementStatusType.PENDING_FINANCE)
)
throw new AccessDeniedException('Only the creator or finance team can edit a reimbursement request. A request that has been pending finance cannot be edited.');
throw new AccessDeniedException(
'Only the creator or finance team can edit a reimbursement request. A request that has been pending finance cannot be edited.'
);
}
};

Expand Down
9 changes: 7 additions & 2 deletions system-tests/cypress.config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
module.exports = {
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
on('task', {
log(message) {
console.log(message);
return null;
}
});
}
},
env: {
base_url: 'http://127.0.0.1:3000'
base_url: 'http://localhost:3000'
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
CHANGE_REQUEST_TABLE
} from '../../utils/selectors.utils';

import { LENGTH_GREATER_THAN, INCLUDE } from '../../utils/cypress-actions.utils';

// To learn more about how Cypress works and
// what makes it such an awesome testing tool,
// please read our getting started guide:
Expand All @@ -22,26 +24,26 @@ describe('Change Request Overview', () => {

it('Change Requests to Review Should Display At Least One CR', () => {
// We use the `cy.get()` command to get all elements that match the selector.
cy.get(CR_ROW('Change Requests To Review')).children().should('have.length.greaterThan', 0);
cy.get(CR_ROW('Change Requests To Review')).children().should(LENGTH_GREATER_THAN, 0);
});

it('My Un-reviewed Change Requests Should Display At Least Two CRs', () => {
cy.get(CR_ROW('My Un-reviewed Change Requests')).children().should('have.length.greaterThan', 1);
cy.get(CR_ROW('My Un-reviewed Change Requests')).children().should(LENGTH_GREATER_THAN, 1);
});

it('My Aproved Change Requests Should Display At Least Three CRs', () => {
cy.get(CR_ROW('My Approved Change Requests')).children().should('have.length.greaterThan', 2);
cy.get(CR_ROW('My Approved Change Requests')).children().should(LENGTH_GREATER_THAN, 2);
});

it('New Change Request Button Redirects to New Change Requeest Form', () => {
cy.contains(NEW_CHANGE_REQUEST_BUTTON).click();

cy.url().should('include', '/change-requests/new');
cy.url().should(INCLUDE, '/change-requests/new');
});

it('Can Switch to All Change Requests Table', () => {
cy.contains(ALL_CHANGE_REQUESTS_TAB).click();
cy.url().should('include', '/change-requests/all');
cy.url().should(INCLUDE, '/change-requests/all');
cy.get(CHANGE_REQUEST_TABLE);
});
});
43 changes: 43 additions & 0 deletions system-tests/cypress/e2e/change-requests/new-change-request.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/// <reference types="cypress" />
import {
PROJECT_OR_WORKPACKAGE_PLACEHOLDER,
ISSUE_BUTTON,
DEFINITION_CHANGE_BUTTON,
OTHER_BUTTON,
WHAT_DESCRIPTOR,
EXPLAIN_TEXT_BOX_PLACEHOLDER,
WHY_DESCRIPTOR,
WHY_DELETE_OPTION,
WHY_TYPE_OPTION,
WHY_EXPLAIN_TEXT_BOX,
ADD_PROPOSED_SOLUTION_BUTTON
} from '../../utils/selectors.utils';
import { VISIBLE, LENGTH_GREATER_THAN, EXIST } from '../../utils/cypress-actions.utils';
import { createChangeRequest } from '../../utils/change-request.utils.cy';

describe('New Change Request', () => {
beforeEach(() => {
cy.login('Thomas Emrax', '/change-requests/new');
});

it('Displays all new CR Fields', () => {
cy.get(PROJECT_OR_WORKPACKAGE_PLACEHOLDER).should(VISIBLE);
cy.contains(ISSUE_BUTTON).should(VISIBLE);
cy.contains(DEFINITION_CHANGE_BUTTON).should(VISIBLE);
cy.contains(OTHER_BUTTON).should(VISIBLE);
cy.contains(WHAT_DESCRIPTOR).should(VISIBLE);
cy.contains(WHAT_DESCRIPTOR).parent().find(EXPLAIN_TEXT_BOX_PLACEHOLDER);
cy.contains(WHY_DESCRIPTOR).should(VISIBLE);
cy.get(WHY_TYPE_OPTION(0)).should(EXIST);
cy.get(WHY_EXPLAIN_TEXT_BOX(0)).should(EXIST);
cy.get(WHY_DELETE_OPTION).should(VISIBLE);
cy.get(WHY_DELETE_OPTION).should(LENGTH_GREATER_THAN, 0);
cy.contains(ADD_PROPOSED_SOLUTION_BUTTON).should(VISIBLE);
});

[{}].forEach((args) => {
it('Creating a Change Request Works', () => {
createChangeRequest(args);
});
});
});
2 changes: 1 addition & 1 deletion system-tests/cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { LOADING_INDICATOR, LOGIN_ICON, DEV_LOGIN_TEXT } from '../utils/selector
//
//
// -- This is a parent command --
Cypress.Commands.add('login', (username, redirect = '/home') => {
Cypress.Commands.add('login', (username = 'Thomas Emrax', redirect = '/home') => {
cy.visit(Cypress.env('base_url') + '/login');
cy.waitForLoading();
cy.contains(DEV_LOGIN_TEXT).parent().click();
Expand Down
Empty file.
101 changes: 101 additions & 0 deletions system-tests/cypress/utils/change-request.utils.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/* eslint-disable no-undef */
import {
PROPOSED_SOLUTION_BUDGET_INPUT,
PROPOSED_SOLUTION_DESCRIPTION_INPUT,
PROPOSED_SOLUTION_SCOPE_INPUT,
PROPOSED_SOLUTION_TIMELINE_INPUT,
DIALOG,
ADD_BUTTON,
PROJECT_OR_WORKPACKAGE_PLACEHOLDER,
EXPLAIN_TEXT_BOX_PLACEHOLDER,
WHAT_DESCRIPTOR,
WHY_EXPLAIN_TEXT_BOX,
ADD_PROPOSED_SOLUTION_BUTTON,
SUBMIT_BUTTON,
CR_ROW,
WHY_TYPE_OPTION,
ADD_REASON,
ACTIONS_BUTTON,
ACTIONS_BUTTON_DELETE,
CONFIRM_DELETE_TEXT_INPUT
} from './selectors.utils';
import { INCLUDE } from './cypress-actions.utils';

const createProposedSolution = ({
description = 'Test Description',
scopeImpact = 'Test Scope',
budgetImpact = 1,
timelineImpact = 2
}) => {
cy.get(PROPOSED_SOLUTION_DESCRIPTION_INPUT).type(description);
cy.get(PROPOSED_SOLUTION_SCOPE_INPUT).type(scopeImpact);
cy.get(PROPOSED_SOLUTION_BUDGET_INPUT).type(budgetImpact);
cy.get(PROPOSED_SOLUTION_TIMELINE_INPUT).type(timelineImpact);
cy.get(DIALOG).find('button').contains(ADD_BUTTON).click();
};

export const createChangeRequest = ({
wbsTitle = '0.1.0 - Impact Attenuator',
what = 'test what',
type = 'ISSUE',
whys = [
{
type: 'OTHER',
description: 'test why'
}
],
psArguments = [
{
description: 'Test Description',
scopeImpact: 'Test Scope',
budgetImpact: 1,
timelineImpact: 2
}
]
}) => {
cy.get(PROJECT_OR_WORKPACKAGE_PLACEHOLDER).click();
cy.contains(wbsTitle).click();
cy.contains(WHAT_DESCRIPTOR).parent().find(EXPLAIN_TEXT_BOX_PLACEHOLDER).type(what);
cy.contains(type).click();
whys.forEach((why, index) => {
cy.get(WHY_TYPE_OPTION(index)).parent().click();
cy.get('li')
.contains(new RegExp(`^${why.type}$`, 'g'))
.click();
cy.get(WHY_EXPLAIN_TEXT_BOX(index)).type(why.description);
if (index !== whys.length - 1) {
cy.contains(ADD_REASON).click();
}
});

cy.contains(ADD_PROPOSED_SOLUTION_BUTTON).click();
psArguments.forEach((argument, index) => {
createProposedSolution(argument);
if (index !== psArguments.length - 1) {
cy.contains(ADD_PROPOSED_SOLUTION_BUTTON).click();
}
});

cy.contains(SUBMIT_BUTTON).click();
cy.url().should(INCLUDE, '/change-requests');
cy.get(CR_ROW('My Un-reviewed Change Requests')).children().first().find('h6').contains('Change Request').click();

cy.contains(what);
whys.forEach((why) => {
cy.contains(why.description);
cy.contains(why.type);
});
psArguments.forEach((argument) => {
cy.contains(argument.budgetImpact);
cy.contains(argument.description);
cy.contains(argument.scopeImpact);
cy.contains(argument.timelineImpact + ' weeks');
});

const crId = 21; // Get this value from the UI. Could not figure out the CRID for some reason

cy.contains(ACTIONS_BUTTON).click();
cy.contains(ACTIONS_BUTTON_DELETE).click();
cy.get(CONFIRM_DELETE_TEXT_INPUT).type(crId);
cy.contains(SUBMIT_BUTTON).click();
};
16 changes: 16 additions & 0 deletions system-tests/cypress/utils/cypress-actions.utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const base = {
EXIST: 'exist',
VISIBLE: 'be.visible',
NOT: 'not',
LENGTH_GREATER_THAN: 'have.length.greaterThan',
INCLUDE: 'include'
};

const built = {
NOT_EXIST: base.NOT + '.' + base.EXIST,
NOT_BE_VISIBLE: base.NOT + '.' + base.VISIBLE
};

const ACTIONS = { ...base, ...built };

export default ACTIONS;
41 changes: 36 additions & 5 deletions system-tests/cypress/utils/selectors.utils.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,40 @@
export default {
LOADING_INDICATOR: '[data-testid="loader"]',
LOGIN_ICON: '[data-testid="LoginIcon"]',
const placeholderBuilder = (value) => `[placeholder="${value}"]`;

const testIdBuilder = (value) => `[data-testid="${value}"]`;

const idBuilder = (value) => `[id="${value}"]`;

const SELECTORS = {
LOADING_INDICATOR: testIdBuilder('loader'),
LOGIN_ICON: testIdBuilder('LoginIcon'),
DEV_LOGIN_TEXT: 'Local Dev User',
CR_ROW: (title) => `[data-testid="${title}crRow"]`,
CR_ROW: (title) => testIdBuilder(`${title}crRow`),
NEW_CHANGE_REQUEST_BUTTON: 'New Change Request',
ALL_CHANGE_REQUESTS_TAB: 'All Change Requests',
CHANGE_REQUEST_TABLE: '[data-testid="Change Request Table"]'
CHANGE_REQUEST_TABLE: testIdBuilder('Change Request Table'),
PROJECT_OR_WORKPACKAGE_PLACEHOLDER: placeholderBuilder('Select a project or work package'),
ISSUE_BUTTON: 'ISSUE',
DEFINITION_CHANGE_BUTTON: 'DEFINITION_CHANGE',
OTHER_BUTTON: 'OTHER',
WHAT_DESCRIPTOR: 'What needs to be changed',
WHY_DESCRIPTOR: 'Why does this need to be changed',
WHY_TYPE_OPTION: (index) => `[name="why.${index}.type"]`,
WHY_EXPLAIN_TEXT_BOX: (index) => idBuilder(`why.${index}.explain-input`),
ADD_REASON: 'ADD REASON',
WHY_DELETE_OPTION: testIdBuilder('DeleteIcon'),
EXPLAIN_TEXT_BOX_PLACEHOLDER: placeholderBuilder('Explain *'),
ADD_PROPOSED_SOLUTION_BUTTON: '+ Add Solution',
PROPOSED_SOLUTION_DESCRIPTION_INPUT: idBuilder('description-input'),
PROPOSED_SOLUTION_SCOPE_INPUT: idBuilder('scopeImpact-input'),
PROPOSED_SOLUTION_BUDGET_INPUT: idBuilder('budgetImpact-input'),
PROPOSED_SOLUTION_TIMELINE_INPUT: idBuilder('timelineImpact-input'),
ADD_BUTTON: new RegExp('^Add$', 'g'),
SUBMIT_BUTTON: new RegExp('^Submit$', 'g'),
DIALOG: '[role="dialog"]',
ACTIONS_BUTTON: 'Actions',
ACTIONS_BUTTON_DELETE: 'Delete',
CONFIRM_DELETE_TEXT_INPUT: idBuilder('identifier-input'),
CHANGE_REQUEST_TITLE: new RegExp('Change Request #\\d+$')
};

export default SELECTORS;
14 changes: 13 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9274,6 +9274,17 @@ __metadata:
languageName: node
linkType: hard

"eslint-plugin-cypress@npm:latest":
version: 3.5.0
resolution: "eslint-plugin-cypress@npm:3.5.0"
dependencies:
globals: ^13.20.0
peerDependencies:
eslint: ">=7"
checksum: b13b3e6c0074ab4246f15072f1c4877ffff0b14a891b0e3714cb13b449515446e814df29cbcf63b60dc09a8d301271f1434ded18398f9aa3f11005a3899bc265
languageName: node
linkType: hard

"eslint-plugin-flowtype@npm:^5.2.0":
version: 5.10.0
resolution: "eslint-plugin-flowtype@npm:5.10.0"
Expand Down Expand Up @@ -10223,6 +10234,7 @@ __metadata:
eslint: ^7.0.0
eslint-config-prettier: ^8.5.0
eslint-config-react-app: ^7.0.1
eslint-plugin-cypress: latest
eslint-plugin-prettier: ^4.2.1
mitt: ^3.0.1
prettier: ^2.0.5
Expand Down Expand Up @@ -10782,7 +10794,7 @@ __metadata:
languageName: node
linkType: hard

"globals@npm:^13.6.0, globals@npm:^13.9.0":
"globals@npm:^13.20.0, globals@npm:^13.6.0, globals@npm:^13.9.0":
version: 13.24.0
resolution: "globals@npm:13.24.0"
dependencies:
Expand Down

0 comments on commit 4e5ec12

Please sign in to comment.