Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(edit-content): Fix the tests for dot-edit-content-field.component.spec #26884 #27429

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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');

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

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');
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 @@ -41,25 +41,26 @@ export class AnnouncementsStore extends ComponentStore<DotAnnouncementsState> {
});
}

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 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
Loading