diff --git a/cypress/e2e/ui-tests/test-deploy-app.cy.js b/cypress/e2e/ui-tests/test-deploy-app.cy.js index 040762fc..cc82ca63 100644 --- a/cypress/e2e/ui-tests/test-deploy-app.cy.js +++ b/cypress/e2e/ui-tests/test-deploy-app.cy.js @@ -65,11 +65,11 @@ describe("Test deploying app", () => { it("can deploy a project and public app using the custom app chart", { defaultCommandTimeout: defaultCmdTimeoutMs }, () => { // Names of objects to create const project_name = "e2e-deploy-app-test" - const app_name_project = "e2e-streamlit-example-project" - const app_name_public = "e2e-streamlit-example-public" - const app_name_public_2 = "e2e-streamlit-example-2-public" - const app_description = "e2e-streamlit-description" - const app_description_2 = "e2e-streamlit-2-description" + const app_name_project = "e2e-custom-example-project" + const app_name_public = "e2e-custom-example-public" + const app_name_public_2 = "e2e-custom-example-2-public" + const app_description = "e2e-custom-description" + const app_description_2 = "e2e-custom-2-description" const image_name = "ghcr.io/scilifelabdatacentre/example-streamlit:latest" const image_name_2 = "ghcr.io/scilifelabdatacentre/example-streamlit:230921-1443" const image_port = "8501" @@ -470,6 +470,132 @@ describe("Test deploying app", () => { } }) + it("can deploy a gradio app", { defaultCommandTimeout: defaultCmdTimeoutMs }, () => { + // Simple test to create and delete a Gradio app + // Names of objects to create + const project_name = "e2e-deploy-app-test" + const app_name = "e2e-gradio-example" + const app_description = "e2e-gradio-description" + const source_code_url = "https://doi.org/example" + const image_name = "ghcr.io/scilifelabdatacentre/gradio-flower-classification:20241118-174426" + const image_port = "7860" + const createResources = Cypress.env('create_resources'); + const app_type = "Gradio App" + + if (createResources === true) { + // Create Gradio app + cy.logf("Creating a gradio app", Cypress.currentTest) + cy.visit("/projects/") + cy.contains('.card-title', project_name).parents('.card-body').siblings('.card-footer').find('a:contains("Open")').first().click() + cy.get('div.card-body:contains("' + app_type + '")').find('a:contains("Create")').click() + cy.get('#id_name').type(app_name) + cy.get('#id_description').type(app_description) + cy.get('#id_access').select('Public') + cy.get('#id_source_code_url').type(source_code_url) + cy.get('#id_image').clear().type(image_name) + cy.get('#id_port').clear().type(image_port) + cy.get('#submit-id-submit').contains('Submit').click() + // Back on project page + cy.url().should("not.include", "/apps/settings") + cy.get('h3').should('have.text', project_name); + // check that the app was created + verifyAppStatus(app_name, "Running", "public") + + // Verify Gradio app values + cy.logf("Checking that all dash app settings were saved", Cypress.currentTest) + cy.visit("/projects/") + cy.contains('.card-title', project_name).parents('.card-body').siblings('.card-footer').find('a:contains("Open")').first().click() + cy.get('tr:contains("' + app_name + '")').find('i.bi-three-dots-vertical').click() + cy.get('tr:contains("' + app_name + '")').find('a').contains('Settings').click() + cy.get('#id_name').should('have.value', app_name) + cy.get('#id_description').should('have.value', app_description) + cy.get('#id_access').find(':selected').should('contain', 'Public') + cy.get('#id_image').should('have.value', image_name) + cy.get('#id_port').should('have.value', image_port) + + // Delete the Gradio app + cy.logf("Deleting the gradio app", Cypress.currentTest) + cy.visit("/projects/") + cy.contains('.card-title', project_name).parents('.card-body').siblings('.card-footer').find('a:contains("Open")').first().click() + cy.get('tr:contains("' + app_name + '")').find('i.bi-three-dots-vertical').click() + cy.get('tr:contains("' + app_name + '")').find('a.confirm-delete').click() + cy.get('button').contains('Delete').click() + verifyAppStatus(app_name, "Deleted", "") + + // check that the app is not visible under public apps + cy.visit('/apps/') + cy.get("title").should("have.text", "Apps and models | SciLifeLab Serve (beta)") + cy.get('h3').should('contain', 'Public applications and models') + cy.contains('h5.card-title', app_name).should('not.exist') + + } else { + cy.logf('Skipped because create_resources is not true', Cypress.currentTest); + } + }) + + it("can deploy a streamlit app", { defaultCommandTimeout: defaultCmdTimeoutMs }, () => { + // Simple test to create and delete a Streamlit app + // Names of objects to create + const project_name = "e2e-deploy-app-test" + const app_name = "e2e-streamlit-example" + const app_description = "e2e-streamlit-description" + const source_code_url = "https://doi.org/example" + const image_name = "ghcr.io/scilifelabdatacentre/streamlit-image-to-smiles:20241112-183549" + const image_port = "8501" + const createResources = Cypress.env('create_resources'); + const app_type = "Streamlit App" + + if (createResources === true) { + // Create Streamlit app + cy.logf("Creating a streamlit app", Cypress.currentTest) + cy.visit("/projects/") + cy.contains('.card-title', project_name).parents('.card-body').siblings('.card-footer').find('a:contains("Open")').first().click() + cy.get('div.card-body:contains("' + app_type + '")').find('a:contains("Create")').click() + cy.get('#id_name').type(app_name) + cy.get('#id_description').type(app_description) + cy.get('#id_access').select('Public') + cy.get('#id_source_code_url').type(source_code_url) + cy.get('#id_image').clear().type(image_name) + cy.get('#id_port').clear().type(image_port) + cy.get('#submit-id-submit').contains('Submit').click() + // Back on project page + cy.url().should("not.include", "/apps/settings") + cy.get('h3').should('have.text', project_name); + // check that the app was created + verifyAppStatus(app_name, "Running", "public") + + // Verify Streamlit app values + cy.logf("Checking that all dash app settings were saved", Cypress.currentTest) + cy.visit("/projects/") + cy.contains('.card-title', project_name).parents('.card-body').siblings('.card-footer').find('a:contains("Open")').first().click() + cy.get('tr:contains("' + app_name + '")').find('i.bi-three-dots-vertical').click() + cy.get('tr:contains("' + app_name + '")').find('a').contains('Settings').click() + cy.get('#id_name').should('have.value', app_name) + cy.get('#id_description').should('have.value', app_description) + cy.get('#id_access').find(':selected').should('contain', 'Public') + cy.get('#id_image').should('have.value', image_name) + cy.get('#id_port').should('have.value', image_port) + + // Delete the Streamlit app + cy.logf("Deleting the dash app", Cypress.currentTest) + cy.visit("/projects/") + cy.contains('.card-title', project_name).parents('.card-body').siblings('.card-footer').find('a:contains("Open")').first().click() + cy.get('tr:contains("' + app_name + '")').find('i.bi-three-dots-vertical').click() + cy.get('tr:contains("' + app_name + '")').find('a.confirm-delete').click() + cy.get('button').contains('Delete').click() + verifyAppStatus(app_name, "Deleted", "") + + // check that the app is not visible under public apps + cy.visit('/apps/') + cy.get("title").should("have.text", "Apps and models | SciLifeLab Serve (beta)") + cy.get('h3').should('contain', 'Public applications and models') + cy.contains('h5.card-title', app_name).should('not.exist') + + } else { + cy.logf('Skipped because create_resources is not true', Cypress.currentTest); + } + }) + it("can modify app settings resulting in NO k8s redeployment shows correct app status", { defaultCommandTimeout: defaultCmdTimeoutMs }, () => { // An advanced test to verify user can modify app settings such as the name and description // Names of objects to create diff --git a/cypress/e2e/ui-tests/test-project-as-contributor.cy.js b/cypress/e2e/ui-tests/test-project-as-contributor.cy.js index c6c53550..efebcb47 100644 --- a/cypress/e2e/ui-tests/test-project-as-contributor.cy.js +++ b/cypress/e2e/ui-tests/test-project-as-contributor.cy.js @@ -102,6 +102,24 @@ describe("Test project contributor user functionality", () => { cy.contains('.card-title', project_name).parents('.card-body').siblings('.card-footer').find('a:contains("Open")').first().click() cy.get('.card-text').should('contain', project_description_2) + cy.logf("Check that creating another project with same existing project name will create an error", Cypress.currentTest) + cy.visit("/projects/") + cy.get("a").contains('New project').click() + cy.get("a").contains('Create').first().click() + cy.get('input[name=name]').type(project_name) // same name used before + cy.get('textarea[name=description]').type(project_description) + cy.get("input[name=save]").contains('Create project').click() // should generate an error + // Check that the error message is displayed + cy.get('#flash-msg') + .should('be.visible') + .and('have.class', 'alert-danger') + .and('contain.text', `Project cannot be created because a project with name '${project_name}' already exists.`); + cy.logf("Error is successfully generated when trying to create a new project with the same existing project name", Cypress.currentTest) + + // go back to the previously created project + cy.visit("/projects/") + cy.contains('.card-title', project_name).parents('.card-body').siblings('.card-footer').find('a.btn').contains('Open').click() + cy.logf("Delete the project from the settings menu", Cypress.currentTest) cy.get('[data-cy="settings"]').click() cy.get('a').contains("Delete").click() @@ -117,85 +135,6 @@ describe("Test project contributor user functionality", () => { }) }) - // This test cannot run properly in GitHub workflows because there is an issue with minio creation there. Therefore, it should be run locally to make sure things work. For GitHub, skipping it. - - // TODO: When models are launched, make sure that this test is activated - it.skip("can create a new project with ML serving template, open settings, delete from settings", { defaultCommandTimeout: defaultCmdTimeoutMs }, () => { - - // Names of objects to create - const project_name = "e2e-create-ml-proj-test" - const project_title_name = project_name + " | SciLifeLab Serve (beta)" - - cy.visit("/projects/") - cy.get("title").should("have.text", "My projects | SciLifeLab Serve (beta)") - - // Click button for UI to create a new project - cy.get("a").contains('New project').click() - cy.url().should("include", "projects/templates") - cy.get('h3').should('contain', 'New project') - - // Next click button to create a new blank project - cy.get(".card-footer").last().contains("Create").click() - cy.url().should("include", "projects/create/?template=") - cy.get('h3').should('contain', 'New project') - - // Fill in the options for creating a new blank project - cy.get('input[name=name]').type(project_name) - cy.get('textarea[name=description]').type("A test project created by an e2e test.") - cy.get("input[name=save]").contains('Create project').click() - cy.wait(5000) // sometimes it takes a while to create a project - .then((href) => { - cy.logf(href, Cypress.currentTest) - cy.reload() - cy.get("title").should("have.text", project_title_name) - cy.get('h3').should('contain', project_name) - - // Check that the correct deployment options are available - cy.get('.card-header').find('h5').should('contain', 'Develop') - cy.get('.card-header').find('h5').should('contain', 'Serve') - cy.get('.card-header').find('h5').should('contain', 'Models') - cy.get('.card-header').find('h5').should('not.contain', 'Additional options [admins only]') - - // Section Models - Machine Learning Models - // Navigate to the create models view and cancel back again - cy.get("div#models").first("h5").should("contain", "Machine Learning Models") - cy.get("div#models").find("a.btn").click() - .then((href) => { - cy.url().should("include", "models/create") - cy.get('h3').should("contain", "Create Model Object") - cy.get("button").contains("Cancel").click() - .then((href) => { - cy.get('h3').should("contain", project_name) - }) - }) - - // Check that project settings are available - cy.get('[data-cy="settings"]').click() - cy.url().should("include", "settings") - cy.get('h3').should('contain', 'Project settings') - - // Check that the correct project settings are visible (i.e. no extra settings) - cy.get('.list-group').find('a').should('contain', 'Access') - cy.get('.list-group').find('a').should('not.contain', 'S3 storage') - cy.get('.list-group').find('a').should('not.contain', 'MLFlow') - cy.get('.list-group').find('a').should('not.contain', 'Flavors') - cy.get('.list-group').find('a').should('not.contain', 'Environments') - - // Delete the project from the settings menu - cy.get('a').contains("Delete").click() - .then((href) => { - cy.get('div#delete').should('have.css', 'display', 'block') - cy.get('#id_delete_button').parent().parent().find('button').contains('Delete').click() - .then((href) => { - cy.get('div#deleteModal').should('have.css', 'display', 'block') - cy.get('div#deleteModal').find('button').contains('Confirm').click() - }) - cy.contains(project_name).should('not.exist') - - }) - }) - }) - it("can delete a project from projects overview", { defaultCommandTimeout: defaultCmdTimeoutMs }, () => { // Names of objects to create diff --git a/cypress/e2e/ui-tests/test-superuser-functionality.cy.js b/cypress/e2e/ui-tests/test-superuser-functionality.cy.js index a30a6170..e4bb0a11 100644 --- a/cypress/e2e/ui-tests/test-superuser-functionality.cy.js +++ b/cypress/e2e/ui-tests/test-superuser-functionality.cy.js @@ -45,6 +45,7 @@ describe("Test superuser access", () => { // Names of objects to create const project_name = "e2e-create-default-proj-test" const project_description = "A test project created by an e2e test." + const project_description_duplicate = "A test project with an existing project name" const project_description_2 = "An alternative project description created by an e2e test." cy.visit("/projects/") @@ -65,12 +66,10 @@ describe("Test superuser access", () => { cy.get('input[name=name]').type(project_name) cy.get('textarea[name=description]').type(project_description) cy.get("input[name=save]").contains('Create project').click() - //cy.wait(5000) // sometimes it takes a while to create a project. Not needed because of cypress retryability. cy.get('h3', {timeout: longCmdTimeoutMs}).should('contain', project_name) cy.get('.card-text').should('contain', project_description) - cy.logf("Checking that project settings are available", Cypress.currentTest) cy.get('[data-cy="settings"]').click() cy.url().should("include", "settings") @@ -88,6 +87,32 @@ describe("Test superuser access", () => { cy.contains('.card-title', project_name).parents('.card-body').siblings('.card-footer').find('a:contains("Open")').first().click() cy.get('.card-text').should('contain', project_description_2) + cy.logf("Check that creating another project with same existing project name will work for a superuser", Cypress.currentTest) + cy.visit("/projects/") + cy.get("a").contains('New project').click() + cy.get("a").contains('Create').first().click() + cy.get('input[name=name]').type(project_name) // this name already exists + cy.get('textarea[name=description]').type(project_description_duplicate) // this will be used to ensure to delete it + cy.get("input[name=save]").contains('Create project').click() + cy.get('h3', {timeout: longCmdTimeoutMs}).should('contain', project_name) + cy.get('.card-text').should('contain', project_description_duplicate) // checking that project creation succeeded + // deleting the project with the duplicate name + cy.get('[data-cy="settings"]').click() + cy.get('a').contains("Delete").click() + .then((href) => { + cy.get('div#delete').should('have.css', 'display', 'block') + cy.get('#id_delete_button').parent().parent().find('button').contains('Delete').click() + .then((href) => { + cy.get('div#deleteModal').should('have.css', 'display', 'block') + cy.get('div#deleteModal').find('button').contains('Confirm').click() + }) + // checking that the project with the duplicate name has been deleted + cy.visit("/projects/") + cy.contains(project_description_duplicate).should('not.exist') + }) + // going to the previously created project's page + cy.contains('.card-title', project_name).parents('.card-body').siblings('.card-footer').find('a.btn').contains('Open').click() + cy.logf("Deleting the project from the settings menu", Cypress.currentTest) cy.get('[data-cy="settings"]').click() cy.get('a').contains("Delete").click()