diff --git a/cypress/e2e/submission-ui.cy.ts b/cypress/e2e/submission-ui.cy.ts index 1b6f9b3ca3b..d26ddfe60a2 100644 --- a/cypress/e2e/submission-ui.cy.ts +++ b/cypress/e2e/submission-ui.cy.ts @@ -283,6 +283,12 @@ describe('Create a new submission', () => { // DON'T upload any file - just check the license section is accessible createItemProcess.checkLicenseSelectionValue('Select a License ...'); + // Allow frontend to propagate the initial section status (no file => valid) + // before asserting the header icon. Mirrors the pattern used in the + // sibling "license validation when file is uploaded" test above. + cy.wait(1000); + cy.get('div[id="section_clarin-license"]').find('.card-header').should('be.visible'); + // Verify warning and error icons do NOT exist cy.get('div[id="section_clarin-license"]') .find('.card-header') @@ -294,9 +300,11 @@ describe('Create a new submission', () => { .find('.fa-exclamation-circle.text-danger') .should('not.exist'); + // Green check must eventually appear (retry-ability with a longer timeout + // handles any remaining async settle of the section status observable). cy.get('div[id="section_clarin-license"]') .find('.card-header') - .find('.fa-check-circle.text-success') + .find('.fa-check-circle.text-success', { timeout: 15000 }) .should('be.visible'); }); diff --git a/src/app/submission/sections/clarin-license-resource/section-license.component.spec.ts b/src/app/submission/sections/clarin-license-resource/section-license.component.spec.ts index 55832cd987f..2a492883f69 100644 --- a/src/app/submission/sections/clarin-license-resource/section-license.component.spec.ts +++ b/src/app/submission/sections/clarin-license-resource/section-license.component.spec.ts @@ -27,6 +27,7 @@ import { FormComponent } from '../../../shared/form/form.component'; import { SubmissionSectionClarinLicenseComponent } from './section-license.component'; import { CollectionDataService } from '../../../core/data/collection-data.service'; import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder'; +import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner'; import { SectionFormOperationsService } from '../form/section-form-operations.service'; import { Collection } from '../../../core/shared/collection.model'; import { License } from '../../../core/shared/license.model'; @@ -37,6 +38,7 @@ import { HALEndpointService } from '../../../core/shared/hal-endpoint.service'; import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service'; import { ConfigurationDataService } from '../../../core/data/configuration-data.service'; import { RequestService } from '../../../core/data/request.service'; +import { PatchRequest } from '../../../core/data/request.models'; import { SubmissionFormsConfigDataService } from 'src/app/core/config/submission-forms-config-data.service'; const collectionId = mockSubmissionCollectionId; @@ -189,6 +191,40 @@ describe('ClarinSubmissionSectionLicenseComponent test suite', () => { it('should create ClarinSubmissionSectionLicenseComponent', inject([SubmissionSectionClarinLicenseComponent], (app: SubmissionSectionClarinLicenseComponent) => { expect(app).toBeDefined(); })); + + it('sendRequest should PATCH /sections//select', + inject([SubmissionSectionClarinLicenseComponent], (app: SubmissionSectionClarinLicenseComponent) => { + // Arrange: enable validation flow so sendRequest actually executes + (app as any).couldShowValidationErrors = true; + (app as any).sectionData = { id: 'clarin-license' } as any; + (app as any).pathCombiner = new JsonPatchOperationPathCombiner('sections', 'clarin-license'); + + const wsiId = 42; + const baseHref = 'http://localhost/api/submission/workspaceitems'; + + spyOn(app as any, 'getActualWorkspaceItem').and.returnValue( + Promise.resolve({ payload: { id: wsiId } }) + ); + spyOn(app as any, 'updateSectionStatus').and.callFake(() => undefined); + + mockRequestService.generateRequestId.and.returnValue('req-id-1'); + mockRequestService.send.calls.reset(); + mockHalService.getEndpoint.and.returnValue(of(baseHref)); + mockRdbService.buildFromRequestUUID.and.returnValue(of({ payload: { sections: {}, errors: [] } } as any)); + + // Act + return (app as any).sendRequest('My CLARIN License').then(() => { + // Assert + expect(mockRequestService.send).toHaveBeenCalledTimes(1); + const sentRequest = mockRequestService.send.calls.mostRecent().args[0] as PatchRequest; + expect(sentRequest.href).toBe(baseHref + '/' + wsiId); + const body: any[] = (sentRequest as any).body; + expect(body.length).toBe(1); + expect(body[0].op).toBe('replace'); + expect(body[0].path).toBe('/sections/clarin-license/select'); + expect(body[0].value).toBe('My CLARIN License'); + }); + })); }); }); diff --git a/src/app/submission/sections/clarin-license-resource/section-license.component.ts b/src/app/submission/sections/clarin-license-resource/section-license.component.ts index 413b50421b9..78c5af9f51a 100644 --- a/src/app/submission/sections/clarin-license-resource/section-license.component.ts +++ b/src/app/submission/sections/clarin-license-resource/section-license.component.ts @@ -278,8 +278,11 @@ export class SubmissionSectionClarinLicenseComponent extends SectionModelCompone const requestId = this.requestService.generateRequestId(); const hrefObs = this.halService.getEndpoint(this.workspaceItemService.getLinkPath()); + // Route the PATCH through the `clarin-license` submission step so it + // works for workflow items too and keeps `sections.license` (CC) and + // `sections.clarin-license` payloads separate on subsequent GETs. const patchOperation2 = { - op: 'replace', path: '/license', value: licenseNameRest + op: 'replace', path: this.pathCombiner.getPath('select').path, value: licenseNameRest } as Operation; hrefObs.pipe(