diff --git a/cypress/integration/basics.js b/cypress/integration/basics.js index 613742b..3fbc7f6 100644 --- a/cypress/integration/basics.js +++ b/cypress/integration/basics.js @@ -1,220 +1,243 @@ /** * Copyright (C) 2020 The Software Heritage developers * See the AUTHORS file at the top-level directory of this distribution * License: GNU Affero General Public License version 3, or any later version * See top-level LICENSE file for more information */ /* * Tests the basic features of the application. */ "use strict"; describe('JSON Generation', function() { beforeEach(function() { /* Clear the session storage, as it is used to restore field data; * and we don't want a test to load data from the previous test. */ cy.window().then((win) => { win.sessionStorage.clear() }) cy.visit('./index.html'); }); it('works just from the software name', function() { cy.get('#name').type('My Test Software'); cy.get('#generateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); cy.get('#codemetaText').then((elem) => JSON.parse(elem.text())) .should('deep.equal', { "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "name": "My Test Software", }); }); it('works just from all main fields when using only one license', function() { cy.get('#name').type('My Test Software'); cy.get('#description').type('This is a\ngreat piece of software'); cy.get('#dateCreated').type('2019-10-02'); cy.get('#datePublished').type('2020-01-01'); cy.get('#license').type('AGPL-3.0'); cy.get("#license").type('{enter}'); cy.get('#generateCodemeta').click(); cy.get("#license").should('have.value', ''); cy.get('#errorMessage').should('have.text', ''); cy.get('#codemetaText').then((elem) => JSON.parse(elem.text())) .should('deep.equal', { "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "license": "https://spdx.org/licenses/AGPL-3.0", "dateCreated": "2019-10-02", "datePublished": "2020-01-01", "name": "My Test Software", "description": "This is a\ngreat piece of software", }); }); it('works just from all main fields when using multiple licenses', function() { cy.get('#name').type('My Test Software'); cy.get('#description').type('This is a\ngreat piece of software'); cy.get('#dateCreated').type('2019-10-02'); cy.get('#datePublished').type('2020-01-01'); cy.get('#license').type('AGPL-3.0'); cy.get("#license").type('{enter}'); cy.get('#license').type('MIT'); cy.get("#license").type('{enter}'); cy.get('#generateCodemeta').click(); cy.get("#license").should('have.value', ''); cy.get('#errorMessage').should('have.text', ''); cy.get('#codemetaText').then((elem) => JSON.parse(elem.text())) .should('deep.equal', { "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "license": ["https://spdx.org/licenses/AGPL-3.0", "https://spdx.org/licenses/MIT"], "dateCreated": "2019-10-02", "datePublished": "2020-01-01", "name": "My Test Software", "description": "This is a\ngreat piece of software", }); }); + + it('works when choosing licenses without the keyboard', function() { + cy.get('#name').type('My Test Software'); + cy.get('#description').type('This is a\ngreat piece of software'); + cy.get('#dateCreated').type('2019-10-02'); + cy.get('#datePublished').type('2020-01-01'); + cy.get('#license').type('AGPL-3.0'); + // no cy.get("#license").type('{enter}'); here + cy.get('#generateCodemeta').click(); + + cy.get("#license").should('have.value', ''); + cy.get('#errorMessage').should('have.text', ''); + cy.get('#codemetaText').then((elem) => JSON.parse(elem.text())) + .should('deep.equal', { + "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@type": "SoftwareSourceCode", + "license": "https://spdx.org/licenses/AGPL-3.0", + "dateCreated": "2019-10-02", + "datePublished": "2020-01-01", + "name": "My Test Software", + "description": "This is a\ngreat piece of software", + }); + }); }); describe('JSON Import', function() { it('works just from the software name', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "name": "My Test Software", })) ); cy.get('#importCodemeta').click(); cy.get('#name').should('have.value', 'My Test Software'); }); it('works just from all main fields when using license as string', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "license": "https://spdx.org/licenses/AGPL-3.0", "dateCreated": "2019-10-02", "datePublished": "2020-01-01", "name": "My Test Software", "description": "This is a\ngreat piece of software", })) ); cy.get('#importCodemeta').click(); cy.get('#name').should('have.value', 'My Test Software'); cy.get('#description').should('have.value', 'This is a\ngreat piece of software'); cy.get('#dateCreated').should('have.value', '2019-10-02'); cy.get('#datePublished').should('have.value', '2020-01-01'); cy.get('#license').should('have.value', ''); cy.get("#selected-licenses").children().should('have.length', 1); cy.get("#selected-licenses").children().first().children().first().should('have.text', 'AGPL-3.0'); }); it('works just from all main fields when using license as array', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "license": ["https://spdx.org/licenses/AGPL-3.0", "https://spdx.org/licenses/MIT"], "dateCreated": "2019-10-02", "datePublished": "2020-01-01", "name": "My Test Software", "description": "This is a\ngreat piece of software", })) ); cy.get('#importCodemeta').click(); cy.get('#name').should('have.value', 'My Test Software'); cy.get('#description').should('have.value', 'This is a\ngreat piece of software'); cy.get('#dateCreated').should('have.value', '2019-10-02'); cy.get('#datePublished').should('have.value', '2020-01-01'); cy.get('#license').should('have.value', ''); cy.get("#selected-licenses").children().should('have.length', 2); cy.get("#selected-licenses").children().eq(0).children().first().should('have.text', 'AGPL-3.0'); cy.get("#selected-licenses").children().eq(1).children().first().should('have.text', 'MIT'); }); it('errors on invalid type', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "foo", "name": "My Test Software", })) ); cy.get('#importCodemeta').click(); // Should still be imported as much as possible cy.get('#name').should('have.value', 'My Test Software'); // But must display an error cy.get('#errorMessage').should('have.text', 'Wrong document type: must be "SoftwareSourceCode"/"SoftwareApplication", not "foo"'); }); it('allows singleton array as context', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": ["https://doi.org/10.5063/schema/codemeta-2.0"], "@type": "SoftwareSourceCode", "name": "My Test Software", })) ); cy.get('#importCodemeta').click(); cy.get('#name').should('have.value', 'My Test Software'); }); it('errors on invalid context URL', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-100000", "@type": "SoftwareSourceCode", "name": "My Test Software", })) ); cy.get('#importCodemeta').click(); cy.get('#errorMessage').should('have.text', '@context must be "https://doi.org/10.5063/schema/codemeta-2.0", not "https://doi.org/10.5063/schema/codemeta-100000"'); }); it('errors on invalid context URL in array', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": ["https://doi.org/10.5063/schema/codemeta-100000"], "@type": "SoftwareSourceCode", "name": "My Test Software", })) ); cy.get('#importCodemeta').click(); cy.get('#errorMessage').should('have.text', '@context must be "https://doi.org/10.5063/schema/codemeta-2.0", not ["https://doi.org/10.5063/schema/codemeta-100000"]'); }); it('errors nicely when there are other contexts', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": [ "https://doi.org/10.5063/schema/codemeta-2.0", "https://schema.org/", ], "@type": "SoftwareSourceCode", "name": "My Test Software", })) ); cy.get('#importCodemeta').click(); cy.get('#errorMessage').should('have.text', 'Multiple values in @context are not supported (@context should be "https://doi.org/10.5063/schema/codemeta-2.0", not ["https://doi.org/10.5063/schema/codemeta-2.0","https://schema.org/"])'); }); }); diff --git a/js/dynamic_form.js b/js/dynamic_form.js index 6ffcbeb..5af7c46 100644 --- a/js/dynamic_form.js +++ b/js/dynamic_form.js @@ -1,188 +1,188 @@ /** * Copyright (C) 2019 The Software Heritage developers * See the AUTHORS file at the top-level directory of this distribution * License: GNU Affero General Public License version 3, or any later version * See top-level LICENSE file for more information */ "use strict"; // List of all HTML fields in a Person fieldset. const personFields = [ 'givenName', 'familyName', 'email', 'id', 'affiliation', ]; function createPersonFieldset(personPrefix, legend) { // Creates a fieldset containing inputs for informations about a person var fieldset = document.createElement("fieldset") var moveButtons; fieldset.classList.add("person"); fieldset.classList.add("leafFieldset"); fieldset.id = personPrefix; fieldset.innerHTML = ` ${legend}

`; return fieldset; } function addPersonWithId(container, prefix, legend, id) { var personPrefix = `${prefix}_${id}`; var fieldset = createPersonFieldset(personPrefix, `${legend} #${id}`); container.appendChild(fieldset); document.querySelector(`#${personPrefix}_moveToLeft`) .addEventListener('click', () => movePerson(prefix, id, "left")); document.querySelector(`#${personPrefix}_moveToRight`) .addEventListener('click', () => movePerson(prefix, id, "right")); } function movePerson(prefix, id1, direction) { var nbPersons = getNbPersons(prefix); var id2; // Computer id2, the id of the person to flip id1 with (wraps around the // end of the list of persons) if (direction == "left") { id2 = id1 - 1; if (id2 <= 0) { id2 = nbPersons; } } else { id2 = id1 + 1; if (id2 > nbPersons) { id2 = 1; } } // Flip the field values, one by one personFields.forEach((fieldName) => { var field1 = document.querySelector(`#${prefix}_${id1}_${fieldName}`); var field2 = document.querySelector(`#${prefix}_${id2}_${fieldName}`); var value1 = field1.value; var value2 = field2.value; field2.value = value1; field1.value = value2; }); // Form was changed; regenerate generateCodemeta(); } function addPerson(prefix, legend) { var container = document.querySelector(`#${prefix}_container`); var personId = getNbPersons(prefix) + 1; addPersonWithId(container, prefix, legend, personId); setNbPersons(prefix, personId); return personId; } function removePerson(prefix) { var personId = getNbPersons(prefix); document.querySelector(`#${prefix}_${personId}`).remove(); setNbPersons(prefix, personId - 1); } // Initialize a group of persons (authors, contributors) on page load. // Useful if the page is reloaded. function initPersons(prefix, legend) { var nbPersons = getNbPersons(prefix); var personContainer = document.querySelector(`#${prefix}_container`) for (let personId = 1; personId <= nbPersons; personId++) { addPersonWithId(personContainer, prefix, legend, personId); } } function removePersons(prefix) { var nbPersons = getNbPersons(prefix); var personContainer = document.querySelector(`#${prefix}_container`) for (let personId = 1; personId <= nbPersons; personId++) { removePerson(prefix) } } function resetForm() { removePersons('author'); removePersons('contributor'); // Reset the list of selected licenses document.getElementById("selected-licenses").innerHTML = ''; // Reset the form after deleting elements, so nbPersons doesn't get // reset before it's read. document.querySelector('#inputForm').reset(); } function fieldToLower(event) { event.target.value = event.target.value.toLowerCase(); } function initCallbacks() { document.querySelector('#license') - .addEventListener('keyup', validateLicense); + .addEventListener('change', validateLicense); document.querySelector('#generateCodemeta') .addEventListener('click', generateCodemeta); document.querySelector('#resetForm') .addEventListener('click', resetForm); document.querySelector('#validateCodemeta') .addEventListener('click', () => parseAndValidateCodemeta(true)); document.querySelector('#importCodemeta') .addEventListener('click', importCodemeta); document.querySelector('#inputForm') .addEventListener('change', generateCodemeta); document.querySelector('#developmentStatus') .addEventListener('change', fieldToLower); initPersons('author', 'Author'); initPersons('contributor', 'Contributor'); }