Skip to content

Commit

Permalink
Merge branch 'master' into issue-29165-npe-on-chained-vanity-urls
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinogiardino authored Aug 23, 2024
2 parents fc208ff + ba4ecf5 commit 01ede6c
Show file tree
Hide file tree
Showing 24 changed files with 2,609 additions and 1,419 deletions.
2 changes: 1 addition & 1 deletion .sdkmanrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
java=11.0.23-ms
java=21.0.4-ms
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ describe('DotNavigationComponent', () => {
});

it('should have scroll', () => {
expect(fixture.debugElement.styles.cssText).toEqual('overflow-y: scroll;');
expect(fixture.debugElement.styles.cssText).toEqual('overflow-y: auto;');
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class DotNavigationComponent implements OnInit {
menu$: Observable<DotMenu[]>;

@HostBinding('style.overflow-y') get overFlow() {
return this.dotNavigationService.collapsed$.getValue() ? '' : 'scroll';
return this.dotNavigationService.collapsed$.getValue() ? '' : 'auto';
}

constructor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,8 @@ describe('DotEmaShellComponent', () => {
{
icon: 'pi-ellipsis-v',
label: 'editema.editor.navbar.properties',
id: 'properties'
id: 'properties',
isDisabled: false
}
]);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect, describe } from '@jest/globals';
import { SpyObject } from '@ngneat/spectator';
import { Spectator, createComponentFactory, mockProvider } from '@ngneat/spectator/jest';
import { MockModule } from 'ng-mocks';
import { MockModule, MockProvider } from 'ng-mocks';
import { of } from 'rxjs';

import { HttpClientTestingModule } from '@angular/common/http/testing';
Expand Down Expand Up @@ -33,17 +33,44 @@ import { EditEmaLayoutComponent } from './edit-ema-layout.component';

import { DotActionUrlService } from '../services/dot-action-url/dot-action-url.service';
import { DotPageApiService } from '../services/dot-page-api.service';
import { UVE_STATUS } from '../shared/enums';
import { UVEStore } from '../store/dot-uve.store';

const PAGE_RESPONSE = {
containers: {},
page: {
identifier: 'test'
},
template: {
theme: 'testTheme'
},
layout: {
body: {
rows: [
{
columns: [
{
containers: [
{
identifier: 'test'
}
]
}
]
}
]
}
}
};

describe('EditEmaLayoutComponent', () => {
let spectator: Spectator<EditEmaLayoutComponent>;
let component: EditEmaLayoutComponent;
let dotRouter: SpyObject<DotRouterService>;
let store: SpyObject<InstanceType<typeof UVEStore>>;
let templateBuilder: TemplateBuilderComponent;
let layoutService: DotPageLayoutService;
let dotPageLayoutService: DotPageLayoutService;
let messageService: MessageService;
let addMock: jest.SpyInstance;

globalThis.structuredClone = jest.fn().mockImplementation((obj) => obj);

Expand All @@ -52,96 +79,54 @@ describe('EditEmaLayoutComponent', () => {
imports: [HttpClientTestingModule, MockModule(TemplateBuilderModule)],
providers: [
UVEStore,
MessageService,
DotMessageService,
DotActionUrlService,
mockProvider(MessageService),
mockProvider(Router),
mockProvider(ActivatedRoute),
{
provide: DotExperimentsService,
useValue: DotExperimentsServiceMock
},
{ provide: DotRouterService, useValue: new MockDotRouterJestService(jest) },
{
provide: DotLicenseService,
useValue: {
isEnterprise: () => of(true)
}
},
{
provide: DotPageApiService,
useValue: {
get: () => {
return of({
containers: {},
page: {
identifier: 'test'
},
template: {
theme: 'testTheme'
},
layout: {
body: {
rows: [
{
columns: [
{
containers: [
{
identifier: 'test'
}
]
}
]
}
]
}
}
});
}
}
},
{
provide: DotPageLayoutService,
useValue: {
save: () => {
return of({
layout: {}
});
}
}
},
mockProvider(DotContentTypeService),
mockProvider(CoreWebService),
{
provide: DotLanguagesService,
useValue: new DotLanguagesServiceMock()
},
{
provide: DotContentletLockerService,
useValue: {
mockProvider(DotPageLayoutService, {
save: jest.fn(() => of(PAGE_RESPONSE))
}),
mockProvider(DotPageApiService, {
get: jest.fn(() => of(PAGE_RESPONSE))
}),
MockProvider(DotExperimentsService, DotExperimentsServiceMock, 'useValue'),
MockProvider(DotRouterService, new MockDotRouterJestService(jest), 'useValue'),
MockProvider(DotLanguagesService, new DotLanguagesServiceMock(), 'useValue'),
MockProvider(
DotLicenseService,
{
isEnterprise: () => of(true)
},
'useValue'
),
MockProvider(
DotContentletLockerService,
{
unlock: (_inode: string) => of({})
}
},
{
provide: LoginService,
useValue: {
},
'useValue'
),
MockProvider(
LoginService,
{
getCurrentUser: () => of({})
}
}
},
'useValue'
)
]
});

beforeEach(async () => {
spectator = createComponent();
component = spectator.component;
dotRouter = spectator.inject(DotRouterService);
store = spectator.inject(UVEStore);
layoutService = spectator.inject(DotPageLayoutService);
store = spectator.inject(UVEStore, true);
dotPageLayoutService = spectator.inject(DotPageLayoutService);
messageService = spectator.inject(MessageService);

addMock = jest.spyOn(messageService, 'add');

store.load({
clientHost: 'http://localhost:3000',
language_id: '1',
Expand All @@ -158,42 +143,40 @@ describe('EditEmaLayoutComponent', () => {

describe('Template Change', () => {
it('should forbid navigation', () => {
const spy = jest.spyOn(dotRouter, 'forbidRouteDeactivation');

templateBuilder.templateChange.emit();

expect(spy).toHaveBeenCalled();
expect(dotRouter.forbidRouteDeactivation).toHaveBeenCalled();
});

it('should trigger a save after 5 secs', fakeAsync(() => {
const layoutServiceSave = jest.spyOn(layoutService, 'save');
const updatePageResponseSpy = jest.spyOn(store, 'updatePageResponse');
const setUveStatusSpy = jest.spyOn(store, 'setUveStatus');

templateBuilder.templateChange.emit();
tick(5000);

expect(layoutServiceSave).toHaveBeenCalled();
expect(dotPageLayoutService.save).toHaveBeenCalled();
expect(updatePageResponseSpy).toHaveBeenCalledWith(PAGE_RESPONSE);
expect(setUveStatusSpy).toHaveBeenCalledWith(UVE_STATUS.LOADING);

expect(addMock).toHaveBeenNthCalledWith(1, {
expect(messageService.add).toHaveBeenNthCalledWith(1, {
severity: 'info',
summary: 'Info',
detail: 'dot.common.message.saving',
life: 1000
});

expect(addMock).toHaveBeenNthCalledWith(2, {
expect(messageService.add).toHaveBeenNthCalledWith(2, {
severity: 'success',
summary: 'Success',
detail: 'dot.common.message.saved'
});
}));

it('should unlock navigation after saving', fakeAsync(() => {
const allowRouting = jest.spyOn(dotRouter, 'allowRouteDeactivation');

templateBuilder.templateChange.emit();
tick(6000);

expect(allowRouting).toHaveBeenCalled();
expect(dotRouter.allowRouteDeactivation).toHaveBeenCalled();
}));

it('should save right away if we request page leave before the 5 secs', () => {
Expand All @@ -205,14 +188,14 @@ describe('EditEmaLayoutComponent', () => {

expect(saveTemplate).toHaveBeenCalled();

expect(addMock).toHaveBeenNthCalledWith(1, {
expect(messageService.add).toHaveBeenNthCalledWith(1, {
severity: 'info',
summary: 'Info',
detail: 'dot.common.message.saving',
life: 1000
});

expect(addMock).toHaveBeenNthCalledWith(2, {
expect(messageService.add).toHaveBeenNthCalledWith(2, {
severity: 'success',
summary: 'Success',
detail: 'dot.common.message.saved'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ import {
finalize,
switchMap,
take,
takeUntil
takeUntil,
tap
} from 'rxjs/operators';

import { DotMessageService, DotPageLayoutService, DotRouterService } from '@dotcms/data-access';
import { DotPageRender, DotTemplateDesigner } from '@dotcms/dotcms-models';
import { TemplateBuilderModule } from '@dotcms/template-builder';

import { DotPageApiResponse } from '../services/dot-page-api.service';
import { UVE_STATUS } from '../shared/enums';
import { UVEStore } from '../store/dot-uve.store';

export const DEBOUNCE_TIME = 5000;
Expand Down Expand Up @@ -110,6 +113,7 @@ export class EditEmaLayoutComponent implements OnInit, OnDestroy {
.pipe(
// debounceTime should be before takeUntil to avoid calling the observable after unsubscribe.
// More information: https://stackoverflow.com/questions/58974320/how-is-it-possible-to-stop-a-debounced-rxjs-observable
tap(() => this.uveStore.setUveStatus(UVE_STATUS.LOADING)), // Prevent the user to access page properties
debounceTime(DEBOUNCE_TIME),
takeUntil(this.destroy$),
switchMap((layout: DotTemplateDesigner) => {
Expand Down Expand Up @@ -138,17 +142,17 @@ export class EditEmaLayoutComponent implements OnInit, OnDestroy {
* Handle the success save template
*
* @private
* @param {DotPageRender} _
* @template T
* @param {T=unkonwm} page // To avoid getting type error with DotPageRender and DotPageApiResponse
* @memberof EditEmaLayoutComponent
*/
private handleSuccessSaveTemplate(page: DotPageRender): void {
private handleSuccessSaveTemplate<T = unknown>(page: T): void {
this.messageService.add({
severity: 'success',
summary: 'Success',
detail: this.dotMessageService.get('dot.common.message.saved')
});

this.uveStore.updateLayout(page.layout);
this.uveStore.updatePageResponse(page as DotPageApiResponse);
}

/**
Expand All @@ -164,6 +168,8 @@ export class EditEmaLayoutComponent implements OnInit, OnDestroy {
summary: 'Error',
detail: this.dotMessageService.get('dot.common.http.error.400.message')
});

this.uveStore.setUveStatus(UVE_STATUS.ERROR);
}

/**
Expand Down
Loading

0 comments on commit 01ede6c

Please sign in to comment.