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 Jun 3, 2024
2 parents 72d1929 + 2ec11fa commit 99dc281
Show file tree
Hide file tree
Showing 75 changed files with 1,779 additions and 896 deletions.
4 changes: 2 additions & 2 deletions .fireq.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"superdesk_branch": "release/2.5"
}
"superdesk_branch": "develop"
}
7 changes: 7 additions & 0 deletions e2e/README-PROTRACTOR.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@
webdriver-manager only supports chrome <114 - https://github.com/angular/protractor/issues/5563

To use newer chrome versions, set `CHROME_BIN` and `CHROMEWEBDRIVER`(should point to folder where `chromedriver` file is located) environment variables. Use [Chrome for testing](https://developer.chrome.com/blog/chrome-for-testing) project to download desired chrome version and driver.

# MacOS Setup
`.app` is not an executable so path to chrome test browser should be pointing to the executable inside that folder

Example setup with chrome test browser executable path:

export CHROME_BIN="/Downloads/chrome-mac-arm64/Google_Chrome_for_Testing.app/Contents/MacOS/Google_Chrome_for_Testing"
2 changes: 2 additions & 0 deletions e2e/client/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export default defineConfig({

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',

screenshot: 'only-on-failure',
},

/* Configure projects for major browsers */
Expand Down
92 changes: 90 additions & 2 deletions e2e/client/playwright/editor3.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import {test, expect} from '@playwright/test';
import {Monitoring} from './page-object-models/monitoring';
import {test, expect} from '@playwright/test';
import {restoreDatabaseSnapshot, s} from './utils';
import {getEditor3Paragraphs} from './utils/editor3';
import {getEditor3FormattingOptions, getEditor3Paragraphs} from './utils/editor3';
import {TreeSelectDriver} from './utils/tree-select-driver';

test('accepting a spelling suggestion', async ({page}) => {
const monitoring = new Monitoring(page);

await restoreDatabaseSnapshot({snapshotName: 'spellchecker'});

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

await monitoring.selectDeskOrWorkspace('Sports');

await page.locator(
s('monitoring-group=Sports / Working Stage', 'article-item=spellchecker test'),
).dblclick();
Expand All @@ -32,10 +37,14 @@ test('accepting a spelling suggestion', async ({page}) => {
});

test('adding word marked as a spellchecker issue to dictionary', async ({page}) => {
const monitoring = new Monitoring(page);

await restoreDatabaseSnapshot({snapshotName: 'spellchecker'});

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

await monitoring.selectDeskOrWorkspace('Sports');

await page.locator(
s('monitoring-group=Sports / Working Stage', 'article-item=spellchecker test'),
).dblclick();
Expand Down Expand Up @@ -206,3 +215,82 @@ test('tables maintaining cursor position when executing "redo" action', async ({
page.locator(s('authoring', 'authoring-field=body_html', 'table-block')).locator('[contenteditable]').first(),
).toHaveText('fobaro');
});

test('configuring a vocabulary for custom blocks', async ({page}) => {
await restoreDatabaseSnapshot();

await page.goto('/#/settings/vocabularies');

await page.locator(s('metadata-navigation')).getByRole('button', {name: 'Custom blocks'}).click();

await page.getByRole('button', {name: 'Add New'}).click();

// Input sample data
await page.locator(s('vocabulary-edit-content')).getByLabel('Id').fill('custom_blocks_2');

await page.locator(s('vocabulary-edit-content')).getByLabel('Name').fill('Custom blocks 2');

await new TreeSelectDriver(
page,
page.locator(s('vocabulary-edit-content', 'formatting-options')),
).setValue(['h1']);

await page.locator(s('vocabulary-edit-content', 'editor3')).getByRole('textbox').fill('test data');


// Apply formatting option to sample text data
await page.locator(s('editor3')).getByText('test data').click();
await page.locator(s('editor3', 'formatting-option=h1')).click();

// Save editor block
await page.locator(s('vocabulary-edit-footer')).getByRole('button', {name: 'Save'}).click();

await expect(page.locator(s('vocabulary-edit-content'))).not.toBeVisible(); // wait for saving to finish

// Edit custom block
await page.locator(s('vocabulary-item=Custom blocks 2')).hover();
await page.locator(s('vocabulary-item=Custom blocks 2', 'vocabulary-item--start-editing')).click();

// Check if formatting option, sample text data
await expect(page.locator(s('editor3', 'formatting-option=h1'))).toBeVisible();
await expect(page.locator(s('editor3')).getByRole('textbox')).toHaveText('test data');
});

test('adding a custom block inside editor3', async ({page}) => {
const monitoring = new Monitoring(page);

await restoreDatabaseSnapshot({snapshotName: 'custom-blocks'});

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

await monitoring.selectDeskOrWorkspace('Sports');

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

await page.locator(s('authoring', 'authoring-field=body_html')).getByRole('textbox').click();

await page.locator(
s('authoring', 'authoring-field=body_html', 'toolbar'),
).getByRole('button', {name: 'Custom block'}).click();

await page.locator(s('tree-menu-popover'))
.getByRole('button', {name: 'Custom Block 1'})
.click();

await expect(
page.locator(s('authoring', 'authoring-field=body_html', 'custom-block')).getByRole('textbox').first(),
).toHaveText('custom block 1 template content');

await page.locator(
s('authoring', 'authoring-field=body_html', 'custom-block'),
).getByRole('textbox').click();

const result = await getEditor3FormattingOptions(
page.locator(s('authoring', 'authoring-field=body_html', 'editor3')),
);

expect(result).toEqual(['h2', 'italic', 'bold']);
});

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {Page, expect} from '@playwright/test';
import {s} from '../../utils';
import {TreeSelectDriver} from '../../utils/tree-select-driver';

interface IOptions {
profileName: string;
sectionName: string;
fieldName: string;
formattingOptionsToAdd: Array<string>;
}

export class ContentProfileSettings {
private page: Page;

constructor(page: Page) {
this.page = page;
}

public async addFormattingOptionToContentProfile(options: IOptions) {
await this.page.locator(s(`content-profile=${options.profileName}`))
.getByRole('button', {name: 'Actions'})
.click();
await this.page.locator(s('content-profile-actions-popover')).getByRole('button', {name: 'Edit'}).click();

await this.page.locator(s('content-profile-edit-view')).getByRole('tab', {name: options.sectionName}).click();
await this.page.locator(s('content-profile-edit-view', `field=${options.fieldName}`)).click();

await new TreeSelectDriver(
this.page,
this.page.locator(s('formatting-options-input')),
).setValue(options.formattingOptionsToAdd);

// this is required for validation. TODO: update DB snapshot to make current items already valid
await this.page.locator(s('generic-list-page', 'item-view-edit', 'gform-input--sdWidth')).selectOption('Full');

await this.page.locator(s('generic-list-page', 'item-view-edit', 'toolbar'))
.getByRole('button', {name: 'Apply'})
.click();

await this.page.locator(s('content-profile-edit-view--footer')).getByRole('button', {name: 'Save'}).click();

// wait for saving to finish and modal to close
await expect(this.page.locator(s('content-profile-edit-view'))).not.toBeVisible();
}
}
9 changes: 9 additions & 0 deletions e2e/client/playwright/utils/editor3.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Locator} from '@playwright/test';
import {s} from '.';

export function getEditor3Paragraphs(field: Locator): Promise<Array<string>> {
return field.locator('.DraftEditor-root')
Expand All @@ -8,4 +9,12 @@ export function getEditor3Paragraphs(field: Locator): Promise<Array<string>> {
.locator('> *')
.allInnerTexts()
.then((items) => items.filter((text) => text.trim().length > 0));
}

export function getEditor3FormattingOptions(field: Locator): Promise<Array<string>> {
return field.locator(s('toolbar', 'formatting-option'))
.all()
.then((elements) => Promise.all(
elements.map((element) => element.getAttribute('data-test-value')),
));
}
50 changes: 50 additions & 0 deletions e2e/client/playwright/utils/tree-select-driver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {Locator, Page} from '@playwright/test';
import {s} from '.';

export class TreeSelectDriver {
private page: Page;
private element: Locator;

constructor(page, element) {
this.page = page;
this.element = element;

this.getValue = this.getValue.bind(this);
this.addValue = this.addValue.bind(this);
this.setValue = this.setValue.bind(this);
}

public async getValue(): Promise<Array<string>> {
return this.element.locator(s('item')).all().then((buttons) =>
Promise.all(buttons.map((button) => button.innerText())),
);
}

public async addValue(...options: Array<Array<string> | string>): Promise<void> {
const setOptions = async (options: Array<Array<string> | string>) => {
for (const option of options) {
if (typeof option == 'string') {
await this.element.locator(s('open-popover')).click();
await this.page.locator(s('tree-select-popover'))
.getByRole('button', {name: new RegExp(option, 'i')})
.click();
} else if (option != null) {
await setOptions(option);
}
}
};

await setOptions(options);
}

public async setValue(...options: Array<Array<string> | string>) {
const removeButton = await this.element.getByRole('button', {name: 'remove-sign'});
const removeButtonVisible = await removeButton.isVisible();

if (removeButtonVisible) {
await removeButton.click();
}

await this.addValue(...options);
}
}
5 changes: 4 additions & 1 deletion e2e/server/dump/records/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
editor3-tables only adds tables formatting option to story content profile. It can be merged to main. The only reason it was added as a separate record is to avoid merge conflicts on open PRs.
# Can easily be ported to main snapshot:

* editor3-tables - adds tables formatting option to story content profile.
* custom-blocks - adds custom blocks to story/body_html content profile. Creates a new custom block vocabulary.
Binary file added e2e/server/dump/records/custom-blocks.json.bz2
Binary file not shown.
12 changes: 6 additions & 6 deletions e2e/server/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ blinker==1.7.0
# flask-mail
# raven
# superdesk-core
boto3==1.34.104
boto3==1.34.110
# via superdesk-core
botocore==1.34.104
botocore==1.34.110
# via
# boto3
# s3transfer
Expand Down Expand Up @@ -77,7 +77,7 @@ draftjs-exporter[lxml]==2.1.0
# via superdesk-core
ecs-logging==2.1.0
# via elastic-apm
elastic-apm[flask]==6.22.0
elastic-apm[flask]==6.22.2
# via superdesk-core
elasticsearch==7.13.4
# via
Expand Down Expand Up @@ -225,7 +225,7 @@ regex==2024.4.28
# via superdesk-core
reportlab==3.6.13
# via superdesk-core
requests==2.31.0
requests==2.32.2
# via
# python-twitter
# requests-oauthlib
Expand Down Expand Up @@ -255,7 +255,7 @@ tzlocal==2.1
# via superdesk-core
unidecode==1.3.8
# via superdesk-core
urllib3==1.25.11
urllib3==1.26.18
# via
# botocore
# elastic-apm
Expand All @@ -275,7 +275,7 @@ werkzeug==1.0.1
# via
# flask
# superdesk-core
wrapt==1.14.1
wrapt==1.16.0
# via elastic-apm
xmlsec==1.3.14
# via superdesk-core
4 changes: 1 addition & 3 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ var path = require('path');
var grunt = require('grunt');
var makeConfig = require('./webpack.config.js');

require('karma-spec-reporter');

process.env.TZ = 'Europe/Prague';

module.exports = function(config) {
Expand Down Expand Up @@ -56,7 +54,7 @@ module.exports = function(config) {
},

// test results reporter to use
reporters: ['spec'],
reporters: ['dots'],

// web server port
port: 8080,
Expand Down
Loading

0 comments on commit 99dc281

Please sign in to comment.