Skip to content

Commit

Permalink
Merge branch 'develop' into templates-e2e-test
Browse files Browse the repository at this point in the history
  • Loading branch information
dzonidoo committed May 14, 2024
2 parents b25d7ea + 9ae1cec commit ee64695
Show file tree
Hide file tree
Showing 38 changed files with 3,533 additions and 299 deletions.
62 changes: 62 additions & 0 deletions e2e/client/playwright/authoring.correct.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {test, expect} from '@playwright/test';
import {Monitoring} from './page-object-models/monitoring';
import {restoreDatabaseSnapshot, s} from './utils';

test.setTimeout(50000);

/**
* publish an item
* correct it - change headline, body
* send correction, open the item again and see if changes persist
*
* test added after discovering a bug SDESK-7248
*/
test('correcting with unsaved changes', async ({page}) => {
const getHeadlineField = async () => await page.locator(s('authoring', 'field--headline')).getByRole('textbox');
const getBodyField = async () =>
await page.locator(s('authoring', 'authoring-field=body_html')).getByRole('textbox');

await restoreDatabaseSnapshot();

const monitoring = new Monitoring(page);

await page.goto('/#/workspace/monitoring');

await monitoring.selectDeskOrWorkspace('Sports');

// publishing the article start

await page.locator(
s('monitoring-group=Sports / Working Stage', 'article-item=test sports story'),
).dblclick();

await page.locator(s('authoring', 'open-send-publish-pane')).click();
await page.locator(s('authoring', 'publish')).click();

// publishing the article end

// TODO: should be 'monitoring-group=Sports / output'
await page.locator(
s('monitoring-group=Sports', 'article-item=test sports story'),
).dblclick({timeout: 10000}); // need to wait until published item appears in output

await page.locator(s('authoring', 'authoring-topbar')).getByLabel('Correct').click();

await (await getHeadlineField()).clear();
await (await getHeadlineField()).fill('test sports story [corrected]');

await (await getBodyField()).clear();
await (await getBodyField()).fill('test sport story body [corrected]');

await page.locator(s('authoring', 'authoring-topbar')).getByRole('button', {name: 'Send Correction'}).click();

await page.locator(
s('monitoring-group=Sports', 'article-item=test sports story [corrected]'),
).dblclick({timeout: 10000}); // need to wait until published item appears in output

// initialize correction only to make field editable and accessible using the same selector
await page.locator(s('authoring', 'authoring-topbar')).getByLabel('Correct').click();

await expect((await getHeadlineField())).toHaveText('test sports story [corrected]');
await expect((await getBodyField())).toHaveText('test sport story body [corrected]');
});
28 changes: 28 additions & 0 deletions e2e/client/playwright/publish-queue.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {test, expect} from '@playwright/test';
import {Monitoring} from './page-object-models/monitoring';
import {restoreDatabaseSnapshot, s} from './utils';

test.setTimeout(50000);

test.skip('item appearing in publish queue after publishing', async ({page}) => {
const monitoring = new Monitoring(page);

await restoreDatabaseSnapshot();
await page.goto('/#/workspace/monitoring');

await monitoring.executeActionOnMonitoringItem(
page.locator(s('article-item=test sports story')),
'Edit',
);

await page.locator(s('authoring', 'open-send-publish-pane')).click();
await page.locator(s('authoring', 'interactive-actions-panel', 'publish')).click();

await expect(page.locator(
s('monitoring-group=Sports', 'article-item=test sports story'),
)).toBeAttached({timeout: 10000});

await page.goto('/#/publish_queue');

await expect(page.locator(s('publish-queue-item=test sports story'))).toBeAttached({timeout: 10000});
});
Binary file not shown.
Binary file not shown.
9 changes: 9 additions & 0 deletions scripts/api/article.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,13 @@ function createNewUsingDeskTemplate(): void {
});
}

function createNewWithData(data: Partial<IArticle>, contentProfileId: string): void {
dataApi.create('archive', {type: 'text', ...data, profile: contentProfileId})
.then((item) => {
openArticle(item._id, 'edit');
});
}

