diff --git a/.eslintrc b/.eslintrc
index 43cd6b850..699df6366 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -30,6 +30,7 @@
"no-unused-vars": "warn",
"no-extra-semi": "warn",
"quotes": ["warn", "single", {"avoidEscape": true, "allowTemplateLiterals": true}], // Checks for single quote usage where possible
+ "jsx-quotes": ["warn", "prefer-single"],
"react-hooks/rules-of-hooks": "error", // Checks rules of Hooks
"react-hooks/exhaustive-deps": "warn", // Checks effect dependencies
"react/jsx-filename-extension": [
@@ -78,8 +79,8 @@
]
},
"extends": [
- "eslint:recommended",
- "plugin:react/recommended",
+ "eslint:recommended",
+ "plugin:react/recommended",
"plugin:@typescript-eslint/eslint-recommended"
]
}
diff --git a/cypress/component/DAC/admin.json b/cypress/component/DAC/admin.json
new file mode 100644
index 000000000..eb012674b
--- /dev/null
+++ b/cypress/component/DAC/admin.json
@@ -0,0 +1,15 @@
+{
+ "userId": 2,
+ "displayName": "Admin",
+ "institution": {
+ "id": 150,
+ "name": "The Broad Institute of MIT and Harvard"
+ },
+ "roles": [
+ {
+ "userId": 2,
+ "roleId": 4,
+ "name": "Admin"
+ }
+ ]
+}
diff --git a/cypress/component/DAC/chair.json b/cypress/component/DAC/chair.json
new file mode 100644
index 000000000..52b268236
--- /dev/null
+++ b/cypress/component/DAC/chair.json
@@ -0,0 +1,16 @@
+{
+ "userId": 1,
+ "displayName": "Chairperson",
+ "institution": {
+ "id": 150,
+ "name": "The Broad Institute of MIT and Harvard"
+ },
+ "roles": [
+ {
+ "userId": 1,
+ "roleId": 2,
+ "name": "Chairperson",
+ "dacId": 1
+ }
+ ]
+}
diff --git a/cypress/component/DAC/daas.json b/cypress/component/DAC/daas.json
new file mode 100644
index 000000000..66d14b316
--- /dev/null
+++ b/cypress/component/DAC/daas.json
@@ -0,0 +1,21 @@
+[
+ {
+ "daaId": 1,
+ "createUserId": 3479,
+ "createDate": 1722023675199,
+ "updateUserId": 3479,
+ "updateDate": 1722023675199,
+ "initialDacId": 1,
+ "file": {
+ "fileStorageObjectId": 1,
+ "entityId": "1",
+ "fileName": "DUOS_Uniform_Data_Access_Agreement.pdf",
+ "category": "dataAccessAgreement",
+ "mediaType": "application/octet-stream",
+ "createUserId": 3479,
+ "createDate": 1722023675199,
+ "deleted": false
+ },
+ "broadDaa": true
+ }
+]
diff --git a/cypress/component/DAC/dac.json b/cypress/component/DAC/dac.json
new file mode 100644
index 000000000..e501436df
--- /dev/null
+++ b/cypress/component/DAC/dac.json
@@ -0,0 +1,67 @@
+{
+ "dacId": 1,
+ "name": "Test DAC",
+ "description": "Test DAC",
+ "createDate": "Oct 6, 2020",
+ "updateDate": "Jun 27, 2024",
+ "chairpersons": [
+ {
+ "userId": 1,
+ "email": "test@broadinstitute.org",
+ "displayName": "Chairperson",
+ "createDate": 1704827256598,
+ "roles": [
+ {
+ "userId": 1,
+ "roleId": 2,
+ "name": "Chairperson",
+ "dacId": 1
+ }
+ ],
+ "emailPreference": true,
+ "institutionId": 150,
+ "eraCommonsId": "test"
+ }
+ ],
+ "members": [
+ {
+ "userId": 2,
+ "email": "test2@broadinstitute.org",
+ "displayName": "Member",
+ "createDate": 1704827256598,
+ "roles": [
+ {
+ "userId": 2,
+ "roleId": 1,
+ "name": "Member",
+ "dacId": 1
+ }
+ ],
+ "emailPreference": true,
+ "institutionId": 150,
+ "eraCommonsId": "test"
+ }
+ ],
+ "electionIds": [],
+ "datasetIds": [],
+ "email": "grushton@broadinstitute.org",
+ "associatedDaa": {
+ "daaId": 1,
+ "createUserId": 5146,
+ "createDate": 1713386755554,
+ "updateUserId": 5146,
+ "updateDate": 1713386755554,
+ "initialDacId": 8,
+ "file": {
+ "fileStorageObjectId": 216,
+ "entityId": 1,
+ "fileName": "test_daa.txt",
+ "category": "dataAccessAgreement",
+ "mediaType": "application/octet-stream",
+ "createUserId": 5146,
+ "createDate": 1713386755554,
+ "deleted": false
+ },
+ "broadDaa": true
+ }
+}
diff --git a/cypress/component/DAC/dacUsers.spec.tsx b/cypress/component/DAC/dacUsers.spec.tsx
new file mode 100644
index 000000000..1daa3afd3
--- /dev/null
+++ b/cypress/component/DAC/dacUsers.spec.tsx
@@ -0,0 +1,36 @@
+/* eslint-disable no-undef,no-console */
+
+import React from 'react';
+import {mount} from 'cypress/react';
+import {DacUsers} from '../../../src/pages/manage_dac/DacUsers.jsx';
+import dac from './dac.json';
+
+describe('Dac User Tests', () => {
+ it('Shows a DAC Members', () => {
+ cy.viewport(600, 800);
+ const props = {
+ dac: dac,
+ removeButton: true,
+ removeHandler: () => { console.log('Remove Button Clicked'); }
+ };
+ mount();
+ dac.chairpersons.forEach(u => {
+ cy.contains(u.displayName);
+ cy.get('[data-cy="remove_button_' + u.userId + '"]').click().then(() => {
+ cy.contains('Pending Removal');
+ });
+ cy.get('[data-cy="remove_button_' + u.userId + '"]').click().then(() => {
+ cy.get('Pending Removal').should('not.exist');
+ });
+ });
+ dac.members.forEach(u => {
+ cy.contains(u.displayName);
+ cy.get('[data-cy="remove_button_' + u.userId + '"]').click().then(() => {
+ cy.contains('Pending Removal');
+ });
+ cy.get('[data-cy="remove_button_' + u.userId + '"]').click().then(() => {
+ cy.get('Pending Removal').should('not.exist');
+ });
+ });
+ });
+});
diff --git a/cypress/component/DAC/editDac.spec.tsx b/cypress/component/DAC/editDac.spec.tsx
new file mode 100644
index 000000000..6ea83af6d
--- /dev/null
+++ b/cypress/component/DAC/editDac.spec.tsx
@@ -0,0 +1,119 @@
+/* eslint-disable no-undef */
+
+import React from 'react';
+import {mount} from 'cypress/react';
+import {DAA} from '../../../src/libs/ajax/DAA';
+import {DAC} from '../../../src/libs/ajax/DAC';
+import {Storage} from '../../../src/libs/storage';
+import EditDac from '../../../src/pages/manage_dac/EditDac';
+import {BrowserRouter} from 'react-router-dom';
+import admin from './admin.json';
+import chair from './chair.json';
+import daas from './daas.json';
+import dac from './dac.json';
+import {setUserRoleStatuses} from '../../../src/libs/utils';
+
+// It's necessary to wrap components that contain `Link` components
+const WrappedEditDac = (props) => {
+ return ;
+};
+
+describe('EditDAC Tests', () => {
+
+ Cypress._.each([admin, chair], (user) => {
+ it('Edit DAC page should load for ' + user.displayName, () => {
+ cy.viewport(600, 800);
+ cy.stub(Storage, 'getCurrentUser').returns(user);
+ cy.stub(DAC, 'get').returns(dac);
+ cy.stub(DAA, 'getDaas').returns([]);
+ const props = {match: {params: {dacId: dac.dacId}}};
+ mount(WrappedEditDac(props));
+ cy.contains(dac.name).should('exist');
+ cy.get('[data-cy="dac_name"]').should('not.be.disabled');
+ cy.get('[data-cy="dac_description"]').should('not.be.disabled');
+ cy.get('[data-cy="dac_email"]').should('not.be.disabled');
+ cy.get('[data-cy="btn_save"]').should('not.be.disabled');
+ cy.get('[data-cy="btn_cancel"]').should('not.be.disabled');
+ cy.get('[data-cy="daa_radio"]').should('not.be.disabled');
+ cy.get('[data-cy="daa_upload_button"]').should('not.be.disabled');
+ });
+ });
+
+ it('Admins can create a DAC', () => {
+ cy.viewport(600, 600);
+ Storage.clearStorage();
+ setUserRoleStatuses(admin, Storage);
+ cy.stub(DAA, 'getDaas').returns(daas);
+ cy.stub(DAC, 'removeDacMember').returns(Promise.resolve(200));
+ cy.stub(DAC, 'addDacChair').returns(Promise.resolve(200));
+ cy.stub(DAC, 'removeDacChair').returns(Promise.resolve(200));
+ cy.stub(DAC, 'addDacMember').returns(Promise.resolve(200));
+ cy.stub(DAA, 'addDaaToDac').returns(Promise.resolve(200));
+ const props = {
+ match: {
+ params: {
+ dacId: undefined
+ }
+ },
+ history: {
+ push() {
+ }
+ }
+ };
+ mount(WrappedEditDac(props));
+ cy.get('[data-cy="dac_name"]').should('not.be.disabled');
+ cy.get('[data-cy="dac_name"]').should('be.empty');
+ cy.get('[data-cy="dac_description"]').should('not.be.disabled');
+ cy.get('[data-cy="dac_description"]').should('be.empty');
+ cy.get('[data-cy="dac_email"]').should('not.be.disabled');
+ cy.get('[data-cy="dac_email"]').should('be.empty');
+ cy.get('[data-cy="btn_save"]').should('not.be.disabled');
+ cy.get('[data-cy="btn_cancel"]').should('not.be.disabled');
+
+ // Create a DAC
+ const dacCreate = cy.stub(DAC, 'create').returns(dac);
+
+ cy.get('[data-cy="dac_name"]').type('New DAC Name');
+ cy.get('[data-cy="dac_description"]').type('New DAC Description');
+ cy.get('[data-cy="dac_email"]').type('New DAC Email');
+ cy.get('[data-cy="daa_radio"]').first().check();
+ cy.get('[data-cy="btn_save"]').click().then(() => {
+ expect(dacCreate).to.be.called;
+ });
+ });
+
+ it('Chairs cannot create a DAC', () => {
+ cy.viewport(600, 600);
+ Storage.clearStorage();
+ setUserRoleStatuses(chair, Storage);
+ cy.stub(DAA, 'getDaas').returns(daas);
+ cy.stub(DAC, 'removeDacMember').returns(Promise.resolve(200));
+ cy.stub(DAC, 'addDacChair').returns(Promise.resolve(200));
+ cy.stub(DAC, 'removeDacChair').returns(Promise.resolve(200));
+ cy.stub(DAC, 'addDacMember').returns(Promise.resolve(200));
+ cy.stub(DAA, 'addDaaToDac').returns(Promise.resolve(200));
+ const props = {
+ match: {
+ params: {
+ dacId: undefined
+ }
+ },
+ history: {
+ push() {
+ }
+ }
+ };
+ mount(WrappedEditDac(props));
+
+ // Try to create a DAC
+ const dacCreate = cy.stub(DAC, 'create');
+ cy.get('[data-cy="dac_name"]').type('New DAC Name');
+ cy.get('[data-cy="dac_description"]').type('New DAC Description');
+ cy.get('[data-cy="dac_email"]').type('New DAC Email');
+ cy.get('[data-cy="daa_radio"]').first().check();
+ cy.get('[data-cy="btn_save"]').click().then(() => {
+ expect(dacCreate).to.not.be.called;
+ });
+ });
+
+});
diff --git a/cypress/component/DAC/manageEditDac.spec.tsx b/cypress/component/DAC/manageEditDac.spec.tsx
new file mode 100644
index 000000000..fcc6a7ef8
--- /dev/null
+++ b/cypress/component/DAC/manageEditDac.spec.tsx
@@ -0,0 +1,101 @@
+/* eslint-disable no-undef */
+
+import React from 'react';
+import {mount} from 'cypress/react';
+import {DAC} from '../../../src/libs/ajax/DAC';
+import {Storage} from '../../../src/libs/storage';
+import ManageEditDac from '../../../src/pages/manage_dac/ManageEditDac';
+import {BrowserRouter} from 'react-router-dom';
+import admin from './admin.json';
+import chair from './chair.json';
+import dac from './dac.json';
+import {setUserRoleStatuses} from '../../../src/libs/utils';
+
+// It's necessary to wrap components that contain `Link` components
+const WrappedManageEditDac = (props) => {
+ return ;
+};
+
+/**
+ * This manage page is the pre-Data Access Agreement way to edit a DAC and will be removed when DAA work is complete.
+ */
+describe('ManageEditDAC Tests', () => {
+
+ Cypress._.each([admin, chair], (user) => {
+ it('Manage Edit DAC page should load for ' + user.displayName, () => {
+ cy.viewport(600, 600);
+ setUserRoleStatuses(user, Storage);
+ cy.stub(DAC, 'get').returns(dac);
+ const props = {match: {params: {dacId: dac.dacId}}};
+ mount(WrappedManageEditDac(props));
+ cy.contains(dac.name).should('exist');
+ cy.get('[data-cy="dac_name"]').should('not.be.disabled');
+ cy.get('[data-cy="dac_description"]').should('not.be.disabled');
+ cy.get('[data-cy="dac_email"]').should('not.be.disabled');
+ cy.get('[data-cy="btn_save"]').should('not.be.disabled');
+ cy.get('[data-cy="btn_cancel"]').should('not.be.disabled');
+ });
+ });
+
+ it('Admins can create a DAC', () => {
+ cy.viewport(600, 600);
+ Storage.clearStorage();
+ setUserRoleStatuses(admin, Storage);
+ const props = {
+ match: {
+ params: {
+ dacId: undefined
+ }
+ },
+ history: {
+ push() {
+ }
+ }
+ };
+ mount(WrappedManageEditDac(props));
+ cy.get('[data-cy="dac_name"]').should('not.be.disabled');
+ cy.get('[data-cy="dac_name"]').should('be.empty');
+ cy.get('[data-cy="dac_description"]').should('not.be.disabled');
+ cy.get('[data-cy="dac_description"]').should('be.empty');
+ cy.get('[data-cy="dac_email"]').should('not.be.disabled');
+ cy.get('[data-cy="dac_email"]').should('be.empty');
+ cy.get('[data-cy="btn_save"]').should('not.be.disabled');
+ cy.get('[data-cy="btn_cancel"]').should('not.be.disabled');
+
+ // Create a DAC
+ const dacCreate = cy.stub(DAC, 'create');
+
+ cy.get('[data-cy="dac_name"]').type('New DAC Name');
+ cy.get('[data-cy="dac_description"]').type('New DAC Description');
+ cy.get('[data-cy="dac_email"]').type('New DAC Email');
+ cy.get('[data-cy="btn_save"]').click().then(() => {
+ expect(dacCreate).to.be.called;
+ });
+ });
+
+ it('Chairs cannot create a DAC', () => {
+ cy.viewport(600, 600);
+ Storage.clearStorage();
+ setUserRoleStatuses(chair, Storage);
+ const dacCreate = cy.stub(DAC, 'create');
+ const props = {
+ match: {
+ params: {
+ dacId: undefined
+ }
+ },
+ history: {
+ push() {
+ }
+ }
+ };
+ mount(WrappedManageEditDac(props));
+ cy.get('[data-cy="dac_name"]').type('New DAC Name');
+ cy.get('[data-cy="dac_description"]').type('New DAC Description');
+ cy.get('[data-cy="dac_email"]').type('New DAC Email');
+ cy.get('[data-cy="btn_save"]').click().then(() => {
+ expect(dacCreate).to.not.be.called;
+ });
+ });
+
+});
diff --git a/cypress/support/component-index.html b/cypress/support/component-index.html
index aec5e614c..23b2efe9d 100644
--- a/cypress/support/component-index.html
+++ b/cypress/support/component-index.html
@@ -10,7 +10,8 @@
-
+
+