Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2d96f1d
fix(babel): Adds missing dependency plugin-transform-typescript
mmichaelis May 30, 2022
96ab3f8
test(itest): First Test for Images
mmichaelis May 30, 2022
80246b3
docs(itest): Fixes wrong TSDoc comment.
mmichaelis May 31, 2022
ba11cc1
chore(update): Update CKEditor to 34.1.0
mmichaelis May 31, 2022
d2a0017
test(itest): Use JSDom in Jest Environment
mmichaelis May 31, 2022
c7d2fc6
chore(typings): Adjust Typing for Emitter
mmichaelis May 31, 2022
bc93a5b
chore(typings): Adjust Typing for Observable
mmichaelis Jun 1, 2022
badf6a0
chore(typings): Adjust Typing for `mix`
mmichaelis Jun 1, 2022
0a5e96c
test(itest): Extend Images Test
mmichaelis Jun 1, 2022
a7311e2
test(itest): Fix Jest Config (Roots)
mmichaelis Jun 1, 2022
206c006
chore(images): Minor Adjustments
mmichaelis Jun 1, 2022
1e4d79a
fix(images): Fully prevent upcasting src-attribute of CoreMedia Images.
JensDallmann Jun 1, 2022
d7d66bf
Merge remote-tracking branch 'origin/main' into update/ckeditor-34.1.0
mmichaelis Jun 1, 2022
18db724
chore: Fix Issues after Main-Merge
mmichaelis Jun 1, 2022
a39c4eb
chore: Fix Dependency Issues
mmichaelis Jun 1, 2022
6608568
fix(images): Remove previously introduced but now obsolete patch.
JensDallmann Jun 2, 2022
6b45452
chore: Update @types/jest
mmichaelis Jun 2, 2022
0d8ee0d
chore: Clean Up Main package.json
mmichaelis Jun 2, 2022
833a725
build(jest): Downgrade to Jest 27.5.1
mmichaelis Jun 3, 2022
21b3b96
build(itest): Downgrade jest-playwright-preset to 1.7.0
mmichaelis Jun 3, 2022
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
56 changes: 28 additions & 28 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,31 @@
"license": "Apache-2.0",
"private": true,
"dependencies": {
"@ckeditor/ckeditor5-alignment": "34.0.0",
"@ckeditor/ckeditor5-autosave": "34.0.0",
"@ckeditor/ckeditor5-basic-styles": "34.0.0",
"@ckeditor/ckeditor5-block-quote": "34.0.0",
"@ckeditor/ckeditor5-clipboard": "34.0.0",
"@ckeditor/ckeditor5-code-block": "34.0.0",
"@ckeditor/ckeditor5-core": "34.0.0",
"@ckeditor/ckeditor5-editor-classic": "34.0.0",
"@ckeditor/ckeditor5-engine": "34.0.0",
"@ckeditor/ckeditor5-essentials": "34.0.0",
"@ckeditor/ckeditor5-heading": "34.0.0",
"@ckeditor/ckeditor5-highlight": "34.0.0",
"@ckeditor/ckeditor5-image": "34.0.0",
"@ckeditor/ckeditor5-indent": "34.0.0",
"@ckeditor/ckeditor5-link": "34.0.0",
"@ckeditor/ckeditor5-list": "34.0.0",
"@ckeditor/ckeditor5-paragraph": "34.0.0",
"@ckeditor/ckeditor5-paste-from-office": "34.0.0",
"@ckeditor/ckeditor5-remove-format": "34.0.0",
"@ckeditor/ckeditor5-source-editing": "34.0.0",
"@ckeditor/ckeditor5-table": "34.0.0",
"@ckeditor/ckeditor5-theme-lark": "34.0.0",
"@ckeditor/ckeditor5-typing": "34.0.0",
"@ckeditor/ckeditor5-ui": "34.0.0",
"@ckeditor/ckeditor5-utils": "34.0.0",
"@ckeditor/ckeditor5-alignment": "34.1.0",
"@ckeditor/ckeditor5-autosave": "34.1.0",
"@ckeditor/ckeditor5-basic-styles": "34.1.0",
"@ckeditor/ckeditor5-block-quote": "34.1.0",
"@ckeditor/ckeditor5-clipboard": "34.1.0",
"@ckeditor/ckeditor5-code-block": "34.1.0",
"@ckeditor/ckeditor5-core": "34.1.0",
"@ckeditor/ckeditor5-editor-classic": "34.1.0",
"@ckeditor/ckeditor5-engine": "34.1.0",
"@ckeditor/ckeditor5-essentials": "34.1.0",
"@ckeditor/ckeditor5-heading": "34.1.0",
"@ckeditor/ckeditor5-highlight": "34.1.0",
"@ckeditor/ckeditor5-image": "34.1.0",
"@ckeditor/ckeditor5-indent": "34.1.0",
"@ckeditor/ckeditor5-link": "34.1.0",
"@ckeditor/ckeditor5-list": "34.1.0",
"@ckeditor/ckeditor5-paragraph": "34.1.0",
"@ckeditor/ckeditor5-paste-from-office": "34.1.0",
"@ckeditor/ckeditor5-remove-format": "34.1.0",
"@ckeditor/ckeditor5-source-editing": "34.1.0",
"@ckeditor/ckeditor5-table": "34.1.0",
"@ckeditor/ckeditor5-theme-lark": "34.1.0",
"@ckeditor/ckeditor5-typing": "34.1.0",
"@ckeditor/ckeditor5-ui": "34.1.0",
"@ckeditor/ckeditor5-utils": "34.1.0",
"@coremedia/ckeditor5-coremedia-content-clipboard": "6.0.1-rc.2",
"@coremedia/ckeditor5-coremedia-images": "6.0.1-rc.2",
"@coremedia/ckeditor5-coremedia-link": "6.0.1-rc.2",
Expand All @@ -44,9 +44,9 @@
"xml-formatter": "^2.6.1"
},
"devDependencies": {
"@ckeditor/ckeditor5-dev-utils": "^30.1.3",
"@ckeditor/ckeditor5-dev-webpack-plugin": "^30.1.3",
"@ckeditor/ckeditor5-inspector": "^4.0.0",
"@ckeditor/ckeditor5-dev-utils": "^30.1.5",
"@ckeditor/ckeditor5-dev-webpack-plugin": "^30.1.5",
"@ckeditor/ckeditor5-inspector": "^4.1.0",
"circular-dependency-plugin": "^5.2.2",
"css-loader": "^6.7.1",
"postcss": "^8.4.14",
Expand Down
17 changes: 3 additions & 14 deletions itest/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
const jestConfig = require("@coremedia-internal/ckeditor5-jest-test-helpers/shared-jest.config.js");

// We still have to use Jest 27 in this module, affected by https://github.com/facebook/jest/issues/9771
/**
* Required workaround for Jest Module Resolution
* (https://github.com/facebook/jest/issues/9771) as long as Jest Playwright
* does not support Jest 28
* (https://github.com/playwright-community/jest-playwright/issues/796).
*/
const enhancedResolveJest27 = {
resolver: "./enhanced-resolve-jest27.js",
};

module.exports = {
...jestConfig,
roots: ["<rootDir>/src/"],
// The default timeout is 5000. This may be not enough for Jest Playwright
// tests. If the test fails due to test-timeout, we will only get unspecific
// failures `Exceeded timeout`.
testTimeout: 60000,
preset: "jest-playwright-preset",
testEnvironment: "./playwright.environment.js",
setupFilesAfterEnv: ["expect-playwright"],
...enhancedResolveJest27,
testEnvironment: require.resolve("./playwright.environment.js"),
setupFilesAfterEnv: [require.resolve("expect-playwright")],
};
9 changes: 6 additions & 3 deletions itest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,21 @@
"devDependencies": {
"@babel/cli": "^7.17.10",
"@babel/core": "^7.18.2",
"@ckeditor/ckeditor5-core": "^32.0.0",
"@ckeditor/ckeditor5-core": "^34.1.0",
"@ckeditor/ckeditor5-engine": "^34.1.0",
"@coremedia-internal/ckeditor5-babel-config": "^1.0.0",
"@coremedia-internal/ckeditor5-jest-test-helpers": "^1.0.0",
"@coremedia/ckeditor5-coremedia-richtext": "6.0.1-rc.2",
"@coremedia/ckeditor5-coremedia-studio-integration": "6.0.1-rc.2",
"@coremedia/ckeditor5-coremedia-studio-integration-mock": "6.0.1-rc.2",
"@coremedia/types-ckeditor__ckeditor5-core": "6.0.1-rc.2",
"@coremedia/types-ckeditor__ckeditor5-engine": "6.0.1-rc.2",
"@types/express": "^4.17.13",
"@types/jest": "^27.5.1",
"@types/node": "^17.0.38",
"@typescript-eslint/eslint-plugin": "^5.27.0",
"@typescript-eslint/parser": "^5.27.0",
"babel-jest": "^27.5.1",
"enhanced-resolve": "^5.9.3",
"eslint": "^8.16.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
Expand All @@ -39,8 +41,9 @@
"jest": "^27.5.1",
"jest-circus": "^27.5.1",
"jest-config": "^27.5.1",
"jest-environment-jsdom": "^27.5.1",
"jest-environment-node": "^27.5.1",
"jest-playwright-preset": "^1.7.2",
"jest-playwright-preset": "1.7.0",
"jest-runner": "^27.5.1",
"playwright": "^1.22.2",
"playwright-core": "^1.22.2",
Expand Down
44 changes: 30 additions & 14 deletions itest/playwright.environment.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
const PlaywrightEnvironment = require("jest-playwright-preset/lib/PlaywrightEnvironment").default;
/*
* To be able using JSDom, we must not use `.default` as documented, but
* instead use `.getPlaywrightEnv("jsdom")`. This got introduced to
* the environment, as some CKEditor classes directly invoke `navigator`
* which again makes tests fail, if jsdom is not available.
*
* Requires `jest-environment-jsdom` dependency.`
*/
// eslint-disable-next-line @typescript-eslint/no-var-requires
const PlaywrightEnvironment = require("jest-playwright-preset/lib/PlaywrightEnvironment").getPlaywrightEnv("jsdom");

/**
* Custom configuration:
Expand All @@ -12,23 +21,30 @@ class CustomPlaywrightEnvironment extends PlaywrightEnvironment {
async handleTestEvent(event) {
await super.handleTestEvent(event);
const { name: eventName, test } = event;
if (eventName !== "test_done") {
// Context may be undefined on early failure.
if (eventName !== "test_done" || this.context === undefined) {
return;
}

const { parent, name: testName, errors } = test;
const { browserName } = this.context;
const parentName = parent.name.replace(/\W/g, "-");
const specName = testName.replace(/\W/g, "-");
const success = errors.length === 0;
const successId = success ? "success" : "failure";
const fullTestName = `${parentName}_${specName}_${browserName}_${successId}`;
try {
const { parent, name: testName, errors } = test;
const { browserName } = this.context;
const parentName = parent.name.replace(/\W/g, "-");
const specName = testName.replace(/\W/g, "-");
const success = errors.length === 0;
const successId = success ? "success" : "failure";
const fullTestName = `${parentName}_${specName}_${browserName}_${successId}`;

if (!success) {
// noinspection JSUnresolvedVariable,JSUnresolvedFunction
await this.global.page.screenshot({
path: `screenshots/${fullTestName}.png`,
});
if (!success) {
// noinspection JSUnresolvedVariable,JSUnresolvedFunction
await this.global.page.screenshot({
path: `screenshots/${fullTestName}.png`,
});
}
} catch (e) {
// Fail-safe: We don't want to fail here, just because we cannot
// take a screenshot.
console.warn("Failed taking screenshot.", e);
}
}
}
Expand Down
99 changes: 99 additions & 0 deletions itest/src/Images.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { ApplicationWrapper } from "./aut/ApplicationWrapper";
import { PNG_RED_240x135 } from "@coremedia/ckeditor5-coremedia-studio-integration-mock/content/MockFixtures";
import { img, p, richtext } from "./fixture/Richtext";
import "./expect/ElementHandleExpectations";

/**
* Simulates a blob reference to some property named `data`.
*
* @param id - numeric id of the document the property is contained in
*/
const blobReference = (id: number) => `content/${id}#properties.data`;

describe("Image Features", () => {
let application: ApplicationWrapper;

beforeAll(async () => {
application = await ApplicationWrapper.start();
await application.goto();
// Wait for CKEditor to be available prior to executing/continuing the tests.
await expect(application).waitForCKEditorToBeAvailable();
});

afterAll(async () => {
await application?.shutdown();
});

beforeEach(() => {
application.console.open();
});

afterEach(() => {
expect(application.console).toHaveNoErrorsOrWarnings();
application.console.close();
});

/**
* This test is especially a regression test for CoreMedia/ckeditor-plugins#65,
* which is, that after upgrade from CKEditor 32.0.0 to 34.0.0 images provided
* by CMS were not detected anymore but appeared as _HTML Objects_ provided
* by General HTML Support rather than as InlineImage objects.
*
* As this regression test has also been used for debugging purpose, it
* validates states on different layers, while in the end only the outcome
* in content-editable is relevant.
*/
it("Should render image blob after loading from data", async () => {
const { currentTestName } = expect.getState();
const { editor, mockContent } = application;
const { ui } = editor;
const editableHandle = await ui.getEditableElement();

const id = 42;
await mockContent.addContents({
id,
blob: PNG_RED_240x135,
name: `Document for test ${currentTestName}`,
});

const data = richtext(
p(
img({
alt: currentTestName,
"xlink:href": blobReference(id),
})
)
);

const dataView = await editor.setDataAndGetDataView(data);

/*
* -----------------------------------------------------------------------
* Validating state in data view (data, which just passed data processor).
* -----------------------------------------------------------------------
*/

// Image Tag should exist.
expect(dataView).toContain(`<img`);
// Alt Text should be available in data view
expect(dataView).toContain(`alt="${currentTestName}"`);
// Some generic image should have been applied, until updated from server.
expect(dataView).toContain(`src="data:image/png;base64`);
// Data View should still contain a reference to "xlink:href" for
// subsequent retrieval of Blob from Studio Server.
expect(dataView).toContain(`data-xlink-href="content/42#properties.data"`);

/*
* --------------------------------------------------------------------------
* Validating state in editing view (data, which just passed data processor).
* --------------------------------------------------------------------------
*/

await expect(editableHandle).toHaveSelector("img");

const imgHandle = await editableHandle.$("img");
// The property reference should have been resolved to some
// BLOB-link to render the image.
await expect(imgHandle).toMatchAttribute("src", PNG_RED_240x135);
});
});
43 changes: 42 additions & 1 deletion itest/src/aut/ClassicEditorWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { EditorWrapper } from "./EditorWrapper";
import { CommandCollectionWrapper } from "./CommandCollectionWrapper";
import { extendingWaitForExpect } from "../expect/Expectations";
import { EditorUiWrapper } from "./EditorUiWrapper";
import RichTextDataProcessor from "@coremedia/ckeditor5-coremedia-richtext/RichTextDataProcessor";

/**
* Provides access to the editor within the example application. It requires
Expand All @@ -25,6 +26,46 @@ export class ClassicEditorWrapper extends EditorWrapper<ClassicEditor> {
return this.evaluate((editor, value) => editor.setData(value), value);
}

/**
* Sets the given data and waits for them being processed to _data view_,
* thus, the result of the `toView` transformation of the data processor.
* @param value - value to set
*/
async setDataAndGetDataView(value: string): Promise<string> {
/*
* What this implementation does:
*
* * It registers a one-time listener for `richtext:toView`.
* * It sets the data as requested.
* * It waits for `richtext:toView` to provide the _data view_.
*
* It also validates, that the event matches the expected data set.
*
* If this should fail, we may want to provide a listener instead, which
* waits until the expected event data are provided.
*/
return this.evaluate((editor, value): Promise<string> => {
return new Promise<string>((resolve, reject) => {
const processor = editor.data.processor as RichTextDataProcessor;
// Prior to setting data, wait for them being processed.
processor.once("richtext:toView", (eventInfo, eventData) => {
if ("dataView" in eventData && "data" in eventData) {
if (eventData.data !== value) {
reject(
new Error(
`Unexpected data being processed. Concurrent changes applied?\n\tExpected: ${value}\n\tActual: ${eventData.data}`
)
);
}
resolve(eventData.dataView);
}
reject(new Error("richtext:toView provided unexpected data: " + JSON.stringify(eventData)));
});
editor.setData(value);
});
}, value);
}

/**
* Provides a handle to the commands of the CKEditor.
*/
Expand Down Expand Up @@ -81,7 +122,7 @@ expect.extend({
});

/**
* Extension to matchers for Application Console.
* Extension to matchers for `ClassicEditorWrapper`.
*/
export interface ClassicEditorWrapperMatchers<R = unknown, T = unknown> {
/**
Expand Down
4 changes: 4 additions & 0 deletions itest/src/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"@ckeditor/ckeditor5-engine/*": ["../../types/ckeditor__ckeditor5-engine/*"],
"@ckeditor/ckeditor5-utils/*": ["../../types/ckeditor__ckeditor5-utils/*"],
"@coremedia/ckeditor5-logging/*": ["../../packages/ckeditor5-logging/src/*"],
"@coremedia/ckeditor5-coremedia-richtext/*": ["../../packages/ckeditor5-coremedia-richtext/src/*"],
"@coremedia/ckeditor5-coremedia-studio-integration/*": [
"../../packages/ckeditor5-coremedia-studio-integration/src/*"
],
Expand All @@ -23,6 +24,9 @@
{
"path": "../../packages/ckeditor5-logging/src"
},
{
"path": "../../packages/ckeditor5-coremedia-richtext/src"
},
{
"path": "../../packages/ckeditor5-coremedia-studio-integration/src"
},
Expand Down
Loading