diff --git a/application/admin-client/cypress/e2e/auditLogs.cy.js b/application/admin-client/cypress/e2e/auditLogs.cy.js index 17c44840e..ccbd485a8 100644 --- a/application/admin-client/cypress/e2e/auditLogs.cy.js +++ b/application/admin-client/cypress/e2e/auditLogs.cy.js @@ -1,4 +1,4 @@ -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') before(() => { cy.task('reset') @@ -9,19 +9,19 @@ before(() => { describe('Audit Logs', () => { it('Organisation Admin can view Audit Log', () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/audit-logs') cy.contains('Audit Logs').should('exist') }) it('Study Amin can view Audit Log', () => { - cy.login(UserType.STUDY_ADMIN) + cy.login(TestUsers.STUDY_ADMIN.email) cy.visit('/audit-logs') cy.contains('Audit Logs').should('exist') }) it('should toggle the View Payload cell and display JSON', () => { - cy.login(UserType.STUDY_ADMIN) + cy.login(TestUsers.STUDY_ADMIN.email) cy.visit('/audit-logs') // Toggle button to view payload @@ -33,7 +33,9 @@ describe('Audit Logs', () => { // Assert JSON appears // Note: this works because the most recent action is the Study Admin // logging in at the start of the test :) - cy.get('.MuiCollapse-root').should('be.visible').and('contain.text', UserType.STUDY_ADMIN) + cy.get('.MuiCollapse-root') + .should('be.visible') + .and('contain.text', TestUsers.STUDY_ADMIN.email) // Toggle button to hide payload cy.get('[data-cy="toggle-payload-view"]').first().should('contain.text', 'Hide Payload').click() @@ -44,7 +46,8 @@ describe('Audit Logs', () => { }) it('should obscure password fields in JSON payload', () => { - cy.login(UserType.STUDY_ADMIN) + cy.login(TestUsers.STUDY_ADMIN.email) + TestUsers.TestUsers cy.visit('/audit-logs') // Toggle button to view payload @@ -55,7 +58,7 @@ describe('Audit Logs', () => { }) it('should obscure redcapToken fields in JSON payload', () => { - cy.login(UserType.STUDY_ADMIN) + cy.login(TestUsers.STUDY_ADMIN.email) cy.visit('/studies') cy.get('[data-cy="advanced-toggle"]').eq(0).click() cy.get('[data-cy="redcapToken"] input').eq(0).type('abc123') diff --git a/application/admin-client/cypress/e2e/auth.cy.js b/application/admin-client/cypress/e2e/auth.cy.js index ce1402278..b8468b3db 100644 --- a/application/admin-client/cypress/e2e/auth.cy.js +++ b/application/admin-client/cypress/e2e/auth.cy.js @@ -1,6 +1,6 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') @@ -15,16 +15,16 @@ describe('auth', () => { it('can login as admin to the admin portal', () => { cy.visit('/') - cy.get('input[name="email"]').type(UserType.ORG_ADMIN) - cy.get('input[name="password"]').type('Testpassword1') + cy.get('input[name="email"]').type(TestUsers.ORG_ADMIN.email) + cy.get('input[name="password"]').type(TestUsers.ORG_ADMIN.password) cy.get('button[type="submit"]').click() cy.url().should('include', '/surveys') // Redirects to /surveys after login }) it('cannot login as a participant to the admin portal', () => { cy.visit('/') - cy.get('input[name="email"]').type(UserType.PARTICIPANT_COMPLETED) - cy.get('input[name="password"]').type('Testpassword1') + cy.get('input[name="email"]').type(TestUsers.PARTICIPANT_COMPLETED.email) + cy.get('input[name="password"]').type(TestUsers.PARTICIPANT_COMPLETED.password) cy.get('button[type="submit"]').click() // Expect to stay on the login page & error message popup diff --git a/application/admin-client/cypress/e2e/basic.cy.js b/application/admin-client/cypress/e2e/basic.cy.js index 7b8c84e3a..fc69a85a0 100644 --- a/application/admin-client/cypress/e2e/basic.cy.js +++ b/application/admin-client/cypress/e2e/basic.cy.js @@ -1,6 +1,6 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') @@ -12,7 +12,7 @@ describe('basic', () => { cy.contains('Sign in to your account').should('exist') }) it('can navigate to tabs', () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/users') cy.contains('Surveys').click() cy.url().should('contain', '/surveys') @@ -20,7 +20,7 @@ describe('basic', () => { cy.url().should('contain', '/participants') }) it('Sidebar hide and show', () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/users') cy.get('button[tabindex="0"]').first().click() cy.contains('CTRL Admin').should('not.be.visible') @@ -29,7 +29,7 @@ describe('basic', () => { }) it('Is redirected to login when attempting to use expired token', () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/users') cy.contains('OrganisationAdmin').should('exist') cy.login_expired() diff --git a/application/admin-client/cypress/e2e/elsa.cy.js b/application/admin-client/cypress/e2e/elsa.cy.js index 93b8a9f4c..52429ce74 100644 --- a/application/admin-client/cypress/e2e/elsa.cy.js +++ b/application/admin-client/cypress/e2e/elsa.cy.js @@ -1,6 +1,6 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') @@ -8,7 +8,7 @@ beforeEach(() => { describe('Elsa Integration', () => { it('Can disable and enable Elsa Integration', () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/integrations') cy.get('[data-cy="elsa-checkbox"] input').should('be.checked').click() cy.get('[data-cy="confirm"]').click() diff --git a/application/admin-client/cypress/e2e/families.cy.js b/application/admin-client/cypress/e2e/families.cy.js index baacaf169..adc204ff6 100644 --- a/application/admin-client/cypress/e2e/families.cy.js +++ b/application/admin-client/cypress/e2e/families.cy.js @@ -1,10 +1,10 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) }) describe('Family Editing', () => { diff --git a/application/admin-client/cypress/e2e/invites.cy.js b/application/admin-client/cypress/e2e/invites.cy.js index acf18b232..2a0ab8cb5 100644 --- a/application/admin-client/cypress/e2e/invites.cy.js +++ b/application/admin-client/cypress/e2e/invites.cy.js @@ -1,10 +1,10 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) }) describe('', () => { diff --git a/application/admin-client/cypress/e2e/multiStudy.cy.js b/application/admin-client/cypress/e2e/multiStudy.cy.js index efc1606f7..30779cfef 100644 --- a/application/admin-client/cypress/e2e/multiStudy.cy.js +++ b/application/admin-client/cypress/e2e/multiStudy.cy.js @@ -1,10 +1,10 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers, TestStudies } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) }) describe('Multi-study features', () => { @@ -21,9 +21,9 @@ describe('Multi-study features', () => { cy.get('[data-cy="study-create"]').click() cy.visit('/surveys') //List of surveys - changeStudy('Test Study') + changeStudy(TestStudies.TEST_STUDY.name) cy.get('[role="rowgroup"]').children().should('have.length', 2) - changeStudy('Study 2') + changeStudy(TestStudies.TEST_STUDY_2.name) cy.get('[role="rowgroup"]').children().should('have.length', 1) //Survey version data is updated correctly (`TEST` has no content) changeStudy('TEST') @@ -31,7 +31,7 @@ describe('Multi-study features', () => { cy.get('[data-cy="step-list"]').children().should('have.length', 0) cy.get('[data-cy="study-dropdown"]').should('be.disabled') cy.contains('Surveys').click() - changeStudy('Test Study') + changeStudy(TestStudies.TEST_STUDY.name) cy.get('[data-cy="edit-draft-button"]').click() cy.get('[data-cy="step-list"]').children().should('have.length', 2) //List of participants and invitations @@ -40,7 +40,7 @@ describe('Multi-study features', () => { cy.get('[data-cy="pending-list"]').should('contain.text', 'Pending') cy.get('[data-cy="pending-list"]').should('contain.text', 'Revoked') cy.get('[data-cy="pending-list"]').should('contain.text', 'Expired') - changeStudy('Study 2') + changeStudy(TestStudies.TEST_STUDY_2.name) cy.get('[data-cy="participants-list"]').should('not.contain.text', 'Second') cy.get('[data-cy="pending-list"]').should('not.contain.text', 'Revoked') cy.get('[data-cy="pending-list"]').should('not.contain.text', 'Expired') @@ -49,8 +49,8 @@ describe('Multi-study features', () => { it('Maintains active study between browsing sessions', () => { cy.visit('/surveys') cy.get('[data-cy="study-dropdown"]').should('have.text', 'Test Study') - changeStudy('Study 2') + changeStudy(TestStudies.TEST_STUDY_2.name) cy.visit('/surveys') - cy.get('[data-cy="study-dropdown"]').should('have.text', 'Study 2') + cy.get('[data-cy="study-dropdown"]').should('have.text', TestStudies.TEST_STUDY_2.name) }) }) diff --git a/application/admin-client/cypress/e2e/participants.cy.js b/application/admin-client/cypress/e2e/participants.cy.js index ec67dd08e..5bc4def1c 100644 --- a/application/admin-client/cypress/e2e/participants.cy.js +++ b/application/admin-client/cypress/e2e/participants.cy.js @@ -1,6 +1,6 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') @@ -8,26 +8,26 @@ beforeEach(() => { describe('Participants', () => { it('List participants', () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/participants') cy.contains('Test').should('exist') cy.contains('Dependent').should('exist') cy.contains('V1').should('exist') }) it('View participant details', () => { - cy.login(UserType.ORG_ADMIN) - cy.visit('/participants/98') + cy.login(TestUsers.ORG_ADMIN.email) + cy.visit(`/participants/${TestUsers.PARTICIPANT_UNANSWERED.id}`) cy.contains('Unanswered User').should('exist') cy.contains('123 smith st').should('exist') cy.contains('V1').should('exist') - cy.visit('/participants/99') + cy.visit(`/participants/${TestUsers.PARTICIPANT_COMPLETED.id}`) cy.contains('Family').should('exist') cy.contains('Dependent').should('exist') }) it('Edit participant details', () => { - cy.login(UserType.ORG_ADMIN) - cy.visit('/participants/edit/98') + cy.login(TestUsers.ORG_ADMIN.email) + cy.visit(`/participants/edit/${TestUsers.PARTICIPANT_UNANSWERED.id}`) cy.contains('Edit Participant').should('exist') cy.get('input[name="profile.addressLine"]').clear().type('1 Smith St') cy.get('input[name="profile.nextOfKin.firstName"]').clear().type('Betty') @@ -41,14 +41,14 @@ describe('Participants', () => { cy.contains('Invalid email').should('exist') cy.get('input[name="profile.nextOfKin.email"]').clear().type('valid@email.com') cy.contains('Save').click() - cy.url().should('contain', 'participants/98') + cy.url().should('contain', `participants/${TestUsers.PARTICIPANT_UNANSWERED.id}`) cy.contains('Betty').should('exist') cy.contains('extID').should('exist') cy.contains('1 Smith St').should('exist') }) it('View answers', () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/participants') cy.get('[data-rowindex="0"]').contains('V1').trigger('mouseover', { force: true }) cy.contains('Incomplete').should('be.visible') @@ -59,7 +59,7 @@ describe('Participants', () => { }) it('Shows completed and partially completed surveys', () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/participants') cy.get('[data-rowindex="0"]').contains('V1').trigger('mouseover', { force: true }) cy.contains('Incomplete').should('be.visible') diff --git a/application/admin-client/cypress/e2e/passwordReset.cy.js b/application/admin-client/cypress/e2e/passwordReset.cy.js index cf7c3441f..e7128ae18 100644 --- a/application/admin-client/cypress/e2e/passwordReset.cy.js +++ b/application/admin-client/cypress/e2e/passwordReset.cy.js @@ -1,6 +1,6 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') @@ -15,11 +15,11 @@ describe('Password Reset', () => { it('requests password reset with registered email', () => { cy.visit('/forgot-password') - cy.get('input[name="email"]').type(UserType.ORG_ADMIN) + cy.get('input[name="email"]').type(TestUsers.ORG_ADMIN.email) cy.intercept( 'POST', '/users/password/generate-reset-link', - `[{ email: ${UserType.ORG_ADMIN}}]`, + `[{ email: ${TestUsers.ORG_ADMIN.email}}]`, ).as('requestReset') cy.get('button[type="submit"]').click() cy.wait('@requestReset') @@ -42,30 +42,30 @@ describe('Password Reset', () => { it('requests password reset with invalid token', () => { cy.visit('/update-password?token=invalid-reset-token') - cy.get('input[id="password"]').type('Password1') - cy.get('input[id="confirmPassword"]').type('Password1{enter}') + cy.get('input[id="password"]').type(TestUsers.ORG_ADMIN.password) + cy.get('input[id="confirmPassword"]').type(`${TestUsers.ORG_ADMIN.password}{enter}`) cy.contains('Error resetting').should('exist') }) it('requests password reset with already-used token', () => { cy.visit('/update-password?token=valid-reset-token') - cy.get('input[id="password"]').type('Password1') - cy.get('input[id="confirmPassword"]').type('Password1{enter}') + cy.get('input[id="password"]').type(TestUsers.ORG_ADMIN.password) + cy.get('input[id="confirmPassword"]').type(`${TestUsers.ORG_ADMIN.password}{enter}`) cy.contains('Success').should('exist') cy.visit('/update-password?token=valid-reset-token') - cy.get('input[id="password"]').type('Password1') - cy.get('input[id="confirmPassword"]').type('Password1{enter}') + cy.get('input[id="password"]').type(TestUsers.ORG_ADMIN.password) + cy.get('input[id="confirmPassword"]').type(`${TestUsers.ORG_ADMIN.password}{enter}`) cy.contains('Error').should('exist') }) it('resets password and logs in with new password', () => { cy.visit('/update-password?token=valid-reset-token') - cy.get('input[id="password"]').type('Password1') - cy.get('input[id="confirmPassword"]').type('Password1{enter}') + cy.get('input[id="password"]').type(TestUsers.ORG_ADMIN.password) + cy.get('input[id="confirmPassword"]').type(`${TestUsers.ORG_ADMIN.password}{enter}`) cy.contains('Success').should('exist') - cy.get('input[name="email"]').type('test-reset-password@example.com') - cy.get('input[name="password"]').type('Password1') + cy.get('input[name="email"]').type(TestUsers.PASSWORD_RESET_USER.email) + cy.get('input[name="password"]').type(TestUsers.PASSWORD_RESET_USER.password) cy.get('button[type="submit"]').click() cy.contains('admin priv').should('exist') }) diff --git a/application/admin-client/cypress/e2e/publish.cy.js b/application/admin-client/cypress/e2e/publish.cy.js index eab49752d..83fb5feb3 100644 --- a/application/admin-client/cypress/e2e/publish.cy.js +++ b/application/admin-client/cypress/e2e/publish.cy.js @@ -1,6 +1,6 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') @@ -8,7 +8,7 @@ beforeEach(() => { describe('Publish and complete', () => { it('Publish', () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/surveys/edit/2') cy.contains('Publish').click() cy.get('[data-cy="publish-confirm"]').click() diff --git a/application/admin-client/cypress/e2e/redcapInstrumentUpload.cy.js b/application/admin-client/cypress/e2e/redcapInstrumentUpload.cy.js index 9eb3b3332..c6a105222 100644 --- a/application/admin-client/cypress/e2e/redcapInstrumentUpload.cy.js +++ b/application/admin-client/cypress/e2e/redcapInstrumentUpload.cy.js @@ -1,10 +1,10 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/integrations') cy.contains('Import Survey').should('exist').click() }) diff --git a/application/admin-client/cypress/e2e/redcapParticipantUpload.cy.js b/application/admin-client/cypress/e2e/redcapParticipantUpload.cy.js index 88233cd9d..28264ae97 100644 --- a/application/admin-client/cypress/e2e/redcapParticipantUpload.cy.js +++ b/application/admin-client/cypress/e2e/redcapParticipantUpload.cy.js @@ -1,10 +1,10 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/integrations') cy.contains('Import Participants').should('exist').click() }) diff --git a/application/admin-client/cypress/e2e/responses.cy.js b/application/admin-client/cypress/e2e/responses.cy.js index b31f1a52d..c3b657478 100644 --- a/application/admin-client/cypress/e2e/responses.cy.js +++ b/application/admin-client/cypress/e2e/responses.cy.js @@ -1,10 +1,10 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) }) describe('', () => { diff --git a/application/admin-client/cypress/e2e/restore.cy.js b/application/admin-client/cypress/e2e/restore.cy.js index 2319da418..e9c6ebdfe 100644 --- a/application/admin-client/cypress/e2e/restore.cy.js +++ b/application/admin-client/cypress/e2e/restore.cy.js @@ -1,6 +1,6 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers, TestStudies } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') @@ -8,52 +8,52 @@ beforeEach(() => { describe('Delete and restore', () => { it('Organisation Admins should be able to delete a user then restore the user', () => { - cy.login(UserType.ORG_ADMIN) - cy.visit(`/users/101`) + cy.login(TestUsers.ORG_ADMIN.email) + cy.visit(`/users/${TestUsers.ORG_ADMIN_2.id}`) cy.contains('Delete').click() cy.contains('Are you sure').parent().contains('Delete').click() cy.contains('Success').should('exist') - cy.contains('testOrgAdmin2@example.com').should('not.exist') + cy.contains(TestUsers.ORG_ADMIN_2.email).should('not.exist') - cy.visit(`/users/106`) + cy.visit(`/users/${TestUsers.STUDY_ADMIN.id}`) cy.contains('Delete').click() cy.contains('Are you sure').parent().contains('Delete').click() cy.contains('Success').should('exist') - cy.contains('studyadmin@example.com').should('not.exist') + cy.contains(TestUsers.STUDY_ADMIN.email).should('not.exist') cy.visit('/restore') - cy.contains('101').should('exist') + cy.contains(TestUsers.ORG_ADMIN_2.id).should('exist') cy.get('[data-cy="restore-user"]').eq(0).click() cy.contains('Successfully restored').should('exist') - cy.contains('101').should('not.exist') + cy.contains(TestUsers.ORG_ADMIN_2.id).should('not.exist') - cy.contains('106').should('exist') + cy.contains(TestUsers.STUDY_ADMIN.id).should('exist') cy.get('[data-cy="restore-user"]').eq(0).click() cy.contains('Successfully restored').should('exist') - cy.contains('106').should('not.exist') + cy.contains(TestUsers.STUDY_ADMIN.id).should('not.exist') cy.visit('/users') - cy.contains('testOrgAdmin2@example.com').should('exist') + cy.contains(TestUsers.ORG_ADMIN_2.email).should('exist') }) it('Organisation Admins should be able to delete a study then restore the study', () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/studies') cy.get('[data-cy="delete-study"]').first().click() cy.get('[data-cy="confirm-delete"]').click() - cy.contains('Test Study').should('not.exist') + cy.contains(TestStudies.TEST_STUDY.name).should('not.exist') cy.visit('/restore') - cy.contains('Test Study').should('exist') + cy.contains(TestStudies.TEST_STUDY.name).should('exist') cy.get('[data-cy="restore-study"]').click() cy.contains('Successfully restored').should('exist') - cy.contains('Test Study').should('not.exist') + cy.contains(TestStudies.TEST_STUDY.name).should('not.exist') cy.visit('/studies') - cy.contains('Test Study').should('exist') + cy.contains(TestStudies.TEST_STUDY.name).should('exist') }) it('Organisation Admins should be able to delete a participant then restore the participant', () => { - cy.login(UserType.ORG_ADMIN) - cy.visit('/participants/98') + cy.login(TestUsers.ORG_ADMIN.email) + cy.visit(`/participants/${TestUsers.PARTICIPANT_UNANSWERED.id}`) cy.contains('Delete').click() cy.contains('Are you sure').parent().contains('Delete').click() cy.contains('Success').should('exist') @@ -68,38 +68,39 @@ describe('Delete and restore', () => { }) it('Study Admins should be able to delete a study that they are admins of and restore the study', () => { - cy.login(UserType.STUDY_ADMIN) - + cy.login(TestUsers.STUDY_ADMIN.email) // Create two new studies + const study1 = 'New Study 1' + const study2 = 'New Study 2' cy.visit('/studies') cy.get('[data-cy="new-study-button"]').click() cy.get('[data-cy="study-create"]').click() - cy.get('[data-cy="study-name"] input').should('be.focused').type('New Study 1') + cy.get('[data-cy="study-name"] input').should('be.focused').type(study1) cy.get('[data-cy="study-create"]').click() cy.get('[data-cy="study-create"]').should('not.exist') - cy.contains('New Study 1').should('exist') + cy.contains(study1).should('exist') cy.visit('/studies') cy.get('[data-cy="new-study-button"]').click() cy.get('[data-cy="study-create"]').click() - cy.get('[data-cy="study-name"] input').should('be.focused').type('New Study 2') + cy.get('[data-cy="study-name"] input').should('be.focused').type(study2) cy.get('[data-cy="study-create"]').click() cy.get('[data-cy="study-create"]').should('not.exist') - cy.contains('New Study 2').should('exist') + cy.contains(study2).should('exist') // Delete study 1 cy.visit('/studies') cy.get('[data-cy="delete-study"]').eq(1).click() cy.get('[data-cy="confirm-delete"]').click() - cy.contains('New Study 1').should('not.exist') + cy.contains(study1).should('not.exist') // Restore study 1 cy.visit('/restore') - cy.contains('New Study 1').should('exist') + cy.contains(study1).should('exist') cy.get('[data-cy="restore-study"]').click() cy.contains('Successfully restored').should('exist') - cy.contains('New Study 1').should('not.exist') + cy.contains(study1).should('not.exist') cy.visit('/studies') - cy.contains('New Study 1').should('exist') + cy.contains(study1).should('exist') }) }) diff --git a/application/admin-client/cypress/e2e/settings.cy.js b/application/admin-client/cypress/e2e/settings.cy.js index 679b301ba..50eb41f30 100644 --- a/application/admin-client/cypress/e2e/settings.cy.js +++ b/application/admin-client/cypress/e2e/settings.cy.js @@ -1,9 +1,10 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') + cy.login(TestUsers.ORG_ADMIN.email) }) describe('Settings page', () => { @@ -13,7 +14,6 @@ describe('Settings page', () => { } it('Can edit settings and save them', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/settings') cy.get('[data-cy="tcLink"] input').should( @@ -33,7 +33,6 @@ describe('Settings page', () => { }) it('Can reset settings', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/settings') cy.get('[data-cy="tcLink"] input').should( @@ -56,7 +55,6 @@ describe('Settings page', () => { it('Invalid values prevent saving and show appropriate error messages', () => { const values = { ...fieldMap, primaryColour: 'abc' } - cy.login(UserType.ORG_ADMIN) cy.visit('/settings') cy.get('[data-cy="tcLink"] input').should( @@ -80,7 +78,6 @@ describe('Settings page', () => { }) it('Can upload a logo', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/settings') cy.uploadCommonFile('[data-cy="logo-upload"]', 'valid_logo.png') cy.contains('Updated logo').should('exist') @@ -99,7 +96,6 @@ describe('Settings page', () => { }) it('Can update an org logo', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/settings') // Upload original logo cy.uploadCommonFile('[data-cy="logo-upload"]', 'valid_logo.png') @@ -135,7 +131,6 @@ describe('Settings page', () => { }) it('Invalid logo fails to update', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/settings') cy.uploadCommonFile('[data-cy="logo-upload"]', 'invalid_logo.png') cy.contains('Failed').should('exist') @@ -143,7 +138,6 @@ describe('Settings page', () => { }) it('Can delete an org Logo', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/settings') // Upload a logo to delete cy.uploadCommonFile('[data-cy="logo-upload"]', 'valid_logo.png') diff --git a/application/admin-client/cypress/e2e/setup.cy.js b/application/admin-client/cypress/e2e/setup.cy.js index 307b78b62..5927133b1 100644 --- a/application/admin-client/cypress/e2e/setup.cy.js +++ b/application/admin-client/cypress/e2e/setup.cy.js @@ -1,4 +1,5 @@ /// +const { TestUsers } = require('../../../common/testing/constants') describe('Setup', () => { it('Redirects to setup page if database empty, can register', () => { @@ -6,7 +7,7 @@ describe('Setup', () => { cy.visit('/') cy.url().should('contain', '/setup') cy.get('[data-cy="setup-email"]').type('abc@d.com') - cy.get('[data-cy="setup-password"]').type('asdfSDFSDIF12343@$#@') + cy.get('[data-cy="setup-password"]').type(TestUsers.ORG_ADMIN.password) // Using test data to conform to pr requirements cy.get('[data-cy="setup-submit"]').click() cy.url().should('contain', '/surveys') cy.visit('/surveys') diff --git a/application/admin-client/cypress/e2e/studyAdmin.cy.js b/application/admin-client/cypress/e2e/studyAdmin.cy.js index 1a5fb5233..e550d8038 100644 --- a/application/admin-client/cypress/e2e/studyAdmin.cy.js +++ b/application/admin-client/cypress/e2e/studyAdmin.cy.js @@ -1,6 +1,6 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers, TestStudies } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') @@ -8,70 +8,71 @@ beforeEach(() => { describe('Study Admins', () => { it('Add and remove studyadmin from studies', () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/users') cy.get('[data-cy="edit-button"]').eq(3).click() - cy.contains('Study 2').click() + cy.contains(TestStudies.TEST_STUDY_2.name).click() cy.contains('Added').should('exist') - cy.contains('Study 2').click() + cy.contains(TestStudies.TEST_STUDY_2.name).click() cy.contains('Removed').should('exist') }) it('Restricted functionality for study admin users', () => { - cy.login(UserType.STUDY_ADMIN) + cy.login(TestUsers.STUDY_ADMIN.email) cy.visit('/users') //Can't see or visit Settings page cy.contains('Settings').should('not.exist') //Can't edit their own role - cy.visit('/users/update/106') + cy.visit(`/users/update/${TestUsers.STUDY_ADMIN.id}`) cy.get('[data-cy="role-select"] input').should('be.disabled') cy.get('[data-cy="first"] input').should('not.be.disabled') //Can't edit another admin - cy.visit('/users/update/97') + cy.visit(`/users/update/${TestUsers.ORG_ADMIN}`) cy.get('[data-cy="role-select"] input').should('be.disabled') cy.get('[data-cy="first"] input').should('be.disabled') //Can't delete another admin - cy.visit('/users/update/97') + cy.visit(`/users/update/${TestUsers.ORG_ADMIN.id}`) cy.contains('Delete').should('not.exist') }) it('Study admin checkboxes not visible when editing an org admin', () => { - cy.visit('/users/update/97') + cy.visit(`/users/update/${TestUsers.ORG_ADMIN.id}`) cy.contains('Admin of Study').should('not.exist') }) it('Can only see studies they are admin of', () => { - cy.login(UserType.STUDY_ADMIN) + cy.login(TestUsers.STUDY_ADMIN.email) cy.visit('/studies') - cy.contains('Study FE').should('not.exist') - cy.contains('Test Study').should('exist') + cy.contains(TestStudies.FE_TEST_STUDY.name).should('not.exist') + cy.contains(TestStudies.TEST_STUDY.name).should('exist') }) it('Cannot edit a family if they are not admin of every related study', () => { - cy.login(UserType.STUDY_ADMIN) + cy.login(TestUsers.STUDY_ADMIN.email) cy.visit('/participants/family/edit/100') cy.get('[data-cy="remove-member-button"]').click() cy.get('[data-cy="remove-icon-button"]').eq(1).click() cy.contains('Failed to remove').should('exist') }) it("Displays correct message when a study admin logs in but they don't have access to any studies", () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/users') cy.get('[data-cy="edit-button"]').eq(3).click() - cy.contains('Test Study').click() + cy.contains(TestStudies.TEST_STUDY.name).click() cy.contains('Removed').should('exist') - cy.login(UserType.STUDY_ADMIN) + cy.login(TestUsers.STUDY_ADMIN.email) cy.visit('/users') cy.contains('You do not have access').should('exist') }) it('Study admin can create a study and gets added to it', () => { - cy.login(UserType.STUDY_ADMIN) + cy.login(TestUsers.STUDY_ADMIN.email) + const newStudy = 'STUDY X' cy.visit('/studies') cy.get('[data-cy="new-study-button"]').click() cy.get('[data-cy="study-create"]').click() - cy.get('[data-cy="study-name"] input').should('be.focused').type('STUDY X') + cy.get('[data-cy="study-name"] input').should('be.focused').type(newStudy) cy.get('[data-cy="study-create"]').click() cy.get('[data-cy="study-create"]').should('not.exist') - cy.contains('STUDY X').should('exist') + cy.contains(newStudy).should('exist') cy.reload() - cy.contains('STUDY X').should('exist') + cy.contains(newStudy).should('exist') }) }) diff --git a/application/admin-client/cypress/e2e/studyManagement.cy.js b/application/admin-client/cypress/e2e/studyManagement.cy.js index 0fce07706..2974aee98 100644 --- a/application/admin-client/cypress/e2e/studyManagement.cy.js +++ b/application/admin-client/cypress/e2e/studyManagement.cy.js @@ -1,10 +1,10 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) }) describe('Study management page', () => { diff --git a/application/admin-client/cypress/e2e/surveyEditor.cy.js b/application/admin-client/cypress/e2e/surveyEditor.cy.js index 1653d75f3..7c0577e8d 100644 --- a/application/admin-client/cypress/e2e/surveyEditor.cy.js +++ b/application/admin-client/cypress/e2e/surveyEditor.cy.js @@ -1,14 +1,14 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') + cy.login(TestUsers.ORG_ADMIN.email) }) describe('Survey Editor', () => { it('Edit title and description', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/surveys') cy.get('[data-rowindex="0"]').contains('Current Draft').should('exist') cy.get('[data-rowindex="0"] button').first().click() @@ -23,7 +23,6 @@ describe('Survey Editor', () => { }) it('Add, delete and rearrange questions', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/surveys/edit/2') cy.contains('Checkbox').click() cy.contains('Mandatory').should('exist') @@ -64,7 +63,6 @@ describe('Survey Editor', () => { cy.get('[data-cy="survey-element"]').eq(1).contains('Subheading').should('exist') }) it('Add, delete and rearrange steps', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/surveys/edit/2') cy.get('[data-cy="options-button"]').should('not.be.disabled').click() cy.contains('step up').should('have.class', 'Mui-disabled') @@ -79,7 +77,6 @@ describe('Survey Editor', () => { cy.get('[data-cy="step-list"]').children().first().contains('New Step').should('exist') }) it('Publish', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/surveys/edit/2') cy.contains('Publish').click() cy.contains('new version').should('exist') @@ -90,7 +87,6 @@ describe('Survey Editor', () => { cy.contains('2').should('exist') }) it('DUO Code Lookup', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/surveys/edit/2') cy.contains('Step 2').click() diff --git a/application/admin-client/cypress/e2e/surveys.cy.js b/application/admin-client/cypress/e2e/surveys.cy.js index f1e8c7e06..3c8a7f835 100644 --- a/application/admin-client/cypress/e2e/surveys.cy.js +++ b/application/admin-client/cypress/e2e/surveys.cy.js @@ -1,14 +1,14 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') + cy.login(TestUsers.ORG_ADMIN.email) }) describe('Surveys', () => { it('List surveys', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/surveys') cy.contains('Surveys').should('exist') cy.contains('Current Draft').should('exist') @@ -17,7 +17,6 @@ describe('Surveys', () => { }) it('View a survey', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/surveys') cy.get('[data-cy="view-button"]').click() diff --git a/application/admin-client/cypress/e2e/users.cy.js b/application/admin-client/cypress/e2e/users.cy.js index 80f5b1ef9..cf3f87cfb 100644 --- a/application/admin-client/cypress/e2e/users.cy.js +++ b/application/admin-client/cypress/e2e/users.cy.js @@ -1,26 +1,24 @@ /// -const { UserType } = require('../../../common/cypress/support/commands') +const { TestUsers } = require('../../../common/testing/constants') beforeEach(() => { cy.task('reset') + cy.login(TestUsers.ORG_ADMIN.email) }) describe('Users', () => { it('List users', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/users') cy.contains('Users').should('exist') }) it('View single user', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/users') cy.get('[data-cy="view-button"]').first().click() cy.contains('First Name').should('exist') }) it('Create user, check validation of email', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/users') cy.contains('Create').click() cy.url().should('contain', '/users/create') @@ -35,7 +33,6 @@ describe('Users', () => { cy.contains('elvis@example.com').should('exist') }) it('Edit user, check validation of email', () => { - cy.login(UserType.ORG_ADMIN) cy.visit('/users') cy.get('[data-cy="edit-button"]').eq(1).click() cy.get('input').eq(0).type('A') diff --git a/application/admin-client/cypress/e2e/viewResponsesPdf.cy.js b/application/admin-client/cypress/e2e/viewResponsesPdf.cy.js index 5b406b0d2..94697f768 100644 --- a/application/admin-client/cypress/e2e/viewResponsesPdf.cy.js +++ b/application/admin-client/cypress/e2e/viewResponsesPdf.cy.js @@ -1,10 +1,11 @@ /// +const { TestUsers } = require('../../../common/testing/constants') + beforeEach(() => { cy.task('reset') }) -const { UserType } = require('../../../common/cypress/support/commands') const downloadsPath = 'cypress/downloads/' const testCases = [ @@ -23,7 +24,7 @@ const testCases = [ describe('Admin PDF Export', () => { testCases.forEach(({ description, selectorIndex, expectedText }) => { it(`Show correct information in PDF for ${description}`, () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/participants') cy.intercept('GET', '/studies/1/participants/*/').as('requestPdf') diff --git a/application/admin-client/cypress/e2e/viewSurveyPdf.cy.js b/application/admin-client/cypress/e2e/viewSurveyPdf.cy.js index 888e137ab..cec7c2e47 100644 --- a/application/admin-client/cypress/e2e/viewSurveyPdf.cy.js +++ b/application/admin-client/cypress/e2e/viewSurveyPdf.cy.js @@ -1,15 +1,16 @@ /// +const { TestUsers } = require('../../../common/testing/constants') + beforeEach(() => { cy.task('reset') }) -const { UserType } = require('../../../common/cypress/support/commands') const downloadsPath = 'cypress/downloads/' describe('viewPdf', () => { it('Show correct information in PDF', () => { - cy.login(UserType.ORG_ADMIN) + cy.login(TestUsers.ORG_ADMIN.email) cy.visit('/surveys') cy.intercept('GET', '/studies/1/surveys/2').as('requestPdf') cy.get('[data-cy="pdf-button"]').first().click() diff --git a/application/admin-client/cypress/support/commands.ts b/application/admin-client/cypress/support/commands.ts index 79e99ae8d..807be6cac 100644 --- a/application/admin-client/cypress/support/commands.ts +++ b/application/admin-client/cypress/support/commands.ts @@ -18,12 +18,13 @@ import 'cypress-file-upload' // import common cypress commands import '../../../common/cypress/support/commands' +import { TestUsers } from '../../../common/testing/constants' -Cypress.Commands.add('login', (type: UserType) => { +Cypress.Commands.add('login', (email: string) => { cy.request({ method: 'POST', url: `localhost:5001/auth/login`, - body: { email: type, password: 'Testpassword1' }, + body: { email: email, password: TestUsers.ORG_ADMIN.password }, headers: { 'x-client-type': 'admin-client', }, diff --git a/application/backend/prisma/seed/seed.ts b/application/backend/prisma/seed/seed.ts index 1f8e08106..297fa4f23 100644 --- a/application/backend/prisma/seed/seed.ts +++ b/application/backend/prisma/seed/seed.ts @@ -3,6 +3,10 @@ import { hashPassword } from '../../src/authentication' import { SurveyStep } from '../../../common/types/survey' import { createDefaultAnswers, recalculateAnswers } from '../../src/utils/answers' import prisma from '../../src/PrismaClient' +import { TestUsers } from '../../../common/testing/constants.ts' + +// Using test data pw to ensure pw requirements are met +const seedUserPassword = TestUsers.PARTICIPANT_COMPLETED.password const main = async () => { await prisma.organisation.upsert({ @@ -53,7 +57,7 @@ const main = async () => { firstName: 'Michael', lastName: 'Wilson', role: 'Participant', - password: hashPassword('SomePassword123'), + password: hashPassword(seedUserPassword), profiles: { create: [ { @@ -104,7 +108,7 @@ const main = async () => { firstName: 'Sally', lastName: 'Wilson', role: 'Participant', - password: hashPassword('SomePassword123'), + password: hashPassword(seedUserPassword), profiles: { create: [ { @@ -198,7 +202,7 @@ const main = async () => { middleName: 'Mary', lastName: 'Johnson', role: 'Participant', - password: hashPassword('SomePassword123'), + password: hashPassword(seedUserPassword), organisations: {}, profiles: { create: [ @@ -284,7 +288,7 @@ const main = async () => { middleName: 'James', lastName: 'Doe', role: 'OrganisationAdmin', - password: hashPassword('SomePassword123'), + password: hashPassword(seedUserPassword), }, }) @@ -296,7 +300,7 @@ const main = async () => { firstName: 'Jane', lastName: 'Smith', role: 'StudyAdmin', - password: hashPassword('SomePassword123'), + password: hashPassword(seedUserPassword), adminOfStudies: { connect: [{ id: defaultStudy.id }, { id: shortStudy.id }] }, }, }) @@ -309,7 +313,7 @@ const main = async () => { firstName: 'Bob', lastName: 'Brown', role: 'OrganisationAdmin', - password: hashPassword('SomePassword123'), + password: hashPassword(seedUserPassword), }, }) @@ -321,7 +325,7 @@ const main = async () => { firstName: 'Emily', lastName: 'Davis', role: 'StudyAdmin', - password: hashPassword('SomePassword123'), + password: hashPassword(seedUserPassword), adminOfStudies: { connect: { id: shortStudy.id } }, }, }) diff --git a/application/backend/src/controllers/AuditLogsController.test.ts b/application/backend/src/controllers/AuditLogsController.test.ts index 042d8c69e..95d864ba0 100644 --- a/application/backend/src/controllers/AuditLogsController.test.ts +++ b/application/backend/src/controllers/AuditLogsController.test.ts @@ -6,7 +6,7 @@ import { resetDB, seedAuditLogs } from 'common/testing/TestHelpers' import { defaultAuditLogsPageSize } from 'common/src/config' import { generateToken } from '../authentication' import type { GetAuditLogsResponse } from 'common/types/api/audit-logs' -import { ORG_ADMIN_ID, PARTICIPANT_UNANSWERED_ID, STUDY_ADMIN_ID } from 'common/testing/seed' +import { TestUsers, TestStudies } from 'common/testing/constants' import { UpdateStudyRequest } from 'common/types/api/studies' import type { OTPLoginRequest, RegisterRequest } from 'common/types/api/auth' const api = new Api() @@ -17,10 +17,13 @@ describe('AuditLogsController', () => { let orgAdminToken: string let studyAdminToken: string + const studyName: string = TestStudies.TEST_STUDY.name + const testStudyId: number = TestStudies.TEST_STUDY.id + beforeAll(async () => { - participantToken = await generateToken({ userId: PARTICIPANT_UNANSWERED_ID }) - orgAdminToken = await generateToken({ userId: ORG_ADMIN_ID }) - studyAdminToken = await generateToken({ userId: STUDY_ADMIN_ID }) + participantToken = await generateToken({ userId: TestUsers.PARTICIPANT_UNANSWERED.id }) + orgAdminToken = await generateToken({ userId: TestUsers.ORG_ADMIN.id }) + studyAdminToken = await generateToken({ userId: TestUsers.STUDY_ADMIN.id }) api.run() }) @@ -212,8 +215,6 @@ describe('AuditLogsController', () => { describe('Sensitive information', () => { it('should not show sensitive token information in payloads', async () => { // Update a redcapToken - const studyName: string = 'Test Study' - const testStudyId: number = 1 // Check test study exists const existingStudy = await prisma.study.findFirst({ where: { name: studyName }, @@ -241,8 +242,6 @@ describe('AuditLogsController', () => { it('should obscure sensitive token information in payloads', async () => { // Update a redcapToken - const studyName: string = 'Test Study' - const testStudyId: number = 1 // Check test study exists const existingStudy = await prisma.study.findFirst({ where: { name: studyName }, @@ -274,7 +273,7 @@ describe('AuditLogsController', () => { email: 'johndoe@example.com', firstName: 'John', lastName: 'Doe', - password: 'Password1', + password: 'Loginforbogusperson1', role: Role.Participant, } @@ -304,7 +303,7 @@ describe('AuditLogsController', () => { code: '1223', expiresAt: new Date(new Date().getTime() + 1000 * 60), id: 'abc123', - userId: PARTICIPANT_UNANSWERED_ID, + userId: TestUsers.PARTICIPANT_UNANSWERED.id, }, }) const loginRequest: OTPLoginRequest = { diff --git a/application/backend/src/controllers/AuthController.test.ts b/application/backend/src/controllers/AuthController.test.ts index 71758ee82..fb0acdc14 100644 --- a/application/backend/src/controllers/AuthController.test.ts +++ b/application/backend/src/controllers/AuthController.test.ts @@ -13,14 +13,7 @@ import type { import prisma from '../PrismaClient' import { Role } from '@prisma/client' import { resetDB, wipeDB } from 'common/testing/TestHelpers' -import { - ORG_ADMIN_EMAIL, - ORG_ADMIN_PASSWORD, - ORG_ADMIN_ID, - PARTICIPANT_UNANSWERED_EMAIL, - PARTICIPANT_UNANSWERED_ID, - TEST_STUDY, -} from 'common/testing/seed' +import { TestUsers, TestStudies, TestInvites } from 'common/testing/constants' import { ContactMethod, ParticipantType, @@ -36,9 +29,15 @@ const app = api.app let orgAdminToken: string describe('AuthController', () => { + const testFirstName = 'John' + const testLastName = 'Doe' + const testEmail = 'johndoe@example.com' + const testPassword = 'Loginfortests123' + const testGuardianFirstName = 'Jenny' + beforeAll(async () => { orgAdminToken = await generateToken({ - userId: ORG_ADMIN_ID, + userId: TestUsers.ORG_ADMIN.id, }) api.run() }) @@ -63,10 +62,10 @@ describe('AuthController', () => { expect(getAllUsersBody1.data).toBe(undefined) const registerRequest: RegisterRequest = { - firstName: 'John', - lastName: 'Doe', + firstName: testFirstName, + lastName: testLastName, email: 'testregister@example.com', - password: 'Password123', + password: testPassword, role: Role.OrganisationAdmin, } @@ -91,10 +90,10 @@ describe('AuthController', () => { it('should register a new user returning a token', async () => { const registerRequest: RegisterRequest = { - firstName: 'John', - lastName: 'Doe', - email: 'newUser@example.com', - password: 'Password123', + firstName: testFirstName, + lastName: testLastName, + email: testEmail, + password: testPassword, role: Role.Participant, } @@ -120,9 +119,9 @@ describe('AuthController', () => { it('should return 422 if validation fails', async () => { const registerRequest = { - firstName: 'John', - lastName: 'Doe', - password: 'password123', + firstName: testFirstName, + lastName: testLastName, + password: 'password123', //Does not meet minimum password requirements role: Role.Participant, } @@ -138,10 +137,10 @@ describe('AuthController', () => { it('should return an error if the user is already registered', async () => { const registerRequest: RegisterRequest = { - firstName: 'John', - lastName: 'Doe', - email: 'johndoe@example.com', - password: 'Password123', + firstName: testFirstName, + lastName: testLastName, + email: testEmail, + password: testPassword, role: Role.Participant, } @@ -162,9 +161,9 @@ describe('AuthController', () => { it('should fail validation if provided with an invalid email', async () => { const registerRequest: RegisterRequest = { email: 'invalid email', - firstName: 'John', - lastName: 'Doe', - password: 'Password123', + firstName: testFirstName, + lastName: testLastName, + password: testPassword, role: Role.Participant, } @@ -186,9 +185,9 @@ describe('AuthController', () => { it('should fail validation if provided with an invalid password', async () => { const registerRequest: RegisterRequest = { - email: 'johndoe@example.com', - firstName: 'John', - lastName: 'Doe', + email: testEmail, + firstName: testFirstName, + lastName: testLastName, password: 'pass', role: Role.Participant, } @@ -203,7 +202,7 @@ describe('AuthController', () => { expect(body.message).toBe('Validation Failed') expect(body.details).toEqual({ 'bodyRequest.password': { - message: 'Password must be at least 8 characters', + message: 'Password must be at least 14 characters', value: 'pass', }, }) @@ -230,16 +229,16 @@ describe('AuthController', () => { 'bodyRequest.firstName': { message: 'minLength 1', value: '' }, 'bodyRequest.lastName': { message: 'minLength 1', value: '' }, 'bodyRequest.email': { message: 'Please provide valid email', value: '' }, - 'bodyRequest.password': { message: 'Password must be at least 8 characters', value: '' }, + 'bodyRequest.password': { message: 'Password must be at least 14 characters', value: '' }, }) }) - it('should fail validation if the password is not strong', async () => { + it('should fail validation if the password does not include caps or numbers', async () => { const registerRequest: RegisterRequest = { - firstName: 'John', - lastName: 'Doe', - email: 'johndoe@example.com', - password: 'somepasswordthatsnotstrong', + firstName: testFirstName, + lastName: testLastName, + email: testEmail, + password: 'nocapsornumber', role: Role.Participant, } @@ -263,26 +262,26 @@ describe('AuthController', () => { await wipeDB() const res = await request(app) .post('/auth/register/setup') - .send({ email: 'testadmin@test.com', password: 'abDFS141@!' }) + .send({ email: testEmail, password: testPassword }) expect(res.status).toEqual(201) - const user = await prisma.user.findFirst({ where: { email: 'testadmin@test.com' } }) + const user = await prisma.user.findFirst({ where: { email: testEmail } }) expect(user).not.toBeNull() }) it('Should not allow setup registration when a user exists', async () => { await resetDB() const res = await request(app) .post('/auth/register/setup') - .send({ email: 'testadmin@test.com', password: 'abDFS141@!' }) + .send({ email: testEmail, password: testPassword }) expect(res.ok).toBe(false) }) }) describe('POST /auth/register/participant/{inviteId}', () => { const registerParticipantRequestBase: RegisterParticipantRequest = { - firstName: 'John', - lastName: 'Doe', - email: 'john@example.com', - password: 'johnDoesP@ssword123', + firstName: testFirstName, + lastName: testLastName, + email: TestInvites.INVITE_PENDING.email, + password: testPassword, mobile: '+61477777777', addressLine: '123 Some Street', suburb: 'Sydney', @@ -300,7 +299,7 @@ describe('AuthController', () => { where: { email: registerParticipantRequestBase.email, study: { - name: TEST_STUDY, + name: TestStudies.TEST_STUDY.name, }, }, }) @@ -316,7 +315,7 @@ describe('AuthController', () => { it('should fail validation if the password is not strong', async () => { const registerParticipantRequest: RegisterParticipantRequest = { ...registerParticipantRequestBase, - password: 'weakpassword', + password: 'passwordtester', } const participantInviteId = await prisma.invite.findFirstOrThrow({ where: { @@ -336,6 +335,10 @@ describe('AuthController', () => { expect(registerParticipantBody.details).toEqual({ Uppercase: { message: 'Password must contain at least one uppercase letter' }, Number: { message: 'Password must contain at least one number' }, + CommonBase: { + message: + 'Password must not contain easily guessable words (i.e. Password, Changeme, Welcome)', + }, }) }) @@ -394,7 +397,7 @@ describe('AuthController', () => { .send(registerParticipantRequest) const registered = await prisma.participantProfile.findFirstOrThrow({ - where: { firstName: 'John', lastName: 'Doe' }, + where: { firstName: testFirstName, lastName: testLastName }, }) const dep1 = await prisma.participantProfile.findFirstOrThrow({ where: { firstName: 'A', lastName: 'B' }, @@ -424,8 +427,8 @@ describe('AuthController', () => { const registerParticipantRequest2: RegisterParticipantRequest = { ...registerParticipantRequestBase, - firstName: 'Jenny', - email: 'jenny@gmail.com', + firstName: testGuardianFirstName, + email: TestInvites.INVITE_2_PENDING.email, dependents: [{ firstName: 'A', lastName: 'B', dob: '2020-01-01', permanent: false }], } const participantInviteId2 = await prisma.invite.findFirstOrThrow({ @@ -443,10 +446,10 @@ describe('AuthController', () => { .send(registerParticipantRequest2) const registered1 = await prisma.participantProfile.findFirstOrThrow({ - where: { firstName: 'John', lastName: 'Doe' }, + where: { firstName: testFirstName, lastName: testLastName }, }) const registered2 = await prisma.participantProfile.findFirstOrThrow({ - where: { firstName: 'Jenny', lastName: 'Doe' }, + where: { firstName: testGuardianFirstName, lastName: testLastName }, }) const dependents = await prisma.participantProfile.findMany({ @@ -463,10 +466,10 @@ describe('AuthController', () => { beforeEach(async () => { // Register a user const registerRequest: RegisterRequest = { - firstName: 'John', - lastName: 'Doe', - email: 'johndoe@email.com', - password: 'johnDoesP@ssword123', + firstName: testFirstName, + lastName: testLastName, + email: testEmail, + password: testPassword, role: Role.OrganisationAdmin, } @@ -481,8 +484,8 @@ describe('AuthController', () => { jest.replaceProperty(config, 'otp', false) const loginRequest: LoginRequest = { - email: ORG_ADMIN_EMAIL, - password: ORG_ADMIN_PASSWORD, + email: TestUsers.ORG_ADMIN.email, + password: TestUsers.ORG_ADMIN.password, } const loginResponse = await request(app).post('/auth/login').send(loginRequest) @@ -491,7 +494,7 @@ describe('AuthController', () => { const loginBody = loginResponse.body as LoginSuccessResponse expect(loginBody.token).toBeDefined() - expect(loginBody.id).toBe(ORG_ADMIN_ID) + expect(loginBody.id).toBe(TestUsers.ORG_ADMIN.id) expect(loginBody.role).toBe(Role.OrganisationAdmin) expect(loginBody).not.toHaveProperty('otp_token') }) @@ -508,8 +511,8 @@ describe('AuthController', () => { // Login the user const loginRequest: LoginRequest = { - email: 'johndoe@email.com', - password: 'johnDoesP@ssword123', + email: testEmail, + password: testPassword, } const loginResponse = await request(app).post('/auth/login').send(loginRequest) expect(loginResponse.status).toEqual(200) @@ -529,7 +532,7 @@ describe('AuthController', () => { it("should return 401 and shouldn't allow the user to login with the incorrect password", async () => { // Login the user with incorrect password const loginRequest: LoginRequest = { - email: 'johndoe@email.com', + email: testEmail, password: 'wrongPassword123', } @@ -543,7 +546,7 @@ describe('AuthController', () => { it('should return 422 if validation fails', async () => { const loginRequest = { - email: 'johndoe@email.com', + email: testEmail, } const response = await request(app).post('/auth/login').send(loginRequest) @@ -572,7 +575,7 @@ describe('AuthController', () => { it('should fail validation if provided with an invalid email', async () => { const loginRequest: LoginRequest = { email: 'Invalid Email', - password: 'SomeGoodPassword123', + password: testPassword, } const response = await request(app).post('/auth/login').send(loginRequest) @@ -587,8 +590,8 @@ describe('AuthController', () => { it('Should return an otp token if otp is enabled', async () => { jest.replaceProperty(config, 'otp', true) const loginRequest: LoginRequest = { - email: PARTICIPANT_UNANSWERED_EMAIL, - password: 'Testpassword1', + email: TestUsers.PARTICIPANT_UNANSWERED.email, + password: TestUsers.PARTICIPANT_UNANSWERED.password, } const loginResponse = await request(app).post('/auth/login').send(loginRequest) expect(loginResponse.ok).toBe(true) @@ -597,47 +600,53 @@ describe('AuthController', () => { }) it('Should lock access for 10 mins if retries exceeded', async () => { await prisma.user.update({ - where: { id: PARTICIPANT_UNANSWERED_ID }, + where: { id: TestUsers.PARTICIPANT_UNANSWERED.id }, data: { retriesRemaining: 1 }, }) const loginRequest: LoginRequest = { - email: PARTICIPANT_UNANSWERED_EMAIL, + email: TestUsers.PARTICIPANT_UNANSWERED.email, password: 'wrong', } await request(app).post('/auth/login').send(loginRequest) - const user = await prisma.user.findFirstOrThrow({ where: { id: PARTICIPANT_UNANSWERED_ID } }) + const user = await prisma.user.findFirstOrThrow({ + where: { id: TestUsers.PARTICIPANT_UNANSWERED.id }, + }) expect(user.retriesRemaining).toBe(0) const loginResponse = await request(app).post('/auth/login').send(loginRequest) expect(loginResponse.body.details).toBe('Retries exceeded, account locked for 10 minutes') }) it('Should lock access for 24 hours if retries exceeded again in 24 hours', async () => { await prisma.user.update({ - where: { id: PARTICIPANT_UNANSWERED_ID }, + where: { id: TestUsers.PARTICIPANT_UNANSWERED.id }, data: { retriesRemaining: 0, lockedUntil: new Date(new Date().getTime() - 1000) }, }) const loginRequest: LoginRequest = { - email: PARTICIPANT_UNANSWERED_EMAIL, + email: TestUsers.PARTICIPANT_UNANSWERED.email, password: 'wrong', } const loginResponse = await request(app).post('/auth/login').send(loginRequest) expect(loginResponse.body.details).toBe('Retries exceeded, account locked for 24 hours') - const user = await prisma.user.findFirstOrThrow({ where: { id: PARTICIPANT_UNANSWERED_ID } }) + const user = await prisma.user.findFirstOrThrow({ + where: { id: TestUsers.PARTICIPANT_UNANSWERED.id }, + }) expect(user.retriesRemaining).toBe(10) }) it('Should refresh retries after successful login', async () => { jest.replaceProperty(config, 'otp', false) await prisma.user.update({ - where: { id: PARTICIPANT_UNANSWERED_ID }, + where: { id: TestUsers.PARTICIPANT_UNANSWERED.id }, data: { retriesRemaining: 1 }, }) const loginRequest: LoginRequest = { - email: PARTICIPANT_UNANSWERED_EMAIL, - password: 'Testpassword1', + email: TestUsers.PARTICIPANT_UNANSWERED.email, + password: TestUsers.PARTICIPANT_UNANSWERED.password, } const loginResponse = await request(app).post('/auth/login').send(loginRequest) expect(loginResponse.ok).toBe(true) - const user = await prisma.user.findFirstOrThrow({ where: { id: PARTICIPANT_UNANSWERED_ID } }) + const user = await prisma.user.findFirstOrThrow({ + where: { id: TestUsers.PARTICIPANT_UNANSWERED.id }, + }) expect(user.retriesRemaining).toBe(10) }) }) @@ -648,7 +657,7 @@ describe('AuthController', () => { code: '1223', expiresAt: new Date(new Date().getTime() + 1000 * 60), id: 'abc123', - userId: PARTICIPANT_UNANSWERED_ID, + userId: TestUsers.PARTICIPANT_UNANSWERED.id, }, }) }) @@ -660,7 +669,7 @@ describe('AuthController', () => { const loginResponse = await request(app).post('/auth/login/otp').send(loginRequest) expect(loginResponse.ok).toBe(true) expect(loginResponse.body.token).toBeDefined() - expect(loginResponse.body.id).toBe(PARTICIPANT_UNANSWERED_ID) + expect(loginResponse.body.id).toBe(TestUsers.PARTICIPANT_UNANSWERED.id) expect(loginResponse.body.role).toBe(Role.Participant) }) it('Should decrement available retries if code is invalid', async () => { @@ -671,7 +680,9 @@ describe('AuthController', () => { const loginResponse = await request(app).post('/auth/login/otp').send(loginRequest) expect(loginResponse.ok).toBe(false) expect(loginResponse.body.token).toBeUndefined() - const user = await prisma.user.findFirstOrThrow({ where: { id: PARTICIPANT_UNANSWERED_ID } }) + const user = await prisma.user.findFirstOrThrow({ + where: { id: TestUsers.PARTICIPANT_UNANSWERED.id }, + }) expect(user.retriesRemaining).toBe(9) }) it('Should prevent login if otp is expired', async () => { @@ -688,7 +699,7 @@ describe('AuthController', () => { }) it('Should not allow login if user is locked out', async () => { await prisma.user.update({ - where: { id: PARTICIPANT_UNANSWERED_ID }, + where: { id: TestUsers.PARTICIPANT_UNANSWERED.id }, data: { lockedUntil: new Date(new Date().getTime() + 1000 * 60) }, }) const loginRequest: OTPLoginRequest = { @@ -721,7 +732,7 @@ describe('AuthController', () => { }) fetchMock.mockGlobal().route('http://token', { access_token: '123' }) fetchMock.mockGlobal().route('http://userinfo', { - email: 'admin@example.com', + email: TestUsers.ORG_ADMIN.email, }) const loginRequest: OIDCLoginRequest = { @@ -734,7 +745,7 @@ describe('AuthController', () => { expect(response.status).toEqual(200) expect(response.body.token).toBeDefined() expect(response.body.role).toBe(Role.OrganisationAdmin) - expect(response.body.id).toBe(ORG_ADMIN_ID) + expect(response.body.id).toBe(TestUsers.ORG_ADMIN.id) }) it('Should allow oidc login', async () => { @@ -744,7 +755,7 @@ describe('AuthController', () => { }) fetchMock.mockGlobal().route('http://token', { access_token: '123' }) fetchMock.mockGlobal().route('http://userinfo', { - email: 'admin@example.com', + email: TestUsers.ORG_ADMIN.email, }) const loginRequest: OIDCLoginRequest = { @@ -764,7 +775,7 @@ describe('AuthController', () => { }) fetchMock.mockGlobal().route('http://token', { access_token: '123' }) fetchMock.mockGlobal().route('http://userinfo', { - email: 'admin@example.com', + email: TestUsers.ORG_ADMIN.email, }) const loginRequest: OIDCLoginRequest = { @@ -785,7 +796,7 @@ describe('AuthController', () => { }) fetchMock.mockGlobal().route('http://token', { access_token: '123' }) fetchMock.mockGlobal().route('http://userinfo', { - email: PARTICIPANT_UNANSWERED_EMAIL, + email: TestUsers.PARTICIPANT_UNANSWERED.email, }) const loginRequest: OIDCLoginRequest = { @@ -806,7 +817,7 @@ describe('AuthController', () => { const response = await request(app).get('/auth/tcs') expect(response.redirect).toBe(true) expect(response.headers['location']).toBe( - 'https://garvan-data-science-platform.github.io/ctrl-docs/docs/terms-and-conditions', + 'https://garvan-data-science-platform.github.io/ctrl-docs/docs/terms-and-conditions', //TODO: this should not have a default value see issue https://github.com/Garvan-Data-Science-Platform/ctrl/issues/870 Should be populated by seed for tests. ) }) }) diff --git a/application/backend/src/controllers/FamiliesController.test.ts b/application/backend/src/controllers/FamiliesController.test.ts index 7e2c05102..ced835784 100644 --- a/application/backend/src/controllers/FamiliesController.test.ts +++ b/application/backend/src/controllers/FamiliesController.test.ts @@ -2,14 +2,7 @@ import request from 'supertest' import { generateToken } from '../authentication' import { Api } from '../Api' import { resetDB } from 'common/testing/TestHelpers' -import { - DEPENDENT_ID, - FE_TEST_STUDY_ID, - ORG_ADMIN_ID, - PARTICIPANT_UNANSWERED_ID, - SECOND_GUARDIAN_ID, - STUDY_ADMIN_ID, -} from 'common/testing/seed' +import { TestUsers, TestStudies } from 'common/testing/constants' import prisma from '../PrismaClient' import { GetFamilyResponse } from 'common/types/api/families' @@ -23,10 +16,10 @@ describe('FamiliesController', () => { beforeAll(async () => { registeredUserToken = await generateToken({ - userId: ORG_ADMIN_ID, + userId: TestUsers.ORG_ADMIN.id, }) studyAdminToken = await generateToken({ - userId: STUDY_ADMIN_ID, + userId: TestUsers.STUDY_ADMIN.id, }) api.run() }) @@ -55,13 +48,13 @@ describe('FamiliesController', () => { describe('POST /studies/{studyId}/families/remove/{profileId}', () => { it('Should remove member from a family and give auto-incremented ID', async () => { const response = await request(app) - .post(`/studies/${studyId}/families/remove/${SECOND_GUARDIAN_ID}`) + .post(`/studies/${studyId}/families/remove/${TestUsers.GUARDIAN_2.id}`) .set({ Authorization: `Bearer ${registeredUserToken}` }) expect(response.status).toBe(204) const profile = await prisma.participantProfile.findFirstOrThrow({ - where: { id: SECOND_GUARDIAN_ID }, + where: { id: TestUsers.GUARDIAN_2.id }, }) expect(profile.familyId).toBe(101) @@ -73,18 +66,18 @@ describe('FamiliesController', () => { }) it('Dependent answers should be recalculated on family change', async () => { let depSP = await prisma.surveyVersionAnswers.findFirstOrThrow({ - where: { profileId: DEPENDENT_ID }, + where: { profileId: TestUsers.DEPENDENT.id }, orderBy: { versionId: 'desc' }, }) expect(depSP.answers[1].answers).toEqual([null, null]) await request(app) - .post(`/studies/${studyId}/families/remove/${SECOND_GUARDIAN_ID}`) + .post(`/studies/${studyId}/families/remove/${TestUsers.GUARDIAN_2.id}`) .set({ Authorization: `Bearer ${registeredUserToken}` }) depSP = await prisma.surveyVersionAnswers.findFirstOrThrow({ - where: { profileId: DEPENDENT_ID }, + where: { profileId: TestUsers.DEPENDENT.id }, orderBy: { versionId: 'desc' }, }) @@ -92,17 +85,17 @@ describe('FamiliesController', () => { }) it('Study admin can remove from a family that is in multiple studies if they are admin of every study', async () => { await prisma.user.update({ - where: { id: STUDY_ADMIN_ID }, - data: { adminOfStudies: { connect: { id: FE_TEST_STUDY_ID } } }, + where: { id: TestUsers.STUDY_ADMIN.id }, + data: { adminOfStudies: { connect: { id: TestStudies.FE_TEST_STUDY.id } } }, }) const res = await request(app) - .post(`/studies/${studyId}/families/remove/${SECOND_GUARDIAN_ID}`) + .post(`/studies/${studyId}/families/remove/${TestUsers.GUARDIAN_2.id}`) .set({ Authorization: `Bearer ${studyAdminToken}` }) expect(res.ok).toBe(true) }) it('Study admin can not remove from a family if they are not admin for every study the family appears in', async () => { const res = await request(app) - .post(`/studies/${studyId}/families/remove/${SECOND_GUARDIAN_ID}`) + .post(`/studies/${studyId}/families/remove/${TestUsers.GUARDIAN_2.id}`) .set({ Authorization: `Bearer ${studyAdminToken}` }) expect(res.ok).toBe(false) }) @@ -111,29 +104,29 @@ describe('FamiliesController', () => { describe('POST /studies/{studyId}/families/:familyId/add/:profileId', () => { it('Should move a member into the family', async () => { await request(app) - .post(`/studies/${studyId}/families/100/add/${PARTICIPANT_UNANSWERED_ID}`) + .post(`/studies/${studyId}/families/100/add/${TestUsers.PARTICIPANT_UNANSWERED.id}`) .set({ Authorization: `Bearer ${registeredUserToken}` }) const newMemberProfile = await prisma.participantProfile.findUniqueOrThrow({ - where: { id: PARTICIPANT_UNANSWERED_ID }, + where: { id: TestUsers.PARTICIPANT_UNANSWERED.id }, }) expect(newMemberProfile.familyId).toBe(100) }) it('Dependent answers should be recalculated', async () => { let depSP = await prisma.surveyVersionAnswers.findFirstOrThrow({ - where: { profileId: DEPENDENT_ID }, + where: { profileId: TestUsers.DEPENDENT.id }, orderBy: { versionId: 'desc' }, }) expect(depSP.answers[1].answers).toEqual([null, null]) await request(app) - .post(`/studies/${studyId}/families/100/add/${PARTICIPANT_UNANSWERED_ID}`) + .post(`/studies/${studyId}/families/100/add/${TestUsers.PARTICIPANT_UNANSWERED.id}`) .set({ Authorization: `Bearer ${registeredUserToken}` }) depSP = await prisma.surveyVersionAnswers.findFirstOrThrow({ - where: { profileId: DEPENDENT_ID }, + where: { profileId: TestUsers.DEPENDENT.id }, orderBy: { versionId: 'desc' }, }) @@ -141,17 +134,17 @@ describe('FamiliesController', () => { }) it('Study admin can move from/to a family that is in multiple studies if they are admin of every study', async () => { await prisma.user.update({ - where: { id: STUDY_ADMIN_ID }, - data: { adminOfStudies: { connect: { id: FE_TEST_STUDY_ID } } }, + where: { id: TestUsers.STUDY_ADMIN.id }, + data: { adminOfStudies: { connect: { id: TestStudies.FE_TEST_STUDY.id } } }, }) const res = await request(app) - .post(`/studies/${studyId}/families/100/add/${PARTICIPANT_UNANSWERED_ID}`) + .post(`/studies/${studyId}/families/100/add/${TestUsers.PARTICIPANT_UNANSWERED.id}`) .set({ Authorization: `Bearer ${studyAdminToken}` }) expect(res.ok).toBe(true) }) it('Study admin can not move from/to a family if they are not admin for every study the families appears in', async () => { const res = await request(app) - .post(`/studies/${studyId}/families/100/add/${PARTICIPANT_UNANSWERED_ID}`) + .post(`/studies/${studyId}/families/100/add/${TestUsers.PARTICIPANT_UNANSWERED.id}`) .set({ Authorization: `Bearer ${studyAdminToken}` }) expect(res.ok).toBe(false) }) diff --git a/application/backend/src/controllers/IntegrationsController.test.ts b/application/backend/src/controllers/IntegrationsController.test.ts index a456d0484..d65e72530 100644 --- a/application/backend/src/controllers/IntegrationsController.test.ts +++ b/application/backend/src/controllers/IntegrationsController.test.ts @@ -3,12 +3,7 @@ import { resetDB } from 'common/testing/TestHelpers' import { Api } from '../Api' import { generateToken } from '../authentication' import prisma from '../PrismaClient' -import { - FE_TEST_STUDY_ID, - ORG_ADMIN_ID, - PARTICIPANT_COMPLETED_ID, - PARTICIPANT_UNANSWERED_ID, -} from 'common/testing/seed' +import { TestUsers, TestStudies } from 'common/testing/constants' import { redcapFetch } from '../../tests/__mocks__/RedcapFetch' import path from 'path' import { SurveysController } from './SurveysController' @@ -19,7 +14,7 @@ let token: string describe('IntegrationsController', () => { beforeAll(async () => { - token = await generateToken({ userId: ORG_ADMIN_ID }) + token = await generateToken({ userId: TestUsers.ORG_ADMIN.id }) api.run() }) @@ -384,7 +379,7 @@ describe('IntegrationsController', () => { const res = await request(app) .post('/elsa/duos') .set({ Authorization: 'Apikey abc123' }) - .send({ participantIds: [`PID-TEST1-${PARTICIPANT_COMPLETED_ID}`, 'dummy'] }) + .send({ participantIds: [`PID-TEST1-${TestUsers.PARTICIPANT_COMPLETED.id}`, 'dummy'] }) expect(res.body.notFoundIds).toEqual(['dummy']) }) @@ -394,8 +389,8 @@ describe('IntegrationsController', () => { .set({ Authorization: 'Apikey abc123' }) .send({ participantIds: [ - `PID-TEST1-${PARTICIPANT_COMPLETED_ID}`, - `PID-TEST1-${PARTICIPANT_UNANSWERED_ID}`, + `PID-TEST1-${TestUsers.PARTICIPANT_COMPLETED.id}`, + `PID-TEST1-${TestUsers.PARTICIPANT_UNANSWERED.id}`, ], }) @@ -409,15 +404,15 @@ describe('IntegrationsController', () => { const res = await request(app) .post('/elsa/duos') .set({ Authorization: 'Apikey abc123' }) - .send({ participantIds: [`PID-TEST1-${PARTICIPANT_UNANSWERED_ID}`] }) + .send({ participantIds: [`PID-TEST1-${TestUsers.PARTICIPANT_UNANSWERED.id}`] }) expect(res.body.data[0].duos).toEqual([]) }) it('DUO codes work with multi studies', async () => { const sva = await prisma.surveyVersionAnswers.findFirstOrThrow({ where: { - version: { studyId: FE_TEST_STUDY_ID }, - profileId: PARTICIPANT_UNANSWERED_ID, + version: { studyId: TestStudies.FE_TEST_STUDY.id }, + profileId: TestUsers.PARTICIPANT_UNANSWERED.id, }, orderBy: { version: { versionNumber: 'desc' } }, }) @@ -429,7 +424,7 @@ describe('IntegrationsController', () => { const res = await request(app) .post('/elsa/duos') .set({ Authorization: 'Apikey abc123' }) - .send({ participantIds: [`PID-TEST2-${PARTICIPANT_UNANSWERED_ID}`] }) + .send({ participantIds: [`PID-TEST2-${TestUsers.PARTICIPANT_UNANSWERED.id}`] }) expect(res.body.data[0].duos).toEqual(['DUO:0000004']) }) @@ -439,7 +434,7 @@ describe('IntegrationsController', () => { const res = await request(app) .post('/elsa/duos') .set({ Authorization: 'Apikey abc123' }) - .send({ participantIds: [`PID-TEST1-${PARTICIPANT_COMPLETED_ID}`] }) + .send({ participantIds: [`PID-TEST1-${TestUsers.PARTICIPANT_COMPLETED.id}`] }) expect(res.body.data[0].duos).toEqual(['DUO:0000006']) }) }) diff --git a/application/backend/src/controllers/MailerController.test.ts b/application/backend/src/controllers/MailerController.test.ts index fe168d5c4..86d41ac7c 100644 --- a/application/backend/src/controllers/MailerController.test.ts +++ b/application/backend/src/controllers/MailerController.test.ts @@ -4,7 +4,7 @@ import { generateToken } from '../authentication' import { resetDB } from 'common/testing/TestHelpers' import { NodemailerMock } from 'nodemailer-mock' import * as nodemailer from 'nodemailer' -import { PARTICIPANT_COMPLETED_ID, SECOND_TEST_STUDY_ID, TEST_STUDY_ID } from 'common/testing/seed' +import { TestUsers, TestStudies } from 'common/testing/constants' const mockNodeMailer = nodemailer as unknown as NodemailerMock const api = new Api() @@ -15,7 +15,7 @@ describe('MailerController', () => { beforeAll(async () => { participantToken = await generateToken({ - userId: PARTICIPANT_COMPLETED_ID, + userId: TestUsers.PARTICIPANT_COMPLETED.id, }) api.run() @@ -37,7 +37,7 @@ describe('MailerController', () => { it('should successfully send emails', async () => { const response = await request(app) .post('/mailer/contact-us') - .send({ content: 'Test Content', studyId: TEST_STUDY_ID }) + .send({ content: 'Test Content', studyId: TestStudies.TEST_STUDY.id }) .set({ Authorization: `Bearer ${participantToken}` }) expect(response.status).toBe(204) @@ -63,28 +63,31 @@ describe('MailerController', () => { it('should send emails to Study specific email if it is set', async () => { const response = await request(app) .post('/mailer/contact-us') - .send({ content: 'Test Content', studyId: TEST_STUDY_ID }) + .send({ content: 'Test Content', studyId: TestStudies.TEST_STUDY.id }) .set({ Authorization: `Bearer ${participantToken}` }) expect(response.status).toBe(204) const sentEmails = mockNodeMailer.mock.getSentMail() expect(sentEmails.length).toBe(2) // 1 to admin, 1 to user - expect(sentEmails.map((v) => v.to)).toEqual([['test@contactus.com'], 'test3@example.com']) + expect(sentEmails.map((v) => v.to)).toEqual([ + ['test@contactus.com'], + TestUsers.PARTICIPANT_COMPLETED.email, + ]) }) it('should send emails to all Admins if Study specific contact email is not set', async () => { const response = await request(app) .post('/mailer/contact-us') - .send({ content: 'Test Content', studyId: SECOND_TEST_STUDY_ID }) + .send({ content: 'Test Content', studyId: TestStudies.TEST_STUDY_2.id }) .set({ Authorization: `Bearer ${participantToken}` }) expect(response.status).toBe(204) const sentEmails = mockNodeMailer.mock.getSentMail() expect(sentEmails.length).toBe(2) // 1 to admin, 1 to user expect(sentEmails.map((v) => v.to)).toEqual([ - ['admin@example.com', 'testOrgAdmin2@example.com'], - 'test3@example.com', + [TestUsers.ORG_ADMIN.email, TestUsers.ORG_ADMIN_2.email], + TestUsers.PARTICIPANT_COMPLETED.email, ]) }) }) diff --git a/application/backend/src/controllers/OrganisationsController.test.ts b/application/backend/src/controllers/OrganisationsController.test.ts index f50f45fc9..0011fc3da 100644 --- a/application/backend/src/controllers/OrganisationsController.test.ts +++ b/application/backend/src/controllers/OrganisationsController.test.ts @@ -11,7 +11,7 @@ import { } from 'common/types/api/organisations' import { resetDB } from 'common/testing/TestHelpers' import { generateToken } from '../authentication' -import { ORG_ADMIN_ID, PARTICIPANT_COMPLETED_ID } from 'common/testing/seed' +import { TestUsers } from 'common/testing/constants' const api = new Api() const app = api.app @@ -28,7 +28,7 @@ describe('OrganisationsController', () => { beforeEach(async () => { await resetDB() - orgAdmintoken = await generateToken({ userId: ORG_ADMIN_ID }) + orgAdmintoken = await generateToken({ userId: TestUsers.ORG_ADMIN.id }) }) afterAll(async () => { @@ -215,7 +215,7 @@ describe('OrganisationsController', () => { const body: GetOrganisationUsersResponse = response.body expect(body.data.length).toBe(4) - expect(body.data[0].id).toBe(ORG_ADMIN_ID) + expect(body.data[0].id).toBe(TestUsers.ORG_ADMIN.id) }) it('should return a 404 error if the organisation is not found', async () => { @@ -234,7 +234,7 @@ describe('OrganisationsController', () => { describe('POST /organisations/:OrgID/users/:UserID', () => { it('should add a user to an organisation', async () => { const response = await request(app) - .post(`/organisations/${testOrganisationId}/users/${PARTICIPANT_COMPLETED_ID}`) + .post(`/organisations/${testOrganisationId}/users/${TestUsers.PARTICIPANT_COMPLETED.id}`) .set({ Authorization: `Bearer ${orgAdmintoken}` }) expect(response.status).toBe(204) }) @@ -254,7 +254,7 @@ describe('OrganisationsController', () => { it('should return a 404 error if the organisation is not found', async () => { const notExistingOrganisationId: number = 1234567890 const response = await request(app) - .post(`/organisations/${notExistingOrganisationId}/users/${ORG_ADMIN_ID}`) + .post(`/organisations/${notExistingOrganisationId}/users/${TestUsers.ORG_ADMIN.id}`) .set({ Authorization: `Bearer ${orgAdmintoken}` }) expect(response.status).toBe(404) @@ -268,7 +268,7 @@ describe('OrganisationsController', () => { describe('DELETE /organisations/:OrgID/users/:UserID', () => { it('should remove a user from an organisation', async () => { const response = await request(app) - .delete(`/organisations/${testOrganisationId}/users/${ORG_ADMIN_ID}`) + .delete(`/organisations/${testOrganisationId}/users/${TestUsers.ORG_ADMIN.id}`) .set({ Authorization: `Bearer ${orgAdmintoken}` }) expect(response.status).toBe(204) @@ -288,7 +288,7 @@ describe('OrganisationsController', () => { it('should return a 404 error if the organisation is not found', async () => { const notExistingOrganisationId: number = 1234567890 const response = await request(app) - .delete(`/organisations/${notExistingOrganisationId}/users/${ORG_ADMIN_ID}`) + .delete(`/organisations/${notExistingOrganisationId}/users/${TestUsers.ORG_ADMIN.id}`) .set({ Authorization: `Bearer ${orgAdmintoken}` }) expect(response.status).toBe(404) diff --git a/application/backend/src/controllers/ParticipantsController.test.ts b/application/backend/src/controllers/ParticipantsController.test.ts index b386f2116..d56587f71 100644 --- a/application/backend/src/controllers/ParticipantsController.test.ts +++ b/application/backend/src/controllers/ParticipantsController.test.ts @@ -7,15 +7,7 @@ import { GetParticipantsResponse, InviteParticipantsResponse, } from 'common/types/api/participants' -import { - ORG_ADMIN_ID, - PARTICIPANT_UNANSWERED_ID, - PARTICIPANT_UNANSWERED_EMAIL, - PASSWORD_RESET_USER_ID, - SECOND_TEST_STUDY_ID, - PARTICIPANT_COMPLETED_EMAIL, - PARTICIPANT_COMPLETED_ID, -} from 'common/testing/seed' +import { TestUsers, TestStudies, TestInvites } from 'common/testing/constants' import { InviteStatus, Role } from '@prisma/client' import prisma from '../PrismaClient' import { hashPassword } from '../authentication' @@ -26,14 +18,14 @@ const mockNodeMailer = nodemailer as unknown as NodemailerMock const api = new Api() const app = api.app -const expectedNumberOfInvites = 6 +const expectedNumberOfInvites = 4 // TODO: used to be 6 but I commented out two possibly redundant seed invites. Double check this describe('ParticipantsController', () => { let organisationAdminToken: string beforeAll(async () => { organisationAdminToken = await generateToken({ - userId: ORG_ADMIN_ID, + userId: TestUsers.ORG_ADMIN.id, }) api.run() @@ -136,7 +128,7 @@ describe('ParticipantsController', () => { await prisma.studyParticipant.update({ where: { participantProfileId_studyId: { - participantProfileId: PARTICIPANT_UNANSWERED_ID, + participantProfileId: TestUsers.PARTICIPANT_UNANSWERED.id, studyId: 1, }, }, @@ -144,26 +136,26 @@ describe('ParticipantsController', () => { }) const response = await request(app) - .post(`/studies/1/participants/${PARTICIPANT_UNANSWERED_ID}`) + .post(`/studies/1/participants/${TestUsers.PARTICIPANT_UNANSWERED.id}`) .set({ Authorization: `Bearer ${organisationAdminToken}` }) expect(response.ok).toBeTruthy() const p = await prisma.studyParticipant.findFirstOrThrow({ - where: { participantProfileId: PARTICIPANT_UNANSWERED_ID, studyId: 1 }, + where: { participantProfileId: TestUsers.PARTICIPANT_UNANSWERED.id, studyId: 1 }, }) expect(p.deleted).toBeFalsy() }) it('Cannot add a participant who is part of another study (they must be invited)', async () => { const response = await request(app) - .post(`/studies/4/participants/${PARTICIPANT_UNANSWERED_ID}`) + .post(`/studies/4/participants/${TestUsers.PARTICIPANT_UNANSWERED.id}`) .set({ Authorization: `Bearer ${organisationAdminToken}` }) expect(response.ok).toBeFalsy() const p = await prisma.studyParticipant.findFirst({ - where: { participantProfileId: PARTICIPANT_UNANSWERED_ID, studyId: 4 }, + where: { participantProfileId: TestUsers.PARTICIPANT_UNANSWERED.id, studyId: 4 }, }) expect(p).toBeNull() }) @@ -172,12 +164,16 @@ describe('ParticipantsController', () => { describe('DELETE /participants/{profileId}', () => { it('Can remove a participant from a study', async () => { const response = await request(app) - .delete(`/studies/1/participants/${PARTICIPANT_COMPLETED_ID}`) + .delete(`/studies/1/participants/${TestUsers.PARTICIPANT_COMPLETED.id}`) .set({ Authorization: `Bearer ${organisationAdminToken}` }) expect(response.ok).toBeTruthy() const p = await prisma.studyParticipant.findFirstOrThrow({ - where: { participantProfileId: PARTICIPANT_COMPLETED_ID, studyId: 1, deleted: true }, + where: { + participantProfileId: TestUsers.PARTICIPANT_COMPLETED.id, + studyId: 1, + deleted: true, + }, }) expect(p.deleted).toBeTruthy() const ans = await prisma.surveyVersionAnswers.findFirstOrThrow({ @@ -197,7 +193,7 @@ describe('ParticipantsController', () => { await prisma.studyParticipant.delete({ where: { participantProfileId_studyId: { - participantProfileId: PARTICIPANT_UNANSWERED_ID, + participantProfileId: TestUsers.PARTICIPANT_UNANSWERED.id, studyId: 1, }, }, @@ -207,14 +203,14 @@ describe('ParticipantsController', () => { .set({ Authorization: `Bearer ${organisationAdminToken}` }) expect(res2.ok).toBe(true) expect(res2.body.data).toHaveLength(1) - expect(res2.body.data[0].profileId).toBe(PARTICIPANT_UNANSWERED_ID) + expect(res2.body.data[0].profileId).toBe(TestUsers.PARTICIPANT_UNANSWERED.id) }) }) describe('PATCH /participants/{profileId}/restore', () => { it('Fails if participant is not deleted', async () => { const res = await request(app) - .patch(`/studies/1/participants/${PARTICIPANT_UNANSWERED_ID}/restore`) + .patch(`/studies/1/participants/${TestUsers.PARTICIPANT_UNANSWERED.id}/restore`) .set({ Authorization: `Bearer ${organisationAdminToken}` }) expect(res.ok).toBe(false) @@ -224,21 +220,21 @@ describe('ParticipantsController', () => { await prisma.studyParticipant.delete({ where: { participantProfileId_studyId: { - participantProfileId: PARTICIPANT_UNANSWERED_ID, + participantProfileId: TestUsers.PARTICIPANT_UNANSWERED.id, studyId: 1, }, }, }) const res = await request(app) - .patch(`/studies/1/participants/${PARTICIPANT_UNANSWERED_ID}/restore`) + .patch(`/studies/1/participants/${TestUsers.PARTICIPANT_UNANSWERED.id}/restore`) .set({ Authorization: `Bearer ${organisationAdminToken}` }) expect(res.ok).toBe(true) const participant = await prisma.studyParticipant.findFirst({ where: { - participantProfileId: PARTICIPANT_UNANSWERED_ID, + participantProfileId: TestUsers.PARTICIPANT_UNANSWERED.id, studyId: 1, }, }) @@ -252,7 +248,7 @@ describe('InvitesController', () => { beforeAll(async () => { organisationAdminToken = await generateToken({ - userId: ORG_ADMIN_ID, + userId: TestUsers.ORG_ADMIN.id, }) api.run() @@ -283,8 +279,8 @@ describe('InvitesController', () => { expect(body.data[1].inviteStatus).toBe(InviteStatus.REVOKED) expect(body.data[2].inviteStatus).toBe(InviteStatus.EXPIRED) expect(body.data[3].inviteStatus).toBe(InviteStatus.PENDING) - expect(body.data[4].inviteStatus).toBe(InviteStatus.PENDING) - expect(body.data[5].inviteStatus).toBe(InviteStatus.PENDING) + // expect(body.data[4].inviteStatus).toBe(InviteStatus.PENDING) // TODO: add these extra invites? + // expect(body.data[5].inviteStatus).toBe(InviteStatus.PENDING) }) }) @@ -380,7 +376,7 @@ describe('InvitesController', () => { where: { studyId_emailHash: { //@ts-ignore - email: 'invite3@revoked.com', + email: TestInvites.INVITE_REVOKED.email, studyId: 1, }, }, @@ -395,7 +391,7 @@ describe('InvitesController', () => { const response = await request(app) .post('/studies/1/invites') .send({ - recipients: [{ email: 'invite3@revoked.com', prefill: {} }], + recipients: [{ email: TestInvites.INVITE_REVOKED.email, prefill: {} }], subjectText: 'ABC', explanatoryText: '123', }) @@ -420,7 +416,7 @@ describe('InvitesController', () => { where: { studyId_emailHash: { //@ts-ignore - email: 'invite3@revoked.com', + email: TestInvites.INVITE_REVOKED.email, studyId: 1, }, }, @@ -434,7 +430,7 @@ describe('InvitesController', () => { }, 100000) it('should resend emails for status PENDING invites and reset the expiry', async () => { - const emailPendingInvite = 'john@example.com' + const emailPendingInvite = TestInvites.INVITE_2_PENDING.email // Check the status REVOKED invite const invite = await prisma.invite.findUnique({ @@ -498,7 +494,7 @@ describe('InvitesController', () => { }) it('should do nothing for status ACCEPTED invites', async () => { - const emailAcceptedInvite = 'invite2@accepted.com' + const emailAcceptedInvite = TestInvites.INVITE_ACCEPTED.email const response = await request(app) .post('/studies/1/invites') @@ -589,7 +585,7 @@ describe('InvitesController', () => { describe('POST /studies/{studyId}/invites/resend', () => { it('should resend all invites of status PENDING and reset their expiry', async () => { - const emailPendingInvite = 'invite1@pending.com' + const emailPendingInvite = TestInvites.INVITE_PENDING.email await prisma.study.update({ where: { id: 1 }, @@ -604,7 +600,12 @@ describe('InvitesController', () => { // Check email(s) were successfully sent const sentEmails = mockNodeMailer.mock.getSentMail() - expect(sentEmails.length).toBe(4) + expect(sentEmails.length).toBe(2) + /* + TODO: above number used to be 4 (removed to pending invites as part of test data refactor). + Come back and remove this note at teh end of the refactor if those two pending + invites were not needed. + */ const targetEmail = sentEmails.find((email) => email.to === emailPendingInvite) expect(targetEmail).toBeDefined() expect(targetEmail).toHaveProperty('from', `CTRL `) @@ -616,7 +617,7 @@ describe('InvitesController', () => { describe('POST /studies/{studyId}/invites/{inviteId}/revoke', () => { it('should change invites status from PENDING to REVOKED given email(s)', async () => { - const emailPendingInvite = 'invite1@pending.com' + const emailPendingInvite = TestInvites.INVITE_PENDING.email const invite = await prisma.invite.findUnique({ where: { @@ -681,15 +682,15 @@ describe('InvitesController', () => { describe('POST /invites/{inviteId}/accept', () => { beforeEach(async () => { - await inviteUser(PARTICIPANT_UNANSWERED_EMAIL, 2, {}) - await inviteUser(PARTICIPANT_COMPLETED_EMAIL, 2, { + await inviteUser(TestUsers.PARTICIPANT_UNANSWERED.email, 2, {}) + await inviteUser(TestUsers.PARTICIPANT_COMPLETED.email, 2, { studyParticipant: { externalId: 'external' }, }) }) it('should fail if inviteId does not exist', async () => { const token = await generateToken({ - userId: PARTICIPANT_UNANSWERED_ID, + userId: TestUsers.PARTICIPANT_UNANSWERED.id, }) const fakeIdString = 'this-is-not-real' @@ -706,7 +707,7 @@ describe('InvitesController', () => { it('should fail if invite has already been accepted', async () => { const invite = await prisma.invite.findFirstOrThrow({ where: { - email: PARTICIPANT_UNANSWERED_EMAIL, + email: TestUsers.PARTICIPANT_UNANSWERED.email, }, }) @@ -714,13 +715,13 @@ describe('InvitesController', () => { await prisma.invite.update({ where: { id: invite.id, - email: PARTICIPANT_UNANSWERED_EMAIL, + email: TestUsers.PARTICIPANT_UNANSWERED.email, }, data: { status: 'ACCEPTED' }, }) const token = await generateToken({ - userId: PARTICIPANT_UNANSWERED_ID, + userId: TestUsers.PARTICIPANT_UNANSWERED.id, }) const response = await request(app) @@ -736,12 +737,12 @@ describe('InvitesController', () => { // generate token for different user. use valid inviteId const invite = await prisma.invite.findFirstOrThrow({ where: { - email: PARTICIPANT_UNANSWERED_EMAIL, + email: TestUsers.PARTICIPANT_UNANSWERED.email, }, }) // Incorrect ID - const token = await generateToken({ userId: PASSWORD_RESET_USER_ID }) + const token = await generateToken({ userId: TestUsers.PASSWORD_RESET_USER.id }) const response = await request(app) .post(`/invites/${invite.id}/accept`) @@ -769,7 +770,7 @@ describe('InvitesController', () => { status: InviteStatus.PENDING, study: { connect: { - id: SECOND_TEST_STUDY_ID, + id: TestStudies.TEST_STUDY_2.id, }, }, expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), // 1 day in the future @@ -791,13 +792,13 @@ describe('InvitesController', () => { it('should add user to study and accept invite', async () => { const invite = await prisma.invite.findFirstOrThrow({ where: { - email: PARTICIPANT_UNANSWERED_EMAIL, + email: TestUsers.PARTICIPANT_UNANSWERED.email, }, }) // need valid invite and token for user that does exist const token = await generateToken({ - userId: PARTICIPANT_UNANSWERED_ID, + userId: TestUsers.PARTICIPANT_UNANSWERED.id, }) const response = await request(app) @@ -808,7 +809,7 @@ describe('InvitesController', () => { const p = await prisma.studyParticipant.findFirstOrThrow({ where: { studyId: 2, - participantProfile: { user: { email: PARTICIPANT_UNANSWERED_EMAIL } }, + participantProfile: { user: { email: TestUsers.PARTICIPANT_UNANSWERED.email } }, }, }) expect(p.externalId).toBeNull() @@ -817,14 +818,14 @@ describe('InvitesController', () => { it('should prefill with external id', async () => { const invite = await prisma.invite.findFirstOrThrow({ where: { - email: PARTICIPANT_COMPLETED_EMAIL, + email: TestUsers.PARTICIPANT_COMPLETED.email, studyId: 2, }, }) // need valid invite and token for user that does exist const token = await generateToken({ - userId: PARTICIPANT_COMPLETED_ID, + userId: TestUsers.PARTICIPANT_COMPLETED.id, }) const response = await request(app) @@ -835,7 +836,7 @@ describe('InvitesController', () => { const p = await prisma.studyParticipant.findFirstOrThrow({ where: { studyId: 2, - participantProfile: { user: { email: PARTICIPANT_COMPLETED_EMAIL } }, + participantProfile: { user: { email: TestUsers.PARTICIPANT_COMPLETED.email } }, }, }) expect(p.externalId).toBe('external') @@ -843,12 +844,12 @@ describe('InvitesController', () => { }) describe('GET /invites/pending', () => { beforeEach(async () => { - await inviteUser(PARTICIPANT_UNANSWERED_EMAIL, 2, {}) + await inviteUser(TestUsers.PARTICIPANT_UNANSWERED.email, 2, {}) }) it('should return correct number of invites', async () => { // One initial invite const token = await generateToken({ - userId: PARTICIPANT_UNANSWERED_ID, + userId: TestUsers.PARTICIPANT_UNANSWERED.id, }) const response = await request(app) @@ -865,7 +866,7 @@ describe('InvitesController', () => { where: { studyId_emailHash: { //@ts-ignore - email: PARTICIPANT_UNANSWERED_EMAIL, + email: TestUsers.PARTICIPANT_UNANSWERED.email, studyId: 2, }, }, diff --git a/application/backend/src/controllers/ProfilesController.test.ts b/application/backend/src/controllers/ProfilesController.test.ts index 3043b3d0c..33bfd6a54 100644 --- a/application/backend/src/controllers/ProfilesController.test.ts +++ b/application/backend/src/controllers/ProfilesController.test.ts @@ -3,7 +3,7 @@ import { GetParticipantProfileResponse, UpdateProfileRequest } from 'common/type import { generateToken } from '../authentication' import { Api } from '../Api' import { resetDB } from 'common/testing/TestHelpers' -import { ORG_ADMIN_ID, PARTICIPANT_COMPLETED_ID } from 'common/testing/seed' +import { TestUsers } from 'common/testing/constants' import { StateTerritory } from 'common/types/api/users/ParticipantProfile' import prisma from '../PrismaClient' @@ -15,10 +15,10 @@ describe('ProfilesController', () => { beforeAll(async () => { orgAdminToken = await generateToken({ - userId: ORG_ADMIN_ID, + userId: TestUsers.ORG_ADMIN.id, }) registeredParticipantToken = await generateToken({ - userId: PARTICIPANT_COMPLETED_ID, + userId: TestUsers.PARTICIPANT_COMPLETED.id, }) api.run() }) @@ -35,7 +35,7 @@ describe('ProfilesController', () => { it('should return the profile of a user if they exist', async () => { // Get user profile const response = await request(app) - .get(`/profiles/${PARTICIPANT_COMPLETED_ID}`) + .get(`/profiles/${TestUsers.PARTICIPANT_COMPLETED.id}`) .set({ Authorization: `Bearer ${orgAdminToken}` }) expect(response.status).toBe(200) @@ -50,7 +50,7 @@ describe('ProfilesController', () => { preferredContact: 'EMAIL', state: 'VIC', suburb: 'Melbourne', - email: 'test3@example.com', + email: TestUsers.PARTICIPANT_COMPLETED.email, firstName: 'Completed', lastName: 'User', familyMembers: [ @@ -92,7 +92,7 @@ describe('ProfilesController', () => { preferredContact: 'EMAIL', state: 'VIC', suburb: 'Melbourne', - email: 'test3@example.com', + email: TestUsers.PARTICIPANT_COMPLETED.email, firstName: 'Completed', lastName: 'User', }) @@ -109,7 +109,7 @@ describe('ProfilesController', () => { .set({ Authorization: `Bearer ${registeredParticipantToken}` }) const participantProfileByIDResponse = await request(app) - .get(`/profiles/${PARTICIPANT_COMPLETED_ID}`) + .get(`/profiles/${TestUsers.PARTICIPANT_COMPLETED.id}`) .set({ Authorization: `Bearer ${orgAdminToken}` }) expect(currentParticipantProfileResponse.status).toBe(200) @@ -139,7 +139,9 @@ describe('ProfilesController', () => { .send(reqBody) expect(response.status).toBe(204) - const user = await prisma.user.findUniqueOrThrow({ where: { id: PARTICIPANT_COMPLETED_ID } }) + const user = await prisma.user.findUniqueOrThrow({ + where: { id: TestUsers.PARTICIPANT_COMPLETED.id }, + }) const profile = await prisma.participantProfile.findFirstOrThrow({ where: { userId: user.id }, }) diff --git a/application/backend/src/controllers/SettingsController.test.ts b/application/backend/src/controllers/SettingsController.test.ts index c21e53da3..df318d10a 100644 --- a/application/backend/src/controllers/SettingsController.test.ts +++ b/application/backend/src/controllers/SettingsController.test.ts @@ -3,7 +3,7 @@ import { generateToken } from '../authentication' import { Api } from '../Api' import { resetDB, updateLogo } from 'common/testing/TestHelpers' import logoHashes from '../../../common/testing/fixtures/logo_hashes.json' -import { ORG_ADMIN_ID } from 'common/testing/seed' +import { TestUsers } from 'common/testing/constants' import prisma from '../PrismaClient' import { createHash } from 'crypto' @@ -17,7 +17,7 @@ describe('SettingsController', () => { beforeAll(async () => { orgAdminToken = await generateToken({ - userId: ORG_ADMIN_ID, + userId: TestUsers.ORG_ADMIN.id, }) api.run() diff --git a/application/backend/src/controllers/StudiesController.test.ts b/application/backend/src/controllers/StudiesController.test.ts index f936c1ba1..bce429b78 100644 --- a/application/backend/src/controllers/StudiesController.test.ts +++ b/application/backend/src/controllers/StudiesController.test.ts @@ -8,15 +8,10 @@ import { UpdateStudyRequest, GetAllStudiesByParticipantResponse, } from 'common/types/api/studies' -import { - PARTICIPANT_UNANSWERED_ID, - PARTICIPANT_COMPLETED_ID, - STUDY_ADMIN_ID, -} from 'common/testing/seed' +import { TestStudies, TestUsers } from 'common/testing/constants' import { resetDB, updateLogo } from 'common/testing/TestHelpers' import logoHashes from '../../../common/testing/fixtures/logo_hashes.json' import { generateToken } from '../authentication' -import { ORG_ADMIN_ID } from 'common/testing/seed' import { createHash } from 'crypto' const fixturesPath = '../common/testing/fixtures/' @@ -28,8 +23,8 @@ describe('StudiesController', () => { let orgAdminToken: string let studyAdminToken: string - const testStudyId: number = 1 - const testStudyId2: number = 2 + const testStudyId: number = TestStudies.TEST_STUDY.id + const testStudyId2: number = TestStudies.TEST_STUDY_2.id beforeAll(async () => { api.run() @@ -38,8 +33,8 @@ describe('StudiesController', () => { beforeEach(async () => { await resetDB() - orgAdminToken = await generateToken({ userId: ORG_ADMIN_ID }) - studyAdminToken = await generateToken({ userId: STUDY_ADMIN_ID }) + orgAdminToken = await generateToken({ userId: TestUsers.ORG_ADMIN.id }) + studyAdminToken = await generateToken({ userId: TestUsers.STUDY_ADMIN.id }) }) afterAll(async () => { @@ -98,7 +93,7 @@ describe('StudiesController', () => { describe('GET /studies/list', () => { it('should return a list of studies for logged in user', async () => { const token = await generateToken({ - userId: PARTICIPANT_UNANSWERED_ID, + userId: TestUsers.PARTICIPANT_UNANSWERED.id, }) const response = await request(app) @@ -113,7 +108,7 @@ describe('StudiesController', () => { it('should not return any token information', async () => { const token = await generateToken({ - userId: PARTICIPANT_UNANSWERED_ID, + userId: TestUsers.PARTICIPANT_UNANSWERED.id, }) const response = await request(app) @@ -140,7 +135,7 @@ describe('StudiesController', () => { it('should return a different list of studies for a different logged in user', async () => { const token = await generateToken({ - userId: PARTICIPANT_COMPLETED_ID, + userId: TestUsers.PARTICIPANT_COMPLETED.id, }) const response = await request(app) @@ -190,7 +185,7 @@ describe('StudiesController', () => { it('should not return any token information to participant', async () => { const token = await generateToken({ - userId: PARTICIPANT_UNANSWERED_ID, + userId: TestUsers.PARTICIPANT_UNANSWERED.id, }) const response = await request(app) .get(`/studies/${testStudyId}`) @@ -263,11 +258,11 @@ describe('StudiesController', () => { select: { name: true, admins: true }, }) expect(createdStudy?.name).toBe(newStudyName) - expect(createdStudy?.admins.map((val) => val.id)).toContain(STUDY_ADMIN_ID) + expect(createdStudy?.admins.map((val) => val.id)).toContain(TestUsers.STUDY_ADMIN.id) }) it('should return an error if the study already exists', async () => { - const studyNameAlreadyExists = 'Test Study' + const studyNameAlreadyExists = TestStudies.TEST_STUDY.name const response = await request(app) .post('/studies') .set({ Authorization: `Bearer ${orgAdminToken}` }) @@ -293,7 +288,7 @@ describe('StudiesController', () => { describe('PATCH /studies/:studyId', () => { it('should update an existing study', async () => { - const studyName: string = 'Test Study' + const studyName: string = TestStudies.TEST_STUDY.name // Check test study exists const existingStudy = await prisma.study.findFirst({ where: { name: studyName }, diff --git a/application/backend/src/controllers/SurveysController.test.ts b/application/backend/src/controllers/SurveysController.test.ts index 166fb7b1a..d98f98761 100644 --- a/application/backend/src/controllers/SurveysController.test.ts +++ b/application/backend/src/controllers/SurveysController.test.ts @@ -13,13 +13,7 @@ import { UpdateSurveyRequest, GetSurveyVersionByVersionNumberResponse, } from 'common/types/api/surveys' -import { - DEPENDENT_ID, - ORG_ADMIN_ID, - PARTICIPANT_COMPLETED_ID, - PARTICIPANT_UNANSWERED_ID, - SECOND_GUARDIAN_ID, -} from 'common/testing/seed' +import { TestUsers } from 'common/testing/constants' const api = new Api() const app = api.app @@ -27,11 +21,11 @@ let token: string, tokenNoAnswers: string, tokenAdmin: string describe('SurveysController', () => { beforeAll(async () => { - token = await generateToken({ userId: PARTICIPANT_COMPLETED_ID }) + token = await generateToken({ userId: TestUsers.PARTICIPANT_COMPLETED.id }) tokenNoAnswers = await generateToken({ - userId: PARTICIPANT_UNANSWERED_ID, + userId: TestUsers.PARTICIPANT_UNANSWERED.id, }) - tokenAdmin = await generateToken({ userId: ORG_ADMIN_ID }) + tokenAdmin = await generateToken({ userId: TestUsers.ORG_ADMIN.id }) api.run() }) @@ -122,7 +116,7 @@ describe('SurveysController', () => { expect(response.status).toBe(204) const participant = await prisma.surveyVersionAnswers.findFirst({ where: { - profileId: PARTICIPANT_COMPLETED_ID, + profileId: TestUsers.PARTICIPANT_COMPLETED.id, version: { studyId: 1, }, @@ -130,7 +124,7 @@ describe('SurveysController', () => { }) expect(participant?.answers[1].answers).toEqual([true, 'Choice 1']) const aLog = await prisma.auditLog.findFirstOrThrow({ - where: { userId: PARTICIPANT_COMPLETED_ID }, + where: { userId: TestUsers.PARTICIPANT_COMPLETED.id }, }) expect(aLog.resource).toBe('studies/survey-answers') expect(aLog.operation).toBe('CREATE') @@ -183,7 +177,7 @@ describe('SurveysController', () => { it('participant should inherit answers from both guardians correctly', async () => { const secondGuardianToken = generateToken({ - userId: SECOND_GUARDIAN_ID, + userId: TestUsers.GUARDIAN_2.id, }) const reqBody: UpdateSurveyAnswersRequest = { @@ -197,7 +191,7 @@ describe('SurveysController', () => { expect(response.status).toBe(204) const dependentAnswers = await prisma.surveyVersionAnswers.findFirstOrThrow({ where: { - profileId: DEPENDENT_ID, + profileId: TestUsers.DEPENDENT.id, version: { studyId: 1, }, @@ -237,7 +231,7 @@ describe('SurveysController', () => { expect(survey?.data[0].elements[1].data.text).toBe('Question 1') const aLog = await prisma.auditLog.findFirstOrThrow({ - where: { userId: ORG_ADMIN_ID }, + where: { userId: TestUsers.ORG_ADMIN.id }, }) expect(aLog.resource).toBe('studies/surveys') expect(aLog.operation).toBe('UPDATE') diff --git a/application/backend/src/controllers/UsersController.test.ts b/application/backend/src/controllers/UsersController.test.ts index 60822eb58..0ca969e72 100644 --- a/application/backend/src/controllers/UsersController.test.ts +++ b/application/backend/src/controllers/UsersController.test.ts @@ -11,16 +11,7 @@ import { ResetPasswordRequest, } from 'common/types/api/users' import { Role } from '@prisma/client' -import { - FE_TEST_STUDY_ID, - OPERATOR_ADMIN_ID, - ORG_ADMIN_2_ID, - ORG_ADMIN_EMAIL, - ORG_ADMIN_ID, - PARTICIPANT_UNANSWERED_ID, - STUDY_ADMIN_ID, - TEST_STUDY_ID, -} from 'common/testing/seed' +import { TestUsers, TestStudies } from 'common/testing/constants' import { NodemailerMock } from 'nodemailer-mock' import * as nodemailer from 'nodemailer' @@ -35,9 +26,9 @@ describe('UsersController', () => { let studyAdminToken: string beforeAll(async () => { - opAdminToken = await generateToken({ userId: OPERATOR_ADMIN_ID }) - orgAdminToken = await generateToken({ userId: ORG_ADMIN_ID }) - studyAdminToken = await generateToken({ userId: STUDY_ADMIN_ID }) + opAdminToken = await generateToken({ userId: TestUsers.OPERATOR_ADMIN.id }) + orgAdminToken = await generateToken({ userId: TestUsers.ORG_ADMIN.id }) + studyAdminToken = await generateToken({ userId: TestUsers.STUDY_ADMIN.id }) api.run() }) @@ -95,7 +86,7 @@ describe('UsersController', () => { describe('GET /users/:id', () => { it('should return a user by ID', async () => { - const userId = PARTICIPANT_UNANSWERED_ID + const userId = TestUsers.PARTICIPANT_UNANSWERED.id const response = await request(app) .get(`/users/${userId}`) .set({ Authorization: `Bearer ${orgAdminToken}` }) @@ -169,7 +160,7 @@ describe('UsersController', () => { describe('PATCH /users/:id', () => { it('should update a user by ID', async () => { - const userId: number = PARTICIPANT_UNANSWERED_ID + const userId: number = TestUsers.PARTICIPANT_UNANSWERED.id const newFirstName: string = 'Updated' @@ -179,8 +170,8 @@ describe('UsersController', () => { const testUser: RegisterRequest = { firstName: 'Test', lastName: 'User', - email: 'test2@example.com', - password: 'Password123', + email: TestUsers.PARTICIPANT_UNANSWERED.email, + password: TestUsers.PARTICIPANT_UNANSWERED.password, role: Role.Participant, } @@ -218,7 +209,7 @@ describe('UsersController', () => { }) it('Study Admins can not edit org admins', async () => { const response = await request(app) - .patch(`/users/${ORG_ADMIN_ID}`) + .patch(`/users/${TestUsers.ORG_ADMIN.id}`) .set({ Authorization: `Bearer ${studyAdminToken}` }) .send({ firstName: 'Afijodsjfo' }) expect(response.ok).toBe(false) @@ -235,7 +226,7 @@ describe('UsersController', () => { }) it('Study Admins can not edit their own role', async () => { const response = await request(app) - .patch(`/users/${STUDY_ADMIN_ID}`) + .patch(`/users/${TestUsers.STUDY_ADMIN.id}`) .set({ Authorization: `Bearer ${studyAdminToken}` }) .send({ role: Role.OrganisationAdmin }) expect(response.ok).toBe(false) @@ -244,21 +235,27 @@ describe('UsersController', () => { describe('POST /users/:id/make-study-admin/:studyId', () => { it('Can make a user a study admin', async () => { - await prisma.user.update({ where: { id: ORG_ADMIN_2_ID }, data: { role: Role.StudyAdmin } }) + await prisma.user.update({ + where: { id: TestUsers.ORG_ADMIN_2.id }, + data: { role: Role.StudyAdmin }, + }) const response = await request(app) - .post(`/users/${ORG_ADMIN_2_ID}/make-study-admin/${TEST_STUDY_ID}`) + .post(`/users/${TestUsers.ORG_ADMIN_2.id}/make-study-admin/${TestStudies.TEST_STUDY.id}`) .set({ Authorization: `Bearer ${studyAdminToken}` }) expect(response.ok).toBe(true) const updatedUser = await prisma.user.findUniqueOrThrow({ - where: { id: ORG_ADMIN_2_ID }, + where: { id: TestUsers.ORG_ADMIN_2.id }, select: { adminOfStudies: { select: { id: true } } }, }) expect(updatedUser.adminOfStudies).toHaveLength(1) }) it('Study admins can only add study admins to their own study', async () => { - await prisma.user.update({ where: { id: ORG_ADMIN_2_ID }, data: { role: Role.StudyAdmin } }) + await prisma.user.update({ + where: { id: TestUsers.ORG_ADMIN_2.id }, + data: { role: Role.StudyAdmin }, + }) const response = await request(app) - .post(`/users/${ORG_ADMIN_2_ID}/make-study-admin/${FE_TEST_STUDY_ID}`) + .post(`/users/${TestUsers.ORG_ADMIN_2.id}/make-study-admin/${TestStudies.FE_TEST_STUDY.id}`) .set({ Authorization: `Bearer ${studyAdminToken}` }) expect(response.ok).toBe(false) }) @@ -267,11 +264,11 @@ describe('UsersController', () => { describe('POST /users/:id/remove-study-admin/:studyId', () => { it('Can remove a study admin from a study', async () => { const response = await request(app) - .post(`/users/${STUDY_ADMIN_ID}/remove-study-admin/${TEST_STUDY_ID}`) + .post(`/users/${TestUsers.STUDY_ADMIN.id}/remove-study-admin/${TestStudies.TEST_STUDY.id}`) .set({ Authorization: `Bearer ${orgAdminToken}` }) expect(response.ok).toBe(true) const updatedUser = await prisma.user.findUniqueOrThrow({ - where: { id: STUDY_ADMIN_ID }, + where: { id: TestUsers.STUDY_ADMIN.id }, select: { adminOfStudies: { select: { id: true } } }, }) expect(updatedUser.adminOfStudies).toHaveLength(0) @@ -279,16 +276,19 @@ describe('UsersController', () => { it('Study admins can remove other study admins', async () => { await prisma.user.update({ - where: { id: ORG_ADMIN_2_ID }, - data: { role: Role.StudyAdmin, adminOfStudies: { connect: { id: TEST_STUDY_ID } } }, + where: { id: TestUsers.ORG_ADMIN_2.id }, + data: { + role: Role.StudyAdmin, + adminOfStudies: { connect: { id: TestStudies.TEST_STUDY.id } }, + }, }) const response = await request(app) - .post(`/users/${ORG_ADMIN_2_ID}/remove-study-admin/${TEST_STUDY_ID}`) + .post(`/users/${TestUsers.ORG_ADMIN_2.id}/remove-study-admin/${TestStudies.TEST_STUDY.id}`) .set({ Authorization: `Bearer ${studyAdminToken}` }) expect(response.ok).toBe(true) const updatedUser = await prisma.user.findUniqueOrThrow({ - where: { id: ORG_ADMIN_2_ID }, + where: { id: TestUsers.ORG_ADMIN_2.id }, select: { adminOfStudies: { select: { id: true } } }, }) expect(updatedUser.adminOfStudies).toHaveLength(0) @@ -297,7 +297,7 @@ describe('UsersController', () => { describe('DELETE /users/:id', () => { it('should delete a user by ID', async () => { - const userId: number = PARTICIPANT_UNANSWERED_ID + const userId: number = TestUsers.PARTICIPANT_UNANSWERED.id // Check that user exists in db const existingUser = await prisma.user.findFirst({ where: { id: userId } }) @@ -332,7 +332,7 @@ describe('UsersController', () => { describe('PATCH /users/:id/role', () => { it('should update a users role to the role provided', async () => { - const userID: number = PARTICIPANT_UNANSWERED_ID + const userID: number = TestUsers.PARTICIPANT_UNANSWERED.id // Check user role const existingUser = await prisma.user.findFirst({ where: { id: userID } }) @@ -355,7 +355,7 @@ describe('UsersController', () => { }) it('should return a Validation Error and keep the same role if the provided role is invalid', async () => { - const userID: number = PARTICIPANT_UNANSWERED_ID + const userID: number = TestUsers.PARTICIPANT_UNANSWERED.id // Check user role const existingUser = await prisma.user.findFirst({ where: { id: userID } }) @@ -396,7 +396,7 @@ describe('UsersController', () => { }) describe('POST /users/password/generate-reset-link', () => { - const userEmail: string = 'test2@example.com' + const userEmail: string = TestUsers.PARTICIPANT_UNANSWERED.email it('should generate and send a password reset link to the users email', async () => { const generatePasswordResetLinkResponse = await request(app) @@ -416,7 +416,7 @@ describe('UsersController', () => { // Validate the URL structure const emailText = sentEmails[0].text - const hostname = process.env.HOSTNAME || 'ctrl.garvan.org.au' + const hostname = process.env.HOSTNAME || 'ctrl.garvan.org.au' // TODO: when will the alternate condition be used (or correct?)? Is it a default var? if so should be changed const urlRegex = new RegExp( `${hostname.replace(/\./g, '\\.')}/reset-password\\?token=[a-f0-9]{64}`, ) @@ -426,7 +426,7 @@ describe('UsersController', () => { it('should link to admin portal for admin reset', async () => { const generatePasswordResetLinkResponse = await request(app) .post('/users/password/generate-reset-link') - .send({ email: ORG_ADMIN_EMAIL }) + .send({ email: TestUsers.ORG_ADMIN.email }) expect(generatePasswordResetLinkResponse.status).toBe(200) @@ -434,14 +434,14 @@ describe('UsersController', () => { expect(sentEmails).toHaveLength(1) expect(sentEmails[0]).toMatchObject({ - from: 'CTRL ', + from: 'CTRL ', //TODO: check if Garvan is hardcoded here subject: 'CTRL - Password Reset Link', - to: ORG_ADMIN_EMAIL, + to: TestUsers.ORG_ADMIN.email, }) // Validate the URL structure const emailText = sentEmails[0].text - const hostname = process.env.ADMIN_HOSTNAME || 'admin.ctrl.garvan.org.au' + const hostname = process.env.ADMIN_HOSTNAME || 'admin.ctrl.garvan.org.au' // TODO: Ditto to above ln 410 const urlRegex = new RegExp( `${hostname.replace(/\./g, '\\.')}/update-password\\?token=[a-f0-9]{64}`, ) @@ -452,7 +452,7 @@ describe('UsersController', () => { const generatePasswordResetLinkResponse = await request(app) .post('/users/password/generate-reset-link') .set('x-client-type', 'user-client') - .send({ email: ORG_ADMIN_EMAIL }) + .send({ email: TestUsers.ORG_ADMIN.email }) expect(generatePasswordResetLinkResponse.status).toBe(200) @@ -477,7 +477,7 @@ describe('UsersController', () => { }) describe('POST /users/password/reset', () => { - const userId = 105 + const userId = TestUsers.PASSWORD_RESET_USER.id const resetToken = 'valid-reset-token' beforeAll(async () => {}) @@ -485,7 +485,7 @@ describe('UsersController', () => { it('should reset the password when given a valid reset token and new password', async () => { const requestBody: ResetPasswordRequest = { token: resetToken, - newPassword: 'NewPassword123!', + newPassword: TestUsers.GUARDIAN_2.password, // Providing a different test users password } const response = await request(app).post('/users/password/reset').send(requestBody) @@ -495,7 +495,9 @@ describe('UsersController', () => { // Check that the user's password was updated const updatedUser = await prisma.user.findUnique({ where: { id: userId } }) expect(updatedUser).not.toBeNull() - expect(await verifyPassword(updatedUser!.password, 'OldPassword123')).toBe(false) + expect( + await verifyPassword(updatedUser!.password, TestUsers.PASSWORD_RESET_USER.password), + ).toBe(false) expect(await verifyPassword(updatedUser!.password, requestBody.newPassword)).toBe(true) // Check that the reset token was marked as used @@ -510,7 +512,7 @@ describe('UsersController', () => { const response = await request(app) .post('/users/password/reset') - .send({ token: invalidToken, newPassword: 'NewPassword123!' }) + .send({ token: invalidToken, newPassword: TestUsers.GUARDIAN_2.password }) // Using random test user's PW here (to ensure it meets pw requirements) expect(response.status).toBe(403) expect(response.body.message).toBe('Reset token invalid') @@ -525,7 +527,7 @@ describe('UsersController', () => { const requestBody: ResetPasswordRequest = { token: resetToken, - newPassword: 'AnotherPassword123!', + newPassword: TestUsers.GUARDIAN_2.password, // Using random test user's PW here (to ensure it meets pw requirements) } const response = await request(app).post('/users/password/reset').send(requestBody) @@ -543,7 +545,7 @@ describe('UsersController', () => { const requestBody: ResetPasswordRequest = { token: resetToken, - newPassword: 'NewPassword123!', + newPassword: TestUsers.GUARDIAN_2.password, // Using random test user's PW here (to ensure it meets pw requirements) } const response = await request(app).post('/users/password/reset').send(requestBody) @@ -573,7 +575,7 @@ describe('UsersController', () => { expect(res1.body.data).toHaveLength(0) await prisma.user.delete({ where: { - id: OPERATOR_ADMIN_ID, + id: TestUsers.OPERATOR_ADMIN.id, }, }) const res2 = await request(app) @@ -581,14 +583,14 @@ describe('UsersController', () => { .set({ Authorization: `Bearer ${orgAdminToken}` }) expect(res2.ok).toBe(true) expect(res2.body.data).toHaveLength(1) - expect(res2.body.data[0].id).toBe(OPERATOR_ADMIN_ID) + expect(res2.body.data[0].id).toBe(TestUsers.OPERATOR_ADMIN.id) }) }) describe('PATCH /users/{userId}/restore', () => { it('Fails if user is not deleted', async () => { const res = await request(app) - .patch(`/users/${OPERATOR_ADMIN_ID}/restore`) + .patch(`/users/${TestUsers.OPERATOR_ADMIN.id}/restore`) .set({ Authorization: `Bearer ${orgAdminToken}` }) expect(res.ok).toBe(false) @@ -597,19 +599,19 @@ describe('UsersController', () => { it('Restores a deleted user', async () => { await prisma.user.delete({ where: { - id: OPERATOR_ADMIN_ID, + id: TestUsers.OPERATOR_ADMIN.id, }, }) const res = await request(app) - .patch(`/users/${OPERATOR_ADMIN_ID}/restore`) + .patch(`/users/${TestUsers.OPERATOR_ADMIN.id}/restore`) .set({ Authorization: `Bearer ${orgAdminToken}` }) expect(res.ok).toBe(true) const user = await prisma.user.findFirst({ where: { - id: OPERATOR_ADMIN_ID, + id: TestUsers.OPERATOR_ADMIN.id, }, }) expect(user).not.toBeNull() diff --git a/application/backend/src/routes.ts b/application/backend/src/routes.ts index 0105ba233..f13375ed7 100644 --- a/application/backend/src/routes.ts +++ b/application/backend/src/routes.ts @@ -183,7 +183,7 @@ const models: TsoaRoute.Models = { "ResetPasswordRequest": { "dataType": "refObject", "properties": { - "newPassword": {"dataType":"string","required":true,"validators":{"minLength":{"errorMsg":"Password must be at least 8 characters","value":8}}}, + "newPassword": {"dataType":"string","required":true,"validators":{"minLength":{"errorMsg":"Password must be at least 14 characters","value":14}}}, "token": {"dataType":"string","required":true}, }, "additionalProperties": false, @@ -562,7 +562,7 @@ const models: TsoaRoute.Models = { // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa "Partial_RegisterParticipantRequest_": { "dataType": "refAlias", - "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"firstName":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"value":1}}},"middleName":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"value":1}}},"lastName":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"value":1}}},"email":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"pattern":{"errorMsg":"please provide valid email","value":"^(.+)@(.+)$"}}},"mobile":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"pattern":{"errorMsg":"please provide valid phone number","value":"^(\\+\\d{1,2}\\s?)?\\(?\\d{3}\\)?[\\s.-]?\\d{3}[\\s.-]?\\d{4}$"}}},"preferredContact":{"dataType":"union","subSchemas":[{"ref":"ContactMethod"},{"dataType":"undefined"}]},"addressLine":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"value":1}}},"suburb":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"value":1}}},"postcode":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"value":1}}},"state":{"dataType":"union","subSchemas":[{"ref":"StateTerritory"},{"dataType":"undefined"}]},"password":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"errorMsg":"Password must be at least 8 characters","value":8}}},"dob":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"isDate":{"errorMsg":"Date of birth must be of date format"}}},"participantType":{"dataType":"union","subSchemas":[{"ref":"ParticipantType"},{"dataType":"undefined"}]},"nextOfKin":{"dataType":"union","subSchemas":[{"ref":"AlternativeContact"},{"dataType":"undefined"}]},"dependents":{"dataType":"union","subSchemas":[{"dataType":"array","array":{"dataType":"refObject","ref":"OnBehalf"}},{"dataType":"undefined"}]},"externalId":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}]}},"validators":{}}, + "type": {"dataType":"nestedObjectLiteral","nestedProperties":{"firstName":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"value":1}}},"middleName":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"value":1}}},"lastName":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"value":1}}},"email":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"pattern":{"errorMsg":"please provide valid email","value":"^(.+)@(.+)$"}}},"mobile":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"pattern":{"errorMsg":"please provide valid phone number","value":"^(\\+\\d{1,2}\\s?)?\\(?\\d{3}\\)?[\\s.-]?\\d{3}[\\s.-]?\\d{4}$"}}},"preferredContact":{"dataType":"union","subSchemas":[{"ref":"ContactMethod"},{"dataType":"undefined"}]},"addressLine":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"value":1}}},"suburb":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"value":1}}},"postcode":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"value":1}}},"state":{"dataType":"union","subSchemas":[{"ref":"StateTerritory"},{"dataType":"undefined"}]},"password":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"minLength":{"errorMsg":"Password must be at least 14 characters","value":14}}},"dob":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}],"validators":{"isDate":{"errorMsg":"Date of birth must be of date format"}}},"participantType":{"dataType":"union","subSchemas":[{"ref":"ParticipantType"},{"dataType":"undefined"}]},"nextOfKin":{"dataType":"union","subSchemas":[{"ref":"AlternativeContact"},{"dataType":"undefined"}]},"dependents":{"dataType":"union","subSchemas":[{"dataType":"array","array":{"dataType":"refObject","ref":"OnBehalf"}},{"dataType":"undefined"}]},"externalId":{"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"undefined"}]}},"validators":{}}, }, // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa "UpdateProfileRequest": { @@ -850,7 +850,7 @@ const models: TsoaRoute.Models = { "middleName": {"dataType":"string","validators":{"minLength":{"value":1}}}, "lastName": {"dataType":"string","required":true,"validators":{"minLength":{"value":1}}}, "email": {"dataType":"string","required":true,"validators":{"pattern":{"errorMsg":"Please provide valid email","value":"^(.+)@(.+)$"}}}, - "password": {"dataType":"string","required":true,"validators":{"minLength":{"errorMsg":"Password must be at least 8 characters","value":8}}}, + "password": {"dataType":"string","required":true,"validators":{"minLength":{"errorMsg":"Password must be at least 14 characters","value":14}}}, "role": {"ref":"Role","required":true}, }, "additionalProperties": false, @@ -870,7 +870,7 @@ const models: TsoaRoute.Models = { "dataType": "refObject", "properties": { "email": {"dataType":"string","required":true,"validators":{"pattern":{"errorMsg":"Please provide valid email","value":"^(.+)@(.+)$"}}}, - "password": {"dataType":"string","required":true,"validators":{"minLength":{"errorMsg":"Password must be at least 8 characters","value":8}}}, + "password": {"dataType":"string","required":true,"validators":{"minLength":{"errorMsg":"Password must be at least 14 characters","value":14}}}, }, "additionalProperties": false, }, @@ -898,7 +898,7 @@ const models: TsoaRoute.Models = { "suburb": {"dataType":"string","required":true,"validators":{"minLength":{"value":1}}}, "postcode": {"dataType":"string","required":true,"validators":{"minLength":{"value":1}}}, "state": {"ref":"StateTerritory","required":true}, - "password": {"dataType":"string","required":true,"validators":{"minLength":{"errorMsg":"Password must be at least 8 characters","value":8}}}, + "password": {"dataType":"string","required":true,"validators":{"minLength":{"errorMsg":"Password must be at least 14 characters","value":14}}}, "dob": {"dataType":"string","required":true,"validators":{"isDate":{"errorMsg":"Date of birth must be of date format"}}}, "participantType": {"ref":"ParticipantType","required":true}, "nextOfKin": {"ref":"AlternativeContact","required":true}, diff --git a/application/backend/swagger.json b/application/backend/swagger.json index 3b1cebc51..628b3d0c4 100644 --- a/application/backend/swagger.json +++ b/application/backend/swagger.json @@ -357,7 +357,7 @@ "properties": { "newPassword": { "type": "string", - "minLength": 8 + "minLength": 14 }, "token": { "type": "string" @@ -1514,7 +1514,7 @@ }, "password": { "type": "string", - "minLength": 8 + "minLength": 14 }, "dob": { "type": "string" @@ -2435,7 +2435,7 @@ }, "password": { "type": "string", - "minLength": 8 + "minLength": 14 }, "role": { "$ref": "#/components/schemas/Role" @@ -2521,7 +2521,7 @@ }, "password": { "type": "string", - "minLength": 8 + "minLength": 14 } }, "required": [ @@ -2598,7 +2598,7 @@ }, "password": { "type": "string", - "minLength": 8 + "minLength": 14 }, "dob": { "type": "string" diff --git a/application/backend/tests/integration/Auth.test.ts b/application/backend/tests/integration/Auth.test.ts index ce65825ce..73e7ab2ab 100644 --- a/application/backend/tests/integration/Auth.test.ts +++ b/application/backend/tests/integration/Auth.test.ts @@ -7,7 +7,7 @@ import { RegisterResponse, } from 'common/types/api/auth' import { resetDB } from 'common/testing/TestHelpers' -import { ORG_ADMIN_ID, PARTICIPANT_UNANSWERED_EMAIL, TEST_STUDY } from 'common/testing/seed' +import { TestUsers, TestStudies, TestInvites } from 'common/testing/constants' import { ContactMethod, ParticipantType, @@ -33,7 +33,7 @@ describe('Auth', () => { firstName: 'Test', lastName: 'Admin', email: 'test@admin.com', - password: 'Password123', + password: TestUsers.ORG_ADMIN.password, // Note: using test data so it fits password policy role: Role.OrganisationAdmin, } @@ -41,7 +41,7 @@ describe('Auth', () => { firstName: 'Test', lastName: 'Participant', email: 'test@participant.com', - password: 'Password123', + password: TestUsers.ORG_ADMIN.password, // Note: using test data so it fits password policy role: Role.Participant, } @@ -53,7 +53,7 @@ describe('Auth', () => { await resetDB() const orgAdminToken = await generateToken({ - userId: ORG_ADMIN_ID, + userId: TestUsers.ORG_ADMIN.id, }) // Register Admin @@ -122,7 +122,7 @@ describe('Auth', () => { const participantRequest: RegisterParticipantRequest = { firstName: 'John', lastName: 'Doe', - email: 'john@example.com', + email: TestInvites.INVITE_2_PENDING.email, password: 'johnDoesP@ssword123', mobile: '+61477777777', addressLine: '123 Some Street', @@ -143,7 +143,7 @@ describe('Auth', () => { const participantInviteId = await prisma.invite.findFirstOrThrow({ where: { email: participantRequest.email, - study: { name: TEST_STUDY }, + study: { name: TestStudies.TEST_STUDY.name }, }, }) @@ -205,8 +205,8 @@ describe('Auth', () => { it('Should support OTP based login', async () => { jest.replaceProperty(config, 'otp', true) const loginRequest: LoginRequest = { - email: PARTICIPANT_UNANSWERED_EMAIL, - password: 'Testpassword1', + email: TestUsers.PARTICIPANT_UNANSWERED.email, + password: TestUsers.PARTICIPANT_UNANSWERED.password, } const res = await request(app).post('/auth/login').send(loginRequest) const sentEmails = mockNodeMailer.mock.getSentMail() diff --git a/application/backend/tests/integration/Dependents.test.ts b/application/backend/tests/integration/Dependents.test.ts index ac9cda6d9..ce900abef 100644 --- a/application/backend/tests/integration/Dependents.test.ts +++ b/application/backend/tests/integration/Dependents.test.ts @@ -11,7 +11,7 @@ import { } from 'common/types/api/users/ParticipantProfile' import prisma from '../../src/PrismaClient' -import { ORG_ADMIN_ID } from 'common/testing/seed' +import { TestUsers } from 'common/testing/constants' const api = new Api() const app = api.app @@ -22,7 +22,7 @@ describe('Survey tests', () => { beforeAll(async () => { api.run() await resetDB() - adminToken = await generateToken({ userId: ORG_ADMIN_ID }) + adminToken = await generateToken({ userId: TestUsers.ORG_ADMIN.id }) }) afterAll(async () => { @@ -56,7 +56,7 @@ describe('Survey tests', () => { mobile: '0412345678', nextOfKin: { email: 'nok@gmail.com', firstName: 'N', lastName: 'k' }, participantType: ParticipantType.STANDARD, - password: 'PASS123of2389vNDFS!', + password: TestUsers.PARTICIPANT_COMPLETED.password, // Using test user pw to meet pw requirements postcode: '1234', preferredContact: ContactMethod.MOBILE, state: StateTerritory.ACT, diff --git a/application/backend/tests/integration/Elsa.test.ts b/application/backend/tests/integration/Elsa.test.ts index 4ee7a27bd..cbb3a301a 100644 --- a/application/backend/tests/integration/Elsa.test.ts +++ b/application/backend/tests/integration/Elsa.test.ts @@ -4,7 +4,7 @@ import { resetDB } from 'common/testing/TestHelpers' import { generateToken } from '../../src/authentication' import prisma from '../../src/PrismaClient' -import { ORG_ADMIN_ID, PARTICIPANT_COMPLETED_ID } from 'common/testing/seed' +import { TestUsers } from 'common/testing/constants' const api = new Api() const app = api.app @@ -14,7 +14,7 @@ describe('Elsa Integration', () => { beforeAll(async () => { api.run() - orgAdminToken = await generateToken({ userId: ORG_ADMIN_ID }) + orgAdminToken = await generateToken({ userId: TestUsers.ORG_ADMIN.id }) await resetDB() }) @@ -36,7 +36,7 @@ describe('Elsa Integration', () => { response = await request(app) .post('/elsa/duos') .set({ Authorization: `Apikey ${token}` }) - .send({ participantIds: [`PID-TEST1-${PARTICIPANT_COMPLETED_ID}`] }) + .send({ participantIds: [`PID-TEST1-${TestUsers.PARTICIPANT_COMPLETED.id}`] }) expect(response.body.data[0].duos).toEqual(['DUO:0000006']) }) it('Can disable elsa integration', async () => { diff --git a/application/backend/tests/integration/Invites.test.ts b/application/backend/tests/integration/Invites.test.ts index f6d6d259e..763342c0f 100644 --- a/application/backend/tests/integration/Invites.test.ts +++ b/application/backend/tests/integration/Invites.test.ts @@ -13,7 +13,7 @@ import { generateToken } from '../../src/authentication' import { RegisterParticipantRequest } from 'common/types/api/auth' import { GetInvitesResponse, InviteParticipantsResponse } from 'common/types/api/participants' import prisma from '../../src/PrismaClient' -import { ORG_ADMIN_ID } from 'common/testing/seed' +import { TestUsers } from 'common/testing/constants' import config from '../../src/config' jest.mock('../../src/config') @@ -31,7 +31,7 @@ describe('Participant Invites', () => { middleName: 'James', lastName: 'Doe', email: 'john.doe@email.com', - password: 'Password123', + password: TestUsers.PARTICIPANT_COMPLETED.password, // Note: using test users pw to match requirements dob: '2000-05-21', mobile: '0412341234', addressLine: '123 Sydney Street', @@ -52,7 +52,7 @@ describe('Participant Invites', () => { beforeAll(async () => { api.run() - orgAdminToken = await generateToken({ userId: ORG_ADMIN_ID }) + orgAdminToken = await generateToken({ userId: TestUsers.ORG_ADMIN.id }) await resetDB() }) diff --git a/application/backend/tests/integration/ProtectedRoutes.test.ts b/application/backend/tests/integration/ProtectedRoutes.test.ts index 6199b9901..3530a0d9b 100644 --- a/application/backend/tests/integration/ProtectedRoutes.test.ts +++ b/application/backend/tests/integration/ProtectedRoutes.test.ts @@ -3,6 +3,7 @@ import { generateToken } from '../../src/authentication' import { Api } from '../../src/Api' import { Role } from '@prisma/client' import { resetDB } from 'common/testing/TestHelpers' +import { TestUsers } from 'common/testing/constants' enum HttpMethod { GET = 'get', @@ -32,9 +33,9 @@ describe('Protected Routes', () => { const checkProtectedRoutes = async (route: Route): Promise => { // Check Role Based Route Protection - const opAdminToken = await generateToken({ userId: 96 }) - const orgAdminToken = await generateToken({ userId: 97 }) - const participantToken = await generateToken({ userId: 98 }) + const opAdminToken = await generateToken({ userId: TestUsers.OPERATOR_ADMIN.id }) + const orgAdminToken = await generateToken({ userId: TestUsers.ORG_ADMIN.id }) + const participantToken = await generateToken({ userId: TestUsers.PARTICIPANT_UNANSWERED.id }) const authHeaders = (token: string) => ({ Authorization: `Bearer ${token}` }) diff --git a/application/backend/tests/integration/ResetPassword.test.ts b/application/backend/tests/integration/ResetPassword.test.ts index fd09ec7af..1fb885862 100644 --- a/application/backend/tests/integration/ResetPassword.test.ts +++ b/application/backend/tests/integration/ResetPassword.test.ts @@ -3,6 +3,7 @@ import { Api } from '../../src/Api' import { resetDB } from 'common/testing/TestHelpers' import { verifyPassword } from '../../src/authentication' import prisma from '../../src/PrismaClient' +import { TestUsers } from 'common/testing/constants' import { NodemailerMock } from 'nodemailer-mock' import * as nodemailer from 'nodemailer' @@ -13,10 +14,11 @@ const app = api.app describe('User Password Reset', () => { let resetToken: string - const userId = 105 - const userEmail = 'test-reset-password@example.com' - const originalPassword = 'OldPassword123' - const newPassword = 'New@Password123' + const userEmail = TestUsers.PASSWORD_RESET_USER.email + const userId = TestUsers.PASSWORD_RESET_USER.id + const originalPassword = TestUsers.PASSWORD_RESET_USER.password + // Note: using different test data pw to ensure consistency with pw requirements + const newPassword = TestUsers.PARTICIPANT_COMPLETED.password beforeAll(async () => { api.run() diff --git a/application/backend/tests/integration/SoftDelete.test.ts b/application/backend/tests/integration/SoftDelete.test.ts index 96f46d2c1..fb6c08d45 100644 --- a/application/backend/tests/integration/SoftDelete.test.ts +++ b/application/backend/tests/integration/SoftDelete.test.ts @@ -4,7 +4,7 @@ import { Api } from '../../src/Api' import { resetDB } from 'common/testing/TestHelpers' import { UpdateSurveyAnswersRequest } from 'common/types/api/surveys' import { CreateStudyRequest } from 'common/types/api/studies' -import { ORG_ADMIN_ID, PARTICIPANT_UNANSWERED_ID } from 'common/testing/seed' +import { TestUsers } from 'common/testing/constants' import prisma from '../../src/PrismaClient' const api = new Api() @@ -20,11 +20,11 @@ describe('Soft Deletion', () => { await resetDB() participantToken = await generateToken({ - userId: PARTICIPANT_UNANSWERED_ID, + userId: TestUsers.PARTICIPANT_UNANSWERED.id, }) orgAdminToken = await generateToken({ - userId: ORG_ADMIN_ID, + userId: TestUsers.ORG_ADMIN.id, }) }) @@ -40,14 +40,14 @@ describe('Soft Deletion', () => { .set({ authorization: `Bearer ${participantToken}` }) .send(reqBody) - await prisma.user.delete({ where: { id: PARTICIPANT_UNANSWERED_ID } }) - const user = await prisma.user.findFirst({ where: { id: PARTICIPANT_UNANSWERED_ID } }) + await prisma.user.delete({ where: { id: TestUsers.PARTICIPANT_UNANSWERED.id } }) + const user = await prisma.user.findFirst({ where: { id: TestUsers.PARTICIPANT_UNANSWERED.id } }) expect(user).toBeNull() }) it('Audit log of submitted answer remains', async () => { const aLog = await prisma.auditLog.findFirstOrThrow({ - where: { userId: PARTICIPANT_UNANSWERED_ID }, + where: { userId: TestUsers.PARTICIPANT_UNANSWERED.id }, }) expect(aLog.resource).toBe('studies/survey-answers') expect(aLog.operation).toBe('CREATE') @@ -55,10 +55,10 @@ describe('Soft Deletion', () => { it('User can be restored', async () => { await prisma.user.update({ - where: { deleted: true, id: PARTICIPANT_UNANSWERED_ID }, + where: { deleted: true, id: TestUsers.PARTICIPANT_UNANSWERED.id }, data: { deleted: false }, }) - const user = await prisma.user.findFirst({ where: { id: PARTICIPANT_UNANSWERED_ID } }) + const user = await prisma.user.findFirst({ where: { id: TestUsers.PARTICIPANT_UNANSWERED.id } }) expect(user).toBeTruthy() }) @@ -79,7 +79,9 @@ describe('Soft Deletion', () => { }) it('Audit log of associated draft survey remains', async () => { - const aLog = await prisma.auditLog.findFirstOrThrow({ where: { userId: ORG_ADMIN_ID } }) + const aLog = await prisma.auditLog.findFirstOrThrow({ + where: { userId: TestUsers.ORG_ADMIN.id }, + }) expect(aLog.resource).toBe('studies') expect(aLog.operation).toBe('CREATE') expect(JSON.parse(aLog.requestBody as any).name).toBe(`${STUDY_NAME}`) diff --git a/application/backend/tests/integration/Studies.test.ts b/application/backend/tests/integration/Studies.test.ts index 518cb278d..df05b645f 100644 --- a/application/backend/tests/integration/Studies.test.ts +++ b/application/backend/tests/integration/Studies.test.ts @@ -13,7 +13,7 @@ import { GetAllStudiesResponse } from 'common/types/api/studies' import prisma from '../../src/PrismaClient' -import { TEST_STUDY, SECOND_TEST_STUDY } from 'common/testing/seed' +import { TestUsers, TestStudies } from 'common/testing/constants' const api = new Api() const app = api.app @@ -34,7 +34,7 @@ describe('Studies tests', () => { it('Two parents register for study 1, with two dependents. None of them appear in study 2', async () => { const testStudy = await prisma.study.findFirstOrThrow({ where: { - name: TEST_STUDY, + name: TestStudies.TEST_STUDY.name, }, select: { id: true, @@ -66,7 +66,7 @@ describe('Studies tests', () => { mobile: '0412345678', nextOfKin: { email: 'nok@gmail.com', firstName: 'N', lastName: 'k' }, participantType: ParticipantType.STANDARD, - password: 'PASS123of2389vNDFS!', + password: TestUsers.PARTICIPANT_COMPLETED.password, // Using test data pw to meet requirements postcode: '1234', preferredContact: ContactMethod.MOBILE, state: StateTerritory.ACT, @@ -130,7 +130,7 @@ describe('Studies tests', () => { studies: { some: { study: { - name: TEST_STUDY, + name: TestStudies.TEST_STUDY.name, }, }, }, @@ -149,7 +149,7 @@ describe('Studies tests', () => { studies: { some: { study: { - name: SECOND_TEST_STUDY, + name: TestStudies.TEST_STUDY_2.name, }, }, }, @@ -161,7 +161,7 @@ describe('Studies tests', () => { it('One of the parents registers for study 2. Study 2 does not show info from the other parent or either dependent', async () => { const secondTestStudy = await prisma.study.findFirstOrThrow({ where: { - name: SECOND_TEST_STUDY, + name: TestStudies.TEST_STUDY_2.name, }, select: { id: true, @@ -224,7 +224,7 @@ describe('Studies tests', () => { studies: { some: { study: { - name: SECOND_TEST_STUDY, + name: TestStudies.TEST_STUDY_2.name, }, }, }, @@ -265,7 +265,7 @@ describe('Studies tests', () => { // Answer study2 questions const secondTestStudy = await prisma.study.findFirstOrThrow({ where: { - name: SECOND_TEST_STUDY, + name: TestStudies.TEST_STUDY_2.name, }, select: { id: true, @@ -301,7 +301,7 @@ describe('Studies tests', () => { const secondTestStudy = await prisma.study.findFirstOrThrow({ where: { - name: SECOND_TEST_STUDY, + name: TestStudies.TEST_STUDY_2.name, }, select: { id: true, diff --git a/application/backend/tests/integration/Survey.test.ts b/application/backend/tests/integration/Survey.test.ts index 1d69d9804..5f06ddf8c 100644 --- a/application/backend/tests/integration/Survey.test.ts +++ b/application/backend/tests/integration/Survey.test.ts @@ -17,19 +17,21 @@ import { } from 'common/types/api/users/ParticipantProfile' import { GetParticipantsResponse } from 'common/types/api/participants' import prisma from '../../src/PrismaClient' -import { ORG_ADMIN_ID } from 'common/testing/seed' +import { TestInvites, TestStudies, TestUsers } from 'common/testing/constants' const api = new Api() const app = api.app let participantToken: string, adminToken: string describe('Survey tests', () => { + const testingUserId: number = 1 + beforeAll(async () => { api.run() await resetDB() - participantToken = await generateToken({ userId: 1 }) - adminToken = await generateToken({ userId: ORG_ADMIN_ID }) + participantToken = await generateToken({ userId: testingUserId }) + adminToken = await generateToken({ userId: TestUsers.ORG_ADMIN.id }) }) afterAll(async () => { @@ -40,13 +42,13 @@ describe('Survey tests', () => { const reqBody: RegisterParticipantRequest = { addressLine: 'abc', dob: '1990-01-01', - email: 'abcsdfwefijsdf@gjiodsf.com', + email: TestInvites.INVITE_PENDING.email, firstName: 'J', lastName: 'K', mobile: '0412345678', nextOfKin: { email: 'nok@gmail.com', firstName: 'N', lastName: 'k' }, participantType: ParticipantType.STANDARD, - password: 'PASS123of2389vNDFS!', + password: TestUsers.PARTICIPANT_COMPLETED.password, // Using test data to meet pw requirements postcode: '1234', preferredContact: ContactMethod.MOBILE, state: StateTerritory.ACT, @@ -59,7 +61,7 @@ describe('Survey tests', () => { studyId_emailHash: { //@ts-ignore email: reqBody.email, - studyId: 1, + studyId: TestStudies.TEST_STUDY.id, }, }, }) @@ -95,7 +97,7 @@ describe('Survey tests', () => { expect(res.statusCode).toBe(204) const res2 = await request(app) - .get('/studies/1/survey-steps') // Not sure why this was previously study 0 + .get('/studies/1/survey-steps') .set({ authorization: `Bearer ${participantToken}` }) expect(res2.statusCode).toBe(200) const data = res2.body as GetUserSurveyStepsResponse @@ -105,7 +107,7 @@ describe('Survey tests', () => { expect(data.data[1].last_updated).toBeUndefined() const res3 = await request(app) - .get('/studies/1/surveys/1/participants/1/answers') //All the seed ParticipantProfiles have ids like 98,99 + .get(`/studies/1/surveys/1/participants/${testingUserId}/answers`) .set({ authorization: `Bearer ${adminToken}` }) expect(res3.statusCode).toBe(200) @@ -174,7 +176,7 @@ describe('Survey tests', () => { expect(data.data[1].last_updated).toBeUndefined() const res3 = await request(app) - .get('/studies/1/surveys/2/participants/99/answers') + .get(`/studies/1/surveys/2/participants/${TestUsers.PARTICIPANT_COMPLETED.id}/answers`) .set({ authorization: `Bearer ${adminToken}` }) expect(res3.statusCode).toBe(200) diff --git a/application/common/cypress/support/commands.ts b/application/common/cypress/support/commands.ts index 0022ad599..80ee4c4b8 100644 --- a/application/common/cypress/support/commands.ts +++ b/application/common/cypress/support/commands.ts @@ -1,14 +1,5 @@ /// -// LEAVING THESE HERE TEMPORARILY WHILE MIGRATING TO CONTSANTS FILE -// TODO: REMOVE THIS AND POINT ALL FILES TO USE CONSTANTS FILE -export enum UserType { - PARTICIPANT_COMPLETED = 'test3@example.com', - PARTICIPANT_UNANSWERED = 'test2@example.com', - ORG_ADMIN = 'admin@example.com', - STUDY_ADMIN = 'studyadmin@example.com', -} - // Shared Cypress commands // Import from the SHARED testing folder diff --git a/application/common/src/PasswordStrength.ts b/application/common/src/PasswordStrength.ts index 534e31837..41871a149 100644 --- a/application/common/src/PasswordStrength.ts +++ b/application/common/src/PasswordStrength.ts @@ -14,8 +14,14 @@ interface PasswordStrengthResult { export function checkPasswordStrength(password: string): PasswordStrengthResult { const fields: FieldErrors = {} - if (password.length < 8) { - fields.Length = { message: 'Password must be at least 8 characters' } + if (password.length < 14) { + fields.Length = { message: 'Password must be at least 14 characters' } + } + if (/password|welcome|changeme/i.test(password)) { + fields.CommonBase = { + message: + 'Password must not contain easily guessable words (i.e. Password, Changeme, Welcome)', + } } if (!/[A-Z]/.test(password)) { fields.Uppercase = { diff --git a/application/common/src/config.ts b/application/common/src/config.ts index 912028bad..1e70aa0c4 100644 --- a/application/common/src/config.ts +++ b/application/common/src/config.ts @@ -1,2 +1,2 @@ -export const backendPort = 5000 -export const defaultAuditLogsPageSize = 25 +export const backendPort: number = 5000 +export const defaultAuditLogsPageSize: number = 25 diff --git a/application/common/testing/TestHelpers.ts b/application/common/testing/TestHelpers.ts index 249119a55..d32a64348 100644 --- a/application/common/testing/TestHelpers.ts +++ b/application/common/testing/TestHelpers.ts @@ -2,7 +2,8 @@ import prisma from '../../backend/src/PrismaClient' import { Prisma, AuditLogOperation } from '@prisma/client' import { SurveysController } from '../../backend/src/controllers/SurveysController' import logger from 'common/src/logger' -import { PARTICIPANT_UNANSWERED_ID, seedTests } from './seed' +import { seedTests } from './seed' +import { TestUsers } from './constants' import { Prefill } from 'common/types/invite' import { createHash } from 'crypto' import { processLogoImage } from '../src/imageHelpers' @@ -35,7 +36,7 @@ export async function publishNewVersion() { export async function partiallyCompleteSurvey() { const sc = new SurveysController() await sc.updateSurveyAnswers( - { user: { userId: PARTICIPANT_UNANSWERED_ID } }, + { user: { userId: TestUsers.PARTICIPANT_UNANSWERED.id } }, 1, // StudyId { data: [], step: 0 }, ) diff --git a/application/common/testing/constants.ts b/application/common/testing/constants.ts index 099f3611b..c862e5eaf 100644 --- a/application/common/testing/constants.ts +++ b/application/common/testing/constants.ts @@ -1,19 +1,85 @@ // Constants shared for all tests -// Test user credentials (from seed data) +// Test user credentials (for seed data and tests) export const TestUsers = { - // TODO: Add study admin here - ADMIN: { + OPERATOR_ADMIN: { + email: 'operatoradmin@example.com', + password: 'Loginforadmin1', + id: 96, + }, + ORG_ADMIN: { email: 'admin@example.com', - password: 'Testpassword1', + password: 'Loginforadmin1', + id: 97, + }, + ORG_ADMIN_2: { + email: 'admin2@example.com', + password: 'Loginforadmin1', + id: 101, }, PARTICIPANT_UNANSWERED: { email: 'test2@example.com', - password: 'Testpassword1', + password: 'Loginforuser12', + id: 98, }, PARTICIPANT_COMPLETED: { email: 'test3@example.com', - password: 'Testpassword1', + password: 'Loginforuser12', + id: 99, + }, + GUARDIAN_2: { + email: 'g2@example.com', + password: 'Loginforuser12', + id: 102, + }, + DEPENDENT: { + id: 100, + }, + STUDY_ADMIN: { + email: 'studyadmin@example.com', + password: 'Loginforadmin1', + id: 106, + }, + PASSWORD_RESET_USER: { + id: 105, + email: 'test-reset-password@example.com', + password: 'Oldloginforuser1', + }, +} + +export const TestStudies = { + TEST_STUDY: { + name: 'Test Study', + id: 1, + }, + TEST_STUDY_2: { + name: 'Study 2', + id: 2, + }, + FE_TEST_STUDY: { + name: 'Study FE', + id: 3, + }, + EMPTY_TEST_STUDY: { + name: 'Empty Study', + }, +} + +export const TestInvites = { + INVITE_PENDING: { + email: 'invite1@pending.com', + }, + INVITE_2_PENDING: { + email: 'invite2@pending.com', + }, + INVITE_ACCEPTED: { + email: 'invite@accepted.com', + }, + INVITE_REVOKED: { + email: 'invite@revoked.com', + }, + INVITE_EXPIRED: { + email: 'invite@expired.com', }, } diff --git a/application/common/testing/seed.ts b/application/common/testing/seed.ts index d9431e622..9133257c8 100644 --- a/application/common/testing/seed.ts +++ b/application/common/testing/seed.ts @@ -2,29 +2,7 @@ import { InviteStatus, PrismaClient, Role } from '@prisma/client' import '../../backend/src/jsontypes' import { SurveyStep } from 'common/types/survey' import { hashPassword } from '../../backend/src/authentication' - -export const OPERATOR_ADMIN_ID = 96 -export const OPERATOR_ADMIN_EMAIL = 'operatoradmin@example.com' -export const ORG_ADMIN_ID = 97 -export const ORG_ADMIN_EMAIL = 'admin@example.com' -export const ORG_ADMIN_PASSWORD = 'Testpassword1' -export const ORG_ADMIN_2_ID = 101 -export const PARTICIPANT_UNANSWERED_ID = 98 -export const PARTICIPANT_UNANSWERED_EMAIL = 'test2@example.com' -export const PARTICIPANT_COMPLETED_ID = 99 -export const PARTICIPANT_COMPLETED_EMAIL = 'test3@example.com' -export const DEPENDENT_ID = 100 -export const SECOND_GUARDIAN_ID = 102 -export const PASSWORD_RESET_USER_ID = 105 -export const STUDY_ADMIN_ID = 106 -export const PASSWORD_RESET_USER_EMAIL = 'test-reset-password@example.com' -export const TEST_STUDY = 'Test Study' -export const TEST_STUDY_ID = 1 -export const SECOND_TEST_STUDY = 'Study 2' -export const SECOND_TEST_STUDY_ID = 2 -export const FE_TEST_STUDY = 'Study FE' -export const FE_TEST_STUDY_ID = 3 -export const EMPTY_TEST_STUDY = 'Empty Study' +import { TestUsers, TestStudies, TestInvites } from './constants' export async function seedTests(prisma: PrismaClient) { const ExampleSurveyStepData = await import('../src/surveys/exampleSurveyStepData.json', { @@ -47,8 +25,8 @@ export async function seedTests(prisma: PrismaClient) { // Create four studies const testStudy = await prisma.study.create({ data: { - name: TEST_STUDY, - id: TEST_STUDY_ID, + name: TestStudies.TEST_STUDY.name, + id: TestStudies.TEST_STUDY.id, redcapToken: 'ABC', redcapURL: 'http://redcaptest.com', contactUsEmail: 'test@contactus.com', @@ -59,16 +37,16 @@ export async function seedTests(prisma: PrismaClient) { // Used to test inviting user to new study (they are invited to this one) const secondTestStudy = await prisma.study.create({ data: { - name: SECOND_TEST_STUDY, - id: SECOND_TEST_STUDY_ID, + name: TestStudies.TEST_STUDY_2.name, + id: TestStudies.TEST_STUDY_2.id, }, }) // This study will have a survey, a participant user and draft answers (mostly for frontend multistudy testing) const frontendTestStudy = await prisma.study.create({ data: { - name: FE_TEST_STUDY, - id: FE_TEST_STUDY_ID, + name: TestStudies.FE_TEST_STUDY.name, + id: TestStudies.FE_TEST_STUDY.id, }, }) @@ -78,18 +56,18 @@ export async function seedTests(prisma: PrismaClient) { // This study will be empty await prisma.study.create({ data: { - name: EMPTY_TEST_STUDY, + name: TestStudies.EMPTY_TEST_STUDY.name, }, }) // OperatorAdminUser await prisma.user.create({ data: { - id: OPERATOR_ADMIN_ID, - email: OPERATOR_ADMIN_EMAIL, + id: TestUsers.OPERATOR_ADMIN.id, + email: TestUsers.OPERATOR_ADMIN.email, firstName: 'Operator', lastName: 'Admin', - password: hashPassword('Testpassword1'), + password: hashPassword(TestUsers.OPERATOR_ADMIN.password), role: Role.OperatorAdmin, }, }) @@ -97,11 +75,11 @@ export async function seedTests(prisma: PrismaClient) { //OrganisationAdminUser await prisma.user.create({ data: { - id: ORG_ADMIN_ID, - email: ORG_ADMIN_EMAIL, + id: TestUsers.ORG_ADMIN.id, + email: TestUsers.ORG_ADMIN.email, firstName: 'Organisation', lastName: 'Admin', - password: hashPassword(ORG_ADMIN_PASSWORD), + password: hashPassword(TestUsers.ORG_ADMIN.password), role: Role.OrganisationAdmin, organisations: { connect: { @@ -114,11 +92,11 @@ export async function seedTests(prisma: PrismaClient) { //OrganisationAdminUser2 await prisma.user.create({ data: { - id: ORG_ADMIN_2_ID, - email: 'testOrgAdmin2@example.com', + id: TestUsers.ORG_ADMIN_2.id, + email: TestUsers.ORG_ADMIN_2.email, firstName: 'Organisation2', lastName: 'Admin2', - password: hashPassword('Testpassword1'), + password: hashPassword(TestUsers.ORG_ADMIN_2.password), role: Role.OrganisationAdmin, organisations: { connect: { @@ -131,11 +109,11 @@ export async function seedTests(prisma: PrismaClient) { //StudyAdminUser await prisma.user.create({ data: { - id: STUDY_ADMIN_ID, - email: 'studyadmin@example.com', + id: TestUsers.STUDY_ADMIN.id, + email: TestUsers.STUDY_ADMIN.email, firstName: 'Study', lastName: 'Admin', - password: hashPassword('Testpassword1'), + password: hashPassword(TestUsers.STUDY_ADMIN.password), role: Role.StudyAdmin, organisations: { connect: { @@ -153,11 +131,11 @@ export async function seedTests(prisma: PrismaClient) { //User with unanswered survey await prisma.user.create({ data: { - id: PARTICIPANT_UNANSWERED_ID, - email: PARTICIPANT_UNANSWERED_EMAIL, + id: TestUsers.PARTICIPANT_UNANSWERED.id, + email: TestUsers.PARTICIPANT_UNANSWERED.email, firstName: 'Test', lastName: 'User', - password: hashPassword('Testpassword1'), + password: hashPassword(TestUsers.PARTICIPANT_UNANSWERED.password), role: Role.Participant, organisations: { connect: { @@ -170,29 +148,29 @@ export async function seedTests(prisma: PrismaClient) { //Second guardian user await prisma.user.create({ data: { - id: SECOND_GUARDIAN_ID, - email: 'g2@example.com', + id: TestUsers.GUARDIAN_2.id, + email: TestUsers.GUARDIAN_2.email, firstName: 'Second', lastName: 'Guardian', - password: hashPassword('Testpassword1'), + password: hashPassword(TestUsers.GUARDIAN_2.password), role: Role.Participant, }, }) //User with completed survey await prisma.user.create({ data: { - id: PARTICIPANT_COMPLETED_ID, - email: PARTICIPANT_COMPLETED_EMAIL, + id: TestUsers.PARTICIPANT_COMPLETED.id, + email: TestUsers.PARTICIPANT_COMPLETED.email, firstName: 'Test', lastName: 'User', - password: hashPassword('Testpassword1'), + password: hashPassword(TestUsers.PARTICIPANT_COMPLETED.password), role: Role.Participant, }, }) const participantUnansweredProfile = await prisma.participantProfile.create({ data: { - id: PARTICIPANT_UNANSWERED_ID, + id: TestUsers.PARTICIPANT_UNANSWERED.id, firstName: 'Unanswered', lastName: 'User', addressLine: '123 smith st', @@ -204,7 +182,7 @@ export async function seedTests(prisma: PrismaClient) { suburb: 'M', studies: { create: { - participantId: `PID-TEST1-${PARTICIPANT_UNANSWERED_ID}`, + participantId: `PID-TEST1-${TestUsers.PARTICIPANT_UNANSWERED.id}`, study: { connect: { id: testStudy.id, @@ -212,14 +190,14 @@ export async function seedTests(prisma: PrismaClient) { }, }, }, - userId: PARTICIPANT_UNANSWERED_ID, + userId: TestUsers.PARTICIPANT_UNANSWERED.id, participantType: 'STANDARD', }, }) await prisma.alternativeContact.create({ data: { - participantProfileId: PARTICIPANT_UNANSWERED_ID, + participantProfileId: TestUsers.PARTICIPANT_UNANSWERED.id, email: 'alt@email.com', firstName: 'Alt', lastName: 'Cont', @@ -228,7 +206,7 @@ export async function seedTests(prisma: PrismaClient) { await prisma.participantProfile.create({ data: { - id: PARTICIPANT_COMPLETED_ID, + id: TestUsers.PARTICIPANT_COMPLETED.id, firstName: 'Completed', lastName: 'User', addressLine: '123 smith st', @@ -240,7 +218,7 @@ export async function seedTests(prisma: PrismaClient) { suburb: 'Melbourne', studies: { create: { - participantId: `PID-TEST1-${PARTICIPANT_COMPLETED_ID}`, + participantId: `PID-TEST1-${TestUsers.PARTICIPANT_COMPLETED.id}`, study: { connect: { id: testStudy.id, @@ -248,7 +226,7 @@ export async function seedTests(prisma: PrismaClient) { }, }, }, - userId: PARTICIPANT_COMPLETED_ID, + userId: TestUsers.PARTICIPANT_COMPLETED.id, familyId: 100, participantType: 'GUARDIAN', }, @@ -257,7 +235,7 @@ export async function seedTests(prisma: PrismaClient) { //Dependent Profile (no user) await prisma.participantProfile.create({ data: { - id: DEPENDENT_ID, + id: TestUsers.DEPENDENT.id, firstName: 'Test', lastName: 'Dependent', addressLine: '123 smith st', @@ -269,7 +247,7 @@ export async function seedTests(prisma: PrismaClient) { suburb: 'Melbourne', studies: { create: { - participantId: `PID-TEST1-${DEPENDENT_ID}`, + participantId: `PID-TEST1-${TestUsers.DEPENDENT.id}`, study: { connect: { id: testStudy.id, @@ -286,7 +264,7 @@ export async function seedTests(prisma: PrismaClient) { //Second guardian await prisma.participantProfile.create({ data: { - id: SECOND_GUARDIAN_ID, + id: TestUsers.GUARDIAN_2.id, firstName: 'Second', lastName: 'Guardian', addressLine: '123 smith st', @@ -298,7 +276,7 @@ export async function seedTests(prisma: PrismaClient) { suburb: 'Melbourne', studies: { create: { - participantId: `PID-TEST1-${SECOND_GUARDIAN_ID}`, + participantId: `PID-TEST1-${TestUsers.GUARDIAN_2.id}`, study: { connect: { id: testStudy.id, @@ -307,7 +285,7 @@ export async function seedTests(prisma: PrismaClient) { }, }, familyId: 100, - userId: SECOND_GUARDIAN_ID, + userId: TestUsers.GUARDIAN_2.id, participantType: 'GUARDIAN', }, }) @@ -357,7 +335,7 @@ export async function seedTests(prisma: PrismaClient) { await prisma.surveyVersionAnswers.create({ data: { versionId: testSurveyVersion.id, - profileId: PARTICIPANT_UNANSWERED_ID, + profileId: TestUsers.PARTICIPANT_UNANSWERED.id, answers: [ { status: 'review_required', answers: [] }, { status: 'review_required', answers: [null, null] }, @@ -367,7 +345,7 @@ export async function seedTests(prisma: PrismaClient) { await prisma.surveyVersionAnswers.create({ data: { versionId: study2survey.id, - profileId: PARTICIPANT_UNANSWERED_ID, + profileId: TestUsers.PARTICIPANT_UNANSWERED.id, answers: [{ status: 'review_required', answers: [null] }], }, }) @@ -375,7 +353,7 @@ export async function seedTests(prisma: PrismaClient) { await prisma.surveyVersionAnswers.create({ data: { versionId: testSurveyVersion.id, - profileId: PARTICIPANT_COMPLETED_ID, + profileId: TestUsers.PARTICIPANT_COMPLETED.id, answers: [ { status: 'viewed', answers: [] }, { @@ -390,7 +368,7 @@ export async function seedTests(prisma: PrismaClient) { await prisma.surveyVersionAnswers.create({ data: { versionId: testSurveyVersion.id, - profileId: DEPENDENT_ID, + profileId: TestUsers.DEPENDENT.id, answers: [ { status: 'viewed', answers: [] }, { @@ -405,7 +383,7 @@ export async function seedTests(prisma: PrismaClient) { await prisma.surveyVersionAnswers.create({ data: { versionId: testSurveyVersion.id, - profileId: SECOND_GUARDIAN_ID, + profileId: TestUsers.GUARDIAN_2.id, answers: [ { status: 'viewed', answers: [] }, { @@ -420,11 +398,11 @@ export async function seedTests(prisma: PrismaClient) { // Seed a user and password reset token await prisma.user.create({ data: { - id: PASSWORD_RESET_USER_ID, - email: PASSWORD_RESET_USER_EMAIL, + id: TestUsers.PASSWORD_RESET_USER.id, + email: TestUsers.PASSWORD_RESET_USER.email, firstName: 'Test', lastName: 'User', - password: await hashPassword('OldPassword123'), + password: hashPassword(TestUsers.PASSWORD_RESET_USER.password), role: Role.Participant, }, }) @@ -432,7 +410,7 @@ export async function seedTests(prisma: PrismaClient) { await prisma.passwordResetToken.create({ data: { token: 'valid-reset-token', - userId: PASSWORD_RESET_USER_ID, + userId: TestUsers.PASSWORD_RESET_USER.id, expiresAt: new Date(Date.now() + 2 * 60 * 1000), // 2 minutes in the future used: false, }, @@ -442,44 +420,32 @@ export async function seedTests(prisma: PrismaClient) { await prisma.invite.createMany({ data: [ { - email: 'invite1@pending.com', + email: TestInvites.INVITE_PENDING.email, status: InviteStatus.PENDING, studyId: testStudy.id, expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), // 1 day in the future }, { - email: 'invite2@accepted.com', + email: TestInvites.INVITE_ACCEPTED.email, status: InviteStatus.ACCEPTED, studyId: testStudy.id, expiresAt: new Date(Date.now() - 24 * 60 * 60 * 1000), // 1 day in the past }, { - email: 'invite3@revoked.com', + email: TestInvites.INVITE_REVOKED.email, status: InviteStatus.REVOKED, studyId: testStudy.id, expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), // 1 day in the future }, { - email: 'invite4@expired.com', + email: TestInvites.INVITE_EXPIRED.email, status: InviteStatus.EXPIRED, studyId: testStudy.id, expiresAt: new Date(Date.now() - 24 * 60 * 60 * 1000), // 1 day in the past }, // Pending invites for testing { - email: 'john@example.com', - status: InviteStatus.PENDING, - studyId: testStudy.id, - expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), // 1 day in the future - }, - { - email: 'jenny@gmail.com', - status: InviteStatus.PENDING, - studyId: testStudy.id, - expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), // 1 day in the future - }, - { - email: 'abcsdfwefijsdf@gjiodsf.com', + email: TestInvites.INVITE_2_PENDING.email, status: InviteStatus.PENDING, studyId: testStudy.id, expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), // 1 day in the future @@ -513,12 +479,12 @@ export async function seedTests(prisma: PrismaClient) { await prisma.participantProfile.update({ where: { - id: SECOND_GUARDIAN_ID, + id: TestUsers.GUARDIAN_2.id, }, data: { studies: { create: { - participantId: `PID-TEST2-${SECOND_GUARDIAN_ID}`, + participantId: `PID-TEST2-${TestUsers.GUARDIAN_2.id}`, study: { connect: { id: frontendTestStudy.id, @@ -536,7 +502,7 @@ export async function seedTests(prisma: PrismaClient) { data: { studies: { create: { - participantId: `PID-TEST2-${PARTICIPANT_UNANSWERED_ID}`, + participantId: `PID-TEST2-${TestUsers.PARTICIPANT_UNANSWERED.id}`, study: { connect: { id: frontendTestStudy.id, @@ -550,14 +516,14 @@ export async function seedTests(prisma: PrismaClient) { await prisma.surveyVersionAnswers.create({ data: { versionId: frontendTestSurveryVersion.id, - profileId: PARTICIPANT_UNANSWERED_ID, + profileId: TestUsers.PARTICIPANT_UNANSWERED.id, answers: [{ status: 'review_required', answers: [null] }], }, }) await prisma.surveyVersionAnswers.create({ data: { versionId: frontendTestSurveryVersion.id, - profileId: SECOND_GUARDIAN_ID, + profileId: TestUsers.GUARDIAN_2.id, answers: [{ status: 'review_required', answers: [null] }], }, }) diff --git a/application/common/types/api/auth/register.ts b/application/common/types/api/auth/register.ts index 2bc544e48..fa10c6292 100644 --- a/application/common/types/api/auth/register.ts +++ b/application/common/types/api/auth/register.ts @@ -26,7 +26,7 @@ export interface RegisterRequest { */ email: string /** - * @minLength 8 Password must be at least 8 characters + * @minLength 14 Password must be at least 14 characters */ password: string role: Role diff --git a/application/common/types/api/auth/registerParticipant.ts b/application/common/types/api/auth/registerParticipant.ts index e39aad114..6b0f44018 100644 --- a/application/common/types/api/auth/registerParticipant.ts +++ b/application/common/types/api/auth/registerParticipant.ts @@ -67,7 +67,7 @@ export interface RegisterParticipantRequest { postcode: string state: StateTerritory /** - * @minLength 8 Password must be at least 8 characters + * @minLength 14 Password must be at least 14 characters */ password: string /** diff --git a/application/common/types/api/auth/registerSetup.ts b/application/common/types/api/auth/registerSetup.ts index 0409b799e..50461c315 100644 --- a/application/common/types/api/auth/registerSetup.ts +++ b/application/common/types/api/auth/registerSetup.ts @@ -10,7 +10,7 @@ export interface RegisterSetupRequest { */ email: string /** - * @minLength 8 Password must be at least 8 characters + * @minLength 14 Password must be at least 14 characters */ password: string } diff --git a/application/common/types/api/users/passwordReset.ts b/application/common/types/api/users/passwordReset.ts index 7fd1943dd..bc80cc724 100644 --- a/application/common/types/api/users/passwordReset.ts +++ b/application/common/types/api/users/passwordReset.ts @@ -18,7 +18,7 @@ export interface GeneratePasswordResetLinkRequest { */ export interface ResetPasswordRequest { /** - * @minLength 8 Password must be at least 8 characters + * @minLength 14 Password must be at least 14 characters */ newPassword: string token: string diff --git a/application/user-client/cypress/support/commands.ts b/application/user-client/cypress/support/commands.ts index a24b3dc71..d23a5a17b 100644 --- a/application/user-client/cypress/support/commands.ts +++ b/application/user-client/cypress/support/commands.ts @@ -17,12 +17,13 @@ // import common cypress commands import '../../../common/cypress/support/commands' +import { TestUsers } from '../../../common/testing/constants' -Cypress.Commands.add('login', (type: UserType) => { +Cypress.Commands.add('login', (email: string) => { cy.request({ method: 'POST', url: `localhost:5001/auth/login`, - body: { email: type, password: 'Testpassword1' }, + body: { email: email, password: TestUsers.PARTICIPANT_COMPLETED.password }, }).then((res) => { window.localStorage.setItem('access_token', res.body.token) })