Skip to content

Commit

Permalink
Merge pull request #950 from geonetwork/ME/delete-record
Browse files Browse the repository at this point in the history
ME: delete a record and its draft, delete a draft without record
  • Loading branch information
LHBruneton-C2C authored Aug 19, 2024
2 parents 618ec56 + eeb79bd commit a9a6128
Show file tree
Hide file tree
Showing 46 changed files with 750 additions and 242 deletions.
65 changes: 65 additions & 0 deletions apps/metadata-editor-e2e/src/e2e/delete.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
describe('delete', () => {
beforeEach(() => {
cy.login('admin', 'admin', false)
cy.visit('/catalog/search')
})

describe('record with draft', () => {
it('should delete the record, delete its associated draft and refresh the interface', () => {
// First create a record and its draft
cy.get('[data-cy="create-record"]').click()
cy.get('gn-ui-form-field[ng-reflect-model=abstract] textarea').type(
'record abstract'
)
cy.intercept({
method: 'PUT',
pathname: '**/records',
}).as('insertRecord')
cy.get('md-editor-publish-button').click()
cy.wait('@insertRecord')
cy.get('gn-ui-form-field[ng-reflect-model=abstract] textarea').type(
'draft abstract'
)
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000) // waiting for draft saving to kick in
cy.visit('/catalog/search?_sort=-changeDate')
cy.get('[data-cy="table-row"]')
.contains('My new record')
.should('have.length', 1)
cy.get('[data-cy="dashboard-drafts-count"]').should('contain', '1')
// Delete the record
cy.get('[data-test="record-menu-button"]').first().click()
cy.get('[data-test="record-menu-delete-button"]').click()
cy.get('[data-cy="confirm-button"]').click()
cy.get('[data-cy="table-row"]')
.contains('My new record')
.should('have.length', 0)
cy.get('[data-cy="dashboard-drafts-count"]').should('contain', '0')
})
})

describe('draft without record', () => {
it('should delete the draft and refresh the interface', () => {
// First create a draft
cy.get('[data-cy="create-record"]').click()
cy.get('gn-ui-form-field[ng-reflect-model=abstract] textarea').type(
'draft abstract'
)
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000) // waiting for draft saving to kick in
cy.visit('/my-space/my-draft')
cy.get('[data-cy="table-row"]')
.contains('My new record')
.should('have.length', 1)
cy.get('[data-cy="dashboard-drafts-count"]').should('contain', '1')
// Delete the draft
cy.get('[data-test="record-menu-button"]').click()
cy.get('[data-test="record-menu-delete-button"]').click()
cy.get('[data-cy="confirm-button"]').click()
cy.get('[data-cy="table-row"]')
.contains('New record')
.should('have.length', 0)
cy.get('[data-cy="dashboard-drafts-count"]').should('contain', '0')
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,11 @@
>
<mat-icon class="material-symbols-outlined">edit_note</mat-icon>
<span translate="">dashboard.records.myDraft</span>
<gn-ui-badge [style.--gn-ui-badge-rounded]="'100px'">{{
draftsCount$ | async
}}</gn-ui-badge>
<gn-ui-badge
[style.--gn-ui-badge-rounded]="'100px'"
data-cy="dashboard-drafts-count"
>{{ draftsCount$ | async }}</gn-ui-badge
>
</a>
<a
class="menu-item"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,26 @@
import { NO_ERRORS_SCHEMA } from '@angular/core'
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { ActivatedRoute } from '@angular/router'
import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface'
import { TranslateModule } from '@ngx-translate/core'
import { of } from 'rxjs'
import { cold, hot } from 'jasmine-marbles'
import { MockBuilder, MockProviders } from 'ng-mocks'
import { DashboardMenuComponent } from './dashboard-menu.component'
import { DATASET_RECORDS } from '@geonetwork-ui/common/fixtures'
import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface'

class RecordsRepositoryMock {
getAllDrafts = jest.fn().mockReturnValue(of(DATASET_RECORDS))
}

describe('DashboardMenuComponent', () => {
let component: DashboardMenuComponent
let fixture: ComponentFixture<DashboardMenuComponent>
let recordsRepository: RecordsRepositoryInterface

beforeEach(() => {
return MockBuilder(DashboardMenuComponent)
})

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [DashboardMenuComponent, TranslateModule.forRoot()],
providers: [
{
provide: ActivatedRoute,
useValue: { params: of({ id: 1 }) },
},
{
provide: RecordsRepositoryInterface,
useClass: RecordsRepositoryMock,
},
],
schemas: [NO_ERRORS_SCHEMA],
providers: [MockProviders(ActivatedRoute, RecordsRepositoryInterface)],
}).compileComponents()
recordsRepository = TestBed.inject(RecordsRepositoryInterface)
fixture = TestBed.createComponent(DashboardMenuComponent)
component = fixture.componentInstance
fixture.detectChanges()
Expand All @@ -38,4 +29,20 @@ describe('DashboardMenuComponent', () => {
it('should create', () => {
expect(component).toBeTruthy()
})

it('should emit draftsCount$ immediately and then on drafts change', () => {
// Mock the source observable that draftsCount$ depends on
recordsRepository.draftsChanged$ = hot('-a-|', {
a: void 0,
})
recordsRepository.getAllDrafts = jest
.fn()
.mockReturnValue(hot('ab-|', { a: [], b: [{}] }))

// Define the expected marble diagram
const expected = cold('ab-|', { a: 0, b: 1 })

// Assert that draftsCount$ behaves as expected
expect(component.draftsCount$).toBeObservable(expected)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { MatIconModule } from '@angular/material/icon'
import { RouterModule } from '@angular/router'
import { TranslateModule } from '@ngx-translate/core'
import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface'
import { map } from 'rxjs/operators'
import { map, startWith, switchMap } from 'rxjs/operators'
import { BadgeComponent } from '@geonetwork-ui/ui/inputs'

@Component({
Expand All @@ -22,9 +22,11 @@ import { BadgeComponent } from '@geonetwork-ui/ui/inputs'
],
})
export class DashboardMenuComponent {
draftsCount$ = this.recordsRepository
.getAllDrafts()
.pipe(map((drafts) => drafts.length))
draftsCount$ = this.recordsRepository.draftsChanged$.pipe(
startWith(void 0),
switchMap(() => this.recordsRepository.getAllDrafts()),
map((drafts) => drafts.length)
)

constructor(private recordsRepository: RecordsRepositoryInterface) {}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { MockBuilder } from 'ng-mocks'
import { DashboardPageComponent } from './dashboard-page.component'
import { CommonModule } from '@angular/common'

describe('DashboardPageComponent', () => {
let component: DashboardPageComponent
let fixture: ComponentFixture<DashboardPageComponent>

beforeEach(async () => {
await TestBed.configureTestingModule({})
.overrideComponent(DashboardPageComponent, {
set: {
imports: [CommonModule],
providers: [],
},
})
.compileComponents()
beforeEach(() => {
return MockBuilder(DashboardPageComponent)
})

beforeEach(() => {
fixture = TestBed.createComponent(DashboardPageComponent)
component = fixture.componentInstance
fixture.detectChanges()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
ChangeDetectionStrategy,
CUSTOM_ELEMENTS_SCHEMA,
NO_ERRORS_SCHEMA,
} from '@angular/core'
import { ChangeDetectionStrategy, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
import { ComponentFixture, TestBed } from '@angular/core/testing'

import { SearchHeaderComponent } from './search-header.component'
Expand Down Expand Up @@ -37,7 +33,6 @@ describe('SearchHeaderComponent', () => {
StoreModule.forRoot({}),
TranslateModule.forRoot(TRANSLATE_DEFAULT_CONFIG),
],
schemas: [NO_ERRORS_SCHEMA],
providers: [
{
provide: AvatarServiceInterface,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,66 +1,30 @@
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { of } from 'rxjs'
import { SidebarComponent } from './sidebar.component'
import { ActivatedRoute } from '@angular/router'
import { TranslateModule } from '@ngx-translate/core'
import { DATASET_RECORDS } from '@geonetwork-ui/common/fixtures'
import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface'
import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface'
import { AvatarServiceInterface } from '@geonetwork-ui/api/repository'
import { OrganizationsServiceInterface } from '@geonetwork-ui/common/domain/organizations.service.interface'

class RecordsRepositoryMock {
getAllDrafts = jest.fn().mockReturnValue(of(DATASET_RECORDS))
}

class PlatformServiceMock {
getMe = jest.fn().mockReturnValue(of({ organisation: 'organisation' }))
}

class AvatarServiceInterfaceMock {
getPlaceholder = () => of('http://placeholder.com')
}

class OrganisationsServiceMock {
organisations$ = of([{ name: 'organisation' }])
}
import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface'
import { TranslateModule } from '@ngx-translate/core'
import { MockBuilder, MockProviders } from 'ng-mocks'
import { SidebarComponent } from './sidebar.component'

describe('SidebarComponent', () => {
let component: SidebarComponent
let fixture: ComponentFixture<SidebarComponent>

beforeEach(() => {
return MockBuilder(SidebarComponent)
})

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SidebarComponent, TranslateModule.forRoot()],
providers: [
{
provide: ActivatedRoute,
useValue: { params: of({ id: 1 }) },
},
{
provide: RecordsRepositoryInterface,
useClass: RecordsRepositoryMock,
},
{
provide: PlatformServiceInterface,
useClass: PlatformServiceMock,
},
{
provide: AvatarServiceInterface,
useClass: AvatarServiceInterfaceMock,
},
{
provide: OrganizationsServiceInterface,
useClass: OrganisationsServiceMock,
},
MockProviders(
PlatformServiceInterface,
AvatarServiceInterface,
OrganizationsServiceInterface
),
],
schemas: [NO_ERRORS_SCHEMA],
})
.overrideComponent(SidebarComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default },
})
.compileComponents()
}).compileComponents()

fixture = TestBed.createComponent(SidebarComponent)
component = fixture.componentInstance
Expand Down
2 changes: 0 additions & 2 deletions apps/metadata-editor/src/app/edit/edit-page.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { EditPageComponent } from './edit-page.component'
import { ActivatedRoute, Router } from '@angular/router'
import { NO_ERRORS_SCHEMA } from '@angular/core'
import { DATASET_RECORDS, EDITOR_CONFIG } from '@geonetwork-ui/common/fixtures'
import { BehaviorSubject, Subject } from 'rxjs'
import { NotificationsService } from '@geonetwork-ui/feature/notifications'
Expand Down Expand Up @@ -49,7 +48,6 @@ describe('EditPageComponent', () => {
TranslateModule.forRoot(),
PageSelectorComponent,
],
schemas: [NO_ERRORS_SCHEMA],
providers: [
{
provide: ActivatedRoute,
Expand Down
12 changes: 10 additions & 2 deletions apps/metadata-editor/src/app/new-record.resolver.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { TestBed } from '@angular/core/testing'
import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record'
import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface'
import { MockProvider } from 'ng-mocks'
import { NewRecordResolver } from './new-record.resolver'

describe('NewRecordResolver', () => {
let resolver: NewRecordResolver
let resolvedData: [CatalogRecord, string, boolean]
let recordsRepository: RecordsRepositoryInterface

beforeEach(() => {
TestBed.configureTestingModule({})
TestBed.configureTestingModule({
providers: [MockProvider(RecordsRepositoryInterface)],
})
resolver = TestBed.inject(NewRecordResolver)
recordsRepository = TestBed.inject(RecordsRepositoryInterface)
})

it('should be created', () => {
Expand All @@ -17,8 +23,10 @@ describe('NewRecordResolver', () => {

describe('new record', () => {
beforeEach(() => {
recordsRepository.generateTemporaryId = jest.fn(() => 'TEMP-ID-123')
resolvedData = undefined
resolver.resolve().subscribe((r) => (resolvedData = r))
recordsRepository.generateTemporaryId = jest.fn(() => 'TEMP-ID-123')
})
it('creates a new empty record with a pregenerated id', () => {
expect(resolvedData).toMatchObject([
Expand All @@ -29,7 +37,7 @@ describe('NewRecordResolver', () => {
status: 'ongoing',
temporalExtents: [],
title: expect.stringMatching(/^My new record/),
uniqueIdentifier: expect.stringMatching(/^TEMP-ID-/),
uniqueIdentifier: 'TEMP-ID-123',
},
null,
false,
Expand Down
7 changes: 5 additions & 2 deletions apps/metadata-editor/src/app/new-record.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { Injectable } from '@angular/core'
import { Observable, of } from 'rxjs'
import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record'
import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface'
import { Observable, of } from 'rxjs'

@Injectable({
providedIn: 'root',
})
export class NewRecordResolver {
constructor(private recordsRepository: RecordsRepositoryInterface) {}

resolve(): Observable<[CatalogRecord, string, boolean]> {
return of([
{
uniqueIdentifier: `TEMP-ID-${Date.now()}`,
uniqueIdentifier: this.recordsRepository.generateTemporaryId(),
title: `My new record (${new Date().toISOString()})`,
abstract: '',
ownerOrganization: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ <h1 class="text-[16px] text-main font-title font-bold" translate>
>
<gn-ui-results-table
[records]="records$ | async"
[recordHasDraft]="hasDraft"
[canDuplicate]="canDuplicate"
[canDelete]="canDelete"
(recordClick)="editRecord($event)"
(deleteRecord)="deleteDraft($event)"
></gn-ui-results-table>
</div>
</main>
Loading

0 comments on commit a9a6128

Please sign in to comment.