Skip to content

Commit d5fa0e7

Browse files
committed
test(paste): cover filter function in tag-based paste config
Adds Cypress test exercising both branches of the filter function (accept and reject), and a 2.31.6 changelog entry.
1 parent 118bd58 commit d5fa0e7

2 files changed

Lines changed: 86 additions & 0 deletions

File tree

docs/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
### 2.31.6
4+
5+
- `Improvement` - `paste` config supports filter functions for tag-based substitution
6+
37
### 2.31.5
48

59
- `Fix` - Handle __Ctrl + click__ on links with inline styles applied (e.g., bold, italic)

test/cypress/tests/copy-paste.cy.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,88 @@ describe('Copy pasting from Editor', function () {
157157
});
158158
});
159159

160+
it('should respect filter function in tag-based paste config', function () {
161+
/**
162+
* Tool that handles only DIVs marked with a specific class
163+
* via a filter function in its pasteConfig.tags entry.
164+
*/
165+
class FilteredDivTool implements BlockTool {
166+
public static pasteConfig = {
167+
tags: [
168+
// eslint-disable-next-line @typescript-eslint/naming-convention
169+
{ DIV: (el: Element): boolean => el.classList.contains('accept') },
170+
],
171+
};
172+
173+
private data: BlockToolData = { text: '' };
174+
175+
/**
176+
* Receive matched element on paste
177+
*/
178+
public onPaste(event: CustomEvent<{ data: HTMLElement }>): void {
179+
this.data = { text: event.detail.data.textContent || '' };
180+
}
181+
182+
/**
183+
* Render block
184+
*/
185+
public render(): HTMLElement {
186+
const block = $.make('div', 'ce-filtered-div');
187+
188+
block.textContent = (this.data.text as string) || '';
189+
190+
return block;
191+
}
192+
193+
/**
194+
* Save block content
195+
*/
196+
public save(blockContent: HTMLElement): BlockToolData {
197+
return { text: blockContent.textContent || '' };
198+
}
199+
}
200+
201+
cy.createEditor({
202+
tools: {
203+
filteredDiv: FilteredDivTool,
204+
},
205+
}).as('editorInstance');
206+
207+
cy.get('[data-cy=editorjs]')
208+
.get('div.ce-block')
209+
.click()
210+
.paste({
211+
// eslint-disable-next-line @typescript-eslint/naming-convention
212+
'text/html': '<div class="accept">Accepted</div><div class="reject">Rejected</div>',
213+
});
214+
215+
/**
216+
* Accepted div is rendered with FilteredDivTool's class
217+
*/
218+
cy.get('[data-cy=editorjs]')
219+
.get('div.ce-filtered-div')
220+
.should('contain', 'Accepted');
221+
222+
/**
223+
* Rejected div falls back to the default paragraph
224+
*/
225+
cy.get('[data-cy=editorjs]')
226+
.get('div.ce-paragraph')
227+
.should('contain', 'Rejected');
228+
229+
/**
230+
* Saved data reflects the same split
231+
*/
232+
cy.get<EditorJS>('@editorInstance')
233+
.then(async (editor) => {
234+
cy.wrap<OutputData>(await editor.save())
235+
.then((data) => {
236+
expect(data.blocks[0].type).to.eq('filteredDiv');
237+
expect(data.blocks[1].type).to.eq('paragraph');
238+
});
239+
});
240+
});
241+
160242
it('should parse pattern', function () {
161243
cy.createEditor({
162244
tools: {

0 commit comments

Comments
 (0)