diff --git a/.gitignore b/.gitignore index f32a8683..c2c5154b 100644 --- a/.gitignore +++ b/.gitignore @@ -111,4 +111,4 @@ sw.* .certs/ test/cypress/videos -test/cypress/downloads \ No newline at end of file +test/cypress/downloads diff --git a/cypress/e2e/datasets.cy.js b/cypress/e2e/datasets.cy.js new file mode 100644 index 00000000..db8575f8 --- /dev/null +++ b/cypress/e2e/datasets.cy.js @@ -0,0 +1,186 @@ +const datasetIds = [127]; + + +datasetIds.forEach(datasetId => { + + describe(`Dataset ${datasetId}`, {testIsolation: false }, function () { + before(function () { + cy.visit(`/datasets/${datasetId}?type=dataset`) + }); + + it("Landing page", function () { + cy.get('.dataset-image').should('have.attr', 'src').and('include', 'https://assets.discover.pennsieve.io/') + // Hover over author + cy.get(':nth-child(2) > .contributor-item').should('be.visible').trigger('mouseenter', { eventConstructor: 'MouseEvent' }) + + //only one visible popover + cy.get('.orcid-popover:visible').should('have.length', 1) + + //Check Get Dataset directs to files tab + cy.contains('.button-container span', 'Get Dataset').click() + cy.get('.nuxt-link-exact-active').should('have.text', ' Files '); + cy.get('[style=""] > .heading2.mb-8').should('have.text', 'Download Dataset').and('be.visible') + //Checkt Cite Dataset direccts to Cite tab + cy.contains('.button-container span', 'Cite Dataset').click() + cy.get('.nuxt-link-exact-active').should('have.text', ' Cite '); + cy.get('.citation-details > .heading2').should('have.text', '\n Dataset Citation\n ').and('be.visible') + cy.get('.dataset-information-box > :nth-child(2) > a').should('have.attr', 'href').and('include', 'doi.org').then((href) => { + cy.request(href).then((resp) => { + expect(resp.status).to.eq(200); + expect(resp.body).to.include(`datasets/${datasetId}/version`); + }) + }); + cy.get(':nth-child(2) > .contributor-list > li > .el-tooltip > .tooltip-item > a').each($el => { + cy.wrap($el).should('have.attr', 'href').and('include', '/data?type='); + }); + cy.get('.dataset-information-box > div').contains('View other versions').click(); + //Check if each link + cy.get('.el-col-push-1 > a').each(($link) => { + cy.wrap($link).should('have.attr', 'href').and('include', 'doi.org').then((href) => { + cy.request(href).then((resp) => { + cy.request(href).its('body').should('include', `/datasets/${datasetId}/version`); + }); + }); + }) + }); + it("Abstract Tab", function () { + cy.contains('#datasetDetailsTabsContainer .style1', ' Abstract ').click(); + cy.get('.nuxt-link-exact-active').should('have.text', ' Abstract '); + cy.get('.dataset-description-info > :nth-child(1) > :nth-child(1) > strong').contains('Study Purpose'); + cy.get('.dataset-description-info > :nth-child(1) > :nth-child(2) > strong').contains('Data Collection'); + cy.get('.dataset-description-info > :nth-child(1) > :nth-child(3) > strong').contains('Primary Conclusion'); + cy.get('.experimental-design-section-text-column').contains('Protocol Links'); + //cy.get('.experimental-design-container .link2').should('have.attr', 'href').and('include', 'https://doi.org/') + //The following regular expression should capture space and letters + cy.get('.dataset-description-info').contains(/Experimental Approach: *(.+)/); + cy.get('.dataset-description-info').contains('Subject Information:'); + cy.get('.dataset-description-info').contains(/Anatomical structure: *(.+)/); + cy.get('.dataset-description-info').contains(/Species: *(.+)/); + cy.get('.dataset-description-info').contains(/Sex: *(.+)/); + cy.get('.dataset-description-info').contains(/Number of samples: *(.+)/); + cy.get('.dataset-description-info').contains(/Keywords: *(.+)/); + cy.contains('.dataset-description-info a', 'Download Metadata file').should('have.attr', 'href').and('include', 'metadata').then((href) => { + cy.request(href).then((resp) => { + expect(resp.status).to.eq(200) + }) + }) + }); + it("About Tab", function () { + cy.contains('#datasetDetailsTabsContainer .style1', ' About ').click(); + cy.get('.nuxt-link-exact-active').should('have.text', ' About '); + cy.get('.dataset-about-info').contains(/Title: *(.+)/); + cy.get('.dataset-about-info').contains(/First Published: *(.+)/); + cy.get('.dataset-about-info').contains(/Last Published: *(.+)/); + cy.get('.dataset-about-info').contains(/Contact Author: *(.+)/); + cy.get('.dataset-about-info').contains(/Award[(]s[)]: (.+)/); + cy.get('.dataset-about-info').contains(/Funding Program[(]s[)]: *(.+)/); + cy.get('.dataset-about-info').contains(/Associated project[(]s[)]: *(.+)/); + cy.get('.dataset-about-info').contains(/Institution[(]s[)]: *(.+)/); + cy.get('.dataset-about-info').contains(/Associated project[(]s[)]: *(.+)/); + cy.get('.dataset-about-info').contains(/Version (.+) Revision (.+): *(.+)/); + cy.get('.dataset-about-info').contains(/Dataset DOI: *(.+)/); + cy.get('.about-section-container > :nth-child(2) > :nth-child(2) > a').should('have.attr', 'href').and('include', 'mailto'); + //Match award link to associated project + cy.get(':nth-child(11) > :nth-child(2) > a').invoke('attr', 'href').then(value => { + cy.get(':nth-child(8) > :nth-child(2) > a').should('have.attr', 'href', value); + }); + //match author to contributors + cy.get('.about-section-container > :nth-child(2) > :nth-child(1)').invoke('text').then(value => { + cy.get('.similar-datasets-container').contains(value); + }) + }); + it("Cite Tab", function () { + cy.contains('#datasetDetailsTabsContainer .style1', ' Cite ').click(); + cy.get('.nuxt-link-exact-active').should('have.text', ' Cite '); + cy.get('.dataset-information-box > :nth-child(2) > a > u').invoke('text').then(value => { + const expectedLink = 'https://citation.crosscite.org/?doi=' + value; + cy.get('.citation-details > p > a').should('have.attr', 'href', expectedLink); + }) + }); + it("Files Tab", function () { + //First check if there is a Files tab + cy.get('#datasetDetailsTabsContainer .style1').then(($tab) => { + if ($tab.text().includes(' Files ')) { + cy.contains('#datasetDetailsTabsContainer .style1', ' Files ').click(); + cy.get('.nuxt-link-exact-active').should('have.text', ' Files '); + cy.get('[style=""] > .heading2.mb-8').should('have.text', 'Download Dataset'); + cy.get('.left-column > :nth-child(1) > div > .label4').should('have.text', 'Option 1 - Direct download: '); + cy.get('.aws-download-column > :nth-child(1) > .label4').should('have.text', 'Option 2 - AWS download: '); + //cy.get('.left-column > :nth-child(1) > a > .el-button > span').should('be.visible'); + cy.get('.left-column .el-button').contains('Download full dataset').should('be.visible'); + //cy.get('.left-column > :nth-child(1) > a > .el-button').should('be.enabled'); + //Find the download file button + cy.contains('.content .body1 .el-table__fixed-body-wrapper .el-table__row', ' dataset_description.xlsx ').should('have.length', 1).as('datasetDescription'); + cy.get('@datasetDescription').find('.el-table_1_column_5').should('have.length', 1).as('icons'); + cy.get('@icons').find('form[id=zipForm]').should('have.length', 1); + //there should be 4 icons, one for each action + cy.get('@icons').find('svg').should('have.length', 4); + //Check get share links + cy.get('@icons').find(':nth-child(4)').click({force: true}); + cy.get('.el-message').should('be.visible'); + //Check oSPARC link + cy.get('@icons').find(':nth-child(3) > .el-tooltip > .svg-icon').click({force: true}); + cy.get('.files-table-table .el-dialog .svg-icon').click(); + } else { + this.skip(); + } + }); + }); + it("Gallery Tab", function () { + cy.contains('#datasetDetailsTabsContainer .style1', ' Gallery ').click(); + cy.get('.content > .full-size').then(($content) => { + //The following call may fail if the wait() is not implemented here + cy.wait(500); + const gallery = $content.find('.gallery-container'); + if (gallery && gallery.length) { + cy.wrap(gallery).find('.sparc-design-system-pagination').as('pagination'); + cy.get('@pagination').find('li.number').should('have.length.least', 1); + cy.wrap(gallery).find('.el-card').should('have.length.least', 1).each($card => { + cy.wrap($card).contains('span', ' View '); + //Need to test newly opened viewers + }); + } else { + cy.wrap($content).contains(' This dataset does not contain gallery items '); + } + }); + }); + it("References Tab", function () { + //First check if reference tab is present + cy.get('#datasetDetailsTabsContainer .style1').then(($tab) => { + if ($tab.text().includes(' References ')) { + cy.contains('#datasetDetailsTabsContainer .style1', ' References ').click(); + cy.get('.nuxt-link-exact-active').should('have.text', ' References '); + cy.get('.dataset-references .heading2').contains('Associated Publications for this Dataset'); + cy.get('.dataset-references .citation-container').each(el => { + cy.wrap(el).find('div > a').should('have.attr', 'href').and('include', 'doi.org'); + cy.wrap(el).find('.copy-button').click(); + cy.get('.el-message').should('be.visible'); + }); + } else { + this.skip(); + } + }); + }); + it("Versions Tab", function () { + //First check if version tab is present + cy.get('#datasetDetailsTabsContainer .style1').then(($tab) => { + if ($tab.text().includes(' Versions ')) { + cy.contains('#datasetDetailsTabsContainer .style1', ' Versions ').click(); + cy.get('.nuxt-link-exact-active').should('have.text', ' Versions '); + cy.get('.table-rows .el-col-push-1 > a').each($el => { + cy.wrap($el).should('have.attr', 'href').and('include', 'doi.org').then((href) => { + cy.request(href).its('body').should('include', `/datasets/${datasetId}/version`); + }) + }); + } + }); + }); + it("Landing page project page", function () { + cy.get('.mt-8 > a > u').click() + cy.get('.subpage').click() + cy.get('.heading2').should('be.visible') + cy.url().should('include', '/projects/') + }); + }); + +}); \ No newline at end of file diff --git a/cypress/e2e/finddata.cy.js b/cypress/e2e/finddata.cy.js new file mode 100644 index 00000000..0f530f19 --- /dev/null +++ b/cypress/e2e/finddata.cy.js @@ -0,0 +1,186 @@ +// const categories = ['dataset'] +const categories = ['dataset', 'model', 'simulation', 'projects'] + +const keywords = ['Spine', 'neck'] + +const singleFacet = 'Male' + +const multipleFacets = ['Human', 'Organ'] + +categories.forEach((category) => { + + describe(`Find Data in ${category}`, { testIsolation: false }, function () { + before(function () { + cy.visit(`/data?type=${category}`) + }) + + it('All Page Features', function () { + // Sort dropdown function testing + // Test whether the sort function can be triggered and text can be shown + cy.get('.label1 > .el-dropdown > .filter-dropdown').then(($dropdown) => { + cy.wrap($dropdown).click() + cy.contains('Z-A').click() + cy.wrap($dropdown).should('contain', 'Z-A') + }) + // Tooltips showup testing + // Test whether content will be displayed + cy.get('[role="tooltip"]').should('not.be.visible') + cy.get('.purple-fill').click() + cy.get('[role="tooltip"]').should('be.visible') + cy.get('[role="tooltip"] > .el-popover__title').should('contain', 'How do filters work?') + cy.get('.label-header > :nth-child(1) > .label-title').then(($label) => { + const tooltipExist = $label.text().includes('Availability') + if (tooltipExist) { + cy.get('.el-tooltip').click() + cy.get('[role="tooltip"]:visible').should('contain', 'SPARC') + } + }) + // Dataset show testing + // Test whether the number of displayed datasets can be changed + cy.get(':nth-child(1) > p > .el-dropdown > .filter-dropdown').click() + cy.get('.el-dropdown-menu > .el-dropdown-menu__item:visible').contains('20').click() + cy.get('.el-table__row').should('have.length', 20) + }) + keywords.forEach((keyword) => { + it(`Keyword Search - ${keyword}`, function () { + cy.get('.el-input__inner').should('have.attr', 'placeholder', 'Enter search criteria') + cy.get('.el-input__inner').clear().type(keyword) + cy.get('.btn-clear-search > .svg-icon').should('be.visible') + cy.get('.search-text').click() + cy.url({ decode: true }).should('contain', keyword) + cy.wait(500) + cy.get(':nth-child(1) > p').then(($p) => { + const noResult = $p.text().includes('\n 0 Results | Showing') + if (noResult) { + cy.get('.el-table__empty-text').should('exist') + } else { + cy.get('.el-table__empty-text').should('not.exist') + cy.get('.table-wrap').then(($table) => { + const keywordExist = $table.text().toLowerCase().includes(keyword.toLowerCase()) + if (keywordExist) { + cy.get('b').contains(new RegExp(keyword, 'i')).should('exist') + } else { + cy.get('b').should('not.exist') + } + }) + } + }) + cy.get('.btn-clear-search > .svg-icon').click() + // *** There are situations that dataset cards do not show the (highlighted) keywords + // *** Just in case this happens for all the displayed dataset cards, extra tests may need to be added + // cy.get('') + }) + }) + it(`Single Faceted Browse Search - ${singleFacet}`, function () { + // let facetCategory + cy.get('.no-facets').should('contain', 'No filters applied') + // Expand all + cy.get('.expand-all-container > .el-link > .el-link--inner').click() + cy.get('.label-content-container').should('be.visible') + cy.get('.label-content-container').should('have.length.above', 0) + if (category !== 'projects') { + // *** This action is used to expand all parent facets in ANATOMICAL STRUCTURE + // *** Avoid error when using child facets as test facets + // *** Need to think of a solution to open the specific parent facet, instead of open all + cy.get('.el-tree-node__expand-icon.el-icon-caret-right:visible').not('.is-leaf').click({ multiple: true }) + } + cy.get('.label-content-container').then(($label) => { + const singleFacetExist = $label.find('span.capitalize:visible').text().toLowerCase().includes(singleFacet.toLowerCase()) + if (singleFacetExist) { + // cy.wrap($label).contains(singleFacet).parents('.sparc-design-system-component-dropdown-multiselect').within(() => { + // cy.get('.label-title').then(($el) => { + // facetCategory = $el.text() + // }) + // }) + const regex = new RegExp(`(^| )${singleFacet}`, 'i') + cy.wrap($label).contains(regex).click() + cy.url({ decode: true }).should('contain', 'selectedFacetIds') + cy.get('.el-card__body > .capitalize').contains(regex).should('have.length', 1) + cy.get(':nth-child(1) > p').then(($p) => { + const noResult = $p.text().includes('\n 0 Results | Showing') + if (noResult) { + cy.get('.el-table__empty-text').should('exist') + } else { + cy.get('.el-table__empty-text').should('not.exist') + cy.get('.table-wrap').then(($table) => { + const facetFoundInCard = $table.text().includes(singleFacet) + if (facetFoundInCard) { + cy.wrap($table).should('contain', singleFacet) + } else { + cy.wrap($table).should('not.contain', singleFacet) + // cy.get(':nth-child(1) > .el-table_1_column_2 > .cell > :nth-child(1) > a').click() + // cy.wait(5000) + // cy.get('.dataset-description-info').contains(singleFacet) + } + }) + } + }) + // Uncheck + cy.get('.el-card__body > .capitalize').contains(regex).should('have.length', 1) + cy.wrap($label).contains(regex).click() + cy.get('.no-facets').should('contain', 'No filters applied') + // Close tag + cy.wrap($label).contains(regex).click() + cy.get('.el-card__body > .capitalize').contains(regex).should('have.length', 1) + cy.get('.el-tag__close').eq(0).click() + cy.get('.no-facets').should('contain', 'No filters applied') + // Reset all + cy.wrap($label).contains(regex).click() + cy.get('.tags-container > .flex > .el-link > .el-link--inner').click() + // *** 'No filters applied' sometimes will not appear after click 'reset all' in Cypress. BUG or Cypress issue? + // cy.get('.no-facets').should('contain', 'No filters applied') + // *** There is a bug with reset all function. + // cy.get('.el-card__body > .capitalize').should('not.exist') + } else { + this.skip() + } + }) + }) + it(`Multiple Faceted Browse Search - ${multipleFacets}`, function () { + cy.get('.expand-all-container > .el-link > .el-link--inner').click() + if (category !== 'projects') { + cy.get('.el-tree-node__expand-icon.el-icon-caret-right:visible').not('.is-leaf').click({ multiple: true }) + } + cy.get('.label-content-container').then(($label) => { + let multipleFacetsExist = true + multipleFacets.forEach((facet) => { + multipleFacetsExist = multipleFacetsExist && $label.find('span.capitalize:visible').text().toLowerCase().includes(facet.toLowerCase()) + }) + if (multipleFacetsExist) { + multipleFacets.forEach((facet) => { + cy.wrap($label).contains(new RegExp(`^${facet}`, 'i')).click() + }) + const multipleRegex = new RegExp(multipleFacets.join('|'), 'i') + cy.get('.el-card__body > .capitalize:visible').should('have.length.above', 1) + cy.get('.el-card__body > .capitalize:visible').contains(multipleRegex).should('exist') + cy.get(':nth-child(1) > p').then(($p) => { + const noResult = $p.text().includes('\n 0 Results | Showing') + if (noResult) { + cy.get('.el-table__empty-text').should('exist') + } else { + cy.get('.el-table__empty-text').should('not.exist') + cy.get('.table-wrap').then(($content) => { + let facetsExistInCard = true + multipleFacets.forEach((facet) => { + facetsExistInCard = facetsExistInCard || $content.text().toLowerCase().includes(facet.toLowerCase()) + }) + if (facetsExistInCard) { + cy.wrap($content).contains(multipleRegex).should('exist') + } else { + cy.wrap($content).contains(multipleRegex).should('not.exist') + } + }) + } + }) + multipleFacets.forEach((facet) => { + cy.get('.el-card__body > .capitalize').contains(new RegExp(` ${facet} `, 'i')).within(() => { + cy.get('.el-tag__close').click() + }) + }) + } else { + this.skip() + } + }) + }) + }) +}) \ No newline at end of file diff --git a/cypress/e2e/homepage.cy.js b/cypress/e2e/homepage.cy.js new file mode 100644 index 00000000..c4c1c4c3 --- /dev/null +++ b/cypress/e2e/homepage.cy.js @@ -0,0 +1,11 @@ +describe('Homepage', () => { + beforeEach(function () { + cy.visit('') + }); + it('Banner', () => { + cy.get('h1').should('contain', 'SPARC') + }) + it('Navigation Bar', () => { + cy.get('.mobile-navigation > :nth-child(1) > :nth-child(1) > a').should('contain', 'Data') + }) +}) diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json new file mode 100644 index 00000000..02e42543 --- /dev/null +++ b/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} diff --git a/cypress/support/commands.js b/cypress/support/commands.js new file mode 100644 index 00000000..b7b3328c --- /dev/null +++ b/cypress/support/commands.js @@ -0,0 +1,43 @@ +/// +// *********************************************** +// This example commands.ts shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add('login', (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) +// +// declare global { +// namespace Cypress { +// interface Chainable { +// login(email: string, password: string): Chainable +// drag(subject: string, options?: Partial): Chainable +// dismiss(subject: string, options?: Partial): Chainable +// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable +// } +// } +// } + +Cypress.on('uncaught:exception', (err, runnable) => { + // returning false here prevents Cypress from + // failing the test + return false +}) \ No newline at end of file diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js new file mode 100644 index 00000000..f80f74f8 --- /dev/null +++ b/cypress/support/e2e.js @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/e2e.ts is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') \ No newline at end of file