Most fields are optional. Mandatory fields will be highlighted when generating Codemeta.
codemeta.json:
diff --git a/cypress/integration/basics.js b/cypress/integration/basics.js index 3dafb40..4a20a2d 100644 --- a/cypress/integration/basics.js +++ b/cypress/integration/basics.js @@ -1,243 +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('#generateCodemetaV2').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('#generateCodemetaV2').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('#generateCodemetaV2').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('#generateCodemetaV2').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"'); + cy.get('#errorMessage').should('have.text', '@context must be one of "https://doi.org/10.5063/schema/codemeta-2.0", "https://w3id.org/codemeta/3.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"]'); + cy.get('#errorMessage').should('have.text', '@context must be one of "https://doi.org/10.5063/schema/codemeta-2.0", "https://w3id.org/codemeta/3.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/cypress/integration/persons.js b/cypress/integration/persons.js index e4e0182..14abd9d 100644 --- a/cypress/integration/persons.js +++ b/cypress/integration/persons.js @@ -1,424 +1,424 @@ /** * 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 author/contributor dynamic fieldsets */ "use strict"; describe('Zero author', function() { it('can be exported', function() { cy.get('#name').type('My Test Software'); - cy.get('#generateCodemeta').click(); + cy.get('#generateCodemetaV2').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('can be imported from no list', 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('#author_nb').should('have.value', '0'); cy.get('#author_0').should('not.exist'); cy.get('#author_1').should('not.exist'); }); it('can be imported from empty list', 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", "author": [], })) ); cy.get('#importCodemeta').click(); cy.get('#author_nb').should('have.value', '0'); cy.get('#author_0').should('not.exist'); cy.get('#author_1').should('not.exist'); }); }); describe('One full author', function() { it('can be exported', function() { cy.get('#name').type('My Test Software'); cy.get('#author_nb').should('have.value', '0'); cy.get('#author_0').should('not.exist'); cy.get('#author_1').should('not.exist'); cy.get('#author_1_givenName').should('not.exist'); cy.get('#author_add').click(); cy.get('#author_nb').should('have.value', '1'); cy.get('#author_0').should('not.exist'); cy.get('#author_1').should('exist'); cy.get('#author_2').should('not.exist'); cy.get('#author_1_givenName').should('have.value', ''); cy.get('#author_1_familyName').should('have.value', ''); cy.get('#author_1_email').should('have.value', ''); cy.get('#author_1_id').should('have.value', ''); cy.get('#author_1_affiliation').should('have.value', ''); cy.get('#author_1_givenName').type('Jane'); cy.get('#author_1_familyName').type('Doe'); cy.get('#author_1_email').type('jdoe@example.org'); cy.get('#author_1_id').type('http://example.org/~jdoe'); cy.get('#author_1_affiliation').type('http://example.org/'); - cy.get('#generateCodemeta').click(); + cy.get('#generateCodemetaV2').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", "author": [ { "type": "Person", "id": "http://example.org/~jdoe", "givenName": "Jane", "familyName": "Doe", "email": "jdoe@example.org", "affiliation": { "type": "Organization", "id": "http://example.org/", } } ], }); }); it('can be imported', 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", "author": [ { "@type": "Person", "@id": "http://example.org/~jdoe", "givenName": "Jane", "familyName": "Doe", "email": "jdoe@example.org", "affiliation": { "@type": "Organization", "@id": "http://example.org/", } } ], })) ); cy.get('#importCodemeta').click(); cy.get('#author_nb').should('have.value', '1'); cy.get('#author_0').should('not.exist'); cy.get('#author_1').should('exist'); cy.get('#author_2').should('not.exist'); cy.get('#author_1_givenName').should('have.value', 'Jane'); cy.get('#author_1_familyName').should('have.value', 'Doe'); cy.get('#author_1_email').should('have.value', 'jdoe@example.org'); cy.get('#author_1_id').should('have.value', 'http://example.org/~jdoe'); cy.get('#author_1_affiliation').should('have.value', 'http://example.org/'); }); }); describe('Affiliation id', function() { it('can be exported', function() { cy.get('#name').type('My Test Software'); cy.get('#author_add').click(); cy.get('#author_1_givenName').type('Jane'); cy.get('#author_1_affiliation').type('http://example.org/'); - cy.get('#generateCodemeta').click(); + cy.get('#generateCodemetaV2').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", "author": [ { "type": "Person", "givenName": "Jane", "affiliation": { "type": "Organization", "id": "http://example.org/", } } ], }); }); it('can be imported', 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", "author": [ { "@type": "Person", "@id": "http://example.org/~jdoe", "givenName": "Jane", "familyName": "Doe", "email": "jdoe@example.org", "affiliation": { "@type": "Organization", "@id": "http://example.org/", } } ], })) ); cy.get('#importCodemeta').click(); cy.get('#author_nb').should('have.value', '1'); cy.get('#author_0').should('not.exist'); cy.get('#author_1').should('exist'); cy.get('#author_2').should('not.exist'); cy.get('#author_1_affiliation').should('have.value', 'http://example.org/'); }); }); describe('Affiliation name', function() { it('can be exported', function() { cy.get('#name').type('My Test Software'); cy.get('#author_add').click(); cy.get('#author_1_givenName').type('Jane'); cy.get('#author_1_affiliation').type('Example Org'); - cy.get('#generateCodemeta').click(); + cy.get('#generateCodemetaV2').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", "author": [ { "type": "Person", "givenName": "Jane", "affiliation": { "type": "Organization", "name": "Example Org", } } ], }); }); it('can be imported', 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", "author": [ { "@type": "Person", "@id": "http://example.org/~jdoe", "givenName": "Jane", "familyName": "Doe", "email": "jdoe@example.org", "affiliation": { "@type": "Organization", "name": "Example Org", } } ], })) ); cy.get('#importCodemeta').click(); cy.get('#author_nb').should('have.value', '1'); cy.get('#author_0').should('not.exist'); cy.get('#author_1').should('exist'); cy.get('#author_2').should('not.exist'); cy.get('#author_1_affiliation').should('have.value', 'Example Org'); }); }); describe('Author order change', function() { it('is a noop with a single author', function() { cy.get('#name').type('My Test Software'); cy.get('#author_add').click(); cy.get('#author_1_givenName').type('Jane'); cy.get('#author_1_affiliation').type('Example Org'); cy.get('#author_1_moveToRight').click(); cy.get('#author_1_givenName').should('have.value', 'Jane'); cy.get('#author_1_affiliation').should('have.value', 'Example Org'); cy.get('#author_1_moveToLeft').click(); cy.get('#author_1_givenName').should('have.value', 'Jane'); cy.get('#author_1_affiliation').should('have.value', 'Example Org'); }); it('flips two authors', function() { cy.get('#name').type('My Test Software'); cy.get('#author_add').click(); cy.get('#author_add').click(); cy.get('#author_add').click(); cy.get('#author_1_givenName').type('Jane'); cy.get('#author_1_affiliation').type('Example Org'); cy.get('#author_2_givenName').type('John'); cy.get('#author_2_familyName').type('Doe'); cy.get('#author_3_givenName').type('Alex'); cy.get('#author_1_moveToRight').click(); cy.get('#author_1_givenName').should('have.value', 'John'); cy.get('#author_1_familyName').should('have.value', 'Doe'); cy.get('#author_1_affiliation').should('have.value', ''); cy.get('#author_2_givenName').should('have.value', 'Jane'); cy.get('#author_2_familyName').should('have.value', ''); cy.get('#author_2_affiliation').should('have.value', 'Example Org'); cy.get('#author_3_givenName').should('have.value', 'Alex'); cy.get('#author_3_familyName').should('have.value', ''); cy.get('#author_3_affiliation').should('have.value', ''); }); it('updates generated Codemeta', function() { cy.get('#name').type('My Test Software'); cy.get('#author_add').click(); cy.get('#author_add').click(); cy.get('#author_1_givenName').type('Jane'); cy.get('#author_1_affiliation').type('Example Org'); cy.get('#author_2_givenName').type('John'); cy.get('#author_2_familyName').type('Doe'); - cy.get('#generateCodemeta').click(); + cy.get('#generateCodemetaV2').click(); 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", "author": [ { "type": "Person", "givenName": "Jane", "affiliation": { "type": "Organization", "name": "Example Org", } }, { "type": "Person", "givenName": "John", "familyName": "Doe", }, ], }); cy.get('#author_1_moveToRight').click(); 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", "author": [ { "type": "Person", "givenName": "John", "familyName": "Doe", }, { "type": "Person", "givenName": "Jane", "affiliation": { "type": "Organization", "name": "Example Org", } }, ], }); }); it('wraps around to the right', function() { cy.get('#name').type('My Test Software'); cy.get('#author_add').click(); cy.get('#author_add').click(); cy.get('#author_add').click(); cy.get('#author_1_givenName').type('Jane'); cy.get('#author_1_affiliation').type('Example Org'); cy.get('#author_2_givenName').type('John'); cy.get('#author_2_familyName').type('Doe'); cy.get('#author_3_givenName').type('Alex'); cy.get('#author_1_moveToLeft').click() cy.get('#author_1_givenName').should('have.value', 'Alex'); cy.get('#author_1_familyName').should('have.value', ''); cy.get('#author_1_affiliation').should('have.value', ''); cy.get('#author_2_givenName').should('have.value', 'John'); cy.get('#author_2_familyName').should('have.value', 'Doe'); cy.get('#author_2_affiliation').should('have.value', ''); cy.get('#author_3_givenName').should('have.value', 'Jane'); cy.get('#author_3_familyName').should('have.value', ''); cy.get('#author_3_affiliation').should('have.value', 'Example Org'); }); it('wraps around to the left', function() { cy.get('#name').type('My Test Software'); cy.get('#author_add').click(); cy.get('#author_add').click(); cy.get('#author_add').click(); cy.get('#author_1_givenName').type('Jane'); cy.get('#author_1_affiliation').type('Example Org'); cy.get('#author_2_givenName').type('John'); cy.get('#author_2_familyName').type('Doe'); cy.get('#author_3_givenName').type('Alex'); cy.get('#author_3_moveToRight').click() cy.get('#author_1_givenName').should('have.value', 'Alex'); cy.get('#author_1_familyName').should('have.value', ''); cy.get('#author_1_affiliation').should('have.value', ''); cy.get('#author_2_givenName').should('have.value', 'John'); cy.get('#author_2_familyName').should('have.value', 'Doe'); cy.get('#author_2_affiliation').should('have.value', ''); cy.get('#author_3_givenName').should('have.value', 'Jane'); cy.get('#author_3_familyName').should('have.value', ''); cy.get('#author_3_affiliation').should('have.value', 'Example Org'); }); }) diff --git a/cypress/integration/special_fields.js b/cypress/integration/special_fields.js index 62eb48d..d770e5f 100644 --- a/cypress/integration/special_fields.js +++ b/cypress/integration/special_fields.js @@ -1,90 +1,90 @@ /** * 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 author/contributor dynamic fieldsets */ "use strict"; describe('Funder id', function() { it('can be exported', function() { cy.get('#name').type('My Test Software'); cy.get('#funder').type('http://example.org/'); - cy.get('#generateCodemeta').click(); + cy.get('#generateCodemetaV2').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", "funder": { "type": "Organization", "id": "http://example.org/", }, }); }); it('can be imported', 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", "funder": { "@type": "Organization", "@id": "http://example.org/", }, })) ); cy.get('#importCodemeta').click(); cy.get('#funder').should('have.value', 'http://example.org/'); }); }); describe('Funder name', function() { it('can be exported', function() { cy.get('#name').type('My Test Software'); cy.get('#funder').type('Example Org'); - cy.get('#generateCodemeta').click(); + cy.get('#generateCodemetaV2').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", "funder": { "type": "Organization", "name": "Example Org", } }); }); it('can be imported', 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", "funder": { "@type": "Organization", "name": "Example Org", } })) ); cy.get('#importCodemeta').click(); cy.get('#funder').should('have.value', 'Example Org'); }); }); diff --git a/cypress/integration/validation.js b/cypress/integration/validation.js index eaff87e..2161406 100644 --- a/cypress/integration/validation.js +++ b/cypress/integration/validation.js @@ -1,1026 +1,1026 @@ /** * Copyright (C) 2020-2021 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('Document validation', function() { it('accepts empty document', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", })) ); cy.get('#validateCodemeta').click(); cy.get('#name').should('have.value', ''); cy.get('#errorMessage').should('have.text', ''); }); it('accepts all main fields', 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('#validateCodemeta').click(); cy.get('#name').should('have.value', ''); cy.get('#errorMessage').should('have.text', ''); }); it('accepts anything in non-validated fields', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "programmingLanguage": "foo", })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "programmingLanguage": 21, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "programmingLanguage": {}, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); 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('#validateCodemeta').click(); cy.get('#name').should('have.value', ''); cy.get('#errorMessage').should('have.text', 'Wrong document type: must be "SoftwareSourceCode"/"SoftwareApplication", not "foo"'); }); it('errors on invalid field name', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "foobar": "baz", })) ); cy.get('#validateCodemeta').click(); cy.get('#name').should('have.value', ''); cy.get('#errorMessage').should('have.text', 'Unknown field "foobar".'); }); }); describe('URLs validation', function() { it('accepts valid URL', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "codeRepository": "http://example.org/", })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('accepts empty list of URLs', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "codeRepository": [], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('accepts list of valid URLs', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "codeRepository": ["http://example.org/", "http://example.com/"], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('errors on invalid URL', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "codeRepository": "foo", })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', 'Invalid URL in field "codeRepository": "foo"'); }); it('errors on non-string instead of URL', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "codeRepository": {}, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"codeRepository" must be an URL (or a list of URLs), not: {}'); }); it('errors on list with an invalid URL at the end', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "codeRepository": ["http://example.org/", "foo"], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', 'Invalid URL in field "codeRepository": "foo"'); }); it('errors on list with an invalid URL at the beginning', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "codeRepository": ["http://example.org/", "foo"], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', 'Invalid URL in field "codeRepository": "foo"'); }); it('errors on non-string in URL list', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "codeRepository": ["http://example.org/", {}], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"codeRepository" must be a list of URLs (or a single URL), but it contains: {}'); }); }); describe('Things or URLs validation', function() { it('accepts valid Thing', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "isPartOf": { "@type": "SoftwareApplication", "name": "Example Soft", } })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('accepts valid URL', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "isPartOf": "http://example.org/", })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('accepts empty list of Things', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "isPartOf": [], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('accepts list of Things', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "isPartOf": [ { "@type": "SoftwareApplication", "name": "Example Soft", }, { "@type": "SoftwareApplication", "name": "Test Soft", } ] })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('errors on non-URL string', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "license": "Copyright 2021 Myself", })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"license" must be an URL or a CreativeWork/SoftwareSourceCode/SoftwareApplication object, not: "Copyright 2021 Myself"'); }); it('errors on wrong type', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "isPartOf": 42, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"isPartOf" must be a CreativeWork/SoftwareSourceCode/SoftwareApplication object or URI, not 42'); }); it('errors on non-Thing object', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "isPartOf": {}, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"isPartOf" must be a (list of) CreativeWork/SoftwareSourceCode/SoftwareApplication object(s) or an URI, but is missing a type/@type.'); }); it('errors on list with an invalid Thing at the beginning', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "isPartOf": [ {}, { "@type": "SoftwareApplication", "name": "Example Soft", } ], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"isPartOf" must be a (list of) CreativeWork/SoftwareSourceCode/SoftwareApplication object(s) or an URI, but is missing a type/@type.'); }); it('errors on list with an invalid Thing at the end', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "isPartOf": [ { "@type": "SoftwareApplication", "name": "Example Soft", }, {} ], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"isPartOf" must be a (list of) CreativeWork/SoftwareSourceCode/SoftwareApplication object(s) or an URI, but is missing a type/@type.'); }); }); describe('Texts or URLs validation', function() { it('accepts valid Text', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "applicationCategory": "foo", })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('accepts valid URL', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "applicationCategory": "http://example.org/", })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('accepts empty list of Texts', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "applicationCategory": [], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('accepts list of Texts', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "applicationCategory": ["foo", "bar"], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('errors on non-string instead of Text', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "applicationCategory": {}, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"applicationCategory" must be a text/URL (or a list of texts/URLs), not: {}'); }); it('errors on list with an invalid Text at the beginning', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "applicationCategory": [{}, "foo"], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"applicationCategory" must be a list of texts/URLs (or a single text/URL), but it contains: {}'); }); it('errors on list with an invalid Text at the end', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "applicationCategory": ["foo", {}], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"applicationCategory" must be a list of texts/URLs (or a single text/URL), but it contains: {}'); }); }); describe('Text validation', function() { it('accepts valid Text', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "description": "foo", })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('errors on empty list of Texts', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "description": [], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"description" must be text, not []'); }); it('errors on list of Texts', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "description": ["foo", "bar"], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"description" must be text, not ["foo","bar"]'); }); it('errors on non-string instead of Text', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "description": {}, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"description" must be text, not {}'); }); }); describe('Date validation', function() { it('accepts valid Date', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "dateCreated": "2020-03-18", })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('errors on empty list of Dates', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "dateCreated": [], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"dateCreated" must be a date, not []'); }); it('errors on list of Dates', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "dateCreated": ["2020-03-18", "2020-03-19"], })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"dateCreated" must be a date, not ["2020-03-18","2020-03-19"]'); }); it('errors on non-string instead of Date', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "dateCreated": {}, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"dateCreated" must be a date, not {}'); }); it('errors on non-Date string', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "dateCreated": "foo", })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"dateCreated" must be a date in the format YYYY-MM-DD, not "foo"'); }); }); describe('Person validation', function() { it('accepts URI', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": "http://example.org/~jdoe", })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('accepts valid complete Person', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": { "@type": "Person", "@id": "http://example.org/~jdoe", "url": "http://example.org/~jdoe", "name": "Jane Doe", "givenName": "Jane", "familyName": "Doe", "email": "jdoe@example.org", "affiliation": { "@type": "Organization", "@id": "http://example.org/", } } })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('errors on Person with missing type', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": { }, })) ); cy.get('#validateCodemeta').click(); - cy.get('#errorMessage').should('have.text', '"author" must be a (list of) Person/Organization object(s) or an URI, but is missing a type/@type.'); + cy.get('#errorMessage').should('have.text', '"author" must be a (list of) Role/Person/Organization object(s) or an URI, but is missing a type/@type.'); }); it('errors on Person with wrong type', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": { "type": "SoftwareSourceCode", }, })) ); cy.get('#validateCodemeta').click(); - cy.get('#errorMessage').should('have.text', '"author" type must be a (list of) Person/Organization object(s), not "SoftwareSourceCode"'); + cy.get('#errorMessage').should('have.text', '"author" type must be a (list of) Role/Person/Organization object(s), not "SoftwareSourceCode"'); }); it('errors on Person with unknown field', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": { "type": "Person", "foo": "bar", }, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', 'Unknown field "foo" in "author".'); }); it('errors on Person with invalid field', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": { "type": "Person", "email": 32, }, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"email" must be text, not 32'); }); it('accepts URI in list', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": [ "http://example.org/~jadoe", { "@type": "Person", "@id": "http://example.org/~jodoe", "givenName": "John", "familyName": "Doe", }, ] })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('accepts list of valid Person', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": [ { "@type": "Person", "@id": "http://example.org/~jadoe", "givenName": "Jane", "familyName": "Doe", }, { "@type": "Person", "@id": "http://example.org/~jodoe", "givenName": "John", "familyName": "Doe", }, ] })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('accepts Person with multiple affiliations', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": { "@type": "Person", "@id": "http://example.org/~jdoe", "name": "Jane Doe", "affiliation": [ { "@type": "Organization", "@id": "http://example.org/", }, { "@type": "Organization", "@id": "http://example.com/", }, ] } })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('errors on list with invalid Person at the beginning', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": [ { "givenName": "Jane", "familyName": "Doe", }, { "@type": "Person", "@id": "http://example.org/~jodoe", "name": "John Doe", "givenName": "John", "familyName": "Doe", }, ] })) ); cy.get('#validateCodemeta').click(); - cy.get('#errorMessage').should('have.text', '"author" must be a (list of) Person/Organization object(s) or an URI, but is missing a type/@type.'); + cy.get('#errorMessage').should('have.text', '"author" must be a (list of) Role/Person/Organization object(s) or an URI, but is missing a type/@type.'); }); it('errors on list with invalid Person at the end', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": [ { "@type": "Person", "@id": "http://example.org/~jadoe", "givenName": "Jane", "familyName": "Doe", }, { "givenName": "John", "familyName": "Doe", }, ] })) ); cy.get('#validateCodemeta').click(); - cy.get('#errorMessage').should('have.text', '"author" must be a (list of) Person/Organization object(s) or an URI, but is missing a type/@type.'); + cy.get('#errorMessage').should('have.text', '"author" must be a (list of) Role/Person/Organization object(s) or an URI, but is missing a type/@type.'); }); }); describe('Organization validation', function() { it('accepts valid complete Organization', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": { "@type": "Organization", "@id": "http://example.org/", "url": "https://example.org/", "name": "Example Org", "identifier": "http://example.org/", "address": "Nowhere", } })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('errors on Organization with missing type', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": { }, })) ); cy.get('#validateCodemeta').click(); - cy.get('#errorMessage').should('have.text', '"author" must be a (list of) Person/Organization object(s) or an URI, but is missing a type/@type.'); + cy.get('#errorMessage').should('have.text', '"author" must be a (list of) Role/Person/Organization object(s) or an URI, but is missing a type/@type.'); }); it('errors on Organization with wrong type', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": { "type": "SoftwareSourceCode", }, })) ); cy.get('#validateCodemeta').click(); - cy.get('#errorMessage').should('have.text', '"author" type must be a (list of) Person/Organization object(s), not "SoftwareSourceCode"'); + cy.get('#errorMessage').should('have.text', '"author" type must be a (list of) Role/Person/Organization object(s), not "SoftwareSourceCode"'); }); it('errors on Organization with unknown field', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": { "type": "Organization", "foo": "bar", }, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', 'Unknown field "foo" in "author".'); }); it('errors on Organization with invalid field', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": { "type": "Organization", "email": 32, }, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"email" must be text, not 32'); }); it('accepts list of valid Organization', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": [ { "@type": "Organization", "@id": "http://example.org/", "name": "Example Org", }, { "@type": "Organization", "@id": "http://example.org/~jodoe", "name": "Example Org", }, ] })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('errors on list with invalid Organization at the beginning', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": [ { "name": "Example Org", }, { "@type": "Organization", "name": "Example Org", }, ] })) ); cy.get('#validateCodemeta').click(); - cy.get('#errorMessage').should('have.text', '"author" must be a (list of) Person/Organization object(s) or an URI, but is missing a type/@type.'); + cy.get('#errorMessage').should('have.text', '"author" must be a (list of) Role/Person/Organization object(s) or an URI, but is missing a type/@type.'); }); it('errors on list with invalid Organization at the end', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "author": [ { "@type": "Organization", "name": "Example Org", }, { "name": "Example Org", }, ] })) ); cy.get('#validateCodemeta').click(); - cy.get('#errorMessage').should('have.text', '"author" must be a (list of) Person/Organization object(s) or an URI, but is missing a type/@type.'); + cy.get('#errorMessage').should('have.text', '"author" must be a (list of) Role/Person/Organization object(s) or an URI, but is missing a type/@type.'); }); }); describe('CreativeWork validation', function() { it('accepts valid CreativeWork', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "name": "Small Software", "isPartOf": { "type": "CreativeWork", "name": "Big Creative Work", "author": "http://example.org/~jdoe", "keywords": ["foo", "bar"], } })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', ''); }); it('errors on CreativeWork with missing type', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "isPartOf": { } })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"isPartOf" must be a (list of) CreativeWork/SoftwareSourceCode/SoftwareApplication object(s) or an URI, but is missing a type/@type.'); }); it('errors on CreativeWork with wrong type', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "isPartOf": { "type": "Person", }, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"isPartOf" type must be a (list of) CreativeWork/SoftwareSourceCode/SoftwareApplication object(s), not "Person"'); }); it('errors on CreativeWork with unknown field', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "isPartOf": { "type": "CreativeWork", "foo": "bar", }, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', 'Unknown field "foo" in "isPartOf".'); }); it('errors on CreativeWork with invalid field', function() { cy.get('#codemetaText').then((elem) => elem.text(JSON.stringify({ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "isPartOf": { "type": "CreativeWork", "url": 32, }, })) ); cy.get('#validateCodemeta').click(); cy.get('#errorMessage').should('have.text', '"url" must be an URL (or a list of URLs), not: 32'); }); }); diff --git a/data/contexts/codemeta-3.0.jsonld b/data/contexts/codemeta-3.0.jsonld new file mode 100644 index 0000000..2db7a78 --- /dev/null +++ b/data/contexts/codemeta-3.0.jsonld @@ -0,0 +1,88 @@ +{ + "@context": { + "type": "@type", + "id": "@id", + "schema":"http://schema.org/", + "codemeta": "https://codemeta.github.io/terms/", + "Organization": {"@id": "schema:Organization"}, + "Person": {"@id": "schema:Person"}, + "Review": {"@id": "schema:Review"}, + "Role": {"@id": "schema:Role"}, + "SoftwareSourceCode": {"@id": "schema:SoftwareSourceCode"}, + "SoftwareApplication": {"@id": "schema:SoftwareApplication"}, + "Text": {"@id": "schema:Text"}, + "URL": {"@id": "schema:URL"}, + "address": { "@id": "schema:address"}, + "affiliation": { "@id": "schema:affiliation"}, + "applicationCategory": { "@id": "schema:applicationCategory", "@type": "@id"}, + "applicationSubCategory": { "@id": "schema:applicationSubCategory", "@type": "@id"}, + "citation": { "@id": "schema:citation"}, + "codeRepository": { "@id": "schema:codeRepository", "@type": "@id"}, + "contributor": { "@id": "schema:contributor"}, + "copyrightHolder": { "@id": "schema:copyrightHolder"}, + "copyrightYear": { "@id": "schema:copyrightYear"}, + "dateCreated": {"@id": "schema:dateCreated", "@type": "schema:Date" }, + "dateModified": {"@id": "schema:dateModified", "@type": "schema:Date" }, + "datePublished": {"@id": "schema:datePublished", "@type": "schema:Date" }, + "description": { "@id": "schema:description"}, + "downloadUrl": { "@id": "schema:downloadUrl", "@type": "@id"}, + "email": { "@id": "schema:email"}, + "editor": { "@id": "schema:editor"}, + "encoding": { "@id": "schema:encoding"}, + "endDate": { "@id": "schema:endDate"}, + "familyName": { "@id": "schema:familyName"}, + "fileFormat": { "@id": "schema:fileFormat", "@type": "@id"}, + "fileSize": { "@id": "schema:fileSize"}, + "funder": { "@id": "schema:funder"}, + "givenName": { "@id": "schema:givenName"}, + "hasPart": { "@id": "schema:hasPart" }, + "identifier": { "@id": "schema:identifier", "@type": "@id"}, + "installUrl": { "@id": "schema:installUrl", "@type": "@id"}, + "isAccessibleForFree": { "@id": "schema:isAccessibleForFree"}, + "isPartOf": { "@id": "schema:isPartOf"}, + "keywords": { "@id": "schema:keywords"}, + "license": { "@id": "schema:license", "@type": "@id"}, + "memoryRequirements": { "@id": "schema:memoryRequirements", "@type": "@id"}, + "name": { "@id": "schema:name"}, + "operatingSystem": { "@id": "schema:operatingSystem"}, + "permissions": { "@id": "schema:permissions"}, + "position": { "@id": "schema:position"}, + "processorRequirements": { "@id": "schema:processorRequirements"}, + "producer": { "@id": "schema:producer"}, + "programmingLanguage": { "@id": "schema:programmingLanguage"}, + "provider": { "@id": "schema:provider"}, + "publisher": { "@id": "schema:publisher"}, + "relatedLink": { "@id": "schema:relatedLink", "@type": "@id"}, + "review": { "@id": "schema:review", "@type": "@id" }, + "reviewAspect": { "@id": "schema:reviewAspect" }, + "reviewBody": { "@id": "schema:reviewBody" }, + "releaseNotes": { "@id": "schema:releaseNotes"}, + "roleName": { "@id": "schema:roleName"}, + "runtimePlatform": { "@id": "schema:runtimePlatform"}, + "sameAs": { "@id": "schema:sameAs", "@type": "@id"}, + "softwareHelp": { "@id": "schema:softwareHelp"}, + "softwareRequirements": { "@id": "schema:softwareRequirements", "@type": "@id"}, + "softwareVersion": { "@id": "schema:softwareVersion"}, + "sponsor": { "@id": "schema:sponsor"}, + "startDate": { "@id": "schema:startDate"}, + "storageRequirements": { "@id": "schema:storageRequirements", "@type": "@id"}, + "supportingData": { "@id": "schema:supportingData"}, + "targetProduct": { "@id": "schema:targetProduct"}, + "url": { "@id": "schema:url", "@type": "@id"}, + "version": { "@id": "schema:version"}, + "author": { "@id": "schema:author", "@container": "@list" }, + + "softwareSuggestions": { "@id": "codemeta:softwareSuggestions", "@type": "@id"}, + "continuousIntegration": { "@id": "codemeta:continuousIntegration", "@type": "@id"}, + "buildInstructions": { "@id": "codemeta:buildInstructions", "@type": "@id"}, + "developmentStatus": { "@id": "codemeta:developmentStatus", "@type": "@id"}, + "embargoEndDate": { "@id":"codemeta:embargoEndDate", "@type": "schema:Date" }, + "funding": { "@id": "codemeta:funding" }, + "readme": { "@id":"codemeta:readme", "@type": "@id" }, + "issueTracker": { "@id":"codemeta:issueTracker", "@type": "@id" }, + "referencePublication": { "@id": "codemeta:referencePublication", "@type": "@id"}, + "maintainer": { "@id": "codemeta:maintainer" }, + "hasSourceCode": { "@id": "codemeta:hasSourceCode", "@type": "@id"}, + "isSourceCodeOf": { "@id": "codemeta:isSourceCodeOf", "@type": "@id"} + } +} diff --git a/data/contexts/codemeta-3.0.txt b/data/contexts/codemeta-3.0.txt new file mode 100644 index 0000000..c7a6ac3 --- /dev/null +++ b/data/contexts/codemeta-3.0.txt @@ -0,0 +1 @@ +Matthew B. Jones, Carl Boettiger, Abby Cabunoc Mayes, Arfon Smith, Morane Gruenpeter, Valentin Lorentz, Thomas Morrell, Daniel Garijo, Peter Slaughter, Kyle Niemeyer, Yolanda Gil, Martin Fenner, Krzysztof Nowak, Mark Hahnel, Luke Coy, Alice Allen, Mercè Crosas, Ashley Sands, Neil Chue Hong, Patricia Cruse, Daniel S. Katz, Carole Goble, Bryce Mecum, Alejandra Gonzalez-Beltran, Noam Ross. 2023. CodeMeta: an exchange schema for software metadata. Version 3.0. https://w3id.org/codemeta/v3.0 diff --git a/data/contexts/codemeta-local.jsonld b/data/contexts/codemeta-local.jsonld new file mode 100644 index 0000000..e6a30f8 --- /dev/null +++ b/data/contexts/codemeta-local.jsonld @@ -0,0 +1,92 @@ +{ + "@context": { + "type": "@type", + "id": "@id", + "schema":"http://schema.org/", + "codemeta": "https://codemeta.github.io/terms/", + "Organization": {"@id": "schema:Organization"}, + "Person": {"@id": "schema:Person"}, + "Review": {"@id": "schema:Review"}, + "Role": {"@id": "schema:Role"}, + "SoftwareSourceCode": {"@id": "schema:SoftwareSourceCode"}, + "SoftwareApplication": {"@id": "schema:SoftwareApplication"}, + "Text": {"@id": "schema:Text"}, + "URL": {"@id": "schema:URL"}, + "address": { "@id": "schema:address"}, + "affiliation": { "@id": "schema:affiliation"}, + "applicationCategory": { "@id": "schema:applicationCategory", "@type": "@id"}, + "applicationSubCategory": { "@id": "schema:applicationSubCategory", "@type": "@id"}, + "citation": { "@id": "schema:citation"}, + "codeRepository": { "@id": "schema:codeRepository", "@type": "@id"}, + "contributor": { "@id": "schema:contributor"}, + "copyrightHolder": { "@id": "schema:copyrightHolder"}, + "copyrightYear": { "@id": "schema:copyrightYear"}, + "creator": { "@id": "schema:creator"}, + "dateCreated": {"@id": "schema:dateCreated", "@type": "schema:Date" }, + "dateModified": {"@id": "schema:dateModified", "@type": "schema:Date" }, + "datePublished": {"@id": "schema:datePublished", "@type": "schema:Date" }, + "description": { "@id": "schema:description"}, + "downloadUrl": { "@id": "schema:downloadUrl", "@type": "@id"}, + "email": { "@id": "schema:email"}, + "editor": { "@id": "schema:editor"}, + "encoding": { "@id": "schema:encoding"}, + "endDate": { "@id": "schema:endDate"}, + "familyName": { "@id": "schema:familyName"}, + "fileFormat": { "@id": "schema:fileFormat", "@type": "@id"}, + "fileSize": { "@id": "schema:fileSize"}, + "funder": { "@id": "schema:funder"}, + "givenName": { "@id": "schema:givenName"}, + "hasPart": { "@id": "schema:hasPart" }, + "identifier": { "@id": "schema:identifier", "@type": "@id"}, + "installUrl": { "@id": "schema:installUrl", "@type": "@id"}, + "isAccessibleForFree": { "@id": "schema:isAccessibleForFree"}, + "isPartOf": { "@id": "schema:isPartOf"}, + "keywords": { "@id": "schema:keywords"}, + "license": { "@id": "schema:license", "@type": "@id"}, + "memoryRequirements": { "@id": "schema:memoryRequirements", "@type": "@id"}, + "name": { "@id": "schema:name"}, + "operatingSystem": { "@id": "schema:operatingSystem"}, + "permissions": { "@id": "schema:permissions"}, + "position": { "@id": "schema:position"}, + "processorRequirements": { "@id": "schema:processorRequirements"}, + "producer": { "@id": "schema:producer"}, + "programmingLanguage": { "@id": "schema:programmingLanguage"}, + "provider": { "@id": "schema:provider"}, + "publisher": { "@id": "schema:publisher"}, + "relatedLink": { "@id": "schema:relatedLink", "@type": "@id"}, + "review": { "@id": "schema:review", "@type": "@id" }, + "reviewAspect": { "@id": "schema:reviewAspect" }, + "reviewBody": { "@id": "schema:reviewBody" }, + "releaseNotes": { "@id": "schema:releaseNotes"}, + "roleName": { "@id": "schema:roleName"}, + "runtimePlatform": { "@id": "schema:runtimePlatform"}, + "sameAs": { "@id": "schema:sameAs", "@type": "@id"}, + "softwareHelp": { "@id": "schema:softwareHelp"}, + "softwareRequirements": { "@id": "schema:softwareRequirements", "@type": "@id"}, + "softwareVersion": { "@id": "schema:softwareVersion"}, + "sponsor": { "@id": "schema:sponsor"}, + "startDate": { "@id": "schema:startDate"}, + "storageRequirements": { "@id": "schema:storageRequirements", "@type": "@id"}, + "supportingData": { "@id": "schema:supportingData"}, + "targetProduct": { "@id": "schema:targetProduct"}, + "url": { "@id": "schema:url", "@type": "@id"}, + "version": { "@id": "schema:version"}, + + "author": { "@id": "schema:author", "@container": "@list" }, + + "softwareSuggestions": { "@id": "codemeta:softwareSuggestions", "@type": "@id"}, + "contIntegration": { "@id": "codemeta:contIntegration", "@type": "@id"}, + "continuousIntegration": { "@id": "codemeta:continuousIntegration", "@type": "@id"}, + "buildInstructions": { "@id": "codemeta:buildInstructions", "@type": "@id"}, + "developmentStatus": { "@id": "codemeta:developmentStatus", "@type": "@id"}, + "embargoDate": { "@id":"codemeta:embargoDate", "@type": "schema:Date" }, + "embargoEndDate": { "@id":"codemeta:embargoEndDate", "@type": "schema:Date" }, + "funding": { "@id": "codemeta:funding" }, + "readme": { "@id":"codemeta:readme", "@type": "@id" }, + "issueTracker": { "@id":"codemeta:issueTracker", "@type": "@id" }, + "referencePublication": { "@id": "codemeta:referencePublication", "@type": "@id"}, + "maintainer": { "@id": "codemeta:maintainer" }, + "hasSourceCode": { "@id": "codemeta:hasSourceCode", "@type": "@id"}, + "isSourceCodeOf": { "@id": "codemeta:isSourceCodeOf", "@type": "@id"} + } +} diff --git a/index.html b/index.html index 8be7617..3af9815 100644 --- a/index.html +++ b/index.html @@ -1,367 +1,394 @@
Most fields are optional. Mandatory fields will be highlighted when generating Codemeta.
codemeta.json:
+ + `; 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")); + document.querySelector(`#${personPrefix}_role_add`) + .addEventListener('click', () => addRole(personPrefix)); } 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 addRole(personPrefix) { + const roleButtonGroup = document.querySelector(`#${personPrefix}_role_add`); + const roleIndexNode = document.querySelector(`#${personPrefix}_role_index`); + const roleIndex = parseInt(roleIndexNode.value, 10); + + const ul = document.createElement("ul") + ul.classList.add("role"); + ul.id = `${personPrefix}_role_${roleIndex}`; + + ul.innerHTML = ` +