diff --git a/cypress/integration/app.spec.ts b/cypress/integration/app.spec.ts index 07844dad1..3160d81f0 100644 --- a/cypress/integration/app.spec.ts +++ b/cypress/integration/app.spec.ts @@ -28,7 +28,7 @@ describe("Basic application flow", function () { */ // Try to send invalid form - cy.formActions("Submit") + cy.formActions("Mark as ready") cy.get("input[data-testid='descriptor.studyTitle']").then($input => { expect($input[0].validationMessage).to.contain("Please fill") @@ -38,7 +38,7 @@ describe("Basic application flow", function () { cy.get("[data-testid='descriptor.studyTitle']").type("Test title") cy.get("[data-testid='descriptor.studyTitle']").should("have.value", "Test title") - cy.formActions("Clear form") + cy.optionsActions("Clear form") cy.get("[data-testid='descriptor.studyTitle']").type("New title") cy.get("[data-testid='descriptor.studyTitle']").should("have.value", "New title") @@ -46,7 +46,7 @@ describe("Basic application flow", function () { cy.get("[data-testid='descriptor.studyAbstract']").type("New abstract") // Submit form - cy.formActions("Submit") + cy.formActions("Mark as ready") cy.get("[data-testid='study-objects-list']").find("li").should("have.length", 1) // DAC form @@ -54,10 +54,10 @@ describe("Basic application flow", function () { // Try to submit empty DAC form. This should be invalid cy.get("[data-testid=title]").type("Test title") - cy.formActions("Submit") + cy.formActions("Mark as ready") cy.get("span").contains("must have at least 1 item") - cy.get("h5").contains("Contacts").parents().children("button").click() + cy.get("div[data-testid='contacts'] > div > button").click() cy.get("[data-testid='contacts.0.name']").type("Test contact name") // Test invalid email address (form array, default) cy.get("[data-testid='contacts.0.email']").type("email") @@ -71,11 +71,11 @@ describe("Basic application flow", function () { cy.get("[data-testid='contacts.0.mainContact']").check() // Submit DAC form - cy.formActions("Submit") + cy.formActions("Mark as ready") // Test DAC form update cy.get("[data-testid='dac-objects-list']").within(() => { - cy.get("a").contains("Test contact name").click() + cy.get("a").contains("Test title").click() }) cy.get("[data-testid='contacts']").should("be.visible") @@ -86,7 +86,7 @@ describe("Basic application flow", function () { cy.formActions("Update") cy.get("[data-testid='dac-objects-list']").within(() => { - cy.get("a").contains("Test contact name").click() + cy.contains("Test title").should("be.visible").click({ force: true }) }) cy.get("[data-testid='contacts.0.name']").should("have.value", "Test contact name edited") @@ -101,7 +101,7 @@ describe("Basic application flow", function () { cy.get("textarea[data-testid='policy.policyText']").type("Test policy text") // Submit Policy form - cy.formActions("Submit") + cy.formActions("Mark as ready") /* * 3rd step, Describe @@ -121,7 +121,7 @@ describe("Basic application flow", function () { cy.get("[data-testid='title']").type("Test Sample title") cy.get("[data-testid='sampleName.taxonId']").type("123") // Submit Sample form - cy.formActions("Submit") + cy.formActions("Mark as ready") // Fill a Experiment form cy.clickAddObject(ObjectTypes.experiment) @@ -155,12 +155,12 @@ describe("Basic application flow", function () { ) // Submit Experiment form - cy.formActions("Submit") + cy.formActions("Mark as ready") // Fill a Run form cy.clickAddObject(ObjectTypes.run) cy.get("[data-testid='title']").type("Test Run title") - cy.get("h5[data-testid='experimentRef']").parents().children("button").click() + cy.get("[data-testid='experimentRef'] > div > button").click() // Select experimentAccessionId cy.get("select[data-testid='experimentRef.0.accessionId']").select(1) @@ -168,7 +168,7 @@ describe("Basic application flow", function () { cy.get("select[data-testid='experimentRef.0.accessionId']").should("contain", " - Title:") // Submit Run form - cy.formActions("Submit") + cy.formActions("Mark as ready") // Fill an Analysis form cy.clickAddObject(ObjectTypes.analysis) @@ -197,31 +197,31 @@ describe("Basic application flow", function () { cy.get("[data-testid='experimentRef.refname']").type("Experiment Test Namespace") // Sample - cy.get("h5").contains("Sample Reference").parents().children("button").click() + cy.get("[data-testid='sampleRef'] > div > button").click() cy.get("[data-testid='sampleRef.0.accessionId']").select(1) cy.get("[data-testid='sampleRef.0.identifiers.submitterId.namespace']").type("Sample Test Namespace") cy.get("[data-testid='sampleRef.0.identifiers.submitterId.value']").type("Sample Test Value") // Run - cy.get("h5").contains("Run Reference").parents().children("button").click() + cy.get("[data-testid='runRef'] > div > button").click() cy.get("[data-testid='runRef.0.accessionId']").select(1) cy.get("[data-testid='runRef.0.identifiers.submitterId.namespace']").type("Run Test Namespace") cy.get("[data-testid='runRef.0.identifiers.submitterId.value']").type("Run Test Value") // Analysis - cy.get("div[data-testid='analysisRef'] > div").eq(1).children("button").click() + cy.get("[data-testid='analysisRef'] > div > button").click() cy.get("[data-testid='analysisRef.0.accessionId']").type("Analysis Test Accession Id") cy.get("[data-testid='analysisRef.0.identifiers.submitterId.namespace']").type("Analysis Test Namespace") cy.get("[data-testid='analysisRef.0.identifiers.submitterId.value']").type("Analysis Test Value") // Files - cy.get("div[data-testid='files'] > div").eq(1).children("button").click() + cy.get("[data-testid='files'] > div > button").click() cy.get("[data-testid='files.0.filename']").type("filename 1") cy.get("select[data-testid='files.0.filetype']").select("other") cy.get("select[data-testid='files.0.checksumMethod']").select("MD5") cy.get("[data-testid='files.0.checksum']").type("b1f4f9a523e36fd969f4573e25af4540") - cy.get("div[data-testid='files'] > div").eq(1).children("button").click() + cy.get("[data-testid='files'] > div > button").click() cy.get("[data-testid='files.1.filename']").type("filename 2") cy.get("select[data-testid='files.1.filetype']").select("info") cy.get("select[data-testid='files.1.checksumMethod']").select("SHA-256") @@ -230,7 +230,7 @@ describe("Basic application flow", function () { ) }) // Submit Analysis form - cy.formActions("Submit") + cy.formActions("Mark as ready") // Fill a Dataset form cy.clickAddObject(ObjectTypes.dataset) @@ -244,17 +244,17 @@ describe("Basic application flow", function () { cy.get("select[data-testid='policyRef.accessionId']").should("contain", " - Title:") // Select runAccessionId - cy.get("div").contains("Run Reference").parents().children("button").click() + cy.get("[data-testid='runRef'] > div > button").click() cy.get("select[data-testid='runRef.0.accessionId']").select(1) cy.get("select[data-testid='runRef.0.accessionId']").should("contain", " - Title:") // Select analysisAccessionId - cy.get("div").contains("Analysis Reference").parents().children("button").click() + cy.get("[data-testid='analysisRef'] > div > button").click() cy.get("select[data-testid='analysisRef.0.accessionId']").select(1) cy.get("select[data-testid='analysisRef.0.accessionId']").should("contain", " - Title:") // Submit Dataset form - cy.formActions("Submit") + cy.formActions("Mark as ready") /* * 5th step, Identifier and publish diff --git a/cypress/integration/doiForm.spec.ts b/cypress/integration/doiForm.spec.ts index 52a6ac130..9cc1a3d55 100644 --- a/cypress/integration/doiForm.spec.ts +++ b/cypress/integration/doiForm.spec.ts @@ -21,7 +21,7 @@ describe("DOI form", function () { } cy.get("[data-testid='title']").type(testRunData.title) - cy.get("h5[data-testid='experimentRef']").parents().children("button").click() + cy.get("div[data-testid='experimentRef'] > div > button").click() cy.get("[data-testid='experimentRef.0.accessionId']").select(1) const testRunFile = { @@ -37,7 +37,7 @@ describe("DOI form", function () { cy.get("[data-testid='files.0.checksum']").type(testRunFile.checksum) // Submit form - cy.formActions("Submit") + cy.formActions("Mark as ready") // Run objects container should have contain created object cy.get("[data-testid='run-objects-list']").find("li").should("have.length", 2) @@ -73,13 +73,13 @@ describe("DOI form", function () { cy.get("[data-testid='files.0.checksum']").type(testAnalysisFile.checksum) // Submit form - cy.formActions("Submit") + cy.formActions("Mark as ready") // Analysis objects container should have contain created object cy.get("[data-testid='analysis-objects-list']").find("li").should("have.length", 2) // Fill another Analysis form with the same fileType as Run form: "bam" - cy.formActions("New form") + cy.get("button").contains("Add analysis").click() cy.get("[data-testid='title']").type(testAnalysisData.title2) cy.get("[data-testid='analysisType']").select("Reference Alignment") cy.get("[data-testid='analysisType.referenceAlignment.assembly']").select("Standard") @@ -91,7 +91,7 @@ describe("DOI form", function () { cy.get("[data-testid='files.0.checksum']").type(testAnalysisFile.checksum) // Submit form - cy.formActions("Submit") + cy.formActions("Mark as ready") // Analysis objects container should have contain both newly created objects cy.get("[data-testid='analysis-objects-list']").find("li").should("have.length", 3) @@ -265,10 +265,10 @@ describe("DOI form", function () { cy.openDOIForm() // Fill in required Creators field - cy.get("[data-testid='creators']").parent().children("button").click() + cy.get("div[data-testid='creators'] > div > button").click() cy.get("[data-testid='creators.0.givenName']").type("Test given name") cy.get("[data-testid='creators.0.familyName']").type("Test family name") - cy.get("[data-testid='creators.0.affiliation']", { timeout: 10000 }).parent().children("button").click() + cy.get("div[data-testid='creators.0.affiliation'] > div > button").click() cy.intercept("/organizations*").as("searchOrganization") cy.get("[data-testid='creators.0.affiliation.0.name-inputField']").type("csc") cy.wait("@searchOrganization") @@ -278,14 +278,14 @@ describe("DOI form", function () { cy.get("[data-testid='creators.0.affiliation.0.schemeUri']").should("have.value", "https://ror.org") // Fill in required Subjects field - cy.get("[data-testid='subjects']").parent().children("button").click() + cy.get("div[data-testid='subjects'] > div > button").click() cy.get("[data-testid='subjects.0.subject']").select("FOS: Mathematics") // Fill in required Keywords cy.get("input[data-testid='keywords']").type("keyword-1,") // Select Dates - cy.get("[data-testid='dates']").parent().children("button").click() + cy.get("div[data-testid='dates'] > div > button").click() cy.get("[data-testid='dates.0.date']").scrollIntoView() cy.get("[data-testid='dates.0.date']").should("be.visible") diff --git a/cypress/integration/draft.spec.ts b/cypress/integration/draft.spec.ts index 2af2625cb..dd2b98bd7 100644 --- a/cypress/integration/draft.spec.ts +++ b/cypress/integration/draft.spec.ts @@ -19,39 +19,31 @@ describe("Draft operations", function () { cy.get("[data-testid=title]").type("Test title") // Save a draft - cy.formActions("Save as Draft") + cy.formActions("Save as draft") cy.get("div[role=alert]", { timeout: 10000 }).contains("Draft saved with") cy.get("[data-testid='policy-objects-list']").find("li").should("have.length", 1) // Save another draft - cy.formActions("New form") + cy.get("button").contains("Add policy").click() + cy.get("[data-testid=title]").should("have.value", "") cy.get("[data-testid=title]").type("Test title 2") - cy.formActions("Save as Draft") + cy.formActions("Save as draft") cy.get("div[role=alert]", { timeout: 10000 }).contains("Draft saved with") cy.get("[data-testid='policy-objects-list']").find("li").should("have.length", 2) // Update draft, save from dialog cy.get("[data-testid=title]").type(" second save") - cy.get("[data-testid='policy-objects-list']").find("li").first().click() - cy.get("h2").contains("Would you like to save draft version of this form") + cy.get("[data-testid='draft-policy-list-item']").first().click() + cy.contains("Would you like to save draft version of this form").should("be.visible") cy.get("div[role=dialog]").contains("Save").click() + cy.get("div[role=dialog]", { timeout: 10000 }).should("not.exist") cy.get("[data-testid='policy-objects-list']").find("li").should("have.length", 2) - // Delete a draft - cy.get("[data-testid='Draft-objects']") - .find("li") - .first() - .within(() => { - cy.get("[data-testid='Delete submission']").first().click() - }) - cy.get("[data-testid='Draft-objects']").find("li", { timeout: 10000 }).should("have.length", 1) - - // Continue draft - cy.continueLatestDraft(ObjectTypes.policy) + // Continue first draft + cy.get("[data-testid='draft-policy-list-item']", { timeout: 10000 }).first().click({ force: true }) - cy.get("[data-testid=title]") - // Clear - cy.formActions("Clear form") + // Clear form + cy.optionsActions("Clear form") // Fill cy.get("[data-testid=title]").should("have.value", "") cy.get("[data-testid=title]").type("New title") @@ -62,38 +54,33 @@ describe("Draft operations", function () { cy.get("div[role=alert]", { timeout: 10000 }).contains("Draft updated with") // Create a new form and save as draft - cy.formActions("New form") + cy.get("button").contains("Add DAC").click() cy.get("[data-testid=title]").should("contain.text", "") cy.get("[data-testid=title]").type("New title 2") cy.get("[data-testid=title]").should("have.value", "New title 2") - cy.get("select[data-testid='dacRef.accessionId']").select(1) - cy.formActions("Save as Draft") + cy.formActions("Save as draft") cy.get("div[role=alert]", { timeout: 10000 }).contains("Draft saved with") // Check that there are 2 drafts saved in drafts list - cy.get("ul[data-testid='Draft-objects']").find("li").should("have.length", 2) + cy.get("ul[data-testid='dac-objects-list']").find("li").should("have.length", 2) // Submit first form draft cy.continueLatestDraft(ObjectTypes.policy) + cy.get("select[data-testid='dacRef.accessionId']").select(1) cy.get("select[data-testid='policy']").select("Policy Text") cy.get("textarea[data-testid='policy.policyText']").type("Test policy text") - cy.formActions("Submit") + cy.formActions("Mark as ready") cy.get("div[role=alert]", { timeout: 10000 }).contains("Submitted with") - cy.get("[data-testid='Form-objects']").find("li").should("have.length", 1) // Submit second form draft - cy.get(`[data-testid='draft-${ObjectTypes.policy}-list-item']`).should("have.length", 1) // Re-query instead of continueLatestDraft -command since original query results in detached DOM element - cy.get(`[data-testid='draft-${ObjectTypes.policy}-list-item']`).click() - cy.get("select[data-testid='policy']").select("Policy Text") + cy.get(`[data-testid='draft-${ObjectTypes.policy}-list-item']`).first().click() + cy.get("select[data-testid='policy']", { timeout: 10000 }).select("Policy Text") cy.get("textarea[data-testid='policy.policyText']").type("Test policy text") - cy.formActions("Submit") + cy.formActions("Mark as ready") // Check that there are 2 submitted objects - cy.get("[data-testid='Form-objects']", { timeout: 10000 }).find("li").should("have.length", 2) - - // Drafts list should be unmounted - cy.get("[data-testid='Draft-objects']").should("have.length", 0) + cy.get("[data-testid='policy-objects-list']", { timeout: 10000 }).find("li").should("have.length", 2) }) }) diff --git a/cypress/integration/draftTemplates.spec.ts b/cypress/integration/draftTemplates.spec.ts index 085f0cd72..3d34bd2c0 100644 --- a/cypress/integration/draftTemplates.spec.ts +++ b/cypress/integration/draftTemplates.spec.ts @@ -12,7 +12,7 @@ describe("draft selections and templates", function () { cy.clickAccordionPanel("Study, DAC and policy") cy.clickAddObject("policy") cy.get("[data-testid=title]").type("Policy draft title") - cy.formActions("Save as Draft") + cy.formActions("Save as draft") cy.clickAccordionPanel("publish") diff --git a/cypress/integration/editForm.spec.ts b/cypress/integration/editForm.spec.ts index f1fec6b13..a50aa5587 100644 --- a/cypress/integration/editForm.spec.ts +++ b/cypress/integration/editForm.spec.ts @@ -33,11 +33,10 @@ describe("Populate form and render form elements by object data", function () { cy.get("select[data-testid='sampleData.gender']").select(testData.gender) // Submit form - cy.get("button[type=submit]").contains("Submit").click() - cy.get(".MuiListItem-container", { timeout: 10000 }).should("have.length", 1) + cy.formActions("Mark as ready") // Clear form - cy.get("button[type=button]").contains("Clear").click() + cy.optionsActions("Clear form") // Edit saved submission cy.get("[data-testid='sample-objects-list']").within(() => { @@ -72,9 +71,6 @@ describe("Populate form and render form elements by object data", function () { cy.get("select[data-testid='sampleData']").should("have.value", testData.sampleData2) cy.get("[data-testid='sampleData.dataDescription']").should("have.value", testData.sampleTypeDescription) - // Clear object in state - cy.formActions("New form") - // Test updated title cy.get("[data-testid='sample-objects-list']").find("li").should("have.length", 2) cy.get("[data-testid='sample-objects-list']").within(() => { @@ -117,7 +113,7 @@ describe("Populate form and render form elements by object data", function () { ) // Save Experiment form - cy.formActions("Save as Draft") + cy.formActions("Save as draft") cy.get("div[role=alert]", { timeout: 10000 }).contains("Draft saved with") cy.continueLatestDraft(ObjectTypes.experiment) @@ -160,7 +156,7 @@ describe("Populate form and render form elements by object data", function () { cy.get("[data-testid='runType.referenceAlignment.assembly.accession']").type(testData.accessionId) // Save draft - cy.get("button[type='button']").contains("Save as Draft").click() + cy.get("button[type='button']").contains("Save as draft").click() cy.get("div[role=alert]", { timeout: 10000 }).contains("Draft saved with") // Select newly saved draft @@ -181,7 +177,7 @@ describe("Populate form and render form elements by object data", function () { cy.get("[type='checkbox']").first().check() // Save draft - cy.get("button[type='button']").contains("Save as Draft").click() + cy.get("button[type='button']").contains("Save as draft").click() cy.get("div[role=alert]", { timeout: 10000 }).contains("Draft saved with") // Select newly saved draft @@ -190,10 +186,7 @@ describe("Populate form and render form elements by object data", function () { cy.get("[type='checkbox']").first().should("be.checked") // Test that checkbox clears with form clear -button - cy.get("button[type=button]") - .contains("Clear form") - .should("be.visible") - .then($el => $el.click()) + cy.optionsActions("Clear form") cy.get("[type='checkbox']").first().should("not.be.checked") }) @@ -201,17 +194,16 @@ describe("Populate form and render form elements by object data", function () { cy.clickAddObject(ObjectTypes.sample) cy.get("[data-testid='title']").type("Test sample title") // Save draft - cy.get("button[type='button']").contains("Save as Draft").click() + cy.get("button[type='button']").contains("Save as draft").click() // Edit the draft and try to submit invalid form cy.continueLatestDraft(ObjectTypes.sample) - cy.get("button[type=submit]").contains("Submit").click() + cy.formActions("Mark as ready") // Taxon field should be empty and the draft cannot be submitted yet cy.get("[data-testid='sampleName.taxonId']").should("have.value", "") - cy.get("[data-testid='Draft-objects']").should("have.length", 1) // Fill in taxonId and submit the form again cy.get("[data-testid='sampleName.taxonId']").type("123") - cy.get("button[type=submit]").contains("Submit").click() + cy.formActions("Mark as ready") // Check that the draft is removed from the draft objects list and submitted cy.get(`[data-testid='sample-objects-list']`).within(() => { diff --git a/cypress/integration/emptyForm.spec.ts b/cypress/integration/emptyForm.spec.ts index 098de0125..f6af516cb 100644 --- a/cypress/integration/emptyForm.spec.ts +++ b/cypress/integration/emptyForm.spec.ts @@ -1,4 +1,4 @@ -import { DisplayObjectTypes, ObjectTypes } from "constants/wizardObject" +import { ObjectTypes } from "constants/wizardObject" describe("empty form should not be alerted or saved", function () { beforeEach(() => { @@ -11,36 +11,30 @@ describe("empty form should not be alerted or saved", function () { cy.clickAccordionPanel("Describe") }) - it("should have New form button and Clear form button emptied the form", () => { + it("should have Clear form button emptied the form", () => { // Check Clear form button in Sample object cy.clickAddObject(ObjectTypes.sample) cy.get("input[data-testid='title']").type("Test sample") cy.get("input[data-testid='sampleName.taxonId']").type("123") - cy.formActions("Clear form") + cy.optionsActions("Clear form") cy.get("input[data-testid='title']").should("have.value", "") cy.get("input[data-testid='sampleName.taxonId']").should("have.value", "") - // Check both New form button and Clear form button with Experiment object + // Check both Clear form button with Experiment object cy.clickAddObject(ObjectTypes.experiment) - // Check if New form button can empty the form - cy.get("form") - cy.formActions("New form") - cy.get("input[data-testid='title']").should("have.value", "") - cy.get("textarea[data-testid='description']").should("have.value", "") - // Fill in the form an check if Clear form button can empty the form cy.get("input[data-testid='title']").type("Test experiment") cy.get("textarea[data-testid='description']").type("Test experiment description") - cy.formActions("Clear form") + cy.optionsActions("Clear form") cy.get("input[data-testid='title']").should("have.value", "") cy.get("textarea[data-testid='description']").should("have.value", "") // Fill in the form again and save as draft cy.get("input[data-testid='title']").type("Test experiment") cy.get("textarea[data-testid='description']").type("Test experiment description") - cy.formActions("Save as Draft") + cy.formActions("Save as draft") cy.get("div[role=alert]", { timeout: 10000 }).contains("Draft saved with") // Select the Experiment draft @@ -50,7 +44,7 @@ describe("empty form should not be alerted or saved", function () { cy.get("textarea[data-testid='description']").should("have.value", "Test experiment description") // Click Clear form button and expect the form is empty - cy.formActions("Clear form") + cy.optionsActions("Clear form") cy.get("input[data-testid='title']").should("have.value", "") cy.get("textarea[data-testid='description']").should("have.value", "") @@ -59,11 +53,6 @@ describe("empty form should not be alerted or saved", function () { cy.get("input[data-testid='title']").should("have.value", "Test experiment") cy.get("textarea[data-testid='description']").should("have.value", "Test experiment description") - - // Click New form button and expect the form is empty - cy.formActions("New form") - cy.get("input[data-testid='title']").should("have.value", "") - cy.get("textarea[data-testid='description']").should("have.value", "") }) it("should not show draft saving alert when form is empty, should not save an empty form", () => { @@ -72,17 +61,15 @@ describe("empty form should not be alerted or saved", function () { // Switch to another object type form and Alert window should not pop up cy.editLatestSubmittedObject(ObjectTypes.experiment) - cy.get("[role='heading']", { timeout: 10000 }).contains(DisplayObjectTypes.experiment).should("be.visible") - // Switch back to Sample form and fill it cy.clickAddObject(ObjectTypes.sample) cy.get("[data-testid='title']").type("Test Sample title") cy.get("[data-testid='sampleName.taxonId']").type("123") // Clear form and Save - cy.formActions("Clear form") + cy.optionsActions("Clear form") cy.get("input[data-testid='title']", { timeout: 10000 }).should("be.empty") - cy.formActions("Save as Draft") + cy.formActions("Save as draft") // Expect Info window should pop up cy.get("div[role=alert]").contains("An empty form cannot be saved.").should("be.visible") @@ -91,12 +78,12 @@ describe("empty form should not be alerted or saved", function () { cy.get("[data-testid='title']").type("Test Sample title") cy.get("input[data-testid='title']").should("have.value", "Test Sample title") - cy.formActions("Save as Draft") + cy.formActions("Save as draft") cy.get("div[role=alert]").contains("Draft saved with") // Clear Study title input and Save cy.get("input[data-testid='title']").clear() - cy.formActions("Save as Draft") + cy.formActions("Save as draft") // Expect Info window should pop up cy.get("div[role=alert]").contains("An empty form cannot be saved.").should("be.visible") diff --git a/cypress/integration/home.spec.ts b/cypress/integration/home.spec.ts index e8a390b9a..651c5fb9b 100644 --- a/cypress/integration/home.spec.ts +++ b/cypress/integration/home.spec.ts @@ -24,19 +24,19 @@ describe("Home e2e", function () { cy.get("select[data-testid='descriptor.studyType']").select("Resequencing") cy.get("[data-testid='descriptor.studyAbstract']").type("Test abstract") // Save draft - cy.formActions("Save as Draft") + cy.formActions("Save as draft") cy.get("div[role=alert]", { timeout: 10000 }).contains("Draft saved with") // Fill a Policy form draft cy.clickAddObject(ObjectTypes.policy) cy.get("[data-testid='title']").type("Test Policy title") - cy.formActions("Save as Draft") + cy.formActions("Save as draft") cy.get("div[role=alert]", { timeout: 10000 }).contains("Draft saved with") // Save another draft for later use - cy.formActions("New form") + cy.get("button").contains("Add policy").click() cy.get("input[data-testid='title']").type("Second test title") - cy.formActions("Save as Draft") + cy.formActions("Save as draft") cy.get("div[role=alert]", { timeout: 10000 }).contains("Draft saved with") // Save submission and navigate to Home page diff --git a/cypress/integration/objectLinksAttributes.spec.ts b/cypress/integration/objectLinksAttributes.spec.ts index d40806a30..5923dd099 100644 --- a/cypress/integration/objectLinksAttributes.spec.ts +++ b/cypress/integration/objectLinksAttributes.spec.ts @@ -55,7 +55,7 @@ describe("render objects' links and attributes ", function () { cy.get("[data-testid='studyAttributes.0.value']").type("Test Attributes Value") // Save as draft - cy.formActions("Save as Draft") + cy.formActions("Save as draft") cy.get("[data-testid='study-objects-list']").find("li").should("have.length", 1) // Check submitted object has correnct rendering data diff --git a/cypress/integration/objectTitles.spec.ts b/cypress/integration/objectTitles.spec.ts index c4daaa289..c0742b6f6 100644 --- a/cypress/integration/objectTitles.spec.ts +++ b/cypress/integration/objectTitles.spec.ts @@ -20,8 +20,7 @@ describe("draft and submitted objects' titles", function () { cy.get("[data-testid='descriptor.studyAbstract']").type("New abstract") // Submit form - cy.formActions("Submit") - cy.get(".MuiListItem-container", { timeout: 10000 }).should("have.length", 1) + cy.formActions("Mark as ready") // Check the submitted object has correct displayTitle cy.get("[data-testid='study-objects-list']").within(() => { @@ -32,7 +31,7 @@ describe("draft and submitted objects' titles", function () { cy.editLatestSubmittedObject(ObjectTypes.study) cy.scrollTo("top") - cy.contains("Update Study", { timeout: 10000 }).should("be.visible") + cy.contains("Update", { timeout: 10000 }).should("be.visible") cy.get("@studyTitle", { timeout: 10000 }).should("have.value", "Test title") cy.get("@studyTitle", { timeout: 10000 }).type(" 2") @@ -59,7 +58,7 @@ describe("draft and submitted objects' titles", function () { cy.get("input[data-testid='sampleName.taxonId']").type("123") // Save a draft - cy.formActions("Save as Draft") + cy.formActions("Save as draft") cy.get("div[role=alert]", { timeout: 10000 }).contains("Draft saved with") cy.get("[data-testid='sample-objects-list']").find("li").should("have.length", 1) diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index cbb0cbb3d..4943586cd 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -40,6 +40,7 @@ declare global { continueLatestDraft(objectType: string): Chainable openDOIForm(): Chainable formActions(buttonName: string): Chainable + optionsActions(optionName: string): Chainable saveDoiForm(): Chainable generateSubmissionAndObjects(stopToObjectType?: string): Chainable generateObject(objectType: string): Chainable @@ -142,7 +143,7 @@ Cypress.Commands.add("editLatestSubmittedObject", objectType => { cy.get(`[data-testid='submitted-${objectType}-list-item']`).last().click() }) cy.scrollTo("top") - cy.contains(`Update ${DisplayObjectTypes[objectType]}`, { timeout: 10000 }).should("be.visible") + cy.contains("Update", { timeout: 10000 }).should("be.visible") }) // Go to DOI form @@ -160,6 +161,11 @@ Cypress.Commands.add("formActions", buttonName => { cy.get("button").contains(buttonName, { timeout: 10000 }).click({ force: true }) }) +Cypress.Commands.add("optionsActions", optionName => { + cy.get("[data-testid='MoreHorizIcon']").click() + cy.contains(optionName).click() +}) + // Fill required fields to submit DOI form Cypress.Commands.add("saveDoiForm", () => { cy.get("button").contains("Add DOI information (optional)").click() @@ -185,7 +191,8 @@ Cypress.Commands.add("saveDoiForm", () => { }) // Method for hanlding request path when generating objects -const addObjectPath = (objectType: string, submissionId: string) => `${baseUrl}objects/${objectType}?submission=${submissionId}` +const addObjectPath = (objectType: string, submissionId: string) => + `${baseUrl}objects/${objectType}?submission=${submissionId}` // Create objects from predefined templates // Possible to stop into specific object type. Add object type as argument diff --git a/src/__tests__/FormAutocompleteField.test.tsx b/src/__tests__/FormAutocompleteField.test.tsx index 8f5bfc065..8ef3d5d49 100644 --- a/src/__tests__/FormAutocompleteField.test.tsx +++ b/src/__tests__/FormAutocompleteField.test.tsx @@ -46,6 +46,7 @@ describe("Test autocomplete on organisation field", () => { name: "Test name", published: false, }, + openedXMLModal: false, }) beforeAll(() => server.listen()) diff --git a/src/__tests__/WizardShowSummaryStep.test.tsx b/src/__tests__/WizardShowSummaryStep.test.tsx index e6a916270..d81d7eb38 100644 --- a/src/__tests__/WizardShowSummaryStep.test.tsx +++ b/src/__tests__/WizardShowSummaryStep.test.tsx @@ -55,11 +55,12 @@ describe("WizardShowSummaryStep", () => { { accessionId: "EDAG9880660036513985", schema: ObjectTypes.dac, - tags: { submissionType: ObjectSubmissionTypes.form, displayTitle: "John Smith" }, + tags: { submissionType: ObjectSubmissionTypes.form, displayTitle: "DAC form" }, }, ], name: "AA", published: false, + openedXMLModal: true, }, }) wrapper = ( @@ -124,8 +125,7 @@ describe("WizardShowSummaryStep", () => { const submittedForm = getAllByRole("listitem") expect(submittedForm.length).toBe(1) - // Expect to render Sample title and accessionId - expect(submittedForm[0]).toHaveTextContent("Main Contact: John Smith") - expect(submittedForm[0]).toHaveTextContent("EDAG9880660036513985") + // Expect to render DAC title and accessionId + expect(submittedForm[0]).toHaveTextContent("DAC form") }) }) diff --git a/src/components/Home/UserDraftTemplateActions.tsx b/src/components/Home/UserDraftTemplateActions.tsx index 9167c009e..6dcbd4420 100644 --- a/src/components/Home/UserDraftTemplateActions.tsx +++ b/src/components/Home/UserDraftTemplateActions.tsx @@ -22,7 +22,7 @@ const FormDialog = (props: { open: boolean; onClose: () => void }) => { return ( - + ) } diff --git a/src/components/SubmissionWizard/WizardComponents/WizardAddObjectCard.tsx b/src/components/SubmissionWizard/WizardComponents/WizardAddObjectCard.tsx index 478afcb3f..6c059ff7b 100644 --- a/src/components/SubmissionWizard/WizardComponents/WizardAddObjectCard.tsx +++ b/src/components/SubmissionWizard/WizardComponents/WizardAddObjectCard.tsx @@ -6,6 +6,7 @@ import WizardFillObjectDetailsForm from "components/SubmissionWizard/WizardForms import WizardXMLObjectPage from "components/SubmissionWizard/WizardForms/WizardXMLObjectPage" import { ObjectSubmissionTypes } from "constants/wizardObject" import { useAppSelector } from "hooks" +import type { FormRef } from "types" const StyledContent = styled("div")(() => ({ width: "100%", @@ -16,13 +17,13 @@ const StyledContent = styled("div")(() => ({ /* * Render correct form to add objects based on submission type in store */ -const WizardAddObjectCard: React.FC = () => { +const WizardAddObjectCard = ({ formRef }: { formRef?: FormRef }) => { const submissionType = useAppSelector(state => state.submissionType) const objectType = useAppSelector(state => state.objectType) const content = { [ObjectSubmissionTypes.form]: { - component: , + component: , testId: ObjectSubmissionTypes.form, }, [ObjectSubmissionTypes.xml]: { diff --git a/src/components/SubmissionWizard/WizardComponents/WizardStep.tsx b/src/components/SubmissionWizard/WizardComponents/WizardStep.tsx index a8b6fd0cd..548c9405d 100644 --- a/src/components/SubmissionWizard/WizardComponents/WizardStep.tsx +++ b/src/components/SubmissionWizard/WizardComponents/WizardStep.tsx @@ -26,7 +26,7 @@ import { setSubmissionType } from "features/wizardSubmissionTypeSlice" import { useAppDispatch, useAppSelector } from "hooks" import draftAPIService from "services/draftAPI" import objectAPIService from "services/objectAPI" -import { ObjectInsideSubmissionWithTags } from "types" +import type { FormRef, ObjectInsideSubmissionWithTags } from "types" import { pathWithLocale } from "utils" const StatusBadge = (props: { draft: boolean }) => { @@ -52,8 +52,14 @@ const StatusBadge = (props: { draft: boolean }) => { ) } -const ActionButton = (props: { step: number; parent: string; buttonText: string; disabled: boolean }) => { - const { step, parent, buttonText, disabled } = props +const ActionButton = (props: { + step: number + parent: string + buttonText: string + disabled: boolean + formRef?: FormRef +}) => { + const { step, parent, buttonText, disabled, formRef } = props const navigate = useNavigate() const submission = useAppSelector(state => state.submission) const formState = useAppSelector(state => state.submissionType) @@ -96,6 +102,7 @@ const ActionButton = (props: { step: number; parent: string; buttonText: string; navigate({ pathname: pathname, search: stepParam }) dispatch(setSubmissionType(ObjectSubmissionTypes.form)) dispatch(setObjectType(parent)) + if (formRef?.current) formRef.current?.dispatchEvent(new Event("reset", { bubbles: true })) } } } @@ -115,6 +122,8 @@ const ActionButton = (props: { step: number; parent: string; buttonText: string; variant="contained" onClick={() => handleClick()} sx={theme => ({ marginTop: theme.spacing(2.4) })} + form="hook-form" + type="reset" > {buttonText} @@ -164,7 +173,9 @@ const StepItems = (props: { const response = await service.getObjectByAccessionId(objectType, item.accessionId) if (response.ok) { - dispatch(setSubmissionType(item.tags.submissionType)) + item.tags.submissionType + ? dispatch(setSubmissionType(item.tags.submissionType)) + : dispatch(setSubmissionType(ObjectSubmissionTypes.xml)) dispatch(setObjectType(objectType)) dispatch(resetCurrentObject()) dispatch( @@ -310,8 +321,9 @@ const WizardStep = (params: { objects?: { ready?: stepItemObject[]; drafts?: stepItemObject[] } }[] actionButtonText: string + formRef?: FormRef }) => { - const { step, stepItems, actionButtonText } = params + const { step, stepItems, actionButtonText, formRef } = params const submission = useAppSelector(state => state.submission) const currentStepObject = useAppSelector(state => state.stepObject) const singleObjectStepItems = [ObjectTypes.study] @@ -366,6 +378,7 @@ const WizardStep = (params: { : actionButtonText } disabled={hasObjects && singleObjectStepItems.indexOf(objectType) > -1} + formRef={formRef} /> diff --git a/src/components/SubmissionWizard/WizardComponents/WizardStepper.tsx b/src/components/SubmissionWizard/WizardComponents/WizardStepper.tsx index 9d521031a..6eb532eb2 100644 --- a/src/components/SubmissionWizard/WizardComponents/WizardStepper.tsx +++ b/src/components/SubmissionWizard/WizardComponents/WizardStepper.tsx @@ -14,7 +14,7 @@ import { DisplayObjectTypes, ObjectTypes } from "constants/wizardObject" import { resetObjectType } from "features/wizardObjectTypeSlice" import { resetStepObject, updateStep } from "features/wizardStepObjectSlice" import { useAppDispatch, useAppSelector } from "hooks" -import { Schema } from "types" +import type { Schema, FormRef } from "types" // Top & bottom borders for first and last disabled elements const AccordionWrapper = styled("div")(({ theme }) => ({ @@ -72,7 +72,7 @@ const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({ * If createSubmissionForm is passed as reference it is used to trigger correct form when clicking next. */ -const WizardStepper = () => { +const WizardStepper = ({ formRef }: { formRef?: FormRef }) => { const objectsArray = useAppSelector(state => state.objectTypesArray) const submission = useAppSelector(state => state.submission) const currentStepObject = useAppSelector(state => state.stepObject) @@ -265,7 +265,12 @@ const WizardStepper = () => { - + ) diff --git a/src/components/SubmissionWizard/WizardForms/WizardFillObjectDetailsForm.tsx b/src/components/SubmissionWizard/WizardForms/WizardFillObjectDetailsForm.tsx index 3a64aaab8..de010b000 100644 --- a/src/components/SubmissionWizard/WizardForms/WizardFillObjectDetailsForm.tsx +++ b/src/components/SubmissionWizard/WizardForms/WizardFillObjectDetailsForm.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState, useRef } from "react" +import React, { useEffect, useState, useRef, RefObject } from "react" import { Theme } from "@mui/material" import Alert from "@mui/material/Alert" @@ -36,7 +36,14 @@ import { useAppSelector, useAppDispatch } from "hooks" import objectAPIService from "services/objectAPI" import schemaAPIService from "services/schemaAPI" import templateAPI from "services/templateAPI" -import type { SubmissionDetailsWithId, FormDataFiles, FormObject, ObjectDetails, ObjectDisplayValues } from "types" +import type { + SubmissionDetailsWithId, + FormDataFiles, + FormObject, + ObjectDetails, + ObjectDisplayValues, + FormRef, +} from "types" import { getObjectDisplayTitle, getAccessionIds, getNewUniqueFileTypes } from "utils" import { dereferenceSchema } from "utils/JSONSchemaUtils" @@ -89,6 +96,7 @@ type FormContentProps = { submission: SubmissionDetailsWithId currentObject: ObjectDetails & { objectId: string; [key: string]: unknown } closeDialog: () => void + formRef?: FormRef } /* @@ -212,6 +220,7 @@ const FormContent = ({ submission, currentObject, closeDialog, + formRef, }: FormContentProps) => { const classes = useStyles() const dispatch = useAppDispatch() @@ -436,6 +445,11 @@ const FormContent = ({ dispatch(setXMLModalOpen()) } + const handleReset = () => { + methods.reset({ undefined }) + setCurrentObjectId(null) + } + return ( handleChange()} onSubmit={methods.handleSubmit(onSubmit)} + ref={formRef as RefObject} + onReset={handleReset} >
{JSONSchemaParser.buildFields(formSchema)}
@@ -465,8 +481,8 @@ const FormContent = ({ /* * Container for json schema based form. Handles json schema loading, form rendering, form submitting and error/success alerts. */ -const WizardFillObjectDetailsForm = (props: { closeDialog?: () => void }) => { - const { closeDialog } = props +const WizardFillObjectDetailsForm = (props: { closeDialog?: () => void; formRef?: FormRef }) => { + const { closeDialog, formRef } = props const classes = useStyles() const dispatch = useAppDispatch() @@ -617,6 +633,7 @@ const WizardFillObjectDetailsForm = (props: { closeDialog?: () => void }) => { currentObject={currentObject} key={currentObject?.accessionId || submission.submissionId} closeDialog={closeDialog || (() => ({}))} + formRef={formRef} /> {submitting && } state.objectType) const { submissionId } = useAppSelector(state => state.submission) const loading = useAppSelector(state => state.loading) + const focusTarget = useRef(null) + const shouldFocus = useAppSelector(state => state.focus) + + useEffect(() => { + if (shouldFocus && focusTarget.current) focusTarget.current.focus() + }, [shouldFocus]) const { register, @@ -186,13 +192,7 @@ const WizardUploadXMLModal = ({ open, handleClose, currentObject }: WizardUpload }) return ( - + Upload XML File @@ -203,6 +203,7 @@ const WizardUploadXMLModal = ({ open, handleClose, currentObject }: WizardUpload Drag and drop the file here or handleButton()} diff --git a/src/components/SubmissionWizard/WizardHooks/WizardSaveDraftHook.tsx b/src/components/SubmissionWizard/WizardHooks/WizardSaveDraftHook.tsx index 8584b4d16..c4febb3d9 100644 --- a/src/components/SubmissionWizard/WizardHooks/WizardSaveDraftHook.tsx +++ b/src/components/SubmissionWizard/WizardHooks/WizardSaveDraftHook.tsx @@ -1,5 +1,5 @@ import { ResponseStatus } from "constants/responseStatus" -import { ObjectStatus } from "constants/wizardObject" +import { ObjectStatus, ObjectSubmissionTypes } from "constants/wizardObject" import { resetDraftStatus } from "features/draftStatusSlice" import { setLoading, resetLoading } from "features/loadingSlice" import { updateStatus } from "features/statusMessageSlice" @@ -29,7 +29,13 @@ const saveDraftHook = async (props: SaveDraftHookProps) => { if (response.ok) { dispatch(resetDraftStatus()) - dispatch(replaceObjectInSubmission(accessionId, { displayTitle: draftDisplayTitle }, ObjectStatus.draft)) + dispatch( + replaceObjectInSubmission( + accessionId, + { displayTitle: draftDisplayTitle, submissionType: ObjectSubmissionTypes.form }, + ObjectStatus.draft + ) + ) dispatch( updateStatus({ status: ResponseStatus.success, @@ -64,7 +70,7 @@ const saveDraftHook = async (props: SaveDraftHookProps) => { addDraftObject({ accessionId: response.data.accessionId, schema: "draft-" + objectType, - tags: { displayTitle: draftDisplayTitle }, + tags: { displayTitle: draftDisplayTitle, submissionType: ObjectSubmissionTypes.form }, }) ) dispatch(resetCurrentObject()) diff --git a/src/components/SubmissionWizard/WizardSteps/WizardAddObjectStep.tsx b/src/components/SubmissionWizard/WizardSteps/WizardAddObjectStep.tsx index 36801c79b..36a4d8d58 100644 --- a/src/components/SubmissionWizard/WizardSteps/WizardAddObjectStep.tsx +++ b/src/components/SubmissionWizard/WizardSteps/WizardAddObjectStep.tsx @@ -7,6 +7,7 @@ import { makeStyles } from "@mui/styles" import WizardAddObjectCard from "../WizardComponents/WizardAddObjectCard" import { useAppSelector } from "hooks" +import type { FormRef } from "types" const useStyles = makeStyles(() => ({ gridContainer: { @@ -33,7 +34,7 @@ const useStyles = makeStyles(() => ({ /** * Show selection for object and submission types and correct form based on users choice. */ -const WizardAddObjectStep: React.FC = () => { +const WizardAddObjectStep = ({ formRef }: { formRef?: FormRef }) => { const classes = useStyles() const objectType = useAppSelector(state => state.objectType) const loading = useAppSelector(state => state.loading) @@ -49,7 +50,7 @@ const WizardAddObjectStep: React.FC = () => {

You can also add objects and edit them after saving your draft.

) : ( - + )} diff --git a/src/components/SubmissionWizard/WizardSteps/WizardCreateSubmissionStep.tsx b/src/components/SubmissionWizard/WizardSteps/WizardCreateSubmissionStep.tsx index f1745c1dd..542b742a1 100644 --- a/src/components/SubmissionWizard/WizardSteps/WizardCreateSubmissionStep.tsx +++ b/src/components/SubmissionWizard/WizardSteps/WizardCreateSubmissionStep.tsx @@ -22,7 +22,7 @@ import { updateStep } from "features/wizardStepObjectSlice" import { createSubmission, updateSubmission } from "features/wizardSubmissionSlice" import { setSubmissionType } from "features/wizardSubmissionTypeSlice" import { useAppSelector, useAppDispatch } from "hooks" -import type { SubmissionDataFromForm, CreateSubmissionFormRef } from "types" +import type { SubmissionDataFromForm, FormRef } from "types" import { pathWithLocale } from "utils" const useStyles = makeStyles(theme => ({ @@ -54,7 +54,7 @@ const useStyles = makeStyles(theme => ({ /** * Define React Hook Form for adding new submission. Ref is added to RHF so submission can be triggered outside this component. */ -const CreateSubmissionForm = ({ createSubmissionFormRef }: { createSubmissionFormRef: CreateSubmissionFormRef }) => { +const CreateSubmissionForm = ({ createSubmissionFormRef }: { createSubmissionFormRef: FormRef }) => { const classes = useStyles() const dispatch = useAppDispatch() const projectId = useAppSelector(state => state.projectId) @@ -187,7 +187,7 @@ const CreateSubmissionForm = ({ createSubmissionFormRef }: { createSubmissionFor * Show form to create submission as first step of new draft wizard */ -const WizardCreateSubmissionStep = ({ createSubmissionFormRef }: { createSubmissionFormRef: CreateSubmissionFormRef }) => ( +const WizardCreateSubmissionStep = ({ createSubmissionFormRef }: { createSubmissionFormRef: FormRef }) => ( <> diff --git a/src/types/index.ts b/src/types/index.ts index 390f9a43c..144f80ecf 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -85,7 +85,7 @@ export type SubmissionDataFromForm = { description: string } -export type CreateSubmissionFormRef = { current: HTMLElement | null } | undefined +export type FormRef = { current: HTMLElement | null } | undefined export type StatusDetails = { status: string | null diff --git a/src/utils/index.tsx b/src/utils/index.tsx index 05c474f85..0b7969800 100644 --- a/src/utils/index.tsx +++ b/src/utils/index.tsx @@ -10,8 +10,6 @@ export const getObjectDisplayTitle = (objectType: string, cleanedValues: ObjectD switch (objectType) { case ObjectTypes.study: return cleanedValues.descriptor?.studyTitle || "" - case ObjectTypes.dac: - return cleanedValues.contacts?.find(contact => contact.mainContact)?.name || "" default: return cleanedValues.title || "" } @@ -20,13 +18,7 @@ export const getObjectDisplayTitle = (objectType: string, cleanedValues: ObjectD // Get Primary text for displaying item's title export const getItemPrimaryText = (item: ObjectInsideSubmissionWithTags): string => { if (item.tags?.displayTitle) { - switch (item.schema) { - case ObjectTypes.dac: - case `draft-${ObjectTypes.dac}`: - return `Main Contact: ${item.tags.displayTitle}` - default: - return item.tags.displayTitle - } + return item.tags.displayTitle } else if (item.tags?.fileName) { return item.tags.fileName } diff --git a/src/views/Submission.tsx b/src/views/Submission.tsx index 861f797e9..dc4416cf3 100644 --- a/src/views/Submission.tsx +++ b/src/views/Submission.tsx @@ -17,7 +17,7 @@ import { updateStatus } from "features/statusMessageSlice" import { setSubmission, resetSubmission } from "features/wizardSubmissionSlice" import { useAppDispatch } from "hooks" import submissionAPIService from "services/submissionAPI" -import type { CreateSubmissionFormRef } from "types" +import type { FormRef } from "types" import { useQuery, pathWithLocale } from "utils" import Page404 from "views/ErrorPages/Page404" @@ -49,14 +49,14 @@ const useStyles = makeStyles(theme => ({ /** * Return correct content for each step */ -const getStepContent = (wizardStep: number, createSubmissionFormRef: CreateSubmissionFormRef) => { +const getStepContent = (wizardStep: number, createSubmissionFormRef: FormRef, objectFormRef: FormRef) => { switch (wizardStep) { case 1: return case 2: case 3: case 4: - return + return case 5: return default: @@ -114,17 +114,19 @@ const SubmissionWizard: React.FC = () => { const createSubmissionFormRef = useRef void })>(null) + const objectFormRef = useRef void })>(null) + return ( - + {isFetchingSubmission && submissionId && } {(!isFetchingSubmission || !submissionId) && ( - {getStepContent(wizardStep, createSubmissionFormRef)} + {getStepContent(wizardStep, createSubmissionFormRef, objectFormRef)} )}