/**
* Checks if associations is with rewrite_of item then open then modal to add associations.
* The user has options to add associated media to the current item and review the media change
Expand Down Expand Up @@ -556,6 +563,7 @@ interface IArticleApi {
unlock(itemId: IArticle['_id']): Promise<IArticle>;

createNewUsingDeskTemplate(): void;
createNewWithData(data: Partial<IArticle>, contentProfileId: string): void;
getWorkQueueItems(): Array<IArticle>;
rewrite(item: IArticle): void;
canPublishOnDesk(deskType: string): boolean;
Expand Down Expand Up @@ -618,6 +626,7 @@ export const article: IArticleApi = {
lock,
unlock,
createNewUsingDeskTemplate,
createNewWithData,
getWorkQueueItems,
get,
canPublishOnDesk,
Expand Down
12 changes: 6 additions & 6 deletions scripts/apps/authoring-react/authoring-integration-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ interface IPropsWrapper extends IProps {
interface IState {
sidebarMode: boolean | 'hidden';
sideWidget: null | {
name: string;
id: string;
pinned: boolean;
};
}
Expand Down Expand Up @@ -313,19 +313,19 @@ export class AuthoringIntegrationWrapper extends React.PureComponent<IPropsWrapp
icon: widget.icon,
size: 'big',
tooltip: widget.label,
id: widget.label,
id: widget._id,
};

return tab;
});

return (
<Nav.SideBarTabs
activeTab={this.state.sideWidget?.name}
activeTab={this.state.sideWidget?.id}
onActiveTabChange={(val) => {
this.setState({
sideWidget: {
name: val,
id: val,
pinned: this.state.sideWidget?.pinned ?? false,
},
});
Expand Down Expand Up @@ -483,8 +483,8 @@ export class AuthoringIntegrationWrapper extends React.PureComponent<IPropsWrapp
getSidebar={this.state.sidebarMode !== true ? null : getSidebar}
secondaryToolbarWidgets={secondaryToolbarWidgetsReady}
validateBeforeSaving={false}
getSideWidgetNameAtIndex={(article, index) => {
return getWidgetsFromExtensions(article)[index].label;
getSideWidgetIdAtIndex={(article, index) => {
return getWidgetsFromExtensions(article)[index]._id;
}}
/>
);
Expand Down
16 changes: 8 additions & 8 deletions scripts/apps/authoring-react/authoring-react.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -335,14 +335,14 @@ export class AuthoringReact<T extends IBaseRestApiResponse> extends React.PureCo
};

widgetReactIntegration.getActiveWidget = () => {
return this.props.sideWidget?.name ?? null;
return this.props.sideWidget?.id ?? null;
};

widgetReactIntegration.getPinnedWidget = () => {
const pinned = this.props.sideWidget?.pinned === true;

if (pinned) {
return this.props.sideWidget.name;
return this.props.sideWidget.id;
} else {
return null;
}
Expand Down Expand Up @@ -1113,13 +1113,13 @@ export class AuthoringReact<T extends IBaseRestApiResponse> extends React.PureCo
authoringStorage: authoringStorage,
storageAdapter: storageAdapter,
fieldsAdapter: fieldsAdapter,
sideWidget: this.props.sideWidget?.name ?? null,
toggleSideWidget: (name) => {
if (name == null || this.props.sideWidget?.name === name) {
sideWidget: this.props.sideWidget?.id ?? null,
toggleSideWidget: (id) => {
if (id == null || this.props.sideWidget?.id === id) {
this.props.onSideWidgetChange(null);
} else {
this.props.onSideWidgetChange({
name: name,
id: id,
pinned: false,
});
}
Expand Down Expand Up @@ -1229,10 +1229,10 @@ export class AuthoringReact<T extends IBaseRestApiResponse> extends React.PureCo

for (let i = 0; i < widgetsCount; i++) {
widgetKeybindings[`ctrl+alt+${i + 1}`] = () => {
const nextWidgetName: string = this.props.getSideWidgetNameAtIndex(exposed.item, i);
const nextWidgetName: string = this.props.getSideWidgetIdAtIndex(exposed.item, i);

this.props.onSideWidgetChange({
name: nextWidgetName,
id: nextWidgetName,
pinned: this.props.sideWidget?.pinned ?? false,
});
};
Expand Down
75 changes: 49 additions & 26 deletions scripts/apps/authoring/authoring/directives/AuthoringDirective.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,11 @@ export function AuthoringDirective(
* Create a new version
*/
$scope.save = function() {
return authoring.save($scope.origItem, $scope.item).then((res) => {
return authoring.save(
$scope.origItem,
$scope.item,
$scope.requestEditor3DirectivesToGenerateHtml,
).then((res) => {
$scope.dirty = false;
_.merge($scope.item, res);

Expand Down Expand Up @@ -542,36 +546,54 @@ export function AuthoringDirective(
* in $scope.
*/
$scope.publish = function() {
if (helpers.itemHasUnresolvedSuggestions($scope.item)) {
modal.alert({
headerText: gettext('Resolving suggestions'),
bodyText: gettext(
'Article cannot be published. Please accept or reject all suggestions first.',
),
$scope.$applyAsync(() => {
$scope.loading = true;
});

return $q((resolve) => {
// delay required for loading state to render
// before possibly long operation (with huge articles)
setTimeout(() => {
for (const fn of $scope.requestEditor3DirectivesToGenerateHtml) {
fn();
}

resolve();
});
}).then(() => {
if (helpers.itemHasUnresolvedSuggestions($scope.item)) {
modal.alert({
headerText: gettext('Resolving suggestions'),
bodyText: gettext(
'Article cannot be published. Please accept or reject all suggestions first.',
),
});

return Promise.reject();
}
return $q.reject();
}

if (helpers.itemHasUnresolvedComments($scope.item)) {
modal.confirm({
bodyText: gettext(
'This article contains unresolved comments.'
+ 'Click on Cancel to go back to editing to'
+ 'resolve those comments or OK to ignore and proceed with publishing',
),
headerText: gettext('Resolving comments'),
okText: gettext('Ok'),
cancelText: gettext('Cancel'),
}).then((ok) => ok ? performPublish() : false);

return Promise.reject();
}
if (helpers.itemHasUnresolvedComments($scope.item)) {
modal.confirm({
bodyText: gettext(
'This article contains unresolved comments.'
+ 'Click on Cancel to go back to editing to'
+ 'resolve those comments or OK to ignore and proceed with publishing',
),
headerText: gettext('Resolving comments'),
okText: gettext('Ok'),
cancelText: gettext('Cancel'),
}).then((ok) => ok ? performPublish() : false);

return $q.reject();
}

return performPublish();
return performPublish();
}).finally(() => {
$scope.loading = false;
});
};

function performPublish() {
function performPublish(): Promise<any> {
if (validatePublishScheduleAndEmbargo($scope.item) && validateForPublish($scope.item)) {
var message = 'publish';

Expand All @@ -597,7 +619,7 @@ export function AuthoringDirective(
return publishItem($scope.origItem, $scope.item);
}

return false;
return $q.reject(false);
}

$scope.showCustomButtons = () => {
Expand Down Expand Up @@ -1006,6 +1028,7 @@ export function AuthoringDirective(
angular.extend($scope.item, event.detail);
angular.extend($scope.origItem, event.detail);
$scope.$apply();
$scope.refresh();
}
},
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ import {IArticleActionInteractive} from 'core/interactive-article-actions-panel/
*
* @description Generates authoring subnav bar
*/
AuthoringTopbarDirective.$inject = ['TranslationService', 'privileges', 'authoringWorkspace'];
AuthoringTopbarDirective.$inject = ['TranslationService', 'privileges', 'authoringWorkspace', '$q'];
export function AuthoringTopbarDirective(
TranslationService,
privileges,
authoringWorkspace: AuthoringWorkspaceService,
$q,
) {
return {
templateUrl: 'scripts/apps/authoring/views/authoring-topbar.html',
Expand Down Expand Up @@ -83,24 +84,25 @@ export function AuthoringTopbarDirective(
* @return {promise}
*/
scope.saveTopbar = function() {
scope.saveTopbarLoading = true;
scope.$applyAsync(() => {
scope.saveTopbarLoading = true;
});

// when very big articles being are saved(~14k words),
// the browser can't animate the loading spinner properly
// the delay is chosen so the spinner freezes in a visible state.
const timeoutDuration = 500;

setTimeout(() => {
for (const fn of scope.requestEditor3DirectivesToGenerateHtml) {
fn();
}

return scope.save(scope.item)
.finally(() => {
scope.saveTopbarLoading = false;
scope.$applyAsync();
});
}, timeoutDuration);
const timeoutDuration = 600;

return $q((resolve) => {
setTimeout(() => {
resolve();
}, timeoutDuration);
})
.then(() => scope.save(scope.item))
.finally(() => {
scope.saveTopbarLoading = false;
scope.$applyAsync();
});
};

// Activate preview formatted item
Expand Down
10 changes: 9 additions & 1 deletion scripts/apps/authoring/authoring/services/AuthoringService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,15 @@ export function AuthoringService(
* @param {Object} origItem
* @param {Object} item
*/
this.save = function saveAuthoring(origItem: IArticle, _item: IArticle) {
this.save = function saveAuthoring(
origItem: IArticle,
_item: IArticle,
requestEditor3DirectivesToGenerateHtml?: Array<()=> void>,
) {
for (const fn of (requestEditor3DirectivesToGenerateHtml ?? [])) {
fn();
}

return authoringApiCommon.saveBefore(_item, origItem).then((item: IArticle) => {
angular.extend(_item, item);

Expand Down
Loading

0 comments on commit ee64695

Please sign in to comment.