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