From 8afe36e8ea07b32cfd5bae2c1dca88d9f916b1b9 Mon Sep 17 00:00:00 2001 From: Ramon Wenger Date: Wed, 7 Feb 2024 11:52:37 +0100 Subject: [PATCH] Add cypress test for highlights --- .../e2e/frontend/modules/highlights.cy.ts | 136 ++++++++++++++++++ client/cypress/tsconfig.json | 7 +- client/package-lock.json | 11 ++ client/package.json | 1 + .../content-blocks/ContentComponent.vue | 19 ++- .../highlights/HighlightPopover.vue | 11 +- .../highlights/HighlightSidebar.vue | 6 +- client/src/components/modals/Confirm.vue | 1 + client/src/helpers/highlight.ts | 1 - client/src/helpers/popover.ts | 11 -- client/tsconfig.cypress.json | 2 +- 11 files changed, 182 insertions(+), 24 deletions(-) create mode 100644 client/cypress/e2e/frontend/modules/highlights.cy.ts diff --git a/client/cypress/e2e/frontend/modules/highlights.cy.ts b/client/cypress/e2e/frontend/modules/highlights.cy.ts new file mode 100644 index 00000000..679cf5be --- /dev/null +++ b/client/cypress/e2e/frontend/modules/highlights.cy.ts @@ -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: '

Dies ist ein Text mit ein paar Wörtern.

', + }, + }, + ], + }, + ], + }, + ], + }, + }, + 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'); + }); +}); diff --git a/client/cypress/tsconfig.json b/client/cypress/tsconfig.json index 18edb199..b9876f7f 100644 --- a/client/cypress/tsconfig.json +++ b/client/cypress/tsconfig.json @@ -2,7 +2,12 @@ "compilerOptions": { "target": "es5", "lib": ["es5", "dom"], - "types": ["cypress", "node"] + "types": ["cypress", "node"], + "baseUrl": "./../src/", + "paths": { + "@/*": ["./*"], + "cypress/*": ["./cypress/*"] + } }, "include": ["**/*.ts"] } diff --git a/client/package-lock.json b/client/package-lock.json index ab18a0df..0926bdb4 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -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", diff --git a/client/package.json b/client/package.json index ae8f8c06..1049650c 100644 --- a/client/package.json +++ b/client/package.json @@ -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", diff --git a/client/src/components/content-blocks/ContentComponent.vue b/client/src/components/content-blocks/ContentComponent.vue index 49dddeca..ff194ec2 100644 --- a/client/src/components/content-blocks/ContentComponent.vue +++ b/client/src/components/content-blocks/ContentComponent.vue @@ -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); }); diff --git a/client/src/components/highlights/HighlightPopover.vue b/client/src/components/highlights/HighlightPopover.vue index 00fa2305..f5978b10 100644 --- a/client/src/components/highlights/HighlightPopover.vue +++ b/client/src/components/highlights/HighlightPopover.vue @@ -1,8 +1,12 @@