Add cypress test for highlights
This commit is contained in:
parent
91dcf3cb20
commit
8afe36e8ea
|
|
@ -0,0 +1,136 @@
|
|||
import { defaultModuleQueriesandMutations } from '../../../support/helpers';
|
||||
|
||||
const contentBlockId = window.btoa('ContentBlockNode:1');
|
||||
const operations = {
|
||||
...defaultModuleQueriesandMutations,
|
||||
ModuleDetailsQuery: {
|
||||
module: {
|
||||
chapters: [
|
||||
{
|
||||
title: 'A Chapter',
|
||||
contentBlocks: [
|
||||
{
|
||||
title: 'A Content Block',
|
||||
highlights: [],
|
||||
id: contentBlockId,
|
||||
contents: [
|
||||
{
|
||||
type: 'text_block',
|
||||
id: 'some-content-component-id',
|
||||
value: {
|
||||
text: '<p>Dies ist ein Text mit ein paar Wörtern.</p>',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
AddHighlight: ({ input: { highlight } }) => {
|
||||
return {
|
||||
addHighlight: {
|
||||
highlight: {
|
||||
...highlight,
|
||||
id: 'new-highlight-id',
|
||||
contentBlock: {
|
||||
id: contentBlockId,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
DeleteHighlight: {
|
||||
deleteHighlight: {
|
||||
success: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const selectText = (elm: Node, start: number, end: number) => {
|
||||
const range = document.createRange();
|
||||
range.setStart(elm, start);
|
||||
range.setEnd(elm, end);
|
||||
cy.window().then((win) => win.getSelection().addRange(range));
|
||||
};
|
||||
|
||||
describe('Highlights', () => {
|
||||
beforeEach(() => {
|
||||
cy.setup();
|
||||
cy.mockGraphqlOps({
|
||||
operations,
|
||||
});
|
||||
});
|
||||
|
||||
it('visits a module and highlights a paragraph', () => {
|
||||
cy.visit('/module/my-module');
|
||||
|
||||
/*
|
||||
* Mark the text (programmatically, as Cypress has no API for this)
|
||||
*/
|
||||
cy.getByDataCy('text-block').then(($elm) => {
|
||||
const textBlock = $elm[0];
|
||||
const paragraph = textBlock.querySelector('p');
|
||||
selectText(paragraph.childNodes[0], 2, 12);
|
||||
});
|
||||
/*
|
||||
* Also trigger the events manually
|
||||
*/
|
||||
cy.document().trigger('selectionchange');
|
||||
cy.getByDataCy('content-block-div').trigger('mouseup');
|
||||
|
||||
cy.getByDataCy('highlight-popover').should('be.visible');
|
||||
cy.getByDataCy('highlight-popover').should('have.length', 1); // there should only be one popover
|
||||
|
||||
/*
|
||||
* manually remove the selection, because cypress does not do that on a click, unlike a real browser
|
||||
*/
|
||||
cy.window().then((win) => {
|
||||
const selection = win.getSelection();
|
||||
selection.removeAllRanges();
|
||||
});
|
||||
|
||||
// mark the text with yellow and check the text
|
||||
cy.getByDataCy('highlight-alpha').click();
|
||||
cy.getByDataCy('highlight-mark').should('contain', 'es ist ein');
|
||||
|
||||
// we only want to have one of each element and not accidentally create multiple
|
||||
cy.getByDataCy('highlight-popover').should('have.length', 1); // there should only be one popover
|
||||
cy.getByDataCy('highlight-mark').should('have.length', 1);
|
||||
|
||||
// display the sidebar and popover and check them
|
||||
cy.getByDataCy('highlight-note').click();
|
||||
cy.getByDataCy('highlight-popover').should('be.visible');
|
||||
cy.getByDataCy('highlight-sidebar').should('be.visible');
|
||||
cy.getByDataCy('highlight-in-sidebar').should('contain', 'es ist ein');
|
||||
|
||||
cy.getByDataCy('highlight-popover').should('have.length', 1); // there should only be one popover
|
||||
cy.getByDataCy('highlight-mark').should('have.length', 1);
|
||||
|
||||
// click outside the created components to make them disappear
|
||||
cy.getByDataCy('module-title').click();
|
||||
cy.getByDataCy('highlight-popover').should('not.exist');
|
||||
cy.getByDataCy('highlight-sidebar').should('not.exist');
|
||||
|
||||
cy.getByDataCy('highlight-mark').should('have.length', 1);
|
||||
|
||||
// click on the highlighted text to make the menus appear again
|
||||
cy.getByDataCy('highlight-mark').click();
|
||||
cy.getByDataCy('highlight-popover').should('be.visible');
|
||||
cy.getByDataCy('highlight-sidebar').should('be.visible');
|
||||
|
||||
// todo: change the color
|
||||
// todo: write a note
|
||||
// todo: click the note icon without first setting a color
|
||||
|
||||
// delete the highlight
|
||||
cy.getByDataCy('highlight-delete').click();
|
||||
cy.getByDataCy('confirm-dialog').should('be.visible');
|
||||
cy.getByDataCy('modal-save-button').click();
|
||||
|
||||
cy.getByDataCy('highlight-popover').should('not.exist');
|
||||
cy.getByDataCy('highlight-sidebar').should('not.exist');
|
||||
cy.getByDataCy('highlight-mark').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
|
@ -2,7 +2,12 @@
|
|||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["es5", "dom"],
|
||||
"types": ["cypress", "node"]
|
||||
"types": ["cypress", "node"],
|
||||
"baseUrl": "./../src/",
|
||||
"paths": {
|
||||
"@/*": ["./*"],
|
||||
"cypress/*": ["./cypress/*"]
|
||||
}
|
||||
},
|
||||
"include": ["**/*.ts"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
"@tiptap/extension-text": "^2.1.11",
|
||||
"@tiptap/vue-3": "^2.1.11",
|
||||
"@types/mark.js": "^8.11.12",
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@types/rangy": "^0.0.38",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||
"@typescript-eslint/parser": "^5.10.0",
|
||||
|
|
@ -6177,6 +6178,11 @@
|
|||
"@types/jquery": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/mocha": {
|
||||
"version": "10.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz",
|
||||
"integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.5.tgz",
|
||||
|
|
@ -22599,6 +22605,11 @@
|
|||
"@types/jquery": "*"
|
||||
}
|
||||
},
|
||||
"@types/mocha": {
|
||||
"version": "10.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz",
|
||||
"integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "18.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.5.tgz",
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
"@tiptap/extension-text": "^2.1.11",
|
||||
"@tiptap/vue-3": "^2.1.11",
|
||||
"@types/mark.js": "^8.11.12",
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@types/rangy": "^0.0.38",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||
"@typescript-eslint/parser": "^5.10.0",
|
||||
|
|
|
|||
|
|
@ -170,13 +170,17 @@ const childElements = computed(() => {
|
|||
return [];
|
||||
});
|
||||
|
||||
const unmark = () => {
|
||||
for (const paragraph of childElements.value) {
|
||||
const instance = new Mark(paragraph);
|
||||
instance.unmark();
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => filteredHighlights.value.map((h) => h.color),
|
||||
() => {
|
||||
for (const paragraph of childElements.value) {
|
||||
const instance = new Mark(paragraph);
|
||||
instance.unmark();
|
||||
}
|
||||
unmark();
|
||||
markHighlights();
|
||||
}
|
||||
);
|
||||
|
|
@ -242,6 +246,7 @@ const markHighlights = () => {
|
|||
className: `highlight highlight--${highlight.color}`,
|
||||
each: (newMark: HTMLElement) => {
|
||||
newMark.dataset.id = highlight.id;
|
||||
newMark.dataset.cy = 'highlight-mark';
|
||||
newMark.addEventListener('click', () => {
|
||||
if (contentComponentDiv.value) {
|
||||
popover.show({
|
||||
|
|
@ -340,8 +345,10 @@ const markHighlights = () => {
|
|||
};
|
||||
|
||||
onMounted(() => {
|
||||
console.log('onMounted ContentComponent called');
|
||||
setTimeout(markHighlights, 500);
|
||||
setTimeout(() => {
|
||||
unmark();
|
||||
markHighlights();
|
||||
}, 1);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
<template>
|
||||
<div class="highlight-popover">
|
||||
<div
|
||||
data-cy="highlight-popover"
|
||||
class="highlight-popover"
|
||||
>
|
||||
<section class="highlight-popover__section">
|
||||
<div
|
||||
class="highlight-popover__color highlight-popover__color--yellow"
|
||||
data-cy="highlight-alpha"
|
||||
@click="$emit('choose-color', 'alpha')"
|
||||
></div>
|
||||
<div
|
||||
|
|
@ -17,12 +21,14 @@
|
|||
<section class="highlight-popover__section">
|
||||
<note-icon
|
||||
class="highlight-popover__icon"
|
||||
data-cy="highlight-note"
|
||||
@click="$emit('note')"
|
||||
/>
|
||||
</section>
|
||||
<section class="highlight-popover__section">
|
||||
<trash-icon
|
||||
class="highlight-popover__icon"
|
||||
data-cy="highlight-delete"
|
||||
@click="confirmDelete"
|
||||
/>
|
||||
</section>
|
||||
|
|
@ -37,10 +43,9 @@ export interface Props {
|
|||
top: string;
|
||||
}
|
||||
|
||||
const emit = defineEmits(['close', 'confirm', 'choose-color']);
|
||||
const emit = defineEmits(['close', 'confirm', 'choose-color', 'delete']);
|
||||
defineProps<Props>();
|
||||
const confirmDelete = () => {
|
||||
console.log('trying to delete');
|
||||
modal
|
||||
.show()
|
||||
.then(() => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<div class="highlight-sidebar">
|
||||
<div
|
||||
data-cy="highlight-sidebar"
|
||||
class="highlight-sidebar"
|
||||
>
|
||||
<div
|
||||
class="highlight-sidebar__close-button"
|
||||
@click="close"
|
||||
|
|
@ -11,6 +14,7 @@
|
|||
<mark
|
||||
class="paragraph highlight-sidebar__highlighted-text"
|
||||
:class="[`highlight--${highlight.color}`]"
|
||||
data-cy="highlight-in-sidebar"
|
||||
ref="highlightMark"
|
||||
>
|
||||
{{ highlight.text }}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<template>
|
||||
<modal
|
||||
class="confirm-dialog"
|
||||
data-cy="confirm-dialog"
|
||||
:small="true"
|
||||
>
|
||||
<template #header>
|
||||
|
|
|
|||
|
|
@ -173,7 +173,6 @@ export const getSelectionHandler =
|
|||
const positionOfSelection = startAncestor?.getBoundingClientRect();
|
||||
const offsetTop = positionOfSelection.top - positionOfContentBlock.top;
|
||||
const onChooseColor = (color: string) => {
|
||||
console.log('chosenColor', color);
|
||||
highlightedText.color = color;
|
||||
if (onChangeColor) {
|
||||
onChangeColor(highlightedText);
|
||||
|
|
|
|||
|
|
@ -16,20 +16,12 @@ export default {
|
|||
const mountEl = document.createElement('div');
|
||||
wrapper.appendChild(mountEl);
|
||||
|
||||
let _resolve: ResolveReject, _reject: ResolveReject;
|
||||
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
_resolve = resolve;
|
||||
_reject = reject;
|
||||
});
|
||||
|
||||
const clickOutsideElementListener = (event: Event) => {
|
||||
// inspired by https://stackoverflow.com/a/3028037/6071058
|
||||
const isInsidePopover = mountEl.contains(event.target as Node); // the click happened inside the Popover
|
||||
// const isInsideWrapper = wrapper.contains(event.target as Node); // the click happened inside the wrapper
|
||||
const isInsideSidebar = document.querySelector('.highlight-sidebar')?.contains(event.target as Node); // the click happened inside the HighlightSidebar
|
||||
if (!(isInsidePopover || isInsideSidebar)) {
|
||||
_reject();
|
||||
cleanUp();
|
||||
}
|
||||
};
|
||||
|
|
@ -44,7 +36,6 @@ export default {
|
|||
top: `${Math.floor(offsetTop)}px`,
|
||||
onConfirm() {
|
||||
cleanUp();
|
||||
_resolve();
|
||||
},
|
||||
onNote() {
|
||||
if (onNote) {
|
||||
|
|
@ -53,7 +44,6 @@ export default {
|
|||
},
|
||||
onClose() {
|
||||
cleanUp();
|
||||
_reject();
|
||||
},
|
||||
onDelete() {
|
||||
if (onDelete) {
|
||||
|
|
@ -69,6 +59,5 @@ export default {
|
|||
setTimeout(() => {
|
||||
document.addEventListener('click', clickOutsideElementListener);
|
||||
}, 1); // do not trigger on the same event that created the popover
|
||||
return promise;
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@
|
|||
"target": "es5",
|
||||
"types": ["cyress", "node"]
|
||||
},
|
||||
"include": ["src/**/*.cy.js"]
|
||||
"include": ["src/**/*.cy.js", "src/**/*.cy.ts"]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue