diff --git a/.gitlab-ci.aperture.yml b/.gitlab-ci.aperture.yml index c168b2d7d7d8a2b2f948f3fed0371b4247417895..0a0dee3462cc4641c8d92e88388092b1221c0137 100644 --- a/.gitlab-ci.aperture.yml +++ b/.gitlab-ci.aperture.yml @@ -54,6 +54,7 @@ test-chrome: - postgres script: - cd ${HOME} + - apt-get update - apt-get -y install postgresql-client # this is needed for pgboss initial setup - psql -h postgres -U kotahidev -d kotahidev -c "create extension pgcrypto;" diff --git a/app/components/component-formbuilder/src/components/builderComponents/RadioBox.js b/app/components/component-formbuilder/src/components/builderComponents/RadioBox.js index f0302c923999488e0bff14579e63e136db2ed916..cd1e92ece70b72b6194266ec6cc3ebfa4c365096 100644 --- a/app/components/component-formbuilder/src/components/builderComponents/RadioBox.js +++ b/app/components/component-formbuilder/src/components/builderComponents/RadioBox.js @@ -1,5 +1,10 @@ import React from 'react' -import { RadioGroup } from '@pubsweet/ui' +import styled from 'styled-components' +import { RadioGroup as UnstableRadioGroup } from '@pubsweet/ui' + +const RadioGroup = styled(UnstableRadioGroup)` + position: relative +` const RadioboxFieldBuilder = input => <RadioGroup {...input} /> export default RadioboxFieldBuilder diff --git a/app/components/component-formbuilder/src/components/config/Elements.js b/app/components/component-formbuilder/src/components/config/Elements.js index c46a8e7f2723809ba3fa773e1eb45b7725783dc3..1729f0c0bafcd83aea3c3380908c2b0c1a809188 100644 --- a/app/components/component-formbuilder/src/components/config/Elements.js +++ b/app/components/component-formbuilder/src/components/config/Elements.js @@ -147,6 +147,23 @@ const elements = { ], }, }, + DoiValidation: { + component: 'RadioBox', + props: { + inline: true, + options: [ + { + value: 'true', + label: 'Yes', + }, + { + value: 'false', + label: 'No', + }, + ], + label: 'DOI Validation', + }, + }, }, CheckboxGroup: { id: textfield, diff --git a/app/components/component-submit/src/components/FormTemplate.js b/app/components/component-submit/src/components/FormTemplate.js index 7a80fbf347d9bf5df18c44ba8d19e2c9149ce839..84e52cae8155ccbc98db368e85be9a3f6b8f3a35 100644 --- a/app/components/component-submit/src/components/FormTemplate.js +++ b/app/components/component-submit/src/components/FormTemplate.js @@ -19,6 +19,8 @@ import LinksInput from './LinksInput' import ValidatedFieldFormik from './ValidatedField' import Confirm from './Confirm' import { articleStatuses } from '../../../../globals' +import { VALIDATE_DOI } from '../../../../queries/index' +import { useApolloClient } from '@apollo/client' const Intro = styled.div` font-style: italic; @@ -110,7 +112,7 @@ const createMarkup = encodedHtml => ({ __html: unescape(encodedHtml), }) -const composeValidate = (vld = [], valueField = {}) => value => { +const composeValidate = (vld = [], valueField = {}, fieldName, client) => value => { const validator = vld || [] if (validator.length === 0) return undefined @@ -129,6 +131,20 @@ const composeValidate = (vld = [], valueField = {}) => value => { return validatorFn }) + + if(errors.length === 0 && fieldName === 'submission.articleURL') { + return client.query({ + query: VALIDATE_DOI, + variables: { + articleURL: value + } + }).then(res => { + if (!res.data.validateDOI.isDOIValid) { + return 'DOI is invalid' + } + return undefined + }) + } return errors.length > 0 ? errors[0] : undefined } @@ -150,6 +166,7 @@ const FormTemplate = ({ validateForm, match, }) => { + const client = useApolloClient() const submitButton = text => ( <div> <Button @@ -256,6 +273,8 @@ const FormTemplate = ({ validate={composeValidate( element.validate, element.validateValue, + element.name, + client )} values={values} /> diff --git a/app/queries/index.js b/app/queries/index.js index d4b8427653b96a29005d1b54cfa91eecef90ecaa..8b36453fbb992089937e1b520c04b4836217a40e 100644 --- a/app/queries/index.js +++ b/app/queries/index.js @@ -83,6 +83,18 @@ export const SEARCH_USERS = gql` } ` +export const VALIDATE_DOI = gql` + query Manuscripts( + $articleURL: String + ) { + validateDOI( + articleURL: $articleURL + ){ + isDOIValid + } + } +` + export const GET_MANUSCRIPTS = gql` query Manuscripts( $sort: String diff --git a/app/storage/forms-ncrc/submit.json b/app/storage/forms-ncrc/submit.json index 5a0f0fcb2af05620377097cbfb3a34f3d1348153..cba65b43a009367cf62364c9fdc24bf1b12e3b1a 100644 --- a/app/storage/forms-ncrc/submit.json +++ b/app/storage/forms-ncrc/submit.json @@ -224,7 +224,7 @@ ] } ], - "id": "NCRC Submission Form", + "id": "submit", "name": "NCRC Submission Form", "description": "<p>NCRC Form</p>", "haspopup": "false" diff --git a/config/permissions.js b/config/permissions.js index 27b697bc679d532c8984047d2fec2c72561ee768..a2c154abd0484ee6db92313f30a4a1722dfb5114 100644 --- a/config/permissions.js +++ b/config/permissions.js @@ -307,6 +307,7 @@ const permissions = { getForm: allow, getForms: allow, user: allow, + validateDOI: allow, }, Mutation: { upload: isAuthenticated, diff --git a/cypress.json b/cypress.json index 44964024078a78571666740a915b8224e2a7f55b..542f48538fb4b71b717e96109488e444e5c61c5b 100644 --- a/cypress.json +++ b/cypress.json @@ -1,5 +1,4 @@ { "baseUrl": "http://localhost:4000", - "nodeVersion": "system", - "defaultCommandTimeout": 8000 + "nodeVersion": "system" } diff --git a/cypress/integration/elife/form_builer_page_spec.js b/cypress/integration/elife/form_builer_page_spec.js index 01954de09f7a8fb708526272290709ac5b56e705..4c366a597d4c3a43adb024797be0d912798c6565 100644 --- a/cypress/integration/elife/form_builer_page_spec.js +++ b/cypress/integration/elife/form_builer_page_spec.js @@ -1,3 +1,4 @@ +/* eslint-disable jest/expect-expect */ import { FormsPage } from '../../page-object/forms-page' import { NewSubmissionPage } from '../../page-object/new-submission-page' import { SubmissionFormPage } from '../../page-object/submission-form-page' @@ -15,6 +16,7 @@ describe('Form builder page tests', () => { cy.fixture('role_names').then(name => { cy.login(name.role.admin, formBuilder) }) + FormsPage.verifyPageLoaded() }) it('check title and elements from form builder', () => { @@ -78,8 +80,9 @@ describe('Form builder page tests', () => { cy.fixture('role_names').then(name => { cy.login(name.role.admin, manuscripts) }) + ManuscriptsPage.getTableHeader().should('be.visible') ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() }) // check if the form contain all the columns diff --git a/cypress/integration/elife/manuscripts_page_spec.js b/cypress/integration/elife/manuscripts_page_spec.js index a1fa7eda6dcce9bba37e1d8a8511b476e10f42a3..58bc7afbc47070e735ce6c387025a3b17eb775b5 100644 --- a/cypress/integration/elife/manuscripts_page_spec.js +++ b/cypress/integration/elife/manuscripts_page_spec.js @@ -1,3 +1,4 @@ +/* eslint-disable jest/expect-expect */ import { ManuscriptsPage } from '../../page-object/manuscripts-page' import { NewSubmissionPage } from '../../page-object/new-submission-page' import { SubmissionFormPage } from '../../page-object/submission-form-page' @@ -15,6 +16,7 @@ describe('Manuscripts page tests', () => { cy.fixture('role_names').then(name => { cy.login(name.role.admin, manuscripts) }) + ManuscriptsPage.getTableHeader().should('be.visible') }) it('check Submit button is visible', () => { @@ -22,13 +24,13 @@ describe('Manuscripts page tests', () => { }) it('evaluation button is visible on unsubmited status article', () => { ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() // fill the submit form and submit it // eslint-disable-next-line jest/valid-expect-in-promise cy.fixture('submission_form_data').then(data => { SubmissionFormPage.fillInArticleld(data.articleId) }) - Menu.clickManuscripts() + Menu.clickManuscriptsAndAssertPageLoad() ManuscriptsPage.getEvaluationButton().should('be.visible') }) }) @@ -43,28 +45,26 @@ describe('Manuscripts page tests', () => { cy.fixture('role_names').then(name => { cy.login(name.role.admin, manuscripts) }) + ManuscriptsPage.getTableHeader().should('be.visible') ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() // fill the submit form and submit it // eslint-disable-next-line jest/valid-expect-in-promise cy.fixture('submission_form_data').then(data => { SubmissionFormPage.fillInArticleld(data.articleId) }) - Menu.clickManuscripts() + Menu.clickManuscriptsAndAssertPageLoad() }) - it('unsubmited article is evaluated', () => { + it('unsubmitted article is evaluated', () => { ManuscriptsPage.clickEvaluation() cy.url().should('contain', 'evaluation') - // SubmissionFormPage.getArticleld().should('have.value', '') SubmissionFormPage.getArticleUrl().should('have.value', '') - // eslint-disable-next-line SubmissionFormPage.getDescription().should('have.value', '') SubmissionFormPage.getEvaluationContent() .find('p') .should('have.value', '') - // eslint-disable-next-line SubmissionFormPage.getFormOptionValue(-1).should('have.value', '') // eslint-disable-next-line jest/valid-expect-in-promise cy.fixture('submission_form_data').then(data => { @@ -75,24 +75,24 @@ describe('Manuscripts page tests', () => { SubmissionFormPage.clickElementFromFormOptionList(4) SubmissionFormPage.selectDropdownOption(1) SubmissionFormPage.clickSubmitResearch() - SubmissionFormPage.clickSubmitManuscript() + SubmissionFormPage.clickSubmitManuscriptAndWaitPageLoad() }) ManuscriptsPage.getStatus(0).should('eq', 'evaluated') }) it('sort article after Article id', () => { ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() SubmissionFormPage.fillInArticleld('456') - Menu.clickManuscripts() + Menu.clickManuscriptsAndAssertPageLoad() ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() SubmissionFormPage.fillInArticleld('abc') - Menu.clickManuscripts() + Menu.clickManuscriptsAndAssertPageLoad() ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() SubmissionFormPage.fillInArticleld('def') - Menu.clickManuscripts() + Menu.clickManuscriptsAndAssertPageLoad() ManuscriptsPage.getArticleTitleByRow(0).should('contain', 'def') ManuscriptsPage.getArticleTitleByRow(1).should('contain', 'abc') ManuscriptsPage.getArticleTitleByRow(2).should('contain', '456') @@ -105,7 +105,7 @@ describe('Manuscripts page tests', () => { }) }) - context('Submited and evaluated article tests', () => { + context('Submitted and evaluated article tests', () => { beforeEach(() => { // task to restore the database as per the dumps/initialState.sql cy.task('restore', 'initialState') @@ -115,10 +115,11 @@ describe('Manuscripts page tests', () => { cy.fixture('role_names').then(name => { cy.login(name.role.admin, manuscripts) + ManuscriptsPage.getTableHeader().should('be.visible') ManuscriptsPage.getEvaluationButton().should('not.exist') ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() // fill the submit form and submit it // eslint-disable-next-line jest/valid-expect-in-promise @@ -131,9 +132,8 @@ describe('Manuscripts page tests', () => { SubmissionFormPage.selectDropdownOption(1) SubmissionFormPage.fillInCreator(name.role.admin) // eslint-disable-next-line - cy.wait(2000) SubmissionFormPage.clickSubmitResearch() - SubmissionFormPage.clickSubmitManuscript() + SubmissionFormPage.clickSubmitManuscriptAndWaitPageLoad() }) }) }) @@ -146,16 +146,16 @@ describe('Manuscripts page tests', () => { }) it('evaluate article and check status is changed', () => { ManuscriptsPage.getStatus(0).should('eq', 'Submitted') - ManuscriptsPage.clickEvaluation(0) + ManuscriptsPage.clickEvaluation() - SubmissionFormPage.clickSubmitResearch() + SubmissionFormPage.clickSubmitResearchAndWaitPageLoad() ManuscriptsPage.getStatus(0).should('eq', 'evaluated') ManuscriptsPage.getEvaluationButton().should('be.visible') }) it('submission details should be visible', () => { ManuscriptsPage.getStatus(0).should('eq', 'Submitted') - ManuscriptsPage.clickEvaluation(0) + ManuscriptsPage.clickEvaluation() // eslint-disable-next-line jest/valid-expect-in-promise cy.fixture('submission_form_data').then(data => { SubmissionFormPage.getArticleld().should('have.value', data.articleId) @@ -183,7 +183,7 @@ describe('Manuscripts page tests', () => { ManuscriptsPage.getAuthor(0).should('eq', name.role.admin) ManuscriptsPage.getStatus(0).should('eq', 'Submitted') }) - ManuscriptsPage.clickEvaluation(0) + ManuscriptsPage.clickEvaluation() SubmissionFormPage.fillInArticleld('123 - Evaluated') SubmissionFormPage.fillInArticleUrl('new url') SubmissionFormPage.fillInDescription('new description') @@ -192,8 +192,7 @@ describe('Manuscripts page tests', () => { SubmissionFormPage.selectDropdownOption(-1) SubmissionFormPage.fillInCreator('creator') // eslint-disable-next-line - cy.wait(2000) - SubmissionFormPage.clickSubmitResearch() + SubmissionFormPage.clickSubmitResearchAndWaitPageLoad() ManuscriptsPage.clickEvaluation() // eslint-disable-next-line SubmissionFormPage.getArticleld().should( diff --git a/cypress/integration/ncrc/form_builder_page_spec.js b/cypress/integration/ncrc/form_builder_page_spec.js index 9bba6426e16ad89031e66f343521b6b4ba4429ea..539b56d6f94d196429594ec79bdf785849f5a2d7 100644 --- a/cypress/integration/ncrc/form_builder_page_spec.js +++ b/cypress/integration/ncrc/form_builder_page_spec.js @@ -1,3 +1,4 @@ +/* eslint-disable jest/expect-expect */ import { formBuilder, manuscripts } from '../../support/routes' import { FormsPage } from '../../page-object/forms-page' import { ManuscriptsPage } from '../../page-object/manuscripts-page' @@ -14,6 +15,7 @@ describe('form builder tests', () => { cy.fixture('role_names').then(name => { cy.login(name.role.admin, formBuilder) }) + FormsPage.verifyPageLoaded() }) it('check form entries are correct', () => { // eslint-disable-next-line jest/valid-expect-in-promise @@ -84,8 +86,9 @@ describe('form builder tests', () => { cy.fixture('role_names').then(name => { cy.login(name.role.admin, manuscripts) }) + ManuscriptsPage.getTableHeader().should('be.visible') ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() }) it('check submission form contains the same fields', () => { diff --git a/cypress/integration/ncrc/manuscripts_page_spec.js b/cypress/integration/ncrc/manuscripts_page_spec.js index a581d239c5f2869dd540a8155ac4b876162303d8..60288f3044726f74467b0087634f0d01456a4ef1 100644 --- a/cypress/integration/ncrc/manuscripts_page_spec.js +++ b/cypress/integration/ncrc/manuscripts_page_spec.js @@ -1,3 +1,4 @@ +/* eslint-disable jest/expect-expect */ import { manuscripts } from '../../support/routes' import { ManuscriptsPage } from '../../page-object/manuscripts-page' import { NewSubmissionPage } from '../../page-object/new-submission-page' @@ -14,6 +15,7 @@ describe('manuscripts page tests', () => { cy.fixture('role_names').then(name => { cy.login(name.role.admin, manuscripts) }) + ManuscriptsPage.getTableHeader().should('be.visible') }) context('elements visibility', () => { it('submit button should be visible & dashboard page should not exist', () => { @@ -23,20 +25,20 @@ describe('manuscripts page tests', () => { it('evaluation button should be visible for unsubmitted articles', () => { ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() // fill the submit form and submit it // eslint-disable-next-line jest/valid-expect-in-promise cy.fixture('submission_form_data').then(data => { SubmissionFormPage.fillInArticleDescription(data.articleId) }) - Menu.clickManuscripts() + Menu.clickManuscriptsAndAssertPageLoad() ManuscriptsPage.getEvaluationButton() .scrollIntoView() .should('be.visible') }) it('label & topics should be visible on manuscripts page', () => { ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() // fill the submit form and submit it // eslint-disable-next-line jest/valid-expect-in-promise cy.fixture('submission_form_data').then(data => { @@ -44,7 +46,7 @@ describe('manuscripts page tests', () => { SubmissionFormPage.selectDropdownOption(1) SubmissionFormPage.clickTopicsCheckboxWithText(data.topic) SubmissionFormPage.clickTopicsCheckboxWithText('epidemiology') - Menu.clickManuscripts() + Menu.clickManuscriptsAndAssertPageLoad() ManuscriptsPage.getArticleLabel() .should('be.visible') .and('contain', 'evaluated') @@ -56,7 +58,7 @@ describe('manuscripts page tests', () => { context('unsubmitted article tests', () => { beforeEach(() => { ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() }) it('unsubmitted article is evaluated', () => { @@ -64,7 +66,7 @@ describe('manuscripts page tests', () => { cy.fixture('submission_form_data').then(data => { SubmissionFormPage.fillInArticleDescription(data.title) }) - Menu.clickManuscripts() + Menu.clickManuscriptsAndAssertPageLoad() ManuscriptsPage.clickEvaluation() cy.url().should('contain', 'evaluation') SubmissionFormPage.getArticleUrl().should('have.value', '') @@ -92,7 +94,7 @@ describe('manuscripts page tests', () => { SubmissionFormPage.clickDropdown(-1) SubmissionFormPage.selectDropdownOption(0) SubmissionFormPage.clickTopicsCheckboxWithText(data.topic) - SubmissionFormPage.clickSubmitManuscript() + SubmissionFormPage.clickSubmitManuscriptAndWaitPageLoad() ManuscriptsPage.getStatus(0).should('eq', 'evaluated') ManuscriptsPage.getArticleTopic(0) .should('be.visible') @@ -104,7 +106,7 @@ describe('manuscripts page tests', () => { context('submitted and evaluated article tests', () => { beforeEach(() => { ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() // fill the submit form and submit it // eslint-disable-next-line jest/valid-expect-in-promise cy.fixture('submission_form_data').then(data => { @@ -122,8 +124,8 @@ describe('manuscripts page tests', () => { SubmissionFormPage.selectDropdownOption(0) SubmissionFormPage.clickTopicsCheckboxWithText(data.topic) // eslint-disable-next-line - cy.wait(2000) - SubmissionFormPage.clickSubmitManuscript() + SubmissionFormPage.waitThreeSec() + SubmissionFormPage.clickSubmitManuscriptAndWaitPageLoad() }) }) it('manuscripts page should contain the correct details after submission', () => { @@ -147,9 +149,9 @@ describe('manuscripts page tests', () => { }) it('evaluate article and check status is changed', () => { ManuscriptsPage.getStatus(0).should('eq', 'Submitted') - ManuscriptsPage.clickEvaluation(0) + ManuscriptsPage.clickEvaluation() - SubmissionFormPage.clickSubmitManuscript() + SubmissionFormPage.clickSubmitManuscriptAndWaitPageLoad() ManuscriptsPage.getStatus(0).should('eq', 'evaluated') }) @@ -157,12 +159,12 @@ describe('manuscripts page tests', () => { // eslint-disable-next-line jest/valid-expect-in-promise cy.fixture('submission_form_data').then(data => { ManuscriptsPage.getStatus(0).should('eq', 'Submitted') - ManuscriptsPage.clickEvaluation(0) + ManuscriptsPage.clickEvaluation() SubmissionFormPage.fillInValueAdded('Evaluated') SubmissionFormPage.clickTopicsCheckboxWithText('vaccines') // eslint-disable-next-line - cy.wait(2500) - SubmissionFormPage.clickSubmitManuscript() + SubmissionFormPage.waitThreeSec() + SubmissionFormPage.clickSubmitManuscriptAndWaitPageLoad() ManuscriptsPage.clickEvaluation() // eslint-disable-next-line SubmissionFormPage.getValueAddedField().should( @@ -176,7 +178,7 @@ describe('manuscripts page tests', () => { context('filter and sort articles', () => { beforeEach(() => { ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() // eslint-disable-next-line jest/valid-expect-in-promise cy.fixture('form_option').then(data => { SubmissionFormPage.fillInArticleDescription('123') @@ -185,9 +187,9 @@ describe('manuscripts page tests', () => { SubmissionFormPage.clickTopicsCheckboxWithText( data.ncrc.topicTypes.vaccines, ) - Menu.clickManuscripts() + Menu.clickManuscriptsAndAssertPageLoad() ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() SubmissionFormPage.fillInArticleDescription('abc') SubmissionFormPage.clickElementFromFormOptionList(9) SubmissionFormPage.selectDropdownOption(1) @@ -197,9 +199,9 @@ describe('manuscripts page tests', () => { SubmissionFormPage.clickTopicsCheckboxWithText( data.ncrc.topicTypes.diagnostics, ) - Menu.clickManuscripts() + Menu.clickManuscriptsAndAssertPageLoad() ManuscriptsPage.clickSubmit() - NewSubmissionPage.clickSubmitURL() + NewSubmissionPage.clickSubmitUrlAndVerifyLink() SubmissionFormPage.fillInArticleDescription('def') SubmissionFormPage.clickElementFromFormOptionList(9) SubmissionFormPage.selectDropdownOption(0) @@ -209,9 +211,8 @@ describe('manuscripts page tests', () => { SubmissionFormPage.clickTopicsCheckboxWithText( data.ncrc.topicTypes.diagnostics, ) - Menu.clickManuscripts() + Menu.clickManuscriptsAndAssertPageLoad() // eslint-disable-next-line - cy.wait(2000) }) }) it('filter article after topic and url contain that topic', () => { @@ -219,7 +220,7 @@ describe('manuscripts page tests', () => { ManuscriptsPage.getTableRows().should('eq', 1) cy.url().should('contain', 'vaccines') ManuscriptsPage.getArticleTopic(0).should('contain', 'vaccines') - Menu.clickManuscripts() + Menu.clickManuscriptsAndAssertPageLoad() ManuscriptsPage.clickArticleTopic(1) ManuscriptsPage.getTableRows().should('eq', 2) cy.url().should('contain', 'diagnostics') @@ -230,7 +231,7 @@ describe('manuscripts page tests', () => { 'ecology and spillover', ) ManuscriptsPage.getArticleTopic(3).should('contain', 'diagnostics') - Menu.clickManuscripts() + Menu.clickManuscriptsAndAssertPageLoad() ManuscriptsPage.clickArticleTopic(0) ManuscriptsPage.getTableRows().should('eq', 1) cy.url().should('contain', 'modeling') diff --git a/cypress/page-object/forms-page.js b/cypress/page-object/forms-page.js index 9bc8175e9ad4e74c1b6d64aa99a38b0009661dc8..9cdd4ea3e050569a67ea3c83f25f9a77051eb574 100644 --- a/cypress/page-object/forms-page.js +++ b/cypress/page-object/forms-page.js @@ -3,37 +3,41 @@ * Page object representing the second option from the left side menu, * which contains a number of options & fields to fill in / dropdowns. */ -const FORM_TITLE_TAB = '[data-test-id="tab-container"] > div'; -const FORM_OPTION_LIST = '[class*=FormBuilder__Element] > button:nth-child(1)'; -const NAME_FIELD = 'name'; +const FORM_TITLE_TAB = '[data-test-id="tab-container"] > div' +const FORM_OPTION_LIST = '[class*=FormBuilder__Element] > button:nth-child(1)' +const NAME_FIELD = 'name' const COMPONENT_TYPE = '[role=listbox]' const FIELD_VALIDATE = '[class*=react-select__value-container]' export const FormsPage = { - getFormTitleTab(nth) { - return cy.get(FORM_TITLE_TAB).eq(nth); - }, - getFormTitleText(nth) { - this.getFormTitleTab(nth).invoke('text'); - }, - getFormOptionList() { - return cy.get(FORM_OPTION_LIST); - }, - clickFormOption(nth) { - this.getFormOptionList().eq(nth).click(); - }, + verifyPageLoaded() { + return cy.get(FORM_TITLE_TAB, { timeout: 10000 }).eq(0).should('be.visible') + }, + getFormTitleTab(nth) { + return cy.get(FORM_TITLE_TAB).eq(nth) + }, + getFormTitleText(nth) { + this.getFormTitleTab(nth).invoke('text') + }, + getFormOptionList() { + return cy.get(FORM_OPTION_LIST) + }, + clickFormOption(nth) { + this.getFormOptionList().eq(nth).click() + }, - - getFormBuilderElementName(nth) { - return cy.get(FORM_OPTION_LIST).eq(nth) - }, - getNameField() { - return cy.getByName(NAME_FIELD); - }, - getComponentType() { - return cy.get(COMPONENT_TYPE); - }, - getFieldValidate() { - return cy.get(FIELD_VALIDATE) - } + getFormBuilderElementName(nth) { + return cy.get(FORM_OPTION_LIST).eq(nth) + }, + getNameField() { + return cy.getByName(NAME_FIELD) + }, + getComponentType() { + return cy.get(COMPONENT_TYPE) + }, + getFieldValidate() { + return cy.get(FIELD_VALIDATE) + }, } + +export default FormsPage diff --git a/cypress/page-object/manuscripts-page.js b/cypress/page-object/manuscripts-page.js index 5532db84321d02b1bc4c0e5eb32db5ad1b99c3bd..4844234241a06e04a035c566904a272e4ebccffc 100644 --- a/cypress/page-object/manuscripts-page.js +++ b/cypress/page-object/manuscripts-page.js @@ -1,4 +1,6 @@ /// <reference types="Cypress" /> +import { evaluate } from '../support/routes' + /** * Page component representing the fourth option in the left side menu, * where users can see the list of submitted manuscripts & select Control, @@ -12,6 +14,7 @@ const CONTROL_BUTTON = '[href*=control]' const CREATED_CARET = 'Carets__Caret' const AUTHOR_FIELD = 'UserCombo__Primary' const STATUS_FIELD = 'Badge__Status' +const TABLE_HEADER = '[class*=Table__Header]' const MANUSCRIPTS_TABLE_HEAD = '[class*=Table__Header] > tr >th' const ARTICLE_TITLE = '[class*=Table__Row]>td:nth-child(1)' const ARTICLE_LABEL = 'style__StyledTableLabel' @@ -44,6 +47,10 @@ export const ManuscriptsPage = { clickEvaluation() { this.getEvaluationButton().click() }, + clickEvaluationAndVerifyUrl() { + this.clickEvaluation() + cy.url({ timeout: 10000 }).should('contain', evaluate) + }, getControlButton() { return cy.get(CONTROL_BUTTON) }, @@ -86,5 +93,8 @@ export const ManuscriptsPage = { getLabelRow(nth) { return cy.get(LABEL).eq(nth) }, + getTableHeader() { + return cy.get(TABLE_HEADER, { timeout: 10000 }) + }, } export default ManuscriptsPage diff --git a/cypress/page-object/new-submission-page.js b/cypress/page-object/new-submission-page.js index 754e8c96ce8db52b530031f0c2270231999fc04c..14382a20df50125774045b5adf931bd4d0b1486e 100644 --- a/cypress/page-object/new-submission-page.js +++ b/cypress/page-object/new-submission-page.js @@ -1,26 +1,34 @@ /// <reference types="Cypress" /> +import { submit } from '../support/routes' + /** * Page object representing the available submission options: * submission through uploading a manuscript or through using an URL. */ -const UPLOAD_MANUSCRIPT_BUTTON = 'UploadManuscript__Info'; -const SUBMIT_URL_BUTTON = 'button'; -const SUBMISSION_MESSAGE = 'body'; +const UPLOAD_MANUSCRIPT_BUTTON = 'UploadManuscript__Info' +const SUBMIT_URL_BUTTON = 'button' +const SUBMISSION_MESSAGE = 'body' export const NewSubmissionPage = { - getUploadManuscriptButton() { - return cy.getByContainsClass(UPLOAD_MANUSCRIPT_BUTTON); - }, - clickUploadManuscript() { - this.getUploadManuscriptButton().click(); - }, - getSubmitURLButton() { - return cy.get(SUBMIT_URL_BUTTON); - }, - clickSubmitURL() { - this.getSubmitURLButton().click(); - }, - getSubmissionMessage() { - return cy.get(SUBMISSION_MESSAGE).invoke('text'); - } -} \ No newline at end of file + getUploadManuscriptButton() { + return cy.getByContainsClass(UPLOAD_MANUSCRIPT_BUTTON) + }, + clickUploadManuscript() { + this.getUploadManuscriptButton().click() + }, + getSubmitURLButton() { + return cy.get(SUBMIT_URL_BUTTON) + }, + clickSubmitURL() { + this.getSubmitURLButton().click() + }, + clickSubmitUrlAndVerifyLink() { + this.clickSubmitURL() + cy.url({ timeout: 15000 }).should('contain', submit) + }, + getSubmissionMessage() { + return cy.get(SUBMISSION_MESSAGE).invoke('text') + }, +} + +export default NewSubmissionPage diff --git a/cypress/page-object/page-component/menu.js b/cypress/page-object/page-component/menu.js index da43dc01378cfc93382dcd9a0032a29589c26fb7..b4ae870e4b311f93ba794b3bfaa9c83cf7cfa63b 100644 --- a/cypress/page-object/page-component/menu.js +++ b/cypress/page-object/page-component/menu.js @@ -1,4 +1,6 @@ /// <reference types="Cypress" /> +import { ManuscriptsPage } from '../manuscripts-page' + /** * Page component which represents the left side menu bar, * which contains the Logged User, Dashboard & My profile options (for non-admin users), @@ -34,6 +36,10 @@ export const Menu = { clickManuscripts() { this.getManuscriptsButton().click() }, + clickManuscriptsAndAssertPageLoad() { + this.clickManuscripts() + ManuscriptsPage.getTableHeader().should('be.visible') + }, getMyProfileButton() { return cy.getByContainsClass(MENU_BUTTON).contains('My profile') }, diff --git a/cypress/page-object/submission-form-page.js b/cypress/page-object/submission-form-page.js index 29e97db337553599b5700c3285d6d7c0cf64b1ac..0c2408ab7c8d23330a6f3362e8b0fde3265bf4e1 100644 --- a/cypress/page-object/submission-form-page.js +++ b/cypress/page-object/submission-form-page.js @@ -1,4 +1,6 @@ /// <reference types="Cypress" /> +import { ManuscriptsPage } from './manuscripts-page' + /** * Page object representing the form which has * to be completed to correctly submit a research paper. @@ -211,12 +213,20 @@ export const SubmissionFormPage = { clickSubmitResearch() { this.getSubmitResearchButton().click() }, + clickSubmitResearchAndWaitPageLoad() { + this.clickSubmitResearch() + ManuscriptsPage.getTableHeader().should('be.visible') + }, getSubmitManuscriptButton() { return cy.get(SUBMIT_MANUSCRIPT_BUTTON) }, clickSubmitManuscript() { this.getSubmitManuscriptButton().click() }, + clickSubmitManuscriptAndWaitPageLoad() { + this.clickSubmitManuscript() + ManuscriptsPage.getTableHeader().should('be.visible') + }, getValidationErrorMessage(error) { return cy.getByContainsClass(VALIDATION_ERROR_MESSAGE).contains(error) }, @@ -336,5 +346,9 @@ export const SubmissionFormPage = { clickTopicsCheckboxWithText(value) { this.getTopicsCheckboxWithText(value).click() }, + waitThreeSec() { + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(3000) + }, } export default SubmissionFormPage diff --git a/cypress/support/routes.js b/cypress/support/routes.js index 6cdab8f2e789701f5b1cce447ef3a83350da3284..3080992947f37f10d444c0e8b34026b18abe893f 100644 --- a/cypress/support/routes.js +++ b/cypress/support/routes.js @@ -4,3 +4,5 @@ export const manuscripts = '/kotahi/admin/manuscripts' export const formBuilder = '/kotahi/admin/form-builder' export const users = '/kotahi/admin/users' export const profile = '/kotahi/profile' +export const submit = '/submit' +export const evaluate = '/evaluate' diff --git a/docker-compose.production.elife.yml b/docker-compose.production.elife.yml index 5b94f49d7b1c6180d7f8c1392f4abd196119b47e..1a4f1d40fe09ac15a100455e587bbfe21f938814 100644 --- a/docker-compose.production.elife.yml +++ b/docker-compose.production.elife.yml @@ -52,7 +52,7 @@ services: - ./db-data:/var/lib/postgresql/data/kotahi:z job-xsweet: - image: pubsweet/job-xsweet:1.5.0 + image: cokoapps/job-xsweet:1.5.1 environment: - DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST:-db}:${POSTGRES_PORT}/${POSTGRES_DB} depends_on: diff --git a/docker-compose.production.ncrc.yml b/docker-compose.production.ncrc.yml index 49a5c276595b0a55dbdcf8081d7e58f5f8a91e2a..3a16954d6791a96fbfcec28af5a01d2750a72d28 100644 --- a/docker-compose.production.ncrc.yml +++ b/docker-compose.production.ncrc.yml @@ -52,7 +52,7 @@ services: - ./db-data:/var/lib/postgresql/data/kotahi:z job-xsweet: - image: pubsweet/job-xsweet:1.5.0 + image: cokoapps/job-xsweet:1.5.1 environment: - DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST:-db}:${POSTGRES_PORT}/${POSTGRES_DB} depends_on: diff --git a/docker-compose.production.yml b/docker-compose.production.yml index 3063a8f3eab9834baed91221165612bf883c508d..66b721686697f071c124016eea6ff0fc434594a4 100644 --- a/docker-compose.production.yml +++ b/docker-compose.production.yml @@ -38,7 +38,7 @@ services: - INSTANCE_NAME=${INSTANCE_NAME:-elife} job-xsweet: - image: pubsweet/job-xsweet:1.5.0 + image: cokoapps/job-xsweet:1.5.1 depends_on: - server command: diff --git a/docker-compose.yml b/docker-compose.yml index 7205cf7ea55d376b479e4bcdeea91f8c07ab2670..46b3caca50cb293b734833932e425354676b105a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -80,7 +80,7 @@ services: - ./server:/home/node/app/server job-xsweet: - image: pubsweet/job-xsweet:1.5.0 + image: cokoapps/job-xsweet:1.5.1 depends_on: - server command: diff --git a/package.json b/package.json index 0fff8235ed1551ca29394a458eeace6b9564bf36..51023f5980ab7c2eb7380403da5aab345cdf3d51 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "@pubsweet/base-model": "4.0.0", "@pubsweet/component-send-email": "0.4.3", "@pubsweet/errors": "^2.0.40", - "@pubsweet/job-xsweet": "^2.1.11", + "@pubsweet/job-xsweet": "^2.2.0", "@pubsweet/logger": "^0.2.50", "@pubsweet/model-user": "6.0.3", "@pubsweet/models": "^0.3.15", diff --git a/server/model-manuscript/src/graphql.js b/server/model-manuscript/src/graphql.js index 2a1726f0144905bebb8ea9a2f236ff254594e5eb..7435cc6b387afa5fc4c5bf695cd154b6c8d12299 100644 --- a/server/model-manuscript/src/graphql.js +++ b/server/model-manuscript/src/graphql.js @@ -507,6 +507,23 @@ const resolvers = { // return ctx.connectors.User.fetchAll(where, ctx, { eager }) }, + + async validateDOI(_, { articleURL }, ctx) { + const DOI = encodeURI(articleURL.split('.org/')[1]) + try { + await axios.get(`https://api.crossref.org/works/${DOI}/agency`) + + return { + isDOIValid: true + } + } catch(err) { + // eslint-disable-next-line + console.log(err) + return { + isDOIValid: false + } + } + } }, // We want submission into to come out as a stringified JSON, so that we don't have to // change our queries if the submission form changes. We still want to store it as JSONB @@ -522,6 +539,7 @@ const typeDefs = ` manuscripts: [Manuscript]! paginatedManuscripts(sort: String, offset: Int, limit: Int, filter: ManuscriptsFilter): PaginatedManuscripts publishedManuscripts(sort:String, offset: Int, limit: Int): PaginatedManuscripts + validateDOI(articleURL: String): validateDOIResponse } input ManuscriptsFilter { @@ -529,6 +547,10 @@ const typeDefs = ` submission: String } + type validateDOIResponse { + isDOIValid: Boolean + } + type PaginatedManuscripts { totalCount: Int manuscripts: [Manuscript] diff --git a/yarn.lock b/yarn.lock index 045d9b3f6a28e069be9e1a0b3eaac2a7c27518ec..7352381b11c60f60bcf30f5b5798859da1ba5c26 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2509,6 +2509,21 @@ tmp-promise "^2.0.0" umzug "^2.1.0" +"@pubsweet/db-manager@^3.1.23": + version "3.1.23" + resolved "https://registry.yarnpkg.com/@pubsweet/db-manager/-/db-manager-3.1.23.tgz#0d5f814605419f1dc53d6b4f306c4bfd279a9e9a" + integrity sha512-/cJq4nntAV5EzuctXapktQqYtj7ywMbcrQt0XMN6QRE5XzBZYevDUGdZdp+2GKhdUG/8pEsPFjDeHMgi1xWbyg== + dependencies: + "@hapi/joi" "^14.3.0" + "@pubsweet/logger" "^0.2.58" + fs-extra "^8.1.0" + knex "^0.21.1" + lodash "^4.17.11" + objection "^2.1.3" + pg "^7.8.0" + tmp-promise "^2.0.0" + umzug "^2.1.0" + "@pubsweet/errors@^2.0.36", "@pubsweet/errors@^2.0.40", "@pubsweet/errors@^2.0.44": version "2.0.44" resolved "https://registry.yarnpkg.com/@pubsweet/errors/-/errors-2.0.44.tgz#0270e4bc19702e79f5583f6161577a87536c57a1" @@ -2516,16 +2531,16 @@ dependencies: http-status-codes "^1.3.0" -"@pubsweet/job-xsweet@^2.1.11": - version "2.1.20" - resolved "https://registry.yarnpkg.com/@pubsweet/job-xsweet/-/job-xsweet-2.1.20.tgz#325eac40ac7765c7060105875bab59749bea8ee3" - integrity sha512-B5XPFMJY6gXDNFaW5cUW3+SO8EkTk5SFLOI85pQtX1TBm6ek4HpnAAJC0BH09IYDV22LUg36SQPVZISLFj1Rog== +"@pubsweet/job-xsweet@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@pubsweet/job-xsweet/-/job-xsweet-2.2.0.tgz#5a0c095cdb4a3232060555957a047701684d9411" + integrity sha512-yvYL9qkWZxDsFHCTFhShTPklox5PaR2Uz5DypkJWDHx4g91q/Hab9uDCBYKfQgjkFNoYN7jihz7FUHODbKzDsw== dependencies: - "@pubsweet/db-manager" "^3.1.19" - "@pubsweet/logger" "^0.2.54" + "@pubsweet/db-manager" "^3.1.23" + "@pubsweet/logger" "^0.2.58" express-fileupload v1.1.1-alpha.2 node-wait-for-it "^0.2.0" - pubsweet-server "^13.12.3" + pubsweet-server "^13.12.7" tmp-promise "^2.0.0" waait "^1.0.5" @@ -2537,6 +2552,14 @@ "@hapi/joi" "^14.5.0" config "^3.0.1" +"@pubsweet/logger@^0.2.58": + version "0.2.58" + resolved "https://registry.yarnpkg.com/@pubsweet/logger/-/logger-0.2.58.tgz#baab6a6f627e0861fd8d485f5f34fe92ffdca68c" + integrity sha512-8KmpEnEeqKLWWANcYbFyjEt/AHUwHVvJ/mMq3AYLPuwNmr2oifxfO3aps3YOFzAAdH3ayvhOXrL7P5D/HJkctg== + dependencies: + "@hapi/joi" "^14.5.0" + config "^3.0.1" + "@pubsweet/model-user@6.0.3": version "6.0.3" resolved "https://registry.yarnpkg.com/@pubsweet/model-user/-/model-user-6.0.3.tgz#b0ad3e307e293d9794f20bcc3797164732eb221b" @@ -16444,7 +16467,7 @@ pubsweet-client@^10.2.5: styled-normalize "^8.0.6" subscriptions-transport-ws "^0.9.12" -pubsweet-server@13.12.3, pubsweet-server@^13.11.6, pubsweet-server@^13.12.3: +pubsweet-server@13.12.3, pubsweet-server@^13.11.6, pubsweet-server@^13.12.3, pubsweet-server@^13.12.7: version "13.12.3" resolved "https://registry.yarnpkg.com/pubsweet-server/-/pubsweet-server-13.12.3.tgz#f5fade9667000d2be8bc448f15b1df9a89fb58b2" integrity sha512-tl3LemBnFBBo5x/UucwevGDBYb2Jg7mwcYaxQ4tkzVHCoFqC9BB5wx9qGVHM9EwcwhiNMK+vqmzvDClFZrrbvw==