Skip to content

Commit

Permalink
chore(edit-content): Fix the tests for dot-edit-content-field.compone…
Browse files Browse the repository at this point in the history
…nt.spec #26884 (#27429)

* Refactor on EditContentField tests

* Fix test on Announcements Store

* Fix announcements store test

---------

Co-authored-by: Arcadio Quintero <oidacra@gmail.com>
Co-authored-by: Manuel Rojas <manuel.rojas.21@gmail.com>
  • Loading branch information
3 people committed Jan 26, 2024
1 parent 4fe51fd commit 09ca895
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,9 @@ describe('AnnouncementsStore', () => {
});

it('should not mark announcements as unread when there are no new announcements', (done) => {
localStorage.removeItem('announcementsData');

localStorage.removeItem('dotAnnouncementsData');
spectator.service.loadAnnouncements();
spectator.service.markAnnouncementsAsRead();
spectator.service.load();

spectator.service.state$.subscribe((state) => {
expect(state.showUnreadAnnouncement).toBe(false);
Expand All @@ -67,10 +66,9 @@ describe('AnnouncementsStore', () => {
});

it('should mark announcements as unread', (done) => {
localStorage.removeItem('announcementsData');

spectator.service.load();
localStorage.removeItem('dotAnnouncementsData');

spectator.service.loadAnnouncements();
spectator.service.state$.subscribe((state) => {
expect(state.showUnreadAnnouncement).toBe(true);
done();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,26 @@ export class AnnouncementsStore extends ComponentStore<DotAnnouncementsState> {
});
}

readonly load = this.effect(() => {
return this.http.get<Announcement[]>(this.announcementsUrl).pipe(
pluck('entity'),
tap((announcements: Announcement[]) => {
this.setState({
announcements: modifiedAnnouncements,
showUnreadAnnouncement: this.hasUnreadAnnouncements(announcements),
utmParameters
});
}),
catchError(() => EMPTY)
);
});
readonly loadAnnouncements = () =>
this.effect(() => {
return this.http.get<Announcement[]>(this.announcementsUrl).pipe(
pluck('entity'),
tap((announcements: Announcement[]) => {
const modifiedAnnouncements = announcements.map((announcement) => {
return {
...announcement,
url: `${announcement.url}?utm_source=dotcms&utm_medium=application&utm_campaign=announcement_menu`
};
});

this.setState({
announcements: modifiedAnnouncements,
showUnreadAnnouncement: this.hasUnreadAnnouncements(announcements)
});
}),
catchError(() => EMPTY)
);
});

readonly announcementsSignal: Signal<Announcement[]> = this.selectSignal(
(state) => state.announcements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ import { MockComponent } from 'ng-mocks';
import { of } from 'rxjs';

import { HttpClientTestingModule } from '@angular/common/http/testing';
import { FactoryProvider, Type } from '@angular/core';
import { Provider, Type } from '@angular/core';
import { ControlContainer, FormGroupDirective } from '@angular/forms';
import { By } from '@angular/platform-browser';

import { ConfirmationService } from 'primeng/api';

import { DotBlockEditorComponent } from '@dotcms/block-editor';
import { BlockEditorModule, DotBlockEditorComponent } from '@dotcms/block-editor';
import { DotLicenseService, DotMessageService } from '@dotcms/data-access';

import { DotEditContentFieldComponent } from './dot-edit-content-field.component';
Expand All @@ -29,11 +27,21 @@ import { DotEditContentTextFieldComponent } from '../../fields/dot-edit-content-
import { FIELD_TYPES } from '../../models/dot-edit-content-field.enum';
import { DotEditContentService } from '../../services/dot-edit-content.service';
import {
BINARY_FIELD_CONTENTLET,
createFormGroupDirectiveMock,
FIELDS_MOCK,
FIELDS_WITH_CONTENTLET_MOCK
DOT_MESSAGE_SERVICE_MOCK,
FIELDS_MOCK
} from '../../utils/mocks';

interface DotEditFieldTestBed {
component: Type<unknown>;
imports?: Type<unknown>[];
providers?: Provider[];
declarations?: Type<unknown>[];
props?: { [key: string]: unknown }[]; // ContentField Props, that we need to pass to the component inside
outsideFormControl?: boolean; //If the component have [formControlName] hardcoded inside this ContentField component
}

/* We need this declare to dont have import errors from CommandType of Tiptap */
declare module '@tiptap/core' {
interface Commands {
Expand All @@ -44,22 +52,9 @@ declare module '@tiptap/core' {
}
}

const dotMessageServiceMock = {
init: jest.fn().mockImplementation(() => {
// mocking init
}),
get: jest.fn().mockImplementation(() => {
// mocking get
})
};

// This holds the mapping between the field type and the component that should be used to render it.
// We need to hold this record here, because for some reason the references just fall to undefined.
const FIELD_TYPES_COMPONENTS: Record<
FIELD_TYPES,
| Type<unknown>
| { component: Type<unknown>; providers?: FactoryProvider[]; declarations?: Type<unknown>[] }
> = {
const FIELD_TYPES_COMPONENTS: Record<FIELD_TYPES, Type<unknown> | DotEditFieldTestBed> = {
// We had to use unknown because components have different types.
[FIELD_TYPES.TEXT]: DotEditContentTextFieldComponent,
[FIELD_TYPES.TEXTAREA]: DotEditContentTextAreaComponent,
Expand All @@ -70,16 +65,49 @@ const FIELD_TYPES_COMPONENTS: Record<
[FIELD_TYPES.TIME]: DotEditContentCalendarFieldComponent,
[FIELD_TYPES.TAG]: {
component: DotEditContentTagFieldComponent,
providers: [mockProvider(DotEditContentService)]
providers: [{ provide: DotEditContentService, useValue: { getTags: () => of([]) } }]
},
[FIELD_TYPES.CHECKBOX]: DotEditContentCheckboxFieldComponent,
[FIELD_TYPES.MULTI_SELECT]: DotEditContentMultiSelectFieldComponent,
[FIELD_TYPES.BLOCK_EDITOR]: DotBlockEditorComponent,
[FIELD_TYPES.BLOCK_EDITOR]: {
component: DotBlockEditorComponent,
declarations: [MockComponent(DotBlockEditorComponent)],
imports: [BlockEditorModule],
outsideFormControl: true
},
[FIELD_TYPES.CUSTOM_FIELD]: {
component: DotEditContentCustomFieldComponent,
providers: [mockProvider(DotEditContentService)]
providers: [
mockProvider(DotEditContentService),
{
provide: DotLicenseService,
useValue: {
isEnterprise: () => of(true)
}
}
]
},
[FIELD_TYPES.BINARY]: {
component: DotEditContentBinaryFieldComponent,
providers: [
{
provide: DotLicenseService,
useValue: {
isEnterprise: () => of(true)
}
},
{
provide: DotMessageService,
useValue: DOT_MESSAGE_SERVICE_MOCK
}
],
props: [
{
contentlet: BINARY_FIELD_CONTENTLET
}
],
outsideFormControl: true
},
[FIELD_TYPES.BINARY]: DotEditContentBinaryFieldComponent,
[FIELD_TYPES.JSON]: {
component: DotEditContentJsonFieldComponent,
declarations: [MockComponent(DotEditContentJsonFieldComponent)]
Expand All @@ -99,8 +127,9 @@ describe('FIELD_TYPES and FIELDS_MOCK', () => {
describe.each([...FIELDS_MOCK])('DotEditContentFieldComponent all fields', (fieldMock) => {
const fieldTestBed = FIELD_TYPES_COMPONENTS[fieldMock.fieldType];
let spectator: Spectator<DotEditContentFieldComponent>;

const createComponent = createComponentFactory({
imports: [HttpClientTestingModule],
imports: [HttpClientTestingModule, ...(fieldTestBed?.imports || [])],
declarations: [...(fieldTestBed?.declarations || [])],
component: DotEditContentFieldComponent,
componentViewProviders: [
Expand All @@ -109,27 +138,16 @@ describe.each([...FIELDS_MOCK])('DotEditContentFieldComponent all fields', (fiel
useValue: createFormGroupDirectiveMock()
}
],
providers: [FormGroupDirective, DotEditContentService, ...(fieldTestBed?.providers || [])]
providers: [FormGroupDirective]
});

beforeEach(async () => {
spectator = createComponent({
props: {
field: fieldMock
field: fieldMock,
...(fieldTestBed?.props || {})
},
providers: [
{
provide: DotLicenseService,
useValue: {
isEnterprise: () => of(true)
}
},
{
provide: DotMessageService,
useValue: dotMessageServiceMock
},
mockProvider(ConfirmationService)
]
providers: [...(fieldTestBed?.providers || [])]
});
});

Expand All @@ -154,40 +172,29 @@ describe.each([...FIELDS_MOCK])('DotEditContentFieldComponent all fields', (fiel
const FIELD_TYPE = fieldTestBed.component ? fieldTestBed.component : fieldTestBed;
expect(field.componentInstance instanceof FIELD_TYPE).toBeTruthy();
});
});
});

describe.each([...FIELDS_WITH_CONTENTLET_MOCK])(
'DotEditContentFieldComponent all fields with contentlets',
({ fieldMock, contentlet }) => {
let spectator: Spectator<DotEditContentFieldComponent>;
const createComponent = createComponentFactory({
component: DotEditContentFieldComponent,
imports: [HttpClientTestingModule],
componentViewProviders: [
{
provide: ControlContainer,
useValue: createFormGroupDirectiveMock()
}
],
providers: [mockProvider(DotLicenseService), FormGroupDirective]
});
beforeEach(async () => {
spectator = createComponent({
props: {
field: fieldMock,
contentlet
}
});
});
describe(`${fieldMock.fieldType} - ${fieldMock.dataType}`, () => {
it('should have contentlet', () => {
if (fieldTestBed.outsideFormControl) {
it('should have a formControlName', () => {
spectator.detectChanges();
const field = spectator.debugElement.query(
By.css(`[data-testId="field-${fieldMock.variable}"]`)
);
expect(field.componentInstance.contentlet).toEqual(contentlet);
expect(field.attributes['ng-reflect-name']).toBe(fieldMock.variable);
});
});
}
);
}

if (fieldTestBed.props) {
describe('With props', () => {
fieldTestBed.props.forEach((prop) => {
it(`should have ${prop.key} property`, () => {
spectator.detectChanges();
const field = spectator.debugElement.query(
By.css(`[data-testId="field-${fieldMock.variable}"]`)
);
expect(field.componentInstance[prop.key]).toEqual(prop.valueExpected);
});
});
});
}
});
});
13 changes: 3 additions & 10 deletions core-web/libs/edit-content/src/lib/utils/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
DotCMSContentTypeField,
DotCMSContentTypeLayoutRow
} from '@dotcms/dotcms-models';
import { MockDotMessageService } from '@dotcms/utils-testing';

import { FIELD_TYPES } from '../models/dot-edit-content-field.enum';
import { EditContentPayload } from '../models/dot-edit-content-form.interface';
Expand Down Expand Up @@ -587,16 +588,6 @@ export const BINARY_FIELD_CONTENTLET: DotCMSContentlet = {
value: '/dA/39de8193694d96c2a6bab783ba9c85b5/binaryField/Screenshot 2023-11-03 at 11.53.40â\u0080¯AM.png'
};

export const FIELDS_WITH_CONTENTLET_MOCK: {
fieldMock: DotCMSContentTypeField;
contentlet: DotCMSContentlet;
}[] = [
{
fieldMock: BINARY_FIELD_MOCK,
contentlet: BINARY_FIELD_CONTENTLET
}
];

/* HELPER FUNCTIONS */

// This creates a mock FormGroup from an array of fielda
Expand Down Expand Up @@ -635,6 +626,8 @@ function getAllFields(data: DotCMSContentTypeLayoutRow[]) {

/* CONSTANTS */

export const DOT_MESSAGE_SERVICE_MOCK = new MockDotMessageService({});

export const CALENDAR_FIELD_TYPES = [FIELD_TYPES.DATE, FIELD_TYPES.DATE_AND_TIME, FIELD_TYPES.TIME];

/* LAYOUT/FORM MOCKS */
Expand Down

0 comments on commit 09ca895

Please sign in to comment.