diff --git a/frontend-e2e/cypress/e2e/experimental.cy.js b/frontend-e2e/cypress/e2e/experimental.cy.js index 68060058..09469f07 100644 --- a/frontend-e2e/cypress/e2e/experimental.cy.js +++ b/frontend-e2e/cypress/e2e/experimental.cy.js @@ -11,3 +11,31 @@ describe('intercept traditions', () => { }); }); }); + +describe('intercept login request', () => { + if (Cypress.env('CY_MODE') === 'headed') { // skip when in headless mode + it('passes in headed mode but fails in headless mode: run only in headed mode', { defaultCommandTimeout: 10000 }, () => { + cy.log("Cypress.env('CY_MODE'): " + Cypress.env('CY_MODE')); + + cy.visit(`${Cypress.env('CY_STEMMAWEB_FRONTEND_URL')}/`); + cy.viewport(1600, 900); + + cy.intercept('POST', `${Cypress.env('CY_STEMMAWEB_FRONTEND_URL')}/requests/login`).as('loginrequest'); + + cy.get('header').contains('a', 'Sign in').wait(500).click(); + cy.get('#loginEmail').wait(500).type('user@example.org', { delay: 50 }); + cy.get('#loginPassword').wait(500).type('UserPass', { delay: 50 }); + cy.get('auth-modal').contains('button', 'Sign in').wait(500).click(); + + cy.wait('@loginrequest').then(interception => { + // const res_str = JSON.stringify(interception.response); + // cy.log('res_str: ' + res_str); + cy.expect(interception.response.statusCode).to.eq(200); + }); + + cy.get('header').contains('a', 'Logged in as user@example.org'); + cy.get('header').should('not.contain', 'Sign in'); + cy.get('header').contains('a', 'Sign out'); // for now, don't click without interception + }); + } +}); diff --git a/frontend-e2e/cypress/e2e/florilegium_cb.cy.js b/frontend-e2e/cypress/e2e/florilegium_cb.cy.js index e6d975b1..21f13fb2 100644 --- a/frontend-e2e/cypress/e2e/florilegium_cb.cy.js +++ b/frontend-e2e/cypress/e2e/florilegium_cb.cy.js @@ -9,27 +9,27 @@ describe("'Florilegium Coislinianum B' has the right owner and witnesses", funct cy.visit(`${Cypress.env('CY_STEMMAWEB_FRONTEND_URL')}/`); cy.wait(500); - /* cy.get('#tradition_name').should(($tn) => { + /* cy.get('#tradition-name').should(($tn) => { expect($tn.text().trim()).to.not.equal('Notre besoin'); }); // should fail. // Does not fail because the tradition_name is not loaded so quickly. // Eventually it is 'Notre besoin'. It fails as it should, // only after waiting a bit, e.g. with cy.wait(1000) */ - /* cy.get('#tradition_name').contains('Notre besoin'); // passes as expected, + /* cy.get('#tradition-name').contains('Notre besoin'); // passes as expected, // it is the intended first view of the page. // But one could also check if Florilegium is not there, // and only there, after clicking on in in the toc. */ const expectedName = 'Florilegium "Coislinianum B"' - cy.get('#tradition_name').should(($tn) => { + cy.get('#tradition-name').should(($tn) => { expect($tn.text().trim()).to.not.equal('Florilegium Coislinianum B'); }); // should pass // is there a better way to assert 'does not contain text xyz'? - cy.get('#tradition_name').should('not.have.text', expectedName) + cy.get('#tradition-name').should('not.have.text', expectedName) cy.get('tradition-list') .contains(expectedName) .click(); - cy.get('#tradition_name').contains(expectedName); + cy.get('#tradition-name').contains(expectedName); cy.get('#sidebar_properties').contains('user@example.org'); // Sort the witness list for better reliability cy.get('#sidebar_properties').contains('A, B, C, D, E, F, G, H, K, P, Q, S, T'); diff --git a/frontend-e2e/cypress/e2e/homepage.cy.js b/frontend-e2e/cypress/e2e/homepage.cy.js new file mode 100644 index 00000000..1b6a37e5 --- /dev/null +++ b/frontend-e2e/cypress/e2e/homepage.cy.js @@ -0,0 +1,132 @@ +/* Assert everything is visible for an admin on the homepage upon login */ + +import test_traditions from '../fixtures/test_traditions.json'; +import users from '../fixtures/users.json'; +const admin = users.filter(({username}) => username === 'admin@example.org')[0]; +const selected_fill_color = 'rgb(207, 220, 238)'; + +beforeEach(() => { + cy.visit(`${Cypress.env('CY_STEMMAWEB_FRONTEND_URL')}/`); + cy.viewport(1600, 900); + test_traditions.sort( (tradition_a, tradition_b) => tradition_a.title.localeCompare( tradition_b.title ) ); + cy.loginViaUi(admin); // TODO: also for headless mode +}); + +afterEach(() => { + cy.logoutViaUi(admin); // TODO: also for headless mode +}); + +// on the homepage, the admin should see all traditions listed +// traditions with stemma should have buttons: edit add delete; those without: add +describe('all traditions are listed and provide stemma add or edit buttons', () => { + it('passes', () => { + // the number of displayed traditions should be equal to the total number of test_traditions + const count = test_traditions.length; // 7 + cy.get('ul#traditions-list').children().should('have.length', count); + test_traditions.forEach((tradition) => { + cy.log("title: " + tradition.title); + // the test_tradition titles should all be found on the homepage + // together with their stemmas + cy.get('ul#traditions-list').contains(tradition.title).should('be.visible').click(); + if (tradition.stemmata.length){ + cy.log('Number of stemmata: ' + tradition.stemmata.length); + // traditions with a stemma should have buttons highlighted: edit add delete + cy.get('edit-stemma-buttons').within( ()=> { + cy.get('a#edit-stemma-button-link').should('be.visible').and('not.have.class', 'greyed-out'); + cy.get('a#add-stemma-button-link').should('be.visible').and('not.have.class', 'greyed-out'); + cy.get('a#delete-stemma-button-link').should('be.visible').and('not.have.class', 'greyed-out'); + }); + } + else { + // traditions with no stemma should have buttons highlighted: add + cy.get('edit-stemma-buttons').within( ()=> { + cy.get('a#edit-stemma-button-link').should('be.visible').and('have.class', 'greyed-out'); + cy.get('a#add-stemma-button-link').should('be.visible').and('not.have.class', 'greyed-out'); + cy.get('a#delete-stemma-button-link').should('be.visible').and('have.class', 'greyed-out'); + }); + } + }); + }); +}); + +// Assert that the stemma “edit” button is only enabled when there is a stemma (also the “delete” button/cross), and that it disappears on click, being being replaced, together with the “new” and “delete” button, by a “save” and a “cancel” button. + +describe('Assert that only one tradition is highlighted in the sidebar menu: \ + the current one, clicked on, or \ + the first one upon loading the page.', () => { + // implements #164 + it('passes', () => { + let n = 0 // check the first tradition at start + test_traditions.forEach((tradition, i) => { + // traditions are displayed in alphabetical order (test_traditions sorted above) + cy.log('idx+1) test_tradition title: ' + String(Number(i)+1) + ') ' +tradition.title); + cy.get('ul#traditions-list > li').eq(i).find('a') + .invoke('text') + .then((text) => { + expect(text.trim()).to.equal(tradition.title.trim()) + cy.log('same idx+1) tradition title: ' + text.trim()) + }); + cy.get('ul#traditions-list > li').eq(i).contains(tradition.title).should('be.visible'); + + // on load only the first tradition is selected and highlighted + if (i == n){ + cy.get('ul#traditions-list > li').eq(i).find('div').should('have.class', 'selected'); + cy.get('ul#traditions-list > li').eq(i).find('svg').should('have.css', 'fill', selected_fill_color) + } + else { + cy.get('ul#traditions-list > li').eq(i).find('div').should('not.have.class', 'selected'); + cy.get('ul#traditions-list > li').eq(i).find('svg').should('not.have.css', 'fill', selected_fill_color); + } + }); + + // Click on another tradition higlights its title and the others are not selected or highlighted + n = 3; // check nth tradition + cy.log('Click on ' + String(Number(n)+1) + '. tradition and assert selection'); + cy.get('ul#traditions-list > li').eq(n).click(); + cy.get('ul#traditions-list > li').eq(n).find('a') //
  • contains also section info text, just the title + .invoke('text') + .then((text) => { + cy.log('Clicked on ' + String(Number(n)+1) + '. tradition title: ' + text.trim()) + }); + // Assert all traditions are correctly un-/selected and un-/filled + test_traditions.forEach((tradition, i) => { + // Only the clicked tradition is selected and highlighted + if (i == n){ + cy.get('ul#traditions-list > li').eq(i).find('div').should('have.class', 'selected'); + cy.get('ul#traditions-list > li').eq(i).find('svg').should('have.css', 'fill', selected_fill_color) + } + else { + cy.get('ul#traditions-list > li').eq(i).find('div').should('not.have.class', 'selected'); + cy.get('ul#traditions-list > li').eq(i).find('svg').should('not.have.css', 'fill', selected_fill_color); + } + }); + }); + +}); + +describe('message console logs errors and successes', () => { + if (Cypress.env('CY_MODE') === 'headed') { + it('passes', () => { // Login needed to add a stemma. Skip in headless mode for now. + const stemma_added_marker = 'Stemma added'; + const stemma_deleted_marker = 'Deleted'; + // initially the message panel should exist without text content + cy.get('#message-console-text-panel').as('messageconsole'); + cy.get('@messageconsole').should('have.value', ''); + // Add a stemma (the default example stemma) + cy.get('#add-stemma-button-link').click(); + cy.get('#save-stemma-button-link').wait(500).click(); + // when a stemma is saved it should have a message with the text "Stemma added" + cy.get('@messageconsole').contains(stemma_added_marker); + // delete the added stemma in order to reset the db + cy.get('#delete-stemma-button-link').click(); + cy.get('.modal-content').contains('button', 'Yes, delete it').wait(500).click(); + cy.get('#modalDialog').should('not.be.visible'); + cy.get('@messageconsole').contains(stemma_deleted_marker); + + // assert the content in the message console stays there also upon clicking on another tradition. + cy.get('ul#traditions-list > li').eq(-1).wait(500).click(); // ultimate tradition + cy.get('@messageconsole').should('be.visible').contains(stemma_deleted_marker); + cy.get('@messageconsole').contains(stemma_added_marker); + }); + } +}); diff --git a/frontend-e2e/cypress/e2e/stemwebdialog.cy.js b/frontend-e2e/cypress/e2e/stemwebdialog.cy.js index e759ddcb..69ce487e 100644 --- a/frontend-e2e/cypress/e2e/stemwebdialog.cy.js +++ b/frontend-e2e/cypress/e2e/stemwebdialog.cy.js @@ -31,11 +31,20 @@ Cypress tests that could be added: Job: 1 Status: Done +3) +Tests for feature: implemented stemma editor +https://github.com/tla/stemmaweb/pull/188#issue-2133307487 +• Test that svg appears. +• Upon edit, svg and box should be there. +• Upon a change in the left box (a valid dot, link btw x and y), verify that svg is just different. + */ import test_traditions from '../fixtures/test_traditions.json'; import stemweb_algorithms from '../fixtures/stemweb_algorithms.json' +import users from '../fixtures/users.json'; const len_stemweb_algorithms = stemweb_algorithms.length; +const admin = users.filter(({username}) => username === 'admin@example.org')[0]; beforeEach(() => { cy.visit(`${Cypress.env('CY_STEMMAWEB_FRONTEND_URL')}/`); @@ -45,7 +54,7 @@ beforeEach(() => { describe('Stemweb dialog should work properly', () => { it('passes', () => { // click on button "Run Stemweb" should open Stemweb dialog - cy.contains('Run Stemweb').click(); + cy.contains('Run Stemweb').wait(500).click(); cy.get('stemmaweb-dialog .modal-content').as('stemwebmodal'); cy.get('@stemwebmodal').contains('Generate a Stemweb tree').should('be.visible'); @@ -124,6 +133,7 @@ describe('Stemweb dialog should work properly', () => { } }); } + cy.reload(); }); }); @@ -198,3 +208,197 @@ describe('Runs a StemWeb algorithm and fetches results (backend)', () => { }); }); }); + +describe('stemma editor tools and svg work properly', () => { + /* Tests for feature: implemented stemma editor + https://github.com/tla/stemmaweb/pull/188#issue-2133307487 + • Test that svg appears. + • Upon edit, svg and box should be there. + • Upon a change in the left box (a valid dot, link btw x and y), verify that svg is just different. + */ + it('passes', { defaultCommandTimeout: 60000, requestTimeout: 60000, responseTimeout: 60000 }, () => { + const tradition = test_traditions.find(trad => trad.title.startsWith('Florilegium')); + cy.log('tradition.title: ' + tradition.title); + // click on the tradition title within the tradition list + cy.get('#traditions-list').contains(tradition.title).click(); + + // Florilegium has 1 stemma svg at start + // the same number of selector icons should be visible as there are stemmata + cy.get('#stemma-editor-graph-container').find('#stemma-selector').find('svg.indicator-svg').should('have.length', tradition.stemmata.length); + // test that the stemma svg appears + cy.get('#graph').find('svg').should('be.visible').and('have.length', 1); + // no box should be there, at first; + cy.get('#stemma-editor-container').should('not.be.visible'); + + // stemma edit buttons should be visible: edit, add, delete, but not save and cancel + cy.get('edit-stemma-buttons').within( ()=> { + cy.get('a#edit-stemma-button-link').should('be.visible'); + cy.get('a#add-stemma-button-link').should('be.visible'); + cy.get('a#delete-stemma-button-link').should('be.visible'); + cy.get('a#save-stemma-button-link').should('not.exist'); + cy.get('a#cancel-edit-stemma-button-link').should('not.exist'); + }); + // Upon edit, svg and box should be there. + cy.get('a#edit-stemma-button-link').wait(500).click(); + cy.get('#stemma-editor-container').wait(1000).as('editorbox'); + cy.get('@editorbox').should('be.visible'); + cy.get('#graph').find('svg').as('stemmasvg'); + cy.get('@stemmasvg').should('be.visible').and('have.length', 1); + + // save and cancel buttons should be available when editing, but not edit, add, delete + cy.get('edit-stemma-buttons').within( ()=> { + cy.get('a#edit-stemma-button-link').should('not.exist'); + cy.get('a#add-stemma-button-link').should('not.exist'); + cy.get('a#delete-stemma-button-link').should('not.exist'); + cy.get('a#save-stemma-button-link').should('be.visible'); + cy.get('a#cancel-edit-stemma-button-link').should('be.visible'); + }); + + // Upon a change in the left box (a valid dot, link btw x and y), verify that svg is just different. + // count edges should be plus one + + // get the editor box and its content + // remember the content + cy.get('@editorbox').find('textarea#stemma-dot-editor').invoke('val').then(v => { + cy.log('old val: ' + v); + // remember the number of its edges '--' or '->' + // let countedges = (v.match(/->/g) || []).length; // Florilegium + const reltypesym = '->'; // Florilegium is directed + const re = new RegExp(reltypesym, 'g'); + const myArray = v.match(re); + let countedges = (myArray || []).length; + cy.log('count "' + reltypesym + '" edges in editor: ' + countedges); + + // get the graph's svg and remember the number of its nodes and edges + cy.get('div#graph > svg').as('graph-svg'); + cy.get('@graph-svg').find('g.edge').should('have.length', countedges); + + // change the edit box's content + const appendatend = 'TESTNODE [class=extant];\nS -> TESTNODE;\n'; + // by .type() editorbox and svg are updated––but not by .invoke('val', newdotcontent) + cy.get('textarea#stemma-dot-editor').type('{moveToEnd}{leftArrow}' + appendatend).wait(1000); + + // get the graph's svg again and assert the number of its edges to be one more than before + cy.get('div#graph > svg').find('g.edge').should('have.length', countedges+1); // 21 + + // save it -- needs login + // reset v at the end // cy.log('old val: ' + v); + }); + }); +}); + +describe('stemma editing error feedback in message console works properly', () => { + it('passes', () => { // needs login + if (Cypress.env('CY_MODE') === 'headed') { // only log in if headed. dont run this test headless because it needs to be logged in // TODO: also for headless mode + // TODO: when fitted also for healess mode, merge with previous test (partly duplicate) + cy.loginViaUi(admin); // TODO: also for headless mode + + // To do: assert that the message console lists unexpected errors + // when editing a stemma and e.g. removing [class=extant] after one of the nodes, + // it should not be possible to save it, and + // there should appear a message in the console panel saying "Error: BAD REQUEST; Witness [witness name here] not marked as either hypothetical or extant" + + // access stemma dot for editing + let tradition = test_traditions.find(trad => trad.title.startsWith('Notre besoin')); + cy.log('tradition.title: ' + tradition.title); + // click on the tradition title within the tradition list + cy.get('#traditions-list').contains(tradition.title).click(); + + // Notre besoin has 2 stemma svgs at start + // the same number of selector icons should be visible as there are stemmata + cy.get('#stemma-editor-graph-container').find('#stemma-selector').find('svg.indicator-svg').should('have.length', tradition.stemmata.length); + // test that the stemma svg appears + cy.get('#graph').find('svg').should('be.visible').and('have.length', 1); + // no box should be there, at first; + cy.get('#stemma-editor-container').should('not.be.visible'); + + // stemma edit buttons should be visible: edit, add, delete, but not save and cancel + cy.get('edit-stemma-buttons').within( ()=> { + cy.get('a#edit-stemma-button-link').should('be.visible'); + cy.get('a#add-stemma-button-link').should('be.visible'); + cy.get('a#delete-stemma-button-link').should('be.visible'); + cy.get('a#save-stemma-button-link').should('not.exist'); + cy.get('a#cancel-edit-stemma-button-link').should('not.exist'); + }); + // Upon edit, svg and box should be there. + cy.get('a#edit-stemma-button-link').wait(500).click(); + cy.get('#stemma-editor-container').wait(1000).as('editorbox'); + cy.get('@editorbox').should('be.visible'); + cy.get('#graph').find('svg').as('stemmasvg'); + cy.get('@stemmasvg').should('be.visible').and('have.length', 1); + + // save and cancel buttons should be available when editing, but not edit, add, delete + cy.get('edit-stemma-buttons').within( ()=> { + cy.get('a#edit-stemma-button-link').should('not.exist'); + cy.get('a#add-stemma-button-link').should('not.exist'); + cy.get('a#delete-stemma-button-link').should('not.exist'); + cy.get('a#save-stemma-button-link').should('be.visible'); + cy.get('a#cancel-edit-stemma-button-link').should('be.visible'); + }); + + // Upon a change in the left box (a valid dot, link btw x and y), verify that svg is just different. + // count edges should be plus one + + // get the editor box and its content + // remember the content + // get current dot graph and remember it for reset later + cy.get('@editorbox').find('textarea#stemma-dot-editor').invoke('val').then(v => { + cy.log('old val: ' + v); + // remember the number of its edges '--' or '->' + // let countedges = (v.match(/->/g) || []).length; // Florilegium + const reltypesym = '--'; // Notre besoin is undirected + const re = new RegExp(reltypesym, 'g'); + const myArray = v.match(re); + let countedges = (myArray || []).length; + cy.log('count "' + reltypesym + '" edges in editor: ' + countedges); + + // get the graph's svg and remember the number of its nodes and edges + cy.get('div#graph > svg').as('graph-svg'); + cy.get('@graph-svg').find('g.edge').should('have.length', countedges); + + // replace current content with a faulty dot graph + const witness = 'F'; + const faultydot = v.replace('F [class=extant];', witness+';'); + cy.get('textarea#stemma-dot-editor').type('{selectAll}{backspace}' + faultydot).wait(1000); + // attempt to save the faulty stemma + cy.get('a#save-stemma-button-link').wait(500).click(); // needs login + // assert that the error message pops up + // "Error: BAD REQUEST; Witness [witness name here] not marked as either hypothetical or extant" + const msg_err = 'Error: BAD REQUEST; Witness ' + witness + ' not marked as either hypothetical or extant' + cy.get('stemmaweb-alert').contains(msg_err); + // assert that the error is logged in the message console + cy.get('#message-console-text-panel').contains(msg_err); + + // reset the dot graph to the correct content + cy.get('textarea#stemma-dot-editor').type('{selectAll}{backspace}' + v).wait(1000); + // save it + cy.get('a#save-stemma-button-link').wait(500).click(); // needs login + const msg_ok = 'Stemma saved' + // assert that there is a success message as an alert + cy.get('stemmaweb-alert').contains(msg_ok); + // assert that the success is logged in the message console + cy.get('#message-console-text-panel').contains(msg_ok); + // again, stemma edit buttons should be visible: edit, add, delete, but not save and cancel + cy.get('edit-stemma-buttons').within( ()=> { + cy.get('a#edit-stemma-button-link').should('be.visible'); + cy.get('a#add-stemma-button-link').should('be.visible'); + cy.get('a#delete-stemma-button-link').should('be.visible'); + cy.get('a#save-stemma-button-link').should('not.exist'); + cy.get('a#cancel-edit-stemma-button-link').should('not.exist'); + }); + + // assert upon click on another tradition the err and ok messages stay in the message console + tradition = test_traditions.find(trad => trad.title.startsWith('Verbum')); + cy.log('tradition.title: ' + tradition.title); + // click on the tradition title within the tradition list + cy.get('#traditions-list').contains(tradition.title).click(); + cy.get('#message-console-text-panel').contains(msg_err); + cy.get('#message-console-text-panel').contains(msg_ok); + + // Test also the CANCEL button + }); + + cy.logoutViaUi(admin); // TODO: also for headless mode + } + }); +}); diff --git a/frontend-e2e/cypress/fixtures/test_traditions.json b/frontend-e2e/cypress/fixtures/test_traditions.json index 0d7cb6a6..8a7bac59 100644 --- a/frontend-e2e/cypress/fixtures/test_traditions.json +++ b/frontend-e2e/cypress/fixtures/test_traditions.json @@ -1,22 +1,4 @@ [ - { "title" : "Notre besoin", - "filetype" : "stemmaweb", - "owner" : "user@example.org", - "language" : "French", - "access" : "Public", - "sectionscount" : 1, - "sections" : [ - { "name" : "DEFAULT", - "language" : "French" - } - ], - "direction" : "Left to Right", - "witnesses" : ["A", "B", "C", "D", "F", "J", "L", "M", "S", "T1", "T2", "U", "V"], - "stemmata" : [ - "Stemweb stemma", - "Stemweb stemma duplicate" - ] - }, { "title" : "Florilegium \"Coislinianum B\"", "filetype" : "csv", "owner" : "user@example.org", @@ -40,6 +22,21 @@ "stemma of Tomas" ] }, + { "title" : "John verse", + "filetype" : "stemmaweb", + "owner" : "benutzer@example.org", + "language" : "Greek", + "access" : "Public", + "sectionscount" : 1, + "sections" : [ + { "name" : "DEFAULT", + "language" : "Greek" + } + ], + "direction" : "Left to Right", + "witnesses" : ["P60", "P66", "base", "w1", "w11", "w13", "w17", "w19", "w2", "w21", "w211", "w22", "w28", "w290", "w3", "w30", "w32", "w33", "w34", "w36", "w37", "w38", "w39", "w41", "w44", "w45", "w54", "w7"], + "stemmata" : [] + }, { "title" : "Legend's fragment", "filetype" : "stemmaweb", "owner" : "user@example.org", @@ -58,7 +55,39 @@ "witnesses" : ["A", "Ab", "B", "BA", "BL", "BLu", "BS", "BSt", "BU", "Bc", "C", "Dr", "Ef", "F", "G", "Gh", "H", "Ho", "JG", "K", "L", "Li", "M", "MN", "N", "O", "P", "Q", "S", "Sk", "St", "T", "U", "V", "Vg", "X", "Y"], "stemmata" : [] }, - + { "title" : "Notre besoin", + "filetype" : "stemmaweb", + "owner" : "user@example.org", + "language" : "French", + "access" : "Public", + "sectionscount" : 1, + "sections" : [ + { "name" : "DEFAULT", + "language" : "French" + } + ], + "direction" : "Left to Right", + "witnesses" : ["A", "B", "C", "D", "F", "J", "L", "M", "S", "T1", "T2", "U", "V"], + "stemmata" : [ + "Stemweb stemma", + "Stemweb stemma duplicate" + ] + }, + { "title" : "Verbum uncorrected", + "filetype" : "stemmaweb", + "owner" : "admin@example.org", + "language" : "Latin", + "access" : "Private", + "sectionscount" : 1, + "sections" : [ + { "name" : "DEFAULT", + "language" : "Latin" + } + ], + "direction" : "Left to Right", + "witnesses" : ["Ba96", "Er16", "Go325", "Gr314", "Kf133", "Kr185", "Kr299", "Mü11475", "Mü22405", "Mü28315", "MüU151", "Sg524", "Wi3818"], + "stemmata" : [] + }, { "title" : "Ժամանակագրութիւն checked", "filetype" : "graphml", "owner" : "benutzer@example.org", @@ -77,21 +106,6 @@ "RHM 1641561271_0" ] }, - { "title" : "John verse", - "filetype" : "stemmaweb", - "owner" : "benutzer@example.org", - "language" : "Greek", - "access" : "Public", - "sectionscount" : 1, - "sections" : [ - { "name" : "DEFAULT", - "language" : "Greek" - } - ], - "direction" : "Left to Right", - "witnesses" : ["P60", "P66", "base", "w1", "w11", "w13", "w17", "w19", "w2", "w21", "w211", "w22", "w28", "w290", "w3", "w30", "w32", "w33", "w34", "w36", "w37", "w38", "w39", "w41", "w44", "w45", "w54", "w7"], - "stemmata" : [] - }, { "title" : "Arabic snippet", "filetype" : "csv", "owner" : "benutzer@example.org", @@ -106,21 +120,5 @@ "direction" : "Right to Left", "witnesses" : ["A", "B"], "stemmata" : [] - }, - - { "title" : "Verbum uncorrected", - "filetype" : "stemmaweb", - "owner" : "admin@example.org", - "language" : "Latin", - "access" : "Private", - "sectionscount" : 1, - "sections" : [ - { "name" : "DEFAULT", - "language" : "Latin" - } - ], - "direction" : "Left to Right", - "witnesses" : ["Ba96", "Er16", "Go325", "Gr314", "Kf133", "Kr185", "Kr299", "Mü11475", "Mü22405", "Mü28315", "MüU151", "Sg524", "Wi3818"], - "stemmata" : [] } ] diff --git a/frontend-e2e/cypress/fixtures/users.json b/frontend-e2e/cypress/fixtures/users.json new file mode 100644 index 00000000..665b2d37 --- /dev/null +++ b/frontend-e2e/cypress/fixtures/users.json @@ -0,0 +1,14 @@ +[ + { "role" : "admin", + "username" : "admin@example.org", + "password" : "AdminPass" + }, + { "role" : "user", + "username" : "user@example.org", + "password" : "UserPass" + }, + { "role" : "user", + "username" : "benutzer@example.org", + "password" : "BenutzerKW" + } +] diff --git a/frontend-e2e/cypress/support/commands.js b/frontend-e2e/cypress/support/commands.js index 119ab03f..02e81775 100644 --- a/frontend-e2e/cypress/support/commands.js +++ b/frontend-e2e/cypress/support/commands.js @@ -23,3 +23,31 @@ // // -- This will overwrite an existing command -- // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) + +// Login via user interface +// TODO: also for headless mode +Cypress.Commands.add('loginViaUi', (userObj) => { + if (Cypress.env('CY_MODE') === 'headed') { // skip when in headless mode + cy.log("Cypress.env('CY_MODE'): " + Cypress.env('CY_MODE')); + cy.contains('header a', 'Sign in').click(); + cy.get('#loginEmail').wait(500).type(userObj.username, { delay: 50 }); + cy.get('#loginPassword').wait(500).type(userObj.password, { delay: 50 }); + cy.get('button').contains('Sign in').wait(500).click(); + cy.get('#authModal').should('not.be.visible'); + cy.contains('Logged in as ' + userObj.username); + cy.contains('header a', 'Sign out'); + cy.get('header').should('not.contain', 'Sign in'); + cy.log('Signed in as ' + userObj.username + '!'); + } +}); + +// Logout via user interface +// TODO: also for headless mode +Cypress.Commands.add('logoutViaUi', (userObj) => { + if (Cypress.env('CY_MODE') === 'headed') { // skip when in headless mode + cy.log("Cypress.env('CY_MODE'): " + Cypress.env('CY_MODE')); + cy.contains('header a', 'Sign out').click(); + cy.contains('header a', 'Sign in'); + cy.get('header').should('not.contain', 'Sign out'); + } +}); diff --git a/frontend-e2e/env.js b/frontend-e2e/env.js index e73223b3..943d3e06 100644 --- a/frontend-e2e/env.js +++ b/frontend-e2e/env.js @@ -17,7 +17,10 @@ const CY_STEMMAWEB_MIDDLEWARE_URL = process.env.CY_STEMMAWEB_MIDDLEWARE_URL || 'http://localhost:8888/stemmaweb/requests'; +const CY_MODE = process.env.CY_STEMMAWEB_FRONTEND_URL ? 'headless' : 'headed'; + module.exports = { + CY_MODE, CY_STEMMAWEB_FRONTEND_URL, CY_STEMMAWEB_MIDDLEWARE_URL }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f6dc79ba..f8bdea15 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -20,7 +20,7 @@ "devDependencies": { "@types/bootstrap": "^5.2.5", "@types/d3": "^7.4.0", - "@types/d3-graphviz": "^2.6.7", + "@types/d3-graphviz": "^2.6.10", "@types/feather-icons": "^4.7.0", "@types/stemmaweb": "file:types/stemmaweb", "live-server": "^1.2.2", @@ -206,9 +206,9 @@ } }, "node_modules/@types/d3-graphviz": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/@types/d3-graphviz/-/d3-graphviz-2.6.7.tgz", - "integrity": "sha512-dKJjD5HiFvAmC0FL/c70VB1diie8FCpyiCZfxMlf6TwYBqUyFvS4XJt6MoxjIuQTJhKDBGzrIvDOgM8gYMLSVA==", + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/@types/d3-graphviz/-/d3-graphviz-2.6.10.tgz", + "integrity": "sha512-YsCRqNqS8QLlsKtF0FGIz42Z47B0sBIxMMn7L4ZdqZcrdk4foJOEPwwMH50Qe2PuZmSSZcWbdgUnj5W68xK0Qw==", "dev": true, "dependencies": { "@types/d3-selection": "^1", @@ -4699,9 +4699,9 @@ } }, "@types/d3-graphviz": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/@types/d3-graphviz/-/d3-graphviz-2.6.7.tgz", - "integrity": "sha512-dKJjD5HiFvAmC0FL/c70VB1diie8FCpyiCZfxMlf6TwYBqUyFvS4XJt6MoxjIuQTJhKDBGzrIvDOgM8gYMLSVA==", + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/@types/d3-graphviz/-/d3-graphviz-2.6.10.tgz", + "integrity": "sha512-YsCRqNqS8QLlsKtF0FGIz42Z47B0sBIxMMn7L4ZdqZcrdk4foJOEPwwMH50Qe2PuZmSSZcWbdgUnj5W68xK0Qw==", "dev": true, "requires": { "@types/d3-selection": "^1", diff --git a/frontend/package.json b/frontend/package.json index e2878468..8782d623 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -20,7 +20,7 @@ "devDependencies": { "@types/bootstrap": "^5.2.5", "@types/d3": "^7.4.0", - "@types/d3-graphviz": "^2.6.7", + "@types/d3-graphviz": "^2.6.10", "@types/feather-icons": "^4.7.0", "@types/stemmaweb": "file:types/stemmaweb", "live-server": "^1.2.2", diff --git a/frontend/www/index.html b/frontend/www/index.html index 7c75f343..d3986658 100644 --- a/frontend/www/index.html +++ b/frontend/www/index.html @@ -182,10 +182,6 @@ src="./src/js/vendor/d3-graphviz.min.js" type="application/javascript" > - \n \n \n \n \n \n \n\n \n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \r\n\r\n\n\n" + "text": "\n\n \n \n \n Stemmaweb\n \n\n \n \n \n \n\n \n \n\n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n\n \n \n \n \n \n\n \n \n
    \n
    \n \n \n \n\n
    \n \n
    \n\n \n \n
    \n
    \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n\n \n\n \n \n \n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \r\n\r\n\n\n" }, "redirectURL": "", "headersSize": -1,